• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 15150396955

20 May 2025 10:32PM UTC coverage: 72.047% (-0.2%) from 72.25%
15150396955

push

github

web-flow
resolved: add new "DNS Delegate" concepts (#34368)

Various long standing issues (at least: #5573 #14159 #20485 #21260
#24532 #32022 #18056) have been asking for a way to delegate DNS
resolution of specific domains to very specific DNS servers.

This PR goes a major step towards that goal by adding a new concept "DNS
Delegate" which allows to configure just that. Basically, this adds a
third kind of DNS scope to resolved's logic: besides the per-link and
global DNS scopes there are now also "delegate" scopes, which can be
created by dropping in a new file /etc/systemd/dns-delegate/*.conf. They
carry DNS= and Domains= lines just like the global setting or what the
per-link configuration can carry.

And they are consulted the same way as link DNS scopes are considered,
following the same routing rules.

This allows to configure these DNS delegates statically via drop-in
files as mentioned, and only adds the most basic functionality. Later on
we might want to extend this:

1. Allow dynamic creation of DNS delegates via IPC with lifecycle bound
to IPC client (usecase: installing a DNS delegate that routes traffic to
some DNS-over-TLS server once basic setup is complete).
2. Allow configuration of protocol details per delegate the same way
this is currently allowed per-link.
3. Instead of strictly using DNS as delegation protocol, support an
alternative varlink based protocol (without retransmission problems and
so on) that systemd-machined and similar can implement.

This PR is not complete yet. Lacks docs and tests. Seems to work fine in
my local tests however.

Fixes: #5573
Fixes: #18056
Fixes: #20485

470 of 586 new or added lines in 14 files covered. (80.2%)

3358 existing lines in 54 files now uncovered.

299091 of 415134 relevant lines covered (72.05%)

703065.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.04
/src/systemctl/systemctl.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <getopt.h>
4
#include <locale.h>
5
#include <unistd.h>
6

7
#include "sd-daemon.h"
8

9
#include "argv-util.h"
10
#include "build.h"
11
#include "bus-util.h"
12
#include "capsule-util.h"
13
#include "dissect-image.h"
14
#include "install.h"
15
#include "logs-show.h"
16
#include "main-func.h"
17
#include "mount-util.h"
18
#include "output-mode.h"
19
#include "pager.h"
20
#include "parse-argument.h"
21
#include "parse-util.h"
22
#include "path-util.h"
23
#include "pretty-print.h"
24
#include "process-util.h"
25
#include "reboot-util.h"
26
#include "rlimit-util.h"
27
#include "signal-util.h"
28
#include "stat-util.h"
29
#include "string-table.h"
30
#include "systemctl.h"
31
#include "systemctl-compat-halt.h"
32
#include "systemctl-compat-runlevel.h"
33
#include "systemctl-compat-shutdown.h"
34
#include "systemctl-compat-telinit.h"
35
#include "systemctl-logind.h"
36
#include "systemctl-mount.h"
37
#include "systemctl-preset-all.h"
38
#include "systemctl-reset-failed.h"
39
#include "systemctl-service-watchdogs.h"
40
#include "systemctl-set-default.h"
41
#include "systemctl-set-environment.h"
42
#include "systemctl-set-property.h"
43
#include "systemctl-show.h"
44
#include "systemctl-start-special.h"
45
#include "systemctl-start-unit.h"
46
#include "systemctl-switch-root.h"
47
#include "systemctl-sysv-compat.h"
48
#include "systemctl-trivial-method.h"
49
#include "systemctl-util.h"
50
#include "systemctl-whoami.h"
51
#include "terminal-util.h"
52
#include "time-util.h"
53
#include "user-util.h"
54
#include "verbs.h"
55
#include "virt.h"
56

57
char **arg_types = NULL;
58
char **arg_states = NULL;
59
char **arg_properties = NULL;
60
bool arg_all = false;
61
enum dependency arg_dependency = DEPENDENCY_FORWARD;
62
const char *_arg_job_mode = NULL;
63
RuntimeScope arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
64
bool arg_wait = false;
65
bool arg_no_block = false;
66
int arg_legend = -1; /* -1: true, unless --quiet is passed, 1: true */
67
PagerFlags arg_pager_flags = 0;
68
bool arg_no_wtmp = false;
69
bool arg_no_sync = false;
70
bool arg_no_wall = false;
71
bool arg_no_reload = false;
72
BusPrintPropertyFlags arg_print_flags = 0;
73
bool arg_show_types = false;
74
int arg_check_inhibitors = -1;
75
bool arg_dry_run = false;
76
bool arg_quiet = false;
77
bool arg_verbose = false;
78
bool arg_no_warn = false;
79
bool arg_full = false;
80
bool arg_recursive = false;
81
bool arg_with_dependencies = false;
82
bool arg_show_transaction = false;
83
int arg_force = 0;
84
bool arg_ask_password = false;
85
bool arg_runtime = false;
86
UnitFilePresetMode arg_preset_mode = UNIT_FILE_PRESET_FULL;
87
char **arg_wall = NULL;
88
const char *arg_kill_whom = NULL;
89
int arg_signal = SIGTERM;
90
int arg_kill_value;
91
bool arg_kill_value_set = false;
92
char *arg_root = NULL;
93
char *arg_image = NULL;
94
usec_t arg_when = 0;
95
bool arg_stdin = false;
96
const char *arg_reboot_argument = NULL;
97
enum action arg_action = ACTION_SYSTEMCTL;
98
BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
99
const char *arg_host = NULL;
100
unsigned arg_lines = 10;
101
OutputMode arg_output = OUTPUT_SHORT;
102
bool arg_plain = false;
103
bool arg_firmware_setup = false;
104
usec_t arg_boot_loader_menu = USEC_INFINITY;
105
const char *arg_boot_loader_entry = NULL;
106
bool arg_now = false;
107
bool arg_jobs_before = false;
108
bool arg_jobs_after = false;
109
char **arg_clean_what = NULL;
110
TimestampStyle arg_timestamp_style = TIMESTAMP_PRETTY;
111
bool arg_read_only = false;
112
bool arg_mkdir = false;
113
bool arg_marked = false;
114
const char *arg_drop_in = NULL;
115
ImagePolicy *arg_image_policy = NULL;
116

117
STATIC_DESTRUCTOR_REGISTER(arg_types, strv_freep);
11,277✔
118
STATIC_DESTRUCTOR_REGISTER(arg_states, strv_freep);
11,277✔
119
STATIC_DESTRUCTOR_REGISTER(arg_properties, strv_freep);
11,277✔
120
STATIC_DESTRUCTOR_REGISTER(_arg_job_mode, unsetp);
11,277✔
121
STATIC_DESTRUCTOR_REGISTER(arg_wall, strv_freep);
11,277✔
122
STATIC_DESTRUCTOR_REGISTER(arg_kill_whom, unsetp);
11,277✔
123
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
11,277✔
124
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
11,277✔
125
STATIC_DESTRUCTOR_REGISTER(arg_reboot_argument, unsetp);
11,277✔
126
STATIC_DESTRUCTOR_REGISTER(arg_host, unsetp);
11,277✔
127
STATIC_DESTRUCTOR_REGISTER(arg_boot_loader_entry, unsetp);
11,277✔
128
STATIC_DESTRUCTOR_REGISTER(arg_clean_what, strv_freep);
11,277✔
129
STATIC_DESTRUCTOR_REGISTER(arg_drop_in, unsetp);
11,277✔
130
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
11,277✔
131

UNCOV
132
static int systemctl_help(void) {
×
UNCOV
133
        _cleanup_free_ char *link = NULL;
×
UNCOV
134
        int r;
×
135

UNCOV
136
        pager_open(arg_pager_flags);
×
137

UNCOV
138
        r = terminal_urlify_man("systemctl", "1", &link);
×
UNCOV
139
        if (r < 0)
×
UNCOV
140
                return log_oom();
×
141

UNCOV
142
        printf("%1$s [OPTIONS...] COMMAND ...\n\n"
×
143
               "%5$sQuery or send control commands to the system manager.%6$s\n"
144
               "\n%3$sUnit Commands:%4$s\n"
145
               "  list-units [PATTERN...]             List units currently in memory\n"
146
               "  list-automounts [PATTERN...]        List automount units currently in memory,\n"
147
               "                                      ordered by path\n"
148
               "  list-paths [PATTERN...]             List path units currently in memory,\n"
149
               "                                      ordered by path\n"
150
               "  list-sockets [PATTERN...]           List socket units currently in memory,\n"
151
               "                                      ordered by address\n"
152
               "  list-timers [PATTERN...]            List timer units currently in memory,\n"
153
               "                                      ordered by next elapse\n"
154
               "  is-active PATTERN...                Check whether units are active\n"
155
               "  is-failed [PATTERN...]              Check whether units are failed or\n"
156
               "                                      system is in degraded state\n"
157
               "  status [PATTERN...|PID...]          Show runtime status of one or more units\n"
158
               "  show [PATTERN...|JOB...]            Show properties of one or more\n"
159
               "                                      units/jobs or the manager\n"
160
               "  cat PATTERN...                      Show files and drop-ins of specified units\n"
161
               "  help PATTERN...|PID...              Show manual for one or more units\n"
162
               "  list-dependencies [UNIT...]         Recursively show units which are required\n"
163
               "                                      or wanted by the units or by which those\n"
164
               "                                      units are required or wanted\n"
165
               "  start UNIT...                       Start (activate) one or more units\n"
166
               "  stop UNIT...                        Stop (deactivate) one or more units\n"
167
               "  reload UNIT...                      Reload one or more units\n"
168
               "  restart UNIT...                     Start or restart one or more units\n"
169
               "  try-restart UNIT...                 Restart one or more units if active\n"
170
               "  reload-or-restart UNIT...           Reload one or more units if possible,\n"
171
               "                                      otherwise start or restart\n"
172
               "  try-reload-or-restart UNIT...       If active, reload one or more units,\n"
173
               "                                      if supported, otherwise restart\n"
174
               "  isolate UNIT                        Start one unit and stop all others\n"
175
               "  kill UNIT...                        Send signal to processes of a unit\n"
176
               "  clean UNIT...                       Clean runtime, cache, state, logs or\n"
177
               "                                      configuration of unit\n"
178
               "  freeze PATTERN...                   Freeze execution of unit processes\n"
179
               "  thaw PATTERN...                     Resume execution of a frozen unit\n"
180
               "  set-property UNIT PROPERTY=VALUE... Sets one or more properties of a unit\n"
181
               "  bind UNIT PATH [PATH]               Bind-mount a path from the host into a\n"
182
               "                                      unit's namespace\n"
183
               "  mount-image UNIT PATH [PATH [OPTS]] Mount an image from the host into a\n"
184
               "                                      unit's namespace\n"
185
               "  service-log-level SERVICE [LEVEL]   Get/set logging threshold for service\n"
186
               "  service-log-target SERVICE [TARGET] Get/set logging target for service\n"
187
               "  reset-failed [PATTERN...]           Reset failed state for all, one, or more\n"
188
               "                                      units\n"
189
               "  whoami [PID...]                     Return unit caller or specified PIDs are\n"
190
               "                                      part of\n"
191
               "\n%3$sUnit File Commands:%4$s\n"
192
               "  list-unit-files [PATTERN...]        List installed unit files\n"
193
               "  enable [UNIT...|PATH...]            Enable one or more unit files\n"
194
               "  disable UNIT...                     Disable one or more unit files\n"
195
               "  reenable UNIT...                    Reenable one or more unit files\n"
196
               "  preset UNIT...                      Enable/disable one or more unit files\n"
197
               "                                      based on preset configuration\n"
198
               "  preset-all                          Enable/disable all unit files based on\n"
199
               "                                      preset configuration\n"
200
               "  is-enabled UNIT...                  Check whether unit files are enabled\n"
201
               "  mask UNIT...                        Mask one or more units\n"
202
               "  unmask UNIT...                      Unmask one or more units\n"
203
               "  link PATH...                        Link one or more units files into\n"
204
               "                                      the search path\n"
205
               "  revert UNIT...                      Revert one or more unit files to vendor\n"
206
               "                                      version\n"
207
               "  add-wants TARGET UNIT...            Add 'Wants' dependency for the target\n"
208
               "                                      on specified one or more units\n"
209
               "  add-requires TARGET UNIT...         Add 'Requires' dependency for the target\n"
210
               "                                      on specified one or more units\n"
211
               "  edit UNIT...                        Edit one or more unit files\n"
212
               "  get-default                         Get the name of the default target\n"
213
               "  set-default TARGET                  Set the default target\n"
214
               "\n%3$sMachine Commands:%4$s\n"
215
               "  list-machines [PATTERN...]          List local containers and host\n"
216
               "\n%3$sJob Commands:%4$s\n"
217
               "  list-jobs [PATTERN...]              List jobs\n"
218
               "  cancel [JOB...]                     Cancel all, one, or more jobs\n"
219
               "\n%3$sEnvironment Commands:%4$s\n"
220
               "  show-environment                    Dump environment\n"
221
               "  set-environment VARIABLE=VALUE...   Set one or more environment variables\n"
222
               "  unset-environment VARIABLE...       Unset one or more environment variables\n"
223
               "  import-environment VARIABLE...      Import all or some environment variables\n"
224
               "\n%3$sManager State Commands:%4$s\n"
225
               "  daemon-reload                       Reload systemd manager configuration\n"
226
               "  daemon-reexec                       Reexecute systemd manager\n"
227
               "  log-level [LEVEL]                   Get/set logging threshold for manager\n"
228
               "  log-target [TARGET]                 Get/set logging target for manager\n"
229
               "  service-watchdogs [BOOL]            Get/set service watchdog state\n"
230
               "\n%3$sSystem Commands:%4$s\n"
231
               "  is-system-running                   Check whether system is fully running\n"
232
               "  default                             Enter system default mode\n"
233
               "  rescue                              Enter system rescue mode\n"
234
               "  emergency                           Enter system emergency mode\n"
235
               "  halt                                Shut down and halt the system\n"
236
               "  poweroff                            Shut down and power-off the system\n"
237
               "  reboot                              Shut down and reboot the system\n"
238
               "  kexec                               Shut down and reboot the system with kexec\n"
239
               "  soft-reboot                         Shut down and reboot userspace\n"
240
               "  exit [EXIT_CODE]                    Request user instance or container exit\n"
241
               "  switch-root [ROOT [INIT]]           Change to a different root file system\n"
242
               "  sleep                               Put the system to sleep (through one of\n"
243
               "                                      the operations below)\n"
244
               "  suspend                             Suspend the system\n"
245
               "  hibernate                           Hibernate the system\n"
246
               "  hybrid-sleep                        Hibernate and suspend the system\n"
247
               "  suspend-then-hibernate              Suspend the system, wake after a period of\n"
248
               "                                      time, and hibernate"
249
               "\n%3$sOptions:%4$s\n"
250
               "  -h --help              Show this help\n"
251
               "     --version           Show package version\n"
252
               "     --system            Connect to system manager\n"
253
               "     --user              Connect to user service manager\n"
254
               "  -C --capsule=NAME      Connect to service manager of specified capsule\n"
255
               "  -H --host=[USER@]HOST  Operate on remote host\n"
256
               "  -M --machine=CONTAINER Operate on a local container\n"
257
               "  -t --type=TYPE         List units of a particular type\n"
258
               "     --state=STATE       List units with particular LOAD or SUB or ACTIVE state\n"
259
               "     --failed            Shortcut for --state=failed\n"
260
               "  -p --property=NAME     Show only properties by this name\n"
261
               "  -P NAME                Equivalent to --value --property=NAME\n"
262
               "  -a --all               Show all properties/all units currently in memory,\n"
263
               "                         including dead/empty ones. To list all units installed\n"
264
               "                         on the system, use 'list-unit-files' instead.\n"
265
               "  -l --full              Don't ellipsize unit names on output\n"
266
               "  -r --recursive         Show unit list of host and local containers\n"
267
               "     --reverse           Show reverse dependencies with 'list-dependencies'\n"
268
               "     --before            Show units ordered before with 'list-dependencies'\n"
269
               "     --after             Show units ordered after with 'list-dependencies'\n"
270
               "     --with-dependencies Show unit dependencies with 'status', 'cat',\n"
271
               "                         'list-units', and 'list-unit-files'.\n"
272
               "     --job-mode=MODE     Specify how to deal with already queued jobs, when\n"
273
               "                         queueing a new job\n"
274
               "  -T --show-transaction  When enqueuing a unit job, show full transaction\n"
275
               "     --show-types        When showing sockets, explicitly show their type\n"
276
               "     --value             When showing properties, only print the value\n"
277
               "     --check-inhibitors=MODE\n"
278
               "                         Whether to check inhibitors before shutting down,\n"
279
               "                         sleeping, or hibernating\n"
280
               "  -i                     Shortcut for --check-inhibitors=no\n"
281
               "     --kill-whom=WHOM    Whom to send signal to\n"
282
               "     --kill-value=INT    Signal value to enqueue\n"
283
               "  -s --signal=SIGNAL     Which signal to send\n"
284
               "     --what=RESOURCES    Which types of resources to remove\n"
285
               "     --now               Start or stop unit after enabling or disabling it\n"
286
               "     --dry-run           Only print what would be done\n"
287
               "                         Currently supported by verbs: halt, poweroff, reboot,\n"
288
               "                             kexec, soft-reboot, suspend, hibernate, \n"
289
               "                             suspend-then-hibernate, hybrid-sleep, default,\n"
290
               "                             rescue, emergency, and exit.\n"
291
               "  -q --quiet             Suppress output\n"
292
               "  -v --verbose           Show unit logs while executing operation\n"
293
               "     --no-warn           Suppress several warnings shown by default\n"
294
               "     --wait              For (re)start, wait until service stopped again\n"
295
               "                         For is-system-running, wait until startup is completed\n"
296
               "                         For kill, wait until service stopped\n"
297
               "     --no-block          Do not wait until operation finished\n"
298
               "     --no-wall           Don't send wall message before halt/power-off/reboot\n"
299
               "     --message=MESSAGE   Specify human readable reason for system shutdown\n"
300
               "     --no-reload         Don't reload daemon after en-/dis-abling unit files\n"
301
               "     --legend=BOOL       Enable/disable the legend (column headers and hints)\n"
302
               "     --no-pager          Do not pipe output into a pager\n"
303
               "     --no-ask-password   Do not ask for system passwords\n"
304
               "     --global            Edit/enable/disable/mask default user unit files\n"
305
               "                         globally\n"
306
               "     --runtime           Edit/enable/disable/mask unit files temporarily until\n"
307
               "                         next reboot\n"
308
               "  -f --force             When enabling unit files, override existing symlinks\n"
309
               "                         When shutting down, execute action immediately\n"
310
               "     --preset-mode=      Apply only enable, only disable, or all presets\n"
311
               "     --root=PATH         Edit/enable/disable/mask unit files in the specified\n"
312
               "                         root directory\n"
313
               "     --image=PATH        Edit/enable/disable/mask unit files in the specified\n"
314
               "                         disk image\n"
315
               "     --image-policy=POLICY\n"
316
               "                         Specify disk image dissection policy\n"
317
               "  -n --lines=INTEGER     Number of journal entries to show\n"
318
               "  -o --output=STRING     Change journal output mode (short, short-precise,\n"
319
               "                             short-iso, short-iso-precise, short-full,\n"
320
               "                             short-monotonic, short-unix, short-delta,\n"
321
               "                             verbose, export, json, json-pretty, json-sse, cat)\n"
322
               "     --firmware-setup    Tell the firmware to show the setup menu on next boot\n"
323
               "     --boot-loader-menu=TIME\n"
324
               "                         Boot into boot loader menu on next boot\n"
325
               "     --boot-loader-entry=NAME\n"
326
               "                         Boot into a specific boot loader entry on next boot\n"
327
               "     --reboot-argument=ARG\n"
328
               "                         Specify argument string to pass to reboot()\n"
329
               "     --plain             Print unit dependencies as a list instead of a tree\n"
330
               "     --timestamp=FORMAT  Change format of printed timestamps (pretty, unix,\n"
331
               "                             us, utc, us+utc)\n"
332
               "     --read-only         Create read-only bind mount\n"
333
               "     --mkdir             Create directory before mounting, if missing\n"
334
               "     --marked            Restart/reload previously marked units\n"
335
               "     --drop-in=NAME      Edit unit files using the specified drop-in file name\n"
336
               "     --when=TIME         Schedule halt/power-off/reboot/kexec action after\n"
337
               "                         a certain timestamp\n"
338
               "     --stdin             Read new contents of edited file from stdin\n"
339
               "\nSee the %2$s for details.\n",
340
               program_invocation_short_name,
341
               link,
342
               ansi_underline(),
343
               ansi_normal(),
344
               ansi_highlight(),
345
               ansi_normal());
346

347
        return 0;
348
}
349

350
static void help_types(void) {
1✔
351
        if (arg_legend != 0)
1✔
352
                puts("Available unit types:");
1✔
353

354
        DUMP_STRING_TABLE(unit_type, UnitType, _UNIT_TYPE_MAX);
12✔
355
}
1✔
356

357
static void help_states(void) {
1✔
358
        if (arg_legend != 0)
1✔
359
                puts("Available unit load states:");
1✔
360
        DUMP_STRING_TABLE(unit_load_state, UnitLoadState, _UNIT_LOAD_STATE_MAX);
8✔
361

362
        if (arg_legend != 0)
1✔
363
                puts("\nAvailable unit active states:");
1✔
364
        DUMP_STRING_TABLE(unit_active_state, UnitActiveState, _UNIT_ACTIVE_STATE_MAX);
9✔
365

366
        if (arg_legend != 0)
1✔
367
                puts("\nAvailable unit file states:");
1✔
368
        DUMP_STRING_TABLE(unit_file_state, UnitFileState, _UNIT_FILE_STATE_MAX);
14✔
369

370
        if (arg_legend != 0)
1✔
371
                puts("\nAvailable automount unit substates:");
1✔
372
        DUMP_STRING_TABLE(automount_state, AutomountState, _AUTOMOUNT_STATE_MAX);
5✔
373

374
        if (arg_legend != 0)
1✔
375
                puts("\nAvailable device unit substates:");
1✔
376
        DUMP_STRING_TABLE(device_state, DeviceState, _DEVICE_STATE_MAX);
4✔
377

378
        if (arg_legend != 0)
1✔
379
                puts("\nAvailable mount unit substates:");
1✔
380
        DUMP_STRING_TABLE(mount_state, MountState, _MOUNT_STATE_MAX);
13✔
381

382
        if (arg_legend != 0)
1✔
383
                puts("\nAvailable path unit substates:");
1✔
384
        DUMP_STRING_TABLE(path_state, PathState, _PATH_STATE_MAX);
5✔
385

386
        if (arg_legend != 0)
1✔
387
                puts("\nAvailable scope unit substates:");
1✔
388
        DUMP_STRING_TABLE(scope_state, ScopeState, _SCOPE_STATE_MAX);
8✔
389

390
        if (arg_legend != 0)
1✔
391
                puts("\nAvailable service unit substates:");
1✔
392
        DUMP_STRING_TABLE(service_state, ServiceState, _SERVICE_STATE_MAX);
28✔
393

394
        if (arg_legend != 0)
1✔
395
                puts("\nAvailable slice unit substates:");
1✔
396
        DUMP_STRING_TABLE(slice_state, SliceState, _SLICE_STATE_MAX);
3✔
397

398
        if (arg_legend != 0)
1✔
399
                puts("\nAvailable socket unit substates:");
1✔
400
        DUMP_STRING_TABLE(socket_state, SocketState, _SOCKET_STATE_MAX);
16✔
401

402
        if (arg_legend != 0)
1✔
403
                puts("\nAvailable swap unit substates:");
1✔
404
        DUMP_STRING_TABLE(swap_state, SwapState, _SWAP_STATE_MAX);
10✔
405

406
        if (arg_legend != 0)
1✔
407
                puts("\nAvailable target unit substates:");
1✔
408
        DUMP_STRING_TABLE(target_state, TargetState, _TARGET_STATE_MAX);
3✔
409

410
        if (arg_legend != 0)
1✔
411
                puts("\nAvailable timer unit substates:");
1✔
412
        DUMP_STRING_TABLE(timer_state, TimerState, _TIMER_STATE_MAX);
6✔
413
}
1✔
414

415
static int systemctl_parse_argv(int argc, char *argv[]) {
11,265✔
416
        enum {
11,265✔
417
                ARG_FAIL = 0x100,            /* compatibility only */
418
                ARG_REVERSE,
419
                ARG_AFTER,
420
                ARG_BEFORE,
421
                ARG_CHECK_INHIBITORS,
422
                ARG_DRY_RUN,
423
                ARG_SHOW_TYPES,
424
                ARG_IRREVERSIBLE,            /* compatibility only */
425
                ARG_IGNORE_DEPENDENCIES,     /* compatibility only */
426
                ARG_VALUE,
427
                ARG_VERSION,
428
                ARG_USER,
429
                ARG_SYSTEM,
430
                ARG_GLOBAL,
431
                ARG_NO_BLOCK,
432
                ARG_LEGEND,
433
                ARG_NO_LEGEND,                /* compatibility only */
434
                ARG_NO_PAGER,
435
                ARG_NO_WALL,
436
                ARG_ROOT,
437
                ARG_IMAGE,
438
                ARG_IMAGE_POLICY,
439
                ARG_NO_RELOAD,
440
                ARG_KILL_WHOM,
441
                ARG_KILL_VALUE,
442
                ARG_NO_ASK_PASSWORD,
443
                ARG_FAILED,
444
                ARG_RUNTIME,
445
                ARG_PLAIN,
446
                ARG_STATE,
447
                ARG_JOB_MODE,
448
                ARG_PRESET_MODE,
449
                ARG_FIRMWARE_SETUP,
450
                ARG_BOOT_LOADER_MENU,
451
                ARG_BOOT_LOADER_ENTRY,
452
                ARG_NOW,
453
                ARG_MESSAGE,
454
                ARG_WITH_DEPENDENCIES,
455
                ARG_WAIT,
456
                ARG_WHAT,
457
                ARG_REBOOT_ARG,
458
                ARG_TIMESTAMP_STYLE,
459
                ARG_READ_ONLY,
460
                ARG_MKDIR,
461
                ARG_MARKED,
462
                ARG_NO_WARN,
463
                ARG_DROP_IN,
464
                ARG_WHEN,
465
                ARG_STDIN,
466
        };
467

468
        static const struct option options[] = {
11,265✔
469
                { "help",                no_argument,       NULL, 'h'                     },
470
                { "version",             no_argument,       NULL, ARG_VERSION             },
471
                { "type",                required_argument, NULL, 't'                     },
472
                { "property",            required_argument, NULL, 'p'                     },
473
                { "all",                 no_argument,       NULL, 'a'                     },
474
                { "reverse",             no_argument,       NULL, ARG_REVERSE             },
475
                { "after",               no_argument,       NULL, ARG_AFTER               },
476
                { "before",              no_argument,       NULL, ARG_BEFORE              },
477
                { "show-types",          no_argument,       NULL, ARG_SHOW_TYPES          },
478
                { "failed",              no_argument,       NULL, ARG_FAILED              },
479
                { "full",                no_argument,       NULL, 'l'                     },
480
                { "job-mode",            required_argument, NULL, ARG_JOB_MODE            },
481
                { "fail",                no_argument,       NULL, ARG_FAIL                }, /* compatibility only */
482
                { "irreversible",        no_argument,       NULL, ARG_IRREVERSIBLE        }, /* compatibility only */
483
                { "ignore-dependencies", no_argument,       NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */
484
                { "ignore-inhibitors",   no_argument,       NULL, 'i'                     }, /* compatibility only */
485
                { "check-inhibitors",    required_argument, NULL, ARG_CHECK_INHIBITORS    },
486
                { "value",               no_argument,       NULL, ARG_VALUE               },
487
                { "user",                no_argument,       NULL, ARG_USER                },
488
                { "system",              no_argument,       NULL, ARG_SYSTEM              },
489
                { "global",              no_argument,       NULL, ARG_GLOBAL              },
490
                { "capsule",             required_argument, NULL, 'C'                     },
491
                { "wait",                no_argument,       NULL, ARG_WAIT                },
492
                { "no-block",            no_argument,       NULL, ARG_NO_BLOCK            },
493
                { "legend",              required_argument, NULL, ARG_LEGEND              },
494
                { "no-legend",           no_argument,       NULL, ARG_NO_LEGEND           }, /* compatibility only */
495
                { "no-pager",            no_argument,       NULL, ARG_NO_PAGER            },
496
                { "no-wall",             no_argument,       NULL, ARG_NO_WALL             },
497
                { "dry-run",             no_argument,       NULL, ARG_DRY_RUN             },
498
                { "quiet",               no_argument,       NULL, 'q'                     },
499
                { "verbose",             no_argument,       NULL, 'v'                     },
500
                { "no-warn",             no_argument,       NULL, ARG_NO_WARN             },
501
                { "root",                required_argument, NULL, ARG_ROOT                },
502
                { "image",               required_argument, NULL, ARG_IMAGE               },
503
                { "image-policy",        required_argument, NULL, ARG_IMAGE_POLICY        },
504
                { "force",               no_argument,       NULL, 'f'                     },
505
                { "no-reload",           no_argument,       NULL, ARG_NO_RELOAD           },
506
                { "kill-whom",           required_argument, NULL, ARG_KILL_WHOM           },
507
                { "kill-value",          required_argument, NULL, ARG_KILL_VALUE          },
508
                { "signal",              required_argument, NULL, 's'                     },
509
                { "no-ask-password",     no_argument,       NULL, ARG_NO_ASK_PASSWORD     },
510
                { "host",                required_argument, NULL, 'H'                     },
511
                { "machine",             required_argument, NULL, 'M'                     },
512
                { "runtime",             no_argument,       NULL, ARG_RUNTIME             },
513
                { "lines",               required_argument, NULL, 'n'                     },
514
                { "output",              required_argument, NULL, 'o'                     },
515
                { "plain",               no_argument,       NULL, ARG_PLAIN               },
516
                { "state",               required_argument, NULL, ARG_STATE               },
517
                { "recursive",           no_argument,       NULL, 'r'                     },
518
                { "with-dependencies",   no_argument,       NULL, ARG_WITH_DEPENDENCIES   },
519
                { "preset-mode",         required_argument, NULL, ARG_PRESET_MODE         },
520
                { "firmware-setup",      no_argument,       NULL, ARG_FIRMWARE_SETUP      },
521
                { "boot-loader-menu",    required_argument, NULL, ARG_BOOT_LOADER_MENU    },
522
                { "boot-loader-entry",   required_argument, NULL, ARG_BOOT_LOADER_ENTRY   },
523
                { "now",                 no_argument,       NULL, ARG_NOW                 },
524
                { "message",             required_argument, NULL, ARG_MESSAGE             },
525
                { "show-transaction",    no_argument,       NULL, 'T'                     },
526
                { "what",                required_argument, NULL, ARG_WHAT                },
527
                { "reboot-argument",     required_argument, NULL, ARG_REBOOT_ARG          },
528
                { "timestamp",           required_argument, NULL, ARG_TIMESTAMP_STYLE     },
529
                { "read-only",           no_argument,       NULL, ARG_READ_ONLY           },
530
                { "mkdir",               no_argument,       NULL, ARG_MKDIR               },
531
                { "marked",              no_argument,       NULL, ARG_MARKED              },
532
                { "drop-in",             required_argument, NULL, ARG_DROP_IN             },
533
                { "when",                required_argument, NULL, ARG_WHEN                },
534
                { "stdin",               no_argument,       NULL, ARG_STDIN               },
535
                {}
536
        };
537

538
        int c, r;
11,265✔
539

540
        assert(argc >= 0);
11,265✔
541
        assert(argv);
11,265✔
542

543
        /* We default to allowing interactive authorization only in systemctl (not in the legacy commands) */
544
        arg_ask_password = true;
11,265✔
545

546
        while ((c = getopt_long(argc, argv, "hC:t:p:P:alqvfs:H:M:n:o:iTr.::", options, NULL)) >= 0)
35,829✔
547

548
                switch (c) {
13,309✔
549

UNCOV
550
                case 'h':
×
UNCOV
551
                        return systemctl_help();
×
552

553
                case ARG_VERSION:
7✔
554
                        return version();
7✔
555

556
                case 't':
53✔
557
                        if (isempty(optarg))
53✔
UNCOV
558
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
559
                                                       "--type= requires arguments.");
560

561
                        for (const char *p = optarg;;) {
53✔
562
                                _cleanup_free_ char *type = NULL;
56✔
563

564
                                r = extract_first_word(&p, &type, ",", 0);
108✔
565
                                if (r < 0)
108✔
566
                                        return log_error_errno(r, "Failed to parse type: %s", optarg);
×
567
                                if (r == 0)
108✔
568
                                        break;
569

570
                                if (streq(type, "help")) {
56✔
571
                                        help_types();
1✔
572
                                        return 0;
573
                                }
574

575
                                if (unit_type_from_string(type) >= 0) {
55✔
576
                                        if (strv_consume(&arg_types, TAKE_PTR(type)) < 0)
53✔
UNCOV
577
                                                return log_oom();
×
578
                                        continue;
53✔
579
                                }
580

581
                                /* It's much nicer to use --state= for load states, but let's support this in
582
                                 * --types= too for compatibility with old versions */
583
                                if (unit_load_state_from_string(type) >= 0) {
2✔
584
                                        if (strv_consume(&arg_states, TAKE_PTR(type)) < 0)
2✔
UNCOV
585
                                                return log_oom();
×
586
                                        continue;
2✔
587
                                }
588

UNCOV
589
                                log_error("Unknown unit type or load state '%s'.", type);
×
UNCOV
590
                                return log_info_errno(SYNTHETIC_ERRNO(EINVAL),
×
591
                                                      "Use -t help to see a list of allowed values.");
592
                        }
593

594
                        break;
52✔
595

596
                case 'P':
240✔
597
                        SET_FLAG(arg_print_flags, BUS_PRINT_PROPERTY_ONLY_VALUE, true);
240✔
598
                        _fallthrough_;
5,389✔
599

600
                case 'p':
5,389✔
601
                        /* Make sure that if the empty property list was specified, we won't show any
602
                           properties. */
603
                        if (isempty(optarg) && !arg_properties) {
5,390✔
604
                                arg_properties = new0(char*, 1);
1✔
605
                                if (!arg_properties)
1✔
606
                                        return log_oom();
×
607
                        } else
608
                                for (const char *p = optarg;;) {
5,388✔
609
                                        _cleanup_free_ char *prop = NULL;
10,786✔
610

611
                                        r = extract_first_word(&p, &prop, ",", 0);
10,786✔
612
                                        if (r < 0)
10,786✔
UNCOV
613
                                                return log_error_errno(r, "Failed to parse property: %s", optarg);
×
614
                                        if (r == 0)
10,786✔
615
                                                break;
616

617
                                        if (strv_consume(&arg_properties, TAKE_PTR(prop)) < 0)
5,398✔
UNCOV
618
                                                return log_oom();
×
619
                                }
620

621
                        /* If the user asked for a particular property, show it, even if it is empty. */
622
                        SET_FLAG(arg_print_flags, BUS_PRINT_PROPERTY_SHOW_EMPTY, true);
5,389✔
623

624
                        break;
5,389✔
625

626
                case 'a':
54✔
627
                        SET_FLAG(arg_print_flags, BUS_PRINT_PROPERTY_SHOW_EMPTY, true);
54✔
628
                        arg_all = true;
54✔
629
                        break;
54✔
630

631
                case ARG_REVERSE:
3✔
632
                        arg_dependency = DEPENDENCY_REVERSE;
3✔
633
                        break;
3✔
634

635
                case ARG_AFTER:
5✔
636
                        arg_dependency = DEPENDENCY_AFTER;
5✔
637
                        arg_jobs_after = true;
5✔
638
                        break;
5✔
639

640
                case ARG_BEFORE:
5✔
641
                        arg_dependency = DEPENDENCY_BEFORE;
5✔
642
                        arg_jobs_before = true;
5✔
643
                        break;
5✔
644

645
                case ARG_SHOW_TYPES:
1✔
646
                        arg_show_types = true;
1✔
647
                        break;
1✔
648

649
                case ARG_VALUE:
5,043✔
650
                        SET_FLAG(arg_print_flags, BUS_PRINT_PROPERTY_ONLY_VALUE, true);
5,043✔
651
                        break;
5,043✔
652

653
                case ARG_JOB_MODE:
16✔
654
                        _arg_job_mode = optarg;
16✔
655
                        break;
16✔
656

UNCOV
657
                case ARG_FAIL:
×
UNCOV
658
                        _arg_job_mode = "fail";
×
UNCOV
659
                        break;
×
660

UNCOV
661
                case ARG_IRREVERSIBLE:
×
UNCOV
662
                        _arg_job_mode = "replace-irreversibly";
×
UNCOV
663
                        break;
×
664

UNCOV
665
                case ARG_IGNORE_DEPENDENCIES:
×
UNCOV
666
                        _arg_job_mode = "ignore-dependencies";
×
UNCOV
667
                        break;
×
668

669
                case ARG_USER:
200✔
670
                        arg_runtime_scope = RUNTIME_SCOPE_USER;
200✔
671
                        break;
200✔
672

673
                case ARG_SYSTEM:
×
674
                        arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
×
675
                        break;
×
676

677
                case ARG_GLOBAL:
×
678
                        arg_runtime_scope = RUNTIME_SCOPE_GLOBAL;
×
679
                        break;
×
680

681
                case 'C':
3✔
682
                        r = capsule_name_is_valid(optarg);
3✔
683
                        if (r < 0)
3✔
UNCOV
684
                                return log_error_errno(r, "Unable to validate capsule name '%s': %m", optarg);
×
685
                        if (r == 0)
3✔
UNCOV
686
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid capsule name: %s", optarg);
×
687

688
                        arg_host = optarg;
3✔
689
                        arg_transport = BUS_TRANSPORT_CAPSULE;
3✔
690
                        arg_runtime_scope = RUNTIME_SCOPE_USER;
3✔
691
                        break;
3✔
692

693
                case ARG_WAIT:
14✔
694
                        arg_wait = true;
14✔
695
                        break;
14✔
696

697
                case ARG_NO_BLOCK:
110✔
698
                        arg_no_block = true;
110✔
699
                        break;
110✔
700

701
                case ARG_NO_LEGEND:
54✔
702
                        arg_legend = false;
54✔
703
                        break;
54✔
704

705
                case ARG_LEGEND:
3✔
706
                        r = parse_boolean_argument("--legend", optarg, NULL);
3✔
707
                        if (r < 0)
3✔
708
                                return r;
709
                        arg_legend = r;
3✔
710
                        break;
3✔
711

712
                case ARG_NO_PAGER:
7✔
713
                        arg_pager_flags |= PAGER_DISABLE;
7✔
714
                        break;
7✔
715

716
                case ARG_NO_WALL:
3✔
717
                        arg_no_wall = true;
3✔
718
                        break;
3✔
719

720
                case ARG_ROOT:
41✔
721
                        r = parse_path_argument(optarg, false, &arg_root);
41✔
722
                        if (r < 0)
41✔
723
                                return r;
724
                        break;
725

UNCOV
726
                case ARG_IMAGE:
×
UNCOV
727
                        r = parse_path_argument(optarg, false, &arg_image);
×
UNCOV
728
                        if (r < 0)
×
729
                                return r;
730
                        break;
731

UNCOV
732
                case ARG_IMAGE_POLICY:
×
UNCOV
733
                        r = parse_image_policy_argument(optarg, &arg_image_policy);
×
UNCOV
734
                        if (r < 0)
×
735
                                return r;
736
                        break;
737

738
                case 'l':
5✔
739
                        arg_full = true;
5✔
740
                        break;
5✔
741

742
                case ARG_FAILED:
743
                        if (strv_extend(&arg_states, "failed") < 0)
1✔
744
                                return log_oom();
×
745

746
                        break;
747

748
                case ARG_DRY_RUN:
23✔
749
                        arg_dry_run = true;
23✔
750
                        break;
23✔
751

752
                case 'q':
2,079✔
753
                        arg_quiet = true;
2,079✔
754

755
                        if (arg_legend < 0)
2,079✔
756
                                arg_legend = false;
2,079✔
757

758
                        break;
759

760
                case 'v':
×
UNCOV
761
                        arg_verbose = true;
×
UNCOV
762
                        break;
×
763

764
                case 'f':
13✔
765
                        arg_force++;
13✔
766
                        break;
13✔
767

UNCOV
768
                case ARG_NO_RELOAD:
×
UNCOV
769
                        arg_no_reload = true;
×
UNCOV
770
                        break;
×
771

772
                case ARG_KILL_WHOM:
9✔
773
                        arg_kill_whom = optarg;
9✔
774
                        break;
9✔
775

776
                case ARG_KILL_VALUE: {
6✔
777
                        unsigned u;
6✔
778

779
                        if (isempty(optarg)) {
6✔
UNCOV
780
                                arg_kill_value_set = false;
×
UNCOV
781
                                return 0;
×
782
                        }
783

784
                        /* First, try to parse unsigned, so that we can support the prefixes 0x, 0o, 0b */
785
                        r = safe_atou_full(optarg, 0, &u);
6✔
786
                        if (r < 0)
6✔
787
                                /* If this didn't work, try as signed integer, without those prefixes */
UNCOV
788
                                r = safe_atoi(optarg, &arg_kill_value);
×
789
                        else if (u > INT_MAX)
6✔
790
                                r = -ERANGE;
791
                        else
792
                                arg_kill_value = (int) u;
6✔
793
                        if (r < 0)
6✔
UNCOV
794
                                return log_error_errno(r, "Unable to parse signal queue value: %s", optarg);
×
795

796
                        arg_kill_value_set = true;
6✔
797
                        break;
6✔
798
                }
799

800
                case 's':
22✔
801
                        r = parse_signal_argument(optarg, &arg_signal);
22✔
802
                        if (r <= 0)
22✔
803
                                return r;
804
                        break;
805

UNCOV
806
                case ARG_NO_ASK_PASSWORD:
×
UNCOV
807
                        arg_ask_password = false;
×
UNCOV
808
                        break;
×
809

810
                case 'H':
×
UNCOV
811
                        arg_transport = BUS_TRANSPORT_REMOTE;
×
UNCOV
812
                        arg_host = optarg;
×
UNCOV
813
                        break;
×
814

815
                case 'M':
21✔
816
                        arg_transport = BUS_TRANSPORT_MACHINE;
21✔
817
                        arg_host = optarg;
21✔
818
                        break;
21✔
819

820
                case ARG_RUNTIME:
16✔
821
                        arg_runtime = true;
16✔
822
                        break;
16✔
823

824
                case 'n':
9✔
825
                        if (safe_atou(optarg, &arg_lines) < 0)
9✔
826
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
827
                                                       "Failed to parse lines '%s'",
828
                                                       optarg);
829
                        break;
830

831
                case 'o':
1✔
832
                        if (streq(optarg, "help")) {
1✔
UNCOV
833
                                DUMP_STRING_TABLE(output_mode, OutputMode, _OUTPUT_MODE_MAX);
×
UNCOV
834
                                return 0;
×
835
                        }
836

837
                        arg_output = output_mode_from_string(optarg);
1✔
838
                        if (arg_output < 0)
1✔
UNCOV
839
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
840
                                                       "Unknown output '%s'.",
841
                                                       optarg);
842

843
                        if (OUTPUT_MODE_IS_JSON(arg_output)) {
24,565✔
844
                                arg_legend = false;
1✔
845
                                arg_plain = true;
1✔
846
                        }
847
                        break;
848

849
                case 'i':
×
850
                        arg_check_inhibitors = 0;
×
UNCOV
851
                        break;
×
852

UNCOV
853
                case ARG_CHECK_INHIBITORS:
×
UNCOV
854
                        r = parse_tristate_full(optarg, "auto", &arg_check_inhibitors);
×
855
                        if (r < 0)
×
UNCOV
856
                                return log_error_errno(r, "Failed to parse --check-inhibitors= argument: %s", optarg);
×
857
                        break;
858

859
                case ARG_PLAIN:
1✔
860
                        arg_plain = true;
1✔
861
                        break;
1✔
862

UNCOV
863
                case ARG_FIRMWARE_SETUP:
×
UNCOV
864
                        arg_firmware_setup = true;
×
865
                        break;
×
866

867
                case ARG_BOOT_LOADER_MENU:
×
868

869
                        r = parse_sec(optarg, &arg_boot_loader_menu);
×
870
                        if (r < 0)
×
871
                                return log_error_errno(r, "Failed to parse --boot-loader-menu= argument '%s': %m", optarg);
×
872

873
                        break;
874

UNCOV
875
                case ARG_BOOT_LOADER_ENTRY:
×
876

UNCOV
877
                        if (streq(optarg, "help")) { /* Yes, this means, "help" is not a valid boot loader entry name we can deal with */
×
UNCOV
878
                                r = help_boot_loader_entry();
×
879
                                if (r < 0)
×
880
                                        return r;
881

UNCOV
882
                                return 0;
×
883
                        }
884

885
                        arg_boot_loader_entry = empty_to_null(optarg);
×
886
                        break;
×
887

888
                case ARG_STATE:
10✔
889
                        if (isempty(optarg))
10✔
UNCOV
890
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
891
                                                       "--state= requires arguments.");
892

893
                        for (const char *p = optarg;;) {
10✔
894
                                _cleanup_free_ char *s = NULL;
12✔
895

896
                                r = extract_first_word(&p, &s, ",", 0);
21✔
897
                                if (r < 0)
21✔
898
                                        return log_error_errno(r, "Failed to parse state: %s", optarg);
×
899
                                if (r == 0)
21✔
900
                                        break;
901

902
                                if (streq(s, "help")) {
12✔
903
                                        help_states();
1✔
904
                                        return 0;
905
                                }
906

907
                                if (strv_consume(&arg_states, TAKE_PTR(s)) < 0)
11✔
UNCOV
908
                                        return log_oom();
×
909
                        }
910
                        break;
9✔
911

912
                case 'r':
1✔
913
                        if (geteuid() != 0)
1✔
914
                                return log_error_errno(SYNTHETIC_ERRNO(EPERM),
×
915
                                                       "--recursive requires root privileges.");
916

917
                        arg_recursive = true;
1✔
918
                        break;
1✔
919

920
                case ARG_PRESET_MODE:
4✔
921
                        if (streq(optarg, "help")) {
4✔
UNCOV
922
                                DUMP_STRING_TABLE(unit_file_preset_mode, UnitFilePresetMode, _UNIT_FILE_PRESET_MODE_MAX);
×
UNCOV
923
                                return 0;
×
924
                        }
925

926
                        arg_preset_mode = unit_file_preset_mode_from_string(optarg);
4✔
927
                        if (arg_preset_mode < 0)
4✔
UNCOV
928
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
929
                                                       "Failed to parse preset mode: %s.", optarg);
