[lxc-devel] [lxc/master] [WIP] deprecate lxc.rootfs.backend
brauner on Github
lxc-bot at linuxcontainers.org
Sat Jul 1 22:44:57 UTC 2017
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20170701/3ba2e224/attachment.bin>
-------------- next part --------------
From d97d4f177282a1d96dfab45ab64333d12d4d0a54 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sat, 1 Jul 2017 17:02:13 +0200
Subject: [PATCH 1/9] storage: deprecate lxc.rootfs.backend
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
src/lxc/bdev/bdev.c | 41 +++++++++++++++++++++--------------------
src/lxc/bdev/lxcaufs.c | 5 +++--
src/lxc/bdev/lxcbtrfs.c | 5 ++++-
src/lxc/bdev/lxcdir.c | 5 +++--
src/lxc/bdev/lxcloop.c | 2 +-
src/lxc/bdev/lxclvm.c | 4 ++--
src/lxc/bdev/lxcnbd.c | 3 ++-
src/lxc/bdev/lxcoverlay.c | 8 ++++++--
src/lxc/bdev/lxcrbd.c | 6 +++++-
src/lxc/bdev/lxczfs.c | 3 +++
src/lxc/confile.c | 22 +++++++---------------
src/lxc/lxccontainer.c | 30 ++++++++++--------------------
12 files changed, 67 insertions(+), 67 deletions(-)
diff --git a/src/lxc/bdev/bdev.c b/src/lxc/bdev/bdev.c
index 44c4e0423..55abefa38 100644
--- a/src/lxc/bdev/bdev.c
+++ b/src/lxc/bdev/bdev.c
@@ -187,11 +187,11 @@ struct bdev_type {
};
static const struct bdev_type bdevs[] = {
+ { .name = "dir", .ops = &dir_ops, },
{ .name = "zfs", .ops = &zfs_ops, },
{ .name = "lvm", .ops = &lvm_ops, },
{ .name = "rbd", .ops = &rbd_ops, },
{ .name = "btrfs", .ops = &btrfs_ops, },
- { .name = "dir", .ops = &dir_ops, },
{ .name = "aufs", .ops = &aufs_ops, },
{ .name = "overlayfs", .ops = &ovl_ops, },
{ .name = "loop", .ops = &loop_ops, },
@@ -890,40 +890,41 @@ static struct bdev *bdev_get(const char *type)
static const struct bdev_type *get_bdev_by_name(const char *name)
{
- size_t i;
+ size_t i, cmplen;
- for (i = 0; i < numbdevs; i++) {
- if (strcmp(bdevs[i].name, name) == 0)
- return &bdevs[i];
- }
+ cmplen = strcspn(name, ":");
+ if (cmplen == 0)
+ return NULL;
- ERROR("Backing store %s unknown but not caught earlier\n", name);
- return NULL;
+ for (i = 0; i < numbdevs; i++)
+ if (strncmp(bdevs[i].name, name, cmplen) == 0)
+ break;
+
+ if (i == numbdevs)
+ return NULL;
+
+ DEBUG("Detected rootfs type \"%s\"", bdevs[i].name);
+ return &bdevs[i];
}
static const struct bdev_type *bdev_query(struct lxc_conf *conf,
const char *src)
{
size_t i;
+ const struct bdev_type *bdev;
- if (conf->rootfs.bdev_type) {
- DEBUG("config file specified rootfs type \"%s\"",
- conf->rootfs.bdev_type);
- return get_bdev_by_name(conf->rootfs.bdev_type);
- }
+ bdev = get_bdev_by_name(src);
+ if (bdev)
+ return bdev;
- for (i = 0; i < numbdevs; i++) {
- int r;
- r = bdevs[i].ops->detect(src);
- if (r)
+ for (i = 0; i < numbdevs; i++)
+ if (bdevs[i].ops->detect(src))
break;
- }
if (i == numbdevs)
return NULL;
- DEBUG("detected rootfs type \"%s\"", bdevs[i].name);
-
+ DEBUG("Detected rootfs type \"%s\"", bdevs[i].name);
return &bdevs[i];
}
diff --git a/src/lxc/bdev/lxcaufs.c b/src/lxc/bdev/lxcaufs.c
index fd5e97503..481b62ffe 100644
--- a/src/lxc/bdev/lxcaufs.c
+++ b/src/lxc/bdev/lxcaufs.c
@@ -229,8 +229,9 @@ int aufs_destroy(struct bdev *orig)
int aufs_detect(const char *path)
{
- if (strncmp(path, "aufs:", 5) == 0)
- return 1; // take their word for it
+ if (!strncmp(path, "aufs:", 5))
+ return 1;
+
return 0;
}
diff --git a/src/lxc/bdev/lxcbtrfs.c b/src/lxc/bdev/lxcbtrfs.c
index 9eaec4a2a..bc0e80502 100644
--- a/src/lxc/bdev/lxcbtrfs.c
+++ b/src/lxc/bdev/lxcbtrfs.c
@@ -174,10 +174,13 @@ int btrfs_detect(const char *path)
struct stat st;
int ret;
+ if (!strncmp(path, "btrfs:", 6))
+ return 1;
+
if (!is_btrfs_fs(path))
return 0;
- // and make sure it's a subvolume.
+ /* make sure it's a subvolume */
ret = stat(path, &st);
if (ret < 0)
return 0;
diff --git a/src/lxc/bdev/lxcdir.c b/src/lxc/bdev/lxcdir.c
index fb258405e..be897bb77 100644
--- a/src/lxc/bdev/lxcdir.c
+++ b/src/lxc/bdev/lxcdir.c
@@ -96,8 +96,9 @@ int dir_destroy(struct bdev *orig)
int dir_detect(const char *path)
{
- if (strncmp(path, "dir:", 4) == 0)
- return 1; // take their word for it
+ if (!strncmp(path, "dir:", 4))
+ return 1;
+
if (is_dir(path))
return 1;
return 0;
diff --git a/src/lxc/bdev/lxcloop.c b/src/lxc/bdev/lxcloop.c
index 65d49525d..9cd63b01a 100644
--- a/src/lxc/bdev/lxcloop.c
+++ b/src/lxc/bdev/lxcloop.c
@@ -161,7 +161,7 @@ int loop_detect(const char *path)
int ret;
struct stat s;
- if (strncmp(path, "loop:", 5) == 0)
+ if (!strncmp(path, "loop:", 5))
return 1;
ret = stat(path, &s);
diff --git a/src/lxc/bdev/lxclvm.c b/src/lxc/bdev/lxclvm.c
index 35c5c92f3..407c55ff8 100644
--- a/src/lxc/bdev/lxclvm.c
+++ b/src/lxc/bdev/lxclvm.c
@@ -134,8 +134,8 @@ int lvm_detect(const char *path)
int ret;
struct stat statbuf;
- if (strncmp(path, "lvm:", 4) == 0)
- return 1; // take their word for it
+ if (!strncmp(path, "lvm:", 4))
+ return 1;
ret = stat(path, &statbuf);
if (ret != 0)
diff --git a/src/lxc/bdev/lxcnbd.c b/src/lxc/bdev/lxcnbd.c
index 8a320d209..a9bf4f186 100644
--- a/src/lxc/bdev/lxcnbd.c
+++ b/src/lxc/bdev/lxcnbd.c
@@ -107,8 +107,9 @@ int nbd_destroy(struct bdev *orig)
int nbd_detect(const char *path)
{
- if (strncmp(path, "nbd:", 4) == 0)
+ if (!strncmp(path, "nbd:", 4))
return 1;
+
return 0;
}
diff --git a/src/lxc/bdev/lxcoverlay.c b/src/lxc/bdev/lxcoverlay.c
index 65daed8db..377cf9263 100644
--- a/src/lxc/bdev/lxcoverlay.c
+++ b/src/lxc/bdev/lxcoverlay.c
@@ -298,8 +298,12 @@ int ovl_destroy(struct bdev *orig)
int ovl_detect(const char *path)
{
- if (strncmp(path, "overlayfs:", 10) == 0)
- return 1; // take their word for it
+ if (!strncmp(path, "overlayfs:", 10))
+ return 1;
+
+ if (!strncmp(path, "overlay:", 8))
+ return 1;
+
return 0;
}
diff --git a/src/lxc/bdev/lxcrbd.c b/src/lxc/bdev/lxcrbd.c
index b6abb75e4..133b67e52 100644
--- a/src/lxc/bdev/lxcrbd.c
+++ b/src/lxc/bdev/lxcrbd.c
@@ -154,8 +154,12 @@ int rbd_destroy(struct bdev *orig)
int rbd_detect(const char *path)
{
- if ( memcmp(path, "/dev/rbd/", 9) == 0)
+ if (!strncmp(path, "rbd:", 4))
return 1;
+
+ if (!strncmp(path, "/dev/rbd/", 9))
+ return 1;
+
return 0;
}
diff --git a/src/lxc/bdev/lxczfs.c b/src/lxc/bdev/lxczfs.c
index 641294560..b8f3c1405 100644
--- a/src/lxc/bdev/lxczfs.c
+++ b/src/lxc/bdev/lxczfs.c
@@ -70,6 +70,9 @@ int zfs_list_entry(const char *path, char *output, size_t inlen)
int zfs_detect(const char *path)
{
+ if (!strncmp(path, "zfs:", 4))
+ return 1;
+
char *output = malloc(LXC_LOG_BUFFER_SIZE);
if (!output) {
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 3c0b3b1d0..7fc97f386 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -162,7 +162,12 @@ static struct lxc_config_t config[] = {
{ "lxc.mount", set_config_fstab, get_config_fstab, clr_config_fstab, },
{ "lxc.rootfs.mount", set_config_rootfs_mount, get_config_rootfs_mount, clr_config_rootfs_mount, },
{ "lxc.rootfs.options", set_config_rootfs_options, get_config_rootfs_options, clr_config_rootfs_options, },
+
+ /* REMOVE IN LXC 3.0
+ legacy rootfs.backend key
+ */
{ "lxc.rootfs.backend", set_config_rootfs_backend, get_config_rootfs_backend, clr_config_rootfs_backend, },
+
{ "lxc.rootfs", set_config_rootfs, get_config_rootfs, clr_config_rootfs, },
/* REMOVE IN LXC 3.0
@@ -2051,18 +2056,7 @@ static int set_config_rootfs_options(const char *key, const char *value,
static int set_config_rootfs_backend(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data)
{
- if (lxc_config_value_empty(value)) {
- free(lxc_conf->rootfs.bdev_type);
- lxc_conf->rootfs.bdev_type = NULL;
- return 0;
- }
-
- if (!is_valid_bdev_type(value)) {
- ERROR("Bad rootfs.backend: '%s'", value);
- return -1;
- }
-
- return set_config_string_item(&lxc_conf->rootfs.bdev_type, value);
+ return 0;
}
static int set_config_uts_name(const char *key, const char *value,
@@ -3053,7 +3047,7 @@ static int get_config_rootfs_options(const char *key, char *retv, int inlen,
static int get_config_rootfs_backend(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data)
{
- return lxc_get_conf_str(retv, inlen, c->rootfs.bdev_type);
+ return 0;
}
static int get_config_uts_name(const char *key, char *retv, int inlen,
@@ -3473,8 +3467,6 @@ static inline int clr_config_rootfs_options(const char *key, struct lxc_conf *c,
static inline int clr_config_rootfs_backend(const char *key, struct lxc_conf *c,
void *data)
{
- free(c->rootfs.bdev_type);
- c->rootfs.bdev_type = NULL;
return 0;
}
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index ae0e708d2..26ae25410 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -1043,7 +1043,7 @@ static bool create_container_dir(struct lxc_container *c)
* it returns a mounted bdev on success, NULL on error.
*/
static struct bdev *do_bdev_create(struct lxc_container *c, const char *type,
- struct bdev_specs *specs)
+ struct bdev_specs *specs)
{
char *dest;
size_t len;
@@ -1051,7 +1051,7 @@ static struct bdev *do_bdev_create(struct lxc_container *c, const char *type,
int ret;
/* rootfs.path or lxcpath/lxcname/rootfs */
- if (c->lxc_conf->rootfs.path && access(c->lxc_conf->rootfs.path, F_OK) == 0) {
+ if (c->lxc_conf->rootfs.path && !access(c->lxc_conf->rootfs.path, F_OK)) {
const char *rpath = c->lxc_conf->rootfs.path;
len = strlen(rpath) + 1;
dest = alloca(len);
@@ -1071,12 +1071,15 @@ static struct bdev *do_bdev_create(struct lxc_container *c, const char *type,
return NULL;
}
- do_lxcapi_set_config_item(c, "lxc.rootfs", bdev->src);
- do_lxcapi_set_config_item(c, "lxc.rootfs.backend", bdev->type);
-
- /* if we are not root, chown the rootfs dir to root in the
- * target uidmap */
+ if (!c->set_config_item(c, "lxc.rootfs", bdev->src)) {
+ ERROR("Failed to set config item \"lxc.rootfs\" to \"%s\"",
+ bdev->src);
+ return NULL;
+ }
+ /* If we are not root, chown the rootfs dir to root in the
+ * target uidmap.
+ */
if (geteuid() != 0 || (c->lxc_conf && !lxc_list_empty(&c->lxc_conf->id_map))) {
if (chown_mapped_root(bdev->dest, c->lxc_conf) < 0) {
ERROR("Error chowning %s to container root", bdev->dest);
@@ -2924,20 +2927,12 @@ static int copy_storage(struct lxc_container *c0, struct lxc_container *c,
/* Set new rootfs. */
free(c->lxc_conf->rootfs.path);
c->lxc_conf->rootfs.path = strdup(bdev->src);
-
- /* Set new bdev type. */
- free(c->lxc_conf->rootfs.bdev_type);
- c->lxc_conf->rootfs.bdev_type = strdup(bdev->type);
bdev_put(bdev);
if (!c->lxc_conf->rootfs.path) {
ERROR("Out of memory while setting storage path.");
return -1;
}
- if (!c->lxc_conf->rootfs.bdev_type) {
- ERROR("Out of memory while setting rootfs backend.");
- return -1;
- }
/* Append a new lxc.rootfs entry to the unexpanded config. */
clear_unexp_config_line(c->lxc_conf, "lxc.rootfs", false);
@@ -2949,11 +2944,6 @@ static int copy_storage(struct lxc_container *c0, struct lxc_container *c,
/* Append a new lxc.rootfs.backend entry to the unexpanded config. */
clear_unexp_config_line(c->lxc_conf, "lxc.rootfs.backend", false);
- if (!do_append_unexp_config_line(c->lxc_conf, "lxc.rootfs.backend",
- c->lxc_conf->rootfs.bdev_type)) {
- ERROR("Error saving new rootfs backend to cloned config.");
- return -1;
- }
if (flags & LXC_CLONE_SNAPSHOT)
copy_rdepends(c, c0);
From cb5e905919955d367e3788dc905bdf1392c70317 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sat, 1 Jul 2017 18:15:59 +0200
Subject: [PATCH 2/9] storage: add storage_utils.{c.h}
non-functional changes
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
src/lxc/Makefile.am | 2 +
src/lxc/bdev/bdev.c | 572 +++++--------------------------------------
src/lxc/bdev/bdev.h | 22 +-
src/lxc/bdev/lxcloop.c | 1 +
src/lxc/bdev/lxclvm.c | 1 +
src/lxc/bdev/lxcnbd.c | 1 +
src/lxc/bdev/lxcrbd.c | 1 +
src/lxc/bdev/storage_utils.c | 480 ++++++++++++++++++++++++++++++++++++
src/lxc/bdev/storage_utils.h | 54 ++++
src/lxc/start.c | 2 +
src/lxc/tools/lxc_create.c | 1 +
11 files changed, 611 insertions(+), 526 deletions(-)
create mode 100644 src/lxc/bdev/storage_utils.c
create mode 100644 src/lxc/bdev/storage_utils.h
diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index ea1982ea7..54fad1226 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -17,6 +17,7 @@ noinst_HEADERS = \
bdev/lxcrbd.h \
bdev/lxcrsync.h \
bdev/lxczfs.h \
+ bdev/storage_utils.h \
cgroups/cgroup.h \
caps.h \
conf.h \
@@ -86,6 +87,7 @@ liblxc_la_SOURCES = \
bdev/lxcrbd.c bdev/lxcrbd.h \
bdev/lxcrsync.c bdev/lxcrsync.h \
bdev/lxczfs.c bdev/lxczfs.h \
+ bdev/storage_utils.c bdev/storage_utils.h \
cgroups/cgfs.c \
cgroups/cgfsng.c \
cgroups/cgroup.c cgroups/cgroup.h \
diff --git a/src/lxc/bdev/bdev.c b/src/lxc/bdev/bdev.c
index 55abefa38..ea1bca17a 100644
--- a/src/lxc/bdev/bdev.c
+++ b/src/lxc/bdev/bdev.c
@@ -65,6 +65,7 @@
#include "lxczfs.h"
#include "namespace.h"
#include "parse.h"
+#include "storage_utils.h"
#include "utils.h"
#ifndef BLKGETSIZE64
@@ -200,86 +201,85 @@ static const struct bdev_type bdevs[] = {
static const size_t numbdevs = sizeof(bdevs) / sizeof(struct bdev_type);
-/* helpers */
-static const struct bdev_type *bdev_query(struct lxc_conf *conf,
- const char *src);
-static struct bdev *bdev_get(const char *type);
-static struct bdev *do_bdev_create(const char *dest, const char *type,
- const char *cname, struct bdev_specs *specs);
-static int find_fstype_cb(char *buffer, void *data);
-static char *linkderef(char *path, char *dest);
-static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap,
- bool maybesnap);
-
-/* the bulk of this needs to become a common helper */
-char *dir_new_path(char *src, const char *oldname, const char *name,
- const char *oldpath, const char *lxcpath)
+static const struct bdev_type *get_bdev_by_name(const char *name)
{
- char *ret, *p, *p2;
- int l1, l2, nlen;
-
- nlen = strlen(src) + 1;
- l1 = strlen(oldpath);
- p = src;
- /* if src starts with oldpath, look for oldname only after
- * that path */
- if (strncmp(src, oldpath, l1) == 0) {
- p += l1;
- nlen += (strlen(lxcpath) - l1);
- }
- l2 = strlen(oldname);
- while ((p = strstr(p, oldname)) != NULL) {
- p += l2;
- nlen += strlen(name) - l2;
- }
+ size_t i, cmplen;
- ret = malloc(nlen);
- if (!ret)
+ cmplen = strcspn(name, ":");
+ if (cmplen == 0)
return NULL;
- p = ret;
- if (strncmp(src, oldpath, l1) == 0) {
- p += sprintf(p, "%s", lxcpath);
- src += l1;
- }
+ for (i = 0; i < numbdevs; i++)
+ if (strncmp(bdevs[i].name, name, cmplen) == 0)
+ break;
- while ((p2 = strstr(src, oldname)) != NULL) {
- strncpy(p, src, p2 - src); // copy text up to oldname
- p += p2 - src; // move target pointer (p)
- p += sprintf(p, "%s",
- name); // print new name in place of oldname
- src = p2 + l2; // move src to end of oldname
- }
- sprintf(p, "%s", src); // copy the rest of src
- return ret;
+ if (i == numbdevs)
+ return NULL;
+
+ DEBUG("Detected rootfs type \"%s\"", bdevs[i].name);
+ return &bdevs[i];
}
-/*
- * attach_block_device returns true if all went well,
- * meaning either a block device was attached or was not
- * needed. It returns false if something went wrong and
- * container startup should be stopped.
- */
-bool attach_block_device(struct lxc_conf *conf)
+const struct bdev_type *bdev_query(struct lxc_conf *conf, const char *src)
{
- char *path;
+ size_t i;
+ const struct bdev_type *bdev;
- if (!conf->rootfs.path)
- return true;
+ bdev = get_bdev_by_name(src);
+ if (bdev)
+ return bdev;
- path = conf->rootfs.path;
- if (!requires_nbd(path))
- return true;
+ for (i = 0; i < numbdevs; i++)
+ if (bdevs[i].ops->detect(src))
+ break;
- path = strchr(path, ':');
- if (!path)
- return false;
+ if (i == numbdevs)
+ return NULL;
- path++;
- if (!attach_nbd(path, conf))
- return false;
+ DEBUG("Detected rootfs type \"%s\"", bdevs[i].name);
+ return &bdevs[i];
+}
+
+struct bdev *bdev_get(const char *type)
+{
+ size_t i;
+ struct bdev *bdev;
+
+ for (i = 0; i < numbdevs; i++) {
+ if (strcmp(bdevs[i].name, type) == 0)
+ break;
+ }
+
+ if (i == numbdevs)
+ 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;
+
+ return bdev;
+}
+
+static struct bdev *do_bdev_create(const char *dest, const char *type,
+ const char *cname, struct bdev_specs *specs)
+{
+
+ struct bdev *bdev;
+
+ bdev = bdev_get(type);
+ if (!bdev)
+ return NULL;
- return true;
+ if (bdev->ops->create(bdev, dest, cname, specs) < 0) {
+ bdev_put(bdev);
+ return NULL;
+ }
+
+ return bdev;
}
bool bdev_can_backup(struct lxc_conf *conf)
@@ -529,29 +529,6 @@ bool bdev_destroy(struct lxc_conf *conf)
return ret;
}
-int bdev_destroy_wrapper(void *data)
-{
- struct lxc_conf *conf = data;
-
- if (setgid(0) < 0) {
- ERROR("Failed to setgid to 0");
- return -1;
- }
-
- if (setgroups(0, NULL) < 0)
- WARN("Failed to clear groups");
-
- if (setuid(0) < 0) {
- ERROR("Failed to setuid to 0");
- return -1;
- }
-
- if (!bdev_destroy(conf))
- return -1;
-
- return 0;
-}
-
struct bdev *bdev_init(struct lxc_conf *conf, const char *src, const char *dst,
const char *mntopts)
{
@@ -607,219 +584,6 @@ void bdev_put(struct bdev *bdev)
free(bdev);
}
-/*
- * return block size of dev->src in units of bytes
- */
-int blk_getsize(struct bdev *bdev, uint64_t *size)
-{
- int fd, ret;
- char *path = bdev->src;
-
- if (strcmp(bdev->type, "loop") == 0)
- path = bdev->src + 5;
-
- fd = open(path, O_RDONLY);
- if (fd < 0)
- return -1;
-
- ret = ioctl(fd, BLKGETSIZE64, size); // size of device in bytes
- close(fd);
- return ret;
-}
-
-void detach_block_device(struct lxc_conf *conf)
-{
- if (conf->nbd_idx != -1)
- detach_nbd_idx(conf->nbd_idx);
-}
-
-/*
- * Given a bdev (presumably blockdev-based), detect the fstype
- * by trying mounting (in a private mntns) it.
- * @bdev: bdev to investigate
- * @type: preallocated char* in which to write the fstype
- * @len: length of passed in char*
- * Returns length of fstype, of -1 on error
- */
-int detect_fs(struct bdev *bdev, char *type, int len)
-{
- int p[2], ret;
- size_t linelen;
- pid_t pid;
- FILE *f;
- char *sp1, *sp2, *sp3, *line = NULL;
- char *srcdev;
-
- if (!bdev || !bdev->src || !bdev->dest)
- return -1;
-
- srcdev = bdev->src;
- if (strcmp(bdev->type, "loop") == 0)
- srcdev = bdev->src + 5;
-
- ret = pipe(p);
- if (ret < 0)
- return -1;
-
- if ((pid = fork()) < 0)
- return -1;
-
- if (pid > 0) {
- int status;
- close(p[1]);
- memset(type, 0, len);
- ret = read(p[0], type, len - 1);
- close(p[0]);
- if (ret < 0) {
- SYSERROR("error reading from pipe");
- wait(&status);
- return -1;
- } else if (ret == 0) {
- ERROR("child exited early - fstype not found");
- wait(&status);
- return -1;
- }
- wait(&status);
- type[len - 1] = '\0';
- INFO("detected fstype %s for %s", type, srcdev);
- return ret;
- }
-
- if (unshare(CLONE_NEWNS) < 0)
- exit(1);
-
- if (detect_shared_rootfs()) {
- if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL)) {
- SYSERROR("Failed to make / rslave");
- ERROR("Continuing...");
- }
- }
-
- ret = mount_unknown_fs(srcdev, bdev->dest, bdev->mntopts);
- if (ret < 0) {
- ERROR("failed mounting %s onto %s to detect fstype", srcdev,
- bdev->dest);
- exit(1);
- }
-
- // if symlink, get the real dev name
- char devpath[MAXPATHLEN];
- char *l = linkderef(srcdev, devpath);
- if (!l)
- exit(1);
- f = fopen("/proc/self/mounts", "r");
- if (!f)
- exit(1);
-
- while (getline(&line, &linelen, f) != -1) {
- sp1 = strchr(line, ' ');
- if (!sp1)
- exit(1);
- *sp1 = '\0';
- if (strcmp(line, l))
- continue;
- sp2 = strchr(sp1 + 1, ' ');
- if (!sp2)
- exit(1);
- *sp2 = '\0';
- sp3 = strchr(sp2 + 1, ' ');
- if (!sp3)
- exit(1);
- *sp3 = '\0';
- sp2++;
- if (write(p[1], sp2, strlen(sp2)) != strlen(sp2))
- exit(1);
-
- exit(0);
- }
-
- exit(1);
-}
-
-int do_mkfs_exec_wrapper(void *args)
-{
- int ret;
- char *mkfs;
- char **data = args;
- /* strlen("mkfs.")
- * +
- * strlen(data[0])
- * +
- * \0
- */
- size_t len = 5 + strlen(data[0]) + 1;
-
- mkfs = malloc(len);
- if (!mkfs)
- return -1;
-
- ret = snprintf(mkfs, len, "mkfs.%s", data[0]);
- if (ret < 0 || (size_t)ret >= len) {
- free(mkfs);
- return -1;
- }
-
- TRACE("executing \"%s %s\"", mkfs, data[1]);
- execlp(mkfs, mkfs, data[1], (char *)NULL);
- SYSERROR("failed to run \"%s %s \"", mkfs, data[1]);
- return -1;
-}
-
-/*
- * This will return 1 for physical disks, qemu-nbd, loop, etc right now only lvm
- * is a block device.
- */
-int is_blktype(struct bdev *b)
-{
- if (strcmp(b->type, "lvm") == 0)
- return 1;
-
- return 0;
-}
-
-int mount_unknown_fs(const char *rootfs, const char *target,
- const char *options)
-{
- size_t i;
- int ret;
- struct cbarg {
- const char *rootfs;
- const char *target;
- const char *options;
- } cbarg = {
- .rootfs = rootfs,
- .target = target,
- .options = options,
- };
-
- /*
- * find the filesystem type with brute force:
- * first we check with /etc/filesystems, in case the modules
- * are auto-loaded and fall back to the supported kernel fs
- */
- char *fsfile[] = {
- "/etc/filesystems",
- "/proc/filesystems",
- };
-
- for (i = 0; i < sizeof(fsfile) / sizeof(fsfile[0]); i++) {
- if (access(fsfile[i], F_OK))
- continue;
-
- ret = lxc_file_for_each_line(fsfile[i], find_fstype_cb, &cbarg);
- if (ret < 0) {
- ERROR("failed to parse '%s'", fsfile[i]);
- return -1;
- }
-
- if (ret)
- return 0;
- }
-
- ERROR("failed to determine fs type for '%s'", rootfs);
- return -1;
-}
-
bool rootfs_is_blockdev(struct lxc_conf *conf)
{
const struct bdev_type *q;
@@ -845,205 +609,3 @@ bool rootfs_is_blockdev(struct lxc_conf *conf)
return false;
}
-
-static struct bdev *do_bdev_create(const char *dest, const char *type,
- const char *cname, struct bdev_specs *specs)
-{
-
- struct bdev *bdev;
-
- bdev = bdev_get(type);
- if (!bdev)
- return NULL;
-
- if (bdev->ops->create(bdev, dest, cname, specs) < 0) {
- bdev_put(bdev);
- return NULL;
- }
-
- return bdev;
-}
-
-static struct bdev *bdev_get(const char *type)
-{
- size_t i;
- struct bdev *bdev;
-
- for (i = 0; i < numbdevs; i++) {
- if (strcmp(bdevs[i].name, type) == 0)
- break;
- }
-
- if (i == numbdevs)
- 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;
-
- return bdev;
-}
-
-static const struct bdev_type *get_bdev_by_name(const char *name)
-{
- size_t i, cmplen;
-
- cmplen = strcspn(name, ":");
- if (cmplen == 0)
- return NULL;
-
- for (i = 0; i < numbdevs; i++)
- if (strncmp(bdevs[i].name, name, cmplen) == 0)
- break;
-
- if (i == numbdevs)
- return NULL;
-
- DEBUG("Detected rootfs type \"%s\"", bdevs[i].name);
- return &bdevs[i];
-}
-
-static const struct bdev_type *bdev_query(struct lxc_conf *conf,
- const char *src)
-{
- size_t i;
- const struct bdev_type *bdev;
-
- bdev = get_bdev_by_name(src);
- if (bdev)
- return bdev;
-
- for (i = 0; i < numbdevs; i++)
- if (bdevs[i].ops->detect(src))
- break;
-
- if (i == numbdevs)
- return NULL;
-
- DEBUG("Detected rootfs type \"%s\"", bdevs[i].name);
- return &bdevs[i];
-}
-
-/*
- * These are copied from conf.c. However as conf.c will be moved to using
- * the callback system, they can be pulled from there eventually, so we
- * don't need to pollute utils.c with these low level functions
- */
-static int find_fstype_cb(char *buffer, void *data)
-{
- struct cbarg {
- const char *rootfs;
- const char *target;
- const char *options;
- } *cbarg = data;
-
- unsigned long mntflags;
- char *mntdata;
- char *fstype;
-
- /* we don't try 'nodev' entries */
- if (strstr(buffer, "nodev"))
- return 0;
-
- fstype = buffer;
- fstype += lxc_char_left_gc(fstype, strlen(fstype));
- fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0';
-
- DEBUG("trying to mount '%s'->'%s' with fstype '%s'", cbarg->rootfs,
- cbarg->target, fstype);
-
- if (parse_mntopts(cbarg->options, &mntflags, &mntdata) < 0) {
- free(mntdata);
- return 0;
- }
-
- if (mount(cbarg->rootfs, cbarg->target, fstype, mntflags, mntdata)) {
- DEBUG("mount failed with error: %s", strerror(errno));
- free(mntdata);
- return 0;
- }
-
- free(mntdata);
-
- INFO("mounted '%s' on '%s', with fstype '%s'", cbarg->rootfs,
- cbarg->target, fstype);
-
- return 1;
-}
-
-static char *linkderef(char *path, char *dest)
-{
- struct stat sbuf;
- ssize_t ret;
-
- ret = stat(path, &sbuf);
- if (ret < 0)
- return NULL;
-
- if (!S_ISLNK(sbuf.st_mode))
- return path;
-
- ret = readlink(path, dest, MAXPATHLEN);
- if (ret < 0) {
- SYSERROR("error reading link %s", path);
- return NULL;
- } else if (ret >= MAXPATHLEN) {
- ERROR("link in %s too long", path);
- return NULL;
- }
- dest[ret] = '\0';
-
- return dest;
-}
-
-/*
- * is an unprivileged user allowed to make this kind of snapshot
- */
-static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap,
- bool maybesnap)
-{
- if (!t) {
- // new type will be same as original
- // (unless snap && b->type == dir, in which case it will be
- // overlayfs -- which is also allowed)
- if (strcmp(b->type, "dir") == 0 ||
- strcmp(b->type, "aufs") == 0 ||
- strcmp(b->type, "overlayfs") == 0 ||
- strcmp(b->type, "btrfs") == 0 ||
- strcmp(b->type, "loop") == 0)
- return true;
-
- return false;
- }
-
- // unprivileged users can copy and snapshot dir, overlayfs,
- // and loop. In particular, not zfs, btrfs, or lvm.
- if (strcmp(t, "dir") == 0 ||
- strcmp(t, "aufs") == 0 ||
- strcmp(t, "overlayfs") == 0 ||
- strcmp(t, "btrfs") == 0 ||
- strcmp(t, "loop") == 0)
- return true;
-
- return false;
-}
-
-bool is_valid_bdev_type(const char *type)
-{
- if (strcmp(type, "dir") == 0 ||
- strcmp(type, "btrfs") == 0 ||
- strcmp(type, "aufs") == 0 ||
- strcmp(type, "loop") == 0 ||
- strcmp(type, "lvm") == 0 ||
- strcmp(type, "nbd") == 0 ||
- strcmp(type, "overlayfs") == 0 ||
- strcmp(type, "rbd") == 0 ||
- strcmp(type, "zfs") == 0)
- return true;
-
- return false;
-}
diff --git a/src/lxc/bdev/bdev.h b/src/lxc/bdev/bdev.h
index 1caf3ae72..b723b5080 100644
--- a/src/lxc/bdev/bdev.h
+++ b/src/lxc/bdev/bdev.h
@@ -124,26 +124,6 @@ bool bdev_destroy(struct lxc_conf *conf);
/* callback function to be used with userns_exec_1() */
int bdev_destroy_wrapper(void *data);
-
-/* Some helpers for lvm, rdb, and/or loop:
- * Maybe they should move to a separate implementation and header-file
- * (bdev_utils.{c,h}) which can be included in bdev.c?
- */
-int blk_getsize(struct bdev *bdev, uint64_t *size);
-int detect_fs(struct bdev *bdev, char *type, int len);
-int do_mkfs_exec_wrapper(void *args);
-int is_blktype(struct bdev *b);
-int mount_unknown_fs(const char *rootfs, const char *target,
- const char *options);
-bool rootfs_is_blockdev(struct lxc_conf *conf);
-
-/*
- * these are really for qemu-nbd support, as container shutdown
- * must explicitly request device detach.
- */
-bool attach_block_device(struct lxc_conf *conf);
-void detach_block_device(struct lxc_conf *conf);
-
-bool is_valid_bdev_type(const char *type);
+extern bool rootfs_is_blockdev(struct lxc_conf *conf);
#endif // __LXC_BDEV_H
diff --git a/src/lxc/bdev/lxcloop.c b/src/lxc/bdev/lxcloop.c
index 9cd63b01a..017ead53a 100644
--- a/src/lxc/bdev/lxcloop.c
+++ b/src/lxc/bdev/lxcloop.c
@@ -34,6 +34,7 @@
#include "bdev.h"
#include "log.h"
#include "lxcloop.h"
+#include "storage_utils.h"
#include "utils.h"
lxc_log_define(lxcloop, lxc);
diff --git a/src/lxc/bdev/lxclvm.c b/src/lxc/bdev/lxclvm.c
index 407c55ff8..9c329a2f3 100644
--- a/src/lxc/bdev/lxclvm.c
+++ b/src/lxc/bdev/lxclvm.c
@@ -36,6 +36,7 @@
#include "config.h"
#include "log.h"
#include "lxclvm.h"
+#include "storage_utils.h"
#include "utils.h"
/* major()/minor() */
diff --git a/src/lxc/bdev/lxcnbd.c b/src/lxc/bdev/lxcnbd.c
index a9bf4f186..4a55e9fff 100644
--- a/src/lxc/bdev/lxcnbd.c
+++ b/src/lxc/bdev/lxcnbd.c
@@ -34,6 +34,7 @@
#include "bdev.h"
#include "log.h"
#include "lxcnbd.h"
+#include "storage_utils.h"
#include "utils.h"
lxc_log_define(lxcnbd, lxc);
diff --git a/src/lxc/bdev/lxcrbd.c b/src/lxc/bdev/lxcrbd.c
index 133b67e52..8e63c3fd0 100644
--- a/src/lxc/bdev/lxcrbd.c
+++ b/src/lxc/bdev/lxcrbd.c
@@ -31,6 +31,7 @@
#include "bdev.h"
#include "log.h"
+#include "storage_utils.h"
#include "utils.h"
lxc_log_define(lxcrbd, lxc);
diff --git a/src/lxc/bdev/storage_utils.c b/src/lxc/bdev/storage_utils.c
new file mode 100644
index 000000000..6ca6b51ec
--- /dev/null
+++ b/src/lxc/bdev/storage_utils.c
@@ -0,0 +1,480 @@
+/*
+ * lxc: linux Container library
+ *
+ * Copyright © 2017 Canonical Ltd.
+ *
+ * Authors:
+ * Christian Brauner <christian.brauner at ubuntu.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <sched.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include "bdev.h"
+#include "log.h"
+#include "lxcnbd.h"
+#include "parse.h"
+#include "storage_utils.h"
+#include "utils.h"
+
+#ifndef BLKGETSIZE64
+#define BLKGETSIZE64 _IOR(0x12, 114, size_t)
+#endif
+
+lxc_log_define(storage_utils, lxc);
+
+/* the bulk of this needs to become a common helper */
+char *dir_new_path(char *src, const char *oldname, const char *name,
+ const char *oldpath, const char *lxcpath)
+{
+ char *ret, *p, *p2;
+ int l1, l2, nlen;
+
+ nlen = strlen(src) + 1;
+ l1 = strlen(oldpath);
+ p = src;
+ /* if src starts with oldpath, look for oldname only after
+ * that path */
+ if (strncmp(src, oldpath, l1) == 0) {
+ p += l1;
+ nlen += (strlen(lxcpath) - l1);
+ }
+ l2 = strlen(oldname);
+ while ((p = strstr(p, oldname)) != NULL) {
+ p += l2;
+ nlen += strlen(name) - l2;
+ }
+
+ ret = malloc(nlen);
+ if (!ret)
+ return NULL;
+
+ p = ret;
+ if (strncmp(src, oldpath, l1) == 0) {
+ p += sprintf(p, "%s", lxcpath);
+ src += l1;
+ }
+
+ while ((p2 = strstr(src, oldname)) != NULL) {
+ strncpy(p, src, p2 - src); // copy text up to oldname
+ p += p2 - src; // move target pointer (p)
+ p += sprintf(p, "%s",
+ name); // print new name in place of oldname
+ src = p2 + l2; // move src to end of oldname
+ }
+ sprintf(p, "%s", src); // copy the rest of src
+ return ret;
+}
+
+/*
+ * attach_block_device returns true if all went well,
+ * meaning either a block device was attached or was not
+ * needed. It returns false if something went wrong and
+ * container startup should be stopped.
+ */
+bool attach_block_device(struct lxc_conf *conf)
+{
+ char *path;
+
+ if (!conf->rootfs.path)
+ return true;
+
+ path = conf->rootfs.path;
+ if (!requires_nbd(path))
+ return true;
+
+ path = strchr(path, ':');
+ if (!path)
+ return false;
+
+ path++;
+ if (!attach_nbd(path, conf))
+ return false;
+
+ return true;
+}
+
+/*
+ * return block size of dev->src in units of bytes
+ */
+int blk_getsize(struct bdev *bdev, uint64_t *size)
+{
+ int fd, ret;
+ char *path = bdev->src;
+
+ if (strcmp(bdev->type, "loop") == 0)
+ path = bdev->src + 5;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ ret = ioctl(fd, BLKGETSIZE64, size); // size of device in bytes
+ close(fd);
+ return ret;
+}
+
+void detach_block_device(struct lxc_conf *conf)
+{
+ if (conf->nbd_idx != -1)
+ detach_nbd_idx(conf->nbd_idx);
+}
+
+/*
+ * Given a bdev (presumably blockdev-based), detect the fstype
+ * by trying mounting (in a private mntns) it.
+ * @bdev: bdev to investigate
+ * @type: preallocated char* in which to write the fstype
+ * @len: length of passed in char*
+ * Returns length of fstype, of -1 on error
+ */
+int detect_fs(struct bdev *bdev, char *type, int len)
+{
+ int p[2], ret;
+ size_t linelen;
+ pid_t pid;
+ FILE *f;
+ char *sp1, *sp2, *sp3, *line = NULL;
+ char *srcdev;
+
+ if (!bdev || !bdev->src || !bdev->dest)
+ return -1;
+
+ srcdev = bdev->src;
+ if (strcmp(bdev->type, "loop") == 0)
+ srcdev = bdev->src + 5;
+
+ ret = pipe(p);
+ if (ret < 0)
+ return -1;
+
+ if ((pid = fork()) < 0)
+ return -1;
+
+ if (pid > 0) {
+ int status;
+ close(p[1]);
+ memset(type, 0, len);
+ ret = read(p[0], type, len - 1);
+ close(p[0]);
+ if (ret < 0) {
+ SYSERROR("error reading from pipe");
+ wait(&status);
+ return -1;
+ } else if (ret == 0) {
+ ERROR("child exited early - fstype not found");
+ wait(&status);
+ return -1;
+ }
+ wait(&status);
+ type[len - 1] = '\0';
+ INFO("detected fstype %s for %s", type, srcdev);
+ return ret;
+ }
+
+ if (unshare(CLONE_NEWNS) < 0)
+ exit(1);
+
+ if (detect_shared_rootfs()) {
+ if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL)) {
+ SYSERROR("Failed to make / rslave");
+ ERROR("Continuing...");
+ }
+ }
+
+ ret = mount_unknown_fs(srcdev, bdev->dest, bdev->mntopts);
+ if (ret < 0) {
+ ERROR("failed mounting %s onto %s to detect fstype", srcdev,
+ bdev->dest);
+ exit(1);
+ }
+
+ // if symlink, get the real dev name
+ char devpath[MAXPATHLEN];
+ char *l = linkderef(srcdev, devpath);
+ if (!l)
+ exit(1);
+ f = fopen("/proc/self/mounts", "r");
+ if (!f)
+ exit(1);
+
+ while (getline(&line, &linelen, f) != -1) {
+ sp1 = strchr(line, ' ');
+ if (!sp1)
+ exit(1);
+ *sp1 = '\0';
+ if (strcmp(line, l))
+ continue;
+ sp2 = strchr(sp1 + 1, ' ');
+ if (!sp2)
+ exit(1);
+ *sp2 = '\0';
+ sp3 = strchr(sp2 + 1, ' ');
+ if (!sp3)
+ exit(1);
+ *sp3 = '\0';
+ sp2++;
+ if (write(p[1], sp2, strlen(sp2)) != strlen(sp2))
+ exit(1);
+
+ exit(0);
+ }
+
+ exit(1);
+}
+
+int do_mkfs_exec_wrapper(void *args)
+{
+ int ret;
+ char *mkfs;
+ char **data = args;
+ /* strlen("mkfs.")
+ * +
+ * strlen(data[0])
+ * +
+ * \0
+ */
+ size_t len = 5 + strlen(data[0]) + 1;
+
+ mkfs = malloc(len);
+ if (!mkfs)
+ return -1;
+
+ ret = snprintf(mkfs, len, "mkfs.%s", data[0]);
+ if (ret < 0 || (size_t)ret >= len) {
+ free(mkfs);
+ return -1;
+ }
+
+ TRACE("executing \"%s %s\"", mkfs, data[1]);
+ execlp(mkfs, mkfs, data[1], (char *)NULL);
+ SYSERROR("failed to run \"%s %s \"", mkfs, data[1]);
+ return -1;
+}
+
+/*
+ * This will return 1 for physical disks, qemu-nbd, loop, etc right now only lvm
+ * is a block device.
+ */
+int is_blktype(struct bdev *b)
+{
+ if (strcmp(b->type, "lvm") == 0)
+ return 1;
+
+ return 0;
+}
+
+int mount_unknown_fs(const char *rootfs, const char *target,
+ const char *options)
+{
+ size_t i;
+ int ret;
+ struct cbarg {
+ const char *rootfs;
+ const char *target;
+ const char *options;
+ } cbarg = {
+ .rootfs = rootfs,
+ .target = target,
+ .options = options,
+ };
+
+ /*
+ * find the filesystem type with brute force:
+ * first we check with /etc/filesystems, in case the modules
+ * are auto-loaded and fall back to the supported kernel fs
+ */
+ char *fsfile[] = {
+ "/etc/filesystems",
+ "/proc/filesystems",
+ };
+
+ for (i = 0; i < sizeof(fsfile) / sizeof(fsfile[0]); i++) {
+ if (access(fsfile[i], F_OK))
+ continue;
+
+ ret = lxc_file_for_each_line(fsfile[i], find_fstype_cb, &cbarg);
+ if (ret < 0) {
+ ERROR("failed to parse '%s'", fsfile[i]);
+ return -1;
+ }
+
+ if (ret)
+ return 0;
+ }
+
+ ERROR("failed to determine fs type for '%s'", rootfs);
+ return -1;
+}
+
+/*
+ * These are copied from conf.c. However as conf.c will be moved to using
+ * the callback system, they can be pulled from there eventually, so we
+ * don't need to pollute utils.c with these low level functions
+ */
+int find_fstype_cb(char *buffer, void *data)
+{
+ struct cbarg {
+ const char *rootfs;
+ const char *target;
+ const char *options;
+ } *cbarg = data;
+
+ unsigned long mntflags;
+ char *mntdata;
+ char *fstype;
+
+ /* we don't try 'nodev' entries */
+ if (strstr(buffer, "nodev"))
+ return 0;
+
+ fstype = buffer;
+ fstype += lxc_char_left_gc(fstype, strlen(fstype));
+ fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0';
+
+ DEBUG("trying to mount '%s'->'%s' with fstype '%s'", cbarg->rootfs,
+ cbarg->target, fstype);
+
+ if (parse_mntopts(cbarg->options, &mntflags, &mntdata) < 0) {
+ free(mntdata);
+ return 0;
+ }
+
+ if (mount(cbarg->rootfs, cbarg->target, fstype, mntflags, mntdata)) {
+ DEBUG("mount failed with error: %s", strerror(errno));
+ free(mntdata);
+ return 0;
+ }
+
+ free(mntdata);
+
+ INFO("mounted '%s' on '%s', with fstype '%s'", cbarg->rootfs,
+ cbarg->target, fstype);
+
+ return 1;
+}
+
+char *linkderef(char *path, char *dest)
+{
+ struct stat sbuf;
+ ssize_t ret;
+
+ ret = stat(path, &sbuf);
+ if (ret < 0)
+ return NULL;
+
+ if (!S_ISLNK(sbuf.st_mode))
+ return path;
+
+ ret = readlink(path, dest, MAXPATHLEN);
+ if (ret < 0) {
+ SYSERROR("error reading link %s", path);
+ return NULL;
+ } else if (ret >= MAXPATHLEN) {
+ ERROR("link in %s too long", path);
+ return NULL;
+ }
+ dest[ret] = '\0';
+
+ return dest;
+}
+
+/*
+ * is an unprivileged user allowed to make this kind of snapshot
+ */
+bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap,
+ bool maybesnap)
+{
+ if (!t) {
+ // new type will be same as original
+ // (unless snap && b->type == dir, in which case it will be
+ // overlayfs -- which is also allowed)
+ if (strcmp(b->type, "dir") == 0 ||
+ strcmp(b->type, "aufs") == 0 ||
+ strcmp(b->type, "overlayfs") == 0 ||
+ strcmp(b->type, "btrfs") == 0 ||
+ strcmp(b->type, "loop") == 0)
+ return true;
+
+ return false;
+ }
+
+ // unprivileged users can copy and snapshot dir, overlayfs,
+ // and loop. In particular, not zfs, btrfs, or lvm.
+ if (strcmp(t, "dir") == 0 ||
+ strcmp(t, "aufs") == 0 ||
+ strcmp(t, "overlayfs") == 0 ||
+ strcmp(t, "btrfs") == 0 ||
+ strcmp(t, "loop") == 0)
+ return true;
+
+ return false;
+}
+
+bool is_valid_bdev_type(const char *type)
+{
+ if (strcmp(type, "dir") == 0 ||
+ strcmp(type, "btrfs") == 0 ||
+ strcmp(type, "aufs") == 0 ||
+ strcmp(type, "loop") == 0 ||
+ strcmp(type, "lvm") == 0 ||
+ strcmp(type, "nbd") == 0 ||
+ strcmp(type, "overlayfs") == 0 ||
+ strcmp(type, "rbd") == 0 ||
+ strcmp(type, "zfs") == 0)
+ return true;
+
+ return false;
+}
+
+int bdev_destroy_wrapper(void *data)
+{
+ struct lxc_conf *conf = data;
+
+ if (setgid(0) < 0) {
+ ERROR("Failed to setgid to 0");
+ return -1;
+ }
+
+ if (setgroups(0, NULL) < 0)
+ WARN("Failed to clear groups");
+
+ if (setuid(0) < 0) {
+ ERROR("Failed to setuid to 0");
+ return -1;
+ }
+
+ if (!bdev_destroy(conf))
+ return -1;
+
+ return 0;
+}
diff --git a/src/lxc/bdev/storage_utils.h b/src/lxc/bdev/storage_utils.h
new file mode 100644
index 000000000..cfd6aa47c
--- /dev/null
+++ b/src/lxc/bdev/storage_utils.h
@@ -0,0 +1,54 @@
+/*
+ * lxc: linux Container library
+ *
+ * Copyright © 2017 Canonical Ltd.
+ *
+ * Authors:
+ * Christian Brauner <christian.brauner at ubuntu.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LXC_STORAGE_UTILS_H
+#define __LXC_STORAGE_UTILS_H
+
+#include "config.h"
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "conf.h"
+
+struct bdev;
+struct lxc_conf;
+
+extern char *dir_new_path(char *src, const char *oldname, const char *name,
+ const char *oldpath, const char *lxcpath);
+extern bool attach_block_device(struct lxc_conf *conf);
+extern void detach_block_device(struct lxc_conf *conf);
+extern int blk_getsize(struct bdev *bdev, uint64_t *size);
+extern int detect_fs(struct bdev *bdev, char *type, int len);
+extern int do_mkfs_exec_wrapper(void *args);
+extern int is_blktype(struct bdev *b);
+extern int mount_unknown_fs(const char *rootfs, const char *target,
+ const char *options);
+extern int find_fstype_cb(char *buffer, void *data);
+extern char *linkderef(char *path, char *dest);
+extern bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap,
+ bool maybesnap);
+extern bool is_valid_bdev_type(const char *type);
+extern int bdev_destroy_wrapper(void *data);
+
+#endif // __LXC_STORAGE_UTILS_H
diff --git a/src/lxc/start.c b/src/lxc/start.c
index e1acc7c89..2d121bfd5 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -71,6 +71,7 @@
#include "console.h"
#include "error.h"
#include "log.h"
+#include "lxccontainer.h"
#include "lxclock.h"
#include "lxcseccomp.h"
#include "lxcutmp.h"
@@ -78,6 +79,7 @@
#include "monitor.h"
#include "namespace.h"
#include "start.h"
+#include "storage_utils.h"
#include "sync.h"
#include "utils.h"
#include "lsm/lsm.h"
diff --git a/src/lxc/tools/lxc_create.c b/src/lxc/tools/lxc_create.c
index dda51a44d..ad449dcad 100644
--- a/src/lxc/tools/lxc_create.c
+++ b/src/lxc/tools/lxc_create.c
@@ -30,6 +30,7 @@
#include "bdev.h"
#include "log.h"
#include "lxc.h"
+#include "storage_utils.h"
#include "utils.h"
lxc_log_define(lxc_create_ui, lxc);
From 1af01db5ba879e89f92d9386925cd14824fd8b34 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sat, 1 Jul 2017 22:36:05 +0200
Subject: [PATCH 3/9] storage: add lxc_storage_get_path()
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
src/lxc/bdev/bdev.c | 11 +++++++++++
src/lxc/bdev/bdev.h | 1 +
2 files changed, 12 insertions(+)
diff --git a/src/lxc/bdev/bdev.c b/src/lxc/bdev/bdev.c
index ea1bca17a..48f2c2759 100644
--- a/src/lxc/bdev/bdev.c
+++ b/src/lxc/bdev/bdev.c
@@ -609,3 +609,14 @@ bool rootfs_is_blockdev(struct lxc_conf *conf)
return false;
}
+
+char *lxc_storage_get_path(char *src, const char *prefix)
+{
+ size_t prefix_len;
+
+ prefix_len = strlen(prefix);
+ if (!strncmp(src, prefix, prefix_len) && (*(src + prefix_len) == ':'))
+ return (src + prefix_len + 1);
+
+ return src;
+}
diff --git a/src/lxc/bdev/bdev.h b/src/lxc/bdev/bdev.h
index b723b5080..22133173a 100644
--- a/src/lxc/bdev/bdev.h
+++ b/src/lxc/bdev/bdev.h
@@ -125,5 +125,6 @@ bool bdev_destroy(struct lxc_conf *conf);
/* callback function to be used with userns_exec_1() */
int bdev_destroy_wrapper(void *data);
extern bool rootfs_is_blockdev(struct lxc_conf *conf);
+extern char *lxc_storage_get_path(char *src, const char *prefix);
#endif // __LXC_BDEV_H
From fd2b982aa3f614fede347653dcad0d59ad519ba1 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sat, 1 Jul 2017 22:36:27 +0200
Subject: [PATCH 4/9] storage: prefix all dir paths
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
src/lxc/bdev/bdev.c | 7 ++++-
src/lxc/bdev/lxcdir.c | 68 ++++++++++++++++++++++++++++++++++++-------------
src/lxc/bdev/lxcrsync.c | 1 -
src/lxc/lxccontainer.c | 6 +++--
4 files changed, 60 insertions(+), 22 deletions(-)
diff --git a/src/lxc/bdev/bdev.c b/src/lxc/bdev/bdev.c
index 48f2c2759..1bc8afcd0 100644
--- a/src/lxc/bdev/bdev.c
+++ b/src/lxc/bdev/bdev.c
@@ -306,6 +306,7 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
struct bdev *orig, *new;
pid_t pid;
int ret;
+ char *src_no_prefix;
bool snap = flags & LXC_CLONE_SNAPSHOT;
bool maybe_snap = flags & LXC_CLONE_MAYBE_SNAPSHOT;
bool keepbdevtype = flags & LXC_CLONE_KEEPBDEVTYPE;
@@ -402,7 +403,9 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
goto err;
}
- if (am_unpriv() && chown_mapped_root(new->src, c0->lxc_conf) < 0)
+ src_no_prefix = lxc_storage_get_path(new->src, new->type);
+
+ if (am_unpriv() && chown_mapped_root(src_no_prefix, c0->lxc_conf) < 0)
WARN("Failed to update ownership of %s", new->dest);
if (snap)
@@ -456,6 +459,8 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
"rsync_rootfs_wrapper");
else
ret = rsync_rootfs(&data);
+ if (ret < 0)
+ ERROR("Failed to rsync");
exit(ret == 0 ? 0 : 1);
diff --git a/src/lxc/bdev/lxcdir.c b/src/lxc/bdev/lxcdir.c
index be897bb77..576736ea9 100644
--- a/src/lxc/bdev/lxcdir.c
+++ b/src/lxc/bdev/lxcdir.c
@@ -39,7 +39,8 @@ int dir_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
const char *cname, const char *oldpath, const char *lxcpath,
int snap, uint64_t newsize, struct lxc_conf *conf)
{
- int len, ret;
+ int ret;
+ size_t len;
if (snap) {
ERROR("directories cannot be snapshotted. Try aufs or overlayfs.");
@@ -49,38 +50,58 @@ int dir_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
if (!orig->dest || !orig->src)
return -1;
- len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3;
+ len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 4 + 3;
new->src = malloc(len);
if (!new->src)
return -1;
- ret = snprintf(new->src, len, "%s/%s/rootfs", lxcpath, cname);
- if (ret < 0 || ret >= len)
+
+ ret = snprintf(new->src, len, "dir:%s/%s/rootfs", lxcpath, cname);
+ if (ret < 0 || (size_t)ret >= len)
return -1;
- if ((new->dest = strdup(new->src)) == NULL)
+
+ new->dest = strdup(new->src + 4);
+ if (!new->dest)
return -1;
return 0;
}
int dir_create(struct bdev *bdev, const char *dest, const char *n,
- struct bdev_specs *specs)
+ struct bdev_specs *specs)
{
+ int ret;
+ const char *src;
+ size_t len;
+
+ /* strlen("dir:") */
+ len = 4;
if (specs && specs->dir)
- bdev->src = strdup(specs->dir);
+ src = specs->dir;
else
- bdev->src = strdup(dest);
+ src = dest;
+
+ len += strlen(src);
+ bdev->src = malloc(len);
+ if (!bdev->src)
+ return -1;
+
+ ret = snprintf(bdev->src, len, "dir:%s", src);
+ if (ret < 0 || (size_t)ret >= len)
+ return -1;
+
bdev->dest = strdup(dest);
- if (!bdev->src || !bdev->dest) {
- ERROR("Out of memory");
+ if (!bdev->dest)
return -1;
- }
- if (mkdir_p(bdev->src, 0755) < 0) {
- ERROR("Error creating %s", bdev->src);
+ ret = mkdir_p(src, 0755);
+ if (ret < 0) {
+ ERROR("Failed to create %s", src);
return -1;
}
- if (mkdir_p(bdev->dest, 0755) < 0) {
- ERROR("Error creating %s", bdev->dest);
+
+ ret = mkdir_p(bdev->dest, 0755);
+ if (ret < 0) {
+ ERROR("Failed to create %s", bdev->dest);
return -1;
}
@@ -89,8 +110,13 @@ int dir_create(struct bdev *bdev, const char *dest, const char *n,
int dir_destroy(struct bdev *orig)
{
- if (lxc_rmdir_onedev(orig->src, NULL) < 0)
+ char *src;
+
+ src = lxc_storage_get_path(orig->src, orig->src);
+
+ if (lxc_rmdir_onedev(src, NULL) < 0)
return -1;
+
return 0;
}
@@ -101,17 +127,19 @@ int dir_detect(const char *path)
if (is_dir(path))
return 1;
+
return 0;
}
int dir_mount(struct bdev *bdev)
{
unsigned long mntflags;
- char *mntdata;
+ char *src, *mntdata;
int ret;
if (strcmp(bdev->type, "dir"))
return -22;
+
if (!bdev->src || !bdev->dest)
return -22;
@@ -120,7 +148,9 @@ int dir_mount(struct bdev *bdev)
return -22;
}
- ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
+ src = lxc_storage_get_path(bdev->src, bdev->type);
+
+ ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
free(mntdata);
return ret;
}
@@ -129,7 +159,9 @@ int dir_umount(struct bdev *bdev)
{
if (strcmp(bdev->type, "dir"))
return -22;
+
if (!bdev->src || !bdev->dest)
return -22;
+
return umount(bdev->dest);
}
diff --git a/src/lxc/bdev/lxcrsync.c b/src/lxc/bdev/lxcrsync.c
index 8af39898d..41eb881c4 100644
--- a/src/lxc/bdev/lxcrsync.c
+++ b/src/lxc/bdev/lxcrsync.c
@@ -139,4 +139,3 @@ int rsync_rootfs_wrapper(void *data)
struct rsync_data *arg = data;
return rsync_rootfs(arg);
}
-
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index 26ae25410..56a34941d 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -1154,8 +1154,10 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
exit(1);
}
} else { // TODO come up with a better way here!
+ char *src;
free(bdev->dest);
- bdev->dest = strdup(bdev->src);
+ src = lxc_storage_get_path(bdev->src, bdev->type);
+ bdev->dest = strdup(src);
}
/*
@@ -1320,7 +1322,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
}
/* execute */
execvp(tpath, newargv);
- SYSERROR("failed to execute template %s", tpath);
+ SYSERROR("Failed to execute template %s", tpath);
exit(1);
}
From 1df4d53369ed33e3550513bf1970296a5fa0eb23 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sat, 1 Jul 2017 23:02:45 +0200
Subject: [PATCH 5/9] storage: prefix all btrfs paths
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
src/lxc/bdev/lxcbtrfs.c | 59 +++++++++++++++++++++++++++++++++++++++----------
1 file changed, 47 insertions(+), 12 deletions(-)
diff --git a/src/lxc/bdev/lxcbtrfs.c b/src/lxc/bdev/lxcbtrfs.c
index bc0e80502..1defa76ee 100644
--- a/src/lxc/bdev/lxcbtrfs.c
+++ b/src/lxc/bdev/lxcbtrfs.c
@@ -194,11 +194,12 @@ int btrfs_detect(const char *path)
int btrfs_mount(struct bdev *bdev)
{
unsigned long mntflags;
- char *mntdata;
+ char *mntdata, *src;
int ret;
if (strcmp(bdev->type, "btrfs"))
return -22;
+
if (!bdev->src || !bdev->dest)
return -22;
@@ -207,7 +208,9 @@ int btrfs_mount(struct bdev *bdev)
return -22;
}
- ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
+ src = lxc_storage_get_path(bdev->src, "btrfs");
+
+ ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
free(mntdata);
return ret;
}
@@ -216,8 +219,10 @@ int btrfs_umount(struct bdev *bdev)
{
if (strcmp(bdev->type, "btrfs"))
return -22;
+
if (!bdev->src || !bdev->dest)
return -22;
+
return umount(bdev->dest);
}
@@ -346,7 +351,9 @@ int btrfs_snapshot(const char *orig, const char *new)
static int btrfs_snapshot_wrapper(void *data)
{
+ char *src;
struct rsync_data_char *arg = data;
+
if (setgid(0) < 0) {
ERROR("Failed to setgid to 0");
return -1;
@@ -357,7 +364,10 @@ static int btrfs_snapshot_wrapper(void *data)
ERROR("Failed to setuid to 0");
return -1;
}
- return btrfs_snapshot(arg->src, arg->dest);
+
+ src = lxc_storage_get_path(arg->src, "btrfs");
+
+ return btrfs_snapshot(src, arg->dest);
}
int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
@@ -365,6 +375,8 @@ int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
const char *lxcpath, int snap, uint64_t newsize,
struct lxc_conf *conf)
{
+ char *src;
+
if (!orig->dest || !orig->src)
return -1;
@@ -375,21 +387,26 @@ int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
orig->type);
return -1;
}
- len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3;
+
+ len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 6 + 3;
new->src = malloc(len);
if (!new->src)
return -1;
- ret = snprintf(new->src, len, "%s/%s/rootfs", lxcpath, cname);
+
+ ret = snprintf(new->src, len, "btrfs:%s/%s/rootfs", lxcpath, cname);
if (ret < 0 || ret >= len)
return -1;
} else {
- // in case rootfs is in custom path, reuse it
- if ((new->src = dir_new_path(orig->src, oldname, cname, oldpath, lxcpath)) == NULL)
+ /* In case rootfs is in custom path, reuse it. */
+ new->src = dir_new_path(orig->src, oldname, cname, oldpath, lxcpath);
+ if (!new->src)
return -1;
}
- if ((new->dest = strdup(new->src)) == NULL)
+ src = lxc_storage_get_path(new->src, "btrfs");
+ new->dest = strdup(src);
+ if (!new->dest)
return -1;
if (orig->mntopts && (new->mntopts = strdup(orig->mntopts)) == NULL)
@@ -734,21 +751,39 @@ bool btrfs_try_remove_subvol(const char *path)
{
if (!btrfs_detect(path))
return false;
+
return btrfs_recursive_destroy(path) == 0;
}
int btrfs_destroy(struct bdev *orig)
{
- return btrfs_recursive_destroy(orig->src);
+ char *src;
+
+ src = lxc_storage_get_path(orig->src, "btrfs");
+
+ return btrfs_recursive_destroy(src);
}
int btrfs_create(struct bdev *bdev, const char *dest, const char *n,
struct bdev_specs *specs)
{
- bdev->src = strdup(dest);
+ int ret;
+ size_t len;
+
+ len = strlen(dest) + 1;
+ /* strlen("btrfs:") */
+ len += 6;
+ bdev->src = malloc(len);
+ if (!bdev->src)
+ return -1;
+
+ ret = snprintf(bdev->src, len, "btrfs:%s", dest);
+ if (ret < 0 || (size_t)ret >= len)
+ return -1;
+
bdev->dest = strdup(dest);
- if (!bdev->src || !bdev->dest)
+ if (!bdev->dest)
return -1;
+
return btrfs_subvolume_create(bdev->dest);
}
-
From 2e04e378fbc5b83c0c4529863eb65030009776c3 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sat, 1 Jul 2017 23:31:18 +0200
Subject: [PATCH 6/9] storage: prefix all lvm paths
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
src/lxc/bdev/lxclvm.c | 52 ++++++++++++++++++++++++++++++++------------
src/lxc/bdev/storage_utils.c | 15 +++++--------
2 files changed, 43 insertions(+), 24 deletions(-)
diff --git a/src/lxc/bdev/lxclvm.c b/src/lxc/bdev/lxclvm.c
index 9c329a2f3..fdbd98707 100644
--- a/src/lxc/bdev/lxclvm.c
+++ b/src/lxc/bdev/lxclvm.c
@@ -162,21 +162,30 @@ int lvm_detect(const char *path)
int lvm_mount(struct bdev *bdev)
{
+ char *src;
+
if (strcmp(bdev->type, "lvm"))
return -22;
+
if (!bdev->src || !bdev->dest)
return -22;
- /* if we might pass in data sometime, then we'll have to enrich
- * mount_unknown_fs */
- return mount_unknown_fs(bdev->src, bdev->dest, bdev->mntopts);
+
+ src = lxc_storage_get_path(bdev->src, bdev->type);
+
+ /* If we might pass in data sometime, then we'll have to enrich
+ * mount_unknown_fs().
+ */
+ return mount_unknown_fs(src, bdev->dest, bdev->mntopts);
}
int lvm_umount(struct bdev *bdev)
{
if (strcmp(bdev->type, "lvm"))
return -22;
+
if (!bdev->src || !bdev->dest)
return -22;
+
return umount(bdev->dest);
}
@@ -298,10 +307,12 @@ int lvm_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
return -1;
}
vg = lxc_global_config_value("lxc.bdev.lvm.vg");
- len = strlen("/dev/") + strlen(vg) + strlen(cname) + 2;
- if ((new->src = malloc(len)) == NULL)
+ len = strlen("/dev/") + strlen(vg) + strlen(cname) + 4 + 2;
+ new->src = malloc(len);
+ if (new->src)
return -1;
- ret = snprintf(new->src, len, "/dev/%s/%s", vg, cname);
+
+ ret = snprintf(new->src, len, "lvm:/dev/%s/%s", vg, cname);
if (ret < 0 || ret >= len)
return -1;
} else {
@@ -342,18 +353,26 @@ int lvm_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
}
if (snap) {
- if (lvm_snapshot(orig->src, new->src, size) < 0) {
+ char *newsrc, *origsrc;
+
+ origsrc = lxc_storage_get_path(orig->src, "lvm");
+ newsrc = lxc_storage_get_path(new->src, "lvm");
+
+ if (lvm_snapshot(origsrc, newsrc, size) < 0) {
ERROR("could not create %s snapshot of %s", new->src, orig->src);
return -1;
}
} else {
- if (do_lvm_create(new->src, size, lxc_global_config_value("lxc.bdev.lvm.thin_pool")) < 0) {
+ char *src;
+
+ src = lxc_storage_get_path(new->src, "lvm");
+ if (do_lvm_create(src, size, lxc_global_config_value("lxc.bdev.lvm.thin_pool")) < 0) {
ERROR("Error creating new lvm blockdev");
return -1;
}
cmd_args[0] = fstype;
- cmd_args[1] = new->src;
+ cmd_args[1] = src;
// create an fs in the loopback file
ret = run_command(cmd_output, sizeof(cmd_output),
do_mkfs_exec_wrapper, (void *)cmd_args);
@@ -366,15 +385,20 @@ int lvm_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
int lvm_destroy(struct bdev *orig)
{
+ char *src;
+
pid_t pid;
if ((pid = fork()) < 0)
return -1;
+
if (!pid) {
(void)setenv("LVM_SUPPRESS_FD_WARNINGS", "1", 1);
- execlp("lvremove", "lvremove", "-f", orig->src, (char *)NULL);
+ src = lxc_storage_get_path(orig->src, "lvm");
+ execlp("lvremove", "lvremove", "-f", src, (char *)NULL);
exit(EXIT_FAILURE);
}
+
return wait_for_pid(pid);
}
@@ -402,12 +426,12 @@ int lvm_create(struct bdev *bdev, const char *dest, const char *n,
if (specs->lvm.lv)
lv = specs->lvm.lv;
- len = strlen(vg) + strlen(lv) + 7;
+ len = strlen(vg) + strlen(lv) + 4 + 7;
bdev->src = malloc(len);
if (!bdev->src)
return -1;
- ret = snprintf(bdev->src, len, "/dev/%s/%s", vg, lv);
+ ret = snprintf(bdev->src, len, "lvm:/dev/%s/%s", vg, lv);
if (ret < 0 || ret >= len)
return -1;
@@ -416,7 +440,7 @@ int lvm_create(struct bdev *bdev, const char *dest, const char *n,
if (!sz)
sz = DEFAULT_FS_SIZE;
- if (do_lvm_create(bdev->src, sz, thinpool) < 0) {
+ if (do_lvm_create(bdev->src + 4, sz, thinpool) < 0) {
ERROR("Error creating new lvm blockdev %s size %"PRIu64" bytes", bdev->src, sz);
return -1;
}
@@ -426,7 +450,7 @@ int lvm_create(struct bdev *bdev, const char *dest, const char *n,
fstype = DEFAULT_FSTYPE;
cmd_args[0] = fstype;
- cmd_args[1] = bdev->src;
+ cmd_args[1] = bdev->src + 4;
ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper,
(void *)cmd_args);
if (ret < 0)
diff --git a/src/lxc/bdev/storage_utils.c b/src/lxc/bdev/storage_utils.c
index 6ca6b51ec..0cf9710fb 100644
--- a/src/lxc/bdev/storage_utils.c
+++ b/src/lxc/bdev/storage_utils.c
@@ -129,12 +129,10 @@ bool attach_block_device(struct lxc_conf *conf)
int blk_getsize(struct bdev *bdev, uint64_t *size)
{
int fd, ret;
- char *path = bdev->src;
+ char *src;
- if (strcmp(bdev->type, "loop") == 0)
- path = bdev->src + 5;
-
- fd = open(path, O_RDONLY);
+ src = lxc_storage_get_path(bdev->src, bdev->type);
+ fd = open(src, O_RDONLY);
if (fd < 0)
return -1;
@@ -163,15 +161,12 @@ int detect_fs(struct bdev *bdev, char *type, int len)
size_t linelen;
pid_t pid;
FILE *f;
- char *sp1, *sp2, *sp3, *line = NULL;
- char *srcdev;
+ char *sp1, *sp2, *sp3, *srcdev, *line = NULL;
if (!bdev || !bdev->src || !bdev->dest)
return -1;
- srcdev = bdev->src;
- if (strcmp(bdev->type, "loop") == 0)
- srcdev = bdev->src + 5;
+ srcdev = lxc_storage_get_path(bdev->src, bdev->type);
ret = pipe(p);
if (ret < 0)
From 1cc9eee2692e22a3db09babe9a796e0f1cbf3880 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sat, 1 Jul 2017 23:33:18 +0200
Subject: [PATCH 7/9] storage: prefix all nbd paths
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
src/lxc/bdev/lxcnbd.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/src/lxc/bdev/lxcnbd.c b/src/lxc/bdev/lxcnbd.c
index 4a55e9fff..e6ce59038 100644
--- a/src/lxc/bdev/lxcnbd.c
+++ b/src/lxc/bdev/lxcnbd.c
@@ -117,17 +117,21 @@ int nbd_detect(const char *path)
int nbd_mount(struct bdev *bdev)
{
int ret = -1, partition;
+ char *src;
char path[50];
if (strcmp(bdev->type, "nbd"))
return -22;
+
if (!bdev->src || !bdev->dest)
return -22;
/* nbd_idx should have been copied by bdev_init from the lxc_conf */
if (bdev->nbd_idx < 0)
return -22;
- partition = nbd_get_partition(bdev->src);
+
+ src = lxc_storage_get_path(bdev->src, bdev->type);
+ partition = nbd_get_partition(src);
if (partition)
ret = snprintf(path, 50, "/dev/nbd%dp%d", bdev->nbd_idx,
partition);
@@ -152,14 +156,13 @@ int nbd_mount(struct bdev *bdev)
int nbd_umount(struct bdev *bdev)
{
- int ret;
-
if (strcmp(bdev->type, "nbd"))
return -22;
+
if (!bdev->src || !bdev->dest)
return -22;
- ret = umount(bdev->dest);
- return ret;
+
+ return umount(bdev->dest);
}
bool requires_nbd(const char *path)
From 4cacc022d9342269e90ec8d8cac14ad63d3e59cc Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sat, 1 Jul 2017 23:35:58 +0200
Subject: [PATCH 8/9] storage: prefix all rbd paths
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
src/lxc/bdev/lxcrbd.c | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/src/lxc/bdev/lxcrbd.c b/src/lxc/bdev/lxcrbd.c
index 8e63c3fd0..85001400b 100644
--- a/src/lxc/bdev/lxcrbd.c
+++ b/src/lxc/bdev/lxcrbd.c
@@ -66,12 +66,12 @@ int rbd_create(struct bdev *bdev, const char *dest, const char *n,
rbdname = specs->rbd.rbdname;
/* source device /dev/rbd/lxc/ctn */
- len = strlen(rbdpool) + strlen(rbdname) + 11;
+ len = strlen(rbdpool) + strlen(rbdname) + 4 + 11;
bdev->src = malloc(len);
if (!bdev->src)
return -1;
- ret = snprintf(bdev->src, len, "/dev/rbd/%s/%s", rbdpool, rbdname);
+ ret = snprintf(bdev->src, len, "rbd:/dev/rbd/%s/%s", rbdpool, rbdname);
if (ret < 0 || ret >= len)
return -1;
@@ -108,7 +108,7 @@ int rbd_create(struct bdev *bdev, const char *dest, const char *n,
fstype = DEFAULT_FSTYPE;
cmd_args[0] = fstype;
- cmd_args[1] = bdev->src;
+ cmd_args[1] = bdev->src + 4;
ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper,
(void *)cmd_args);
if (ret < 0)
@@ -127,14 +127,16 @@ int rbd_create(struct bdev *bdev, const char *dest, const char *n,
int rbd_destroy(struct bdev *orig)
{
+ char *src;
pid_t pid;
char *rbdfullname;
- if ( file_exists(orig->src) ) {
+ src = lxc_storage_get_path(orig->src, orig->type);
+ if (file_exists(src)) {
if ((pid = fork()) < 0)
return -1;
if (!pid) {
- execlp("rbd", "rbd", "unmap" , orig->src, (char *)NULL);
+ execlp("rbd", "rbd", "unmap" , src, (char *)NULL);
exit(1);
}
if (wait_for_pid(pid) < 0)
@@ -144,8 +146,8 @@ int rbd_destroy(struct bdev *orig)
if ((pid = fork()) < 0)
return -1;
if (!pid) {
- rbdfullname = alloca(strlen(orig->src) - 8);
- strcpy( rbdfullname, &orig->src[9] );
+ rbdfullname = alloca(strlen(src) - 8);
+ strcpy( rbdfullname, &src[9] );
execlp("rbd", "rbd", "rm" , rbdfullname, (char *)NULL);
exit(1);
}
@@ -166,12 +168,15 @@ int rbd_detect(const char *path)
int rbd_mount(struct bdev *bdev)
{
+ char *src;
if (strcmp(bdev->type, "rbd"))
return -22;
+
if (!bdev->src || !bdev->dest)
return -22;
- if ( !file_exists(bdev->src) ) {
+ src = lxc_storage_get_path(bdev->src, bdev->type);
+ if (!file_exists(src)) {
// if blkdev does not exist it should be mapped, because it is not persistent on reboot
ERROR("Block device %s is not mapped.", bdev->src);
return -1;
@@ -184,7 +189,9 @@ int rbd_umount(struct bdev *bdev)
{
if (strcmp(bdev->type, "rbd"))
return -22;
+
if (!bdev->src || !bdev->dest)
return -22;
+
return umount(bdev->dest);
}
From 214e6e2aeaa47dadd894144099545e01e064628e Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sat, 1 Jul 2017 23:41:49 +0200
Subject: [PATCH 9/9] storage: prefix all zfs paths
Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
src/lxc/bdev/lxczfs.c | 77 ++++++++++++++++++++++++++++++++++++---------------
1 file changed, 54 insertions(+), 23 deletions(-)
diff --git a/src/lxc/bdev/lxczfs.c b/src/lxc/bdev/lxczfs.c
index b8f3c1405..8fe74137d 100644
--- a/src/lxc/bdev/lxczfs.c
+++ b/src/lxc/bdev/lxczfs.c
@@ -88,20 +88,23 @@ int zfs_detect(const char *path)
int zfs_mount(struct bdev *bdev)
{
+ int ret;
+ char *mntdata, *src;
+ unsigned long mntflags;
+
if (strcmp(bdev->type, "zfs"))
return -22;
if (!bdev->src || !bdev->dest)
return -22;
- char *mntdata;
- unsigned long mntflags;
if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
free(mntdata);
return -22;
}
- int ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
+ src = lxc_storage_get_path(bdev->src, bdev->type);
+ ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
free(mntdata);
return ret;
@@ -208,6 +211,7 @@ int zfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
const char *cname, const char *oldpath, const char *lxcpath, int snap,
uint64_t newsize, struct lxc_conf *conf)
{
+ char *origsrc, *newsrc;
int len, ret;
if (!orig->src || !orig->dest)
@@ -218,19 +222,22 @@ int zfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
return -1;
}
- len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3;
+ len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 4 + 3;
new->src = malloc(len);
if (!new->src)
return -1;
- ret = snprintf(new->src, len, "%s/%s/rootfs", lxcpath, cname);
+ ret = snprintf(new->src, len, "zfs:%s/%s/rootfs", lxcpath, cname);
if (ret < 0 || ret >= len)
return -1;
- if ((new->dest = strdup(new->src)) == NULL)
+ newsrc = lxc_storage_get_path(new->src, new->type);
+ new->dest = strdup(newsrc);
+ if (!new->dest)
return -1;
- return zfs_clone(orig->src, new->src, oldname, cname, lxcpath, snap);
+ origsrc = lxc_storage_get_path(orig->src, orig->type);
+ return zfs_clone(origsrc, newsrc, oldname, cname, lxcpath, snap);
}
/*
@@ -242,14 +249,15 @@ int zfs_destroy(struct bdev *orig)
{
pid_t pid;
char output[MAXPATHLEN];
- char *p;
+ char *p, *src;
if ((pid = fork()) < 0)
return -1;
if (pid)
return wait_for_pid(pid);
- if (!zfs_list_entry(orig->src, output, MAXPATHLEN)) {
+ src = lxc_storage_get_path(orig->src, orig->type);
+ if (!zfs_list_entry(src, output, MAXPATHLEN)) {
ERROR("Error: zfs entry for %s not found", orig->src);
return -1;
}
@@ -263,41 +271,64 @@ int zfs_destroy(struct bdev *orig)
exit(EXIT_FAILURE);
}
+struct zfs_exec_args {
+ char *dataset;
+ char *options;
+};
+
+int zfs_create_exec_wrapper(void *args)
+{
+ struct zfs_exec_args *zfs_args = args;
+
+ execlp("zfs", "zfs", "create", zfs_args->options, zfs_args->dataset,
+ (char *)NULL);
+ return -1;
+}
+
int zfs_create(struct bdev *bdev, const char *dest, const char *n,
struct bdev_specs *specs)
{
const char *zfsroot;
- char option[MAXPATHLEN];
+ char cmd_output[MAXPATHLEN], dev[MAXPATHLEN], option[MAXPATHLEN];
int ret;
- pid_t pid;
+ size_t len;
+ struct zfs_exec_args cmd_args;
if (!specs || !specs->zfs.zfsroot)
zfsroot = lxc_global_config_value("lxc.bdev.zfs.root");
else
zfsroot = specs->zfs.zfsroot;
- if (!(bdev->dest = strdup(dest))) {
+ bdev->dest = strdup(dest);
+ if (!bdev->dest) {
ERROR("No mount target specified or out of memory");
return -1;
}
- if (!(bdev->src = strdup(bdev->dest))) {
- ERROR("out of memory");
+
+ len = strlen(bdev->dest) + 1;
+ /* strlen("zfs:") */
+ len += 4;
+ bdev->src = malloc(len);
+ if (!bdev->src)
+ return -1;
+
+ ret = snprintf(bdev->src, len, "zfs:%s", bdev->dest);
+ if (ret < 0 || (size_t)ret >= len)
return -1;
- }
ret = snprintf(option, MAXPATHLEN, "-omountpoint=%s", bdev->dest);
if (ret < 0 || ret >= MAXPATHLEN)
return -1;
- if ((pid = fork()) < 0)
- return -1;
- if (pid)
- return wait_for_pid(pid);
- char dev[MAXPATHLEN];
ret = snprintf(dev, MAXPATHLEN, "%s/%s", zfsroot, n);
if (ret < 0 || ret >= MAXPATHLEN)
- exit(EXIT_FAILURE);
+ return -1;
- execlp("zfs", "zfs", "create", option, dev, (char *)NULL);
- exit(EXIT_FAILURE);
+ cmd_args.options = option;
+ cmd_args.dataset = dev;
+ ret = run_command(cmd_output, sizeof(cmd_output),
+ zfs_create_exec_wrapper, (void *)&cmd_args);
+ if (ret < 0)
+ ERROR("Failed to create zfs dataset \"%s\": %s", dev, cmd_output);
+ return ret;
}
More information about the lxc-devel
mailing list