mirror of
https://github.com/systemd/systemd.git
synced 2026-08-13 17:08:14 +00:00
sysupdate: optionally load a per-component *.component file
This file can be used for metadata about a component. It may also be used to "disable" a component. This brings components as a concept to a similar conceptual level as features: both can be enabled/disabled, and carry metadata
This commit is contained in:
@@ -37,6 +37,9 @@ bool component_name_valid(const char *c) {
|
||||
if (!string_is_safe(c, STRING_FILENAME_PART))
|
||||
return false;
|
||||
|
||||
if (endswith(c, ".component")) /* don't allow ambiguity around sysupdate.<foobar>.component.d/ */
|
||||
return false;
|
||||
|
||||
/* Stack allocation is safe, since STRING_FILENAME_PART includes a length check */
|
||||
const char *j = strjoina("sysupdate.", c, ".d");
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "build.h"
|
||||
#include "bus-polkit.h"
|
||||
#include "conf-files.h"
|
||||
#include "conf-parser.h"
|
||||
#include "constants.h"
|
||||
#include "discover-image.h"
|
||||
#include "dissect-image.h"
|
||||
@@ -38,6 +39,7 @@
|
||||
#include "strv.h"
|
||||
#include "sysupdate.h"
|
||||
#include "sysupdate-cleanup.h"
|
||||
#include "sysupdate-config.h"
|
||||
#include "sysupdate-feature.h"
|
||||
#include "sysupdate-instance.h"
|
||||
#include "sysupdate-target.h"
|
||||
@@ -75,6 +77,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_transfer_source, freep);
|
||||
|
||||
#define CONTEXT_NULL \
|
||||
(Context) { \
|
||||
.component_enabled = true, \
|
||||
.sync = true, \
|
||||
.instances_max = UINT64_MAX, \
|
||||
.verify = -1, \
|
||||
@@ -114,6 +117,8 @@ void context_done(Context *c) {
|
||||
c->root = mfree(c->root);
|
||||
c->image = mfree(c->image);
|
||||
c->component = mfree(c->component);
|
||||
c->component_description = mfree(c->component_description);
|
||||
c->component_documentation = strv_free(c->component_documentation);
|
||||
c->image_policy = image_policy_free(c->image_policy);
|
||||
c->transfer_source = mfree(c->transfer_source);
|
||||
|
||||
@@ -280,9 +285,46 @@ static int read_transfers(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_component(Context *c) {
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
|
||||
/* Read a component description file, but only if we actually operate on a component */
|
||||
if (c->definitions || !c->component)
|
||||
return 0;
|
||||
|
||||
_cleanup_free_ char *j = strjoin("sysupdate.", c->component, ".component");
|
||||
if (!j)
|
||||
return log_oom();
|
||||
|
||||
ConfigTableItem table[] = {
|
||||
{ "Component", "Description", config_parse_string, 0, &c->component_description },
|
||||
{ "Component", "Documentation", config_parse_url_specifiers_many, 0, &c->component_documentation },
|
||||
{ "Component", "Enabled", config_parse_bool, 0, &c->component_enabled },
|
||||
{}
|
||||
};
|
||||
|
||||
r = config_parse_standard_file_with_dropins_full(
|
||||
c->root,
|
||||
/* root_fd= */ -EBADF,
|
||||
j,
|
||||
"Component\0",
|
||||
config_item_table_lookup, table,
|
||||
CONFIG_PARSE_WARN,
|
||||
/* userdata= */ (void *) c->root,
|
||||
/* ret_stats_by_path= */ NULL,
|
||||
/* ret_dropin_files= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef enum ReadDefinitionsFlags {
|
||||
READ_DEFINITIONS_REQUIRES_ENABLED_TRANSFERS = 1 << 0,
|
||||
READ_DEFINITIONS_REQUIRES_ANY_TRANSFERS = 1 << 1,
|
||||
READ_DEFINITIONS_REQUIRES_ENABLED_TRANSFERS = 1 << 0, /* fail unless there's at least one enabled transfer */
|
||||
READ_DEFINITIONS_REQUIRES_ANY_TRANSFERS = 1 << 1, /* fail unless there's at least one transfer */
|
||||
READ_DEFINITIONS_REQUIRES_ENABLED_COMPONENT = 1 << 2, /* fail if component is disabled */
|
||||
} ReadDefinitionsFlags;
|
||||
|
||||
static int context_read_definitions(Context *c, const char* node, ReadDefinitionsFlags flags) {
|
||||
@@ -315,6 +357,10 @@ static int context_read_definitions(Context *c, const char* node, ReadDefinition
|
||||
if (!dirs)
|
||||
return log_oom();
|
||||
|
||||
r = read_component(c);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = read_features(c, (const char**) dirs);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -344,6 +390,9 @@ static int context_read_definitions(Context *c, const char* node, ReadDefinition
|
||||
"No transfer definitions found.");
|
||||
}
|
||||
|
||||
if (FLAGS_SET(flags, READ_DEFINITIONS_REQUIRES_ENABLED_COMPONENT) && !c->component_enabled)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EHOSTDOWN), "Component is disabled.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1094,7 +1143,9 @@ static int context_load_offline(
|
||||
|
||||
static int context_load_online(
|
||||
Context *context,
|
||||
ProcessImageFlags process_image_flags) {
|
||||
ProcessImageFlags process_image_flags,
|
||||
ReadDefinitionsFlags read_definitions_flags) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(context);
|
||||
@@ -1105,7 +1156,7 @@ static int context_load_online(
|
||||
r = context_load_offline(
|
||||
context,
|
||||
process_image_flags,
|
||||
READ_DEFINITIONS_REQUIRES_ENABLED_TRANSFERS|READ_DEFINITIONS_REQUIRES_ANY_TRANSFERS);
|
||||
read_definitions_flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1156,7 +1207,10 @@ static int context_load_paths_from_image(Context *context, Image *image) {
|
||||
* syntactically validated by dispatch_target_identifier(), but might still point to components which don’t
|
||||
* exist, images which the user isn’t privileged to access, etc. This function validates the TargetIdentifier
|
||||
* against an enumerated list of known targets, which are safe to update without additional permissions. */
|
||||
static int context_load_online_from_target(Context *context, ProcessImageFlags process_image_flags) {
|
||||
static int context_load_online_from_target(
|
||||
Context *context,
|
||||
ProcessImageFlags process_image_flags,
|
||||
ReadDefinitionsFlags read_definitions_flags) {
|
||||
int r;
|
||||
|
||||
assert(context);
|
||||
@@ -1247,7 +1301,7 @@ static int context_load_online_from_target(Context *context, ProcessImageFlags p
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
return context_load_online(context, process_image_flags);
|
||||
return context_load_online(context, process_image_flags, read_definitions_flags);
|
||||
}
|
||||
|
||||
static int context_on_acquire_progress(const Transfer *t, const Instance *inst, unsigned percentage) {
|
||||
@@ -1650,7 +1704,11 @@ static int verb_list(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
if (context.component_all)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "--component-all currently not supported for '%s'.", argv[0]);
|
||||
|
||||
r = context_load_online(&context, PROCESS_IMAGE_READ_ONLY);
|
||||
r = context_load_online(
|
||||
&context,
|
||||
PROCESS_IMAGE_READ_ONLY,
|
||||
READ_DEFINITIONS_REQUIRES_ENABLED_TRANSFERS|
|
||||
READ_DEFINITIONS_REQUIRES_ANY_TRANSFERS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1860,7 +1918,9 @@ static int verb_check_new(int argc, char *argv[], uintptr_t _data, void *userdat
|
||||
|
||||
r = context_load_online(
|
||||
&context,
|
||||
PROCESS_IMAGE_READ_ONLY);
|
||||
PROCESS_IMAGE_READ_ONLY,
|
||||
READ_DEFINITIONS_REQUIRES_ENABLED_TRANSFERS|
|
||||
READ_DEFINITIONS_REQUIRES_ANY_TRANSFERS);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -1919,7 +1979,11 @@ static int vl_method_check_new(sd_varlink *link, sd_json_variant *parameters, sd
|
||||
/* CheckNew is always online */
|
||||
context.offline = false;
|
||||
|
||||
r = context_load_online_from_target(&context, PROCESS_IMAGE_READ_ONLY);
|
||||
r = context_load_online_from_target(
|
||||
&context,
|
||||
PROCESS_IMAGE_READ_ONLY,
|
||||
READ_DEFINITIONS_REQUIRES_ENABLED_TRANSFERS|
|
||||
READ_DEFINITIONS_REQUIRES_ANY_TRANSFERS);
|
||||
if (r == -ENOENT)
|
||||
return sd_varlink_error(link, "io.systemd.SysUpdate.NoSuchTarget", NULL);
|
||||
if (r < 0)
|
||||
@@ -1976,7 +2040,10 @@ static int verb_update_impl(int argc, char **argv, UpdateActionFlags action_flag
|
||||
|
||||
r = context_load_online(
|
||||
&context,
|
||||
/* process_image_flags= */ 0);
|
||||
/* process_image_flags= */ 0,
|
||||
READ_DEFINITIONS_REQUIRES_ENABLED_TRANSFERS|
|
||||
READ_DEFINITIONS_REQUIRES_ANY_TRANSFERS|
|
||||
READ_DEFINITIONS_REQUIRES_ENABLED_COMPONENT);
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT)
|
||||
return r;
|
||||
@@ -2108,7 +2175,9 @@ static int verb_pending_or_reboot(int argc, char *argv[], uintptr_t _data, void
|
||||
r = context_load_offline(
|
||||
&context,
|
||||
/* process_image_flags= */ 0,
|
||||
READ_DEFINITIONS_REQUIRES_ENABLED_TRANSFERS|READ_DEFINITIONS_REQUIRES_ANY_TRANSFERS);
|
||||
READ_DEFINITIONS_REQUIRES_ENABLED_TRANSFERS|
|
||||
READ_DEFINITIONS_REQUIRES_ANY_TRANSFERS|
|
||||
READ_DEFINITIONS_REQUIRES_ENABLED_COMPONENT);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -24,6 +24,10 @@ typedef struct Context {
|
||||
LoopDevice *loop_device;
|
||||
char *mounted_dir;
|
||||
|
||||
char *component_description;
|
||||
char **component_documentation;
|
||||
bool component_enabled;
|
||||
|
||||
Transfer **transfers;
|
||||
size_t n_transfers;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user