Line data Source code
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 46 0 : start_daemon_has_been_called(void) 47 : { 48 0 : 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 58 0 : start_daemon(void) 59 : { 60 0 : pid_t pid; 61 : 62 0 : if (start_daemon_called) 63 : return 0; 64 0 : start_daemon_called = 1; 65 : 66 0 : 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 0 : pid = fork(); 73 0 : 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 0 : if (pid) { /* Parent */ 80 0 : int ok; 81 0 : char c; 82 : 83 0 : close(daemon_filedes[1]); /* we only read */ 84 0 : ok = -1; 85 0 : while (0 < read(daemon_filedes[0], &c, sizeof(char))) { 86 0 : if (c == '.') 87 0 : ok = 1; 88 : } 89 0 : fflush(stdout); 90 0 : if (ok == 1) 91 0 : exit(0); // exit ok: during daemonize, daemonizing. 92 : else 93 0 : exit(1); /* child reported error. exit ok: daemonize failed. */ 94 : return 0; // LCOV_EXCL_LINE unreachable 95 : } else { /* Child */ 96 0 : close(daemon_filedes[0]); /* we only write */ 97 : 98 0 : (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 0 : if (fork() != 0) { 106 0 : exit(0); // exit ok: during daemonize, fork failed (2) 107 : } 108 0 : set_main_thread(); /* We are now the main thread. */ 109 : 110 0 : 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 0 : finish_daemon(const char *desired_cwd) 122 : { 123 0 : int nullfd; 124 0 : char c = '.'; 125 0 : if (finish_daemon_called) 126 : return 0; 127 0 : if (!start_daemon_called) 128 0 : start_daemon(); 129 0 : finish_daemon_called = 1; 130 : 131 0 : if (!desired_cwd) 132 0 : desired_cwd = "/"; 133 : /* Don't hold the wrong FS mounted */ 134 0 : if (chdir(desired_cwd) < 0) { 135 0 : log_err(LD_GENERAL,"chdir to \"%s\" failed. Exiting.",desired_cwd); 136 0 : exit(1); // exit ok: during daemonize, chdir failed. 137 : } 138 : 139 0 : nullfd = tor_open_cloexec("/dev/null", O_RDWR, 0); 140 0 : 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 0 : if (dup2(nullfd,0) < 0 || 151 0 : dup2(nullfd,1) < 0 || 152 0 : 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 0 : if (nullfd > 2) 159 0 : close(nullfd); 160 : /* signal success */ 161 0 : if (write(daemon_filedes[1], &c, sizeof(char)) != sizeof(char)) { 162 0 : log_err(LD_GENERAL,"write failed. Exiting."); 163 : } 164 0 : close(daemon_filedes[1]); 165 : 166 0 : 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 182 : start_daemon_has_been_called(void) 183 : { 184 : return false; 185 : } 186 : 187 : #endif /* !defined(_WIN32) */