mirror of
https://github.com/troglobit/finit.git
synced 2026-11-01 13:10:32 +00:00
Merge branch 'westermo-finit-sm'
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
This commit is contained in:
commit
969ecffc05
9 files changed
+307
-152
No files matched your search
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
ACLOCAL_AMFLAGS = -I m4
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
sbin_PROGRAMS = finit initctl reboot
|
sbin_PROGRAMS = finit initctl reboot
|
||||||
finit_SOURCES = finit.c api.c client.c conf.c exec.c helpers.c pid.c \
|
finit_SOURCES = finit.c api.c client.c conf.c exec.c helpers.c pid.c \
|
||||||
sig.c svc.c service.c plugin.c tty.c cond.c cond-w.c
|
sig.c svc.c service.c plugin.c tty.c cond.c cond-w.c sm.c
|
||||||
pkginclude_HEADERS = cond.h finit.h helpers.h inetd.h plugin.h queue.h svc.h
|
pkginclude_HEADERS = cond.h finit.h helpers.h inetd.h plugin.h queue.h svc.h
|
||||||
if INETD
|
if INETD
|
||||||
finit_SOURCES += inetd.c
|
finit_SOURCES += inetd.c
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "lite/lite.h"
|
#include "lite/lite.h"
|
||||||
#include "inetd.h"
|
#include "inetd.h"
|
||||||
|
#include "sm.h"
|
||||||
|
|
||||||
int debug = 0;
|
int debug = 0;
|
||||||
int quiet = QUIET_MODE; /* Delayed disable of silent mode. */
|
int quiet = QUIET_MODE; /* Delayed disable of silent mode. */
|
||||||
@@ -53,6 +54,7 @@ char *hostname = NULL;
|
|||||||
char *rcsd = FINIT_RCSD;
|
char *rcsd = FINIT_RCSD;
|
||||||
char *runparts = NULL;
|
char *runparts = NULL;
|
||||||
char *console = NULL;
|
char *console = NULL;
|
||||||
|
sm_t sm;
|
||||||
|
|
||||||
uev_ctx_t *ctx = NULL; /* Main loop context */
|
uev_ctx_t *ctx = NULL; /* Main loop context */
|
||||||
|
|
||||||
@@ -176,9 +178,10 @@ int main(int argc, char* argv[])
|
|||||||
plugin_run_hooks(HOOK_BASEFS_UP);
|
plugin_run_hooks(HOOK_BASEFS_UP);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start all bootstrap tasks, no network available!
|
* Initalize finit state machine and start all bootstrap tasks, no network available!
|
||||||
*/
|
*/
|
||||||
service_bootstrap();
|
sm_init(&sm);
|
||||||
|
sm_step(&sm);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Network stuff
|
* Network stuff
|
||||||
|
|||||||
@@ -33,8 +33,9 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <lite/lite.h>
|
||||||
|
|
||||||
#include "lite/lite.h"
|
#include "sm.h"
|
||||||
|
|
||||||
#define CMD_SIZE 256
|
#define CMD_SIZE 256
|
||||||
#define LINE_SIZE 1024
|
#define LINE_SIZE 1024
|
||||||
@@ -79,6 +80,7 @@ extern char *username;
|
|||||||
extern char *runparts;
|
extern char *runparts;
|
||||||
extern char *console;
|
extern char *console;
|
||||||
extern char *__progname;
|
extern char *__progname;
|
||||||
|
extern sm_t sm;
|
||||||
|
|
||||||
#endif /* FINIT_H_ */
|
#endif /* FINIT_H_ */
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -71,7 +71,7 @@ static void pidfile_callback(void *UNUSED(arg), int fd, int UNUSED(events))
|
|||||||
|
|
||||||
_d("%s: match %s", basename, svc->cmd);
|
_d("%s: match %s", basename, svc->cmd);
|
||||||
snprintf(cond, sizeof(cond), "svc%s", svc->cmd);
|
snprintf(cond, sizeof(cond), "svc%s", svc->cmd);
|
||||||
if (ev->mask & (IN_CREATE | IN_ATTRIB)) {
|
if (ev->mask & (IN_CREATE | IN_ATTRIB | IN_MODIFY)) {
|
||||||
svc_started(svc);
|
svc_started(svc);
|
||||||
cond_set(cond);
|
cond_set(cond);
|
||||||
} else if (ev->mask & IN_DELETE)
|
} else if (ev->mask & IN_DELETE)
|
||||||
@@ -105,7 +105,7 @@ static void pidfile_init(void *arg)
|
|||||||
struct context *ctx = arg;
|
struct context *ctx = arg;
|
||||||
|
|
||||||
ctx->wd = inotify_add_watch(ctx->fd, _PATH_VARRUN,
|
ctx->wd = inotify_add_watch(ctx->fd, _PATH_VARRUN,
|
||||||
IN_CREATE | IN_ATTRIB | IN_DELETE);
|
IN_CREATE | IN_ATTRIB | IN_DELETE | IN_MODIFY);
|
||||||
if (ctx->wd < 0) {
|
if (ctx->wd < 0) {
|
||||||
_pe("inotify_add_watch()");
|
_pe("inotify_add_watch()");
|
||||||
close(ctx->fd);
|
close(ctx->fd);
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ uev_ctx_t *ctx; /* Main loop context */
|
|||||||
int api_init (uev_ctx_t *ctx);
|
int api_init (uev_ctx_t *ctx);
|
||||||
int client (int argc, char *argv[]);
|
int client (int argc, char *argv[]);
|
||||||
|
|
||||||
void service_bootstrap(void);
|
|
||||||
void service_monitor (pid_t lost);
|
void service_monitor (pid_t lost);
|
||||||
|
|
||||||
void plugin_run_hook (hook_point_t no, void *arg);
|
void plugin_run_hook (hook_point_t no, void *arg);
|
||||||
|
|||||||
@@ -38,27 +38,14 @@
|
|||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
#include "inetd.h"
|
#include "inetd.h"
|
||||||
|
#include "sm.h"
|
||||||
|
|
||||||
#define RESPAWN_MAX 10 /* Prevent endless respawn of faulty services. */
|
#define RESPAWN_MAX 10 /* Prevent endless respawn of faulty services. */
|
||||||
|
|
||||||
static int in_teardown = 0, in_dyn_teardown = 0;
|
|
||||||
|
|
||||||
#ifndef INETD_DISABLED
|
#ifndef INETD_DISABLED
|
||||||
static svc_t *find_inetd_svc (char *path, char *service, char *proto);
|
static svc_t *find_inetd_svc (char *path, char *service, char *proto);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* service_bootstrap - Start bootstrap services and tasks
|
|
||||||
*
|
|
||||||
* System startup, runlevel S, where only services, tasks and
|
|
||||||
* run commands absolutely essential to bootstrap are located.
|
|
||||||
*/
|
|
||||||
void service_bootstrap(void)
|
|
||||||
{
|
|
||||||
_d("Bootstrapping all services in runlevel S from %s", FINIT_CONF);
|
|
||||||
service_step_all(SVC_TYPE_RUN | SVC_TYPE_TASK | SVC_TYPE_SERVICE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* service_enabled - Should the service run?
|
* service_enabled - Should the service run?
|
||||||
* @svc: Pointer to &svc_t object
|
* @svc: Pointer to &svc_t object
|
||||||
@@ -85,7 +72,7 @@ int service_enabled(svc_t *svc)
|
|||||||
* Returns:
|
* Returns:
|
||||||
* 1, if all stopped services have been collected. 0 otherwise.
|
* 1, if all stopped services have been collected. 0 otherwise.
|
||||||
*/
|
*/
|
||||||
static int service_stop_is_done(void)
|
int service_stop_is_done(void)
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
@@ -372,30 +359,6 @@ static int service_restart(svc_t *svc)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* service_reload_dynamic_finish - Finish dynamic service reload
|
|
||||||
*
|
|
||||||
* Second stage of dynamic reload. Called either directly from first
|
|
||||||
* stage if no services had to be stopped, or later from
|
|
||||||
* service_monitor() once all stopped services have been collected.
|
|
||||||
*/
|
|
||||||
static void service_reload_dynamic_finish(void)
|
|
||||||
{
|
|
||||||
in_dyn_teardown = 0;
|
|
||||||
|
|
||||||
/* Cleanup stale services */
|
|
||||||
svc_clean_dynamic(service_unregister);
|
|
||||||
|
|
||||||
_d("Starting services after reconf ...");
|
|
||||||
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
|
||||||
|
|
||||||
_d("Calling reconf hooks ...");
|
|
||||||
plugin_run_hooks(HOOK_SVC_RECONF);
|
|
||||||
|
|
||||||
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
|
||||||
_d("Reconfiguration done");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* service_reload_dynamic - Called on SIGHUP, 'init q' or 'initctl reload'
|
* service_reload_dynamic - Called on SIGHUP, 'init q' or 'initctl reload'
|
||||||
*
|
*
|
||||||
@@ -405,62 +368,8 @@ static void service_reload_dynamic_finish(void)
|
|||||||
*/
|
*/
|
||||||
void service_reload_dynamic(void)
|
void service_reload_dynamic(void)
|
||||||
{
|
{
|
||||||
/* First reload all *.conf in /etc/finit.d/ */
|
sm_set_reload(&sm);
|
||||||
conf_reload_dynamic();
|
sm_step(&sm);
|
||||||
|
|
||||||
/* Then, mark all affected service conditions as in-flux and
|
|
||||||
* let all affected services move to WAITING/HALTED */
|
|
||||||
_d("Stopping services services not allowed after reconf ...");
|
|
||||||
in_dyn_teardown = 1;
|
|
||||||
cond_reload();
|
|
||||||
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
|
||||||
|
|
||||||
/* Need to wait for any services to stop? If so, exit early
|
|
||||||
* and perform second stage from service_monitor() later. */
|
|
||||||
if (!service_stop_is_done())
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Otherwise, kick all svcs again right away */
|
|
||||||
service_reload_dynamic_finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* service_runlevel_finish - Finish runlevel change
|
|
||||||
*
|
|
||||||
* Second stage of runlevel change. Called either directly from first
|
|
||||||
* stage if no services had to be stopped, or later from
|
|
||||||
* service_monitor() once all stopped services have been collected.
|
|
||||||
*/
|
|
||||||
static void service_runlevel_finish(void)
|
|
||||||
{
|
|
||||||
/* 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 ...");
|
|
||||||
in_teardown = 0;
|
|
||||||
service_step_all(SVC_TYPE_ANY);
|
|
||||||
|
|
||||||
/* 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");
|
|
||||||
|
|
||||||
/* No TTYs run at bootstrap, they have a delayed start. */
|
|
||||||
if (prevlevel > 0)
|
|
||||||
tty_runlevel(runlevel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -472,31 +381,8 @@ static void service_runlevel_finish(void)
|
|||||||
*/
|
*/
|
||||||
void service_runlevel(int newlevel)
|
void service_runlevel(int newlevel)
|
||||||
{
|
{
|
||||||
if (runlevel == newlevel)
|
sm_set_runlevel(&sm, newlevel);
|
||||||
return;
|
sm_step(&sm);
|
||||||
|
|
||||||
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 ...");
|
|
||||||
in_teardown = 1;
|
|
||||||
service_step_all(SVC_TYPE_ANY);
|
|
||||||
|
|
||||||
/* Need to wait for any services to stop? If so, exit early
|
|
||||||
* and perform second stage from service_monitor() later. */
|
|
||||||
if (!service_stop_is_done())
|
|
||||||
return;
|
|
||||||
|
|
||||||
service_runlevel_finish();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -744,32 +630,10 @@ void service_unregister(svc_t *svc)
|
|||||||
svc_del(svc);
|
svc_del(svc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* service_teardown_finish - Complete runlevel change or dynamic reload
|
|
||||||
*
|
|
||||||
* If any runlevel change or dynamic service reload is in progress and
|
|
||||||
* all services that had to be stopped have been collected, run the
|
|
||||||
* corresponding second stage.
|
|
||||||
*/
|
|
||||||
static void service_teardown_finish(void)
|
|
||||||
{
|
|
||||||
if (!(in_teardown || in_dyn_teardown))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!service_stop_is_done())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (in_teardown)
|
|
||||||
service_runlevel_finish();
|
|
||||||
|
|
||||||
if (in_dyn_teardown)
|
|
||||||
service_reload_dynamic_finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void service_monitor(pid_t lost)
|
void service_monitor(pid_t lost)
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
char pidfile[MAX_ARG_LEN];
|
||||||
|
|
||||||
if (fexist(SYNC_SHUTDOWN) || lost <= 1)
|
if (fexist(SYNC_SHUTDOWN) || lost <= 1)
|
||||||
return;
|
return;
|
||||||
@@ -791,12 +655,15 @@ void service_monitor(pid_t lost)
|
|||||||
|
|
||||||
_d("collected %s(%d)", svc->cmd, lost);
|
_d("collected %s(%d)", svc->cmd, lost);
|
||||||
|
|
||||||
|
/* Remove pid file (in case service is careless) */
|
||||||
|
snprintf(pidfile, sizeof(pidfile), "%s%s.pid", _PATH_VARRUN, basename(svc->cmd));
|
||||||
|
remove(pidfile);
|
||||||
|
|
||||||
/* No longer running, update books. */
|
/* No longer running, update books. */
|
||||||
svc->pid = 0;
|
svc->pid = 0;
|
||||||
service_step(svc);
|
service_step(svc);
|
||||||
|
|
||||||
/* Check if we're still collecting stopped dynamic services */
|
sm_step(&sm);
|
||||||
service_teardown_finish();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void svc_set_state(svc_t *svc, svc_state_t new)
|
static void svc_set_state(svc_t *svc, svc_state_t new)
|
||||||
@@ -877,6 +744,10 @@ restart:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* wait until all processes has been stopped before continuing... */
|
||||||
|
if (sm_is_in_teardown(&sm))
|
||||||
|
break;
|
||||||
|
|
||||||
err = service_start(svc);
|
err = service_start(svc);
|
||||||
if (err) {
|
if (err) {
|
||||||
(*restart_counter)++;
|
(*restart_counter)++;
|
||||||
@@ -933,6 +804,9 @@ restart:
|
|||||||
case COND_ON:
|
case COND_ON:
|
||||||
if (svc_is_changed(svc)) {
|
if (svc_is_changed(svc)) {
|
||||||
if (svc->sighup) {
|
if (svc->sighup) {
|
||||||
|
/* wait until all processes has been stopped before continuing... */
|
||||||
|
if (sm_is_in_teardown(&sm))
|
||||||
|
break;
|
||||||
service_restart(svc);
|
service_restart(svc);
|
||||||
} else {
|
} else {
|
||||||
service_stop(svc);
|
service_stop(svc);
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ void service_reload_dynamic (void);
|
|||||||
void service_step(svc_t *svc);
|
void service_step(svc_t *svc);
|
||||||
void service_step_all(int types);
|
void service_step_all(int types);
|
||||||
|
|
||||||
|
int service_stop_is_done(void);
|
||||||
|
|
||||||
#endif /* FINIT_SERVICE_H_ */
|
#endif /* FINIT_SERVICE_H_ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,219 @@
|
|||||||
|
/* Finit state machine
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 xxx
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h" /* Generated by configure script */
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "finit.h"
|
||||||
|
#include "cond.h"
|
||||||
|
#include "conf.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "private.h"
|
||||||
|
#include "service.h"
|
||||||
|
#include "sig.h"
|
||||||
|
#include "tty.h"
|
||||||
|
#include "sm.h"
|
||||||
|
|
||||||
|
void sm_init(sm_t *sm)
|
||||||
|
{
|
||||||
|
sm->state = SM_BOOTSTRAP_STATE;
|
||||||
|
sm->newlevel = -1;
|
||||||
|
sm->reload = 0;
|
||||||
|
sm->in_teardown = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *sm_status(sm_t *sm)
|
||||||
|
{
|
||||||
|
switch (sm->state) {
|
||||||
|
case SM_BOOTSTRAP_STATE:
|
||||||
|
return "bootstrap";
|
||||||
|
case SM_RUNNING_STATE:
|
||||||
|
return "running";
|
||||||
|
case SM_RUNLEVEL_CHANGE_STATE:
|
||||||
|
return "runlevel/change";
|
||||||
|
case SM_RUNLEVEL_WAIT_STATE:
|
||||||
|
return "runlevel/wait";
|
||||||
|
case SM_RELOAD_CHANGE_STATE:
|
||||||
|
return "reload/change";
|
||||||
|
case SM_RELOAD_WAIT_STATE:
|
||||||
|
return "reload/wait";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sm_set_runlevel(sm_t *sm, int newlevel)
|
||||||
|
{
|
||||||
|
sm->newlevel = newlevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sm_set_reload(sm_t *sm)
|
||||||
|
{
|
||||||
|
sm->reload = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sm_is_in_teardown(sm_t *sm)
|
||||||
|
{
|
||||||
|
return sm->in_teardown;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sm_step(sm_t *sm)
|
||||||
|
{
|
||||||
|
sm_state_t old_state;
|
||||||
|
|
||||||
|
restart:
|
||||||
|
old_state = sm->state;
|
||||||
|
|
||||||
|
_d("state: %s", sm_status(sm));
|
||||||
|
|
||||||
|
switch (sm->state) {
|
||||||
|
case SM_BOOTSTRAP_STATE:
|
||||||
|
_d("Bootstrapping all services in runlevel S from %s", FINIT_CONF);
|
||||||
|
service_step_all(SVC_TYPE_RUN | SVC_TYPE_TASK | SVC_TYPE_SERVICE);
|
||||||
|
sm->state = SM_RUNNING_STATE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SM_RUNNING_STATE:
|
||||||
|
/* runlevel changed? */
|
||||||
|
if (sm->newlevel >= 0 && sm->newlevel <= 9) {
|
||||||
|
if (runlevel == sm->newlevel) {
|
||||||
|
sm->newlevel = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sm->state = SM_RUNLEVEL_CHANGE_STATE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* reload ? */
|
||||||
|
if (sm->reload) {
|
||||||
|
sm->reload = 0;
|
||||||
|
sm->state = SM_RELOAD_CHANGE_STATE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SM_RUNLEVEL_CHANGE_STATE:
|
||||||
|
prevlevel = runlevel;
|
||||||
|
runlevel = sm->newlevel;
|
||||||
|
sm->newlevel = -1;
|
||||||
|
|
||||||
|
_d("Setting new runlevel --> %d <-- previous %d", runlevel, prevlevel);
|
||||||
|
runlevel_set(prevlevel, runlevel);
|
||||||
|
|
||||||
|
/* Make sure to (re)load all *.conf in /etc/finit.d/ */
|
||||||
|
conf_reload_dynamic();
|
||||||
|
|
||||||
|
_d("Stopping services services not allowed in new runlevel ...");
|
||||||
|
sm->in_teardown = 1;
|
||||||
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
|
sm->state = SM_RUNLEVEL_WAIT_STATE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SM_RUNLEVEL_WAIT_STATE:
|
||||||
|
/* Need to wait for any services to stop? If so, exit early
|
||||||
|
* and perform second stage from service_monitor later. */
|
||||||
|
if (!service_stop_is_done())
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* 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 ...");
|
||||||
|
sm->in_teardown = 0;
|
||||||
|
service_step_all(SVC_TYPE_ANY);
|
||||||
|
|
||||||
|
/* Cleanup stale services */
|
||||||
|
svc_clean_dynamic(service_unregister);
|
||||||
|
|
||||||
|
if (0 == runlevel) {
|
||||||
|
do_shutdown(SIGUSR2);
|
||||||
|
sm->state = SM_RUNNING_STATE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (6 == runlevel) {
|
||||||
|
do_shutdown(SIGUSR1);
|
||||||
|
sm->state = SM_RUNNING_STATE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runlevel == 1)
|
||||||
|
touch("/etc/nologin"); /* Disable login in single-user mode */
|
||||||
|
else
|
||||||
|
erase("/etc/nologin");
|
||||||
|
|
||||||
|
/* No TTYs run at bootstrap, they have a delayed start. */
|
||||||
|
if (prevlevel > 0)
|
||||||
|
tty_runlevel(runlevel);
|
||||||
|
|
||||||
|
sm->state = SM_RUNNING_STATE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SM_RELOAD_CHANGE_STATE:
|
||||||
|
/* First reload all *.conf in /etc/finit.d/ */
|
||||||
|
conf_reload_dynamic();
|
||||||
|
|
||||||
|
/* Then, mark all affected service conditions as in-flux and
|
||||||
|
* let all affected services move to WAITING/HALTED */
|
||||||
|
_d("Stopping services services not allowed after reconf ...");
|
||||||
|
sm->in_teardown = 1;
|
||||||
|
cond_reload();
|
||||||
|
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
||||||
|
|
||||||
|
sm->state = SM_RELOAD_WAIT_STATE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SM_RELOAD_WAIT_STATE:
|
||||||
|
/* Need to wait for any services to stop? If so, exit early
|
||||||
|
* and perform second stage from service_monitor later. */
|
||||||
|
if (!service_stop_is_done())
|
||||||
|
break;
|
||||||
|
|
||||||
|
sm->in_teardown = 0;
|
||||||
|
/* Cleanup stale services */
|
||||||
|
svc_clean_dynamic(service_unregister);
|
||||||
|
|
||||||
|
_d("Starting services after reconf ...");
|
||||||
|
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
||||||
|
|
||||||
|
_d("Calling reconf hooks ...");
|
||||||
|
plugin_run_hooks(HOOK_SVC_RECONF);
|
||||||
|
|
||||||
|
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
||||||
|
_d("Reconfiguration done");
|
||||||
|
|
||||||
|
sm->state = SM_RUNNING_STATE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sm->state != old_state) {
|
||||||
|
goto restart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/* Finit state machine
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 xxx
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FINIT_SM_H_
|
||||||
|
#define FINIT_SM_H_
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SM_BOOTSTRAP_STATE = 0, /* Init state, bootstrap services */
|
||||||
|
SM_RUNNING_STATE, /* Normal state, services running */
|
||||||
|
SM_RUNLEVEL_CHANGE_STATE, /* A runlevel change has occured */
|
||||||
|
SM_RUNLEVEL_WAIT_STATE, /* Waiting for all stopped runlevel processes to be halted */
|
||||||
|
SM_RELOAD_CHANGE_STATE, /* A reload event has occured */
|
||||||
|
SM_RELOAD_WAIT_STATE, /* Waiting for all stopped reload processes to be halted */
|
||||||
|
} sm_state_t;
|
||||||
|
|
||||||
|
typedef struct sm {
|
||||||
|
sm_state_t state; /* Running, Changed, Waiting, ... */
|
||||||
|
int newlevel; /* Set on runlevel change to new runlevel, -1 if not change */
|
||||||
|
int reload; /* Set on reload event, else 0 */
|
||||||
|
int in_teardown; /* Set when waiting for all processes to be halted */
|
||||||
|
} sm_t;
|
||||||
|
|
||||||
|
void sm_init(sm_t *sm);
|
||||||
|
void sm_step(sm_t *sm);
|
||||||
|
void sm_set_runlevel(sm_t *sm, int newlevel);
|
||||||
|
void sm_set_reload(sm_t *sm);
|
||||||
|
int sm_is_in_teardown(sm_t *sm);
|
||||||
|
|
||||||
|
#endif /* FINIT_SM_H_ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* indent-tabs-mode: t
|
||||||
|
* c-file-style: "linux"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
Reference in new issue
Block a user