930

931
                        break;
932

933
                case ARG_NOW:
8✔
934
                        arg_now = true;
8✔
935
                        break;
8✔
936

937
                case ARG_MESSAGE:
3✔
938
                        if (strv_extend(&arg_wall, optarg) < 0)
3✔
939
                                return log_oom();
×
940
                        break;
941

942
                case 'T':
10✔
943
                        arg_show_transaction = true;
10✔
944
                        break;
10✔
945

946
                case ARG_WITH_DEPENDENCIES:
3✔
947
                        arg_with_dependencies = true;
3✔
948
                        break;
3✔
949

950
                case ARG_WHAT:
20✔
951
                        if (isempty(optarg))
20✔
UNCOV
952
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--what= requires arguments (see --what=help).");
×
953

954
                        for (const char *p = optarg;;) {
20✔
955
                                _cleanup_free_ char *k = NULL;
20✔
956

957
                                r = extract_first_word(&p, &k, ",", 0);
40✔
958
                                if (r < 0)
40✔
UNCOV
959
                                        return log_error_errno(r, "Failed to parse directory type: %s", optarg);
×
960
                                if (r == 0)
40✔
961
                                        break;
962

963
                                if (streq(k, "help")) {
20✔
UNCOV
964
                                        puts("runtime\n"
×
965
                                             "state\n"
966
                                             "cache\n"
967
                                             "logs\n"
968
                                             "configuration\n"
969
                                             "fdstore\n"
970
                                             "all");
971
                                        return 0;
972
                                }
973

974
                                r = strv_consume(&arg_clean_what, TAKE_PTR(k));
20✔
975
                                if (r < 0)
20✔
UNCOV
976
                                        return log_oom();
×
977
                        }
