[git commit] run-init: implement -n "dry run"

Denys Vlasenko vda.linux at googlemail.com
Tue Aug 22 08:37:30 UTC 2017


commit: https://git.busybox.net/busybox/commit/?id=bbc26c6934fac218e19c7897f2dc2e6084e963b0
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

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 at googlemail.com>
---
 selinux/setfiles.c       |  2 +-
 util-linux/switch_root.c | 77 +++++++++++++++++++++++++++---------------------
 2 files changed, 44 insertions(+), 35 deletions(-)

diff --git a/selinux/setfiles.c b/selinux/setfiles.c
index fca6982..8da47d2 100644
--- a/selinux/setfiles.c
+++ b/selinux/setfiles.c
@@ -679,7 +679,7 @@ int setfiles_main(int argc UNUSED_PARAM, char **argv)
 			bb_show_usage();
 		xstat(argv[0], &sb);
 		if (!S_ISREG(sb.st_mode)) {
-			bb_error_msg_and_die("spec file %s is not a regular file", argv[0]);
+			bb_error_msg_and_die("'%s' is not a regular file", argv[0]);
 		}
 		/* Load the file contexts configuration and check it. */
 		rc = matchpathcon_init(argv[0]);
diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c
index fe9ab68..16abcb6 100644
--- a/util-linux/switch_root.c
+++ b/util-linux/switch_root.c
@@ -24,6 +24,8 @@
 //config:	* Because the Linux kernel uses rootfs internally as the starting
 //config:	and ending point for searching through the kernel's doubly linked
 //config:	list of active mount points. That's why.
+//config:
+// RUN_INIT config item is in klibc-utils
 
 //applet:IF_SWITCH_ROOT(APPLET(switch_root, BB_DIR_SBIN, BB_SUID_DROP))
 //                      APPLET_ODDNAME:name      main         location     suid_type     help
@@ -32,23 +34,6 @@
 //kbuild:lib-$(CONFIG_SWITCH_ROOT) += switch_root.o
 //kbuild:lib-$(CONFIG_RUN_INIT)    += switch_root.o
 
-//usage:#define switch_root_trivial_usage
-//usage:       "[-c CONSOLE_DEV] NEW_ROOT NEW_INIT [ARGS]"
-//usage:#define switch_root_full_usage "\n\n"
-//usage:       "Free initramfs and switch to another root fs:\n"
-//usage:       "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n"
-//usage:       "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n"
-//usage:     "\n	-c DEV	Reopen stdio to DEV after switch"
-
-//usage:#define run_init_trivial_usage
-//usage:       "[-d CAP,CAP...] [-c CONSOLE_DEV] NEW_ROOT NEW_INIT [ARGS]"
-//usage:#define run_init_full_usage "\n\n"
-//usage:       "Free initramfs and switch to another root fs:\n"
-//usage:       "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n"
-//usage:       "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n"
-//usage:     "\n	-c DEV	Reopen stdio to DEV after switch"
-//usage:     "\n	-d CAPS	Drop capabilities"
-
 #include <sys/vfs.h>
 #include <sys/mount.h>
 #if ENABLE_RUN_INIT
@@ -122,13 +107,8 @@ static void drop_capset(int cap_idx)
 {
 	struct caps caps;
 
-	/* Get the current capability mask */
 	getcaps(&caps);
-
-	/* Drop the bit */
 	caps.data[CAP_TO_INDEX(cap_idx)].inheritable &= ~CAP_TO_MASK(cap_idx);
-
-	/* And drop the capability. */
 	if (capset(&caps.header, caps.data) != 0)
 		bb_perror_msg_and_die("capset");
 }
@@ -199,10 +179,18 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv)
 	char *newroot, *console = NULL;
 	struct stat st;
 	struct statfs stfs;
+	unsigned dry_run = 0;
 	dev_t rootdev;
 
