factor out NOFORK/NOEXEC code from find. Use it for xargs too.
This commit is contained in:
		| @@ -243,32 +243,14 @@ ACTF(exec) | ||||
| 		argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName); | ||||
| 	argv[i] = NULL; /* terminate the list */ | ||||
|  | ||||
| 	if (ENABLE_FEATURE_EXEC_PREFER_APPLETS) { | ||||
| 		const struct BB_applet *a = find_applet_by_name(argv[0]); | ||||
| 		if (a) { | ||||
| 			if (a->nofork) { | ||||
| 				rc = a->main(ap->exec_argc, argv); | ||||
| 				goto f; | ||||
| 			} | ||||
| #ifndef BB_NOMMU | ||||
| 			if (a->noexec) { | ||||
| 				rc = fork(); | ||||
| 				if (rc) goto w; | ||||
| 				current_applet = a; | ||||
| 				run_current_applet_and_exit(ap->exec_argc, argv); | ||||
| 			} | ||||
| #endif | ||||
| 		} | ||||
| 	} | ||||
| 	rc = spawn(argv); | ||||
|  w: | ||||
| 	rc = wait4pid(rc); | ||||
| 	rc = spawn_and_wait(argv); | ||||
| 	if (rc < 0) | ||||
| 		bb_perror_msg("%s", argv[0]); | ||||
|  f: | ||||
| 	for (i = 0; i < ap->exec_argc; i++) | ||||
| 		free(argv[i]); | ||||
| 	return rc == 0; /* return 1 if success */ | ||||
|  | ||||
| 	i = 0; | ||||
| 	while (argv[i]) | ||||
| 		free(argv[i++]); | ||||
| 	return rc == 0; /* return 1 if exitcode 0 */ | ||||
| } | ||||
| #endif | ||||
|  | ||||
|   | ||||
| @@ -48,47 +48,32 @@ | ||||
|    This function has special algorithm. | ||||
|    Don't use fork and include to main! | ||||
| */ | ||||
| static int xargs_exec(char *const *args) | ||||
| static int xargs_exec(char **args) | ||||
| { | ||||
| 	pid_t p; | ||||
| 	volatile int exec_errno = 0;    /* shared vfork stack */ | ||||
| 	int status; | ||||
|  | ||||
| 	p = vfork(); | ||||
| 	if (p < 0) | ||||
| 		bb_perror_msg_and_die("vfork"); | ||||
|  | ||||
| 	if (p == 0) { | ||||
| 		/* vfork -- child */ | ||||
| 		BB_EXECVP(args[0], args); | ||||
| 		exec_errno = errno;     /* set error to shared stack */ | ||||
| 		_exit(1); | ||||
| 	} | ||||
|  | ||||
| 	/* vfork -- parent */ | ||||
| 	while (wait(&status) == (pid_t) -1) | ||||
| 		if (errno != EINTR) | ||||
| 			break; | ||||
| 	if (exec_errno) { | ||||
| 		errno = exec_errno; | ||||
| 	status = spawn_and_wait(args); | ||||
| 	if (status < 0) { | ||||
| 		bb_perror_msg("%s", args[0]); | ||||
| 		return exec_errno == ENOENT ? 127 : 126; | ||||
| 		return errno == ENOENT ? 127 : 126; | ||||
| 	} | ||||
| 	if (WEXITSTATUS(status) == 255) { | ||||
| 	if (status == 255) { | ||||
| 		bb_error_msg("%s: exited with status 255; aborting", args[0]); | ||||
| 		return 124; | ||||
| 	} | ||||
| /* Huh? I think we won't see this, ever. We don't wait with WUNTRACED! | ||||
| 	if (WIFSTOPPED(status)) { | ||||
| 		bb_error_msg("%s: stopped by signal %d", | ||||
| 			args[0], WSTOPSIG(status)); | ||||
| 		return 125; | ||||
| 	} | ||||
| 	if (WIFSIGNALED(status)) { | ||||
| */ | ||||
| 	if (status >= 1000) { | ||||
| 		bb_error_msg("%s: terminated by signal %d", | ||||
| 			args[0], WTERMSIG(status)); | ||||
| 			args[0], status - 1000); | ||||
| 		return 125; | ||||
| 	} | ||||
| 	if (WEXITSTATUS(status)) | ||||
| 	if (status) | ||||
| 		return 123; | ||||
| 	return 0; | ||||
| } | ||||
|   | ||||
| @@ -269,17 +269,6 @@ char *xrealloc_getcwd_or_warn(char *cwd); | ||||
| char *xmalloc_readlink_or_warn(const char *path); | ||||
| char *xmalloc_realpath(const char *path); | ||||
|  | ||||
| /* Unlike waitpid, waits ONLY for one process, | ||||
|  * It's safe to pass negative 'pids' from failed [v]fork - | ||||
|  * wait4pid will return -1 and ECHILD in errno. | ||||
|  * IOW: rc = wait4pid(spawn(argv)); | ||||
|  *      if (rc < 0) bb_perror_msg("%s", argv[0]); | ||||
|  *      if (rc > 0) bb_error_msg("exit code: %d", rc); | ||||
|  */ | ||||
| extern int wait4pid(int pid); | ||||
| extern int wait_pid(int *wstat, int pid); | ||||
| extern int wait_nohang(int *wstat); | ||||
| //TODO: signal(sid, f) is the same? then why? | ||||
| extern void sig_catch(int,void (*)(int)); | ||||
| //#define sig_ignore(s) (sig_catch((s), SIG_IGN)) | ||||
| //#define sig_uncatch(s) (sig_catch((s), SIG_DFL)) | ||||
| @@ -288,10 +277,6 @@ extern void sig_unblock(int); | ||||
| /* UNUSED: extern void sig_blocknone(void); */ | ||||
| extern void sig_pause(void); | ||||
|  | ||||
| #define wait_crashed(w) ((w) & 127) | ||||
| #define wait_exitcode(w) ((w) >> 8) | ||||
| #define wait_stopsig(w) ((w) >> 8) | ||||
| #define wait_stopped(w) (((w) & 127) == 127) | ||||
|  | ||||
|  | ||||
| void xsetgid(gid_t gid); | ||||
| @@ -528,6 +513,25 @@ int bb_execvp(const char *file, char *const argv[]); | ||||
| /* NOMMU friendy fork+exec */ | ||||
| pid_t spawn(char **argv); | ||||
| pid_t xspawn(char **argv); | ||||
|  | ||||
| /* Unlike waitpid, waits ONLY for one process, | ||||
|  * It's safe to pass negative 'pids' from failed [v]fork - | ||||
|  * wait4pid will return -1 and ECHILD in errno. | ||||
|  * IOW: rc = wait4pid(spawn(argv)); | ||||
|  *      if (rc < 0) bb_perror_msg("%s", argv[0]); | ||||
|  *      if (rc > 0) bb_error_msg("exit code: %d", rc); | ||||
|  */ | ||||
| int wait_pid(int *wstat, int pid); | ||||
| int wait_nohang(int *wstat); | ||||
| int wait4pid(int pid); | ||||
| //TODO: signal(sid, f) is the same? then why? | ||||
| #define wait_crashed(w) ((w) & 127) | ||||
| #define wait_exitcode(w) ((w) >> 8) | ||||
| #define wait_stopsig(w) ((w) >> 8) | ||||
| #define wait_stopped(w) (((w) & 127) == 127) | ||||
| /* wait4pid(spawn(argv)) + NOFORK/NOEXEC (if configured) */ | ||||
| int spawn_and_wait(char **argv); | ||||
|  | ||||
| /* Helpers for daemonization. | ||||
|  * | ||||
|  * bb_daemonize(flags) = daemonize, does not compile on NOMMU | ||||
| @@ -573,6 +577,7 @@ void bb_daemonize_or_rexec(int flags, char **argv); | ||||
| void bb_sanitize_stdio(void); | ||||
|  | ||||
|  | ||||
| // TODO: always error out? | ||||
| enum { BB_GETOPT_ERROR = 0x80000000 }; | ||||
| extern const char *opt_complementary; | ||||
| #if ENABLE_GETOPT_LONG | ||||
|   | ||||
| @@ -16,7 +16,7 @@ | ||||
|  */ | ||||
|  | ||||
| #include <paths.h> | ||||
| #include "libbb.h" | ||||
| #include "busybox.h" /* for struct BB_applet */ | ||||
|  | ||||
| /* This does a fork/exec in one call, using vfork().  Returns PID of new child, | ||||
|  * -1 for failure.  Runs argv[0], searching path if that has no / in it. */ | ||||
| @@ -72,7 +72,8 @@ int wait4pid(int pid) | ||||
| 	int status; | ||||
|  | ||||
| 	if (pid <= 0) { | ||||
| 		/*errno = ECHILD; -- wrong. we expect errno to be set from failed exec */ | ||||
| 		/*errno = ECHILD; -- wrong. */ | ||||
| 		/* we expect errno to be already set from failed [v]fork/exec */ | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if (waitpid(pid, &status, 0) == -1) | ||||
| @@ -80,7 +81,7 @@ int wait4pid(int pid) | ||||
| 	if (WIFEXITED(status)) | ||||
| 		return WEXITSTATUS(status); | ||||
| 	if (WIFSIGNALED(status)) | ||||
| 		return WTERMSIG(status) + 10000; | ||||
| 		return WTERMSIG(status) + 1000; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @@ -99,6 +100,41 @@ int wait_pid(int *wstat, int pid) | ||||
| 	return r; | ||||
| } | ||||
|  | ||||
| int spawn_and_wait(char **argv) | ||||
| { | ||||
| 	int rc; | ||||
|  | ||||
| 	if (ENABLE_FEATURE_EXEC_PREFER_APPLETS) { | ||||
| 		const struct BB_applet *a = find_applet_by_name(argv[0]); | ||||
| 		if (a && (a->nofork | ||||
| #ifndef BB_NOMMU | ||||
| 			 || a->noexec /* NOEXEC cannot be used on NOMMU */ | ||||
| #endif | ||||
| 		)) { | ||||
| 			int argc = 1; | ||||
| 			char **pp = argv; | ||||
| 			while (*++pp) | ||||
| 				argc++; | ||||
| #ifdef BB_NOMMU | ||||
| 			return a->main(argc, argv); | ||||
| #else | ||||
| 			if (a->nofork) | ||||
| 				return a->main(argc, argv); | ||||
| 			/* a->noexec is true */ | ||||
| 			rc = fork(); | ||||
| 			if (rc) | ||||
| 				goto w; | ||||
| 			/* child */ | ||||
| 			current_applet = a; | ||||
| 			run_current_applet_and_exit(argc, argv); | ||||
| #endif | ||||
| 		} | ||||
| 	} | ||||
| 	rc = spawn(argv); | ||||
|  w: | ||||
| 	return wait4pid(rc); | ||||
| } | ||||
|  | ||||
| #if 0 //ndef BB_NOMMU | ||||
| // Die with an error message if we can't daemonize. | ||||
| void xdaemon(int nochdir, int noclose) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user