commit c7d72a8a56312057d41c4033683395121748e132
Author: FRIGN <[email protected]>
Date:   Mon Apr 14 00:07:06 2014 +0200

    Implement switch_root

diff --git a/LICENSE b/LICENSE
index a1078df..91107e6 100644
--- a/LICENSE
+++ b/LICENSE
@@ -6,6 +6,7 @@ MIT/X Consortium License
 © 2013 Jakob Kramer <[email protected]>
 © 2014 Carlos J. Torres <[email protected]>
 © 2014 Hiltjo Posthuma <[email protected]>
+© 2014 Laslo Hunhold <[email protected]>
 
 Permission is hereby granted, free of charge, to any person obtaining a
 copy of this software and associated documentation files (the "Software"),
diff --git a/Makefile b/Makefile
index c139777..0e9d26e 100644
--- a/Makefile
+++ b/Makefile
@@ -45,6 +45,7 @@ SRC = \
        su.c                \
        swapoff.c           \
        swapon.c            \
+       switch_root.c       \
        truncate.c          \
        umount.c            \
        unshare.c           \
diff --git a/switch_root.c b/switch_root.c
new file mode 100644
index 0000000..ede292e
--- /dev/null
+++ b/switch_root.c
@@ -0,0 +1,137 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <linux/magic.h>
+#include <linux/limits.h>
+#include <unistd.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include "util.h"
+
+static void
+delete_content(const char *dir, dev_t curdevice)
+{
+       char path[PATH_MAX];
+       DIR *d;
+       struct stat st;
+       struct dirent *dent;
+
+       /* don't dive into other filesystems */
+       if (lstat(dir, &st) || st.st_dev != curdevice){
+               return;
+       }
+       /* delete contents recursively */
+       if (S_ISDIR(st.st_mode)) {
+               d = opendir(dir);
+               if (d) {
+                       for(; (dent = readdir(d)) ;) {
+                               /* skip ".." and "." */
+                               if (dent->d_name[0] == '.'
+                                && ((dent->d_name[1] == '.' && dent->d_name[2] 
== 0)
+                                    || (dent->d_name[1] == 0)))
+                               {
+                                       continue;
+                               }
+
+                               /* build path and dive deeper */
+                               strlcat(path, dir, sizeof(path));
+                               strlcat(path, dent->d_name, sizeof(path));
+
+                               delete_content(path, curdevice);
+                               path[0] = 0;
+                       }
+                       closedir(d);
+
+                       /* remove now empty dir */
+                       rmdir(dir);
+               }
+       } else {
+               /* unlink non-directory */
+               unlink(dir);
+       }
+}
+
+static void
+usage(void)
+{
+       eprintf("usage: %s [-c console] [newroot] [init] (PID 1)
", argv0);
+}
+
+int
+main(int argc, char **argv)
+{
+       char *console = NULL;
+       dev_t curdev;
+       struct stat st;
+       struct statfs stfs;
+
+       ARGBEGIN {
+       case 'c':
+               console = EARGF(usage());
+               break;
+       default:
+               usage();
+       } ARGEND;
+
+       /* check number of args and if we are PID 1 */
+       if (argc != 2 || getpid() != 1){
+               usage();
+       }
+
+       /* chdir to newroot and make sure it's a different fs */
+       if (chdir(argv[0])) {
+               eprintf("chdir %s:", argv[0]);
+       }
+       if (stat("/", &st)) {
+               eprintf("stat %s:", "/");
+       }
+       curdev = st.st_dev;
+       if (stat(".", &st)) {
+               eprintf("stat %s:", ".");
+       }
+       if (st.st_dev == curdev) {
+               usage();
+       }
+
+       /* further checks */
+       if (stat("/init", &st) || !S_ISREG(st.st_mode)) {
+               /* avoids trouble with real filesystems */
+               eprintf("/init is not a regular file
");
+       }
+       statfs("/", &stfs);
+       if ((unsigned)stfs.f_type != RAMFS_MAGIC && (unsigned)stfs.f_type != 
TMPFS_MAGIC){
+               eprintf("current filesystem is not a RAMFS or TMPFS
");
+       }
+
+       /* wipe / */
+       delete_content("/", curdev);
+
+       /* overmount / with newroot and chroot into it */
+       if (mount(".", "/", NULL, MS_MOVE, NULL)) {
+               eprintf("mount %s:", ".");
+       }
+       if (chroot(".")) {
+               eprintf("chroot failed
");
+       }
+
+       /* if -c is set, redirect stdin/stdout/stderr to console */
+       if (console) {
+               close(0);
+               if(open(console, O_RDWR) == -1){
+                       eprintf("open %s:", console);
+               }
+               if (dup2(0,1) == -1){
+                       eprintf("dup2 %s:", "0,1");
+               }
+               if (dup2(0,2) == -1){
+                       eprintf("dup2 %s:", "0,2");
+               }
+       }
+
+       /* execute init */
+       execv(argv[1], argv);
+       eprintf("can't execute '%s'
", argv[1]);
+}


Reply via email to