From: Zbigniew Jędrzejewski-Szmek Date: Mon, 27 Apr 2026 22:04:50 +0000 (+0200) Subject: run: convert parse_argv() to OPTION macros X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4c0e12b3b922f99a9be09e3be9df6a7a44b5db04;p=thirdparty%2Fsystemd.git run: convert parse_argv() to OPTION macros --system is now documented (fixup for 66b1e746055b9c56fd72c0451a4cfb2b06cf3f20). --capsule is now documented (fixup for 759b3c082d463a488235592df45cbebefbe1ad5c). --help output is generally the same, except for the formatting changes related to use of the new output helpers and common option macros. Co-developed-by: Claude Opus 4.7 --- diff --git a/src/run/run.c b/src/run/run.c index 60eaeb12d5b..36ebe32f2d4 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -40,9 +40,11 @@ #include "format-table.h" #include "format-util.h" #include "fs-util.h" +#include "help-util.h" #include "hostname-util.h" #include "log.h" #include "main-func.h" +#include "options.h" #include "osc-context.h" #include "pager.h" #include "parse-argument.h" @@ -139,80 +141,43 @@ STATIC_DESTRUCTOR_REGISTER(arg_shell_prompt_prefix, freep); STATIC_DESTRUCTOR_REGISTER(arg_area, freep); static int help(void) { - _cleanup_free_ char *link = NULL; int r; pager_open(arg_pager_flags); - r = terminal_urlify_man("systemd-run", "1", &link); - if (r < 0) - return log_oom(); + static const char* const groups[] = { + NULL, + "Path options", + "Socket options", + "Timer options", + }; - printf("%1$s [OPTIONS...] COMMAND [ARGUMENTS...]\n" - "\n%5$sRun the specified command in a transient scope or service.%6$s\n\n" - " -h --help Show this help\n" - " --version Show package version\n" - " --no-ask-password Do not prompt for password\n" - " --user Run as user unit\n" - " -H --host=[USER@]HOST Operate on remote host\n" - " -M --machine=CONTAINER Operate on local container\n" - " --scope Run this as scope rather than service\n" - " -u --unit=UNIT Run under the specified unit name\n" - " -p --property=NAME=VALUE Set service or scope unit property\n" - " --description=TEXT Description for unit\n" - " --slice=SLICE Run in the specified slice\n" - " --slice-inherit Inherit the slice from the caller\n" - " --expand-environment=BOOL Control expansion of environment variables\n" - " --no-block Do not wait until operation finished\n" - " -r --remain-after-exit Leave service around until explicitly stopped\n" - " --wait Wait until service stopped again\n" - " --send-sighup Send SIGHUP when terminating\n" - " --service-type=TYPE Service type\n" - " --uid=USER Run as system user\n" - " --gid=GROUP Run as system group\n" - " --nice=NICE Nice level\n" - " --working-directory=PATH Set working directory\n" - " -d --same-dir Inherit working directory from caller\n" - " --root-directory=PATH Set root directory\n" - " -R --same-root-dir Inherit root directory from caller\n" - " -E --setenv=NAME[=VALUE] Set environment variable\n" - " -t --pty Run service on pseudo TTY as STDIN/STDOUT/\n" - " STDERR\n" - " -T --pty-late Just like --pty, but leave TTY access to\n" - " agents until unit is started up\n" - " -P --pipe Pass STDIN/STDOUT/STDERR directly to service\n" - " -q --quiet Suppress information messages during runtime\n" - " -v --verbose Show unit logs while executing operation\n" - " --output=STRING Controls formatting of verbose logs, see\n" - " journalctl for valid values\n" - " --json=pretty|short|off Print unit name and invocation id as JSON\n" - " -G --collect Unload unit after it ran, even when failed\n" - " -S --shell Invoke a $SHELL interactively\n" - " --job-mode=MODE Specify how to deal with already queued jobs,\n" - " when queueing a new job\n" - " --ignore-failure Ignore the exit status of the invoked process\n" - " --background=COLOR Set ANSI color for background\n" - " --no-pager Do not pipe output into a pager\n" - "\n%3$sPath options:%4$s\n" - " --path-property=NAME=VALUE Set path unit property\n" - "\n%3$sSocket options:%4$s\n" - " --socket-property=NAME=VALUE Set socket unit property\n" - "\n%3$sTimer options:%4$s\n" - " --on-active=SECONDS Run after SECONDS delay\n" - " --on-boot=SECONDS Run SECONDS after machine was booted up\n" - " --on-startup=SECONDS Run SECONDS after systemd activation\n" - " --on-unit-active=SECONDS Run SECONDS after the last activation\n" - " --on-unit-inactive=SECONDS Run SECONDS after the last deactivation\n" - " --on-calendar=SPEC Realtime timer\n" - " --on-timezone-change Run when the timezone changes\n" - " --on-clock-change Run when the realtime clock jumps\n" - " --timer-property=NAME=VALUE Set timer unit property\n" - "\nSee the %2$s for details.\n", - program_invocation_short_name, - link, - ansi_underline(), ansi_normal(), - ansi_highlight(), ansi_normal()); + _cleanup_(table_unref_many) Table *tables[ELEMENTSOF(groups) + 1] = {}; + + for (size_t i = 0; i < ELEMENTSOF(groups); i++) { + r = option_parser_get_help_table_group(groups[i], &tables[i]); + if (r < 0) + return r; + } + + (void) table_sync_column_widths(0, tables[0], tables[1], tables[2], tables[3]); + + help_cmdline("[OPTIONS...] COMMAND [ARGUMENTS...]"); + help_abstract("Run the specified command in a transient scope or service."); + + for (size_t i = 0; i < ELEMENTSOF(groups); i++) { + _cleanup_free_ char *title = strjoin(groups[i] ?: "Options", ":"); + if (!title) + return log_oom(); + + help_section(title); + r = table_print_or_warn(tables[i]); + if (r < 0) + return r; + } + + help_man_page_reference("systemd-run", "1"); return 0; } @@ -306,239 +271,142 @@ static char** make_login_shell_cmdline(const char *shell) { } static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_VERSION = 0x100, - ARG_USER, - ARG_SYSTEM, - ARG_SCOPE, - ARG_DESCRIPTION, - ARG_SLICE, - ARG_SLICE_INHERIT, - ARG_EXPAND_ENVIRONMENT, - ARG_SEND_SIGHUP, - ARG_SERVICE_TYPE, - ARG_EXEC_USER, - ARG_EXEC_GROUP, - ARG_NICE, - ARG_OUTPUT, - ARG_ON_ACTIVE, - ARG_ON_BOOT, - ARG_ON_STARTUP, - ARG_ON_UNIT_ACTIVE, - ARG_ON_UNIT_INACTIVE, - ARG_ON_CALENDAR, - ARG_ON_TIMEZONE_CHANGE, - ARG_ON_CLOCK_CHANGE, - ARG_TIMER_PROPERTY, - ARG_PATH_PROPERTY, - ARG_SOCKET_PROPERTY, - ARG_NO_BLOCK, - ARG_NO_ASK_PASSWORD, - ARG_WAIT, - ARG_WORKING_DIRECTORY, - ARG_ROOT_DIRECTORY, - ARG_JOB_MODE, - ARG_IGNORE_FAILURE, - ARG_BACKGROUND, - ARG_NO_PAGER, - ARG_JSON, - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "user", no_argument, NULL, ARG_USER }, - { "system", no_argument, NULL, ARG_SYSTEM }, - { "capsule", required_argument, NULL, 'C' }, - { "scope", no_argument, NULL, ARG_SCOPE }, - { "unit", required_argument, NULL, 'u' }, - { "description", required_argument, NULL, ARG_DESCRIPTION }, - { "slice", required_argument, NULL, ARG_SLICE }, - { "slice-inherit", no_argument, NULL, ARG_SLICE_INHERIT }, - { "remain-after-exit", no_argument, NULL, 'r' }, - { "expand-environment", required_argument, NULL, ARG_EXPAND_ENVIRONMENT }, - { "send-sighup", no_argument, NULL, ARG_SEND_SIGHUP }, - { "host", required_argument, NULL, 'H' }, - { "machine", required_argument, NULL, 'M' }, - { "service-type", required_argument, NULL, ARG_SERVICE_TYPE }, - { "wait", no_argument, NULL, ARG_WAIT }, - { "uid", required_argument, NULL, ARG_EXEC_USER }, - { "gid", required_argument, NULL, ARG_EXEC_GROUP }, - { "nice", required_argument, NULL, ARG_NICE }, - { "setenv", required_argument, NULL, 'E' }, - { "property", required_argument, NULL, 'p' }, - { "tty", no_argument, NULL, 't' }, /* deprecated alias */ - { "pty", no_argument, NULL, 't' }, - { "pty-late", no_argument, NULL, 'T' }, - { "pipe", no_argument, NULL, 'P' }, - { "quiet", no_argument, NULL, 'q' }, - { "verbose", no_argument, NULL, 'v' }, - { "output", required_argument, NULL, ARG_OUTPUT }, - { "on-active", required_argument, NULL, ARG_ON_ACTIVE }, - { "on-boot", required_argument, NULL, ARG_ON_BOOT }, - { "on-startup", required_argument, NULL, ARG_ON_STARTUP }, - { "on-unit-active", required_argument, NULL, ARG_ON_UNIT_ACTIVE }, - { "on-unit-inactive", required_argument, NULL, ARG_ON_UNIT_INACTIVE }, - { "on-calendar", required_argument, NULL, ARG_ON_CALENDAR }, - { "on-timezone-change", no_argument, NULL, ARG_ON_TIMEZONE_CHANGE }, - { "on-clock-change", no_argument, NULL, ARG_ON_CLOCK_CHANGE }, - { "timer-property", required_argument, NULL, ARG_TIMER_PROPERTY }, - { "path-property", required_argument, NULL, ARG_PATH_PROPERTY }, - { "socket-property", required_argument, NULL, ARG_SOCKET_PROPERTY }, - { "no-block", no_argument, NULL, ARG_NO_BLOCK }, - { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, - { "collect", no_argument, NULL, 'G' }, - { "working-directory", required_argument, NULL, ARG_WORKING_DIRECTORY }, - { "same-dir", no_argument, NULL, 'd' }, - { "root-directory", required_argument, NULL, ARG_ROOT_DIRECTORY }, - { "same-root-dir", no_argument, NULL, 'R' }, - { "shell", no_argument, NULL, 'S' }, - { "job-mode", required_argument, NULL, ARG_JOB_MODE }, - { "ignore-failure", no_argument, NULL, ARG_IGNORE_FAILURE }, - { "background", required_argument, NULL, ARG_BACKGROUND }, - { "no-pager", no_argument, NULL, ARG_NO_PAGER }, - { "json", required_argument, NULL, ARG_JSON }, - {}, - }; - bool with_trigger = false, same_dir = false; - int r, c; + int r; assert(argc >= 0); assert(argv); - /* 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, "+hrC:H:M:E:p:tTPqvGdSu:", options, NULL)) >= 0) + OptionParser opts = { argc, argv, OPTION_PARSER_STOP_AT_FIRST_NONOPTION }; + FOREACH_OPTION(c, &opts, /* on_error= */ return c) switch (c) { - case 'h': + OPTION_COMMON_HELP: return help(); - case ARG_VERSION: + OPTION_COMMON_VERSION: return version(); - case ARG_NO_ASK_PASSWORD: + OPTION_COMMON_NO_ASK_PASSWORD: arg_ask_password = false; break; - case ARG_USER: + OPTION_LONG("user", NULL, "Run as user unit"): arg_runtime_scope = RUNTIME_SCOPE_USER; break; - case ARG_SYSTEM: + OPTION_LONG("system", NULL, "Talk to the service manager (implied default)"): arg_runtime_scope = RUNTIME_SCOPE_SYSTEM; break; - case 'H': + OPTION_COMMON_HOST: arg_transport = BUS_TRANSPORT_REMOTE; - arg_host = optarg; + arg_host = opts.arg; break; - case 'M': - r = parse_machine_argument(optarg, &arg_host, &arg_transport); + OPTION_COMMON_MACHINE: + r = parse_machine_argument(opts.arg, &arg_host, &arg_transport); if (r < 0) return r; break; - case 'C': - r = capsule_name_is_valid(optarg); + OPTION('C', "capsule", "NAME", "Operate on specified capsule"): + r = capsule_name_is_valid(opts.arg); if (r < 0) - return log_error_errno(r, "Unable to validate capsule name '%s': %m", optarg); + return log_error_errno(r, "Unable to validate capsule name '%s': %m", opts.arg); if (r == 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid capsule name: %s", optarg); + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid capsule name: %s", opts.arg); - arg_host = optarg; + arg_host = opts.arg; arg_transport = BUS_TRANSPORT_CAPSULE; arg_runtime_scope = RUNTIME_SCOPE_USER; break; - case ARG_SCOPE: + OPTION_LONG("scope", NULL, "Run this as scope rather than service"): arg_scope = true; break; - case 'u': - arg_unit = optarg; + OPTION('u', "unit", "UNIT", "Run under the specified unit name"): + arg_unit = opts.arg; break; - case 'p': - if (strv_extend(&arg_property, optarg) < 0) + OPTION('p', "property", "NAME=VALUE", "Set service or scope unit property"): + if (strv_extend(&arg_property, opts.arg) < 0) return log_oom(); - break; - case ARG_DESCRIPTION: - r = free_and_strdup_warn(&arg_description, optarg); + OPTION_LONG("description", "TEXT", "Description for unit"): + r = free_and_strdup_warn(&arg_description, opts.arg); if (r < 0) return r; break; - case ARG_SLICE: - r = free_and_strdup_warn(&arg_slice, optarg); + OPTION_LONG("slice", "SLICE", "Run in the specified slice"): + r = free_and_strdup_warn(&arg_slice, opts.arg); if (r < 0) return r; break; - case ARG_SLICE_INHERIT: + OPTION_LONG("slice-inherit", NULL, "Inherit the slice from the caller"): arg_slice_inherit = true; break; - case ARG_EXPAND_ENVIRONMENT: - r = parse_boolean_argument("--expand-environment=", optarg, &arg_expand_environment); + OPTION_LONG("expand-environment", "BOOL", + "Control expansion of environment variables"): + r = parse_boolean_argument("--expand-environment=", opts.arg, &arg_expand_environment); if (r < 0) return r; break; - case ARG_NO_BLOCK: + OPTION_LONG("no-block", NULL, "Do not wait until operation finished"): arg_no_block = true; break; - case 'r': + OPTION('r', "remain-after-exit", NULL, + "Leave service around until explicitly stopped"): arg_remain_after_exit = true; break; - case ARG_WAIT: + OPTION_LONG("wait", NULL, "Wait until service stopped again"): arg_wait = true; break; - case ARG_SEND_SIGHUP: + OPTION_LONG("send-sighup", NULL, "Send SIGHUP when terminating"): arg_send_sighup = true; break; - case ARG_SERVICE_TYPE: - arg_service_type = optarg; + OPTION_LONG("service-type", "TYPE", "Service type"): + arg_service_type = opts.arg; break; - case ARG_EXEC_USER: - r = free_and_strdup_warn(&arg_exec_user, optarg); + OPTION_LONG("uid", "USER", "Run as system user"): + r = free_and_strdup_warn(&arg_exec_user, opts.arg); if (r < 0) return r; break; - case ARG_EXEC_GROUP: - arg_exec_group = optarg; + OPTION_LONG("gid", "GROUP", "Run as system group"): + arg_exec_group = opts.arg; break; - case ARG_NICE: - r = parse_nice(optarg, &arg_nice); + OPTION_LONG("nice", "NICE", "Nice level"): + r = parse_nice(opts.arg, &arg_nice); if (r < 0) - return log_error_errno(r, "Failed to parse nice value: %s", optarg); + return log_error_errno(r, "Failed to parse nice value: %s", opts.arg); arg_nice_set = true; break; - case ARG_WORKING_DIRECTORY: - r = parse_path_argument(optarg, true, &arg_working_directory); + OPTION_LONG("working-directory", "PATH", "Set working directory"): + r = parse_path_argument(opts.arg, true, &arg_working_directory); if (r < 0) return r; same_dir = false; break; - case 'd': { + OPTION('d', "same-dir", NULL, "Inherit working directory from caller"): { _cleanup_free_ char *p = NULL; r = safe_getcwd(&p); @@ -554,151 +422,156 @@ static int parse_argv(int argc, char *argv[]) { break; } - case ARG_ROOT_DIRECTORY: - r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_root_directory); + OPTION_LONG("root-directory", "PATH", "Set root directory"): + r = parse_path_argument(opts.arg, /* suppress_root= */ false, &arg_root_directory); if (r < 0) return r; - break; - case 'R': + OPTION('R', "same-root-dir", NULL, "Inherit root directory from caller"): r = free_and_strdup_warn(&arg_root_directory, "/"); if (r < 0) return r; - break; - case 'E': - r = strv_env_replace_strdup_passthrough(&arg_environment, optarg); + OPTION('E', "setenv", "NAME[=VALUE]", "Set environment variable"): + r = strv_env_replace_strdup_passthrough(&arg_environment, opts.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", opts.arg); break; - case 't': /* --pty (and --tty deprecated alias) */ - case 'T': /* --pty-late */ + OPTION_LONG("tty", NULL, NULL): {} /* deprecated alias for --pty */ + OPTION('t', "pty", NULL, + "Run service on pseudo TTY as STDIN/STDOUT/STDERR"): {} + OPTION('T', "pty-late", NULL, + "Just like --pty, but leave TTY access to agents until unit is started up"): arg_stdio |= ARG_STDIO_PTY; - arg_pty_late = c == 'T'; + arg_pty_late = opts.opt->short_code == 'T'; break; - case 'P': /* --pipe */ + OPTION('P', "pipe", NULL, "Pass STDIN/STDOUT/STDERR directly to service"): arg_stdio |= ARG_STDIO_DIRECT; break; - case 'q': + OPTION('q', "quiet", NULL, "Suppress information messages during runtime"): arg_quiet = true; break; - case 'v': + OPTION('v', "verbose", NULL, "Show unit logs while executing operation"): arg_verbose = true; break; - case ARG_OUTPUT: - if (streq(optarg, "help")) + OPTION_LONG("output", "MODE", + "Controls formatting of verbose logs, see journalctl for valid values"): + if (streq(opts.arg, "help")) return DUMP_STRING_TABLE(output_mode, OutputMode, _OUTPUT_MODE_MAX); - arg_output = output_mode_from_string(optarg); + arg_output = output_mode_from_string(opts.arg); if (arg_output < 0) - return log_error_errno(arg_output, "Unknown output format '%s'.", optarg); + return log_error_errno(arg_output, "Unknown output format '%s'.", opts.arg); break; - case ARG_JSON: - r = parse_json_argument(optarg, &arg_json_format_flags); + OPTION_COMMON_JSON: + r = parse_json_argument(opts.arg, &arg_json_format_flags); if (r <= 0) return r; break; - case 'G': + OPTION('G', "collect", NULL, "Unload unit after it ran, even when failed"): arg_aggressive_gc = true; break; - case 'S': + OPTION('S', "shell", NULL, "Invoke a $SHELL interactively"): arg_shell = true; break; - case ARG_JOB_MODE: - if (streq(optarg, "help")) + OPTION_LONG("job-mode", "MODE", + "Specify how to deal with already queued jobs, when queueing a new job"): + if (streq(opts.arg, "help")) return DUMP_STRING_TABLE(job_mode, JobMode, _JOB_MODE_MAX); - r = job_mode_from_string(optarg); + r = job_mode_from_string(opts.arg); if (r < 0) - return log_error_errno(r, "Invalid job mode: %s", optarg); + return log_error_errno(r, "Invalid job mode: %s", opts.arg); arg_job_mode = r; break; - case ARG_IGNORE_FAILURE: + OPTION_LONG("ignore-failure", NULL, "Ignore the exit status of the invoked process"): arg_ignore_failure = 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(opts.arg, &arg_background); if (r < 0) return r; break; - case ARG_NO_PAGER: + OPTION_COMMON_NO_PAGER: arg_pager_flags |= PAGER_DISABLE; break; - case ARG_PATH_PROPERTY: + OPTION_GROUP("Path options"): {} - if (strv_extend(&arg_path_property, optarg) < 0) + OPTION_LONG("path-property", "NAME=VALUE", "Set path unit property"): + if (strv_extend(&arg_path_property, opts.arg) < 0) return log_oom(); - break; - case ARG_SOCKET_PROPERTY: + OPTION_GROUP("Socket options"): {} - if (strv_extend(&arg_socket_property, optarg) < 0) + OPTION_LONG("socket-property", "NAME=VALUE", "Set socket unit property"): + if (strv_extend(&arg_socket_property, opts.arg) < 0) return log_oom(); - break; - case ARG_ON_ACTIVE: - r = add_timer_property("OnActiveSec", optarg); + OPTION_GROUP("Timer options"): {} + + OPTION_LONG("on-active", "SECONDS", "Run after SECONDS delay"): + r = add_timer_property("OnActiveSec", opts.arg); if (r < 0) return r; arg_with_timer = true; break; - case ARG_ON_BOOT: - r = add_timer_property("OnBootSec", optarg); + OPTION_LONG("on-boot", "SECONDS", "Run SECONDS after machine was booted up"): + r = add_timer_property("OnBootSec", opts.arg); if (r < 0) return r; arg_with_timer = true; break; - case ARG_ON_STARTUP: - r = add_timer_property("OnStartupSec", optarg); + OPTION_LONG("on-startup", "SECONDS", "Run SECONDS after systemd activation"): + r = add_timer_property("OnStartupSec", opts.arg); if (r < 0) return r; arg_with_timer = true; break; - case ARG_ON_UNIT_ACTIVE: - r = add_timer_property("OnUnitActiveSec", optarg); + OPTION_LONG("on-unit-active", "SECONDS", "Run SECONDS after the last activation"): + r = add_timer_property("OnUnitActiveSec", opts.arg); if (r < 0) return r; arg_with_timer = true; break; - case ARG_ON_UNIT_INACTIVE: - r = add_timer_property("OnUnitInactiveSec", optarg); + OPTION_LONG("on-unit-inactive", "SECONDS", + "Run SECONDS after the last deactivation"): + r = add_timer_property("OnUnitInactiveSec", opts.arg); if (r < 0) return r; arg_with_timer = true; break; - case ARG_ON_CALENDAR: { + OPTION_LONG("on-calendar", "SPEC", "Realtime timer"): { _cleanup_(calendar_spec_freep) CalendarSpec *cs = NULL; - r = calendar_spec_from_string(optarg, &cs); + r = calendar_spec_from_string(opts.arg, &cs); if (r < 0) return log_error_errno(r, "Failed to parse calendar event specification: %m"); @@ -713,7 +586,7 @@ static int parse_argv(int argc, char *argv[]) { else if (r < 0) return log_error_errno(r, "Failed to calculate next time calendar expression elapses: %m"); - r = add_timer_property("OnCalendar", optarg); + r = add_timer_property("OnCalendar", opts.arg); if (r < 0) return r; @@ -721,7 +594,7 @@ static int parse_argv(int argc, char *argv[]) { break; } - case ARG_ON_TIMEZONE_CHANGE: + OPTION_LONG("on-timezone-change", NULL, "Run when the timezone changes"): r = add_timer_property("OnTimezoneChange", "yes"); if (r < 0) return r; @@ -729,7 +602,7 @@ static int parse_argv(int argc, char *argv[]) { arg_with_timer = true; break; - case ARG_ON_CLOCK_CHANGE: + OPTION_LONG("on-clock-change", NULL, "Run when the realtime clock jumps"): r = add_timer_property("OnClockChange", "yes"); if (r < 0) return r; @@ -737,13 +610,12 @@ static int parse_argv(int argc, char *argv[]) { arg_with_timer = true; break; - case ARG_TIMER_PROPERTY: - - if (strv_extend(&arg_timer_property, optarg) < 0) + OPTION_LONG("timer-property", "NAME=VALUE", "Set timer unit property"): + if (strv_extend(&arg_timer_property, opts.arg) < 0) return log_oom(); arg_with_timer = arg_with_timer || - STARTSWITH_SET(optarg, + STARTSWITH_SET(opts.arg, "OnActiveSec=", "OnBootSec=", "OnStartupSec=", @@ -751,12 +623,6 @@ static int parse_argv(int argc, char *argv[]) { "OnUnitInactiveSec=", "OnCalendar="); break; - - case '?': - return -EINVAL; - - default: - assert_not_reached(); } /* If we are talking to the per-user instance PolicyKit isn't going to help */ @@ -805,13 +671,14 @@ static int parse_argv(int argc, char *argv[]) { if (arg_pty_late < 0) arg_pty_late = false; /* For systemd-run this defaults to false, for compat reasons */ - if (argc > optind) { + char **args = option_parser_get_args(&opts); + if (!strv_isempty(args)) { char **l; if (arg_shell) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "If --shell is used, no command line is expected."); - l = strv_copy(argv + optind); + l = strv_copy(args); if (!l) return log_oom();