factor out NOFORK/NOEXEC code from find. Use it for xargs too.
This commit is contained in:
		| @@ -238,37 +238,19 @@ ACTF(inum) | |||||||
| ACTF(exec) | ACTF(exec) | ||||||
| { | { | ||||||
| 	int i, rc; | 	int i, rc; | ||||||
| 	char *argv[ap->exec_argc+1]; | 	char *argv[ap->exec_argc + 1]; | ||||||
| 	for (i = 0; i < ap->exec_argc; i++) | 	for (i = 0; i < ap->exec_argc; i++) | ||||||
| 		argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName); | 		argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName); | ||||||
| 	argv[i] = NULL; /* terminate the list */ | 	argv[i] = NULL; /* terminate the list */ | ||||||
|  |  | ||||||
| 	if (ENABLE_FEATURE_EXEC_PREFER_APPLETS) { | 	rc = spawn_and_wait(argv); | ||||||
| 		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); |  | ||||||
| 	if (rc < 0) | 	if (rc < 0) | ||||||
| 		bb_perror_msg("%s", argv[0]); | 		bb_perror_msg("%s", argv[0]); | ||||||
|  f: |  | ||||||
| 	for (i = 0; i < ap->exec_argc; i++) | 	i = 0; | ||||||
| 		free(argv[i]); | 	while (argv[i]) | ||||||
| 	return rc == 0; /* return 1 if success */ | 		free(argv[i++]); | ||||||
|  | 	return rc == 0; /* return 1 if exitcode 0 */ | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   | |||||||
| @@ -48,47 +48,32 @@ | |||||||
|    This function has special algorithm. |    This function has special algorithm. | ||||||
|    Don't use fork and include to main! |    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; | 	int status; | ||||||
|  |  | ||||||
| 	p = vfork(); | 	status = spawn_and_wait(args); | ||||||
| 	if (p < 0) | 	if (status < 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; |  | ||||||
| 		bb_perror_msg("%s", args[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]); | 		bb_error_msg("%s: exited with status 255; aborting", args[0]); | ||||||
| 		return 124; | 		return 124; | ||||||
| 	} | 	} | ||||||
|  | /* Huh? I think we won't see this, ever. We don't wait with WUNTRACED! | ||||||
| 	if (WIFSTOPPED(status)) { | 	if (WIFSTOPPED(status)) { | ||||||
| 		bb_error_msg("%s: stopped by signal %d", | 		bb_error_msg("%s: stopped by signal %d", | ||||||
| 			args[0], WSTOPSIG(status)); | 			args[0], WSTOPSIG(status)); | ||||||
| 		return 125; | 		return 125; | ||||||
| 	} | 	} | ||||||
| 	if (WIFSIGNALED(status)) { | */ | ||||||
|  | 	if (status >= 1000) { | ||||||
| 		bb_error_msg("%s: terminated by signal %d", | 		bb_error_msg("%s: terminated by signal %d", | ||||||
| 			args[0], WTERMSIG(status)); | 			args[0], status - 1000); | ||||||
| 		return 125; | 		return 125; | ||||||
| 	} | 	} | ||||||
| 	if (WEXITSTATUS(status)) | 	if (status) | ||||||
| 		return 123; | 		return 123; | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -269,17 +269,6 @@ char *xrealloc_getcwd_or_warn(char *cwd); | |||||||
| char *xmalloc_readlink_or_warn(const char *path); | char *xmalloc_readlink_or_warn(const char *path); | ||||||
| char *xmalloc_realpath(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)); | extern void sig_catch(int,void (*)(int)); | ||||||
| //#define sig_ignore(s) (sig_catch((s), SIG_IGN)) | //#define sig_ignore(s) (sig_catch((s), SIG_IGN)) | ||||||
| //#define sig_uncatch(s) (sig_catch((s), SIG_DFL)) | //#define sig_uncatch(s) (sig_catch((s), SIG_DFL)) | ||||||
| @@ -288,10 +277,6 @@ extern void sig_unblock(int); | |||||||
| /* UNUSED: extern void sig_blocknone(void); */ | /* UNUSED: extern void sig_blocknone(void); */ | ||||||
| extern void sig_pause(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); | void xsetgid(gid_t gid); | ||||||
| @@ -528,6 +513,25 @@ int bb_execvp(const char *file, char *const argv[]); | |||||||
| /* NOMMU friendy fork+exec */ | /* NOMMU friendy fork+exec */ | ||||||
| pid_t spawn(char **argv); | pid_t spawn(char **argv); | ||||||
| pid_t xspawn(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. | /* Helpers for daemonization. | ||||||
|  * |  * | ||||||
|  * bb_daemonize(flags) = daemonize, does not compile on NOMMU |  * 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); | void bb_sanitize_stdio(void); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // TODO: always error out? | ||||||
| enum { BB_GETOPT_ERROR = 0x80000000 }; | enum { BB_GETOPT_ERROR = 0x80000000 }; | ||||||
| extern const char *opt_complementary; | extern const char *opt_complementary; | ||||||
| #if ENABLE_GETOPT_LONG | #if ENABLE_GETOPT_LONG | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ | |||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include <paths.h> | #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, | /* 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. */ |  * -1 for failure.  Runs argv[0], searching path if that has no / in it. */ | ||||||
| @@ -72,7 +72,8 @@ int wait4pid(int pid) | |||||||
| 	int status; | 	int status; | ||||||
|  |  | ||||||
| 	if (pid <= 0) { | 	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; | 		return -1; | ||||||
| 	} | 	} | ||||||
| 	if (waitpid(pid, &status, 0) == -1) | 	if (waitpid(pid, &status, 0) == -1) | ||||||
| @@ -80,7 +81,7 @@ int wait4pid(int pid) | |||||||
| 	if (WIFEXITED(status)) | 	if (WIFEXITED(status)) | ||||||
| 		return WEXITSTATUS(status); | 		return WEXITSTATUS(status); | ||||||
| 	if (WIFSIGNALED(status)) | 	if (WIFSIGNALED(status)) | ||||||
| 		return WTERMSIG(status) + 10000; | 		return WTERMSIG(status) + 1000; | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -99,6 +100,41 @@ int wait_pid(int *wstat, int pid) | |||||||
| 	return r; | 	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 | #if 0 //ndef BB_NOMMU | ||||||
| // Die with an error message if we can't daemonize. | // Die with an error message if we can't daemonize. | ||||||
| void xdaemon(int nochdir, int noclose) | void xdaemon(int nochdir, int noclose) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user