diff --git a/init/init.c++ b/init/init.c++ index 33cdd175..4b0dd8b8 100644 --- a/init/init.c++ +++ b/init/init.c++ @@ -16,13 +16,14 @@ this program. If not, see . init.c++ - Initializes the system by setting up the terminal and starting the shell. + Start the operating system. *******************************************************************************/ #define __STDC_CONSTANT_MACROS #define __STDC_LIMIT_MACROS +#include #include #include #include @@ -46,15 +47,6 @@ #include -bool has_descriptor(int fd) -{ - struct stat st; - int saved_errno = errno; - bool ret = fstat(fd, &st) == 0; - errno = saved_errno; - return ret; -} - char* read_single_line(FILE* fp) { char* ret = NULL; @@ -67,18 +59,14 @@ char* read_single_line(FILE* fp) return ret; } -char* strdup_null(const char* src) -{ - return src ? strdup(src) : NULL; -} - char* print_string(const char* format, ...) { char* ret = NULL; va_list ap; va_start(ap, format); - vasprintf(&ret, format, ap); + int status = vasprintf(&ret, format, ap); va_end(ap); + assert(0 <= status); return ret; } @@ -86,7 +74,8 @@ char* join_paths(const char* a, const char* b) { size_t a_len = strlen(a); bool has_slash = (a_len && a[a_len-1] == '/') || b[0] == '/'; - return has_slash ? print_string("%s%s", a, b) : print_string("%s/%s", a, b); + return has_slash ? print_string("%s%s", a, b) + : print_string("%s/%s", a, b); } typedef struct @@ -137,7 +126,7 @@ bool string_array_append(string_array_t* sa, const char* str) sa->strings = new_strings; sa->capacity = new_capacity; } - char* copy = strdup_null(str); + char* copy = str ? strdup(str) : NULL; if ( str && !copy ) return false; sa->strings[sa->length++] = copy; @@ -186,13 +175,13 @@ int child() int runsystem() { pid_t childpid = fork(); - if ( childpid < 0 ) { perror("fork"); return 2; } + if ( childpid < 0 ) + error(2, errno, "fork"); if ( childpid ) { int status; waitpid(childpid, &status, 0); - while ( 0 < waitpid(-1, NULL, WNOHANG) ); // TODO: Use the proper macro! if ( 128 <= WEXITSTATUS(status) || WIFSIGNALED(status) ) { @@ -205,7 +194,7 @@ int runsystem() exit(child()); } -int chain_boot_path(const char* path, pid_t fs_pid = -1) +int chain_boot_path(const char* path) { // Run the next init program and restart it in case of a crash. try_reboot_system: @@ -213,14 +202,6 @@ try_reboot_system: { int status; waitpid(child_pid, &status, 0); - while ( 0 < waitpid(-1, NULL, WNOHANG) ); - if ( 0 < fs_pid ) - { - int fs_status; - kill(fs_pid, SIGTERM); - waitpid(fs_pid, &fs_status, 0); - } - while ( 0 < waitpid(-1, NULL, WNOHANG) ); // TODO: Use the proper macro! if ( 128 <= WEXITSTATUS(status) || WIFSIGNALED(status) ) { @@ -364,7 +345,20 @@ int chain_boot_device(const char* dev_path) close(new_dev_fd); close(old_dev_fd); - int ret = chain_boot_path(mount_point, fs_pid); + int ret = chain_boot_path(mount_point); + + int root_fd = open(mount_point, O_RDONLY); + if ( 0 <= root_fd ) + { + fsync(root_fd); + close(root_fd); + } + + unmount(mount_point, 0); + + int fs_exitstatus; + waitpid(fs_pid, &fs_exitstatus, 0); + if ( ret == 127 ) return init_emergency(errno, "Unable to locate the next init program"); return ret; @@ -441,8 +435,42 @@ retry_ask_root_block_device: return chain_boot_device(root_block_devices.strings[index]); } -int main(int /*argc*/, char* /*argv*/[]) +void set_hostname() { + FILE* hostname_fp = fopen("/etc/hostname", "r"); + if ( !hostname_fp ) + { + if ( errno == ENOENT ) + return; + error(0, errno, "unable to open /etc/hostname, hostname is not set"); + return; + } + + char* hostname = read_single_line(hostname_fp); + if ( !hostname ) + { + error(0, errno, "unable to read /etc/hostname, hostname is not set"); + fclose(hostname_fp); + return; + } + + fclose(hostname_fp); + + if ( sethostname(hostname, strlen(hostname) + 1) < 0 ) + { + error(0, errno, "unable to set hostname to `%s'", hostname); + free(hostname); + return; + } + + free(hostname); +} + +int init_main(int argc, char* argv[]) +{ + if ( 3 <= argc && !strcmp(argv[1], "--chain") ) + return chain_boot_device(argv[2]); + // Reset the terminal's color and the rest of it. printf(BRAND_INIT_BOOT_MESSAGE); fflush(stdout); @@ -465,6 +493,9 @@ int main(int /*argc*/, char* /*argv*/[]) // Make sure that we have a /tmp directory. mkdir("/tmp", 01777); + // Set the hostname as found in /etc/hostname. + set_hostname(); + // Find the uuid of the root filesystem. const char* root_uuid_file = "/etc/init/rootfs.uuid"; FILE* root_uuid_fp = fopen(root_uuid_file, "r"); @@ -485,3 +516,33 @@ int main(int /*argc*/, char* /*argv*/[]) return chain_boot_uuid(root_uuid); } + +int main(int argc, char* argv[]) +{ + if ( getpid() == 1 ) + { + pid_t direct_child_pid = fork(); + if ( direct_child_pid < 0 ) + error(2, errno, "fork"); + if ( direct_child_pid ) + { + int status; + while ( true ) + { + pid_t child_pid = waitpid(-1, &status, 0); + if ( child_pid < 0 ) + error(2, errno, "waitpid"); + if ( child_pid == direct_child_pid ) + break; + } + int exit_value = WEXITSTATUS(status); + // TODO: Broadcast SIGKILL and wait for all processes to finish. + while ( 0 < waitpid(-1, &status, WNOHANG) ) + { + } + return exit_value; + } + } + + return init_main(argc, argv); +}