blob: 0eb24ee64a5fb10513dfb3e808e535a253853e0b [file] [log] [blame]
henrike@webrtc.orgf7795df2014-05-13 18:00:26 +00001/*
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
22namespace rtc {
23
24#if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID)
25static 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
36enum {
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
45bool 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