89ae9a73cfa6ef5d53b4f8cf98d37c0fbbd5b369
[oweals/busybox.git] / libbb / vfork_daemon_rexec.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Rexec program for system have fork() as vfork() with foreground option
4  *
5  * Copyright (C) Vladimir N. Oleynik <dzo@simtreas.ru>
6  * Copyright (C) 2003 Russ Dill <Russ.Dill@asu.edu>
7  *
8  * daemon() portion taken from uClibc:
9  *
10  * Copyright (c) 1991, 1993
11  *      The Regents of the University of California.  All rights reserved.
12  *
13  * Modified for uClibc by Erik Andersen <andersee@debian.org>
14  *
15  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
16  */
17
18 #include <paths.h>
19 #include "libbb.h"
20
21 /* This does a fork/exec in one call, using vfork().  Returns PID of new child,
22  * -1 for failure.  Runs argv[0], searching path if that has no / in it. */
23 pid_t spawn(char **argv)
24 {
25         /* Compiler should not optimize stores here */
26         volatile int failed;
27         pid_t pid;
28
29         // Be nice to nommu machines.
30         failed = 0;
31         pid = vfork();
32         if (pid < 0) /* error */
33                 return pid;
34         if (!pid) { /* child */
35                 /* Don't use BB_EXECVP tricks here! */
36                 execvp(argv[0], argv);
37
38                 /* We are (maybe) sharing a stack with blocked parent,
39                  * let parent know we failed and then exit to unblock parent
40                  * (but don't run atexit() stuff, which would screw up parent.)
41                  */
42                 failed = errno;
43                 _exit(0);
44         }
45         /* parent */
46         /* Unfortunately, this is not reliable: vfork()
47          * can be equivalent to fork() according to standards */
48         if (failed) {
49                 errno = failed;
50                 return -1;
51         }
52         return pid;
53 }
54
55 /* Die with an error message if we can't spawn a child process. */
56 pid_t xspawn(char **argv)
57 {
58         pid_t pid = spawn(argv);
59         if (pid < 0) bb_perror_msg_and_die("%s", *argv);
60         return pid;
61 }
62
63
64
65 #if 0 //ndef BB_NOMMU
66 // Die with an error message if we can't daemonize.
67 void xdaemon(int nochdir, int noclose)
68 {
69         if (daemon(nochdir, noclose))
70                 bb_perror_msg_and_die("daemon");
71 }
72 #endif
73
74 #if 0 // def BB_NOMMU
75 void vfork_daemon_rexec(int nochdir, int noclose, char **argv)
76 {
77         int fd;
78
79         /* Maybe we are already re-execed and come here again? */
80         if (re_execed)
81                 return;
82
83         setsid();
84
85         if (!nochdir)
86                 xchdir("/");
87
88         if (!noclose) {
89                 /* if "/dev/null" doesn't exist, bail out! */
90                 fd = xopen(bb_dev_null, O_RDWR);
91                 dup2(fd, STDIN_FILENO);
92                 dup2(fd, STDOUT_FILENO);
93                 dup2(fd, STDERR_FILENO);
94                 while (fd > 2)
95                         close(fd--);
96         }
97
98         switch (vfork()) {
99         case 0: /* child */
100                 /* Make certain we are not a session leader, or else we
101                  * might reacquire a controlling terminal */
102                 if (vfork())
103                         _exit(0);
104                 /* High-order bit of first char in argv[0] is a hidden
105                  * "we have (alrealy) re-execed, don't do it again" flag */
106                 argv[0][0] |= 0x80;
107                 execv(CONFIG_BUSYBOX_EXEC_PATH, argv);
108                 bb_perror_msg_and_die("exec %s", CONFIG_BUSYBOX_EXEC_PATH);
109         case -1: /* error */
110                 bb_perror_msg_and_die("vfork");
111         default: /* parent */
112                 exit(0);
113         }
114 }
115 #endif /* BB_NOMMU */
116
117 #ifdef BB_NOMMU
118 void forkexit_or_rexec(char **argv)
119 {
120         pid_t pid;
121         /* Maybe we are already re-execed and come here again? */
122         if (re_execed)
123                 return;
124
125         pid = vfork();
126         if (pid < 0) /* wtf? */
127                 bb_perror_msg_and_die("vfork");
128         if (pid) /* parent */
129                 exit(0);
130         /* child - re-exec ourself */
131         /* high-order bit of first char in argv[0] is a hidden
132          * "we have (alrealy) re-execed, don't do it again" flag */
133         argv[0][0] |= 0x80;
134         execv(CONFIG_BUSYBOX_EXEC_PATH, argv);
135         bb_perror_msg_and_die("exec %s", CONFIG_BUSYBOX_EXEC_PATH);
136 }
137 #else
138 /* Dance around (void)...*/
139 #undef forkexit_or_rexec
140 void forkexit_or_rexec(void)
141 {
142         pid_t pid;
143         pid = fork();
144         if (pid < 0) /* wtf? */
145                 bb_perror_msg_and_die("fork");
146         if (pid) /* parent */
147                 exit(0);
148         /* child */
149 }
150 #define forkexit_or_rexec(argv) forkexit_or_rexec()
151 #endif
152
153
154 /* Due to a #define in libbb.h on MMU systems we actually have 1 argument -
155  * char **argv "vanishes" */
156 void bb_daemonize_or_rexec(int flags, char **argv)
157 {
158         int fd;
159
160         fd = xopen(bb_dev_null, O_RDWR);
161
162         if (flags & DAEMON_CHDIR_ROOT)
163                 xchdir("/");
164
165         if (flags & DAEMON_DEVNULL_STDIO) {
166                 close(0);
167                 close(1);
168                 close(2);
169         }
170
171         while ((unsigned)fd < 2)
172                 fd = dup(fd); /* have 0,1,2 open at least to /dev/null */
173
174         if (!(flags & DAEMON_ONLY_SANITIZE)) {
175                 forkexit_or_rexec(argv);
176                 /* if daemonizing, make sure we detach from stdio */
177                 setsid();
178                 dup2(fd, 0);
179                 dup2(fd, 1);
180                 dup2(fd, 2);
181         }
182         if (fd > 2)
183                 close(fd--);
184         if (flags & DAEMON_CLOSE_EXTRA_FDS)
185                 while (fd > 2)
186                         close(fd--); /* close everything after fd#2 */
187 }
188
189 void bb_sanitize_stdio(void)
190 {
191         bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE, NULL);
192 }