init: Retain traditional restart behavior for critical and oneshot services.

Adds an SVC_RESTART state that's used for an explicit "restart" of a
running service.  This retains the traditional restart behavior for
critical and oneshot services (previously altered by 7e36edd8), whereby
these services are "simply restarted" instead of counting as a crash (for a
critical serivce) or going into the disabled state (for a oneshot service).
This commit is contained in:
Mike Kasick 2012-01-25 23:48:46 -05:00
parent 7e36edd80f
commit b54f39fdd9
4 changed files with 35 additions and 11 deletions

View File

@ -523,8 +523,7 @@ int do_restart(int nargs, char **args)
struct service *svc;
svc = service_find_by_name(args[1]);
if (svc) {
service_stop(svc);
service_start(svc, NULL);
service_restart(svc);
}
return 0;
}

View File

@ -169,7 +169,7 @@ void service_start(struct service *svc, const char *dynamic_args)
* state and immediately takes it out of the restarting
* state if it was in there
*/
svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET));
svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART));
svc->time_started = 0;
/* running processes require no additional work -- if
@ -366,14 +366,14 @@ void service_start(struct service *svc, const char *dynamic_args)
notify_service_state(svc->name, "running");
}
/* The how field should be either SVC_DISABLED or SVC_RESET */
/* The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART */
static void service_stop_or_reset(struct service *svc, int how)
{
/* The service is still SVC_RUNNING until its process exits, but if it has
* already exited it shoudn't attempt a restart yet. */
svc->flags &= (~SVC_RESTARTING);
if ((how != SVC_DISABLED) && (how != SVC_RESET)) {
if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) {
/* Hrm, an illegal flag. Default to SVC_DISABLED */
how = SVC_DISABLED;
}
@ -405,6 +405,17 @@ void service_stop(struct service *svc)
service_stop_or_reset(svc, SVC_DISABLED);
}
void service_restart(struct service *svc)
{
if (svc->flags & SVC_RUNNING) {
/* Stop, wait, then start the service. */
service_stop_or_reset(svc, SVC_RESTART);
} else if (!(svc->flags & SVC_RESTARTING)) {
/* Just start the service since it's not running. */
service_start(svc, NULL);
} /* else: Service is restarting anyways. */
}
void property_changed(const char *name, const char *value)
{
if (property_triggers_enabled)
@ -471,6 +482,17 @@ static void msg_stop(const char *name)
}
}
static void msg_restart(const char *name)
{
struct service *svc = service_find_by_name(name);
if (svc) {
service_restart(svc);
} else {
ERROR("no such service '%s'\n", name);
}
}
void handle_control_message(const char *msg, const char *arg)
{
if (!strcmp(msg,"start")) {
@ -478,8 +500,7 @@ void handle_control_message(const char *msg, const char *arg)
} else if (!strcmp(msg,"stop")) {
msg_stop(arg);
} else if (!strcmp(msg,"restart")) {
msg_stop(arg);
msg_start(arg);
msg_restart(arg);
} else {
ERROR("unknown control msg '%s'\n", msg);
}

View File

@ -72,6 +72,7 @@ struct svcenvinfo {
#define SVC_RESET 0x40 /* Use when stopping a process, but not disabling
so it can be restarted with its class */
#define SVC_RC_DISABLED 0x80 /* Remember if the disabled flag was set in the rc script */
#define SVC_RESTART 0x100 /* Use to safely restart (stop, wait, start) a service */
#define NR_SVC_SUPP_GIDS 12 /* twelve supplementary groups */
@ -129,6 +130,7 @@ void service_for_each_flags(unsigned matchflags,
void (*func)(struct service *svc));
void service_stop(struct service *svc);
void service_reset(struct service *svc);
void service_restart(struct service *svc);
void service_start(struct service *svc, const char *dynamic_args);
void property_changed(const char *name, const char *value);

View File

@ -63,7 +63,7 @@ static int wait_for_one_process(int block)
NOTICE("process '%s', pid %d exited\n", svc->name, pid);
if (!(svc->flags & SVC_ONESHOT)) {
if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) {
kill(-pid, SIGKILL);
NOTICE("process '%s' killing any children in process group\n", svc->name);
}
@ -78,8 +78,9 @@ static int wait_for_one_process(int block)
svc->pid = 0;
svc->flags &= (~SVC_RUNNING);
/* oneshot processes go into the disabled state on exit */
if (svc->flags & SVC_ONESHOT) {
/* oneshot processes go into the disabled state on exit,
* except when manually restarted. */
if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) {
svc->flags |= SVC_DISABLED;
}
@ -90,7 +91,7 @@ static int wait_for_one_process(int block)
}
now = gettime();
if (svc->flags & SVC_CRITICAL) {
if ((svc->flags & SVC_CRITICAL) && !(svc->flags & SVC_RESTART)) {
if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
ERROR("critical process '%s' exited %d times in %d minutes; "
@ -105,6 +106,7 @@ static int wait_for_one_process(int block)
}
}
svc->flags &= (~SVC_RESTART);
svc->flags |= SVC_RESTARTING;
/* Execute all onrestart commands for this service. */