diff --git a/man/systemd-dissect.xml b/man/systemd-dissect.xml index e72c66386a..b65a2c39f1 100644 --- a/man/systemd-dissect.xml +++ b/man/systemd-dissect.xml @@ -124,9 +124,7 @@ project='man-pages'>fstab5. For details see below. - In place of the image path a .v/ versioned directory may be specified, see - systemd.v7 for - details. + diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index f39f1a8ca6..29edbba4cc 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -217,9 +217,7 @@ machinectl1 section "Files and Directories" for the precise search path. - In place of the directory path a .v/ versioned directory may be specified, see - systemd.v7 for - details. + If neither , , nor are specified, the current directory will be used. May not be specified @@ -317,9 +315,7 @@ Any other partitions, such as foreign partitions or swap partitions are not mounted. May not be specified together with , . - In place of the image path a .v/ versioned directory may be specified, see - systemd.v7 for - details. + diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index dac19d6537..05f5f20f44 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -155,9 +155,7 @@ BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout - In place of the directory path a .v/ versioned directory may be specified, - see systemd.v7 for - details. + @@ -195,9 +193,7 @@ systemd-soft-reboot.service8), in case the service is configured to survive it. - In place of the image path a .v/ versioned directory may be specified, see - systemd.v7 for - details. + @@ -555,6 +551,8 @@ PrivateDevices= below, as it may change the setting of DevicePolicy=. + + @@ -590,6 +588,8 @@ Note that usage from user units requires overlayfs support in unprivileged user namespaces, which was first introduced in kernel v5.11. + + diff --git a/man/systemd.v.xml b/man/systemd.v.xml index b29d32f69a..43e77bdba2 100644 --- a/man/systemd.v.xml +++ b/man/systemd.v.xml @@ -26,7 +26,7 @@ In various places systemd components accept paths whose trailing components have the .v/ suffix, pointing to a directory. These components will then automatically look for suitable files inside the directory, do a version comparison and open the newest file found (by - version). Specifically, two expressions are supported: + version). Available since version v256. Specifically, two expressions are supported: diff --git a/man/vpick.xml b/man/vpick.xml new file mode 100644 index 0000000000..e212895947 --- /dev/null +++ b/man/vpick.xml @@ -0,0 +1,17 @@ + + + + + + + + <para id="image">In place of the image path a <literal>.v/</literal> versioned directory may be specified, see + <citerefentry><refentrytitle>systemd.v</refentrytitle><manvolnum>7</manvolnum></citerefentry> for + details.</para> + + <para id="directory">In place of the directory path a <literal>.v/</literal> versioned directory may be specified, + see <citerefentry><refentrytitle>systemd.v</refentrytitle><manvolnum>7</manvolnum></citerefentry> for + details.</para> +</refsect1> diff --git a/src/core/namespace.c b/src/core/namespace.c index d87079ccbc..e55982ffa5 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -47,6 +47,7 @@ #include "tmpfile-util.h" #include "umask-util.h" #include "user-util.h" +#include "vpick.h" #define DEV_MOUNT_OPTIONS (MS_NOSUID|MS_STRICTATIME|MS_NOEXEC) @@ -500,9 +501,24 @@ static int append_extensions( /* First, prepare a mount for each image, but these won't be visible to the unit, instead * they will be mounted in our propagate directory, and used as a source for the overlay. */ for (size_t i = 0; i < n; i++) { + _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL; _cleanup_free_ char *mount_point = NULL; const MountImage *m = mount_images + i; + r = path_pick(/* toplevel_path= */ NULL, + /* toplevel_fd= */ AT_FDCWD, + m->source, + &pick_filter_image_raw, + PICK_ARCHITECTURE|PICK_TRIES, + &result); + if (r < 0) + return r; + if (!result.path) + return log_debug_errno( + SYNTHETIC_ERRNO(ENOENT), + "No matching entry in .v/ directory %s found.", + m->source); + if (asprintf(&mount_point, "%s/%zu", extension_dir, i) < 0) return -ENOMEM; @@ -524,7 +540,7 @@ static int append_extensions( .path_malloc = TAKE_PTR(mount_point), .image_options_const = m->mount_options, .ignore = m->ignore_enoent, - .source_const = m->source, + .source_malloc = TAKE_PTR(result.path), .mode = MOUNT_EXTENSION_IMAGE, .has_prefix = true, }; @@ -534,7 +550,8 @@ static int append_extensions( * Bind mount them in the same location as the ExtensionImages, so that we * can check that they are valid trees (extension-release.d). */ STRV_FOREACH(extension_directory, extension_directories) { - _cleanup_free_ char *mount_point = NULL, *source = NULL; + _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL; + _cleanup_free_ char *mount_point = NULL; const char *e = *extension_directory; bool ignore_enoent = false; @@ -551,9 +568,19 @@ static int append_extensions( if (startswith(e, "+")) e++; - source = strdup(e); - if (!source) - return -ENOMEM; + r = path_pick(/* toplevel_path= */ NULL, + /* toplevel_fd= */ AT_FDCWD, + e, + &pick_filter_image_dir, + PICK_ARCHITECTURE|PICK_TRIES, + &result); + if (r < 0) + return r; + if (!result.path) + return log_debug_errno( + SYNTHETIC_ERRNO(ENOENT), + "No matching entry in .v/ directory %s found.", + e); for (size_t j = 0; hierarchies && hierarchies[j]; ++j) { char *prefixed_hierarchy = path_join(mount_point, hierarchies[j]); @@ -571,7 +598,7 @@ static int append_extensions( *me = (MountEntry) { .path_malloc = TAKE_PTR(mount_point), - .source_malloc = TAKE_PTR(source), + .source_malloc = TAKE_PTR(result.path), .mode = MOUNT_EXTENSION_DIRECTORY, .ignore = ignore_enoent, .has_prefix = true, diff --git a/test/units/testsuite-50.sh b/test/units/testsuite-50.sh index af379a4d8b..e34cbd915b 100755 --- a/test/units/testsuite-50.sh +++ b/test/units/testsuite-50.sh @@ -435,6 +435,18 @@ EOF systemctl start testservice-50e.service systemctl is-active testservice-50e.service +# Check vpick support in ExtensionImages= +VBASE="vtest$RANDOM" +VDIR="/tmp/${VBASE}.v" +mkdir "$VDIR" + +ln -s /usr/share/app0.raw "$VDIR/${VBASE}_0.raw" +ln -s /usr/share/app1.raw "$VDIR/${VBASE}_1.raw" + +systemd-run -P -p ExtensionImages="$VDIR" bash -c '/opt/script1.sh | grep ID' + +rm -rf "$VDIR" + # ExtensionDirectories will set up an overlay mkdir -p "${image_dir}/app0" "${image_dir}/app1" "${image_dir}/app-nodistro" "${image_dir}/service-scoped-test" (! systemd-run -P --property ExtensionDirectories="${image_dir}/nonexistent" --property RootImage="${image}.raw" cat /opt/script0.sh) @@ -467,6 +479,19 @@ RemainAfterExit=yes EOF systemctl start testservice-50f.service systemctl is-active testservice-50f.service + +# Check vpick support in ExtensionDirectories= +VBASE="vtest$RANDOM" +VDIR="/tmp/${VBASE}.v" +mkdir "$VDIR" + +ln -s "${image_dir}/app0" "$VDIR/${VBASE}_0" +ln -s "${image_dir}/app1" "$VDIR/${VBASE}_1" + +systemd-run -P --property ExtensionDirectories="$VDIR" cat /opt/script1.sh | grep -q -F "extension-release.app2" + +rm -rf "$VDIR" + systemd-dissect --umount "${image_dir}/app0" systemd-dissect --umount "${image_dir}/app1"