summary refs log tree commit diff
path: root/service.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--service.c72
1 files changed, 65 insertions, 7 deletions
diff --git a/service.c b/service.c
index 290372d..35d15f3 100644
--- a/service.c
+++ b/service.c
@@ -25,6 +25,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/time.h>
+#include <sys/wait.h>
 #include <syslog.h>
 #include <time.h>
 #include <unistd.h>
@@ -109,6 +110,14 @@ err:
 	return -1;
 }
 
+static void setDeadline(struct Service *service) {
+	clock_gettime(CLOCK_MONOTONIC_FAST, &service->restartDeadline);
+	timespecadd(
+		&service->restartDeadline, &service->restartInterval,
+		&service->restartDeadline
+	);
+}
+
 void serviceStart(struct Service *service) {
 	if (service->state != Stop) return;
 
@@ -118,11 +127,7 @@ void serviceStart(struct Service *service) {
 	} else {
 		service->restartInterval = restartInterval;
 	}
-	clock_gettime(CLOCK_MONOTONIC_FAST, &service->restartDeadline);
-	timespecadd(
-		&service->restartDeadline, &service->restartInterval,
-		&service->restartDeadline
-	);
+	setDeadline(service);
 
 	service->intent = Start;
 	service->pid = fork();
@@ -131,6 +136,10 @@ void serviceStart(struct Service *service) {
 		return;
 	}
 	if (service->pid) {
+		syslog(
+			LOG_INFO, "%s[%jd] start",
+			service->name, (intmax_t)service->pid
+		);
 		service->state = Start;
 		return;
 	}
@@ -172,8 +181,8 @@ void serviceSignal(struct Service *service, int signal) {
 	int error = kill(service->pid, signal);
 	if (error) {
 		syslog(
-			LOG_ERR, "signal %s %s[%ju]: %m",
-			sys_signame[signal], service->name, (uintmax_t)service->pid
+			LOG_ERR, "kill(%s[%jd], %s): %m",
+			service->name, (intmax_t)service->pid, sys_signame[signal]
 		);
 	}
 }
@@ -191,3 +200,52 @@ void serviceRestart(struct Service *service) {
 		serviceStart(service);
 	}
 }
+
+void serviceReap(pid_t pid, int status) {
+	struct Service *service = NULL;
+	for (size_t i = 0; i < services.len; ++i) {
+		if (services.ptr[i].state != Start) continue;
+		if (services.ptr[i].pid != pid) continue;
+		service = &services.ptr[i];
+		break;
+	}
+	if (!service) {
+		syslog(LOG_WARNING, "reaping unknown child %jd", (intmax_t)pid);
+		return;
+	}
+
+	// TODO: Flush line buffers.
+
+	service->state = Stop;
+	if (WIFEXITED(status)) {
+		int exit = WEXITSTATUS(status);
+		if (exit == StopExit || setTest(&stopExits, exit)) {
+			service->intent = Stop;
+		}
+		if (exit) {
+			syslog(
+				LOG_WARNING, "%s[%jd] exit %d",
+				service->name, (intmax_t)pid, exit
+			);
+		}
+	} else if (WIFSIGNALED(status)) {
+		syslog(
+			LOG_WARNING, "%s[%jd] signal %s",
+			service->name, (intmax_t)pid, sys_signame[WTERMSIG(status)]
+		);
+	}
+
+	if (service->intent == Start) {
+		setDeadline(service);
+		syslog(
+			LOG_INFO, "%s[%jd] restart in %jds",
+			service->name, (intmax_t)pid,
+			(intmax_t)service->restartInterval.tv_sec
+		);
+	} else {
+		syslog(LOG_INFO, "%s[%jd] stop", service->name, (intmax_t)pid);
+	}
+	if (service->intent == Restart) {
+		serviceStart(service);
+	}
+}