image-discovery: add per-user scope (#35510)

This commit is contained in:
Lennart Poettering
2024-12-20 22:12:35 +01:00
committed by GitHub
31 changed files with 329 additions and 87 deletions
+21 -2
View File
@@ -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");
}
+3 -2
View File
@@ -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)
+2 -1
View File
@@ -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);
+2 -1
View File
@@ -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);
+5 -1
View File
@@ -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;
+2 -1
View File
@@ -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);
+3 -2
View File
@@ -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;
+1 -1
View File
@@ -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);
}
+2 -2
View File
@@ -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;
+3 -3
View File
@@ -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;
+3 -2
View File
@@ -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");
+5 -1
View File
@@ -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;
+2
View File
@@ -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);
+2 -1
View File
@@ -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)
+45 -19
View File
@@ -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;
}
+5 -4
View File
@@ -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);
+4
View File
@@ -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,
+11 -5
View File
@@ -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);
+1 -1
View File
@@ -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;
+5 -1
View File
@@ -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;
+3
View File
@@ -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;
+138 -22
View File
@@ -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) {
/* 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;
+7 -6
View File
@@ -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);
+3 -3
View File
@@ -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;
+8 -2
View File
@@ -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;
+2 -1
View File
@@ -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)