[libvirt] PATCH: 4/4: Add pivot_root support to container

Dan Smith danms at us.ibm.com
Wed Aug 13 17:57:11 UTC 2008


DB> +#if 0
DB> +    ttyfd = open(argv->ttyPath, O_RDWR|O_NOCTTY);
DB> +    if (ttyfd < 0) {
DB> +        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
DB> +                 _("open(%s) failed: %s"), argv->ttyPath, strerror(errno));
DB> +        return -1;
DB> +    }
DB> +#endif

Should this bit be removed?

DB> +    if (root) {
DB> +        char *oldroot;
DB> +        struct mntent *mntent;
DB> +        char **mounts = NULL;
DB> +        int nmounts = 0;
DB> +        FILE *procmnt;
DB> +        const struct {
DB> +            int maj;
DB> +            int min;
DB> +            mode_t mode;
DB> +            const char *path;
DB> +        } devs[] = {
DB> +            { 1, 3, 0666, "/dev/null" },
DB> +            { 1, 5, 0666, "/dev/zero" },
DB> +            { 1, 7, 0666, "/dev/full" },
DB> +            { 5, 1, 0600, "/dev/console" },
DB> +            { 1, 8, 0666, "/dev/random" },
DB> +            { 1, 9, 0666, "/dev/urandom" },
DB> +        };
DB> +
DB> +        /* Got a FS mapped to /, we're going the pivot_root
DB> +           approach to do a better-chroot-than-chroot */
DB> +
DB> +        /* this is based on this thread http://lkml.org/lkml/2008/3/5/29 */
DB> +
DB> +        /* First step is to ensure the new root itself is
DB> +           a mount point */
DB> +        if (mount(root->src, root->src, NULL, MS_BIND, NULL) < 0) {
DB>              lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
DB> -                     _("failed to mount %s at %s for container: %s"),
DB> -                     curMount->src, curMount->dst, strerror(errno));
DB> +                     _("failed to bind new root %s: %s"),
DB> +                     root->src, strerror(errno));
DB> +            return -1;
DB> +        }
DB> +
DB> +        if (asprintf(&oldroot, "%s/.oldroot", root->src) < 0) {
DB> +            lxcError(NULL, NULL, VIR_ERR_NO_MEMORY, NULL);
DB> +            return -1;
DB> +        }
DB> +
DB> +        if (virFileMakePath(oldroot) < 0) {
DB> +            lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
DB> +                     _("failed to create %s: %s"),
DB> +                     oldroot, strerror(errno));
DB> +            return -1;
DB> +        }
DB> +
DB> +        /* The old root directory will live at /.oldroot after
DB> +         * this and will soon be unmounted completely */
DB> +        if (pivot_root(root->src, oldroot) < 0) {
DB> +            lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
DB> +                     _("failed to pivot root %s to %s: %s"),
DB> +                     oldroot, root->src, strerror(errno));
DB> +            return -1;
DB> +        }
DB> +
DB> +        /* CWD is undefined after pivot_root, so go to / */
DB> +        if (chdir("/") < 0) {
DB> +            return -1;
DB> +        }
DB> +
DB> +        if (virFileMakePath("/proc") < 0 ||
DB> +            mount("none", "/proc", "proc", 0, NULL) < 0) {
DB> +            lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
DB> +                     _("failed to mount /proc for container: %s"),
DB> +                     strerror(errno));
DB> +            return -1;
DB> +        }
DB> +        if (virFileMakePath("/dev") < 0 ||
DB> +            mount("none", "/dev", "tmpfs", 0, NULL) < 0) {
DB> +            lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
DB> +                     _("failed to mount /dev tmpfs for container: %s"),
DB> +                     strerror(errno));
DB> +            return -1;
DB> +        }
DB> +        /* Move old devpts into container, since we have to
DB> +           connect to the master ptmx which was opened in
DB> +           the parent.
DB> +           XXX This sucks, we need to figure out how to get our
DB> +           own private devpts for isolation
DB> +        */
DB> +        if (virFileMakePath("/dev/pts") < 0 ||
DB> +            mount("/.oldroot/dev/pts", "/dev/pts", NULL,
DB> +                  MS_MOVE, NULL) < 0) {
DB> +            lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
DB> +                     _("failed to move /dev/pts into container: %s"),
DB> +                     strerror(errno));
DB> +            return -1;
DB> +        }
DB> +
DB> +        /* Populate /dev/ with a few important bits */
DB> +        for (i = 0 ; i < ARRAY_CARDINALITY(devs) ; i++) {
DB> +            dev_t dev = makedev(devs[i].maj, devs[i].min);
DB> +            if (mknod(devs[i].path, 0, dev) < 0 ||
DB> +                chmod(devs[i].path, devs[i].mode)) {
DB> +                lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
DB> +                         _("failed to make device %s: %s"),
DB> +                         devs[i].path, strerror(errno));
DB> +                return -1;
DB> +            }
DB> +        }
DB> +
DB> +        /* Pull in rest of container's mounts */
DB> +        for (tmp = vmDef->fss; tmp; tmp = tmp->next) {
DB> +            char *src;
DB> +            if (STREQ(tmp->dst, "/"))
DB> +                continue;
DB> +            // XXX fix
DB> +            if (tmp->type != VIR_DOMAIN_FS_TYPE_MOUNT)
DB> +                continue;
DB> +
DB> +            if (asprintf(&src, "/.oldroot/%s", tmp->src) < 0)
DB> +                return -1;
DB> +
DB> +            if (virFileMakePath(tmp->dst) < 0 ||
DB> +                mount(src, tmp->dst, NULL, MS_BIND, NULL) < 0) {
DB> +                VIR_FREE(src);
DB> +                lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
DB> +                         _("failed to mount %s at %s for container: %s"),
DB> +                         tmp->src, tmp->dst, strerror(errno));
DB> +                return -1;
DB> +            }
DB> +            VIR_FREE(src);
DB> +        }
DB> +
DB> +        if (!(procmnt = setmntent("/proc/mounts", "r"))) {
DB> +            lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
DB> +                     _("failed to read /proc/mounts: %s"),
DB> +                     strerror(errno));
DB> +            return -1;
DB> +        }
DB> +        while ((mntent = getmntent(procmnt)) != NULL) {
DB> +            if (!STRPREFIX(mntent->mnt_dir, "/.oldroot"))
DB> +                continue;
DB> +            if (VIR_REALLOC_N(mounts, nmounts+1) < 0) {
DB> +                endmntent(procmnt);
DB> +                return -1;
DB> +            }
DB> +            if (!(mounts[nmounts++] = strdup(mntent->mnt_dir))) {
DB> +                endmntent(procmnt);
DB> +                return -1;
DB> +            }
DB> +        }
DB> +        endmntent(procmnt);
DB> +
DB> +        qsort(mounts, nmounts, sizeof(mounts[0]),
DB> +              lxcContainerChildMountSort);
DB> +
DB> +        for (i = 0 ; i < nmounts ; i++) {
DB> +            if (umount(mounts[i]) < 0) {
DB> +                lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
DB> +                         _("failed to unmount %s: %s"),
DB> +                         mounts[i], strerror(errno));
DB> +                return -1;
DB> +            }
DB> +            VIR_FREE(mounts[i]);
DB> +        }
DB> +        VIR_FREE(mounts);

