/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#include <getopt.h>
#include <locale.h>
#include "sd-bus.h"
#include "hashmap.h"
#include "json-util.h"
#include "main-func.h"
+#include "options.h"
#include "pager.h"
#include "polkit-agent.h"
#include "pretty-print.h"
return table_print_with_pager(table, SD_JSON_FORMAT_OFF, arg_pager_flags, arg_legend);
}
+VERB(verb_list, "list", "[TARGET[@VERSION]]", VERB_ANY, 2, VERB_DEFAULT|VERB_ONLINE_ONLY,
+ "List available targets and versions");
static int verb_list(int argc, char *argv[], uintptr_t _data, void *userdata) {
sd_bus *bus = ASSERT_PTR(userdata);
_cleanup_free_ char *target_path = NULL, *version = NULL;
return 0;
}
+VERB(verb_check, "check", "[TARGET...]", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY,
+ "Check for updates");
static int verb_check(int argc, char *argv[], uintptr_t _data, void *userdata) {
sd_bus *bus = ASSERT_PTR(userdata);
_cleanup_(table_unrefp) Table *table = NULL;
return did_anything ? 1 : 0;
}
+VERB(verb_update, "update", "[TARGET[@VERSION]...]", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY,
+ "Install updates");
static int verb_update(int argc, char *argv[], uintptr_t _data, void *userdata) {
sd_bus *bus = ASSERT_PTR(userdata);
_cleanup_strv_free_ char **targets = NULL;
return count + disabled > 0 ? 1 : 0;
}
+VERB(verb_vacuum, "vacuum", "[TARGET...]", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY,
+ "Clean up old updates");
static int verb_vacuum(int argc, char *argv[], uintptr_t _data, void *userdata) {
sd_bus *bus = ASSERT_PTR(userdata);
_cleanup_strv_free_ char **targets = NULL, **target_paths = NULL;
return table_print_with_pager(table, SD_JSON_FORMAT_OFF, arg_pager_flags, arg_legend);
}
+VERB(verb_features, "features", "[FEATURE]", VERB_ANY, 2, VERB_ONLINE_ONLY,
+ "List and inspect optional features on host OS");
static int verb_features(int argc, char *argv[], uintptr_t _data, void *userdata) {
sd_bus *bus = ASSERT_PTR(userdata);
_cleanup_(table_unrefp) Table *table = NULL;
return table_print_with_pager(table, SD_JSON_FORMAT_OFF, arg_pager_flags, false);
}
+VERB(verb_enable, "enable", "FEATURE...", 2, VERB_ANY, VERB_ONLINE_ONLY,
+ "Enable optional feature on host OS");
+VERB(verb_enable, "disable", "FEATURE...", 2, VERB_ANY, VERB_ONLINE_ONLY,
+ "Disable optional feature on host OS");
static int verb_enable(int argc, char *argv[], uintptr_t _data, void *userdata) {
sd_bus *bus = ASSERT_PTR(userdata);
bool did_anything = false, enable;
static int help(void) {
_cleanup_free_ char *link = NULL;
+ _cleanup_(table_unrefp) Table *verbs = NULL, *verbs2 = NULL, *options = NULL;
int r;
r = terminal_urlify_man("updatectl", "1", &link);
if (r < 0)
return log_oom();
- printf("%1$s [OPTIONS...] [VERSION]\n"
- "\n%5$sManage system updates.%6$s\n"
- "\n%3$sCommands:%4$s\n"
- " list [TARGET[@VERSION]] List available targets and versions\n"
- " check [TARGET...] Check for updates\n"
- " update [TARGET[@VERSION]...] Install updates\n"
- " vacuum [TARGET...] Clean up old updates\n"
- " features [FEATURE] List and inspect optional features on host OS\n"
- " enable FEATURE... Enable optional feature on host OS\n"
- " disable FEATURE... Disable optional feature on host OS\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- "\n%3$sOptions:%4$s\n"
- " --reboot Reboot after updating to newer version\n"
- " --offline Do not fetch metadata from the network\n"
- " --now Download/delete resources immediately\n"
- " -H --host=[USER@]HOST Operate on remote host\n"
- " --no-pager Do not pipe output into a pager\n"
- " --no-legend Do not show the headers and footers\n"
- "\nSee the %2$s for details.\n"
- , program_invocation_short_name
- , link
- , ansi_underline(), ansi_normal()
- , ansi_highlight(), ansi_normal()
- );
+ r = verbs_get_help_table(&verbs);
+ if (r < 0)
+ return r;
- return 0;
-}
+ r = option_parser_get_help_table_group("Verbs", &verbs2);
+ if (r < 0)
+ return r;
-static int parse_argv(int argc, char *argv[]) {
+ r = option_parser_get_help_table(&options);
+ if (r < 0)
+ return r;
- enum {
- ARG_VERSION = 0x100,
- ARG_NO_PAGER,
- ARG_NO_LEGEND,
- ARG_REBOOT,
- ARG_OFFLINE,
- ARG_NOW,
- };
+ (void) table_sync_column_widths(0, verbs, verbs2, options);
- static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "no-pager", no_argument, NULL, ARG_NO_PAGER },
- { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
- { "host", required_argument, NULL, 'H' },
- { "reboot", no_argument, NULL, ARG_REBOOT },
- { "offline", no_argument, NULL, ARG_OFFLINE },
- { "now", no_argument, NULL, ARG_NOW },
- {}
- };
+ printf("%s [OPTIONS...] [VERSION]\n"
+ "\n%sManage system updates.%s\n"
+ "\n%sCommands:%s\n",
+ program_invocation_short_name,
+ ansi_highlight(),
+ ansi_normal(),
+ ansi_underline(),
+ ansi_normal());
+
+ r = table_print_or_warn(verbs);
+ if (r < 0)
+ return r;
+ r = table_print_or_warn(verbs2);
+ if (r < 0)
+ return r;
+
+ printf("\n%sOptions:%s\n",
+ ansi_underline(),
+ ansi_normal());
+
+ r = table_print_or_warn(options);
+ if (r < 0)
+ return r;
+
+ printf("\nSee the %s for details.\n", link);
+ return 0;
+}
- int c;
+VERB_COMMON_HELP_HIDDEN(help);
+static int parse_argv(int argc, char *argv[], char ***ret_args) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "hH:", options, NULL)) >= 0) {
- switch (c) {
+ OptionParser state = { argc, argv };
+ const char *arg;
- case 'h':
- return help();
+ FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c)
+ switch (c) {
- case ARG_VERSION:
- return version();
+ OPTION_LONG("reboot", NULL, "Reboot after updating to newer version"):
+ arg_reboot = true;
+ break;
- case ARG_NO_PAGER:
- arg_pager_flags |= PAGER_DISABLE;
+ OPTION_LONG("offline", NULL, "Do not fetch metadata from the network"):
+ arg_offline = true;
break;
- case ARG_NO_LEGEND:
- arg_legend = false;
+ OPTION_LONG("now", NULL, "Download/delete resources immediately"):
+ arg_now = true;
break;
- case 'H':
+ OPTION_COMMON_HOST:
arg_transport = BUS_TRANSPORT_REMOTE;
- arg_host = optarg;
+ arg_host = arg;
break;
- case ARG_REBOOT:
- arg_reboot = true;
+ OPTION_COMMON_NO_PAGER:
+ arg_pager_flags |= PAGER_DISABLE;
break;
- case ARG_OFFLINE:
- arg_offline = true;
+ OPTION_COMMON_NO_LEGEND:
+ arg_legend = false;
break;
- case ARG_NOW:
- arg_now = true;
- break;
+ OPTION_GROUP("Verbs"): {}
- case '?':
- return -EINVAL;
+ OPTION_COMMON_HELP:
+ return help();
- default:
- assert_not_reached();
+ OPTION_COMMON_VERSION:
+ return version();
}
- }
+ *ret_args = option_parser_get_args(&state);
return 1;
}
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
- static const Verb verbs[] = {
- { "list", VERB_ANY, 2, VERB_DEFAULT|VERB_ONLINE_ONLY, verb_list },
- { "check", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_check },
- { "update", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_update },
- { "vacuum", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, verb_vacuum },
- { "features", VERB_ANY, 2, VERB_ONLINE_ONLY, verb_features },
- { "enable", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_enable },
- { "disable", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_enable },
- {}
- };
-
setlocale(LC_ALL, "");
log_setup();
(void) signal(SIGWINCH, columns_lines_cache_reset);
- r = parse_argv(argc, argv);
+ char **args = NULL;
+ r = parse_argv(argc, argv, &args);
if (r <= 0)
return r;
(void) sd_bus_set_allow_interactive_authorization(bus, true);
- return dispatch_verb(argc, argv, verbs, bus);
+ return dispatch_verb_with_args(args, bus);
}
DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);