diff options
Diffstat (limited to 'mdk-stage1/init.c')
-rw-r--r-- | mdk-stage1/init.c | 177 |
1 files changed, 123 insertions, 54 deletions
diff --git a/mdk-stage1/init.c b/mdk-stage1/init.c index 3f912c2ac..7cec1076b 100644 --- a/mdk-stage1/init.c +++ b/mdk-stage1/init.c @@ -22,6 +22,7 @@ #include <stdlib.h> #include <unistd.h> #include <stdio.h> +#include <dirent.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> @@ -56,7 +57,6 @@ static inline long reboot(unsigned int command) #endif -#define BINARY "/sbin/stage1" #define BINARY_STAGE2 "/usr/bin/runinstall2" @@ -378,7 +378,86 @@ int in_reboot(void) return 0; } -int exit_value_proceed = 66; +int recursive_remove(char *file); +int recursive_remove(char *file) +{ + struct stat sb; + + if (lstat(file, &sb) != 0) { + printf("failed to stat %s: %d\n", file, errno); + return -1; + } + + /* only descend into subdirectories if device is same as dir */ + if (S_ISDIR(sb.st_mode)) { + char * strBuf = alloca(strlen(file) + 1024); + DIR * dir; + struct dirent * d; + + if (!(dir = opendir(file))) { + printf("error opening %s: %d\n", file, errno); + return -1; + } + while ((d = readdir(dir))) { + if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) + continue; + + strcpy(strBuf, file); + strcat(strBuf, "/"); + strcat(strBuf, d->d_name); + + if (recursive_remove(strBuf) != 0) { + closedir(dir); + return -1; + } + } + closedir(dir); + + if (rmdir(file)) { + printf("failed to rmdir %s: %d\n", file, errno); + return -1; + } + } else { + if (unlink(file) != 0) { + printf("failed to remove %s: %d\n", file, errno); + return -1; + } + } + return 0; +} + + +int create_initial_fs_symlinks(char* symlinks) +{ + FILE *f; + char buf[5000]; + + if (!(f = fopen(symlinks, "rb"))) { + printf("Error opening symlink definitions file '%s'\n", symlinks); + return -1; + } + while (fgets(buf, sizeof(buf), f)) { + char oldpath[500], newpath[500]; + struct stat sb; + + buf[strlen(buf)-1] = '\0'; // trim \n + if (sscanf(buf, "%s %s", oldpath, newpath) != 2) { + sprintf(oldpath, "%s%s", STAGE2_LOCATION, buf); + sprintf(newpath, "%s", buf); + } + if (lstat(newpath, &sb) == 0) + recursive_remove(newpath); + printf("Creating symlink %s -> %s\n", oldpath, newpath); + if (symlink(oldpath, newpath)) { + printf("Error creating symlink\n"); + return -1; + } + } + fclose(f); + return 0; +} + + int exit_value_restart = 0x35; int main(int argc, char **argv) @@ -386,7 +465,6 @@ int main(int argc, char **argv) pid_t installpid, childpid; int wait_status; int fd; - int counter = 0; int abnormal_termination = 0; if (argc > 1 && argv[1][0] >= '0' && argv[1][0] <= '9') { @@ -404,24 +482,6 @@ int main(int argc, char **argv) printf("*** TESTING MODE *** (pid is %d)\n", getpid()); - if (!testing) { - if (mount("/proc", "/proc", "proc", 0, NULL)) - fatal_error("Unable to mount proc filesystem"); - if (mount("none", "/sys", "sysfs", 0, NULL)) - fatal_error("Unable to mount sysfs filesystem"); - if (mount("none", "/sys/kernel/debug", "debugfs", MS_NOSUID, "mode=0755")) - fatal_error("Unable to mount debugfs filesystem"); - if (mount("none", "/dev", "devtmpfs", 0, NULL)) - fatal_error("Unable to mount dev filesystem"); - mkdir("/dev/pts", 0755); - if (mount("/dev/pts", "/dev/pts", "devpts", MS_NOSUID|MS_NOEXEC, "gid=5,mode=0620")) - fatal_error("Unable to mount /dev/pts devpts filesystem"); - mkdir("/dev/shm", 0755); - if (mount("/dev/shm", "/dev/shm", "tmpfs", MS_NOSUID|MS_NODEV, "mode=1777")) - fatal_error("Unable to mount /dev/shm tmpfs filesystem"); - } - - /* ignore Control-C and keyboard stop signals */ signal(SIGINT, SIG_IGN); signal(SIGTSTP, SIG_IGN); @@ -454,57 +514,66 @@ int main(int argc, char **argv) if (!testing) doklog(); - /* Go into normal init mode - keep going, and then do a orderly shutdown - when: + if (create_initial_fs_symlinks(STAGE2_LOCATION "/usr/share/symlinks") != 0) + fatal_error("Fatal error finishing initialization (could not create symlinks)."); - 1) install exits - 2) we receive a SIGHUP - */ + /* kernel modules and firmware is needed by stage2, so move them to the root */ + if (rename("/usr/lib/modules", "/modules")) + fatal_error("Cannot rename modules folder"); - do { - if (counter == 1) { - printf("proceeding, please wait...\n"); - } + if (rename("/usr/lib/firmware", "/firmware")) + fatal_error("Cannot rename firmware folder"); - if (!(installpid = fork())) { - /* child */ - char * child_argv[2]; - child_argv[0] = counter == 0 ? BINARY : BINARY_STAGE2; - child_argv[1] = NULL; + /* Add some symlinks so stage1 is still valid on it's own - not strictly needed */ + if (symlink("/modules", "/usr/lib/modules")) + fatal_error("Cannot symlink modules folder"); - execve(child_argv[0], child_argv, env); - printf("error in exec of %s :-( [%d]\n", child_argv[0], errno); - return 0; - } + if (symlink("/firmware", "/usr/lib/firmware")) + fatal_error("Cannot symlink firmware folder"); - do { - childpid = wait4(-1, &wait_status, 0, NULL); - } while (childpid != installpid); + if (mount(STAGE2_LOCATION "/usr", "/usr", "none", MS_BIND|MS_RDONLY, NULL)) + fatal_error("Unable to bind mount /usr filesystem from rescue or installer stage2"); - counter++; - } while (WIFEXITED(wait_status) && WEXITSTATUS(wait_status) == exit_value_restart); - /* allow Ctrl Alt Del to reboot */ - reboot(LINUX_REBOOT_CMD_CAD_ON); + if (access("/run/drakx/run-init", R_OK) == 0) { + /* This is typically used in rescue mode */ + char * child_argv[2] = { "/sbin/init", NULL }; - if (in_reboot()) { - // any exitcode is valid if we're in_reboot - } else if (WIFEXITED(wait_status) && WEXITSTATUS(wait_status) == exit_value_proceed) { kill(klog_pid, 9); printf("proceeding, please wait...\n"); + execve(child_argv[0], child_argv, env); + fatal_error("failed to exec /sbin/init"); + } + + /* This is installer mode */ + do { + printf("proceeding, please wait...\n"); - { - char * child_argv[2] = { "/sbin/init", NULL }; + if (!(installpid = fork())) { + /* child */ + char * child_argv[2] = { BINARY_STAGE2, NULL }; execve(child_argv[0], child_argv, env); + printf("error in exec of %s :-( [%d]\n", child_argv[0], errno); + return 0; } - fatal_error("failed to exec /sbin/init"); - } else if (!WIFEXITED(wait_status) || WEXITSTATUS(wait_status) != 0) { + + do { + childpid = wait4(-1, &wait_status, 0, NULL); + } while (childpid != installpid); + } while (WIFEXITED(wait_status) && WEXITSTATUS(wait_status) == exit_value_restart); + + /* allow Ctrl Alt Del to reboot */ + reboot(LINUX_REBOOT_CMD_CAD_ON); + + if (in_reboot()) { + // any exitcode is valid if we're in_reboot + } else if (!WIFEXITED(wait_status) || WEXITSTATUS(wait_status) != 0) { printf("exited abnormally :-( "); if (WIFSIGNALED(wait_status)) printf("-- received signal %d", WTERMSIG(wait_status)); printf("\n"); abnormal_termination = 1; - } + } if (!abnormal_termination) { int i; |