Fix #227: set svc state late when stopping services, nay be dead

A service may have unexpectedly died, and we never got the signal, so
when stopping services we must set the new state after we've tried to
stop the service.  Otherwise the svc_set_state() function starts a
background timer for the SIGKILL job, which may block a reboot.

The kill() syscall tells us if the service was there or not, if not we
must clean up and go to HALTED state.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2022-03-22 07:18:37 +01:00
parent 996ab8c6c6
commit 7dc7f9a968
+10 -6
View File
@@ -746,8 +746,6 @@ static int service_stop(svc_t *svc)
*/
svc_started(svc);
svc_set_state(svc, SVC_STOPPING_STATE);
if (!svc->desc[0])
do_progress = 0;
@@ -758,12 +756,17 @@ static int service_stop(svc_t *svc)
if (svc->pid > 1) {
/* Kill all children in the same proess group, e.g. logit */
rc = kill(-svc->pid, svc->sighalt);
_d("kill(-%d, %d) => rc %d", svc->pid, svc->sighalt, rc);
_d("kill(-%d, %d) => rc %d, errno %d", svc->pid, svc->sighalt, rc, errno);
/* PID lost or forking process never really started */
if (rc == -1 && ESRCH == errno)
service_cleanup(svc);
} else
if (rc == -1 && errno == ESRCH) {
service_cleanup(svc);
svc_set_state(svc, SVC_HALTED_STATE);
} else
svc_set_state(svc, SVC_STOPPING_STATE);
} else {
service_cleanup(svc);
svc_set_state(svc, SVC_HALTED_STATE);
}
} else {
char *args[] = { svc->cmd, "stop", NULL };
pid_t pid;
@@ -781,6 +784,7 @@ static int service_stop(svc_t *svc)
rc = 1;
break;
default:
svc_set_state(svc, SVC_STOPPING_STATE);
rc = WEXITSTATUS(complete(svc->cmd, pid));
break;
}