Blame SOURCES/0245-daemon-trigger-dump-location-cleanup-after-detection.patch

baab13
From b963494f41fe75463a14c127e9ded5760cb09cec Mon Sep 17 00:00:00 2001
baab13
From: Jakub Filak <jfilak@redhat.com>
baab13
Date: Tue, 19 Jul 2016 20:34:02 +0200
baab13
Subject: [PATCH] daemon: trigger dump location cleanup after detection
baab13
baab13
This commit restores the old behaviour where the cleanup algorithm was
baab13
started right after new dump directory is created. This prevents piling
baab13
up of new dump directories which could lead to consumption of too much
baab13
disk space. The piling up of dump directories is currently prevented by
baab13
the plugins removing old dump directories on their own, which is in fact
baab13
problematic because the plugins don't know about each other and that causes
baab13
race conditions.
baab13
baab13
The post-create EVENT execution was moved from abrtd to abrt-server in
baab13
commit b6640620e27a029b3f1f8dcec22fb4c95e48db2a in order to replace the
baab13
inotify watch in abrtd with the /creation_notification method of
baab13
abrt-server.
baab13
baab13
What are the cases we must deal with
baab13
-----------------------------------
baab13
baab13
1) an old directory is to be removed
baab13
2) one of the queued directory is to be removed
baab13
3) currently processing directory is to be removed
baab13
baab13
The case 1) is not problematic at all (except removing directories that
baab13
are currently being handled by users).
baab13
baab13
The case 2) would cause an error message produced by abrt-handle-event
baab13
waked up from waiting for post-create.lock - the error message could be
baab13
avoided by ignoring the error in case of running post-create EVENT.
baab13
baab13
The case 3) is extremely problematic and must be avoid in all situation.
baab13
There is no other way how to avoid this case without a central
baab13
synchronization algorithm. One could claim that we should lock the
baab13
currently processed dump directory and don't removed the locked ones but
baab13
libreport's locking algorithm doesn't support recursive locking between
baab13
processes - however, the recursive inter process locking would get rid
baab13
of the case 1). Or abrt-handle-event could write the handled directory
baab13
name to a new file but it is not clear where the file would be consumed
baab13
as there is no authority doing the cleanup. And, what is the worst,
baab13
communication trough files will lead to another type race conditions.
baab13
baab13
What this patch introduces
baab13
--------------------------
baab13
baab13
This patch adds communication between abrtd and its child processes
baab13
abrt-server. When abrt-server is asked to run post-create EVENT, it
baab13
sends the "NEW_PROBLEM_DETECTED: $DUMP_DIR" message to abrtd over
baab13
STDERR. STDERR is used because STDOUT is occupied by the socket (we
baab13
might want to make it less obfuscated in future and use a FIFO
baab13
or something else, but now I am happy with using STDERR). abrtd
baab13
then pushes the abrt-server process to a queue used to track abrt-server
baab13
processes wanting to run post-create EVENT. When a process from the
baab13
queue is to be executed abrtd sends it SIGUSR1 signal. If a dump
baab13
directory of any of queued process was removed, abrtd sends the relevant
baab13
abrt-server process SIGINT signal.
baab13
baab13
Resolves #1132459
baab13
baab13
Signed-off-by: Jakub Filak <jfilak@redhat.com>
baab13
baab13
Conflicts:
baab13
	src/daemon/abrt-server.c
baab13
	src/daemon/abrtd.c
baab13
---
baab13
 src/daemon/abrt-server.c | 129 ++++++++++++++++++++
baab13
 src/daemon/abrtd.c       | 303 +++++++++++++++++++++++++++++++++++++++++++++--
baab13
 2 files changed, 420 insertions(+), 12 deletions(-)
baab13
baab13
diff --git a/src/daemon/abrt-server.c b/src/daemon/abrt-server.c
baab13
index afd9fd3..a0faef6 100644
baab13
--- a/src/daemon/abrt-server.c
baab13
+++ b/src/daemon/abrt-server.c
baab13
@@ -16,6 +16,7 @@
baab13
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
baab13
 */
