From d69d7614ea8b9720f934a94249ee8199bbcaf70c Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Sat, 13 Aug 2022 17:40:44 +0200
Subject: user: add /initctl for shutting the system down in a cleaner way

---
 src/user/app/init/driver/driver.h  |  2 ++
 src/user/app/init/driver/initctl.c | 40 ++++++++++++++++++++++++++++++++++++++
 src/user/app/init/init.c           | 26 +++++++++++++++++++++----
 3 files changed, 64 insertions(+), 4 deletions(-)
 create mode 100644 src/user/app/init/driver/initctl.c

(limited to 'src/user/app/init')

diff --git a/src/user/app/init/driver/driver.h b/src/user/app/init/driver/driver.h
index c99955a..fc9f51b 100644
--- a/src/user/app/init/driver/driver.h
+++ b/src/user/app/init/driver/driver.h
@@ -1,5 +1,7 @@
 #pragma once
+#include <camellia/types.h>
 
+void initctl_drv(handle_t killswitch);
 void ps2_drv(void);
 void tmpfs_drv(void);
 
diff --git a/src/user/app/init/driver/initctl.c b/src/user/app/init/driver/initctl.c
new file mode 100644
index 0000000..b8fbb9b
--- /dev/null
+++ b/src/user/app/init/driver/initctl.c
@@ -0,0 +1,40 @@
+#include "driver.h"
+#include <camellia/syscalls.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+void initctl_drv(handle_t killswitch) {
+	struct fs_wait_response res;
+	char buf[64];
+	const size_t buflen = sizeof buf;
+	while (!_syscall_fs_wait(buf, buflen, &res)) {
+		switch (res.op) {
+			case VFSOP_OPEN:
+				_syscall_fs_respond(NULL, res.len == 0 ? 0 : -1, 0);
+				break;
+			case VFSOP_WRITE:
+				/* null terminate */
+				if (res.len > buflen - 1)
+					res.len = buflen - 1;
+				buf[res.len] = '\0';
+				/* cut at first whitespace */
+				for (size_t i = 0; buf[i]; i++) {
+					if (isspace(buf[i])) {
+						buf[i] = '\0';
+						break;
+					}
+				}
+				if (!strcmp(buf, "halt")) {
+					_syscall_write(killswitch, "halt", 4, 0, 0);
+					exit(1);
+				}
+				_syscall_fs_respond(NULL, res.len, 0);
+				break;
+			default:
+				_syscall_fs_respond(NULL, -ENOSYS, 0);
+				break;
+		}
+	}
+	exit(1);
+}
diff --git a/src/user/app/init/init.c b/src/user/app/init/init.c
index 2ae8048..ee8554f 100644
--- a/src/user/app/init/init.c
+++ b/src/user/app/init/init.c
@@ -25,6 +25,8 @@ void redirect(const char *exe, const char *out, const char *in) {
 }
 
 int main(void) {
+	handle_t killswitch_pipe[2];
+
 	freopen("/kdev/com1", "a+", stdout);
 	freopen("/kdev/com1", "a+", stderr);
 	printf("in init (stage 2), main at 0x%x\n", &main);
@@ -50,6 +52,16 @@ int main(void) {
 		fs_union(list);
 	}
 
+	if (_syscall_pipe(killswitch_pipe, 0) < 0) {
+		printf("couldn't create the killswitch pipe, quitting...\n");
+		return 1;
+	}
+	MOUNT_AT("/initctl") {
+		close(killswitch_pipe[0]);
+		initctl_drv(killswitch_pipe[1]);
+	}
+	close(killswitch_pipe[1]);
+
 	if (fork()) {
 		/* used to trigger a kernel bug
 		 * 7c96f9c03502e0c60f23f4c550d12a629f3b3daf */
@@ -57,10 +69,16 @@ int main(void) {
 		exit(1);
 	}
 
-	redirect("/bin/shell", "/kdev/com1", "/kdev/com1");
-	redirect("/bin/shell", "/vtty", "/keyboard");
+	if (!fork()) {
+		// TODO close on exec
+		close(killswitch_pipe[0]);
+		redirect("/bin/shell", "/kdev/com1", "/kdev/com1");
+		redirect("/bin/shell", "/vtty", "/keyboard");
+		_syscall_await();
+		printf("init: restarting children not yet implemented\n");
+		exit(1);
+	}
 
-	_syscall_await();
-	printf("init: quitting\n");
+	_syscall_read(killswitch_pipe[0], NULL, 0, 0);
 	return 0;
 }
-- 
cgit v1.2.3