I'd really like to see this mondo if block broken out into at least an
lxcPivotRoot() function, if not further.  This is pretty long and
hairy, IMHO.

DB> +    } else {
DB> +        /* Nothing mapped to /, we're using the main root,
DB> +           but with extra stuff mapped in */
DB> +        for (tmp = vmDef->fss; tmp; tmp = tmp->next) {
DB> +            // XXX fix
DB> +            if (tmp->type != VIR_DOMAIN_FS_TYPE_MOUNT)
DB> +                continue;
DB> +            rc = mount(tmp->src,
DB> +                       tmp->dst,
DB> +                       NULL,
DB> +                       MS_BIND,
DB> +                       NULL);
DB> +            if (0 != rc) {
DB> +                lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
DB> +                         _("failed to mount %s at %s for container: %s"),
DB> +                         tmp->src, tmp->dst, strerror(errno));
DB> +                return -1;
DB> +            }
DB> +        }
DB> +
DB> +        /* mount /proc */
DB> +        if (mount("lxcproc", "/proc", "proc", 0, NULL) < 0) {
DB> +            lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
DB> +                     _("failed to mount /proc for container: %s"),
DB> +                     strerror(errno));
DB>              return -1;
DB>          }
DB>      }

Can we do the same mount of /proc no matter which option we take above?
It seems like after the root has been pivoted (or not), we can do the
same mount of proc, no?

It seems like all of the above could/should be in an
lxcContainerDoMounts() function or something, just like the
lxcContainerSetStdio() function that gets called a bit later.

The added functionality is excellent, by the way :)

Thanks!

-- 
Dan Smith
IBM Linux Technology Center
Open Hypervisor Team
email: danms at us.ibm.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 188 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20080813/4792fe43/attachment-0001.sig>


More information about the libvir-list mailing list