aboutsummaryrefslogtreecommitdiff
path: root/util-linux
diff options
context:
space:
mode:
Diffstat (limited to 'util-linux')
-rw-r--r--util-linux/Config.in22
-rw-r--r--util-linux/switch_root.c118
2 files changed, 140 insertions, 0 deletions
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}