baab13
 #include "problem_api.h"
baab13
+#include "abrt_glib.h"
baab13
 #include "libabrt.h"
baab13
 
baab13
 /* Maximal length of backtrace. */
baab13
@@ -71,10 +72,75 @@ MANDATORY ITEMS:
baab13
 You can send more messages using the same KEY=value format.
baab13
 */
baab13
 
baab13
+static int g_signal_pipe[2];
baab13
+
baab13
+struct waiting_context
baab13
+{
baab13
+    GMainLoop *main_loop;
baab13
+    const char *dirname;
baab13
+    int retcode;
baab13
+    enum abrt_daemon_reply
baab13
+    {
baab13
+        ABRT_CONTINUE,
baab13
+        ABRT_INTERRUPT,
baab13
+    } reply;
baab13
+};
baab13
+
baab13
 static unsigned total_bytes_read = 0;
baab13
 
baab13
 static uid_t client_uid = (uid_t)-1L;
baab13
 
baab13
+static void
baab13
+handle_signal(int signo)
baab13
+{
baab13
+    int save_errno = errno;
baab13
+    uint8_t sig_caught = signo;
baab13
+    if (write(g_signal_pipe[1], &sig_caught, 1))
baab13
+        /* we ignore result, if () shuts up stupid compiler */;
baab13
+    errno = save_errno;
baab13
+}
baab13
+
baab13
+static gboolean
baab13
+handle_signal_pipe_cb(GIOChannel *gio, GIOCondition condition, gpointer user_data)
baab13
+{
baab13
+    gsize len = 0;
baab13
+    uint8_t signals[2];
baab13
+
baab13
+    for (;;)
baab13
+    {
baab13
+        GError *error = NULL;
baab13
+        GIOStatus stat = g_io_channel_read_chars(gio, (void *)signals, sizeof(signals), &len, NULL);
baab13
+        if (stat == G_IO_STATUS_ERROR)
baab13
+            error_msg_and_die(_("Can't read from gio channel: '%s'"), error ? error->message : "");
baab13
+        if (stat == G_IO_STATUS_EOF)
baab13
+            return FALSE; /* Remove this GLib source */
baab13
+        if (stat == G_IO_STATUS_AGAIN)
baab13
+            break;
baab13
+
baab13
+        /* G_IO_STATUS_NORMAL */
baab13
+        for (unsigned signo = 0; signo < len; ++signo)
baab13
+        {
baab13
+            /* we did receive a signal */
baab13
+            struct waiting_context *context = (struct waiting_context *)user_data;
baab13
+            log_debug("Got signal %d through signal pipe", signals[signo]);
baab13
+            switch (signals[signo])
baab13
+            {
baab13
+                case SIGUSR1: context->reply = ABRT_CONTINUE; break;
baab13
+                case SIGINT:  context->reply = ABRT_INTERRUPT; break;
baab13
+                default:
baab13
+                {
baab13
+                    error_msg("Bug - aborting - unsupported signal: %d", signals[signo]);
baab13
+                    abort();
baab13
+                }
baab13
+            }
baab13
+
baab13
+            g_main_loop_quit(context->main_loop);
baab13
+            return FALSE; /* remove this event */
baab13
+        }
baab13
+    }
baab13
+
baab13
+    return TRUE; /* "please don't remove this event" */
baab13
+}
baab13
 
baab13
 /* Remove dump dir */
baab13
 static int delete_path(const char *dump_dir_name)
baab13
@@ -153,6 +219,24 @@ static pid_t spawn_event_handler_child(const char *dump_dir_name, const char *ev
baab13
     return child;
baab13
 }
baab13
 
baab13
+static gboolean emit_new_problem_signal(gpointer data)
baab13
+{
baab13
+    struct waiting_context *context = (struct waiting_context *)data;
baab13
+
baab13
+    const size_t wrote = fprintf(stderr, "NEW_PROBLEM_DETECTED: %s\n", context->dirname);
baab13
+    fflush(stderr);
baab13
+
baab13
+    if (wrote <= 0)
baab13
+    {
baab13
+        error_msg("Failed to communicate with the daemon");
baab13
+        context->retcode = 503;
baab13
+        g_main_loop_quit(context->main_loop);
baab13
+    }
baab13
+
baab13
+    log_notice("Emitted new problem signal, waiting for SIGUSR1|SIGINT");
baab13
+    return FALSE;
baab13
+}
baab13
+
baab13
 static int run_post_create(const char *dirname)