-	// Parse args (-c console). '+': stop at first non-option
+	// Parse args. '+': stop at first non-option
 	if (ENABLE_SWITCH_ROOT && (!ENABLE_RUN_INIT || applet_name[0] == 's')) {
+//usage:#define switch_root_trivial_usage
+//usage:       "[-c CONSOLE_DEV] NEW_ROOT NEW_INIT [ARGS]"
+//usage:#define switch_root_full_usage "\n\n"
+//usage:       "Free initramfs and switch to another root fs:\n"
+//usage:       "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n"
+//usage:       "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n"
+//usage:     "\n	-c DEV	Reopen stdio to DEV after switch"
 		getopt32(argv, "^+"
 			"c:"
 			"\0" "-2" /* minimum 2 args */,
@@ -210,13 +198,23 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv)
 		);
 	} else {
 #if ENABLE_RUN_INIT
+//usage:#define run_init_trivial_usage
+//usage:       "[-d CAP,CAP...] [-n] [-c CONSOLE_DEV] NEW_ROOT NEW_INIT [ARGS]"
+//usage:#define run_init_full_usage "\n\n"
+//usage:       "Free initramfs and switch to another root fs:\n"
+//usage:       "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n"
+//usage:       "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n"
+//usage:     "\n	-c DEV	Reopen stdio to DEV after switch"
+//usage:     "\n	-d CAPS	Drop capabilities"
+//usage:     "\n	-n	Dry run"
 		char *cap_list = NULL;
-		getopt32(argv, "^+"
-			"c:d:"
+		dry_run = getopt32(argv, "^+"
+			"c:d:n"
 			"\0" "-2" /* minimum 2 args */,
 			&console,
 			&cap_list
 		);
+		dry_run >>= 2; // -n
 		if (cap_list)
 			drop_capabilities(cap_list);
 #endif
@@ -239,7 +237,7 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv)
 	// we mean it. I could make this a CONFIG option, but I would get email
 	// from all the people who WILL destroy their filesystems.
 	if (stat("/init", &st) != 0 || !S_ISREG(st.st_mode)) {
-		bb_error_msg_and_die("/init is not a regular file");
+		bb_error_msg_and_die("'%s' is not a regular file", "/init");
 	}
 	statfs("/", &stfs); // this never fails
 	if ((unsigned)stfs.f_type != RAMFS_MAGIC
@@ -248,13 +246,15 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv)
 		bb_error_msg_and_die("root filesystem is not ramfs/tmpfs");
 	}
 
-	// Zap everything out of rootdev
-	delete_contents("/", rootdev);
+	if (!dry_run) {
+		// Zap everything out of rootdev
+		delete_contents("/", rootdev);
 
-	// Overmount / with newdir and chroot into it
-	if (mount(".", "/", NULL, MS_MOVE, NULL)) {
-		// For example, fails when newroot is not a mountpoint
-		bb_perror_msg_and_die("error moving root");
+		// Overmount / with newdir and chroot into it
+		if (mount(".", "/", NULL, MS_MOVE, NULL)) {
+			// For example, fails when newroot is not a mountpoint
+			bb_perror_msg_and_die("error moving root");
+		}
 	}
 	xchroot(".");
 	// The chdir is needed to recalculate "." and ".." links
@@ -270,8 +270,17 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv)
 		}
 	}
 
-	// Exec real init
-	execv(argv[0], argv);
+	if (dry_run) {
+		// Does NEW_INIT look like it can be executed?
+		//xstat(argv[0], &st);
+		//if (!S_ISREG(st.st_mode))
+		//	bb_perror_msg_and_die("'%s' is not a regular file", argv[0]);
+		if (access(argv[0], X_OK) == 0)
+			return 0;
+	} else {
+		// Exec NEW_INIT
+		execv(argv[0], argv);
+	}
 	bb_perror_msg_and_die("can't execute '%s'", argv[0]);
 }
 


More information about the busybox-cvs mailing list