diff options
author | Lennart Poettering <lennart@poettering.net> | 2024-12-09 11:38:05 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2024-12-20 18:04:01 +0100 |
commit | 1c0ade2e1f76b50431f941980b76e8ec5cdf3b12 (patch) | |
tree | 80712c9107ab7c761a4d82c74c84b309ef4ab045 | |
parent | po: Translated using Weblate (Finnish) (diff) | |
download | systemd-1c0ade2e1f76b50431f941980b76e8ec5cdf3b12.tar.xz systemd-1c0ade2e1f76b50431f941980b76e8ec5cdf3b12.zip |
discover-image: introduce per-user image directories
We nowadays support unprivileged invocation of systemd-nspawn +
systemd-vmspawn, but there was no support for discovering suitable disk
images (i.e. no per-user counterpart of /var/lib/machines). Add this
now, and hook it up everywhere.
Instead of hardcoding machined's, importd's, portabled's, sysupdated's
image discovery to RUNTIME_SCOPE_SYSTEM I introduced a field that make
the scope variable, even if this field is always initialized to
RUNTIME_SCOPE_SYSTEM for now. I think these four services should
eventually be updated to support a per-user concept too, this is
preparation for that, even though it doesn't outright add support for
this.
This is for the largest part not user visible, except for in nspawn,
vmspawn and the dissect tool. For the latter I added a pair of
--user/--system switches to select the discovery scope.
30 files changed, 317 insertions, 85 deletions
diff --git a/man/systemd-dissect.xml b/man/systemd-dissect.xml index b65a2c39f1..191ae3394b 100644 --- a/man/systemd-dissect.xml +++ b/man/systemd-dissect.xml @@ -503,6 +503,17 @@ <xi:include href="version-info.xml" xpointer="v254"/></listitem> </varlistentry> + <varlistentry> + <term><option>--system</option></term> + <term><option>--user</option></term> + + <listitem><para>When used together with <option>--discover</option> controls whether to search for + images installed system-wide or in the user's directories in <varname>$HOME</varname>. If neither + switch is specified, will search within both scopes.</para> + + <xi:include href="version-info.xml" xpointer="v258"/></listitem> + </varlistentry> + <xi:include href="standard-options.xml" xpointer="image-policy-open" /> <xi:include href="standard-options.xml" xpointer="no-pager" /> <xi:include href="standard-options.xml" xpointer="no-legend" /> diff --git a/shell-completion/bash/systemd-dissect b/shell-completion/bash/systemd-dissect index 8d2b43423c..a9fa639c3f 100644 --- a/shell-completion/bash/systemd-dissect +++ b/shell-completion/bash/systemd-dissect @@ -29,6 +29,8 @@ _systemd_dissect() { local cur=${COMP_WORDS[COMP_CWORD]} prev_1=${COMP_WORDS[COMP_CWORD-1]} prev_2=${COMP_WORDS[COMP_CWORD-2]} words cword local -A OPTS=( [STANDALONE]='-h --help --version + --user + --system --discover --no-pager --no-legend diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c index 78a830d574..8739e130c3 100644 --- a/src/dissect/dissect.c +++ b/src/dissect/dissect.c @@ -95,6 +95,7 @@ static char *arg_loop_ref = NULL; static ImagePolicy *arg_image_policy = NULL; static bool arg_mtree_hash = true; static bool arg_via_service = false; +static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID; STATIC_DESTRUCTOR_REGISTER(arg_image, freep); STATIC_DESTRUCTOR_REGISTER(arg_root, freep); @@ -151,6 +152,8 @@ static int help(void) { " Generate JSON output\n" " --loop-ref=NAME Set reference string for loopback device\n" " --mtree-hash=BOOL Whether to include SHA256 hash in the mtree output\n" + " --user Discover user images\n" + " --system Discover system images\n" "\n%3$sCommands:%4$s\n" " -h --help Show this help\n" " --version Show package version\n" @@ -274,6 +277,8 @@ static int parse_argv(int argc, char *argv[]) { ARG_VALIDATE, ARG_MTREE_HASH, ARG_MAKE_ARCHIVE, + ARG_SYSTEM, + ARG_USER, }; static const struct option options[] = { @@ -307,10 +312,13 @@ static int parse_argv(int argc, char *argv[]) { { "validate", no_argument, NULL, ARG_VALIDATE }, { "mtree-hash", required_argument, NULL, ARG_MTREE_HASH }, { "make-archive", no_argument, NULL, ARG_MAKE_ARCHIVE }, + { "system", no_argument, NULL, ARG_SYSTEM }, + { "user", no_argument, NULL, ARG_USER }, {} }; _cleanup_free_ char **buf = NULL; /* we use free(), not strv_free() here, as we don't copy the strings here */ + bool system_scope_requested = false, user_scope_requested = false; int c, r; assert(argc >= 0); @@ -531,7 +539,6 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_MAKE_ARCHIVE: - r = dlopen_libarchive(); if (r < 0) return log_error_errno(r, "Archive support not available (compiled without libarchive, or libarchive not installed?)."); @@ -539,6 +546,14 @@ static int parse_argv(int argc, char *argv[]) { arg_action = ACTION_MAKE_ARCHIVE; break; + case ARG_SYSTEM: + system_scope_requested = true; + break; + + case ARG_USER: + user_scope_requested = true; + break; + case '?': return -EINVAL; @@ -547,6 +562,10 @@ static int parse_argv(int argc, char *argv[]) { } } + if (system_scope_requested || user_scope_requested) + arg_runtime_scope = system_scope_requested && user_scope_requested ? _RUNTIME_SCOPE_INVALID : + system_scope_requested ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER; + switch (arg_action) { case ACTION_DISSECT: @@ -1851,7 +1870,7 @@ static int action_discover(void) { return log_oom(); for (ImageClass cl = 0; cl < _IMAGE_CLASS_MAX; cl++) { - r = image_discover(cl, NULL, images); + r = image_discover(arg_runtime_scope, cl, NULL, images); if (r < 0) return log_error_errno(r, "Failed to discover images: %m"); } diff --git a/src/import/export.c b/src/import/export.c index 1e82e84d7d..346aca9446 100644 --- a/src/import/export.c +++ b/src/import/export.c @@ -25,6 +25,7 @@ static ImportCompressType arg_compress = IMPORT_COMPRESS_UNKNOWN; static ImageClass arg_class = IMAGE_MACHINE; +static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID; static void determine_compression_from_filename(const char *p) { @@ -66,7 +67,7 @@ static int export_tar(int argc, char *argv[], void *userdata) { local = argv[1]; if (image_name_is_valid(local)) { - r = image_find(arg_class, local, NULL, &image); + r = image_find(arg_runtime_scope, arg_class, local, NULL, &image); if (r == -ENOENT) return log_error_errno(r, "Image %s not found.", local); if (r < 0) @@ -139,7 +140,7 @@ static int export_raw(int argc, char *argv[], void *userdata) { local = argv[1]; if (image_name_is_valid(local)) { - r = image_find(arg_class, local, NULL, &image); + r = image_find(arg_runtime_scope, arg_class, local, NULL, &image); if (r == -ENOENT) return log_error_errno(r, "Image %s not found.", local); if (r < 0) diff --git a/src/import/import-fs.c b/src/import/import-fs.c index e74d36288a..440ae85ba1 100644 --- a/src/import/import-fs.c +++ b/src/import/import-fs.c @@ -34,6 +34,7 @@ static bool arg_sync = true; static bool arg_direct = false; static const char *arg_image_root = NULL; static ImageClass arg_class = IMAGE_MACHINE; +static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID; typedef struct ProgressInfo { RateLimit limit; @@ -145,7 +146,7 @@ static int import_fs(int argc, char *argv[], void *userdata) { return log_oom(); if (!arg_force) { - r = image_find(arg_class, local, NULL, NULL); + r = image_find(arg_runtime_scope, arg_class, local, NULL, NULL); if (r < 0) { if (r != -ENOENT) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); diff --git a/src/import/import.c b/src/import/import.c index 97db0b836a..6568c59156 100644 --- a/src/import/import.c +++ b/src/import/import.c @@ -30,6 +30,7 @@ static const char *arg_image_root = NULL; static ImportFlags arg_import_flags = IMPORT_BTRFS_SUBVOL | IMPORT_BTRFS_QUOTA | IMPORT_CONVERT_QCOW2 | IMPORT_SYNC; static uint64_t arg_offset = UINT64_MAX, arg_size_max = UINT64_MAX; static ImageClass arg_class = IMAGE_MACHINE; +static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID; static int normalize_local(const char *local, char **ret) { _cleanup_free_ char *ll = NULL; @@ -63,7 +64,7 @@ static int normalize_local(const char *local, char **ret) { local = "imported"; if (!FLAGS_SET(arg_import_flags, IMPORT_FORCE)) { - r = image_find(arg_class, local, NULL, NULL); + r = image_find(arg_runtime_scope, arg_class, local, NULL, NULL); if (r < 0) { if (r != -ENOENT) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); diff --git a/src/import/importd.c b/src/import/importd.c index db081205ab..ea8257a833 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -111,6 +111,8 @@ struct Manager { bool use_btrfs_subvol; bool use_btrfs_quota; + + RuntimeScope runtime_scope; /* for now: always RUNTIME_SCOPE_SYSTEM */ }; #define TRANSFERS_MAX 64 @@ -721,6 +723,7 @@ static int manager_new(Manager **ret) { *m = (Manager) { .use_btrfs_subvol = true, .use_btrfs_quota = true, + .runtime_scope = RUNTIME_SCOPE_SYSTEM, }; r = sd_event_default(&m->event); @@ -1332,6 +1335,7 @@ static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_er static int method_list_images(sd_bus_message *msg, void *userdata, sd_bus_error *error) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; ImageClass class = _IMAGE_CLASS_INVALID; + Manager *m = ASSERT_PTR(userdata); int r; assert(msg); @@ -1372,7 +1376,7 @@ static int method_list_images(sd_bus_message *msg, void *userdata, sd_bus_error if (!h) return -ENOMEM; - r = image_discover(c, /* root= */ NULL, h); + r = image_discover(m->runtime_scope, c, /* root= */ NULL, h); if (r < 0) { if (class >= 0) return r; diff --git a/src/import/pull.c b/src/import/pull.c index 46055ce5e7..b2614fa8f5 100644 --- a/src/import/pull.c +++ b/src/import/pull.c @@ -33,6 +33,7 @@ static ImportFlags arg_import_flags = IMPORT_PULL_SETTINGS | IMPORT_PULL_ROOTHAS static uint64_t arg_offset = UINT64_MAX, arg_size_max = UINT64_MAX; static char *arg_checksum = NULL; static ImageClass arg_class = IMAGE_MACHINE; +static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID; STATIC_DESTRUCTOR_REGISTER(arg_checksum, freep); @@ -66,7 +67,7 @@ static int normalize_local(const char *local, const char *url, char **ret) { local); if (!FLAGS_SET(arg_import_flags, IMPORT_FORCE)) { - r = image_find(arg_class, local, NULL, NULL); + r = image_find(arg_runtime_scope, arg_class, local, NULL, NULL); if (r < 0) { if (r != -ENOENT) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index 8eca1e4c95..8f18e78c7d 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -178,7 +178,7 @@ int bus_image_method_clone( return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m"); if (r == 0) { errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]); - r = image_clone(image, new_name, read_only); + r = image_clone(image, new_name, read_only, m->runtime_scope); report_errno_and_exit(errno_pipe_fd[1], r); } @@ -402,6 +402,7 @@ char* image_bus_path(const char *name) { static int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { _cleanup_hashmap_free_ Hashmap *images = NULL; _cleanup_strv_free_ char **l = NULL; + Manager *m = ASSERT_PTR(userdata); Image *image; int r; @@ -413,7 +414,7 @@ static int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, if (!images) return -ENOMEM; - r = image_discover(IMAGE_MACHINE, NULL, images); + r = image_discover(m->runtime_scope, IMAGE_MACHINE, NULL, images); if (r < 0) return r; diff --git a/src/machine/image-varlink.c b/src/machine/image-varlink.c index 5eb636960d..1784de6146 100644 --- a/src/machine/image-varlink.c +++ b/src/machine/image-varlink.c @@ -148,7 +148,7 @@ int vl_method_clone_image(sd_varlink *link, sd_json_variant *parameters, sd_varl return log_debug_errno(r, "Failed to fork: %m"); if (r == 0) { errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]); - r = image_clone(image, p.new_name, p.read_only > 0); + r = image_clone(image, p.new_name, p.read_only > 0, manager->runtime_scope); report_errno_and_exit(errno_pipe_fd[1], r); } diff --git a/src/machine/machined-core.c b/src/machine/machined-core.c index b1468b62c6..52cb915c30 100644 --- a/src/machine/machined-core.c +++ b/src/machine/machined-core.c @@ -440,7 +440,7 @@ int manager_acquire_image(Manager *m, const char *name, Image **ret) { return log_debug_errno(r, "Failed to enable source: %m") ; _cleanup_(image_unrefp) Image *image = NULL; - r = image_find(IMAGE_MACHINE, name, NULL, &image); + r = image_find(m->runtime_scope, IMAGE_MACHINE, name, NULL, &image); if (r < 0) return log_debug_errno(r, "Failed to find image: %m"); @@ -467,7 +467,7 @@ int rename_image_and_update_cache(Manager *m, Image *image, const char* new_name /* The image is cached with its name, hence it is necessary to remove from the cache before renaming. */ assert_se(hashmap_remove_value(m->image_cache, image->name, image)); - r = image_rename(image, new_name); + r = image_rename(image, new_name, m->runtime_scope); if (r < 0) { image = image_unref(image); return r; diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index f4915f67da..fc50d3f147 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -123,7 +123,7 @@ static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_erro if (r < 0) return r; - r = image_find(IMAGE_MACHINE, name, NULL, NULL); + r = image_find(m->runtime_scope, IMAGE_MACHINE, name, NULL, NULL); if (r == -ENOENT) return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name); if (r < 0) @@ -476,7 +476,7 @@ static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_er if (!images) return -ENOMEM; - r = image_discover(IMAGE_MACHINE, NULL, images); + r = image_discover(m->runtime_scope, IMAGE_MACHINE, NULL, images); if (r < 0) return r; @@ -753,7 +753,7 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err goto child_fail; } - r = image_discover(IMAGE_MACHINE, NULL, images); + r = image_discover(m->runtime_scope, IMAGE_MACHINE, NULL, images); if (r < 0) goto child_fail; diff --git a/src/machine/machined-varlink.c b/src/machine/machined-varlink.c index e0e27c4496..104b841dd5 100644 --- a/src/machine/machined-varlink.c +++ b/src/machine/machined-varlink.c @@ -641,6 +641,7 @@ static int list_image_one_and_maybe_read_metadata(sd_varlink *link, Image *image } static int vl_method_list_images(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { + Manager *m = ASSERT_PTR(userdata); struct params { const char *image_name; AcquireMetadata acquire_metadata; @@ -667,7 +668,7 @@ static int vl_method_list_images(sd_varlink *link, sd_json_variant *parameters, if (!image_name_is_valid(p.image_name)) return sd_varlink_error_invalid_parameter_name(link, "name"); - r = image_find(IMAGE_MACHINE, p.image_name, /* root = */ NULL, &found); + r = image_find(m->runtime_scope, IMAGE_MACHINE, p.image_name, /* root = */ NULL, &found); if (r == -ENOENT) return sd_varlink_error(link, "io.systemd.MachineImage.NoSuchImage", NULL); if (r < 0) @@ -683,7 +684,7 @@ static int vl_method_list_images(sd_varlink *link, sd_json_variant *parameters, if (!images) return -ENOMEM; - r = image_discover(IMAGE_MACHINE, /* root = */ NULL, images); + r = image_discover(m->runtime_scope, IMAGE_MACHINE, /* root = */ NULL, images); if (r < 0) return log_debug_errno(r, "Failed to discover images: %m"); diff --git a/src/machine/machined.c b/src/machine/machined.c index a0c4ef751a..3a235aa0d4 100644 --- a/src/machine/machined.c +++ b/src/machine/machined.c @@ -40,10 +40,14 @@ static int manager_new(Manager **ret) { assert(ret); - m = new0(Manager, 1); + m = new(Manager, 1); if (!m) return -ENOMEM; + *m = (Manager) { + .runtime_scope = RUNTIME_SCOPE_SYSTEM, + }; + m->machines = hashmap_new(&machine_hash_ops); if (!m->machines) return -ENOMEM; diff --git a/src/machine/machined.h b/src/machine/machined.h index 3d1f502699..758678a205 100644 --- a/src/machine/machined.h +++ b/src/machine/machined.h @@ -42,6 +42,8 @@ struct Manager { sd_varlink_server *varlink_userdb_server; sd_varlink_server *varlink_machine_server; + + RuntimeScope runtime_scope; /* for now: always RUNTIME_SCOPE_SYSTEM */ }; int manager_add_machine(Manager *m, const char *name, Machine **ret); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 66a8771eea..1b452014e3 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -3167,7 +3167,8 @@ static int determine_names(void) { if (arg_machine) { _cleanup_(image_unrefp) Image *i = NULL; - r = image_find(IMAGE_MACHINE, arg_machine, NULL, &i); + r = image_find(arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER, + IMAGE_MACHINE, arg_machine, NULL, &i); if (r == -ENOENT) return log_error_errno(r, "No image for machine '%s'.", arg_machine); if (r < 0) diff --git a/src/portable/portable.c b/src/portable/portable.c index 18a8060a9f..61c13abe12 100644 --- a/src/portable/portable.c +++ b/src/portable/portable.c @@ -173,6 +173,7 @@ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(portable_metadata_hash_ops, char, PortableMetadata, portable_metadata_unref); static int extract_now( + RuntimeScope scope, const char *where, char **matches, const char *image_name, @@ -199,6 +200,7 @@ static int extract_now( * parent. To handle both cases in one call this function also gets a 'socket_fd' parameter, which when >= 0 is * used to send the data to the parent. */ + assert(scope < _RUNTIME_SCOPE_MAX); assert(where); /* First, find os-release/extension-release and send it upstream (or just save it). */ @@ -248,7 +250,7 @@ static int extract_now( /* Then, send unit file data to the parent (or/and add it to the hashmap). For that we use our usual unit * discovery logic. Note that we force looking inside of /lib/systemd/system/ for units too, as the * image might have a legacy split-usr layout. */ - r = lookup_paths_init(&paths, RUNTIME_SCOPE_SYSTEM, LOOKUP_PATHS_SPLIT_USR, where); + r = lookup_paths_init(&paths, scope, LOOKUP_PATHS_SPLIT_USR, where); if (r < 0) return log_debug_errno(r, "Failed to acquire lookup paths: %m"); @@ -348,6 +350,7 @@ static int extract_now( } static int portable_extract_by_path( + RuntimeScope scope, const char *path, bool path_is_extension, bool relax_extension_release_check, @@ -381,7 +384,7 @@ static int portable_extract_by_path( if (r < 0) return log_error_errno(r, "Failed to extract image name from path '%s': %m", path); - r = extract_now(path, matches, image_name, path_is_extension, /* relax_extension_release_check= */ false, -1, &os_release, &unit_files); + r = extract_now(scope, path, matches, image_name, path_is_extension, /* relax_extension_release_check= */ false, -1, &os_release, &unit_files); if (r < 0) return r; @@ -458,7 +461,7 @@ static int portable_extract_by_path( goto child_finish; } - r = extract_now(tmpdir, matches, m->image_name, path_is_extension, relax_extension_release_check, seq[1], NULL, NULL); + r = extract_now(scope, tmpdir, matches, m->image_name, path_is_extension, relax_extension_release_check, seq[1], NULL, NULL); child_finish: _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS); @@ -549,6 +552,7 @@ static int portable_extract_by_path( } static int extract_image_and_extensions( + RuntimeScope scope, const char *name_or_path, char **matches, char **extension_image_paths, @@ -595,7 +599,7 @@ static int extract_image_and_extensions( name_or_path = result.path; } - r = image_find_harder(IMAGE_PORTABLE, name_or_path, /* root= */ NULL, &image); + r = image_find_harder(scope, IMAGE_PORTABLE, name_or_path, /* root= */ NULL, &image); if (r < 0) return r; @@ -633,7 +637,7 @@ static int extract_image_and_extensions( path = ext_result.path; } - r = image_find_harder(IMAGE_PORTABLE, path, NULL, &new); + r = image_find_harder(scope, IMAGE_PORTABLE, path, NULL, &new); if (r < 0) return r; @@ -645,6 +649,7 @@ static int extract_image_and_extensions( } r = portable_extract_by_path( + scope, image->path, /* path_is_extension= */ false, /* relax_extension_release_check= */ false, @@ -687,6 +692,7 @@ static int extract_image_and_extensions( const char *e; r = portable_extract_by_path( + scope, ext->path, /* path_is_extension= */ true, relax_extension_release_check, @@ -754,6 +760,7 @@ static int extract_image_and_extensions( } int portable_extract( + RuntimeScope scope, const char *name_or_path, char **matches, char **extension_image_paths, @@ -775,6 +782,7 @@ int portable_extract( assert(name_or_path); r = extract_image_and_extensions( + scope, name_or_path, matches, extension_image_paths, @@ -1426,6 +1434,7 @@ static int image_target_path( } static int install_image( + RuntimeScope scope, const char *image_path, PortableFlags flags, PortableChange **changes, @@ -1434,13 +1443,14 @@ static int install_image( _cleanup_free_ char *target = NULL; int r; + assert(scope < _RUNTIME_SCOPE_MAX); assert(image_path); /* If the image is outside of the image search also link it into it, so that it can be found with * short image names and is listed among the images. If we are operating in mixed mode, the image is * copied instead. */ - if (image_in_search_path(IMAGE_PORTABLE, NULL, image_path)) + if (image_in_search_path(scope, IMAGE_PORTABLE, NULL, image_path)) return 0; r = image_target_path(image_path, flags, &target); @@ -1485,6 +1495,7 @@ static int install_image( } static int install_image_and_extensions( + RuntimeScope scope, const Image *image, OrderedHashmap *extension_images, PortableFlags flags, @@ -1497,12 +1508,12 @@ static int install_image_and_extensions( assert(image); ORDERED_HASHMAP_FOREACH(ext, extension_images) { - r = install_image(ext->path, flags, changes, n_changes); + r = install_image(scope, ext->path, flags, changes, n_changes); if (r < 0) return r; } - r = install_image(image->path, flags, changes, n_changes); + r = install_image(scope, image->path, flags, changes, n_changes); if (r < 0) return r; @@ -1595,6 +1606,7 @@ static void log_portable_verb( } int portable_attach( + RuntimeScope scope, sd_bus *bus, const char *name_or_path, char **matches, @@ -1615,7 +1627,10 @@ int portable_attach( PortableMetadata *item; int r; + assert(scope < _RUNTIME_SCOPE_MAX); + r = extract_image_and_extensions( + scope, name_or_path, matches, extension_image_paths, @@ -1672,13 +1687,13 @@ int portable_attach( strempty(extensions_joined)); } - r = lookup_paths_init(&paths, RUNTIME_SCOPE_SYSTEM, /* flags= */ 0, NULL); + r = lookup_paths_init(&paths, scope, /* flags= */ 0, NULL); if (r < 0) return r; if (!FLAGS_SET(flags, PORTABLE_REATTACH) && !FLAGS_SET(flags, PORTABLE_FORCE_ATTACH)) HASHMAP_FOREACH(item, unit_files) { - r = unit_file_exists(RUNTIME_SCOPE_SYSTEM, &paths, item->name); + r = unit_file_exists(scope, &paths, item->name); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to determine whether unit '%s' exists on the host: %m", item->name); if (r > 0) @@ -1700,7 +1715,7 @@ int portable_attach( /* We don't care too much for the image symlink/copy, it's just a convenience thing, it's not necessary for * proper operation otherwise. */ - (void) install_image_and_extensions(image, extension_images, flags, changes, n_changes); + (void) install_image_and_extensions(scope, image, extension_images, flags, changes, n_changes); log_portable_verb( "attached", @@ -1844,6 +1859,7 @@ static int test_chroot_dropin( } int portable_detach( + RuntimeScope scope, sd_bus *bus, const char *name_or_path, char **extension_image_paths, @@ -1857,12 +1873,12 @@ int portable_detach( _cleanup_free_ char *extensions = NULL; _cleanup_closedir_ DIR *d = NULL; const char *where, *item; - int ret = 0; - int r; + int r, ret = 0; + assert(scope < _RUNTIME_SCOPE_MAX); assert(name_or_path); - r = lookup_paths_init(&paths, RUNTIME_SCOPE_SYSTEM, /* flags= */ 0, NULL); + r = lookup_paths_init(&paths, scope, /* flags= */ 0, NULL); if (r < 0) return r; @@ -1930,7 +1946,7 @@ int portable_detach( if (r == 0) break; - if (path_is_absolute(image) && !image_in_search_path(IMAGE_PORTABLE, NULL, image)) { + if (path_is_absolute(image) && !image_in_search_path(scope, IMAGE_PORTABLE, NULL, image)) { r = set_ensure_consume(&markers, &path_hash_ops_free, TAKE_PTR(image)); if (r < 0) return r; @@ -2031,6 +2047,7 @@ not_found: } static int portable_get_state_internal( + RuntimeScope scope, sd_bus *bus, const char *name_or_path, char **extension_image_paths, @@ -2045,10 +2062,11 @@ static int portable_get_state_internal( const char *where; int r; + assert(scope < _RUNTIME_SCOPE_MAX); assert(name_or_path); assert(ret); - r = lookup_paths_init(&paths, RUNTIME_SCOPE_SYSTEM, /* flags= */ 0, NULL); + r = lookup_paths_init(&paths, scope, /* flags= */ 0, NULL); if (r < 0) return r; @@ -2084,7 +2102,7 @@ static int portable_get_state_internal( if (r == 0) continue; - r = unit_file_lookup_state(RUNTIME_SCOPE_SYSTEM, &paths, de->d_name, &state); + r = unit_file_lookup_state(scope, &paths, de->d_name, &state); if (r < 0) return log_debug_errno(r, "Failed to determine unit file state of '%s': %m", de->d_name); if (!IN_SET(state, UNIT_FILE_STATIC, UNIT_FILE_DISABLED, UNIT_FILE_LINKED, UNIT_FILE_LINKED_RUNTIME)) @@ -2109,6 +2127,7 @@ static int portable_get_state_internal( } int portable_get_state( + RuntimeScope scope, sd_bus *bus, const char *name_or_path, char **extension_image_paths, @@ -2125,12 +2144,19 @@ int portable_get_state( /* We look for matching units twice: once in the regular directories, and once in the runtime directories — but * the latter only if we didn't find anything in the former. */ - r = portable_get_state_internal(bus, name_or_path, extension_image_paths, flags & ~PORTABLE_RUNTIME, &state, error); + r = portable_get_state_internal( + scope, + bus, + name_or_path, + extension_image_paths, + flags & ~PORTABLE_RUNTIME, + &state, + error); if (r < 0) return r; if (state == PORTABLE_DETACHED) { - r = portable_get_state_internal(bus, name_or_path, extension_image_paths, flags | PORTABLE_RUNTIME, &state, error); + r = portable_get_state_internal(scope, bus, name_or_path, extension_image_paths, flags | PORTABLE_RUNTIME, &state, error); if (r < 0) return r; } diff --git a/src/portable/portable.h b/src/portable/portable.h index 281b57e321..03977159f0 100644 --- a/src/portable/portable.h +++ b/src/portable/portable.h @@ -6,6 +6,7 @@ #include "dissect-image.h" #include "hashmap.h" #include "macro.h" +#include "runtime-scope.h" #include "set.h" #include "string-util.h" @@ -69,12 +70,12 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(PortableMetadata*, portable_metadata_unref); int portable_metadata_hashmap_to_sorted_array(Hashmap *unit_files, PortableMetadata ***ret); -int portable_extract(const char *image, char **matches, char **extension_image_paths, const ImagePolicy *image_policy, PortableFlags flags, PortableMetadata **ret_os_release, OrderedHashmap **ret_extension_releases, Hashmap **ret_unit_files, char ***ret_valid_prefixes, sd_bus_error *error); +int portable_extract(RuntimeScope scope, const char *image, char **matches, char **extension_image_paths, const ImagePolicy *image_policy, PortableFlags flags, PortableMetadata **ret_os_release, OrderedHashmap **ret_extension_releases, Hashmap **ret_unit_files, char ***ret_valid_prefixes, sd_bus_error *error); -int portable_attach(sd_bus *bus, const char *name_or_path, char **matches, const char *profile, char **extension_images, const ImagePolicy* image_policy, PortableFlags flags, PortableChange **changes, size_t *n_changes, sd_bus_error *error); -int portable_detach(sd_bus *bus, const char *name_or_path, char **extension_image_paths, PortableFlags flags, PortableChange **changes, size_t *n_changes, sd_bus_error *error); +int portable_attach(RuntimeScope scope, sd_bus *bus, const char *name_or_path, char **matches, const char *profile, char **extension_images, const ImagePolicy* image_policy, PortableFlags flags, PortableChange **changes, size_t *n_changes, sd_bus_error *error); +int portable_detach(RuntimeScope scope, sd_bus *bus, const char *name_or_path, char **extension_image_paths, PortableFlags flags, PortableChange **changes, size_t *n_changes, sd_bus_error *error); -int portable_get_state(sd_bus *bus, const char *name_or_path, char **extension_image_paths, PortableFlags flags, PortableState *ret, sd_bus_error *error); +int portable_get_state(RuntimeScope scope, sd_bus *bus, const char *name_or_path, char **extension_image_paths, PortableFlags flags, PortableState *ret, sd_bus_error *error); int portable_get_profiles(char ***ret); diff --git a/src/portable/portabled-bus.c b/src/portable/portabled-bus.c index 4f239e2b12..0476796dbe 100644 --- a/src/portable/portabled-bus.c +++ b/src/portable/portabled-bus.c @@ -165,6 +165,7 @@ static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_er return r; r = portable_get_state( + m->runtime_scope, sd_bus_message_get_bus(message), image->path, NULL, @@ -225,6 +226,7 @@ static int method_get_image_metadata(sd_bus_message *message, void *userdata, sd static int method_get_image_state(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_strv_free_ char **extension_images = NULL; + Manager *m = ASSERT_PTR(userdata); const char *name_or_path; PortableState state; int r; @@ -254,6 +256,7 @@ static int method_get_image_state(sd_bus_message *message, void *userdata, sd_bu } r = portable_get_state( + m->runtime_scope, sd_bus_message_get_bus(message), name_or_path, extension_images, @@ -330,6 +333,7 @@ static int method_detach_image(sd_bus_message *message, void *userdata, sd_bus_e return 1; /* Will call us back */ r = portable_detach( + m->runtime_scope, sd_bus_message_get_bus(message), name_or_path, extension_images, diff --git a/src/portable/portabled-image-bus.c b/src/portable/portabled-image-bus.c index 0ca04d3a0b..ab0e44e038 100644 --- a/src/portable/portabled-image-bus.c +++ b/src/portable/portabled-image-bus.c @@ -114,10 +114,8 @@ int bus_image_common_get_metadata( assert(name_or_path || image); assert(message); - if (!m) { - assert(image); - m = image->userdata; - } + if (!m) + m = ASSERT_PTR(ASSERT_PTR(image)->userdata); bool have_exti = sd_bus_message_is_method_call(message, NULL, "GetImageMetadataWithExtensions") || sd_bus_message_is_method_call(message, NULL, "GetMetadataWithExtensions"); @@ -160,6 +158,7 @@ int bus_image_common_get_metadata( return 1; r = portable_extract( + m->runtime_scope, image->path, matches, extension_images, @@ -264,6 +263,7 @@ static int bus_image_method_get_state( _cleanup_strv_free_ char **extension_images = NULL; Image *image = ASSERT_PTR(userdata); + Manager *m = ASSERT_PTR(image->userdata); PortableState state; int r; @@ -288,6 +288,7 @@ static int bus_image_method_get_state( } r = portable_get_state( + m->runtime_scope, sd_bus_message_get_bus(message), image->path, extension_images, @@ -385,6 +386,7 @@ int bus_image_common_attach( return 1; r = portable_attach( + m->runtime_scope, sd_bus_message_get_bus(message), image->path, matches, @@ -463,6 +465,7 @@ static int bus_image_method_detach( return 1; /* Will call us back */ r = portable_detach( + m->runtime_scope, sd_bus_message_get_bus(message), image->path, extension_images, @@ -513,6 +516,7 @@ int bus_image_common_remove( return 1; /* Will call us back */ r = portable_get_state( + m->runtime_scope, sd_bus_message_get_bus(message), image->path, NULL, @@ -716,6 +720,7 @@ int bus_image_common_reattach( return 1; r = portable_detach( + m->runtime_scope, sd_bus_message_get_bus(message), image->path, extension_images, @@ -727,6 +732,7 @@ int bus_image_common_reattach( return r; r = portable_attach( + m->runtime_scope, sd_bus_message_get_bus(message), image->path, matches, @@ -1039,7 +1045,7 @@ int bus_image_acquire( if (image_name_is_valid(name_or_path)) { /* If it's a short name, let's search for it */ - r = image_find(IMAGE_PORTABLE, name_or_path, NULL, &loaded); + r = image_find(m->runtime_scope, IMAGE_PORTABLE, name_or_path, NULL, &loaded); if (r == -ENOENT) return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PORTABLE_IMAGE, "No image '%s' found.", name_or_path); diff --git a/src/portable/portabled-image.c b/src/portable/portabled-image.c index 6d2839125f..50e0e7a99c 100644 --- a/src/portable/portabled-image.c +++ b/src/portable/portabled-image.c @@ -91,7 +91,7 @@ int manager_image_cache_discover(Manager *m, Hashmap *images, sd_bus_error *erro /* A wrapper around image_discover() (for finding images in search path) and portable_discover_attached() (for * finding attached images). */ - r = image_discover(IMAGE_PORTABLE, NULL, images); + r = image_discover(m->runtime_scope, IMAGE_PORTABLE, NULL, images); if (r < 0) return r; diff --git a/src/portable/portabled.c b/src/portable/portabled.c index 766999ff0d..6d7c3b534f 100644 --- a/src/portable/portabled.c +++ b/src/portable/portabled.c @@ -28,10 +28,14 @@ static int manager_new(Manager **ret) { assert(ret); - m = new0(Manager, 1); + m = new(Manager, 1); if (!m) return -ENOMEM; + *m = (Manager) { + .runtime_scope = RUNTIME_SCOPE_SYSTEM, + }; + r = sd_event_default(&m->event); if (r < 0) return r; diff --git a/src/portable/portabled.h b/src/portable/portabled.h index 71ec41d4f1..8503451ccc 100644 --- a/src/portable/portabled.h +++ b/src/portable/portabled.h @@ -7,6 +7,7 @@ #include "bus-object.h" #include "hashmap.h" #include "list.h" +#include "runtime-scope.h" typedef struct Manager Manager; @@ -23,6 +24,8 @@ struct Manager { LIST_HEAD(Operation, operations); unsigned n_operations; + + RuntimeScope runtime_scope; /* for now always RUNTIME_SCOPE_SYSTEM */ }; extern const BusObjectImplementation manager_object; diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c index 674811ca35..53e9821412 100644 --- a/src/shared/discover-image.c +++ b/src/shared/discover-image.c @@ -12,6 +12,8 @@ #include <sys/stat.h> #include <unistd.h> +#include "sd-path.h" + #include "alloc-util.h" #include "blockdev-util.h" #include "btrfs-util.h" @@ -553,12 +555,95 @@ static int image_make( return -EMEDIUMTYPE; } -static const char *pick_image_search_path(ImageClass class) { - if (class < 0 || class >= _IMAGE_CLASS_MAX) - return NULL; +static int pick_image_search_path( + RuntimeScope scope, + ImageClass class, + char ***ret) { + + int r; + + assert(scope < _RUNTIME_SCOPE_MAX && scope != RUNTIME_SCOPE_GLOBAL); + assert(class < _IMAGE_CLASS_MAX); + assert(ret); + + if (class < 0) { + *ret = NULL; + return 0; + } + + if (scope < 0) { + _cleanup_strv_free_ char **a = NULL, **b = NULL; + + r = pick_image_search_path(RUNTIME_SCOPE_USER, class, &a); + if (r < 0) + return r; + + r = pick_image_search_path(RUNTIME_SCOPE_SYSTEM, class, &b); + if (r < 0) + return r; + + r = strv_extend_strv(&a, b, /* filter_duplicates= */ false); + if (r < 0) + return r; + + *ret = TAKE_PTR(a); + return 0; + } + + switch (scope) { + + case RUNTIME_SCOPE_SYSTEM: { + const char *ns; + /* Use the initrd search path if there is one, otherwise use the common one */ + ns = in_initrd() && image_search_path_initrd[class] ? + image_search_path_initrd[class] : + image_search_path[class]; + if (!ns) + break; + + _cleanup_strv_free_ char **search = strv_split_nulstr(ns); + if (!search) + return -ENOMEM; + + *ret = TAKE_PTR(search); + return 0; + } + + case RUNTIME_SCOPE_USER: { + if (class != IMAGE_MACHINE) + break; + + static const uint64_t dirs[] = { + SD_PATH_USER_RUNTIME, + SD_PATH_USER_STATE_PRIVATE, + SD_PATH_USER_LIBRARY_PRIVATE, + }; - /* Use the initrd search path if there is one, otherwise use the common one */ - return in_initrd() && image_search_path_initrd[class] ? image_search_path_initrd[class] : image_search_path[class]; + _cleanup_strv_free_ char **search = NULL; + FOREACH_ELEMENT(d, dirs) { + _cleanup_free_ char *p = NULL; + + r = sd_path_lookup(*d, "machines", &p); + if (r == -ENXIO) /* No XDG_RUNTIME_DIR set */ + continue; + if (r < 0) + return r; + + r = strv_consume(&search, TAKE_PTR(p)); + if (r < 0) + return r; + } + + *ret = TAKE_PTR(search); + return 0; + } + + default: + assert_not_reached(); + } + + *ret = NULL; + return 0; } static char **make_possible_filenames(ImageClass class, const char *image_name) { @@ -592,7 +677,8 @@ static char **make_possible_filenames(ImageClass class, const char *image_name) return TAKE_PTR(l); } -int image_find(ImageClass class, +int image_find(RuntimeScope scope, + ImageClass class, const char *name, const char *root, Image **ret) { @@ -602,6 +688,7 @@ int image_find(ImageClass class, * some root directory.) */ int open_flags = root ? O_NOFOLLOW : 0, r; + assert(scope < _RUNTIME_SCOPE_MAX && scope != RUNTIME_SCOPE_GLOBAL); assert(class >= 0); assert(class < _IMAGE_CLASS_MAX); assert(name); @@ -614,11 +701,16 @@ int image_find(ImageClass class, if (!names) return -ENOMEM; - NULSTR_FOREACH(path, pick_image_search_path(class)) { + _cleanup_strv_free_ char **search = NULL; + r = pick_image_search_path(scope, class, &search); + if (r < 0) + return r; + + STRV_FOREACH(path, search) { _cleanup_free_ char *resolved = NULL; _cleanup_closedir_ DIR *d = NULL; - r = chase_and_opendir(path, root, CHASE_PREFIX_ROOT, &resolved, &d); + r = chase_and_opendir(*path, root, CHASE_PREFIX_ROOT, &resolved, &d); if (r == -ENOENT) continue; if (r < 0) @@ -722,7 +814,7 @@ int image_find(ImageClass class, } } - if (class == IMAGE_MACHINE && streq(name, ".host")) { + if (scope == RUNTIME_SCOPE_SYSTEM && class == IMAGE_MACHINE && streq(name, ".host")) { r = image_make(class, ".host", /* dir_fd= */ AT_FDCWD, @@ -771,14 +863,21 @@ int image_from_path(const char *path, Image **ret) { ret); } -int image_find_harder(ImageClass class, const char *name_or_path, const char *root, Image **ret) { +int image_find_harder( + RuntimeScope scope, + ImageClass class, + const char *name_or_path, + const char *root, + Image **ret) { + if (image_name_is_valid(name_or_path)) - return image_find(class, name_or_path, root, ret); + return image_find(scope, class, name_or_path, root, ret); return image_from_path(name_or_path, ret); } int image_discover( + RuntimeScope scope, ImageClass class, const char *root, Hashmap *h) { @@ -788,15 +887,21 @@ int image_discover( * some root directory.) */ int open_flags = root ? O_NOFOLLOW : 0, r; + assert(scope < _RUNTIME_SCOPE_MAX && scope != RUNTIME_SCOPE_GLOBAL); assert(class >= 0); assert(class < _IMAGE_CLASS_MAX); assert(h); - NULSTR_FOREACH(path, pick_image_search_path(class)) { + _cleanup_strv_free_ char **search = NULL; + r = pick_image_search_path(scope, class, &search); + if (r < 0) + return r; + + STRV_FOREACH(path, search) { _cleanup_free_ char *resolved = NULL; _cleanup_closedir_ DIR *d = NULL; - r = chase_and_opendir(path, root, CHASE_PREFIX_ROOT, &resolved, &d); + r = chase_and_opendir(*path, root, CHASE_PREFIX_ROOT, &resolved, &d); if (r == -ENOENT) continue; if (r < 0) @@ -946,7 +1051,7 @@ int image_discover( } } - if (class == IMAGE_MACHINE && !hashmap_contains(h, ".host")) { + if (scope == RUNTIME_SCOPE_SYSTEM && class == IMAGE_MACHINE && !hashmap_contains(h, ".host")) { _cleanup_(image_unrefp) Image *image = NULL; r = image_make(IMAGE_MACHINE, @@ -1063,7 +1168,7 @@ static int rename_auxiliary_file(const char *path, const char *new_name, const c return rename_noreplace(AT_FDCWD, path, AT_FDCWD, rs); } -int image_rename(Image *i, const char *new_name) { +int image_rename(Image *i, const char *new_name, RuntimeScope scope) { _cleanup_(release_lock_file) LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT, name_lock = LOCK_FILE_INIT; _cleanup_free_ char *new_path = NULL, *nn = NULL, *roothash = NULL; _cleanup_strv_free_ char **settings = NULL; @@ -1098,7 +1203,7 @@ int image_rename(Image *i, const char *new_name) { if (r < 0) return r; - r = image_find(IMAGE_MACHINE, new_name, NULL, NULL); + r = image_find(scope, IMAGE_MACHINE, new_name, NULL, NULL); if (r >= 0) return -EEXIST; if (r != -ENOENT) @@ -1185,7 +1290,7 @@ static int clone_auxiliary_file(const char *path, const char *new_name, const ch return copy_file_atomic(path, rs, 0664, COPY_REFLINK); } -int image_clone(Image *i, const char *new_name, bool read_only) { +int image_clone(Image *i, const char *new_name, bool read_only, RuntimeScope scope) { _cleanup_(release_lock_file) LockFile name_lock = LOCK_FILE_INIT; _cleanup_strv_free_ char **settings = NULL; _cleanup_free_ char *roothash = NULL; @@ -1212,7 +1317,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) { if (r < 0) return r; - r = image_find(IMAGE_MACHINE, new_name, NULL, NULL); + r = image_find(scope, IMAGE_MACHINE, new_name, NULL, NULL); if (r >= 0) return -EEXIST; if (r != -ENOENT) @@ -1646,24 +1751,35 @@ int image_name_lock(const char *name, int operation, LockFile *ret) { } bool image_in_search_path( + RuntimeScope scope, ImageClass class, const char *root, const char *image) { + int r; + + assert(scope < _RUNTIME_SCOPE_MAX && scope != RUNTIME_SCOPE_GLOBAL); + assert(class >= 0); + assert(class < _IMAGE_CLASS_MAX); assert(image); - NULSTR_FOREACH(path, pick_image_search_path(class)) { + _cleanup_strv_free_ char **search = NULL; + r = pick_image_search_path(scope, class, &search); + if (r < 0) + return r; + + STRV_FOREACH(path, search) { const char *p, *q; size_t k; if (!empty_or_root(root)) { - q = path_startswith(path, root); + q = path_startswith(*path, root); if (!q) continue; } else - q = path; + q = *path; - p = path_startswith(q, path); + p = path_startswith(q, *path); if (!p) continue; diff --git a/src/shared/discover-image.h b/src/shared/discover-image.h index b20b586ae0..c1fdf15d15 100644 --- a/src/shared/discover-image.h +++ b/src/shared/discover-image.h @@ -13,6 +13,7 @@ #include "macro.h" #include "os-util.h" #include "path-util.h" +#include "runtime-scope.h" #include "string-util.h" #include "time-util.h" @@ -60,14 +61,14 @@ Image *image_ref(Image *i); DEFINE_TRIVIAL_CLEANUP_FUNC(Image*, image_unref); -int image_find(ImageClass class, const char *name, const char *root, Image **ret); +int image_find(RuntimeScope scope, ImageClass class, const char *name, const char *root, Image **ret); int image_from_path(const char *path, Image **ret); -int image_find_harder(ImageClass class, const char *name_or_path, const char *root, Image **ret); -int image_discover(ImageClass class, const char *root, Hashmap *map); +int image_find_harder(RuntimeScope scope, ImageClass class, const char *name_or_path, const char *root, Image **ret); +int image_discover(RuntimeScope scope, ImageClass class, const char *root, Hashmap *map); int image_remove(Image *i); -int image_rename(Image *i, const char *new_name); -int image_clone(Image *i, const char *new_name, bool read_only); +int image_rename(Image *i, const char *new_name, RuntimeScope scope); +int image_clone(Image *i, const char *new_name, bool read_only, RuntimeScope scope); int image_read_only(Image *i, bool b); const char* image_type_to_string(ImageType t) _const_; @@ -80,7 +81,7 @@ int image_set_limit(Image *i, uint64_t referenced_max); int image_read_metadata(Image *i, const ImagePolicy *image_policy); -bool image_in_search_path(ImageClass class, const char *root, const char *image); +bool image_in_search_path(RuntimeScope scope, ImageClass class, const char *root, const char *image); static inline char **image_extension_release(Image *image, ImageClass class) { assert(image); diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index 6401fc4c0f..9b1839d43a 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -2031,7 +2031,7 @@ static int image_discover_and_read_metadata( if (!images) return log_oom(); - r = image_discover(image_class, arg_root, images); + r = image_discover(RUNTIME_SCOPE_SYSTEM, image_class, arg_root, images); if (r < 0) return log_error_errno(r, "Failed to discover images: %m"); @@ -2278,7 +2278,7 @@ static int verb_list(int argc, char **argv, void *userdata) { if (!images) return log_oom(); - r = image_discover(arg_image_class, arg_root, images); + r = image_discover(RUNTIME_SCOPE_SYSTEM, arg_image_class, arg_root, images); if (r < 0) return log_error_errno(r, "Failed to discover images: %m"); @@ -2339,7 +2339,7 @@ static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varl if (!images) return -ENOMEM; - r = image_discover(image_class, arg_root, images); + r = image_discover(RUNTIME_SCOPE_SYSTEM, image_class, arg_root, images); if (r < 0) return r; diff --git a/src/sysupdate/sysupdated.c b/src/sysupdate/sysupdated.c index 7dda16b8b5..58967930f7 100644 --- a/src/sysupdate/sysupdated.c +++ b/src/sysupdate/sysupdated.c @@ -46,6 +46,8 @@ typedef struct Manager { Hashmap *polkit_registry; sd_event_source *notify_event; + + RuntimeScope runtime_scope; /* For now only RUNTIME_SCOPE_SYSTEM */ } Manager; /* Forward declare so that jobs can call it on exit */ @@ -1730,10 +1732,14 @@ static int manager_new(Manager **ret) { assert(ret); - m = new0(Manager, 1); + m = new(Manager, 1); if (!m) return -ENOMEM; + *m = (Manager) { + .runtime_scope = RUNTIME_SCOPE_SYSTEM, + }; + r = sd_event_default(&m->event); if (r < 0) return r; @@ -1795,7 +1801,7 @@ static int manager_enumerate_image_class(Manager *m, TargetClass class) { if (!images) return -ENOMEM; - r = image_discover((ImageClass) class, NULL, images); + r = image_discover(m->runtime_scope, (ImageClass) class, NULL, images); if (r < 0) return r; diff --git a/src/vmspawn/vmspawn.c b/src/vmspawn/vmspawn.c index 1c49aff4a3..d2a9a6ee01 100644 --- a/src/vmspawn/vmspawn.c +++ b/src/vmspawn/vmspawn.c @@ -2236,7 +2236,8 @@ static int determine_names(void) { if (arg_machine) { _cleanup_(image_unrefp) Image *i = NULL; - r = image_find(IMAGE_MACHINE, arg_machine, NULL, &i); + r = image_find(arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER, + IMAGE_MACHINE, arg_machine, NULL, &i); if (r == -ENOENT) return log_error_errno(r, "No image for machine '%s'.", arg_machine); if (r < 0) diff --git a/test/units/TEST-13-NSPAWN.nspawn.sh b/test/units/TEST-13-NSPAWN.nspawn.sh index 3120d98bf4..f561575582 100755 --- a/test/units/TEST-13-NSPAWN.nspawn.sh +++ b/test/units/TEST-13-NSPAWN.nspawn.sh @@ -1129,7 +1129,7 @@ testcase_unpriv() { local tmpdir name tmpdir="$(mktemp -d /var/tmp/TEST-13-NSPAWN.unpriv.XXX)" - name="unpriv-${tmpdir##*.}" + name="unprv-${tmpdir##*.}" trap 'rm -fr ${tmpdir@Q} || true; rm -f /run/verity.d/test-13-nspawn-${name@Q} || true' RETURN ERR create_dummy_ddi "$tmpdir" "$name" chown --recursive testuser: "$tmpdir" @@ -1141,6 +1141,17 @@ testcase_unpriv() { -- \ systemd-nspawn --pipe --private-network --register=no --keep-unit --image="$tmpdir/$name.raw" echo hello >"$tmpdir/stdout.txt" echo hello | cmp "$tmpdir/stdout.txt" - + + # Make sure per-user search path logic works + systemd-run --pipe --uid=testuser mkdir -p /home/testuser/.local/state/machines + systemd-run --pipe --uid=testuser ln -s "$tmpdir/$name.raw" /home/testuser/.local/state/machines/"x$name.raw" + systemd-run \ + --pipe \ + --uid=testuser \ + --property=Delegate=yes \ + -- \ + systemd-nspawn --pipe --private-network --register=no --keep-unit --machine="x$name" echo hello >"$tmpdir/stdout.txt" + echo hello | cmp "$tmpdir/stdout.txt" - } testcase_fuse() { diff --git a/test/units/TEST-50-DISSECT.dissect.sh b/test/units/TEST-50-DISSECT.dissect.sh index a7122855d9..fc33d91f0f 100755 --- a/test/units/TEST-50-DISSECT.dissect.sh +++ b/test/units/TEST-50-DISSECT.dissect.sh @@ -615,6 +615,10 @@ grep -q -F '{"name":"b","type":"raw","class":"portable","ro":false,"path":"/run/ grep -q -F '{"name":"c","type":"raw","class":"sysext","ro":false,"path":"/run/extensions/c.raw"' /tmp/discover.json rm /tmp/discover.json /run/machines/a.raw /run/portables/b.raw /run/extensions/c.raw +systemd-dissect --discover --system +systemd-dissect --discover --user +systemd-dissect --discover --system --user + LOOP="$(systemd-dissect --attach --loop-ref=waldo "$MINIMAL_IMAGE.raw")" # Wait until the symlinks we want to test are established |