From 2ad6ee8ed15d1bf898645a16dbc06991a3c1425e Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Wed, 25 Jan 2023 19:22:18 +0100
Subject: user: process titles, /bin/ps

---
 src/user/app/init/init.c      |  4 +--
 src/user/app/ps/ps.c          | 73 +++++++++++++++++++++++++++++++++++++++++++
 src/user/bootstrap/linker.ld  |  2 +-
 src/user/bootstrap/main.c     |  8 ++++-
 src/user/lib/_start2.c        | 11 +++++++
 src/user/lib/elfload.c        |  2 +-
 src/user/lib/fs/misc.c        |  2 ++
 src/user/lib/include/_proc.h  |  7 +++++
 src/user/lib/include/stdlib.h |  1 +
 src/user/lib/stdlib.c         | 14 +++++++++
 10 files changed, 118 insertions(+), 6 deletions(-)
 create mode 100644 src/user/app/ps/ps.c
 create mode 100644 src/user/lib/include/_proc.h

diff --git a/src/user/app/init/init.c b/src/user/app/init/init.c
index 73e863e..d872b24 100644
--- a/src/user/app/init/init.c
+++ b/src/user/app/init/init.c
@@ -41,7 +41,7 @@ int main(void) {
 
 	freopen("/kdev/com1", "a+", stdout);
 	freopen("/kdev/com1", "a+", stderr);
-	printf("[init] stage 2, main at %p, testtr at %p\n", &main, teststr);
+	printf("[init] stage 2, main at %p, teststr at %p\n", &main, teststr);
 
 	MOUNT_AT("/keyboard") {
 		MOUNT_AT("/") { fs_whitelist((const char*[]){"/kdev/ps2/kb", NULL}); }
@@ -101,8 +101,6 @@ int main(void) {
 		close(killswitch_pipe[0]);
 		redirect("/bin/shell", "/kdev/com1", "/kdev/com1");
 		redirect("/bin/shell", "/vtty", "/keyboard");
-		// TODO busy loop without no children
-		for (;;) _syscall_await();
 		exit(1);
 	}
 
diff --git a/src/user/app/ps/ps.c b/src/user/app/ps/ps.c
new file mode 100644
index 0000000..78d4204
--- /dev/null
+++ b/src/user/app/ps/ps.c
@@ -0,0 +1,73 @@
+#include <_proc.h>
+#include <ctype.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* returns a pointer that can be set to NUL to undo the strcat */
+static char *
+strtcat(char *dst, const char *src)
+{
+	char *s = dst + strlen(dst);
+	strcpy(s, src);
+	return s;
+}
+
+static void
+do_proc(char *path)
+{
+	const int bufl = 4096;
+	char *buf = malloc(bufl);
+	FILE *f;
+
+	{ /* read the psdata into buf */
+		char *s = strtcat(path, "mem");
+		f = fopen(path, "r");
+		*s = '\0';
+		if (!f) errx(1, "couldn't open '%s'", path);
+		fseek(f, (long)_libc_psdata, SEEK_SET);
+		if (fread(buf, 1, 128, f) <= 0) {
+			strcpy(buf, "(no psdata)");
+		}
+		buf[128] = '\0';
+		fclose(f);
+	}
+
+	printf("%20s %s\n", path, buf);
+
+	f = fopen(path, "r");
+	if (!f) errx(1, "couldn't open '%s'", path);
+
+	// TODO library for iterating over directories
+	for (;;) {
+		int len = fread(buf, 1, bufl, f);
+		if (len <= 0) break;
+		for (int pos = 0; pos < len; ) {
+			const char *end = memchr(buf + pos, 0, len - pos);
+			if (!end) {
+				errx(1, "unimplemented: buffer overflow");
+			}
+			size_t entryl = end - (buf + pos) + 1;
+			if (isdigit(buf[pos])) {
+				/* yup, no overflow check */
+				char *s = strtcat(path, buf + pos);
+				do_proc(path);
+				*s = '\0';
+			}
+			pos += entryl;
+		}
+	}
+
+	free(buf);
+	fclose(f);
+}
+
+int
+main(void)
+{
+	char *buf = malloc(4096);
+	strcpy(buf, "/proc/");
+	do_proc(buf);
+	return 0;
+}
diff --git a/src/user/bootstrap/linker.ld b/src/user/bootstrap/linker.ld
index f2d718f..34d8101 100644
--- a/src/user/bootstrap/linker.ld
+++ b/src/user/bootstrap/linker.ld
@@ -3,7 +3,7 @@ OUTPUT_FORMAT("binary")
 
 SECTIONS
 {
-	. = 0x10000;
+	. = 0x20000;
 	_bss_start = .;
 	.bss BLOCK(4K) : ALIGN(4K)
 	{
diff --git a/src/user/bootstrap/main.c b/src/user/bootstrap/main.c
index f145e74..577f1d8 100644
--- a/src/user/bootstrap/main.c
+++ b/src/user/bootstrap/main.c
@@ -1,3 +1,4 @@
+#include <_proc.h>
 #include <camellia/flags.h>
 #include <camellia/syscalls.h>
 #include <stdio.h>
@@ -13,6 +14,10 @@ extern char _initrd;
 
 __attribute__((section(".text")))
 _Noreturn void main(void) {
+	_syscall_memflag(_libc_psdata, 1, MEMFLAG_PRESENT);
+	setprogname("bootstrap");
+	setproctitle(NULL);
+
 	/* move everything provided by the kernel to /kdev */
 	MOUNT_AT("/kdev/") { fs_passthru(NULL); }
 	MOUNT_AT("/") {
@@ -26,10 +31,11 @@ _Noreturn void main(void) {
 	MOUNT_AT("/init/") { tar_driver(&_initrd); }
 
 	const char *initpath = "bin/amd64/init";
+	char *initargv[] = {"init", NULL};
 	void *init = tar_find(initpath, strlen(initpath), &_initrd, ~0) + 512;
 	if (init) {
 		_klogf("execing init");
-		elf_exec(init, NULL, NULL);
+		elf_exec(init, initargv, NULL);
 		_klogf("elf_exec failed");
 	} else {
 		_klogf("couldn't find init.elf");
diff --git a/src/user/lib/_start2.c b/src/user/lib/_start2.c
index 495f046..2cf8667 100644
--- a/src/user/lib/_start2.c
+++ b/src/user/lib/_start2.c
@@ -1,3 +1,5 @@
+#include <_proc.h>
+#include <camellia/flags.h>
 #include <camellia/syscalls.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -22,6 +24,15 @@ void intr_trampoline(void); /* intr.s */
 _Noreturn void _start2(struct execdata *ed) {
 	const char *progname;
 	elf_selfreloc();
+
+	/* done first so it isn't allocated elsewhere by accident */
+	_syscall_memflag(_libc_psdata, 1, MEMFLAG_PRESENT);
+	if (ed->argv[0]) {
+		strcpy(_libc_psdata, ed->argv[0]);
+	} else {
+		strcpy(_libc_psdata, "?");
+	}
+
 	_syscall_intr_set(intr_trampoline);
 	intr_set(intr_default);
 	__setinitialcwd(ed->cwd);
diff --git a/src/user/lib/elfload.c b/src/user/lib/elfload.c
index 7cad10f..a4ee91e 100644
--- a/src/user/lib/elfload.c
+++ b/src/user/lib/elfload.c
@@ -160,7 +160,7 @@ void elf_exec(void *base, char **argv, char **envp) {
 	void *exebase = elf_loadmem(ehdr);
 	if (!exebase) return;
 
-	void *newstack = _syscall_memflag((void*)0x1000, 0x1000, MEMFLAG_FINDFREE | MEMFLAG_PRESENT);
+	void *newstack = _syscall_memflag((void*)0x11000, 0x1000, MEMFLAG_FINDFREE | MEMFLAG_PRESENT);
 	if (!newstack) return;
 
 	_freejmp_chstack(exebase + ehdr->e_entry, exebase, elf_spread(ehdr) + 0x1000, (const char**)argv, envp, newstack);
diff --git a/src/user/lib/fs/misc.c b/src/user/lib/fs/misc.c
index 11428b8..ee0b54c 100644
--- a/src/user/lib/fs/misc.c
+++ b/src/user/lib/fs/misc.c
@@ -233,11 +233,13 @@ bool mount_at_pred(const char *path) {
 	if (!fork2_n_mount(path)) {
 		/* child -> go into the for body */
 		_klogf("%s: impl", path);
+		setproctitle("i'%s'", path);
 		return true;
 	}
 
 	if (strcmp("/", path) && !fork2_n_mount("/")) {
 		_klogf("%s: dir", path);
+		setproctitle("d'%s'", path);
 		fs_dir_inject(path);
 		exit(1);
 	}
diff --git a/src/user/lib/include/_proc.h b/src/user/lib/include/_proc.h
new file mode 100644
index 0000000..c8fd70b
--- /dev/null
+++ b/src/user/lib/include/_proc.h
@@ -0,0 +1,7 @@
+#pragma once
+
+/* That page contains a null-terminated string that describes the process
+ * for tools such as ps. It's first allocated in the bootstrap process, and
+ * then it's freed on every exec() - just to be immediately reallocated by
+ * _start2(). */
+static char *const _libc_psdata = (void*)0x10000;
diff --git a/src/user/lib/include/stdlib.h b/src/user/lib/include/stdlib.h
index 8a86265..050ca80 100644
--- a/src/user/lib/include/stdlib.h
+++ b/src/user/lib/include/stdlib.h
@@ -14,6 +14,7 @@ _Noreturn void exit(int);
 
 const char *getprogname(void);
 void setprogname(const char *progname);
+void setproctitle(const char *fmt, ...);
 
 int mkstemp(char *template);
 char *getenv(const char *name);
diff --git a/src/user/lib/stdlib.c b/src/user/lib/stdlib.c
index 5d1b09f..4e471ba 100644
--- a/src/user/lib/stdlib.c
+++ b/src/user/lib/stdlib.c
@@ -1,3 +1,4 @@
+#include <_proc.h>
 #include <camellia.h>
 #include <camellia/syscalls.h>
 #include <errno.h>
@@ -16,6 +17,19 @@ void setprogname(const char *pg) {
 	progname = pg;
 }
 
+void setproctitle(const char *fmt, ...) {
+	if (!fmt) {
+		strcpy(_libc_psdata, progname);
+		return;
+	}
+	sprintf(_libc_psdata, "%s: ", progname);
+
+	va_list argp;
+	va_start(argp, fmt);
+	vsnprintf(_libc_psdata + strlen(_libc_psdata), 128, fmt, argp);
+	va_end(argp);
+}
+
 int mkstemp(char *template) {
 	// TODO randomize template
 	handle_t h = camellia_open(template, OPEN_CREATE | OPEN_RW);
-- 
cgit v1.2.3