예제 #1
0
파일: service.c 프로젝트: rrogers96/finit
/**
 * service_enabled - Should the service run?
 * @svc:   Pointer to &svc_t object
 * @event: Dynamic event, opaque flag passed to callback
 * @arg:   Event argument, used only by external service plugins.
 *
 * This method calls an associated service callback, if registered by a
 * plugin, and returns the &svc_cmd_t status. If no plugin is registered
 * the service is statically enabled in /etc/finit.conf and the result
 * will always be %SVC_START.
 *
 * Returns:
 * Either one of %SVC_START, %SVC_STOP, %SVC_RELOAD.
 */
svc_cmd_t service_enabled(svc_t *svc, int event, void *arg)
{
	if (!svc) {
		errno = EINVAL;
		return SVC_STOP;
	}

	if (!svc_in_runlevel(svc, runlevel))
		return SVC_STOP;

	/*
	 * Event conditions for services are ignored during bootstrap.
	 */
	if (runlevel && !event_service_cond(svc->events))
		return SVC_STOP;

	/* Is there a service plugin registered? */
	if (svc->cb) {
		int   status;
		pid_t pid;

		/* Let callback run in separate process so it doesn't crash PID 1 */
		pid = fork();
		if (-1 == pid) {
			_pe("Failed in %s callback", svc->cmd);
			return SVC_STOP;
		}

		if (!pid) {
			status = svc->cb(svc, event, arg);
			exit(status);
		}

		if (waitpid(pid, &status, 0) == -1) {
			_pe("Failed reading status from %s callback", svc->cmd);
			return SVC_STOP;
		}

		/* Callback normally exits here. */
		if (WIFEXITED(status))
			return WEXITSTATUS(status);

		/* Check for SEGFAULT or other error ... */
		if (WIFSIGNALED(status) && WCOREDUMP(status))
			_e("Callback to %s crashed!\n", svc->cmd);
		else
			_e("Callback to %s did not exit normally!\n", svc->cmd);

		return SVC_STOP;
	}

	/* No service plugin, default to start, since listed in finit.conf */
	return SVC_START;
}
예제 #2
0
파일: service.c 프로젝트: rrogers96/finit
/**
 * service_runlevel - Change to a new runlevel
 * @newlevel: New runlevel to activate
 *
 * Stops all services not in @newlevel and starts, or lets continue to run,
 * those in @newlevel.  Also updates @prevlevel and active @runlevel.
 */
void service_runlevel(int newlevel)
{
	svc_t *svc;

	if (runlevel == newlevel)
		return;

	if (newlevel < 0 || newlevel > 9)
		return;

	prevlevel = runlevel;
	runlevel  = newlevel;

	_d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel);
	runlevel_set(prevlevel, newlevel);

	/* Make sure to (re)load all *.conf in /etc/finit.d/ */
	conf_reload_dynamic();

	_d("Stopping services services not allowed in new runlevel ...");
	for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
		if (!svc_in_runlevel(svc, runlevel)) {
#ifndef INETD_DISABLED
			if (svc_is_inetd(svc))
				inetd_stop(&svc->inetd);
			else
#endif
				service_stop(svc);
		}

		/* ... or disabled/removed services from /etc/finit.d/ */
		if (svc_is_dynamic(svc) && svc_is_changed(svc))
			service_stop(svc);
	}

	/* Prev runlevel services stopped, call hooks before starting new runlevel ... */
	_d("All services have been stoppped, calling runlevel change hooks ...");
	plugin_run_hooks(HOOK_RUNLEVEL_CHANGE);  /* Reconfigure HW/VLANs/etc here */

	_d("Starting services services new to this runlevel ...");
	for (svc = svc_iterator(1); svc; svc = svc_iterator(0)) {
#ifndef INETD_DISABLED
		/* Inetd services have slightly different semantics */
		if (svc_is_inetd(svc)) {
			if (svc_in_runlevel(svc, runlevel))
				inetd_start(&svc->inetd);

			continue;
		}
#endif

		/* All other services consult their callback here */
		svc_dance(svc);
	}

	/* Cleanup stale services */
	svc_clean_dynamic(service_unregister);

	if (0 == runlevel) {
		do_shutdown(SIGUSR2);
		return;
	}
	if (6 == runlevel) {
		do_shutdown(SIGUSR1);
		return;
	}

	if (runlevel == 1)
		touch("/etc/nologin");	/* Disable login in single-user mode */
	else
		erase("/etc/nologin");

	if (0 != prevlevel)
		tty_runlevel(runlevel);
}
예제 #3
0
파일: service.c 프로젝트: wkz/finit
/**
 * service_enabled - Should the service run?
 * @svc:   Pointer to &svc_t object
 * @event: Dynamic event, opaque flag passed to callback
 * @arg:   Event argument, used only by external service plugins.
 *
 * This method calls an associated service callback, if registered by a
 * plugin, and returns the &svc_cmd_t status. If no plugin is registered
 * the service is statically enabled in /etc/finit.conf and the result
 * will always be %SVC_START.
 *
 * Returns:
 * Either one of %SVC_START, %SVC_STOP, %SVC_RELOAD.
 */
svc_cmd_t service_enabled(svc_t *svc, int event, void *arg)
{
	svc_cmd_t cmd = SVC_START; /* Default to start, since listed in finit.conf */

	if (!svc) {
		errno = EINVAL;
		return SVC_STOP;
	}

	if (!svc_in_runlevel(svc, runlevel))
		return SVC_STOP;

	/*
	 * Event conditions for services are ignored during bootstrap.
	 */
	_d("Checking %s runlevel %d and events %s", svc->cmd, runlevel, svc->events);
	if (runlevel && !event_service_cond(svc->events))
		return SVC_STOP;

	if (svc->state == SVC_RELOAD_STATE)
		cmd = SVC_RELOAD;
	if (svc->state == SVC_PAUSED_STATE)
		cmd = SVC_STOP;

	/* Is there a service plugin registered? */
	if (svc->cb) {
		int   status;
		pid_t pid;

		/* Let callback run in separate process so it doesn't crash PID 1 */
		pid = fork();
		if (-1 == pid) {
			_pe("Failed in %s callback", svc->cmd);
			return SVC_STOP;
		}

		if (!pid)
			_exit(svc->cb(svc, event, arg));

		if (waitpid(pid, &status, 0) == -1) {
			_pe("Failed reading status from %s callback", svc->cmd);
			return SVC_STOP;
		}

		/* Callback normally exits here. */
		if (WIFEXITED(status)) {
			svc_cmd_t tmp = WEXITSTATUS(status);
			return tmp == SVC_START ? cmd : tmp;
		}

		/* Check for SEGFAULT or other error ... */
		if (WIFSIGNALED(status) && WCOREDUMP(status))
			_e("Callback to %s crashed!\n", svc->cmd);
		else
			_e("Callback to %s did not exit normally!\n", svc->cmd);

		return SVC_STOP;
	}

	_d("%s => %s", svc->cmd, (cmd == SVC_START
				  ? "SVC_START"
				  : (cmd == SVC_RELOAD
				     ? "SVC_RELOAD"
				     : "SVC_STOP")));

	return cmd;
}