]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
nspawn: Support relative source paths for --bind and --overlay 23979/head
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 11 Jul 2022 19:45:08 +0000 (21:45 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Tue, 12 Jul 2022 11:14:11 +0000 (13:14 +0200)
man/systemd-nspawn.xml
src/nspawn/nspawn-mount.c

index b5a02f0a788a7ad5812adca18794354d11faf5ce..975ddd0be33566200bc9b1795656bb999dc548bb 100644 (file)
@@ -1357,7 +1357,8 @@ After=sys-subsystem-net-devices-ens1.device</programlisting>
         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 <filename>/var/tmp/</filename> directory is used. It is automatically removed when the container is
-        shut down. The <option>--bind-ro=</option> 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>--bind-ro=</option> option creates read-only bind mounts. Backslash escapes are interpreted,
         so <literal>\:</literal> may be used to embed colons in either path. This option may be specified
         multiple times for creating multiple independent bind mount points.</para>
 
@@ -1481,7 +1482,8 @@ After=sys-subsystem-net-devices-ens1.device</programlisting>
         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 <literal>--overlay=+/var::/var</literal> in order to automatically overlay a writable
-        temporary directory on a read-only <filename>/var/</filename> directory.</para>
+        temporary directory on a read-only <filename>/var/</filename> directory. If a source path is not
+        absolute, it is resolved relative to the current working directory.</para>
 
         <para>For details about overlay file systems, see <ulink
         url="https://docs.kernel.org/filesystems/overlayfs.html">Overlay Filesystem</ulink>.
index 26a2cc9e7ec76bf712d7e5460accb6e52209e00a..60cb007baa9e43a997c3c113687590a2eec90e4f 100644 (file)
@@ -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 (isempty(p))
+                return -EINVAL;
+
+        if (*p == '+') {
+                if (!path_is_absolute(p + 1))
+                        return -EINVAL;
+
+                char *s = strdup(p);
+                if (!s)
+                        return -ENOMEM;
 
-        if (*p == '+')
-                p++;
+                *ret = TAKE_PTR(s);
+                return 0;
+        }
 
-        return path_is_absolute(p);
+        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,7 +237,7 @@ 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;
+        _cleanup_free_ char *source = NULL, *destination = NULL, *opts = NULL, *p = NULL;
         CustomMount *m;
         int r;
 
@@ -235,10 +260,9 @@ int bind_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only)
                         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;
@@ -247,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);
@@ -295,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)
@@ -303,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]);
 
@@ -316,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;