[hackers] [ubase] Implement switch_root || FRIGN

From: <git_AT_suckless.org>
Date: Mon, 14 Apr 2014 10:46:13 +0200

commit c7d72a8a56312057d41c4033683395121748e132
Author: FRIGN <dev_AT_frign.de>
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
_AT_@ -6,6 +6,7 @@ MIT/X Consortium License
 © 2013 Jakob Kramer <jakob.kramer_AT_gmx.de>
 © 2014 Carlos J. Torres <vlaadbrain_AT_gmail.com>
 © 2014 Hiltjo Posthuma <hiltjo_AT_codemadness.org>
+© 2014 Laslo Hunhold <dev_AT_frign.de>
 
 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
_AT_@ -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
_AT_@ -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]);
+}
Received on Mon Apr 14 2014 - 10:46:13 CEST

This archive was generated by hypermail 2.3.0 : Mon Apr 14 2014 - 10:48:19 CEST