</listitem>
</varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.rootfs.options</option>
+ </term>
+ <listitem>
+ <para>
+ extra mount options to use when mounting the rootfs.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term>
<option>lxc.pivotdir</option>
struct cbarg {
const char *rootfs;
const char *target;
- int mntopt;
+ const char *options;
} *cbarg = data;
+ unsigned long mntflags;
+ char *mntdata;
char *fstype;
/* we don't try 'nodev' entries */
DEBUG("trying to mount '%s'->'%s' with fstype '%s'",
cbarg->rootfs, cbarg->target, fstype);
- if (mount(cbarg->rootfs, cbarg->target, fstype, cbarg->mntopt, NULL)) {
+ 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 int mount_unknown_fs(const char *rootfs, const char *target, int mntopt)
+static int mount_unknown_fs(const char *rootfs, const char *target,
+ const char *options)
{
int i;
struct cbarg {
const char *rootfs;
const char *target;
- int mntopt;
+ const char *options;
} cbarg = {
.rootfs = rootfs,
.target = target,
- .mntopt = mntopt,
+ .options = options,
};
/*
if (unshare(CLONE_NEWNS) < 0)
exit(1);
- ret = mount_unknown_fs(srcdev, bdev->dest, 0);
+ 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);
//
static int dir_mount(struct bdev *bdev)
{
+ unsigned long mntflags;
+ char *mntdata;
+ int ret;
+
if (strcmp(bdev->type, "dir"))
return -22;
if (!bdev->src || !bdev->dest)
return -22;
- return mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC, NULL);
+
+ if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
+ free(mntdata);
+ return -22;
+ }
+
+ ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
+ free(mntdata);
+ return ret;
}
static int dir_umount(struct bdev *bdev)
static int zfs_mount(struct bdev *bdev)
{
+ unsigned long mntflags;
+ char *mntdata;
+ int ret;
+
if (strcmp(bdev->type, "zfs"))
return -22;
if (!bdev->src || !bdev->dest)
return -22;
- return mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC, NULL);
+
+ if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
+ free(mntdata);
+ return -22;
+ }
+
+ ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
+ free(mntdata);
+ return ret;
}
static int zfs_umount(struct bdev *bdev)
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, 0);
+ return mount_unknown_fs(bdev->src, bdev->dest, bdev->mntopts);
}
static int lvm_umount(struct bdev *bdev)
return -1;
}
- if (orig->data) {
- new->data = strdup(orig->data);
- if (!new->data)
+ if (orig->mntopts) {
+ new->mntopts = strdup(orig->mntopts);
+ if (!new->mntopts)
return -1;
}
static int btrfs_mount(struct bdev *bdev)
{
+ unsigned long mntflags;
+ char *mntdata;
+ int ret;
+
if (strcmp(bdev->type, "btrfs"))
return -22;
if (!bdev->src || !bdev->dest)
return -22;
- return mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC, NULL);
+
+ if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
+ free(mntdata);
+ return -22;
+ }
+
+ ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
+ free(mntdata);
+ return ret;
}
static int btrfs_umount(struct bdev *bdev)
if ((new->dest = strdup(new->src)) == NULL)
return -1;
- if (orig->data && (new->data = strdup(orig->data)) == NULL)
+ if (orig->mntopts && (new->mntopts = strdup(orig->mntopts)) == NULL)
return -1;
if (snap)
goto out;
}
- ret = mount_unknown_fs(loname, bdev->dest, 0);
+ ret = mount_unknown_fs(loname, bdev->dest, bdev->mntopts);
if (ret < 0)
ERROR("Error mounting %s\n", bdev->src);
else
{
char *options, *dup, *lower, *upper;
int len;
+ unsigned long mntflags;
+ char *mntdata;
int ret;
if (strcmp(bdev->type, "overlayfs"))
*upper = '\0';
upper++;
+ if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
+ free(mntdata);
+ return -22;
+ }
+
// TODO We should check whether bdev->src is a blockdev, and if so
// but for now, only support overlays of a basic directory
- len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=") + 1;
- options = alloca(len);
- ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper, lower);
- if (ret < 0 || ret >= len)
+ if (mntdata) {
+ len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=,") + strlen(mntdata) + 1;
+ options = alloca(len);
+ ret = snprintf(options, len, "upperdir=%s,lowerdir=%s,%s", upper, lower, mntdata);
+ }
+ else {
+ len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=") + 1;
+ options = alloca(len);
+ ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper, lower);
+ }
+ if (ret < 0 || ret >= len) {
+ free(mntdata);
return -1;
- ret = mount(lower, bdev->dest, "overlayfs", MS_MGC_VAL, options);
+ }
+
+ ret = mount(lower, bdev->dest, "overlayfs", MS_MGC_VAL | mntflags, options);
if (ret < 0)
SYSERROR("overlayfs: error mounting %s onto %s options %s",
lower, bdev->dest, options);
void bdev_put(struct bdev *bdev)
{
- if (bdev->data)
- free(bdev->data);
+ if (bdev->mntopts)
+ free(bdev->mntopts);
if (bdev->src)
free(bdev->src);
if (bdev->dest)
return bdev;
}
-struct bdev *bdev_init(const char *src, const char *dst, const char *data)
+struct bdev *bdev_init(const char *src, const char *dst, const char *mntopts)
{
int i;
struct bdev *bdev;
memset(bdev, 0, sizeof(struct bdev));
bdev->ops = bdevs[i].ops;
bdev->type = bdevs[i].name;
- if (data)
- bdev->data = strdup(data);
+ if (mntopts)
+ bdev->mntopts = strdup(mntopts);
if (src)
bdev->src = strdup(src);
if (dst)
const char *type;
char *src;
char *dest;
- char *data;
+ char *mntopts;
// turn the following into a union if need be
// lofd is the open fd for the mounted loopback file
int lofd;
struct cbarg {
const char *rootfs;
const char *target;
- int mntopt;
+ const char *options;
} *cbarg = data;
+ unsigned long mntflags;
+ char *mntdata;
char *fstype;
/* we don't try 'nodev' entries */
DEBUG("trying to mount '%s'->'%s' with fstype '%s'",
cbarg->rootfs, cbarg->target, fstype);
- if (mount(cbarg->rootfs, cbarg->target, fstype, cbarg->mntopt, NULL)) {
+ if (parse_mntopts(cbarg->options, &mntflags, &mntdata) < 0) {
+ free(mntdata);
+ return -1;
+ }
+
+ 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 int mount_unknown_fs(const char *rootfs, const char *target, int mntopt)
+static int mount_unknown_fs(const char *rootfs, const char *target,
+ const char *options)
{
int i;
struct cbarg {
const char *rootfs;
const char *target;
- int mntopt;
+ const char *options;
} cbarg = {
.rootfs = rootfs,
.target = target,
- .mntopt = mntopt,
+ .options = options,
};
/*
return -1;
}
-static int mount_rootfs_dir(const char *rootfs, const char *target)
+static int mount_rootfs_dir(const char *rootfs, const char *target,
+ const char *options)
{
- return mount(rootfs, target, "none", MS_BIND | MS_REC, NULL);
+ unsigned long mntflags;
+ char *mntdata;
+ int ret;
+
+ if (parse_mntopts(options, &mntflags, &mntdata) < 0) {
+ free(mntdata);
+ return -1;
+ }
+
+ ret = mount(rootfs, target, "none", MS_BIND | MS_REC | mntflags, mntdata);
+ free(mntdata);
+
+ return ret;
}
static int setup_lodev(const char *rootfs, int fd, struct loop_info64 *loinfo)
return ret;
}
-static int mount_rootfs_file(const char *rootfs, const char *target)
+static int mount_rootfs_file(const char *rootfs, const char *target,
+ const char *options)
{
struct dirent dirent, *direntp;
struct loop_info64 loinfo;
ret = setup_lodev(rootfs, fd, &loinfo);
if (!ret)
- ret = mount_unknown_fs(path, target, 0);
+ ret = mount_unknown_fs(path, target, options);
close(fd);
break;
return ret;
}
-static int mount_rootfs_block(const char *rootfs, const char *target)
+static int mount_rootfs_block(const char *rootfs, const char *target,
+ const char *options)
{
- return mount_unknown_fs(rootfs, target, 0);
+ return mount_unknown_fs(rootfs, target, options);
}
/*
return 0;
}
-static int mount_rootfs(const char *rootfs, const char *target)
+static int mount_rootfs(const char *rootfs, const char *target, const char *options)
{
char absrootfs[MAXPATHLEN];
struct stat s;
int i;
- typedef int (*rootfs_cb)(const char *, const char *);
+ typedef int (*rootfs_cb)(const char *, const char *, const char *);
struct rootfs_type {
int type;
if (!__S_ISTYPE(s.st_mode, rtfs_type[i].type))
continue;
- return rtfs_type[i].cb(absrootfs, target);
+ return rtfs_type[i].cb(absrootfs, target, options);
}
ERROR("unsupported rootfs type for '%s'", absrootfs);
}
// First try mounting rootfs using a bdev
- struct bdev *bdev = bdev_init(rootfs->path, rootfs->mount, NULL);
+ struct bdev *bdev = bdev_init(rootfs->path, rootfs->mount, rootfs->options);
if (bdev && bdev->ops->mount(bdev) == 0) {
bdev_put(bdev);
DEBUG("mounted '%s' on '%s'", rootfs->path, rootfs->mount);
}
if (bdev)
bdev_put(bdev);
- if (mount_rootfs(rootfs->path, rootfs->mount)) {
+ if (mount_rootfs(rootfs->path, rootfs->mount, rootfs->options)) {
ERROR("failed to mount rootfs");
return -1;
}
strcat(*data, opt);
}
-static int parse_mntopts(const char *mntopts, unsigned long *mntflags,
+int parse_mntopts(const char *mntopts, unsigned long *mntflags,
char **mntdata)
{
char *s, *data;
FILE *pathfile = NULL;
char* pathdirname = NULL;
- if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) {
- ERROR("failed to parse mount option '%s'", mntent->mnt_opts);
- return -1;
- }
-
if (hasmntopt(mntent, "create=dir")) {
if (!mkdir_p(mntent->mnt_dir, 0755)) {
WARN("Failed to create mount target '%s'", mntent->mnt_dir);
fclose(pathfile);
}
+ if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) {
+ free(mntdata);
+ return -1;
+ }
+
ret = mount_entry(mntent->mnt_fsname, mntent->mnt_dir,
mntent->mnt_type, mntflags, mntdata);
FILE *pathfile = NULL;
char *pathdirname = NULL;
- if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) {
- ERROR("failed to parse mount option '%s'", mntent->mnt_opts);
- return -1;
- }
-
lxcpath = lxc_global_config_value("lxc.lxcpath");
if (!lxcpath) {
ERROR("Out of memory");
fclose(pathfile);
}
+ if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) {
+ free(mntdata);
+ return -1;
+ }
+
ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type,
mntflags, mntdata);
+ free(mntdata);
+
if (hasmntopt(mntent, "optional") != NULL)
ret = 0;
out:
free(pathdirname);
- free(mntdata);
return ret;
}
FILE *pathfile = NULL;
char *pathdirname = NULL;
- if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) {
- ERROR("failed to parse mount option '%s'", mntent->mnt_opts);
- return -1;
- }
-
/* relative to root mount point */
ret = snprintf(path, sizeof(path), "%s/%s", rootfs, mntent->mnt_dir);
if (ret >= sizeof(path)) {
fclose(pathfile);
}
+ if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) {
+ free(mntdata);
+ return -1;
+ }
+
ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type,
mntflags, mntdata);
free(conf->console.path);
if (conf->rootfs.mount)
free(conf->rootfs.mount);
+ if (conf->rootfs.options)
+ free(conf->rootfs.options);
if (conf->rootfs.path)
free(conf->rootfs.path);
if (conf->rootfs.pivot)
char *path;
char *mount;
char *pivot;
+ char *options;
};
/*
extern int chown_mapped_root(char *path, struct lxc_conf *conf);
extern int ttys_shift_ids(struct lxc_conf *c);
extern int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data);
+extern int parse_mntopts(const char *mntopts, unsigned long *mntflags,
+ char **mntdata);
#endif
static int config_mount(const char *, const char *, struct lxc_conf *);
static int config_rootfs(const char *, const char *, struct lxc_conf *);
static int config_rootfs_mount(const char *, const char *, struct lxc_conf *);
+static int config_rootfs_options(const char *, const char *, struct lxc_conf *);
static int config_pivotdir(const char *, const char *, struct lxc_conf *);
static int config_utsname(const char *, const char *, struct lxc_conf *);
static int config_hook(const char *, const char *, struct lxc_conf *lxc_conf);
{ "lxc.logfile", config_logfile },
{ "lxc.mount", config_mount },
{ "lxc.rootfs.mount", config_rootfs_mount },
+ { "lxc.rootfs.options", config_rootfs_options },
{ "lxc.rootfs", config_rootfs },
{ "lxc.pivotdir", config_pivotdir },
{ "lxc.utsname", config_utsname },
return config_path_item(&lxc_conf->rootfs.mount, value);
}
+static int config_rootfs_options(const char *key, const char *value,
+ struct lxc_conf *lxc_conf)
+{
+ return config_string_item(&lxc_conf->rootfs.options, value);
+}
+
static int config_pivotdir(const char *key, const char *value,
struct lxc_conf *lxc_conf)
{
v = c->console.path;
else if (strcmp(key, "lxc.rootfs.mount") == 0)
v = c->rootfs.mount;
+ else if (strcmp(key, "lxc.rootfs.options") == 0)
+ v = c->rootfs.options;
else if (strcmp(key, "lxc.rootfs") == 0)
v = c->rootfs.path;
else if (strcmp(key, "lxc.pivotdir") == 0)
fprintf(fout, "lxc.rootfs = %s\n", c->rootfs.path);
if (c->rootfs.mount && strcmp(c->rootfs.mount, LXCROOTFSMOUNT) != 0)
fprintf(fout, "lxc.rootfs.mount = %s\n", c->rootfs.mount);
+ if (c->rootfs.options)
+ fprintf(fout, "lxc.rootfs.options = %s\n", c->rootfs.options);
if (c->rootfs.pivot)
fprintf(fout, "lxc.pivotdir = %s\n", c->rootfs.pivot);
if (c->start_auto)