1 /* Copyright (c) 2003, Roger Dingledine
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
8 * \brief Run the tor process in the background (unix only)
12 #include "lib/process/daemon.h"
16 #include "lib/fs/files.h"
17 #include "lib/log/log.h"
18 #include "lib/thread/threads.h"
20 #ifdef HAVE_SYS_TYPES_H
21 #include <sys/types.h>
33 /* Based on code contributed by christian grothoff */
34 /** True iff we've called start_daemon(). */
35 static int start_daemon_called
= 0;
36 /** True iff we've called finish_daemon(). */
37 static int finish_daemon_called
= 0;
38 /** Socketpair used to communicate between parent and child process while
40 static int daemon_filedes
[2];
43 * Return true iff we've called start_daemon() at least once.
46 start_daemon_has_been_called(void)
48 return start_daemon_called
!= 0;
51 /** Start putting the process into daemon mode: fork and drop all resources
52 * except standard fds. The parent process never returns, but stays around
53 * until finish_daemon is called. (Note: it's safe to call this more
54 * than once: calls after the first are ignored.) Return true if we actually
55 * forked and this is the child; false otherwise.
62 if (start_daemon_called
)
64 start_daemon_called
= 1;
66 if (pipe(daemon_filedes
)) {
68 log_err(LD_GENERAL
,"pipe failed; exiting. Error was %s", strerror(errno
));
69 exit(1); // exit ok: during daemonize, pipe failed.
75 log_err(LD_GENERAL
,"fork failed. Exiting.");
76 exit(1); // exit ok: during daemonize, fork failed
79 if (pid
) { /* Parent */
83 close(daemon_filedes
[1]); /* we only read */
85 while (0 < read(daemon_filedes
[0], &c
, sizeof(char))) {
91 exit(0); // exit ok: during daemonize, daemonizing.
93 exit(1); /* child reported error. exit ok: daemonize failed. */
94 return 0; // LCOV_EXCL_LINE unreachable
96 close(daemon_filedes
[0]); /* we only write */
98 (void) setsid(); /* Detach from controlling terminal */
100 * Fork one more time, so the parent (the session group leader) can exit.
101 * This means that we, as a non-session group leader, can never regain a
102 * controlling terminal. This part is recommended by Stevens's
103 * _Advanced Programming in the Unix Environment_.
106 exit(0); // exit ok: during daemonize, fork failed (2)
108 set_main_thread(); /* We are now the main thread. */
114 /** Finish putting the process into daemon mode: drop standard fds, and tell
115 * the parent process to exit. (Note: it's safe to call this more than once:
116 * calls after the first are ignored. Calls start_daemon first if it hasn't
117 * been called already.) Return true if we actually did a fork; false if we
121 finish_daemon(const char *desired_cwd
)
125 if (finish_daemon_called
)
127 if (!start_daemon_called
)
129 finish_daemon_called
= 1;
133 /* Don't hold the wrong FS mounted */
134 if (chdir(desired_cwd
) < 0) {
135 log_err(LD_GENERAL
,"chdir to \"%s\" failed. Exiting.",desired_cwd
);
136 exit(1); // exit ok: during daemonize, chdir failed.
139 nullfd
= tor_open_cloexec("/dev/null", O_RDWR
, 0);
141 /* LCOV_EXCL_START */
142 log_err(LD_GENERAL
,"/dev/null can't be opened. Exiting.");
143 exit(1); // exit ok: during daemonize, couldn't open /dev/null
146 /* close fds linking to invoking terminal, but
147 * close usual incoming fds, but redirect them somewhere
148 * useful so the fds don't get reallocated elsewhere.
150 if (dup2(nullfd
,0) < 0 ||
151 dup2(nullfd
,1) < 0 ||
152 dup2(nullfd
,2) < 0) {
153 /* LCOV_EXCL_START */
154 log_err(LD_GENERAL
,"dup2 failed. Exiting.");
155 exit(1); // exit ok: during daemonize, dup2 failed.
161 if (write(daemon_filedes
[1], &c
, sizeof(char)) != sizeof(char)) {
162 log_err(LD_GENERAL
,"write failed. Exiting.");
164 close(daemon_filedes
[1]);
168 #else /* defined(_WIN32) */
169 /* defined(_WIN32) */
176 finish_daemon(const char *cp
)
182 start_daemon_has_been_called(void)
187 #endif /* !defined(_WIN32) */