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>
This commit is contained in:
Denys Vlasenko 2017-08-22 10:37:30 +02:00
parent 200bcc851a
commit bbc26c6934
2 changed files with 44 additions and 35 deletions

View File

@ -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]);

View File

@ -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]);
}