diff options
-rw-r--r-- | common/Makefile.am | 2 | ||||
-rw-r--r-- | common/gdm-signal-handler.c | 265 | ||||
-rw-r--r-- | common/gdm-signal-handler.h | 66 | ||||
-rw-r--r-- | daemon/gdm-display-store.c | 4 | ||||
-rw-r--r-- | daemon/gdm-display-store.h | 4 | ||||
-rw-r--r-- | daemon/gdm-display.c | 22 | ||||
-rw-r--r-- | daemon/gdm-greeter.c | 91 | ||||
-rw-r--r-- | daemon/gdm-manager.c | 32 | ||||
-rw-r--r-- | daemon/gdm-manager.h | 5 | ||||
-rw-r--r-- | daemon/gdm-server.c | 141 | ||||
-rw-r--r-- | daemon/gdm-slave-proxy.c | 16 | ||||
-rw-r--r-- | daemon/gdm-slave.c | 14 | ||||
-rw-r--r-- | daemon/main.c | 133 | ||||
-rw-r--r-- | daemon/slave-main.c | 106 |
14 files changed, 812 insertions, 89 deletions
diff --git a/common/Makefile.am b/common/Makefile.am index cc6b0e11..dd9d1218 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -38,6 +38,8 @@ libgdmcommon_a_SOURCES = \ gdm-config.c \ gdm-log.h \ gdm-log.c \ + gdm-signal-handler.h \ + gdm-signal-handler.c \ ve-signal.h \ ve-signal.c \ $(NULL) diff --git a/common/gdm-signal-handler.c b/common/gdm-signal-handler.c new file mode 100644 index 00000000..401bc2fb --- /dev/null +++ b/common/gdm-signal-handler.c @@ -0,0 +1,265 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> + +#include <glib.h> +#include <glib/gi18n.h> +#include <glib-object.h> + +#include "gdm-signal-handler.h" + +#define GDM_SIGNAL_HANDLER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_SIGNAL_HANDLER, GdmSignalHandlerPrivate)) + +typedef struct { + GdmSignalHandlerFunc func; + gpointer data; +} CallbackData; + +struct GdmSignalHandlerPrivate +{ + GMainLoop *main_loop; + GHashTable *lookup; +}; + +static void gdm_signal_handler_class_init (GdmSignalHandlerClass *klass); +static void gdm_signal_handler_init (GdmSignalHandler *signal_handler); +static void gdm_signal_handler_finalize (GObject *object); + +static gpointer signal_handler_object = NULL; +static int signal_pipes[2]; +static int signals_blocked = 0; +static sigset_t signals_block_mask; +static sigset_t signals_oldmask; + +G_DEFINE_TYPE (GdmSignalHandler, gdm_signal_handler, G_TYPE_OBJECT) + +static void +block_signals_push (void) +{ + signals_blocked++; + + if (signals_blocked == 1) { + /* Set signal mask */ + sigemptyset (&signals_block_mask); + sigfillset (&signals_block_mask); + sigprocmask (SIG_BLOCK, &signals_block_mask, &signals_oldmask); + } +} + +static void +block_signals_pop (void) +{ + signals_blocked--; + + if (signals_blocked == 0) { + /* Set signal mask */ + sigprocmask (SIG_SETMASK, &signals_oldmask, NULL); + } +} + +static gboolean +signal_io_watch (GIOChannel *ioc, + GIOCondition condition, + GdmSignalHandler *handler) +{ + char buf[256]; + gboolean is_fatal; + gsize bytes_read; + int i; + + block_signals_push (); + + g_io_channel_read_chars (ioc, buf, sizeof (buf), &bytes_read, NULL); + + is_fatal = FALSE; + + g_debug ("Read %d chars", (int)bytes_read); + + for (i = 0; i < bytes_read; i++) { + int signum; + GSList *handlers; + GSList *l; + + signum = (gint32)buf[i]; + + g_debug ("handling signal %d", signum); + handlers = g_hash_table_lookup (handler->priv->lookup, GINT_TO_POINTER (signum)); + + g_debug ("Found %u callbacks", g_slist_length (handlers)); + for (l = handlers; l != NULL; l = l->next) { + gboolean res; + CallbackData *data; + + data = l->data; + g_debug ("running %d handler: %p", signum, data->func); + res = data->func (signum, data->data); + if (! res) { + is_fatal = TRUE; + } + } + } + + block_signals_pop (); + + if (is_fatal) { + g_debug ("Caught termination signal - exiting main loop"); + g_main_loop_quit (handler->priv->main_loop); + return FALSE; + } + + g_debug ("Done handling signals"); + + return TRUE; +} + +static void +signal_handler (int signo) +{ + int ignore; + + /* FIXME: should probably use int32 here */ + ignore = write (signal_pipes [1], (guchar *)&signo, 1); +} + +static void +catch_signal (GdmSignalHandler *handler, + int signal_number) +{ + struct sigaction action; + + action.sa_handler = signal_handler; + sigemptyset (&action.sa_mask); + action.sa_flags = 0; + + /* FIXME: save old action? */ + sigaction (signal_number, &action, NULL); +} + +void +gdm_signal_handler_add (GdmSignalHandler *handler, + int signal_number, + GdmSignalHandlerFunc callback, + gpointer data) +{ + CallbackData *cdata; + GSList *list; + + g_return_if_fail (GDM_IS_SIGNAL_HANDLER (handler)); + + cdata = g_new0 (CallbackData, 1); + cdata->func = callback; + cdata->data = data; + + list = g_hash_table_lookup (handler->priv->lookup, GINT_TO_POINTER (signal_number)); + if (list == NULL) { + catch_signal (handler, signal_number); + } + + list = g_slist_prepend (list, cdata); + g_debug ("Inserting %d callback %p", signal_number, cdata->func); + g_hash_table_insert (handler->priv->lookup, GINT_TO_POINTER (signal_number), list); +} + +static void +gdm_signal_handler_class_init (GdmSignalHandlerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gdm_signal_handler_finalize; + + g_type_class_add_private (klass, sizeof (GdmSignalHandlerPrivate)); +} + +static void +signal_list_free (GSList *list) +{ + g_slist_foreach (list, (GFunc)g_free, NULL); + g_slist_free (list); +} + +void +gdm_signal_handler_set_main_loop (GdmSignalHandler *handler, + GMainLoop *main_loop) +{ + g_return_if_fail (GDM_IS_SIGNAL_HANDLER (handler)); + + /* FIXME: take a ref */ + handler->priv->main_loop = main_loop; +} + +static void +gdm_signal_handler_init (GdmSignalHandler *handler) +{ + GIOChannel *ioc; + + handler->priv = GDM_SIGNAL_HANDLER_GET_PRIVATE (handler); + + handler->priv->lookup = g_hash_table_new (NULL, NULL); + + if (pipe (signal_pipes) == -1) { + g_error ("Could not create pipe() for signal handling"); + } + + ioc = g_io_channel_unix_new (signal_pipes[0]); + g_io_channel_set_flags (ioc, G_IO_FLAG_NONBLOCK, NULL); + g_io_add_watch (ioc, G_IO_IN, (GIOFunc)signal_io_watch, handler); + g_io_channel_set_close_on_unref (ioc, TRUE); + g_io_channel_unref (ioc); +} + +static void +gdm_signal_handler_finalize (GObject *object) +{ + GdmSignalHandler *handler; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDM_IS_SIGNAL_HANDLER (object)); + + handler = GDM_SIGNAL_HANDLER (object); + + g_return_if_fail (handler->priv != NULL); + + /* FIXME: free hash lists */ + g_hash_table_destroy (handler->priv->lookup); + + G_OBJECT_CLASS (gdm_signal_handler_parent_class)->finalize (object); +} + +GdmSignalHandler * +gdm_signal_handler_new (void) +{ + if (signal_handler_object != NULL) { + g_object_ref (signal_handler_object); + } else { + signal_handler_object = g_object_new (GDM_TYPE_SIGNAL_HANDLER, NULL); + g_object_add_weak_pointer (signal_handler_object, + (gpointer *) &signal_handler_object); + } + + return GDM_SIGNAL_HANDLER (signal_handler_object); +} diff --git a/common/gdm-signal-handler.h b/common/gdm-signal-handler.h new file mode 100644 index 00000000..43e5808b --- /dev/null +++ b/common/gdm-signal-handler.h @@ -0,0 +1,66 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + + +#ifndef __GDM_SIGNAL_HANDLER_H +#define __GDM_SIGNAL_HANDLER_H + +#include <glib-object.h> + +G_BEGIN_DECLS + +#define GDM_TYPE_SIGNAL_HANDLER (gdm_signal_handler_get_type ()) +#define GDM_SIGNAL_HANDLER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_SIGNAL_HANDLER, GdmSignalHandler)) +#define GDM_SIGNAL_HANDLER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_SIGNAL_HANDLER, GdmSignalHandlerClass)) +#define GDM_IS_SIGNAL_HANDLER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_SIGNAL_HANDLER)) +#define GDM_IS_SIGNAL_HANDLER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_SIGNAL_HANDLER)) +#define GDM_SIGNAL_HANDLER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_SIGNAL_HANDLER, GdmSignalHandlerClass)) + + +typedef gboolean (*GdmSignalHandlerFunc) (int signal, + gpointer data); + +typedef struct GdmSignalHandlerPrivate GdmSignalHandlerPrivate; + +typedef struct +{ + GObject parent; + GdmSignalHandlerPrivate *priv; +} GdmSignalHandler; + +typedef struct +{ + GObjectClass parent_class; +} GdmSignalHandlerClass; + +GType gdm_signal_handler_get_type (void); + +GdmSignalHandler * gdm_signal_handler_new (void); +void gdm_signal_handler_set_main_loop (GdmSignalHandler *handler, + GMainLoop *main_loop); + +void gdm_signal_handler_add (GdmSignalHandler *handler, + int signal_number, + GdmSignalHandlerFunc callback, + gpointer data); + +G_END_DECLS + +#endif /* __GDM_SIGNAL_HANDLER_H */ diff --git a/daemon/gdm-display-store.c b/daemon/gdm-display-store.c index f6b469f7..f636bea1 100644 --- a/daemon/gdm-display-store.c +++ b/daemon/gdm-display-store.c @@ -68,6 +68,7 @@ gdm_display_store_error_quark (void) void gdm_display_store_clear (GdmDisplayStore *store) { + g_debug ("Clearing display store"); g_hash_table_remove_all (store->priv->displays); } @@ -177,7 +178,8 @@ gdm_display_store_class_init (GdmDisplayStoreClass *klass) static void display_unref (GdmDisplay *display) { - /* nothing yet */ + g_debug ("Unreffing display"); + g_object_unref (display); } static void diff --git a/daemon/gdm-display-store.h b/daemon/gdm-display-store.h index 1c7f78bc..1d014466 100644 --- a/daemon/gdm-display-store.h +++ b/daemon/gdm-display-store.h @@ -47,9 +47,9 @@ typedef struct GObjectClass parent_class; void (* display_added) (GdmDisplayStore *display_store, - GdmDisplay *display); + const char *id); void (* display_removed) (GdmDisplayStore *display_store, - GdmDisplay *display); + const char *id); } GdmDisplayStoreClass; typedef enum diff --git a/daemon/gdm-display.c b/daemon/gdm-display.c index 612396ee..5855f0bb 100644 --- a/daemon/gdm-display.c +++ b/daemon/gdm-display.c @@ -184,7 +184,7 @@ gdm_display_real_manage (GdmDisplay *display) { g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE); - g_debug ("Manage display"); + g_debug ("GdmDisplay manage display"); display->priv->status = GDM_DISPLAY_MANAGED; @@ -203,6 +203,8 @@ gdm_display_manage (GdmDisplay *display) g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE); + g_debug ("Unmanaging display"); + g_object_ref (display); ret = GDM_DISPLAY_GET_CLASS (display)->manage (display); g_object_unref (display); @@ -217,6 +219,8 @@ gdm_display_real_unmanage (GdmDisplay *display) display->priv->status = GDM_DISPLAY_UNMANAGED; + g_debug ("GdmDisplay unmanage display"); + if (display->priv->slave_proxy != NULL) { gdm_slave_proxy_stop (display->priv->slave_proxy); @@ -234,6 +238,8 @@ gdm_display_unmanage (GdmDisplay *display) g_return_val_if_fail (GDM_IS_DISPLAY (display), FALSE); + g_debug ("Unmanaging display"); + g_object_ref (display); ret = GDM_DISPLAY_GET_CLASS (display)->unmanage (display); g_object_unref (display); @@ -477,6 +483,19 @@ gdm_display_constructor (GType type, } static void +gdm_display_dispose (GObject *object) +{ + GdmDisplay *display; + + display = GDM_DISPLAY (object); + + g_debug ("Disposing display"); + gdm_display_unmanage (display); + + G_OBJECT_CLASS (gdm_display_parent_class)->dispose (object); +} + +static void gdm_display_class_init (GdmDisplayClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); @@ -484,6 +503,7 @@ gdm_display_class_init (GdmDisplayClass *klass) object_class->get_property = gdm_display_get_property; object_class->set_property = gdm_display_set_property; object_class->constructor = gdm_display_constructor; + object_class->dispose = gdm_display_dispose; object_class->finalize = gdm_display_finalize; klass->create_authority = gdm_display_real_create_authority; diff --git a/daemon/gdm-greeter.c b/daemon/gdm-greeter.c index 1c10e847..e8c78ed2 100644 --- a/daemon/gdm-greeter.c +++ b/daemon/gdm-greeter.c @@ -86,14 +86,6 @@ static void gdm_greeter_finalize (GObject *object); G_DEFINE_TYPE (GdmGreeter, gdm_greeter, G_TYPE_OBJECT) -gboolean -gdm_greeter_stop (GdmGreeter *greeter) -{ - g_debug ("Stopping greeter"); - - return TRUE; -} - static void change_user (GdmGreeter *greeter) { @@ -1014,6 +1006,87 @@ gdm_greeter_start (GdmGreeter *greeter) return res; } +static int +signal_pid (int pid, + int signal) +{ + int status = -1; + + /* perhaps block sigchld */ + + status = kill (pid, signal); + + if (status < 0) { + if (errno == ESRCH) { + g_warning ("Child process %lu was already dead.", + (unsigned long) pid); + } else { + g_warning ("Couldn't kill child process %lu: %s", + (unsigned long) pid, + g_strerror (errno)); + } + } + + /* perhaps unblock sigchld */ + + return status; +} + +static int +wait_on_child (int pid) +{ + int status; + + wait_again: + if (waitpid (pid, &status, 0) < 0) { + if (errno == EINTR) { + goto wait_again; + } else if (errno == ECHILD) { + ; /* do nothing, child already reaped */ + } else { + g_debug ("waitpid () should not fail"); + } + } + + return status; +} + +static void +greeter_died (GdmGreeter *greeter) +{ + int exit_status; + + g_debug ("Waiting on process %d", greeter->priv->pid); + exit_status = wait_on_child (greeter->priv->pid); + + if (WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) != 0)) { + g_debug ("Wait on child process failed"); + } else { + /* exited normally */ + } + + g_spawn_close_pid (greeter->priv->pid); + greeter->priv->pid = -1; + + g_debug ("Greeter died"); +} + +gboolean +gdm_greeter_stop (GdmGreeter *greeter) +{ + + if (greeter->priv->pid <= 1) { + return TRUE; + } + + g_debug ("Stopping greeter"); + + signal_pid (greeter->priv->pid, SIGTERM); + greeter_died (greeter); + + return TRUE; +} + static void _gdm_greeter_set_display_name (GdmGreeter *greeter, @@ -1131,6 +1204,8 @@ gdm_greeter_finalize (GObject *object) g_return_if_fail (greeter->priv != NULL); + gdm_greeter_stop (greeter); + G_OBJECT_CLASS (gdm_greeter_parent_class)->finalize (object); } diff --git a/daemon/gdm-manager.c b/daemon/gdm-manager.c index 9d0f0510..443108c5 100644 --- a/daemon/gdm-manager.c +++ b/daemon/gdm-manager.c @@ -71,6 +71,14 @@ struct GdmManagerPrivate DBusGConnection *connection; }; +enum { + DISPLAY_ADDED, + DISPLAY_REMOVED, + LAST_SIGNAL +}; + +static guint signals [LAST_SIGNAL] = { 0, }; + static void gdm_manager_class_init (GdmManagerClass *klass); static void gdm_manager_init (GdmManager *manager); static void gdm_manager_finalize (GObject *object); @@ -214,6 +222,9 @@ load_static_displays_from_file (GdmManager *manager) } gdm_display_store_add (manager->priv->display_store, display); + + /* let store own the ref */ + g_object_unref (display); } } @@ -358,6 +369,27 @@ gdm_manager_class_init (GdmManagerClass *klass) object_class->finalize = gdm_manager_finalize; + signals [DISPLAY_ADDED] = + g_signal_new ("display-added", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdmManagerClass, display_added), + NULL, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, G_TYPE_STRING); + signals [DISPLAY_REMOVED] = + g_signal_new ("display-removed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdmManagerClass, display_removed), + NULL, + NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, G_TYPE_STRING); + g_type_class_add_private (klass, sizeof (GdmManagerPrivate)); dbus_g_object_type_install_info (GDM_TYPE_MANAGER, &dbus_glib_gdm_manager_object_info); diff --git a/daemon/gdm-manager.h b/daemon/gdm-manager.h index 5dd091d9..99187b77 100644 --- a/daemon/gdm-manager.h +++ b/daemon/gdm-manager.h @@ -44,6 +44,11 @@ typedef struct typedef struct { GObjectClass parent_class; + + void (* display_added) (GdmManager *manager, + const char *id); + void (* display_removed) (GdmManager *manager, + const char *id); } GdmManagerClass; typedef enum diff --git a/daemon/gdm-server.c b/daemon/gdm-server.c index 6f14737b..0d0eea7f 100644 --- a/daemon/gdm-server.c +++ b/daemon/gdm-server.c @@ -39,6 +39,7 @@ #include <X11/Xlib.h> /* for Display */ #include "gdm-common.h" +#include "gdm-signal-handler.h" #include "gdm-server.h" @@ -103,58 +104,37 @@ static void gdm_server_finalize (GObject *object); G_DEFINE_TYPE (GdmServer, gdm_server, G_TYPE_OBJECT) -/* copied from nautilus */ -static int ready_pipes[2]; - static gboolean -ready_io_cb (GIOChannel *io, - GIOCondition condition, - GdmServer *server) +emit_ready_idle (GdmServer *server) { - char a; - - while (read (ready_pipes[0], &a, 1) != 1) - ; - g_debug ("Got USR1 from X server - emitting READY"); g_signal_emit (server, signals[READY], 0); - - return TRUE; + return FALSE; } -static void -sigusr1_handler (int sig) -{ - while (write (ready_pipes[1], "a", 1) != 1) - ; -} -static void -setup_ready_signal (GdmServer *server) -{ - struct sigaction sa; - GIOChannel *io; - - if (pipe (ready_pipes) == -1) { - g_error ("Could not create pipe() for ready signal"); - } +static gboolean +signal_cb (int signo, + GdmServer *server) - io = g_io_channel_unix_new (ready_pipes[0]); - g_io_add_watch (io, G_IO_IN, (GIOFunc)ready_io_cb, server); +{ + g_idle_add ((GSourceFunc)emit_ready_idle, server); - sa.sa_handler = sigusr1_handler; - sigemptyset (&sa.sa_mask); - sa.sa_flags = 0; - sigaction (SIGUSR1, &sa, NULL); + return TRUE; } -gboolean -gdm_server_stop (GdmServer *server) +static void +setup_ready_signal (GdmServer *server) { - g_debug ("Stopping server"); - - return TRUE; + GdmSignalHandler *signal_handler; + + signal_handler = gdm_signal_handler_new (); + gdm_signal_handler_add (signal_handler, + SIGUSR1, + (GdmSignalHandlerFunc)signal_cb, + server); + g_object_unref (signal_handler); } /* We keep a connection (parent_dsp) open with the parent X server @@ -647,6 +627,87 @@ gdm_server_start (GdmServer *server) return res; } +static int +signal_pid (int pid, + int signal) +{ + int status = -1; + + /* perhaps block sigchld */ + + status = kill (pid, signal); + + if (status < 0) { + if (errno == ESRCH) { + g_warning ("Child process %lu was already dead.", + (unsigned long) pid); + } else { + g_warning ("Couldn't kill child process %lu: %s", + (unsigned long) pid, + g_strerror (errno)); + } + } + + /* perhaps unblock sigchld */ + + return status; +} + +static int +wait_on_child (int pid) +{ + int status; + + wait_again: + if (waitpid (pid, &status, 0) < 0) { + if (errno == EINTR) { + goto wait_again; + } else if (errno == ECHILD) { + ; /* do nothing, child already reaped */ + } else { + g_debug ("waitpid () should not fail"); + } + } + + return status; +} + +static void +server_died (GdmServer *server) +{ + int exit_status; + + g_debug ("Waiting on process %d", server->priv->pid); + exit_status = wait_on_child (server->priv->pid); + + if (WIFEXITED (exit_status) && (WEXITSTATUS (exit_status) != 0)) { + g_debug ("Wait on child process failed"); + } else { + /* exited normally */ + } + + g_spawn_close_pid (server->priv->pid); + server->priv->pid = -1; + + g_debug ("Server died"); +} + +gboolean +gdm_server_stop (GdmServer *server) +{ + if (server->priv->pid <= 1) { + return TRUE; + } + + g_debug ("Stopping server"); + + signal_pid (server->priv->pid, SIGTERM); + server_died (server); + + return TRUE; +} + + static void _gdm_server_set_display_name (GdmServer *server, const char *name) @@ -768,6 +829,8 @@ gdm_server_finalize (GObject *object) g_return_if_fail (server->priv != NULL); + gdm_server_stop (server); + G_OBJECT_CLASS (gdm_server_parent_class)->finalize (object); } diff --git a/daemon/gdm-slave-proxy.c b/daemon/gdm-slave-proxy.c index 3b3f1dab..961d88da 100644 --- a/daemon/gdm-slave-proxy.c +++ b/daemon/gdm-slave-proxy.c @@ -83,6 +83,10 @@ slave_died (GdmSlaveProxy *slave) { int exit_status; + if (slave->priv->pid < 0) { + return; + } + g_debug ("Waiting on process %d", slave->priv->pid); exit_status = wait_on_child (slave->priv->pid); @@ -288,6 +292,7 @@ signal_pid (int pid, int status = -1; /* perhaps block sigchld */ + g_debug ("Killing pid %d", pid); status = kill (pid, signal); @@ -315,8 +320,7 @@ kill_slave (GdmSlaveProxy *slave) } signal_pid (slave->priv->pid, SIGTERM); - - /* watch should call slave_died */ + slave_died (slave); } gboolean @@ -330,7 +334,15 @@ gdm_slave_proxy_start (GdmSlaveProxy *slave) gboolean gdm_slave_proxy_stop (GdmSlaveProxy *slave) { + g_debug ("Killing slave"); + kill_slave (slave); + if (slave->priv->output_watch_id > 0) { + g_source_remove (slave->priv->output_watch_id); + } + if (slave->priv->error_watch_id > 0) { + g_source_remove (slave->priv->error_watch_id); + } return TRUE; } diff --git a/daemon/gdm-slave.c b/daemon/gdm-slave.c index ed4552ed..797de0d6 100644 --- a/daemon/gdm-slave.c +++ b/daemon/gdm-slave.c @@ -813,6 +813,18 @@ gdm_slave_stop (GdmSlave *slave) { g_debug ("Stopping slave"); + if (slave->priv->greeter != NULL) { + gdm_greeter_stop (slave->priv->greeter); + g_object_unref (slave->priv->greeter); + slave->priv->greeter = NULL; + } + + if (slave->priv->server != NULL) { + gdm_server_stop (slave->priv->server); + g_object_unref (slave->priv->server); + slave->priv->server = NULL; + } + if (slave->priv->display_proxy != NULL) { g_object_unref (slave->priv->display_proxy); } @@ -965,6 +977,8 @@ gdm_slave_finalize (GObject *object) g_return_if_fail (slave->priv != NULL); + gdm_slave_stop (slave); + G_OBJECT_CLASS (gdm_slave_parent_class)->finalize (object); } diff --git a/daemon/main.c b/daemon/main.c index d47a10f5..38c82f67 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -44,6 +44,7 @@ #include "gdm-manager.h" #include "gdm-log.h" +#include "gdm-signal-handler.h" #include "gdm-master-config.h" #include "gdm-daemon-config-entries.h" @@ -445,35 +446,97 @@ gdm_daemon_change_user (uid_t *uidp, g_free (groupname); } -static void -setup_signal_handlers (void) +static gboolean +signal_cb (int signo, + gpointer data) { - /* FIXME */ + int ret; + + g_debug ("Got callback for signal %d", signo); + + ret = TRUE; + + switch (signo) { + case SIGSEGV: + case SIGBUS: + case SIGILL: + case SIGABRT: + g_debug ("Caught signal %d.", signo); + + ret = FALSE; + break; + + case SIGFPE: + case SIGPIPE: + /* let the fatal signals interrupt us */ + g_debug ("Caught signal %d, shutting down abnormally.", signo); + ret = FALSE; + + break; + + case SIGINT: + case SIGTERM: + /* let the fatal signals interrupt us */ + g_debug ("Caught signal %d, shutting down normally.", signo); + ret = FALSE; + + break; + + case SIGHUP: + g_debug ("Got HUP signal"); + /* FIXME: + * Reread config stuff like system config files, VPN service files, etc + */ + ret = TRUE; + + break; + + case SIGUSR1: + g_debug ("Got USR1 signal"); + /* FIXME: + * Play with log levels or something + */ + ret = TRUE; + break; + + default: + g_debug ("Caught unhandled signal %d", signo); + ret = TRUE; + + break; + } + + return ret; } int main (int argc, char **argv) { - GMainLoop *loop; - GOptionContext *context; - DBusGProxy *bus_proxy; - DBusGConnection *connection; - int ret; - int i; - gboolean debug; + GMainLoop *main_loop; + GOptionContext *context; + DBusGProxy *bus_proxy; + DBusGConnection *connection; + GError *error; + int ret; + int i; + gboolean res; + gboolean debug; + GdmSignalHandler *signal_handler; static char *config_file = NULL; static gboolean no_daemon = FALSE; static gboolean no_console = FALSE; static gboolean do_timed_exit = FALSE; static gboolean print_version = FALSE; + static gboolean fatal_warnings = FALSE; static GOptionEntry entries [] = { { "config", 0, 0, G_OPTION_ARG_STRING, &config_file, N_("Alternative GDM System Defaults configuration file"), N_("CONFIGFILE") }, - { "nodaemon", 0, 0, G_OPTION_ARG_NONE, &no_daemon, N_("Don't become a daemon"), NULL }, + { "no-daemon", 0, 0, G_OPTION_ARG_NONE, &no_daemon, N_("Don't become a daemon"), NULL }, { "no-console", 0, 0, G_OPTION_ARG_NONE, &no_console, N_("No console (static) servers to be run"), NULL }, { "timed-exit", 0, 0, G_OPTION_ARG_NONE, &do_timed_exit, N_("Exit after a time - for debugging"), NULL }, + { "fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &fatal_warnings, N_("Make all warnings fatal"), NULL }, { "version", 0, 0, G_OPTION_ARG_NONE, &print_version, N_("Print GDM version"), NULL }, { NULL } @@ -497,12 +560,27 @@ main (int argc, * option */ for (i = 0; i < argc; i++) { - if (strcmp (argv[i], "-nodaemon") == 0) - argv[i] = (char *) "--nodaemon"; + if (strcmp (argv[i], "-nodaemon") == 0) { + argv[i] = (char *) "--no-daemon"; + } } - g_option_context_parse (context, &argc, &argv, NULL); + error = NULL; + res = g_option_context_parse (context, &argc, &argv, &error); g_option_context_free (context); + if (! res) { + g_warning ("%s", error->message); + g_error_free (error); + goto out; + } + + if (fatal_warnings) { + GLogLevelFlags fatal_mask; + + fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK); + fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL; + g_log_set_always_fatal (fatal_mask); + } if (! no_daemon && daemon (0, 0)) { g_error ("Could not daemonize: %s", g_strerror (errno)); @@ -556,8 +634,6 @@ main (int argc, g_mkdir (SDTLOGIN_DIR, 0700); #endif - setup_signal_handlers (); - manager = gdm_manager_new (); if (manager == NULL) { @@ -569,24 +645,41 @@ main (int argc, G_CALLBACK (bus_proxy_destroyed_cb), manager); - loop = g_main_loop_new (NULL, FALSE); + main_loop = g_main_loop_new (NULL, FALSE); + + signal_handler = gdm_signal_handler_new (); + gdm_signal_handler_set_main_loop (signal_handler, main_loop); + gdm_signal_handler_add (signal_handler, SIGTERM, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGINT, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGILL, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGBUS, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGFPE, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGHUP, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGSEGV, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGABRT, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGUSR1, signal_cb, NULL); if (do_timed_exit) { - g_timeout_add (1000 * 30, (GSourceFunc) timed_exit_cb, loop); + g_timeout_add (1000 * 30, (GSourceFunc) timed_exit_cb, main_loop); } gdm_manager_start (manager); - g_main_loop_run (loop); + g_main_loop_run (main_loop); if (manager != NULL) { g_object_unref (manager); } + if (daemon_config != NULL) { g_object_unref (daemon_config); } - g_main_loop_unref (loop); + if (signal_handler != NULL) { + g_object_unref (signal_handler); + } + + g_main_loop_unref (main_loop); ret = 0; diff --git a/daemon/slave-main.c b/daemon/slave-main.c index b5ae04fc..fdea7a1b 100644 --- a/daemon/slave-main.c +++ b/daemon/slave-main.c @@ -28,6 +28,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#include <signal.h> #include <glib.h> #include <glib/gi18n.h> @@ -37,6 +38,7 @@ #include <dbus/dbus-glib.h> #include <dbus/dbus-glib-lowlevel.h> +#include "gdm-signal-handler.h" #include "gdm-log.h" #include "gdm-slave.h" @@ -63,22 +65,80 @@ get_system_bus (void) return bus; } -static void -setup_signal_handlers (void) +static gboolean +signal_cb (int signo, + gpointer data) { - /* FIXME */ + int ret; + + g_debug ("Got callback for signal %d", signo); + + ret = TRUE; + + switch (signo) { + case SIGSEGV: + case SIGBUS: + case SIGILL: + case SIGABRT: + g_debug ("Caught signal %d.", signo); + + ret = FALSE; + break; + + case SIGFPE: + case SIGPIPE: + /* let the fatal signals interrupt us */ + g_debug ("Caught signal %d, shutting down abnormally.", signo); + ret = FALSE; + + break; + + case SIGINT: + case SIGTERM: + /* let the fatal signals interrupt us */ + g_debug ("Caught signal %d, shutting down normally.", signo); + ret = FALSE; + + break; + + case SIGHUP: + g_debug ("Got HUP signal"); + /* FIXME: + * Reread config stuff like system config files, VPN service files, etc + */ + ret = TRUE; + + break; + + case SIGUSR1: + g_debug ("Got USR1 signal"); + /* FIXME: + * Play with log levels or something + */ + ret = TRUE; + break; + + default: + g_debug ("Caught unhandled signal %d", signo); + ret = TRUE; + + break; + } + + return ret; } int main (int argc, char **argv) { - GMainLoop *loop; - GOptionContext *context; - DBusGConnection *connection; - int ret; - GdmSlave *slave; - static char *display_id = NULL; + GMainLoop *main_loop; + GOptionContext *context; + DBusGConnection *connection; + int ret; + GdmSlave *slave; + static char *display_id = NULL; + GdmSignalHandler *signal_handler; static GOptionEntry entries [] = { { "display-id", 0, 0, G_OPTION_ARG_STRING, &display_id, N_("Display ID"), N_("id") }, { NULL } @@ -112,29 +172,43 @@ main (int argc, exit (1); } - setup_signal_handlers (); + main_loop = g_main_loop_new (NULL, FALSE); - slave = gdm_slave_new (display_id); + signal_handler = gdm_signal_handler_new (); + gdm_signal_handler_set_main_loop (signal_handler, main_loop); + gdm_signal_handler_add (signal_handler, SIGTERM, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGINT, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGILL, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGBUS, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGFPE, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGHUP, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGSEGV, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGABRT, signal_cb, NULL); + gdm_signal_handler_add (signal_handler, SIGUSR1, signal_cb, NULL); + slave = gdm_slave_new (display_id); if (slave == NULL) { goto out; } - - loop = g_main_loop_new (NULL, FALSE); - gdm_slave_start (slave); - g_main_loop_run (loop); + g_main_loop_run (main_loop); if (slave != NULL) { g_object_unref (slave); } - g_main_loop_unref (loop); + if (signal_handler != NULL) { + g_object_unref (signal_handler); + } + + g_main_loop_unref (main_loop); ret = 0; out: + g_debug ("Slave finished"); + return ret; } |