chiark / gitweb /
Prep v235: Allow elogind to daemonize itself with "-D|--daemon".
authorSven Eden <yamakuzure@gmx.net>
Wed, 16 Aug 2017 08:28:51 +0000 (10:28 +0200)
committerSven Eden <yamakuzure@gmx.net>
Wed, 16 Aug 2017 08:30:24 +0000 (10:30 +0200)
src/login/elogind.c
src/login/elogind.h
src/login/logind.c

index 30cab4949820a90262b2042d0c3919e9e07e28cd..43c9e3d9eec01227e72eae4b0a0ab74dbf8a37d9 100644 (file)
 #include "cgroup.h"
 #include "elogind.h"
 #include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
 #include "mount-setup.h"
+#include "process-util.h"
 #include "socket-util.h"
+#include "stdio-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "umask-util.h"
 
 
 #define CGROUPS_AGENT_RCVBUF_SIZE (8*1024*1024)
+#define ELOGIND_PID_FILE "/run/elogind.pid"
+
+
+static void remove_pid_file(void) {
+        if (access(ELOGIND_PID_FILE, F_OK) == 0)
+                unlink_noerrno(ELOGIND_PID_FILE);
+}
+
+
+/* daemonize elogind by double forking.
+   The grand child returns 0.
+   The parent and child return their forks PID.
+   On error, a value < 0 is returned.
+*/
+int elogind_daemonize(void) {
+        char c[DECIMAL_STR_MAX(pid_t) + 2];
+        pid_t child;
+        pid_t grandchild;
+        pid_t SID;
+        int r;
+
+        child = fork();
+
+        if (child < 0)
+                return log_error_errno(errno, "Failed to fork: %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;
+                return child;
+        }
+
+        /* 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");
+        umask(0022);
+
+        /* Now the grandchild, the true daemon, can be created. */
+        grandchild = fork();
+
+        if (grandchild < 0)
+                return log_error_errno(errno, "Failed to double fork: %m");
+
+        if (grandchild)
+                /* Exit immediately! */
+                return grandchild;
+
+        close_all_fds(NULL, 0);
+        umask(0022);
+
+        /* Take care of our PID-file now */
+        grandchild = getpid_cached();
+
+        xsprintf(c, PID_FMT "\n", grandchild);
+
+        r = write_string_file(ELOGIND_PID_FILE, c,
+                              WRITE_STRING_FILE_CREATE |
+                              WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+        if (r < 0)
+                log_error_errno(-r, "Failed to write PID file /run/elogind.pid: %m");
+
+        /* Make sure the PID file gets cleaned up on exit! */
+        atexit(remove_pid_file);
+
+        return 0;
+}
 
 
 static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
index 3a6b89b744893be8b6c26f6237b6fb056638173e..637f564e996a03b539d2bd2ab85dace9a617250a 100644 (file)
 #include "sd-bus.h"
 
 
-/// Add-Ons for manager_connect_bus()
-int  elogind_setup_cgroups_agent(Manager *m);
+/// Add-On for main() to daemonize elogind upon request with a double fork
+int elogind_daemonize(void);
+
+/// Add-On for manager_connect_bus()
+int elogind_setup_cgroups_agent(Manager *m);
 
 /// Add-On for manager_free()
 void elogind_manager_free(Manager* m);
index b09ecf6118934962b8310cd4f34bcc76673fffd9..b66f9a3a509c769e33daf6c3fd18d78e8b4ce5b2 100644 (file)
@@ -1280,6 +1280,25 @@ int main(int argc, char *argv[]) {
 
         umask(0022);
 
+#if 1 /// elogind allows to be daemonized using one argument "-D" / "--daemon"
+        if (argc == 2) {
+
+                if (!argv[1] || (0 == strlen(argv[1]))
+                  || ( !streq(argv[1], "-D")
+                    && !streq(argv[1], "--daemon") ) ) {
+                        fprintf(stderr, "%s [-D|--daemon]\n", argv[0]);
+                        r = -EINVAL;
+                        goto finish;
+                }
+
+                r = elogind_daemonize();
+                if (r)
+                        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;;
+
+                argc = 1; /* Use the rest of main() as usual */
+        }
+#endif // 1
+
         if (argc != 1) {
                 log_error("This program takes no arguments.");
                 r = -EINVAL;