Add rc_program function which uses fork and signal masking to try and resolve the waitpid issue, Gentoo #219179.
This commit is contained in:
		
							
								
								
									
										107
									
								
								src/rc/rc.c
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								src/rc/rc.c
									
									
									
									
									
								
							| @@ -277,12 +277,53 @@ static void mark_interactive(void) | |||||||
| 		fclose(fp); | 		fclose(fp); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void sulogin(bool cont) | static void run_program(const char *prog) | ||||||
| { | { | ||||||
| 	struct sigaction sa; | 	struct sigaction sa; | ||||||
| 	sigset_t full; | 	sigset_t full; | ||||||
| 	sigset_t old; | 	sigset_t old; | ||||||
| 	pid_t pid; | 	pid_t pid; | ||||||
|  |  | ||||||
|  | 	/* We need to block signals until we have forked */ | ||||||
|  | 	memset(&sa, 0, sizeof(sa)); | ||||||
|  | 	sa.sa_handler = SIG_DFL; | ||||||
|  | 	sigemptyset(&sa.sa_mask); | ||||||
|  | 	sigfillset(&full); | ||||||
|  | 	sigprocmask(SIG_SETMASK, &full, &old); | ||||||
|  | 	pid = fork(); | ||||||
|  |  | ||||||
|  | 	if (pid == -1) | ||||||
|  | 		eerrorx("%s: fork: %s", applet, strerror(errno)); | ||||||
|  | 	if (pid == 0) { | ||||||
|  | 		/* Restore default handlers */ | ||||||
|  | 		sigaction(SIGCHLD, &sa, NULL); | ||||||
|  | 		sigaction(SIGHUP, &sa, NULL); | ||||||
|  | 		sigaction(SIGINT, &sa, NULL); | ||||||
|  | 		sigaction(SIGQUIT, &sa, NULL); | ||||||
|  | 		sigaction(SIGTERM, &sa, NULL); | ||||||
|  | 		sigaction(SIGUSR1, &sa, NULL); | ||||||
|  | 		sigaction(SIGWINCH, &sa, NULL); | ||||||
|  |  | ||||||
|  | 		/* Unmask signals */ | ||||||
|  | 		sigprocmask(SIG_SETMASK, &old, NULL); | ||||||
|  |  | ||||||
|  | 		if (termios_orig) | ||||||
|  | 			tcsetattr(fileno(stdin), TCSANOW, termios_orig); | ||||||
|  |  | ||||||
|  | 		execl(prog, prog, (char *) NULL); | ||||||
|  | 		eerror("%s: unable to exec `%s': %s", applet, prog, | ||||||
|  | 		       strerror(errno)); | ||||||
|  | 		_exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Unmask signals and wait for child */ | ||||||
|  | 	sigprocmask(SIG_SETMASK, &old, NULL); | ||||||
|  | 	if (rc_waitpid(pid) == -1) | ||||||
|  | 		eerrorx("%s: failed to exec `%s'", applet, prog); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void sulogin(bool cont) | ||||||
|  | { | ||||||
| #ifdef __linux__ | #ifdef __linux__ | ||||||
| 	const char *sys = rc_sys(); | 	const char *sys = rc_sys(); | ||||||
|  |  | ||||||
| @@ -305,47 +346,11 @@ static void sulogin(bool cont) | |||||||
| #endif | #endif | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* We need to block signals until we have forked */ |  | ||||||
| 	memset(&sa, 0, sizeof(sa)); |  | ||||||
| 	sa.sa_handler = SIG_DFL; |  | ||||||
| 	sigemptyset(&sa.sa_mask); |  | ||||||
| 	sigfillset(&full); |  | ||||||
| 	sigprocmask(SIG_SETMASK, &full, &old); |  | ||||||
| 	pid = vfork(); |  | ||||||
|  |  | ||||||
| 	if (pid == -1) |  | ||||||
| 		eerrorx("%s: fork: %s", applet, strerror(errno)); |  | ||||||
| 	if (pid == 0) { |  | ||||||
| 		/* Restore default handlers */ |  | ||||||
| 		sigaction(SIGCHLD, &sa, NULL); |  | ||||||
| 		sigaction(SIGHUP, &sa, NULL); |  | ||||||
| 		sigaction(SIGINT, &sa, NULL); |  | ||||||
| 		sigaction(SIGQUIT, &sa, NULL); |  | ||||||
| 		sigaction(SIGTERM, &sa, NULL); |  | ||||||
| 		sigaction(SIGUSR1, &sa, NULL); |  | ||||||
| 		sigaction(SIGWINCH, &sa, NULL); |  | ||||||
|  |  | ||||||
| 		/* Unmask signals */ |  | ||||||
| 		sigprocmask(SIG_SETMASK, &old, NULL); |  | ||||||
|  |  | ||||||
| 		if (termios_orig) |  | ||||||
| 			tcsetattr(fileno(stdin), TCSANOW, termios_orig); |  | ||||||
|  |  | ||||||
| #ifdef __linux__ | #ifdef __linux__ | ||||||
| 		execl(SULOGIN, SULOGIN, (char *) NULL); | 	run_program(SULOGIN); | ||||||
| 		eerror("%s: unable to exec `%s': %s", applet, SULOGIN, |  | ||||||
| 		       strerror(errno)); |  | ||||||
| #else | #else | ||||||
| 		execl("/bin/sh", "/bin/sh", (char *) NULL); | 	run_program("/bin/sh"); | ||||||
| 		eerror("%s: unable to exec `/bin/sh': %s", applet, |  | ||||||
| 		       strerror(errno)); |  | ||||||
| #endif | #endif | ||||||
| 		_exit(EXIT_FAILURE); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* Unmask signals and wait for child */ |  | ||||||
| 	sigprocmask(SIG_SETMASK, &old, NULL); |  | ||||||
| 	rc_waitpid(pid); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static void single_user(void) | static void single_user(void) | ||||||
| @@ -510,23 +515,6 @@ static void handle_signal(int sig) | |||||||
| 	errno = serrno; | 	errno = serrno; | ||||||
| } | } | ||||||
|  |  | ||||||
| static void run_script(const char *script) |  | ||||||
| { |  | ||||||
| 	pid_t pid = vfork(); |  | ||||||
|  |  | ||||||
| 	if (pid < 0) |  | ||||||
| 		eerrorx("%s: vfork: %s", applet, strerror(errno)); |  | ||||||
| 	else if (pid == 0) { |  | ||||||
| 		execl(script, script, (char *) NULL); |  | ||||||
| 		eerror("%s: unable to exec `%s': %s", |  | ||||||
| 			script, applet, strerror(errno)); |  | ||||||
| 		_exit(EXIT_FAILURE); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (rc_waitpid(pid) != 0) |  | ||||||
| 		eerrorx("%s: failed to exec `%s'", applet, script); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void do_coldplug(void) | static void do_coldplug(void) | ||||||
| { | { | ||||||
| 	size_t l; | 	size_t l; | ||||||
| @@ -651,7 +639,7 @@ static void do_newlevel(const char *newlevel) | |||||||
| 		 * This should just setup the console to use the correct | 		 * This should just setup the console to use the correct | ||||||
| 		 * font. Maybe it should setup the keyboard too? */ | 		 * font. Maybe it should setup the keyboard too? */ | ||||||
| 		if (exists(INITEARLYSH)) | 		if (exists(INITEARLYSH)) | ||||||
| 			run_script(INITEARLYSH); | 			run_program(INITEARLYSH); | ||||||
|  |  | ||||||
| 		uname(&uts); | 		uname(&uts); | ||||||
| 		printf("\n   %sOpenRC %s" VERSION "%s is starting up %s", | 		printf("\n   %sOpenRC %s" VERSION "%s is starting up %s", | ||||||
| @@ -679,7 +667,7 @@ static void do_newlevel(const char *newlevel) | |||||||
| 		setenv("RC_RUNLEVEL", newlevel, 1); | 		setenv("RC_RUNLEVEL", newlevel, 1); | ||||||
| 		rc_plugin_run(RC_HOOK_RUNLEVEL_START_IN, newlevel); | 		rc_plugin_run(RC_HOOK_RUNLEVEL_START_IN, newlevel); | ||||||
| 		hook_out = RC_HOOK_RUNLEVEL_START_OUT; | 		hook_out = RC_HOOK_RUNLEVEL_START_OUT; | ||||||
| 		run_script(INITSH); | 		run_program(INITSH); | ||||||
|  |  | ||||||
| #ifdef __linux__ | #ifdef __linux__ | ||||||
| 		/* If we requested a runlevel, save it now */ | 		/* If we requested a runlevel, save it now */ | ||||||
| @@ -1050,8 +1038,7 @@ int main(int argc, char **argv) | |||||||
| 	rc_logger_open(newlevel ? newlevel : runlevel); | 	rc_logger_open(newlevel ? newlevel : runlevel); | ||||||
|  |  | ||||||
| 	/* Setup a signal handler */ | 	/* Setup a signal handler */ | ||||||
| 	if (signal_setup(SIGINT, handle_signal) != 0) | 	signal_setup(SIGINT, handle_signal); | ||||||
| 		eerror ("signal_setup: %s", strerror(errno)); |  | ||||||
| 	signal_setup(SIGQUIT, handle_signal); | 	signal_setup(SIGQUIT, handle_signal); | ||||||
| 	signal_setup(SIGTERM, handle_signal); | 	signal_setup(SIGTERM, handle_signal); | ||||||
| 	signal_setup(SIGUSR1, handle_signal); | 	signal_setup(SIGUSR1, handle_signal); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user