Tor  0.4.7.0-alpha-dev
daemon.c
Go to the documentation of this file.
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 */
5 
6 /**
7  * \file daemon.c
8  * \brief Run the tor process in the background (unix only)
9  **/
10 
11 #include "orconfig.h"
12 #include "lib/process/daemon.h"
13 
14 #ifndef _WIN32
15 
16 #include "lib/fs/files.h"
17 #include "lib/log/log.h"
18 #include "lib/thread/threads.h"
19 
20 #ifdef HAVE_SYS_TYPES_H
21 #include <sys/types.h>
22 #endif
23 #ifdef HAVE_UNISTD_H
24 #include <unistd.h>
25 #endif
26 #ifdef HAVE_FCNTL_H
27 #include <fcntl.h>
28 #endif
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
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
39  * daemonizing. */
40 static int daemon_filedes[2];
41 
42 /**
43  * Return true iff we've called start_daemon() at least once.
44  */
45 bool
47 {
48  return start_daemon_called != 0;
49 }
50 
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.
56  */
57 int
59 {
60  pid_t pid;
61 
63  return 0;
65 
66  if (pipe(daemon_filedes)) {
67  /* LCOV_EXCL_START */
68  log_err(LD_GENERAL,"pipe failed; exiting. Error was %s", strerror(errno));
69  exit(1); // exit ok: during daemonize, pipe failed.
70  /* LCOV_EXCL_STOP */
71  }
72  pid = fork();
73  if (pid < 0) {
74  /* LCOV_EXCL_START */
75  log_err(LD_GENERAL,"fork failed. Exiting.");
76  exit(1); // exit ok: during daemonize, fork failed
77  /* LCOV_EXCL_STOP */
78  }
79  if (pid) { /* Parent */
80  int ok;
81  char c;
82 
83  close(daemon_filedes[1]); /* we only read */
84  ok = -1;
85  while (0 < read(daemon_filedes[0], &c, sizeof(char))) {
86  if (c == '.')
87  ok = 1;
88  }
89  fflush(stdout);
90  if (ok == 1)
91  exit(0); // exit ok: during daemonize, daemonizing.
92  else
93  exit(1); /* child reported error. exit ok: daemonize failed. */
94  return 0; // LCOV_EXCL_LINE unreachable
95  } else { /* Child */
96  close(daemon_filedes[0]); /* we only write */
97 
98  (void) setsid(); /* Detach from controlling terminal */
99  /*
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_.
104  */
105  if (fork() != 0) {
106  exit(0); // exit ok: during daemonize, fork failed (2)
107  }
108  set_main_thread(); /* We are now the main thread. */
109 
110  return 1;
111  }
112 }
113 
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
118  * didn't.
119  */
120 int
121 finish_daemon(const char *desired_cwd)
122 {
123  int nullfd;
124  char c = '.';
126  return 0;
127  if (!start_daemon_called)
128  start_daemon();
130 
131  if (!desired_cwd)
132  desired_cwd = "/";
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.
137  }
138 
139  nullfd = tor_open_cloexec("/dev/null", O_RDWR, 0);
140  if (nullfd < 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
144  /* LCOV_EXCL_STOP */
145  }
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.
149  */
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.
156  /* LCOV_EXCL_STOP */
157  }
158  if (nullfd > 2)
159  close(nullfd);
160  /* signal success */
161  if (write(daemon_filedes[1], &c, sizeof(char)) != sizeof(char)) {
162  log_err(LD_GENERAL,"write failed. Exiting.");
163  }
164  close(daemon_filedes[1]);
165 
166  return 0;
167 }
168 #else /* defined(_WIN32) */
169 /* defined(_WIN32) */
170 int
171 start_daemon(void)
172 {
173  return 0;
174 }
175 int
176 finish_daemon(const char *cp)
177 {
178  (void)cp;
179  return 0;
180 }
181 bool
183 {
184  return false;
185 }
186 
187 #endif /* !defined(_WIN32) */
void set_main_thread(void)
static int finish_daemon_called
Definition: daemon.c:37
bool start_daemon_has_been_called(void)
Definition: daemon.c:46
int start_daemon(void)
Definition: daemon.c:58
int finish_daemon(const char *desired_cwd)
Definition: daemon.c:121
static int daemon_filedes[2]
Definition: daemon.c:40
static int start_daemon_called
Definition: daemon.c:35
Header for daemon.c.
Wrappers for reading and writing data to files on disk.
int tor_open_cloexec(const char *path, int flags, unsigned mode)
Definition: files.c:54
Headers for log.c.
#define LD_GENERAL
Definition: log.h:62
Header for threads.c.