nspawn: optionally, automatically allocated --bind=/--overlay source from /var/tmp

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.
This commit is contained in:
Lennart Poettering 2016-11-30 18:57:42 +01:00
parent 86c0dd4a71
commit c7a4890ce4
3 changed files with 57 additions and 16 deletions

View File

@ -741,16 +741,18 @@
<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>
@ -805,7 +807,12 @@
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

View 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;
}

View 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);