summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/Makefile.am2
-rw-r--r--common/gdm-signal-handler.c265
-rw-r--r--common/gdm-signal-handler.h66
-rw-r--r--daemon/gdm-display-store.c4
-rw-r--r--daemon/gdm-display-store.h4
-rw-r--r--daemon/gdm-display.c22
-rw-r--r--daemon/gdm-greeter.c91
-rw-r--r--daemon/gdm-manager.c32
-rw-r--r--daemon/gdm-manager.h5
-rw-r--r--daemon/gdm-server.c141
-rw-r--r--daemon/gdm-slave-proxy.c16
-rw-r--r--daemon/gdm-slave.c14
-rw-r--r--daemon/main.c133
-rw-r--r--daemon/slave-main.c106
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;
}