]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
fill_autodev: bind-mount if mknod fails (v3)
authorSerge Hallyn <serge.hallyn@ubuntu.com>
Mon, 12 Jan 2015 23:56:28 +0000 (23:56 +0000)
committerStéphane Graber <stgraber@ubuntu.com>
Fri, 16 Jan 2015 00:10:15 +0000 (19:10 -0500)
First, rename setup_autodev to fill_autodev, since all it
does is populate it, not fully set it up.

Secondly, if mknod of a device fails, then try bind-mounting
it from the host rather than failing immediately.

Note that this isn't an urgent patch because the common.userns
configuration hook already specifies bind,create=file mount
entries for all the devices we would want.

Changelog (v3): ignore if /dev doesn't exist

Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
Acked-by: Stéphane Graber <stgraber@ubuntu.com>
src/lxc/conf.c

index 28c108181e6f152f06fa179f0c332cc9d1af4191..0e663e9ab3ce0b9586453a546a78a7754194e457 100644 (file)
@@ -1155,7 +1155,7 @@ static const struct lxc_devs lxc_devs[] = {
        { "console",    S_IFCHR | S_IRUSR | S_IWUSR,           5, 1     },
 };
 
-static int setup_autodev(const char *root)
+static int fill_autodev(const char *root)
 {
        int ret;
        char path[MAXPATHLEN];
@@ -1170,6 +1170,9 @@ static int setup_autodev(const char *root)
                return -1;
        }
 
+       if (!dir_exists(path))  // ignore, just don't try to fill in
+               return 0;
+
        INFO("Populating /dev under %s", root);
        cmask = umask(S_IXUSR | S_IXGRP | S_IXOTH);
        for (i = 0; i < sizeof(lxc_devs) / sizeof(lxc_devs[0]); i++) {
@@ -1179,8 +1182,25 @@ static int setup_autodev(const char *root)
                        return -1;
                ret = mknod(path, d->mode, makedev(d->maj, d->min));
                if (ret && errno != EEXIST) {
-                       SYSERROR("Error creating %s", d->name);
-                       return -1;
+                       char hostpath[MAXPATHLEN];
+                       FILE *pathfile;
+
+                       // Unprivileged containers cannot create devices, so
+                       // bind mount the device from the host
+                       ret = snprintf(hostpath, MAXPATHLEN, "/dev/%s", d->name);
+                       if (ret < 0 || ret >= MAXPATHLEN)
+                               return -1;
+                       pathfile = fopen(path, "wb");
+                       if (!pathfile) {
+                               SYSERROR("Failed to create device mount target '%s'", path);
+                               return -1;
+                       }
+                       fclose(pathfile);
+                       if (mount(hostpath, path, 0, MS_BIND, NULL) != 0) {
+                               SYSERROR("Failed bind mounting device %s from host into container",
+                                       d->name);
+                               return -1;
+                       }
                }
        }
        umask(cmask);
@@ -3847,7 +3867,7 @@ int lxc_setup(struct lxc_handler *handler)
                        ERROR("failed to run autodev hooks for container '%s'.", name);
                        return -1;
                }
-               if (setup_autodev(lxc_conf->rootfs.mount)) {
+               if (fill_autodev(lxc_conf->rootfs.mount)) {
                        ERROR("failed to populate /dev in the container");
                        return -1;
                }