common: uuid: add `uuid_to_str` which returns an std::string
[lttng-tools.git] / src / common / daemonize.cpp
1 /*
2 * Copyright (C) 2013 David Goulet <dgoulet@efficios.com>
3 * Copyright (C) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-only
6 *
7 */
8
9 #define _LGPL_SOURCE
10 #include <unistd.h>
11 #include <common/compat/paths.hpp>
12 #include <fcntl.h>
13 #include <sys/wait.h>
14 #include <stdlib.h>
15
16 #include <urcu/system.h>
17
18 #include <common/daemonize.hpp>
19 #include <common/error.hpp>
20
21 int lttng_daemonize(pid_t *child_ppid, int *completion_flag,
22 int close_fds)
23 {
24 pid_t pid;
25
26 /* Get parent pid of this process. */
27 *child_ppid = getppid();
28
29 pid = fork();
30 if (pid < 0) {
31 PERROR("fork");
32 goto error;
33 } else if (pid == 0) {
34 int fd;
35 pid_t sid;
36 int ret;
37
38 /* Child */
39
40 /*
41 * Get the newly created parent pid so we can signal
42 * that process when we are ready to operate.
43 */
44 *child_ppid = getppid();
45
46 sid = setsid();
47 if (sid < 0) {
48 PERROR("setsid");
49 goto error;
50 }
51
52 /*
53 * Try to change directory to /. If we can't well at
54 * least notify.
55 */
56 ret = chdir("/");
57 if (ret < 0) {
58 PERROR("chdir");
59 }
60
61 if (close_fds) {
62 fd = open(_PATH_DEVNULL, O_RDWR, 0);
63 if (fd < 0) {
64 PERROR("open %s", _PATH_DEVNULL);
65 /*
66 * Let 0, 1 and 2 open since we can't
67 * bind them to /dev/null.
68 */
69 } else {
70 (void) dup2(fd, STDIN_FILENO);
71 (void) dup2(fd, STDOUT_FILENO);
72 (void) dup2(fd, STDERR_FILENO);
73 if (fd > 2) {
74 ret = close(fd);
75 if (ret < 0) {
76 PERROR("close");
77 }
78 }
79 }
80 }
81 goto end;
82 } else {
83 /* Parent */
84
85 /*
86 * Waiting for child to notify this parent that it can
87 * exit. Note that sleep() is interrupted before the 1
88 * second delay as soon as the signal is received, so it
89 * will not cause visible delay for the user.
90 */
91 while (!CMM_LOAD_SHARED(*completion_flag)) {
92 int status;
93 pid_t ret;
94
95 /*
96 * Check if child exists without blocking. If
97 * so, we have to stop this parent process and
98 * return an error.
99 */
100 ret = waitpid(pid, &status, WNOHANG);
101 if (ret < 0 || (ret != 0 && WIFEXITED(status))) {
102 /* The child exited somehow or was not valid. */
103 goto error;
104 }
105 sleep(1);
106 }
107
108 /*
109 * From this point on, the parent can exit and the child
110 * is now an operational session daemon ready to serve
111 * clients and applications.
112 */
113 exit(EXIT_SUCCESS);
114 }
115
116 end:
117 return 0;
118
119 error:
120 return -1;
121 }
This page took 0.033755 seconds and 4 git commands to generate.