978

979
                        break;
20✔
980

UNCOV
981
                case ARG_REBOOT_ARG:
×
UNCOV
982
                        arg_reboot_argument = optarg;
×
UNCOV
983
                        break;
×
984

985
                case ARG_TIMESTAMP_STYLE:
6✔
986
                        if (streq(optarg, "help")) {
6✔
UNCOV
987
                                DUMP_STRING_TABLE(timestamp_style, TimestampStyle, _TIMESTAMP_STYLE_MAX);
×
UNCOV
988
                                return 0;
×
989
                        }
990

991
                        arg_timestamp_style = timestamp_style_from_string(optarg);
6✔
992
                        if (arg_timestamp_style < 0)
6✔
UNCOV
993
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
994
                                                       "Invalid value: %s.", optarg);
995

996
                        break;
997

998
                case ARG_READ_ONLY:
×
999
                        arg_read_only = true;
×
UNCOV
1000
                        break;
×
1001

1002
                case ARG_MKDIR:
6✔
1003
                        arg_mkdir = true;
6✔
1004
                        break;
6✔
1005

1006
                case ARG_MARKED:
1✔
1007
                        arg_marked = true;
1✔
1008
                        break;
1✔
1009

UNCOV
1010
                case ARG_NO_WARN:
×
UNCOV
1011
                        arg_no_warn = true;
