diff options
| author | Alexander V Vershilov <qnikst@gentoo.org> | 2013-08-07 11:03:51 +0400 | 
|---|---|---|
| committer | William Hubbs <w.d.hubbs@gmail.com> | 2013-09-20 14:27:31 -0500 | 
| commit | 7716bf31de5030b761613834e11e4e62f36403a5 (patch) | |
| tree | 60daee3287bbadf7143291945c2a0411d1491878 /src/rc | |
| parent | 445b297360b85c03b4509458f194a0d964c1d71a (diff) | |
| download | openrc-7716bf31de5030b761613834e11e4e62f36403a5.tar.xz | |
Fix stacked runlevel support
Patch was provided by  Max Hacking <max.gentoo.bugzilla@hacking.co.uk>
and slightly fixed by Alexander Vershilov <qnikst@gentoo.org> and
William Hubbs <williamh@gentoo.org>.
Fixes:
1). Rebase to newest OpenRC version.
2). Remove code style fixes. Port to currect code style.
3). Fix rc_runlevel_stack instead of introducing new function.
4). Make get_runlevel_chain a private function.
X-Gentoo-Bug: 467368
X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=467368
Diffstat (limited to 'src/rc')
| -rw-r--r-- | src/rc/rc-status.c | 65 | ||||
| -rw-r--r-- | src/rc/rc.c | 94 | 
2 files changed, 98 insertions, 61 deletions
| diff --git a/src/rc/rc-status.c b/src/rc/rc-status.c index d0492168..d14dd63a 100644 --- a/src/rc/rc-status.c +++ b/src/rc/rc-status.c @@ -171,6 +171,26 @@ print_services(const char *runlevel, RC_STRINGLIST *svcs)  	rc_stringlist_free(l);  } +static void +print_stacked_services(const char *runlevel) +{ +	RC_STRINGLIST *stackedlevels, *servicelist; +	RC_STRING *stackedlevel; + +	stackedlevels = rc_runlevel_stacks(runlevel); +	TAILQ_FOREACH(stackedlevel, stackedlevels, entries) { +		if (rc_stringlist_find(levels, stackedlevel->value) != NULL) +			continue; +		print_level("Stacked", stackedlevel->value); +		servicelist = rc_services_in_runlevel(stackedlevel->value); +		print_services(stackedlevel->value, servicelist); +		rc_stringlist_free(servicelist); +		print_stacked_services(stackedlevel->value); +	} +	rc_stringlist_free(stackedlevels); +	stackedlevels = NULL; +} +  #include "_usage.h"  #define usagestring ""						\  	"Usage: rc-status [options] <runlevel>...\n"		\ @@ -199,7 +219,8 @@ static const char * const longopts_help[] = {  int  rc_status(int argc, char **argv)  { -	RC_STRING *s, *l, *t; +    RC_STRING *s, *l, *t, *level; +  	char *p, *runlevel = NULL;  	int opt, aflag = 0, retval = 0; @@ -280,16 +301,7 @@ rc_status(int argc, char **argv)  		print_level(NULL, l->value);  		services = rc_services_in_runlevel(l->value);  		print_services(l->value, services); -		nservices = rc_runlevel_stacks(l->value); -		TAILQ_FOREACH(s, nservices, entries) { -			if (rc_stringlist_find(levels, s->value) != NULL) -				continue; -			print_level("Stacked", s->value); -			sservices = rc_services_in_runlevel(s->value); -			print_services(s->value, sservices); -			rc_stringlist_free(sservices); -		} -		sservices = NULL; +		print_stacked_services(l->value);  		rc_stringlist_free(nservices);  		nservices = NULL;  		rc_stringlist_free(services); @@ -317,16 +329,14 @@ rc_status(int argc, char **argv)  		services = rc_services_in_runlevel(NULL);  		sservices = rc_stringlist_new();  		TAILQ_FOREACH(l, levels, entries) { -			nservices = rc_services_in_runlevel(l->value); +			nservices = rc_services_in_runlevel_stacked(l->value);  			TAILQ_CONCAT(sservices, nservices, entries);  			free(nservices);  		}  		TAILQ_FOREACH_SAFE(s, services, entries, t) { -			if (rc_stringlist_find(sservices, s->value) || -			    rc_service_state(s->value) & -			    (RC_SERVICE_STOPPED | RC_SERVICE_HOTPLUGGED)) -		{ -			TAILQ_REMOVE(services, s, entries); +			if ((rc_stringlist_find(sservices, s->value) || +			    (rc_service_state(s->value) & ( RC_SERVICE_STOPPED | RC_SERVICE_HOTPLUGGED)))) { +				TAILQ_REMOVE(services, s, entries);  				free(s->value);  				free(s);  			} @@ -337,18 +347,17 @@ rc_status(int argc, char **argv)  		alist = rc_stringlist_new();  		l = rc_stringlist_add(alist, "");  		p = l->value; -		if (!runlevel) -			runlevel = rc_runlevel_get(); -		TAILQ_FOREACH_SAFE(s, services, entries, t) { -			l->value = s->value; -			unsetenv("RC_SVCNAME"); -			setenv("RC_SVCNAME", l->value, 1); -			tmp = rc_deptree_depends(deptree, needsme, alist, runlevel, RC_DEP_TRACE); -			if (TAILQ_FIRST(tmp)) { -				TAILQ_REMOVE(services, s, entries); -				TAILQ_INSERT_TAIL(nservices, s, entries); +		TAILQ_FOREACH(level, levels, entries) { +			TAILQ_FOREACH_SAFE(s, services, entries, t) { +				l->value = s->value; +				setenv("RC_SVCNAME", l->value, 1); +				tmp = rc_deptree_depends(deptree, needsme, alist, level->value, RC_DEP_TRACE); +				if (TAILQ_FIRST(tmp)) { +					TAILQ_REMOVE(services, s, entries); +					TAILQ_INSERT_TAIL(nservices, s, entries); +				} +				rc_stringlist_free(tmp);  			} -			rc_stringlist_free(tmp);  		}  		l->value = p;  		/* we are unsetting RC_SVCNAME because last loaded service  diff --git a/src/rc/rc.c b/src/rc/rc.c index 0e37182c..0c983721 100644 --- a/src/rc/rc.c +++ b/src/rc/rc.c @@ -79,12 +79,6 @@ const char rc_copyright[] = "Copyright (c) 2007-2008 Roy Marples";  const char *applet = NULL;  static char *runlevel; -static RC_STRINGLIST *hotplugged_services; -static RC_STRINGLIST *stop_services; -static RC_STRINGLIST *start_services; -static RC_STRINGLIST *types_n; -static RC_STRINGLIST *types_nua; -static RC_DEPTREE *deptree;  static RC_HOOK hook_out;  struct termios *termios_orig = NULL; @@ -524,7 +518,9 @@ runlevel_config(const char *service, const char *level)  }  static void -do_stop_services(const char *newlevel, bool parallel, bool going_down) +do_stop_services(const RC_STRINGLIST *types_n, const RC_STRINGLIST *start_services, +				 const RC_STRINGLIST *stop_services, const RC_DEPTREE *deptree, +				 const char *newlevel, bool parallel, bool going_down)  {  	pid_t pid;  	RC_STRING *service, *svc1, *svc2; @@ -627,7 +623,7 @@ stop:  }  static void -do_start_services(bool parallel) +do_start_services(const RC_STRINGLIST *start_services, bool parallel)  {  	RC_STRING *service;  	pid_t pid; @@ -754,6 +750,12 @@ main(int argc, char **argv)  {  	const char *bootlevel = NULL;  	char *newlevel = NULL; +	static RC_STRINGLIST *hotplugged_services; +	static RC_STRINGLIST *stop_services; +	static RC_STRINGLIST *start_services; +	static RC_STRINGLIST *types_n; +	static RC_STRINGLIST *types_nua; +	static RC_DEPTREE *deptree;  	RC_STRINGLIST *deporder = NULL;  	RC_STRINGLIST *tmplist;  	RC_STRING *service; @@ -868,7 +870,11 @@ main(int argc, char **argv)  	snprintf(pidstr, sizeof(pidstr), "%d", getpid());  	setenv("RC_PID", pidstr, 1); -	/* Load current runlevel */ +	/* Create a list of all services which should be started for the new or +	* current runlevel including those in boot, sysinit and hotplugged +	* runlevels.  Clearly, some of these will already be started so we +	* won't actually be starting them all. +	*/  	bootlevel = getenv("RC_BOOTLEVEL");  	runlevel = rc_runlevel_get(); @@ -972,8 +978,13 @@ main(int argc, char **argv)  		    applet, RC_STOPPING, strerror(errno));  	} -	/* Build a list of all services to stop and then work out the -	 * correct order for stopping them */ +	/* Create a list of all services which we could stop (assuming +	* they won't be active in the new or current runlevel) including +	* all those services which have been started, are inactive or +	* are currently starting.  Clearly, some of these will be listed +	* in the new or current runlevel so we won't actually be stopping +	* them all. +	*/  	stop_services = rc_services_in_state(RC_SERVICE_STARTED);  	tmplist = rc_services_in_state(RC_SERVICE_INACTIVE);  	TAILQ_CONCAT(stop_services, tmplist, entries); @@ -996,7 +1007,11 @@ main(int argc, char **argv)  		stop_services = tmplist;  	} -	/* Load our list of start services */ +	/* Create a list of all services which should be started for the new or +	 * current runlevel including those in boot, sysinit and hotplugged +	 * runlevels.  Clearly, some of these will already be started so we +	 * won't actually be starting them all. +	 */  	hotplugged_services = rc_services_in_state(RC_SERVICE_HOTPLUGGED);  	start_services = rc_services_in_runlevel_stacked(newlevel ?  	    newlevel : runlevel); @@ -1006,9 +1021,11 @@ main(int argc, char **argv)  		tmplist = rc_services_in_runlevel(RC_LEVEL_SYSINIT);  		TAILQ_CONCAT(start_services, tmplist, entries);  		free(tmplist); +		/* If we are NOT headed for the single-user runlevel... */  		if (strcmp(newlevel ? newlevel : runlevel,  			RC_LEVEL_SINGLE) != 0)  		{ +			/* If we are NOT headed for the boot runlevel... */  			if (strcmp(newlevel ? newlevel : runlevel,  				bootlevel) != 0)  			{ @@ -1029,7 +1046,7 @@ main(int argc, char **argv)  	/* Now stop the services that shouldn't be running */  	if (stop_services && !nostop) -		do_stop_services(newlevel, parallel, going_down); +		do_stop_services(types_n, start_services, stop_services, deptree, newlevel, parallel, going_down);  	/* Wait for our services to finish */  	wait_for_services(); @@ -1065,18 +1082,10 @@ main(int argc, char **argv)  		TAILQ_FOREACH(service, hotplugged_services, entries)  		    rc_service_mark(service->value, RC_SERVICE_HOTPLUGGED); -	/* Order the services to start */ -	if (start_services) { -		rc_stringlist_sort(&start_services); -		deporder = rc_deptree_depends(deptree, types_nua, -		    start_services, runlevel, -		    depoptions | RC_DEP_START); -		rc_stringlist_free(start_services); -		start_services = deporder; -	} -  #ifdef __linux__ -	/* mark any services skipped as started */ +	/* If the "noinit" parameter was passed on the kernel command line then +	 * mark the specified services as started so they will not be started +	 * by us. */  	proc = p = rc_proc_getent("noinit");  	if (proc) {  		while ((token = strsep(&p, ","))) @@ -1085,19 +1094,38 @@ main(int argc, char **argv)  	}  #endif +	/* If we have a list of services to start then... */  	if (start_services) { -		do_start_services(parallel); -		/* FIXME: If we skip the boot runlevel and go straight -		 * to default from sysinit, we should now re-evaluate our -		 * start services + hotplugged services and call -		 * do_start_services a second time. */ - -		/* Wait for our services to finish */ -		wait_for_services(); +		/* Get a list of the chained runlevels which compose the target runlevel */ +		RC_STRINGLIST *runlevel_chain = rc_runlevel_stacks(runlevel); + +		/* Loop through them in reverse order. */ +		RC_STRING *rlevel; +		TAILQ_FOREACH_REVERSE(rlevel, runlevel_chain, rc_stringlist, entries) +		{ +			/* Get a list of all the services in that runlevel */ +			RC_STRINGLIST *run_services = rc_services_in_runlevel(rlevel->value); + +			/* Start those services. */ +			rc_stringlist_sort(&run_services); +			deporder = rc_deptree_depends(deptree, types_nua, run_services, rlevel->value, depoptions | RC_DEP_START); +			rc_stringlist_free(run_services); +			run_services = deporder; +			do_start_services(run_services, parallel); + +			/* Wait for our services to finish */ +			wait_for_services(); +			 +			/* Free the list of services, we're done with it. */ +			rc_stringlist_free(run_services); +		} +		rc_stringlist_free(runlevel_chain);  	}  #ifdef __linux__ -	/* mark any services skipped as stopped */ +	/* If the "noinit" parameter was passed on the kernel command line then +	 * mark the specified services as stopped so that our records reflect +	 * reality.	 */  	proc = p = rc_proc_getent("noinit");  	if (proc) {  		while ((token = strsep(&p, ","))) | 
