about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeah Neukirchen <leah@vuxu.org>2023-11-26 20:57:12 +0100
committerLeah Neukirchen <leah@vuxu.org>2023-11-26 20:57:12 +0100
commit16a8cf434df10e57437db74b4b5b2c77ee57540e (patch)
treeaf50c349187c0df7f3b373a6dd4fce8177da3c6e
parentf7e7e62419c456e01ca777bf0d5465f2be6aea98 (diff)
downloadnitro-16a8cf434df10e57437db74b4b5b2c77ee57540e.tar.gz
nitro-16a8cf434df10e57437db74b4b5b2c77ee57540e.tar.xz
nitro-16a8cf434df10e57437db74b4b5b2c77ee57540e.zip
add internal global logger
-rw-r--r--nitro.c147
1 files changed, 130 insertions, 17 deletions
diff --git a/nitro.c b/nitro.c
index 7998bb5..bf7527c 100644
--- a/nitro.c
+++ b/nitro.c
@@ -11,10 +11,11 @@
 #include <limits.h>
 #include <poll.h>
 #include <signal.h>
-#include <stdio.h>
 #include <stdarg.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <syslog.h>
 #include <time.h>
 #include <unistd.h>
 
@@ -27,6 +28,14 @@ deadline time_now()
 	return (int64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000;
 }
 
+enum log_format {
+	LOGF_PLAIN,
+	LOGF_KMSG,
+	LOGF_TIME,
+	LOGF_TAI64N,
+	// LOGF_NONE?
+} log_format = LOGF_TAI64N;
+
 enum global_state {
 	GLBL_UP,
 	GLBL_WANT_SHUTDOWN,
@@ -70,7 +79,10 @@ int controlsock;
 int nullfd;
 int selfpipe[2];
 int globallog[2];
+int globaloutfd = 2;
 DIR *cwd;
+char logbuf[4096];
+char *logbufend = logbuf;
 
 volatile sig_atomic_t want_rescan;
 volatile sig_atomic_t want_shutdown;
@@ -132,6 +144,7 @@ proc_launch(int i)
 		chdir(services[i].name);
 
 		if (strcmp(services[i].name, "LOG") == 0) {
+			assert(!"nyi");
 			dup2(globallog[0], 0);
 			dup2(1, 2);
 		} else if (services[i].islog) {
@@ -452,14 +465,6 @@ rescan(int first)
 
 		int i = add_service(name);
 
-		if (strcmp(name, "LOG") == 0 && globallog[0] == -1) {
-			printf("making global pipe\n");
-			pipe(globallog);
-			fcntl(globallog[1], F_SETFL, O_NONBLOCK);
-			fcntl(globallog[0], F_SETFD, FD_CLOEXEC);
-			fcntl(globallog[1], F_SETFD, FD_CLOEXEC);
-		}
-
 		if (first && stat_slash(name, "down", &st) == 0) {
 			services[i].state = PROC_DOWN;
 			services[i].timeout = 0;
@@ -681,10 +686,6 @@ fail:
 	}
 }
 
-
-#define CHLD 0
-#define CTRL 1
-
 void
 has_died(pid_t pid, int status)
 {
@@ -700,6 +701,100 @@ has_died(pid_t pid, int status)
 	}
 }
 
