diff options
Diffstat (limited to 'src/rc')
| -rw-r--r-- | src/rc/rc-misc.c | 63 | ||||
| -rw-r--r-- | src/rc/rc.c | 55 | ||||
| -rw-r--r-- | src/rc/runscript.c | 10 | 
3 files changed, 98 insertions, 30 deletions
| diff --git a/src/rc/rc-misc.c b/src/rc/rc-misc.c index 32fe50e3..afe7893c 100644 --- a/src/rc/rc-misc.c +++ b/src/rc/rc-misc.c @@ -43,6 +43,7 @@  #include <stdio.h>  #include <stdlib.h>  #include <string.h> +#include <unistd.h>  #include "einfo.h"  #include "rc.h" @@ -310,3 +311,65 @@ int signal_setup(int sig, void (*handler)(int))  	sa.sa_handler = handler;  	return sigaction(sig, &sa, NULL);  } + +pid_t exec_service(const char *service, const char *arg) +{ +	char *file; +	char fifo[PATH_MAX]; +	pid_t pid = -1; +	sigset_t full; +	sigset_t old; +	struct sigaction sa; + +	file = rc_service_resolve(service); +	if (! exists(file)) { +		rc_service_mark(service, RC_SERVICE_STOPPED); +		free(file); +		return 0; +	} + +	/* We create a fifo so that other services can wait until we complete */ +	snprintf(fifo, sizeof(fifo), RC_SVCDIR "/exclusive/%s", +		 basename_c(service)); +	if (mkfifo(fifo, 0600) != 0 && errno != EEXIST) { +		free(file); +		return -1; +	} + +	/* 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); + +	if ((pid = fork()) == 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); + +		/* Safe to run now */ +		execl(file, file, arg, (char *) NULL); +		fprintf(stderr, "unable to exec `%s': %s\n", +			file, strerror(errno)); +		unlink(fifo); +		_exit(EXIT_FAILURE); +	} + +	if (pid == -1) +		fprintf(stderr, "fork: %s\n",strerror (errno)); + +	sigprocmask(SIG_SETMASK, &old, NULL); + +	free(file); + +	return pid; +} diff --git a/src/rc/rc.c b/src/rc/rc.c index a6f58b4f..43bcb48e 100644 --- a/src/rc/rc.c +++ b/src/rc/rc.c @@ -771,6 +771,7 @@ static void do_stop_services(const char *newlevel, bool going_down, bool paralle  	pid_t pid;  	RC_STRING *service, *svc1, *svc2;  	RC_STRINGLIST *deporder, *tmplist; +	RC_SERVICE state;  	if (! types_n) {  		types_n = rc_stringlist_new(); @@ -779,12 +780,13 @@ static void do_stop_services(const char *newlevel, bool going_down, bool paralle  	TAILQ_FOREACH_REVERSE(service, stop_services, rc_stringlist, entries)  	{ -		if (rc_service_state(service->value) & RC_SERVICE_STOPPED) +		state = rc_service_state(service->value); +		if (state & RC_SERVICE_STOPPED || state & RC_SERVICE_FAILED)  			continue;  		/* We always stop the service when in these runlevels */  		if (going_down || ! start_services) { -			pid = rc_service_stop(service->value); +			pid = service_stop(service->value);  			if (pid > 0 && ! parallel)  				rc_waitpid(pid);  			continue; @@ -832,7 +834,7 @@ static void do_stop_services(const char *newlevel, bool going_down, bool paralle  		}  		/* After all that we can finally stop the blighter! */ -		pid = rc_service_stop(service->value); +		pid = service_stop(service->value);  		if (pid > 0) {  			add_pid(pid);  			if (! parallel) { @@ -848,44 +850,47 @@ static void do_start_services(bool parallel)  	RC_STRING *service;  	pid_t pid;  	bool interactive = false; +	RC_SERVICE state;  	if (! rc_yesno(getenv("EINFO_QUIET")))  		interactive = exists(INTERACTIVE);  	TAILQ_FOREACH(service, start_services, entries) { -		if (rc_service_state(service->value) & RC_SERVICE_STOPPED) { -			if (! interactive) -				interactive = want_interactive(); +		state = rc_service_state(service->value); +		if (!(state & RC_SERVICE_STOPPED) || state & RC_SERVICE_FAILED) +			continue; + +		if (! interactive) +			interactive = want_interactive(); -			if (interactive) { +		if (interactive) {  interactive_retry: -				printf("\n"); -				einfo("About to start the service %s", -				      service->value); -				eindent(); -				einfo("1) Start the service\t\t2) Skip the service"); -				einfo("3) Continue boot process\t\t4) Exit to shell"); -				eoutdent(); +			printf("\n"); +			einfo("About to start the service %s", +			      service->value); +			eindent(); +			einfo("1) Start the service\t\t2) Skip the service"); +			einfo("3) Continue boot process\t\t4) Exit to shell"); +			eoutdent();  interactive_option: -				switch (read_key(true)) { +			switch (read_key(true)) {  				case '1': break;  				case '2': continue;  				case '3': interactive = false; break;  				case '4': sulogin(true); goto interactive_retry;  				default: goto interactive_option; -				}  			} +		} -			pid = rc_service_start(service->value); -			 -			/* Remember the pid if we're running in parallel */ -			if (pid > 0) { -				add_pid(pid); +		pid = service_start(service->value); -				if (! parallel) { -					rc_waitpid(pid); -					remove_pid(pid); -				} +		/* Remember the pid if we're running in parallel */ +		if (pid > 0) { +			add_pid(pid); + +			if (! parallel) { +				rc_waitpid(pid); +				remove_pid(pid);  			}  		}  	} diff --git a/src/rc/runscript.c b/src/rc/runscript.c index 8720c02f..421f432f 100644 --- a/src/rc/runscript.c +++ b/src/rc/runscript.c @@ -273,7 +273,7 @@ static void start_services(RC_STRINGLIST *list) {  					      " when %s has started",  					       svc->value, applet);  				} else -					rc_service_start(svc->value); +					service_start(svc->value);  			}  		}  	} @@ -727,7 +727,7 @@ static void svc_start(bool deps)  		if (! rc_runlevel_starting() && use_services)  			TAILQ_FOREACH(svc, use_services, entries)  				if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) { -					pid_t pid = rc_service_start(svc->value); +					pid_t pid = service_start(svc->value);  					if (! rc_conf_yesno("rc_parallel"))  						rc_waitpid(pid);  				} @@ -851,7 +851,7 @@ static void svc_start(bool deps)  	if (services) {  		TAILQ_FOREACH(svc, services, entries)  			if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) -				rc_service_start(svc->value); +				service_start(svc->value);  		rc_stringlist_free(services);  		services = NULL;  	} @@ -864,7 +864,7 @@ static void svc_start(bool deps)  			if (services) {  				TAILQ_FOREACH(svc2, services, entries)  					if (rc_service_state(svc2->value) & RC_SERVICE_STOPPED) -						rc_service_start(svc2->value); +						service_start(svc2->value);  				rc_stringlist_free(services);  				services = NULL;  			} @@ -939,7 +939,7 @@ static void svc_stop(bool deps)  					if (svcs & RC_SERVICE_STARTED ||  							svcs & RC_SERVICE_INACTIVE)  					{ -						pid_t pid = rc_service_stop(svc->value); +						pid_t pid = service_stop(svc->value);  						if (! rc_conf_yesno("rc_parallel"))  							rc_waitpid(pid);  						if (! tmplist) | 
