diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml
index e7008648735..975ddd0be33 100644
--- a/man/systemd-nspawn.xml
+++ b/man/systemd-nspawn.xml
@@ -1357,7 +1357,8 @@ After=sys-subsystem-net-devices-ens1.device
source path is taken relative to the image's root directory. This permits setting up bind mounts within the
container image. The source path may be specified as empty string, in which case a temporary directory below
the host's /var/tmp/ directory is used. It is automatically removed when the container is
- shut down. The option creates read-only bind mounts. Backslash escapes are interpreted,
+ shut down. If the source path is not absolute, it is resolved relative to the current working directory.
+ The option creates read-only bind mounts. Backslash escapes are interpreted,
so \: may be used to embed colons in either path. This option may be specified
multiple times for creating multiple independent bind mount points.
@@ -1455,33 +1456,25 @@ After=sys-subsystem-net-devices-ens1.device
- Combine multiple directory trees into one
- overlay file system and mount it into the container. Takes a
- list of colon-separated paths to the directory trees to
- combine and the destination mount point.
+ Combine multiple directory trees into one overlay file system and mount it into the
+ container. Takes a list of colon-separated paths to the directory trees to combine and the
+ destination mount point.
- Backslash escapes are interpreted in the paths, so
- \: may be used to embed colons in the paths.
+ Backslash escapes are interpreted in the paths, so \: may be used to embed
+ colons in the paths.
+
+ If three or more paths are specified, then the last specified path is the destination mount
+ point in the container, all paths specified before refer to directory trees on the host and are
+ combined in the specified order into one overlay file system. The left-most path is hence the lowest
+ directory tree, the second-to-last path the highest directory tree in the stacking order. If
+ is used instead of , a read-only overlay
+ file system is created. If a writable overlay file system is created, all changes made to it are
+ written to the highest directory tree in the stacking order, i.e. the second-to-last specified.
- If three or more paths are specified, then the last
- specified path is the destination mount point in the
- container, all paths specified before refer to directory trees
- on the host and are combined in the specified order into one
- overlay file system. The left-most path is hence the lowest
- directory tree, the second-to-last path the highest directory
- tree in the stacking order. If
- is used instead of , a read-only
- overlay file system is created. If a writable overlay file
- system is created, all changes made to it are written to the
- highest directory tree in the stacking order, i.e. the
- second-to-last specified.
-
- If only two paths are specified, then the second
- specified path is used both as the top-level directory tree in
- the stacking order as seen from the host, as well as the mount
- point for the overlay file system in the container. At least
- two paths have to be specified.
+ If only two paths are specified, then the second specified path is used both as the top-level
+ directory tree in the stacking order as seen from the host, as well as the mount point for the
+ overlay file system in the container. At least two paths have to be specified.The source paths may optionally be prefixed with + character. If so they are
taken relative to the image's root directory. The uppermost source path may also be specified as an
@@ -1489,7 +1482,8 @@ After=sys-subsystem-net-devices-ens1.device
used. The directory is removed automatically when the container is shut down. This behaviour is
useful in order to make read-only container directories writable while the container is running. For
example, use --overlay=+/var::/var in order to automatically overlay a writable
- temporary directory on a read-only /var/ directory.
+ temporary directory on a read-only /var/ directory. If a source path is not
+ absolute, it is resolved relative to the current working directory.For details about overlay file systems, see Overlay Filesystem.
diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c
index 6378e1b703e..60cb007baa9 100644
--- a/src/nspawn/nspawn-mount.c
+++ b/src/nspawn/nspawn-mount.c
@@ -83,13 +83,38 @@ static int custom_mount_compare(const CustomMount *a, const CustomMount *b) {
return CMP(a->type, b->type);
}
-static bool source_path_is_valid(const char *p) {
+static int source_path_parse(const char *p, char **ret) {
assert(p);
+ assert(ret);
- if (*p == '+')
- p++;
+ if (isempty(p))
+ return -EINVAL;
- return path_is_absolute(p);
+ if (*p == '+') {
+ if (!path_is_absolute(p + 1))
+ return -EINVAL;
+
+ char *s = strdup(p);
+ if (!s)
+ return -ENOMEM;
+
+ *ret = TAKE_PTR(s);
+ return 0;
+ }
+
+ return path_make_absolute_cwd(p, ret);
+}
+
+static int source_path_parse_nullable(const char *p, char **ret) {
+ assert(p);
+ assert(ret);
+
+ if (isempty(p)) {
+ *ret = NULL;
+ return 0;
+ }
+
+ return source_path_parse(p, ret);
}
static char *resolve_source_path(const char *dest, const char *source) {
@@ -212,15 +237,14 @@ int custom_mount_prepare_all(const char *dest, CustomMount *l, size_t n) {
}
int bind_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only) {
- _cleanup_free_ char *source = NULL, *destination = NULL, *opts = NULL;
- const char *p = s;
+ _cleanup_free_ char *source = NULL, *destination = NULL, *opts = NULL, *p = NULL;
CustomMount *m;
int r;
assert(l);
assert(n);
- r = extract_many_words(&p, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &source, &destination, NULL);
+ r = extract_many_words(&s, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &source, &destination, NULL);
if (r < 0)
return r;
if (r == 0)
@@ -230,16 +254,15 @@ int bind_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only)
if (!destination)
return -ENOMEM;
}
- if (r == 2 && !isempty(p)) {
- opts = strdup(p);
+ if (r == 2 && !isempty(s)) {
+ opts = strdup(s);
if (!opts)
return -ENOMEM;
}
- if (isempty(source))
- source = mfree(source);
- else if (!source_path_is_valid(source))
- return -EINVAL;
+ r = source_path_parse_nullable(source, &p);
+ if (r < 0)
+ return r;
if (!path_is_absolute(destination))
return -EINVAL;
@@ -248,7 +271,7 @@ int bind_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only)
if (!m)
return -ENOMEM;
- m->source = TAKE_PTR(source);
+ m->source = TAKE_PTR(p);
m->destination = TAKE_PTR(destination);
m->read_only = read_only;
m->options = TAKE_PTR(opts);
@@ -296,7 +319,7 @@ int overlay_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_onl
_cleanup_free_ char *upper = NULL, *destination = NULL;
_cleanup_strv_free_ char **lower = NULL;
CustomMount *m;
- int k;
+ int r, k;
k = strv_split_full(&lower, s, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
if (k < 0)
@@ -304,12 +327,22 @@ int overlay_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_onl
if (k < 2)
return -EADDRNOTAVAIL;
if (k == 2) {
+ _cleanup_free_ char *p = NULL;
+
/* If two parameters are specified, the first one is the lower, the second one the upper directory. And
* we'll also define the destination mount point the same as the upper. */
- if (!source_path_is_valid(lower[0]) ||
- !source_path_is_valid(lower[1]))
- return -EINVAL;
+ r = source_path_parse(lower[0], &p);
+ if (r < 0)
+ return r;
+
+ free_and_replace(lower[0], p);
+
+ r = source_path_parse(lower[1], &p);
+ if (r < 0)
+ return r;
+
+ free_and_replace(lower[1], p);
upper = TAKE_PTR(lower[1]);
@@ -317,22 +350,29 @@ int overlay_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_onl
if (!destination)
return -ENOMEM;
} else {
+ _cleanup_free_ char *p = NULL;
+
/* If more than two parameters are specified, the last one is the destination, the second to last one
* the "upper", and all before that the "lower" directories. */
destination = lower[k - 1];
upper = TAKE_PTR(lower[k - 2]);
- STRV_FOREACH(i, lower)
- if (!source_path_is_valid(*i))
- return -EINVAL;
+ STRV_FOREACH(i, lower) {
+ r = source_path_parse(*i, &p);
+ if (r < 0)
+ return r;
+
+ free_and_replace(*i, p);
+ }
/* If the upper directory is unspecified, then let's create it automatically as a throw-away directory
* in /var/tmp */
- if (isempty(upper))
- upper = mfree(upper);
- else if (!source_path_is_valid(upper))
- return -EINVAL;
+ r = source_path_parse_nullable(upper, &p);
+ if (r < 0)
+ return r;
+
+ free_and_replace(upper, p);
if (!path_is_absolute(destination))
return -EINVAL;