/* 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 "abrt_glib.h" #include "abrt-inotify.h" #include "libabrt.h" #include "problem_api.h" /* I want to use -Werror, but gcc-4.4 throws a curveball: * "warning: ignoring return value of 'ftruncate', declared with attribute warn_unused_result" * and (void) cast is not enough to shut it up! Oh God... */ #define IGNORE_RESULT(func_call) do { if (func_call) /* nothing */; } while (0) #define VAR_RUN_PIDFILE VAR_RUN"/abrt/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 #define IN_DUMP_LOCATION_FLAGS (IN_DELETE_SELF | IN_MOVE_SELF) #define ABRTD_DBUS_NAME ABRT_DBUS_NAME".daemon" /* Daemon initializes, then sits in glib main loop, waiting for events. * Events can be: * - inotify: something new appeared under /var/tmp/abrt or /var/spool/abrt-upload * - signal: we got SIGTERM, SIGINT, SIGALRM or SIGCHLD * - new socket connection */ static volatile sig_atomic_t s_sig_caught; static int s_signal_pipe[2]; static int s_signal_pipe_write = -1; static unsigned s_timeout; static int s_timeout_src; static GMainLoop *s_main_loop; GList *s_processes; GList *s_dir_queue; static GIOChannel *channel_socket = NULL; static guint channel_id_socket = 0; static int child_count = 0; struct abrt_server_proc { pid_t pid; int fdout; char *dirname; GIOChannel *channel; guint watch_id; enum { AS_UKNOWN, AS_POST_CREATE, } type; }; /* Returns 0 if proc's pid equals the the given pid */ static gint abrt_server_compare_pid(struct abrt_server_proc *proc, pid_t *pid) { return proc->pid != *pid; } /* Returns 0 if proc's fdout equals the the given fdout */ static gint abrt_server_compare_fdout(struct abrt_server_proc *proc, int *fdout) { return proc->fdout != *fdout; } /* Returns 0 if proc's dirname equals the the given dirname */ static gint abrt_server_compare_dirname(struct abrt_server_proc *proc, const char *dirname) { return g_strcmp0(proc->dirname, dirname); } /* 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; } static void stop_abrt_server(struct abrt_server_proc *proc) { kill(proc->pid, SIGINT); } static void dispose_abrt_server(struct abrt_server_proc *proc) { free(proc->dirname); if (proc->watch_id > 0) g_source_remove(proc->watch_id); if (proc->channel != NULL) g_io_channel_unref(proc->channel); } static void notify_next_post_create_process(struct abrt_server_proc *finished) { if (finished != NULL) s_dir_queue = g_list_remove(s_dir_queue, finished); while (s_dir_queue != NULL) { struct abrt_server_proc *n = (struct abrt_server_proc *)s_dir_queue->data; if (n->type == AS_POST_CREATE) break; if (kill(n->pid, SIGUSR1) >= 0) { n->type = AS_POST_CREATE; break; } /* This could happen only if the notified process disappeared - crashed? */ perror_msg("Failed to send SIGUSR1 to %d", n->pid); log_warning("Directory '%s' will not be processed", n->dirname); /* Remove the problematic process from the post-crate directory queue * and go to try to notify another process. */ s_dir_queue = g_list_delete_link(s_dir_queue, s_dir_queue); } } /* Queueing the process will also lead to cleaning up the dump location. */ static void queue_post_craete_process(struct abrt_server_proc *proc) { load_abrt_conf(); struct abrt_server_proc *running = s_dir_queue == NULL ? NULL : (struct abrt_server_proc *)s_dir_queue->data; if (g_settings_nMaxCrashReportsSize == 0) goto consider_processing; const char *full_path_ignored = running != NULL ? running->dirname : proc->dirname; const char *ignored = strrchr(full_path_ignored, '/'); if (NULL == ignored) /* Paranoia, this should not happen. */ ignored = full_path_ignored; else /* Move behind '/' */ ++ignored; char *worst_dir = NULL; const double max_size = 1024 * 1024 * g_settings_nMaxCrashReportsSize; while (get_dirsize_find_largest_dir(g_settings_dump_location, &worst_dir, ignored) >= max_size && worst_dir) { const char *kind = "old"; GList *proc_of_deleted_item = NULL; if (proc != NULL && strcmp(worst_dir, proc->dirname) == 0) { kind = "new"; stop_abrt_server(proc); proc = NULL; } else if ((proc_of_deleted_item = g_list_find_custom(s_dir_queue, worst_dir, (GCompareFunc)abrt_server_compare_dirname))) { kind = "unprocessed"; struct abrt_server_proc *removed_proc = (struct abrt_server_proc *)proc_of_deleted_item->data; s_dir_queue = g_list_delete_link(s_dir_queue, proc_of_deleted_item); stop_abrt_server(removed_proc); } log_warning("Size of '%s' >= %u MB (MaxCrashReportsSize), deleting %s directory '%s'", g_settings_dump_location, g_settings_nMaxCrashReportsSize, kind, worst_dir); char *deleted = concat_path_file(g_settings_dump_location, worst_dir); free(worst_dir); worst_dir = NULL; struct dump_dir *dd = dd_opendir(deleted, DD_FAIL_QUIETLY_ENOENT); if (dd != NULL) dd_delete(dd); free(deleted); } consider_processing: /* If the process survived cleaning up the dump location, append it to the * post-create queue. */ if (proc != NULL) s_dir_queue = g_list_append(s_dir_queue, proc); /* If there were no running post-crate process before we added the * currently handled process to the post-create queue, start processing of * the currently handled process. */ if (running == NULL) notify_next_post_create_process(NULL/*finished*/); } static gboolean abrt_server_output_cb(GIOChannel *channel, GIOCondition condition, gpointer user_data) { int fdout = g_io_channel_unix_get_fd(channel); GList *item = g_list_find_custom(s_processes, &fdout, (GCompareFunc)abrt_server_compare_fdout); if (item == NULL) { log_warning("Removing an input channel fd (%d) without a process assigned", fdout); return FALSE; } struct abrt_server_proc *proc = (struct abrt_server_proc *)item->data; if (condition & G_IO_HUP) { log_debug("abrt-server(%d) closed its pipe", proc->pid); proc->watch_id = 0; return FALSE; } for (;;) { gchar *line; gsize len = 0; gsize pos = 0; GError *error = NULL; /* We use buffered channel so we do not need to read from the channel in a * loop */ GIOStatus stat = g_io_channel_read_line(channel, &line, &len, &pos, &error); if (stat == G_IO_STATUS_ERROR) error_msg_and_die("Can't read from pipe of abrt-server(%d): '%s'", proc->pid, error ? error->message : ""); if (stat == G_IO_STATUS_EOF) { log_debug("abrt-server(%d)'s output read till end", proc->pid); proc->watch_id = 0; return FALSE; /* Remove this event */ } if (stat == G_IO_STATUS_AGAIN) break; /* G_IO_STATUS_NORMAL) */ line[pos] = '\0'; if (g_str_has_prefix(line, "NEW_PROBLEM_DETECTED: ")) { if (proc->dirname != NULL) { log_warning("abrt-server(%d): already handling: %s", proc->pid, proc->dirname); free(proc->dirname); /* Because process can be only once in the dir queue */ s_dir_queue = g_list_remove(s_dir_queue, proc); } proc->dirname = xstrdup(line + strlen("NEW_PROBLEM_DETECTED: ")); log_notice("abrt-server(%d): handling new problem: %s", proc->pid, proc->dirname); queue_post_craete_process(proc); } else log_warning("abrt-server(%d): not recognized message: '%s'", proc->pid, line); g_free(line); } return TRUE; /* Keep this event */ } static void add_abrt_server_proc(const pid_t pid, int fdout) { struct abrt_server_proc *proc = xmalloc(sizeof(*proc)); proc->pid = pid; proc->fdout = fdout; proc->dirname = NULL; proc->type = AS_UKNOWN; proc->channel = abrt_gio_channel_unix_new(proc->fdout); proc->watch_id = g_io_add_watch(proc->channel, G_IO_IN | G_IO_HUP, abrt_server_output_cb, proc); GError *error = NULL; g_io_channel_set_flags(proc->channel, G_IO_FLAG_NONBLOCK, &error); if (error != NULL) error_msg_and_die("g_io_channel_set_flags failed: '%s'", error->message); g_io_channel_set_buffered(proc->channel, TRUE); s_processes = g_list_append(s_processes, proc); if (g_list_length(s_processes) >= 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. */ g_source_remove(channel_id_socket); channel_id_socket = 0; } } static void start_idle_timeout(void) { if (s_timeout == 0 || child_count > 0) return; s_timeout_src = g_timeout_add_seconds(s_timeout, (GSourceFunc)g_main_loop_quit, s_main_loop); } static void kill_idle_timeout(void) { if (s_timeout == 0) return; if (s_timeout_src != 0) g_source_remove(s_timeout_src); s_timeout_src = 0; } static gboolean server_socket_cb(GIOChannel *source, GIOCondition condition, gpointer ptr_unused); static void remove_abrt_server_proc(pid_t pid, int status) { GList *item = g_list_find_custom(s_processes, &pid, (GCompareFunc)abrt_server_compare_pid); if (item == NULL) return; struct abrt_server_proc *proc = (struct abrt_server_proc *)item->data; item->data = NULL; s_processes = g_list_delete_link(s_processes, item); if (proc->type == AS_POST_CREATE) notify_next_post_create_process(proc); else { /* Make sure out-of-order exited abrt-server post-create processes do * not stay in the post-create queue. */ s_dir_queue = g_list_remove(s_dir_queue, proc); } dispose_abrt_server(proc); free(proc); if (g_list_length(s_processes) < MAX_CLIENT_COUNT && !channel_id_socket) { log_info("Accepting connections on '%s'", SOCKET_FILE); channel_id_socket = add_watch_or_die(channel_socket, G_IO_IN | G_IO_PRI | G_IO_HUP, server_socket_cb); } } /* 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) { kill_idle_timeout(); load_abrt_conf(); int socket = accept(g_io_channel_unix_get_fd(source), NULL, NULL); if (socket == -1) { perror_msg("accept"); goto server_socket_finitio; } log_notice("New client connected"); fflush(NULL); /* paranoia */ int pipefd[2]; xpipe(pipefd); pid_t pid = fork(); if (pid < 0) { perror_msg("fork"); close(socket); close(pipefd[0]); close(pipefd[1]); goto server_socket_finitio; } if (pid == 0) /* child */ { xdup2(socket, STDIN_FILENO); xdup2(socket, STDOUT_FILENO); close(socket); close(pipefd[0]); xmove_fd(pipefd[1], STDERR_FILENO); char *argv[3]; /* abrt-server [-s] NULL */ char **pp = argv; *pp++ = (char*)"abrt-server"; if (logmode & LOGMODE_JOURNAL) *pp++ = (char*)"-s"; *pp = NULL; execvp(argv[0], argv); perror_msg_and_die("Can't execute '%s'", argv[0]); } /* parent */ close(socket); close(pipefd[1]); add_abrt_server_proc(pid, pipefd[0]); server_socket_finitio: start_idle_timeout(); return TRUE; } /* Signal pipe handler */ static gboolean handle_signal_cb(GIOChannel *gio, GIOCondition condition, gpointer ptr_unused) { uint8_t signo; gsize len = 0; g_io_channel_read_chars(gio, (void*) &signo, 1, &len, NULL); if (len == 1) { /* we did receive a signal */ log_debug("Got signal %d through signal pipe", signo); if (signo != SIGCHLD) g_main_loop_quit(s_main_loop); else { pid_t cpid; int status; while ((cpid = safe_waitpid(-1, &status, WNOHANG)) > 0) { if (WIFSIGNALED(status)) log_debug("abrt-server(%d) signaled with %d", cpid, WTERMSIG(status)); else if (WIFEXITED(status)) log_debug("abrt-server(%d) exited with %d", cpid, WEXITSTATUS(status)); else { log_debug("abrt-server(%d) is being debugged", cpid); continue; } remove_abrt_server_proc(cpid, status); } } } start_idle_timeout(); return TRUE; /* "please don't remove this event" */ } static void sanitize_dump_dir_rights(void) { /* 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_group(g_settings_dump_location, DEFAULT_DUMP_LOCATION_MODE, "root", "abrt"); /* temp dir */ ensure_writable_dir(VAR_RUN"/abrt", 0755, "root"); } /* Inotify handler */ static void handle_inotify_cb(struct abrt_inotify_watch *watch, struct inotify_event *event, gpointer ptr_unused) { kill_idle_timeout(); if (event->mask & IN_DELETE_SELF || event->mask & IN_MOVE_SELF) { log_warning("Recreating deleted dump location '%s'", g_settings_dump_location); load_abrt_conf(); sanitize_dump_dir_rights(); abrt_inotify_watch_reset(watch, g_settings_dump_location, IN_DUMP_LOCATION_FLAGS); } start_idle_timeout(); } /* Initializes the dump socket, usually in /var/run directory * (the path depends on compile-time configuration). */ static void dumpsocket_init(void) { 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); channel_socket = abrt_gio_channel_unix_new(socketfd); g_io_channel_set_buffered(channel_socket, FALSE); channel_id_socket = add_watch_or_die(channel_socket, G_IO_IN | G_IO_PRI | G_IO_HUP, server_socket_cb); } /* Releases all resources used by dumpsocket. */ static void dumpsocket_shutdown(void) { /* Set everything to pre-initialization state. */ if (channel_socket) { /* Undo add_watch_or_die */ g_source_remove(channel_id_socket); /* Undo g_io_channel_unix_new */ g_io_channel_unref(channel_socket); channel_socket = NULL; } } static int create_pidfile(void) { /* 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_RDWR|O_CREAT, 0644); if (fd >= 0) { if (lockf(fd, F_TLOCK, 0) < 0) { perror_msg("Can't lock file '%s'", VAR_RUN_PIDFILE); /* should help with problems like rhbz#859724 */ char pid_str[sizeof(long)*3 + 4]; int r = full_read(fd, pid_str, sizeof(pid_str)); close(fd); /* File can contain garbage. Be careful interpreting it as PID */ if (r > 0) { pid_str[r] = '\0'; errno = 0; long locking_pid = strtol(pid_str, NULL, 10); if (!errno && locking_pid > 0 && locking_pid <= INT_MAX) { char *cmdline = get_cmdline(locking_pid); if (cmdline) { error_msg("Process %lu '%s' is holding the lock", locking_pid, cmdline); free(cmdline); } } } 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()); IGNORE_RESULT(write(fd, buf, len)); IGNORE_RESULT(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 //log_debug("Got signal %d", signo); uint8_t sig_caught; s_sig_caught = 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) IGNORE_RESULT(write(s_signal_pipe_write, &sig_caught, 1)); errno = save_errno; } static void start_logging(void) { /* 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); logmode = LOGMODE_JOURNAL; putenv((char*)"ABRT_SYSLOG=1"); } /* The function expects that FILENAME_COUNT dump dir element is created by * abrtd after all post-create events are successfully done. Thus if * FILENAME_COUNT element doesn't exist abrtd can consider the dump directory * as unprocessed. * * Relying on content of dump directory has one problem. If a hook provides * FILENAME_COUNT abrtd will consider the dump directory as processed. */ static void mark_unprocessed_dump_dirs_not_reportable(const char *path) { log_notice("Searching for unprocessed dump directories"); DIR *dp = opendir(path); if (!dp) { perror_msg("Can't open directory '%s'", path); return; } struct dirent *dent; while ((dent = readdir(dp)) != NULL) { if (dot_or_dotdot(dent->d_name)) continue; /* skip "." and ".." */ char *full_name = concat_path_file(path, dent->d_name); struct stat stat_buf; if (stat(full_name, &stat_buf) != 0) { perror_msg("Can't access path '%s'", full_name); goto next_dd; } if (S_ISDIR(stat_buf.st_mode) == 0) /* This is expected. The dump location contains some aux files */ goto next_dd; struct dump_dir *dd = dd_opendir(full_name, /*flags*/0); if (dd) { if (!problem_dump_dir_is_complete(dd) && !dd_exist(dd, FILENAME_NOT_REPORTABLE)) { log_warning("Marking '%s' not reportable (no '"FILENAME_COUNT"' item)", full_name); dd_save_text(dd, FILENAME_NOT_REPORTABLE, _("The problem data are " "incomplete. This usually happens when a problem " "is detected while computer is shutting down or " "user is logging out. In order to provide " "valuable problem reports, ABRT will not allow " "you to submit this problem. If you have time and " "want to help the developers in their effort to " "sort out this problem, please contact them directly.")); } dd_close(dd); } next_dd: free(full_name); } closedir(dp); } static void on_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) { log_debug("Going to own bus '%s'", name); } static void on_name_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { log_debug("Acquired the name '%s' on the system bus", name); } static void on_name_lost(GDBusConnection *connection, const gchar *name, gpointer user_data) { error_msg_and_die(_("The name '%s' has been lost, please check if other " "service owning the name is not running.\n"), name); } int main(int argc, char** argv) { /* I18n */ setlocale(LC_ALL, ""); #if ENABLE_NLS bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif abrt_init(argv); int parent_pid = getpid(); const char *program_usage_string = _( "& [options]" ); enum { OPT_v = 1 << 0, OPT_d = 1 << 1, OPT_s = 1 << 2, // TODO: get rid of -t NUM, it is no longer useful since dbus is moved to a separate tool 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 NUM 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); export_abrt_envvars(opts & OPT_p); #if 0 /* We no longer use dbus */ /* 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"); #endif unsetenv("ABRT_SYSLOG"); msg_prefix = g_progname; /* for log_warning(), error_msg() and such */ if (getuid() != 0) error_msg_and_die("Must be run as root"); if (opts & OPT_s) start_logging(); xpipe(s_signal_pipe); close_on_exec_on(s_signal_pipe[0]); close_on_exec_on(s_signal_pipe[1]); ndelay_on(s_signal_pipe[0]); /* I/O should not block - */ ndelay_on(s_signal_pipe[1]); /* especially writes! they happen in signal handler! */ signal(SIGTERM, handle_signal); signal(SIGINT, handle_signal); signal(SIGCHLD, handle_signal); GIOChannel* channel_signal = NULL; guint channel_id_signal_event = 0; bool pidfile_created = false; struct abrt_inotify_watch *aiw = NULL; int ret = 1; /* Initialization */ log_notice("Loading settings"); if (load_abrt_conf() != 0) goto init_error; /* Moved before daemonization because parent waits for signal from daemon * only for short period and time consumed by * mark_unprocessed_dump_dirs_not_reportable() is slightly unpredictable. */ sanitize_dump_dir_rights(); mark_unprocessed_dump_dirs_not_reportable(g_settings_dump_location); /* Daemonize unless -d */ if (!(opts & OPT_d)) { /* forking to background */ fflush(NULL); /* paranoia */ 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 */ if (setsid() < 0) perror_msg_and_die("setsid"); if (g_verbose == 0 && logmode != LOGMODE_JOURNAL) start_logging(); } log_notice("Creating glib main loop"); s_main_loop = g_main_loop_new(NULL, FALSE); /* Watching 'g_settings_dump_location' for delete self * because hooks expects that the dump location exists if abrtd is running */ aiw = abrt_inotify_watch_init(g_settings_dump_location, IN_DUMP_LOCATION_FLAGS, handle_inotify_cb, /*user data*/NULL); /* Add an event source which waits for INT/TERM signal */ log_notice("Adding signal pipe watch to glib main loop"); channel_signal = abrt_gio_channel_unix_new(s_signal_pipe[0]); channel_id_signal_event = add_watch_or_die(channel_signal, G_IO_IN | G_IO_PRI | G_IO_HUP, handle_signal_cb); guint name_id = 0; /* Mark the territory */ log_notice("Creating pid file"); if (create_pidfile() != 0) goto init_error; pidfile_created = true; /* Open socket to receive new problem data (from python etc). */ dumpsocket_init(); /* Inform parent that we initialized ok */ if (!(opts & OPT_d)) { log_notice("Signalling parent"); kill(parent_pid, SIGTERM); if (logmode != LOGMODE_JOURNAL) start_logging(); } /* Only now we want signal pipe to work */ s_signal_pipe_write = s_signal_pipe[1]; /* Own a name on D-Bus */ name_id = g_bus_own_name(G_BUS_TYPE_SYSTEM, ABRTD_DBUS_NAME, G_BUS_NAME_OWNER_FLAGS_NONE, on_bus_acquired, on_name_acquired, on_name_lost, NULL, NULL); start_idle_timeout(); /* Enter the event loop */ log_debug("Init complete, entering main loop"); g_main_loop_run(s_main_loop); ret = 0; /* Jump to exit */ goto cleanup; init_error: /* Initialization error */ error_msg("Error while initializing daemon"); /* Inform parent that initialization failed */ if (!(opts & OPT_d)) kill(parent_pid, SIGINT); cleanup: if (name_id > 0) g_bus_unown_name (name_id); /* 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_id_signal_event > 0) g_source_remove(channel_id_signal_event); if (channel_signal) g_io_channel_unref(channel_signal); abrt_inotify_watch_destroy(aiw); if (s_main_loop) g_main_loop_unref(s_main_loop); free_abrt_conf_data(); if (s_sig_caught && s_sig_caught != SIGCHLD) { /* We use TERM to stop abrtd, so not printing out error message. */ if (s_sig_caught != SIGTERM) { error_msg("Got signal %d, exiting", s_sig_caught); signal(s_sig_caught, SIG_DFL); raise(s_sig_caught); } } /* Exiting */ log_notice("Exiting"); return ret; }