1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-10 01:17:44 +03:00

portabled: refactor extraction/validation into a common helper

This commit is contained in:
Luca Boccassi 2021-09-06 13:19:47 +01:00
parent 239ac0c7f7
commit 9ff61565be

View File

@ -527,14 +527,18 @@ static int portable_extract_by_path(
return 0;
}
int portable_extract(
static int extract_image_and_extensions(
const char *name_or_path,
char **matches,
char **extension_image_paths,
bool validate_sysext,
Image **ret_image,
OrderedHashmap **ret_extension_images,
PortableMetadata **ret_os_release,
Hashmap **ret_unit_files,
sd_bus_error *error) {
_cleanup_free_ char *id = NULL, *version_id = NULL, *sysext_level = NULL;
_cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
_cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL;
_cleanup_hashmap_free_ Hashmap *unit_files = NULL;
@ -543,6 +547,9 @@ int portable_extract(
int r;
assert(name_or_path);
assert(matches);
assert(ret_image);
assert(ret_extension_images);
r = image_find_harder(IMAGE_PORTABLE, name_or_path, NULL, &image);
if (r < 0)
@ -573,17 +580,91 @@ int portable_extract(
if (r < 0)
return r;
ORDERED_HASHMAP_FOREACH(ext, extension_images) {
_cleanup_hashmap_free_ Hashmap *extra_unit_files = NULL;
/* If we are layering extension images on top of a runtime image, check that the os-release and extension-release metadata
* match, otherwise reject it immediately as invalid, or it will fail when the units are started. */
if (validate_sysext) {
_cleanup_fclose_ FILE *f = NULL;
r = portable_extract_by_path(ext->path, /* path_is_extension= */ true, matches, NULL, &extra_unit_files, error);
r = take_fdopen_unlocked(&os_release->fd, "r", &f);
if (r < 0)
return r;
r = hashmap_move(unit_files, extra_unit_files);
r = parse_env_file(f, os_release->name,
"ID", &id,
"VERSION_ID", &version_id,
"SYSEXT_LEVEL", &sysext_level);
if (r < 0)
return r;
}
ORDERED_HASHMAP_FOREACH(ext, extension_images) {
_cleanup_(portable_metadata_unrefp) PortableMetadata *extension_release_meta = NULL;
_cleanup_hashmap_free_ Hashmap *extra_unit_files = NULL;
_cleanup_strv_free_ char **extension_release = NULL;
_cleanup_fclose_ FILE *f = NULL;
r = portable_extract_by_path(ext->path, /* path_is_extension= */ true, matches, &extension_release_meta, &extra_unit_files, error);
if (r < 0)
return r;
r = hashmap_move(unit_files, extra_unit_files);
if (r < 0)
return r;
if (!validate_sysext)
continue;
r = take_fdopen_unlocked(&extension_release_meta->fd, "r", &f);
if (r < 0)
return r;
r = load_env_file_pairs(f, extension_release_meta->name, &extension_release);
if (r < 0)
return r;
r = extension_release_validate(ext->path, id, version_id, sysext_level, extension_release);
if (r == 0)
return sd_bus_error_set_errnof(error, SYNTHETIC_ERRNO(ESTALE), "Image %s extension-release metadata does not match the root's", ext->path);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to compare image %s extension-release metadata with the root's os-release: %m", ext->path);
}
*ret_image = TAKE_PTR(image);
*ret_extension_images = TAKE_PTR(extension_images);
if (ret_os_release)
*ret_os_release = TAKE_PTR(os_release);
if (ret_unit_files)
*ret_unit_files = TAKE_PTR(unit_files);
return 0;
}
int portable_extract(
const char *name_or_path,
char **matches,
char **extension_image_paths,
PortableMetadata **ret_os_release,
Hashmap **ret_unit_files,
sd_bus_error *error) {
_cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
_cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL;
_cleanup_hashmap_free_ Hashmap *unit_files = NULL;
_cleanup_(image_unrefp) Image *image = NULL;
int r;
r = extract_image_and_extensions(name_or_path,
matches,
extension_image_paths,
/* validate_sysext= */ false,
&image,
&extension_images,
&os_release,
&unit_files,
error);
if (r < 0)
return r;
if (hashmap_isempty(unit_files)) {
_cleanup_free_ char *extensions = strv_join(extension_image_paths, ", ");
if (!extensions)
@ -1165,90 +1246,24 @@ int portable_attach(
size_t *n_changes,
sd_bus_error *error) {
_cleanup_free_ char *id = NULL, *version_id = NULL, *sysext_level = NULL;
_cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
_cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL;
_cleanup_hashmap_free_ Hashmap *unit_files = NULL;
_cleanup_(lookup_paths_free) LookupPaths paths = {};
_cleanup_(image_unrefp) Image *image = NULL;
PortableMetadata *item;
Image *ext;
char **p;
int r;
assert(name_or_path);
r = image_find_harder(IMAGE_PORTABLE, name_or_path, NULL, &image);
r = extract_image_and_extensions(name_or_path,
matches,
extension_image_paths,
/* validate_sysext= */ true,
&image,
&extension_images,
/* os_release= */ NULL,
&unit_files,
error);
if (r < 0)
return r;
if (!strv_isempty(extension_image_paths)) {
extension_images = ordered_hashmap_new(&image_hash_ops);
if (!extension_images)
return -ENOMEM;
STRV_FOREACH(p, extension_image_paths) {
_cleanup_(image_unrefp) Image *new = NULL;
r = image_find_harder(IMAGE_PORTABLE, *p, NULL, &new);
if (r < 0)
return r;
r = ordered_hashmap_put(extension_images, new->name, new);
if (r < 0)
return r;
TAKE_PTR(new);
}
}
r = portable_extract_by_path(image->path, /* path_is_extension= */ false, matches, &os_release, &unit_files, error);
if (r < 0)
return r;
/* If we are layering extension images on top of a runtime image, check that the os-release and extension-release metadata
* match, otherwise reject it immediately as invalid, or it will fail when the units are started. */
if (os_release) {
_cleanup_fclose_ FILE *f = NULL;
r = take_fdopen_unlocked(&os_release->fd, "r", &f);
if (r < 0)
return r;
r = parse_env_file(f, os_release->name,
"ID", &id,
"VERSION_ID", &version_id,
"SYSEXT_LEVEL", &sysext_level);
if (r < 0)
return r;
}
ORDERED_HASHMAP_FOREACH(ext, extension_images) {
_cleanup_(portable_metadata_unrefp) PortableMetadata *extension_release_meta = NULL;
_cleanup_hashmap_free_ Hashmap *extra_unit_files = NULL;
_cleanup_strv_free_ char **extension_release = NULL;
_cleanup_fclose_ FILE *f = NULL;
r = portable_extract_by_path(ext->path, /* path_is_extension= */ true, matches, &extension_release_meta, &extra_unit_files, error);
if (r < 0)
return r;
r = take_fdopen_unlocked(&extension_release_meta->fd, "r", &f);
if (r < 0)
return r;
r = load_env_file_pairs(f, extension_release_meta->name, &extension_release);
if (r < 0)
return r;
r = extension_release_validate(ext->path, id, version_id, sysext_level, extension_release);
if (r == 0)
return sd_bus_error_set_errnof(error, SYNTHETIC_ERRNO(ESTALE), "Image %s extension-release metadata does not match the root's", ext->path);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to compare image %s extension-release metadata with the root's os-release: %m", ext->path);
r = hashmap_move(unit_files, extra_unit_files);
if (r < 0)
return r;
}
if (hashmap_isempty(unit_files)) {
_cleanup_free_ char *extensions = strv_join(extension_image_paths, ", ");