diff --git a/man/systemd-dissect.xml b/man/systemd-dissect.xml index b65a2c39f1d..191ae3394bb 100644 --- a/man/systemd-dissect.xml +++ b/man/systemd-dissect.xml @@ -503,6 +503,17 @@ + + + + + When used together with controls whether to search for + images installed system-wide or in the user's directories in $HOME. If neither + switch is specified, will search within both scopes. + + + + diff --git a/shell-completion/bash/systemd-dissect b/shell-completion/bash/systemd-dissect index 8d2b43423cb..a9fa639c3f9 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 78a830d574b..8739e130c38 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 1e82e84d7d9..346aca94460 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 e74d36288af..440ae85ba16 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 97db0b836a4..6568c591560 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 db081205ab7..ea8257a833d 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 46055ce5e73..b2614fa8f56 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 8eca1e4c958..8f18e78c7dd 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 5eb636960de..1784de61465 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 b1468b62c65..52cb915c309 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 f4915f67da4..fc50d3f1471 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 e0e27c44964..104b841dd5e 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 a0c4ef751ae..3a235aa0d40 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 3d1f5026997..758678a2059 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 66a8771eea6..1b452014e34 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 18a8060a9f8..61c13abe12d 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 281b57e321d..03977159f08 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 4f239e2b125..0476796dbe4 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 0ca04d3a0b9..ab0e44e038f 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 6d2839125f2..50e0e7a99cb 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 766999ff0de..6d7c3b534f4 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 71ec41d4f1b..8503451ccce 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 674811ca354..53e98214128 100644 --- a/src/shared/discover-image.c +++ b/src/shared/discover-image.c @@ -12,6 +12,8 @@ #include #include +#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) { - /* 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]; + 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, + }; + + _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 b20b586ae04..c1fdf15d155 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 6401fc4c0ff..9b1839d43a9 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 7dda16b8b5a..58967930f77 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 1c49aff4a3b..d2a9a6ee019 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 3120d98bf4d..f5615755820 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 a7122855d9c..fc33d91f0fa 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