| @@ -5,11 +5,10 @@ |
| * |
| * Licensed under GPL version 2, see file LICENSE in this tarball for details. |
| */ |
| - | |
| #include "libbb.h" |
| #include <sys/vfs.h> |
| |
| - | // Make up for header deficiencies. |
| + | // Make up for header deficiencies |
| #ifndef RAMFS_MAGIC |
| #define RAMFS_MAGIC ((unsigned)0x858458f6) |
| #endif |
| @@ -22,7 +21,7 @@ |
| #define MS_MOVE 8192 |
| #endif |
| |
| - | // Recursively delete contents of rootfs. |
| + | // Recursively delete contents of rootfs |
| static void delete_contents(const char *directory, dev_t rootdev) |
| { |
| DIR *dir; |
| @@ -33,7 +32,7 @@ static void delete_contents(const char *directory, dev_t rootdev) |
| if (lstat(directory, &st) || st.st_dev != rootdev) |
| return; |
| |
| - | // Recursively delete the contents of directories. |
| + | // Recursively delete the contents of directories |
| if (S_ISDIR(st.st_mode)) { |
| dir = opendir(directory); |
| if (dir) { |
| @@ -51,42 +50,47 @@ static void delete_contents(const char *directory, dev_t rootdev) |
| } |
| closedir(dir); |
| |
| - | // Directory should now be empty. Zap it. |
| + | // Directory should now be empty, zap it |
| rmdir(directory); |
| } |
| - | |
| - | // It wasn't a directory. Zap it. |
| - | } else unlink(directory); |
| + | } else { |
| + | // It wasn't a directory, zap it |
| + | unlink(directory); |
| + | } |
| } |
| |
| int switch_root_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| int switch_root_main(int argc UNUSED_PARAM, char **argv) |
| { |
| char *newroot, *console = NULL; |
| - | struct stat st1, st2; |
| + | struct stat st; |
| struct statfs stfs; |
| dev_t rootdev; |
| |
| // Parse args (-c console) |
| opt_complementary = "-2"; // minimum 2 params |
| - | getopt32(argv, "+c:", &console); // '+': stop parsing at first non-option |
| + | getopt32(argv, "+c:", &console); // '+': stop at first non-option |
| argv += optind; |
| - | |
| - | // Change to new root directory and verify it's a different fs. |
| newroot = *argv++; |
| |
| + | // Change to new root directory and verify it's a different fs |
| xchdir(newroot); |
| - | if (lstat(".", &st1) || lstat("/", &st2) || st1.st_dev == st2.st_dev) { |
| - | bb_error_msg_and_die("bad newroot %s", newroot); |
| + | xstat("/", &st); |
| + | rootdev = st.st_dev; |
| + | xstat(".", &st); |
| + | if (st.st_dev == rootdev || getpid() != 1) { |
| + | // Show usage, it says new root must be a mountpoint |
| + | // and we must be PID 1 |
| + | bb_show_usage(); |
| } |
| - | rootdev = st2.st_dev; |
| - | |
| - | // Additional sanity checks: we're about to rm -rf /, so be REALLY SURE |
| - | // we mean it. (I could make this a CONFIG option, but I would get email |
| - | // from all the people who WILL eat their filesystems.) |
| - | if (lstat("/init", &st1) || !S_ISREG(st1.st_mode) || statfs("/", &stfs) |
| - | || (((unsigned)stfs.f_type != RAMFS_MAGIC) && ((unsigned)stfs.f_type != TMPFS_MAGIC)) |
| - | || (getpid() != 1) |
| + | |
| + | // Additional sanity checks: we're about to rm -rf /, so be REALLY SURE |
| + | // we mean it. I could make this a CONFIG option, but I would get email |
| + | // from all the people who WILL destroy their filesystems. |
| + | statfs("/", &stfs); // this never fails |
| + | if (lstat("/init", &st) != 0 || !S_ISREG(st.st_mode) |
| + | || ((unsigned)stfs.f_type != RAMFS_MAGIC |
| + | && (unsigned)stfs.f_type != TMPFS_MAGIC) |
| ) { |
| bb_error_msg_and_die("not rootfs"); |
| } |
| @@ -94,14 +98,16 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) |
| // Zap everything out of rootdev |
| delete_contents("/", rootdev); |
| |
| - | // Overmount / with newdir and chroot into it. The chdir is needed to |
| - | // recalculate "." and ".." links. |
| - | if (mount(".", "/", NULL, MS_MOVE, NULL)) |
| + | // 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"); |
| + | } |
| + | // The chdir is needed to recalculate "." and ".." links |
| xchroot("."); |
| xchdir("/"); |
| |
| - | // If a new console specified, redirect stdin/stdout/stderr to that. |
| + | // If a new console specified, redirect stdin/stdout/stderr to it |
| if (console) { |
| close(0); |
| xopen(console, O_RDWR); |
| @@ -109,7 +115,7 @@ int switch_root_main(int argc UNUSED_PARAM, char **argv) |
| xdup2(0, 2); |
| } |
| |
| - | // Exec real init. (This is why we must be pid 1.) |
| + | // Exec real init |
| execv(argv[0], argv); |
| - | bb_perror_msg_and_die("bad init %s", argv[0]); |
| + | bb_perror_msg_and_die("can't execute '%s'", argv[0]); |
| } |