×
UNCOV
1012
                        break;
×
1013

1014
                case ARG_DROP_IN:
9✔
1015
                        arg_drop_in = optarg;
9✔
1016
                        break;
9✔
1017

UNCOV
1018
                case ARG_WHEN:
×
UNCOV
1019
                        if (streq(optarg, "show")) {
×
UNCOV
1020
                                arg_action = ACTION_SYSTEMCTL_SHOW_SHUTDOWN;
×
UNCOV
1021
                                return 1;
×
1022
                        }
1023

UNCOV
1024
                        if (STR_IN_SET(optarg, "", "cancel")) {
×
UNCOV
1025
                                arg_action = ACTION_CANCEL_SHUTDOWN;
×
1026
                                return 1;
×
1027
                        }
1028

UNCOV
1029
                        if (streq(optarg, "auto")) {
×
UNCOV
1030
                                arg_when = USEC_INFINITY; /* logind chooses on server side */
×
UNCOV
1031
                                break;
×
1032
                        }
1033

1034
                        r = parse_timestamp(optarg, &arg_when);
×
1035
                        if (r < 0)
×
1036
                                return log_error_errno(r, "Failed to parse --when= argument '%s': %m", optarg);
×
1037

UNCOV
1038
                        if (!timestamp_is_set(arg_when))
