diff options
Diffstat (limited to 'src/sysbin/init')
-rw-r--r-- | src/sysbin/init/Makefile | 12 | ||||
-rw-r--r-- | src/sysbin/init/main.c | 211 |
2 files changed, 223 insertions, 0 deletions
diff --git a/src/sysbin/init/Makefile b/src/sysbin/init/Makefile new file mode 100644 index 0000000..53a1f45 --- /dev/null +++ b/src/sysbin/init/Makefile @@ -0,0 +1,12 @@ + +OBJ = main.o + +LIB = ../../lib/libkogata/libkogata.lib ../../common/libc/libc.lib ../../common/libalgo/libalgo.lib + +CFLAGS = -I ./include -I ../../common/include -I ../../lib/include + +LDFLAGS = -T ../linker.ld -Xlinker -Map=init.map + +OUT = init.bin + +include ../../rules.make diff --git a/src/sysbin/init/main.c b/src/sysbin/init/main.c new file mode 100644 index 0000000..a2c607d --- /dev/null +++ b/src/sysbin/init/main.c @@ -0,0 +1,211 @@ +#include <string.h> +#include <printf.h> + +#include <malloc.h> + +#include <syscall.h> +#include <debug.h> +#include <user_region.h> + +#include <btree.h> + +pid_t giosrv_pid = 0, login_pid = 0; +fd_pair_t root_gip_chan; + +btree_t *parse_cmdline(const char* x) { + btree_t *ret = create_btree(str_key_cmp_fun, free_key_val); + ASSERT(ret != 0); + + x = strchr(x, ' '); + if (x == 0) return ret; + + while ((*x) != 0) { + while (*x == ' ') x++; + + char* eq = strchr(x, '='); + char* sep = strchr(x, ' '); + if (sep == 0) { + if (eq == 0) { + btree_add(ret, strdup(x), strdup(x)); + } else { + btree_add(ret, strndup(x, eq - x), strdup(eq + 1)); + } + break; + } else { + if (eq == 0 || eq > sep) { + btree_add(ret, strndup(x, sep - x), strndup(x, sep - x)); + } else { + btree_add(ret, strndup(x, eq - x), strndup(eq + 1, sep - eq - 1)); + } + x = sep + 1; + } + } + + void iter(void* a, void* b) { + dbg_printf(" '%s' -> '%s'\n", a, b); + } + btree_iter(ret, iter); + + return ret; +} + +btree_t* read_cmdline() { + char cmdline_buf[256]; + + fd_t f = open("io:/cmdline", FM_READ); + if (f == 0) return 0; + + size_t len = read(f, 0, 255, cmdline_buf); + cmdline_buf[len] = 0; + + close(f); + + return parse_cmdline(cmdline_buf); +} + +void setup_sys() { + fd_t sysdir_cfg = open("config:/sysdir", FM_READ); + if (sysdir_cfg == 0) PANIC("[init] Could not read config:/sysdir"); + + char buf[256]; + size_t l = read(sysdir_cfg, 0, 255, buf); + buf[l] = 0; + close(sysdir_cfg); + + char* eol = strchr(buf, '\n'); + if (eol) *eol = 0; + + dbg_printf("[init] Using system directory %s\n", buf); + bool ok; + + char* sep = strchr(buf, ':'); + if (sep == 0) { + ok = fs_subfs("sys", "root", buf, FM_READ | FM_MMAP); + } else { + *sep = 0; + ok = fs_subfs("sys", buf, sep +1, FM_READ | FM_MMAP); + } + + if (!ok) PANIC("[init] Could not bind root:/sys to sys:/"); +} + +void launch_giosrv() { + if (giosrv_pid != 0) return; + + giosrv_pid = new_proc(); + if (giosrv_pid == 0) { + PANIC("[init] Could not create process for giosrv"); + } + + dbg_printf("[init] Setting up giosrv, pid: %d\n", giosrv_pid); + + bool ok; + + ok = bind_fs(giosrv_pid, "io", "io"); + if (!ok) PANIC("[init] Could not bind io:/ to giosrv"); + + ok = bind_fs(giosrv_pid, "sys", "sys"); + if (!ok) PANIC("[init] Could not bind sys:/ to giosrv"); + + ok = bind_fs(giosrv_pid, "config", "config"); + if (!ok) PANIC("[init] Could not bind config:/ to giosrv"); + + ok = bind_fd(giosrv_pid, 1, root_gip_chan.a); + if (!ok) PANIC("[init] Could not bind root GIP channel FD to giosrv"); + + ok = proc_exec(giosrv_pid, "sys:/bin/giosrv.bin"); + if (!ok) PANIC("[init] Could not run giosrv.bin"); + + dbg_printf("[init] giosrv started.\n"); +} + +void launch_login() { + if (login_pid != 0) return; + + login_pid = new_proc(); + if (login_pid == 0) { + PANIC("[init] Could not create process for login"); + } + + dbg_printf("[init] Setting up login, pid: %d\n", login_pid); + + bool ok; + + ok = bind_fs(login_pid, "root", "root"); + if (!ok) PANIC("[init] Could not bind root:/ to login"); + + ok = bind_fs(login_pid, "sys", "sys"); + if (!ok) PANIC("[init] Could not bind sys:/ to login"); + + ok = bind_fs(login_pid, "config", "config"); + if (!ok) PANIC("[init] Could not bind config:/ to login"); + + ok = bind_fd(login_pid, 1, root_gip_chan.a); + if (!ok) PANIC("[init] Could not bind root GIP channel FD to login"); + + ok = proc_exec(login_pid, "sys:/bin/login.bin"); + if (!ok) PANIC("[init] Could not run login.bin"); + + dbg_printf("[init] login started.\n"); +} + +int main(int argc, char **argv) { + dbg_print("[init] Starting up!\n"); + + // Read kernel cmdline + btree_t *cmdline = read_cmdline(); + if (cmdline == 0) PANIC("[init] Could not parse cmdline"); + + // Later : setup config: and read config file + if (btree_find(cmdline, "config") == 0) { + PANIC("[init] No config=xxx option specified on command line"); + } else { + char* config = (char*)btree_find(cmdline, "config"); + dbg_printf("[init] Loading system configuration: %s\n", config); + ASSERT(strlen(config) < 30); + + char buf[50]; + snprintf(buf, 50, "/config/%s", config); + bool ok = fs_subfs("config", "root", buf, FM_READ | FM_WRITE | FM_MMAP); + if (!ok) PANIC("[init] Could not setup config:"); + } + + // Setup sys: partition + setup_sys(); + + // Setup GIP channel for communication between giosrv and login + root_gip_chan = make_channel(false); + if (root_gip_chan.a == 0 || root_gip_chan.b == 0) { + PANIC("[init] Could not create root GIP channel."); + } + + // Launch giosrv && login + launch_giosrv(); + launch_login(); + + // Make sure no one dies + while(true) { + proc_status_t s; + proc_wait(0, false, &s); + if (s.pid != 0) { + if (s.pid == giosrv_pid) { + giosrv_pid = 0; + + dbg_printf("[init] giosrv died, restarting.\n"); + launch_giosrv(); + } else if (s.pid == login_pid) { + login_pid = 0; + + dbg_printf("[init] login died, restarting.\n"); + launch_login(); + } else { + ASSERT(false); + } + } + usleep(1000000); + } + + return 0; +} + +/* vim: set ts=4 sw=4 tw=0 noet :*/ |