diff options
Diffstat (limited to 'mdk-stage1/init.c')
-rw-r--r-- | mdk-stage1/init.c | 231 |
1 files changed, 151 insertions, 80 deletions
diff --git a/mdk-stage1/init.c b/mdk-stage1/init.c index 1d5841610..7c48f64ec 100644 --- a/mdk-stage1/init.c +++ b/mdk-stage1/init.c @@ -1,5 +1,5 @@ /* - * Guillaume Cottenceau (gc@mandriva.com) + * Guillaume Cottenceau (gc) * * Copyright 2000 Mandriva * @@ -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=linux", "TERMINFO=/etc/terminfo", + "LC_CTYPE=UTF-8", NULL }; @@ -116,20 +106,20 @@ void print_int_init(int fd, int i) char buf[10]; char * chptr = buf + 9; int j = 0; - + if (i < 0) { write(1, "-", 1); i = -1 * i; } - + while (i) { *chptr-- = '0' + (i % 10); j++; i = i / 10; } - + write(fd, chptr + 1, j); } @@ -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); @@ -176,7 +165,7 @@ void doklog() close(1); close(2); } - + out = open("/dev/tty4", O_WRONLY, 0); if (out < 0) print_warning("couldn't open tty for syslog -- still using /tmp/syslog\n"); @@ -218,7 +207,7 @@ void doklog() if (sock >= 0) FD_SET(sock, &readset); FD_SET(in, &readset); - + i = select(20, &readset, NULL, NULL, NULL); if (i <= 0) continue; @@ -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; } @@ -305,10 +296,9 @@ void unmount_filesystems(void) struct filesystem fs[500]; int numfs = 0; int i, nb; - int disallow_eject = 0; printf("unmounting filesystems...\n"); - + fd = open("/proc/mounts", O_RDONLY, 0); if (fd < 1) { print_error("failed to open /proc/mounts"); @@ -335,8 +325,6 @@ void unmount_filesystems(void) *p++ = '\0'; while (*p != '\n') p++; p++; - if (!strcmp(fs[numfs].fs, "nfs")) - disallow_eject = 1; if (strcmp(fs[numfs].name, "/") && !strstr(fs[numfs].dev, "ram") && strcmp(fs[numfs].name, "/dev") @@ -360,14 +348,14 @@ void unmount_filesystems(void) } } } while (nb); - + for (i = nb = 0; i < numfs; i++) if (fs[i].mounted) { printf("\tumount failed: %s\n", fs[i].name); if (strcmp(fs[i].fs, "ext3") == 0) nb++; /* don't count not-ext3 umount failed */ } - + if (nb) { printf("failed to umount some filesystems\n"); select(0, NULL, NULL, NULL, NULL); @@ -382,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) @@ -396,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') { @@ -414,15 +480,11 @@ 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 */ signal(SIGINT, SIG_IGN); @@ -432,13 +494,13 @@ int main(int argc, char **argv) fd = open("/dev/console", O_RDWR, 0); if (fd < 0) fatal_error("failed to open /dev/console"); - + dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); close(fd); } - + /* I set me up as session leader (probably not necessary?) */ setsid(); @@ -456,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: - - 1) install exits - 2) we receive a SIGHUP - */ + if (create_initial_fs_symlinks(STAGE2_LOCATION "/usr/share/symlinks") != 0) + fatal_error("Fatal error finishing initialization (could not create symlinks)."); - do { - if (counter == 1) { - printf("proceeding, please wait...\n"); - } + /* 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"); - if (!(installpid = fork())) { - /* child */ - char * child_argv[2]; - child_argv[0] = counter == 0 ? BINARY : BINARY_STAGE2; - child_argv[1] = NULL; + if (rename("/usr/lib/firmware", "/firmware")) + fatal_error("Cannot rename firmware folder"); - execve(child_argv[0], child_argv, env); - printf("error in exec of %s :-( [%d]\n", child_argv[0], errno); - return 0; - } + /* 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"); - do { - childpid = wait4(-1, &wait_status, 0, NULL); - } while (childpid != installpid); + if (symlink("/firmware", "/usr/lib/firmware")) + fatal_error("Cannot symlink firmware folder"); - counter++; - } while (WIFEXITED(wait_status) && WEXITSTATUS(wait_status) == exit_value_restart); + 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"); - /* allow Ctrl Alt Del to reboot */ - reboot(BMAGIC_HARD); - if (in_reboot()) { - // any exitcode is valid if we're in_reboot - } else if (WIFEXITED(wait_status) && WEXITSTATUS(wait_status) == exit_value_proceed) { + if (access("/run/drakx/run-init", R_OK) == 0) { + /* This is typically used in rescue mode */ + char * child_argv[2] = { "/sbin/init", NULL }; + 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; @@ -535,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); |