X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Fdaemonize.cpp;fp=src%2Fcommon%2Fdaemonize.cpp;h=16af5a3f78ccec5da76033a48a7d0a04bd0c38f2;hp=0000000000000000000000000000000000000000;hb=a6bc4ca9d659caf016ef932fcd944029737ac57c;hpb=97535efaa975ca52bf02c2d5e76351bfd2e3defa diff --git a/src/common/daemonize.cpp b/src/common/daemonize.cpp new file mode 100644 index 000000000..16af5a3f7 --- /dev/null +++ b/src/common/daemonize.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2013 David Goulet + * Copyright (C) 2014 Mathieu Desnoyers + * + * SPDX-License-Identifier: GPL-2.0-only + * + */ + +#define _LGPL_SOURCE +#include +#include +#include +#include +#include + +#include + +#include +#include + +int lttng_daemonize(pid_t *child_ppid, int *completion_flag, + int close_fds) +{ + 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; + int ret; + + /* 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 operational session daemon ready to serve + * clients and applications. + */ + exit(EXIT_SUCCESS); + } + +end: + return 0; + +error: + return -1; +}