diff options
Diffstat (limited to 'mdk-stage1/init.c')
| -rw-r--r-- | mdk-stage1/init.c | 204 |
1 files changed, 139 insertions, 65 deletions
diff --git a/mdk-stage1/init.c b/mdk-stage1/init.c index 1b07e715a..7c48f64ec 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> @@ -36,19 +37,12 @@ #include <linux/unistd.h> #include <sys/select.h> #include <sys/ioctl.h> +#include <linux/reboot.h> #include <sys/syscall.h> #define syslog(...) syscall(__NR_syslog, __VA_ARGS__) -#define LINUX_REBOOT_MAGIC1 0xfee1dead -#define LINUX_REBOOT_MAGIC2 672274793 -#define BMAGIC_HARD 0x89ABCDEF -#define BMAGIC_SOFT 0 -#define BMAGIC_REBOOT 0x01234567 -#define BMAGIC_HALT 0xCDEF0123 -#define BMAGIC_POWEROFF 0x4321FEDC - -static unsigned int reboot_magic = BMAGIC_REBOOT; +static unsigned int reboot_magic = LINUX_REBOOT_CMD_RESTART; static inline long reboot(unsigned int command) { @@ -58,25 +52,21 @@ static inline long reboot(unsigned int command) #include "config-stage1.h" #include <linux/cdrom.h> -#if defined(__powerpc__) -#define TIOCSCTTY 0x540E -#endif - -#define BINARY "/sbin/stage1" #define BINARY_STAGE2 "/usr/bin/runinstall2" char * env[] = { "PATH=/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sbin:/mnt/usr/sbin:/mnt/bin:/mnt/usr/bin", - "LD_LIBRARY_PATH=/lib:/usr/lib:/mnt/lib:/mnt/usr/lib:/usr/X11R6/lib:/mnt/usr/X11R6/lib" -#if defined(__x86_64__) || defined(__ppc64__) - ":/lib64:/usr/lib64:/usr/X11R6/lib64:/mnt/lib64:/mnt/usr/lib64:/mnt/usr/X11R6/lib64" + "LD_LIBRARY_PATH=/lib:/usr/lib:/mnt/lib:/mnt/usr/lib" +#if defined(__x86_64__) + ":/lib64:/usr/lib64:/mnt/lib64:/mnt/usr/lib64" #endif , "HOME=/", - "TERM=screen", + "TERM=linux", "TERMINFO=/etc/terminfo", + "LC_CTYPE=UTF-8", NULL }; @@ -160,7 +150,6 @@ void doklog() return; } - mkdir("/tmp", 0755); if ((log = open("/tmp/syslog", O_WRONLY | O_CREAT | O_APPEND, 0644)) < 0) { print_error("error opening /tmp/syslog"); sleep(5); @@ -291,7 +280,9 @@ char* strcat(register char* s,register const char* t) char *dest=s; s+=strlen(s); for (;;) { - if (!(*s = *t)) break; ++s; ++t; + if (!(*s = *t)) + break; + ++s; ++t; } return dest; } @@ -379,13 +370,92 @@ int in_reboot(void) int i = read(fd, buf, sizeof(buf)); close(fd); if (strstr(buf, "halt")) - reboot_magic = BMAGIC_POWEROFF; + reboot_magic = LINUX_REBOOT_CMD_POWER_OFF; return i > 0; } 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) { + snprintf(oldpath, sizeof(oldpath), "%s%s", STAGE2_LOCATION, buf); + snprintf(newpath, sizeof(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) @@ -393,7 +463,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') { @@ -411,14 +480,10 @@ int main(int argc, char **argv) printf("*** TESTING MODE *** (pid is %d)\n", getpid()); - if (!testing) { - mkdir("/proc", 0755); - if (mount("/proc", "/proc", "proc", 0, NULL)) - fatal_error("Unable to mount proc filesystem"); - mkdir("/sys", 0755); - if (mount("none", "/sys", "sysfs", 0, NULL)) - fatal_error("Unable to mount sysfs filesystem"); - } + // needed for ldetect: + if (!testing) + if (mount("none", "/sys/kernel/debug", "debugfs", MS_NOSUID, "mode=0755")) + fatal_error("Unable to mount debugfs filesystem"); /* ignore Control-C and keyboard stop signals */ @@ -453,57 +518,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(BMAGIC_HARD); + 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; @@ -532,7 +606,7 @@ int main(int argc, char **argv) sync(); sync(); if (!abnormal_termination) { - if (reboot_magic == BMAGIC_REBOOT) { + if (reboot_magic == LINUX_REBOOT_CMD_RESTART) { #ifdef DEBUG printf("automatic reboot in 10 seconds\n"); sleep(10); |