×
UNCOV
1039
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1040
                                                       "Invalid timestamp '%s' specified for --when=.", optarg);
1041

1042
                        break;
1043

1044
                case ARG_STDIN:
11✔
1045
                        arg_stdin = true;
11✔
1046
                        break;
11✔
1047

1048
                case '.':
1049
                        /* Output an error mimicking getopt, and print a hint afterwards */
1050
                        log_error("%s: invalid option -- '.'", program_invocation_name);
×
1051
                        log_notice("Hint: to specify units starting with a dash, use \"--\":\n"
×
1052
                                   "      %s [OPTIONS...] COMMAND -- -.%s ...",
1053
                                   program_invocation_name, optarg ?: "mount");
1054
                        _fallthrough_;
1055

1056
                case '?':
1057
                        return -EINVAL;
1058

UNCOV
1059
                default:
×
UNCOV
1060
                        assert_not_reached();
×
1061
                }
1062

1063
        /* If we are in --user mode, there's no point in talking to PolicyKit or the infra to query system
1064
         * passwords */
1065
        if (arg_runtime_scope != RUNTIME_SCOPE_SYSTEM)
11,255✔
1066
                arg_ask_password = false;
203✔
1067

1068
        if (arg_transport == BUS_TRANSPORT_REMOTE && arg_runtime_scope != RUNTIME_SCOPE_SYSTEM)
