diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-21 20:40:51 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-21 20:40:51 +0000 |
| commit | f9d4fc3cf8ca91dbebfa305c5c08f8781caa1a0f (patch) | |
| tree | b341f97661b629cc112ebe09933c044ebb31a6f7 /util-linux | |
| parent | 950bd729665cecf1fbee65bc6e57e087c93aaab6 (diff) | |
| download | busybox-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')
| -rw-r--r-- | util-linux/switch_root.c | 62 |
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 |
| 26 | static void delete_contents(const char *directory, dev_t rootdev) | 25 | static 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 | ||
| 62 | int switch_root_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 62 | int switch_root_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| 63 | int switch_root_main(int argc UNUSED_PARAM, char **argv) | 63 | int 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 | } |
