1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#define FOR_switch_root
21#include "toys.h"
22#include <sys/vfs.h>
23
24GLOBALS(
25 char *c;
26
27 dev_t rootdev;
28)
29
30static int del_node(struct dirtree *node)
31{
32 if (node->st.st_dev == TT.rootdev && dirtree_notdotdot(node)) {
33 int flag = 0;
34 if (S_ISDIR(node->st.st_mode)) {
35 if (!node->again) return DIRTREE_COMEAGAIN;
36 flag = AT_REMOVEDIR;
37 }
38 unlinkat(dirtree_parentfd(node), node->name, flag);
39 }
40
41 return 0;
42}
43
44void switch_root_main(void)
45{
46 char *newroot = *toys.optargs, **cmdline = toys.optargs+1;
47 struct stat st1, st2;
48 struct statfs stfs;
49 int console QUIET;
50
51 if (getpid() != 1) error_exit("not pid 1");
52
53
54 if (statfs("/", &stfs) ||
55 (stfs.f_type != 0x858458f6 && stfs.f_type != 0x01021994))
56 {
57 error_msg("not ramfs");
58 goto panic;
59 }
60
61
62 if (chdir(newroot) || stat(".", &st1) || stat("/", &st2) ||
63 st1.st_dev == st2.st_dev)
64 {
65 error_msg("bad newroot '%s'", newroot);
66 goto panic;
67 }
68 TT.rootdev=st2.st_dev;
69
70
71
72
73 while (**cmdline == '/') (*cmdline)++;
74
75
76 if (stat(*cmdline, &st1) || !S_ISREG(st1.st_mode) || !(st1.st_mode&0100)) {
77 error_msg("bad init");
78 goto panic;
79 }
80
81 if (TT.c && -1 == (console = open(TT.c, O_RDWR))) {
82 perror_msg("bad console '%s'", TT.c);
83 goto panic;
84 }
85
86
87 dirtree_read("/", del_node);
88
89
90 if (mount(".", "/", NULL, MS_MOVE, NULL)) {
91 perror_msg("mount");
92 goto panic;
93 }
94
95
96 if (chroot(".")) {
97 perror_msg("chroot");
98 goto panic;
99 }
100
101
102 if (chdir("/")) {
103 perror_msg("chdir");
104 goto panic;
105 }
106
107 if (TT.c) {
108 int i;
109 for (i=0; i<3; i++) if (console != i) dup2(console, i);
110 if (console>2) close(console);
111 }
112 execv(*cmdline, cmdline);
113 perror_msg("Failed to exec '%s'", *cmdline);
114panic:
115 if (toys.optflags & FLAG_h) for (;;) wait(NULL);
116}
117