A few more conversions to the option and verb macros (#41797)

This commit is contained in:
Daan De Meyer
2026-04-24 11:32:31 +02:00
committed by GitHub
9 changed files with 518 additions and 706 deletions
+47 -78
View File
@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <fcntl.h>
#include <getopt.h>
#include <microhttpd.h>
#include <stdlib.h>
#include <string.h>
@@ -18,6 +17,7 @@
#include "errno-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "format-table.h"
#include "glob-util.h"
#include "hostname-setup.h"
#include "hostname-util.h"
@@ -28,6 +28,7 @@
#include "main-func.h"
#include "memory-util.h"
#include "microhttpd-util.h"
#include "options.h"
#include "os-util.h"
#include "output-mode.h"
#include "parse-util.h"
@@ -1090,92 +1091,52 @@ static mhd_result request_handler(
static int help(void) {
_cleanup_free_ char *link = NULL;
_cleanup_(table_unrefp) Table *options = NULL;
int r;
r = terminal_urlify_man("systemd-journal-gatewayd.service", "8", &link);
if (r < 0)
return log_oom();
printf("%s [OPTIONS...] ...\n\n"
"HTTP server for journal events.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --cert=CERT.PEM Server certificate in PEM format\n"
" --key=KEY.PEM Server key in PEM format\n"
" --trust=CERT.PEM Certificate authority certificate in PEM format\n"
" --system Serve system journal\n"
" --user Serve the user journal for the current user\n"
" -m --merge Serve all available journals\n"
" -D --directory=PATH Serve journal files in directory\n"
" --file=PATH Serve this journal file\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
link);
r = option_parser_get_help_table(&options);
if (r < 0)
return r;
printf("%s [OPTIONS...] ...\n\n"
"HTTP server for journal events.\n\n",
program_invocation_short_name);
r = table_print_or_warn(options);
if (r < 0)
return r;
printf("\nSee the %s for details.\n", link);
return 0;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_KEY,
ARG_CERT,
ARG_TRUST,
ARG_USER,
ARG_SYSTEM,
ARG_MERGE,
ARG_FILE,
};
int r, c;
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "key", required_argument, NULL, ARG_KEY },
{ "cert", required_argument, NULL, ARG_CERT },
{ "trust", required_argument, NULL, ARG_TRUST },
{ "user", no_argument, NULL, ARG_USER },
{ "system", no_argument, NULL, ARG_SYSTEM },
{ "merge", no_argument, NULL, 'm' },
{ "directory", required_argument, NULL, 'D' },
{ "file", required_argument, NULL, ARG_FILE },
{}
};
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "hD:", options, NULL)) >= 0)
OptionParser state = { argc, argv };
const char *arg;
int r;
FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c)
switch (c) {
case 'h':
OPTION_COMMON_HELP:
return help();
case ARG_VERSION:
OPTION_COMMON_VERSION:
return version();
case ARG_KEY:
if (arg_key_pem)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Key file specified twice");
r = read_full_file_full(
AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
NULL,
&arg_key_pem, NULL);
if (r < 0)
return log_error_errno(r, "Failed to read key file: %m");
assert(arg_key_pem);
break;
case ARG_CERT:
OPTION_LONG("cert", "CERT.PEM", "Server certificate in PEM format"):
if (arg_cert_pem)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Certificate file specified twice");
r = read_full_file_full(
AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
AT_FDCWD, arg, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_CONNECT_SOCKET,
NULL,
&arg_cert_pem, NULL);
@@ -1184,13 +1145,27 @@ static int parse_argv(int argc, char *argv[]) {
assert(arg_cert_pem);
break;
case ARG_TRUST:
OPTION_LONG("key", "KEY.PEM", "Server key in PEM format"):
if (arg_key_pem)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Key file specified twice");
r = read_full_file_full(
AT_FDCWD, arg, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
NULL,
&arg_key_pem, NULL);
if (r < 0)
return log_error_errno(r, "Failed to read key file: %m");
assert(arg_key_pem);
break;
OPTION_LONG("trust", "CERT.PEM", "Certificate authority certificate in PEM format"):
#if HAVE_GNUTLS
if (arg_trust_pem)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"CA certificate file specified twice");
r = read_full_file_full(
AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
AT_FDCWD, arg, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_CONNECT_SOCKET,
NULL,
&arg_trust_pem, NULL);
@@ -1203,38 +1178,32 @@ static int parse_argv(int argc, char *argv[]) {
"Option --trust= is not available.");
#endif
case ARG_SYSTEM:
OPTION_LONG("system", NULL, "Serve system journal"):
arg_journal_type |= SD_JOURNAL_SYSTEM;
break;
case ARG_USER:
OPTION_LONG("user", NULL, "Serve the user journal for the current user"):
arg_journal_type |= SD_JOURNAL_CURRENT_USER;
break;
case 'm':
OPTION('m', "merge", NULL, "Serve all available journals"):
arg_merge = true;
break;
case 'D':
r = free_and_strdup_warn(&arg_directory, optarg);
OPTION('D', "directory", "PATH", "Serve journal files in directory"):
r = free_and_strdup_warn(&arg_directory, arg);
if (r < 0)
return r;
break;
case ARG_FILE:
r = glob_extend(&arg_file, optarg, GLOB_NOCHECK);
OPTION_LONG("file", "PATH", "Serve this journal file"):
r = glob_extend(&arg_file, arg, GLOB_NOCHECK);
if (r < 0)
return log_error_errno(r, "Failed to add paths: %m");
break;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
if (optind < argc)
if (option_parser_get_n_args(&state) > 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"This program does not take arguments.");
+5 -11
View File
@@ -100,15 +100,13 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) {
OPTION_COMMON_VERSION:
return version();
OPTION_LONG("private-key", "KEY", "Private key in PEM format"):
OPTION_COMMON_PRIVATE_KEY("Private key in PEM format"):
r = free_and_strdup_warn(&arg_private_key, arg);
if (r < 0)
return r;
break;
OPTION_LONG("private-key-source", "SOURCE",
"Specify how to use KEY for --private-key= "
"(file, provider:PROVIDER, engine:ENGINE)"):
OPTION_COMMON_PRIVATE_KEY_SOURCE:
r = parse_openssl_key_source_argument(
arg,
&arg_private_key_source,
@@ -117,17 +115,13 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) {
return r;
break;
OPTION_LONG("certificate", "PATH|URI",
"PEM certificate to use for signing, "
"or a provider-specific designation if --certificate-source= is used"):
OPTION_COMMON_CERTIFICATE("PEM certificate to use for signing"):
r = free_and_strdup_warn(&arg_certificate, arg);
if (r < 0)
return r;
break;
OPTION_LONG("certificate-source", "SOURCE",
"Specify how to interpret the certificate from --certificate= "
"(file, provider:PROVIDER)"):
OPTION_COMMON_CERTIFICATE_SOURCE:
r = parse_openssl_certificate_source_argument(
arg,
&arg_certificate_source,
@@ -226,7 +220,7 @@ static int verb_validate(int argc, char *argv[], uintptr_t _data, void *userdata
VERB_NOARG(verb_extract_public, "extract-public",
"Extract a public key");
VERB(verb_extract_public, "public", NULL, VERB_ANY, 1, 0, NULL); /* Deprecated alias */
VERB_NOARG(verb_extract_public, "public", /* help= */ NULL); /* Deprecated but kept for backward compat. */
static int verb_extract_public(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(EVP_PKEY_freep) EVP_PKEY *public_key = NULL;
int r;
+60 -98
View File
@@ -2,7 +2,6 @@
#include <fcntl.h>
#include <fnmatch.h>
#include <getopt.h>
#include <stdio.h>
#include <unistd.h>
@@ -18,6 +17,7 @@
#include "format-table.h"
#include "log.h"
#include "main-func.h"
#include "options.h"
#include "pager.h"
#include "parse-argument.h"
#include "pidref.h"
@@ -170,139 +170,100 @@ static int print_inhibitors(sd_bus *bus) {
static int help(void) {
_cleanup_free_ char *link = NULL;
_cleanup_(table_unrefp) Table *options = NULL;
int r;
r = terminal_urlify_man("systemd-inhibit", "1", &link);
if (r < 0)
return log_oom();
printf("%s [OPTIONS...] COMMAND ...\n"
"\n%sExecute a process while inhibiting shutdown/sleep/idle.%s\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --no-ask-password Do not attempt interactive authorization\n"
" --no-pager Do not pipe output into a pager\n"
" --no-legend Do not show the headers and footers\n"
" --json=pretty|short|off\n"
" Generate JSON output\n"
" --what=WHAT Operations to inhibit, colon separated list of:\n"
" shutdown, sleep, idle, handle-power-key,\n"
" handle-suspend-key, handle-hibernate-key,\n"
" handle-lid-switch\n"
" --who=STRING A descriptive string who is inhibiting\n"
" --why=STRING A descriptive string why is being inhibited\n"
" --mode=MODE One of block, block-weak, or delay\n"
" --list List active inhibitors\n"
"\nSee the %s for details.\n",
r = option_parser_get_help_table(&options);
if (r < 0)
return r;
printf("%s [OPTIONS...] COMMAND ...\n\n"
"%sExecute a process while inhibiting shutdown/sleep/idle.%s\n\n",
program_invocation_short_name,
ansi_highlight(),
ansi_normal(),
link);
ansi_normal());
r = table_print_or_warn(options);
if (r < 0)
return r;
printf("\nSee the %s for details.\n", link);
return 0;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_WHAT,
ARG_WHO,
ARG_WHY,
ARG_MODE,
ARG_LIST,
ARG_NO_ASK_PASSWORD,
ARG_NO_PAGER,
ARG_NO_LEGEND,
ARG_JSON,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
{ "what", required_argument, NULL, ARG_WHAT },
{ "who", required_argument, NULL, ARG_WHO },
{ "why", required_argument, NULL, ARG_WHY },
{ "mode", required_argument, NULL, ARG_MODE },
{ "list", no_argument, NULL, ARG_LIST },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
{ "json", required_argument, NULL, ARG_JSON },
{}
};
int c, r;
static int parse_argv(int argc, char *argv[], char ***remaining_args) {
assert(argc >= 0);
assert(argv);
assert(remaining_args);
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
optind = 0;
while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0)
OptionParser state = { argc, argv, OPTION_PARSER_STOP_AT_FIRST_NONOPTION };
const char *arg;
int r;
FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c)
switch (c) {
case 'h':
OPTION_COMMON_HELP:
return help();
case ARG_VERSION:
OPTION_COMMON_VERSION:
return version();
case ARG_WHAT:
arg_what = optarg;
break;
case ARG_WHO:
arg_who = optarg;
break;
case ARG_WHY:
arg_why = optarg;
break;
case ARG_MODE:
arg_mode = optarg;
break;
case ARG_LIST:
arg_action = ACTION_LIST;
break;
case ARG_NO_ASK_PASSWORD:
OPTION_COMMON_NO_ASK_PASSWORD:
arg_ask_password = false;
break;
case ARG_NO_PAGER:
OPTION_COMMON_NO_PAGER:
arg_pager_flags |= PAGER_DISABLE;
break;
case ARG_NO_LEGEND:
OPTION_COMMON_NO_LEGEND:
arg_legend = false;
break;
case ARG_JSON:
r = parse_json_argument(optarg, &arg_json_format_flags);
OPTION_COMMON_JSON:
r = parse_json_argument(arg, &arg_json_format_flags);
if (r <= 0)
return r;
break;
case '?':
return -EINVAL;
OPTION_LONG("what", "WHAT",
"Operations to inhibit, colon separated list "
"(shutdown, sleep, idle, handle-power-key, "
"handle-suspend-key, handle-hibernate-key, "
"handle-lid-switch)"):
arg_what = arg;
break;
default:
assert_not_reached();
OPTION_LONG("who", "STRING",
"A descriptive string who is inhibiting"):
arg_who = arg;
break;
OPTION_LONG("why", "STRING",
"A descriptive string why is being inhibited"):
arg_why = arg;
break;
OPTION_LONG("mode", "MODE", "One of block, block-weak, or delay"):
arg_mode = arg;
break;
OPTION_LONG("list", NULL, "List active inhibitors"):
arg_action = ACTION_LIST;
break;
}
if (arg_action == ACTION_INHIBIT && optind == argc)
char **args = option_parser_get_args(&state);
if (arg_action == ACTION_INHIBIT && strv_isempty(args))
arg_action = ACTION_LIST;
else if (arg_action == ACTION_INHIBIT && optind >= argc)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Missing command line to execute.");
*remaining_args = args;
return 1;
}
@@ -312,7 +273,8 @@ static int run(int argc, char *argv[]) {
log_setup();
r = parse_argv(argc, argv);
char **args = NULL;
r = parse_argv(argc, argv, &args);
if (r <= 0)
return r;
@@ -337,7 +299,7 @@ static int run(int argc, char *argv[]) {
arg_what = "idle:sleep:shutdown";
if (!arg_who) {
w = strv_join(argv + optind, " ");
w = strv_join(args, " ");
if (!w)
return log_oom();
@@ -354,7 +316,7 @@ static int run(int argc, char *argv[]) {
if (fd < 0)
return log_error_errno(fd, "Failed to inhibit: %s", bus_error_message(&error, fd));
arguments = strv_copy(argv + optind);
arguments = strv_copy(args);
if (!arguments)
return log_oom();
@@ -370,7 +332,7 @@ static int run(int argc, char *argv[]) {
_exit(EXIT_FAILURE);
}
return pidref_wait_for_terminate_and_check(argv[optind], &pidref, WAIT_LOG_ABNORMAL);
return pidref_wait_for_terminate_and_check(args[0], &pidref, WAIT_LOG_ABNORMAL);
}
}
+37 -53
View File
@@ -1,14 +1,15 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include <unistd.h>
#include "alloc-util.h"
#include "build.h"
#include "event-util.h"
#include "fd-util.h"
#include "format-table.h"
#include "log.h"
#include "main-func.h"
#include "options.h"
#include "parse-argument.h"
#include "pidref.h"
#include "pretty-print.h"
@@ -28,95 +29,77 @@ STATIC_DESTRUCTOR_REGISTER(arg_title, freep);
static int help(void) {
_cleanup_free_ char *link = NULL;
_cleanup_(table_unrefp) Table *options = NULL;
int r;
r = terminal_urlify_man("systemd-pty-forward", "1", &link);
if (r < 0)
return log_oom();
printf("%1$s [OPTIONS...] COMMAND ...\n"
"\n%5$sRun command with a custom terminal background color or title.%6$s\n"
"\n%3$sOptions:%4$s\n"
" -h --help Show this help\n"
" --version Print version\n"
" -q --quiet Suppress information messages during runtime\n"
" --read-only Do not accept any user input on stdin\n"
" --background=COLOR Set ANSI color for background\n"
" --title=TITLE Set terminal title\n"
"\nSee the %2$s for details.\n",
r = option_parser_get_help_table(&options);
if (r < 0)
return r;
printf("%s [OPTIONS...] COMMAND ...\n"
"\n%sRun command with a custom terminal background color or title.%s\n"
"\n%sOptions:%s\n",
program_invocation_short_name,
link,
ansi_underline(),
ansi_normal(),
ansi_highlight(),
ansi_normal(),
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;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_READ_ONLY,
ARG_BACKGROUND,
ARG_TITLE,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "quiet", no_argument, NULL, 'q' },
{ "read-only", no_argument, NULL, ARG_READ_ONLY },
{ "background", required_argument, NULL, ARG_BACKGROUND },
{ "title", required_argument, NULL, ARG_TITLE },
{}
};
int c, r;
static int parse_argv(int argc, char *argv[], char ***remaining_args) {
assert(argc >= 0);
assert(argv);
assert(remaining_args);
optind = 0;
while ((c = getopt_long(argc, argv, "+hq", options, NULL)) >= 0)
OptionParser state = { argc, argv, OPTION_PARSER_STOP_AT_FIRST_NONOPTION };
const char *arg;
int r;
FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c)
switch (c) {
case 'h':
OPTION_COMMON_HELP:
return help();
case ARG_VERSION:
OPTION_COMMON_VERSION:
return version();
case 'q':
OPTION('q', "quiet", NULL, "Suppress information messages during runtime"):
arg_quiet = true;
break;
case ARG_READ_ONLY:
OPTION_LONG("read-only", NULL, "Do not accept any user input on stdin"):
arg_read_only = true;
break;
case ARG_BACKGROUND:
r = parse_background_argument(optarg, &arg_background);
OPTION_LONG("background", "COLOR", "Set ANSI color for background"):
r = parse_background_argument(arg, &arg_background);
if (r < 0)
return r;
break;
case ARG_TITLE:
r = free_and_strdup_warn(&arg_title, optarg);
OPTION_LONG("title", "TITLE", "Set terminal title"):
r = free_and_strdup_warn(&arg_title, arg);
if (r < 0)
return r;
break;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
if (optind >= argc)
if (option_parser_get_n_args(&state) == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected command line, refusing.");
*remaining_args = option_parser_get_args(&state);
return 1;
}
@@ -155,11 +138,12 @@ static int run(int argc, char *argv[]) {
log_setup();
r = parse_argv(argc, argv);
char **args = NULL;
r = parse_argv(argc, argv, &args);
if (r <= 0)
return r;
_cleanup_strv_free_ char **l = strv_copy(argv + optind);
_cleanup_strv_free_ char **l = strv_copy(args);
if (!l)
return log_oom();
+52 -68
View File
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include <sys/epoll.h>
#include <sys/wait.h>
#include <unistd.h>
@@ -14,9 +13,11 @@
#include "errno-util.h"
#include "escape.h"
#include "fd-util.h"
#include "format-table.h"
#include "format-util.h"
#include "log.h"
#include "main-func.h"
#include "options.h"
#include "pidfd-util.h"
#include "pidref.h"
#include "pretty-print.h"
@@ -320,83 +321,63 @@ static int install_chld_handler(void) {
static int help(void) {
_cleanup_free_ char *link = NULL;
_cleanup_(table_unrefp) Table *options = NULL;
int r;
r = terminal_urlify_man("systemd-socket-activate", "1", &link);
if (r < 0)
return log_oom();
r = option_parser_get_help_table(&options);
if (r < 0)
return r;
printf("%s [OPTIONS...] COMMAND ...\n"
"\n%sListen on sockets and launch child on connection.%s\n"
"\nOptions:\n"
" -h --help Show this help and exit\n"
" --version Print version string and exit\n"
" -l --listen=ADDR Listen for raw connections at ADDR\n"
" -d --datagram Listen on datagram instead of stream socket\n"
" --seqpacket Listen on SOCK_SEQPACKET instead of stream socket\n"
" -a --accept Spawn separate child for each connection\n"
" -E --setenv=NAME[=VALUE] Pass an environment variable to children\n"
" --fdname=NAME[:NAME...] Specify names for file descriptors\n"
" --inetd Enable inetd file descriptor passing protocol\n"
" --now Start instantly instead of waiting for connection\n"
"\nNote: file descriptors from sd_listen_fds() will be passed through.\n"
"\nSee the %s for details.\n",
"\n%sOptions:%s\n",
program_invocation_short_name,
ansi_highlight(),
ansi_normal(),
link);
ansi_underline(),
ansi_normal());
r = table_print_or_warn(options);
if (r < 0)
return r;
printf("\nNote: file descriptors from sd_listen_fds() will be passed through.\n"
"\nSee the %s for details.\n", link);
return 0;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_FDNAME,
ARG_SEQPACKET,
ARG_INETD,
ARG_NOW,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "datagram", no_argument, NULL, 'd' },
{ "seqpacket", no_argument, NULL, ARG_SEQPACKET },
{ "listen", required_argument, NULL, 'l' },
{ "accept", no_argument, NULL, 'a' },
{ "setenv", required_argument, NULL, 'E' },
{ "environment", required_argument, NULL, 'E' }, /* legacy alias */
{ "fdname", required_argument, NULL, ARG_FDNAME },
{ "inetd", no_argument, NULL, ARG_INETD },
{ "now", no_argument, NULL, ARG_NOW },
{}
};
int c, r;
static int parse_argv(int argc, char *argv[], char ***remaining_args) {
assert(argc >= 0);
assert(argv);
assert(remaining_args);
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
optind = 0;
while ((c = getopt_long(argc, argv, "+hl:aE:d", options, NULL)) >= 0)
OptionParser state = { argc, argv, OPTION_PARSER_STOP_AT_FIRST_NONOPTION };
const char *arg;
int r;
FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c)
switch (c) {
case 'h':
OPTION_COMMON_HELP:
return help();
case ARG_VERSION:
OPTION_COMMON_VERSION:
return version();
case 'l':
r = strv_extend(&arg_listen, optarg);
OPTION('l', "listen", "ADDR",
"Listen for raw connections at ADDR"):
r = strv_extend(&arg_listen, arg);
if (r < 0)
return log_oom();
break;
case 'd':
OPTION('d', "datagram", NULL,
"Listen on datagram instead of stream socket"):
if (arg_socket_type == SOCK_SEQPACKET)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--datagram may not be combined with --seqpacket.");
@@ -404,7 +385,8 @@ static int parse_argv(int argc, char *argv[]) {
arg_socket_type = SOCK_DGRAM;
break;
case ARG_SEQPACKET:
OPTION_LONG("seqpacket", NULL,
"Listen on SOCK_SEQPACKET instead of stream socket"):
if (arg_socket_type == SOCK_DGRAM)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--seqpacket may not be combined with --datagram.");
@@ -412,20 +394,24 @@ static int parse_argv(int argc, char *argv[]) {
arg_socket_type = SOCK_SEQPACKET;
break;
case 'a':
OPTION('a', "accept", NULL,
"Spawn separate child for each connection"):
arg_accept = true;
break;
case 'E':
r = strv_env_replace_strdup_passthrough(&arg_setenv, optarg);
OPTION('E', "setenv", "NAME[=VALUE]",
"Pass an environment variable to children"): {}
OPTION_LONG("environment", "NAME[=VALUE]", /* help= */ NULL): /* legacy alias */
r = strv_env_replace_strdup_passthrough(&arg_setenv, arg);
if (r < 0)
return log_error_errno(r, "Cannot assign environment variable %s: %m", optarg);
return log_error_errno(r, "Cannot assign environment variable %s: %m", arg);
break;
case ARG_FDNAME: {
OPTION_LONG("fdname", "NAME[:NAME...]",
"Specify names for file descriptors"): {
_cleanup_strv_free_ char **names = NULL;
names = strv_split(optarg, ":");
names = strv_split(arg, ":");
if (!names)
return log_oom();
@@ -446,22 +432,19 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
case ARG_INETD:
OPTION_LONG("inetd", NULL,
"Enable inetd file descriptor passing protocol"):
arg_inetd = true;
break;
case ARG_NOW:
OPTION_LONG("now", NULL,
"Start instantly instead of waiting for connection"):
arg_now = true;
break;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
if (optind == argc)
*remaining_args = option_parser_get_args(&state);
if (strv_isempty(*remaining_args))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: command to execute is missing.",
program_invocation_short_name);
@@ -488,11 +471,12 @@ static int run(int argc, char **argv) {
log_setup();
r = parse_argv(argc, argv);
char **args = NULL;
r = parse_argv(argc, argv, &args);
if (r <= 0)
return r;
exec_argv = strv_copy(argv + optind);
exec_argv = strv_copy(args);
if (!exec_argv)
return log_oom();
+37 -49
View File
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include <stdlib.h>
#include <sys/file.h>
#include <unistd.h>
@@ -17,12 +16,14 @@
#include "device-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "format-table.h"
#include "fs-util.h"
#include "hashmap.h"
#include "id128-util.h"
#include "local-addresses.h"
#include "main-func.h"
#include "mountpoint-util.h"
#include "options.h"
#include "os-util.h"
#include "path-util.h"
#include "plymouth-util.h"
@@ -47,99 +48,86 @@ STATIC_DESTRUCTOR_REGISTER(arg_nqn, freep);
static int help(void) {
_cleanup_free_ char *link = NULL;
_cleanup_(table_unrefp) Table *options = NULL;
int r;
r = terminal_urlify_man("systemd-storagetm", "8", &link);
if (r < 0)
return log_oom();
r = option_parser_get_help_table(&options);
if (r < 0)
return r;
printf("%s [OPTIONS...] [DEVICE...]\n"
"\n%sExpose a block device or regular file as NVMe-TCP volume.%s\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --nqn=STRING Select NQN (NVMe Qualified Name)\n"
" -a --all Expose all devices\n"
" --list-devices List candidate block devices to operate on\n"
"\nSee the %s for details.\n",
"\n%sExpose a block device or regular file as NVMe-TCP volume.%s\n\n",
program_invocation_short_name,
ansi_highlight(),
ansi_normal(),
link);
ansi_normal());
r = table_print_or_warn(options);
if (r < 0)
return r;
printf("\nSee the %s for details.\n", link);
return 0;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_NQN = 0x100,
ARG_VERSION,
ARG_LIST_DEVICES,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "nqn", required_argument, NULL, ARG_NQN },
{ "all", no_argument, NULL, 'a' },
{ "list-devices", no_argument, NULL, ARG_LIST_DEVICES },
{}
};
int r, c;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "ha", options, NULL)) >= 0)
OptionParser state = { argc, argv };
const char *arg;
int r;
FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c)
switch (c) {
case 'h':
OPTION_COMMON_HELP:
return help();
case ARG_VERSION:
OPTION_COMMON_VERSION:
return version();
case ARG_NQN:
if (!filename_is_valid(optarg))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "NQN invalid: %s", optarg);
OPTION_LONG("nqn", "STRING",
"Select NQN (NVMe Qualified Name)"):
if (!filename_is_valid(arg))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "NQN invalid: %s", arg);
if (free_and_strdup(&arg_nqn, optarg) < 0)
if (free_and_strdup(&arg_nqn, arg) < 0)
return log_oom();
break;
case 'a':
OPTION('a', "all", NULL, "Expose all devices"):
arg_all++;
break;
case ARG_LIST_DEVICES:
OPTION_LONG("list-devices", NULL,
"List candidate block devices to operate on"):
r = blockdev_list(BLOCKDEV_LIST_SHOW_SYMLINKS|BLOCKDEV_LIST_IGNORE_ZRAM, /* ret_devices= */ NULL, /* ret_n_devices= */ NULL);
if (r < 0)
return r;
return 0;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
char **args = option_parser_get_args(&state);
if (arg_all > 0) {
if (argc > optind)
if (!strv_isempty(args))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expects no further arguments if --all/-a is specified.");
} else {
if (optind >= argc)
if (strv_isempty(args))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expecting device name or --all/-a.");
for (int i = optind; i < argc; i++)
if (!path_is_valid(argv[i]))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid path: %s", argv[i]);
STRV_FOREACH(a, args)
if (!path_is_valid(*a))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid path: %s", *a);
arg_devices = strv_copy(argv + optind);
arg_devices = strv_copy(args);
if (!arg_devices)
return log_oom();
}
if (!arg_nqn) {
+77 -87
View File
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include <stdio.h>
#include <sys/stat.h>
@@ -10,10 +9,12 @@
#include "constants.h"
#include "creds-util.h"
#include "errno-util.h"
#include "format-table.h"
#include "glob-util.h"
#include "hashmap.h"
#include "log.h"
#include "main-func.h"
#include "options.h"
#include "pager.h"
#include "path-util.h"
#include "pretty-print.h"
@@ -29,13 +30,13 @@ static PagerFlags arg_pager_flags = 0;
STATIC_DESTRUCTOR_REGISTER(arg_prefixes, strv_freep);
typedef struct Option {
typedef struct SysctlOption {
char *key;
char *value;
bool ignore_failure;
} Option;
} SysctlOption;
static Option* option_free(Option *o) {
static SysctlOption* sysctl_option_free(SysctlOption *o) {
if (!o)
return NULL;
@@ -45,11 +46,11 @@ static Option* option_free(Option *o) {
return mfree(o);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(Option*, option_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(SysctlOption*, sysctl_option_free);
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
option_hash_ops,
sysctl_option_hash_ops,
char, string_hash_func, string_compare_func,
Option, option_free);
SysctlOption, sysctl_option_free);
static bool test_prefix(const char *p) {
if (strv_isempty(arg_prefixes))
@@ -58,20 +59,20 @@ static bool test_prefix(const char *p) {
return path_startswith_strv(p, arg_prefixes);
}
static Option* option_new(
static SysctlOption* sysctl_option_new(
const char *key,
const char *value,
bool ignore_failure) {
_cleanup_(option_freep) Option *o = NULL;
_cleanup_(sysctl_option_freep) SysctlOption *o = NULL;
assert(key);
o = new(Option, 1);
o = new(SysctlOption, 1);
if (!o)
return NULL;
*o = (Option) {
*o = (SysctlOption) {
.key = strdup(key),
.value = value ? strdup(value) : NULL,
.ignore_failure = ignore_failure,
@@ -108,7 +109,7 @@ static int sysctl_write_or_warn(const char *key, const char *value, bool ignore_
return 0;
}
static int apply_glob_option_with_prefix(OrderedHashmap *sysctl_options, Option *option, const char *prefix) {
static int apply_glob_option_with_prefix(OrderedHashmap *sysctl_options, SysctlOption *option, const char *prefix) {
_cleanup_strv_free_ char **paths = NULL;
_cleanup_free_ char *pattern = NULL;
int r;
@@ -179,7 +180,7 @@ static int apply_glob_option_with_prefix(OrderedHashmap *sysctl_options, Option
return r;
}
static int apply_glob_option(OrderedHashmap *sysctl_options, Option *option) {
static int apply_glob_option(OrderedHashmap *sysctl_options, SysctlOption *option) {
int r = 0;
if (strv_isempty(arg_prefixes))
@@ -191,7 +192,7 @@ static int apply_glob_option(OrderedHashmap *sysctl_options, Option *option) {
}
static int apply_all(OrderedHashmap *sysctl_options) {
Option *option;
SysctlOption *option;
int r = 0;
ORDERED_HASHMAP_FOREACH(option, sysctl_options) {
@@ -253,7 +254,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
if (!string_is_glob(key) && !test_prefix(key))
return 0;
Option *existing = ordered_hashmap_get(*sysctl_options, key);
SysctlOption *existing = ordered_hashmap_get(*sysctl_options, key);
if (existing) {
if (streq_ptr(value, existing->value)) {
existing->ignore_failure = existing->ignore_failure || ignore_failure;
@@ -262,14 +263,14 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
log_syntax(NULL, LOG_DEBUG, fname, line, 0,
"Overwriting earlier assignment of '%s'.", key);
option_free(ordered_hashmap_remove(*sysctl_options, key));
sysctl_option_free(ordered_hashmap_remove(*sysctl_options, key));
}
_cleanup_(option_freep) Option *option = option_new(key, value, ignore_failure);
_cleanup_(sysctl_option_freep) SysctlOption *option = sysctl_option_new(key, value, ignore_failure);
if (!option)
return log_oom();
r = ordered_hashmap_ensure_put(sysctl_options, &option_hash_ops, option->key, option);
r = ordered_hashmap_ensure_put(sysctl_options, &sysctl_option_hash_ops, option->key, option);
if (r < 0)
return log_error_errno(r, "Failed to add sysctl variable '%s' to hashmap: %m", key);
@@ -314,122 +315,110 @@ static int cat_config(char **files) {
static int help(void) {
_cleanup_free_ char *link = NULL;
_cleanup_(table_unrefp) Table *commands = NULL, *options = NULL;
int r;
r = terminal_urlify_man("systemd-sysctl.service", "8", &link);
if (r < 0)
return log_oom();
printf("%1$s [OPTIONS...] [CONFIGURATION FILE...]\n"
"\n%2$sApplies kernel sysctl settings.%4$s\n"
"\n%3$sCommands:%4$s\n"
" --cat-config Show configuration files\n"
" --tldr Show non-comment parts of configuration\n"
" -h --help Show this help\n"
" --version Show package version\n"
"\n%3$sOptions:%4$s\n"
" --prefix=PATH Only apply rules with the specified prefix\n"
" --no-pager Do not pipe output into a pager\n"
" --strict Fail on any kind of failures\n"
" --inline Treat arguments as configuration lines\n"
"\nSee the %5$s for details.\n",
r = option_parser_get_help_table(&commands);
if (r < 0)
return r;
r = option_parser_get_help_table_group("Options", &options);
if (r < 0)
return r;
(void) table_sync_column_widths(0, commands, options);
printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n"
"\n%sApplies kernel sysctl settings.%s\n"
"\n%sCommands:%s\n",
program_invocation_short_name,
ansi_highlight(),
ansi_underline(),
ansi_normal(),
link);
ansi_underline(),
ansi_normal());
r = table_print_or_warn(commands);
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;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_CAT_CONFIG,
ARG_TLDR,
ARG_PREFIX,
ARG_NO_PAGER,
ARG_STRICT,
ARG_INLINE,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "cat-config", no_argument, NULL, ARG_CAT_CONFIG },
{ "tldr", no_argument, NULL, ARG_TLDR },
{ "prefix", required_argument, NULL, ARG_PREFIX },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "strict", no_argument, NULL, ARG_STRICT },
{ "inline", no_argument, NULL, ARG_INLINE },
{}
};
int c;
static int parse_argv(int argc, char *argv[], char ***remaining_args) {
assert(argc >= 0);
assert(argv);
assert(remaining_args);
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
OptionParser state = { argc, argv };
const char *arg;
FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c)
switch (c) {
case 'h':
OPTION_COMMON_HELP:
return help();
case ARG_VERSION:
OPTION_COMMON_VERSION:
return version();
case ARG_CAT_CONFIG:
OPTION_COMMON_CAT_CONFIG:
arg_cat_flags = CAT_CONFIG_ON;
break;
case ARG_TLDR:
OPTION_COMMON_TLDR:
arg_cat_flags = CAT_TLDR;
break;
case ARG_PREFIX: {
const char *s;
char *p;
OPTION_GROUP("Options"): {}
OPTION_LONG("prefix", "PATH",
"Only apply rules with the specified prefix"): {
_cleanup_free_ char *normalized = strdup(arg);
if (!normalized)
return log_oom();
sysctl_normalize(normalized);
/* We used to require people to specify absolute paths
* in /proc/sys in the past. This is kinda useless, but
* we need to keep compatibility. We now support any
* sysctl name available. */
sysctl_normalize(optarg);
const char *s = path_startswith(normalized, "/proc/sys");
s = path_startswith(optarg, "/proc/sys");
p = strdup(s ?: optarg);
if (!p)
return log_oom();
if (strv_consume(&arg_prefixes, p) < 0)
if (strv_extend(&arg_prefixes, s ?: normalized) < 0)
return log_oom();
break;
}
case ARG_NO_PAGER:
OPTION_COMMON_NO_PAGER:
arg_pager_flags |= PAGER_DISABLE;
break;
case ARG_STRICT:
OPTION_LONG("strict", NULL,
"Fail on any kind of failures"):
arg_strict = true;
break;
case ARG_INLINE:
OPTION_LONG("inline", NULL,
"Treat arguments as configuration lines"):
arg_inline = true;
break;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
if (arg_cat_flags != CAT_CONFIG_OFF && argc > optind)
*remaining_args = option_parser_get_args(&state);
if (arg_cat_flags != CAT_CONFIG_OFF && !strv_isempty(*remaining_args))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Positional arguments are not allowed with --cat-config/--tldr.");
@@ -440,7 +429,8 @@ static int run(int argc, char *argv[]) {
_cleanup_ordered_hashmap_free_ OrderedHashmap *sysctl_options = NULL;
int r;
r = parse_argv(argc, argv);
char **args = NULL;
r = parse_argv(argc, argv, &args);
if (r <= 0)
return r;
@@ -448,10 +438,10 @@ static int run(int argc, char *argv[]) {
umask(0022);
if (argc > optind) {
if (!strv_isempty(args)) {
unsigned pos = 0;
STRV_FOREACH(arg, strv_skip(argv, optind)) {
STRV_FOREACH(arg, args) {
if (arg_inline)
/* Use (argument):n, where n==1 for the first positional arg */
RET_GATHER(r, parse_line("(argument)", ++pos, *arg, /* invalid_config= */ NULL, &sysctl_options));
+169 -202
View File
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include <unistd.h>
#include "sd-daemon.h"
@@ -16,6 +15,7 @@
#include "loop-util.h"
#include "main-func.h"
#include "mount-util.h"
#include "options.h"
#include "os-util.h"
#include "pager.h"
#include "parse-argument.h"
@@ -1275,6 +1275,8 @@ static int process_image(
return 0;
}
VERB(verb_list, "list", "[VERSION]", VERB_ANY, 2, VERB_DEFAULT,
"Show installed and available versions");
static int verb_list(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(umount_and_rmdir_and_freep) char *mounted_dir = NULL;
@@ -1343,6 +1345,8 @@ static int verb_list(int argc, char *argv[], uintptr_t _data, void *userdata) {
}
}
VERB(verb_features, "features", "[FEATURE]", VERB_ANY, 2, 0,
"Show optional features");
static int verb_features(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(umount_and_rmdir_and_freep) char *mounted_dir = NULL;
@@ -1477,6 +1481,8 @@ static int verb_features(int argc, char *argv[], uintptr_t _data, void *userdata
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) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(umount_and_rmdir_and_freep) char *mounted_dir = NULL;
@@ -1518,29 +1524,6 @@ static int verb_check_new(int argc, char *argv[], uintptr_t _data, void *userdat
return EXIT_SUCCESS;
}
static int verb_vacuum(int argc, char *argv[], uintptr_t _data, 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;
int r;
assert(argc <= 1);
if (arg_instances_max < 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"The --instances-max argument must be >= 1 while vacuuming");
r = process_image(/* ro= */ false, &mounted_dir, &loop_device);
if (r < 0)
return r;
r = context_make_offline(&context, loop_device ? loop_device->node : NULL, /* requires_enabled_transfers= */ false);
if (r < 0)
return r;
return context_vacuum(context, 0, NULL);
}
typedef enum {
UPDATE_ACTION_ACQUIRE = 1 << 0,
UPDATE_ACTION_INSTALL = 1 << 1,
@@ -1613,6 +1596,8 @@ static int verb_update_impl(int argc, char **argv, UpdateActionFlags action_flag
return 0;
}
VERB(verb_update, "update", "[VERSION]", VERB_ANY, 2, 0,
"Install new version now");
static int verb_update(int argc, char *argv[], uintptr_t _data, void *userdata) {
UpdateActionFlags flags = UPDATE_ACTION_INSTALL;
@@ -1622,10 +1607,41 @@ static int verb_update(int argc, char *argv[], uintptr_t _data, void *userdata)
return verb_update_impl(argc, argv, flags);
}
VERB(verb_acquire, "acquire", "[VERSION]", VERB_ANY, 2, 0,
"Acquire (download) new version now");
static int verb_acquire(int argc, char *argv[], uintptr_t _data, void *userdata) {
return verb_update_impl(argc, argv, UPDATE_ACTION_ACQUIRE);
}
VERB_NOARG(verb_vacuum, "vacuum",
"Make room, by deleting old versions");
static int verb_vacuum(int argc, char *argv[], uintptr_t _data, 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;
int r;
assert(argc <= 1);
if (arg_instances_max < 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"The --instances-max argument must be >= 1 while vacuuming");
r = process_image(/* ro= */ false, &mounted_dir, &loop_device);
if (r < 0)
return r;
r = context_make_offline(&context, loop_device ? loop_device->node : NULL, /* requires_enabled_transfers= */ false);
if (r < 0)
return r;
return context_vacuum(context, 0, NULL);
}
VERB(verb_pending_or_reboot, "pending", NULL, 1, 1, 0,
"Report whether a newer version is installed than currently booted");
VERB(verb_pending_or_reboot, "reboot", NULL, 1, 1, 0,
"Reboot if a newer version is installed than booted");
static int verb_pending_or_reboot(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(context_freep) Context* context = NULL;
_cleanup_free_ char *booted_version = NULL;
@@ -1700,6 +1716,8 @@ static int component_name_valid(const char *c) {
return filename_is_valid(j);
}
VERB_NOARG(verb_components, "components",
"Show list of components");
static int verb_components(int argc, char *argv[], uintptr_t _data, void *userdata) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(umount_and_rmdir_and_freep) char *mounted_dir = NULL;
@@ -1792,190 +1810,149 @@ static int verb_components(int argc, char *argv[], uintptr_t _data, void *userda
static int help(void) {
_cleanup_free_ char *link = NULL;
_cleanup_(table_unrefp) Table *common_options = NULL, *options = NULL, *verbs = NULL;
int r;
r = terminal_urlify_man("systemd-sysupdate", "8", &link);
if (r < 0)
return log_oom();
printf("%1$s [OPTIONS...] [VERSION]\n"
"\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"
" acquire [VERSION] Acquire (download) new version now\n"
" vacuum Make room, by deleting old versions\n"
" pending Report whether a newer version is installed than\n"
" currently booted\n"
" reboot Reboot if a newer version is installed than booted\n"
" components Show list of components\n"
" -h --help Show this help\n"
" --version Show package version\n"
"\n%3$sOptions:%4$s\n"
" -C --component=NAME Select component to update\n"
" --definitions=DIR Find transfer definitions in specified directory\n"
" --root=PATH Operate on an alternate filesystem root\n"
" --image=PATH Operate on disk image as filesystem root\n"
" --image-policy=POLICY\n"
" Specify disk image dissection policy\n"
" -m --instances-max=INT How many instances to maintain\n"
" --sync=BOOL Controls whether to sync data to disk\n"
" --verify=BOOL Force signature verification on or off\n"
" --reboot Reboot after updating to newer version\n"
" --offline Do not fetch metadata from the network\n"
" --no-pager Do not pipe output into a pager\n"
" --no-legend Do not show the headers and footers\n"
" --json=pretty|short|off\n"
" Generate JSON output\n"
" --transfer-source=PATH\n"
" Specify the directory to transfer sources from\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;
r = option_parser_get_help_table(&common_options);
if (r < 0)
return r;
r = option_parser_get_help_table_group("Options", &options);
if (r < 0)
return r;
(void) table_sync_column_widths(0, verbs, common_options, options);
printf("%s [OPTIONS...] [VERSION]\n"
"\n%sUpdate OS images.%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(common_options);
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;
}
static int verb_help(int argc, char *argv[], uintptr_t _data, void *userdata) {
return help();
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_NO_PAGER,
ARG_NO_LEGEND,
ARG_SYNC,
ARG_DEFINITIONS,
ARG_JSON,
ARG_ROOT,
ARG_IMAGE,
ARG_IMAGE_POLICY,
ARG_REBOOT,
ARG_VERIFY,
ARG_OFFLINE,
ARG_TRANSFER_SOURCE,
};
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 },
{ "definitions", required_argument, NULL, ARG_DEFINITIONS },
{ "instances-max", required_argument, NULL, 'm' },
{ "sync", required_argument, NULL, ARG_SYNC },
{ "json", required_argument, NULL, ARG_JSON },
{ "root", required_argument, NULL, ARG_ROOT },
{ "image", required_argument, NULL, ARG_IMAGE },
{ "image-policy", required_argument, NULL, ARG_IMAGE_POLICY },
{ "reboot", no_argument, NULL, ARG_REBOOT },
{ "component", required_argument, NULL, 'C' },
{ "verify", required_argument, NULL, ARG_VERIFY },
{ "offline", no_argument, NULL, ARG_OFFLINE },
{ "transfer-source", required_argument, NULL, ARG_TRANSFER_SOURCE },
{}
};
int c, r;
VERB_COMMON_HELP_HIDDEN(help);
static int parse_argv(int argc, char *argv[], char ***remaining_args) {
assert(argc >= 0);
assert(argv);
assert(remaining_args);
while ((c = getopt_long(argc, argv, "hm:C:", options, NULL)) >= 0) {
OptionParser state = { argc, argv };
const char *arg;
int r;
FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c)
switch (c) {
case 'h':
OPTION_COMMON_HELP:
return help();
case ARG_VERSION:
OPTION_COMMON_VERSION:
return version();
case ARG_NO_PAGER:
arg_pager_flags |= PAGER_DISABLE;
OPTION_GROUP("Options"):
break;
case ARG_NO_LEGEND:
arg_legend = false;
break;
case 'm':
r = safe_atou64(optarg, &arg_instances_max);
if (r < 0)
return log_error_errno(r, "Failed to parse --instances-max= parameter: %s", optarg);
break;
case ARG_SYNC:
r = parse_boolean_argument("--sync=", optarg, &arg_sync);
if (r < 0)
return r;
break;
case ARG_DEFINITIONS:
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_definitions);
if (r < 0)
return r;
break;
case ARG_JSON:
r = parse_json_argument(optarg, &arg_json_format_flags);
if (r <= 0)
return r;
break;
case ARG_ROOT:
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_root);
if (r < 0)
return r;
break;
case ARG_IMAGE:
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_image);
if (r < 0)
return r;
break;
case ARG_IMAGE_POLICY:
r = parse_image_policy_argument(optarg, &arg_image_policy);
if (r < 0)
return r;
break;
case ARG_REBOOT:
arg_reboot = true;
break;
case 'C':
if (isempty(optarg)) {
OPTION('C', "component", "NAME",
"Select component to update"):
if (isempty(arg)) {
arg_component = mfree(arg_component);
break;
}
r = component_name_valid(optarg);
r = component_name_valid(arg);
if (r < 0)
return log_error_errno(r, "Failed to determine if component name is valid: %m");
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Component name invalid: %s", optarg);
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Component name invalid: %s", arg);
r = free_and_strdup_warn(&arg_component, optarg);
r = free_and_strdup_warn(&arg_component, arg);
if (r < 0)
return r;
break;
case ARG_VERIFY: {
OPTION_LONG("definitions", "DIR",
"Find transfer definitions in specified directory"):
r = parse_path_argument(arg, /* suppress_root= */ false, &arg_definitions);
if (r < 0)
return r;
break;
OPTION_LONG("root", "PATH",
"Operate on an alternate filesystem root"):
r = parse_path_argument(arg, /* suppress_root= */ false, &arg_root);
if (r < 0)
return r;
break;
OPTION_LONG("image", "PATH",
"Operate on disk image as filesystem root"):
r = parse_path_argument(arg, /* suppress_root= */ false, &arg_image);
if (r < 0)
return r;
break;
OPTION_LONG("image-policy", "POLICY",
"Specify disk image dissection policy"):
r = parse_image_policy_argument(arg, &arg_image_policy);
if (r < 0)
return r;
break;
OPTION_LONG("transfer-source", "PATH",
"Specify the directory to transfer sources from"):
r = parse_path_argument(arg, /* suppress_root= */ false, &arg_transfer_source);
if (r < 0)
return r;
break;
OPTION('m', "instances-max", "INT",
"How many instances to maintain"):
r = safe_atou64(arg, &arg_instances_max);
if (r < 0)
return log_error_errno(r, "Failed to parse --instances-max= parameter: %s", arg);
break;
OPTION_LONG("sync", "BOOL",
"Controls whether to sync data to disk"):
r = parse_boolean_argument("--sync=", arg, &arg_sync);
if (r < 0)
return r;
break;
OPTION_LONG("verify", "BOOL",
"Force signature verification on or off"): {
bool b;
r = parse_boolean_argument("--verify=", optarg, &b);
r = parse_boolean_argument("--verify=", arg, &b);
if (r < 0)
return r;
@@ -1983,24 +1960,31 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
case ARG_OFFLINE:
OPTION_LONG("reboot", NULL,
"Reboot after updating to newer version"):
arg_reboot = true;
break;
OPTION_LONG("offline", NULL,
"Do not fetch metadata from the network"):
arg_offline = true;
break;
case ARG_TRANSFER_SOURCE:
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_transfer_source);
if (r < 0)
OPTION_COMMON_NO_PAGER:
arg_pager_flags |= PAGER_DISABLE;
break;
OPTION_COMMON_NO_LEGEND:
arg_legend = false;
break;
OPTION_COMMON_JSON:
r = parse_json_argument(arg, &arg_json_format_flags);
if (r <= 0)
return r;
break;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
}
if (arg_image && arg_root)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Please specify either --root= or --image=, the combination of both is not supported.");
@@ -2011,38 +1995,21 @@ static int parse_argv(int argc, char *argv[]) {
if (arg_definitions && arg_component)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "The --definitions= and --component= switches may not be combined.");
*remaining_args = option_parser_get_args(&state);
return 1;
}
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 },
{ "acquire", VERB_ANY, 2, 0, verb_acquire },
{ "vacuum", VERB_ANY, 1, 0, verb_vacuum },
{ "reboot", 1, 1, 0, verb_pending_or_reboot },
{ "pending", 1, 1, 0, verb_pending_or_reboot },
{ "help", VERB_ANY, 1, 0, verb_help },
{}
};
return dispatch_verb(argc, argv, verbs, NULL);
}
static int run(int argc, char *argv[]) {
int r;
log_setup();
r = parse_argv(argc, argv);
char **args = NULL;
r = parse_argv(argc, argv, &args);
if (r <= 0)
return r;
return sysupdate_main(argc, argv);
return dispatch_verb_with_args(args, NULL);
}
DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);
@@ -4,7 +4,6 @@
***/
#include <fcntl.h>
#include <getopt.h>
#include <poll.h>
#include <stdlib.h>
#include <sys/prctl.h>
@@ -23,12 +22,14 @@
#include "errno-util.h"
#include "exit-status.h"
#include "fd-util.h"
#include "format-util.h"
#include "fileio.h"
#include "format-table.h"
#include "format-util.h"
#include "inotify-util.h"
#include "io-util.h"
#include "main-func.h"
#include "mkdir-label.h"
#include "options.h"
#include "path-util.h"
#include "pidref.h"
#include "pretty-print.h"
@@ -442,112 +443,85 @@ static int process_and_watch_password_files(bool watch) {
static int help(void) {
_cleanup_free_ char *link = NULL;
_cleanup_(table_unrefp) Table *options = NULL;
int r;
r = terminal_urlify_man("systemd-tty-ask-password-agent", "1", &link);
if (r < 0)
return log_oom();
printf("%s [OPTIONS...]\n\n"
"%sProcess system password requests.%s\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --list Show pending password requests\n"
" --query Process pending password requests\n"
" --watch Continuously process password requests\n"
" --wall Continuously forward password requests to wall\n"
" --plymouth Ask question with Plymouth instead of on TTY\n"
" --console[=DEVICE] Ask question on /dev/console (or DEVICE if specified)\n"
" instead of the current TTY\n"
"\nSee the %s for details.\n",
r = option_parser_get_help_table(&options);
if (r < 0)
return r;
printf("%s [OPTIONS...]\n"
"\n%sProcess system password requests.%s\n\n",
program_invocation_short_name,
ansi_highlight(),
ansi_normal(),
link);
ansi_normal());
r = table_print_or_warn(options);
if (r < 0)
return r;
printf("\nSee the %s for details.\n", link);
return 0;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_LIST = 0x100,
ARG_QUERY,
ARG_WATCH,
ARG_WALL,
ARG_PLYMOUTH,
ARG_CONSOLE,
ARG_VERSION
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "list", no_argument, NULL, ARG_LIST },
{ "query", no_argument, NULL, ARG_QUERY },
{ "watch", no_argument, NULL, ARG_WATCH },
{ "wall", no_argument, NULL, ARG_WALL },
{ "plymouth", no_argument, NULL, ARG_PLYMOUTH },
{ "console", optional_argument, NULL, ARG_CONSOLE },
{}
};
int r, c;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
OptionParser state = { argc, argv };
const char *arg;
int r;
FOREACH_OPTION(&state, c, &arg, /* on_error= */ return c)
switch (c) {
case 'h':
OPTION_COMMON_HELP:
return help();
case ARG_VERSION:
OPTION_COMMON_VERSION:
return version();
case ARG_LIST:
OPTION_LONG("list", NULL, "Show pending password requests"):
arg_action = ACTION_LIST;
break;
case ARG_QUERY:
OPTION_LONG("query", NULL, "Process pending password requests"):
arg_action = ACTION_QUERY;
break;
case ARG_WATCH:
OPTION_LONG("watch", NULL, "Continuously process password requests"):
arg_action = ACTION_WATCH;
break;
case ARG_WALL:
OPTION_LONG("wall", NULL, "Continuously forward password requests to wall"):
arg_action = ACTION_WALL;
break;
case ARG_PLYMOUTH:
OPTION_LONG("plymouth", NULL,
"Ask question with Plymouth instead of on TTY"):
arg_plymouth = true;
break;
case ARG_CONSOLE:
OPTION_LONG_FLAGS(OPTION_OPTIONAL_ARG, "console", "DEVICE",
"Ask question on /dev/console (or DEVICE if specified) instead of the current TTY"):
arg_console = true;
if (optarg) {
if (isempty(optarg))
if (arg) {
if (isempty(arg))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Empty console device path is not allowed.");
r = free_and_strdup_warn(&arg_device, optarg);
r = free_and_strdup_warn(&arg_device, arg);
if (r < 0)
return r;
}
break;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
if (optind != argc)
if (option_parser_get_n_args(&state) > 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"%s takes no arguments.", program_invocation_short_name);