[PATCH] Implement switch_root

From: FRIGN <dev_AT_frign.de>
Date: Mon, 14 Apr 2014 00:07:06 +0200

---
 LICENSE       |   1 +
 Makefile      |   1 +
 switch_root.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++=
++++
 3 files changed, 138 insertions(+)
 create mode 100644 switch_root.c
diff --git a/LICENSE b/LICENSE
index a1078df..91107e6 100644
--- a/LICENSE
+++ b/LICENSE
_AT_@ -6,6 +6,7 @@ MIT/X Consortium License
 =C2=A9 2013 Jakob Kramer <jakob.kramer_AT_gmx.de>
 =C2=A9 2014 Carlos J. Torres <vlaadbrain_AT_gmail.com>
 =C2=A9 2014 Hiltjo Posthuma <hiltjo_AT_codemadness.org>
+=C2=A9 2014 Laslo Hunhold <dev_AT_frign.de>
=20
 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 =3D \
 	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..cfa37e9
--- /dev/null
+++ b/switch_root.c
_AT_@ -0,0 +1,136 @@
+/* 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;
+=09
+	/* don't dive into other filesystems */
+	if (lstat(dir, &st) || st.st_dev !=3D curdevice){
+		return;
+	}
+	/* delete contents recursively */
+	if (S_ISDIR(st.st_mode)) {
+		d =3D opendir(dir);
+		if (d) {
+			for(; (dent =3D readdir(d)) ;) {
+				/* skip ".." and "." */
+				if (dent->d_name[0] =3D=3D '.'
+				 && ((dent->d_name[1] =3D=3D '.' && dent->d_name[2] =3D=3D 0)
+				     || (dent->d_name[1] =3D=3D 0)))
+				{
+					continue;
+				}
+			=09
+				/* build path and dive deeper */
+				strlcat(path, dir, sizeof(path));
+				strlcat(path, dent->d_name, sizeof(path));
+
+				delete_content(path, curdevice);
+				path[0] =3D 0;
+			}
+			closedir(d);
+		=09
+			/* 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)\n", argv0);
+}
+
+int
+main(int argc, char **argv)
+{
+	char *console =3D NULL;
+	dev_t curdev;
+	struct stat st;
+	struct statfs stfs;
+
+	ARGBEGIN {
+	case 'c':
+		console =3D EARGF(usage());
+		break;
+	default:
+		usage();
+	} ARGEND;
+
+	/* check number of args and if we are PID 1 */
+	if (argc !=3D 2 || getpid() !=3D 1){
+		usage();
+	}
+=09
+	/* 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 =3D st.st_dev;
+	if (stat(".", &st)) {
+		eprintf("stat %s:", ".");
+	}
+	if (st.st_dev =3D=3D 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\n");
+	}
+	statfs("/", &stfs);
+	if ((unsigned)stfs.f_type !=3D RAMFS_MAGIC && (unsigned)stfs.f_type !=3D =
TMPFS_MAGIC){
+		eprintf("current filesystem is not a RAMFS or TMPFS\n");
+	}
+=09
+	/* wipe / */
+	delete_content("/", curdev);
+=09
+	/* overmount / with newroot and chroot into it */
+	if (mount(".", "/", NULL, MS_MOVE, NULL)) {
+		eprintf("mount %s:", ".");
+	}
+	if (chroot(".")) {
+		eprintf("chroot failed\n");
+	}
+
+	/* if -c is set, redirect stdin/stdout/stderr to console */
+	if (console) {
+		close(0);
+		if(open(console, O_RDWR) =3D=3D -1){
+			eprintf("open %s:", console);
+		}
+		if (dup2(0,1) =3D=3D -1){
+			eprintf("dup2 %s:", "0,1");
+		}
+		if (dup2(0,2) =3D=3D -1){
+			eprintf("dup2 %s:", "0,2");
+		}
+	}
+
+	/* execute init */
+	execv(argv[1], argv);
+	eprintf("can't execute '%s'\n", argv[1]);
+}
--=20
1.8.3.2
--Multipart=_Mon__14_Apr_2014_00_15_12_+0200_PFbmMdwa_u.7YJDY--
Received on Mon Sep 17 2001 - 00:00:00 CEST

This archive was generated by hypermail 2.3.0 : Mon Apr 14 2014 - 02:12:03 CEST