A few more conversions to the option and verb macros (#41797)
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user