aboutsummaryrefslogtreecommitdiff
path: root/util-linux/switch_root.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-04-21 20:40:51 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-04-21 20:40:51 +0000
commitf9d4fc3cf8ca91dbebfa305c5c08f8781caa1a0f (patch)
treeb341f97661b629cc112ebe09933c044ebb31a6f7 /util-linux/switch_root.c
parent950bd729665cecf1fbee65bc6e57e087c93aaab6 (diff)
downloadbusybox-w32-f9d4fc3cf8ca91dbebfa305c5c08f8781caa1a0f.tar.gz
busybox-w32-f9d4fc3cf8ca91dbebfa305c5c08f8781caa1a0f.tar.bz2
busybox-w32-f9d4fc3cf8ca91dbebfa305c5c08f8781caa1a0f.zip
switch_root: improve behavior on error; improve help text
*: make "can't execute '%s'" message uniform
Diffstat (limited to 'util-linux/switch_root.c')
-rw-r--r--util-linux/switch_root.c62
1 files changed, 34 insertions, 28 deletions
diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c
index 08aa72597..f9e3444d5 100644
--- a/util-linux/switch_root.c
+++ b/util-linux/switch_root.c
@@ -5,11 +5,10 @@
5 * 5 *
6 * Licensed under GPL version 2, see file LICENSE in this tarball for details. 6 * Licensed under GPL version 2, see file LICENSE in this tarball for details.
7 */ 7 */
8
9#include "libbb.h" 8#include "libbb.h"
10#include <sys/vfs.h> 9#include <sys/vfs.h>
11 10
12// Make up for header deficiencies. 11// Make up for header deficiencies
13#ifndef RAMFS_MAGIC 12#ifndef RAMFS_MAGIC
14#define RAMFS_MAGIC ((unsigned)0x858458f6) 13#define RAMFS_MAGIC ((unsigned)0x858458f6)
15#endif 14#endif
@@ -22,7 +21,7 @@
22#define MS_MOVE 8192 21#define MS_MOVE 8192
23#endif 22#endif
24 23
25// Recursively delete contents of rootfs. 24// Recursively delete contents of rootfs
26static void delete_contents(const char *directory, dev_t rootdev) 25static void delete_contents(const char *directory, dev_t rootdev)
27{ 26{
28 DIR *dir; 27 DIR *dir;
@@ -33,7 +32,7 @@ static void delete_contents(const char *directory, dev_t rootdev)
33 if (lstat(directory, &st) || st.st_dev != rootdev) 32 if (lstat(directory, &st) || st.st_dev != rootdev)
34 return; 33 return;
35 34
36 // Recursively delete the contents of directories. 35 // Recursively delete the contents of directories
37 if (S_ISDIR(st.st_mode)) { 36 if (S_ISDIR(st.st_mode)) {
38 dir = opendir(directory); 37 dir = opendir(directory);
39 if (dir) { 38 if (dir) {
@@ -51,42 +50,47 @@ static void delete_contents(const char *directory, dev_t rootdev)
51 } 50 }
52 closedir(dir); 51 closedir(dir);
53 52
54 // Directory should now be empty. Zap it. 53 // Directory should now be empty, zap it
55 rmdir(directory); 54 rmdir(directory);
56 } 55 }
57 56 } else {
58 // It wasn't a directory. Zap it. 57 // It wasn't a directory, zap it
59 } else unlink(directory); 58 unlink(directory);
59 }
60} 60}
61 61
62int switch_root_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 62int switch_root_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
63int switch_root_main(int argc UNUSED_PARAM, char **argv) 63int switch_root_main(int argc UNUSED_PARAM, char **argv)
64{ 64{
65 char *newroot, *console = NULL; 65 char *newroot, *console = NULL;
66 struct stat st1, st2; 66 struct stat st;
67 struct statfs stfs; 67 struct statfs stfs;
68 dev_t rootdev; 68 dev_t rootdev;
69 69
70 // Parse args (-c console) 70 // Parse args (-c console)
71 opt_complementary = "-2"; // minimum 2 params 71 opt_complementary = "-2"; // minimum 2 params
72 getopt32(argv, "+c:", &console); // '+': stop parsing at first non-option 72 getopt32(argv, "+c:", &console); // '+': stop at first non-option
73 argv += optind; 73 argv += optind;
74
75 // Change to new root directory and verify it's a different fs.
76 newroot = *argv++; 74 newroot = *argv++;
77 75
76 // Change to new root directory and verify it's a different fs
78 xchdir(newroot); 77 xchdir(newroot);
79 if (lstat(".", &st1) || lstat("/", &st2) || st1.st_dev == st2.st_dev) { 78 xstat("/", &st);
80 bb_error_msg_and_die("bad newroot %s", newroot); 79 rootdev = st.st_dev;
80 xstat(".", &st);
81 if (st.st_dev == rootdev || getpid() != 1) {
82 // Show usage, it says new root must be a mountpoint
83 // and we must be PID 1
84 bb_show_usage();
81 } 85 }
82 rootdev = st2.st_dev; 86
83 87 // Additional sanity checks: we're about to rm -rf /, so be REALLY SURE
84 // Additional sanity checks: we're about to rm -rf /, so be REALLY SURE 88 // we mean it. I could make this a CONFIG option, but I would get email
85 // we mean it. (I could make this a CONFIG option, but I would get email 89 // from all the people who WILL destroy their filesystems.
86 // from all the people who WILL eat their filesystems.) 90 statfs("/", &stfs); // this never fails
87 if (lstat("/init", &st1) || !S_ISREG(st1.st_mode) || statfs("/", &stfs) 91 if (lstat("/init", &st) != 0 || !S_ISREG(st.st_mode)
88 || (((unsigned)stfs.f_type != RAMFS_MAGIC) && ((unsigned)stfs.f_type != TMPFS_MAGIC)) 92 || ((unsigned)stfs.f_type != RAMFS_MAGIC
89 || (getpid() != 1) 93 && (unsigned)stfs.f_type != TMPFS_MAGIC)
90 ) { 94 ) {
91 bb_error_msg_and_die("not rootfs"); 95 bb_error_msg_and_die("not rootfs");
92 } 96 }
@@ -94,14 +98,16 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv)
94 // Zap everything out of rootdev 98 // Zap everything out of rootdev
95 delete_contents("/", rootdev); 99 delete_contents("/", rootdev);
96 100
97 // Overmount / with newdir and chroot into it. The chdir is needed to 101 // Overmount / with newdir and chroot into it
98 // recalculate "." and ".." links. 102 if (mount(".", "/", NULL, MS_MOVE, NULL)) {
99 if (mount(".", "/", NULL, MS_MOVE, NULL)) 103 // For example, fails when newroot is not a mountpoint
100 bb_perror_msg_and_die("error moving root"); 104 bb_perror_msg_and_die("error moving root");
105 }
106 // The chdir is needed to recalculate "." and ".." links
101 xchroot("."); 107 xchroot(".");
102 xchdir("/"); 108 xchdir("/");
103 109
104 // If a new console specified, redirect stdin/stdout/stderr to that. 110 // If a new console specified, redirect stdin/stdout/stderr to it
105 if (console) { 111 if (console) {
106 close(0); 112 close(0);
107 xopen(console, O_RDWR); 113 xopen(console, O_RDWR);
@@ -109,7 +115,7 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv)
109 xdup2(0, 2); 115 xdup2(0, 2);
110 } 116 }
111 117
112 // Exec real init. (This is why we must be pid 1.) 118 // Exec real init
113 execv(argv[0], argv); 119 execv(argv[0], argv);
114 bb_perror_msg_and_die("bad init %s", argv[0]); 120 bb_perror_msg_and_die("can't execute '%s'", argv[0]);
115} 121}