• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "webrtc/base/posix.h"
12 
13 #include <sys/wait.h>
14 #include <errno.h>
15 #include <unistd.h>
16 
17 #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID)
18 #include "webrtc/base/linuxfdwalk.h"
19 #endif
20 #include "webrtc/base/logging.h"
21 
22 namespace rtc {
23 
24 #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID)
closefds(void * close_errors,int fd)25 static void closefds(void *close_errors, int fd) {
26   if (fd <= 2) {
27     // We leave stdin/out/err open to the browser's terminal, if any.
28     return;
29   }
30   if (close(fd) < 0) {
31     *static_cast<bool *>(close_errors) = true;
32   }
33 }
34 #endif
35 
36 enum {
37   EXIT_FLAG_CHDIR_ERRORS       = 1 << 0,
38 #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID)
39   EXIT_FLAG_FDWALK_ERRORS      = 1 << 1,
40   EXIT_FLAG_CLOSE_ERRORS       = 1 << 2,
41 #endif
42   EXIT_FLAG_SECOND_FORK_FAILED = 1 << 3,
43 };
44 
RunAsDaemon(const char * file,const char * const argv[])45 bool RunAsDaemon(const char *file, const char *const argv[]) {
46   // Fork intermediate child to daemonize.
47   pid_t pid = fork();
48   if (pid < 0) {
49     LOG_ERR(LS_ERROR) << "fork()";
50     return false;
51   } else if (!pid) {
52     // Child.
53 
54     // We try to close all fds and change directory to /, but if that fails we
55     // keep going because it's not critical.
56     int exit_code = 0;
57     if (chdir("/") < 0) {
58       exit_code |= EXIT_FLAG_CHDIR_ERRORS;
59     }
60 #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID)
61     bool close_errors = false;
62     if (fdwalk(&closefds, &close_errors) < 0) {
63       exit_code |= EXIT_FLAG_FDWALK_ERRORS;
64     }
65     if (close_errors) {
66       exit_code |= EXIT_FLAG_CLOSE_ERRORS;
67     }
68 #endif
69 
70     // Fork again to become a daemon.
71     pid = fork();
72     // It is important that everything here use _exit() and not exit(), because
73     // exit() would call the destructors of all global variables in the whole
74     // process, which is both unnecessary and unsafe.
75     if (pid < 0) {
76       exit_code |= EXIT_FLAG_SECOND_FORK_FAILED;
77       _exit(exit_code);  // if second fork failed
78     } else if (!pid) {
79       // Child.
80       // Successfully daemonized. Run command.
81       // WEBRTC_POSIX requires the args to be typed as non-const for historical
82       // reasons, but it mandates that the actual implementation be const, so
83       // the cast is safe.
84       execvp(file, const_cast<char *const *>(argv));
85       _exit(255);  // if execvp failed
86     }
87 
88     // Parent.
89     // Successfully spawned process, but report any problems to the parent where
90     // we can log them.
91     _exit(exit_code);
92   }
93 
94   // Parent. Reap intermediate child.
95   int status;
96   pid_t child = waitpid(pid, &status, 0);
97   if (child < 0) {
98     LOG_ERR(LS_ERROR) << "Error in waitpid()";
99     return false;
100   }
101   if (child != pid) {
102     // Should never happen (see man page).
103     LOG(LS_ERROR) << "waitpid() chose wrong child???";
104     return false;
105   }
106   if (!WIFEXITED(status)) {
107     LOG(LS_ERROR) << "Intermediate child killed uncleanly";  // Probably crashed
108     return false;
109   }
110 
111   int exit_code = WEXITSTATUS(status);
112   if (exit_code & EXIT_FLAG_CHDIR_ERRORS) {
113     LOG(LS_WARNING) << "Child reported probles calling chdir()";
114   }
115 #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID)
116   if (exit_code & EXIT_FLAG_FDWALK_ERRORS) {
117     LOG(LS_WARNING) << "Child reported problems calling fdwalk()";
118   }
119   if (exit_code & EXIT_FLAG_CLOSE_ERRORS) {
120     LOG(LS_WARNING) << "Child reported problems calling close()";
121   }
122 #endif
123   if (exit_code & EXIT_FLAG_SECOND_FORK_FAILED) {
124     LOG(LS_ERROR) << "Failed to daemonize";
125     // This means the command was not launched, so failure.
126     return false;
127   }
128   return true;
129 }
130 
131 }  // namespace rtc
132