1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-03 05:18:09 +03:00

sysupdate: Add verb to inspect features

This commit is contained in:
Adrian Vovk 2024-07-03 17:49:36 -04:00
parent 2ffc8b23f0
commit 0cd1a58921
No known key found for this signature in database
GPG Key ID: 90A7B546533E15FB
5 changed files with 163 additions and 1 deletions

View File

@ -106,6 +106,16 @@
<xi:include href="version-info.xml" xpointer="v251"/></listitem>
</varlistentry>
<varlistentry>
<term><option>features</option> <optional><replaceable>FEATURE</replaceable></optional></term>
<listitem><para>If invoked without an argument, enumerates optional features and shows a summarizing
table, including which features are enabled or disabled. If a feature argument is specified, shows
details about the specific feature, including the transfers that are controlled by the feature.</para>
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
</varlistentry>
<varlistentry>
<term><option>check-new</option></term>

View File

@ -45,11 +45,16 @@ Transfer* transfer_free(Transfer *t) {
t->temporary_path = rm_rf_subvolume_and_free(t->temporary_path);
free(t->id);
free(t->min_version);
strv_free(t->protected_versions);
free(t->current_symlink);
free(t->final_path);
strv_free(t->features);
strv_free(t->requisite_features);
strv_free(t->changelog);
strv_free(t->appstream);
@ -520,6 +525,7 @@ int transfer_read_definition(Transfer *t, const char *path, const char **dirs, H
};
_cleanup_free_ char *filename = NULL;
char *e;
int r;
assert(path);
@ -545,6 +551,10 @@ int transfer_read_definition(Transfer *t, const char *path, const char **dirs, H
if (r < 0)
return r;
e = ASSERT_PTR(endswith(filename, ".transfer") ?: endswith(filename, ".conf"));
*e = 0; /* Remove the file extension */
t->id = TAKE_PTR(filename);
t->enabled = transfer_decide_if_enabled(t, known_features);
if (!RESOURCE_IS_SOURCE(t->source.type))

View File

@ -15,11 +15,15 @@ typedef struct Transfer Transfer;
#include "sysupdate.h"
struct Transfer {
char *id;
char *min_version;
char **protected_versions;
char *current_symlink;
bool verify;
char **features;
char **requisite_features;
bool enabled;
Resource source, target;

View File

@ -1201,6 +1201,140 @@ static int verb_list(int argc, char **argv, void *userdata) {
}
}
static int verb_features(int argc, char **argv, void *userdata) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(umount_and_rmdir_and_freep) char *mounted_dir = NULL;
_cleanup_(context_freep) Context* context = NULL;
_cleanup_(table_unrefp) Table *table = NULL;
const char *feature_id;
Feature *f;
int r;
assert(argc <= 2);
feature_id = argc >= 2 ? argv[1] : NULL;
r = process_image(/* ro= */ true, &mounted_dir, &loop_device);
if (r < 0)
return r;
r = context_make_offline(&context, loop_device ? loop_device->node : NULL);
if (r < 0)
return r;
if (feature_id) {
_cleanup_strv_free_ char **transfers = NULL;
f = hashmap_get(context->features, feature_id);
if (!f)
return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
"Optional feature not found: %s",
feature_id);
table = table_new_vertical();
if (!table)
return log_oom();
FOREACH_ARRAY(tr, context->transfers, context->n_transfers) {
Transfer *t = *tr;
if (!strv_contains(t->features, f->id) && !strv_contains(t->requisite_features, f->id))
continue;
r = strv_extend(&transfers, t->id);
if (r < 0)
return log_oom();
}
FOREACH_ARRAY(tr, context->disabled_transfers, context->n_disabled_transfers) {
Transfer *t = *tr;
if (!strv_contains(t->features, f->id) && !strv_contains(t->requisite_features, f->id))
continue;
r = strv_extend(&transfers, t->id);
if (r < 0)
return log_oom();
}
r = table_add_many(table,
TABLE_FIELD, "Name",
TABLE_STRING, f->id,
TABLE_FIELD, "Enabled",
TABLE_BOOLEAN, f->enabled);
if (r < 0)
return table_log_add_error(r);
if (f->description) {
r = table_add_many(table, TABLE_FIELD, "Description", TABLE_STRING, f->description);
if (r < 0)
return table_log_add_error(r);
}
if (f->documentation) {
r = table_add_many(table,
TABLE_FIELD, "Documentation",
TABLE_STRING, f->documentation,
TABLE_SET_URL, f->documentation);
if (r < 0)
return table_log_add_error(r);
}
if (f->appstream) {
r = table_add_many(table,
TABLE_FIELD, "AppStream",
TABLE_STRING, f->appstream,
TABLE_SET_URL, f->appstream);
if (r < 0)
return table_log_add_error(r);
}
if (!strv_isempty(transfers)) {
r = table_add_many(table, TABLE_FIELD, "Transfers", TABLE_STRV_WRAPPED, transfers);
if (r < 0)
return table_log_add_error(r);
}
return table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
} else if (FLAGS_SET(arg_json_format_flags, SD_JSON_FORMAT_OFF)) {
table = table_new("", "feature", "description", "documentation");
if (!table)
return log_oom();
HASHMAP_FOREACH(f, context->features) {
r = table_add_many(table,
TABLE_BOOLEAN_CHECKMARK, f->enabled,
TABLE_SET_COLOR, ansi_highlight_green_red(f->enabled),
TABLE_STRING, f->id,
TABLE_STRING, f->description,
TABLE_STRING, f->documentation,
TABLE_SET_URL, f->documentation);
if (r < 0)
return table_log_add_error(r);
}
return table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
} else {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *json = NULL;
_cleanup_strv_free_ char **features = NULL;
HASHMAP_FOREACH(f, context->features) {
r = strv_extend(&features, f->id);
if (r < 0)
return log_oom();
}
r = sd_json_buildo(&json, SD_JSON_BUILD_PAIR_STRV("features", features));
if (r < 0)
return log_error_errno(r, "Failed to create JSON: %m");
r = sd_json_variant_dump(json, arg_json_format_flags, stdout, NULL);
if (r < 0)
return log_error_errno(r, "Failed to print JSON: %m");
}
return 0;
}
static int verb_check_new(int argc, char **argv, void *userdata) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(umount_and_rmdir_and_freep) char *mounted_dir = NULL;
@ -1517,6 +1651,7 @@ static int verb_help(int argc, char **argv, void *userdata) {
"\n%5$sUpdate OS images.%6$s\n"
"\n%3$sCommands:%4$s\n"
" list [VERSION] Show installed and available versions\n"
" features [FEATURE] Show optional features\n"
" check-new Check if there's a new version available\n"
" update [VERSION] Install new version now\n"
" vacuum Make room, by deleting old versions\n"
@ -1729,8 +1864,9 @@ static int sysupdate_main(int argc, char *argv[]) {
static const Verb verbs[] = {
{ "list", VERB_ANY, 2, VERB_DEFAULT, verb_list },
{ "components", VERB_ANY, 1, 0, verb_components },
{ "features", VERB_ANY, 2, 0, verb_features },
{ "check-new", VERB_ANY, 1, 0, verb_check_new },
{ "update", VERB_ANY, 2, 0, verb_update },
{ "update", VERB_ANY, 2, 0, verb_update },
{ "vacuum", VERB_ANY, 1, 0, verb_vacuum },
{ "reboot", 1, 1, 0, verb_pending_or_reboot },
{ "pending", 1, 1, 0, verb_pending_or_reboot },

View File

@ -303,6 +303,8 @@ EOF
verify_version_current "$blockdev" "$sector_size" v5 2
# Now let's try enabling an optional feature
"$SYSUPDATE" features | grep "optional"
"$SYSUPDATE" features optional | grep "99-optional"
test ! -f "$WORKDIR/xbootldr/EFI/Linux/uki_v5.efi.extra.d/optional.efi"
mkdir "$CONFIGDIR/optional.feature.d"
echo -e "[Feature]\nEnabled=true" > "$CONFIGDIR/optional.feature.d/enable.conf"