Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/libbb/vfork_daemon_rexec.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/libbb/vfork_daemon_rexec.c
r821 r1770 16 16 */ 17 17 18 #include <unistd.h>19 #include <stdio.h>20 #include <fcntl.h>21 18 #include <paths.h> 22 #include "libbb.h" 23 24 25 #ifdef BB_NOMMU 26 void vfork_daemon_rexec(int nochdir, int noclose, 27 int argc, char **argv, char *foreground_opt) 19 #include "busybox.h" /* for struct bb_applet */ 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 // Ain't it a good place to fflush(NULL)? 30 31 /* Be nice to nommu machines. */ 32 failed = 0; 33 pid = vfork(); 34 if (pid < 0) /* error */ 35 return pid; 36 if (!pid) { /* child */ 37 /* This macro is ok - it doesn't do NOEXEC/NOFORK tricks */ 38 BB_EXECVP(argv[0], argv); 39 40 /* We are (maybe) sharing a stack with blocked parent, 41 * let parent know we failed and then exit to unblock parent 42 * (but don't run atexit() stuff, which would screw up parent.) 43 */ 44 failed = errno; 45 _exit(111); 46 } 47 /* parent */ 48 /* Unfortunately, this is not reliable: according to standards 49 * vfork() can be equivalent to fork() and we won't see value 50 * of 'failed'. 51 * Interested party can wait on pid and learn exit code. 52 * If 111 - then it (most probably) failed to exec */ 53 if (failed) { 54 errno = failed; 55 return -1; 56 } 57 return pid; 58 } 59 60 /* Die with an error message if we can't spawn a child process. */ 61 pid_t xspawn(char **argv) 62 { 63 pid_t pid = spawn(argv); 64 if (pid < 0) 65 bb_perror_msg_and_die("%s", *argv); 66 return pid; 67 } 68 69 // Wait for the specified child PID to exit, returning child's error return. 70 int wait4pid(int pid) 71 { 72 int status; 73 74 if (pid <= 0) { 75 /*errno = ECHILD; -- wrong. */ 76 /* we expect errno to be already set from failed [v]fork/exec */ 77 return -1; 78 } 79 if (waitpid(pid, &status, 0) == -1) 80 return -1; 81 if (WIFEXITED(status)) 82 return WEXITSTATUS(status); 83 if (WIFSIGNALED(status)) 84 return WTERMSIG(status) + 1000; 85 return 0; 86 } 87 88 int wait_nohang(int *wstat) 89 { 90 return waitpid(-1, wstat, WNOHANG); 91 } 92 93 int wait_pid(int *wstat, int pid) 94 { 95 int r; 96 97 do 98 r = waitpid(pid, wstat, 0); 99 while ((r == -1) && (errno == EINTR)); 100 return r; 101 } 102 103 #if ENABLE_FEATURE_PREFER_APPLETS 104 void save_nofork_data(struct nofork_save_area *save) 105 { 106 memcpy(&save->die_jmp, &die_jmp, sizeof(die_jmp)); 107 save->current_applet = current_applet; 108 save->xfunc_error_retval = xfunc_error_retval; 109 save->option_mask32 = option_mask32; 110 save->die_sleep = die_sleep; 111 save->saved = 1; 112 } 113 114 void restore_nofork_data(struct nofork_save_area *save) 115 { 116 memcpy(&die_jmp, &save->die_jmp, sizeof(die_jmp)); 117 current_applet = save->current_applet; 118 xfunc_error_retval = save->xfunc_error_retval; 119 option_mask32 = save->option_mask32; 120 die_sleep = save->die_sleep; 121 122 applet_name = current_applet->name; 123 } 124 125 int run_nofork_applet_prime(struct nofork_save_area *old, const struct bb_applet *a, char **argv) 126 { 127 int rc, argc; 128 129 current_applet = a; 130 applet_name = a->name; 131 xfunc_error_retval = EXIT_FAILURE; 132 /*option_mask32 = 0; - not needed */ 133 /* special flag for xfunc_die(). If xfunc will "die" 134 * in NOFORK applet, xfunc_die() sees negative 135 * die_sleep and longjmp here instead. */ 136 die_sleep = -1; 137 138 argc = 1; 139 while (argv[argc]) 140 argc++; 141 142 rc = setjmp(die_jmp); 143 if (!rc) { 144 /* Some callers (xargs) 145 * need argv untouched because they free argv[i]! */ 146 char *tmp_argv[argc+1]; 147 memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0])); 148 /* Finally we can call NOFORK applet's main() */ 149 rc = a->main(argc, tmp_argv); 150 } else { /* xfunc died in NOFORK applet */ 151 /* in case they meant to return 0... */ 152 if (rc == -2222) 153 rc = 0; 154 } 155 156 /* Restoring globals */ 157 restore_nofork_data(old); 158 return rc; 159 } 160 161 int run_nofork_applet(const struct bb_applet *a, char **argv) 162 { 163 struct nofork_save_area old; 164 165 /* Saving globals */ 166 save_nofork_data(&old); 167 return run_nofork_applet_prime(&old, a, argv); 168 } 169 #endif /* FEATURE_PREFER_APPLETS */ 170 171 int spawn_and_wait(char **argv) 172 { 173 int rc; 174 #if ENABLE_FEATURE_PREFER_APPLETS 175 const struct bb_applet *a = find_applet_by_name(argv[0]); 176 177 if (a && (a->nofork 178 #if BB_MMU 179 || a->noexec /* NOEXEC trick needs fork() */ 180 #endif 181 )) { 182 #if BB_MMU 183 if (a->nofork) 184 #endif 185 { 186 return run_nofork_applet(a, argv); 187 } 188 #if BB_MMU 189 /* MMU only */ 190 /* a->noexec is true */ 191 rc = fork(); 192 if (rc) /* parent or error */ 193 return wait4pid(rc); 194 /* child */ 195 xfunc_error_retval = EXIT_FAILURE; 196 current_applet = a; 197 run_current_applet_and_exit(argv); 198 #endif 199 } 200 #endif /* FEATURE_PREFER_APPLETS */ 201 rc = spawn(argv); 202 return wait4pid(rc); 203 } 204 205 #if !BB_MMU 206 void re_exec(char **argv) 207 { 208 /* high-order bit of first char in argv[0] is a hidden 209 * "we have (already) re-execed, don't do it again" flag */ 210 argv[0][0] |= 0x80; 211 execv(bb_busybox_exec_path, argv); 212 bb_perror_msg_and_die("exec %s", bb_busybox_exec_path); 213 } 214 215 void forkexit_or_rexec(char **argv) 216 { 217 pid_t pid; 218 /* Maybe we are already re-execed and come here again? */ 219 if (re_execed) 220 return; 221 222 pid = vfork(); 223 if (pid < 0) /* wtf? */ 224 bb_perror_msg_and_die("vfork"); 225 if (pid) /* parent */ 226 exit(0); 227 /* child - re-exec ourself */ 228 re_exec(argv); 229 } 230 #else 231 /* Dance around (void)...*/ 232 #undef forkexit_or_rexec 233 void forkexit_or_rexec(void) 234 { 235 pid_t pid; 236 pid = fork(); 237 if (pid < 0) /* wtf? */ 238 bb_perror_msg_and_die("fork"); 239 if (pid) /* parent */ 240 exit(0); 241 /* child */ 242 } 243 #define forkexit_or_rexec(argv) forkexit_or_rexec() 244 #endif 245 246 /* Due to a #define in libbb.h on MMU systems we actually have 1 argument - 247 * char **argv "vanishes" */ 248 void bb_daemonize_or_rexec(int flags, char **argv) 28 249 { 29 250 int fd; 30 char **vfork_args; 31 int a = 0; 32 33 setsid(); 34 35 if (!nochdir) 36 chdir("/"); 37 38 if (!noclose && (fd = open(bb_dev_null, O_RDWR, 0)) != -1) { 39 dup2(fd, STDIN_FILENO); 40 dup2(fd, STDOUT_FILENO); 41 dup2(fd, STDERR_FILENO); 42 if (fd > 2) 43 close(fd); 44 } 45 46 vfork_args = xcalloc(sizeof(char *), argc + 3); 47 vfork_args[a++] = "/bin/busybox"; 48 while(*argv) { 49 vfork_args[a++] = *argv; 50 argv++; 51 } 52 vfork_args[a] = foreground_opt; 53 switch (vfork()) { 54 case 0: /* child */ 55 /* Make certain we are not a session leader, or else we 56 * might reacquire a controlling terminal */ 57 if (vfork()) 58 _exit(0); 59 execv(vfork_args[0], vfork_args); 60 bb_perror_msg_and_die("execv %s", vfork_args[0]); 61 case -1: /* error */ 62 bb_perror_msg_and_die("vfork"); 63 default: /* parent */ 64 exit(0); 65 } 66 } 67 #endif /* BB_NOMMU */ 251 252 if (flags & DAEMON_CHDIR_ROOT) 253 xchdir("/"); 254 255 if (flags & DAEMON_DEVNULL_STDIO) { 256 close(0); 257 close(1); 258 close(2); 259 } 260 261 fd = xopen(bb_dev_null, O_RDWR); 262 263 while ((unsigned)fd < 2) 264 fd = dup(fd); /* have 0,1,2 open at least to /dev/null */ 265 266 if (!(flags & DAEMON_ONLY_SANITIZE)) { 267 forkexit_or_rexec(argv); 268 /* if daemonizing, make sure we detach from stdio & ctty */ 269 setsid(); 270 dup2(fd, 0); 271 dup2(fd, 1); 272 dup2(fd, 2); 273 } 274 while (fd > 2) { 275 close(fd--); 276 if (!(flags & DAEMON_CLOSE_EXTRA_FDS)) 277 return; 278 /* else close everything after fd#2 */ 279 } 280 } 281 282 void bb_sanitize_stdio(void) 283 { 284 bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE, NULL); 285 }
Note:
See TracChangeset
for help on using the changeset viewer.