From: Lennart Poettering Date: Wed, 24 Jun 2026 10:35:01 +0000 (+0200) Subject: sysupdate: add enable-feature/disable-feature verbs X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0c7992f67489e8ae9c60c819b0058ffd2664e3c3;p=thirdparty%2Fsystemd.git sysupdate: add enable-feature/disable-feature verbs These do what updatectl's verbs of the same name does, but are implemented as low-level concepts in sysupdate itself. (The idea is to eventually wrap this in Varlink IPC, and make updatectl use them that way.) --- diff --git a/src/sysupdate/sysupdate.c b/src/sysupdate/sysupdate.c index c31e7117956..61761435188 100644 --- a/src/sysupdate/sysupdate.c +++ b/src/sysupdate/sysupdate.c @@ -15,6 +15,7 @@ #include "discover-image.h" #include "dissect-image.h" #include "dlopen-note.h" +#include "dropin.h" #include "env-util.h" #include "errno-util.h" #include "fd-util.h" @@ -33,6 +34,7 @@ #include "pager.h" #include "parse-argument.h" #include "parse-util.h" +#include "path-util.h" #include "pretty-print.h" #include "runtime-scope.h" #include "sort-util.h" @@ -1945,6 +1947,93 @@ static int verb_features(int argc, char *argv[], uintptr_t _data, void *userdata return 0; } +static int make_dropin_dir(Context *c, char **ret) { + _cleanup_free_ char *dir = NULL; + + assert(c); + assert(ret); + + /* Returns the (writable) directory where feature definitions live, so that we can drop our + * 'Enabled=' override right next to them. This mirrors the directory logic in + * context_read_definitions(), but settles on a single writable location below /etc. */ + + if (c->definitions) + dir = strdup(c->definitions); /* --root= is not supported for this for now */ + else if (c->component) { + _cleanup_free_ char *n = strjoin("sysupdate.", c->component, ".d"); + if (!n) + return log_oom(); + + dir = path_join(c->root, SYSCONF_DIR, n); + } else + dir = path_join(c->root, SYSCONF_DIR "/sysupdate.d"); + if (!dir) + return log_oom(); + + *ret = TAKE_PTR(dir); + return 0; +} + +VERB(verb_enable_feature, "enable-feature", "FEATURE…", 2, VERB_ANY, 0, + "Enable optional feature"); +VERB(verb_enable_feature, "disable-feature", "FEATURE…", 2, VERB_ANY, 0, + "Disable optional feature"); +static int verb_enable_feature(int argc, char *argv[], uintptr_t _data, void *userdata) { + bool enable = streq(argv[0], "enable-feature"); + int r; + + _cleanup_(context_done) Context context = CONTEXT_NULL; + r = context_from_cmdline(&context); + if (r < 0) + return r; + + if (context.component_all) + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "--component-all currently not supported for '%s'.", argv[0]); + + r = context_load_offline( + &context, + /* process_image_flags= */ 0, + /* read_definitions_flags= */ 0); + if (r < 0) + return r; + + _cleanup_free_ char *dropin_dir = NULL; + r = make_dropin_dir(&context, &dropin_dir); + if (r < 0) + return r; + + STRV_FOREACH(name, strv_skip(argv, 1)) { + + if (!feature_name_valid(*name)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Feature name invalid: %s", *name); + + if (!hashmap_contains(context.features, *name)) + return log_error_errno(SYNTHETIC_ERRNO(ENOENT), + "Optional feature not found: %s", *name); + + _cleanup_free_ char *fname = strjoin(*name, ".feature"); + if (!fname) + return log_oom(); + + /* We assume that no sysadmin will name their config 50-systemd-sysupdate-enabled.conf */ + r = write_drop_in_format( + dropin_dir, + fname, + 50, "systemd-sysupdate-enabled", + "# Generated via 'systemd-sysupdate %s'\n\n" + "[Feature]\n" + "Enabled=%s\n", + argv[0], + yes_no(enable)); + if (r < 0) + return log_error_errno(r, "Failed to write drop-in for feature '%s': %m", *name); + + log_info("Feature '%s' %s.", *name, enable ? "enabled" : "disabled"); + } + + return 0; +} + VERB_NOARG(verb_check_new, "check-new", "Check if there's a new version available"); static int verb_check_new(int argc, char *argv[], uintptr_t _data, void *userdata) {