summaryrefslogtreecommitdiffstats
path: root/src/Daemon/Daemon.cpp
diff options
context:
space:
mode:
authorNikola Pajkovsky <npajkovs@redhat.com>2010-08-10 10:21:25 +0200
committerNikola Pajkovsky <npajkovs@redhat.com>2010-08-10 10:21:56 +0200
commit83a6ce9ad4b1828e163dc7172ef603201b748473 (patch)
tree9d0580eba6c01cb5964655df42bafab9de91329b /src/Daemon/Daemon.cpp
parente84ab7783d05eb7b5f1b55ab44e7c23c85e50516 (diff)
downloadabrt-83a6ce9ad4b1828e163dc7172ef603201b748473.tar.gz
abrt-83a6ce9ad4b1828e163dc7172ef603201b748473.tar.xz
abrt-83a6ce9ad4b1828e163dc7172ef603201b748473.zip
lower case direcotry(no code changed)
Signed-off-by: Nikola Pajkovsky <npajkovs@redhat.com>
Diffstat (limited to 'src/Daemon/Daemon.cpp')
-rw-r--r--src/Daemon/Daemon.cpp1000
1 files changed, 0 insertions, 1000 deletions
diff --git a/src/Daemon/Daemon.cpp b/src/Daemon/Daemon.cpp
deleted file mode 100644
index 735da5af..00000000
--- a/src/Daemon/Daemon.cpp
+++ /dev/null
@@ -1,1000 +0,0 @@
-/*
- Copyright (C) 2009 Jiri Moskovcak (jmoskovc@redhat.com)
- Copyright (C) 2009 RedHat inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-#include <syslog.h>
-#include <pthread.h>
-#include <resolv.h> /* res_init */
-#include <string>
-#include <sys/inotify.h>
-#include <sys/ioctl.h> /* ioctl(FIONREAD) */
-#include <xmlrpc-c/base.h>
-#include <xmlrpc-c/client.h>
-#include <glib.h>
-#if HAVE_CONFIG_H
- #include <config.h>
-#endif
-#if HAVE_LOCALE_H
- #include <locale.h>
-#endif
-#if ENABLE_NLS
- #include <libintl.h>
- #define _(S) gettext(S)
-#else
- #define _(S) (S)
-#endif
-#include "abrtlib.h"
-#include "abrt_exception.h"
-#include "CrashWatcher.h"
-#include "debug_dump.h"
-#include "Daemon.h"
-#include "dumpsocket.h"
-#include "rpm.h"
-
-using namespace std;
-
-
-/* Daemon initializes, then sits in glib main loop, waiting for events.
- * Events can be:
- * - inotify: something new appeared under /var/spool/abrt
- * - DBus: dbus message arrived
- * - signal: we got SIGTERM or SIGINT
- *
- * DBus methods we have:
- * - GetCrashInfos(): returns a vector_map_crash_data_t (vector_map_vector_string_t)
- * of crashes for given uid
- * v[N]["executable"/"uid"/"kernel"/"backtrace"][N] = "contents"
- * - StartJob(crash_id,force): starts creating a report for /var/spool/abrt/DIR with this UID:UUID.
- * Returns job id (uint64).
- * After thread returns, when report creation thread has finished,
- * JobDone() dbus signal is emitted.
- * - CreateReport(crash_id): returns map_crash_data_t (map_vector_string_t)
- * - Report(map_crash_data_t (map_vector_string_t[, map_map_string_t])):
- * "Please report this crash": calls Report() of all registered reporter plugins.
- * Returns report_status_t (map_vector_string_t) - the status of each call.
- * 2nd parameter is the contents of user's abrt.conf.
- * - DeleteDebugDump(crash_id): delete it from DB and delete corresponding /var/spool/abrt/DIR
- * - GetPluginsInfo(): returns map_map_string_t
- * map["plugin"] = { "Name": "plugin", "Enabled": "yes" ... }
- * - GetPluginSettings(PluginName): returns map_plugin_settings_t (map_string_t)
- * - SetPluginSettings(PluginName, map_plugin_settings_t): returns void
- * - RegisterPlugin(PluginName): returns void
- * - UnRegisterPlugin(PluginName): returns void
- * - GetSettings(): returns map_abrt_settings_t (map_map_string_t)
- * - SetSettings(map_abrt_settings_t): returns void
- *
- * DBus signals we emit:
- * - Crash(progname, crash_id, uid) - a new crash occurred (new /var/spool/abrt/DIR is found)
- * - JobDone(client_dbus_ID) - see StartJob above.
- * Sent as unicast to the client which did StartJob.
- * - Warning(msg)
- * - Update(msg)
- * Both are sent as unicast to last client set by set_client_name(name).
- * If set_client_name(NULL) was done, they are not sent.
- */
-
-
-#define VAR_RUN_LOCK_FILE VAR_RUN"/abrt/abrtd.lock"
-#define VAR_RUN_PIDFILE VAR_RUN"/abrtd.pid"
-
-
-//FIXME: add some struct to be able to join all threads!
-typedef struct cron_callback_data_t
-{
- std::string m_sPluginName;
- std::string m_sPluginArgs;
- unsigned int m_nTimeout;
-
- cron_callback_data_t(
- const std::string& pPluginName,
- const std::string& pPluginArgs,
- const unsigned int& pTimeout) :
- m_sPluginName(pPluginName),
- m_sPluginArgs(pPluginArgs),
- m_nTimeout(pTimeout)
- {}
-} cron_callback_data_t;
-
-
-static volatile sig_atomic_t s_sig_caught;
-static int s_signal_pipe[2];
-static int s_signal_pipe_write = -1;
-static int s_upload_watch = -1;
-static unsigned s_timeout;
-static bool s_exiting;
-
-CCommLayerServer* g_pCommLayer;
-
-
-static void cron_delete_callback_data_cb(gpointer data)
-{
- cron_callback_data_t* cronDeleteCallbackData = static_cast<cron_callback_data_t*>(data);
- delete cronDeleteCallbackData;
-}
-
-static gboolean cron_activation_periodic_cb(gpointer data)
-{
- cron_callback_data_t* cronPeriodicCallbackData = static_cast<cron_callback_data_t*>(data);
- VERB1 log("Activating plugin: %s", cronPeriodicCallbackData->m_sPluginName.c_str());
- RunAction(DEBUG_DUMPS_DIR,
- cronPeriodicCallbackData->m_sPluginName.c_str(),
- cronPeriodicCallbackData->m_sPluginArgs.c_str()
- );
- return TRUE;
-}
-static gboolean cron_activation_one_cb(gpointer data)
-{
- cron_callback_data_t* cronOneCallbackData = static_cast<cron_callback_data_t*>(data);
- VERB1 log("Activating plugin: %s", cronOneCallbackData->m_sPluginName.c_str());
- RunAction(DEBUG_DUMPS_DIR,
- cronOneCallbackData->m_sPluginName.c_str(),
- cronOneCallbackData->m_sPluginArgs.c_str()
- );
- return FALSE;
-}
-static gboolean cron_activation_reshedule_cb(gpointer data)
-{
- cron_callback_data_t* cronResheduleCallbackData = static_cast<cron_callback_data_t*>(data);
- VERB1 log("Rescheduling plugin: %s", cronResheduleCallbackData->m_sPluginName.c_str());
- cron_callback_data_t* cronPeriodicCallbackData = new cron_callback_data_t(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;
-}
-
-static int SetUpMW()
-{
- set_string_t::iterator it_k = g_settings_setOpenGPGPublicKeys.begin();
- for (; it_k != g_settings_setOpenGPGPublicKeys.end(); it_k++)
- {
- LoadOpenGPGPublicKey(it_k->c_str());
- }
- VERB1 log("Adding actions or reporters");
- vector_pair_string_string_t::iterator it_ar = g_settings_vectorActionsAndReporters.begin();
- for (; it_ar != g_settings_vectorActionsAndReporters.end(); it_ar++)
- {
- AddActionOrReporter(it_ar->first.c_str(), it_ar->second.c_str());
- }
- VERB1 log("Adding analyzers, actions or reporters");
- map_analyzer_actions_and_reporters_t::iterator it_aar = g_settings_mapAnalyzerActionsAndReporters.begin();
- for (; it_aar != g_settings_mapAnalyzerActionsAndReporters.end(); it_aar++)
- {
- vector_pair_string_string_t::iterator it_ar = it_aar->second.begin();
- for (; it_ar != it_aar->second.end(); it_ar++)
- {
- AddAnalyzerActionOrReporter(it_aar->first.c_str(), it_ar->first.c_str(), it_ar->second.c_str());
- }
- }
- return 0;
-}
-
-static int SetUpCron()
-{
- map_cron_t::iterator it_c = g_settings_mapCron.begin();
- for (; it_c != g_settings_mapCron.end(); it_c++)
- {
- std::string::size_type pos = it_c->first.find(":");
- int timeout = 0;
- int nH = -1;
- int nM = -1;
- int nS = -1;
-
-//TODO: rewrite using good old sscanf?
-
- if (pos != std::string::npos)
- {
- std::string sH;
- std::string sM;
-
- sH = it_c->first.substr(0, pos);
- nH = xatou(sH.c_str());
- nH = nH > 23 ? 23 : nH;
- nH = nH < 0 ? 0 : nH;
- timeout += nH * 60 * 60;
- sM = it_c->first.substr(pos + 1);
- nM = xatou(sM.c_str());
- nM = nM > 59 ? 59 : nM;
- nM = nM < 0 ? 0 : nM;
- timeout += nM * 60;
- }
- else
- {
- std::string sS;
-
- sS = it_c->first;
- nS = xatou(sS.c_str());
- nS = nS <= 0 ? 1 : nS;
- timeout = nS;
- }
-
- if (nS != -1)
- {
- vector_pair_string_string_t::iterator it_ar = it_c->second.begin();
- for (; it_ar != it_c->second.end(); it_ar++)
- {
- cron_callback_data_t* cronPeriodicCallbackData = new cron_callback_data_t(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);
- struct tm locTime;
- localtime_r(&actTime, &locTime);
- locTime.tm_hour = nH;
- locTime.tm_min = nM;
- locTime.tm_sec = 0;
- time_t nextTime = mktime(&locTime);
- if (nextTime == ((time_t)-1))
- {
- /* paranoia */
- perror_msg("Can't set up cron time");
- return -1;
- }
- if (actTime > nextTime)
- {
- timeout = 24*60*60 + (nextTime - actTime);
- }
- else
- {
- timeout = nextTime - actTime;
- }
- vector_pair_string_string_t::iterator it_ar = it_c->second.begin();
- for (; it_ar != it_c->second.end(); it_ar++)
- {
- cron_callback_data_t* cronOneCallbackData = new cron_callback_data_t(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(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);
- }
- }
- }
- return 0;
-}
-
-static void FindNewDumps(const char* pPath)
-{
- /* Get all debugdump directories in the pPath directory */
- vector_string_t dirs;
- DIR *dp = opendir(pPath);
- if (dp == NULL)
- {
- perror_msg("Can't open directory '%s'", pPath);
- return;
- }
- struct dirent *ep;
- while ((ep = readdir(dp)))
- {
- if (dot_or_dotdot(ep->d_name))
- continue; /* skip "." and ".." */
- std::string dname = concat_path_file(pPath, ep->d_name);
- struct stat stats;
- if (lstat(dname.c_str(), &stats) == 0)
- {
- if (S_ISDIR(stats.st_mode))
- {
- VERB1 log("Will check directory '%s'", ep->d_name);
- dirs.push_back(dname);
- }
- }
- }
- closedir(dp);
-
- unsigned size = dirs.size();
- if (size == 0)
- return;
- log("Checking for unsaved crashes (dirs to check:%u)", size);
-
- /* Get potentially non-processed debugdumps */
- vector_string_t::iterator itt = dirs.begin();
- for (; itt != dirs.end(); ++itt)
- {
- try
- {
- const char *dir_name = itt->c_str();
- map_crash_data_t crashinfo;
- mw_result_t res = SaveDebugDump(dir_name, crashinfo);
- switch (res)
- {
- case MW_OK:
- /* Not VERB1: this is new, unprocessed crash dump.
- * Last abrtd somehow missed it - need to inform user */
- log("Non-processed crash in %s, saving into database", dir_name);
- /* Run automatic actions and reporters on it (if we have them configured) */
- RunActionsAndReporters(dir_name);
- break;
- case MW_IN_DB:
- /* This debugdump was found in DB, nothing else was done
- * by SaveDebugDump or needs to be done by us */
- VERB1 log("%s is already saved in database", dir_name);
- break;
- case MW_REPORTED: /* already reported dup */
- case MW_OCCURRED: /* not-yet-reported dup */
- VERB1 log("Duplicate crash %s, deleting", dir_name);
- delete_debug_dump_dir(dir_name);
- break;
- default:
- log("Corrupted or bad crash %s (res:%d), deleting", dir_name, (int)res);
- delete_debug_dump_dir(dir_name);
- break;
- }
- }
- catch (CABRTException& e)
- {
- error_msg("%s", e.what());
- }
- }
- log("Done checking for unsaved crashes");
-}
-
-static int 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(long)*3 + 2];
- int len = sprintf(buf, "%lu\n", (long)getpid());
- write(fd, buf, len);
- close(fd);
- return 0;
- }
-
- /* something went wrong */
- perror_msg("Can't open '%s'", VAR_RUN_PIDFILE);
- return -1;
-}
-
-static int Lock()
-{
- int lfd = open(VAR_RUN_LOCK_FILE, O_RDWR|O_CREAT, 0640);
- if (lfd < 0)
- {
- perror_msg("Can't open '%s'", VAR_RUN_LOCK_FILE);
- return -1;
- }
- if (lockf(lfd, F_TLOCK, 0) < 0)
- {
- perror_msg("Can't lock file '%s'", VAR_RUN_LOCK_FILE);
- return -1;
- }
- close_on_exec_on(lfd);
- return 0;
- /* we leak opened lfd intentionally */
-}
-
-static void handle_fatal_signal(int signo)
-{
- // Enable for debugging only, malloc/printf are unsafe in signal handlers
- //VERB3 log("Got signal %d", signo);
-
- uint8_t l_sig_caught;
- s_sig_caught = l_sig_caught = signo;
- /* Using local copy of s_sig_caught so that concurrent signal
- * won't change it under us */
- if (s_signal_pipe_write >= 0)
- write(s_signal_pipe_write, &l_sig_caught, 1);
-}
-
-/* Signal pipe handler */
-static gboolean handle_signal_cb(GIOChannel *gio, GIOCondition condition, gpointer ptr_unused)
-{
- char signo;
- gsize len = 0;
- g_io_channel_read(gio, &signo, 1, &len);
- if (len == 1)
- {
- /* we did receive a signal */
- VERB3 log("Got signal %d through signal pipe", signo);
- s_exiting = 1;
- return TRUE;
- }
- return FALSE;
-}
-
-/* Inotify handler */
-static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpointer ptr_unused)
-{
- /* Default size: 128 simultaneous actions (about 1/2 meg) */
-#define INOTIFY_BUF_SIZE ((sizeof(struct inotify_event) + FILENAME_MAX)*128)
- /* Determine how much to read (it usually is much smaller) */
- /* NB: this variable _must_ be int-sized, ioctl expects that! */
- int inotify_bytes = INOTIFY_BUF_SIZE;
- if (ioctl(g_io_channel_unix_get_fd(gio), FIONREAD, &inotify_bytes) != 0
- || inotify_bytes < sizeof(struct inotify_event)
- || inotify_bytes > INOTIFY_BUF_SIZE
- ) {
- inotify_bytes = INOTIFY_BUF_SIZE;
- }
- VERB3 log("FIONREAD:%d", inotify_bytes);
-
- char *buf = (char*)xmalloc(inotify_bytes);
- errno = 0;
- gsize len;
- GIOError err = g_io_channel_read(gio, buf, inotify_bytes, &len);
- if (err != G_IO_ERROR_NONE)
- {
- perror_msg("Error reading inotify fd");
- free(buf);
- return FALSE;
- }
-
- /* Reconstruct each event and send message to the dbus */
- gsize i = 0;
- while (i < len)
- {
- struct inotify_event *event = (struct inotify_event *) &buf[i];
- const char *name = NULL;
- if (event->len)
- name = event->name;
- //log("i:%d len:%d event->mask:%x IN_ISDIR:%x IN_CLOSE_WRITE:%x event->len:%d",
- // i, len, event->mask, IN_ISDIR, IN_CLOSE_WRITE, event->len);
- i += sizeof(*event) + event->len;
-
- if (event->wd == s_upload_watch)
- {
- /* Was the (presumable newly created) file closed in upload dir,
- * or a file moved to upload dir? */
- if (!(event->mask & IN_ISDIR)
- && event->mask & (IN_CLOSE_WRITE|IN_MOVED_TO)
- && name
- ) {
- const char *ext = strrchr(name, '.');
- if (ext && strcmp(ext + 1, "working") == 0)
- continue;
-
- const char *dir = g_settings_sWatchCrashdumpArchiveDir.c_str();
- log("Detected creation of file '%s' in upload directory '%s'", name, dir);
- if (fork() == 0)
- {
- xchdir(dir);
- execlp("abrt-handle-upload", "abrt-handle-upload", DEBUG_DUMPS_DIR, dir, name, (char*)NULL);
- error_msg_and_die("Can't execute '%s'", "abrt-handle-upload");
- }
- }
- continue;
- }
-
- if (!(event->mask & IN_ISDIR) || !name)
- {
- /* ignore lock files and such */
- // Happens all the time during normal run
- //VERB3 log("File '%s' creation detected, ignoring", name);
- continue;
- }
- if (strcmp(strchrnul(name, '.'), ".new") == 0)
- {
- //VERB3 log("Directory '%s' creation detected, ignoring", name);
- continue;
- }
- log("Directory '%s' creation detected", name);
-
- if (g_settings_nMaxCrashReportsSize > 0)
- {
- std::string worst_dir;
- while (g_settings_nMaxCrashReportsSize > 0
- && get_dirsize_find_largest_dir(DEBUG_DUMPS_DIR, &worst_dir, name) / (1024*1024) >= g_settings_nMaxCrashReportsSize
- && worst_dir != ""
- ) {
- log("Size of '%s' >= %u MB, deleting '%s'", DEBUG_DUMPS_DIR, g_settings_nMaxCrashReportsSize, worst_dir.c_str());
- g_pCommLayer->QuotaExceed(_("The size of the report exceeded the quota. Please check system's MaxCrashReportsSize value in abrt.conf."));
- /* deletes both directory and DB record */
- DeleteDebugDump_by_dir(concat_path_file(DEBUG_DUMPS_DIR, worst_dir.c_str()).c_str());
- worst_dir = "";
- }
- }
-
- try
- {
- std::string fullname = concat_path_file(DEBUG_DUMPS_DIR, name);
- /* Note: SaveDebugDump does not save crashinfo, it _fetches_ crashinfo */
- map_crash_data_t crashinfo;
- mw_result_t res = SaveDebugDump(fullname.c_str(), crashinfo);
- switch (res)
- {
- case MW_OK:
- log("New crash %s, processing", fullname.c_str());
- /* Run automatic actions and reporters on it (if we have them configured) */
- RunActionsAndReporters(fullname.c_str());
- /* Fall through */
-
- case MW_REPORTED: /* already reported dup */
- case MW_OCCURRED: /* not-yet-reported dup */
- {
- if (res != MW_OK)
- {
- const char *first = get_crash_data_item_content(crashinfo, CD_DUMPDIR).c_str();
- log("Deleting crash %s (dup of %s), sending dbus signal",
- strrchr(fullname.c_str(), '/') + 1,
- strrchr(first, '/') + 1);
- delete_debug_dump_dir(fullname.c_str());
- }
-#define fullname fullname_should_not_be_used_here
-
- const char *analyzer = get_crash_data_item_content(crashinfo, FILENAME_ANALYZER).c_str();
- const char *uid_str = get_crash_data_item_content(crashinfo, CD_UID).c_str();
-
- /* Autoreport it if configured to do so */
- if (res != MW_REPORTED
- && analyzer_has_AutoReportUIDs(analyzer, uid_str)
- ) {
- VERB1 log("Reporting the crash automatically");
- map_crash_data_t crash_report;
- string crash_id = ssprintf("%s:%s", uid_str, get_crash_data_item_content(crashinfo, CD_UUID).c_str());
- mw_result_t crash_result = CreateCrashReport(
- crash_id.c_str(),
- /*caller_uid:*/ 0,
- /*force:*/ 0,
- crash_report
- );
- if (crash_result == MW_OK)
- {
- map_analyzer_actions_and_reporters_t::const_iterator it = g_settings_mapAnalyzerActionsAndReporters.find(analyzer);
- map_analyzer_actions_and_reporters_t::const_iterator end = g_settings_mapAnalyzerActionsAndReporters.end();
- if (it != end)
- {
- vector_pair_string_string_t keys = it->second;
- unsigned size = keys.size();
- for (unsigned ii = 0; ii < size; ii++)
- {
- autoreport(keys[ii], crash_report);
- }
- }
- }
- }
- /* Send dbus signal */
- if (analyzer_has_InformAllUsers(analyzer))
- uid_str = NULL;
- char *crash_id = xasprintf("%s:%s",
- get_crash_data_item_content(crashinfo, CD_UID).c_str(),
- get_crash_data_item_content(crashinfo, CD_UUID).c_str()
- );
- g_pCommLayer->Crash(get_crash_data_item_content(crashinfo, FILENAME_PACKAGE).c_str(),
- crash_id,
- uid_str);
- free(crash_id);
- break;
-#undef fullname
- }
- case MW_IN_DB:
- log("Huh, this crash is already in db?! Nothing to do");
- break;
- case MW_BLACKLISTED:
- case MW_CORRUPTED:
- case MW_PACKAGE_ERROR:
- case MW_GPG_ERROR:
- case MW_FILE_ERROR:
- default:
- log("Corrupted or bad crash %s (res:%d), deleting", fullname.c_str(), (int)res);
- delete_debug_dump_dir(fullname.c_str());
- break;
- }
- }
- catch (CABRTException& e)
- {
- error_msg("%s", e.what());
- }
- catch (...)
- {
- free(buf);
- throw;
- }
- } /* while */
-
- free(buf);
- return TRUE;
-}
-
-/* Run main loop with idle timeout.
- * Basically, almost like glib's g_main_run(loop)
- */
-static void run_main_loop(GMainLoop* loop)
-{
- GMainContext *context = g_main_loop_get_context(loop);
- time_t old_time = 0;
- time_t dns_conf_hash = 0;
-
- while (!s_exiting)
- {
- /* we have just a handful of sources, 32 should be ample */
- const unsigned NUM_POLLFDS = 32;
- GPollFD fds[NUM_POLLFDS];
- gboolean some_ready;
- gint max_priority;
- gint timeout;
-
- some_ready = g_main_context_prepare(context, &max_priority);
- if (some_ready)
- g_main_context_dispatch(context);
-
- gint nfds = g_main_context_query(context, max_priority, &timeout, fds, NUM_POLLFDS);
- if (nfds > NUM_POLLFDS)
- error_msg_and_die("Internal error");
-
- if (s_timeout)
- alarm(s_timeout);
- g_poll(fds, nfds, timeout);
- if (s_timeout)
- alarm(0);
-
- /* res_init() makes glibc reread /etc/resolv.conf.
- * I'd think libc should be clever enough to do it itself
- * at every name resolution attempt, but no...
- * We need to guess ourself whether we want to do it.
- */
- time_t now = time(NULL) >> 2;
- if (old_time != now) /* check once in 4 seconds */
- {
- old_time = now;
-
- time_t hash = 0;
- struct stat sb;
- if (stat("/etc/resolv.conf", &sb) == 0)
- hash = sb.st_mtime;
- if (stat("/etc/host.conf", &sb) == 0)
- hash += sb.st_mtime;
- if (stat("/etc/hosts", &sb) == 0)
- hash += sb.st_mtime;
- if (stat("/etc/nsswitch.conf", &sb) == 0)
- hash += sb.st_mtime;
- if (dns_conf_hash != hash)
- {
- dns_conf_hash = hash;
- res_init();
- }
- }
-
- some_ready = g_main_context_check(context, max_priority, fds, nfds);
- if (some_ready)
- g_main_context_dispatch(context);
- }
-
- g_main_context_unref(context);
-}
-
-static void start_syslog_logging()
-{
- /* Open stdin to /dev/null */
- xmove_fd(xopen("/dev/null", O_RDWR), STDIN_FILENO);
- /* We must not leave fds 0,1,2 closed.
- * Otherwise fprintf(stderr) dumps messages into random fds, etc. */
- xdup2(STDIN_FILENO, STDOUT_FILENO);
- xdup2(STDIN_FILENO, STDERR_FILENO);
- openlog("abrtd", 0, LOG_DAEMON);
- logmode = LOGMODE_SYSLOG;
-}
-
-static void ensure_writable_dir(const char *dir, mode_t mode, const char *user)
-{
- struct stat sb;
-
- if (mkdir(dir, mode) != 0 && errno != EEXIST)
- perror_msg_and_die("Can't create '%s'", dir);
- if (stat(dir, &sb) != 0 || !S_ISDIR(sb.st_mode))
- error_msg_and_die("'%s' is not a directory", dir);
-
- struct passwd *pw = getpwnam(user);
- if (!pw)
- perror_msg_and_die("Can't find user '%s'", user);
-
- if ((sb.st_uid != pw->pw_uid || sb.st_gid != pw->pw_gid) && chown(dir, pw->pw_uid, pw->pw_gid) != 0)
- perror_msg_and_die("Can't set owner %u:%u on '%s'", (unsigned int)pw->pw_uid, (unsigned int)pw->pw_gid, dir);
- if ((sb.st_mode & 07777) != mode && chmod(dir, mode) != 0)
- perror_msg_and_die("Can't set mode %o on '%s'", mode, dir);
-}
-
-static void sanitize_dump_dir_rights()
-{
- /* We can't allow everyone to create dumps: otherwise users can flood
- * us with thousands of bogus or malicious dumps */
- /* 07000 bits are setuid, setgit, and sticky, and they must be unset */
- /* 00777 bits are usual "rwxrwxrwx" access rights */
- ensure_writable_dir(DEBUG_DUMPS_DIR, 0755, "abrt");
- /* debuginfo cache */
- ensure_writable_dir(DEBUG_INFO_DIR, 0755, "root");
- /* temp dir */
- ensure_writable_dir(VAR_RUN"/abrt", 0755, "root");
-}
-
-int main(int argc, char** argv)
-{
- bool daemonize = true;
- int opt;
- int parent_pid = getpid();
-
- setlocale(LC_ALL, "");
-
-#if ENABLE_NLS
- bindtextdomain(PACKAGE, LOCALEDIR);
- textdomain(PACKAGE);
-#endif
-
- if (getuid() != 0)
- error_msg_and_die("ABRT daemon must be run as root");
-
- while ((opt = getopt(argc, argv, "dsvt:")) != -1)
- {
- unsigned long ul;
-
- switch (opt)
- {
- case 'd':
- daemonize = false;
- break;
- case 's':
- start_syslog_logging();
- break;
- case 'v':
- g_verbose++;
- break;
- case 't':
- char *end;
- errno = 0;
- s_timeout = ul = strtoul(optarg, &end, 0);
- if (errno == 0 && *end == '\0' && ul <= INT_MAX)
- break;
- /* fall through to error */
- default:
- error_msg_and_die(
- "Usage: abrtd [-dsv] [-t SEC]\n"
- "\nOptions:"
- "\n\t-d\tDo not daemonize"
- "\n\t-s\tLog to syslog even with -d"
- "\n\t-t SEC\tExit after SEC seconds of inactivity"
- "\n\t-v\tVerbose"
- );
- }
- }
-
- msg_prefix = "abrtd: "; /* for log(), error_msg() and such */
-
- xpipe(s_signal_pipe);
- close_on_exec_on(s_signal_pipe[0]);
- close_on_exec_on(s_signal_pipe[1]);
- signal(SIGTERM, handle_fatal_signal);
- signal(SIGINT, handle_fatal_signal);
- if (s_timeout)
- signal(SIGALRM, handle_fatal_signal);
-
- /* Daemonize unless -d */
- if (daemonize)
- {
- /* forking to background */
- pid_t pid = fork();
- if (pid < 0)
- {
- perror_msg_and_die("fork");
- }
- if (pid > 0)
- {
- /* Parent */
- /* Wait for child to notify us via SIGTERM that it feels ok */
- int i = 20; /* 2 sec */
- while (s_sig_caught == 0 && --i)
- {
- usleep(100 * 1000);
- }
- if (s_sig_caught == SIGTERM)
- {
- exit(0);
- }
- if (s_sig_caught)
- {
- error_msg_and_die("Failed to start: got sig %d", s_sig_caught);
- }
- error_msg_and_die("Failed to start: timeout waiting for child");
- }
- /* Child (daemon) continues */
- setsid(); /* never fails */
- if (g_verbose == 0 && logmode != LOGMODE_SYSLOG)
- start_syslog_logging();
- }
-
- GMainLoop* pMainloop = NULL;
- GIOChannel* channel_inotify = NULL;
- guint channel_inotify_event_id = 0;
- GIOChannel* channel_signal = NULL;
- guint channel_signal_event_id = 0;
- bool lockfile_created = false;
- bool pidfile_created = false;
- CCrashWatcher watcher;
-
- /* Initialization */
- try
- {
- init_daemon_logging(&watcher);
-
- VERB1 log("Loading settings");
- if (LoadSettings() != 0)
- throw 1;
-
- VERB1 log("Initializing XML-RPC library");
- xmlrpc_env env;
- xmlrpc_env_init(&env);
- xmlrpc_client_setup_global_const(&env);
- if (env.fault_occurred)
- error_msg_and_die("XML-RPC Fault: %s(%d)", env.fault_string, env.fault_code);
-
- VERB1 log("Initializing rpm library");
- rpm_init();
-
- VERB1 log("Creating glib main loop");
- pMainloop = g_main_loop_new(NULL, FALSE);
- /* Watching DEBUG_DUMPS_DIR for new files... */
-
- VERB1 log("Initializing inotify");
- sanitize_dump_dir_rights();
- errno = 0;
- int inotify_fd = inotify_init();
- if (inotify_fd == -1)
- perror_msg_and_die("inotify_init failed");
- close_on_exec_on(inotify_fd);
- if (inotify_add_watch(inotify_fd, DEBUG_DUMPS_DIR, IN_CREATE | IN_MOVED_TO) < 0)
- perror_msg_and_die("inotify_add_watch failed on '%s'", DEBUG_DUMPS_DIR);
- if (!g_settings_sWatchCrashdumpArchiveDir.empty())
- {
- s_upload_watch = inotify_add_watch(inotify_fd, g_settings_sWatchCrashdumpArchiveDir.c_str(), IN_CLOSE_WRITE|IN_MOVED_TO);
- if (s_upload_watch < 0)
- perror_msg_and_die("inotify_add_watch failed on '%s'", g_settings_sWatchCrashdumpArchiveDir.c_str());
- }
- VERB1 log("Adding inotify watch to glib main loop");
- channel_inotify = g_io_channel_unix_new(inotify_fd);
- channel_inotify_event_id = g_io_add_watch(channel_inotify,
- G_IO_IN,
- handle_inotify_cb,
- NULL);
-
- VERB1 log("Loading plugins from "PLUGINS_LIB_DIR);
- g_pPluginManager = new CPluginManager();
- g_pPluginManager->LoadPlugins();
-
- if (SetUpMW() != 0) /* logging is inside */
- throw 1;
- if (SetUpCron() != 0)
- throw 1;
-
- /* Add an event source which waits for INT/TERM signal */
- VERB1 log("Adding signal pipe watch to glib main loop");
- channel_signal = g_io_channel_unix_new(s_signal_pipe[0]);
- channel_signal_event_id = g_io_add_watch(channel_signal,
- G_IO_IN,
- handle_signal_cb,
- NULL);
-
- /* Mark the territory */
- VERB1 log("Creating lock file");
- if (Lock() != 0)
- throw 1;
- lockfile_created = true;
- VERB1 log("Creating pid file");
- if (CreatePidFile() != 0)
- throw 1;
- pidfile_created = true;
-
- /* Open socket to receive new crashes. */
- dumpsocket_init();
-
- /* Note: this already may process a few dbus messages,
- * therefore it should be the last thing to initialize.
- */
- VERB1 log("Initializing dbus");
- g_pCommLayer = new CCommLayerServerDBus();
- if (g_pCommLayer->m_init_error)
- throw 1;
- }
- catch (...)
- {
- /* Initialization error */
- error_msg("Error while initializing daemon");
- /* Inform parent that initialization failed */
- if (daemonize)
- kill(parent_pid, SIGINT);
- goto cleanup;
- }
-
- /* Inform parent that we initialized ok */
- if (daemonize)
- {
- VERB1 log("Signalling parent");
- kill(parent_pid, SIGTERM);
- if (logmode != LOGMODE_SYSLOG)
- start_syslog_logging();
- }
-
- /* Only now we want signal pipe to work */
- s_signal_pipe_write = s_signal_pipe[1];
-
- /* Enter the event loop */
- try
- {
- /* This may take a while, therefore we don't do it in init section */
- FindNewDumps(DEBUG_DUMPS_DIR);
- log("Init complete, entering main loop");
- run_main_loop(pMainloop);
- }
- catch (CABRTException& e)
- {
- error_msg("Error: %s", e.what());
- }
- catch (std::exception& e)
- {
- error_msg("Error: %s", e.what());
- }
-
- cleanup:
- /* Error or INT/TERM. Clean up, in reverse order.
- * Take care to not undo things we did not do.
- */
- dumpsocket_shutdown();
- rpm_destroy();
- if (pidfile_created)
- unlink(VAR_RUN_PIDFILE);
- if (lockfile_created)
- unlink(VAR_RUN_LOCK_FILE);
-
- if (channel_signal_event_id > 0)
- g_source_remove(channel_signal_event_id);
- if (channel_signal)
- g_io_channel_unref(channel_signal);
- if (channel_inotify_event_id > 0)
- g_source_remove(channel_inotify_event_id);
- if (channel_inotify)
- g_io_channel_unref(channel_inotify);
-
- delete g_pCommLayer;
- if (g_pPluginManager)
- {
- /* This restores /proc/sys/kernel/core_pattern, among other things: */
- g_pPluginManager->UnLoadPlugins();
- delete g_pPluginManager;
- }
- if (pMainloop)
- g_main_loop_unref(pMainloop);
-
- /* Exiting */
- if (s_sig_caught && s_sig_caught != SIGALRM)
- {
- error_msg_and_die("Got signal %d, exiting", s_sig_caught);
- signal(s_sig_caught, SIG_DFL);
- raise(s_sig_caught);
- }
- error_msg_and_die("Exiting");
-}