mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-03-08 20:58:20 +03:00
os-util: split extension_release_validate out of sysext
This commit is contained in:
parent
bcf94222a5
commit
7eda2d7fa5
@ -3,6 +3,7 @@
|
||||
#include "alloc-util.h"
|
||||
#include "discover-image.h"
|
||||
#include "env-file.h"
|
||||
#include "env-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
@ -192,3 +193,69 @@ int load_extension_release_pairs(const char *root, const char *extension, char *
|
||||
|
||||
return load_env_file_pairs(f, p, ret);
|
||||
}
|
||||
|
||||
int extension_release_validate(
|
||||
const char *name,
|
||||
const char *host_os_release_id,
|
||||
const char *host_os_release_version_id,
|
||||
const char *host_os_release_sysext_level,
|
||||
char **extension_release) {
|
||||
|
||||
const char *extension_release_id = NULL, *extension_release_sysext_level = NULL;
|
||||
|
||||
assert(name);
|
||||
assert(!isempty(host_os_release_id));
|
||||
assert(!isempty(host_os_release_version_id) || !isempty(host_os_release_sysext_level));
|
||||
|
||||
/* Now that we can look into the extension image, let's see if the OS version is compatible */
|
||||
if (strv_isempty(extension_release)) {
|
||||
log_debug("Extension '%s' carries no extension-release data, ignoring extension.", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
extension_release_id = strv_env_pairs_get(extension_release, "ID");
|
||||
if (isempty(extension_release_id)) {
|
||||
log_debug("Extension '%s' does not contain ID in extension-release but requested to match '%s'",
|
||||
name, strna(host_os_release_id));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!streq_ptr(host_os_release_id, extension_release_id)) {
|
||||
log_debug("Extension '%s' is for OS '%s', but deployed on top of '%s'.",
|
||||
name, strna(extension_release_id), strna(host_os_release_id));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the extension has a sysext API level declared, then it must match the host API
|
||||
* level. Otherwise, compare OS version as a whole */
|
||||
extension_release_sysext_level = strv_env_pairs_get(extension_release, "SYSEXT_LEVEL");
|
||||
if (!isempty(host_os_release_sysext_level) && !isempty(extension_release_sysext_level)) {
|
||||
if (!streq_ptr(host_os_release_sysext_level, extension_release_sysext_level)) {
|
||||
log_debug("Extension '%s' is for sysext API level '%s', but running on sysext API level '%s'",
|
||||
name, strna(extension_release_sysext_level), strna(host_os_release_sysext_level));
|
||||
return 0;
|
||||
}
|
||||
} else if (!isempty(host_os_release_version_id)) {
|
||||
const char *extension_release_version_id;
|
||||
|
||||
extension_release_version_id = strv_env_pairs_get(extension_release, "VERSION_ID");
|
||||
if (isempty(extension_release_version_id)) {
|
||||
log_debug("Extension '%s' does not contain VERSION_ID in extension-release but requested to match '%s'",
|
||||
name, strna(host_os_release_version_id));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!streq_ptr(host_os_release_version_id, extension_release_version_id)) {
|
||||
log_debug("Extension '%s' is for OS '%s', but deployed on top of '%s'.",
|
||||
name, strna(extension_release_version_id), strna(host_os_release_version_id));
|
||||
return 0;
|
||||
}
|
||||
} else if (isempty(host_os_release_version_id) && isempty(host_os_release_sysext_level)) {
|
||||
/* Rolling releases do not typically set VERSION_ID (eg: ArchLinux) */
|
||||
log_debug("No version info on the host (rolling release?), but ID in %s matched.", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
log_debug("Version info of extension '%s' matches host.", name);
|
||||
return 1;
|
||||
}
|
||||
|
@ -26,3 +26,8 @@ int parse_os_release(const char *root, ...) _sentinel_;
|
||||
int load_extension_release_pairs(const char *root, const char *extension, char ***ret);
|
||||
int load_os_release_pairs(const char *root, char ***ret);
|
||||
int load_os_release_pairs_with_prefix(const char *root, const char *prefix, char ***ret);
|
||||
|
||||
/* Given an image name (for logging purposes), a set of os-release values from the host
|
||||
* and a key-value pair vector of extension-release variables, check that the distro and
|
||||
* (system extension level or distro version) match and return 1, and 0 otherwise. */
|
||||
int extension_release_validate(const char *name, const char *host_os_release_id, const char *host_os_release_version_id, const char *host_os_release_sysext_level, char **extension_release);
|
||||
|
@ -403,16 +403,15 @@ static int strverscmp_improvedp(char *const* a, char *const* b) {
|
||||
|
||||
static int validate_version(
|
||||
const char *root,
|
||||
const char *name,
|
||||
const Image *img,
|
||||
const char *host_os_release_id,
|
||||
const char *host_os_release_version_id,
|
||||
const char *host_os_release_sysext_level) {
|
||||
|
||||
_cleanup_free_ char *extension_release_id = NULL, *extension_release_version_id = NULL, *extension_release_sysext_level = NULL;
|
||||
int r;
|
||||
|
||||
assert(root);
|
||||
assert(name);
|
||||
assert(img);
|
||||
|
||||
if (arg_force) {
|
||||
log_debug("Force mode enabled, skipping version validation.");
|
||||
@ -430,45 +429,12 @@ static int validate_version(
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Extension image contains /usr/lib/os-release file, which is not allowed (it may carry /etc/os-release), refusing.");
|
||||
|
||||
/* Now that we can look into the extension image, let's see if the OS version is compatible */
|
||||
r = parse_extension_release(
|
||||
root,
|
||||
name,
|
||||
"ID", &extension_release_id,
|
||||
"VERSION_ID", &extension_release_version_id,
|
||||
"SYSEXT_LEVEL", &extension_release_sysext_level,
|
||||
NULL);
|
||||
if (r == -ENOENT) {
|
||||
log_notice_errno(r, "Extension '%s' carries no extension-release data, ignoring extension.", name);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to acquire 'os-release' data of extension '%s': %m", name);
|
||||
|
||||
if (!streq_ptr(host_os_release_id, extension_release_id)) {
|
||||
log_notice("Extension '%s' is for OS '%s', but running on '%s', ignoring extension.",
|
||||
name, strna(extension_release_id), strna(host_os_release_id));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the extension has a sysext API level declared, then it must match the host API
|
||||
* level. Otherwise, compare OS version as a whole */
|
||||
if (extension_release_sysext_level) {
|
||||
if (!streq_ptr(host_os_release_sysext_level, extension_release_sysext_level)) {
|
||||
log_notice("Extension '%s' is for sysext API level '%s', but running on sysext API level '%s', ignoring extension.",
|
||||
name, extension_release_sysext_level, strna(host_os_release_sysext_level));
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (!streq_ptr(host_os_release_version_id, extension_release_version_id)) {
|
||||
log_notice("Extension '%s' is for OS version '%s', but running on OS version '%s', ignoring extension.",
|
||||
name, extension_release_version_id, strna(host_os_release_version_id));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
log_debug("Version info of extension '%s' matches host.", name);
|
||||
return 1;
|
||||
return extension_release_validate(
|
||||
img->name,
|
||||
host_os_release_id,
|
||||
host_os_release_version_id,
|
||||
host_os_release_sysext_level,
|
||||
img->extension_release);
|
||||
}
|
||||
|
||||
static int merge_subprocess(Hashmap *images, const char *workspace) {
|
||||
@ -596,7 +562,7 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
|
||||
|
||||
r = validate_version(
|
||||
p,
|
||||
img->name,
|
||||
img,
|
||||
host_os_release_id,
|
||||
host_os_release_version_id,
|
||||
host_os_release_sysext_level);
|
||||
@ -742,13 +708,12 @@ static int merge(Hashmap *images) {
|
||||
return r != 123; /* exit code 123 means: didn't do anything */
|
||||
}
|
||||
|
||||
static int verb_merge(int argc, char **argv, void *userdata) {
|
||||
static int image_discover_and_read_metadata(Hashmap **ret_images) {
|
||||
_cleanup_(hashmap_freep) Hashmap *images = NULL;
|
||||
char **p;
|
||||
Image *img;
|
||||
int r;
|
||||
|
||||
if (!have_effective_cap(CAP_SYS_ADMIN))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Need to be privileged.");
|
||||
assert(ret_images);
|
||||
|
||||
images = hashmap_new(&image_hash_ops);
|
||||
if (!images)
|
||||
@ -758,6 +723,29 @@ static int verb_merge(int argc, char **argv, void *userdata) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to discover extension images: %m");
|
||||
|
||||
HASHMAP_FOREACH(img, images) {
|
||||
r = image_read_metadata(img);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read metadata for image %s: %m", img->name);
|
||||
}
|
||||
|
||||
*ret_images = TAKE_PTR(images);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verb_merge(int argc, char **argv, void *userdata) {
|
||||
_cleanup_(hashmap_freep) Hashmap *images = NULL;
|
||||
char **p;
|
||||
int r;
|
||||
|
||||
if (!have_effective_cap(CAP_SYS_ADMIN))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Need to be privileged.");
|
||||
|
||||
r = image_discover_and_read_metadata(&images);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* In merge mode fail if things are already merged. (In --refresh mode below we'll unmerge if we find
|
||||
* things are already merged...) */
|
||||
STRV_FOREACH(p, arg_hierarchies) {
|
||||
@ -789,13 +777,9 @@ static int verb_refresh(int argc, char **argv, void *userdata) {
|
||||
if (!have_effective_cap(CAP_SYS_ADMIN))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Need to be privileged.");
|
||||
|
||||
images = hashmap_new(&image_hash_ops);
|
||||
if (!images)
|
||||
return log_oom();
|
||||
|
||||
r = image_discover(IMAGE_EXTENSION, arg_root, images);
|
||||
r = image_discover_and_read_metadata(&images);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to discover extension images: %m");
|
||||
return r;
|
||||
|
||||
r = merge(images); /* Returns > 0 if it did something, i.e. a new overlayfs is mounted now. When it
|
||||
* does so it implicitly unmounts any overlayfs placed there before. Returns == 0
|
||||
|
Loading…
x
Reference in New Issue
Block a user