summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeah Neukirchen <leah@vuxu.org>2022-02-12 23:44:54 +0100
committerLeah Neukirchen <leah@vuxu.org>2022-02-12 23:44:54 +0100
commit06769a66a616d4d984eb91614bb3e88d289de79c (patch)
treed954c3f46e07cdc393d9c02d2f27dcd371b265c0
parentee94145132953271fb3fd606d00154442689e7ec (diff)
downloadrvnit-06769a66a616d4d984eb91614bb3e88d289de79c.tar.gz
rvnit-06769a66a616d4d984eb91614bb3e88d289de79c.tar.xz
rvnit-06769a66a616d4d984eb91614bb3e88d289de79c.zip
rvnitctl: hack some start/stop commands ala sv
This is quite ugly still but shows a polling approach works.
Services need to be up/down for 250ms for the start/stop to succeed.
-rw-r--r--rvnitctl.c92
1 files changed, 91 insertions, 1 deletions
diff --git a/rvnitctl.c b/rvnitctl.c
index 9920f30..5fca706 100644
--- a/rvnitctl.c
+++ b/rvnitctl.c
@@ -1,12 +1,59 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 
+#include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
 #include <unistd.h>
 
 int
+check(const char *path, const char *service)
+{
+	struct sockaddr_un addr = { 0 };
+	addr.sun_family = AF_UNIX;
+	strncpy(addr.sun_path, path, sizeof addr.sun_path - 1);
+	int connfd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+	if (connfd < 0) {
+		perror("socket");
+		exit(111);
+	}
+
+	if (connect(connfd, (struct sockaddr *)&addr, sizeof addr) < 0) {
+		perror("connect");
+		exit(111);
+	}
+
+	write(connfd, "s", 1);
+
+	// XXX what if too low?
+	char buf[4096];
+	ssize_t rd = read(connfd, buf, sizeof buf);
+	if (rd < 0) {
+		perror("read");
+		exit(111);
+	}
+
+	char *p;
+	char *f = strstr(buf, service);
+	if (f && (f == buf || f[-1] == '\n') &&
+	    f[strlen(service)+1] == ' ' &&
+	    (p = strstr(f, "pid="))) {
+		p += 4;
+		printf("found pid %c\n", p[0]);
+		if (isdigit(p[0])) {
+			close(connfd);
+			return 1;  // has pid >= 0
+		}
+	}
+	// XXX fix multiple strstr matches
+
+	close(connfd);
+	return 0;
+}
+
+int
 main(int argc, char *argv[])
 {
 	if (argc < 2 || (
@@ -24,6 +71,8 @@ main(int argc, char *argv[])
 	    strcmp(argv[1], "k") != 0 && strcmp(argv[1], "kill") != 0 &&
 	    strcmp(argv[1], "1") != 0 &&
 	    strcmp(argv[1], "2") != 0 &&
+	    strcmp(argv[1], "start") != 0 &&
+	    strcmp(argv[1], "stop") != 0 &&
 	    strcmp(argv[1], "Restart") != 0 &&
 	    strcmp(argv[1], "Shutdown") != 0)) {
 		dprintf(2, "usage: rvnitctl COMMAND [SERVICE]\n");
@@ -49,7 +98,14 @@ main(int argc, char *argv[])
 		exit(111);
 	}
 
-	dprintf(connfd, "%c%s", *argv[1], argv[2] ? argv[2] : "");
+	char cmd = argv[1][0];
+
+	if (strcmp(argv[1], "start") == 0 && argv[2])
+		cmd = 'u';
+	else if (strcmp(argv[1], "stop") == 0 && argv[2])
+		cmd = 'd';
+
+	dprintf(connfd, "%c%s", cmd, argv[2] ? argv[2] : "");
 
 	int status = 1;
 
@@ -66,5 +122,39 @@ main(int argc, char *argv[])
 		write(1, buf, rd);
 	} while (rd > 0);
 
+	if (strcmp(argv[1], "start") == 0 && argv[2]) {
+		int i;
+		int up = 0;
+		for (i = 7*4; i > 0; i--) {
+			if (check(path, argv[2])) {
+				if (++up >= 2)
+					break;
+			} else {
+				up = 0;
+			}
+			nanosleep(&(struct timespec){0, 250000000}, 0);
+		}
+		if (up < 2) {
+			fprintf(stderr, "start failed\n");
+			return 1;
+		}
+	} else if (strcmp(argv[1], "stop") == 0 && argv[2]) {
+		int i;
+		int down = 0;
+		for (i = 7*4; i > 0; i--) {
+			if (!check(path, argv[2])) {
+				if (++down >= 2)
+					break;
+			} else {
+				down = 0;
+			}
+			nanosleep(&(struct timespec){0, 250000000}, 0);
+		}
+		if (down < 2) {
+			fprintf(stderr, "stop failed\n");
+			return 1;
+		}
+	}
+
 	return status;
 }