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