diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-08-22 10:37:30 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-08-22 10:37:30 +0200 |
commit | bbc26c6934fac218e19c7897f2dc2e6084e963b0 (patch) | |
tree | 3c45605f562471b6a853a29f750d57c0aee8ed37 /util-linux/switch_root.c | |
parent | 200bcc851acbe1ba30fe90b5cf918f88370a5d15 (diff) | |
download | busybox-w32-bbc26c6934fac218e19c7897f2dc2e6084e963b0.tar.gz busybox-w32-bbc26c6934fac218e19c7897f2dc2e6084e963b0.tar.bz2 busybox-w32-bbc26c6934fac218e19c7897f2dc2e6084e963b0.zip |
run-init: implement -n "dry run"
function old new delta
switch_root_main 637 706 +69
packed_usage 31743 31757 +14
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 83/0) Total: 83 bytes
text data bss dec hex filename
915247 563 5844 921654 e1036 busybox_old
915303 563 5844 921710 e106e busybox_unstripped
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'util-linux/switch_root.c')
-rw-r--r-- | util-linux/switch_root.c | 77 |
1 files changed, 43 insertions, 34 deletions
diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c index fe9ab68d0..16abcb634 100644 --- a/util-linux/switch_root.c +++ b/util-linux/switch_root.c | |||
@@ -24,6 +24,8 @@ | |||
24 | //config: * Because the Linux kernel uses rootfs internally as the starting | 24 | //config: * Because the Linux kernel uses rootfs internally as the starting |
25 | //config: and ending point for searching through the kernel's doubly linked | 25 | //config: and ending point for searching through the kernel's doubly linked |
26 | //config: list of active mount points. That's why. | 26 | //config: list of active mount points. That's why. |
27 | //config: | ||
28 | // RUN_INIT config item is in klibc-utils | ||
27 | 29 | ||
28 | //applet:IF_SWITCH_ROOT(APPLET(switch_root, BB_DIR_SBIN, BB_SUID_DROP)) | 30 | //applet:IF_SWITCH_ROOT(APPLET(switch_root, BB_DIR_SBIN, BB_SUID_DROP)) |
29 | // APPLET_ODDNAME:name main location suid_type help | 31 | // APPLET_ODDNAME:name main location suid_type help |
@@ -32,23 +34,6 @@ | |||
32 | //kbuild:lib-$(CONFIG_SWITCH_ROOT) += switch_root.o | 34 | //kbuild:lib-$(CONFIG_SWITCH_ROOT) += switch_root.o |
33 | //kbuild:lib-$(CONFIG_RUN_INIT) += switch_root.o | 35 | //kbuild:lib-$(CONFIG_RUN_INIT) += switch_root.o |
34 | 36 | ||
35 | //usage:#define switch_root_trivial_usage | ||
36 | //usage: "[-c CONSOLE_DEV] NEW_ROOT NEW_INIT [ARGS]" | ||
37 | //usage:#define switch_root_full_usage "\n\n" | ||
38 | //usage: "Free initramfs and switch to another root fs:\n" | ||
39 | //usage: "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n" | ||
40 | //usage: "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n" | ||
41 | //usage: "\n -c DEV Reopen stdio to DEV after switch" | ||
42 | |||
43 | //usage:#define run_init_trivial_usage | ||
44 | //usage: "[-d CAP,CAP...] [-c CONSOLE_DEV] NEW_ROOT NEW_INIT [ARGS]" | ||
45 | //usage:#define run_init_full_usage "\n\n" | ||
46 | //usage: "Free initramfs and switch to another root fs:\n" | ||
47 | //usage: "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n" | ||
48 | //usage: "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n" | ||
49 | //usage: "\n -c DEV Reopen stdio to DEV after switch" | ||
50 | //usage: "\n -d CAPS Drop capabilities" | ||
51 | |||
52 | #include <sys/vfs.h> | 37 | #include <sys/vfs.h> |
53 | #include <sys/mount.h> | 38 | #include <sys/mount.h> |
54 | #if ENABLE_RUN_INIT | 39 | #if ENABLE_RUN_INIT |
@@ -122,13 +107,8 @@ static void drop_capset(int cap_idx) | |||
122 | { | 107 | { |
123 | struct caps caps; | 108 | struct caps caps; |
124 | 109 | ||
125 | /* Get the current capability mask */ | ||
126 | getcaps(&caps); | 110 | getcaps(&caps); |
127 | |||
128 | /* Drop the bit */ | ||
129 | caps.data[CAP_TO_INDEX(cap_idx)].inheritable &= ~CAP_TO_MASK(cap_idx); | 111 | caps.data[CAP_TO_INDEX(cap_idx)].inheritable &= ~CAP_TO_MASK(cap_idx); |
130 | |||
131 | /* And drop the capability. */ | ||
132 | if (capset(&caps.header, caps.data) != 0) | 112 | if (capset(&caps.header, caps.data) != 0) |
133 | bb_perror_msg_and_die("capset"); | 113 | bb_perror_msg_and_die("capset"); |
134 | } | 114 | } |
@@ -199,10 +179,18 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) | |||
199 | char *newroot, *console = NULL; | 179 | char *newroot, *console = NULL; |
200 | struct stat st; | 180 | struct stat st; |
201 | struct statfs stfs; | 181 | struct statfs stfs; |
182 | unsigned dry_run = 0; | ||
202 | dev_t rootdev; | 183 | dev_t rootdev; |
203 | 184 | ||
204 | // Parse args (-c console). '+': stop at first non-option | 185 | // Parse args. '+': stop at first non-option |
205 | if (ENABLE_SWITCH_ROOT && (!ENABLE_RUN_INIT || applet_name[0] == 's')) { | 186 | if (ENABLE_SWITCH_ROOT && (!ENABLE_RUN_INIT || applet_name[0] == 's')) { |
187 | //usage:#define switch_root_trivial_usage | ||
188 | //usage: "[-c CONSOLE_DEV] NEW_ROOT NEW_INIT [ARGS]" | ||
189 | //usage:#define switch_root_full_usage "\n\n" | ||
190 | //usage: "Free initramfs and switch to another root fs:\n" | ||
191 | //usage: "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n" | ||
192 | //usage: "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n" | ||
193 | //usage: "\n -c DEV Reopen stdio to DEV after switch" | ||
206 | getopt32(argv, "^+" | 194 | getopt32(argv, "^+" |
207 | "c:" | 195 | "c:" |
208 | "\0" "-2" /* minimum 2 args */, | 196 | "\0" "-2" /* minimum 2 args */, |
@@ -210,13 +198,23 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) | |||
210 | ); | 198 | ); |
211 | } else { | 199 | } else { |
212 | #if ENABLE_RUN_INIT | 200 | #if ENABLE_RUN_INIT |
201 | //usage:#define run_init_trivial_usage | ||
202 | //usage: "[-d CAP,CAP...] [-n] [-c CONSOLE_DEV] NEW_ROOT NEW_INIT [ARGS]" | ||
203 | //usage:#define run_init_full_usage "\n\n" | ||
204 | //usage: "Free initramfs and switch to another root fs:\n" | ||
205 | //usage: "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n" | ||
206 | //usage: "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n" | ||
207 | //usage: "\n -c DEV Reopen stdio to DEV after switch" | ||
208 | //usage: "\n -d CAPS Drop capabilities" | ||
209 | //usage: "\n -n Dry run" | ||
213 | char *cap_list = NULL; | 210 | char *cap_list = NULL; |
214 | getopt32(argv, "^+" | 211 | dry_run = getopt32(argv, "^+" |
215 | "c:d:" | 212 | "c:d:n" |
216 | "\0" "-2" /* minimum 2 args */, | 213 | "\0" "-2" /* minimum 2 args */, |
217 | &console, | 214 | &console, |
218 | &cap_list | 215 | &cap_list |
219 | ); | 216 | ); |
217 | dry_run >>= 2; // -n | ||
220 | if (cap_list) | 218 | if (cap_list) |
221 | drop_capabilities(cap_list); | 219 | drop_capabilities(cap_list); |
222 | #endif | 220 | #endif |
@@ -239,7 +237,7 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) | |||
239 | // we mean it. I could make this a CONFIG option, but I would get email | 237 | // we mean it. I could make this a CONFIG option, but I would get email |
240 | // from all the people who WILL destroy their filesystems. | 238 | // from all the people who WILL destroy their filesystems. |
241 | if (stat("/init", &st) != 0 || !S_ISREG(st.st_mode)) { | 239 | if (stat("/init", &st) != 0 || !S_ISREG(st.st_mode)) { |
242 | bb_error_msg_and_die("/init is not a regular file"); | 240 | bb_error_msg_and_die("'%s' is not a regular file", "/init"); |
243 | } | 241 | } |
244 | statfs("/", &stfs); // this never fails | 242 | statfs("/", &stfs); // this never fails |
245 | if ((unsigned)stfs.f_type != RAMFS_MAGIC | 243 | if ((unsigned)stfs.f_type != RAMFS_MAGIC |
@@ -248,13 +246,15 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) | |||
248 | bb_error_msg_and_die("root filesystem is not ramfs/tmpfs"); | 246 | bb_error_msg_and_die("root filesystem is not ramfs/tmpfs"); |
249 | } | 247 | } |
250 | 248 | ||
251 | // Zap everything out of rootdev | 249 | if (!dry_run) { |
252 | delete_contents("/", rootdev); | 250 | // Zap everything out of rootdev |
251 | delete_contents("/", rootdev); | ||
253 | 252 | ||
254 | // Overmount / with newdir and chroot into it | 253 | // Overmount / with newdir and chroot into it |
255 | if (mount(".", "/", NULL, MS_MOVE, NULL)) { | 254 | if (mount(".", "/", NULL, MS_MOVE, NULL)) { |
256 | // For example, fails when newroot is not a mountpoint | 255 | // For example, fails when newroot is not a mountpoint |
257 | bb_perror_msg_and_die("error moving root"); | 256 | bb_perror_msg_and_die("error moving root"); |
257 | } | ||
258 | } | 258 | } |
259 | xchroot("."); | 259 | xchroot("."); |
260 | // The chdir is needed to recalculate "." and ".." links | 260 | // The chdir is needed to recalculate "." and ".." links |
@@ -270,8 +270,17 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) | |||
270 | } | 270 | } |
271 | } | 271 | } |
272 | 272 | ||
273 | // Exec real init | 273 | if (dry_run) { |
274 | execv(argv[0], argv); | 274 | // Does NEW_INIT look like it can be executed? |
275 | //xstat(argv[0], &st); | ||
276 | //if (!S_ISREG(st.st_mode)) | ||
277 | // bb_perror_msg_and_die("'%s' is not a regular file", argv[0]); | ||
278 | if (access(argv[0], X_OK) == 0) | ||
279 | return 0; | ||
280 | } else { | ||
281 | // Exec NEW_INIT | ||
282 | execv(argv[0], argv); | ||
283 | } | ||
275 | bb_perror_msg_and_die("can't execute '%s'", argv[0]); | 284 | bb_perror_msg_and_die("can't execute '%s'", argv[0]); |
276 | } | 285 | } |
277 | 286 | ||