about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeah Neukirchen <leah@vuxu.org>2024-03-04 18:53:58 +0100
committerLeah Neukirchen <leah@vuxu.org>2024-03-04 18:53:58 +0100
commit6e1c3313884ea208eb193418c2f1a0f5d4078b1c (patch)
tree34d5da9992ae382cb688128a682261ad58132db4
parentdd8da679a0c22c4009b842305cabe00ec5c77712 (diff)
downloadnitro-6e1c3313884ea208eb193418c2f1a0f5d4078b1c.tar.gz
nitro-6e1c3313884ea208eb193418c2f1a0f5d4078b1c.tar.xz
nitro-6e1c3313884ea208eb193418c2f1a0f5d4078b1c.zip
remove log/ dirs, use symlinks instead
This also allows sharing loggers.
-rw-r--r--README.md7
-rw-r--r--nitro.c116
2 files changed, 54 insertions, 69 deletions
diff --git a/README.md b/README.md
index c721d63..f8e0caa 100644
--- a/README.md
+++ b/README.md
@@ -46,8 +46,9 @@ can contain several files:
   process finished.  It is passed two arguments, the exit status
   of the `run` process (or -1 if it was killed by a signal)
   and the signal that killed it (or 0, if it exited regularly).
-- `log`, another service that is brought up.  The standard output
-  of `run` is connected to the standard input by a pipe.
+- `log`, a symlink to another service directory.
+  The standard output of `run` is connected to the standard input of the
+  service under `log` by a pipe.
 - `down`, an optional file that causes nitro to not bring up this
   service by default.
 - Service directories ending with '@' are ignored; they can be used
@@ -58,7 +59,7 @@ You may find runit's `chpst` useful when writing `run` scripts.
 ## Special services
 
 - `LOG`: this service is used as a logging service for all services
-  that don't have a `log` directory.
+  that don't have a `log` symlink.
 - `SYS`: `SYS/setup` is run before other services are brought up.
   You can already use `nitroctl` in `rc.boot/setup` to bring up services
   in a certain order.
diff --git a/nitro.c b/nitro.c
index 0f4dc0c..64a909e 100644
--- a/nitro.c
+++ b/nitro.c
@@ -830,76 +830,63 @@ add_service(const char *name)
 	int i;
 	for (i = 0; i < max_service; i++)
 		if (strcmp(services[i].name, name) == 0)
-			break;
-
-	if (i == max_service) {
-		if (strlen(name) >= sizeof (services[i].name)) {
-			return -1;
-		}
-
-		if (max_service >= MAXSV - 1) {
-			prn(2, "- nitro: too many services, limit=%d\n", MAXSV);
-			return -1;
-		}
-
-		max_service++;
-
-		strcpy(services[i].name, name);
-		services[i].pid = 0;
-		services[i].logpipe[0] = -1;
-		services[i].logpipe[1] = -1;
-		services[i].state = PROC_DELAY;
-		services[i].startstop = time_now();
-		services[i].timeout = 1;
-		services[i].deadline = 0;
-		services[i].islog = 0;
-	}
+			return i;
 
-	services[i].seen = 1;
-	return i;
-}
+	/* else set up a new service */
 
-int
-add_log_service(char *name, int first)
-{
-	/* check loggee exists */
-	int j = -1;
-	int i = find_service(name);
-	if (i < 0)
+	if (strlen(name) >= sizeof (services[i].name)) {
 		return -1;
-
-	char buf[PATH_MAX];
-	sprn(buf, buf + sizeof buf, "%s/log", name);
-
-	struct stat st;
-	if (stat_slash_to_at(name, "log", &st) < 0 || !S_ISDIR(st.st_mode))
+	} else if (max_service >= MAXSV - 1) {
+		prn(2, "- nitro: too many services, limit=%d\n", MAXSV);
 		return -1;
+	}
 
-	j = add_service(buf);
-	if (j < 0)
-		return -1;
-	services[j].islog = 1;
+	max_service++;
 
-	if (first && stat_slash(buf, "down", &st) == 0) {
-		services[j].state = PROC_DOWN;
-		services[j].timeout = 0;
-	}
+	strcpy(services[i].name, name);
+	services[i].pid = 0;
+	services[i].state = PROC_DELAY;
+	services[i].startstop = time_now();
+	services[i].timeout = 1;
+	services[i].deadline = 0;
+	services[i].islog = 0;
 
-	if (services[j].logpipe[0] == -1) {
-		if (pipe(services[j].logpipe) < 0) {
-			prn(2, "- nitro: can't create log pipe: errno=%d\n", errno);
-			services[j].logpipe[0] = -1;
-			services[j].logpipe[1] = -1;
-		} else {
-			fcntl(services[j].logpipe[0], F_SETFD, FD_CLOEXEC);
-			fcntl(services[j].logpipe[1], F_SETFD, FD_CLOEXEC);
+	char log_target[PATH_MAX];
+	char log_link[PATH_MAX];
+	sprn(log_link, log_link + sizeof log_link, "%s/log", name);
+
+	ssize_t r = readlink(log_link, log_target, sizeof log_target - 1);
+	if (r < 0 || (size_t)r >= sizeof log_target - 1) {
+		if (errno == EINVAL)
+			prn(2, "warning: ignoring log, it is not a symlink: %s\n", name);
+		services[i].logpipe[0] = -1;
+		services[i].logpipe[1] = -1;
+	} else {
+		log_target[r] = 0;
+		char *target_name = strrchr(log_target, '/');
+		if (target_name)
+			target_name++;
+		else
+			target_name = log_target;
+
+		int j = add_service(target_name);
+		services[j].islog = 1;
+		if (services[j].logpipe[0] == -1) {
+			if (pipe(services[j].logpipe) < 0) {
+				prn(2, "- nitro: can't create log pipe: errno=%d\n", errno);
+				services[j].logpipe[0] = -1;
+				services[j].logpipe[1] = -1;
+			} else {
+				fcntl(services[j].logpipe[0], F_SETFD, FD_CLOEXEC);
+				fcntl(services[j].logpipe[1], F_SETFD, FD_CLOEXEC);
+			}
 		}
-	}
 
-	services[i].logpipe[0] = services[j].logpipe[0];
-	services[i].logpipe[1] = services[j].logpipe[1];
+		services[i].logpipe[0] = services[j].logpipe[0];
+		services[i].logpipe[1] = services[j].logpipe[1];
+	}
 
-	return j;
+	return i;
 }
 
 void
@@ -933,12 +920,12 @@ rescan(int first)
 		if (i < 0)
 			continue;
 
+		services[i].seen = 1;
+
 		if (first && stat_slash(name, "down", &st) == 0) {
 			services[i].state = PROC_DOWN;
 			services[i].timeout = 0;
 		}
-
-		add_log_service(name, first);
 	}
 
 	for (i = 0; i < max_service; i++)
@@ -1196,11 +1183,8 @@ handle_control_sock() {
 		struct stat st;
 
 		int i = find_service(buf + 1);
-		if (stat_slash_to_at(buf + 1, ".", &st) == 0) {
+		if (stat_slash_to_at(buf + 1, ".", &st) == 0)
 			i = add_service(buf + 1);
-			if (i >= 0 && !services[i].islog)
-				add_log_service(buf + 1, 0);
-		}
 		if (i < 0)
 			goto fail;