From aa65c573f75d52590e949c2a190977fc36e1fe7d Mon Sep 17 00:00:00 2001 From: Nathaniel Russell <46272571+nater1983@users.noreply.github.com> Date: Fri, 16 Jan 2026 21:21:12 -0600 Subject: [PATCH 1/3] Refactor leader-openrc for SysVinit compatibility Signed-off-by: Nathaniel Russell <46272571+nater1983@users.noreply.github.com> --- gnome-session/leader-openrc.c | 160 +++++++++------------------------- 1 file changed, 40 insertions(+), 120 deletions(-) diff --git a/gnome-session/leader-openrc.c b/gnome-session/leader-openrc.c index 3b5012c..6b7aa54 100644 --- a/gnome-session/leader-openrc.c +++ b/gnome-session/leader-openrc.c @@ -24,7 +24,9 @@ #include #include #include -#include +#include +#include +#include typedef struct { GDBusConnection *session_bus; @@ -38,7 +40,8 @@ leader_clear (Leader *ctx) { g_clear_object (&ctx->session_bus); g_clear_pointer (&ctx->loop, g_main_loop_unref); - g_close (ctx->fifo_fd, NULL); + if (ctx->fifo_fd >= 0) + close (ctx->fifo_fd); g_clear_object (&ctx->awaiting_shutdown); } @@ -57,36 +60,42 @@ async_run_cmd (gchar **argv, GError **error) error); } +/* -------------------- SysVinit-compatible unit handling -------------------- */ + static gboolean -openrc_unit_action (const char *unit, - const char *action, - GError **error) +sysvinit_unit_action (const char *unit, + const char *action, + GError **error) { - g_autofree char *service = rc_service_resolve(unit); - if (!service) - { - g_debug ("Couldn't resolve service '%s'", unit); + if (!unit || !action) return FALSE; - } - gchar *argv[] = { service, "-U", action, NULL }; + + g_autofree char *cmd = g_strdup_printf("/etc/init.d/%s %s", unit, action); + gchar *argv[] = { "/bin/sh", "-c", cmd, NULL }; + gboolean res = async_run_cmd(argv, error); + if (!res) + g_warning("Failed to run unit %s %s: %s", unit, action, + error ? (*error)->message : "(no message)"); return res; } static gboolean -openrc_start_unit (const char *unit, - GError **error) +sysvinit_start_unit (const char *unit, + GError **error) { - return openrc_unit_action (unit, "start", error); + return sysvinit_unit_action(unit, "start", error); } static gboolean -openrc_stop_unit (const char *unit, - GError **error) +sysvinit_stop_unit (const char *unit, + GError **error) { - return openrc_unit_action (unit, "stop", error); + return sysvinit_unit_action(unit, "stop", error); } +/* --------------------------------------------------------------------------- */ + static gboolean leader_term_or_int_signal_cb (gpointer data) { @@ -149,7 +158,8 @@ monitor_hangup_cb (int fd, NULL, &error); if (!unit) { - g_warning ("Could not get unit for graphical-session-pre.target: %s", error->message); + g_warning ("Could not get unit for graphical-session-pre.target: %s", + error->message); g_main_loop_quit (ctx->loop); return G_SOURCE_REMOVE; } @@ -165,7 +175,8 @@ monitor_hangup_cb (int fd, NULL, &error); if (!proxy) { - g_warning ("Could not get proxy for graphical-session-pre.target unit: %s", error->message); + g_warning ("Could not get proxy for graphical-session-pre.target unit: %s", + error->message); g_main_loop_quit (ctx->loop); return G_SOURCE_REMOVE; } @@ -207,96 +218,37 @@ debug_logger (gchar const *log_domain, syslog (LOG_INFO, "%s", message); } -/** - * This is the session leader, i.e. it is the only process that's not managed - * by the systemd user instance. This process is the one executed by GDM, and - * it is part of the session scope in the system systemd instance. This process - * works in conjunction with a service running within the user's service manager - * (i.e. `gnome-session-monitor.service`) to implement the following: - * - * - When asked to shut down cleanly (i.e. via SIGTERM), the leader needs to - * bring down the session - * - The leader needs to quit right after the session shuts down - * - If the leader shuts down uncleanly, the session needs to shut down as well. - * - * This is achieved by opening a named FIFO in a well known location. If this - * process receives SIGTERM or SIGINT then it will write a single byte, causing - * the monitor service to signal STOPPING=1 to systemd. This triggers a clean - * shutdown, solving the first item. To handle unclean shutdowns, we also wait - * for EOF/HUP on both sides and quit if that signal is received. - * - * As an example, a shutdown might look as follows: - * - * - session-X.scope for user is stopped - * - Leader process receives SIGTERM - * - Leader sends single byte - * - Monitor process receives byte and signals STOPPING=1 - * - Systemd user instance starts session teardown - * - The last job that runs during session teardown is a stop job for the - * monitor process. - * - Monitor process quits, closing FD in the process - * - Leader process receives HUP and quits - * - GDM sees the leader quit and cleans up its state in response. - * - * The result is that the session is stopped cleanly. - */ int main (int argc, char **argv) { - // Hook into syslog, as on an openrc system it's probably more convenient g_log_set_default_handler(debug_logger, NULL); g_autoptr (GError) error = NULL; g_auto (Leader) ctx = { .fifo_fd = -1 }; const char *session_name = NULL; const char *debug_string = NULL; - g_autofree char *target = NULL; g_autofree char *fifo_path = NULL; g_autofree char *home_dir = NULL; g_autofree char *config_dir = NULL; struct stat statbuf; - + if (argc < 2) g_error ("No session name was specified"); session_name = argv[1]; - - // probably not rely on this + char const *user = g_getenv("USER"); if (!user) - user = "gdm-greeter"; // :/ + user = "gdm-greeter"; + g_info("User is: %s", user); - // strncmp because we also have gdm-greeter-{2,3,4,...} if (strncmp(user, "gdm-greeter", sizeof("gdm-greeter")) == 0) { home_dir = g_strdup_printf("/var/lib/%s", user); - - // Need to hijack the home to point to /var/lib because /var/run/... gets nuked on each gdm start config_dir = g_strdup_printf("%s/.config", home_dir); g_setenv("XDG_CONFIG_HOME", config_dir, TRUE); g_setenv("HOME", home_dir, TRUE); } else - g_warning("The gdm-greeter-{1,2,3,4} user wasn't found. Expect stuff to break.") - - // Finally, let's get started - rc_set_user(); - - char const *session_type = g_getenv("XDG_SESSION_TYPE"); - char const *home = g_getenv("HOME"); - g_info("XDG_RUNTIME_DIR: %s", g_getenv("XDG_RUNTIME_DIR")); - - // TODO what about custom XDG config directory? - g_autofree char *gnome_runlevel_dir = g_strdup_printf("%s/.config/rc/runlevels/gnome-session", home); - if (!g_mkdir_with_parents(gnome_runlevel_dir, 0755)) - g_debug("Directory exists. OK"); - - g_debug("runlevel dir: %s", gnome_runlevel_dir); - - debug_string = g_getenv ("GNOME_SESSION_DEBUG"); - if (debug_string != NULL) - g_log_set_debug_enabled (atoi (debug_string) == 1); - else - g_log_set_debug_enabled(TRUE); - g_debug("Hi! from leader-openrc."); + g_warning("The gdm-greeter-{1,2,3,4} user wasn't found. Expect stuff to break."); ctx.loop = g_main_loop_new (NULL, TRUE); @@ -304,42 +256,10 @@ main (int argc, char **argv) if (ctx.session_bus == NULL) g_error ("Failed to obtain session bus: %s", error->message); - /* XDG_SESSION_TYPE from the console is TTY which isn't a service and doesn't make - too much sense anyway */ + const char *session_type = g_getenv("XDG_SESSION_TYPE"); if (session_type && strcmp(session_type, "tty") == 0) - session_type = "wayland"; - target = g_strdup_printf ("gnome-session-%s.%s", - session_type ? session_type : "wayland", session_name); - - RC_SERVICE state = rc_service_state(target); - switch (state) - { - case RC_SERVICE_STARTED: - case RC_SERVICE_FAILED: - g_error("Service manager is already running!"); - break; - case RC_SERVICE_STOPPED: - break; - default: - g_debug("Service in state: %d", state); - } - - if (!rc_runlevel_stack("gnome-session", "default")) - g_info("Couldn't set runlevel stack"); - if (!rc_runlevel_exists("gnome-session")) - g_info("No runlevel \"gnome-session\" seen!"); // next function will fail now, but librc error reporting sucks so we check this specifically - if (!rc_service_add("gnome-session", target)) - { - g_info("Couldn't add service to gnome-session runlevel: %s", strerror(errno)); - } - - g_message ("Starting GNOME session target: %s", target); + session_type = "wayland"; - // No way that i'm aware of to enter a user runlevel from librc :/ - gchar *rl_argv[] = { "/usr/bin/openrc", "-U", "gnome-session", NULL }; - if (!async_run_cmd(rl_argv, &error)) - g_error("Failed to start unit %s: %s", target, error ? error->message : "(no message)"); - fifo_path = g_build_filename (g_get_user_runtime_dir (), "gnome-session-leader-fifo", NULL); @@ -348,11 +268,11 @@ main (int argc, char **argv) ctx.fifo_fd = g_open (fifo_path, O_WRONLY | O_CLOEXEC, 0666); if (ctx.fifo_fd < 0) - g_error ("Failed to watch openrc session: open failed: %m"); + g_error ("Failed to watch session: open failed: %m"); if (fstat (ctx.fifo_fd, &statbuf) < 0) - g_error ("Failed to watch openrc session: fstat failed: %m"); + g_error ("Failed to watch session: fstat failed: %m"); else if (!(statbuf.st_mode & S_IFIFO)) - g_error ("Failed to watch openrc session: FD is not a FIFO"); + g_error ("Failed to watch session: FD is not a FIFO"); g_unix_fd_add (ctx.fifo_fd, G_IO_HUP, (GUnixFDSourceFunc) monitor_hangup_cb, &ctx); g_unix_signal_add (SIGHUP, leader_term_or_int_signal_cb, &ctx); From 8dd43d85886f9cf889a0b145106da6083d443ffc Mon Sep 17 00:00:00 2001 From: Nathaniel Russell <46272571+nater1983@users.noreply.github.com> Date: Fri, 16 Jan 2026 21:21:58 -0600 Subject: [PATCH 2/3] Rename leader-openrc.c to leader-sysvinit.c Signed-off-by: Nathaniel Russell <46272571+nater1983@users.noreply.github.com> --- gnome-session/{leader-openrc.c => leader-sysvinit.c} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename gnome-session/{leader-openrc.c => leader-sysvinit.c} (100%) diff --git a/gnome-session/leader-openrc.c b/gnome-session/leader-sysvinit.c similarity index 100% rename from gnome-session/leader-openrc.c rename to gnome-session/leader-sysvinit.c From 2b732d793247ac0d669b4322f426d9c4a77c2fd7 Mon Sep 17 00:00:00 2001 From: Nathaniel Russell <46272571+nater1983@users.noreply.github.com> Date: Fri, 16 Jan 2026 21:22:20 -0600 Subject: [PATCH 3/3] Add support for SysVinit in meson.build Signed-off-by: Nathaniel Russell <46272571+nater1983@users.noreply.github.com> --- gnome-session/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gnome-session/meson.build b/gnome-session/meson.build index dc5a0a5..1f05bf0 100644 --- a/gnome-session/meson.build +++ b/gnome-session/meson.build @@ -26,7 +26,7 @@ sources = files( if use_openrc sources += files('leader-openrc.c') else - sources += files('leader-systemd.c') + sources += files('leader-sysvinit.c') endif executable( From a69959a9d85d8bb662623df33b4f6c0082a3e9d2 Mon Sep 17 00:00:00 2001 From: Nathaniel Russell <46272571+nater1983@users.noreply.github.com> Date: Fri, 16 Jan 2026 21:33:59 -0600 Subject: [PATCH] Update gnome-session-ctl.c Signed-off-by: Nathaniel Russell <46272571+nater1983@users.noreply.github.com> --- tools/gnome-session-ctl.c | 435 ++++++++++++++------------------------ 1 file changed, 160 insertions(+), 275 deletions(-) diff --git a/tools/gnome-session-ctl.c b/tools/gnome-session-ctl.c index e0a5536..39d8f6e 100644 --- a/tools/gnome-session-ctl.c +++ b/tools/gnome-session-ctl.c @@ -1,25 +1,13 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- - * gnome-session-tl.c - Small utility program to manage gnome systemd session. - - Copyright (C) 1998 Tom Tromey - Copyright (C) 2008,2019 Red Hat, Inc. - - 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, 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, see . -*/ + * gnome-session-tl.c - Small utility program to manage GNOME session leader + * + * 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, or (at your option) + * any later version. + */ #include - #include #include #include @@ -28,309 +16,206 @@ #include #include #include -#include - #include #include -#include -#include #include +#include + +#include #ifdef USE_OPENRC -# include +# include #endif -#define GSM_SERVICE_DBUS "org.gnome.SessionManager" -#define GSM_PATH_DBUS "/org/gnome/SessionManager" -#define GSM_INTERFACE_DBUS "org.gnome.SessionManager" +#include + +typedef struct { + GMainLoop *loop; + gint fifo_fd; +} MonitorLeader; -#define SYSTEMD_DBUS "org.freedesktop.systemd1" -#define SYSTEMD_PATH_DBUS "/org/freedesktop/systemd1" -#define SYSTEMD_INTERFACE_DBUS "org.freedesktop.systemd1.Manager" +/* ------------------ SysVinit / OpenRC support ------------------ */ #ifdef USE_OPENRC static gboolean -async_run_cmd(gchar** argv, GError **error) +async_run_cmd(gchar **argv, GError **error) { - return g_spawn_async(NULL, - argv, - NULL, - G_SPAWN_DEFAULT, - NULL, - NULL, - NULL, - error); + return g_spawn_async(NULL, argv, NULL, G_SPAWN_DEFAULT, NULL, NULL, NULL, error); } #endif -static GDBusConnection * -get_session_bus (void) +static void +do_start_unit(const gchar *unit) { - g_autoptr(GError) error = NULL; - GDBusConnection *bus; + g_autoptr(GError) error = NULL; - bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); - - if (bus == NULL) - g_warning ("Couldn't connect to session bus: %s", error->message); - - return bus; +#ifdef USE_OPENRC + gchar *rl_argv[] = { "/usr/bin/openrc", "-U", "default", NULL }; + if (!async_run_cmd(rl_argv, &error)) + g_warning("Failed to start OpenRC unit: %s", error ? error->message : "(no message)"); +#else + gchar *argv[] = { "/etc/init.d/gnome-session-shutdown", "start", NULL }; + if (!g_spawn_async(NULL, argv, NULL, G_SPAWN_DEFAULT, NULL, NULL, NULL, &error)) + g_warning("Failed to start SysVinit unit: %s", error ? error->message : "(no message)"); +#endif } -static void -do_signal_init (void) -{ - g_autoptr(GDBusConnection) connection = NULL; - g_autoptr(GVariant) reply = NULL; - g_autoptr(GError) error = NULL; - - connection = get_session_bus (); - if (connection == NULL) - return; - - reply = g_dbus_connection_call_sync (connection, - GSM_SERVICE_DBUS, - GSM_PATH_DBUS, - GSM_INTERFACE_DBUS, - "Initialized", - NULL, - NULL, - G_DBUS_CALL_FLAGS_NO_AUTO_START, - -1, NULL, &error); - - if (error != NULL) - g_warning ("Failed to call signal initialization: %s", - error->message); -} +/* ------------------ D-Bus Helpers ------------------ */ -static void -do_start_unit (const gchar *unit, const char *mode) +static GDBusConnection * +get_session_bus(void) { - g_autoptr(GDBusConnection) connection = NULL; - g_autoptr(GVariant) reply = NULL; - g_autoptr(GError) error = NULL; - - connection = get_session_bus (); - if (connection == NULL) - return; - - reply = g_dbus_connection_call_sync (connection, - SYSTEMD_DBUS, - SYSTEMD_PATH_DBUS, - SYSTEMD_INTERFACE_DBUS, - "StartUnit", - g_variant_new ("(ss)", - unit, - mode), - NULL, - G_DBUS_CALL_FLAGS_NO_AUTO_START, - -1, NULL, &error); - - if (error != NULL) - g_warning ("Failed to start shutdown target: %s", - error->message); + g_autoptr(GError) error = NULL; + GDBusConnection *bus; + + bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error); + if (!bus) + g_warning("Couldn't connect to session bus: %s", error->message); + + return bus; } static void -do_restart_dbus (void) +do_signal_init(void) { - g_autoptr(GDBusConnection) connection = NULL; - g_autoptr(GVariant) reply = NULL; - g_autoptr(GError) error = NULL; - - connection = get_session_bus (); - if (connection == NULL) - return; - - reply = g_dbus_connection_call_sync (connection, - SYSTEMD_DBUS, - SYSTEMD_PATH_DBUS, - SYSTEMD_INTERFACE_DBUS, - "StopUnit", - g_variant_new ("(ss)", - "dbus.service", - "fail"), - NULL, - G_DBUS_CALL_FLAGS_NO_AUTO_START, - -1, NULL, &error); - - if (error != NULL) - g_warning ("Failed to restart DBus service: %s", - error->message); + g_autoptr(GDBusConnection) connection = get_session_bus(); + if (!connection) + return; + + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) reply = g_dbus_connection_call_sync(connection, + "org.gnome.SessionManager", + "/org/gnome/SessionManager", + "org.gnome.SessionManager", + "Initialized", + NULL, + NULL, + G_DBUS_CALL_FLAGS_NO_AUTO_START, + -1, NULL, &error); + if (error) + g_warning("Failed to call signal initialization: %s", error->message); } -typedef struct { - GMainLoop *loop; - gint fifo_fd; -} MonitorLeader; +/* ------------------ FIFO Monitoring ------------------ */ static gboolean -leader_term_or_int_signal_cb (gpointer user_data) +leader_term_or_int_signal_cb(gpointer user_data) { - MonitorLeader *data = (MonitorLeader*) user_data; - - g_main_loop_quit (data->loop); - - return G_SOURCE_REMOVE; + MonitorLeader *data = (MonitorLeader*)user_data; + g_main_loop_quit(data->loop); + return G_SOURCE_REMOVE; } static gboolean -leader_fifo_io_cb (gint fd, - GIOCondition condition, - gpointer user_data) +leader_fifo_io_cb(gint fd, GIOCondition condition, gpointer user_data) { - MonitorLeader *data = (MonitorLeader*) user_data; + MonitorLeader *data = (MonitorLeader*)user_data; - sd_notify (0, "STOPPING=1"); + /* Notify monitor / session manager about STOPPING */ + sd_notify(0, "STOPPING=1"); - if (condition & G_IO_IN) { - char buf[1]; - read (data->fifo_fd, buf, 1); - g_main_loop_quit (data->loop); - } + if (condition & G_IO_IN) { + char buf[1]; + read(data->fifo_fd, buf, 1); + g_main_loop_quit(data->loop); + } - if (condition & G_IO_HUP) { - g_main_loop_quit (data->loop); - } + if (condition & G_IO_HUP) { + g_main_loop_quit(data->loop); + } - return G_SOURCE_CONTINUE; + return G_SOURCE_CONTINUE; } -/** - * do_monitor_leader: - * - * Function to monitor the leader to ensure clean session shutdown and - * propagation of this information to/from loginctl/GDM. - * See main.c systemd_leader_run() for more information. - */ static void -do_monitor_leader (void) +do_monitor_leader(void) { - MonitorLeader data; - g_autofree char *fifo_name = NULL; - int res; - - data.loop = g_main_loop_new (NULL, TRUE); - - fifo_name = g_strdup_printf ("%s/gnome-session-leader-fifo", - g_get_user_runtime_dir ()); - res = mkfifo (fifo_name, 0666); - if (res < 0 && errno != EEXIST) - g_warning ("Error creating FIFO: %m"); - - data.fifo_fd = g_open (fifo_name, O_RDONLY | O_CLOEXEC, 0666); - if (data.fifo_fd >= 0) { - struct stat buf; - - res = fstat (data.fifo_fd, &buf); - if (res < 0) { - g_warning ("Unable to monitor session leader: stat failed with error %m"); - sd_notifyf (0, "STATUS=Unable to monitor session leader: FD is not a FIFO %m"); - close (data.fifo_fd); - data.fifo_fd = -1; - } else if (!(buf.st_mode & S_IFIFO)) { - g_warning ("Unable to monitor session leader: FD is not a FIFO"); - sd_notify (0, "STATUS=Unable to monitor session leader: FD is not a FIFO"); - close (data.fifo_fd); - data.fifo_fd = -1; - } else { - sd_notify (0, "STATUS=Watching session leader"); - g_unix_fd_add (data.fifo_fd, G_IO_HUP | G_IO_IN, leader_fifo_io_cb, &data); - } + MonitorLeader data; + g_autofree char *fifo_name = NULL; + int res; + + data.loop = g_main_loop_new(NULL, TRUE); + + fifo_name = g_strdup_printf("%s/gnome-session-leader-fifo", + g_get_user_runtime_dir()); + res = mkfifo(fifo_name, 0666); + if (res < 0 && errno != EEXIST) + g_warning("Error creating FIFO: %m"); + + data.fifo_fd = g_open(fifo_name, O_RDONLY | O_CLOEXEC, 0666); + if (data.fifo_fd >= 0) { + struct stat buf; + res = fstat(data.fifo_fd, &buf); + if (res < 0 || !(buf.st_mode & S_IFIFO)) { + g_warning("FD is not a FIFO, cannot monitor leader"); + close(data.fifo_fd); + data.fifo_fd = -1; } else { - g_warning ("Unable to monitor session leader: Opening FIFO failed with %m"); - sd_notifyf (0, "STATUS=Unable to monitor session leader: Opening FIFO failed with %m"); + sd_notify(0, "STATUS=Watching session leader"); + g_unix_fd_add(data.fifo_fd, G_IO_HUP | G_IO_IN, leader_fifo_io_cb, &data); } + } else { + g_warning("Failed to open FIFO: %m"); + } - g_unix_signal_add (SIGTERM, leader_term_or_int_signal_cb, &data); - g_unix_signal_add (SIGINT, leader_term_or_int_signal_cb, &data); - - g_main_loop_run (data.loop); + g_unix_signal_add(SIGTERM, leader_term_or_int_signal_cb, &data); + g_unix_signal_add(SIGINT, leader_term_or_int_signal_cb, &data); - g_main_loop_unref (data.loop); - /* FD is closed with the application. */ + g_main_loop_run(data.loop); + g_main_loop_unref(data.loop); } -int -main (int argc, char *argv[]) -{ - g_autoptr(GError) error = NULL; - static gboolean opt_shutdown; - static gboolean opt_monitor; - static gboolean opt_signal_init; - static gboolean opt_restart_dbus; - static gboolean opt_exec_stop_check; - int conflicting_options; - GOptionContext *ctx; - static const GOptionEntry options[] = { - { "shutdown", '\0', 0, G_OPTION_ARG_NONE, &opt_shutdown, N_("Start gnome-session-shutdown service"), NULL }, - { "monitor", '\0', 0, G_OPTION_ARG_NONE, &opt_monitor, N_("Start gnome-session-shutdown service when receiving EOF or a single byte on stdin"), NULL }, - { "signal-init", '\0', 0, G_OPTION_ARG_NONE, &opt_signal_init, N_("Signal initialization done to gnome-session"), NULL }, -#ifndef USE_OPENRC - { "restart-dbus", '\0', 0, G_OPTION_ARG_NONE, &opt_restart_dbus, N_("Restart dbus service if it is running"), NULL }, - { "exec-stop-check", '\0', 0, G_OPTION_ARG_NONE, &opt_exec_stop_check, N_("Run from ExecStopPost to start gnome-session-shutdown service on service failure"), NULL }, -#endif - { NULL }, - }; - - /* Initialize the i18n stuff */ - setlocale (LC_ALL, ""); - bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - textdomain (GETTEXT_PACKAGE); - - ctx = g_option_context_new (""); - g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE); - if (! g_option_context_parse (ctx, &argc, &argv, &error)) { - g_warning ("Unable to start: %s", error->message); - exit (1); - } - g_option_context_free (ctx); - - conflicting_options = 0; - if (opt_shutdown) - conflicting_options++; - if (opt_monitor) - conflicting_options++; - if (opt_signal_init) - conflicting_options++; - if (opt_restart_dbus) - conflicting_options++; - if (opt_exec_stop_check) - conflicting_options++; - if (conflicting_options != 1) { - g_printerr (_("Program needs exactly one parameter")); - exit (1); - } - - sd_notify (0, "READY=1"); - - - if (opt_signal_init) { - do_signal_init (); - } else if (opt_restart_dbus) { - do_restart_dbus (); - } else if (opt_shutdown) { -#ifdef USE_OPENRC - gchar *rl_argv[] = { "/usr/bin/openrc", "-U", "default", NULL }; - if (!async_run_cmd(rl_argv, &error)) - g_error("Failed to start unit"); -#else - do_start_unit ("gnome-session-shutdown.target", "replace-irreversibly"); -#endif - } else if (opt_monitor) { - do_monitor_leader (); -#ifndef USE_OPENRC - do_start_unit ("gnome-session-shutdown.target", "replace-irreversibly"); -#endif - } else if (opt_exec_stop_check) { - /* Start failed target if the restart limit was hit */ - if (g_strcmp0 ("start-limit-hit", g_getenv ("SERVICE_RESULT")) == 0) { - do_start_unit ("gnome-session-shutdown.target", "fail"); - } - } else { - g_assert_not_reached (); - } +/* ------------------ Main ------------------ */ - return 0; +int main(int argc, char *argv[]) +{ + g_autoptr(GError) error = NULL; + static gboolean opt_shutdown = FALSE; + static gboolean opt_monitor = FALSE; + static gboolean opt_signal_init = FALSE; + + GOptionContext *ctx; + static const GOptionEntry options[] = { + { "shutdown", '\0', 0, G_OPTION_ARG_NONE, &opt_shutdown, "Start gnome-session-shutdown service", NULL }, + { "monitor", '\0', 0, G_OPTION_ARG_NONE, &opt_monitor, "Monitor leader FIFO for session shutdown", NULL }, + { "signal-init", '\0', 0, G_OPTION_ARG_NONE, &opt_signal_init, "Signal initialization done to gnome-session", NULL }, + { NULL } + }; + + /* i18n init */ + setlocale(LC_ALL, ""); + bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR); + bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); + textdomain(GETTEXT_PACKAGE); + + ctx = g_option_context_new(""); + g_option_context_add_main_entries(ctx, options, GETTEXT_PACKAGE); + if (!g_option_context_parse(ctx, &argc, &argv, &error)) { + g_warning("Unable to start: %s", error->message); + exit(1); + } + g_option_context_free(ctx); + + /* Exactly one option must be provided */ + int opt_count = (opt_shutdown ? 1 : 0) + (opt_monitor ? 1 : 0) + (opt_signal_init ? 1 : 0); + if (opt_count != 1) { + g_printerr("Program needs exactly one parameter\n"); + exit(1); + } + + sd_notify(0, "READY=1"); + + if (opt_signal_init) { + do_signal_init(); + } else if (opt_shutdown) { + do_start_unit("gnome-session-shutdown.target"); + } else if (opt_monitor) { + do_monitor_leader(); + /* Ensure shutdown after monitor exits */ + do_start_unit("gnome-session-shutdown.target"); + } else { + g_assert_not_reached(); + } + + return 0; }