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 | ||
