Add daemonize() to libcommon
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Mon, 27 Jan 2014 03:23:09 +0000 (22:23 -0500)
committerDavid Goulet <dgoulet@efficios.com>
Tue, 28 Jan 2014 21:19:41 +0000 (16:19 -0500)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
src/common/Makefile.am
src/common/daemonize.c [new file with mode: 0644]
src/common/daemonize.h [new file with mode: 0644]

index a8dccc617e0d3dfca1fda305f5671e885e10ec13..3ba5fed5149ab91ff8536e7566858919b93dd34e 100644 (file)
@@ -14,7 +14,8 @@ noinst_LTLIBRARIES = libcommon.la
 
 libcommon_la_SOURCES = error.h error.c utils.c utils.h runas.c runas.h \
                        common.h futex.c futex.h uri.c uri.h defaults.c \
-                       pipe.c pipe.h readwrite.c readwrite.h
+                       pipe.c pipe.h readwrite.c readwrite.h \
+                       daemonize.c daemonize.h
 libcommon_la_LIBADD = -luuid
 
 # Consumer library
diff --git a/src/common/daemonize.c b/src/common/daemonize.c
new file mode 100644 (file)
index 0000000..a8e2906
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
+ * Copyright (C) 2014 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License, version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <paths.h>
+#include <fcntl.h>
+#include <wait.h>
+#include <stdlib.h>
+
+#include <urcu/system.h>
+
+#include <src/common/daemonize.h>
+#include <src/common/error.h>
+
+int lttng_daemonize(pid_t *child_ppid, int *completion_flag,
+               int close_fds)
+{
+       int ret;
+       pid_t pid;
+
+       /* Get parent pid of this process. */
+       *child_ppid = getppid();
+
+       pid = fork();
+       if (pid < 0) {
+               PERROR("fork");
+               goto error;
+       } else if (pid == 0) {
+               int fd;
+               pid_t sid;
+
+               /* Child */
+
+               /*
+                * Get the newly created parent pid so we can signal
+                * that process when we are ready to operate.
+                */
+               *child_ppid = getppid();
+
+               sid = setsid();
+               if (sid < 0) {
+                       PERROR("setsid");
+                       goto error;
+               }
+
+               /*
+                * Try to change directory to /. If we can't well at
+                * least notify.
+                */
+               ret = chdir("/");
+               if (ret < 0) {
+                       PERROR("chdir");
+               }
+
+               if (close_fds) {
+                       fd = open(_PATH_DEVNULL, O_RDWR, 0);
+                       if (fd < 0) {
+                               PERROR("open %s", _PATH_DEVNULL);
+                               /*
+                                * Let 0, 1 and 2 open since we can't
+                                * bind them to /dev/null.
+                                */
+                       } else {
+                               (void) dup2(fd, STDIN_FILENO);
+                               (void) dup2(fd, STDOUT_FILENO);
+                               (void) dup2(fd, STDERR_FILENO);
+                               if (fd > 2) {
+                                       ret = close(fd);
+                                       if (ret < 0) {
+                                               PERROR("close");
+                                       }
+                               }
+                       }
+               }
+               goto end;
+       } else {
+               /* Parent */
+
+               /*
+                * Waiting for child to notify this parent that it can
+                * exit. Note that sleep() is interrupted before the 1
+                * second delay as soon as the signal is received, so it
+                * will not cause visible delay for the user.
+                */
+               while (!CMM_LOAD_SHARED(*completion_flag)) {
+                       int status;
+                       pid_t ret;
+
+                       /*
+                        * Check if child exists without blocking. If
+                        * so, we have to stop this parent process and
+                        * return an error.
+                        */
+                       ret = waitpid(pid, &status, WNOHANG);
+                       if (ret < 0 || (ret != 0 && WIFEXITED(status))) {
+                               /* The child exited somehow or was not valid. */
+                               goto error;
+                       }
+                       sleep(1);
+               }
+
+               /*
+                * From this point on, the parent can exit and the child
+                * is now an operationnal session daemon ready to serve
+                * clients and applications.
+                */
+               exit(EXIT_SUCCESS);
+       }
+
+end:
+       return 0;
+
+error:
+       return -1;
+}
diff --git a/src/common/daemonize.h b/src/common/daemonize.h
new file mode 100644 (file)
index 0000000..345c5a5
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef LTTNG_DAEMONIZE_H
+#define LTTNG_DAEMONIZE_H
+
+/*
+ * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
+ * Copyright (C) 2014 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License, version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <unistd.h>
+
+/*
+ * Daemonize this process by forking and making the parent wait for the child
+ * to signal it indicating readiness. Once received, the parent successfully
+ * quits.
+ *
+ * The child process undergoes the same action that daemon(3) does meaning
+ * setsid, chdir, and dup /dev/null into 0, 1 and 2.
+ *
+ * Return 0 on success else -1 on error.
+ */
+int lttng_daemonize(pid_t *child_ppid, int *completion_flag,
+               int close_fds);
+
+#endif /* LTTNG_DAEMONIZE_H */
This page took 0.027532 seconds and 4 git commands to generate.