socket-activate: convert to the new option parser
--help is identical except for whitespace and common option strings. Co-developed-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user