summaryrefslogtreecommitdiffstats
path: root/src/Daemon/Daemon.cpp
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-08-21 17:01:41 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2009-08-21 17:01:41 +0200
commitbc71159f125f58bd48af950988b8ed19213f57b6 (patch)
tree6ebf9fd3332e1df5dda460fd6886ade3d9f5f5fa /src/Daemon/Daemon.cpp
parent574e102451faba061502c07a0a78ab9c300e2191 (diff)
downloadabrt-bc71159f125f58bd48af950988b8ed19213f57b6.tar.gz
abrt-bc71159f125f58bd48af950988b8ed19213f57b6.tar.xz
abrt-bc71159f125f58bd48af950988b8ed19213f57b6.zip
move class CCrashWatcher into daemon.cpp
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'src/Daemon/Daemon.cpp')
-rw-r--r--src/Daemon/Daemon.cpp1062
1 files changed, 1056 insertions, 6 deletions
diff --git a/src/Daemon/Daemon.cpp b/src/Daemon/Daemon.cpp
index 8f08eb6..b40cef7 100644
--- a/src/Daemon/Daemon.cpp
+++ b/src/Daemon/Daemon.cpp
@@ -18,15 +18,1065 @@
*/
#include "abrtlib.h"
-#include "CrashWatcher.h"
+#include <sys/inotify.h>
+#include <glib.h>
+#include <pthread.h>
+
#include "ABRTException.h"
#include <iostream>
-#include <cstdio>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
+//#include <sstream>
+#include <string>
+
+//#include "DBusManager.h"
+//#include "DBusServerProxy.h"
+#include "MiddleWare.h"
+#include "Settings.h"
+
+//FIXME remove when it gets to autoconf
+//#include "CommLayerServerDBus.h"
+//#include "CommLayerServerSocket.h"
+#ifdef ENABLE_DBUS
+ #include "CommLayerServerDBus.h"
+#elif ENABLE_SOCKET
+ #include "CommLayerServerSocket.h"
+#endif
+#include "CommLayerInner.h"
+
+// 1024 simultaneous actions
+#define INOTIFY_BUFF_SIZE ((sizeof(struct inotify_event)+FILENAME_MAX)*1024)
+
+#define VAR_RUN_LOCK_FILE VAR_RUN"/abrt.lock"
+#define VAR_RUN_PIDFILE VAR_RUN"/abrt.pid"
+
+static uint8_t sig_caught; /* = 0 */
+
+
+/* CCrashWatcher interface */
+
+namespace { /* make it all static */
+
+class CCrashWatcher
+//: public CDBusServer_adaptor,
+// public DBus::IntrospectableAdaptor,
+// public DBus::ObjectAdaptor,
+: public CObserver
+{
+ private:
+ //FIXME: add some struct to be able to join all threads!
+ typedef struct SCronCallbackData
+ {
+ CCrashWatcher* m_pCrashWatcher;
+ std::string m_sPluginName;
+ std::string m_sPluginArgs;
+ unsigned int m_nTimeout;
+
+ SCronCallbackData(CCrashWatcher* pCrashWatcher,
+ const std::string& pPluginName,
+ const std::string& pPluginArgs,
+ const unsigned int& pTimeout) :
+ m_pCrashWatcher(pCrashWatcher),
+ m_sPluginName(pPluginName),
+ m_sPluginArgs(pPluginArgs),
+ m_nTimeout(pTimeout)
+ {}
+
+ } cron_callback_data_t;
+
+ typedef struct SThreadData {
+ pthread_t thread_id;
+ char* UUID;
+ char* UID;
+ char *dest;
+ CCrashWatcher *daemon;
+ } thread_data_t;
+
+ /**
+ * Map to cache the results from CreateReport_t
+ * <UID, <UUID, result>>
+ */
+ std::map <const std::string, std::map <int, map_crash_report_t > > pending_jobs;
+ /**
+ * mutex to protect pending_jobs from being accesed by multiple threads at the same time
+ */
+ pthread_mutex_t m_pJobsMutex;
+
+ static gboolean handle_event_cb(GIOChannel *gio, GIOCondition condition, gpointer data);
+ static void *create_report(void *arg);
+ static gboolean cron_activation_periodic_cb(gpointer data);
+ static gboolean cron_activation_one_cb(gpointer data);
+ static gboolean cron_activation_reshedule_cb(gpointer data);
+ static void cron_delete_callback_data_cb(gpointer data);
+
+ void StartWatch();
+ void GStartWatch();
+ void CreatePidFile();
+ void Lock();
+ void SetUpMW();
+ void SetUpCron();
+ /* finds dumps created when daemon wasn't running */
+ // FIXME: how to catch abrt itself without this?
+ void FindNewDumps(const std::string& pPath);
+
+ int m_nFd;
+ GIOChannel* m_pGio;
+ GMainLoop *m_pMainloop;
+ std::string m_sTarget;
+ CMiddleWare *m_pMW;
+ CCommLayerServer *m_pCommLayer;
+ /*FIXME not needed */
+ //DBus::Connection *m_pConn;
+ CSettings *m_pSettings;
+ public:
+ //CCrashWatcher(const std::string& pPath,DBus::Connection &connection);
+ CCrashWatcher(const std::string& pPath);
+ virtual ~CCrashWatcher();
+ void Run();
+ void StopRun();
+
+ /* methods exported on dbus */
+ public:
+ virtual vector_crash_infos_t GetCrashInfos(const std::string &pUID);
+ /*FIXME: fix CLI and remove this stub*/
+ virtual map_crash_report_t CreateReport(const std::string &pUUID,const std::string &pUID){map_crash_report_t retval; return retval;};
+ uint64_t CreateReport_t(const std::string &pUUID,const std::string &pUID, const std::string &pSender);
+ virtual CMiddleWare::report_status_t Report(map_crash_report_t pReport, const std::string &pUID);
+ virtual bool DeleteDebugDump(const std::string& pUUID, const std::string& pUID);
+ virtual map_crash_report_t GetJobResult(uint64_t pJobID, const std::string& pSender);
+ /* plugins related */
+ virtual vector_map_string_string_t GetPluginsInfo();
+ virtual map_plugin_settings_t GetPluginSettings(const std::string& pName, const std::string& pUID);
+ void SetPluginSettings(const std::string& pName, const std::string& pUID, const map_plugin_settings_t& pSettings);
+ void RegisterPlugin(const std::string& pName);
+ void UnRegisterPlugin(const std::string& pName);
+
+ /* Observer methods */
+ void Status(const std::string& pMessage,const std::string& pDest="0");
+ void Debug(const std::string& pMessage, const std::string& pDest="0");
+ void Warning(const std::string& pMessage, const std::string& pDest="0");
+};
+
+} /* unnamed namespace */
+
+
+/* CCrashWatcher implementation */
+
+namespace { /* make it all static */
+
+/* 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 double GetDirSize(const std::string &pPath);
+
+gboolean CCrashWatcher::handle_event_cb(GIOChannel *gio, GIOCondition condition, gpointer daemon)
+{
+ GIOError err;
+ char *buf = new char[INOTIFY_BUFF_SIZE];
+ gsize len;
+ gsize i = 0;
+ err = g_io_channel_read(gio, buf, INOTIFY_BUFF_SIZE, &len);
+ CCrashWatcher *cc = (CCrashWatcher*)daemon;
+ if (err != G_IO_ERROR_NONE)
+ {
+ cc->Warning("Error reading inotify fd.");
+ delete[] buf;
+ return FALSE;
+ }
+ /* reconstruct each event and send message to the dbus */
+ while (i < len)
+ {
+ const char *name = NULL;
+ struct inotify_event *event;
+
+ event = (struct inotify_event *) &buf[i];
+ if (event->len)
+ name = &buf[i] + sizeof (struct inotify_event);
+ i += sizeof (struct inotify_event) + event->len;
+
+ cc->Debug(std::string("Created file: ") + name);
+
+ /* we want to ignore the lock files */
+ if (event->mask & IN_ISDIR)
+ {
+ if (GetDirSize(DEBUG_DUMPS_DIR) / (1024*1024) < cc->m_pSettings->GetMaxCrashReportsSize())
+ {
+ //std::string sName = name;
+ map_crash_info_t crashinfo;
+ try
+ {
+ CMiddleWare::mw_result_t res;
+ res = cc->m_pMW->SaveDebugDump(std::string(DEBUG_DUMPS_DIR) + "/" + name, crashinfo);
+ switch (res)
+ {
+ case CMiddleWare::MW_OK:
+ cc->Debug("New crash, saving...");
+ cc->m_pMW->RunActionsAndReporters(crashinfo[CD_MWDDD][CD_CONTENT]);
+ /* send message to dbus */
+ cc->m_pCommLayer->Crash(crashinfo[CD_PACKAGE][CD_CONTENT]);
+ break;
+ case CMiddleWare::MW_REPORTED:
+ case CMiddleWare::MW_OCCURED:
+ /* send message to dbus */
+ cc->Debug("Already saved crash, deleting...");
+ cc->m_pCommLayer->Crash(crashinfo[CD_PACKAGE][CD_CONTENT]);
+ cc->m_pMW->DeleteDebugDumpDir(std::string(DEBUG_DUMPS_DIR) + "/" + name);
+ break;
+ case CMiddleWare::MW_BLACKLISTED:
+ case CMiddleWare::MW_CORRUPTED:
+ case CMiddleWare::MW_PACKAGE_ERROR:
+ case CMiddleWare::MW_GPG_ERROR:
+ case CMiddleWare::MW_IN_DB:
+ case CMiddleWare::MW_FILE_ERROR:
+ default:
+ cc->Warning("Corrupted or bad crash, deleting...");
+ cc->m_pMW->DeleteDebugDumpDir(std::string(DEBUG_DUMPS_DIR) + "/" + name);
+ break;
+ }
+ }
+ catch (CABRTException& e)
+ {
+ cc->Warning(e.what());
+ if (e.type() == EXCEP_FATAL)
+ {
+ delete[] buf;
+ return -1;
+ }
+ }
+ catch (...)
+ {
+ delete[] buf;
+ throw;
+ }
+ }
+ else
+ {
+ cc->Debug(std::string("DebugDumps size has exceeded the limit, deleting the last dump: ") + name);
+ cc->m_pMW->DeleteDebugDumpDir(std::string(DEBUG_DUMPS_DIR) + "/" + name);
+ }
+ }
+ else
+ {
+ cc->Debug("Some file created, ignoring...");
+ }
+ }
+ delete[] buf;
+ return TRUE;
+}
+
+void *CCrashWatcher::create_report(void *arg)
+{
+ thread_data_t *thread_data = (thread_data_t *) arg;
+ map_crash_info_t crashReport;
+ thread_data->daemon->Debug("Creating report...");
+ try
+ {
+ CMiddleWare::mw_result_t res;
+ res = thread_data->daemon->m_pMW->CreateCrashReport(thread_data->UUID,thread_data->UID,crashReport);
+ switch (res)
+ {
+ case CMiddleWare::MW_OK:
+ break;
+ case CMiddleWare::MW_IN_DB_ERROR:
+ thread_data->daemon->Warning(std::string("Did not find crash with UUID ")+thread_data->UUID+ " in database.");
+ break;
+ case CMiddleWare::MW_PLUGIN_ERROR:
+ thread_data->daemon->Warning(std::string("Particular analyzer plugin isn't loaded or there is an error within plugin(s)."));
+ break;
+ case CMiddleWare::MW_CORRUPTED:
+ case CMiddleWare::MW_FILE_ERROR:
+ default:
+ {
+ std::string debugDumpDir;
+ thread_data->daemon->Warning(std::string("Corrupted crash with UUID ")+thread_data->UUID+", deleting.");
+ debugDumpDir = thread_data->daemon->m_pMW->DeleteCrashInfo(thread_data->UUID, thread_data->UID);
+ thread_data->daemon->m_pMW->DeleteDebugDumpDir(debugDumpDir);
+ }
+ break;
+ }
+ /* only one thread can write */
+ pthread_mutex_lock(&(thread_data->daemon->m_pJobsMutex));
+ thread_data->daemon->pending_jobs[std::string(thread_data->UID)][thread_data->thread_id] = crashReport;
+ pthread_mutex_unlock(&(thread_data->daemon->m_pJobsMutex));
+ thread_data->daemon->m_pCommLayer->JobDone(thread_data->dest, thread_data->thread_id);
+ }
+ catch (CABRTException& e)
+ {
+ if (e.type() == EXCEP_FATAL)
+ {
+ /* free strduped strings */
+ free(thread_data->UUID);
+ free(thread_data->UID);
+ free(thread_data->dest);
+ free(thread_data);
+ throw e;
+ }
+ thread_data->daemon->Warning(e.what());
+ }
+ /* free strduped strings */
+ free(thread_data->UUID);
+ free(thread_data->UID);
+ free(thread_data->dest);
+ free(thread_data);
+
+ /* Bogus value. pthreads require us to return void* */
+ return NULL;
+}
+
+gboolean CCrashWatcher::cron_activation_periodic_cb(gpointer data)
+{
+ cron_callback_data_t* cronPeriodicCallbackData = static_cast<cron_callback_data_t*>(data);
+ cronPeriodicCallbackData->m_pCrashWatcher->Debug("Activating plugin: " + cronPeriodicCallbackData->m_sPluginName);
+ cronPeriodicCallbackData->m_pCrashWatcher->m_pMW->RunAction(cronPeriodicCallbackData->m_pCrashWatcher->m_sTarget,
+ cronPeriodicCallbackData->m_sPluginName,
+ cronPeriodicCallbackData->m_sPluginArgs);
+ return TRUE;
+}
+gboolean CCrashWatcher::cron_activation_one_cb(gpointer data)
+{
+ cron_callback_data_t* cronOneCallbackData = static_cast<cron_callback_data_t*>(data);
+ cronOneCallbackData->m_pCrashWatcher->Debug("Activating plugin: " + cronOneCallbackData->m_sPluginName);
+ cronOneCallbackData->m_pCrashWatcher->m_pMW->RunAction(cronOneCallbackData->m_pCrashWatcher->m_sTarget,
+ cronOneCallbackData->m_sPluginName,
+ cronOneCallbackData->m_sPluginArgs);
+ return FALSE;
+}
+gboolean CCrashWatcher::cron_activation_reshedule_cb(gpointer data)
+{
+ cron_callback_data_t* cronResheduleCallbackData = static_cast<cron_callback_data_t*>(data);
+ cronResheduleCallbackData->m_pCrashWatcher->Debug("Rescheduling plugin: " + cronResheduleCallbackData->m_sPluginName);
+ cron_callback_data_t* cronPeriodicCallbackData = new cron_callback_data_t(cronResheduleCallbackData->m_pCrashWatcher,
+ cronResheduleCallbackData->m_sPluginName,
+ cronResheduleCallbackData->m_sPluginArgs,
+ cronResheduleCallbackData->m_nTimeout);
+ g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
+ cronPeriodicCallbackData->m_nTimeout,
+ cron_activation_periodic_cb,
+ static_cast<gpointer>(cronPeriodicCallbackData),
+ cron_delete_callback_data_cb);
+
+
+ return FALSE;
+}
+
+void CCrashWatcher::cron_delete_callback_data_cb(gpointer data)
+{
+ cron_callback_data_t* cronDeleteCallbackData = static_cast<cron_callback_data_t*>(data);
+ delete cronDeleteCallbackData;
+}
+
+void CCrashWatcher::SetUpMW()
+{
+ m_pMW->SetOpenGPGCheck(m_pSettings->GetOpenGPGCheck());
+ m_pMW->SetDatabase(m_pSettings->GetDatabase());
+ CSettings::set_strings_t openGPGPublicKeys = m_pSettings->GetOpenGPGPublicKeys();
+ CSettings::set_strings_t::iterator it_k;
+ for (it_k = openGPGPublicKeys.begin(); it_k != openGPGPublicKeys.end(); it_k++)
+ {
+ m_pMW->AddOpenGPGPublicKey(*it_k);
+ }
+ CSettings::set_strings_t blackList = m_pSettings->GetBlackList();
+ CSettings::set_strings_t::iterator it_b;
+ for (it_b = blackList.begin(); it_b != blackList.end(); it_b++)
+ {
+ m_pMW->AddBlackListedPackage(*it_b);
+ }
+ CSettings::set_strings_t enabledPlugins = m_pSettings->GetEnabledPlugins();
+ CSettings::set_strings_t::iterator it_p;
+ for (it_p = enabledPlugins.begin(); it_p != enabledPlugins.end(); it_p++)
+ {
+ m_pMW->RegisterPlugin(*it_p);
+ }
+ CSettings::vector_pair_strings_t actionsAndReporters = m_pSettings->GetActionsAndReporters();
+ CSettings::vector_pair_strings_t::iterator it_ar;
+ for (it_ar = actionsAndReporters.begin(); it_ar != actionsAndReporters.end(); it_ar++)
+ {
+ m_pMW->AddActionOrReporter((*it_ar).first, (*it_ar).second);
+ }
+
+ CSettings::map_analyzer_actions_and_reporters_t analyzerActionsAndReporters = m_pSettings->GetAnalyzerActionsAndReporters();
+ CSettings::map_analyzer_actions_and_reporters_t::iterator it_aar;
+ for (it_aar = analyzerActionsAndReporters.begin(); it_aar != analyzerActionsAndReporters.end(); it_aar++)
+ {
+ CSettings::vector_pair_strings_t::iterator it_ar;
+ for (it_ar = it_aar->second.begin(); it_ar != it_aar->second.end(); it_ar++)
+ {
+ m_pMW->AddAnalyzerActionOrReporter(it_aar->first, (*it_ar).first, (*it_ar).second);
+ }
+ }
+}
+
+void CCrashWatcher::SetUpCron()
+{
+ CSettings::map_cron_t cron = m_pSettings->GetCron();
+ CSettings::map_cron_t::iterator it_c;
+ for (it_c = cron.begin(); it_c != cron.end(); it_c++)
+ {
+ std::string::size_type pos = it_c->first.find(":");
+ int timeout = 0;
+ int nH = -1;
+ int nM = -1;
+ int nS = -1;
+
+ if (pos != std::string::npos)
+ {
+ std::string sH = "";
+ std::string sM = "";
+
+ sH = it_c->first.substr(0, pos);
+ nH = atoi(sH.c_str());
+ nH = nH > 23 ? 23 : nH;
+ nH = nH < 0 ? 0 : nH;
+ nM = nM > 59 ? 59 : nM;
+ nM = nM < 0 ? 0 : nM;
+ timeout += nH * 60 * 60;
+ sM = it_c->first.substr(pos + 1);
+ nM = atoi(sM.c_str());
+ timeout += nM * 60;
+ }
+ else
+ {
+ std::string sS = "";
+
+ sS = it_c->first;
+ nS = atoi(sS.c_str());
+ nS = nS <= 0 ? 1 : nS;
+ timeout = nS;
+ }
+
+ if (nS != -1)
+ {
+ CSettings::vector_pair_strings_t::iterator it_ar;
+ for (it_ar = it_c->second.begin(); it_ar != it_c->second.end(); it_ar++)
+ {
+
+ cron_callback_data_t* cronPeriodicCallbackData = new cron_callback_data_t(this, (*it_ar).first, (*it_ar).second, timeout);
+ g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
+ timeout,
+ cron_activation_periodic_cb,
+ static_cast<gpointer>(cronPeriodicCallbackData),
+ cron_delete_callback_data_cb);
+ }
+ }
+ else
+ {
+ time_t actTime = time(NULL);
+ if (actTime == ((time_t)-1))
+ {
+ throw CABRTException(EXCEP_FATAL, "CCrashWatcher::SetUpCron(): Cannot get time.");
+ }
+ struct tm locTime;
+ if (localtime_r(&actTime, &locTime) == NULL)
+ {
+ throw CABRTException(EXCEP_FATAL, "CCrashWatcher::SetUpCron(): Cannot get local time.");
+ }
+ locTime.tm_hour = nH;
+ locTime.tm_min = nM;
+ locTime.tm_sec = 0;
+ time_t nextTime = mktime(&locTime);
+ if (nextTime == ((time_t)-1))
+ {
+ throw CABRTException(EXCEP_FATAL, "CCrashWatcher::SetUpCron(): Cannot set up time.");
+ }
+ if (actTime > nextTime)
+ {
+ timeout = 24*60*60 + (nextTime - actTime);
+ }
+ else
+ {
+ timeout = nextTime - actTime;
+ }
+ CSettings::vector_pair_strings_t::iterator it_ar;
+ for (it_ar = it_c->second.begin(); it_ar != it_c->second.end(); it_ar++)
+ {
+
+ cron_callback_data_t* cronOneCallbackData = new cron_callback_data_t(this, (*it_ar).first, (*it_ar).second, timeout);
+ g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
+ timeout,
+ cron_activation_one_cb,
+ static_cast<gpointer>(cronOneCallbackData),
+ cron_delete_callback_data_cb);
+ cron_callback_data_t* cronResheduleCallbackData = new cron_callback_data_t(this, (*it_ar).first, (*it_ar).second, 24 * 60 * 60);
+ g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
+ timeout,
+ cron_activation_reshedule_cb,
+ static_cast<gpointer>(cronResheduleCallbackData),
+ cron_delete_callback_data_cb);
+ }
+ }
+ }
+}
+
+void CCrashWatcher::Status(const std::string& pMessage, const std::string& pDest)
+{
+ std::cout << "Update: " + pMessage << std::endl;
+ //FIXME: send updates only to job owner
+ if(m_pCommLayer != NULL)
+ m_pCommLayer->Update(pDest,pMessage);
+}
+
+void CCrashWatcher::Warning(const std::string& pMessage, const std::string& pDest)
+{
+ std::cerr << "Warning: " + pMessage << std::endl;
+ if(m_pCommLayer != NULL)
+ m_pCommLayer->Warning(pDest,pMessage);
+}
+
+void CCrashWatcher::Debug(const std::string& pMessage, const std::string& pDest)
+{
+ //some logic to add logging levels?
+ std::cout << "Debug: " + pMessage << std::endl;
+}
+
+static double GetDirSize(const std::string &pPath)
+{
+ double size = 0;
+ struct dirent *ep;
+ struct stat stats;
+ DIR *dp;
+
+ dp = opendir(pPath.c_str());
+ if (dp != NULL)
+ {
+ while ((ep = readdir(dp)) != NULL)
+ {
+ if (dot_or_dotdot(ep->d_name))
+ continue;
+ std::string dname = pPath + "/" + ep->d_name;
+ if (lstat(dname.c_str(), &stats) == 0)
+ {
+ if (S_ISDIR(stats.st_mode))
+ {
+ size += GetDirSize(dname);
+ }
+ else if (S_ISREG(stats.st_mode))
+ {
+ size += stats.st_size;
+ }
+ }
+ }
+ closedir(dp);
+ }
+ else
+ {
+ throw CABRTException(EXCEP_FATAL, std::string(__func__) + ": Init Failed");
+ }
+ return size;
+}
+
+CCrashWatcher::CCrashWatcher(const std::string& pPath)
+{
+ int watch = 0;
+ m_sTarget = pPath;
+
+ // TODO: initialize object according parameters -w -d
+ // status has to be always created.
+ m_pCommLayer = NULL;
+ comm_layer_inner_init(this);
+
+ m_pSettings = new CSettings();
+ m_pSettings->LoadSettings(std::string(CONF_DIR) + "/abrt.conf");
+
+ m_pMainloop = g_main_loop_new(NULL,FALSE);
+ m_pMW = new CMiddleWare(PLUGINS_CONF_DIR,PLUGINS_LIB_DIR);
+ if (pthread_mutex_init(&m_pJobsMutex, NULL) != 0)
+ {
+ throw CABRTException(EXCEP_FATAL, "CCrashWatcher::CCrashWatcher(): Can't init mutex!");
+ }
+ try
+ {
+ SetUpMW();
+ SetUpCron();
+ FindNewDumps(pPath);
+#ifdef ENABLE_DBUS
+ m_pCommLayer = new CCommLayerServerDBus();
+#elif ENABLE_SOCKET
+ m_pCommLayer = new CCommLayerServerSocket();
+#endif
+// m_pCommLayer = new CCommLayerServerDBus();
+// m_pCommLayer = new CCommLayerServerSocket();
+ m_pCommLayer->Attach(this);
+
+ if ((m_nFd = inotify_init()) == -1)
+ {
+ throw CABRTException(EXCEP_FATAL, "CCrashWatcher::CCrashWatcher(): Init Failed");
+ }
+ if ((watch = inotify_add_watch(m_nFd, pPath.c_str(), IN_CREATE)) == -1)
+ {
+ throw CABRTException(EXCEP_FATAL, "CCrashWatcher::CCrashWatcher(): Add watch failed:" + pPath);
+ }
+ m_pGio = g_io_channel_unix_new(m_nFd);
+ }
+ catch (...)
+ {
+ /* This restores /proc/sys/kernel/core_pattern, among other things */
+ delete m_pMW;
+ //too? delete m_pCommLayer;
+ throw;
+ }
+}
+
+CCrashWatcher::~CCrashWatcher()
+{
+ //delete dispatcher, connection, etc..
+ //m_pConn->disconnect();
+
+ g_io_channel_unref(m_pGio);
+ g_main_loop_unref(m_pMainloop);
+
+ delete m_pCommLayer;
+ delete m_pMW;
+ delete m_pSettings;
+ if (pthread_mutex_destroy(&m_pJobsMutex) != 0)
+ {
+ throw CABRTException(EXCEP_FATAL, "CCrashWatcher::CCrashWatcher(): Can't destroy mutex!");
+ }
+ /* delete pid file */
+ unlink(VAR_RUN_PIDFILE);
+ /* delete lock file */
+ unlink(VAR_RUN_LOCK_FILE);
+}
+
+void CCrashWatcher::FindNewDumps(const std::string& pPath)
+{
+ Debug("Scanning for unsaved entries...");
+ struct dirent *ep;
+ struct stat stats;
+ DIR *dp;
+ std::vector<std::string> dirs;
+ std::string dname;
+ // get potential unsaved debugdumps
+ dp = opendir(pPath.c_str());
+ if (dp != NULL)
+ {
+ while ((ep = readdir(dp)))
+ {
+ if (dot_or_dotdot(ep->d_name))
+ continue;
+ dname = pPath + "/" + ep->d_name;
+ if (lstat(dname.c_str(), &stats) == 0)
+ {
+ if (S_ISDIR(stats.st_mode))
+ {
+ dirs.push_back(dname);
+ }
+ }
+ }
+ (void) closedir(dp);
+ }
+ else
+ {
+ throw CABRTException(EXCEP_FATAL, "CCrashWatcher::FindNewDumps(): Couldn't open the directory:" + pPath);
+ }
+
+ for (std::vector<std::string>::iterator itt = dirs.begin(); itt != dirs.end(); ++itt){
+ map_crash_info_t crashinfo;
+ try
+ {
+ CMiddleWare::mw_result_t res;
+ res = m_pMW->SaveDebugDump(*itt, crashinfo);
+ switch (res)
+ {
+ case CMiddleWare::MW_OK:
+ Debug("Saving into database (" + *itt + ").");
+ m_pMW->RunActionsAndReporters(crashinfo[CD_MWDDD][CD_CONTENT]);
+ break;
+ case CMiddleWare::MW_IN_DB:
+ Debug("Already saved in database (" + *itt + ").");
+ break;
+ case CMiddleWare::MW_REPORTED:
+ case CMiddleWare::MW_OCCURED:
+ case CMiddleWare::MW_BLACKLISTED:
+ case CMiddleWare::MW_CORRUPTED:
+ case CMiddleWare::MW_PACKAGE_ERROR:
+ case CMiddleWare::MW_GPG_ERROR:
+ case CMiddleWare::MW_FILE_ERROR:
+ default:
+ Warning("Corrupted, bad or already saved crash, deleting.");
+ m_pMW->DeleteDebugDumpDir(*itt);
+ break;
+ }
+ }
+ catch (CABRTException& e)
+ {
+ if (e.type() == EXCEP_FATAL)
+ {
+ throw e;
+ }
+ Warning(e.what());
+ }
+ }
+}
+
+void CCrashWatcher::CreatePidFile()
+{
+ int fd;
+
+ /* JIC */
+ unlink(VAR_RUN_PIDFILE);
+
+ /* open the pidfile */
+ fd = open(VAR_RUN_PIDFILE, O_WRONLY|O_CREAT|O_EXCL, 0644);
+ if (fd >= 0)
+ {
+ /* write our pid to it */
+ char buf[sizeof(int)*3 + 2];
+ int len = sprintf(buf, "%u\n", (unsigned)getpid());
+ write(fd, buf, len);
+ close(fd);
+ return;
+ }
+
+ /* something went wrong */
+ throw CABRTException(EXCEP_FATAL, "CCrashWatcher::CreatePidFile(): can not open pid file");
+}
+
+void CCrashWatcher::Lock()
+{
+ int lfp = open(VAR_RUN_LOCK_FILE, O_RDWR|O_CREAT, 0640);
+ if (lfp < 0)
+ {
+ throw CABRTException(EXCEP_FATAL, "CCrashWatcher::Lock(): can not open lock file");
+ }
+ if (lockf(lfp, F_TLOCK, 0) < 0)
+ {
+ throw CABRTException(EXCEP_FATAL, "CCrashWatcher::Lock(): cannot create lock on lockfile");
+ }
+ /* only first instance continues */
+ //sprintf(str,"%d\n",getpid());
+ //write(lfp,str,strlen(str)); /* record pid to lockfile */
+}
+
+void CCrashWatcher::StartWatch()
+{
+ char *buff = new char[INOTIFY_BUFF_SIZE];
+ int len = 0;
+ int i = 0;
+ char action[FILENAME_MAX];
+ struct inotify_event *pevent;
+ //run forever
+ while (1)
+ {
+ i = 0;
+ len = read(m_nFd,buff,INOTIFY_BUFF_SIZE);
+ while (i < len)
+ {
+ pevent = (struct inotify_event *)&buff[i];
+ if (pevent->len)
+ {
+ strcpy(action, pevent->name);
+ }
+ else
+ {
+ strcpy(action, m_sTarget.c_str());
+ }
+
+ i += sizeof(struct inotify_event) + pevent->len;
+ Debug(std::string("Created file: ") + action);
+ }
+ }
+ delete[] buff;
+}
+
+//prepare()
+//If the source can determine that it is ready here (without waiting
+//for the results of the poll() call) it should return TRUE. It can also
+//return a timeout_ value which should be the maximum timeout (in milliseconds)
+//which should be passed to the poll() call.
+//check()
+//Called after all the file descriptors are polled. The source should
+//return TRUE if it is ready to be dispatched.
+//dispatch()
+//Called to dispatch the event source, after it has returned TRUE
+//in either its prepare or its check function. The dispatch function
+//is passed in a callback function and data. The callback function
+//may be NULL if the source was never connected to a callback using
+//g_source_set_callback(). The dispatch function should
+//call the callback function with user_data and whatever additional
+//parameters are needed for this type of event source.
+typedef struct SignalSource
+{
+ GSource src;
+ CCrashWatcher* watcher;
+} SignalSource;
+static gboolean waitsignal_prepare(GSource *source, gint *timeout_)
+{
+ /* We depend on the fact that in Unix, poll() is interrupted
+ * by caught signals (returns EINTR). Thus we do not need to set
+ * a small timeout here: infinite timeout (-1) works too */
+ *timeout_ = -1;
+ return sig_caught != 0;
+}
+static gboolean waitsignal_check(GSource *source)
+{
+ return sig_caught != 0;
+}
+static gboolean waitsignal_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
+{
+ SignalSource *ssrc = (SignalSource*) source;
+ ssrc->watcher->StopRun();
+ return 1;
+}
+
+/* daemon loop with glib */
+void CCrashWatcher::GStartWatch()
+{
+ g_io_add_watch(m_pGio, G_IO_IN, handle_event_cb, this);
+
+ GSourceFuncs waitsignal_funcs;
+ memset(&waitsignal_funcs, 0, sizeof(waitsignal_funcs));
+ waitsignal_funcs.prepare = waitsignal_prepare;
+ waitsignal_funcs.check = waitsignal_check;
+ waitsignal_funcs.dispatch = waitsignal_dispatch;
+ //waitsignal_funcs.finalize = NULL; - already done
+ SignalSource *waitsignal_src = (SignalSource*) g_source_new(&waitsignal_funcs, sizeof(*waitsignal_src));
+ waitsignal_src->watcher = this;
+ g_source_attach(&waitsignal_src->src, g_main_context_default());
+
+ //enter the event loop
+ g_main_run(m_pMainloop);
+}
+
+void CCrashWatcher::Run()
+{
+ Debug("Running...");
+ Lock();
+ CreatePidFile();
+ GStartWatch();
+}
+
+void CCrashWatcher::StopRun()
+{
+ g_main_quit(m_pMainloop);
+}
+
+vector_crash_infos_t CCrashWatcher::GetCrashInfos(const std::string &pUID)
+{
+ vector_crash_infos_t retval;
+ Debug("Getting crash infos...");
+ try
+ {
+ vector_pair_string_string_t UUIDsUIDs;
+ UUIDsUIDs = m_pMW->GetUUIDsOfCrash(pUID);
+
+ unsigned int ii;
+ for (ii = 0; ii < UUIDsUIDs.size(); ii++)
+ {
+ CMiddleWare::mw_result_t res;
+ map_crash_info_t info;
+
+ res = m_pMW->GetCrashInfo(UUIDsUIDs[ii].first, UUIDsUIDs[ii].second, info);
+ switch (res)
+ {
+ case CMiddleWare::MW_OK:
+ retval.push_back(info);
+ break;
+ case CMiddleWare::MW_ERROR:
+ Warning("Can not find debug dump directory for UUID: " + UUIDsUIDs[ii].first + ", deleting from database");
+ Status("Can not find debug dump directory for UUID: " + UUIDsUIDs[ii].first + ", deleting from database");
+ m_pMW->DeleteCrashInfo(UUIDsUIDs[ii].first, UUIDsUIDs[ii].second);
+ break;
+ case CMiddleWare::MW_FILE_ERROR:
+ {
+ std::string debugDumpDir;
+ Warning("Can not open file in debug dump directory for UUID: " + UUIDsUIDs[ii].first + ", deleting ");
+ Status("Can not open file in debug dump directory for UUID: " + UUIDsUIDs[ii].first + ", deleting ");
+ debugDumpDir = m_pMW->DeleteCrashInfo(UUIDsUIDs[ii].first, UUIDsUIDs[ii].second);
+ m_pMW->DeleteDebugDumpDir(debugDumpDir);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ catch (CABRTException& e)
+ {
+ if (e.type() == EXCEP_FATAL)
+ {
+ throw e;
+ }
+ Warning(e.what());
+ Status(e.what());
+ }
+
+ //retval = m_pMW->GetCrashInfos(pUID);
+ //Notify("Sent crash info");
+ return retval;
+}
+
+uint64_t CCrashWatcher::CreateReport_t(const std::string &pUUID,const std::string &pUID, const std::string &pSender)
+{
+ thread_data_t *thread_data = (thread_data_t *)xzalloc(sizeof(thread_data_t));
+ if (thread_data != NULL)
+ {
+ thread_data->UUID = xstrdup(pUUID.c_str());
+ thread_data->UID = xstrdup(pUID.c_str());
+ thread_data->dest = xstrdup(pSender.c_str());
+ thread_data->daemon = this;
+ if (pthread_create(&(thread_data->thread_id), NULL, create_report, (void *)thread_data) != 0)
+ {
+ throw CABRTException(EXCEP_FATAL, "CCrashWatcher::CreateReport_t(): Cannot create thread!");
+ }
+ }
+ else
+ {
+ throw CABRTException(EXCEP_FATAL, "CCrashWatcher::CreateReport_t(): Cannot allocate memory!");
+ }
+ //FIXME: we don't use this value anymore, so fix the API
+ return 0;
+}
+
+CMiddleWare::report_status_t CCrashWatcher::Report(map_crash_report_t pReport, const std::string& pUID)
+{
+ //#define FIELD(X) crashReport.m_s##X = pReport[#X];
+ //crashReport.m_sUUID = pReport["UUID"];
+ //ALL_CRASH_REPORT_FIELDS;
+ //#undef FIELD
+ //for (dbus_map_report_info_t::iterator it = pReport.begin(); it!=pReport.end(); ++it) {
+ // std::cerr << it->second << std::endl;
+ //}
+ CMiddleWare::report_status_t rs;
+ try
+ {
+ rs = m_pMW->Report(pReport, pUID);
+ }
+ catch (CABRTException& e)
+ {
+ if (e.type() == EXCEP_FATAL)
+ {
+ throw e;
+ }
+ Warning(e.what());
+ Status(e.what());
+ return rs;
+ }
+ return rs;
+}
+
+bool CCrashWatcher::DeleteDebugDump(const std::string& pUUID, const std::string& pUID)
+{
+ try
+ {
+ std::string debugDumpDir;
+ debugDumpDir = m_pMW->DeleteCrashInfo(pUUID,pUID);
+ m_pMW->DeleteDebugDumpDir(debugDumpDir);
+ }
+ catch (CABRTException& e)
+ {
+ if (e.type() == EXCEP_FATAL)
+ {
+ throw e;
+ }
+ Warning(e.what());
+ Status(e.what());
+ return false;
+ }
+ return true;
+}
+
+map_crash_report_t CCrashWatcher::GetJobResult(uint64_t pJobID, const std::string& pSender)
+{
+ /* FIXME: once we return the result, we should remove it from map to free memory
+ - use some TTL to clean the memory even if client won't get it
+ - if we don't find it in the cache we should try to ask MW to get it again??
+ */
+ return pending_jobs[pSender][pJobID];
+}
+
+vector_map_string_string_t CCrashWatcher::GetPluginsInfo()
+{
+ try
+ {
+ return m_pMW->GetPluginsInfo();
+ }
+ catch (CABRTException &e)
+ {
+ if (e.type() == EXCEP_FATAL)
+ {
+ throw e;
+ }
+ Warning(e.what());
+ }
+ // TODO: is it right? I added it just to disable a warning...
+ // but maybe returning empty map is wrong here?
+ return vector_map_string_string_t();
+}
+
+map_plugin_settings_t CCrashWatcher::GetPluginSettings(const std::string& pName, const std::string& pUID)
+{
+ try
+ {
+ return m_pMW->GetPluginSettings(pName, pUID);
+ }
+ catch(CABRTException &e)
+ {
+ if (e.type() == EXCEP_FATAL)
+ {
+ throw e;
+ }
+ Warning(e.what());
+ }
+}
+
+void CCrashWatcher::RegisterPlugin(const std::string& pName)
+{
+ try
+ {
+ m_pMW->RegisterPlugin(pName);
+ }
+ catch(CABRTException &e)
+ {
+ if (e.type() == EXCEP_FATAL)
+ {
+ throw e;
+ }
+ Warning(e.what());
+ }
+}
+
+void CCrashWatcher::UnRegisterPlugin(const std::string& pName)
+{
+ try
+ {
+ m_pMW->UnRegisterPlugin(pName);
+ }
+ catch(CABRTException &e)
+ {
+ if (e.type() == EXCEP_FATAL)
+ {
+ throw e;
+ }
+ Warning(e.what());
+ }
+}
+
+void CCrashWatcher::SetPluginSettings(const std::string& pName, const std::string& pUID, const map_plugin_settings_t& pSettings)
+{
+ try
+ {
+ m_pMW->SetPluginSettings(pName, pUID, pSettings);
+ }
+ catch(CABRTException &e)
+ {
+ if (e.type() == EXCEP_FATAL)
+ {
+ throw e;
+ }
+ Warning(e.what());
+ }
+}
+
+} /* unnamed namespace */
+
-uint8_t sig_caught;
+/* Daemon's main() */
static void handle_fatal_signal(int signal)
{