300851bb3ca6e01a8b3d10fe824c8b2935172b0d
[lttng-tools.git] / src / common / daemonize.c
1 /*
2 * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
3 * Copyright (C) 2014 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License, version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 51
16 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #define _LGPL_SOURCE
20 #include <unistd.h>
21 #include <common/compat/paths.h>
22 #include <fcntl.h>
23 #include <wait.h>
24 #include <stdlib.h>
25
26 #include <urcu/system.h>
27
28 #include <src/common/daemonize.h>
29 #include <src/common/error.h>
30
31 LTTNG_HIDDEN
32 int lttng_daemonize(pid_t *child_ppid, int *completion_flag,
33 int close_fds)
34 {
35 int ret;
36 pid_t pid;
37
38 /* Get parent pid of this process. */
39 *child_ppid = getppid();
40
41 pid = fork();
42 if (pid < 0) {
43 PERROR("fork");
44 goto error;
45 } else if (pid == 0) {
46 int fd;
47 pid_t sid;
48
49 /* Child */
50
51 /*
52 * Get the newly created parent pid so we can signal
53 * that process when we are ready to operate.
54 */
55 *child_ppid = getppid();
56
57 sid = setsid();
58 if (sid < 0) {
59 PERROR("setsid");
60 goto error;
61 }
62
63 /*
64 * Try to change directory to /. If we can't well at
65 * least notify.
66 */
67 ret = chdir("/");
68 if (ret < 0) {
69 PERROR("chdir");
70 }
71
72 if (close_fds) {
73 fd = open(_PATH_DEVNULL, O_RDWR, 0);
74 if (fd < 0) {
75 PERROR("open %s", _PATH_DEVNULL);
76 /*
77 * Let 0, 1 and 2 open since we can't
78 * bind them to /dev/null.
79 */
80 } else {
81 (void) dup2(fd, STDIN_FILENO);
82 (void) dup2(fd, STDOUT_FILENO);
83 (void) dup2(fd, STDERR_FILENO);
84 if (fd > 2) {
85 ret = close(fd);
86 if (ret < 0) {
87 PERROR("close");
88 }
89 }
90 }
91 }
92 goto end;
93 } else {
94 /* Parent */
95
96 /*
97 * Waiting for child to notify this parent that it can
98 * exit. Note that sleep() is interrupted before the 1
99 * second delay as soon as the signal is received, so it
100 * will not cause visible delay for the user.
101 */
102 while (!CMM_LOAD_SHARED(*completion_flag)) {
103 int status;
104 pid_t ret;
105
106 /*
107 * Check if child exists without blocking. If
108 * so, we have to stop this parent process and
109 * return an error.
110 */
111 ret = waitpid(pid, &status, WNOHANG);
112 if (ret < 0 || (ret != 0 && WIFEXITED(status))) {
113 /* The child exited somehow or was not valid. */
114 goto error;
115 }
116 sleep(1);
117 }
118
119 /*
120 * From this point on, the parent can exit and the child
121 * is now an operationnal session daemon ready to serve
122 * clients and applications.
123 */
124 exit(EXIT_SUCCESS);
125 }
126
127 end:
128 return 0;
129
130 error:
131 return -1;
132 }
This page took 0.046293 seconds and 4 git commands to generate.