+void
+write_global_log(char *log, size_t ulen)
+{
+	int len = ulen;
+
+	switch (log_format) {
+	case LOGF_PLAIN:
+		dprintf(globaloutfd, "%.*s\n", len, log);
+		break;
+	case LOGF_KMSG: {
+		// printk keeps track of time, we just need facility and level.
+		// printk doesn't like dprintf using lseek etc, so do a single
+		// write.
+		char buf[4096];
+		int r = snprintf(buf, sizeof buf,
+		    "<%d>nitro: %.*s\n", LOG_DAEMON | LOG_NOTICE, len, log);
+		write(globaloutfd, buf, r);
+		break;
+	}
+	case LOGF_TIME: {
+		struct timespec now;
+		clock_gettime(CLOCK_REALTIME, &now);
+		struct tm *tms = gmtime(&now.tv_sec);
+		int usec10 = (int)now.tv_nsec / 10000;
+
+		dprintf(globaloutfd,
+		    "%04d-%02d-%02dT%02d:%02d:%02d.%05d %.*s\n",
+		    tms->tm_year + 1900,
+		    tms->tm_mon + 1,
+		    tms->tm_mday,
+		    tms->tm_hour,
+		    tms->tm_min,
+		    tms->tm_sec,
+		    usec10,
+		    len,
+		    log);
+		break;
+	}
+	case LOGF_TAI64N: {
+		struct timespec now;
+		clock_gettime(CLOCK_REALTIME, &now);
+		dprintf(globaloutfd,
+		    "@%016llx.%08lx %.*s\n",
+		    (unsigned long long)now.tv_sec + 0x400000000000000aULL,
+		    (unsigned long)now.tv_nsec,
+		    len,
+		    log);
+		break;
+	}
+	}
+}
+
+void
+read_global_log(int fd)
+{
+	size_t maxlen = logbuf + sizeof logbuf - logbufend;
+	ssize_t l = read(fd, logbufend, maxlen);
+	printf("read %ld of %ld: |%.*s|\n", l, maxlen,
+	    (int)l, logbufend);
+
+	if (l == 0)
+		return;
+
+	if (l < 0)
+		abort();
+
+	logbufend += l;
+
+	char *linestart;
+	char *lineend;
+	for (linestart = logbuf;
+	     (lineend = memchr(linestart, '\n',
+		 sizeof logbuf - (linestart - logbuf)));
+	     linestart = lineend + 1) {
+		write_global_log(linestart, lineend - linestart);
+	}
+
+	if (linestart == logbuf) {
+		if ((int)l == (int)maxlen) {
+			write_global_log(logbuf, sizeof logbuf);
+			logbufend = logbuf;
+		}
+	} else {
+		memmove(logbuf, linestart, logbufend - logbuf);
+		logbufend -= linestart - logbuf;
+	}
+
+	printf("logbufsize: %d\n", (int)(logbufend - logbuf));
+}
+
+#define CHLD 0
+#define CTRL 1
+#define GLOG 2
+
 int
 main(int argc, char *argv[])
 {
@@ -725,14 +820,26 @@ main(int argc, char *argv[])
 		close(fd[1]);
 	}
 
+	if (access("/dev/kmsg", W_OK) == 0) {
+		if ((globaloutfd = open("/dev/kmsg",
+		    O_WRONLY | O_APPEND | O_CLOEXEC)) < 0) {
+			globaloutfd = 2;
+		} else {
+			log_format = LOGF_KMSG;
+		}
+	}
+
 	pipe(selfpipe);
 	fcntl(selfpipe[0], F_SETFL, O_NONBLOCK);
 	fcntl(selfpipe[1], F_SETFL, O_NONBLOCK);
 	fcntl(selfpipe[0], F_SETFD, FD_CLOEXEC);
 	fcntl(selfpipe[1], F_SETFD, FD_CLOEXEC);
 
-	globallog[0] = -1;
-	globallog[1] = -1;
+	pipe(globallog);
+	/* keep globallog[0] blocking */
+	fcntl(globallog[1], F_SETFL, O_NONBLOCK);
+	fcntl(globallog[0], F_SETFD, FD_CLOEXEC);
+	fcntl(globallog[1], F_SETFD, FD_CLOEXEC);
 
 	sigset_t allset;
 	sigfillset(&allset);
@@ -754,11 +861,13 @@ main(int argc, char *argv[])
 
 	rescan(1);
 
-	struct pollfd fds[2];
+	struct pollfd fds[3];
 	fds[CHLD].fd = selfpipe[0];
 	fds[CHLD].events = POLLIN;
 	fds[CTRL].fd = controlsock;
 	fds[CTRL].events = POLLIN;
+	fds[GLOG].fd = globallog[0];
+	fds[GLOG].events = POLLIN;
 
 	while (1) {
 		deadline now = time_now();
@@ -802,7 +911,7 @@ printf("TO %s %d\n", services[i].name, services[i].timeout);
 
 		printf("poll(timeout=%d)\n", timeout);
 
-		poll(fds, 2, timeout);
+		poll(fds, sizeof fds / sizeof fds[0], timeout);
 
 		if (fds[CHLD].revents & POLLIN) {
 			char ch;
@@ -828,6 +937,10 @@ printf("TO %s %d\n", services[i].name, services[i].timeout);
 			handle_control_sock();
 		}
 
+		if (fds[GLOG].revents & POLLIN) {
+			read_global_log(fds[GLOG].fd);
+		}
+
 		if (want_rescan) {
 			rescan(0);
 			want_rescan = 0;