Skip to content
Newer
Older
100644 675 lines (541 sloc) 15.6 KB
418495e @falconindy initial commit. works for me!
authored
1 #define _GNU_SOURCE
2 #include <ctype.h>
3 #include <dirent.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <getopt.h>
7 #include <limits.h>
8 #include <linux/magic.h>
9 #include <signal.h>
10 #include <stdarg.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/mount.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <sys/vfs.h>
18 #include <sys/wait.h>
19 #include <unistd.h>
20
21 /* util-linux */
22 #include <blkid.h>
23
24 #define msg(...) {if (!quiet) fprintf(stderr, ":: " __VA_ARGS__);}
ee2af86 @falconindy fix output in err()
authored
25 #define err(...) {fprintf(stderr, "error: " __VA_ARGS__);}
418495e @falconindy initial commit. works for me!
authored
26 #define die(...) {err(__VA_ARGS__); _exit(1);}
27
8be2cf2 @falconindy pause events processing before sending TERM to udev
authored
28 #define CMDLINE_SIZE 2048 /* from arch/x86/include/asm/setup.h */
2567d96 @falconindy new NEWROOT in place of hardcoded path
authored
29 #define TMPFS_FLAGS MS_NOEXEC|MS_NODEV|MS_NOSUID
8be2cf2 @falconindy pause events processing before sending TERM to udev
authored
30
2567d96 @falconindy new NEWROOT in place of hardcoded path
authored
31 #define NEWROOT "/new_root"
8be2cf2 @falconindy pause events processing before sending TERM to udev
authored
32 #define UDEVD "/sbin/udevd"
33 #define UDEVADM "/sbin/udevadm"
418495e @falconindy initial commit. works for me!
authored
34
35 int rootflags = 0;
36 int quiet = 0;
37
38 /* utility */
66eeb68 @falconindy use _exit to leave a child process
authored
39 static int forkexecwait(char **argv) { /* {{{ */
418495e @falconindy initial commit. works for me!
authored
40 pid_t pid;
4b5d25d @falconindy cleanup scoping and compiler warnings
authored
41 int statloc;
418495e @falconindy initial commit. works for me!
authored
42
43 pid = fork();
44 if (pid == -1) {
45 perror("fork");
46 return;
47 }
48
49 if (pid == 0) {
50 execv(argv[0], argv);
66eeb68 @falconindy use _exit to leave a child process
authored
51 fprintf(stderr, "exec: %s: %s\n", argv[0], strerror(errno));
52 _exit(errno); /* avoid flushing streams */
418495e @falconindy initial commit. works for me!
authored
53 }
54
949ba05 @falconindy refactor bbox launching into forkexecwait
authored
55 /* block for process exit */
418495e @falconindy initial commit. works for me!
authored
56 waitpid(pid, &statloc, 0);
57
66eeb68 @falconindy use _exit to leave a child process
authored
58 if (WIFEXITED(statloc) > 0) {
59 return WEXITSTATUS(statloc);
60 }
61
62 /* should do a better job of this */
63 return 1;
418495e @falconindy initial commit. works for me!
authored
64 } /* }}} */
65
b1811bb @falconindy refactor xasprintf and last_char_is into concat_path
authored
66 static char *concat_path(const char *path, const char *filename) { /* {{{ */
67 const char *ss, *lc;
68 char *concat;
69 int ret;
418495e @falconindy initial commit. works for me!
authored
70
71 if (!path) {
72 path = "";
73 }
74
b1811bb @falconindy refactor xasprintf and last_char_is into concat_path
authored
75 for (ss = path; *ss; ss++);
76 lc = (*--ss == '/' ? "" : "/");
77
418495e @falconindy initial commit. works for me!
authored
78 while (*filename == '/') {
79 filename++;
80 }
b1811bb @falconindy refactor xasprintf and last_char_is into concat_path
authored
81
82 ret = asprintf(&concat, "%s%s%s", path, lc, filename);
83 if (ret < 0) {
84 return NULL;
85 }
86
87 return concat;
418495e @falconindy initial commit. works for me!
authored
88 } /* }}} */
89
90 static char *sanitize_var(char *var) { /* {{{ */
91 char *p;
92
93 p = var;
7a35dc6 @falconindy be stricter about accepting environment vars
authored
94 if (!(isalpha(*p) || *p == '_')) {
95 /* invalid var name, can't use this */
418495e @falconindy initial commit. works for me!
authored
96 return NULL;
97 }
98
7a35dc6 @falconindy be stricter about accepting environment vars
authored
99 p++;
418495e @falconindy initial commit. works for me!
authored
100 while (*p) {
101 switch (*p) {
102 case '-': /* fallthrough */
103 case '.':
104 *p = '_';
105 break;
106 case '=': /* don't touch anything past this */
107 return var;
108 }
109 p++;
110 }
111
112 return var;
113 } /* }}} */
114
115 static void delete_contents(const char *directory, dev_t rootdev) { /* {{{ */
116 DIR *dir;
117 struct dirent *d;
118 struct stat st;
119
120 /* Don't descend into other filesystems */
121 if (lstat(directory, &st) || st.st_dev != rootdev) {
122 return;
123 }
124
125 /* Recursively delete the contents of directories */
126 if (S_ISDIR(st.st_mode)) {
127 dir = opendir(directory);
128 if (dir) {
129 while ((d = readdir(dir))) {
130 char *newdir = d->d_name;
131
132 /* Skip . and .. */
133 if (strcmp(newdir, ".") == 0 || strcmp(newdir, "..") == 0) {
134 continue;
135 }
136
137 /* Recurse to delete contents */
b1811bb @falconindy refactor xasprintf and last_char_is into concat_path
authored
138 newdir = concat_path(directory, newdir);
418495e @falconindy initial commit. works for me!
authored
139 delete_contents(newdir, rootdev);
140 free(newdir);
141 }
142 closedir(dir);
143
144 /* Directory should now be empty, zap it */
145 rmdir(directory);
146 }
147 } else {
148 /* It wasn't a directory, zap it */
149 unlink(directory);
150 }
151 } /* }}} */
152
153 static void start_rescue_shell(void) { /* {{{ */
154 char *bboxinstall[] = { "/bin/busybox", "--install", NULL };
155 char *bboxlaunch[] = { "/bin/busybox", "ash", NULL };
156
157 /* install symlinks */
949ba05 @falconindy refactor bbox launching into forkexecwait
authored
158 forkexecwait(bboxinstall);
418495e @falconindy initial commit. works for me!
authored
159
160 /* set a prompt */
161 putenv("PS1=[ramfs \\W]\\$ ");
162
163 /* start the shell */
949ba05 @falconindy refactor bbox launching into forkexecwait
authored
164 forkexecwait(bboxlaunch);
418495e @falconindy initial commit. works for me!
authored
165
166 } /* }}} */
167
4b5d25d @falconindy cleanup scoping and compiler warnings
authored
168 static char *probe_fstype(const char *devname) { /* {{{ */
418495e @falconindy initial commit. works for me!
authored
169 int ret;
170 char *fstype;
171 blkid_probe pr;
172
173 pr = blkid_new_probe_from_filename(devname);
174 if (!pr) {
175 err("%s: failed to create a new libblkid probe\n", devname);
176 return NULL;
177 }
178
179 blkid_probe_enable_superblocks(pr, 1);
180 blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_TYPE);
181
182 ret = blkid_do_safeprobe(pr);
183 if (ret == -1) {
184 return NULL;
185 } else if (ret == 1) {
186 err("failed to probe device %s\n", devname);
187 return NULL;
188 } else {
189 const char *name, *data;
190 blkid_probe_get_value(pr, 0, &name, &data, NULL);
191 fstype = strdup(data);
192 }
193
194 blkid_free_probe(pr);
195
196 return fstype;
197 } /* }}} */
198
199 /* meat */
200 static void mount_setup(void) { /* {{{ */
201 int ret;
202
203 /* setup basic filesystems */
99b14a4 @falconindy wrap at 80 cols
authored
204 mount("proc", "/proc", "proc", TMPFS_FLAGS, NULL);
205 mount("sys", "/sys", "sysfs", TMPFS_FLAGS, NULL);
206 mount("tmpfs", "/run", "tmpfs", TMPFS_FLAGS, "mode=1777,size=10M");
418495e @falconindy initial commit. works for me!
authored
207
208 /* mountpoint for our eventual real root */
2567d96 @falconindy new NEWROOT in place of hardcoded path
authored
209 mkdir(NEWROOT, 0755);
418495e @falconindy initial commit. works for me!
authored
210
211 /* ENODEV returned on non-existant FS */
212 ret = mount("udev", "/dev", "devtmpfs", MS_NOSUID, "mode=0755,size=10M");
213 if (ret == -1 && errno == ENODEV) {
214 /* devtmpfs not available, use standard tmpfs */
215 mount("udev", "/dev", "tmpfs", MS_NOSUID, "mode=0755,size=10M");
216
217 /* create necessary nodes
218 * crw------- 1 root root 5, 1 Apr 2 18:30 /dev/console
219 * crw-rw-rw- 1 root root 1, 3 Apr 2 18:30 /dev/null
220 * crw-rw-rw- 1 root root 1, 5 Apr 2 18:30 /dev/zero
221 */
222 mknod("/dev/console", S_IFCHR|0600, makedev(5, 1));
223 mknod("/dev/null", S_IFCHR|0666, makedev(1, 3));
224 mknod("/dev/zero", S_IFCHR|0666, makedev(1, 5));
225 }
226 } /* }}} */
227
228 static void put_cmdline(void) { /* {{{ */
229 char cmdline[CMDLINE_SIZE], token[CMDLINE_SIZE];
230 char quoted = '\0';
231 char *c, *tp;
232 int isvar = 0;
233 FILE *fp;
234
235 /* a bit of pointer/var hell going on...
4b5d25d @falconindy cleanup scoping and compiler warnings
authored
236 * c = pointer along contents of /proc/cmdline
237 * token = container for current token being parsed
238 * tp = pointer along contents of token
418495e @falconindy initial commit. works for me!
authored
239 */
240
241 fp = fopen("/proc/cmdline", "r");
242 if (!fp) {
243 return;
244 }
245
246 if (!fgets(cmdline, CMDLINE_SIZE, fp)) {
247 return;
248 }
249 fclose(fp);
250
251 tp = token;
252 for (c = cmdline; *c; c++) {
253 if (*c == '#') { /* full stop! */
254 break;
255 }
256
257 if (isspace((unsigned char)*c)) {
258 /* don't break inside a quoted region */
259 if (!quoted && tp != token) {
260 *tp = '\0';
261 if (sanitize_var(token)) {
262 if (isvar) {
263 putenv(strdup(token));
264 } else {
265 setenv(strdup(token), "y", 1);
266 }
267 if (strcmp(token, "ro") == 0) {
268 rootflags |= MS_RDONLY;
269 } else if (strcmp(token, "quiet") == 0) {
270 quiet = 1;
271 }
272 }
273 isvar = 0;
274 tp = token;
275 }
276 continue;
277 } else if (*c == '\'' || *c == '"') {
278 if (quoted) {
279 if (quoted == *c) {
280 quoted = '\0';
281 continue;
282 }
283 } else {
284 quoted = *c;
285 continue;
286 }
287 }
288
289 if (*c == '=') {
290 isvar = 1;
291 }
292
293 *tp++ = *c;
294 }
295 } /* }}} */
296
297 static void disable_modules(void) { /* {{{ */
298 char *tok, *var;
299 FILE *fp;
300
301 if (getenv("disablemodules") == NULL) {
302 return;
303 }
304
305 /* ensure parent dirs exist */
306 mkdir("/etc", 0755);
307 mkdir("/etc/modprobe.d", 0755);
308
309 fp = fopen("/etc/modprobe.d/initcpio.conf", "w");
310 if (!fp) {
311 perror("error: /etc/modprobe.d/initcpio.conf");
312 return;
313 }
314
315 var = strdup(getenv("disablemodules"));
316 for (tok = strtok(var, ","); tok; tok = strtok(NULL, ",")) {
317 fprintf(fp, "install %s /bin/false\n", tok);
318 }
319
320 fclose(fp);
321 free(var);
322 } /* }}} */
323
324 static pid_t launch_udev(void) { /* {{{ */
8be2cf2 @falconindy pause events processing before sending TERM to udev
authored
325 char *argv[] = { UDEVD, "--resolve-names=never", NULL };
418495e @falconindy initial commit. works for me!
authored
326 pid_t pid;
327
8be2cf2 @falconindy pause events processing before sending TERM to udev
authored
328 if (access(UDEVD, X_OK) != 0) {
418495e @falconindy initial commit. works for me!
authored
329 return 0;
330 }
331
332 msg("Starting udev...\n");
333
334 pid = fork();
335 if (pid == -1) {
336 perror("fork");
337 return 1;
338 }
339
340 if (pid == 0) {
5cc90d2 @falconindy remove twice hardcoded path to udev
authored
341 execv(argv[0], argv);
8be2cf2 @falconindy pause events processing before sending TERM to udev
authored
342 perror("exec: " UDEVD);
66eeb68 @falconindy use _exit to leave a child process
authored
343 _exit(errno);
418495e @falconindy initial commit. works for me!
authored
344 }
345
346 return pid;
347 } /* }}} */
348
4cbca7f @falconindy parse MODULES declaration out config file. fix a bug or two along the…
authored
349 static void load_extra_modules(void) { /* {{{ */
350 FILE *fp;
418495e @falconindy initial commit. works for me!
authored
351 char *tok, *var;
352 char **argv;
4cbca7f @falconindy parse MODULES declaration out config file. fix a bug or two along the…
authored
353 char line[PATH_MAX];
418495e @falconindy initial commit. works for me!
authored
354 int modcount = 2;
355
4cbca7f @falconindy parse MODULES declaration out config file. fix a bug or two along the…
authored
356 /* load early modules */
357 if (getenv("earlymodules") != NULL) {
358 argv = calloc(2, sizeof(argv));
359 *argv = "/sbin/modprobe";
360 *(argv + 1) = "-qa";
418495e @falconindy initial commit. works for me!
authored
361
4cbca7f @falconindy parse MODULES declaration out config file. fix a bug or two along the…
authored
362 var = strdup(getenv("earlymodules"));
363 for (tok = strtok(var, ","); tok; tok = strtok(NULL, ",")) {
364 argv = realloc(argv, sizeof(argv) * ++modcount);
365 *(argv + (modcount - 1)) = tok;
366 }
418495e @falconindy initial commit. works for me!
authored
367
4cbca7f @falconindy parse MODULES declaration out config file. fix a bug or two along the…
authored
368 if (modcount > 2) {
369 argv = realloc(argv, sizeof(argv) * ++modcount);
370 *(argv + (modcount - 1)) = NULL;
371 forkexecwait(argv);
372 }
373 free(argv);
418495e @falconindy initial commit. works for me!
authored
374 }
375
4cbca7f @falconindy parse MODULES declaration out config file. fix a bug or two along the…
authored
376 /* load modules from /config */
377 fp = fopen("/config", "r");
378 if (fp) {
379 while (fgets(line, PATH_MAX, fp) != NULL) {
380 if (strncmp(line, "MODULES=", 8) == 0) {
381 argv = calloc(2, sizeof(argv));
382 *argv = "/sbin/modprobe";
383 *(argv + 1) = "-qa";
384 modcount = 2;
385
386 for (tok = strtok(&line[9], " \"\n"); tok; tok = strtok(NULL, " \"\n")) {
387 argv = realloc(argv, sizeof(argv) * ++modcount);
388 *(argv + (modcount - 1)) = tok;
389 }
418495e @falconindy initial commit. works for me!
authored
390
4cbca7f @falconindy parse MODULES declaration out config file. fix a bug or two along the…
authored
391 /* make sure array wasn't empty */
392 if (modcount > 2) {
393 argv = realloc(argv, sizeof(argv) * ++modcount);
394 *(argv + (modcount - 1)) = NULL;
395 forkexecwait(argv);
396 }
397
398 free(argv);
399 break;
400 }
401 }
402 fclose(fp);
403 }
418495e @falconindy initial commit. works for me!
authored
404
405 } /* }}} */
406
407 static void trigger_udev_events(void) { /* {{{ */
408 char *argv[] = { "/sbin/udevadm", "trigger", "--action=add", NULL };
3664974 @falconindy add missing udev msg
authored
409
410 msg("triggering udev events...\n");
418495e @falconindy initial commit. works for me!
authored
411 forkexecwait(argv);
412 } /* }}} */
413
414 static void disable_hooks(void) { /* {{{ */
415 char *hook, *list, *disable;
416
417 disable = getenv("disablehooks");
418 if (!disable) {
419 return;
420 }
421
422 list = strdup(disable);
423 for (hook = strtok(list, ", "); hook; hook = strtok(NULL, ", ")) {
424 char path[PATH_MAX];
425 snprintf(path, PATH_MAX, "/hooks/%s", hook);
426
427 /* mark as non-executable so run_hooks skips over it */
428 chmod(path, 0644);
429 }
430
431 free(list);
432 } /* }}} */
433
4b5d25d @falconindy cleanup scoping and compiler warnings
authored
434 static void run_hooks(void) { /* {{{ */
418495e @falconindy initial commit. works for me!
authored
435 FILE *fp;
436 char line[PATH_MAX];
437 char *hook;
438
439 fp = fopen("/config", "r");
440 if (!fp) {
441 return;
442 }
443
444 while (fgets(line, PATH_MAX, fp) != NULL) {
445 if (strncmp(line, "HOOKS=", 6) != 0) {
446 continue;
447 }
448
99b14a4 @falconindy wrap at 80 cols
authored
449 for (hook = strtok(&line[6], " \"\n"); hook; hook = strtok(NULL, " \"\n")) {
418495e @falconindy initial commit. works for me!
authored
450 char path[PATH_MAX];
451
452 snprintf(path, 4096, "hooks/%s", hook);
453
454 if (access(path, X_OK) != 0) {
455 continue;
456 }
457
458 char *argv[] = { path, path, NULL };
459 forkexecwait(argv);
460 }
87e4fbb @falconindy drop out of fgets loop after successfully finding HOOKS=
authored
461
462 break;
418495e @falconindy initial commit. works for me!
authored
463 }
60000b7 @falconindy add missing fclose on /config file
authored
464
465 fclose(fp);
418495e @falconindy initial commit. works for me!
authored
466 } /* }}} */
467
a681c38 @falconindy add support for a user requested rescue_shell via "break"
authored
468 static void check_for_break(void) { /* {{{ */
469 if (getenv("break") == NULL) {
470 return;
471 }
472
473 msg("break requested. type 'exit' or 'logout' to resume\n");
474 start_rescue_shell();
475 } /* }}} */
476
418495e @falconindy initial commit. works for me!
authored
477 static void wait_for_root(void) { /* {{{ */
478 char *rootdelay, *root;
479 int found = 0, delay = 0;
480
481 rootdelay = getenv("rootdelay");
482 if (rootdelay) {
db36095 @falconindy rootdelay <=0 is invalid
authored
483 /* atoi is "safe" here because 0 is invalid */
418495e @falconindy initial commit. works for me!
authored
484 delay = atoi(rootdelay);
485 }
486
db36095 @falconindy rootdelay <=0 is invalid
authored
487 if (delay <= 0) {
418495e @falconindy initial commit. works for me!
authored
488 delay = 10;
489 }
490
491 root = getenv("root");
88c21fa @falconindy overhaul later logic to be more robust and simpler.
authored
492 if (!root) {
493 die("no root device was specified on command line!\n");
494 }
418495e @falconindy initial commit. works for me!
authored
495
496 msg("waiting up to %d seconds for %s ...\n", delay, root);
497 while (delay--) {
498 if (access(root, R_OK) == 0) {
499 found = 1;
500 break;
501 }
502 sleep(1);
503 }
504
505 if (!found) {
506 err("root didn't show up! You are on your own, good luck\n");
507 start_rescue_shell();
508 msg("continuing... this will probably fail\n");
509 }
510
511 } /* }}} */
512
88c21fa @falconindy overhaul later logic to be more robust and simpler.
authored
513 static int mount_root(void) { /* {{{ */
418495e @falconindy initial commit. works for me!
authored
514 char *root, *fstype;
88c21fa @falconindy overhaul later logic to be more robust and simpler.
authored
515 int ret = 1;
418495e @falconindy initial commit. works for me!
authored
516
517 root = getenv("root");
518
88c21fa @falconindy overhaul later logic to be more robust and simpler.
authored
519 fstype = getenv("rootfstype");
520 if (fstype) {
521 return mount(root, NEWROOT, fstype, rootflags, NULL);
418495e @falconindy initial commit. works for me!
authored
522 }
523
524 fstype = probe_fstype(root);
88c21fa @falconindy overhaul later logic to be more robust and simpler.
authored
525 if (!fstype) { /* still no fstype, we're out of ideas */
526 /* should hopefully never reach this */
527 err("the filesystem of the root device could not be determined!\n");
528 fprintf(stderr, "Try adding the rootfstype= parameter to the"
529 "kernel command line\n");
530 return ret;
418495e @falconindy initial commit. works for me!
authored
531 }
532
88c21fa @falconindy overhaul later logic to be more robust and simpler.
authored
533 ret = mount(root, NEWROOT, fstype, rootflags, NULL);
418495e @falconindy initial commit. works for me!
authored
534 free(fstype);
88c21fa @falconindy overhaul later logic to be more robust and simpler.
authored
535
536 return ret;
418495e @falconindy initial commit. works for me!
authored
537 } /* }}} */
538
88c21fa @falconindy overhaul later logic to be more robust and simpler.
authored
539 static int set_init(void) { /* {{{ */
418495e @falconindy initial commit. works for me!
authored
540 char path[PATH_MAX];
541
88c21fa @falconindy overhaul later logic to be more robust and simpler.
authored
542 /* don't overwrite, but make sure something is set */
543 setenv("init", "/sbin/init", 0);
418495e @falconindy initial commit. works for me!
authored
544
88c21fa @falconindy overhaul later logic to be more robust and simpler.
authored
545 /* existance check */
546 snprintf(path, PATH_MAX, NEWROOT "%s", getenv("init"));
547 return access(path, F_OK);
418495e @falconindy initial commit. works for me!
authored
548 } /* }}} */
549
550 static void kill_udev(pid_t pid) { /* {{{ */
8be2cf2 @falconindy pause events processing before sending TERM to udev
authored
551 char *argv[] = { UDEVADM, "control", "--stop-exec-queue", NULL };
418495e @falconindy initial commit. works for me!
authored
552 char path[PATH_MAX];
553 char *exe;
554
555 if (pid <= 1) { /* error launching udev */
556 return;
557 }
558
8be2cf2 @falconindy pause events processing before sending TERM to udev
authored
559 /* pause event queue to facilitate shutdown */
560 forkexecwait(argv);
561
418495e @falconindy initial commit. works for me!
authored
562 snprintf(path, PATH_MAX, "/proc/%d/exe", pid);
563 exe = realpath(path, NULL);
564
8be2cf2 @falconindy pause events processing before sending TERM to udev
authored
565 if (strcmp(exe, UDEVD) == 0) {
418495e @falconindy initial commit. works for me!
authored
566 kill(pid, SIGTERM);
567 }
568
8e83f11 @falconindy udev best be comin down, yo
authored
569 /* bitch, please */
570 if (access(exe, F_OK) == 0) {
571 kill(pid, SIGKILL);
572 }
573
418495e @falconindy initial commit. works for me!
authored
574 free(exe);
575 } /*}}}*/
576
577 static int switch_root(char *argv[]) { /* {{{ */
578 struct stat st;
579 struct statfs stfs;
580 dev_t rootdev;
581
582 /* this is mostly taken from busybox's util_linux/switch_root.c */
583
88c21fa @falconindy overhaul later logic to be more robust and simpler.
authored
584 /* change to new root directory and verify it's a different fs. In practice,
585 * this should never be a concern as we catch mount failing in mount_root */
2567d96 @falconindy new NEWROOT in place of hardcoded path
authored
586 chdir(NEWROOT);
418495e @falconindy initial commit. works for me!
authored
587 stat("/", &st);
588 rootdev = st.st_dev;
589 stat(".", &st);
590
591 if (st.st_dev == rootdev) {
2567d96 @falconindy new NEWROOT in place of hardcoded path
authored
592 die("nothing was mounted on " NEWROOT "!\n");
418495e @falconindy initial commit. works for me!
authored
593 }
594
595 /* Additional sanity checks: we're about to rm -rf /, so be REALLY SURE we
596 * mean it. I could make this a CONFIG option, but I would get email from all
597 * the people who WILL destroy their filesystems. */
598 if (stat("/init", &st) != 0 || !S_ISREG(st.st_mode)) {
88c21fa @falconindy overhaul later logic to be more robust and simpler.
authored
599 die("/init not found or not a regular file\n");
418495e @falconindy initial commit. works for me!
authored
600 }
601
602 statfs("/", &stfs); /* this never fails */
99b14a4 @falconindy wrap at 80 cols
authored
603 if ((unsigned)stfs.f_type != RAMFS_MAGIC &&
604 (unsigned)stfs.f_type != TMPFS_MAGIC) {
88c21fa @falconindy overhaul later logic to be more robust and simpler.
authored
605 die("root filesystem is not ramfs/tmpfs!\n");
418495e @falconindy initial commit. works for me!
authored
606 }
607
608 /* zap everything out of rootdev */
609 delete_contents("/", rootdev);
610
611 /* mount $PWD over / and chroot into it */
612 if (mount(".", "/", NULL, MS_MOVE, NULL) != 0) {
613 /* fails when newroot is not a mountpoint */
614 die("error moving root\n");
615 }
616 chroot(".");
617
618 /* The chdir is needed to recalculate "." and ".." links */
619 chdir("/");
620
621 /* redirect stdin/stdout/stderr to new console */
622 close(0);
623 open("/dev/console", O_RDWR);
624 dup2(0, 1);
625 dup2(0, 2);
626
6577f64 @falconindy add bailout message after failed pid 1 exec
authored
627 /* exec real pid shady */
418495e @falconindy initial commit. works for me!
authored
628 execv(argv[0], argv);
6577f64 @falconindy add bailout message after failed pid 1 exec
authored
629 err("failed to execute '%s'\n", argv[0]);
99b14a4 @falconindy wrap at 80 cols
authored
630 fprintf(stderr, ":: This is the end. Something has gone terribly wrong.\n"
631 ":: Please file a detailed bug report.\n");
66eeb68 @falconindy use _exit to leave a child process
authored
632 exit(EXIT_FAILURE);
418495e @falconindy initial commit. works for me!
authored
633 } /* }}} */
634
635 int main(int argc, char *argv[]) {
636 pid_t udevpid;
637
6577f64 @falconindy add bailout message after failed pid 1 exec
authored
638 (void)argc; /* poor unloved argc */
418495e @falconindy initial commit. works for me!
authored
639
640 mount_setup(); /* create early tmpfs mountpoints */
641 put_cmdline(); /* parse cmdline and set environment */
642 disable_modules(); /* blacklist modules passed in on cmdline */
643 udevpid = launch_udev(); /* try to launch udev */
4cbca7f @falconindy parse MODULES declaration out config file. fix a bug or two along the…
authored
644 load_extra_modules(); /* load modules passed in on cmdline */
418495e @falconindy initial commit. works for me!
authored
645 trigger_udev_events(); /* read and process uevent queue */
646 disable_hooks(); /* delete hooks specified on cmdline */
647 run_hooks(); /* run remaining hooks */
a681c38 @falconindy add support for a user requested rescue_shell via "break"
authored
648 check_for_break(); /* did the user request a shell? */
418495e @falconindy initial commit. works for me!
authored
649 wait_for_root(); /* ensure that root shows up */
88c21fa @falconindy overhaul later logic to be more robust and simpler.
authored
650
651 if (mount_root() != 0) { /* this is what we're here for */
652 err("failed to mount the root device: %s\n", strerror(errno));
653 start_rescue_shell();
654 }
655
656 if (set_init() != 0) { /* mounted something, now find init */
657 err("root device was mounted, but %s does not exist!\n", getenv("init"));
658 start_rescue_shell();
659 }
660
418495e @falconindy initial commit. works for me!
authored
661 kill_udev(udevpid); /* shutdown udev in prep switch_root */
662
663 /* move mount points (fstype, options and flags are ignored) */
2567d96 @falconindy new NEWROOT in place of hardcoded path
authored
664 mount("/proc", NEWROOT "/proc", NULL, MS_MOVE, NULL);
665 mount("/sys", NEWROOT "/sys", NULL, MS_MOVE, NULL);
666 mount("/run", NEWROOT "/run", NULL, MS_MOVE, NULL);
418495e @falconindy initial commit. works for me!
authored
667
88c21fa @falconindy overhaul later logic to be more robust and simpler.
authored
668 argv[0] = getenv("init");
418495e @falconindy initial commit. works for me!
authored
669 switch_root(argv);
6577f64 @falconindy add bailout message after failed pid 1 exec
authored
670 /* unreached */
418495e @falconindy initial commit. works for me!
authored
671 return 0;
672 }
673
674 /* vim: set et ts=2 sw=2 */
Something went wrong with that request. Please try again.