Blame src/daemon/abrtd.c

Packit 8ea169
/*
Packit 8ea169
    Copyright (C) 2009  Jiri Moskovcak (jmoskovc@redhat.com)
Packit 8ea169
    Copyright (C) 2009  RedHat inc.
Packit 8ea169
Packit 8ea169
    This program is free software; you can redistribute it and/or modify
Packit 8ea169
    it under the terms of the GNU General Public License as published by
Packit 8ea169
    the Free Software Foundation; either version 2 of the License, or
Packit 8ea169
    (at your option) any later version.
Packit 8ea169
Packit 8ea169
    This program is distributed in the hope that it will be useful,
Packit 8ea169
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8ea169
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8ea169
    GNU General Public License for more details.
Packit 8ea169
Packit 8ea169
    You should have received a copy of the GNU General Public License along
Packit 8ea169
    with this program; if not, write to the Free Software Foundation, Inc.,
Packit 8ea169
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit 8ea169
*/
Packit 8ea169
#if HAVE_LOCALE_H
Packit 8ea169
# include <locale.h>
Packit 8ea169
#endif
Packit 8ea169
#include <sys/un.h>
Packit 8ea169
#include <glib-unix.h>
Packit 8ea169
Packit 8ea169
#include "abrt_glib.h"
Packit 8ea169
#include "abrt-inotify.h"
Packit 8ea169
#include "libabrt.h"
Packit 8ea169
#include "problem_api.h"
Packit 8ea169
Packit 8ea169
Packit 8ea169
/* I want to use -Werror, but gcc-4.4 throws a curveball:
Packit 8ea169
 * "warning: ignoring return value of 'ftruncate', declared with attribute warn_unused_result"
Packit 8ea169
 * and (void) cast is not enough to shut it up! Oh God...
Packit 8ea169
 */
Packit 8ea169
#define IGNORE_RESULT(func_call) do { if (func_call) /* nothing */; } while (0)
Packit 8ea169
Packit 8ea169
Packit 8ea169
#define VAR_RUN_PIDFILE   VAR_RUN"/abrt/abrtd.pid"
Packit 8ea169
Packit 8ea169
#define SOCKET_FILE       VAR_RUN"/abrt/abrt.socket"
Packit 8ea169
#define SOCKET_PERMISSION 0666
Packit 8ea169
/* Maximum number of simultaneously opened client connections. */
Packit 8ea169
#define MAX_CLIENT_COUNT  10
Packit 8ea169
Packit 8ea169
#define IN_DUMP_LOCATION_FLAGS (IN_DELETE_SELF | IN_MOVE_SELF)
Packit 8ea169
Packit 8ea169
#define ABRTD_DBUS_NAME ABRT_DBUS_NAME".daemon"
Packit 8ea169
Packit 8ea169
/* Daemon initializes, then sits in glib main loop, waiting for events.
Packit 8ea169
 * Events can be:
Packit 8ea169
 * - inotify: something new appeared under /var/tmp/abrt or /var/spool/abrt-upload
Packit 8ea169
 * - signal: we got SIGTERM, SIGINT, SIGALRM or SIGCHLD
Packit 8ea169
 * - new socket connection
Packit 8ea169
 */