baab13
 {
baab13
     /* If doesn't start with "g_settings_dump_location/"... */
baab13
@@ -179,6 +263,51 @@ static int run_post_create(const char *dirname)
baab13
         }
baab13
     }
baab13
 
baab13
+    /*
baab13
+     * The post-create event cannot be run concurrently for more problem
baab13
+     * directories. The problem is in searching for duplicates process
baab13
+     * in case when two concurrently processed directories are duplicates
baab13
+     * of each other. Both of the directories are marked as duplicates
baab13
+     * of each other and are deleted.
baab13
+     */
baab13
+    log_debug("Creating glib main loop");
baab13
+    struct waiting_context context = {0};
baab13
+    context.main_loop = g_main_loop_new(NULL, FALSE);
baab13
+    context.dirname = dirname;
baab13
+
baab13
+    log_debug("Setting up a signal handler");
baab13
+    /* Set up signal pipe */
baab13
+    xpipe(g_signal_pipe);
baab13
+    close_on_exec_on(g_signal_pipe[0]);
baab13
+    close_on_exec_on(g_signal_pipe[1]);
baab13
+    ndelay_on(g_signal_pipe[0]);
baab13
+    ndelay_on(g_signal_pipe[1]);
baab13
+    signal(SIGUSR1, handle_signal);
baab13
+    signal(SIGINT, handle_signal);
baab13
+    GIOChannel *channel_signal = abrt_gio_channel_unix_new(g_signal_pipe[0]);
baab13
+    g_io_add_watch(channel_signal, G_IO_IN | G_IO_PRI, handle_signal_pipe_cb, &context);
baab13
+
baab13
+    g_idle_add(emit_new_problem_signal, &context);
baab13
+
baab13
+    g_main_loop_run(context.main_loop);
baab13
+
baab13
+    g_main_loop_unref(context.main_loop);
baab13
+    g_io_channel_unref(channel_signal);
baab13
+    close(g_signal_pipe[1]);
baab13
+    close(g_signal_pipe[0]);
baab13
+
baab13
+    log_notice("Waiting finished");
baab13
+
baab13
+    if (context.retcode != 0)
baab13
+        return context.retcode;
baab13
+
baab13
+    if (context.reply != ABRT_CONTINUE)
baab13
+        /* The only reason for the interruption is removed problem directory */
baab13
+        return 413;
baab13
+    /*
baab13
+     * The post-create event synchronization done.
baab13
+     */
baab13
+
baab13
     int child_stdout_fd;
baab13
     int child_pid = spawn_event_handler_child(dirname, "post-create", &child_stdout_fd);
baab13
 
baab13
diff --git a/src/daemon/abrtd.c b/src/daemon/abrtd.c
baab13
index b79e940..ff0565c 100644
baab13
--- a/src/daemon/abrtd.c
baab13
+++ b/src/daemon/abrtd.c
baab13
@@ -55,9 +55,42 @@ static int s_signal_pipe_write = -1;
baab13
 static unsigned s_timeout;
baab13
 static bool s_exiting;
baab13
 
baab13
+GList *s_processes;
baab13
+GList *s_dir_queue;
baab13
+
baab13
 static GIOChannel *channel_socket = NULL;
baab13
 static guint channel_id_socket = 0;
