// Copyright (C) 2020 Seshan Ravikumar // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // Welcome to my disaster of an init. #include // mmm POSIX #include #include #include #include #include #include #include #include #include "inipp.h" #include "running_process.h" bool is_booting = true; void print_status_screen(); void update_boot_screen(const std::string& msg); void fatal_error(const std::string& err_msg); sigset_t set; int main() { update_boot_screen("Starting Sineware..."); if(mount("proc", "/proc", "proc", NULL, NULL) != 0) { fatal_error("Mount proc: " + std::to_string(errno)); } if(mount("sysfs", "/sys", "sysfs", NULL, NULL) != 0) { fatal_error("Mount sys: " + std::to_string(errno)); } update_boot_screen("Getting ready..."); // Load config options. inipp::Ini ini; std::ifstream is("/sineware.ini"); ini.parse(is); std::string config_version; inipp::extract(ini.sections["sineware"]["version"], config_version); std::cout << "Version " << config_version << std::endl; std::string config_init; inipp::extract(ini.sections["sineware"]["init"], config_init); std::cout << "Starting with: " << config_init << std::endl; sethostname("sineware-live", 13); if(mount(NULL, "/", NULL, MS_REMOUNT, NULL) != 0) { fatal_error("Remount /: " + std::to_string(errno)); } if(mount("/proc", "/root_a/proc", "proc", NULL, NULL) != 0) { fatal_error("Mount proc in chroot: " + std::to_string(errno)); } if(mount("/sys", "/root_a/sys/", NULL, MS_BIND | MS_REC, NULL) != 0) { fatal_error("Bind sys in chroot: " + std::to_string(errno)); } if(mount("/dev", "/root_a/dev/", NULL, MS_BIND | MS_REC, NULL) != 0) { fatal_error("Bind dev in chroot: " + std::to_string(errno)); } if(mount("/", "/root_a/sineware/", NULL, MS_BIND | MS_REC, NULL) != 0) { fatal_error("Bind root in chroot: " + std::to_string(errno)); } // Switch into the rootfs and boot up processes! // todo should we fork off so the main process remains in real root? update_boot_screen("Switching into rootfs..."); chdir("/root_a"); if (chroot("/root_a") != 0) { perror("chroot /root_a"); fatal_error("chroot /root_a"); return 1; } // Create an empty signal set sigemptyset(&set); // Add signals to the set sigaddset(&set, SIGINT); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGUSR1); // Block all signals we set (i.e make them caught by sigwait) sigprocmask(SIG_BLOCK, &set, NULL); int sig; // Start OpenRC system("mkdir /run/openrc"); sleep(1); system("touch /run/openrc/softlevel"); sleep(1); system("/sbin/openrc sysinit"); system("/sbin/openrc boot"); system("/sbin/openrc default"); is_booting = false; //print_status_screen(); std::cout << "Welcome to Sineware! (Switching into init loop)" << std::endl; while(true) { sigwait(&set, &sig); int status; int pid = waitpid(-1, &status, WNOHANG); switch(sig) { case SIGINT: std::cout << "caught sigint" << std::endl; return 0; case SIGCHLD: std::cout << "caught sigchld (a child process has exited)" << std::endl; std::cout << "The Signal is " << status << std::endl; std::cout << "The Child was " << pid << std::endl; while (waitpid(-1, NULL, WNOHANG) > 0); // Reap the child break; case SIGUSR1: // todo use this to make init do stuff break; default: std::cout << "The Signal is " << sig << std::endl; std::cout << "The Child was " << pid << std::endl; } } // Should never get here... fatal_error("Init Exited"); return 0; } void print_status_screen() { //std::cout << "\033[2J"; std::cout << "\u001B[1;1H" << std::string(80, '-') << "\u001B[24;1H" << std::string(80, '-') << std::flush; for(int i = 2; i < 24; i++) { printf("\033[%d;1H|", i); printf("\033[%d;80H|", i); } if (!is_booting) { std::cout << "\u001B[4;4H Welcome to \u001b[35mSineware\u001b[0m!" "\u001B[6;4H System Status: \u001b[33m" "Unknown" "\u001B[0m" "\u001B[10;4H IP Address: \u001b[32m" "Unknown" "\u001B[0m" "\u001B[11;4H The Web Interface is available on port 8086." "\u001B[12;4H Press Ctrl+Alt+F2 to access the command line." "\u001B[16;4H\u001b[32mDEVELOPMENT BUILD. For Evaluation Purposes Only." << std::endl; } else { std::cout << "\u001B[4;4H Welcome to \u001b[35mSineware\u001b[0m!" "\u001B[6;4H System Status: \u001b[33mStarting Up...\u001B[0m" "\u001B[16;4H\u001b[32mDEVELOPMENT BUILD. For Evaluation Purposes Only." << std::endl; } } void update_boot_screen(const std::string& msg) { //print_status_screen();  std::cout << "\u001b[33m" << msg << std::endl; } void fatal_error(const std::string& err_msg) { std::cout << "\033[2J \u001B[1;1H" << std::string(80, '-') << "Sineware has run into an unrecoverable error and had to stop.\n" << "Error: " << err_msg << "\n\n\n" << std::endl; while (true); }