aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2005-10-27 22:55:50 +0000
committerRob Landley <rob@landley.net>2005-10-27 22:55:50 +0000
commit0f34a821ab99e4936c7aa4974f58784442172211 (patch)
tree1341f988aa02110b3a997edc52e54bcc27ea1000
parent2454ebd85ddbbdc0971e9b848032f66e23245ebe (diff)
downloadbusybox-w32-0f34a821ab99e4936c7aa4974f58784442172211.tar.gz
busybox-w32-0f34a821ab99e4936c7aa4974f58784442172211.tar.bz2
busybox-w32-0f34a821ab99e4936c7aa4974f58784442172211.zip
Add a switch_root utility (like kconfig's utils/run_init.c, although not
actuall using any of that code). This is needed because pivot_root doesn't work right under initramfs. (See the menuconfig help.)
-rw-r--r--include/applets.h3
-rw-r--r--include/usage.h6
-rw-r--r--util-linux/Config.in22
-rw-r--r--util-linux/switch_root.c118
4 files changed, 149 insertions, 0 deletions
diff --git a/include/applets.h b/include/applets.h
index a814ce1b1..883e55990 100644
--- a/include/applets.h
+++ b/include/applets.h
@@ -625,6 +625,9 @@
625#ifdef CONFIG_SWAPONOFF 625#ifdef CONFIG_SWAPONOFF
626 APPLET(swapon, swap_on_off_main, _BB_DIR_SBIN, _BB_SUID_NEVER) 626 APPLET(swapon, swap_on_off_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
627#endif 627#endif
628#ifdef CONFIG_SWITCH_ROOT
629 APPLET(switch_root, switch_root_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
630#endif
628#ifdef CONFIG_SYNC 631#ifdef CONFIG_SYNC
629 APPLET(sync, sync_main, _BB_DIR_BIN, _BB_SUID_NEVER) 632 APPLET(sync, sync_main, _BB_DIR_BIN, _BB_SUID_NEVER)
630#endif 633#endif
diff --git a/include/usage.h b/include/usage.h
index bef6a4dd2..69c50b97b 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -2735,6 +2735,12 @@
2735 "Options:\n" \ 2735 "Options:\n" \
2736 "\t-a\tStart swapping on all swap devices" 2736 "\t-a\tStart swapping on all swap devices"
2737 2737
2738#define switch_root_trivial_usage \
2739 "NEW_ROOT NEW_INIT [ARGUMENTS_TO_INIT]"
2740#define switch_root_full_usage \
2741 "Use from PID 1 under initramfs to free initramfs, chroot to NEW_ROOT,\n" \
2742 "and exec NEW_INIT.\n"
2743
2738#define sync_trivial_usage \ 2744#define sync_trivial_usage \
2739 "" 2745 ""
2740#define sync_full_usage \ 2746#define sync_full_usage \
diff --git a/util-linux/Config.in b/util-linux/Config.in
index dc6d8fdad..fe71dac2c 100644
--- a/util-linux/Config.in
+++ b/util-linux/Config.in
@@ -288,6 +288,28 @@ config CONFIG_PIVOT_ROOT
288 of wild and crazy things with your Linux system and is far more 288 of wild and crazy things with your Linux system and is far more
289 powerful than 'chroot'. 289 powerful than 'chroot'.
290 290
291 Note: This is for initrd in linux 2.4. Under initramfs (introduced
292 in linux 2.6) use switch_root instead.
293
294config CONFIG_SWITCH_ROOT
295 bool "switch_root"
296 default n
297 help
298 The switch_root utility is used from initramfs to select a new
299 root device. Under initramfs, you have to use this instead of
300 pivot_root. (Stop reading here if you don't care why.)
301
302 Booting with initramfs extracts a gzipped cpio archive into rootfs
303 (which is a variant of ramfs/tmpfs). Because rootfs can't be moved
304 or unmounted*, pivot_root will not work from initramfs. Instead,
305 switch_root deletes everything out of rootfs (including itself),
306 does a mount --move that overmounts rootfs with the new root, and
307 then execs the specified init program.
308
309 * Because the Linux kernel uses rootfs internally as the starting
310 and ending point for searching through the kernel's doubly linked
311 list of active mount points. That's why.
312
291config CONFIG_RDATE 313config CONFIG_RDATE
292 bool "rdate" 314 bool "rdate"
293 default n 315 default n
diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c
new file mode 100644
index 000000000..242699560
--- /dev/null
+++ b/util-linux/switch_root.c
@@ -0,0 +1,118 @@
1/* vi:set ts=4:*/
2
3#include <dirent.h>
4#include <fcntl.h>
5#include <stdio.h>
6#include <sys/mount.h>
7#include <sys/stat.h>
8#include <sys/types.h>
9#include <sys/vfs.h>
10#include <unistd.h>
11
12#include "busybox.h"
13
14// Make up for header deficiencies.
15
16#ifndef RAMFS_MAGIC
17#define RAMFS_MAGIC 0x858458f6
18#endif
19
20#ifndef TMPFS_MAGIC
21#define TMPFS_MAGIC 0x01021994
22#endif
23
24#ifndef MS_MOVE
25#define MS_MOVE 8192
26#endif
27
28dev_t rootdev;
29
30// Recursively delete contents of rootfs.
31
32static void delete_contents(char *directory)
33{
34 DIR *dir;
35 struct dirent *d;
36 struct stat st;
37
38 // Don't descend into other filesystems
39 if (stat(directory,&st) || st.st_dev != rootdev) return;
40
41 // Recursively delete the contents of directories.
42 if (S_ISDIR(st.st_mode)) {
43 if((dir = opendir(directory))) {
44 while ((d = readdir(dir))) {
45 char *newdir=d->d_name;
46
47 // Skip . and ..
48 if(*newdir=='.' && (!newdir[1] || (newdir[1]=='.' && !newdir[2])))
49 continue;
50
51 // Recurse to delete contents
52 newdir = alloca(strlen(directory) + strlen(d->d_name) + 2);
53 sprintf(newdir, "%s/%s", directory, d->d_name);
54 delete_contents(newdir);
55 }
56 closedir(dir);
57
58 // Directory should now be empty. Zap it.
59 printf("rmdir %s\n",directory); // rmdir(directory);
60 }
61
62 // It wasn't a directory. Zap it.
63
64 } else printf("unlink %s\n",directory); //unlink(directory);
65}
66
67int switch_root_main(int argc, char *argv[])
68{
69 char *newroot, *console="/dev/console";
70 struct stat st1, st2;
71 struct statfs stfs;
72
73 // Parse args (-c console)
74
75 bb_opt_complementally="-2";
76 bb_getopt_ulflags(argc,argv,"c:",&console);
77
78 // Change to new root directory and verify it's a different fs.
79
80 newroot=argv[optind++];
81
82 if (chdir(newroot) || stat(".", &st1) || stat("/", &st2) ||
83 st1.st_dev == st2.st_dev)
84 {
85 bb_error_msg_and_die("bad newroot %s",newroot);
86 }
87 rootdev=st2.st_dev;
88
89 // Additional sanity checks: we're about to rm -rf /, so be REALLY SURE
90 // we mean it. (I could make this a CONFIG option, but I would get email
91 // from all the people who WILL eat their filesystemss.)
92
93 if (stat("/init", &st1) || !S_ISREG(st1.st_mode) || statfs("/", &stfs) ||
94 (stfs.f_type != RAMFS_MAGIC && stfs.f_type != TMPFS_MAGIC) ||
95 getpid() != 1)
96 {
97 bb_error_msg_and_die("not rootfs");
98 }
99
100 // Zap everything out of rootdev
101 delete_contents("/");
102
103 // Overmount / with newdir
104
105 if (mount(".", "/", NULL, MS_MOVE, NULL) || chdir("/"))
106 bb_error_msg_and_die("moving root");
107
108 // Reopen stdin/stdout/stderr to /dev/console
109 close(0);
110 if(open(console, O_RDWR) < 0)
111 bb_error_msg_and_die("Bad console '%s'",console);
112 dup2(0, 1);
113 dup2(0, 2);
114
115 // Exec real init. (This is why we must be pid 1.)
116 execv(argv[optind],argv+optind+1);
117 bb_error_msg_and_die("Bad init '%s'",argv[optind]);
118}