baab13
-static int child_count = 0;
baab13
+
baab13
+struct abrt_server_proc
baab13
+{
baab13
+    pid_t pid;
baab13
+    int fdout;
baab13
+    char *dirname;
baab13
+    GIOChannel *channel;
baab13
+    guint watch_id;
baab13
+    enum {
baab13
+        AS_UKNOWN,
baab13
+        AS_POST_CREATE,
baab13
+    } type;
baab13
+};
baab13
+
baab13
+/* Returns 0 if proc's pid equals the the given pid */
baab13
+static gint abrt_server_compare_pid(struct abrt_server_proc *proc, pid_t *pid)
baab13
+{
baab13
+    return proc->pid != *pid;
baab13
+}
baab13
+
baab13
+/* Returns 0 if proc's fdout equals the the given fdout */
baab13
+static gint abrt_server_compare_fdout(struct abrt_server_proc *proc, int *fdout)
baab13
+{
baab13
+    return proc->fdout != *fdout;
baab13
+}
baab13
+
baab13
+/* Returns 0 if proc's dirname equals the the given dirname */
baab13
+static gint abrt_server_compare_dirname(struct abrt_server_proc *proc, const char *dirname)
baab13
+{
baab13
+    return g_strcmp0(proc->dirname, dirname);
baab13
+}
baab13
 
baab13
 /* Helpers */
baab13
 static guint add_watch_or_die(GIOChannel *channel, unsigned condition, GIOFunc func)
baab13
@@ -69,9 +102,212 @@ static guint add_watch_or_die(GIOChannel *channel, unsigned condition, GIOFunc f
baab13
     return r;
baab13
 }
baab13
 
