portable: add support for confext
Support confexts for portable services
This commit is contained in:
committed by
Luca Boccassi
parent
f0304df6e4
commit
db776f6935
+35
-12
@@ -198,8 +198,18 @@ static int extract_now(
|
||||
|
||||
/* First, find os-release/extension-release and send it upstream (or just save it). */
|
||||
if (path_is_extension) {
|
||||
os_release_id = strjoina("/usr/lib/extension-release.d/extension-release.", image_name);
|
||||
ImageClass class = IMAGE_SYSEXT;
|
||||
|
||||
r = open_extension_release(where, IMAGE_SYSEXT, image_name, relax_extension_release_check, &os_release_path, &os_release_fd);
|
||||
if (r == -ENOENT) {
|
||||
r = open_extension_release(where, IMAGE_CONFEXT, image_name, relax_extension_release_check, &os_release_path, &os_release_fd);
|
||||
if (r >= 0)
|
||||
class = IMAGE_CONFEXT;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open extension release from '%s': %m", image_name);
|
||||
|
||||
os_release_id = strjoina((class == IMAGE_SYSEXT) ? "/usr/lib" : "/etc", "/extension-release.d/extension-release.", image_name);
|
||||
} else {
|
||||
os_release_id = "/etc/os-release";
|
||||
r = open_os_release(where, &os_release_path, &os_release_fd);
|
||||
@@ -530,7 +540,7 @@ static int extract_image_and_extensions(
|
||||
const char *name_or_path,
|
||||
char **matches,
|
||||
char **extension_image_paths,
|
||||
bool validate_sysext,
|
||||
bool validate_extension,
|
||||
bool relax_extension_release_check,
|
||||
const ImagePolicy *image_policy,
|
||||
Image **ret_image,
|
||||
@@ -541,7 +551,7 @@ static int extract_image_and_extensions(
|
||||
char ***ret_valid_prefixes,
|
||||
sd_bus_error *error) {
|
||||
|
||||
_cleanup_free_ char *id = NULL, *version_id = NULL, *sysext_level = NULL;
|
||||
_cleanup_free_ char *id = NULL, *version_id = NULL, *sysext_level = NULL, *confext_level = NULL;
|
||||
_cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
|
||||
_cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL, *extension_releases = NULL;
|
||||
_cleanup_hashmap_free_ Hashmap *unit_files = NULL;
|
||||
@@ -596,13 +606,14 @@ static int extract_image_and_extensions(
|
||||
/* 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. Also, collect valid portable prefixes if caller requested that. */
|
||||
if (validate_sysext || ret_valid_prefixes) {
|
||||
if (validate_extension || ret_valid_prefixes) {
|
||||
_cleanup_free_ char *prefixes = NULL;
|
||||
|
||||
r = parse_env_file_fd(os_release->fd, os_release->name,
|
||||
"ID", &id,
|
||||
"VERSION_ID", &version_id,
|
||||
"SYSEXT_LEVEL", &sysext_level,
|
||||
"CONFEXT_LEVEL", &confext_level,
|
||||
"PORTABLE_PREFIXES", &prefixes);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -638,15 +649,18 @@ static int extract_image_and_extensions(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!validate_sysext && !ret_valid_prefixes && !ret_extension_releases)
|
||||
if (!validate_extension && !ret_valid_prefixes && !ret_extension_releases)
|
||||
continue;
|
||||
|
||||
r = load_env_file_pairs_fd(extension_release_meta->fd, extension_release_meta->name, &extension_release);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (validate_sysext) {
|
||||
if (validate_extension) {
|
||||
r = extension_release_validate(ext->path, id, version_id, sysext_level, "portable", extension_release, IMAGE_SYSEXT);
|
||||
if (r < 0)
|
||||
r = extension_release_validate(ext->path, id, version_id, confext_level, "portable", extension_release, IMAGE_CONFEXT);
|
||||
|
||||
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)
|
||||
@@ -717,8 +731,8 @@ int portable_extract(
|
||||
name_or_path,
|
||||
matches,
|
||||
extension_image_paths,
|
||||
/* validate_sysext= */ false,
|
||||
/* relax_extension_release_check= */ FLAGS_SET(flags, PORTABLE_FORCE_SYSEXT),
|
||||
/* validate_extension= */ false,
|
||||
/* relax_extension_release_check= */ FLAGS_SET(flags, PORTABLE_FORCE_EXTENSION),
|
||||
image_policy,
|
||||
&image,
|
||||
&extension_images,
|
||||
@@ -979,16 +993,18 @@ static int append_release_log_fields(
|
||||
static const char *const field_versions[_IMAGE_CLASS_MAX][4]= {
|
||||
[IMAGE_PORTABLE] = { "IMAGE_VERSION", "VERSION_ID", "BUILD_ID", NULL },
|
||||
[IMAGE_SYSEXT] = { "SYSEXT_IMAGE_VERSION", "SYSEXT_VERSION_ID", "SYSEXT_BUILD_ID", NULL },
|
||||
[IMAGE_CONFEXT] = { "CONFEXT_IMAGE_VERSION", "CONFEXT_VERSION_ID", "CONFEXT_BUILD_ID", NULL },
|
||||
};
|
||||
static const char *const field_ids[_IMAGE_CLASS_MAX][3]= {
|
||||
[IMAGE_PORTABLE] = { "IMAGE_ID", "ID", NULL },
|
||||
[IMAGE_SYSEXT] = { "SYSEXT_IMAGE_ID", "SYSEXT_ID", NULL },
|
||||
[IMAGE_CONFEXT] = { "CONFEXT_IMAGE_ID", "CONFEXT_ID", NULL },
|
||||
};
|
||||
_cleanup_strv_free_ char **fields = NULL;
|
||||
const char *id = NULL, *version = NULL;
|
||||
int r;
|
||||
|
||||
assert(IN_SET(type, IMAGE_PORTABLE, IMAGE_SYSEXT));
|
||||
assert(IN_SET(type, IMAGE_PORTABLE, IMAGE_SYSEXT, IMAGE_CONFEXT));
|
||||
assert(!strv_isempty((char *const *)field_ids[type]));
|
||||
assert(!strv_isempty((char *const *)field_versions[type]));
|
||||
assert(field_name);
|
||||
@@ -1111,7 +1127,7 @@ static int install_chroot_dropin(
|
||||
/* With --force tell PID1 to avoid enforcing that the image <name> and
|
||||
* extension-release.<name> have to match. */
|
||||
!IN_SET(type, IMAGE_DIRECTORY, IMAGE_SUBVOLUME) &&
|
||||
FLAGS_SET(flags, PORTABLE_FORCE_SYSEXT) ?
|
||||
FLAGS_SET(flags, PORTABLE_FORCE_EXTENSION) ?
|
||||
":x-systemd.relax-extension-release-check\n" :
|
||||
"\n",
|
||||
/* In PORTABLE= we list the 'main' image name for this unit
|
||||
@@ -1131,6 +1147,13 @@ static int install_chroot_dropin(
|
||||
"PORTABLE_EXTENSION_NAME_AND_VERSION");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = append_release_log_fields(&text,
|
||||
ordered_hashmap_get(extension_releases, ext->name),
|
||||
IMAGE_CONFEXT,
|
||||
"PORTABLE_EXTENSION_NAME_AND_VERSION");
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1432,8 +1455,8 @@ int portable_attach(
|
||||
name_or_path,
|
||||
matches,
|
||||
extension_image_paths,
|
||||
/* validate_sysext= */ true,
|
||||
/* relax_extension_release_check= */ FLAGS_SET(flags, PORTABLE_FORCE_SYSEXT),
|
||||
/* validate_extension= */ true,
|
||||
/* relax_extension_release_check= */ FLAGS_SET(flags, PORTABLE_FORCE_EXTENSION),
|
||||
image_policy,
|
||||
&image,
|
||||
&extension_images,
|
||||
|
||||
@@ -18,19 +18,19 @@ typedef struct PortableMetadata {
|
||||
} PortableMetadata;
|
||||
|
||||
#define PORTABLE_METADATA_IS_OS_RELEASE(m) (streq((m)->name, "/etc/os-release"))
|
||||
#define PORTABLE_METADATA_IS_EXTENSION_RELEASE(m) (startswith((m)->name, "/usr/lib/extension-release.d/extension-release."))
|
||||
#define PORTABLE_METADATA_IS_EXTENSION_RELEASE(m) (startswith_strv((m)->name, STRV_MAKE("/usr/lib/extension-release.d/extension-release.", "/etc/extension-release.d/extension-release.")))
|
||||
#define PORTABLE_METADATA_IS_UNIT(m) (!IN_SET((m)->name[0], 0, '/'))
|
||||
|
||||
typedef enum PortableFlags {
|
||||
PORTABLE_RUNTIME = 1 << 0, /* Public API via DBUS, do not change */
|
||||
PORTABLE_FORCE_ATTACH = 1 << 1, /* Public API via DBUS, do not change */
|
||||
PORTABLE_FORCE_SYSEXT = 1 << 2, /* Public API via DBUS, do not change */
|
||||
PORTABLE_PREFER_COPY = 1 << 3,
|
||||
PORTABLE_PREFER_SYMLINK = 1 << 4,
|
||||
PORTABLE_REATTACH = 1 << 5,
|
||||
_PORTABLE_MASK_PUBLIC = PORTABLE_RUNTIME | PORTABLE_FORCE_ATTACH | PORTABLE_FORCE_SYSEXT,
|
||||
PORTABLE_RUNTIME = 1 << 0, /* Public API via DBUS, do not change */
|
||||
PORTABLE_FORCE_ATTACH = 1 << 1, /* Public API via DBUS, do not change */
|
||||
PORTABLE_FORCE_EXTENSION = 1 << 2, /* Public API via DBUS, do not change */
|
||||
PORTABLE_PREFER_COPY = 1 << 3,
|
||||
PORTABLE_PREFER_SYMLINK = 1 << 4,
|
||||
PORTABLE_REATTACH = 1 << 5,
|
||||
_PORTABLE_MASK_PUBLIC = PORTABLE_RUNTIME | PORTABLE_FORCE_ATTACH | PORTABLE_FORCE_EXTENSION,
|
||||
_PORTABLE_TYPE_MAX,
|
||||
_PORTABLE_TYPE_INVALID = -EINVAL,
|
||||
_PORTABLE_TYPE_INVALID = -EINVAL,
|
||||
} PortableFlags;
|
||||
|
||||
/* This enum is anonymous, since we usually store it in an 'int', as we overload it with negative errno
|
||||
|
||||
+33
-18
@@ -248,7 +248,7 @@ static int maybe_reload(sd_bus **bus) {
|
||||
static int get_image_metadata(sd_bus *bus, const char *image, char **matches, sd_bus_message **reply) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
uint64_t flags = arg_force ? PORTABLE_FORCE_SYSEXT : 0;
|
||||
uint64_t flags = arg_force ? PORTABLE_FORCE_EXTENSION : 0;
|
||||
const char *method;
|
||||
int r;
|
||||
|
||||
@@ -384,9 +384,16 @@ static int inspect_image(int argc, char *argv[], void *userdata) {
|
||||
fflush(stdout);
|
||||
nl = true;
|
||||
} else {
|
||||
_cleanup_free_ char *pretty_portable = NULL, *pretty_os = NULL, *sysext_level = NULL,
|
||||
*sysext_id = NULL, *sysext_version_id = NULL, *sysext_scope = NULL, *portable_prefixes = NULL,
|
||||
*id = NULL, *version_id = NULL, *image_id = NULL, *image_version = NULL, *build_id = NULL;
|
||||
_cleanup_free_ char *pretty_portable = NULL, *sysext_pretty_os = NULL,
|
||||
*sysext_level = NULL, *sysext_id = NULL,
|
||||
*sysext_version_id = NULL, *sysext_scope = NULL,
|
||||
*portable_prefixes = NULL, *id = NULL, *version_id = NULL,
|
||||
*sysext_image_id = NULL, *sysext_image_version = NULL,
|
||||
*sysext_build_id = NULL, *confext_pretty_os = NULL,
|
||||
*confext_level = NULL, *confext_id = NULL,
|
||||
*confext_version_id = NULL, *confext_scope = NULL,
|
||||
*confext_image_id = NULL, *confext_image_version = NULL,
|
||||
*confext_build_id = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
|
||||
f = fmemopen_unlocked((void*) data, sz, "r");
|
||||
@@ -396,12 +403,20 @@ static int inspect_image(int argc, char *argv[], void *userdata) {
|
||||
r = parse_env_file(f, name,
|
||||
"SYSEXT_ID", &sysext_id,
|
||||
"SYSEXT_VERSION_ID", &sysext_version_id,
|
||||
"SYSEXT_BUILD_ID", &build_id,
|
||||
"SYSEXT_IMAGE_ID", &image_id,
|
||||
"SYSEXT_IMAGE_VERSION", &image_version,
|
||||
"SYSEXT_PRETTY_NAME", &pretty_os,
|
||||
"SYSEXT_BUILD_ID", &sysext_build_id,
|
||||
"SYSEXT_IMAGE_ID", &sysext_image_id,
|
||||
"SYSEXT_IMAGE_VERSION", &sysext_image_version,
|
||||
"SYSEXT_SCOPE", &sysext_scope,
|
||||
"SYSEXT_LEVEL", &sysext_level,
|
||||
"SYSEXT_PRETTY_NAME", &sysext_pretty_os,
|
||||
"CONFEXT_ID", &confext_id,
|
||||
"CONFEXT_VERSION_ID", &confext_version_id,
|
||||
"CONFEXT_BUILD_ID", &confext_build_id,
|
||||
"CONFEXT_IMAGE_ID", &confext_image_id,
|
||||
"CONFEXT_IMAGE_VERSION", &confext_image_version,
|
||||
"CONFEXT_SCOPE", &confext_scope,
|
||||
"CONFEXT_LEVEL", &confext_level,
|
||||
"CONFEXT_PRETTY_NAME", &confext_pretty_os,
|
||||
"ID", &id,
|
||||
"VERSION_ID", &version_id,
|
||||
"PORTABLE_PRETTY_NAME", &pretty_portable,
|
||||
@@ -418,18 +433,18 @@ static int inspect_image(int argc, char *argv[], void *userdata) {
|
||||
"\tPortable Prefixes:\n\t\t%s\n"
|
||||
"\tExtension Image:\n\t\t%s%s%s %s%s%s\n",
|
||||
name,
|
||||
strna(sysext_scope),
|
||||
strna(sysext_level),
|
||||
strna(sysext_scope ?: confext_scope),
|
||||
strna(sysext_level ?: confext_level),
|
||||
strna(id),
|
||||
strna(version_id),
|
||||
strna(pretty_portable),
|
||||
strna(portable_prefixes),
|
||||
strempty(pretty_os),
|
||||
pretty_os ? " (" : "ID: ",
|
||||
strna(sysext_id ?: image_id),
|
||||
pretty_os ? "" : "Version: ",
|
||||
strna(sysext_version_id ?: image_version ?: build_id),
|
||||
pretty_os ? ")" : "");
|
||||
strempty(sysext_pretty_os ?: confext_pretty_os),
|
||||
(sysext_pretty_os ?: confext_pretty_os) ? " (" : "ID: ",
|
||||
strna(sysext_id ?: sysext_image_id ?: confext_id ?: confext_image_id),
|
||||
(sysext_pretty_os ?: confext_pretty_os) ? "" : "Version: ",
|
||||
strna(sysext_version_id ?: sysext_image_version ?: sysext_build_id ?: confext_version_id ?: confext_image_version ?: confext_build_id),
|
||||
(sysext_pretty_os ?: confext_pretty_os) ? ")" : "");
|
||||
}
|
||||
|
||||
r = sd_bus_message_exit_container(reply);
|
||||
@@ -871,7 +886,7 @@ static int attach_reattach_image(int argc, char *argv[], const char *method) {
|
||||
return bus_log_create_error(r);
|
||||
|
||||
if (STR_IN_SET(method, "AttachImageWithExtensions", "ReattachImageWithExtensions")) {
|
||||
uint64_t flags = (arg_runtime ? PORTABLE_RUNTIME : 0) | (arg_force ? PORTABLE_FORCE_ATTACH | PORTABLE_FORCE_SYSEXT : 0);
|
||||
uint64_t flags = (arg_runtime ? PORTABLE_RUNTIME : 0) | (arg_force ? PORTABLE_FORCE_ATTACH | PORTABLE_FORCE_EXTENSION : 0);
|
||||
|
||||
r = sd_bus_message_append(m, "st", arg_copy_mode, flags);
|
||||
} else
|
||||
@@ -943,7 +958,7 @@ static int detach_image(int argc, char *argv[], void *userdata) {
|
||||
if (streq(method, "DetachImage"))
|
||||
r = sd_bus_message_append(m, "b", arg_runtime);
|
||||
else {
|
||||
uint64_t flags = (arg_runtime ? PORTABLE_RUNTIME : 0) | (arg_force ? PORTABLE_FORCE_ATTACH | PORTABLE_FORCE_SYSEXT : 0);
|
||||
uint64_t flags = (arg_runtime ? PORTABLE_RUNTIME : 0) | (arg_force ? PORTABLE_FORCE_ATTACH | PORTABLE_FORCE_EXTENSION : 0);
|
||||
|
||||
r = sd_bus_message_append(m, "t", flags);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user