summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSven Eden <yamakuzure@gmx.net>2017-08-16 10:28:51 +0200
committerSven Eden <yamakuzure@gmx.net>2017-08-16 10:30:24 +0200
commit132565d5bc5f179532fe56c08abbba979e342a35 (patch)
tree8fb64992be5d4e5b217d46ae15c77aee53f3826e
parentbd290286fb032bfdb03901202245621ccc2908ba (diff)
Prep v235: Allow elogind to daemonize itself with "-D|--daemon".
-rw-r--r--src/login/elogind.c76
-rw-r--r--src/login/elogind.h7
-rw-r--r--src/login/logind.c19
3 files changed, 100 insertions, 2 deletions
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;