return bdev;
}
-struct bdev *bdev_init(struct lxc_conf *conf, const char *src, const char *dst, const char *mntopts)
+static const struct bdev_type *bdev_query(const char *src)
{
int i;
- struct bdev *bdev;
-
for (i=0; i<numbdevs; i++) {
int r;
r = bdevs[i].ops->detect(src);
if (i == numbdevs)
return NULL;
+ return &bdevs[i];
+}
+
+struct bdev *bdev_init(struct lxc_conf *conf, const char *src, const char *dst, const char *mntopts)
+{
+ struct bdev *bdev;
+ const struct bdev_type *q;
+
+ q = bdev_query(src);
+ if (!q)
+ return NULL;
+
bdev = malloc(sizeof(struct bdev));
if (!bdev)
return NULL;
memset(bdev, 0, sizeof(struct bdev));
- bdev->ops = bdevs[i].ops;
- bdev->type = bdevs[i].name;
+ bdev->ops = q->ops;
+ bdev->type = q->name;
if (mntopts)
bdev->mntopts = strdup(mntopts);
if (src)
*p1 = '\0';
return p;
}
+
+bool rootfs_is_blockdev(struct lxc_conf *conf)
+{
+ const struct bdev_type *q;
+ struct stat st;
+ int ret;
+
+ ret = stat(conf->rootfs.path, &st);
+ if (ret == 0 && S_ISBLK(st.st_mode))
+ return true;
+ q = bdev_query(conf->rootfs.path);
+ if (!q)
+ return false;
+ if (strcmp(q->name, "lvm") == 0 ||
+ strcmp(q->name, "loop") == 0 ||
+ strcmp(q->name, "nbd") == 0)
+ return true;
+ return false;
+}
free(line);
}
-int lxc_setup(struct lxc_handler *handler)
+/*
+ * This does the work of remounting / if it is shared, calling the
+ * container pre-mount hooks, and mounting the rootfs.
+ */
+int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath)
{
- const char *name = handler->name;
- struct lxc_conf *lxc_conf = handler->conf;
- const char *lxcpath = handler->lxcpath;
- void *data = handler->data;
+ if (conf->rootfs_setup) {
+ /*
+ * rootfs was set up in another namespace. bind-mount it
+ * to give us a mount in our own ns so we can pivot_root to it
+ */
+ const char *path = conf->rootfs.mount;
+ if (mount(path, path, "rootfs", MS_BIND, NULL) < 0) {
+ ERROR("Failed to bind-mount container / onto itself");
+ return false;
+ }
+ }
if (detect_ramfs_rootfs()) {
- if (chroot_into_slave(lxc_conf)) {
+ if (chroot_into_slave(conf)) {
ERROR("Failed to chroot into slave /");
return -1;
}
remount_all_slave();
+ if (run_lxc_hooks(name, "pre-mount", conf, lxcpath, NULL)) {
+ ERROR("failed to run pre-mount hooks for container '%s'.", name);
+ return -1;
+ }
+
+ if (setup_rootfs(conf)) {
+ ERROR("failed to setup rootfs for '%s'", name);
+ return -1;
+ }
+
+ conf->rootfs_setup = true;
+ return 0;
+}
+
+int lxc_setup(struct lxc_handler *handler)
+{
+ const char *name = handler->name;
+ struct lxc_conf *lxc_conf = handler->conf;
+ const char *lxcpath = handler->lxcpath;
+ void *data = handler->data;
+
+ if (do_rootfs_setup(lxc_conf, name, lxcpath) < 0) {
+ ERROR("Error setting up rootfs mount after spawn");
+ return -1;
+ }
+
if (lxc_conf->inherit_ns_fd[LXC_NS_UTS] == -1) {
if (setup_utsname(lxc_conf->utsname)) {
ERROR("failed to setup the utsname for '%s'", name);
return -1;
}
- if (run_lxc_hooks(name, "pre-mount", lxc_conf, lxcpath, NULL)) {
- ERROR("failed to run pre-mount hooks for container '%s'.", name);
- return -1;
- }
-
- if (setup_rootfs(lxc_conf)) {
- ERROR("failed to setup rootfs for '%s'", name);
- return -1;
- }
-
if (lxc_conf->autodev < 0) {
lxc_conf->autodev = check_autodev(lxc_conf->rootfs.mount, data);
}
goto out_fini_nonet;
}
+ if (geteuid() == 0 && !lxc_list_empty(&conf->id_map)) {
+ /* if the backing store is a device, mount it here and now */
+ if (rootfs_is_blockdev(conf)) {
+ if (unshare(CLONE_NEWNS) < 0) {
+ ERROR("Error unsharing mounts");
+ goto out_fini_nonet;
+ }
+ if (do_rootfs_setup(conf, name, lxcpath) < 0) {
+ ERROR("Error setting up rootfs mount as root before spawn");
+ goto out_fini_nonet;
+ }
+ INFO("Set up container rootfs as host root");
+ }
+ }
+
err = lxc_spawn(handler);
if (err) {
ERROR("failed to spawn '%s'", name);