[lxc-devel] Patch: pivot_root, v6
Michael Holzt
lxc at my.fqdn.org
Thu Jan 7 00:00:07 UTC 2010
Hello everyone,
please find my latest patch attached. The new patch now replaces the chroot
code completely by my pivot_root code. The config keyword 'pivotdir' is now
optional and allows to specify the temporary mountpoint for the old root fs
in the new root fs. If it is omitted, a temporary mountpoint is create in
the new root fs and rmdir'd after the umounts are finished.
Regards,
Michael
--
It's an insane world, but i'm proud to be a part of it. -- Bill Hicks
-------------- next part --------------
diff -Naur lxc-0.6.4/src/lxc/conf.c lxc-0.6.4-pivot/src/lxc/conf.c
--- lxc-0.6.4/src/lxc/conf.c 2009-11-24 09:47:26.000000000 +0100
+++ lxc-0.6.4-pivot/src/lxc/conf.c 2010-01-07 00:55:06.000000000 +0100
@@ -65,6 +65,8 @@
#define MS_REC 16384
#endif
+extern int pivot_root(const char * new_root, const char * put_old);
+
typedef int (*instanciate_cb)(struct lxc_netdev *);
struct mount_opt {
@@ -334,7 +336,183 @@
return 0;
}
-static int setup_rootfs(const char *rootfs)
+static int setup_rootfs_pivot_root_cb(void *buffer, void *data)
+{
+ struct lxc_list *mountlist, *listentry, *iterator;
+ char *pivotdir, *mountpoint, *mountentry;
+ int found;
+ void **cbparm;
+
+ mountentry = buffer;
+ cbparm = (void **)data;
+
+ mountlist = cbparm[0];
+ pivotdir = cbparm[1];
+
+ /* parse entry, first field is mountname, ignore */
+ mountpoint = strtok(mountentry, " ");
+ if (!mountpoint)
+ return -1;
+
+ /* second field is mountpoint */
+ mountpoint = strtok(NULL, " ");
+ if (!mountpoint)
+ return -1;
+
+ /* only consider mountpoints below old root fs */
+ if (strncmp(mountpoint, pivotdir, strlen(pivotdir)))
+ return 0;
+
+ /* filter duplicate mountpoints */
+ found = 0;
+ lxc_list_for_each(iterator, mountlist) {
+ if (!strcmp(iterator->elem, mountpoint)) {
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ return 0;
+
+ /* add entry to list */
+ listentry = malloc(sizeof(*listentry));
+ if (!listentry) {
+ SYSERROR("malloc for mountpoint listentry failed");
+ return -1;
+ }
+
+ listentry->elem = strdup(mountpoint);
+ if (!listentry->elem) {
+ SYSERROR("strdup failed");
+ return -1;
+ }
+ lxc_list_add_tail(mountlist, listentry);
+
+ return 0;
+}
+
+
+static int setup_rootfs_pivot_root(const char *rootfs, const char *pivotdir)
+{
+ char path[MAXPATHLEN], buffer[MAXPATHLEN];
+ void *cbparm[2];
+ struct lxc_list mountlist, *iterator;
+ int ok, still_mounted, last_still_mounted;
+ int pivotdir_is_temp = 0;
+
+ /* change into new root fs */
+ if (chdir(rootfs)) {
+ SYSERROR("can't chroot to new rootfs '%s'", rootfs);
+ return -1;
+ }
+
+ /* create temporary mountpoint if none specified */
+ if (!pivotdir) {
+
+ snprintf(path, sizeof(path), "./lxc-oldrootfs-XXXXXX" );
+ if (!mkdtemp(path)) {
+ SYSERROR("can't make temporary mountpoint");
+ return -1;
+ }
+
+ pivotdir = strdup(&path[1]); /* get rid of leading dot */
+ if (!pivotdir) {
+ SYSERROR("strdup failed");
+ return -1;
+ }
+
+ pivotdir_is_temp = 1;
+ }
+ else {
+ snprintf(path, sizeof(path), ".%s", pivotdir);
+ }
+
+ DEBUG("temporary mountpoint for old rootfs is '%s'", path);
+
+ /* pivot_root into our new root fs */
+
+ if (pivot_root(".", path)) {
+ SYSERROR("pivot_root syscall failed");
+ return -1;
+ }
+
+ if (chdir("/")) {
+ SYSERROR("can't chroot to / after pivot_root");
+ return -1;
+ }
+
+ DEBUG("pivot_root syscall to '%s' successful", pivotdir);
+
+ /* read and parse /proc/mounts in old root fs */
+ lxc_list_init(&mountlist);
+
+ snprintf(path, sizeof(path), "%s/", pivotdir);
+ cbparm[0] = &mountlist;
+ cbparm[1] = strdup(path);
+
+ if (!cbparm[1]) {
+ SYSERROR("strdup failed");
+ return -1;
+ }
+
+ snprintf(path, sizeof(path), "/%s/proc/mounts", pivotdir);
+ ok = lxc_file_for_each_line(path,
+ setup_rootfs_pivot_root_cb,
+ buffer, sizeof(buffer), &cbparm);
+ if (ok < 0) {
+ SYSERROR("failed to read or parse mount list '%s'", path);
+ return -1;
+ }
+
+ /* umount filesystems until none left or list no longer shrinks */
+ still_mounted = 0;
+ do {
+ last_still_mounted = still_mounted;
+ still_mounted = 0;
+
+ lxc_list_for_each(iterator, &mountlist) {
+
+ if (!umount(iterator->elem)) {
+ DEBUG("umounted '%s'", (char *)iterator->elem);
+ lxc_list_del(iterator);
+ continue;
+ }
+
+ if (errno != EBUSY) {
+ SYSERROR("failed to umount '%s'", (char *)iterator->elem);
+ return -1;
+ }
+
+ still_mounted++;
+ }
+ } while (still_mounted > 0 && still_mounted != last_still_mounted);
+
+ if (still_mounted) {
+ ERROR("could not umount %d mounts", still_mounted);
+ return -1;
+ }
+
+ /* umount old root fs */
+ if (umount(pivotdir)) {
+ SYSERROR("could not unmount old rootfs");
+ return -1;
+ }
+ DEBUG("umounted '%s'", pivotdir);
+
+ /* remove temporary mount point */
+ if (pivotdir_is_temp) {
+ if (rmdir(pivotdir)) {
+ SYSERROR("can't remove temporary mountpoint");
+ return -1;
+ }
+
+ }
+
+ INFO("pivoted to '%s'", rootfs);
+ return 0;
+}
+
+static int setup_rootfs(const char *rootfs, const char *pivotdir)
{
char *tmpname;
int ret = -1;
@@ -358,18 +536,11 @@
goto out;
}
- if (chroot(tmpname)) {
- SYSERROR("failed to set chroot %s", tmpname);
+ if (setup_rootfs_pivot_root(tmpname, pivotdir)) {
+ ERROR("failed to pivot_root to '%s'", rootfs);
goto out;
}
- if (chdir(getenv("HOME")) && chdir("/")) {
- SYSERROR("failed to change to home directory");
- goto out;
- }
-
- INFO("chrooted to '%s'", rootfs);
-
ret = 0;
out:
rmdir(tmpname);
@@ -816,6 +987,7 @@
int lxc_conf_init(struct lxc_conf *conf)
{
conf->rootfs = NULL;
+ conf->pivotdir = NULL;
conf->fstab = NULL;
conf->utsname = NULL;
conf->tty = 0;
@@ -1086,7 +1258,7 @@
return -1;
}
- if (setup_rootfs(lxc_conf->rootfs)) {
+ if (setup_rootfs(lxc_conf->rootfs, lxc_conf->pivotdir)) {
ERROR("failed to set rootfs for '%s'", name);
return -1;
}
diff -Naur lxc-0.6.4/src/lxc/conf.h lxc-0.6.4-pivot/src/lxc/conf.h
--- lxc-0.6.4/src/lxc/conf.h 2009-11-19 15:06:02.000000000 +0100
+++ lxc-0.6.4-pivot/src/lxc/conf.h 2010-01-06 05:10:18.000000000 +0100
@@ -133,6 +133,7 @@
*/
struct lxc_conf {
char *rootfs;
+ char *pivotdir;
char *fstab;
int tty;
int pts;
@@ -167,6 +168,7 @@
#define conf_has_fstab(__name) conf_has(__name, "fstab")
#define conf_has_rootfs(__name) conf_has(__name, "rootfs")
+#define conf_has_pivotdir(__name) conf_has(__name, "pivotdir")
#define conf_has_utsname(__name) conf_has(__name, "utsname")
#define conf_has_network(__name) conf_has(__name, "network")
#define conf_has_console(__name) conf_has(__name, "console")
diff -Naur lxc-0.6.4/src/lxc/confile.c lxc-0.6.4-pivot/src/lxc/confile.c
--- lxc-0.6.4/src/lxc/confile.c 2009-11-19 15:06:02.000000000 +0100
+++ lxc-0.6.4-pivot/src/lxc/confile.c 2010-01-06 19:36:32.000000000 +0100
@@ -44,6 +44,7 @@
static int config_cgroup(const char *, char *, struct lxc_conf *);
static int config_mount(const char *, char *, struct lxc_conf *);
static int config_rootfs(const char *, char *, struct lxc_conf *);
+static int config_pivotdir(const char *, char *, struct lxc_conf *);
static int config_utsname(const char *, char *, struct lxc_conf *);
static int config_network_type(const char *, char *, struct lxc_conf *);
static int config_network_flags(const char *, char *, struct lxc_conf *);
@@ -68,6 +69,7 @@
{ "lxc.cgroup", config_cgroup },
{ "lxc.mount", config_mount },
{ "lxc.rootfs", config_rootfs },
+ { "lxc.pivotdir", config_pivotdir },
{ "lxc.utsname", config_utsname },
{ "lxc.network.type", config_network_type },
{ "lxc.network.flags", config_network_flags },
@@ -494,6 +496,22 @@
return 0;
}
+static int config_pivotdir(const char *key, char *value, struct lxc_conf *lxc_conf)
+{
+ if (strlen(value) >= MAXPATHLEN) {
+ ERROR("%s path is too long", value);
+ return -1;
+ }
+
+ lxc_conf->pivotdir = strdup(value);
+ if (!lxc_conf->pivotdir) {
+ SYSERROR("failed to duplicate string %s", value);
+ return -1;
+ }
+
+ return 0;
+}
+
static int config_utsname(const char *key, char *value, struct lxc_conf *lxc_conf)
{
struct utsname *utsname;
More information about the lxc-devel
mailing list