Remove rc_service_start/stop from librc as they block and unmask signals. The application may not wish this behaviour and should fork/exec the service itself.
This commit is contained in:
		| @@ -31,11 +31,10 @@ | ||||
| .Nm rc_service_mark , rc_service_extra_commands , rc_service_plugable , | ||||
| .Nm rc_service_resolve , rc_service_schedule_start , rc_services_scheduled_by , | ||||
| .Nm rc_service_schedule_clear , rc_service_state , | ||||
| .Nm rc_service_start , rc_service_stop , | ||||
| .Nm rc_service_started_daemon , rc_service_value_get , rc_service_value_set , | ||||
| .Nm rc_services_in_runlevel , rc_services_in_state , rc_services_scheduled , | ||||
| .Nm rc_service_daemons_crashed | ||||
| .Nd functions to start, stop and query OpenRC services | ||||
| .Nd functions to query OpenRC services | ||||
| .Sh LIBRARY | ||||
| Run Command library (librc, -lrc) | ||||
| .Sh SYNOPSIS | ||||
| @@ -66,8 +65,6 @@ Run Command library (librc, -lrc) | ||||
| .Ft "RC_STRINGLIST *" Fn rc_services_scheduled_by "const char *service" | ||||
| .Ft bool Fn rc_service_schedule_clear "const char *service" | ||||
| .Ft RC_SERVICE Fn rc_service_state "const char *service" | ||||
| .Ft pid_t Fn rc_service_start "const char *service" | ||||
| .Ft pid_t Fn rc_service_stop "const char *service" | ||||
| .Ft bool Fo rc_service_started_daemon | ||||
| .Fa "const char *service" | ||||
| .Fa "const char *exec" | ||||
| @@ -176,16 +173,6 @@ clears these scheduled services for | ||||
| .Fa service . | ||||
| The return value is a bitmask, where more than one state can apply. | ||||
| .Pp | ||||
| .Fn rc_service_start | ||||
| starts | ||||
| .Fa service , | ||||
| returning the pid of new process. | ||||
| .Pp | ||||
| .Fn rc_service_stop | ||||
| stops | ||||
| .Fa service , | ||||
| returning the pid of new process. | ||||
| .Pp | ||||
| .Fn rc_service_started_daemon | ||||
| checks to see if | ||||
| .Fa service | ||||
|   | ||||
| @@ -196,6 +196,10 @@ void env_filter(void); | ||||
| void env_config(void); | ||||
| bool service_plugable(const char *service); | ||||
| int signal_setup(int sig, void (*handler)(int)); | ||||
| pid_t exec_service(const char *, const char *); | ||||
|  | ||||
| #define service_start(service) exec_service(service, "start"); | ||||
| #define service_stop(service)  exec_service(service, "stop"); | ||||
|  | ||||
| /* basename_c never modifies the argument. As such, if there is a trailing | ||||
|  * slash then an empty string is returned. */ | ||||
|   | ||||
| @@ -673,95 +673,6 @@ bool rc_service_value_set(const char *service, const char *option, | ||||
| } | ||||
| librc_hidden_def(rc_service_value_set) | ||||
|  | ||||
| static 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; | ||||
| } | ||||
|  | ||||
| pid_t rc_service_stop(const char *service) | ||||
| { | ||||
| 	RC_SERVICE state = rc_service_state(service); | ||||
|  | ||||
| 	if (state & RC_SERVICE_FAILED) | ||||
| 		return -1; | ||||
|  | ||||
| 	if (state & RC_SERVICE_STOPPED) | ||||
| 		return 0; | ||||
|  | ||||
| 	return _exec_service(service, "stop"); | ||||
| } | ||||
| librc_hidden_def(rc_service_stop) | ||||
|  | ||||
| pid_t rc_service_start(const char *service) | ||||
| { | ||||
| 	RC_SERVICE state = rc_service_state(service); | ||||
|  | ||||
| 	if (state & RC_SERVICE_FAILED) | ||||
| 		return -1; | ||||
|  | ||||
| 	if (! state & RC_SERVICE_STOPPED) | ||||
| 		return 0; | ||||
|  | ||||
| 	return _exec_service(service, "start"); | ||||
| } | ||||
| librc_hidden_def(rc_service_start) | ||||
|  | ||||
| bool rc_service_schedule_start(const char *service, | ||||
| 			       const char *service_to_start) | ||||
|   | ||||
| @@ -104,8 +104,6 @@ librc_hidden_proto(rc_service_mark) | ||||
| librc_hidden_proto(rc_service_resolve) | ||||
| librc_hidden_proto(rc_service_schedule_clear) | ||||
| librc_hidden_proto(rc_service_schedule_start) | ||||
| librc_hidden_proto(rc_service_start) | ||||
| librc_hidden_proto(rc_service_stop) | ||||
| librc_hidden_proto(rc_services_in_runlevel) | ||||
| librc_hidden_proto(rc_services_in_state) | ||||
| librc_hidden_proto(rc_services_scheduled) | ||||
|   | ||||
| @@ -172,16 +172,6 @@ bool rc_service_schedule_clear(const char *); | ||||
|  * @return state of the service */ | ||||
| RC_SERVICE rc_service_state(const char *); | ||||
|  | ||||
| /*! Start a service | ||||
|  * @param service to start | ||||
|  * @return pid of the service starting process */ | ||||
| pid_t rc_service_start(const char *); | ||||
|  | ||||
| /*! Stop a service | ||||
|  * @param service to stop | ||||
|  * @return pid of service stopping process */ | ||||
| pid_t rc_service_stop(const char *); | ||||
|  | ||||
| /*! Check if the service started the daemon | ||||
|  * @param service to check | ||||
|  * @param exec to check | ||||
|   | ||||
| @@ -32,8 +32,6 @@ global: | ||||
| 	rc_service_resolve; | ||||
| 	rc_service_schedule_clear; | ||||
| 	rc_service_schedule_start; | ||||
| 	rc_service_start; | ||||
| 	rc_service_stop; | ||||
| 	rc_services_in_runlevel; | ||||
| 	rc_services_in_state; | ||||
| 	rc_services_scheduled; | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|   | ||||
							
								
								
									
										17
									
								
								src/rc/rc.c
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								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,12 +850,16 @@ 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) { | ||||
| 		state = rc_service_state(service->value); | ||||
| 		if (!(state & RC_SERVICE_STOPPED) || state & RC_SERVICE_FAILED) | ||||
| 			continue; | ||||
|  | ||||
| 		if (! interactive) | ||||
| 			interactive = want_interactive(); | ||||
|  | ||||
| @@ -876,7 +882,7 @@ interactive_option: | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 			pid = rc_service_start(service->value); | ||||
| 		pid = service_start(service->value); | ||||
|  | ||||
| 		/* Remember the pid if we're running in parallel */ | ||||
| 		if (pid > 0) { | ||||
| @@ -888,7 +894,6 @@ interactive_option: | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	} | ||||
|  | ||||
| 	/* Store our interactive status for boot */ | ||||
| 	if (interactive && strcmp(runlevel, getenv("RC_BOOTLEVEL")) == 0) | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -29,10 +29,8 @@ rc_service_mark | ||||
| rc_service_resolve | ||||
| rc_service_schedule_clear | ||||
| rc_service_schedule_start | ||||
| rc_service_start | ||||
| rc_service_started_daemon | ||||
| rc_service_state | ||||
| rc_service_stop | ||||
| rc_service_value_get | ||||
| rc_service_value_set | ||||
| rc_services_in_runlevel | ||||
|   | ||||
| @@ -58,14 +58,10 @@ rc_service_schedule_clear | ||||
| rc_service_schedule_clear@@RC_1.0 | ||||
| rc_service_schedule_start | ||||
| rc_service_schedule_start@@RC_1.0 | ||||
| rc_service_start | ||||
| rc_service_start@@RC_1.0 | ||||
| rc_service_started_daemon | ||||
| rc_service_started_daemon@@RC_1.0 | ||||
| rc_service_state | ||||
| rc_service_state@@RC_1.0 | ||||
| rc_service_stop | ||||
| rc_service_stop@@RC_1.0 | ||||
| rc_service_value_get | ||||
| rc_service_value_get@@RC_1.0 | ||||
| rc_service_value_set | ||||
|   | ||||
		Reference in New Issue
	
	Block a user