Packit 8ea169
static volatile sig_atomic_t s_sig_caught;
Packit 8ea169
static int s_signal_pipe[2];
Packit 8ea169
static int s_signal_pipe_write = -1;
Packit 8ea169
static unsigned s_timeout;
Packit 8ea169
static int s_timeout_src;
Packit 8ea169
static GMainLoop *s_main_loop;
Packit 8ea169
Packit 8ea169
GList *s_processes;
Packit 8ea169
GList *s_dir_queue;
Packit 8ea169
Packit 8ea169
static GIOChannel *channel_socket = NULL;
Packit 8ea169
static guint channel_id_socket = 0;
Packit 8ea169
static int child_count = 0;
Packit 8ea169
Packit 8ea169
struct abrt_server_proc
Packit 8ea169
{
Packit 8ea169
    pid_t pid;
Packit 8ea169
    int fdout;
Packit 8ea169
    char *dirname;
Packit 8ea169
    GIOChannel *channel;
Packit 8ea169
    guint watch_id;
Packit 8ea169
    enum {
Packit 8ea169
        AS_UKNOWN,
Packit 8ea169
        AS_POST_CREATE,
Packit 8ea169
    } type;
Packit 8ea169
};
Packit 8ea169
Packit 8ea169
/* Returns 0 if proc's pid equals the the given pid */
Packit 8ea169
static gint abrt_server_compare_pid(struct abrt_server_proc *proc, pid_t *pid)
Packit 8ea169
{
Packit 8ea169
    return proc->pid != *pid;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
/* Returns 0 if proc's fdout equals the the given fdout */
Packit 8ea169
static gint abrt_server_compare_fdout(struct abrt_server_proc *proc, int *fdout)
Packit 8ea169
{
Packit 8ea169
    return proc->fdout != *fdout;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
/* Returns 0 if proc's dirname equals the the given dirname */
Packit 8ea169
static gint abrt_server_compare_dirname(struct abrt_server_proc *proc, const char *dirname)
Packit 8ea169
{
Packit 8ea169
    return g_strcmp0(proc->dirname, dirname);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
/* Helpers */
Packit 8ea169
static guint add_watch_or_die(GIOChannel *channel, unsigned condition, GIOFunc func)
Packit 8ea169
{
Packit 8ea169
    errno = 0;
Packit 8ea169
    guint r = g_io_add_watch(channel, (GIOCondition)condition, func, NULL);
Packit 8ea169
    if (!r)
Packit 8ea169
        perror_msg_and_die("g_io_add_watch failed");
Packit 8ea169
    return r;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void stop_abrt_server(struct abrt_server_proc *proc)
Packit 8ea169
{
Packit 8ea169
    kill(proc->pid, SIGINT);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void dispose_abrt_server(struct abrt_server_proc *proc)
Packit 8ea169
{
Packit 8ea169
    free(proc->dirname);
Packit 8ea169
Packit 8ea169
    if (proc->watch_id > 0)
Packit 8ea169
        g_source_remove(proc->watch_id);
Packit 8ea169
Packit 8ea169
    if (proc->channel != NULL)
Packit 8ea169
        g_io_channel_unref(proc->channel);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void notify_next_post_create_process(struct abrt_server_proc *finished)
Packit 8ea169
{
Packit 8ea169
    if (finished != NULL)
Packit 8ea169
        s_dir_queue = g_list_remove(s_dir_queue, finished);
Packit 8ea169
Packit 8ea169
    while (s_dir_queue != NULL)
Packit 8ea169
    {
Packit 8ea169
        struct abrt_server_proc *n = (struct abrt_server_proc *)s_dir_queue->data;
Packit 8ea169
        if (n->type == AS_POST_CREATE)
Packit 8ea169
            break;
Packit 8ea169
Packit 8ea169
        if (kill(n->pid, SIGUSR1) >= 0)
Packit 8ea169
        {
Packit 8ea169
            n->type = AS_POST_CREATE;
Packit 8ea169
            break;
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        /* This could happen only if the notified process disappeared - crashed?
Packit 8ea169
         */
Packit 8ea169
        perror_msg("Failed to send SIGUSR1 to %d", n->pid);
Packit 8ea169
        log_warning("Directory '%s' will not be processed", n->dirname);
Packit 8ea169
Packit 8ea169
        /* Remove the problematic process from the post-crate directory queue
Packit 8ea169
         * and go to try to notify another process.
Packit 8ea169
         */
Packit 8ea169
        s_dir_queue = g_list_delete_link(s_dir_queue, s_dir_queue);
Packit 8ea169
    }
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
/* Queueing the process will also lead to cleaning up the dump location.
Packit 8ea169
 */
Packit 8ea169
static void queue_post_craete_process(struct abrt_server_proc *proc)
Packit 8ea169
{
Packit 8ea169
    load_abrt_conf();
Packit 8ea169
    struct abrt_server_proc *running = s_dir_queue == NULL ? NULL
Packit 8ea169
                                                           : (struct abrt_server_proc *)s_dir_queue->data;
Packit 8ea169
    if (g_settings_nMaxCrashReportsSize == 0)
Packit 8ea169
        goto consider_processing;
Packit 8ea169
Packit 8ea169
    const char *full_path_ignored = running != NULL ? running->dirname
Packit 8ea169
                                                    : proc->dirname;
Packit 8ea169
    const char *ignored = strrchr(full_path_ignored, '/');
Packit 8ea169
    if (NULL == ignored)
Packit 8ea169
        /* Paranoia, this should not happen. */
Packit 8ea169
        ignored = full_path_ignored;
Packit 8ea169
    else
Packit 8ea169
        /* Move behind '/' */
Packit 8ea169
        ++ignored;
Packit 8ea169
Packit 8ea169
    char *worst_dir = NULL;
Packit 8ea169
    const double max_size = 1024 * 1024 * g_settings_nMaxCrashReportsSize;
Packit 8ea169
    while (get_dirsize_find_largest_dir(g_settings_dump_location, &worst_dir, ignored) >= max_size
Packit 8ea169
           && worst_dir)
Packit 8ea169
    {
Packit 8ea169
        const char *kind = "old";
Packit 8ea169
Packit 8ea169
        GList *proc_of_deleted_item = NULL;
Packit 8ea169
        if (proc != NULL && strcmp(worst_dir, proc->dirname) == 0)
Packit 8ea169
        {
Packit 8ea169
            kind = "new";
Packit 8ea169
            stop_abrt_server(proc);
Packit 8ea169
            proc = NULL;
Packit 8ea169
        }
Packit 8ea169
        else if ((proc_of_deleted_item = g_list_find_custom(s_dir_queue, worst_dir, (GCompareFunc)abrt_server_compare_dirname)))
Packit 8ea169
        {
Packit 8ea169
            kind = "unprocessed";
Packit 8ea169
            struct abrt_server_proc *removed_proc = (struct abrt_server_proc *)proc_of_deleted_item->data;
Packit 8ea169
            s_dir_queue = g_list_delete_link(s_dir_queue, proc_of_deleted_item);
Packit 8ea169
            stop_abrt_server(removed_proc);
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        log_warning("Size of '%s' >= %u MB (MaxCrashReportsSize), deleting %s directory '%s'",
Packit 8ea169
                g_settings_dump_location, g_settings_nMaxCrashReportsSize,
Packit 8ea169
                kind, worst_dir);
Packit 8ea169
Packit 8ea169
        char *deleted = concat_path_file(g_settings_dump_location, worst_dir);
Packit 8ea169
        free(worst_dir);
Packit 8ea169
        worst_dir = NULL;
Packit 8ea169
Packit 8ea169
        struct dump_dir *dd = dd_opendir(deleted, DD_FAIL_QUIETLY_ENOENT);
Packit 8ea169
        if (dd != NULL)
Packit 8ea169
            dd_delete(dd);
Packit 8ea169
Packit 8ea169
        free(deleted);
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
consider_processing:
Packit 8ea169
    /* If the process survived cleaning up the dump location, append it to the
Packit 8ea169
     * post-create queue.
Packit 8ea169
     */
Packit 8ea169
    if (proc != NULL)
Packit 8ea169
        s_dir_queue = g_list_append(s_dir_queue, proc);
Packit 8ea169
Packit 8ea169
    /* If there were no running post-crate process before we added the
Packit 8ea169
     * currently handled process to the post-create queue, start processing of
Packit 8ea169
     * the currently handled process.
Packit 8ea169
     */
Packit 8ea169
    if (running == NULL)
Packit 8ea169
        notify_next_post_create_process(NULL/*finished*/);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static gboolean abrt_server_output_cb(GIOChannel *channel, GIOCondition condition, gpointer user_data)
Packit 8ea169
{
Packit 8ea169
    int fdout = g_io_channel_unix_get_fd(channel);
Packit 8ea169
    GList *item = g_list_find_custom(s_processes, &fdout, (GCompareFunc)abrt_server_compare_fdout);
Packit 8ea169
    if (item == NULL)
Packit 8ea169
    {
Packit 8ea169
        log_warning("Removing an input channel fd (%d) without a process assigned", fdout);
Packit 8ea169
        return FALSE;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    struct abrt_server_proc *proc = (struct abrt_server_proc *)item->data;
Packit 8ea169
Packit 8ea169
    if (condition & G_IO_HUP)
Packit 8ea169
    {
Packit 8ea169
        log_debug("abrt-server(%d) closed its pipe", proc->pid);
Packit 8ea169
        proc->watch_id = 0;
Packit 8ea169
        return FALSE;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    for (;;)
Packit 8ea169
    {
Packit 8ea169
        gchar *line;
Packit 8ea169
        gsize len = 0;
Packit 8ea169
        gsize pos = 0;
Packit 8ea169
        GError *error = NULL;
Packit 8ea169
Packit 8ea169
        /* We use buffered channel so we do not need to read from the channel in a
Packit 8ea169
         * loop */
Packit 8ea169
        GIOStatus stat = g_io_channel_read_line(channel, &line, &len, &pos, &error);
Packit 8ea169
        if (stat == G_IO_STATUS_ERROR)
Packit 8ea169
            error_msg_and_die("Can't read from pipe of abrt-server(%d): '%s'", proc->pid, error ? error->message : "");
Packit 8ea169
        if (stat == G_IO_STATUS_EOF)
Packit 8ea169
        {
Packit 8ea169
            log_debug("abrt-server(%d)'s output read till end", proc->pid);
Packit 8ea169
            proc->watch_id = 0;
Packit 8ea169
            return FALSE; /* Remove this event */
Packit 8ea169
        }
Packit 8ea169
        if (stat == G_IO_STATUS_AGAIN)
Packit 8ea169
            break;
Packit 8ea169
Packit 8ea169
        /* G_IO_STATUS_NORMAL) */
Packit 8ea169
        line[pos] = '\0';
Packit 8ea169
        if (g_str_has_prefix(line, "NEW_PROBLEM_DETECTED: "))
Packit 8ea169
        {
Packit 8ea169
            if (proc->dirname != NULL)
Packit 8ea169
            {
Packit 8ea169
                log_warning("abrt-server(%d): already handling: %s", proc->pid, proc->dirname);
Packit 8ea169
                free(proc->dirname);
Packit 8ea169
                /* Because process can be only once in the dir queue */
Packit 8ea169
                s_dir_queue = g_list_remove(s_dir_queue, proc);
Packit 8ea169
            }
Packit 8ea169
Packit 8ea169
            proc->dirname = xstrdup(line + strlen("NEW_PROBLEM_DETECTED: "));
Packit 8ea169
            log_notice("abrt-server(%d): handling new problem: %s", proc->pid, proc->dirname);
Packit 8ea169
            queue_post_craete_process(proc);
Packit 8ea169
        }
Packit 8ea169
        else
Packit 8ea169
            log_warning("abrt-server(%d): not recognized message: '%s'", proc->pid, line);
Packit 8ea169
Packit 8ea169
        g_free(line);
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    return TRUE; /* Keep this event */
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void add_abrt_server_proc(const pid_t pid, int fdout)
Packit 8ea169
{
Packit 8ea169
    struct abrt_server_proc *proc = xmalloc(sizeof(*proc));
Packit 8ea169
    proc->pid = pid;
Packit 8ea169
    proc->fdout = fdout;
Packit 8ea169
    proc->dirname = NULL;
Packit 8ea169
    proc->type = AS_UKNOWN;
Packit 8ea169
    proc->channel = abrt_gio_channel_unix_new(proc->fdout);
Packit 8ea169
    proc->watch_id = g_io_add_watch(proc->channel,
Packit 8ea169
                                    G_IO_IN | G_IO_HUP,
Packit 8ea169
                                    abrt_server_output_cb,
Packit 8ea169
                                    proc);
Packit 8ea169
Packit 8ea169
    GError *error = NULL;
Packit 8ea169
    g_io_channel_set_flags(proc->channel, G_IO_FLAG_NONBLOCK, &error);
Packit 8ea169
    if (error != NULL)
Packit 8ea169
        error_msg_and_die("g_io_channel_set_flags failed: '%s'", error->message);
Packit 8ea169
Packit 8ea169
    g_io_channel_set_buffered(proc->channel, TRUE);
Packit 8ea169
Packit 8ea169
    s_processes = g_list_append(s_processes, proc);
Packit 8ea169
    if (g_list_length(s_processes) >= MAX_CLIENT_COUNT)
Packit 8ea169
    {
Packit 8ea169
        error_msg("Too many clients, refusing connections to '%s'", SOCKET_FILE);
Packit 8ea169
        /* To avoid infinite loop caused by the descriptor in "ready" state,
Packit 8ea169
         * the callback must be disabled.
Packit 8ea169
         */
Packit 8ea169
        g_source_remove(channel_id_socket);
Packit 8ea169
        channel_id_socket = 0;
Packit 8ea169
    }
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void start_idle_timeout(void)
Packit 8ea169
{
Packit 8ea169
    if (s_timeout == 0 || child_count > 0)
Packit 8ea169
        return;
Packit 8ea169
Packit 8ea169
    s_timeout_src = g_timeout_add_seconds(s_timeout, (GSourceFunc)g_main_loop_quit, s_main_loop);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void kill_idle_timeout(void)
Packit 8ea169
{
Packit 8ea169
    if (s_timeout == 0)
Packit 8ea169
        return;
Packit 8ea169
Packit 8ea169
    if (s_timeout_src != 0)
Packit 8ea169
        g_source_remove(s_timeout_src);
Packit 8ea169
Packit 8ea169
    s_timeout_src = 0;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
Packit 8ea169
static gboolean server_socket_cb(GIOChannel *source, GIOCondition condition, gpointer ptr_unused);
Packit 8ea169
Packit 8ea169
static void remove_abrt_server_proc(pid_t pid, int status)
Packit 8ea169
{
Packit 8ea169
    GList *item = g_list_find_custom(s_processes, &pid, (GCompareFunc)abrt_server_compare_pid);
Packit 8ea169
    if (item == NULL)
Packit 8ea169
        return;
Packit 8ea169
Packit 8ea169
    struct abrt_server_proc *proc = (struct abrt_server_proc *)item->data;
Packit 8ea169
    item->data = NULL;
Packit 8ea169
    s_processes = g_list_delete_link(s_processes, item);
Packit 8ea169
Packit 8ea169
    if (proc->type == AS_POST_CREATE)
Packit 8ea169
        notify_next_post_create_process(proc);
Packit 8ea169
    else
Packit 8ea169
    {   /* Make sure out-of-order exited abrt-server post-create processes do
Packit 8ea169
         * not stay in the post-create queue.
Packit 8ea169
         */
Packit 8ea169
        s_dir_queue = g_list_remove(s_dir_queue, proc);
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    dispose_abrt_server(proc);
Packit 8ea169
    free(proc);
Packit 8ea169
Packit 8ea169
    if (g_list_length(s_processes) < MAX_CLIENT_COUNT && !channel_id_socket)
Packit 8ea169
    {
Packit 8ea169
        log_info("Accepting connections on '%s'", SOCKET_FILE);
Packit 8ea169
        channel_id_socket = add_watch_or_die(channel_socket, G_IO_IN | G_IO_PRI | G_IO_HUP, server_socket_cb);
Packit 8ea169
    }
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
/* Callback called by glib main loop when a client connects to ABRT's socket. */
Packit 8ea169
static gboolean server_socket_cb(GIOChannel *source, GIOCondition condition, gpointer ptr_unused)
Packit 8ea169
{
Packit 8ea169
    kill_idle_timeout();
Packit 8ea169
    load_abrt_conf();
Packit 8ea169
Packit 8ea169
    int socket = accept(g_io_channel_unix_get_fd(source), NULL, NULL);
Packit 8ea169
    if (socket == -1)
Packit 8ea169
    {
Packit 8ea169
        perror_msg("accept");
Packit 8ea169
        goto server_socket_finitio;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    log_notice("New client connected");
Packit 8ea169
    fflush(NULL); /* paranoia */
Packit 8ea169
Packit 8ea169
    int pipefd[2];
Packit 8ea169
    xpipe(pipefd);
Packit 8ea169
Packit 8ea169
    pid_t pid = fork();
Packit 8ea169
    if (pid < 0)
Packit 8ea169
    {
Packit 8ea169
        perror_msg("fork");
Packit 8ea169
        close(socket);
Packit 8ea169
        close(pipefd[0]);
Packit 8ea169
        close(pipefd[1]);
Packit 8ea169
        goto server_socket_finitio;
Packit 8ea169
    }
Packit 8ea169
    if (pid == 0) /* child */
Packit 8ea169
    {
Packit 8ea169
        xdup2(socket, STDIN_FILENO);
Packit 8ea169
        xdup2(socket, STDOUT_FILENO);
Packit 8ea169
        close(socket);
Packit 8ea169
Packit 8ea169
        close(pipefd[0]);
Packit 8ea169
        xmove_fd(pipefd[1], STDERR_FILENO);
Packit 8ea169
Packit 8ea169
        char *argv[3];  /* abrt-server [-s] NULL */
Packit 8ea169
        char **pp = argv;
Packit 8ea169
        *pp++ = (char*)"abrt-server";
Packit 8ea169
        if (logmode & LOGMODE_JOURNAL)
Packit 8ea169
            *pp++ = (char*)"-s";
Packit 8ea169
        *pp = NULL;
Packit 8ea169
Packit 8ea169
        execvp(argv[0], argv);
Packit 8ea169
        perror_msg_and_die("Can't execute '%s'", argv[0]);
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    /* parent */
Packit 8ea169
    close(socket);
Packit 8ea169
    close(pipefd[1]);
Packit 8ea169
    add_abrt_server_proc(pid, pipefd[0]);
Packit 8ea169
Packit 8ea169
server_socket_finitio:
Packit 8ea169
    start_idle_timeout();
Packit 8ea169
    return TRUE;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
/* Signal pipe handler */
Packit 8ea169
static gboolean handle_signal_cb(GIOChannel *gio, GIOCondition condition, gpointer ptr_unused)
Packit 8ea169
{
Packit 8ea169
    uint8_t signo;
Packit 8ea169
    gsize len = 0;
Packit 8ea169
    g_io_channel_read_chars(gio, (void*) &signo, 1, &len, NULL);
Packit 8ea169
    if (len == 1)
Packit 8ea169
    {
Packit 8ea169
        /* we did receive a signal */
Packit 8ea169
        log_debug("Got signal %d through signal pipe", signo);
Packit 8ea169
        if (signo != SIGCHLD)
Packit 8ea169
            g_main_loop_quit(s_main_loop);
Packit 8ea169
        else
Packit 8ea169
        {
Packit 8ea169
            pid_t cpid;
Packit 8ea169
            int status;
Packit 8ea169
            while ((cpid = safe_waitpid(-1, &status, WNOHANG)) > 0)
Packit 8ea169
            {
Packit 8ea169
                if (WIFSIGNALED(status))
Packit 8ea169
                    log_debug("abrt-server(%d) signaled with %d", cpid, WTERMSIG(status));
Packit 8ea169
                else if (WIFEXITED(status))
Packit 8ea169
                    log_debug("abrt-server(%d) exited with %d", cpid, WEXITSTATUS(status));
Packit 8ea169
                else
Packit 8ea169
                {
Packit 8ea169
                    log_debug("abrt-server(%d) is being debugged", cpid);
Packit 8ea169
                    continue;
Packit 8ea169
                }
Packit 8ea169
Packit 8ea169
                remove_abrt_server_proc(cpid, status);
Packit 8ea169
            }
Packit 8ea169
        }
Packit 8ea169
    }
Packit 8ea169
    start_idle_timeout();
Packit 8ea169
    return TRUE; /* "please don't remove this event" */
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void sanitize_dump_dir_rights(void)
Packit 8ea169
{
Packit 8ea169
    /* We can't allow everyone to create dumps: otherwise users can flood
Packit 8ea169
     * us with thousands of bogus or malicious dumps */
Packit 8ea169
    /* 07000 bits are setuid, setgit, and sticky, and they must be unset */
Packit 8ea169
    /* 00777 bits are usual "rwxrwxrwx" access rights */
Packit 8ea169
    ensure_writable_dir_group(g_settings_dump_location, DEFAULT_DUMP_LOCATION_MODE, "root", "abrt");
Packit 8ea169
    /* temp dir */
Packit 8ea169
    ensure_writable_dir(VAR_RUN"/abrt", 0755, "root");
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
/* Inotify handler */
Packit 8ea169
Packit 8ea169
static void handle_inotify_cb(struct abrt_inotify_watch *watch, struct inotify_event *event, gpointer ptr_unused)
Packit 8ea169
{
Packit 8ea169
    kill_idle_timeout();
Packit 8ea169
Packit 8ea169
    if (event->mask & IN_DELETE_SELF || event->mask & IN_MOVE_SELF)
Packit 8ea169
    {
Packit 8ea169
        log_warning("Recreating deleted dump location '%s'", g_settings_dump_location);
Packit 8ea169
Packit 8ea169
        load_abrt_conf();
Packit 8ea169
Packit 8ea169
        sanitize_dump_dir_rights();
Packit 8ea169
        abrt_inotify_watch_reset(watch, g_settings_dump_location, IN_DUMP_LOCATION_FLAGS);
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    start_idle_timeout();
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
/* Initializes the dump socket, usually in /var/run directory
Packit 8ea169
 * (the path depends on compile-time configuration).
Packit 8ea169
 */
Packit 8ea169
static void dumpsocket_init(void)
Packit 8ea169
{
Packit 8ea169
    unlink(SOCKET_FILE); /* not caring about the result */
Packit 8ea169
Packit 8ea169
    int socketfd = xsocket(AF_UNIX, SOCK_STREAM, 0);
Packit 8ea169
    close_on_exec_on(socketfd);
Packit 8ea169
Packit 8ea169
    struct sockaddr_un local;
Packit 8ea169
    memset(&local, 0, sizeof(local));
Packit 8ea169
    local.sun_family = AF_UNIX;
Packit 8ea169
    strcpy(local.sun_path, SOCKET_FILE);
Packit 8ea169
    xbind(socketfd, (struct sockaddr*)&local, sizeof(local));
Packit 8ea169
    xlisten(socketfd, MAX_CLIENT_COUNT);
Packit 8ea169
Packit 8ea169
    if (chmod(SOCKET_FILE, SOCKET_PERMISSION) != 0)
Packit 8ea169
        perror_msg_and_die("chmod '%s'", SOCKET_FILE);
Packit 8ea169
Packit 8ea169
    channel_socket = abrt_gio_channel_unix_new(socketfd);
Packit 8ea169
    g_io_channel_set_buffered(channel_socket, FALSE);
Packit 8ea169
Packit 8ea169
    channel_id_socket = add_watch_or_die(channel_socket, G_IO_IN | G_IO_PRI | G_IO_HUP, server_socket_cb);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
/* Releases all resources used by dumpsocket. */
Packit 8ea169
static void dumpsocket_shutdown(void)
Packit 8ea169
{
Packit 8ea169
    /* Set everything to pre-initialization state. */
Packit 8ea169
    if (channel_socket)
Packit 8ea169
    {
Packit 8ea169
        /* Undo add_watch_or_die */
Packit 8ea169
        g_source_remove(channel_id_socket);
Packit 8ea169
        /* Undo g_io_channel_unix_new */
Packit 8ea169
        g_io_channel_unref(channel_socket);
Packit 8ea169
        channel_socket = NULL;
Packit 8ea169
    }
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static int create_pidfile(void)
Packit 8ea169
{
Packit 8ea169
    /* Note:
Packit 8ea169
     * No O_EXCL: we would happily overwrite stale pidfile from previous boot.
Packit 8ea169
     * No O_TRUNC: we must first try to lock the file, and if lock fails,
Packit 8ea169
     * there is another live abrtd. O_TRUNCing the file in this case
Packit 8ea169
     * would be wrong - it'll erase the pid to empty string!
Packit 8ea169
     */
Packit 8ea169
    int fd = open(VAR_RUN_PIDFILE, O_RDWR|O_CREAT, 0644);
Packit 8ea169
    if (fd >= 0)
Packit 8ea169
    {
Packit 8ea169
        if (lockf(fd, F_TLOCK, 0) < 0)
Packit 8ea169
        {
Packit 8ea169
            perror_msg("Can't lock file '%s'", VAR_RUN_PIDFILE);
Packit 8ea169
            /* should help with problems like rhbz#859724 */
Packit 8ea169
            char pid_str[sizeof(long)*3 + 4];
Packit 8ea169
            int r = full_read(fd, pid_str, sizeof(pid_str));
Packit 8ea169
            close(fd);
Packit 8ea169
Packit 8ea169
            /* File can contain garbage. Be careful interpreting it as PID */
Packit 8ea169
            if (r > 0)
Packit 8ea169
            {
Packit 8ea169
                pid_str[r] = '\0';
Packit 8ea169
                errno = 0;
Packit 8ea169
                long locking_pid = strtol(pid_str, NULL, 10);
Packit 8ea169
                if (!errno && locking_pid > 0 && locking_pid <= INT_MAX)
Packit 8ea169
                {
Packit 8ea169
                    char *cmdline = get_cmdline(locking_pid);
Packit 8ea169
                    if (cmdline)
Packit 8ea169
                    {
Packit 8ea169
                        error_msg("Process %lu '%s' is holding the lock", locking_pid, cmdline);
Packit 8ea169
                        free(cmdline);
Packit 8ea169
                    }
Packit 8ea169
                }
Packit 8ea169
            }
Packit 8ea169
Packit 8ea169
            return -1;
Packit 8ea169
        }
Packit 8ea169
        close_on_exec_on(fd);
Packit 8ea169
        /* write our pid to it */
Packit 8ea169
        char buf[sizeof(long)*3 + 2];
Packit 8ea169
        int len = sprintf(buf, "%lu\n", (long)getpid());
Packit 8ea169
        IGNORE_RESULT(write(fd, buf, len));
Packit 8ea169
        IGNORE_RESULT(ftruncate(fd, len));
Packit 8ea169
        /* we leak opened+locked fd intentionally */
Packit 8ea169
        return 0;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    perror_msg("Can't open '%s'", VAR_RUN_PIDFILE);
Packit 8ea169
    return -1;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void handle_signal(int signo)
Packit 8ea169
{
Packit 8ea169
    int save_errno = errno;
Packit 8ea169
Packit 8ea169
    // Enable for debugging only, malloc/printf are unsafe in signal handlers
Packit 8ea169
    //log_debug("Got signal %d", signo);
Packit 8ea169
Packit 8ea169
    uint8_t sig_caught;
Packit 8ea169
    s_sig_caught = sig_caught = signo;
Packit 8ea169
    /* Using local copy of s_sig_caught so that concurrent signal
Packit 8ea169
     * won't change it under us */
Packit 8ea169
    if (s_signal_pipe_write >= 0)
Packit 8ea169
        IGNORE_RESULT(write(s_signal_pipe_write, &sig_caught, 1));
Packit 8ea169
Packit 8ea169
    errno = save_errno;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
Packit 8ea169
static void start_logging(void)
Packit 8ea169
{
Packit 8ea169
    /* Open stdin to /dev/null */
Packit 8ea169
    xmove_fd(xopen("/dev/null", O_RDWR), STDIN_FILENO);
Packit 8ea169
    /* We must not leave fds 0,1,2 closed.
Packit 8ea169
     * Otherwise fprintf(stderr) dumps messages into random fds, etc. */
Packit 8ea169
    xdup2(STDIN_FILENO, STDOUT_FILENO);
Packit 8ea169
    xdup2(STDIN_FILENO, STDERR_FILENO);
Packit 8ea169
    logmode = LOGMODE_JOURNAL;
Packit 8ea169
    putenv((char*)"ABRT_SYSLOG=1");
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
/* The function expects that FILENAME_COUNT dump dir element is created by
Packit 8ea169
 * abrtd after all post-create events are successfully done. Thus if
Packit 8ea169
 * FILENAME_COUNT element doesn't exist abrtd can consider the dump directory
Packit 8ea169
 * as unprocessed.
Packit 8ea169
 *
Packit 8ea169
 * Relying on content of dump directory has one problem. If a hook provides
Packit 8ea169
 * FILENAME_COUNT abrtd will consider the dump directory as processed.
Packit 8ea169
 */
Packit 8ea169
static void mark_unprocessed_dump_dirs_not_reportable(const char *path)
Packit 8ea169
{
Packit 8ea169
    log_notice("Searching for unprocessed dump directories");
Packit 8ea169
Packit 8ea169
    DIR *dp = opendir(path);
Packit 8ea169
    if (!dp)
Packit 8ea169
    {
Packit 8ea169
        perror_msg("Can't open directory '%s'", path);
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    struct dirent *dent;
Packit 8ea169
    while ((dent = readdir(dp)) != NULL)
Packit 8ea169
    {
Packit 8ea169
        if (dot_or_dotdot(dent->d_name))
Packit 8ea169
            continue; /* skip "." and ".." */
Packit 8ea169
Packit 8ea169
        char *full_name = concat_path_file(path, dent->d_name);
Packit 8ea169
Packit 8ea169
        struct stat stat_buf;
Packit 8ea169
        if (stat(full_name, &stat_buf) != 0)
Packit 8ea169
        {
Packit 8ea169
            perror_msg("Can't access path '%s'", full_name);
Packit 8ea169
            goto next_dd;
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        if (S_ISDIR(stat_buf.st_mode) == 0)
Packit 8ea169
            /* This is expected. The dump location contains some aux files */
Packit 8ea169
            goto next_dd;
Packit 8ea169
Packit 8ea169
        struct dump_dir *dd = dd_opendir(full_name, /*flags*/0);
Packit 8ea169
        if (dd)
Packit 8ea169
        {
Packit 8ea169
            if (!problem_dump_dir_is_complete(dd) && !dd_exist(dd, FILENAME_NOT_REPORTABLE))
Packit 8ea169
            {
Packit 8ea169
                log_warning("Marking '%s' not reportable (no '"FILENAME_COUNT"' item)", full_name);
Packit 8ea169
Packit 8ea169
                dd_save_text(dd, FILENAME_NOT_REPORTABLE, _("The problem data are "
Packit 8ea169
                            "incomplete. This usually happens when a problem "
Packit 8ea169
                            "is detected while computer is shutting down or "
Packit 8ea169
                            "user is logging out. In order to provide "
Packit 8ea169
                            "valuable problem reports, ABRT will not allow "
Packit 8ea169
                            "you to submit this problem. If you have time and "
Packit 8ea169
                            "want to help the developers in their effort to "
Packit 8ea169
                            "sort out this problem, please contact them directly."));
Packit 8ea169
Packit 8ea169
            }
Packit 8ea169
            dd_close(dd);
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
  next_dd:
Packit 8ea169
        free(full_name);
Packit 8ea169
    }
Packit 8ea169
    closedir(dp);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void on_bus_acquired(GDBusConnection *connection,
Packit 8ea169
                 const gchar     *name,
Packit 8ea169
                 gpointer         user_data)
Packit 8ea169
{
Packit 8ea169
    log_debug("Going to own bus '%s'", name);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void on_name_acquired (GDBusConnection *connection,
Packit 8ea169
                  const gchar     *name,
Packit 8ea169
                  gpointer         user_data)
Packit 8ea169
{
Packit 8ea169
    log_debug("Acquired the name '%s' on the system bus", name);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void on_name_lost(GDBusConnection *connection,
Packit 8ea169
                      const gchar *name,
Packit 8ea169
                      gpointer user_data)
Packit 8ea169
{
Packit 8ea169
    error_msg_and_die(_("The name '%s' has been lost, please check if other "
Packit 8ea169
                        "service owning the name is not running.\n"), name);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
int main(int argc, char** argv)
Packit 8ea169
{
Packit 8ea169
    /* I18n */
Packit 8ea169
    setlocale(LC_ALL, "");
Packit 8ea169
#if ENABLE_NLS
Packit 8ea169
    bindtextdomain(PACKAGE, LOCALEDIR);
Packit 8ea169
    textdomain(PACKAGE);
Packit 8ea169
#endif
Packit 8ea169
Packit 8ea169
    abrt_init(argv);
Packit 8ea169
Packit 8ea169
    int parent_pid = getpid();
Packit 8ea169
Packit 8ea169
    const char *program_usage_string = _(
Packit 8ea169
        "& [options]"
Packit 8ea169
    );
Packit 8ea169
    enum {
Packit 8ea169
        OPT_v = 1 << 0,
Packit 8ea169
        OPT_d = 1 << 1,
Packit 8ea169
        OPT_s = 1 << 2,
Packit 8ea169
// TODO: get rid of -t NUM, it is no longer useful since dbus is moved to a separate tool
Packit 8ea169
        OPT_t = 1 << 3,
Packit 8ea169
        OPT_p = 1 << 4,
Packit 8ea169
    };
Packit 8ea169
    /* Keep enum above and order of options below in sync! */
Packit 8ea169
    struct options program_options[] = {
Packit 8ea169
        OPT__VERBOSE(&g_verbose),
Packit 8ea169
        OPT_BOOL(   'd', NULL, NULL      , _("Do not daemonize")),
Packit 8ea169
        OPT_BOOL(   's', NULL, NULL      , _("Log to syslog even with -d")),
Packit 8ea169
        OPT_INTEGER('t', NULL, &s_timeout, _("Exit after NUM seconds of inactivity")),
Packit 8ea169
        OPT_BOOL(   'p', NULL, NULL      , _("Add program names to log")),
Packit 8ea169
        OPT_END()
Packit 8ea169
    };
Packit 8ea169
    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
Packit 8ea169
Packit 8ea169
    export_abrt_envvars(opts & OPT_p);
Packit 8ea169
Packit 8ea169
#if 0 /* We no longer use dbus */
Packit 8ea169
    /* When dbus daemon starts us, it doesn't set PATH
Packit 8ea169
     * (I saw it set only DBUS_STARTER_ADDRESS and DBUS_STARTER_BUS_TYPE).
Packit 8ea169
     * In this case, set something sane:
Packit 8ea169
     */
Packit 8ea169
    const char *env_path = getenv("PATH");
Packit 8ea169
    if (!env_path || !env_path[0])
Packit 8ea169
        putenv((char*)"PATH=/usr/sbin:/usr/bin:/sbin:/bin");
Packit 8ea169
#endif
Packit 8ea169
Packit 8ea169
    unsetenv("ABRT_SYSLOG");
Packit 8ea169
    msg_prefix = g_progname; /* for log_warning(), error_msg() and such */
Packit 8ea169
Packit 8ea169
    if (getuid() != 0)
Packit 8ea169
        error_msg_and_die("Must be run as root");
Packit 8ea169
Packit 8ea169
    if (opts & OPT_s)
Packit 8ea169
        start_logging();
Packit 8ea169
Packit 8ea169
    xpipe(s_signal_pipe);
Packit 8ea169
    close_on_exec_on(s_signal_pipe[0]);
Packit 8ea169
    close_on_exec_on(s_signal_pipe[1]);
Packit 8ea169
    ndelay_on(s_signal_pipe[0]); /* I/O should not block - */
Packit 8ea169
    ndelay_on(s_signal_pipe[1]); /* especially writes! they happen in signal handler! */
Packit 8ea169
    signal(SIGTERM, handle_signal);
Packit 8ea169
    signal(SIGINT,  handle_signal);
Packit 8ea169
    signal(SIGCHLD, handle_signal);
Packit 8ea169
Packit 8ea169
    GIOChannel* channel_signal = NULL;
Packit 8ea169
    guint channel_id_signal_event = 0;
Packit 8ea169
    bool pidfile_created = false;
Packit 8ea169
    struct abrt_inotify_watch *aiw = NULL;
Packit 8ea169
    int ret = 1;
Packit 8ea169
Packit 8ea169
    /* Initialization */
Packit 8ea169
    log_notice("Loading settings");
Packit 8ea169
    if (load_abrt_conf() != 0)
Packit 8ea169
        goto init_error;
Packit 8ea169
Packit 8ea169
    /* Moved before daemonization because parent waits for signal from daemon
Packit 8ea169
     * only for short period and time consumed by
Packit 8ea169
     * mark_unprocessed_dump_dirs_not_reportable() is slightly unpredictable.
Packit 8ea169
     */
Packit 8ea169
    sanitize_dump_dir_rights();
Packit 8ea169
    mark_unprocessed_dump_dirs_not_reportable(g_settings_dump_location);
Packit 8ea169
Packit 8ea169
    /* Daemonize unless -d */
Packit 8ea169
    if (!(opts & OPT_d))
Packit 8ea169
    {
Packit 8ea169
        /* forking to background */
Packit 8ea169
        fflush(NULL); /* paranoia */
Packit 8ea169
        pid_t pid = fork();
Packit 8ea169
        if (pid < 0)
Packit 8ea169
        {
Packit 8ea169
            perror_msg_and_die("fork");
Packit 8ea169
        }
Packit 8ea169
        if (pid > 0)
Packit 8ea169
        {
Packit 8ea169
            /* Parent */
Packit 8ea169
            /* Wait for child to notify us via SIGTERM that it feels ok */
Packit 8ea169
            int i = 20; /* 2 sec */
Packit 8ea169
            while (s_sig_caught == 0 && --i)
Packit 8ea169
            {
Packit 8ea169
                usleep(100 * 1000);
Packit 8ea169
            }
Packit 8ea169
            if (s_sig_caught == SIGTERM)
Packit 8ea169
            {
Packit 8ea169
                exit(0);
Packit 8ea169
            }
Packit 8ea169
            if (s_sig_caught)
Packit 8ea169
            {
Packit 8ea169
                error_msg_and_die("Failed to start: got sig %d", s_sig_caught);
Packit 8ea169
            }
Packit 8ea169
            error_msg_and_die("Failed to start: timeout waiting for child");
Packit 8ea169
        }
Packit 8ea169
        /* Child (daemon) continues */
Packit 8ea169
        if (setsid() < 0)
Packit 8ea169
            perror_msg_and_die("setsid");
Packit 8ea169
        if (g_verbose == 0 && logmode != LOGMODE_JOURNAL)
Packit 8ea169
            start_logging();
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    log_notice("Creating glib main loop");
Packit 8ea169
    s_main_loop = g_main_loop_new(NULL, FALSE);
Packit 8ea169
Packit 8ea169
    /* Watching 'g_settings_dump_location' for delete self
Packit 8ea169
     * because hooks expects that the dump location exists if abrtd is running
Packit 8ea169
     */
Packit 8ea169
    aiw = abrt_inotify_watch_init(g_settings_dump_location,
Packit 8ea169
            IN_DUMP_LOCATION_FLAGS, handle_inotify_cb, /*user data*/NULL);
Packit 8ea169
Packit 8ea169
    /* Add an event source which waits for INT/TERM signal */
Packit 8ea169
    log_notice("Adding signal pipe watch to glib main loop");
Packit 8ea169
    channel_signal = abrt_gio_channel_unix_new(s_signal_pipe[0]);
Packit 8ea169
    channel_id_signal_event = add_watch_or_die(channel_signal,
Packit 8ea169
                        G_IO_IN | G_IO_PRI | G_IO_HUP,
Packit 8ea169
                        handle_signal_cb);
Packit 8ea169
Packit 8ea169
    guint name_id = 0;
Packit 8ea169
Packit 8ea169
    /* Mark the territory */
Packit 8ea169
    log_notice("Creating pid file");
Packit 8ea169
    if (create_pidfile() != 0)
Packit 8ea169
        goto init_error;
Packit 8ea169
    pidfile_created = true;
Packit 8ea169
Packit 8ea169
    /* Open socket to receive new problem data (from python etc). */
Packit 8ea169
    dumpsocket_init();
Packit 8ea169
Packit 8ea169
    /* Inform parent that we initialized ok */
Packit 8ea169
    if (!(opts & OPT_d))
Packit 8ea169
    {
Packit 8ea169
        log_notice("Signalling parent");
Packit 8ea169
        kill(parent_pid, SIGTERM);
Packit 8ea169
        if (logmode != LOGMODE_JOURNAL)
Packit 8ea169
            start_logging();
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    /* Only now we want signal pipe to work */
Packit 8ea169
    s_signal_pipe_write = s_signal_pipe[1];
Packit 8ea169
Packit 8ea169
    /* Own a name on D-Bus */
Packit 8ea169
    name_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
Packit 8ea169
                             ABRTD_DBUS_NAME,
Packit 8ea169
                             G_BUS_NAME_OWNER_FLAGS_NONE,
Packit 8ea169
                             on_bus_acquired,
Packit 8ea169
                             on_name_acquired,
Packit 8ea169
                             on_name_lost,
Packit 8ea169
                             NULL, NULL);
Packit 8ea169
Packit 8ea169
    start_idle_timeout();
Packit 8ea169
Packit 8ea169
    /* Enter the event loop */
Packit 8ea169
    log_debug("Init complete, entering main loop");
Packit 8ea169
    g_main_loop_run(s_main_loop);
Packit 8ea169
Packit 8ea169
    ret = 0;
Packit 8ea169
    /* Jump to exit */
Packit 8ea169
    goto cleanup;
Packit 8ea169
Packit 8ea169
Packit 8ea169
 init_error:
Packit 8ea169
    /* Initialization error */
Packit 8ea169
    error_msg("Error while initializing daemon");
Packit 8ea169
    /* Inform parent that initialization failed */
Packit 8ea169
    if (!(opts & OPT_d))
Packit 8ea169
        kill(parent_pid, SIGINT);
Packit 8ea169
Packit 8ea169
Packit 8ea169
 cleanup:
Packit 8ea169
    if (name_id > 0)
Packit 8ea169
        g_bus_unown_name (name_id);
Packit 8ea169
Packit 8ea169
    /* Error or INT/TERM. Clean up, in reverse order.
Packit 8ea169
     * Take care to not undo things we did not do.
Packit 8ea169
     */
Packit 8ea169
    dumpsocket_shutdown();
Packit 8ea169
    if (pidfile_created)
Packit 8ea169
        unlink(VAR_RUN_PIDFILE);
Packit 8ea169
Packit 8ea169
    if (channel_id_signal_event > 0)
Packit 8ea169
        g_source_remove(channel_id_signal_event);
Packit 8ea169
    if (channel_signal)
Packit 8ea169
        g_io_channel_unref(channel_signal);
Packit 8ea169
Packit 8ea169
    abrt_inotify_watch_destroy(aiw);
Packit 8ea169
Packit 8ea169
    if (s_main_loop)
Packit 8ea169
        g_main_loop_unref(s_main_loop);
Packit 8ea169
Packit 8ea169
    free_abrt_conf_data();
Packit 8ea169
Packit 8ea169
    if (s_sig_caught && s_sig_caught != SIGCHLD)
Packit 8ea169
    {
Packit 8ea169
        /* We use TERM to stop abrtd, so not printing out error message. */
Packit 8ea169
        if (s_sig_caught != SIGTERM)
Packit 8ea169
        {
Packit 8ea169
            error_msg("Got signal %d, exiting", s_sig_caught);
Packit 8ea169
            signal(s_sig_caught, SIG_DFL);
Packit 8ea169
            raise(s_sig_caught);
Packit 8ea169
        }
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    /* Exiting */
Packit 8ea169
    log_notice("Exiting");
Packit 8ea169
    return ret;
Packit 8ea169
}