Cleanup init

This commit is contained in:
K. Lange 2018-08-14 14:45:30 +09:00
parent 64ae8d07bd
commit 2d231a97af

View File

@ -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 <dirent.h>
#include <errno.h>
#include <stdio.h>
@ -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;
}