preinit.c (2780B)
1 #include <string.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <fcntl.h> 5 #include <sys/mount.h> 6 #include <sys/wait.h> 7 #include <string.h> 8 #include <stdint.h> 9 #include <errno.h> 10 11 #include <asm/setup.h> /* for COMMAND_LINE_SIZE */ 12 13 #include "opts.h" 14 15 #define ERR(x) write(2, x, strlen(x)) 16 #define AVER(c) do { if(c < 0) { ERR("failed: " #c ": error=0x" ); pr_u32(errno); ERR("\n"); } } while(0) 17 18 char * pr_u32(int32_t input); 19 20 static void die() { 21 /* if init exits, it causes a kernel panic. On the Turris 22 * Omnia (and maybe other hardware, I don't know), the kernel 23 * panics _before_ any of the messages from AVER are printed, 24 * which makes it really hard to tell what went wrong. So 25 * let's wait a little here to give the console a chance to 26 * catch up. 27 * 28 * Yes, I know that file descriptor IO is supposedly 29 * non-buffered. Empirical observation suggests that there 30 * must be a buffer of some kind somewhere though. 31 */ 32 33 sleep(10); 34 exit(1); 35 } 36 37 static int fork_exec(char * command, char *args[]) 38 { 39 int fork_pid = fork(); 40 AVER(fork_pid); 41 if(fork_pid > 0) 42 return wait(NULL); 43 else 44 return execve(command, args, NULL); 45 } 46 47 char banner[] = "Running pre-init...\n"; 48 char buf[COMMAND_LINE_SIZE]; 49 50 int main(int argc, char *argv[], char *envp[]) 51 { 52 struct root_opts opts = { 53 .device = NULL, 54 .fstype = NULL, 55 .mount_opts = NULL 56 }; 57 58 write(1, banner, strlen(banner)); 59 60 AVER(mount("none", "/proc", "proc", 0, NULL)); 61 AVER(mount("none", "/dev", "devtmpfs", 0, NULL)); 62 63 int cmdline = open("/proc/cmdline", O_RDONLY, 0); 64 65 if(cmdline>=0) { 66 int len = read(cmdline, buf, sizeof buf - 1); 67 buf[len]='\0'; 68 while(buf[len-1]=='\n') { 69 buf[len-1]='\0'; 70 len--; 71 } 72 write(1, "cmdline: \"", 10); 73 write(1, buf, len); 74 write(1, "\"\n", 2); 75 } else { 76 ERR("failed: open(\"/proc/cmdline\")\n"); 77 die(); 78 } 79 parseopts(buf, &opts); 80 81 if(opts.device) { 82 if(!opts.fstype) opts.fstype = "jffs2"; /* backward compatibility */ 83 write(1, "rootdevice ", 11); 84 write(1, opts.device, strlen(opts.device)); 85 write(1, " (", 2); 86 write(1, opts.fstype, strlen(opts.fstype)); 87 if(opts.mount_opts) { 88 write(1, ", opts=", 7); 89 write(1, opts.mount_opts, strlen(opts.mount_opts)); 90 } 91 write(1, ")\n", 2); 92 AVER(mount(opts.device, "/target/persist", opts.fstype, 0, opts.mount_opts)); 93 AVER(mount("/target/persist/nix", "/target/nix", 94 "bind", MS_BIND, NULL)); 95 96 char *exec_args[] = { "activate", "/target", NULL }; 97 AVER(fork_exec("/target/persist/activate", exec_args)); 98 AVER(chdir("/target")); 99 100 AVER(mount("/target", "/", "bind", MS_BIND | MS_REC, NULL)); 101 AVER(chroot(".")); 102 103 argv[0] = "init"; 104 argv[1] = NULL; 105 AVER(execve("/persist/init", argv, envp)); 106 } 107 die(); 108 }