11,255✔
UNCOV
1069
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1070
                                       "Cannot access user instance remotely.");
1071

1072
        if (arg_transport == BUS_TRANSPORT_CAPSULE && arg_runtime_scope != RUNTIME_SCOPE_USER)
11,255✔
UNCOV
1073
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1074
                                       "Cannot access system instance with --capsule=/-C.");
1075

1076
        if (arg_wait && arg_no_block)
11,255✔
UNCOV
1077
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1078
                                       "--wait may not be combined with --no-block.");
1079

1080
        bool do_reload_or_restart = streq_ptr(argv[optind], "reload-or-restart");
11,255✔
1081
        if (arg_marked) {
11,255✔
1082
                if (!do_reload_or_restart)
1✔
UNCOV
1083
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1084
                                               "--marked may only be used with 'reload-or-restart'.");
1085
                if (optind + 1 < argc)
1✔
UNCOV
1086
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1087
                                               "No additional arguments allowed with 'reload-or-restart --marked'.");
1088
                if (arg_wait)
1✔
1089
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1090
                                               "--marked --wait is not supported.");
1091
                if (arg_show_transaction)
1✔
UNCOV
1092
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1093
                                               "--marked --show-transaction is not supported.");
1094

1095
        } else if (do_reload_or_restart) {
11,254✔
UNCOV
1096
                if (optind + 1 >= argc)
×
UNCOV
1097
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1098
                                               "List of units to restart/reload is required.");
