summaryrefslogtreecommitdiffstats
path: root/lib/Utils/DebugDump.cpp
diff options
context:
space:
mode:
authorKarel Klic <kklic@redhat.com>2009-11-09 13:55:20 +0100
committerKarel Klic <kklic@redhat.com>2009-11-09 13:55:20 +0100
commit19f406b4930c931a932dc6930762e8e12e29ce8b (patch)
treeb08468bf9a010cbce0ecd000a0279222f0d4b4e7 /lib/Utils/DebugDump.cpp
parent801ab58f32f2cb7dca3352b721a07c83705a0287 (diff)
parent8fa9a6ecd247454ab758efecf818d8067455c778 (diff)
downloadabrt-19f406b4930c931a932dc6930762e8e12e29ce8b.tar.gz
abrt-19f406b4930c931a932dc6930762e8e12e29ce8b.tar.xz
abrt-19f406b4930c931a932dc6930762e8e12e29ce8b.zip
merge
Diffstat (limited to 'lib/Utils/DebugDump.cpp')
-rw-r--r--lib/Utils/DebugDump.cpp280
1 files changed, 132 insertions, 148 deletions
diff --git a/lib/Utils/DebugDump.cpp b/lib/Utils/DebugDump.cpp
index 43eb324..bf793bb 100644
--- a/lib/Utils/DebugDump.cpp
+++ b/lib/Utils/DebugDump.cpp
@@ -23,45 +23,41 @@
#include <iostream>
#include <sstream>
#include <sys/utsname.h>
-#include <magic.h>
+//#include <magic.h>
#include "abrtlib.h"
#include "DebugDump.h"
#include "ABRTException.h"
#include "CommLayerInner.h"
-/* Is it "." or ".."? */
-/* abrtlib candidate */
-static bool dot_or_dotdot(const char *filename)
-{
- if (filename[0] != '.') return false;
- if (filename[1] == '\0') return true;
- if (filename[1] != '.') return false;
- if (filename[2] == '\0') return true;
- return false;
-}
-
static bool isdigit_str(const char *str)
{
- while (*str)
+ do
{
if (*str < '0' || *str > '9') return false;
str++;
- }
+ } while (*str);
return true;
}
-static std::string RemoveBackSlashes(const std::string& pDir);
+static std::string RemoveBackSlashes(const char *pDir)
+{
+ unsigned len = strlen(pDir);
+ while (len != 0 && pDir[len-1] == '/')
+ len--;
+ return std::string(pDir, len);
+}
+
static bool ExistFileDir(const char* pPath);
-static void LoadTextFile(const std::string& pPath, std::string& pData);
+static void LoadTextFile(const char *pPath, std::string& pData);
CDebugDump::CDebugDump() :
m_sDebugDumpDir(""),
- m_bOpened(false),
m_pGetNextFileDir(NULL),
- m_nLockfileFD(-1)
+ m_bOpened(false),
+ m_bLocked(false)
{}
-void CDebugDump::Open(const std::string& pDir)
+void CDebugDump::Open(const char *pDir)
{
if (m_bOpened)
{
@@ -70,7 +66,7 @@ void CDebugDump::Open(const std::string& pDir)
m_sDebugDumpDir = RemoveBackSlashes(pDir);
if (!ExistFileDir(m_sDebugDumpDir.c_str()))
{
- throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::CDebugDump(): "+m_sDebugDumpDir+" does not exist.");
+ throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::CDebugDump(): " + m_sDebugDumpDir + " does not exist.");
}
Lock();
m_bOpened = true;
@@ -96,10 +92,49 @@ static bool ExistFileDir(const char* pPath)
return false;
}
-static int GetAndSetLock(const char* pLockFile, const char* pPID)
+static bool GetAndSetLock(const char* pLockFile, const char* pPID)
{
- int fd;
+ while (symlink(pPID, pLockFile) != 0)
+ {
+ if (errno != EEXIST)
+ perror_msg_and_die("Can't create lock file '%s'", pLockFile);
+ char pid_buf[sizeof(pid_t)*3 + 4];
+ ssize_t r = readlink(pLockFile, pid_buf, sizeof(pid_buf) - 1);
+ if (r < 0)
+ perror_msg_and_die("Can't read lock file '%s'", pLockFile);
+ pid_buf[r] = '\0';
+
+ if (strcmp(pid_buf, pPID) == 0)
+ {
+ log("Lock file '%s' is already locked by us", pLockFile);
+ return false;
+ }
+ if (isdigit_str(pid_buf))
+ {
+ if (access(ssprintf("/proc/%s", pid_buf).c_str(), F_OK) == 0)
+ {
+ log("Lock file '%s' is locked by process %s", pLockFile, pid_buf);
+ return false;
+ }
+ log("Lock file '%s' was locked by process %s, but it crashed?", pLockFile, pid_buf);
+ }
+ /* The file may be deleted by now by other process. Ignore ENOENT */
+ if (unlink(pLockFile) != 0 && errno != ENOENT)
+ {
+ perror_msg_and_die("Can't remove stale lock file '%s'", pLockFile);
+ }
+ }
+
+ VERB1 log("Locked '%s'", pLockFile);
+ return true;
+
+#if 0
+/* Old code was using ordinary files instead of symlinks,
+ * but it had a race window between open and write, during which file was
+ * empty. It was seen to happen in practice.
+ */
+ int fd;
while ((fd = open(pLockFile, O_WRONLY | O_CREAT | O_EXCL, 0640)) < 0)
{
if (errno != EEXIST)
@@ -148,20 +183,22 @@ static int GetAndSetLock(const char* pLockFile, const char* pPID)
/* close(fd); - not needed, exiting does it too */
perror_msg_and_die("Can't write lock file '%s'", pLockFile);
}
+ close(fd);
VERB1 log("Locked '%s'", pLockFile);
- return fd;
+ return true;
+#endif
}
void CDebugDump::Lock()
{
- if (m_nLockfileFD >= 0)
+ if (m_bLocked)
error_msg_and_die("Locking bug on '%s'", m_sDebugDumpDir.c_str());
std::string lockFile = m_sDebugDumpDir + ".lock";
char pid_buf[sizeof(int)*3 + 2];
sprintf(pid_buf, "%u", (unsigned)getpid());
- while ((m_nLockfileFD = GetAndSetLock(lockFile.c_str(), pid_buf)) < 0)
+ while ((m_bLocked = GetAndSetLock(lockFile.c_str(), pid_buf)) != true)
{
usleep(500000);
}
@@ -169,27 +206,26 @@ void CDebugDump::Lock()
void CDebugDump::UnLock()
{
- if (m_nLockfileFD >= 0)
+ if (m_bLocked)
{
+ m_bLocked = false;
std::string lockFile = m_sDebugDumpDir + ".lock";
- close(m_nLockfileFD);
- m_nLockfileFD = -1;
xunlink(lockFile.c_str());
VERB1 log("UnLocked '%s'", lockFile.c_str());
}
}
-void CDebugDump::Create(const std::string& pDir, uid_t uid)
+void CDebugDump::Create(const char *pDir, int64_t uid)
{
if (m_bOpened)
{
- throw CABRTException(EXCEP_ERROR, "CDebugDump::CDebugDump(): DebugDump is already opened.");
+ throw CABRTException(EXCEP_ERROR, "DebugDump is already opened");
}
m_sDebugDumpDir = RemoveBackSlashes(pDir);
if (ExistFileDir(m_sDebugDumpDir.c_str()))
{
- throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::CDebugDump(): "+m_sDebugDumpDir+" already exists.");
+ throw CABRTException(EXCEP_DD_OPEN, ssprintf("'%s' already exists", m_sDebugDumpDir.c_str()));
}
Lock();
@@ -199,13 +235,13 @@ void CDebugDump::Create(const std::string& pDir, uid_t uid)
{
UnLock();
m_bOpened = false;
- throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::Create(): Cannot create dir: " + pDir);
+ throw CABRTException(EXCEP_DD_OPEN, ssprintf("Can't create dir '%s'", pDir));
}
if (chmod(m_sDebugDumpDir.c_str(), 0700) == -1)
{
UnLock();
m_bOpened = false;
- throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::Create(): Cannot change permissions, dir: " + pDir);
+ throw CABRTException(EXCEP_DD_OPEN, ssprintf("Can't change mode of '%s'", pDir));
}
struct passwd* pw = getpwuid(uid);
gid_t gid = pw ? pw->pw_gid : uid;
@@ -216,14 +252,15 @@ void CDebugDump::Create(const std::string& pDir, uid_t uid)
perror_msg("can't change '%s' ownership to %u:%u", m_sDebugDumpDir.c_str(), (int)uid, (int)gid);
}
- SaveText(FILENAME_UID, ssprintf("%u", (int)uid));
+ SaveText(FILENAME_UID, to_string(uid).c_str());
SaveKernelArchitectureRelease();
- SaveTime();
+ time_t t = time(NULL);
+ SaveText(FILENAME_TIME, to_string(t).c_str());
}
-static void DeleteFileDir(const std::string& pDir)
+static void DeleteFileDir(const char *pDir)
{
- DIR *dir = opendir(pDir.c_str());
+ DIR *dir = opendir(pDir);
if (!dir)
return;
@@ -232,26 +269,28 @@ static void DeleteFileDir(const std::string& pDir)
{
if (dot_or_dotdot(dent->d_name))
continue;
- std::string fullPath = pDir + "/" + dent->d_name;
+ std::string fullPath = concat_path_file(pDir, dent->d_name);
if (unlink(fullPath.c_str()) == -1)
{
if (errno != EISDIR)
{
closedir(dir);
- throw CABRTException(EXCEP_DD_DELETE, std::string(__func__) + ": Cannot remove file: " + fullPath);
+ throw CABRTException(EXCEP_DD_DELETE, ssprintf("Can't remove dir %s", fullPath.c_str()));
}
- DeleteFileDir(fullPath);
+ DeleteFileDir(fullPath.c_str());
}
}
closedir(dir);
- if (remove(pDir.c_str()) == -1)
+ if (remove(pDir) == -1)
{
- throw CABRTException(EXCEP_DD_DELETE, std::string(__func__) + ": Cannot remove dir: " + pDir);
+ throw CABRTException(EXCEP_DD_DELETE, ssprintf("Can't remove dir %s", pDir));
}
}
-static bool IsTextFile(const std::string& pName)
+static bool IsTextFile(const char *name)
{
+/* This idiotic library thinks that file containing just "0" is not text (!!)
+
magic_t m = magic_open(MAGIC_MIME_TYPE);
if (m == NULL)
@@ -280,16 +319,24 @@ static bool IsTextFile(const std::string& pName)
magic_close(m);
return isText;
-}
+ */
+ int fd = open(name, O_RDONLY);
+ if (fd < 0)
+ return false;
-static std::string RemoveBackSlashes(const std::string& pDir)
-{
- std::string ret = pDir;
- while (ret[ret.length() - 1] == '/')
+ unsigned char buf[4*1024];
+ int r = full_read(fd, buf, sizeof(buf));
+ close(fd);
+
+ while (--r >= 0)
{
- ret = ret.substr(0, ret.length() - 2);
+ if (buf[r] >= 0x7f)
+ return false;
+ /* Among control chars, only '\t','\n' etc are allowed */
+ if (buf[r] < ' ' && !isspace(buf[r]))
+ return false;
}
- return ret;
+ return true;
}
void CDebugDump::Delete()
@@ -298,7 +345,7 @@ void CDebugDump::Delete()
{
return;
}
- DeleteFileDir(m_sDebugDumpDir);
+ DeleteFileDir(m_sDebugDumpDir.c_str());
}
void CDebugDump::Close()
@@ -322,100 +369,47 @@ void CDebugDump::SaveKernelArchitectureRelease()
}
std::string release;
LoadTextFile("/etc/redhat-release", release);
- SaveText(FILENAME_RELEASE, release);
+ const char *release_ptr = release.c_str();
+ unsigned len_1st_str = strchrnul(release_ptr, '\n') - release_ptr;
+ release.erase(len_1st_str); /* usually simply removes trailing '\n' */
+ SaveText(FILENAME_RELEASE, release.c_str());
}
-void CDebugDump::SaveTime()
+static void LoadTextFile(const char *pPath, std::string& pData)
{
- time_t t = time(NULL);
- SaveText(FILENAME_TIME, to_string(t));
-}
-
-static void LoadTextFile(const std::string& pPath, std::string& pData)
-{
- std::ifstream fIn;
+ FILE *fp = fopen(pPath, "r");
+ if (!fp)
+ {
+ throw CABRTException(EXCEP_DD_LOAD, ssprintf("Can't open file '%s'", pPath));
+ }
pData = "";
- fIn.open(pPath.c_str());
- if (fIn.is_open())
+ int ch;
+ while ((ch = fgetc(fp)) != EOF)
{
- // TODO: rewrite this
- int ch;
- while ((ch = fIn.get())!= EOF)
+ if (ch == '\0')
{
- if (ch == 0)
- {
- pData += " ";
- }
- else if (isspace(ch) || (isascii(ch) && !iscntrl(ch)))
- {
- pData += ch;
- }
+ pData += ' ';
}
- fIn.close();
- }
- else
- {
- throw CABRTException(EXCEP_DD_LOAD, std::string(__func__) + ": Cannot open file " + pPath);
- }
-}
-
-static void LoadBinaryFile(const std::string& pPath, char** pData, unsigned int* pSize)
-{
- std::ifstream fIn;
- fIn.open(pPath.c_str(), std::ios::binary | std::ios::ate);
- unsigned int size;
- if (fIn.is_open())
- {
- size = fIn.tellg();
- char *data = new char [size];
- fIn.read(data, size);
-
- *pData = data;
- *pSize = size;
-
- fIn.close();
- }
- else
- {
- throw CABRTException(EXCEP_DD_LOAD, std::string(__func__) + ": Cannot open file " + pPath);
- }
-}
-
-static void SaveTextFile(const std::string& pPath, const std::string& pData)
-{
- std::ofstream fOut;
- fOut.open(pPath.c_str());
- if (fOut.is_open())
- {
- fOut << pData;
- if (!fOut.good())
+ else if (isspace(ch) || (isascii(ch) && !iscntrl(ch)))
{
- throw CABRTException(EXCEP_DD_SAVE, std::string(__func__) + ": Cannot save file " + pPath);
+ pData += ch;
}
- fOut.close();
- }
- else
- {
- throw CABRTException(EXCEP_DD_SAVE, std::string(__func__) + ": Cannot open file " + pPath);
}
+ fclose(fp);
}
-static void SaveBinaryFile(const std::string& pPath, const char* pData, const unsigned pSize)
+static void SaveBinaryFile(const char *pPath, const char* pData, unsigned pSize)
{
- std::ofstream fOut;
- fOut.open(pPath.c_str(), std::ios::binary);
- if (fOut.is_open())
+ int fd = open(pPath, O_WRONLY | O_TRUNC | O_CREAT, 0666);
+ if (fd < 0)
{
- fOut.write(pData, pSize);
- if (!fOut.good())
- {
- throw CABRTException(EXCEP_DD_SAVE, std::string(__func__) + ": Cannot save file " + pPath);
- }
- fOut.close();
+ throw CABRTException(EXCEP_DD_SAVE, ssprintf("Can't open file '%s'", pPath));
}
- else
+ unsigned r = full_write(fd, pData, pSize);
+ close(fd);
+ if (r != pSize)
{
- throw CABRTException(EXCEP_DD_SAVE, std::string(__func__) + ": Cannot open file " + pPath);
+ throw CABRTException(EXCEP_DD_SAVE, ssprintf("Can't save file '%s'", pPath));
}
}
@@ -425,36 +419,27 @@ void CDebugDump::LoadText(const char* pName, std::string& pData)
{
throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::LoadText(): DebugDump is not opened.");
}
- std::string fullPath = m_sDebugDumpDir + "/" + pName;
- LoadTextFile(fullPath, pData);
-}
-void CDebugDump::LoadBinary(const char* pName, char** pData, unsigned int* pSize)
-{
- if (!m_bOpened)
- {
- throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::LoadBinary(): DebugDump is not opened.");
- }
- std::string fullPath = m_sDebugDumpDir + "/" + pName;
- LoadBinaryFile(fullPath, pData, pSize);
+ std::string fullPath = m_sDebugDumpDir + '/' + pName;
+ LoadTextFile(fullPath.c_str(), pData);
}
-void CDebugDump::SaveText(const char* pName, const std::string& pData)
+void CDebugDump::SaveText(const char* pName, const char* pData)
{
if (!m_bOpened)
{
throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::SaveText(): DebugDump is not opened.");
}
std::string fullPath = m_sDebugDumpDir + "/" + pName;
- SaveTextFile(fullPath, pData);
+ SaveBinaryFile(fullPath.c_str(), pData, strlen(pData));
}
-void CDebugDump::SaveBinary(const char* pName, const char* pData, const unsigned int pSize)
+void CDebugDump::SaveBinary(const char* pName, const char* pData, unsigned pSize)
{
if (!m_bOpened)
{
throw CABRTException(EXCEP_DD_OPEN, "CDebugDump::SaveBinary(): DebugDump is not opened.");
}
std::string fullPath = m_sDebugDumpDir + "/" + pName;
- SaveBinaryFile(fullPath, pData, pSize);
+ SaveBinaryFile(fullPath.c_str(), pData, pSize);
}
void CDebugDump::InitGetNextFile()
@@ -486,17 +471,17 @@ bool CDebugDump::GetNextFile(std::string& pFileName, std::string& pContent, bool
{
if (is_regular_file(dent, m_sDebugDumpDir.c_str()))
{
- std::string fullname = m_sDebugDumpDir + "/" + dent->d_name;
+ std::string fullname = m_sDebugDumpDir + '/' + dent->d_name;
pFileName = dent->d_name;
- if (IsTextFile(fullname))
+ if (IsTextFile(fullname.c_str()))
{
LoadText(dent->d_name, pContent);
pIsTextFile = true;
}
else
{
- pContent = "";
+ pContent.clear();
pIsTextFile = false;
}
return true;
@@ -506,4 +491,3 @@ bool CDebugDump::GetNextFile(std::string& pFileName, std::string& pContent, bool
m_pGetNextFileDir = NULL;
return false;
}
-