]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
nspawn: optionally, automatically allocated --bind=/--overlay source from /var/tmp
authorLennart Poettering <lennart@poettering.net>
Wed, 30 Nov 2016 17:57:42 +0000 (18:57 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 1 Dec 2016 11:41:18 +0000 (12:41 +0100)
This extends the --bind= and --overlay= syntax so that an empty string as source/upper
directory is taken as request to automatically allocate a temporary directory
below /var/tmp, whose lifetime is bound to the nspawn runtime. In combination
with the "+" path extension this permits a switch "--overlay=+/var::/var" in
order to use the container's shipped /var, combine it with a writable temporary
directory and mount it to the runtime /var of the container.

man/systemd-nspawn.xml
src/nspawn/nspawn-mount.c
src/nspawn/nspawn-mount.h

index 84fa9cadefe9fee8fb9d25f3c13d0b9beb1d67a4..cd0a90d82f3fe6dcbccac5f0b2337be1aa9fff28 100644 (file)
         <term><option>--bind-ro=</option></term>
 
         <listitem><para>Bind mount a file or directory from the host into the container. Takes one of: a path
-        argument — in which case the specified path will be mounted from the host to the same path in the container —,
-        or a colon-separated pair of paths — in which case the first specified path is the source in the host, and the
-        second path is the destination in the container —, or a colon-separated triple of source path, destination path
+        argument — in which case the specified path will be mounted from the host to the same path in the container, or
+        a colon-separated pair of paths — in which case the first specified path is the source in the host, and the
+        second path is the destination in the container, or a colon-separated triple of source path, destination path
         and mount options. The source path may optionally be prefixed with a <literal>+</literal> character. If so, the
-        source path is taken relative to the images root directory. This permits setting up bind mounts within the
-        container image. Mount options are comma-separated and currently, only "rbind" and "norbind" are allowed,
-        controlling whether to create a recursive or a regular bind mount. Defaults to "rbind". 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. The <option>--bind-ro=</option> option
-        creates read-only bind mounts.</para></listitem>
+        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. Mount options are comma-separated and currently, only <option>rbind</option> and
+        <option>norbind</option> are allowed, controlling whether to create a recursive or a regular bind
+        mount. Defaults to "rbind". 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. The <option>--bind-ro=</option> option creates read-only bind mounts.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         two paths have to be specified.</para>
 
         <para>The source paths may optionally be prefixed with <literal>+</literal> character. If so they are taken
-        relative to the image's root directory.</para>
+        relative to the image's root directory. The uppermost source path may also be specified as empty string, in
+        which case a temporary directory below the host's <filename>/var/tmp</filename> is 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 the
+        <literal>--overlay=+/var::/var</literal> option in order to automatically overlay a writable temporary
+        directory on a read-only <filename>/var</filename> directory.</para>
 
         <para>For details about overlay file systems, see <ulink
         url="https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt">overlayfs.txt</ulink>. Note
index 291a88a9ac5035a013d79b65a35b9db9aac23fc0..3a069cf0e02729972c222bb5df36bfe8c013b68a 100644 (file)
@@ -75,6 +75,11 @@ void custom_mount_free_all(CustomMount *l, unsigned n) {
                         free(m->work_dir);
                 }
 
+                if (m->rm_rf_tmpdir) {
+                        (void) rm_rf(m->rm_rf_tmpdir, REMOVE_ROOT|REMOVE_PHYSICAL);
+                        free(m->rm_rf_tmpdir);
+                }
+
                 strv_free(m->lower);
         }
 
@@ -142,6 +147,24 @@ int custom_mount_prepare_all(const char *dest, CustomMount *l, unsigned n) {
 
                         free(m->source);
                         m->source = s;
+                } else {
+                        /* No source specified? In that case, use a throw-away temporary directory in /var/tmp */
+
+                        m->rm_rf_tmpdir = strdup("/var/tmp/nspawn-temp-XXXXXX");
+                        if (!m->rm_rf_tmpdir)
+                                return log_oom();
+
+                        if (!mkdtemp(m->rm_rf_tmpdir)) {
+                                m->rm_rf_tmpdir = mfree(m->rm_rf_tmpdir);
+                                return log_error_errno(errno, "Failed to acquire temporary directory: %m");
+                        }
+
+                        m->source = strjoin(m->rm_rf_tmpdir, "/src");
+                        if (!m->source)
+                                return log_oom();
+
+                        if (mkdir(m->source, 0755) < 0)
+                                return log_error_errno(errno, "Failed to create %s: %m", m->source);
                 }
 
                 if (m->type == CUSTOM_MOUNT_OVERLAY) {
@@ -207,8 +230,11 @@ int bind_mount_parse(CustomMount **l, unsigned *n, const char *s, bool read_only
                         return -ENOMEM;
         }
 
-        if (!source_path_is_valid(source))
+        if (isempty(source))
+                source = NULL;
+        else if (!source_path_is_valid(source))
                 return -EINVAL;
+
         if (!path_is_absolute(destination))
                 return -EINVAL;
 
@@ -288,19 +314,26 @@ int overlay_mount_parse(CustomMount **l, unsigned *n, const char *s, bool read_o
                 if (!destination)
                         return -ENOMEM;
         } else {
-                int i;
+                char **i;
 
                 /* 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. */
 
-                for (i = 0; i < k - 1; i++)
-                        if (!source_path_is_valid(lower[i]))
-                                return -EINVAL;
-
                 destination = lower[k - 1];
                 upper = lower[k - 2];
                 lower[k - 2] = NULL;
 
+                STRV_FOREACH(i, lower)
+                        if (!source_path_is_valid(*i))
+                                return -EINVAL;
+
+                /* If the upper directory is unspecified, then let's create it automatically as a throw-away directory
+                 * in /var/tmp */
+                if (isempty(upper))
+                        upper = NULL;
+                else if (!source_path_is_valid(upper))
+                        return -EINVAL;
+
                 if (!path_is_absolute(destination))
                         return -EINVAL;
         }
index dc8be438ac819f8477f881fd9fd3cd6899b8f9b8..467082a737729aee845eb400c6bf966eb0fe0b7f 100644 (file)
@@ -56,6 +56,7 @@ typedef struct CustomMount {
         char *options;
         char *work_dir;
         char **lower;
+        char *rm_rf_tmpdir;
 } CustomMount;
 
 CustomMount* custom_mount_add(CustomMount **l, unsigned *n, CustomMountType t);