baab13
-static void increment_child_count(void)
baab13
+static void stop_abrt_server(struct abrt_server_proc *proc)
baab13
+{
baab13
+    kill(proc->pid, SIGINT);
baab13
+}
baab13
+
baab13
+static void dispose_abrt_server(struct abrt_server_proc *proc)
baab13
+{
baab13
+    close(proc->fdout);
baab13
+    free(proc->dirname);
baab13
+
baab13
+    if (proc->watch_id > 0)
baab13
+        g_source_remove(proc->watch_id);
baab13
+
baab13
+    if (proc->channel != NULL)
baab13
+        g_io_channel_unref(proc->channel);
baab13
+}
baab13
+
baab13
+static void notify_next_post_create_process(struct abrt_server_proc *finished)
baab13
+{
baab13
+    if (finished != NULL)
baab13
+        s_dir_queue = g_list_remove(s_dir_queue, finished);
baab13
+
baab13
+    while (s_dir_queue != NULL)
baab13
+    {
baab13
+        struct abrt_server_proc *n = (struct abrt_server_proc *)s_dir_queue->data;
baab13
+        if (n->type == AS_POST_CREATE)
baab13
+            break;
baab13
+
baab13
+        if (kill(n->pid, SIGUSR1) >= 0)
baab13
+        {
baab13
+            n->type = AS_POST_CREATE;
baab13
+            break;
baab13
+        }
baab13
+
baab13
+        /* This could happen only if the notified process disappeared - crashed?
baab13
+         */
baab13
+        perror_msg("Failed to send SIGUSR1 to %d", n->pid);
baab13
+        log_warning("Directory '%s' will not be processed", n->dirname);
baab13
+
baab13
+        /* Remove the problematic process from the post-crate directory queue
baab13
+         * and go to try to notify another process.
baab13
+         */
baab13
+        s_dir_queue = g_list_delete_link(s_dir_queue, s_dir_queue);
baab13
+    }
baab13
+}
baab13
+
baab13
+/* Queueing the process will also lead to cleaning up the dump location.
baab13
+ */
baab13
+static void queue_post_craete_process(struct abrt_server_proc *proc)
baab13
+{
baab13
+    load_abrt_conf();
baab13
+    struct abrt_server_proc *running = s_dir_queue == NULL ? NULL
baab13
+                                                           : (struct abrt_server_proc *)s_dir_queue->data;
baab13
+    if (g_settings_nMaxCrashReportsSize == 0)
baab13
+        goto consider_processing;
baab13
+
baab13
+    const char *full_path_ignored = running != NULL ? running->dirname
baab13
+                                                    : proc->dirname;
baab13
+    const char *ignored = strrchr(full_path_ignored, '/');
baab13
+    if (NULL == ignored)
baab13
+        /* Paranoia, this should not happen. */
baab13
+        ignored = full_path_ignored;
baab13
+    else
baab13
+        /* Move behind '/' */
baab13
+        ++ignored;
baab13
+
baab13
+    char *worst_dir = NULL;
baab13
+    const double max_size = 1024 * 1024 * g_settings_nMaxCrashReportsSize;
baab13
+    while (get_dirsize_find_largest_dir(g_settings_dump_location, &worst_dir, ignored) >= max_size
baab13
+           && worst_dir)
baab13
+    {
baab13
+        const char *kind = "old";
baab13
+        char *deleted = concat_path_file(g_settings_dump_location, worst_dir);
baab13
+
baab13
+        GList *proc_of_deleted_item = NULL;
baab13
+        if (proc != NULL && strcmp(deleted, proc->dirname) == 0)
baab13
+        {
baab13
+            kind = "new";
baab13
+            stop_abrt_server(proc);
baab13
+            proc = NULL;
baab13
+        }
baab13
+        else if ((proc_of_deleted_item = g_list_find_custom(s_dir_queue, deleted, (GCompareFunc)abrt_server_compare_dirname)))
baab13
+        {
baab13
+            kind = "unprocessed";
baab13
+            struct abrt_server_proc *removed_proc = (struct abrt_server_proc *)proc_of_deleted_item->data;
baab13
+            s_dir_queue = g_list_delete_link(s_dir_queue, proc_of_deleted_item);
baab13
+            stop_abrt_server(removed_proc);
baab13
+        }
baab13
+
baab13
+        log("Size of '%s' >= %u MB (MaxCrashReportsSize), deleting %s directory '%s'",
baab13
+                g_settings_dump_location, g_settings_nMaxCrashReportsSize,
baab13
+                kind, worst_dir);
baab13
+
baab13
+        free(worst_dir);
baab13
+        worst_dir = NULL;
baab13
+
baab13
+        struct dump_dir *dd = dd_opendir(deleted, DD_FAIL_QUIETLY_ENOENT);
baab13
+        if (dd != NULL)
baab13
+            dd_delete(dd);
baab13
+
baab13
+        free(deleted);
baab13
+    }
baab13
+
baab13
+consider_processing:
baab13
+    /* If the process survived cleaning up the dump location, append it to the
baab13
+     * post-create queue.
baab13
+     */
baab13
+    if (proc != NULL)
baab13
+        s_dir_queue = g_list_append(s_dir_queue, proc);
baab13
+
baab13
+    /* If there were no running post-crate process before we added the
baab13
+     * currently handled process to the post-create queue, start processing of
baab13
+     * the currently handled process.
baab13
+     */
baab13
+    if (running == NULL)
baab13
+        notify_next_post_create_process(NULL/*finished*/);
baab13
+}
baab13
+
baab13
+static gboolean abrt_server_output_cb(GIOChannel *channel, GIOCondition condition, gpointer user_data)
baab13
+{
baab13
+    int fdout = g_io_channel_unix_get_fd(channel);
baab13
+    GList *item = g_list_find_custom(s_processes, &fdout, (GCompareFunc)abrt_server_compare_fdout);
baab13
+    if (item == NULL)
baab13
+    {
baab13
+        log_warning("Closing a pipe fd (%d) without a process assigned", fdout);
baab13
+        close(fdout);
baab13
+        return FALSE;
baab13
+    }
baab13
+
baab13
+    struct abrt_server_proc *proc = (struct abrt_server_proc *)item->data;
baab13
+
baab13
+    if (condition & G_IO_HUP)
baab13
+    {
baab13
+        log_debug("abrt-server(%d) closed its pipe", proc->pid);
baab13
+        proc->watch_id = 0;
baab13
+        return FALSE;
baab13
+    }
baab13
+
baab13
+    for (;;)
baab13
+    {
baab13
+        gchar *line;
baab13
+        gsize len = 0;
baab13
+        gsize pos = 0;
baab13
+        GError *error = NULL;
baab13
+
baab13
+        /* We use buffered channel so we do not need to read from the channel in a
baab13
+         * loop */
baab13
+        GIOStatus stat = g_io_channel_read_line(channel, &line, &len, &pos, &error);
baab13
+        if (stat == G_IO_STATUS_ERROR)
baab13
+            error_msg_and_die("Can't read from pipe of abrt-server(%d): '%s'", proc->pid, error ? error->message : "");
baab13
+        if (stat == G_IO_STATUS_EOF)
baab13
+        {
baab13
+            log_debug("abrt-server(%d)'s output read till end", proc->pid);
baab13
+            proc->watch_id = 0;
baab13
+            return FALSE; /* Remove this event */
baab13
+        }
baab13
+        if (stat == G_IO_STATUS_AGAIN)
baab13
+            break;
baab13
+
baab13
+        /* G_IO_STATUS_NORMAL) */
baab13
+        line[pos] = '\0';
baab13
+        if (g_str_has_prefix(line, "NEW_PROBLEM_DETECTED: "))
baab13
+        {
baab13
+            if (proc->dirname != NULL)
baab13
+            {
baab13
+                log_warning("abrt-server(%d): already handling: %s", proc->pid, proc->dirname);
baab13
+                free(proc->dirname);
baab13
+                /* Because process can be only once in the dir queue */
baab13
+                s_dir_queue = g_list_remove(s_dir_queue, proc);
baab13
+            }
baab13
+
baab13
+            proc->dirname = xstrdup(line + strlen("NEW_PROBLEM_DETECTED: "));
baab13
+            log_notice("abrt-server(%d): handling new problem: %s", proc->pid, proc->dirname);
baab13
+            queue_post_craete_process(proc);
baab13
+        }
baab13
+        else
baab13
+            log("abrt-server(%d): not recognized message: '%s'", proc->pid, line);
baab13
+
baab13
+        g_free(line);
baab13
+    }
baab13
+
baab13
+    return TRUE; /* Keep this event */
baab13
+}
baab13
+
baab13
+static void add_abrt_server_proc(const pid_t pid, int fdout)
baab13
 {
baab13
-    if (++child_count >= MAX_CLIENT_COUNT)
baab13
+    struct abrt_server_proc *proc = xmalloc(sizeof(*proc));
baab13
+    proc->pid = pid;
baab13
+    proc->fdout = fdout;
baab13
+    proc->dirname = NULL;
baab13
+    proc->type = AS_UKNOWN;
baab13
+    proc->channel = abrt_gio_channel_unix_new(proc->fdout);
baab13
+    proc->watch_id = g_io_add_watch(proc->channel,
baab13
+                                    G_IO_IN | G_IO_HUP,
baab13
+                                    abrt_server_output_cb,
baab13
+                                    proc);
baab13
+
baab13
+    GError *error = NULL;
baab13
+    g_io_channel_set_flags(proc->channel, G_IO_FLAG_NONBLOCK, &error);
baab13
+    if (error != NULL)
baab13
+        error_msg_and_die("g_io_channel_set_flags failed: '%s'", error->message);
baab13
+
baab13
+    g_io_channel_set_buffered(proc->channel, TRUE);
baab13
+
baab13
+    s_processes = g_list_append(s_processes, proc);
baab13
+    if (g_list_length(s_processes) >= MAX_CLIENT_COUNT)
baab13
     {
baab13
         error_msg("Too many clients, refusing connections to '%s'", SOCKET_FILE);
baab13
         /* To avoid infinite loop caused by the descriptor in "ready" state,
baab13
@@ -84,11 +320,29 @@ static void increment_child_count(void)
baab13
 
baab13
 static gboolean server_socket_cb(GIOChannel *source, GIOCondition condition, gpointer ptr_unused);
baab13
 
baab13
-static void decrement_child_count(void)
baab13
+static void remove_abrt_server_proc(pid_t pid, int status)
baab13
 {
baab13
-    if (child_count)
baab13
-        child_count--;
baab13
-    if (child_count < MAX_CLIENT_COUNT && !channel_id_socket)
baab13
+    GList *item = g_list_find_custom(s_processes, &pid, (GCompareFunc)abrt_server_compare_pid);
baab13
+    if (item == NULL)
baab13
+        return;
baab13
+
baab13
+    struct abrt_server_proc *proc = (struct abrt_server_proc *)item->data;
baab13
+    item->data = NULL;
baab13
+    s_processes = g_list_delete_link(s_processes, item);
baab13
+
baab13
+    if (proc->type == AS_POST_CREATE)
baab13
+        notify_next_post_create_process(proc);
baab13
+    else
baab13
+    {   /* Make sure out-of-order exited abrt-server post-create processes do
baab13
+         * not stay in the post-create queue.
baab13
+         */
baab13
+        s_dir_queue = g_list_remove(s_dir_queue, proc);
baab13
+    }
baab13
+
baab13
+    dispose_abrt_server(proc);
baab13
+    free(proc);
baab13
+
baab13
+    if (g_list_length(s_processes) < MAX_CLIENT_COUNT && !channel_id_socket)
baab13
     {
baab13
         log_info("Accepting connections on '%s'", SOCKET_FILE);
baab13
         channel_id_socket = add_watch_or_die(channel_socket, G_IO_IN | G_IO_PRI | G_IO_HUP, server_socket_cb);
baab13
@@ -107,17 +361,27 @@ static gboolean server_socket_cb(GIOChannel *source, GIOCondition condition, gpo
baab13
 
baab13
     log_notice("New client connected");
baab13
     fflush(NULL); /* paranoia */
baab13
+
baab13
+    int pipefd[2];
baab13
+    xpipe(pipefd);
baab13
+
baab13
     pid_t pid = fork();
baab13
     if (pid < 0)
baab13
     {
baab13
         perror_msg("fork");
baab13
+        close(pipefd[0]);
baab13
+        close(pipefd[1]);
baab13
         close(socket);
baab13
         return TRUE;
baab13
     }
baab13
     if (pid == 0) /* child */
baab13
     {
baab13
-        xmove_fd(socket, 0);
baab13
-        xdup2(0, 1);
baab13
+        xdup2(socket, STDIN_FILENO);
baab13
+        xdup2(socket, STDOUT_FILENO);
baab13
+        close(socket);
baab13
+
baab13
+        close(pipefd[0]);
baab13
+        xmove_fd(pipefd[1], STDERR_FILENO);
baab13
 
baab13
         char *argv[3];  /* abrt-server [-s] NULL */
baab13
         char **pp = argv;
baab13
@@ -129,9 +393,12 @@ static gboolean server_socket_cb(GIOChannel *source, GIOCondition condition, gpo
baab13
         execvp(argv[0], argv);
baab13
         perror_msg_and_die("Can't execute '%s'", argv[0]);
baab13
     }
baab13
+
baab13
     /* parent */
baab13
-    increment_child_count();
baab13
     close(socket);
baab13
+    close(pipefd[1]);
baab13
+    add_abrt_server_proc(pid, pipefd[0]);
baab13
+
baab13
     return TRUE;
baab13
 }
baab13
 
baab13
@@ -149,9 +416,21 @@ static gboolean handle_signal_cb(GIOChannel *gio, GIOCondition condition, gpoint
baab13
             s_exiting = 1;
baab13
         else
baab13
         {
baab13
-            while (safe_waitpid(-1, NULL, WNOHANG) > 0)
baab13
+            pid_t cpid;
baab13
+            int status;
baab13
+            while ((cpid = safe_waitpid(-1, &status, WNOHANG)) > 0)
baab13
             {
baab13
-                decrement_child_count();
baab13
+                if (WIFSIGNALED(status))
baab13
+                    log_debug("abrt-server(%d) signaled with %d", cpid, WTERMSIG(status));
baab13
+                else if (WIFEXITED(status))
baab13
+                    log_debug("abrt-server(%d) exited with %d", cpid, WEXITSTATUS(status));
baab13
+                else
baab13
+                {
baab13
+                    log_debug("abrt-server(%d) is being debugged", cpid);
baab13
+                    continue;
baab13
+                }
baab13
+
baab13
+                remove_abrt_server_proc(cpid, status);
baab13
             }
baab13
         }
baab13
     }
baab13
-- 
baab13
1.8.3.1
baab13