sm: handle runlevel change

Signed-off-by: Jonas Johansson <jonas.johansson@westermo.se>
This commit is contained in:
Jonas Johansson committed 2016-05-18 10:18:40 +02:00
1 parent 364f3bbafb
commit 60df2043ac
5 files changed
+105 -52

No files matched your search

+2
View File
@@ -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_ */
+5 -52
View File
@@ -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);
}
/**
+2
View File
@@ -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_ */
/**
+92
View File
@@ -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;
}
+4
View File
@@ -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_ */