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