From 99ed9c436a035b26c64b8efcbaec8b3d91d754d6 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Sun, 26 Jan 2014 22:23:09 -0500 Subject: [PATCH] Add daemonize() to libcommon Signed-off-by: Mathieu Desnoyers --- src/common/Makefile.am | 3 +- src/common/daemonize.c | 131 +++++++++++++++++++++++++++++++++++++++++ src/common/daemonize.h | 37 ++++++++++++ 3 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 src/common/daemonize.c create mode 100644 src/common/daemonize.h diff --git a/src/common/Makefile.am b/src/common/Makefile.am index a8dccc617..3ba5fed51 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -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 index 000000000..a8e290603 --- /dev/null +++ b/src/common/daemonize.c @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2013 - David Goulet + * Copyright (C) 2014 - Mathieu Desnoyers + * + * 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 +#include +#include +#include +#include + +#include + +#include +#include + +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 index 000000000..345c5a5e6 --- /dev/null +++ b/src/common/daemonize.h @@ -0,0 +1,37 @@ +#ifndef LTTNG_DAEMONIZE_H +#define LTTNG_DAEMONIZE_H + +/* + * Copyright (C) 2013 - David Goulet + * Copyright (C) 2014 - Mathieu Desnoyers + * + * 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 + +/* + * 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 */ -- 2.34.1