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/rc.c | |
| 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/rc.c')
| -rw-r--r-- | src/rc/rc.c | 94 | 
1 files changed, 61 insertions, 33 deletions
| 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, ","))) | 
