aboutsummaryrefslogtreecommitdiff
path: root/util-linux/switch_root.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-08-22 10:37:30 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-08-22 10:37:30 +0200
commitbbc26c6934fac218e19c7897f2dc2e6084e963b0 (patch)
tree3c45605f562471b6a853a29f750d57c0aee8ed37 /util-linux/switch_root.c
parent200bcc851acbe1ba30fe90b5cf918f88370a5d15 (diff)
downloadbusybox-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.c77
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