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