From 35a4d47385d043cf4df62c2723508e4edce4dfb4 Mon Sep 17 00:00:00 2001 From: Xiaoguang Wang Date: Thu, 16 May 2019 13:26:16 +0800 Subject: [PATCH 2/7] session-worker: kill user sessions when stopping gdm service At the moment the session worker exits as soon as it gets SIGTERM. That means it may fail to stop the user session (which only happens in the orderly shutdown path). This commit sets up a SIGTERM handler that integrates with and quits the main loop after the session is started. It still retains the _exit-on-SIGTERM behavior before the session is started, to ensure a stuck pam module doesn't prevent the process from dying. Some small changes to commit by Ray Strode. Closes #400 --- daemon/gdm-session-worker.c | 38 +++++++++++++++++++++++++++--------- daemon/session-worker-main.c | 33 +++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c index d897779f3..e526fa5db 100644 --- a/daemon/gdm-session-worker.c +++ b/daemon/gdm-session-worker.c @@ -159,60 +159,61 @@ struct GdmSessionWorkerPrivate guint32 display_is_initial : 1; guint state_change_idle_id; GdmSessionDisplayMode display_mode; char *server_address; GDBusConnection *connection; GdmDBusWorkerManager *manager; GHashTable *reauthentication_requests; GdmSessionAuditor *auditor; GdmSessionSettings *user_settings; GDBusMethodInvocation *pending_invocation; }; #ifdef SUPPORTS_PAM_EXTENSIONS static char gdm_pam_extension_environment_block[_POSIX_ARG_MAX]; static const char * const gdm_supported_pam_extensions[] = { GDM_PAM_EXTENSION_CHOICE_LIST, NULL }; #endif enum { PROP_0, PROP_SERVER_ADDRESS, PROP_IS_REAUTH_SESSION, + PROP_STATE, }; static void gdm_session_worker_class_init (GdmSessionWorkerClass *klass); static void gdm_session_worker_init (GdmSessionWorker *session_worker); static void gdm_session_worker_finalize (GObject *object); static void gdm_session_worker_set_environment_variable (GdmSessionWorker *worker, const char *key, const char *value); static void queue_state_change (GdmSessionWorker *worker); static void worker_interface_init (GdmDBusWorkerIface *iface); typedef int (* GdmSessionWorkerPamNewMessagesFunc) (int, const struct pam_message **, struct pam_response **, gpointer); G_DEFINE_TYPE_WITH_CODE (GdmSessionWorker, gdm_session_worker, GDM_DBUS_TYPE_WORKER_SKELETON, G_IMPLEMENT_INTERFACE (GDM_DBUS_TYPE_WORKER, worker_interface_init)) /* adapted from glib script_execute */ static void script_execute (const gchar *file, char **argv, @@ -966,100 +967,111 @@ jump_to_vt (GdmSessionWorker *worker, g_debug ("GdmSessionWorker: first setting graphics mode to prevent flicker"); if (ioctl (fd, KDSETMODE, KD_GRAPHICS) < 0) { g_debug ("GdmSessionWorker: couldn't set graphics mode: %m"); } /* It's possible that the current VT was left in a broken * combination of states (KD_GRAPHICS with VT_AUTO), that * can't be switched away from. This call makes sure things * are set in a way that VT_ACTIVATE should work and * VT_WAITACTIVE shouldn't hang. */ fix_terminal_vt_mode (worker, active_vt_tty_fd); } else { fd = active_vt_tty_fd; } handle_terminal_vt_switches (worker, fd); if (ioctl (fd, VT_ACTIVATE, vt_number) < 0) { g_debug ("GdmSessionWorker: couldn't initiate jump to VT %d: %m", vt_number); } else if (ioctl (fd, VT_WAITACTIVE, vt_number) < 0) { g_debug ("GdmSessionWorker: couldn't finalize jump to VT %d: %m", vt_number); } close (active_vt_tty_fd); } +static void +gdm_session_worker_set_state (GdmSessionWorker *worker, + GdmSessionWorkerState state) +{ + if (worker->priv->state == state) + return; + + worker->priv->state = state; + g_object_notify (G_OBJECT (worker), "state"); +} + static void gdm_session_worker_uninitialize_pam (GdmSessionWorker *worker, int status) { g_debug ("GdmSessionWorker: uninitializing PAM"); if (worker->priv->pam_handle == NULL) return; gdm_session_worker_get_username (worker, NULL); if (worker->priv->state >= GDM_SESSION_WORKER_STATE_SESSION_OPENED) { pam_close_session (worker->priv->pam_handle, 0); gdm_session_auditor_report_logout (worker->priv->auditor); } else { gdm_session_auditor_report_login_failure (worker->priv->auditor, status, pam_strerror (worker->priv->pam_handle, status)); } if (worker->priv->state >= GDM_SESSION_WORKER_STATE_ACCREDITED) { pam_setcred (worker->priv->pam_handle, PAM_DELETE_CRED); } pam_end (worker->priv->pam_handle, status); worker->priv->pam_handle = NULL; gdm_session_worker_stop_auditor (worker); if (g_strcmp0 (worker->priv->display_seat_id, "seat0") == 0) { if (worker->priv->login_vt != worker->priv->session_vt) { jump_to_vt (worker, worker->priv->login_vt); } } worker->priv->login_vt = 0; worker->priv->session_vt = 0; g_debug ("GdmSessionWorker: state NONE"); - worker->priv->state = GDM_SESSION_WORKER_STATE_NONE; + gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_NONE); } static char * _get_tty_for_pam (const char *x11_display_name, const char *display_device) { #ifdef __sun return g_strdup (display_device); #else return g_strdup (x11_display_name); #endif } #ifdef PAM_XAUTHDATA static struct pam_xauth_data * _get_xauth_for_pam (const char *x11_authority_file) { FILE *fh; Xauth *auth = NULL; struct pam_xauth_data *retval = NULL; gsize len = sizeof (*retval) + 1; fh = fopen (x11_authority_file, "r"); if (fh) { auth = XauReadAuth (fh); fclose (fh); } if (auth) { len += auth->name_length + auth->data_length; retval = g_malloc0 (len); @@ -1168,61 +1180,61 @@ gdm_session_worker_initialize_pam (GdmSessionWorker *worker, goto out; } } /* set RHOST */ if (hostname != NULL && hostname[0] != '\0') { error_code = pam_set_item (worker->priv->pam_handle, PAM_RHOST, hostname); g_debug ("error informing authentication system of user's hostname %s: %s", hostname, pam_strerror (worker->priv->pam_handle, error_code)); if (error_code != PAM_SUCCESS) { g_set_error (error, GDM_SESSION_WORKER_ERROR, GDM_SESSION_WORKER_ERROR_AUTHENTICATING, "%s", ""); goto out; } } /* set seat ID */ if (seat_id != NULL && seat_id[0] != '\0') { gdm_session_worker_set_environment_variable (worker, "XDG_SEAT", seat_id); } if (strcmp (service, "gdm-launch-environment") == 0) { gdm_session_worker_set_environment_variable (worker, "XDG_SESSION_CLASS", "greeter"); } g_debug ("GdmSessionWorker: state SETUP_COMPLETE"); - worker->priv->state = GDM_SESSION_WORKER_STATE_SETUP_COMPLETE; + gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_SETUP_COMPLETE); /* Temporarily set PAM_TTY with the currently active VT (login screen) PAM_TTY will be reset with the users VT right before the user session is opened */ ensure_login_vt (worker); g_snprintf (tty_string, 256, "/dev/tty%d", worker->priv->login_vt); pam_set_item (worker->priv->pam_handle, PAM_TTY, tty_string); if (!display_is_local) worker->priv->password_is_required = TRUE; out: if (error_code != PAM_SUCCESS) { gdm_session_worker_uninitialize_pam (worker, error_code); return FALSE; } return TRUE; } static gboolean gdm_session_worker_authenticate_user (GdmSessionWorker *worker, gboolean password_is_required, GError **error) { int error_code; int authentication_flags; g_debug ("GdmSessionWorker: authenticating user %s", worker->priv->username); authentication_flags = 0; @@ -1233,61 +1245,61 @@ gdm_session_worker_authenticate_user (GdmSessionWorker *worker, /* blocking call, does the actual conversation */ error_code = pam_authenticate (worker->priv->pam_handle, authentication_flags); if (error_code == PAM_AUTHINFO_UNAVAIL) { g_debug ("GdmSessionWorker: authentication service unavailable"); g_set_error (error, GDM_SESSION_WORKER_ERROR, GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE, "%s", ""); goto out; } else if (error_code != PAM_SUCCESS) { g_debug ("GdmSessionWorker: authentication returned %d: %s", error_code, pam_strerror (worker->priv->pam_handle, error_code)); /* * Do not display a different message for user unknown versus * a failed password for a valid user. */ if (error_code == PAM_USER_UNKNOWN) { error_code = PAM_AUTH_ERR; } g_set_error (error, GDM_SESSION_WORKER_ERROR, GDM_SESSION_WORKER_ERROR_AUTHENTICATING, "%s", get_friendly_error_message (error_code)); goto out; } g_debug ("GdmSessionWorker: state AUTHENTICATED"); - worker->priv->state = GDM_SESSION_WORKER_STATE_AUTHENTICATED; + gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_AUTHENTICATED); out: if (error_code != PAM_SUCCESS) { gdm_session_worker_uninitialize_pam (worker, error_code); return FALSE; } return TRUE; } static gboolean gdm_session_worker_authorize_user (GdmSessionWorker *worker, gboolean password_is_required, GError **error) { int error_code; int authentication_flags; g_debug ("GdmSessionWorker: determining if authenticated user (password required:%d) is authorized to session", password_is_required); authentication_flags = 0; if (password_is_required) { authentication_flags |= PAM_DISALLOW_NULL_AUTHTOK; } /* check that the account isn't disabled or expired */ error_code = pam_acct_mgmt (worker->priv->pam_handle, authentication_flags); @@ -1298,61 +1310,61 @@ gdm_session_worker_authorize_user (GdmSessionWorker *worker, g_debug ("GdmSessionWorker: authenticated user requires new auth token"); error_code = pam_chauthtok (worker->priv->pam_handle, PAM_CHANGE_EXPIRED_AUTHTOK); gdm_session_worker_get_username (worker, NULL); if (error_code != PAM_SUCCESS) { gdm_session_auditor_report_password_change_failure (worker->priv->auditor); } else { gdm_session_auditor_report_password_changed (worker->priv->auditor); } } /* If the user is reauthenticating, then authorization isn't required to * proceed, the user is already logged in after all. */ if (worker->priv->is_reauth_session) { error_code = PAM_SUCCESS; } if (error_code != PAM_SUCCESS) { g_debug ("GdmSessionWorker: user is not authorized to log in: %s", pam_strerror (worker->priv->pam_handle, error_code)); g_set_error (error, GDM_SESSION_WORKER_ERROR, GDM_SESSION_WORKER_ERROR_AUTHORIZING, "%s", get_friendly_error_message (error_code)); goto out; } g_debug ("GdmSessionWorker: state AUTHORIZED"); - worker->priv->state = GDM_SESSION_WORKER_STATE_AUTHORIZED; + gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_AUTHORIZED); out: if (error_code != PAM_SUCCESS) { gdm_session_worker_uninitialize_pam (worker, error_code); return FALSE; } return TRUE; } static void gdm_session_worker_set_environment_variable (GdmSessionWorker *worker, const char *key, const char *value) { int error_code; char *environment_entry; if (value != NULL) { environment_entry = g_strdup_printf ("%s=%s", key, value); } else { /* empty value means "remove from environment" */ environment_entry = g_strdup (key); } error_code = pam_putenv (worker->priv->pam_handle, environment_entry); if (error_code != PAM_SUCCESS) { g_warning ("cannot put %s in pam environment: %s\n", @@ -1710,61 +1722,61 @@ gdm_session_worker_accredit_user (GdmSessionWorker *worker, /* If the user is reauthenticating and they've made it this far, then there * is no reason we should lock them out of their session. They've already * proved they are they same person who logged in, and that's all we care * about. */ if (worker->priv->is_reauth_session) { error_code = PAM_SUCCESS; } if (error_code != PAM_SUCCESS) { g_set_error (error, GDM_SESSION_WORKER_ERROR, GDM_SESSION_WORKER_ERROR_GIVING_CREDENTIALS, "%s", pam_strerror (worker->priv->pam_handle, error_code)); goto out; } ret = TRUE; out: g_free (home); g_free (shell); if (ret) { g_debug ("GdmSessionWorker: state ACCREDITED"); ret = TRUE; gdm_session_worker_get_username (worker, NULL); gdm_session_auditor_report_user_accredited (worker->priv->auditor); - worker->priv->state = GDM_SESSION_WORKER_STATE_ACCREDITED; + gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_ACCREDITED); } else { gdm_session_worker_uninitialize_pam (worker, error_code); } return ret; } static const char * const * gdm_session_worker_get_environment (GdmSessionWorker *worker) { return (const char * const *) pam_getenvlist (worker->priv->pam_handle); } static gboolean run_script (GdmSessionWorker *worker, const char *dir) { /* scripts are for non-program sessions only */ if (worker->priv->is_program_session) { return TRUE; } return gdm_run_script (dir, worker->priv->username, worker->priv->x11_display_name, worker->priv->display_is_local? NULL : worker->priv->hostname, worker->priv->x11_authority_file); } static void @@ -2154,61 +2166,61 @@ gdm_session_worker_start_session (GdmSessionWorker *worker, (char **) environment, TRUE); gdm_log_init (); g_debug ("GdmSessionWorker: child '%s' could not be started: %s", worker->priv->arguments[0], g_strerror (errno)); _exit (EXIT_FAILURE); } if (worker->priv->session_tty_fd > 0) { close (worker->priv->session_tty_fd); worker->priv->session_tty_fd = -1; } /* If we end up execing again, make sure we don't use the executable context set up * by pam_selinux durin pam_open_session */ #ifdef HAVE_SELINUX setexeccon (NULL); #endif worker->priv->child_pid = session_pid; g_debug ("GdmSessionWorker: session opened creating reply..."); g_assert (sizeof (GPid) <= sizeof (int)); g_debug ("GdmSessionWorker: state SESSION_STARTED"); - worker->priv->state = GDM_SESSION_WORKER_STATE_SESSION_STARTED; + gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_SESSION_STARTED); gdm_session_worker_watch_child (worker); out: if (error_code != PAM_SUCCESS) { gdm_session_worker_uninitialize_pam (worker, error_code); return FALSE; } return TRUE; } static gboolean set_up_for_new_vt (GdmSessionWorker *worker) { int fd; char vt_string[256], tty_string[256]; int session_vt = 0; fd = open ("/dev/tty0", O_RDWR | O_NOCTTY); if (fd < 0) { g_debug ("GdmSessionWorker: couldn't open VT master: %m"); return FALSE; } if (worker->priv->display_is_initial) { session_vt = atoi (GDM_INITIAL_VT); } else { if (ioctl(fd, VT_OPENQRY, &session_vt) < 0) { @@ -2377,61 +2389,61 @@ gdm_session_worker_open_session (GdmSessionWorker *worker, break; case GDM_SESSION_DISPLAY_MODE_NEW_VT: case GDM_SESSION_DISPLAY_MODE_LOGIND_MANAGED: if (!set_up_for_new_vt (worker)) { g_set_error (error, GDM_SESSION_WORKER_ERROR, GDM_SESSION_WORKER_ERROR_OPENING_SESSION, "Unable to open VT"); return FALSE; } break; } flags = 0; if (worker->priv->is_program_session) { flags |= PAM_SILENT; } error_code = pam_open_session (worker->priv->pam_handle, flags); if (error_code != PAM_SUCCESS) { g_set_error (error, GDM_SESSION_WORKER_ERROR, GDM_SESSION_WORKER_ERROR_OPENING_SESSION, "%s", pam_strerror (worker->priv->pam_handle, error_code)); goto out; } g_debug ("GdmSessionWorker: state SESSION_OPENED"); - worker->priv->state = GDM_SESSION_WORKER_STATE_SESSION_OPENED; + gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_SESSION_OPENED); session_id = gdm_session_worker_get_environment_variable (worker, "XDG_SESSION_ID"); if (session_id != NULL) { g_free (worker->priv->session_id); worker->priv->session_id = session_id; } out: if (error_code != PAM_SUCCESS) { gdm_session_worker_uninitialize_pam (worker, error_code); return FALSE; } gdm_session_worker_get_username (worker, NULL); gdm_session_auditor_report_login (worker->priv->auditor); return TRUE; } static void gdm_session_worker_set_server_address (GdmSessionWorker *worker, const char *address) { g_free (worker->priv->server_address); worker->priv->server_address = g_strdup (address); } static void gdm_session_worker_set_is_reauth_session (GdmSessionWorker *worker, @@ -2454,61 +2466,61 @@ gdm_session_worker_set_property (GObject *object, case PROP_SERVER_ADDRESS: gdm_session_worker_set_server_address (self, g_value_get_string (value)); break; case PROP_IS_REAUTH_SESSION: gdm_session_worker_set_is_reauth_session (self, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gdm_session_worker_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GdmSessionWorker *self; self = GDM_SESSION_WORKER (object); switch (prop_id) { case PROP_SERVER_ADDRESS: g_value_set_string (value, self->priv->server_address); break; case PROP_IS_REAUTH_SESSION: g_value_set_boolean (value, self->priv->is_reauth_session); break; case PROP_STATE: - g_value_set_int (value, self->priv->state); + g_value_set_enum (value, self->priv->state); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static gboolean gdm_session_worker_handle_set_environment_variable (GdmDBusWorker *object, GDBusMethodInvocation *invocation, const char *key, const char *value) { GdmSessionWorker *worker = GDM_SESSION_WORKER (object); gdm_session_worker_set_environment_variable (worker, key, value); gdm_dbus_worker_complete_set_environment_variable (object, invocation); return TRUE; } static gboolean gdm_session_worker_handle_set_session_name (GdmDBusWorker *object, GDBusMethodInvocation *invocation, const char *session_name) { GdmSessionWorker *worker = GDM_SESSION_WORKER (object); g_debug ("GdmSessionWorker: session name set to %s", session_name); gdm_session_settings_set_session_name (worker->priv->user_settings, session_name); gdm_dbus_worker_complete_set_session_name (object, invocation); return TRUE; @@ -2639,61 +2651,61 @@ do_authorize (GdmSessionWorker *worker) g_dbus_method_invocation_take_error (worker->priv->pending_invocation, error); } worker->priv->pending_invocation = NULL; } static void do_accredit (GdmSessionWorker *worker) { GError *error; gboolean res; /* get kerberos tickets, setup group lists, etc */ error = NULL; res = gdm_session_worker_accredit_user (worker, &error); if (res) { gdm_dbus_worker_complete_establish_credentials (GDM_DBUS_WORKER (worker), worker->priv->pending_invocation); } else { g_dbus_method_invocation_take_error (worker->priv->pending_invocation, error); } worker->priv->pending_invocation = NULL; } static void save_account_details_now (GdmSessionWorker *worker) { g_assert (worker->priv->state == GDM_SESSION_WORKER_STATE_ACCREDITED); g_debug ("GdmSessionWorker: saving account details for user %s", worker->priv->username); - worker->priv->state = GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED; + gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_ACCOUNT_DETAILS_SAVED); if (!gdm_session_settings_save (worker->priv->user_settings, worker->priv->username)) { g_warning ("could not save session and language settings"); } queue_state_change (worker); } static void on_settings_is_loaded_changed (GdmSessionSettings *user_settings, GParamSpec *pspec, GdmSessionWorker *worker) { if (!gdm_session_settings_is_loaded (worker->priv->user_settings)) { return; } /* These signal handlers should be disconnected after the loading, * so that gdm_session_settings_set_* APIs don't cause the emitting * of Saved*NameRead D-Bus signals any more. */ g_signal_handlers_disconnect_by_func (worker->priv->user_settings, G_CALLBACK (on_saved_session_name_read), worker); g_signal_handlers_disconnect_by_func (worker->priv->user_settings, G_CALLBACK (on_saved_language_name_read), worker); if (worker->priv->state == GDM_SESSION_WORKER_STATE_NONE) { g_debug ("GdmSessionWorker: queuing setup for user: %s %s", @@ -3443,60 +3455,68 @@ worker_interface_init (GdmDBusWorkerIface *interface) interface->handle_start_reauthentication = gdm_session_worker_handle_start_reauthentication; } static void gdm_session_worker_class_init (GdmSessionWorkerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->get_property = gdm_session_worker_get_property; object_class->set_property = gdm_session_worker_set_property; object_class->constructor = gdm_session_worker_constructor; object_class->finalize = gdm_session_worker_finalize; g_type_class_add_private (klass, sizeof (GdmSessionWorkerPrivate)); g_object_class_install_property (object_class, PROP_SERVER_ADDRESS, g_param_spec_string ("server-address", "server address", "server address", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_IS_REAUTH_SESSION, g_param_spec_boolean ("is-reauth-session", "is reauth session", "is reauth session", FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + g_object_class_install_property (object_class, + PROP_STATE, + g_param_spec_enum ("state", + "state", + "state", + GDM_TYPE_SESSION_WORKER_STATE, + GDM_SESSION_WORKER_STATE_NONE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); } static void reauthentication_request_free (ReauthenticationRequest *request) { g_signal_handlers_disconnect_by_func (request->session, G_CALLBACK (on_reauthentication_client_connected), request); g_signal_handlers_disconnect_by_func (request->session, G_CALLBACK (on_reauthentication_client_disconnected), request); g_signal_handlers_disconnect_by_func (request->session, G_CALLBACK (on_reauthentication_cancelled), request); g_signal_handlers_disconnect_by_func (request->session, G_CALLBACK (on_reauthentication_conversation_started), request); g_signal_handlers_disconnect_by_func (request->session, G_CALLBACK (on_reauthentication_conversation_stopped), request); g_signal_handlers_disconnect_by_func (request->session, G_CALLBACK (on_reauthentication_verification_complete), request); g_clear_object (&request->session); g_slice_free (ReauthenticationRequest, request); } static void gdm_session_worker_init (GdmSessionWorker *worker) diff --git a/daemon/session-worker-main.c b/daemon/session-worker-main.c index 4a3a8ebbe..d96844d2d 100644 --- a/daemon/session-worker-main.c +++ b/daemon/session-worker-main.c @@ -37,104 +37,137 @@ #include #include "gdm-common.h" #include "gdm-log.h" #include "gdm-session-worker.h" #include "gdm-settings.h" #include "gdm-settings-direct.h" #include "gdm-settings-keys.h" static GdmSettings *settings = NULL; static gboolean on_sigusr1_cb (gpointer user_data) { g_debug ("Got USR1 signal"); gdm_log_toggle_debug (); return TRUE; } static gboolean is_debug_set (void) { gboolean debug; gdm_settings_direct_get_boolean (GDM_KEY_DEBUG, &debug); return debug; } +static gboolean +on_shutdown_signal_cb (gpointer user_data) +{ + GMainLoop *mainloop = user_data; + + g_main_loop_quit (mainloop); + + return FALSE; +} + +static void +on_state_changed (GdmSessionWorker *worker, + GParamSpec *pspec, + GMainLoop *main_loop) +{ + GdmSessionWorkerState state; + + g_object_get (G_OBJECT (worker), "state", &state, NULL); + + if (state != GDM_SESSION_WORKER_STATE_SESSION_STARTED) + return; + + g_unix_signal_add (SIGTERM, on_shutdown_signal_cb, main_loop); +} + static void on_sigterm_cb (int signal_number) { _exit (EXIT_SUCCESS); } int main (int argc, char **argv) { GMainLoop *main_loop; GOptionContext *context; GdmSessionWorker *worker; const char *address; gboolean is_for_reauth; static GOptionEntry entries [] = { { NULL } }; signal (SIGTERM, on_sigterm_cb); bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); textdomain (GETTEXT_PACKAGE); setlocale (LC_ALL, ""); /* Translators: worker is a helper process that does the work of starting up a session */ context = g_option_context_new (_("GNOME Display Manager Session Worker")); g_option_context_add_main_entries (context, entries, NULL); g_option_context_parse (context, &argc, &argv, NULL); g_option_context_free (context); gdm_log_init (); settings = gdm_settings_new (); if (settings == NULL) { g_warning ("Unable to initialize settings"); exit (EXIT_FAILURE); } if (! gdm_settings_direct_init (settings, DATADIR "/gdm/gdm.schemas", "/")) { g_warning ("Unable to initialize settings"); exit (EXIT_FAILURE); } gdm_log_set_debug (is_debug_set ()); address = g_getenv ("GDM_SESSION_DBUS_ADDRESS"); if (address == NULL) { g_warning ("GDM_SESSION_DBUS_ADDRESS not set"); exit (EXIT_FAILURE); } is_for_reauth = g_getenv ("GDM_SESSION_FOR_REAUTH") != NULL; worker = gdm_session_worker_new (address, is_for_reauth); main_loop = g_main_loop_new (NULL, FALSE); + g_signal_connect (G_OBJECT (worker), + "notify::state", + G_CALLBACK (on_state_changed), + main_loop); + g_unix_signal_add (SIGUSR1, on_sigusr1_cb, NULL); g_main_loop_run (main_loop); if (worker != NULL) { + g_signal_handlers_disconnect_by_func (worker, + G_CALLBACK (on_state_changed), + main_loop); g_object_unref (worker); } g_main_loop_unref (main_loop); g_debug ("Worker finished"); return 0; } -- 2.21.0