chiark / gitweb /
Prep v239: Fix main() to call manager_new() again.
[elogind.git] / src / login / elogind.c
index 79037a4d922182818e086e7266004d64916df6ab..9fe52a94c1e9005aee93c96f4f979cf10625fe92 100644 (file)
@@ -27,6 +27,7 @@
 #include "mount-setup.h"
 #include "parse-util.h"
 #include "process-util.h"
+#include "signal-util.h"
 #include "socket-util.h"
 #include "stdio-util.h"
 #include "string-util.h"
 #  define ELOGIND_PID_FILE "/run/elogind.pid"
 #endif // ELOGIND_PID_FILE
 
+
+static int elogind_signal_handler(sd_event_source *s,
+                                   const struct signalfd_siginfo *si,
+                                   void *userdata) {
+        Manager *m = userdata;
+        int r;
+
+        log_warning("Received signal %u [%s]", si->ssi_signo,
+                    signal_to_string(si->ssi_signo));
+
+        r = sd_event_get_state(m->event);
+
+        if (r != SD_EVENT_FINISHED)
+                sd_event_exit(m->event, si->ssi_signo);
+
+        return 0;
+}
+
+
 static void remove_pid_file(void) {
         if (access(ELOGIND_PID_FILE, F_OK) == 0)
                 unlink_noerrno(ELOGIND_PID_FILE);
@@ -77,58 +97,52 @@ static int elogind_daemonize(void) {
         pid_t SID;
         int r;
 
-#ifdef ENABLE_DEBUG_ELOGIND
+#if ENABLE_DEBUG_ELOGIND
         log_notice("Double forking elogind");
         log_notice("Parent PID     : %5d", getpid_cached());
         log_notice("Parent SID     : %5d", getsid(getpid_cached()));
 #endif // ENABLE_DEBUG_ELOGIND
 
-        child = fork();
+        r = safe_fork_full("elogind-forker", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_NULL_STDIO|FORK_WAIT, &child);
 
-        if (child < 0)
-                return log_error_errno(errno, "Failed to fork: %m");
+        if (r < 0)
+                return log_error_errno(errno, "Failed to fork daemon leader: %m");
 
-        if (child) {
-                /* Wait for the child to terminate, so the decoupling
-                 * is guaranteed to succeed.
-                 */
-                r = wait_for_terminate_and_warn("elogind control child", child, true);
-                if (r < 0)
-                        return r;
+        /* safe_fork_full() Has waited for the child to terminate, so we
+         * are safe to return here. The child already has forked off the
+         * daemon itself.
+         */
+        if (r)
                 return child;
-        }
 
-#ifdef ENABLE_DEBUG_ELOGIND
+#if ENABLE_DEBUG_ELOGIND
         log_notice("Child PID      : %5d", getpid_cached());
         log_notice("Child SID      : %5d", getsid(getpid_cached()));
 #endif // ENABLE_DEBUG_ELOGIND
 
-        /* The first child has to become a new session leader. */
-        close_all_fds(NULL, 0);
         SID = setsid();
         if ((pid_t)-1 == SID)
                 return log_error_errno(errno, "Failed to create new SID: %m");
 
-#ifdef ENABLE_DEBUG_ELOGIND
+#if ENABLE_DEBUG_ELOGIND
         log_notice("Child new SID  : %5d", getsid(getpid_cached()));
 #endif // ENABLE_DEBUG_ELOGIND
 
         umask(0022);
 
         /* Now the grandchild, the true daemon, can be created. */
-        grandchild = fork();
+        r = safe_fork_full("elogind-daemon", NULL, 0, FORK_REOPEN_LOG, &grandchild);
 
-        if (grandchild < 0)
-                return log_error_errno(errno, "Failed to double fork: %m");
+        if (r < 0)
+                return log_error_errno(errno, "Failed to fork daemon: %m");
 
-        if (grandchild)
+        if (r)
                 /* Exit immediately! */
                 return grandchild;
 
-        close_all_fds(NULL, 0);
         umask(0022);
 
-#ifdef ENABLE_DEBUG_ELOGIND
+#if ENABLE_DEBUG_ELOGIND
         log_notice("Grand child PID: %5d", getpid_cached());
         log_notice("Grand child SID: %5d", getsid(getpid_cached()));
 #endif // ENABLE_DEBUG_ELOGIND
@@ -223,7 +237,7 @@ int elogind_setup_cgroups_agent(Manager *m) {
          * to it. The system instance hence listens on this special socket, but the user instances listen on the system
          * bus for these messages. */
 
-        if (m->test_run)
+        if (m->test_run_flags)
                 return 0;
 
         if (!MANAGER_IS_SYSTEM(m))
@@ -305,7 +319,7 @@ int elogind_startup(int argc, char *argv[]) {
 
         /* Note: At this point, the logging is not initialized, so we can not
                  use log_debug_elogind(). */
-#ifdef ENABLE_DEBUG_ELOGIND
+#if ENABLE_DEBUG_ELOGIND
         log_notice("elogind startup: Daemonize: %s, Show Help: %s, Wrong arg: %s",
                 daemonize ? "True" : "False",
                 show_help ? "True" : "False",
@@ -362,15 +376,16 @@ int elogind_manager_new(Manager* m) {
 
         m->cgroups_agent_fd = -1;
         m->pin_cgroupfs_fd  = -1;
-        m->test_run         = false;
+        m->test_run_flags   = 0;
 
         /* Init sleep modes and states */
-        m->suspend_mode       = NULL;
-        m->suspend_state      = NULL;
-        m->hibernate_mode     = NULL;
-        m->hibernate_state    = NULL;
-        m->hybrid_sleep_mode  = NULL;
-        m->hybrid_sleep_state = NULL;
+        m->suspend_mode        = NULL;
+        m->suspend_state       = NULL;
+        m->hibernate_mode      = NULL;
+        m->hibernate_state     = NULL;
+        m->hybrid_sleep_mode   = NULL;
+        m->hybrid_sleep_state  = NULL;
+        m->hibernate_delay_sec = 0;
 
         /* If elogind should be its own controller, mount its cgroup */
         if (streq(SYSTEMD_CGROUP_CONTROLLER, "_elogind")) {
@@ -390,7 +405,7 @@ int elogind_manager_new(Manager* m) {
 /// Add-On for manager_reset_config()
 void elogind_manager_reset_config(Manager* m) {
 
-#ifdef ENABLE_DEBUG_ELOGIND
+#if ENABLE_DEBUG_ELOGIND
         int dbg_cnt;
 #endif // ENABLE_DEBUG_ELOGIND
 
@@ -405,8 +420,10 @@ void elogind_manager_reset_config(Manager* m) {
                 m->hybrid_sleep_mode = strv_new("suspend", "platform", "shutdown", NULL);
         if (!m->hybrid_sleep_state)
                 m->hybrid_sleep_state = strv_new("disk", NULL);
+        if (!m->hibernate_delay_sec)
+                m->hibernate_delay_sec = 180 * USEC_PER_MINUTE;
 
-#ifdef ENABLE_DEBUG_ELOGIND
+#if ENABLE_DEBUG_ELOGIND
         dbg_cnt = -1;
         while (m->suspend_mode && m->suspend_mode[++dbg_cnt])
                 log_debug_elogind("suspend_mode[%d] = %s",
@@ -431,5 +448,33 @@ void elogind_manager_reset_config(Manager* m) {
         while (m->hybrid_sleep_state[++dbg_cnt])
                 log_debug_elogind("hybrid_sleep_state[%d] = %s",
                                   dbg_cnt, m->hybrid_sleep_state[dbg_cnt]);
+        log_debug_elogind("hibernate_delay_sec: %lu seconds (%lu minutes)",
+                          m->hibernate_delay_sec / USEC_PER_SEC,
+                          m->hibernate_delay_sec / USEC_PER_MINUTE);
 #endif // ENABLE_DEBUG_ELOGIND
 }
+
+
+/// Add-On for manager_startup()
+int elogind_manager_startup(Manager *m) {
+        int r;
+
+        assert(m);
+
+        assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, -1) >= 0);
+        r = sd_event_add_signal(m->event, NULL, SIGINT, elogind_signal_handler, m);
+        if (r < 0)
+                return log_error_errno(r, "Failed to register SIGINT handler: %m");
+
+        assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGQUIT, -1) >= 0);
+        r = sd_event_add_signal(m->event, NULL, SIGQUIT, elogind_signal_handler, m);
+        if (r < 0)
+                return log_error_errno(r, "Failed to register SIGQUIT handler: %m");
+
+        assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGTERM, -1) >= 0);
+        r = sd_event_add_signal(m->event, NULL, SIGTERM, elogind_signal_handler, m);
+        if (r < 0)
+                return log_error_errno(r, "Failed to register SIGTERM handler: %m");
+
+        return 0;
+}