From 3655115e5a3c50fc06afd801100a9d75d813fd2b Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Wed, 19 Oct 2022 14:23:14 +0200
Subject: user/libc: BSD err.h, getprogname()

---
 src/user/app/httpd/httpd.c    |  9 +++------
 src/user/lib/_start2.c        | 17 ++++++++++++++++
 src/user/lib/elfload.c        | 46 ++++++++++++++++++++++---------------------
 src/user/lib/err.c            | 36 +++++++++++++++++++++++++++++++++
 src/user/lib/include/err.h    |  8 ++++++++
 src/user/lib/include/stdlib.h |  3 +++
 src/user/lib/stdlib.c         |  8 ++++++++
 7 files changed, 99 insertions(+), 28 deletions(-)
 create mode 100644 src/user/lib/err.c

(limited to 'src/user')

diff --git a/src/user/app/httpd/httpd.c b/src/user/app/httpd/httpd.c
index 2ffc2ba..02f9e6b 100644
--- a/src/user/app/httpd/httpd.c
+++ b/src/user/app/httpd/httpd.c
@@ -2,12 +2,11 @@
  * easily DoSable (like the rest of the network stack), vulnerable to path traversal, etc */
 #include <camellia/flags.h>
 #include <camellia/syscalls.h>
+#include <err.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 
-#define eprintf(fmt, ...) fprintf(stderr, "httpd: "fmt"\n" __VA_OPT__(,) __VA_ARGS__)
-
 static void handle(FILE *c) {
 	char buf[2048];
 	fgets(buf, sizeof buf, c);
@@ -69,10 +68,8 @@ int main(int argc, char **argv) {
 	handle_t conn;
 	for (;;) {
 		conn = _syscall_open(path, strlen(path), OPEN_RW);
-		if (conn < 0) {
-			eprintf("open('%s') failed, %d", path, conn);
-			return 1;
-		}
+		if (conn < 0)
+			errx(1, "open('%s') failed, errno %d", path, -conn);
 		FILE *f = fdopen(conn, "a+");
 		handle(f);
 		fclose(f);
diff --git a/src/user/lib/_start2.c b/src/user/lib/_start2.c
index 6d1431f..0582dde 100644
--- a/src/user/lib/_start2.c
+++ b/src/user/lib/_start2.c
@@ -1,13 +1,30 @@
 #include <camellia/syscalls.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <user/lib/elfload.h>
 
 int main(int argc, char **argv, char **envp);
 
+__attribute__((visibility("hidden")))
+extern char _image_base[];
+
+const char *shortname(const char *path) {
+	if (!path) return "unknown program";
+	const char *slash = strrchr(path, '/');
+	if (slash) return slash + 1;
+	return path;
+}
+
 _Noreturn void _start2(struct execdata *ed) {
+	const char *progname;
 	elf_selfreloc();
 	__setinitialcwd(ed->cwd);
+
+	progname = shortname(ed->argv[0]);
+	setprogname(progname);
+	_klogf("_start2 %s 0x%x", progname, _image_base);
+
 	exit(main(ed->argc, ed->argv, ed->envp));
 }
diff --git a/src/user/lib/elfload.c b/src/user/lib/elfload.c
index 9776a13..99633d1 100644
--- a/src/user/lib/elfload.c
+++ b/src/user/lib/elfload.c
@@ -71,6 +71,8 @@ static void *memdup(const void *orig, size_t len) {
 	return n;
 }
 
+static const char *default_argv[] = {NULL};
+
 /* frees memory outside of [low; low + len] and jumps to *entry
  * also sets up main's stack */
 void _freejmp_chstack(void *entry, void *low, size_t len, const char **argv, char **envp, void *stack); // elfload.s
@@ -78,30 +80,30 @@ _Noreturn void execbuf_chstack(void *stack, void __user *buf, size_t len);
 void _freejmp(void *entry, void *low, size_t imglen, const char **argv, char **envp) {
 	void *stack = (void*)~0;
 	struct execdata ed;
+	size_t argv_len;
 
-	if (argv) {
-		size_t argv_len;
-		ed.argc = 0;
-		while (argv[ed.argc]) ed.argc++;
-		argv_len = (ed.argc+1) * sizeof(char *);
-
-		/* make a copy of argv, so it doesn't get overridden
-		 * if it overlaps with the new stack. */
-		argv = memdup(argv, argv_len);
-		for (int i = 0; i < ed.argc; i++)
-			argv[i] = strdup(argv[i]);
-
-		stack -= argv_len;
-		ed.argv = stack;
-
-		for (int i = 0; i < ed.argc; i++) {
-			size_t len = strlen(argv[i]) + 1;
-			stack -= len;
-			memcpy(stack, argv[i], len);
-			ed.argv[i] = stack;
-		}
-		ed.argv[ed.argc] = NULL;
+	if (!argv) argv = default_argv;
+
+	ed.argc = 0;
+	while (argv[ed.argc]) ed.argc++;
+	argv_len = (ed.argc+1) * sizeof(char *);
+
+	/* make a copy of argv, so it doesn't get overridden
+	 * if it overlaps with the new stack. */
+	argv = memdup(argv, argv_len);
+	for (int i = 0; i < ed.argc; i++)
+		argv[i] = strdup(argv[i]);
+
+	stack -= argv_len;
+	ed.argv = stack;
+
+	for (int i = 0; i < ed.argc; i++) {
+		size_t len = strlen(argv[i]) + 1;
+		stack -= len;
+		memcpy(stack, argv[i], len);
+		ed.argv[i] = stack;
 	}
+	ed.argv[ed.argc] = NULL;
 
 	/* push cwd */
 	size_t len = absolutepath(NULL, NULL, 0);
diff --git a/src/user/lib/err.c b/src/user/lib/err.c
new file mode 100644
index 0000000..7684b6d
--- /dev/null
+++ b/src/user/lib/err.c
@@ -0,0 +1,36 @@
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+_Noreturn void err(int ret, const char *fmt, ...) {
+	va_list args;
+	va_start(args, fmt);
+	vwarn(fmt, args);
+	va_end(args);
+	exit(ret);
+}
+
+_Noreturn void errx(int ret, const char *fmt, ...) {
+	va_list args;
+	va_start(args, fmt);
+	vwarnx(fmt, args);
+	va_end(args);
+	exit(ret);
+}
+
+void vwarn(const char *fmt, va_list args) {
+	fprintf(stderr, "%s: ", getprogname());
+	if (fmt) {
+		vfprintf(stderr, fmt, args);
+		fprintf(stderr, ": ");
+	}
+	fprintf(stderr, "%s\n", strerror(errno));
+}
+
+void vwarnx(const char *fmt, va_list args) {
+	fprintf(stderr, "%s: ", getprogname());
+	if (fmt) vfprintf(stderr, fmt, args);
+	fprintf(stderr, "\n");
+}
diff --git a/src/user/lib/include/err.h b/src/user/lib/include/err.h
index e69de29..9ce4253 100644
--- a/src/user/lib/include/err.h
+++ b/src/user/lib/include/err.h
@@ -0,0 +1,8 @@
+#pragma once
+#include <stdarg.h>
+
+_Noreturn void err(int ret, const char *fmt, ...);
+_Noreturn void errx(int ret, const char *fmt, ...);
+
+void vwarn(const char *fmt, va_list args);
+void vwarnx(const char *fmt, va_list args);
diff --git a/src/user/lib/include/stdlib.h b/src/user/lib/include/stdlib.h
index 2df0bf7..8a86265 100644
--- a/src/user/lib/include/stdlib.h
+++ b/src/user/lib/include/stdlib.h
@@ -12,6 +12,9 @@
 _Noreturn void abort(void);
 _Noreturn void exit(int);
 
+const char *getprogname(void);
+void setprogname(const char *progname);
+
 int mkstemp(char *template);
 char *getenv(const char *name);
 int system(const char *cmd);
diff --git a/src/user/lib/stdlib.c b/src/user/lib/stdlib.c
index ffa9f15..5d1b09f 100644
--- a/src/user/lib/stdlib.c
+++ b/src/user/lib/stdlib.c
@@ -8,6 +8,14 @@ _Noreturn void abort(void) {
 	_syscall_exit(1);
 }
 
+static const char *progname;
+const char *getprogname(void) {
+	return progname;
+}
+void setprogname(const char *pg) {
+	progname = pg;
+}
+
 int mkstemp(char *template) {
 	// TODO randomize template
 	handle_t h = camellia_open(template, OPEN_CREATE | OPEN_RW);
-- 
cgit v1.2.3