From 1ab41dec5fcc9d9411a7d318523f647ded40b37e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 20 Apr 2011 14:01:32 +0200 Subject: rename Daemon.cpp to abrtd.c This loses libstdc++, libm and libgcc_s libraries from abrtd Signed-off-by: Denys Vlasenko --- src/daemon/Daemon.cpp | 709 -------------------------------------------------- 1 file changed, 709 deletions(-) delete mode 100644 src/daemon/Daemon.cpp (limited to 'src/daemon/Daemon.cpp') diff --git a/src/daemon/Daemon.cpp b/src/daemon/Daemon.cpp deleted file mode 100644 index 6b894f01..00000000 --- a/src/daemon/Daemon.cpp +++ /dev/null @@ -1,709 +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. -*/ -#if HAVE_LOCALE_H -# include -#endif -#include -#include -#include -#include /* ioctl(FIONREAD) */ -#include "abrtlib.h" -#include "comm_layer_inner.h" -#include "Settings.h" -#include "CommLayerServerDBus.h" -#include "MiddleWare.h" -#include "parse_options.h" - -#define PROGNAME "abrtd" - -#define VAR_RUN_PIDFILE VAR_RUN"/abrtd.pid" - -#define SOCKET_FILE VAR_RUN"/abrt/abrt.socket" -#define SOCKET_PERMISSION 0666 -/* Maximum number of simultaneously opened client connections. */ -#define MAX_CLIENT_COUNT 10 - - -/* 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: - * - DeleteDebugDump(crash_id): delete it from DB and delete corresponding /var/spool/abrt/DIR - * - * DBus signals we emit: - * - Crash(progname, crash_id, dir, uid) - a new crash occurred (new /var/spool/abrt/DIR is found) - * - 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. - */ -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; - -static GIOChannel *socket_channel = NULL; -static guint socket_channel_cb_id = 0; -static int socket_client_count = 0; - - -/* Helpers */ - -static guint add_watch_or_die(GIOChannel *channel, unsigned condition, GIOFunc func) -{ - errno = 0; - guint r = g_io_add_watch(channel, (GIOCondition)condition, func, NULL); - if (!r) - perror_msg_and_die("g_io_add_watch failed"); - return r; -} - - -/* Socket handling */ - -/* Callback called by glib main loop when a client connects to ABRT's socket. */ -static gboolean server_socket_cb(GIOChannel *source, GIOCondition condition, gpointer ptr_unused) -{ - /* Check the limit for number of simultaneously attached clients. */ - if (socket_client_count >= MAX_CLIENT_COUNT) - { - error_msg("Too many clients, refusing connections to '%s'", SOCKET_FILE); - /* To avoid infinite loop caused by the descriptor in "ready" state, - * the callback must be disabled. - * It is added back in client_free(). */ - g_source_remove(socket_channel_cb_id); - socket_channel_cb_id = 0; - return TRUE; - } - - int socket = accept(g_io_channel_unix_get_fd(source), NULL, NULL); - if (socket == -1) - { - perror_msg("accept"); - return TRUE; - } - - log("New client connected"); - pid_t pid = fork(); - if (pid < 0) - { - perror_msg("fork"); - close(socket); - return TRUE; - } - if (pid == 0) /* child */ - { - xmove_fd(socket, 0); - xdup2(0, 1); - - char *argv[3]; /* abrt-server [-s] NULL */ - char **pp = argv; - *pp++ = (char*)"abrt-server"; - if (logmode & LOGMODE_SYSLOG) - *pp++ = (char*)"-s"; - *pp = NULL; - - execvp(argv[0], argv); - perror_msg_and_die("Can't execute '%s'", argv[0]); - } - /* parent */ - socket_client_count++; - close(socket); - return TRUE; -} - -/* Initializes the dump socket, usually in /var/run directory - * (the path depends on compile-time configuration). - */ -static void dumpsocket_init() -{ - unlink(SOCKET_FILE); /* not caring about the result */ - - int socketfd = xsocket(AF_UNIX, SOCK_STREAM, 0); - close_on_exec_on(socketfd); - - struct sockaddr_un local; - memset(&local, 0, sizeof(local)); - local.sun_family = AF_UNIX; - strcpy(local.sun_path, SOCKET_FILE); - xbind(socketfd, (struct sockaddr*)&local, sizeof(local)); - xlisten(socketfd, MAX_CLIENT_COUNT); - - if (chmod(SOCKET_FILE, SOCKET_PERMISSION) != 0) - perror_msg_and_die("chmod '%s'", SOCKET_FILE); - - socket_channel = g_io_channel_unix_new(socketfd); - g_io_channel_set_close_on_unref(socket_channel, TRUE); - socket_channel_cb_id = add_watch_or_die(socket_channel, G_IO_IN | G_IO_PRI, server_socket_cb); -} - -/* Releases all resources used by dumpsocket. */ -static void dumpsocket_shutdown() -{ - /* Set everything to pre-initialization state. */ - if (socket_channel) - { - /* Undo add_watch_or_die */ - g_source_remove(socket_channel_cb_id); - /* Undo g_io_channel_unix_new */ - g_io_channel_unref(socket_channel); - socket_channel = NULL; - } -} - -static int create_pidfile() -{ - /* Note: - * No O_EXCL: we would happily overwrite stale pidfile from previous boot. - * No O_TRUNC: we must first try to lock the file, and if lock fails, - * there is another live abrtd. O_TRUNCing the file in this case - * would be wrong - it'll erase the pid to empty string! - */ - int fd = open(VAR_RUN_PIDFILE, O_WRONLY|O_CREAT, 0644); - if (fd >= 0) - { - if (lockf(fd, F_TLOCK, 0) < 0) - { - perror_msg("Can't lock file '%s'", VAR_RUN_PIDFILE); - return -1; - } - close_on_exec_on(fd); - /* write our pid to it */ - char buf[sizeof(long)*3 + 2]; - int len = sprintf(buf, "%lu\n", (long)getpid()); - write(fd, buf, len); - ftruncate(fd, len); - /* we leak opened+locked fd intentionally */ - return 0; - } - - perror_msg("Can't open '%s'", VAR_RUN_PIDFILE); - return -1; -} - -static void handle_signal(int signo) -{ - int save_errno = errno; - - // 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); - - errno = save_errno; -} - -/* 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); - if (signo != SIGCHLD) - s_exiting = 1; - else - { - pid_t pid; - while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) - { - if (socket_client_count) - socket_client_count--; - if (!socket_channel_cb_id) - { - log("Accepting connections on '%s'", SOCKET_FILE); - socket_channel_cb_id = add_watch_or_die(socket_channel, G_IO_IN | G_IO_PRI, server_socket_cb); - } - } - } - 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; - 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) - { - char *worst_dir = NULL; - 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); - send_dbus_sig_QuotaExceeded(_("The size of the report exceeded the quota. Please check system's MaxCrashReportsSize value in abrt.conf.")); - /* deletes both directory and DB record */ - char *d = concat_path_file(DEBUG_DUMPS_DIR, worst_dir); - free(worst_dir); - worst_dir = NULL; - delete_dump_dir(d); - free(d); - } - } - - char *fullname = NULL; - crash_data_t *crash_data = NULL; - fullname = concat_path_file(DEBUG_DUMPS_DIR, name); - mw_result_t res = LoadDebugDump(fullname, &crash_data); - const char *first = crash_data ? get_crash_item_content_or_NULL(crash_data, CD_DUMPDIR) : NULL; - switch (res) - { - case MW_OK: - log("New dump directory %s, processing", fullname); - /* Fall through */ - - case MW_OCCURRED: /* dup */ - { - if (res != MW_OK) - { - log("Deleting dump directory %s (dup of %s), sending dbus signal", - strrchr(fullname, '/') + 1, - strrchr(first, '/') + 1); - delete_dump_dir(fullname); - } - - const char *uid_str = get_crash_item_content_or_NULL(crash_data, FILENAME_UID); - /* When dup occurs we need to return first occurence, - * not the one which is deleted - */ - send_dbus_sig_Crash(get_crash_item_content_or_NULL(crash_data, FILENAME_PACKAGE), - (first) ? first : fullname, - uid_str - ); - break; - } - case MW_CORRUPTED: - case MW_GPG_ERROR: - default: - log("Corrupted or bad dump %s (res:%d), deleting", fullname, (int)res); - delete_dump_dir(fullname); - break; - } - free(fullname); - free_crash_data(crash_data); - } /* 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); - int fds_size = 0; - GPollFD *fds = NULL; - - while (!s_exiting) - { - gboolean some_ready; - gint max_priority; - gint timeout; - gint nfds; - - some_ready = g_main_context_prepare(context, &max_priority); - if (some_ready) - g_main_context_dispatch(context); - - while (1) - { - nfds = g_main_context_query(context, max_priority, &timeout, fds, fds_size); - if (nfds <= fds_size) - break; - fds_size = nfds + 16; /* +16: optimizing realloc frequency */ - fds = (GPollFD *)xrealloc(fds, fds_size * sizeof(fds[0])); - } - - if (s_timeout != 0) - alarm(s_timeout); - g_poll(fds, nfds, timeout); - if (s_timeout != 0) - alarm(0); - - some_ready = g_main_context_check(context, max_priority, fds, nfds); - if (some_ready) - g_main_context_dispatch(context); - } - - free(fds); - 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(PROGNAME, 0, LOG_DAEMON); - logmode = LOGMODE_SYSLOG; - putenv((char*)"ABRT_SYSLOG=1"); -} - -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, 0775, "abrt"); - /* temp dir */ - ensure_writable_dir(VAR_RUN"/abrt", 0755, "root"); -} - -int main(int argc, char** argv) -{ - 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"); - - char *env_verbose = getenv("ABRT_VERBOSE"); - if (env_verbose) - g_verbose = atoi(env_verbose); - - const char *program_usage_string = _( - PROGNAME" [options]" - ); - enum { - OPT_v = 1 << 0, - OPT_d = 1 << 1, - OPT_s = 1 << 2, - OPT_t = 1 << 3, - OPT_p = 1 << 4, - }; - /* Keep enum above and order of options below in sync! */ - struct options program_options[] = { - OPT__VERBOSE(&g_verbose), - OPT_BOOL( 'd', NULL, NULL , _("Do not daemonize")), - OPT_BOOL( 's', NULL, NULL , _("Log to syslog even with -d")), - OPT_INTEGER('t', NULL, &s_timeout, _("Exit after SEC seconds of inactivity")), - OPT_BOOL( 'p', NULL, NULL , _("Add program names to log")), - OPT_END() - }; - unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); - - /* When dbus daemon starts us, it doesn't set PATH - * (I saw it set only DBUS_STARTER_ADDRESS and DBUS_STARTER_BUS_TYPE). - * In this case, set something sane: - */ - const char *env_path = getenv("PATH"); - if (!env_path || !env_path[0]) - putenv((char*)"PATH=/usr/sbin:/usr/bin:/sbin:/bin"); - - unsetenv("ABRT_SYSLOG"); - putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); - msg_prefix = PROGNAME; /* for log(), error_msg() and such */ - if (opts & OPT_p) - putenv((char*)"ABRT_PROG_PREFIX=1"); - if (opts & OPT_s) - start_syslog_logging(); - - xpipe(s_signal_pipe); - close_on_exec_on(s_signal_pipe[0]); - close_on_exec_on(s_signal_pipe[1]); - signal(SIGTERM, handle_signal); - signal(SIGINT, handle_signal); - signal(SIGCHLD, handle_signal); - if (s_timeout != 0) - signal(SIGALRM, handle_signal); - - /* Daemonize unless -d */ - if (!(opts & OPT_d)) - { - /* 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 pidfile_created = false; - - /* Initialization */ - init_daemon_logging(); - - VERB1 log("Loading settings"); - if (load_settings() != 0) - goto init_error; - - sanitize_dump_dir_rights(); - - VERB1 log("Creating glib main loop"); - pMainloop = g_main_loop_new(NULL, FALSE); - - VERB1 log("Initializing inotify"); - errno = 0; - int inotify_fd = inotify_init(); - if (inotify_fd == -1) - perror_msg_and_die("inotify_init failed"); - close_on_exec_on(inotify_fd); - - /* Watching DEBUG_DUMPS_DIR for new files... */ - if (inotify_add_watch(inotify_fd, DEBUG_DUMPS_DIR, IN_CREATE | IN_MOVED_TO) < 0) - { - perror_msg("inotify_add_watch failed on '%s'", DEBUG_DUMPS_DIR); - goto init_error; - } - if (g_settings_sWatchCrashdumpArchiveDir) - { - s_upload_watch = inotify_add_watch(inotify_fd, g_settings_sWatchCrashdumpArchiveDir, IN_CLOSE_WRITE|IN_MOVED_TO); - if (s_upload_watch < 0) - { - perror_msg("inotify_add_watch failed on '%s'", g_settings_sWatchCrashdumpArchiveDir); - goto init_error; - } - } - 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); - - /* 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 pid file"); - if (create_pidfile() != 0) - goto init_error; - 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"); - if (init_dbus() != 0) - goto init_error; - - /* Inform parent that we initialized ok */ - if (!(opts & OPT_d)) - { - 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 */ - log("Init complete, entering main loop"); - run_main_loop(pMainloop); - - cleanup: - /* Error or INT/TERM. Clean up, in reverse order. - * Take care to not undo things we did not do. - */ - dumpsocket_shutdown(); - if (pidfile_created) - unlink(VAR_RUN_PIDFILE); - - 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); - - deinit_dbus(); - - if (pMainloop) - g_main_loop_unref(pMainloop); - - free_settings(); - - /* Exiting */ - if (s_sig_caught && s_sig_caught != SIGALRM && s_sig_caught != SIGCHLD) - { - error_msg("Got signal %d, exiting", s_sig_caught); - signal(s_sig_caught, SIG_DFL); - raise(s_sig_caught); - } - error_msg_and_die("Exiting"); - - init_error: - /* Initialization error */ - error_msg("Error while initializing daemon"); - /* Inform parent that initialization failed */ - if (!(opts & OPT_d)) - kill(parent_pid, SIGINT); - goto cleanup; -} -- cgit