Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/libbb/vfork_daemon_rexec.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/libbb/vfork_daemon_rexec.c
r1765 r2725 13 13 * Modified for uClibc by Erik Andersen <andersee@debian.org> 14 14 * 15 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.15 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 16 16 */ 17 17 18 #include <paths.h> 19 #include "busybox.h" /* for struct bb_applet */ 18 #include "busybox.h" /* uses applet tables */ 20 19 21 20 /* This does a fork/exec in one call, using vfork(). Returns PID of new child, 22 21 * -1 for failure. Runs argv[0], searching path if that has no / in it. */ 23 pid_t spawn(char **argv)22 pid_t FAST_FUNC spawn(char **argv) 24 23 { 25 24 /* Compiler should not optimize stores here */ … … 27 26 pid_t pid; 28 27 29 // Ain't it a good place to fflush(NULL)? 28 fflush_all(); 30 29 31 30 /* Be nice to nommu machines. */ … … 43 42 */ 44 43 failed = errno; 44 /* mount, for example, does not want the message */ 45 /*bb_perror_msg("can't execute '%s'", argv[0]);*/ 45 46 _exit(111); 46 47 } … … 52 53 * If 111 - then it (most probably) failed to exec */ 53 54 if (failed) { 55 safe_waitpid(pid, NULL, 0); /* prevent zombie */ 54 56 errno = failed; 55 57 return -1; … … 59 61 60 62 /* Die with an error message if we can't spawn a child process. */ 61 pid_t xspawn(char **argv)63 pid_t FAST_FUNC xspawn(char **argv) 62 64 { 63 65 pid_t pid = spawn(argv); 64 66 if (pid < 0) 65 bb_ perror_msg_and_die("%s",*argv);67 bb_simple_perror_msg_and_die(*argv); 66 68 return pid; 67 69 } 68 70 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 do98 r = waitpid(pid, wstat, 0);99 while ((r == -1) && (errno == EINTR));100 return r;101 }102 103 71 #if ENABLE_FEATURE_PREFER_APPLETS 104 void save_nofork_data(struct nofork_save_area *save)72 void FAST_FUNC save_nofork_data(struct nofork_save_area *save) 105 73 { 106 74 memcpy(&save->die_jmp, &die_jmp, sizeof(die_jmp)); 107 save-> current_applet = current_applet;75 save->applet_name = applet_name; 108 76 save->xfunc_error_retval = xfunc_error_retval; 109 77 save->option_mask32 = option_mask32; … … 112 80 } 113 81 114 void restore_nofork_data(struct nofork_save_area *save)82 void FAST_FUNC restore_nofork_data(struct nofork_save_area *save) 115 83 { 116 84 memcpy(&die_jmp, &save->die_jmp, sizeof(die_jmp)); 117 current_applet = save->current_applet;85 applet_name = save->applet_name; 118 86 xfunc_error_retval = save->xfunc_error_retval; 119 87 option_mask32 = save->option_mask32; 120 88 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) 89 } 90 91 int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char **argv) 126 92 { 127 93 int rc, argc; 128 94 129 current_applet = a;130 applet_name = a->name; 95 applet_name = APPLET_NAME(applet_no); 96 131 97 xfunc_error_retval = EXIT_FAILURE; 132 /*option_mask32 = 0; - not needed */ 133 /* special flag for xfunc_die(). If xfunc will "die"98 99 /* Special flag for xfunc_die(). If xfunc will "die" 134 100 * in NOFORK applet, xfunc_die() sees negative 135 101 * die_sleep and longjmp here instead. */ 136 102 die_sleep = -1; 103 104 /* In case getopt() or getopt32() was already called: 105 * reset the libc getopt() function, which keeps internal state. 106 * 107 * BSD-derived getopt() functions require that optind be set to 1 in 108 * order to reset getopt() state. This used to be generally accepted 109 * way of resetting getopt(). However, glibc's getopt() 110 * has additional getopt() state beyond optind, and requires that 111 * optind be set to zero to reset its state. So the unfortunate state of 112 * affairs is that BSD-derived versions of getopt() misbehave if 113 * optind is set to 0 in order to reset getopt(), and glibc's getopt() 114 * will core dump if optind is set 1 in order to reset getopt(). 115 * 116 * More modern versions of BSD require that optreset be set to 1 in 117 * order to reset getopt(). Sigh. Standards, anyone? 118 */ 119 #ifdef __GLIBC__ 120 optind = 0; 121 #else /* BSD style */ 122 optind = 1; 123 /* optreset = 1; */ 124 #endif 125 /* optarg = NULL; opterr = 1; optopt = 63; - do we need this too? */ 126 /* (values above are what they initialized to in glibc and uclibc) */ 127 /* option_mask32 = 0; - not needed, no applet depends on it being 0 */ 137 128 138 129 argc = 1; … … 147 138 memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0])); 148 139 /* Finally we can call NOFORK applet's main() */ 149 rc = a->main(argc, tmp_argv); 140 rc = applet_main[applet_no](argc, tmp_argv); 141 142 /* The whole reason behind nofork_save_area is that <applet>_main 143 * may exit non-locally! For example, in hush Ctrl-Z tries 144 * (modulo bugs) to dynamically create a child (backgrounded task) 145 * if it detects that Ctrl-Z was pressed when a NOFORK was running. 146 * Testcase: interactive "rm -i". 147 * Don't fool yourself into thinking "and <applet>_main() returns 148 * quickly here" and removing "useless" nofork_save_area code. */ 149 150 150 } else { /* xfunc died in NOFORK applet */ 151 151 /* in case they meant to return 0... */ … … 154 154 } 155 155 156 /* Restoring globals */156 /* Restoring some globals */ 157 157 restore_nofork_data(old); 158 return rc; 159 } 160 161 int run_nofork_applet(const struct bb_applet *a, char **argv) 158 159 /* Other globals can be simply reset to defaults */ 160 #ifdef __GLIBC__ 161 optind = 0; 162 #else /* BSD style */ 163 optind = 1; 164 #endif 165 166 return rc & 0xff; /* don't confuse people with "exitcodes" >255 */ 167 } 168 169 int FAST_FUNC run_nofork_applet(int applet_no, char **argv) 162 170 { 163 171 struct nofork_save_area old; … … 165 173 /* Saving globals */ 166 174 save_nofork_data(&old); 167 return run_nofork_applet_prime(&old, a , argv);175 return run_nofork_applet_prime(&old, applet_no, argv); 168 176 } 169 177 #endif /* FEATURE_PREFER_APPLETS */ 170 178 171 int spawn_and_wait(char **argv)179 int FAST_FUNC spawn_and_wait(char **argv) 172 180 { 173 181 int rc; 174 182 #if ENABLE_FEATURE_PREFER_APPLETS 175 const struct bb_applet *a = find_applet_by_name(argv[0]);176 177 if (a && (a->nofork183 int a = find_applet_by_name(argv[0]); 184 185 if (a >= 0 && (APPLET_IS_NOFORK(a) 178 186 #if BB_MMU 179 || a->noexec/* NOEXEC trick needs fork() */187 || APPLET_IS_NOEXEC(a) /* NOEXEC trick needs fork() */ 180 188 #endif 181 189 )) { 182 190 #if BB_MMU 183 if ( a->nofork)191 if (APPLET_IS_NOFORK(a)) 184 192 #endif 185 193 { … … 194 202 /* child */ 195 203 xfunc_error_retval = EXIT_FAILURE; 196 current_applet = a; 197 run_current_applet_and_exit(argv); 204 run_applet_no_and_exit(a, argv); 198 205 #endif 199 206 } … … 204 211 205 212 #if !BB_MMU 206 void re_exec(char **argv)213 void FAST_FUNC re_exec(char **argv) 207 214 { 208 215 /* high-order bit of first char in argv[0] is a hidden … … 210 217 argv[0][0] |= 0x80; 211 218 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)219 bb_perror_msg_and_die("can't execute '%s'", bb_busybox_exec_path); 220 } 221 222 pid_t FAST_FUNC fork_or_rexec(char **argv) 216 223 { 217 224 pid_t pid; 218 225 /* Maybe we are already re-execed and come here again? */ 219 226 if (re_execed) 220 return; 221 222 pid = vfork(); 223 if (pid < 0) /* wtf? */ 224 bb_perror_msg_and_die("vfork"); 227 return 0; 228 pid = xvfork(); 225 229 if (pid) /* parent */ 226 exit(0);230 return pid; 227 231 /* child - re-exec ourself */ 228 232 re_exec(argv); 229 233 } 230 #else231 /* Dance around (void)...*/232 #undef forkexit_or_rexec233 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 234 #endif 245 235 246 236 /* Due to a #define in libbb.h on MMU systems we actually have 1 argument - 247 237 * char **argv "vanishes" */ 248 void bb_daemonize_or_rexec(int flags, char **argv)238 void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv) 249 239 { 250 240 int fd; … … 259 249 } 260 250 261 fd = xopen(bb_dev_null, O_RDWR); 251 fd = open(bb_dev_null, O_RDWR); 252 if (fd < 0) { 253 /* NB: we can be called as bb_sanitize_stdio() from init 254 * or mdev, and there /dev/null may legitimately not (yet) exist! 255 * Do not use xopen above, but obtain _ANY_ open descriptor, 256 * even bogus one as below. */ 257 fd = xopen("/", O_RDONLY); /* don't believe this can fail */ 258 } 262 259 263 260 while ((unsigned)fd < 2) … … 265 262 266 263 if (!(flags & DAEMON_ONLY_SANITIZE)) { 267 forkexit_or_rexec(argv); 264 if (fork_or_rexec(argv)) 265 exit(EXIT_SUCCESS); /* parent */ 268 266 /* if daemonizing, make sure we detach from stdio & ctty */ 269 267 setsid(); … … 280 278 } 281 279 282 void bb_sanitize_stdio(void)280 void FAST_FUNC bb_sanitize_stdio(void) 283 281 { 284 282 bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE, NULL);
Note:
See TracChangeset
for help on using the changeset viewer.