mirror of
https://github.com/troglobit/finit.git
synced 2026-10-21 11:29:42 +00:00
sm: handle runlevel change
Signed-off-by: Jonas Johansson <jonas.johansson@westermo.se>
This commit is contained in:
1 parent
364f3bbafb
commit
60df2043ac
5 files changed
+105
-52
No files matched your search
@@ -34,6 +34,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sm.h"
|
||||
#include "libite/lite.h"
|
||||
|
||||
#define CMD_SIZE 256
|
||||
@@ -78,6 +79,7 @@ extern char *username;
|
||||
extern char *runparts;
|
||||
extern char *console;
|
||||
extern char *__progname;
|
||||
extern sm_t sm;
|
||||
|
||||
#endif /* FINIT_H_ */
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "tty.h"
|
||||
#include "service.h"
|
||||
#include "inetd.h"
|
||||
#include "sm.h"
|
||||
|
||||
#define RESPAWN_MAX 10 /* Prevent endless respawn of faulty services. */
|
||||
|
||||
@@ -73,7 +74,7 @@ int service_enabled(svc_t *svc)
|
||||
* Returns:
|
||||
* 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;
|
||||
|
||||
@@ -392,34 +393,8 @@ void service_reload_dynamic(void)
|
||||
*/
|
||||
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);
|
||||
sm_step(&sm);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -431,31 +406,9 @@ static void service_runlevel_finish(void)
|
||||
*/
|
||||
void service_runlevel(int newlevel)
|
||||
{
|
||||
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 ...");
|
||||
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();
|
||||
sm_set_runlevel(&sm, newlevel);
|
||||
sm_step(&sm);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,6 +37,8 @@ void service_reload_dynamic (void);
|
||||
void service_step(svc_t *svc);
|
||||
void service_step_all(int types);
|
||||
|
||||
int service_stop_is_done(void);
|
||||
|
||||
#endif /* FINIT_SERVICE_H_ */
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,13 +26,39 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "finit.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;
|
||||
}
|
||||
|
||||
void sm_set_runlevel(sm_t *sm, int newlevel)
|
||||
{
|
||||
sm->newlevel = newlevel;
|
||||
}
|
||||
|
||||
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_STOP_STATE:
|
||||
return "runlevel/wait";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void sm_step(sm_t *sm)
|
||||
@@ -42,6 +68,8 @@ void sm_step(sm_t *sm)
|
||||
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);
|
||||
@@ -50,6 +78,70 @@ restart:
|
||||
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;
|
||||
}
|
||||
|
||||
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 ...");
|
||||
service_step_all(SVC_TYPE_ANY);
|
||||
|
||||
sm->state = SM_RUNLEVEL_WAIT_STOP_STATE;
|
||||
break;
|
||||
|
||||
case SM_RUNLEVEL_WAIT_STOP_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 ...");
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,14 +27,18 @@
|
||||
typedef enum {
|
||||
SM_BOOTSTRAP_STATE = 0,
|
||||
SM_RUNNING_STATE,
|
||||
SM_RUNLEVEL_CHANGE_STATE,
|
||||
SM_RUNLEVEL_WAIT_STOP_STATE,
|
||||
} sm_state_t;
|
||||
|
||||
typedef struct sm {
|
||||
sm_state_t state;
|
||||
int newlevel;
|
||||
} sm_t;
|
||||
|
||||
void sm_init(sm_t *sm);
|
||||
void sm_step(sm_t *sm);
|
||||
void sm_set_runlevel(sm_t *sm, int newlevel);
|
||||
|
||||
#endif /* FINIT_SM_H_ */
|
||||
|
||||
|
||||
Reference in new issue
Block a user