]>
git.proxmox.com Git - swtpm.git/blob - src/swtpm/daemonize.c
bce735f3c56428631f114bd4db0b3647eeaa0feb
2 * daemonize.c -- Utility functions for race-free daemonization
4 * (c) Two Sigma Open Source, LLC 2021.
6 * Author: Nicolas Williams <nico@twosigma.com>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are
14 * Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
17 * Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * Neither the names of the IBM Corporation nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 #include "daemonize.h"
41 #include <sys/types.h>
52 * daemon(3) is racy because it fork()s and exits in the parent before the
53 * child can get ready to provide its services.
55 * Not every daemon can set up services before calling daemon(3), as some
56 * APIs are not fork-safe and must be called in the child-side of the
57 * daemon(3)'s fork() calls.
59 * Even if a daemon can set up services before calling daemon(3), it will not
60 * be able to write the correct PID into a pidfile until after daemon(3)
68 * some-serviced --daemon --pid=... ...
71 * call-some-service ping || echo "oops, we won the race but lost the game"
73 * To address this we split daemon(3) into two functions, daemonize_prep() and
74 * daemonize_finish(). A daemon program should call daemonize_prep() early
75 * when it knows it will have to daemonize (e.g., because of a --daemon
76 * command-line option), then it should do all the setup required to start
77 * providing its services, then it should call daemonize_finish().
79 * These two functions do all that daemon(3) does, but in two phases so that
80 * the original process that calls daemonize_prep() does not exit until the
83 * daemonize_prep() calls fork(), setsid(), and then forks again, and returns
84 * in the grandchild, but exits in the original and middle processes when the
85 * grandchild calls daemonize_finish().
90 * pid_t old_pid, new_pid;
93 * if (daemonize_prep() == -1)
94 * err(1, "Failed to daemonize");
96 * // We're now in a grandchild, but the original parent should still be
99 * assert(old_pid != new_pid);
102 * // setup sockets, listen() on them, etc...
103 * my_setup_service_and_listen_on_sockets();
105 * // Tell the waiting parent and grandparent that we're ready:
106 * // (doing this even if daemonize_prep() wasn't called is ok)
107 * daemonize_finish();
109 * // daemonize_finish() did not fork() again:
110 * assert(new_pid == getpid());
112 * Note: the processes that exit will use _exit(). The process that
113 * daemonize_prep() returns to should be able to use exit().
116 static int devnullfd
= -1;
120 wait_or_die_like_it(pid_t pid
)
124 while (waitpid(pid
, &status
, 0) == -1) {
127 /* XXX Should just use err(3). */
128 fprintf(stderr
, "waitpid() failed: %s\n", strerror(errno
));
132 if (WIFSIGNALED(status
)) {
134 * Child died in a fire; die like it so the parent sees the same exit
137 kill(getpid(), WTERMSIG(status
));
139 if (!WIFEXITED(status
)) {
140 /* If fire doesn't kill us, _exit(). */
143 /* Child exited willingly. */
144 return WEXITSTATUS(status
);
148 * Prepare to daemonize. When ready, the caller should call
149 * daemonize_finish().
151 * This arranges for the parent to exit when and only when the child is ready
152 * to service clients.
154 * This forks a grandchild and returns in the grandchild
155 * but exits in the parent and grandparent, but only once the child calls
156 * daemonize_finish() (or exits/dies, whichever comes first).
158 * Because the parent side of the fork() calls _exit(), the child can exit().
160 * Returns -1 on error (sets errno), 0 on success.
167 int save_errno
= errno
;
168 int pfds
[2] = { -1, -1 };
172 * Be idempotent. If called twice because, e.g., --daemon is given twice,
173 * do nothing the second time.
178 /* Grand parent process. */
182 if (pid
== (pid_t
)-1) {
183 fprintf(stderr
, "Failed to daemonize: Failed to fork: %s\n",
190 * Grand parent process: exit when the grandchild is ready or die in
193 _exit(wait_or_die_like_it(pid
));
196 /* Intermediate process. Detach from tty, fork() again. */
197 if (setsid() == -1) {
198 fprintf(stderr
, "Failed to daemonize: Failed to detach from tty: %s\n",
203 /* Set things up so the grandchild can finish daemonizing. */
204 devnullfd
= open("/dev/null", O_RDWR
);
205 if (devnullfd
== -1) {
206 fprintf(stderr
, "Failed to daemonize: Could not open /dev/null: %s\n",
210 if (pipe(pfds
) == -1) {
211 fprintf(stderr
, "Failed to daemonize: Could not make a pipe: %s\n",
217 /* Fork the grandchild so it cannot get a controlling tty by accident. */
219 if (pid
== (pid_t
)-1) {
220 fprintf(stderr
, "Failed to daemonize: Could not fork: %s\n",
228 * Wait for ready notification from the child, then _exit()
231 (void) close(pfds
[1]);
233 bytes
= read(pfds
[0], &buf
, sizeof(buf
));
234 } while (bytes
== -1 && errno
== EINTR
);
236 fprintf(stderr
, "Failed to daemonize: "
237 "Error reading from pipe: %s\n", strerror(errno
));
238 /* Let init reap the grandchild. */
242 /* Die like the grandchild. */
243 _exit(wait_or_die_like_it(pid
));
250 * We're on the grandchild side now, and we'll return with the expectation
251 * that the caller will call daemonize_finish(). The parent, which will
252 * continue executing this function, will _exit() when the child indicates
255 (void) close(pfds
[0]);
261 * Indicate that the service is now ready.
263 * Will cause the ancestor processes waiting in daemonize_prep() to _exit().
266 daemonize_finish(void)
269 int save_errno
= errno
;
271 /* pfds[1] will be > -1 IFF daemonize_prep() was called */
276 if (chdir("/") == -1) {
277 fprintf(stderr
, "Failed to change directory to /: %s\n",
282 if (dup2(devnullfd
, STDOUT_FILENO
) == -1) {
283 fprintf(stderr
, "Failed to redirect output stream to /dev/null: %s\n",
288 if (dup2(devnullfd
, STDERR_FILENO
) == -1) {
289 fprintf(stderr
, "Failed to redirect error stream to /dev/null: %s\n",
294 (void) close(devnullfd
);
298 bytes
= write(pfd
, "", sizeof(""));
299 } while (bytes
== -1 && errno
== EINTR
);
301 /* There's no point writing to stderr now that it goes to /dev/null */