From: Christian Goll <cgoll@suse.com>
Date: Wed Apr 11 17:43:28 2018 +0200
Subject: split daemon in daemon_init and daemon_finish for systemd compatibilty
Patch-mainline: Not yet
Git-repo: https://github.com/SchedMD/slurm
Git-commit: fd1350631062386d845b03e98bff926299a6e23e
References: bsc#1084125

Signed-off-by: Egbert Eich <eich@suse.com>
Signed-off-by: Egbert Eich <eich@suse.de>
---
 src/common/daemonize.c | 110 +++++++++++++++++++++++++++++++++++--------------
 src/common/daemonize.h |  19 ++++++---
 2 files changed, 94 insertions(+), 35 deletions(-)
diff --git a/src/common/daemonize.c b/src/common/daemonize.c
index dc6379ac9a..db5418e9af 100644
--- a/src/common/daemonize.c
+++ b/src/common/daemonize.c
@@ -57,55 +57,105 @@
  * if noclose == 0, will close all FDs
  */
 int
-daemon(int nochdir, int noclose)
+daemon_init(void)
 {
+	int fds [2];
+	/*
+	 * Create pipe in order to get signal from grand child to terminate
+	 */
+	if (pipe (fds) < 0) {
+		error("Failed to create daemon pipe");
+	}
 	switch (fork()) {
 		case  0 : break;        /* child */
 		case -1 : return -1;
-		default : _exit(0);     /* exit parent */
+	        default : {
+			int n;
+			signed char priority;
+			char ebuf [1024];
+			if (close (fds[1]) < 0) {
+				error("Failed to close write-pipe in parent process");
+			}
+
+			/*
+			 * get signal of grandchild to exit
+			 */
+			if ((n = read (fds[0], &priority, sizeof (priority))) < 0) {
+				error("Failed to read status from grandchild process");
+			}
+			if ((n > 0) && (priority >= 0)) {
+				if ((n = read (fds[0], ebuf, sizeof (ebuf))) < 0) {
+					error("Failed to read err msg from grandchild process");
+				}
+				if ((n > 0) && (ebuf[0] != '\0')) {
+					error("Error with forking and steeing up pipe: %s", ebuf);
+				}
+				return -1;
+			}
+			_exit(0); /* exit parent */
+		}
 	}
 
 	if (setsid() < 0)
 		return -1;
 
+	if (close (fds[0]) < 0) {
+		error("Failed to close read-pipe in child process");
+	}
+
 	switch (fork()) {
 		case 0 : break;         /* child */
 		case -1: return -1;
-		default: _exit(0);      /* exit parent */
+	        default: _exit(0);      /* exit parent */
 	}
 
-	if (!nochdir && chdir("/") < 0) {
-		error("chdir(/): %m");
-		return -1;
-	}
+	return (fds[1]);
+}
+
+/*
+ * finish daemonization after pidfile was written
+ */
+
+
+void daemon_finish(int fd)
+{
+	/*
+	 * PID file was written, now do dup stdin, stdout,
+	 * and stderr onto /dev/null and close pipe
+	 * so that systemd realizes we are daemonized
+	 */
 
-	/* Close all file descriptors if requested
+	/* Close all file descriptors
 	 */
-	if (!noclose) {
-		closeall(0);
-		if (open("/dev/null", O_RDWR) != 0)
-			error("Unable to open /dev/null on stdin: %m");
-		dup2(0, STDOUT_FILENO);
-		dup2(0, STDERR_FILENO);
-	} else {
-		/*
-		 * Otherwise, dup stdin, stdout, and stderr onto /dev/null
-		 */
-		int devnull = open("/dev/null", O_RDWR);
-		if (devnull < 0)
-			error("Unable to open /dev/null: %m");
-		if (dup2(devnull, STDIN_FILENO) < 0)
-			error("Unable to dup /dev/null onto stdin: %m");
-		if (dup2(devnull, STDOUT_FILENO) < 0)
-			error("Unable to dup /dev/null onto stdout: %m");
-		if (dup2(devnull, STDERR_FILENO) < 0)
-			error("Unable to dup /dev/null onto stderr: %m");
-		if (close(devnull) < 0)
-			error("Unable to close /dev/null: %m");
+	/*
+	 * Otherwise, dup stdin, stdout, and stderr onto /dev/null
+	 */
+	int devnull = open("/dev/null", O_RDWR);
+	if (devnull < 0)
+		error("Unable to open /dev/null: %m");
+	if (dup2(devnull, STDIN_FILENO) < 0)
+		error("Unable to dup /dev/null onto stdin: %m");
+	if (dup2(devnull, STDOUT_FILENO) < 0)
+		error("Unable to dup /dev/null onto stdout: %m");
+	if (dup2(devnull, STDERR_FILENO) < 0)
+		error("Unable to dup /dev/null onto stderr: %m");
+	if (close(devnull) < 0)
+		error("Unable to close /dev/null: %m");
+	if ((fd >= 0) && (close (fd) < 0)) {
+		error( "Failed to close write-pipe in grandchild process");
 	}
+}
 
-	return 0;
+/*
+ * keep depercated api
+ */
 
+int daemon(int nochdir, int noclose)
+{
+	int ret_val;
+	ret_val = daemon_init();
+	daemon_finish(ret_val);
+	return ret_val;
 }
 
 /*
diff --git a/src/common/daemonize.h b/src/common/daemonize.h
index d7b4cc4a9a..e53111d789 100644
--- a/src/common/daemonize.h
+++ b/src/common/daemonize.h
@@ -40,14 +40,23 @@
 #ifndef _HAVE_DAEMONIZE_H
 #define _HAVE_DAEMONIZE_H
 
-/* fork process into background and inherit new session
- * if nochdir is 0, performs a chdir("/")
- * if noclose is 0, closes all fds and dups stdout/err of daemon onto /dev/null
+/* Old API - to be removed.
+ * fork process into background and inherit new session
+ * return file descriptor of pipe to communicate with child
  *
- * returns -1 on error.
+ * returns fd of pipe, -1 on error.
  */
 extern int daemon(int nochdir, int noclose);
-
+/* fork process into background and inherit new session
+ * return file descriptor of pipe to communicate with child
+ *
+ * returns fd of pipe, -1 on error.
+ */
+extern int daemon_init(void);
+/* finish daemonization - dup stdin, stdout on /dev/null if requested
+ * closes all fds and dups stdout/err of daemon onto /dev/null
+ */
+extern void daemon_finish(int fd);
 /* Write pid into file pidfile if uid is not 0 change the owner of the
  * pidfile to that user.
  */
