about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeah Neukirchen <leah@vuxu.org>2023-11-27 17:26:00 +0100
committerLeah Neukirchen <leah@vuxu.org>2023-11-27 17:26:00 +0100
commit9d44c45f9c37f7543e0ed89415e36ff370a34618 (patch)
treed3482e82733f482347f6757e82dea2a1fa4460cf
parentc5f88b6d0ecd69880e7b890c6cadc501c3b8e5c0 (diff)
downloadnitro-9d44c45f9c37f7543e0ed89415e36ff370a34618.tar.gz
nitro-9d44c45f9c37f7543e0ed89415e36ff370a34618.tar.xz
nitro-9d44c45f9c37f7543e0ed89415e36ff370a34618.zip
add finish scripts
-rw-r--r--nitro.c64
1 files changed, 63 insertions, 1 deletions
diff --git a/nitro.c b/nitro.c
index db02491..f3dd782 100644
--- a/nitro.c
+++ b/nitro.c
@@ -60,6 +60,7 @@ enum process_events {
 	EVNT_WANT_DOWN,
 	EVNT_WANT_RESTART,
 	EVNT_EXITED,
+	EVNT_FINISHED,		/* finish script exited */
 	// EVNT_DIED,   health check failed
 };
 
@@ -69,6 +70,7 @@ struct service {
 	deadline deadline;
 	int timeout;
 	pid_t pid;
+	pid_t finishpid;
 	int logpipe[2];
 	enum process_state state;
 	char seen;
@@ -119,6 +121,8 @@ stat_slash(const char *dir, const char *name, struct stat *st)
 	return stat(buf, st);
 }
 
+void process_step(int i, enum process_events ev);
+
 void
 proc_launch(int i)
 {
@@ -193,6 +197,36 @@ proc_launch(int i)
 }
 
 void
+proc_finish(int i)
+{
+	struct stat st;
+	if (stat_slash(services[i].name, "finish", &st) < 0 && errno == ENOENT) {
+		process_step(i, EVNT_FINISHED);
+		return;
+	}
+
+	pid_t child = fork();
+	if (child == 0) {
+		chdir(services[i].name);
+
+		dup2(nullfd, 0);
+		if (services[i].logpipe[1] != -1)
+			dup2(services[i].logpipe[1], 1);
+		else if (globallog[1] != -1)
+			dup2(globallog[1], 1);
+
+		setsid();
+
+		execl("finish", "finish", (char *)0);
+		_exit(127);
+	} else if (child < 0) {
+		abort();	/* XXX handle retry */
+	}
+
+	services[i].finishpid = child;
+}
+
+void
 proc_shutdown(int i)
 {
 	if (services[i].pid)
@@ -223,6 +257,7 @@ void
 proc_cleanup(int i)
 {
 	services[i].pid = 0;
+	services[i].finishpid = 0;
 	services[i].timeout = 0;
 	services[i].deadline = 0;
 	services[i].state = PROC_DOWN;
@@ -331,6 +366,26 @@ process_step(int i, enum process_events ev)
 		services[i].deadline = 0;
 		switch (services[i].state) {
 		case PROC_STARTING:
+		case PROC_UP:
+		case PROC_RESTART:
+		case PROC_SHUTDOWN:
+			proc_finish(i);
+			break;
+
+		case PROC_DOWN:                /* can't happen */
+		case PROC_FATAL:	       /* can't happen */
+		case PROC_DELAY:	       /* can't happen */
+		case PROC_ONESHOT:	       /* can't happen */
+			assert(!"invalid state transition");
+			break;
+		}
+		break;
+
+	case EVNT_FINISHED:
+		services[i].timeout = 0;
+		services[i].deadline = 0;
+		switch (services[i].state) {
+		case PROC_STARTING:
 			proc_cleanup(i);
 			if (global_state != GLBL_UP)
 				break;
@@ -361,7 +416,6 @@ process_step(int i, enum process_events ev)
 		}
 		break;
 
-
 	case EVNT_TIMEOUT:
 		services[i].timeout = 0;
 		services[i].deadline = 0;
@@ -697,12 +751,20 @@ has_died(pid_t pid, int status)
 {
 	for (int i = 0; i < max_service; i++) {
 		if (services[i].pid == pid) {
+			// XXX store status
 			printf("service %s[%d] has died with status %d\n",
 			    services[i].name, pid, status);
 			process_step(i, EVNT_EXITED);
 			return;
 		}
 
+		if (services[i].finishpid == pid) {
+			printf("finish script %s[%d] has died with status %d\n",
+			    services[i].name, pid, status);
+			process_step(i, EVNT_FINISHED);
+			return;
+		}
+
 		// XXX handle logger?
 	}
 }