diff --git a/apps/init.c b/apps/init.c index 54700242..765386ee 100644 --- a/apps/init.c +++ b/apps/init.c @@ -1,3 +1,35 @@ +/* vim: ts=4 sw=4 noexpandtab + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2018 K. Lange + * + * init - First process. + * + * `init` calls startup scripts and then waits for them to complete. + * It also waits for orphaned proceses so they can be collected. + * + * `init` itself is statically-linked, so minimizing libc dependencies + * is worthwhile as it reduces to the total size of init itself, which + * remains in memory throughout the entire lifetime of the OS. + * + * Startup scripts for init are stored in /etc/startup.d and are run + * in sorted alphabetical order. It is generally recommended that these + * startup scripts be named with numbers at the front to ensure easy + * ordering. This system of running a set of scripts on startup is + * somewhat similar to how sysvinit worked, but no claims of + * compatibility are made. + * + * Startup scripts can be any executable binary. Shell scripts are + * generally used to allow easy editing, but you could also use + * a binary (even a dynamically linked one) as a startup script. + * `init` will wait for each startup script (that is, it will wait for + * the original process it started to exit) before running the next one. + * So if you wish to run daemons, be sure to fork them off and then + * exit so that the rest of the startup process can continue. + * + * When the last startup script finishes, `init` will reboot the system. + */ + #include #include #include @@ -10,43 +42,56 @@ #define INITD_PATH "/etc/startup.d" +/* Initialize fd 0, 1, 2 */ void set_console(void) { + /* default to /dev/ttyS0 (serial COM1) */ int _stdin = syscall_open("/dev/ttyS0", 0, 0); - int _stdout = syscall_open("/dev/ttyS0", 1, 0); - int _stderr = syscall_open("/dev/ttyS0", 1, 0); - - if (_stdout < 0) { - _stdout = syscall_open("/dev/null", 1, 0); - _stderr = syscall_open("/dev/null", 1, 0); + if (_stdin < 0) { + /* if /dev/ttyS0 failed to open, fall back to /dev/null */ + syscall_open("/dev/null", 0, 0); + syscall_open("/dev/null", 1, 0); + syscall_open("/dev/null", 1, 0); + } else { + /* otherwise also use /dev/ttyS0 for stdout, stderr */ + syscall_open("/dev/ttyS0", 1, 0); + syscall_open("/dev/ttyS0", 1, 0); } - - (void)_stderr; - (void)_stdin; } +/* Run a startup script and wait for it to finish */ int start_options(char * args[]) { + + /* Fork child to run script */ int cpid = syscall_fork(); + + /* Child process... */ if (!cpid) { - char * _envp[] = { - "LD_LIBRARY_PATH=/lib:/usr/lib", - "PATH=/bin:/usr/bin", - "USER=root", - "HOME=/home/root", - NULL, - }; - syscall_execve(args[0], args, _envp); + /* Pass environment from init to child */ + syscall_execve(args[0], args, environ); + /* exec failed, exit this subprocess */ syscall_exit(0); } + /* Wait for the child process to finish */ int pid = 0; do { + /* + * Wait, ignoring kernel threads + * (which also end up as children to init) + */ pid = waitpid(-1, NULL, WNOKERN); + if (pid == -1 && errno == ECHILD) { + /* There are no more children */ break; } + if (pid == cpid) { + /* The child process finished */ break; } + + /* Continue while no error (or error was "interrupted") */ } while ((pid > 0) || (pid == -1 && errno == EINTR)); return cpid; @@ -95,6 +140,7 @@ int main(int argc, char * argv[]) { } } + /* Self-explanatory */ syscall_reboot(); return 0; }