1099
        }
1100

1101
        if (arg_image && arg_root)
11,255✔
1102
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1103
                                       "Please specify either --root= or --image=, the combination of both is not supported.");
1104

1105
        return 1;
1106
}
1107

1108
int systemctl_dispatch_parse_argv(int argc, char *argv[]) {
11,277✔
1109
        assert(argc >= 0);
11,277✔
1110
        assert(argv);
11,277✔
1111

1112
        if (invoked_as(argv, "halt")) {
11,277✔
1113
                arg_action = ACTION_HALT;
×
UNCOV
1114
                return halt_parse_argv(argc, argv);
×
1115

1116
        } else if (invoked_as(argv, "poweroff")) {
11,277✔
UNCOV
1117
                arg_action = ACTION_POWEROFF;
×
1118
                return halt_parse_argv(argc, argv);
×
1119

1120
        } else if (invoked_as(argv, "reboot")) {
11,277✔
1121
                arg_action = ACTION_REBOOT;
5✔
1122
                return halt_parse_argv(argc, argv);
5✔
1123

1124
        } else if (invoked_as(argv, "shutdown")) {
11,272✔
1125
                arg_action = ACTION_POWEROFF;
7✔
1126
                return shutdown_parse_argv(argc, argv);
7✔
1127

1128
        } else if (invoked_as(argv, "init")) {
11,265✔
1129

1130
                /* Matches invocations as "init" as well as "telinit", which are synonymous when run
1131
                 * as PID != 1 on SysV.
1132
                 *
1133
                 * On SysV "telinit" was the official command to communicate with PID 1, but "init" would
1134
                 * redirect itself to "telinit" if called with PID != 1. We follow the same logic here still,
1135
                 * though we add one level of indirection, as we implement "telinit" in "systemctl". Hence,
1136
                 * for us if you invoke "init" you get "systemd", but it will execve() "systemctl"
1137
                 * immediately with argv[] unmodified if PID is != 1. If you invoke "telinit" you directly
1138
                 * get "systemctl". In both cases we shall do the same thing, which is why we do
1139
                 * invoked_as(argv, "init") here, as a quick way to match both.
1140
                 *
1141
                 * Also see redirect_telinit() in src/core/main.c. */
1142

UNCOV
1143
                arg_action = _ACTION_INVALID; /* telinit_parse_argv() will figure out the actual action we'll execute */
×
UNCOV
1144
                return telinit_parse_argv(argc, argv);
×
1145

1146
        } else if (invoked_as(argv, "runlevel")) {
11,265✔
UNCOV
1147
                arg_action = ACTION_RUNLEVEL;
×
UNCOV
1148
                return runlevel_parse_argv(argc, argv);
×
1149
        }
1150

1151
        arg_action = ACTION_SYSTEMCTL;
11,265✔
1152
        return systemctl_parse_argv(argc, argv);
11,265✔
1153
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc