From: Sven Eden Date: Wed, 16 Aug 2017 08:28:51 +0000 (+0200) Subject: Prep v235: Allow elogind to daemonize itself with "-D|--daemon". X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=132565d5bc5f179532fe56c08abbba979e342a35;p=elogind.git Prep v235: Allow elogind to daemonize itself with "-D|--daemon". --- diff --git a/src/login/elogind.c b/src/login/elogind.c index 30cab4949..43c9e3d9e 100644 --- a/src/login/elogind.c +++ b/src/login/elogind.c @@ -22,14 +22,90 @@ #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) { diff --git a/src/login/elogind.h b/src/login/elogind.h index 3a6b89b74..637f564e9 100644 --- a/src/login/elogind.h +++ b/src/login/elogind.h @@ -26,8 +26,11 @@ #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); diff --git a/src/login/logind.c b/src/login/logind.c index b09ecf611..b66f9a3a5 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -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;