]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl.c
tree-wide: use TAKE_PTR() and TAKE_FD() macros
[thirdparty/systemd.git] / src / systemctl / systemctl.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
7e4249b9
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
f459b602 6 Copyright 2013 Marc-Antoine Perennou
7e4249b9
LP
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
7e4249b9
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
7e4249b9 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
7e4249b9
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
03a7b521
LP
22#include <errno.h>
23#include <fcntl.h>
7e4249b9 24#include <getopt.h>
a9cdc94f 25#include <locale.h>
7e4249b9 26#include <stdbool.h>
03a7b521
LP
27#include <stddef.h>
28#include <stdio.h>
7e4249b9 29#include <string.h>
4bb2e9d4 30#include <sys/prctl.h>
03a7b521 31#include <sys/reboot.h>
f1c5860b 32#include <sys/socket.h>
03a7b521 33#include <unistd.h>
81527be1 34
03a7b521 35#include "sd-bus.h"
f459b602 36#include "sd-daemon.h"
f459b602 37#include "sd-login.h"
03a7b521 38
b5efdb8a 39#include "alloc-util.h"
4bb2e9d4 40#include "bootspec.h"
03a7b521
LP
41#include "bus-common-errors.h"
42#include "bus-error.h"
43#include "bus-message.h"
291d565a 44#include "bus-unit-util.h"
03a7b521 45#include "bus-util.h"
ab35fb1b 46#include "cgroup-show.h"
c6c18be3 47#include "cgroup-util.h"
cda134ab 48#include "copy.h"
ad2a0358 49#include "dropin.h"
5bdf2243 50#include "efivars.h"
03a7b521 51#include "env-util.h"
804ee07c 52#include "escape.h"
03a7b521 53#include "exit-status.h"
3ffd4af2 54#include "fd-util.h"
03a7b521 55#include "fileio.h"
f97b34a6 56#include "format-util.h"
f4f15635 57#include "fs-util.h"
7d50b32a 58#include "glob-util.h"
08f3be7a 59#include "hexdecoct.h"
c52a937b 60#include "hostname-util.h"
03a7b521
LP
61#include "initreq.h"
62#include "install.h"
c004493c 63#include "io-util.h"
03a7b521 64#include "list.h"
8752c575 65#include "locale-util.h"
03a7b521
LP
66#include "log.h"
67#include "logs-show.h"
68#include "macro.h"
69#include "mkdir.h"
70#include "pager.h"
6bedfcbb 71#include "parse-util.h"
03a7b521
LP
72#include "path-lookup.h"
73#include "path-util.h"
74#include "process-util.h"
e3631d1c 75#include "reboot-util.h"
78f22b97 76#include "rlimit-util.h"
03a7b521 77#include "set.h"
592705f2 78#include "sigbus.h"
24882e06 79#include "signal-util.h"
03a7b521
LP
80#include "socket-util.h"
81#include "spawn-ask-password-agent.h"
82#include "spawn-polkit-agent.h"
83#include "special.h"
8fcde012 84#include "stat-util.h"
8559e61d 85#include "string-table.h"
03a7b521
LP
86#include "strv.h"
87#include "terminal-util.h"
89ada3ba 88#include "unit-def.h"
03a7b521 89#include "unit-name.h"
b1d4f8e1 90#include "user-util.h"
03a7b521
LP
91#include "util.h"
92#include "utmp-wtmp.h"
e449de87 93#include "verbs.h"
7f4b3c5e 94#include "virt.h"
7e4249b9 95
b613907e
SS
96/* The init script exit status codes
97 0 program is running or service is OK
98 1 program is dead and /var/run pid file exists
99 2 program is dead and /var/lock lock file exists
100 3 program is not running
101 4 program or service status is unknown
102 5-99 reserved for future LSB use
103 100-149 reserved for distribution use
104 150-199 reserved for application use
105 200-254 reserved
106*/
107enum {
108 EXIT_PROGRAM_RUNNING_OR_SERVICE_OK = 0,
109 EXIT_PROGRAM_DEAD_AND_PID_EXISTS = 1,
110 EXIT_PROGRAM_DEAD_AND_LOCK_FILE_EXISTS = 2,
111 EXIT_PROGRAM_NOT_RUNNING = 3,
112 EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN = 4,
113};
114
20b3f379 115static char **arg_types = NULL;
9b9b3d36 116static char **arg_states = NULL;
20b3f379 117static char **arg_properties = NULL;
7e4249b9 118static bool arg_all = false;
afba4199
ZJS
119static enum dependency {
120 DEPENDENCY_FORWARD,
121 DEPENDENCY_REVERSE,
122 DEPENDENCY_AFTER,
123 DEPENDENCY_BEFORE,
071066a5 124 _DEPENDENCY_MAX
afba4199 125} arg_dependency = DEPENDENCY_FORWARD;
e67c3609 126static const char *arg_job_mode = "replace";
729e3769 127static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
93a08841 128static bool arg_wait = false;
ee5762e3 129static bool arg_no_block = false;
ebed32bf 130static bool arg_no_legend = false;
0736af98 131static bool arg_no_pager = false;
e4b61340 132static bool arg_no_wtmp = false;
f3f054f0 133static bool arg_no_sync = false;
514f4ef5 134static bool arg_no_wall = false;
ee5762e3 135static bool arg_no_reload = false;
4f9a9105 136static bool arg_value = false;
991f2a39 137static bool arg_show_types = false;
b37844d3 138static bool arg_ignore_inhibitors = false;
1ae17672 139static bool arg_dry_run = false;
0183528f 140static bool arg_quiet = false;
ee5762e3 141static bool arg_full = false;
1238ee09 142static bool arg_recursive = false;
e606bb61 143static int arg_force = 0;
16f017fa 144static bool arg_ask_password = false;
729e3769 145static bool arg_runtime = false;
d309c1c3 146static UnitFilePresetMode arg_preset_mode = UNIT_FILE_PRESET_FULL;
e4b61340 147static char **arg_wall = NULL;
8a0867d6 148static const char *arg_kill_who = NULL;
8a0867d6 149static int arg_signal = SIGTERM;
0f03c2a4 150static char *arg_root = NULL;
f6144808 151static usec_t arg_when = 0;
4bb2e9d4 152static char *arg_esp_path = NULL;
acc28e2e 153static char *argv_cmdline = NULL;
4445a875 154static enum action {
e4b61340
LP
155 ACTION_SYSTEMCTL,
156 ACTION_HALT,
157 ACTION_POWEROFF,
158 ACTION_REBOOT,
20b09ca7
LP
159 ACTION_KEXEC,
160 ACTION_EXIT,
6edd7d0a
LP
161 ACTION_SUSPEND,
162 ACTION_HIBERNATE,
6524990f 163 ACTION_HYBRID_SLEEP,
e68c79db 164 ACTION_SUSPEND_THEN_HIBERNATE,
e4b61340
LP
165 ACTION_RUNLEVEL2,
166 ACTION_RUNLEVEL3,
167 ACTION_RUNLEVEL4,
168 ACTION_RUNLEVEL5,
169 ACTION_RESCUE,
514f4ef5
LP
170 ACTION_EMERGENCY,
171 ACTION_DEFAULT,
e4b61340
LP
172 ACTION_RELOAD,
173 ACTION_REEXEC,
174 ACTION_RUNLEVEL,
f6144808 175 ACTION_CANCEL_SHUTDOWN,
913c1916
AJ
176 _ACTION_MAX,
177 _ACTION_INVALID = -1
e4b61340 178} arg_action = ACTION_SYSTEMCTL;
f459b602 179static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
fc2ffaf1 180static const char *arg_host = NULL;
df50185b
LP
181static unsigned arg_lines = 10;
182static OutputMode arg_output = OUTPUT_SHORT;
5d0c05e5 183static bool arg_plain = false;
5bdf2243 184static bool arg_firmware_setup = false;
57ab2eab 185static bool arg_now = false;
82948f6c
LP
186static bool arg_jobs_before = false;
187static bool arg_jobs_after = false;
1238ee09 188
e449de87 189static int daemon_reload(int argc, char *argv[], void* userdata);
2853b60a 190static int trivial_method(int argc, char *argv[], void *userdata);
477def80 191static int halt_now(enum action a);
fa0d5878 192static int get_state_one_unit(sd_bus *bus, const char *name, UnitActiveState *active_state);
dbc2c080 193
4fbd7192
LP
194static bool original_stdout_is_tty;
195
196typedef enum BusFocus {
197 BUS_FULL, /* The full bus indicated via --system or --user */
198 BUS_MANAGER, /* The manager itself, possibly directly, possibly via the bus */
199 _BUS_FOCUS_MAX
200} BusFocus;
201
202static sd_bus *busses[_BUS_FOCUS_MAX] = {};
203
b3796dd8
JS
204static UnitFileFlags args_to_flags(void) {
205 return (arg_runtime ? UNIT_FILE_RUNTIME : 0) |
206 (arg_force ? UNIT_FILE_FORCE : 0);
207}
208
4fbd7192
LP
209static int acquire_bus(BusFocus focus, sd_bus **ret) {
210 int r;
211
212 assert(focus < _BUS_FOCUS_MAX);
213 assert(ret);
214
215 /* We only go directly to the manager, if we are using a local transport */
216 if (arg_transport != BUS_TRANSPORT_LOCAL)
217 focus = BUS_FULL;
218
d4015567
LP
219 if (getenv_bool("SYSTEMCTL_FORCE_BUS") > 0)
220 focus = BUS_FULL;
221
4fbd7192
LP
222 if (!busses[focus]) {
223 bool user;
224
225 user = arg_scope != UNIT_FILE_SYSTEM;
226
861f16d2
LP
227 if (!user && sd_booted() <= 0) {
228 /* Print a friendly message when the local system is actually not running systemd as PID 1. */
229 log_error("System has not been booted with systemd as init system (PID 1). Can't operate.");
230 return -EHOSTDOWN;
231 }
232
4fbd7192
LP
233 if (focus == BUS_MANAGER)
234 r = bus_connect_transport_systemd(arg_transport, arg_host, user, &busses[focus]);
235 else
236 r = bus_connect_transport(arg_transport, arg_host, user, &busses[focus]);
237 if (r < 0)
238 return log_error_errno(r, "Failed to connect to bus: %m");
239
240 (void) sd_bus_set_allow_interactive_authorization(busses[focus], arg_ask_password);
241 }
242
243 *ret = busses[focus];
244 return 0;
245}
246
247static void release_busses(void) {
248 BusFocus w;
249
250 for (w = 0; w < _BUS_FOCUS_MAX; w++)
251 busses[w] = sd_bus_flush_close_unref(busses[w]);
252}
253
6bb92a16 254static void ask_password_agent_open_if_enabled(void) {
501fc174 255
729e3769 256 /* Open the password agent as a child process if necessary */
501fc174 257
1ae17672
ZJS
258 if (arg_dry_run)
259 return;
260
501fc174
LP
261 if (!arg_ask_password)
262 return;
715554e7 263
729e3769 264 if (arg_scope != UNIT_FILE_SYSTEM)
501fc174
LP
265 return;
266
cbc9fbd1
LP
267 if (arg_transport != BUS_TRANSPORT_LOCAL)
268 return;
269
6bb92a16
LP
270 ask_password_agent_open();
271}
272
8a4b13c5 273static void polkit_agent_open_maybe(void) {
6bb92a16
LP
274 /* Open the polkit agent as a child process if necessary */
275
6bb92a16
LP
276 if (arg_scope != UNIT_FILE_SYSTEM)
277 return;
278
8a4b13c5 279 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
501fc174
LP
280}
281
3c756001
LP
282static OutputFlags get_output_flags(void) {
283 return
284 arg_all * OUTPUT_SHOW_ALL |
459b9f9f 285 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
40c9fe4c 286 colors_enabled() * OUTPUT_COLOR |
8b0cc9a3 287 !arg_quiet * OUTPUT_WARN_CUTOFF;
3c756001
LP
288}
289
f459b602 290static int translate_bus_error_to_exit_status(int r, const sd_bus_error *error) {
22f4096c
LP
291 assert(error);
292
f459b602 293 if (!sd_bus_error_is_set(error))
22f4096c
LP
294 return r;
295
f459b602
MAP
296 if (sd_bus_error_has_name(error, SD_BUS_ERROR_ACCESS_DENIED) ||
297 sd_bus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) ||
298 sd_bus_error_has_name(error, BUS_ERROR_NO_ISOLATION) ||
299 sd_bus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
22f4096c
LP
300 return EXIT_NOPERMISSION;
301
f459b602 302 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
22f4096c
LP
303 return EXIT_NOTINSTALLED;
304
f459b602 305 if (sd_bus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) ||
718db961 306 sd_bus_error_has_name(error, SD_BUS_ERROR_NOT_SUPPORTED))
22f4096c
LP
307 return EXIT_NOTIMPLEMENTED;
308
f459b602 309 if (sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
22f4096c
LP
310 return EXIT_NOTCONFIGURED;
311
312 if (r != 0)
313 return r;
314
315 return EXIT_FAILURE;
316}
317
4fbd7192 318static bool install_client_side(void) {
729e3769 319
4fbd7192
LP
320 /* Decides when to execute enable/disable/... operations
321 * client-side rather than server-side. */
4f16c1f4 322
f38951a6 323 if (running_in_chroot_or_offline())
729e3769
LP
324 return true;
325
326 if (sd_booted() <= 0)
327 return true;
328
329 if (!isempty(arg_root))
330 return true;
331
332 if (arg_scope == UNIT_FILE_GLOBAL)
333 return true;
334
b41b9d2a
LP
335 /* Unsupported environment variable, mostly for debugging purposes */
336 if (getenv_bool("SYSTEMCTL_INSTALL_CLIENT_SIDE") > 0)
337 return true;
338
729e3769
LP
339 return false;
340}
341
36c32ba2 342static int compare_unit_info(const void *a, const void *b) {
f459b602 343 const UnitInfo *u = a, *v = b;
36c32ba2 344 const char *d1, *d2;
1238ee09
LP
345 int r;
346
347 /* First, order by machine */
348 if (!u->machine && v->machine)
349 return -1;
350 if (u->machine && !v->machine)
351 return 1;
352 if (u->machine && v->machine) {
353 r = strcasecmp(u->machine, v->machine);
354 if (r != 0)
355 return r;
356 }
36c32ba2 357
1238ee09 358 /* Second, order by unit type */
36c32ba2
LP
359 d1 = strrchr(u->id, '.');
360 d2 = strrchr(v->id, '.');
36c32ba2 361 if (d1 && d2) {
f84190d8
LP
362 r = strcasecmp(d1, d2);
363 if (r != 0)
36c32ba2
LP
364 return r;
365 }
366
1238ee09 367 /* Third, order by name */
a2a3a5b9 368 return strcasecmp(u->id, v->id);
36c32ba2
LP
369}
370
16484a8a
ZJS
371static const char* unit_type_suffix(const char *name) {
372 const char *dot;
373
374 dot = strrchr(name, '.');
375 if (!dot)
376 return "";
377
378 return dot + 1;
379}
380
d8fba7c6 381static bool output_show_unit(const UnitInfo *u, char **patterns) {
f8591ee1
LP
382 assert(u);
383
2404701e 384 if (!strv_fnmatch_or_empty(patterns, u->id, FNM_NOESCAPE))
d8fba7c6 385 return false;
d8fba7c6 386
16484a8a
ZJS
387 if (arg_types && !strv_find(arg_types, unit_type_suffix(u->id)))
388 return false;
6c71341a
ZJS
389
390 if (arg_all)
391 return true;
392
409472cb
FB
393 /* Note that '--all' is not purely a state filter, but also a
394 * filter that hides units that "follow" other units (which is
395 * used for device units that appear under different names). */
396 if (!isempty(u->following))
397 return false;
398
ebc96265
FB
399 if (!strv_isempty(arg_states))
400 return true;
401
402 /* By default show all units except the ones in inactive
403 * state and with no pending job */
6c71341a
ZJS
404 if (u->job_id > 0)
405 return true;
406
409472cb 407 if (streq(u->active_state, "inactive"))
6c71341a
ZJS
408 return false;
409
410 return true;
33330222
ZJS
411}
412
1238ee09 413static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
b5d7f1bb 414 unsigned circle_len = 0, id_len, max_id_len, load_len, active_len, sub_len, job_len, desc_len, max_desc_len;
f459b602 415 const UnitInfo *u;
a1074881 416 unsigned n_shown = 0;
b5d7f1bb 417 int job_count = 0;
33330222 418
fbd0b64f
LP
419 max_id_len = STRLEN("UNIT");
420 load_len = STRLEN("LOAD");
421 active_len = STRLEN("ACTIVE");
422 sub_len = STRLEN("SUB");
423 job_len = STRLEN("JOB");
424 max_desc_len = STRLEN("DESCRIPTION");
b036fc00
LP
425
426 for (u = unit_infos; u < unit_infos + c; u++) {
1238ee09 427 max_id_len = MAX(max_id_len, strlen(u->id) + (u->machine ? strlen(u->machine)+1 : 0));
a1074881 428 load_len = MAX(load_len, strlen(u->load_state));
b036fc00
LP
429 active_len = MAX(active_len, strlen(u->active_state));
430 sub_len = MAX(sub_len, strlen(u->sub_state));
b5d7f1bb 431 max_desc_len = MAX(max_desc_len, strlen(u->description));
f459b602 432
ccd41387 433 if (u->job_id != 0) {
b036fc00 434 job_len = MAX(job_len, strlen(u->job_type));
ccd41387
ZJS
435 job_count++;
436 }
90c3f79d
LP
437
438 if (!arg_no_legend &&
439 (streq(u->active_state, "failed") ||
440 STR_IN_SET(u->load_state, "error", "not-found", "masked")))
441 circle_len = 2;
33330222
ZJS
442 }
443
184ecaf7 444 if (!arg_full && original_stdout_is_tty) {
4deb3b93 445 unsigned basic_len;
cbc9fbd1 446
b5d7f1bb 447 id_len = MIN(max_id_len, 25u); /* as much as it needs, but at most 25 for now */
a9bd056a 448 basic_len = circle_len + 1 + id_len + 1 + load_len + 1 + active_len + 1 + sub_len + 1;
cbc9fbd1 449
ccd41387
ZJS
450 if (job_count)
451 basic_len += job_len + 1;
cbc9fbd1 452
4deb3b93
MS
453 if (basic_len < (unsigned) columns()) {
454 unsigned extra_len, incr;
455 extra_len = columns() - basic_len;
cbc9fbd1 456
4deb3b93
MS
457 /* Either UNIT already got 25, or is fully satisfied.
458 * Grant up to 25 to DESC now. */
9607d947 459 incr = MIN(extra_len, 25u);
b5d7f1bb 460 desc_len = incr;
4deb3b93 461 extra_len -= incr;
cbc9fbd1 462
b5d7f1bb
LP
463 /* Of the remainder give as much as the ID needs to the ID, and give the rest to the
464 * description but not more than it needs. */
4deb3b93 465 if (extra_len > 0) {
b5d7f1bb 466 incr = MIN(max_id_len - id_len, extra_len);
4deb3b93 467 id_len += incr;
b5d7f1bb 468 desc_len += MIN(extra_len - incr, max_desc_len - desc_len);
4deb3b93 469 }
43479f8d
ZJS
470 } else
471 desc_len = 0;
b5d7f1bb 472 } else {
4deb3b93 473 id_len = max_id_len;
b5d7f1bb
LP
474 desc_len = max_desc_len;
475 }
4deb3b93 476
b036fc00 477 for (u = unit_infos; u < unit_infos + c; u++) {
1238ee09 478 _cleanup_free_ char *e = NULL, *j = NULL;
16484a8a 479 const char *on_underline = "", *off_underline = "";
90c3f79d
LP
480 const char *on_loaded = "", *off_loaded = "";
481 const char *on_active = "", *off_active = "";
482 const char *on_circle = "", *off_circle = "";
1238ee09 483 const char *id;
16484a8a 484 bool circle = false, underline = false;
b036fc00 485
ad94ad63 486 if (!n_shown && !arg_no_legend) {
90c3f79d
LP
487
488 if (circle_len > 0)
489 fputs(" ", stdout);
490
16484a8a
ZJS
491 printf("%s%-*s %-*s %-*s %-*s ",
492 ansi_underline(),
cbc9fbd1
LP
493 id_len, "UNIT",
494 load_len, "LOAD",
495 active_len, "ACTIVE",
496 sub_len, "SUB");
497
ccd41387
ZJS
498 if (job_count)
499 printf("%-*s ", job_len, "JOB");
cbc9fbd1 500
b5d7f1bb
LP
501 printf("%-*.*s%s\n",
502 desc_len,
503 !arg_full && arg_no_pager ? (int) desc_len : -1,
16484a8a
ZJS
504 "DESCRIPTION",
505 ansi_normal());
ad94ad63
ZJS
506 }
507
688c6725
LP
508 n_shown++;
509
16484a8a
ZJS
510 if (u + 1 < unit_infos + c &&
511 !streq(unit_type_suffix(u->id), unit_type_suffix((u + 1)->id))) {
512 on_underline = ansi_underline();
513 off_underline = ansi_normal();
514 underline = true;
515 }
516
250ba664 517 if (STR_IN_SET(u->load_state, "error", "not-found", "masked") && !arg_plain) {
90c3f79d 518 on_circle = ansi_highlight_yellow();
16484a8a 519 off_circle = ansi_normal();
90c3f79d 520 circle = true;
16484a8a 521 on_loaded = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
835a19e0 522 off_loaded = underline ? on_underline : ansi_normal();
250ba664 523 } else if (streq(u->active_state, "failed") && !arg_plain) {
16484a8a
ZJS
524 on_circle = ansi_highlight_red();
525 off_circle = ansi_normal();
90c3f79d 526 circle = true;
16484a8a 527 on_active = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
835a19e0 528 off_active = underline ? on_underline : ansi_normal();
90c3f79d 529 }
eb68c413 530
1238ee09 531 if (u->machine) {
605405c6 532 j = strjoin(u->machine, ":", u->id);
1238ee09
LP
533 if (!j)
534 return log_oom();
535
536 id = j;
537 } else
538 id = u->id;
539
540 if (arg_full) {
541 e = ellipsize(id, id_len, 33);
542 if (!e)
543 return log_oom();
544
545 id = e;
546 }
eb68c413 547
90c3f79d 548 if (circle_len > 0)
323b7dc9 549 printf("%s%s%s ", on_circle, circle ? special_glyph(BLACK_CIRCLE) : " ", off_circle);
90c3f79d 550
16484a8a
ZJS
551 printf("%s%s%-*s%s %s%-*s%s %s%-*s %-*s%s %-*s",
552 on_underline,
90c3f79d 553 on_active, id_len, id, off_active,
a1074881 554 on_loaded, load_len, u->load_state, off_loaded,
b036fc00
LP
555 on_active, active_len, u->active_state,
556 sub_len, u->sub_state, off_active,
ccd41387 557 job_count ? job_len + 1 : 0, u->job_id ? u->job_type : "");
cbc9fbd1 558
b5d7f1bb
LP
559 printf("%-*.*s%s\n",
560 desc_len,
561 !arg_full && arg_no_pager ? (int) desc_len : -1,
16484a8a
ZJS
562 u->description,
563 off_underline);
eb68c413
ZJS
564 }
565
ebed32bf 566 if (!arg_no_legend) {
57f7ae4f
ZJS
567 const char *on, *off;
568
569 if (n_shown) {
90c3f79d
LP
570 puts("\n"
571 "LOAD = Reflects whether the unit definition was properly loaded.\n"
e3e0314b
ZJS
572 "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
573 "SUB = The low-level unit activation state, values depend on unit type.");
574 puts(job_count ? "JOB = Pending job for the unit.\n" : "");
0b5a519c 575 on = ansi_highlight();
1fc464f6 576 off = ansi_normal();
57f7ae4f 577 } else {
0b5a519c 578 on = ansi_highlight_red();
1fc464f6 579 off = ansi_normal();
57f7ae4f 580 }
eb68c413
ZJS
581
582 if (arg_all)
48c2826b 583 printf("%s%u loaded units listed.%s\n"
57f7ae4f
ZJS
584 "To show all installed unit files use 'systemctl list-unit-files'.\n",
585 on, n_shown, off);
eb68c413 586 else
48c2826b 587 printf("%s%u loaded units listed.%s Pass --all to see loaded but inactive units, too.\n"
57f7ae4f
ZJS
588 "To show all installed unit files use 'systemctl list-unit-files'.\n",
589 on, n_shown, off);
eb68c413 590 }
1238ee09
LP
591
592 return 0;
eb68c413
ZJS
593}
594
a00963a2 595static int get_unit_list(
f459b602 596 sd_bus *bus,
1238ee09
LP
597 const char *machine,
598 char **patterns,
599 UnitInfo **unit_infos,
600 int c,
601 sd_bus_message **_reply) {
a00963a2 602
4afd3348
LP
603 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
604 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
605 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
ca2d3784 606 size_t size = c;
1238ee09 607 int r;
f459b602 608 UnitInfo u;
313fe66f 609 bool fallback = false;
7e4249b9 610
265a7a2a 611 assert(bus);
1238ee09 612 assert(unit_infos);
f459b602 613 assert(_reply);
1238ee09 614
cdc06ed7 615 r = sd_bus_message_new_method_call(
f22f08cd 616 bus,
cdc06ed7 617 &m,
f22f08cd
SP
618 "org.freedesktop.systemd1",
619 "/org/freedesktop/systemd1",
620 "org.freedesktop.systemd1.Manager",
313fe66f 621 "ListUnitsByPatterns");
cdc06ed7
DS
622 if (r < 0)
623 return bus_log_create_error(r);
624
625 r = sd_bus_message_append_strv(m, arg_states);
626 if (r < 0)
627 return bus_log_create_error(r);
628
313fe66f 629 r = sd_bus_message_append_strv(m, patterns);
630 if (r < 0)
631 return bus_log_create_error(r);
632
cdc06ed7 633 r = sd_bus_call(bus, m, 0, &error, &reply);
33d52725
ZJS
634 if (r < 0 && (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD) ||
635 sd_bus_error_has_name(&error, SD_BUS_ERROR_ACCESS_DENIED))) {
313fe66f 636 /* Fallback to legacy ListUnitsFiltered method */
637 fallback = true;
638 log_debug_errno(r, "Failed to list units: %s Falling back to ListUnitsFiltered method.", bus_error_message(&error, r));
639 m = sd_bus_message_unref(m);
640 sd_bus_error_free(&error);
641
642 r = sd_bus_message_new_method_call(
643 bus,
644 &m,
645 "org.freedesktop.systemd1",
646 "/org/freedesktop/systemd1",
647 "org.freedesktop.systemd1.Manager",
648 "ListUnitsFiltered");
649 if (r < 0)
650 return bus_log_create_error(r);
651
652 r = sd_bus_message_append_strv(m, arg_states);
653 if (r < 0)
654 return bus_log_create_error(r);
655
656 r = sd_bus_call(bus, m, 0, &error, &reply);
657 }
4c3e8e39
LP
658 if (r < 0)
659 return log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
7e4249b9 660
f459b602
MAP
661 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
662 if (r < 0)
663 return bus_log_parse_error(r);
7e4249b9 664
f459b602 665 while ((r = bus_parse_unit_info(reply, &u)) > 0) {
1238ee09
LP
666 u.machine = machine;
667
313fe66f 668 if (!output_show_unit(&u, fallback ? patterns : NULL))
8d5ba5a9 669 continue;
7e4249b9 670
1238ee09 671 if (!GREEDY_REALLOC(*unit_infos, size, c+1))
f459b602 672 return log_oom();
36c32ba2 673
1238ee09 674 (*unit_infos)[c++] = u;
991f2a39 675 }
f459b602
MAP
676 if (r < 0)
677 return bus_log_parse_error(r);
991f2a39 678
f459b602
MAP
679 r = sd_bus_message_exit_container(reply);
680 if (r < 0)
681 return bus_log_parse_error(r);
682
1cc6c93a 683 *_reply = TAKE_PTR(reply);
f459b602 684
1238ee09
LP
685 return c;
686}
687
688static void message_set_freep(Set **set) {
224b0e7a 689 set_free_with_destructor(*set, sd_bus_message_unref);
1238ee09
LP
690}
691
692static int get_unit_list_recursive(
693 sd_bus *bus,
694 char **patterns,
695 UnitInfo **_unit_infos,
696 Set **_replies,
697 char ***_machines) {
698
699 _cleanup_free_ UnitInfo *unit_infos = NULL;
700 _cleanup_(message_set_freep) Set *replies;
701 sd_bus_message *reply;
702 int c, r;
703
704 assert(bus);
705 assert(_replies);
706 assert(_unit_infos);
707 assert(_machines);
708
d5099efc 709 replies = set_new(NULL);
1238ee09
LP
710 if (!replies)
711 return log_oom();
712
713 c = get_unit_list(bus, NULL, patterns, &unit_infos, 0, &reply);
714 if (c < 0)
715 return c;
716
717 r = set_put(replies, reply);
718 if (r < 0) {
719 sd_bus_message_unref(reply);
4c3e8e39 720 return log_oom();
1238ee09
LP
721 }
722
723 if (arg_recursive) {
724 _cleanup_strv_free_ char **machines = NULL;
725 char **i;
726
727 r = sd_get_machine_names(&machines);
728 if (r < 0)
4c3e8e39 729 return log_error_errno(r, "Failed to get machine names: %m");
1238ee09
LP
730
731 STRV_FOREACH(i, machines) {
4afd3348 732 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *container = NULL;
1238ee09
LP
733 int k;
734
de33fc62 735 r = sd_bus_open_system_machine(&container, *i);
1238ee09 736 if (r < 0) {
4c3e8e39 737 log_warning_errno(r, "Failed to connect to container %s, ignoring: %m", *i);
1238ee09
LP
738 continue;
739 }
740
741 k = get_unit_list(container, *i, patterns, &unit_infos, c, &reply);
742 if (k < 0)
743 return k;
744
745 c = k;
746
747 r = set_put(replies, reply);
748 if (r < 0) {
749 sd_bus_message_unref(reply);
4c3e8e39 750 return log_oom();
1238ee09
LP
751 }
752 }
753
1cc6c93a 754 *_machines = TAKE_PTR(machines);
1238ee09
LP
755 } else
756 *_machines = NULL;
757
1cc6c93a 758 *_unit_infos = TAKE_PTR(unit_infos);
f459b602 759
1cc6c93a 760 *_replies = TAKE_PTR(replies);
1238ee09 761
f459b602 762 return c;
991f2a39
ZJS
763}
764
e449de87 765static int list_units(int argc, char *argv[], void *userdata) {
f459b602 766 _cleanup_free_ UnitInfo *unit_infos = NULL;
1238ee09
LP
767 _cleanup_(message_set_freep) Set *replies = NULL;
768 _cleanup_strv_free_ char **machines = NULL;
4fbd7192 769 sd_bus *bus;
991f2a39
ZJS
770 int r;
771
4fbd7192
LP
772 r = acquire_bus(BUS_MANAGER, &bus);
773 if (r < 0)
774 return r;
775
ee5324aa 776 (void) pager_open(arg_no_pager, false);
d2ad7e1b 777
e449de87 778 r = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
991f2a39
ZJS
779 if (r < 0)
780 return r;
781
f459b602 782 qsort_safe(unit_infos, r, sizeof(UnitInfo), compare_unit_info);
1238ee09 783 return output_units_list(unit_infos, r);
991f2a39
ZJS
784}
785
a00963a2 786static int get_triggered_units(
f459b602
MAP
787 sd_bus *bus,
788 const char* path,
789 char*** ret) {
a00963a2 790
4afd3348 791 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
991f2a39
ZJS
792 int r;
793
4fbd7192
LP
794 assert(bus);
795 assert(path);
796 assert(ret);
797
f459b602
MAP
798 r = sd_bus_get_property_strv(
799 bus,
800 "org.freedesktop.systemd1",
801 path,
802 "org.freedesktop.systemd1.Unit",
803 "Triggers",
804 &error,
805 ret);
f459b602 806 if (r < 0)
691395d8 807 return log_error_errno(r, "Failed to determine triggers: %s", bus_error_message(&error, r));
991f2a39
ZJS
808
809 return 0;
810}
811
f459b602
MAP
812static int get_listening(
813 sd_bus *bus,
814 const char* unit_path,
cbb76c29 815 char*** listening) {
f459b602 816
4afd3348
LP
817 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
818 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
f459b602 819 const char *type, *path;
cbb76c29 820 int r, n = 0;
991f2a39 821
f459b602
MAP
822 r = sd_bus_get_property(
823 bus,
824 "org.freedesktop.systemd1",
825 unit_path,
826 "org.freedesktop.systemd1.Socket",
827 "Listen",
828 &error,
829 &reply,
830 "a(ss)");
691395d8
LP
831 if (r < 0)
832 return log_error_errno(r, "Failed to get list of listening sockets: %s", bus_error_message(&error, r));
991f2a39 833
f459b602
MAP
834 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)");
835 if (r < 0)
836 return bus_log_parse_error(r);
991f2a39 837
f459b602 838 while ((r = sd_bus_message_read(reply, "(ss)", &type, &path)) > 0) {
36c32ba2 839
0d95178e 840 r = strv_extend(listening, type);
f459b602
MAP
841 if (r < 0)
842 return log_oom();
991f2a39 843
0d95178e 844 r = strv_extend(listening, path);
f459b602
MAP
845 if (r < 0)
846 return log_oom();
7e4249b9 847
cbb76c29 848 n++;
36c32ba2 849 }
f459b602
MAP
850 if (r < 0)
851 return bus_log_parse_error(r);
852
853 r = sd_bus_message_exit_container(reply);
854 if (r < 0)
855 return bus_log_parse_error(r);
36c32ba2 856
cbb76c29 857 return n;
991f2a39
ZJS
858}
859
860struct socket_info {
0cfc3525 861 const char *machine;
991f2a39
ZJS
862 const char* id;
863
864 char* type;
865 char* path;
866
867 /* Note: triggered is a list here, although it almost certainly
868 * will always be one unit. Nevertheless, dbus API allows for multiple
f7340ab2 869 * values, so let's follow that. */
991f2a39
ZJS
870 char** triggered;
871
872 /* The strv above is shared. free is set only in the first one. */
873 bool own_triggered;
874};
875
cbb76c29 876static int socket_info_compare(const struct socket_info *a, const struct socket_info *b) {
cbc9fbd1
LP
877 int o;
878
cbb76c29
LP
879 assert(a);
880 assert(b);
881
0cfc3525
TA
882 if (!a->machine && b->machine)
883 return -1;
884 if (a->machine && !b->machine)
885 return 1;
886 if (a->machine && b->machine) {
887 o = strcasecmp(a->machine, b->machine);
888 if (o != 0)
889 return o;
890 }
891
cbc9fbd1 892 o = strcmp(a->path, b->path);
991f2a39
ZJS
893 if (o == 0)
894 o = strcmp(a->type, b->type);
cbc9fbd1 895
991f2a39
ZJS
896 return o;
897}
898
899static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
900 struct socket_info *s;
fbd0b64f
LP
901 unsigned pathlen = STRLEN("LISTEN"),
902 typelen = STRLEN("TYPE") * arg_show_types,
903 socklen = STRLEN("UNIT"),
904 servlen = STRLEN("ACTIVATES");
991f2a39
ZJS
905 const char *on, *off;
906
907 for (s = socket_infos; s < socket_infos + cs; s++) {
991f2a39 908 unsigned tmp = 0;
cbc9fbd1 909 char **a;
991f2a39
ZJS
910
911 socklen = MAX(socklen, strlen(s->id));
912 if (arg_show_types)
913 typelen = MAX(typelen, strlen(s->type));
0cfc3525 914 pathlen = MAX(pathlen, strlen(s->path) + (s->machine ? strlen(s->machine)+1 : 0));
991f2a39
ZJS
915
916 STRV_FOREACH(a, s->triggered)
917 tmp += strlen(*a) + 2*(a != s->triggered);
918 servlen = MAX(servlen, tmp);
919 }
920
921 if (cs) {
571bfc6c
MM
922 if (!arg_no_legend)
923 printf("%-*s %-*.*s%-*s %s\n",
924 pathlen, "LISTEN",
925 typelen + arg_show_types, typelen + arg_show_types, "TYPE ",
926 socklen, "UNIT",
927 "ACTIVATES");
991f2a39
ZJS
928
929 for (s = socket_infos; s < socket_infos + cs; s++) {
0cfc3525
TA
930 _cleanup_free_ char *j = NULL;
931 const char *path;
991f2a39
ZJS
932 char **a;
933
0cfc3525 934 if (s->machine) {
605405c6 935 j = strjoin(s->machine, ":", s->path);
0cfc3525
TA
936 if (!j)
937 return log_oom();
938 path = j;
939 } else
940 path = s->path;
941
991f2a39
ZJS
942 if (arg_show_types)
943 printf("%-*s %-*s %-*s",
0cfc3525 944 pathlen, path, typelen, s->type, socklen, s->id);
991f2a39
ZJS
945 else
946 printf("%-*s %-*s",
0cfc3525 947 pathlen, path, socklen, s->id);
991f2a39
ZJS
948 STRV_FOREACH(a, s->triggered)
949 printf("%s %s",
950 a == s->triggered ? "" : ",", *a);
951 printf("\n");
952 }
953
0b5a519c 954 on = ansi_highlight();
1fc464f6 955 off = ansi_normal();
571bfc6c
MM
956 if (!arg_no_legend)
957 printf("\n");
991f2a39 958 } else {
0b5a519c 959 on = ansi_highlight_red();
1fc464f6 960 off = ansi_normal();
991f2a39
ZJS
961 }
962
571bfc6c
MM
963 if (!arg_no_legend) {
964 printf("%s%u sockets listed.%s\n", on, cs, off);
965 if (!arg_all)
966 printf("Pass --all to see loaded but inactive sockets, too.\n");
967 }
265a7a2a
ZJS
968
969 return 0;
970}
971
e449de87 972static int list_sockets(int argc, char *argv[], void *userdata) {
0cfc3525
TA
973 _cleanup_(message_set_freep) Set *replies = NULL;
974 _cleanup_strv_free_ char **machines = NULL;
f459b602 975 _cleanup_free_ UnitInfo *unit_infos = NULL;
8d5ba5a9 976 _cleanup_free_ struct socket_info *socket_infos = NULL;
f459b602 977 const UnitInfo *u;
991f2a39 978 struct socket_info *s;
cbb76c29 979 unsigned cs = 0;
991f2a39 980 size_t size = 0;
ad83b4c4 981 int r = 0, n;
4fbd7192 982 sd_bus *bus;
265a7a2a 983
4fbd7192
LP
984 r = acquire_bus(BUS_MANAGER, &bus);
985 if (r < 0)
986 return r;
987
ee5324aa 988 (void) pager_open(arg_no_pager, false);
d2ad7e1b 989
e449de87 990 n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
cbb76c29
LP
991 if (n < 0)
992 return n;
265a7a2a 993
cbb76c29 994 for (u = unit_infos; u < unit_infos + n; u++) {
0d95178e 995 _cleanup_strv_free_ char **listening = NULL, **triggered = NULL;
cbb76c29 996 int i, c;
991f2a39 997
cbc9fbd1 998 if (!endswith(u->id, ".socket"))
991f2a39
ZJS
999 continue;
1000
1001 r = get_triggered_units(bus, u->unit_path, &triggered);
1002 if (r < 0)
1003 goto cleanup;
1004
cbb76c29
LP
1005 c = get_listening(bus, u->unit_path, &listening);
1006 if (c < 0) {
1007 r = c;
991f2a39 1008 goto cleanup;
cbb76c29 1009 }
991f2a39
ZJS
1010
1011 if (!GREEDY_REALLOC(socket_infos, size, cs + c)) {
1012 r = log_oom();
1013 goto cleanup;
1014 }
1015
1016 for (i = 0; i < c; i++)
1017 socket_infos[cs + i] = (struct socket_info) {
0cfc3525 1018 .machine = u->machine,
991f2a39 1019 .id = u->id,
0d95178e
KS
1020 .type = listening[i*2],
1021 .path = listening[i*2 + 1],
991f2a39
ZJS
1022 .triggered = triggered,
1023 .own_triggered = i==0,
1024 };
1025
1026 /* from this point on we will cleanup those socket_infos */
1027 cs += c;
0d95178e
KS
1028 free(listening);
1029 listening = triggered = NULL; /* avoid cleanup */
991f2a39
ZJS
1030 }
1031
7ff7394d
ZJS
1032 qsort_safe(socket_infos, cs, sizeof(struct socket_info),
1033 (__compar_fn_t) socket_info_compare);
991f2a39
ZJS
1034
1035 output_sockets_list(socket_infos, cs);
1036
1037 cleanup:
1038 assert(cs == 0 || socket_infos);
1039 for (s = socket_infos; s < socket_infos + cs; s++) {
1040 free(s->type);
1041 free(s->path);
1042 if (s->own_triggered)
1043 strv_free(s->triggered);
1044 }
4445a875 1045
872c8faa 1046 return r;
4445a875
LP
1047}
1048
cbb76c29
LP
1049static int get_next_elapse(
1050 sd_bus *bus,
1051 const char *path,
1052 dual_timestamp *next) {
1053
4afd3348 1054 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
cbb76c29
LP
1055 dual_timestamp t;
1056 int r;
1057
1058 assert(bus);
1059 assert(path);
1060 assert(next);
1061
1062 r = sd_bus_get_property_trivial(
1063 bus,
1064 "org.freedesktop.systemd1",
1065 path,
1066 "org.freedesktop.systemd1.Timer",
1067 "NextElapseUSecMonotonic",
1068 &error,
1069 't',
1070 &t.monotonic);
691395d8 1071 if (r < 0)
021723c6 1072 return log_error_errno(r, "Failed to get next elapse time: %s", bus_error_message(&error, r));
cbb76c29
LP
1073
1074 r = sd_bus_get_property_trivial(
1075 bus,
1076 "org.freedesktop.systemd1",
1077 path,
1078 "org.freedesktop.systemd1.Timer",
1079 "NextElapseUSecRealtime",
1080 &error,
1081 't',
1082 &t.realtime);
691395d8 1083 if (r < 0)
021723c6 1084 return log_error_errno(r, "Failed to get next elapse time: %s", bus_error_message(&error, r));
cbb76c29
LP
1085
1086 *next = t;
1087 return 0;
1088}
1089
d784e2db
LP
1090static int get_last_trigger(
1091 sd_bus *bus,
1092 const char *path,
1093 usec_t *last) {
1094
4afd3348 1095 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
d784e2db
LP
1096 int r;
1097
1098 assert(bus);
1099 assert(path);
1100 assert(last);
1101
1102 r = sd_bus_get_property_trivial(
1103 bus,
1104 "org.freedesktop.systemd1",
1105 path,
1106 "org.freedesktop.systemd1.Timer",
dedabea4 1107 "LastTriggerUSec",
d784e2db
LP
1108 &error,
1109 't',
1110 last);
691395d8
LP
1111 if (r < 0)
1112 return log_error_errno(r, "Failed to get last trigger time: %s", bus_error_message(&error, r));
d784e2db
LP
1113
1114 return 0;
1115}
1116
cbb76c29 1117struct timer_info {
806a37e7 1118 const char* machine;
cbb76c29
LP
1119 const char* id;
1120 usec_t next_elapse;
d784e2db 1121 usec_t last_trigger;
cbb76c29
LP
1122 char** triggered;
1123};
1124
1125static int timer_info_compare(const struct timer_info *a, const struct timer_info *b) {
806a37e7
TA
1126 int o;
1127
cbb76c29
LP
1128 assert(a);
1129 assert(b);
1130
806a37e7
TA
1131 if (!a->machine && b->machine)
1132 return -1;
1133 if (a->machine && !b->machine)
1134 return 1;
1135 if (a->machine && b->machine) {
1136 o = strcasecmp(a->machine, b->machine);
1137 if (o != 0)
1138 return o;
1139 }
1140
cbb76c29
LP
1141 if (a->next_elapse < b->next_elapse)
1142 return -1;
1143 if (a->next_elapse > b->next_elapse)
1144 return 1;
1145
1146 return strcmp(a->id, b->id);
1147}
1148
1149static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
1150 struct timer_info *t;
1151 unsigned
fbd0b64f
LP
1152 nextlen = STRLEN("NEXT"),
1153 leftlen = STRLEN("LEFT"),
1154 lastlen = STRLEN("LAST"),
1155 passedlen = STRLEN("PASSED"),
1156 unitlen = STRLEN("UNIT"),
1157 activatelen = STRLEN("ACTIVATES");
cbb76c29
LP
1158
1159 const char *on, *off;
1160
1161 assert(timer_infos || n == 0);
1162
1163 for (t = timer_infos; t < timer_infos + n; t++) {
1164 unsigned ul = 0;
1165 char **a;
1166
1167 if (t->next_elapse > 0) {
1168 char tstamp[FORMAT_TIMESTAMP_MAX] = "", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = "";
1169
1170 format_timestamp(tstamp, sizeof(tstamp), t->next_elapse);
1171 nextlen = MAX(nextlen, strlen(tstamp) + 1);
1172
1173 format_timestamp_relative(trel, sizeof(trel), t->next_elapse);
1174 leftlen = MAX(leftlen, strlen(trel));
1175 }
1176
d784e2db
LP
1177 if (t->last_trigger > 0) {
1178 char tstamp[FORMAT_TIMESTAMP_MAX] = "", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = "";
1179
1180 format_timestamp(tstamp, sizeof(tstamp), t->last_trigger);
1181 lastlen = MAX(lastlen, strlen(tstamp) + 1);
1182
1183 format_timestamp_relative(trel, sizeof(trel), t->last_trigger);
1184 passedlen = MAX(passedlen, strlen(trel));
1185 }
1186
806a37e7 1187 unitlen = MAX(unitlen, strlen(t->id) + (t->machine ? strlen(t->machine)+1 : 0));
cbb76c29
LP
1188
1189 STRV_FOREACH(a, t->triggered)
1190 ul += strlen(*a) + 2*(a != t->triggered);
d784e2db 1191
cbb76c29
LP
1192 activatelen = MAX(activatelen, ul);
1193 }
1194
1195 if (n > 0) {
1196 if (!arg_no_legend)
d784e2db
LP
1197 printf("%-*s %-*s %-*s %-*s %-*s %s\n",
1198 nextlen, "NEXT",
1199 leftlen, "LEFT",
1200 lastlen, "LAST",
1201 passedlen, "PASSED",
1202 unitlen, "UNIT",
1203 "ACTIVATES");
cbb76c29
LP
1204
1205 for (t = timer_infos; t < timer_infos + n; t++) {
806a37e7
TA
1206 _cleanup_free_ char *j = NULL;
1207 const char *unit;
d784e2db
LP
1208 char tstamp1[FORMAT_TIMESTAMP_MAX] = "n/a", trel1[FORMAT_TIMESTAMP_RELATIVE_MAX] = "n/a";
1209 char tstamp2[FORMAT_TIMESTAMP_MAX] = "n/a", trel2[FORMAT_TIMESTAMP_RELATIVE_MAX] = "n/a";
cbb76c29
LP
1210 char **a;
1211
d784e2db
LP
1212 format_timestamp(tstamp1, sizeof(tstamp1), t->next_elapse);
1213 format_timestamp_relative(trel1, sizeof(trel1), t->next_elapse);
cbb76c29 1214
d784e2db
LP
1215 format_timestamp(tstamp2, sizeof(tstamp2), t->last_trigger);
1216 format_timestamp_relative(trel2, sizeof(trel2), t->last_trigger);
1217
806a37e7 1218 if (t->machine) {
605405c6 1219 j = strjoin(t->machine, ":", t->id);
806a37e7
TA
1220 if (!j)
1221 return log_oom();
1222 unit = j;
1223 } else
1224 unit = t->id;
1225
d784e2db 1226 printf("%-*s %-*s %-*s %-*s %-*s",
806a37e7 1227 nextlen, tstamp1, leftlen, trel1, lastlen, tstamp2, passedlen, trel2, unitlen, unit);
cbb76c29
LP
1228
1229 STRV_FOREACH(a, t->triggered)
1230 printf("%s %s",
1231 a == t->triggered ? "" : ",", *a);
1232 printf("\n");
1233 }
1234
1235 on = ansi_highlight();
1fc464f6 1236 off = ansi_normal();
cbb76c29
LP
1237 if (!arg_no_legend)
1238 printf("\n");
1239 } else {
1240 on = ansi_highlight_red();
1fc464f6 1241 off = ansi_normal();
cbb76c29
LP
1242 }
1243
1244 if (!arg_no_legend) {
1245 printf("%s%u timers listed.%s\n", on, n, off);
1246 if (!arg_all)
1247 printf("Pass --all to see loaded but inactive timers, too.\n");
1248 }
1249
1250 return 0;
1251}
1252
f5080e73
DH
1253static usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next) {
1254 usec_t next_elapse;
1255
1256 assert(nw);
1257 assert(next);
1258
3a43da28 1259 if (next->monotonic != USEC_INFINITY && next->monotonic > 0) {
f5080e73
DH
1260 usec_t converted;
1261
1262 if (next->monotonic > nw->monotonic)
1263 converted = nw->realtime + (next->monotonic - nw->monotonic);
1264 else
1265 converted = nw->realtime - (nw->monotonic - next->monotonic);
1266
3a43da28 1267 if (next->realtime != USEC_INFINITY && next->realtime > 0)
f5080e73
DH
1268 next_elapse = MIN(converted, next->realtime);
1269 else
1270 next_elapse = converted;
1271
1272 } else
1273 next_elapse = next->realtime;
1274
1275 return next_elapse;
1276}
1277
e449de87 1278static int list_timers(int argc, char *argv[], void *userdata) {
806a37e7
TA
1279 _cleanup_(message_set_freep) Set *replies = NULL;
1280 _cleanup_strv_free_ char **machines = NULL;
cbb76c29
LP
1281 _cleanup_free_ struct timer_info *timer_infos = NULL;
1282 _cleanup_free_ UnitInfo *unit_infos = NULL;
1283 struct timer_info *t;
1284 const UnitInfo *u;
1285 size_t size = 0;
1823b86e 1286 int n, c = 0;
cbb76c29 1287 dual_timestamp nw;
4fbd7192 1288 sd_bus *bus;
1823b86e 1289 int r = 0;
cbb76c29 1290
4fbd7192
LP
1291 r = acquire_bus(BUS_MANAGER, &bus);
1292 if (r < 0)
1293 return r;
1294
ee5324aa 1295 (void) pager_open(arg_no_pager, false);
d2ad7e1b 1296
e449de87 1297 n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
cbb76c29
LP
1298 if (n < 0)
1299 return n;
1300
1301 dual_timestamp_get(&nw);
1302
1303 for (u = unit_infos; u < unit_infos + n; u++) {
1304 _cleanup_strv_free_ char **triggered = NULL;
5cb14b37 1305 dual_timestamp next = DUAL_TIMESTAMP_NULL;
d784e2db 1306 usec_t m, last = 0;
cbb76c29 1307
cbb76c29
LP
1308 if (!endswith(u->id, ".timer"))
1309 continue;
1310
1311 r = get_triggered_units(bus, u->unit_path, &triggered);
1312 if (r < 0)
1313 goto cleanup;
1314
1315 r = get_next_elapse(bus, u->unit_path, &next);
1316 if (r < 0)
1317 goto cleanup;
1318
d784e2db
LP
1319 get_last_trigger(bus, u->unit_path, &last);
1320
cbb76c29
LP
1321 if (!GREEDY_REALLOC(timer_infos, size, c+1)) {
1322 r = log_oom();
1323 goto cleanup;
1324 }
1325
f5080e73
DH
1326 m = calc_next_elapse(&nw, &next);
1327
cbb76c29 1328 timer_infos[c++] = (struct timer_info) {
806a37e7 1329 .machine = u->machine,
cbb76c29
LP
1330 .id = u->id,
1331 .next_elapse = m,
d784e2db 1332 .last_trigger = last,
1cc6c93a 1333 .triggered = TAKE_PTR(triggered),
cbb76c29 1334 };
cbb76c29
LP
1335 }
1336
1337 qsort_safe(timer_infos, c, sizeof(struct timer_info),
1338 (__compar_fn_t) timer_info_compare);
1339
1340 output_timers_list(timer_infos, c);
1341
1342 cleanup:
1343 for (t = timer_infos; t < timer_infos + c; t++)
1344 strv_free(t->triggered);
1345
1346 return r;
1347}
1348
729e3769
LP
1349static int compare_unit_file_list(const void *a, const void *b) {
1350 const char *d1, *d2;
1351 const UnitFileList *u = a, *v = b;
1352
1353 d1 = strrchr(u->path, '.');
1354 d2 = strrchr(v->path, '.');
1355
1356 if (d1 && d2) {
1357 int r;
1358
1359 r = strcasecmp(d1, d2);
1360 if (r != 0)
1361 return r;
1362 }
1363
2b6bf07d 1364 return strcasecmp(basename(u->path), basename(v->path));
729e3769
LP
1365}
1366
313fe66f 1367static bool output_show_unit_file(const UnitFileList *u, char **states, char **patterns) {
f8591ee1
LP
1368 assert(u);
1369
2404701e 1370 if (!strv_fnmatch_or_empty(patterns, basename(u->path), FNM_NOESCAPE))
d8fba7c6 1371 return false;
d8fba7c6 1372
6c71341a
ZJS
1373 if (!strv_isempty(arg_types)) {
1374 const char *dot;
1375
1376 dot = strrchr(u->path, '.');
1377 if (!dot)
1378 return false;
1379
1380 if (!strv_find(arg_types, dot+1))
1381 return false;
1382 }
1383
313fe66f 1384 if (!strv_isempty(states) &&
1385 !strv_find(states, unit_file_state_to_string(u->state)))
bceccd5e 1386 return false;
fec1530e 1387
6c71341a 1388 return true;
729e3769
LP
1389}
1390
8d5ba5a9 1391static void output_unit_file_list(const UnitFileList *units, unsigned c) {
0d292f5e 1392 unsigned max_id_len, id_cols, state_cols;
729e3769
LP
1393 const UnitFileList *u;
1394
fbd0b64f
LP
1395 max_id_len = STRLEN("UNIT FILE");
1396 state_cols = STRLEN("STATE");
cbc9fbd1 1397
1c0a113f 1398 for (u = units; u < units + c; u++) {
2b6bf07d 1399 max_id_len = MAX(max_id_len, strlen(basename(u->path)));
1c0a113f
ZJS
1400 state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state)));
1401 }
1402
1403 if (!arg_full) {
1404 unsigned basic_cols;
cbc9fbd1 1405
9607d947 1406 id_cols = MIN(max_id_len, 25u);
1c0a113f
ZJS
1407 basic_cols = 1 + id_cols + state_cols;
1408 if (basic_cols < (unsigned) columns())
1409 id_cols += MIN(columns() - basic_cols, max_id_len - id_cols);
1410 } else
1411 id_cols = max_id_len;
1412
11690bcc 1413 if (!arg_no_legend && c > 0)
6ae3e62a
ZJS
1414 printf("%s%-*s %-*s%s\n",
1415 ansi_underline(),
cbc9fbd1 1416 id_cols, "UNIT FILE",
6ae3e62a
ZJS
1417 state_cols, "STATE",
1418 ansi_normal());
729e3769
LP
1419
1420 for (u = units; u < units + c; u++) {
aaa6732d 1421 const char *on_underline = NULL, *on_color = NULL, *off = NULL, *id;
7fd1b19b 1422 _cleanup_free_ char *e = NULL;
aaa6732d
LP
1423 bool underline;
1424
1425 underline = u + 1 < units + c &&
1426 !streq(unit_type_suffix(u->path), unit_type_suffix((u + 1)->path));
6ae3e62a 1427
aaa6732d 1428 if (underline)
6ae3e62a 1429 on_underline = ansi_underline();
729e3769 1430
4c315c2c
IS
1431 if (IN_SET(u->state,
1432 UNIT_FILE_MASKED,
1433 UNIT_FILE_MASKED_RUNTIME,
1434 UNIT_FILE_DISABLED,
6ae3e62a 1435 UNIT_FILE_BAD))
aaa6732d 1436 on_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
6ae3e62a 1437 else if (u->state == UNIT_FILE_ENABLED)
aaa6732d
LP
1438 on_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
1439
1440 if (on_underline || on_color)
1441 off = ansi_normal();
729e3769 1442
2b6bf07d 1443 id = basename(u->path);
729e3769 1444
1c0a113f 1445 e = arg_full ? NULL : ellipsize(id, id_cols, 33);
729e3769 1446
aaa6732d
LP
1447 printf("%s%-*s %s%-*s%s\n",
1448 strempty(on_underline),
1c0a113f 1449 id_cols, e ? e : id,
aaa6732d 1450 strempty(on_color), state_cols, unit_file_state_to_string(u->state), strempty(off));
729e3769
LP
1451 }
1452
1c0a113f 1453 if (!arg_no_legend)
0d292f5e 1454 printf("\n%u unit files listed.\n", c);
729e3769
LP
1455}
1456
e449de87 1457static int list_unit_files(int argc, char *argv[], void *userdata) {
4afd3348 1458 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
f84190d8 1459 _cleanup_free_ UnitFileList *units = NULL;
8d5ba5a9
ZJS
1460 UnitFileList *unit;
1461 size_t size = 0;
f459b602
MAP
1462 unsigned c = 0;
1463 const char *state;
1464 char *path;
f84190d8 1465 int r;
313fe66f 1466 bool fallback = false;
729e3769 1467
4fbd7192 1468 if (install_client_side()) {
729e3769
LP
1469 Hashmap *h;
1470 UnitFileList *u;
1471 Iterator i;
f459b602 1472 unsigned n_units;
729e3769 1473
d5099efc 1474 h = hashmap_new(&string_hash_ops);
0d0f0c50
SL
1475 if (!h)
1476 return log_oom();
729e3769 1477
313fe66f 1478 r = unit_file_get_list(arg_scope, arg_root, h, arg_states, strv_skip(argv, 1));
729e3769 1479 if (r < 0) {
8ea913b2 1480 unit_file_list_free(h);
691395d8 1481 return log_error_errno(r, "Failed to get unit file list: %m");
729e3769
LP
1482 }
1483
1484 n_units = hashmap_size(h);
fdbdf6ec 1485
0da999fa
ZJS
1486 units = new(UnitFileList, n_units ?: 1); /* avoid malloc(0) */
1487 if (!units) {
729e3769 1488 unit_file_list_free(h);
0d0f0c50 1489 return log_oom();
729e3769
LP
1490 }
1491
1492 HASHMAP_FOREACH(u, h, i) {
313fe66f 1493 if (!output_show_unit_file(u, NULL, NULL))
8d5ba5a9
ZJS
1494 continue;
1495
1496 units[c++] = *u;
729e3769
LP
1497 free(u);
1498 }
1499
8d5ba5a9 1500 assert(c <= n_units);
729e3769 1501 hashmap_free(h);
5f056378
CH
1502
1503 r = 0;
729e3769 1504 } else {
313fe66f 1505 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
4afd3348 1506 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192
LP
1507 sd_bus *bus;
1508
1509 r = acquire_bus(BUS_MANAGER, &bus);
1510 if (r < 0)
1511 return r;
6e646d22 1512
313fe66f 1513 r = sd_bus_message_new_method_call(
f22f08cd 1514 bus,
313fe66f 1515 &m,
729e3769
LP
1516 "org.freedesktop.systemd1",
1517 "/org/freedesktop/systemd1",
1518 "org.freedesktop.systemd1.Manager",
313fe66f 1519 "ListUnitFilesByPatterns");
1520 if (r < 0)
1521 return bus_log_create_error(r);
1522
1523 r = sd_bus_message_append_strv(m, arg_states);
1524 if (r < 0)
1525 return bus_log_create_error(r);
1526
1527 r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
1528 if (r < 0)
1529 return bus_log_create_error(r);
1530
1531 r = sd_bus_call(bus, m, 0, &error, &reply);
1532 if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
1533 /* Fallback to legacy ListUnitFiles method */
1534 fallback = true;
1535 log_debug_errno(r, "Failed to list unit files: %s Falling back to ListUnitsFiles method.", bus_error_message(&error, r));
1536 m = sd_bus_message_unref(m);
1537 sd_bus_error_free(&error);
1538
1539 r = sd_bus_message_new_method_call(
1540 bus,
1541 &m,
1542 "org.freedesktop.systemd1",
1543 "/org/freedesktop/systemd1",
1544 "org.freedesktop.systemd1.Manager",
1545 "ListUnitFiles");
1546 if (r < 0)
1547 return bus_log_create_error(r);
1548
1549 r = sd_bus_call(bus, m, 0, &error, &reply);
1550 }
691395d8
LP
1551 if (r < 0)
1552 return log_error_errno(r, "Failed to list unit files: %s", bus_error_message(&error, r));
729e3769 1553
f459b602
MAP
1554 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)");
1555 if (r < 0)
1556 return bus_log_parse_error(r);
729e3769 1557
f459b602 1558 while ((r = sd_bus_message_read(reply, "(ss)", &path, &state)) > 0) {
729e3769 1559
f459b602
MAP
1560 if (!GREEDY_REALLOC(units, size, c + 1))
1561 return log_oom();
729e3769 1562
8d5ba5a9 1563 units[c] = (struct UnitFileList) {
f459b602
MAP
1564 path,
1565 unit_file_state_from_string(state)
1566 };
8d5ba5a9 1567
313fe66f 1568 if (output_show_unit_file(&units[c],
1569 fallback ? arg_states : NULL,
1570 fallback ? strv_skip(argv, 1) : NULL))
313cefa1 1571 c++;
8d5ba5a9 1572
729e3769 1573 }
f459b602
MAP
1574 if (r < 0)
1575 return bus_log_parse_error(r);
1576
1577 r = sd_bus_message_exit_container(reply);
1578 if (r < 0)
1579 return bus_log_parse_error(r);
729e3769
LP
1580 }
1581
ee5324aa 1582 (void) pager_open(arg_no_pager, false);
d2ad7e1b 1583
4fe1be9c
LP
1584 qsort_safe(units, c, sizeof(UnitFileList), compare_unit_file_list);
1585 output_unit_file_list(units, c);
729e3769 1586
0da999fa 1587 if (install_client_side())
8d5ba5a9
ZJS
1588 for (unit = units; unit < units + c; unit++)
1589 free(unit->path);
1590
f84190d8 1591 return 0;
729e3769
LP
1592}
1593
55c0b89c 1594static int list_dependencies_print(const char *name, int level, unsigned int branches, bool last) {
55c0b89c 1595 _cleanup_free_ char *n = NULL;
9607d947 1596 size_t max_len = MAX(columns(),20u);
cbc9fbd1
LP
1597 size_t len = 0;
1598 int i;
55c0b89c 1599
5d0c05e5 1600 if (!arg_plain) {
cbc9fbd1 1601
5d0c05e5
LN
1602 for (i = level - 1; i >= 0; i--) {
1603 len += 2;
f168c273 1604 if (len > max_len - 3 && !arg_full) {
5d0c05e5
LN
1605 printf("%s...\n",max_len % 2 ? "" : " ");
1606 return 0;
1607 }
323b7dc9 1608 printf("%s", special_glyph(branches & (1 << i) ? TREE_VERTICAL : TREE_SPACE));
5d0c05e5 1609 }
55c0b89c 1610 len += 2;
cbc9fbd1 1611
f168c273 1612 if (len > max_len - 3 && !arg_full) {
55c0b89c
LN
1613 printf("%s...\n",max_len % 2 ? "" : " ");
1614 return 0;
1615 }
cbc9fbd1 1616
323b7dc9 1617 printf("%s", special_glyph(last ? TREE_RIGHT : TREE_BRANCH));
55c0b89c 1618 }
55c0b89c 1619
9ed794a3 1620 if (arg_full) {
55c0b89c
LN
1621 printf("%s\n", name);
1622 return 0;
1623 }
1624
1625 n = ellipsize(name, max_len-len, 100);
f168c273 1626 if (!n)
55c0b89c
LN
1627 return log_oom();
1628
1629 printf("%s\n", n);
1630 return 0;
1631}
1632
f459b602
MAP
1633static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, char ***deps) {
1634
32b47279
YW
1635 struct DependencyStatusInfo {
1636 char **dep[5];
1637 } info = {};
1638
1639 static const struct bus_properties_map map[_DEPENDENCY_MAX][6] = {
1640 [DEPENDENCY_FORWARD] = {
1641 { "Requires", "as", NULL, offsetof(struct DependencyStatusInfo, dep[0]) },
1642 { "Requisite", "as", NULL, offsetof(struct DependencyStatusInfo, dep[1]) },
1643 { "Wants", "as", NULL, offsetof(struct DependencyStatusInfo, dep[2]) },
1644 { "ConsistsOf", "as", NULL, offsetof(struct DependencyStatusInfo, dep[3]) },
1645 { "BindsTo", "as", NULL, offsetof(struct DependencyStatusInfo, dep[4]) },
1646 {}
1647 },
1648 [DEPENDENCY_REVERSE] = {
1649 { "RequiredBy", "as", NULL, offsetof(struct DependencyStatusInfo, dep[0]) },
1650 { "RequisiteOf", "as", NULL, offsetof(struct DependencyStatusInfo, dep[1]) },
1651 { "WantedBy", "as", NULL, offsetof(struct DependencyStatusInfo, dep[2]) },
1652 { "PartOf", "as", NULL, offsetof(struct DependencyStatusInfo, dep[3]) },
1653 { "BoundBy", "as", NULL, offsetof(struct DependencyStatusInfo, dep[4]) },
1654 {}
1655 },
1656 [DEPENDENCY_AFTER] = {
1657 { "After", "as", NULL, offsetof(struct DependencyStatusInfo, dep[0]) },
1658 {}
1659 },
1660 [DEPENDENCY_BEFORE] = {
1661 { "Before", "as", NULL, offsetof(struct DependencyStatusInfo, dep[0]) },
1662 {}
1663 },
afba4199 1664 };
55c0b89c 1665
4afd3348 1666 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
f459b602
MAP
1667 _cleanup_strv_free_ char **ret = NULL;
1668 _cleanup_free_ char *path = NULL;
32b47279 1669 int i, r;
55c0b89c
LN
1670
1671 assert(bus);
1672 assert(name);
1673 assert(deps);
1674
1675 path = unit_dbus_path_from_name(name);
f459b602
MAP
1676 if (!path)
1677 return log_oom();
55c0b89c 1678
32b47279
YW
1679 r = bus_map_all_properties(bus,
1680 "org.freedesktop.systemd1",
1681 path,
1682 map[arg_dependency],
a7e4861c 1683 0,
32b47279 1684 &error,
f37f8a61 1685 NULL,
32b47279 1686 &info);
691395d8
LP
1687 if (r < 0)
1688 return log_error_errno(r, "Failed to get properties of %s: %s", name, bus_error_message(&error, r));
55c0b89c 1689
32b47279
YW
1690 if (IN_SET(arg_dependency, DEPENDENCY_AFTER, DEPENDENCY_BEFORE)) {
1691 *deps = info.dep[0];
1692 return 0;
1693 }
55c0b89c 1694
32b47279
YW
1695 for (i = 0; i < 5; i++) {
1696 r = strv_extend_strv(&ret, info.dep[i], true);
f459b602 1697 if (r < 0)
32b47279
YW
1698 return log_oom();
1699 info.dep[i] = strv_free(info.dep[i]);
f459b602 1700 }
540e7dbe 1701
1cc6c93a 1702 *deps = TAKE_PTR(ret);
540e7dbe 1703
f459b602 1704 return 0;
55c0b89c
LN
1705}
1706
1707static int list_dependencies_compare(const void *_a, const void *_b) {
1708 const char **a = (const char**) _a, **b = (const char**) _b;
cbc9fbd1 1709
55c0b89c
LN
1710 if (unit_name_to_type(*a) == UNIT_TARGET && unit_name_to_type(*b) != UNIT_TARGET)
1711 return 1;
1712 if (unit_name_to_type(*a) != UNIT_TARGET && unit_name_to_type(*b) == UNIT_TARGET)
1713 return -1;
cbc9fbd1 1714
55c0b89c
LN
1715 return strcasecmp(*a, *b);
1716}
1717
f459b602
MAP
1718static int list_dependencies_one(
1719 sd_bus *bus,
1720 const char *name,
1721 int level,
1722 char ***units,
1723 unsigned int branches) {
1724
e3e45d4f 1725 _cleanup_strv_free_ char **deps = NULL;
55c0b89c 1726 char **c;
55c0b89c
LN
1727 int r = 0;
1728
cbc9fbd1
LP
1729 assert(bus);
1730 assert(name);
1731 assert(units);
1732
e3e45d4f
SP
1733 r = strv_extend(units, name);
1734 if (r < 0)
55c0b89c
LN
1735 return log_oom();
1736
1737 r = list_dependencies_get_dependencies(bus, name, &deps);
1738 if (r < 0)
cec7eda5 1739 return r;
55c0b89c 1740
7ff7394d 1741 qsort_safe(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
55c0b89c
LN
1742
1743 STRV_FOREACH(c, deps) {
e3e45d4f 1744 if (strv_contains(*units, *c)) {
5d0c05e5 1745 if (!arg_plain) {
60705040 1746 printf(" ");
5d0c05e5
LN
1747 r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
1748 if (r < 0)
1749 return r;
1750 }
55c0b89c
LN
1751 continue;
1752 }
1753
250ba664
ZJS
1754 if (arg_plain)
1755 printf(" ");
1756 else {
fa0d5878 1757 UnitActiveState active_state = _UNIT_ACTIVE_STATE_INVALID;
250ba664
ZJS
1758 const char *on;
1759
fa0d5878 1760 (void) get_state_one_unit(bus, *c, &active_state);
baa9ecc1 1761
fa0d5878 1762 switch (active_state) {
baa9ecc1
LP
1763 case UNIT_ACTIVE:
1764 case UNIT_RELOADING:
1765 case UNIT_ACTIVATING:
1766 on = ansi_highlight_green();
1767 break;
1768
1769 case UNIT_INACTIVE:
1770 case UNIT_DEACTIVATING:
1771 on = ansi_normal();
1772 break;
1773
1774 default:
1775 on = ansi_highlight_red();
1776 break;
fa0d5878
BR
1777 }
1778
323b7dc9 1779 printf("%s%s%s ", on, special_glyph(BLACK_CIRCLE), ansi_normal());
250ba664 1780 }
dbc2c080 1781
55c0b89c 1782 r = list_dependencies_print(*c, level, branches, c[1] == NULL);
cec7eda5
ZJS
1783 if (r < 0)
1784 return r;
55c0b89c
LN
1785
1786 if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) {
e3e45d4f 1787 r = list_dependencies_one(bus, *c, level + 1, units, (branches << 1) | (c[1] == NULL ? 0 : 1));
f168c273 1788 if (r < 0)
cec7eda5 1789 return r;
55c0b89c
LN
1790 }
1791 }
f459b602 1792
e3e45d4f
SP
1793 if (!arg_plain)
1794 strv_remove(*units, name);
f459b602 1795
cec7eda5 1796 return 0;
55c0b89c
LN
1797}
1798
e449de87 1799static int list_dependencies(int argc, char *argv[], void *userdata) {
5d0c05e5 1800 _cleanup_strv_free_ char **units = NULL;
f459b602 1801 _cleanup_free_ char *unit = NULL;
e31165b2 1802 const char *u;
4fbd7192 1803 sd_bus *bus;
7410616c 1804 int r;
55c0b89c 1805
e449de87 1806 if (argv[1]) {
37cbc1d5 1807 r = unit_name_mangle(argv[1], arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, &unit);
7410616c
LP
1808 if (r < 0)
1809 return log_error_errno(r, "Failed to mangle unit name: %m");
1810
e31165b2
LP
1811 u = unit;
1812 } else
1813 u = SPECIAL_DEFAULT_TARGET;
55c0b89c 1814
4fbd7192
LP
1815 r = acquire_bus(BUS_MANAGER, &bus);
1816 if (r < 0)
1817 return r;
1818
ee5324aa 1819 (void) pager_open(arg_no_pager, false);
d2ad7e1b 1820
e31165b2
LP
1821 puts(u);
1822
5d0c05e5 1823 return list_dependencies_one(bus, u, 0, &units, 0);
55c0b89c
LN
1824}
1825
0d292f5e
LP
1826struct machine_info {
1827 bool is_host;
1828 char *name;
0d292f5e 1829 char *state;
8fcf784d
LP
1830 char *control_group;
1831 uint32_t n_failed_units;
1832 uint32_t n_jobs;
1833 usec_t timestamp;
1834};
1835
1836static const struct bus_properties_map machine_info_property_map[] = {
1837 { "SystemState", "s", NULL, offsetof(struct machine_info, state) },
1838 { "NJobs", "u", NULL, offsetof(struct machine_info, n_jobs) },
1839 { "NFailedUnits", "u", NULL, offsetof(struct machine_info, n_failed_units) },
1840 { "ControlGroup", "s", NULL, offsetof(struct machine_info, control_group) },
1841 { "UserspaceTimestamp", "t", NULL, offsetof(struct machine_info, timestamp) },
1842 {}
0d292f5e
LP
1843};
1844
e7e55dbd 1845static void machine_info_clear(struct machine_info *info) {
f8654baa
ZJS
1846 assert(info);
1847
1848 free(info->name);
1849 free(info->state);
1850 free(info->control_group);
1851 zero(*info);
e7e55dbd
DH
1852}
1853
0d292f5e
LP
1854static void free_machines_list(struct machine_info *machine_infos, int n) {
1855 int i;
1856
1857 if (!machine_infos)
1858 return;
1859
e7e55dbd
DH
1860 for (i = 0; i < n; i++)
1861 machine_info_clear(&machine_infos[i]);
0d292f5e
LP
1862
1863 free(machine_infos);
1864}
1865
1866static int compare_machine_info(const void *a, const void *b) {
1867 const struct machine_info *u = a, *v = b;
1868
1869 if (u->is_host != v->is_host)
50933da0 1870 return u->is_host > v->is_host ? -1 : 1;
0d292f5e
LP
1871
1872 return strcasecmp(u->name, v->name);
1873}
1874
1875static int get_machine_properties(sd_bus *bus, struct machine_info *mi) {
4afd3348 1876 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *container = NULL;
0d292f5e
LP
1877 int r;
1878
1879 assert(mi);
1880
1881 if (!bus) {
de33fc62 1882 r = sd_bus_open_system_machine(&container, mi->name);
0d292f5e
LP
1883 if (r < 0)
1884 return r;
1885
1886 bus = container;
1887 }
1888
a7e4861c
YW
1889 r = bus_map_all_properties(
1890 bus,
1891 "org.freedesktop.systemd1",
1892 "/org/freedesktop/systemd1",
1893 machine_info_property_map,
1894 BUS_MAP_STRDUP,
1895 NULL,
1896 NULL,
1897 mi);
0d292f5e
LP
1898 if (r < 0)
1899 return r;
1900
1901 return 0;
1902}
1903
1904static bool output_show_machine(const char *name, char **patterns) {
2404701e 1905 return strv_fnmatch_or_empty(patterns, name, FNM_NOESCAPE);
0d292f5e
LP
1906}
1907
1908static int get_machine_list(
1909 sd_bus *bus,
1910 struct machine_info **_machine_infos,
1911 char **patterns) {
1912
1913 struct machine_info *machine_infos = NULL;
1914 _cleanup_strv_free_ char **m = NULL;
1915 _cleanup_free_ char *hn = NULL;
1916 size_t sz = 0;
1917 char **i;
4c3e8e39 1918 int c = 0, r;
0d292f5e
LP
1919
1920 hn = gethostname_malloc();
1921 if (!hn)
1922 return log_oom();
1923
1924 if (output_show_machine(hn, patterns)) {
1925 if (!GREEDY_REALLOC0(machine_infos, sz, c+1))
1926 return log_oom();
1927
1928 machine_infos[c].is_host = true;
ae2a15bc 1929 machine_infos[c].name = TAKE_PTR(hn);
0d292f5e 1930
f9e0eefc 1931 (void) get_machine_properties(bus, &machine_infos[c]);
0d292f5e
LP
1932 c++;
1933 }
1934
4c3e8e39
LP
1935 r = sd_get_machine_names(&m);
1936 if (r < 0)
1937 return log_error_errno(r, "Failed to get machine list: %m");
1938
0d292f5e
LP
1939 STRV_FOREACH(i, m) {
1940 _cleanup_free_ char *class = NULL;
1941
1942 if (!output_show_machine(*i, patterns))
1943 continue;
1944
1945 sd_machine_get_class(*i, &class);
1946 if (!streq_ptr(class, "container"))
1947 continue;
1948
1949 if (!GREEDY_REALLOC0(machine_infos, sz, c+1)) {
1950 free_machines_list(machine_infos, c);
1951 return log_oom();
1952 }
1953
1954 machine_infos[c].is_host = false;
1955 machine_infos[c].name = strdup(*i);
1956 if (!machine_infos[c].name) {
1957 free_machines_list(machine_infos, c);
1958 return log_oom();
1959 }
1960
f9e0eefc 1961 (void) get_machine_properties(NULL, &machine_infos[c]);
0d292f5e
LP
1962 c++;
1963 }
1964
1965 *_machine_infos = machine_infos;
1966 return c;
1967}
1968
1969static void output_machines_list(struct machine_info *machine_infos, unsigned n) {
1970 struct machine_info *m;
1971 unsigned
90c3f79d 1972 circle_len = 0,
fbd0b64f
LP
1973 namelen = STRLEN("NAME"),
1974 statelen = STRLEN("STATE"),
1975 failedlen = STRLEN("FAILED"),
1976 jobslen = STRLEN("JOBS");
0d292f5e
LP
1977
1978 assert(machine_infos || n == 0);
1979
1980 for (m = machine_infos; m < machine_infos + n; m++) {
fbd0b64f
LP
1981 namelen = MAX(namelen,
1982 strlen(m->name) + (m->is_host ? STRLEN(" (host)") : 0));
7bf7ce28 1983 statelen = MAX(statelen, strlen_ptr(m->state));
0d292f5e
LP
1984 failedlen = MAX(failedlen, DECIMAL_STR_WIDTH(m->n_failed_units));
1985 jobslen = MAX(jobslen, DECIMAL_STR_WIDTH(m->n_jobs));
90c3f79d 1986
250ba664 1987 if (!arg_plain && !streq_ptr(m->state, "running"))
90c3f79d 1988 circle_len = 2;
0d292f5e
LP
1989 }
1990
90c3f79d
LP
1991 if (!arg_no_legend) {
1992 if (circle_len > 0)
1993 fputs(" ", stdout);
1994
0d292f5e
LP
1995 printf("%-*s %-*s %-*s %-*s\n",
1996 namelen, "NAME",
1997 statelen, "STATE",
1998 failedlen, "FAILED",
1999 jobslen, "JOBS");
90c3f79d 2000 }
0d292f5e
LP
2001
2002 for (m = machine_infos; m < machine_infos + n; m++) {
90c3f79d
LP
2003 const char *on_state = "", *off_state = "";
2004 const char *on_failed = "", *off_failed = "";
2005 bool circle = false;
0d292f5e
LP
2006
2007 if (streq_ptr(m->state, "degraded")) {
2008 on_state = ansi_highlight_red();
1fc464f6 2009 off_state = ansi_normal();
90c3f79d 2010 circle = true;
0d292f5e
LP
2011 } else if (!streq_ptr(m->state, "running")) {
2012 on_state = ansi_highlight_yellow();
1fc464f6 2013 off_state = ansi_normal();
90c3f79d
LP
2014 circle = true;
2015 }
0d292f5e
LP
2016
2017 if (m->n_failed_units > 0) {
2018 on_failed = ansi_highlight_red();
1fc464f6 2019 off_failed = ansi_normal();
0d292f5e
LP
2020 } else
2021 on_failed = off_failed = "";
2022
90c3f79d 2023 if (circle_len > 0)
323b7dc9 2024 printf("%s%s%s ", on_state, circle ? special_glyph(BLACK_CIRCLE) : " ", off_state);
90c3f79d 2025
0d292f5e 2026 if (m->is_host)
c6ba5b80 2027 printf("%-*s (host) %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n",
fbd0b64f
LP
2028 (int) (namelen - (STRLEN(" (host)"))),
2029 strna(m->name),
0d292f5e
LP
2030 on_state, statelen, strna(m->state), off_state,
2031 on_failed, failedlen, m->n_failed_units, off_failed,
2032 jobslen, m->n_jobs);
2033 else
c6ba5b80 2034 printf("%-*s %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n",
0d292f5e
LP
2035 namelen, strna(m->name),
2036 on_state, statelen, strna(m->state), off_state,
2037 on_failed, failedlen, m->n_failed_units, off_failed,
2038 jobslen, m->n_jobs);
2039 }
2040
2041 if (!arg_no_legend)
2042 printf("\n%u machines listed.\n", n);
2043}
2044
e449de87 2045static int list_machines(int argc, char *argv[], void *userdata) {
0d292f5e 2046 struct machine_info *machine_infos = NULL;
4fbd7192 2047 sd_bus *bus;
0d292f5e
LP
2048 int r;
2049
4fbd7192
LP
2050 r = acquire_bus(BUS_MANAGER, &bus);
2051 if (r < 0)
2052 return r;
2053
e449de87 2054 r = get_machine_list(bus, &machine_infos, strv_skip(argv, 1));
0d292f5e
LP
2055 if (r < 0)
2056 return r;
2057
ee5324aa 2058 (void) pager_open(arg_no_pager, false);
d2ad7e1b 2059
0d292f5e
LP
2060 qsort_safe(machine_infos, r, sizeof(struct machine_info), compare_machine_info);
2061 output_machines_list(machine_infos, r);
2062 free_machines_list(machine_infos, r);
2063
2064 return 0;
2065}
2066
e449de87 2067static int get_default(int argc, char *argv[], void *userdata) {
4afd3348 2068 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
f459b602
MAP
2069 _cleanup_free_ char *_path = NULL;
2070 const char *path;
99504dd4 2071 int r;
99504dd4 2072
4fbd7192 2073 if (install_client_side()) {
f459b602 2074 r = unit_file_get_default(arg_scope, arg_root, &_path);
f647962d
MS
2075 if (r < 0)
2076 return log_error_errno(r, "Failed to get default target: %m");
f459b602 2077 path = _path;
99504dd4 2078
5f056378 2079 r = 0;
99504dd4 2080 } else {
4afd3348 2081 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192
LP
2082 sd_bus *bus;
2083
2084 r = acquire_bus(BUS_MANAGER, &bus);
2085 if (r < 0)
2086 return r;
6e646d22 2087
f459b602
MAP
2088 r = sd_bus_call_method(
2089 bus,
2090 "org.freedesktop.systemd1",
2091 "/org/freedesktop/systemd1",
2092 "org.freedesktop.systemd1.Manager",
2093 "GetDefaultTarget",
2094 &error,
2095 &reply,
2096 NULL);
691395d8
LP
2097 if (r < 0)
2098 return log_error_errno(r, "Failed to get default target: %s", bus_error_message(&error, r));
99504dd4 2099
f459b602
MAP
2100 r = sd_bus_message_read(reply, "s", &path);
2101 if (r < 0)
2102 return bus_log_parse_error(r);
99504dd4
VP
2103 }
2104
2105 if (path)
2106 printf("%s\n", path);
2107
f459b602 2108 return 0;
99504dd4
VP
2109}
2110
e449de87 2111static int set_default(int argc, char *argv[], void *userdata) {
718db961 2112 _cleanup_free_ char *unit = NULL;
acc0269c
CH
2113 UnitFileChange *changes = NULL;
2114 unsigned n_changes = 0;
718db961
LP
2115 int r;
2116
e449de87
LP
2117 assert(argc >= 2);
2118 assert(argv);
2119
37cbc1d5 2120 r = unit_name_mangle_with_suffix(argv[1], arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, ".target", &unit);
7410616c
LP
2121 if (r < 0)
2122 return log_error_errno(r, "Failed to mangle unit name: %m");
718db961 2123
4fbd7192 2124 if (install_client_side()) {
b3796dd8 2125 r = unit_file_set_default(arg_scope, UNIT_FILE_FORCE, arg_root, unit, &changes, &n_changes);
af3d8113 2126 unit_file_dump_changes(r, "set default", changes, n_changes, arg_quiet);
5f056378
CH
2127
2128 if (r > 0)
2129 r = 0;
718db961 2130 } else {
4afd3348
LP
2131 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2132 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
4fbd7192 2133 sd_bus *bus;
718db961 2134
8a4b13c5 2135 polkit_agent_open_maybe();
6e646d22 2136
4fbd7192
LP
2137 r = acquire_bus(BUS_MANAGER, &bus);
2138 if (r < 0)
2139 return r;
2140
6e646d22 2141 r = sd_bus_call_method(
718db961
LP
2142 bus,
2143 "org.freedesktop.systemd1",
2144 "/org/freedesktop/systemd1",
2145 "org.freedesktop.systemd1.Manager",
6e646d22
LP
2146 "SetDefaultTarget",
2147 &error,
2148 &reply,
2149 "sb", unit, 1);
691395d8
LP
2150 if (r < 0)
2151 return log_error_errno(r, "Failed to set default target: %s", bus_error_message(&error, r));
718db961 2152
acc0269c 2153 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
718db961 2154 if (r < 0)
acc0269c 2155 goto finish;
718db961 2156
93c941e3 2157 /* Try to reload if enabled */
718db961 2158 if (!arg_no_reload)
e449de87 2159 r = daemon_reload(argc, argv, userdata);
718db961
LP
2160 else
2161 r = 0;
2162 }
2163
acc0269c
CH
2164finish:
2165 unit_file_changes_free(changes, n_changes);
2166
718db961
LP
2167 return r;
2168}
2169
76d8ca22 2170static int output_waiting_jobs(sd_bus *bus, uint32_t id, const char *method, const char *prefix) {
82948f6c
LP
2171 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2172 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
2173 const char *name, *type, *state, *job_path, *unit_path;
2174 uint32_t other_id;
2175 int r;
2176
2177 assert(bus);
2178
2179 r = sd_bus_call_method(
2180 bus,
2181 "org.freedesktop.systemd1",
2182 "/org/freedesktop/systemd1",
2183 "org.freedesktop.systemd1.Manager",
2184 method,
2185 &error,
2186 &reply,
2187 "u", id);
76d8ca22
ZJS
2188 if (r < 0)
2189 return log_debug_errno(r, "Failed to get waiting jobs for job %" PRIu32, id);
82948f6c
LP
2190
2191 r = sd_bus_message_enter_container(reply, 'a', "(usssoo)");
76d8ca22
ZJS
2192 if (r < 0)
2193 return bus_log_parse_error(r);
82948f6c
LP
2194
2195 while ((r = sd_bus_message_read(reply, "(usssoo)", &other_id, &name, &type, &state, &job_path, &unit_path)) > 0)
bc357ce5 2196 printf("%s %u (%s/%s)\n", prefix, other_id, name, type);
76d8ca22
ZJS
2197 if (r < 0)
2198 return bus_log_parse_error(r);
82948f6c
LP
2199
2200 r = sd_bus_message_exit_container(reply);
76d8ca22
ZJS
2201 if (r < 0)
2202 return bus_log_parse_error(r);
2203
2204 return 0;
82948f6c
LP
2205}
2206
75add28a
ZJS
2207struct job_info {
2208 uint32_t id;
f459b602 2209 const char *name, *type, *state;
75add28a
ZJS
2210};
2211
82948f6c 2212static void output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n, bool skipped) {
f459b602
MAP
2213 unsigned id_len, unit_len, type_len, state_len;
2214 const struct job_info *j;
75add28a
ZJS
2215 const char *on, *off;
2216 bool shorten = false;
2217
2218 assert(n == 0 || jobs);
2219
2220 if (n == 0) {
250ba664
ZJS
2221 if (!arg_no_legend) {
2222 on = ansi_highlight_green();
1fc464f6 2223 off = ansi_normal();
75add28a 2224
250ba664
ZJS
2225 printf("%sNo jobs %s.%s\n", on, skipped ? "listed" : "running", off);
2226 }
75add28a
ZJS
2227 return;
2228 }
2229
ee5324aa 2230 (void) pager_open(arg_no_pager, false);
75add28a 2231
fbd0b64f
LP
2232 id_len = STRLEN("JOB");
2233 unit_len = STRLEN("UNIT");
2234 type_len = STRLEN("TYPE");
2235 state_len = STRLEN("STATE");
6d6d40c9 2236
f459b602
MAP
2237 for (j = jobs; j < jobs + n; j++) {
2238 uint32_t id = j->id;
2239 assert(j->name && j->type && j->state);
75add28a 2240
f459b602
MAP
2241 id_len = MAX(id_len, DECIMAL_STR_WIDTH(id));
2242 unit_len = MAX(unit_len, strlen(j->name));
2243 type_len = MAX(type_len, strlen(j->type));
2244 state_len = MAX(state_len, strlen(j->state));
2245 }
75add28a 2246
f459b602
MAP
2247 if (!arg_full && id_len + 1 + unit_len + type_len + 1 + state_len > columns()) {
2248 unit_len = MAX(33u, columns() - id_len - type_len - state_len - 3);
2249 shorten = true;
2250 }
75add28a 2251
6ce774fd
MM
2252 if (!arg_no_legend)
2253 printf("%*s %-*s %-*s %-*s\n",
2254 id_len, "JOB",
2255 unit_len, "UNIT",
2256 type_len, "TYPE",
2257 state_len, "STATE");
75add28a 2258
f459b602
MAP
2259 for (j = jobs; j < jobs + n; j++) {
2260 _cleanup_free_ char *e = NULL;
75add28a 2261
f459b602
MAP
2262 if (streq(j->state, "running")) {
2263 on = ansi_highlight();
1fc464f6 2264 off = ansi_normal();
f459b602
MAP
2265 } else
2266 on = off = "";
2267
2268 e = shorten ? ellipsize(j->name, unit_len, 33) : NULL;
2269 printf("%*u %s%-*s%s %-*s %s%-*s%s\n",
2270 id_len, j->id,
2271 on, unit_len, e ? e : j->name, off,
2272 type_len, j->type,
2273 on, state_len, j->state, off);
82948f6c
LP
2274
2275 if (arg_jobs_after)
bc357ce5 2276 output_waiting_jobs(bus, j->id, "GetJobAfter", "\twaiting for job");
82948f6c 2277 if (arg_jobs_before)
bc357ce5 2278 output_waiting_jobs(bus, j->id, "GetJobBefore", "\tblocking job");
75add28a
ZJS
2279 }
2280
6ce774fd
MM
2281 if (!arg_no_legend) {
2282 on = ansi_highlight();
1fc464f6 2283 off = ansi_normal();
75add28a 2284
6ce774fd
MM
2285 printf("\n%s%u jobs listed%s.\n", on, n, off);
2286 }
75add28a
ZJS
2287}
2288
d8fba7c6 2289static bool output_show_job(struct job_info *job, char **patterns) {
2404701e 2290 return strv_fnmatch_or_empty(patterns, job->name, FNM_NOESCAPE);
d8fba7c6
ZJS
2291}
2292
e449de87 2293static int list_jobs(int argc, char *argv[], void *userdata) {
4afd3348
LP
2294 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2295 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
f459b602
MAP
2296 const char *name, *type, *state, *job_path, *unit_path;
2297 _cleanup_free_ struct job_info *jobs = NULL;
2298 size_t size = 0;
2299 unsigned c = 0;
4fbd7192 2300 sd_bus *bus;
f459b602 2301 uint32_t id;
f84190d8 2302 int r;
d8fba7c6 2303 bool skipped = false;
ec14911e 2304
4fbd7192
LP
2305 r = acquire_bus(BUS_MANAGER, &bus);
2306 if (r < 0)
2307 return r;
2308
f459b602 2309 r = sd_bus_call_method(
f22f08cd
SP
2310 bus,
2311 "org.freedesktop.systemd1",
2312 "/org/freedesktop/systemd1",
2313 "org.freedesktop.systemd1.Manager",
2314 "ListJobs",
f459b602 2315 &error,
f22f08cd 2316 &reply,
f459b602 2317 NULL);
691395d8
LP
2318 if (r < 0)
2319 return log_error_errno(r, "Failed to list jobs: %s", bus_error_message(&error, r));
7e4249b9 2320
f459b602
MAP
2321 r = sd_bus_message_enter_container(reply, 'a', "(usssoo)");
2322 if (r < 0)
2323 return bus_log_parse_error(r);
7e4249b9 2324
f459b602 2325 while ((r = sd_bus_message_read(reply, "(usssoo)", &id, &name, &type, &state, &job_path, &unit_path)) > 0) {
d8fba7c6
ZJS
2326 struct job_info job = { id, name, type, state };
2327
e449de87 2328 if (!output_show_job(&job, strv_skip(argv, 1))) {
d8fba7c6
ZJS
2329 skipped = true;
2330 continue;
2331 }
8fe914ec 2332
f459b602
MAP
2333 if (!GREEDY_REALLOC(jobs, size, c + 1))
2334 return log_oom();
7e4249b9 2335
d8fba7c6 2336 jobs[c++] = job;
7e4249b9 2337 }
f459b602
MAP
2338 if (r < 0)
2339 return bus_log_parse_error(r);
7e4249b9 2340
f459b602
MAP
2341 r = sd_bus_message_exit_container(reply);
2342 if (r < 0)
2343 return bus_log_parse_error(r);
f73e33d9 2344
ee5324aa 2345 (void) pager_open(arg_no_pager, false);
d2ad7e1b 2346
82948f6c 2347 output_jobs_list(bus, jobs, c, skipped);
91d0f17e 2348 return 0;
7e4249b9
LP
2349}
2350
e449de87 2351static int cancel_job(int argc, char *argv[], void *userdata) {
4fbd7192 2352 sd_bus *bus;
729e3769 2353 char **name;
342641fb 2354 int r = 0;
7e4249b9 2355
e449de87 2356 if (argc <= 1)
2853b60a 2357 return trivial_method(argc, argv, userdata);
ee5762e3 2358
4fbd7192
LP
2359 r = acquire_bus(BUS_MANAGER, &bus);
2360 if (r < 0)
2361 return r;
2362
8a4b13c5 2363 polkit_agent_open_maybe();
d2ad7e1b 2364
e449de87 2365 STRV_FOREACH(name, strv_skip(argv, 1)) {
4afd3348 2366 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5dd9014f 2367 uint32_t id;
342641fb 2368 int q;
7e4249b9 2369
342641fb 2370 q = safe_atou32(*name, &id);
f647962d
MS
2371 if (q < 0)
2372 return log_error_errno(q, "Failed to parse job id \"%s\": %m", *name);
7e4249b9 2373
6e646d22 2374 q = sd_bus_call_method(
f22f08cd
SP
2375 bus,
2376 "org.freedesktop.systemd1",
2377 "/org/freedesktop/systemd1",
2378 "org.freedesktop.systemd1.Manager",
6e646d22
LP
2379 "CancelJob",
2380 &error,
2381 NULL,
2382 "u", id);
342641fb 2383 if (q < 0) {
691395d8 2384 log_error_errno(q, "Failed to cancel job %"PRIu32": %s", id, bus_error_message(&error, q));
342641fb
LP
2385 if (r == 0)
2386 r = q;
f459b602 2387 }
7e4249b9
LP
2388 }
2389
342641fb 2390 return r;
7e4249b9
LP
2391}
2392
f459b602 2393static int need_daemon_reload(sd_bus *bus, const char *unit) {
4afd3348 2394 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
f459b602
MAP
2395 const char *path;
2396 int b, r;
94c01aeb 2397
f459b602
MAP
2398 /* We ignore all errors here, since this is used to show a
2399 * warning only */
45fb0699 2400
f459b602
MAP
2401 /* We don't use unit_dbus_path_from_name() directly since we
2402 * don't want to load the unit if it isn't loaded. */
f84190d8 2403
f459b602 2404 r = sd_bus_call_method(
f22f08cd
SP
2405 bus,
2406 "org.freedesktop.systemd1",
2407 "/org/freedesktop/systemd1",
2408 "org.freedesktop.systemd1.Manager",
2409 "GetUnit",
f459b602 2410 NULL,
f22f08cd 2411 &reply,
e3e0314b 2412 "s", unit);
f84190d8
LP
2413 if (r < 0)
2414 return r;
45fb0699 2415
f459b602
MAP
2416 r = sd_bus_message_read(reply, "o", &path);
2417 if (r < 0)
2418 return r;
f84190d8 2419
f459b602 2420 r = sd_bus_get_property_trivial(
f22f08cd 2421 bus,
b0193f1c
LP
2422 "org.freedesktop.systemd1",
2423 path,
f459b602
MAP
2424 "org.freedesktop.systemd1.Unit",
2425 "NeedDaemonReload",
2426 NULL,
2427 'b', &b);
f84190d8
LP
2428 if (r < 0)
2429 return r;
45fb0699 2430
45fb0699
LP
2431 return b;
2432}
2433
3f36991e 2434static void warn_unit_file_changed(const char *name) {
87ec20ef
LP
2435 assert(name);
2436
e9f4aabd 2437 log_warning("%sWarning:%s The unit file, source configuration file or drop-ins of %s changed on disk. Run 'systemctl%s daemon-reload' to reload units.",
3f36991e 2438 ansi_highlight_red(),
1fc464f6 2439 ansi_normal(),
3f36991e
ZJS
2440 name,
2441 arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
2442}
2443
33f6c497
ZJS
2444static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **unit_path) {
2445 char **p;
2446
2447 assert(lp);
2448 assert(unit_name);
33f6c497 2449
a3c4eb07 2450 STRV_FOREACH(p, lp->search_path) {
c6dd36b6
FS
2451 _cleanup_free_ char *path = NULL, *lpath = NULL;
2452 int r;
33f6c497 2453
3ef21542 2454 path = path_join(NULL, *p, unit_name);
33f6c497
ZJS
2455 if (!path)
2456 return log_oom();
2457
c4f4fce7 2458 r = chase_symlinks(path, arg_root, 0, &lpath);
c6dd36b6
FS
2459 if (r == -ENOENT)
2460 continue;
2461 if (r == -ENOMEM)
2462 return log_oom();
2463 if (r < 0)
2464 return log_error_errno(r, "Failed to access path '%s': %m", path);
2465
ae2a15bc
LP
2466 if (unit_path)
2467 *unit_path = TAKE_PTR(lpath);
2468
c6dd36b6 2469 return 1;
33f6c497
ZJS
2470 }
2471
2472 return 0;
2473}
2474
173471b7
ZJS
2475static int unit_find_template_path(
2476 const char *unit_name,
2477 LookupPaths *lp,
2478 char **fragment_path,
2479 char **template) {
2480
2481 _cleanup_free_ char *_template = NULL;
2482 int r;
2483
2484 /* Returns 1 if a fragment was found, 0 if not found, negative on error. */
2485
2486 r = unit_file_find_path(lp, unit_name, fragment_path);
2487 if (r != 0)
2488 return r; /* error or found a real unit */
2489
2490 r = unit_name_template(unit_name, &_template);
2491 if (r == -EINVAL)
2492 return 0; /* not a template, does not exist */
2493 if (r < 0)
2494 return log_error_errno(r, "Failed to determine template name: %m");
2495
2496 r = unit_file_find_path(lp, _template, fragment_path);
2497 if (r < 0)
2498 return r;
2499
ae2a15bc
LP
2500 if (template)
2501 *template = TAKE_PTR(_template);
2502
173471b7
ZJS
2503 return r;
2504}
2505
6e646d22
LP
2506static int unit_find_paths(
2507 sd_bus *bus,
2508 const char *unit_name,
6e646d22
LP
2509 LookupPaths *lp,
2510 char **fragment_path,
2511 char ***dropin_paths) {
dab2bce8
IS
2512
2513 _cleanup_free_ char *path = NULL;
2514 _cleanup_strv_free_ char **dropins = NULL;
33f6c497
ZJS
2515 int r;
2516
ad2a0358
ZJS
2517 /**
2518 * Finds where the unit is defined on disk. Returns 0 if the unit
2519 * is not found. Returns 1 if it is found, and sets
2520 * - the path to the unit in *path, if it exists on disk,
2521 * - and a strv of existing drop-ins in *dropins,
2522 * if the arg is not NULL and any dropins were found.
2523 */
2524
33f6c497 2525 assert(unit_name);
ad2a0358 2526 assert(fragment_path);
33f6c497
ZJS
2527 assert(lp);
2528
4fbd7192 2529 if (!install_client_side() && !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
4afd3348 2530 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
33f6c497 2531 _cleanup_free_ char *unit = NULL;
33f6c497
ZJS
2532
2533 unit = unit_dbus_path_from_name(unit_name);
2534 if (!unit)
2535 return log_oom();
2536
33f6c497
ZJS
2537 r = sd_bus_get_property_string(
2538 bus,
2539 "org.freedesktop.systemd1",
2540 unit,
2541 "org.freedesktop.systemd1.Unit",
2542 "FragmentPath",
2543 &error,
ad2a0358
ZJS
2544 &path);
2545 if (r < 0)
2546 return log_error_errno(r, "Failed to get FragmentPath: %s", bus_error_message(&error, r));
2547
dab2bce8
IS
2548 if (dropin_paths) {
2549 r = sd_bus_get_property_strv(
2550 bus,
2551 "org.freedesktop.systemd1",
2552 unit,
2553 "org.freedesktop.systemd1.Unit",
2554 "DropInPaths",
2555 &error,
2556 &dropins);
2557 if (r < 0)
2558 return log_error_errno(r, "Failed to get DropInPaths: %s", bus_error_message(&error, r));
33f6c497 2559 }
ad2a0358 2560 } else {
173471b7 2561 _cleanup_set_free_ Set *names = NULL;
6483ad89 2562 _cleanup_free_ char *template = NULL;
33f6c497 2563
ad2a0358
ZJS
2564 names = set_new(NULL);
2565 if (!names)
7410616c 2566 return log_oom();
33f6c497 2567
173471b7 2568 r = unit_find_template_path(unit_name, lp, &path, &template);
ad2a0358
ZJS
2569 if (r < 0)
2570 return r;
2571
173471b7 2572 if (r > 0)
6483ad89
ZJS
2573 /* We found the unit file. If we followed symlinks, this name might be
2574 * different then the unit_name with started with. Look for dropins matching
2575 * that "final" name. */
2576 r = set_put(names, basename(path));
2577 else if (!template)
2578 /* No unit file, let's look for dropins matching the original name.
2579 * systemd has fairly complicated rules (based on unit type and provenience),
2580 * which units are allowed not to have the main unit file. We err on the
2581 * side of including too many files, and always try to load dropins. */
2582 r = set_put(names, unit_name);
2583 else
2584 /* The cases where we allow a unit to exist without the main file are
2585 * never valid for templates. Don't try to load dropins in this case. */
2586 goto not_found;
2587
c6dd36b6
FS
2588 if (r < 0)
2589 return log_error_errno(r, "Failed to add unit name: %m");
2590
dab2bce8 2591 if (dropin_paths) {
95778782
ZJS
2592 r = unit_file_find_dropin_conf_paths(arg_root, lp->search_path,
2593 NULL, names, &dropins);
dab2bce8
IS
2594 if (r < 0)
2595 return r;
2596 }
2597 }
2598
2599 r = 0;
2600
2601 if (!isempty(path)) {
1cc6c93a 2602 *fragment_path = TAKE_PTR(path);
dab2bce8
IS
2603 r = 1;
2604 }
2605
2606 if (dropin_paths && !strv_isempty(dropins)) {
1cc6c93a 2607 *dropin_paths = TAKE_PTR(dropins);
dab2bce8 2608 r = 1;
33f6c497 2609 }
6483ad89 2610 not_found:
39c38ce1 2611 if (r == 0 && !arg_force)
b5e6a600
IS
2612 log_error("No files found for %s.", unit_name);
2613
ad2a0358 2614 return r;
33f6c497
ZJS
2615}
2616
fa0d5878 2617static int get_state_one_unit(sd_bus *bus, const char *name, UnitActiveState *active_state) {
b430f85f 2618 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
3d083b22 2619 _cleanup_free_ char *buf = NULL, *path = NULL;
fa0d5878 2620 UnitActiveState state;
f22f08cd 2621 int r;
701cdcb9 2622
31be1221 2623 assert(name);
fa0d5878 2624 assert(active_state);
701cdcb9 2625
3d083b22
LP
2626 path = unit_dbus_path_from_name(name);
2627 if (!path)
2628 return log_oom();
2629
2630 r = sd_bus_get_property_string(
f22f08cd
SP
2631 bus,
2632 "org.freedesktop.systemd1",
3d083b22
LP
2633 path,
2634 "org.freedesktop.systemd1.Unit",
2635 "ActiveState",
b430f85f 2636 &error,
3d083b22
LP
2637 &buf);
2638 if (r < 0)
2639 return log_error_errno(r, "Failed to retrieve unit state: %s", bus_error_message(&error, r));
b430f85f 2640
3d083b22
LP
2641 state = unit_active_state_from_string(buf);
2642 if (state == _UNIT_ACTIVE_STATE_INVALID) {
2643 log_error("Invalid unit state '%s' for: %s", buf, name);
2644 return -EINVAL;
60f9ba0b 2645 }
701cdcb9 2646
fa0d5878
BR
2647 *active_state = state;
2648 return 0;
701cdcb9
MS
2649}
2650
9d9dd746 2651static int unit_is_masked(sd_bus *bus, const char *name) {
4afd3348 2652 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
9d9dd746 2653 _cleanup_free_ char *path = NULL, *load_state = NULL;
f22f08cd 2654 int r;
701cdcb9 2655
9d9dd746 2656 path = unit_dbus_path_from_name(name);
f459b602
MAP
2657 if (!path)
2658 return log_oom();
701cdcb9 2659
f459b602 2660 r = sd_bus_get_property_string(
d0a5cdb2
JJ
2661 bus,
2662 "org.freedesktop.systemd1",
f459b602
MAP
2663 path,
2664 "org.freedesktop.systemd1.Unit",
2665 "LoadState",
2666 &error,
fa0d5878 2667 &load_state);
691395d8 2668 if (r < 0)
9d9dd746 2669 return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
d0a5cdb2 2670
9d9dd746
ZJS
2671 return streq(load_state, "masked");
2672}
2673
2674static int check_triggering_units(sd_bus *bus, const char *name) {
2675 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2676 _cleanup_free_ char *n = NULL, *path = NULL;
2677 _cleanup_strv_free_ char **triggered_by = NULL;
2678 bool print_warning_label = true;
2679 UnitActiveState active_state;
2680 char **i;
2681 int r;
2682
2683 r = unit_name_mangle(name, 0, &n);
2684 if (r < 0)
2685 return log_error_errno(r, "Failed to mangle unit name: %m");
2686
2687 r = unit_is_masked(bus, n);
2688 if (r != 0)
2689 return r < 0 ? r : 0;
2690
2691 path = unit_dbus_path_from_name(n);
2692 if (!path)
2693 return log_oom();
701cdcb9 2694
f459b602
MAP
2695 r = sd_bus_get_property_strv(
2696 bus,
2697 "org.freedesktop.systemd1",
2698 path,
2699 "org.freedesktop.systemd1.Unit",
2700 "TriggeredBy",
2701 &error,
2702 &triggered_by);
691395d8
LP
2703 if (r < 0)
2704 return log_error_errno(r, "Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r));
701cdcb9 2705
f459b602 2706 STRV_FOREACH(i, triggered_by) {
fa0d5878 2707 r = get_state_one_unit(bus, *i, &active_state);
f647962d 2708 if (r < 0)
fa0d5878 2709 return r;
701cdcb9 2710
fa0d5878 2711 if (!IN_SET(active_state, UNIT_ACTIVE, UNIT_RELOADING))
f459b602 2712 continue;
60f9ba0b 2713
f459b602
MAP
2714 if (print_warning_label) {
2715 log_warning("Warning: Stopping %s, but it can still be activated by:", n);
2716 print_warning_label = false;
701cdcb9 2717 }
1c291cf3 2718
f459b602 2719 log_warning(" %s", *i);
701cdcb9 2720 }
f459b602
MAP
2721
2722 return 0;
701cdcb9
MS
2723}
2724
2fc9a280
LP
2725static const struct {
2726 const char *verb;
2727 const char *method;
2728} unit_actions[] = {
2729 { "start", "StartUnit" },
2730 { "stop", "StopUnit" },
2731 { "condstop", "StopUnit" },
2732 { "reload", "ReloadUnit" },
2733 { "restart", "RestartUnit" },
2734 { "try-restart", "TryRestartUnit" },
2735 { "condrestart", "TryRestartUnit" },
2736 { "reload-or-restart", "ReloadOrRestartUnit" },
aabf5d42 2737 { "try-reload-or-restart", "ReloadOrTryRestartUnit" },
2fc9a280
LP
2738 { "reload-or-try-restart", "ReloadOrTryRestartUnit" },
2739 { "condreload", "ReloadOrTryRestartUnit" },
2740 { "force-reload", "ReloadOrTryRestartUnit" }
2741};
2742
39602c39
TA
2743static const char *verb_to_method(const char *verb) {
2744 uint i;
2745
2746 for (i = 0; i < ELEMENTSOF(unit_actions); i++)
2747 if (streq_ptr(unit_actions[i].verb, verb))
2748 return unit_actions[i].method;
2749
2750 return "StartUnit";
2751}
2752
2753static const char *method_to_verb(const char *method) {
2754 uint i;
2755
2756 for (i = 0; i < ELEMENTSOF(unit_actions); i++)
2757 if (streq_ptr(unit_actions[i].method, method))
2758 return unit_actions[i].verb;
2759
2760 return "n/a";
2761}
2762
93a08841
MP
2763typedef struct {
2764 sd_bus_slot *match;
2765 sd_event *event;
2766 Set *unit_paths;
2767 bool any_failed;
2768} WaitContext;
2769
2770static void wait_context_free(WaitContext *c) {
2771 c->match = sd_bus_slot_unref(c->match);
2772 c->event = sd_event_unref(c->event);
6fa4160d 2773 c->unit_paths = set_free_free(c->unit_paths);
93a08841
MP
2774}
2775
2776static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
2777 WaitContext *c = userdata;
2778 const char *path;
2779 int r;
2780
2781 path = sd_bus_message_get_path(m);
2782 if (!set_contains(c->unit_paths, path))
2783 return 0;
2784
2785 /* Check if ActiveState changed to inactive/failed */
2786 /* (s interface, a{sv} changed_properties, as invalidated_properties) */
2787 r = sd_bus_message_skip(m, "s");
2788 if (r < 0)
2789 return bus_log_parse_error(r);
6fa4160d 2790
93a08841
MP
2791 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
2792 if (r < 0)
2793 return bus_log_parse_error(r);
2794
2795 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
2796 const char *s;
93a08841
MP
2797
2798 r = sd_bus_message_read(m, "s", &s);
2799 if (r < 0)
2800 return bus_log_parse_error(r);
6fa4160d 2801
93a08841 2802 if (streq(s, "ActiveState")) {
6fa4160d
LP
2803 bool is_failed;
2804
93a08841
MP
2805 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "s");
2806 if (r < 0)
2807 return bus_log_parse_error(r);
6fa4160d 2808
93a08841
MP
2809 r = sd_bus_message_read(m, "s", &s);
2810 if (r < 0)
2811 return bus_log_parse_error(r);
6fa4160d 2812
93a08841
MP
2813 is_failed = streq(s, "failed");
2814 if (streq(s, "inactive") || is_failed) {
2815 log_debug("%s became %s, dropping from --wait tracking", path, s);
6fa4160d
LP
2816 free(set_remove(c->unit_paths, path));
2817 c->any_failed = c->any_failed || is_failed;
93a08841
MP
2818 } else
2819 log_debug("ActiveState on %s changed to %s", path, s);
6fa4160d 2820
93a08841
MP
2821 break; /* no need to dissect the rest of the message */
2822 } else {
2823 /* other property */
2824 r = sd_bus_message_skip(m, "v");
2825 if (r < 0)
2826 return bus_log_parse_error(r);
2827 }
2828 r = sd_bus_message_exit_container(m);
2829 if (r < 0)
2830 return bus_log_parse_error(r);
2831 }
2832 if (r < 0)
2833 return bus_log_parse_error(r);
2834
2835 if (set_isempty(c->unit_paths))
2836 sd_event_exit(c->event, EXIT_SUCCESS);
2837
2838 return 0;
2839}
2840
e4b61340 2841static int start_unit_one(
f459b602 2842 sd_bus *bus,
e4b61340
LP
2843 const char *method,
2844 const char *name,
2845 const char *mode,
f459b602 2846 sd_bus_error *error,
93a08841
MP
2847 BusWaitForJobs *w,
2848 WaitContext *wait_context) {
7e4249b9 2849
4afd3348 2850 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
45fb0699 2851 const char *path;
7e4249b9 2852 int r;
7e4249b9 2853
e4b61340
LP
2854 assert(method);
2855 assert(name);
2856 assert(mode);
22f4096c 2857 assert(error);
7e4249b9 2858
93a08841
MP
2859 if (wait_context) {
2860 _cleanup_free_ char *unit_path = NULL;
93a08841
MP
2861
2862 log_debug("Watching for property changes of %s", name);
2863 r = sd_bus_call_method(
2864 bus,
2865 "org.freedesktop.systemd1",
2866 "/org/freedesktop/systemd1",
2867 "org.freedesktop.systemd1.Manager",
2868 "RefUnit",
2869 error,
2870 NULL,
2871 "s", name);
2872 if (r < 0)
2873 return log_error_errno(r, "Failed to RefUnit %s: %s", name, bus_error_message(error, r));
2874
2875 unit_path = unit_dbus_path_from_name(name);
2876 if (!unit_path)
2877 return log_oom();
2878
2879 r = set_put_strdup(wait_context->unit_paths, unit_path);
2880 if (r < 0)
2881 return log_error_errno(r, "Failed to add unit path %s to set: %m", unit_path);
2882
75152a4d
LP
2883 r = sd_bus_match_signal_async(bus,
2884 &wait_context->match,
2885 NULL,
2886 unit_path,
2887 "org.freedesktop.DBus.Properties",
2888 "PropertiesChanged",
2889 on_properties_changed, NULL, wait_context);
93a08841 2890 if (r < 0)
75152a4d 2891 return log_error_errno(r, "Failed to request match for PropertiesChanged signal: %m");
93a08841
MP
2892 }
2893
dbc9830c
ZJS
2894 log_debug("%s dbus call org.freedesktop.systemd1.Manager %s(%s, %s)",
2895 arg_dry_run ? "Would execute" : "Executing",
1ae17672
ZJS
2896 method, name, mode);
2897 if (arg_dry_run)
2898 return 0;
342641fb 2899
6e646d22 2900 r = sd_bus_call_method(
f22f08cd 2901 bus,
b0193f1c
LP
2902 "org.freedesktop.systemd1",
2903 "/org/freedesktop/systemd1",
2904 "org.freedesktop.systemd1.Manager",
6e646d22
LP
2905 method,
2906 error,
2907 &reply,
2908 "ss", name, mode);
f459b602 2909 if (r < 0) {
39602c39
TA
2910 const char *verb;
2911
033f0ab8
LP
2912 /* There's always a fallback possible for legacy actions. */
2913 if (arg_action != ACTION_SYSTEMCTL)
2914 return r;
67f3c402 2915
39602c39
TA
2916 verb = method_to_verb(method);
2917
ee87525c
FB
2918 log_error("Failed to %s %s: %s", verb, name, bus_error_message(error, r));
2919
2920 if (!sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) &&
5b464a18
ZJS
2921 !sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED) &&
2922 !sd_bus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE))
a6405ca2 2923 log_error("See %s logs and 'systemctl%s status%s %s' for details.",
0b8505b7
RC
2924 arg_scope == UNIT_FILE_SYSTEM ? "system" : "user",
2925 arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
a6405ca2 2926 name[0] == '-' ? " --" : "",
0b8505b7 2927 name);
ee87525c
FB
2928
2929 return r;
7e4249b9
LP
2930 }
2931
f459b602
MAP
2932 r = sd_bus_message_read(reply, "o", &path);
2933 if (r < 0)
2934 return bus_log_parse_error(r);
45fb0699 2935
e3e0314b 2936 if (need_daemon_reload(bus, name) > 0)
3f36991e 2937 warn_unit_file_changed(name);
45fb0699 2938
ebd011d9
LP
2939 if (w) {
2940 log_debug("Adding %s to the set", path);
2941 r = bus_wait_for_jobs_add(w, path);
cbc9fbd1
LP
2942 if (r < 0)
2943 return log_oom();
e4b61340 2944 }
7e4249b9 2945
46eddbb5 2946 return 0;
7e4249b9
LP
2947}
2948
e3e0314b 2949static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) {
e3e0314b
ZJS
2950 _cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
2951 char **name;
7410616c 2952 int r, i;
e3e0314b 2953
4fbd7192
LP
2954 assert(bus);
2955 assert(ret);
2956
e3e0314b
ZJS
2957 STRV_FOREACH(name, names) {
2958 char *t;
37cbc1d5 2959 UnitNameMangle options = UNIT_NAME_MANGLE_GLOB | (arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN);
e3e0314b 2960
e80733be 2961 if (suffix)
37cbc1d5 2962 r = unit_name_mangle_with_suffix(*name, options, suffix, &t);
e80733be 2963 else
37cbc1d5 2964 r = unit_name_mangle(*name, options, &t);
7410616c
LP
2965 if (r < 0)
2966 return log_error_errno(r, "Failed to mangle name: %m");
e3e0314b
ZJS
2967
2968 if (string_is_glob(t))
6e18964d 2969 r = strv_consume(&globs, t);
e3e0314b 2970 else
6e18964d
ZJS
2971 r = strv_consume(&mangled, t);
2972 if (r < 0)
e3e0314b 2973 return log_oom();
e3e0314b
ZJS
2974 }
2975
2976 /* Query the manager only if any of the names are a glob, since
2977 * this is fairly expensive */
2978 if (!strv_isempty(globs)) {
4afd3348 2979 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
e3e0314b 2980 _cleanup_free_ UnitInfo *unit_infos = NULL;
1b53f64b 2981 size_t allocated, n;
e3e0314b 2982
1238ee09 2983 r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
e3e0314b
ZJS
2984 if (r < 0)
2985 return r;
2986
1b53f64b
LP
2987 n = strv_length(mangled);
2988 allocated = n + 1;
2989
2990 for (i = 0; i < r; i++) {
2991 if (!GREEDY_REALLOC(mangled, allocated, n+2))
2992 return log_oom();
2993
2994 mangled[n] = strdup(unit_infos[i].id);
2995 if (!mangled[n])
e3e0314b 2996 return log_oom();
1b53f64b
LP
2997
2998 mangled[++n] = NULL;
2999 }
e3e0314b
ZJS
3000 }
3001
1cc6c93a 3002 *ret = TAKE_PTR(mangled);
1238ee09 3003
e3e0314b
ZJS
3004 return 0;
3005}
3006
47a0eaa6
MS
3007static const struct {
3008 const char *target;
3009 const char *verb;
3010 const char *mode;
3011} action_table[_ACTION_MAX] = {
e68c79db
ML
3012 [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" },
3013 [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
3014 [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" },
3015 [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" },
3016 [ACTION_RUNLEVEL2] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
3017 [ACTION_RUNLEVEL3] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
3018 [ACTION_RUNLEVEL4] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
3019 [ACTION_RUNLEVEL5] = { SPECIAL_GRAPHICAL_TARGET, NULL, "isolate" },
3020 [ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" },
3021 [ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" },
3022 [ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" },
3023 [ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" },
3024 [ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" },
3025 [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" },
3026 [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
3027 [ACTION_SUSPEND_THEN_HIBERNATE] = { SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET, "suspend-then-hibernate", "replace-irreversibly" },
47a0eaa6
MS
3028};
3029
514f4ef5 3030static enum action verb_to_action(const char *verb) {
47a0eaa6
MS
3031 enum action i;
3032
913c1916 3033 for (i = 0; i < _ACTION_MAX; i++)
f459b602 3034 if (streq_ptr(action_table[i].verb, verb))
47a0eaa6 3035 return i;
514f4ef5 3036
f459b602
MAP
3037 return _ACTION_INVALID;
3038}
e4b61340 3039
e449de87 3040static int start_unit(int argc, char *argv[], void *userdata) {
ebd011d9 3041 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
08073121 3042 const char *method, *mode, *one_name, *suffix = NULL;
ebd011d9 3043 _cleanup_strv_free_ char **names = NULL;
4fbd7192 3044 sd_bus *bus;
93a08841 3045 _cleanup_(wait_context_free) WaitContext wait_context = {};
729e3769 3046 char **name;
b6520546 3047 int r = 0;
e4b61340 3048
f886603b
AJ
3049 if (arg_wait && !STR_IN_SET(argv[0], "start", "restart")) {
3050 log_error("--wait may only be used with the 'start' or 'restart' commands.");
93a08841
MP
3051 return -EINVAL;
3052 }
3053
3054 /* we cannot do sender tracking on the private bus, so we need the full
3055 * one for RefUnit to implement --wait */
3056 r = acquire_bus(arg_wait ? BUS_FULL : BUS_MANAGER, &bus);
4fbd7192
LP
3057 if (r < 0)
3058 return r;
3059
d2ad7e1b 3060 ask_password_agent_open_if_enabled();
8a4b13c5 3061 polkit_agent_open_maybe();
d2ad7e1b 3062
e4b61340 3063 if (arg_action == ACTION_SYSTEMCTL) {
47a0eaa6 3064 enum action action;
e4b61340 3065
e449de87
LP
3066 action = verb_to_action(argv[0]);
3067
913c1916
AJ
3068 if (action != _ACTION_INVALID) {
3069 method = "StartUnit";
3070 mode = action_table[action].mode;
3071 one_name = action_table[action].target;
3072 } else {
3073 if (streq(argv[0], "isolate")) {
3074 method = "StartUnit";
3075 mode = "isolate";
3076
3077 suffix = ".target";
3078 } else {
3079 method = verb_to_method(argv[0]);
3080 mode = arg_job_mode;
3081 }
3082 one_name = NULL;
3083 }
e4b61340 3084 } else {
78ca9099 3085 assert(arg_action >= 0 && arg_action < _ACTION_MAX);
47a0eaa6 3086 assert(action_table[arg_action].target);
913c1916 3087 assert(action_table[arg_action].mode);
e4b61340
LP
3088
3089 method = "StartUnit";
47a0eaa6 3090 mode = action_table[arg_action].mode;
e3e0314b 3091 one_name = action_table[arg_action].target;
514f4ef5
LP
3092 }
3093
e3e0314b
ZJS
3094 if (one_name)
3095 names = strv_new(one_name, NULL);
3096 else {
e449de87 3097 r = expand_names(bus, strv_skip(argv, 1), suffix, &names);
e3e0314b 3098 if (r < 0)
691395d8 3099 return log_error_errno(r, "Failed to expand names: %m");
e3e0314b 3100 }
b6520546 3101
6e905d93 3102 if (!arg_no_block) {
ebd011d9 3103 r = bus_wait_for_jobs_new(bus, &w);
f647962d
MS
3104 if (r < 0)
3105 return log_error_errno(r, "Could not watch jobs: %m");
e4b61340
LP
3106 }
3107
93a08841 3108 if (arg_wait) {
93a08841
MP
3109 wait_context.unit_paths = set_new(&string_hash_ops);
3110 if (!wait_context.unit_paths)
3111 return log_oom();
3112
31b2cd5d 3113 r = sd_bus_call_method_async(
93a08841 3114 bus,
31b2cd5d 3115 NULL,
93a08841
MP
3116 "org.freedesktop.systemd1",
3117 "/org/freedesktop/systemd1",
3118 "org.freedesktop.systemd1.Manager",
3119 "Subscribe",
31b2cd5d
LP
3120 NULL, NULL,
3121 NULL);
93a08841 3122 if (r < 0)
31b2cd5d 3123 return log_error_errno(r, "Failed to enable subscription: %m");
93a08841
MP
3124 r = sd_event_default(&wait_context.event);
3125 if (r < 0)
3126 return log_error_errno(r, "Failed to allocate event loop: %m");
3127 r = sd_bus_attach_event(bus, wait_context.event, 0);
3128 if (r < 0)
3129 return log_error_errno(r, "Failed to attach bus to event loop: %m");
3130 }
3131
b6520546 3132 STRV_FOREACH(name, names) {
4afd3348 3133 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
b6520546 3134 int q;
f459b602 3135
93a08841 3136 q = start_unit_one(bus, method, *name, mode, &error, w, arg_wait ? &wait_context : NULL);
e3e0314b 3137 if (r >= 0 && q < 0)
b6520546 3138 r = translate_bus_error_to_exit_status(q, &error);
e4b61340
LP
3139 }
3140
67f3c402 3141 if (!arg_no_block) {
c11bda1e
ZJS
3142 int q, arg_count = 0;
3143 const char* extra_args[4] = {};
4524439e 3144
4524439e
ZJS
3145 if (arg_scope != UNIT_FILE_SYSTEM)
3146 extra_args[arg_count++] = "--user";
3147
3148 assert(IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_REMOTE, BUS_TRANSPORT_MACHINE));
3149 if (arg_transport == BUS_TRANSPORT_REMOTE) {
3150 extra_args[arg_count++] = "-H";
3151 extra_args[arg_count++] = arg_host;
3152 } else if (arg_transport == BUS_TRANSPORT_MACHINE) {
3153 extra_args[arg_count++] = "-M";
3154 extra_args[arg_count++] = arg_host;
3155 }
f459b602 3156
4524439e 3157 q = bus_wait_for_jobs(w, arg_quiet, extra_args);
f459b602
MAP
3158 if (q < 0)
3159 return q;
49111a70
ZJS
3160
3161 /* When stopping units, warn if they can still be triggered by
3162 * another active unit (socket, path, timer) */
b6520546
ZJS
3163 if (!arg_quiet && streq(method, "StopUnit"))
3164 STRV_FOREACH(name, names)
3165 check_triggering_units(bus, *name);
67f3c402 3166 }
514f4ef5 3167
93a08841
MP
3168 if (r >= 0 && arg_wait) {
3169 int q;
3170 q = sd_event_loop(wait_context.event);
3171 if (q < 0)
3172 return log_error_errno(q, "Failed to run event loop: %m");
3173 if (wait_context.any_failed)
3174 r = EXIT_FAILURE;
3175 }
3176
f459b602 3177 return r;
e4b61340
LP
3178}
3179
349cc4a5 3180#if ENABLE_LOGIND
4fbd7192 3181static int logind_set_wall_message(void) {
4afd3348 3182 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192 3183 sd_bus *bus;
f2d11d35
LP
3184 _cleanup_free_ char *m = NULL;
3185 int r;
3186
4fbd7192
LP
3187 r = acquire_bus(BUS_FULL, &bus);
3188 if (r < 0)
3189 return r;
f2d11d35
LP
3190
3191 m = strv_join(arg_wall, " ");
3192 if (!m)
3193 return log_oom();
3194
dbc9830c
ZJS
3195 log_debug("%s wall message \"%s\".", arg_dry_run ? "Would set" : "Setting", m);
3196 if (arg_dry_run)
3197 return 0;
3198
f2d11d35
LP
3199 r = sd_bus_call_method(
3200 bus,
3201 "org.freedesktop.login1",
3202 "/org/freedesktop/login1",
3203 "org.freedesktop.login1.Manager",
3204 "SetWallMessage",
3205 &error,
3206 NULL,
3207 "sb",
3208 m,
3209 !arg_no_wall);
3210
3211 if (r < 0)
3212 return log_warning_errno(r, "Failed to set wall message, ignoring: %s", bus_error_message(&error, r));
f2d11d35
LP
3213 return 0;
3214}
79f1c8f6 3215#endif
f2d11d35 3216
7e59bfcb
LP
3217/* Ask systemd-logind, which might grant access to unprivileged users
3218 * through PolicyKit */
4fbd7192 3219static int logind_reboot(enum action a) {
349cc4a5 3220#if ENABLE_LOGIND
4afd3348 3221 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
58158dc7 3222 const char *method, *description;
4fbd7192 3223 sd_bus *bus;
f459b602 3224 int r;
4c80c73c 3225
4fbd7192
LP
3226 r = acquire_bus(BUS_FULL, &bus);
3227 if (r < 0)
3228 return r;
f2d11d35 3229
4c80c73c
KS
3230 switch (a) {
3231
36b69c31
LP
3232 case ACTION_POWEROFF:
3233 method = "PowerOff";
3234 description = "power off system";
3235 break;
3236
4c80c73c
KS
3237 case ACTION_REBOOT:
3238 method = "Reboot";
58158dc7 3239 description = "reboot system";
4c80c73c
KS
3240 break;
3241
36b69c31
LP
3242 case ACTION_HALT:
3243 method = "Halt";
3244 description = "halt system";
4c80c73c
KS
3245 break;
3246
d889a206
LP
3247 case ACTION_SUSPEND:
3248 method = "Suspend";
58158dc7 3249 description = "suspend system";
d889a206
LP
3250 break;
3251
3252 case ACTION_HIBERNATE:
3253 method = "Hibernate";
58158dc7 3254 description = "hibernate system";
d889a206
LP
3255 break;
3256
6524990f
LP
3257 case ACTION_HYBRID_SLEEP:
3258 method = "HybridSleep";
58158dc7 3259 description = "put system into hybrid sleep";
6524990f
LP
3260 break;
3261
e68c79db
ML
3262 case ACTION_SUSPEND_THEN_HIBERNATE:
3263 method = "SuspendThenHibernate";
c58493c0
ML
3264 description = "put system into suspend followed by hibernate";
3265 break;
3266
4c80c73c
KS
3267 default:
3268 return -EINVAL;
3269 }
3270
8a4b13c5 3271 polkit_agent_open_maybe();
d2ad7e1b
ZJS
3272 (void) logind_set_wall_message();
3273
dbc9830c
ZJS
3274 log_debug("%s org.freedesktop.login1.Manager %s dbus call.", arg_dry_run ? "Would execute" : "Executing", method);
3275 if (arg_dry_run)
3276 return 0;
3277
f459b602 3278 r = sd_bus_call_method(
f22f08cd
SP
3279 bus,
3280 "org.freedesktop.login1",
3281 "/org/freedesktop/login1",
3282 "org.freedesktop.login1.Manager",
3283 method,
f459b602 3284 &error,
f22f08cd 3285 NULL,
342641fb 3286 "b", arg_ask_password);
f459b602 3287 if (r < 0)
691395d8 3288 return log_error_errno(r, "Failed to %s via logind: %s", description, bus_error_message(&error, r));
f459b602 3289
691395d8 3290 return 0;
4c80c73c
KS
3291#else
3292 return -ENOSYS;
3293#endif
3294}
3295
4fbd7192 3296static int logind_check_inhibitors(enum action a) {
349cc4a5 3297#if ENABLE_LOGIND
4afd3348 3298 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
59164be4 3299 _cleanup_strv_free_ char **sessions = NULL;
f459b602
MAP
3300 const char *what, *who, *why, *mode;
3301 uint32_t uid, pid;
4fbd7192 3302 sd_bus *bus;
f459b602 3303 unsigned c = 0;
59164be4 3304 char **s;
f459b602 3305 int r;
b37844d3 3306
748ebafa
LP
3307 if (arg_ignore_inhibitors || arg_force > 0)
3308 return 0;
3309
3310 if (arg_when > 0)
3311 return 0;
3312
3313 if (geteuid() == 0)
b37844d3
LP
3314 return 0;
3315
3316 if (!on_tty())
3317 return 0;
e08ab379
LP
3318
3319 if (arg_transport != BUS_TRANSPORT_LOCAL)
3320 return 0;
b37844d3 3321
4fbd7192
LP
3322 r = acquire_bus(BUS_FULL, &bus);
3323 if (r < 0)
3324 return r;
3325
f459b602 3326 r = sd_bus_call_method(
b37844d3
LP
3327 bus,
3328 "org.freedesktop.login1",
3329 "/org/freedesktop/login1",
3330 "org.freedesktop.login1.Manager",
3331 "ListInhibitors",
b37844d3 3332 NULL,
f459b602
MAP
3333 &reply,
3334 NULL);
b37844d3
LP
3335 if (r < 0)
3336 /* If logind is not around, then there are no inhibitors... */
3337 return 0;
3338
4aa2beac 3339 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
f459b602
MAP
3340 if (r < 0)
3341 return bus_log_parse_error(r);
b37844d3 3342
4aa2beac 3343 while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
59164be4 3344 _cleanup_free_ char *comm = NULL, *user = NULL;
f459b602 3345 _cleanup_strv_free_ char **sv = NULL;
b37844d3
LP
3346
3347 if (!streq(mode, "block"))
f459b602 3348 continue;
b37844d3
LP
3349
3350 sv = strv_split(what, ":");
3351 if (!sv)
3352 return log_oom();
3353
ee043777 3354 if (!pid_is_valid((pid_t) pid)) {
72b3f82e 3355 log_error("Invalid PID "PID_FMT".", (pid_t) pid);
ee043777
LP
3356 return -ERANGE;
3357 }
d028e018 3358
b37844d3 3359 if (!strv_contains(sv,
4c315c2c
IS
3360 IN_SET(a,
3361 ACTION_HALT,
3362 ACTION_POWEROFF,
3363 ACTION_REBOOT,
3364 ACTION_KEXEC) ? "shutdown" : "sleep"))
f459b602 3365 continue;
b37844d3
LP
3366
3367 get_process_comm(pid, &comm);
59164be4 3368 user = uid_to_name(uid);
f459b602 3369
de0671ee 3370 log_warning("Operation inhibited by \"%s\" (PID "PID_FMT" \"%s\", user %s), reason is \"%s\".",
d028e018 3371 who, (pid_t) pid, strna(comm), strna(user), why);
b37844d3 3372
f459b602 3373 c++;
b37844d3 3374 }
f459b602
MAP
3375 if (r < 0)
3376 return bus_log_parse_error(r);
b37844d3 3377
f459b602
MAP
3378 r = sd_bus_message_exit_container(reply);
3379 if (r < 0)
3380 return bus_log_parse_error(r);
b37844d3 3381
59164be4
LP
3382 /* Check for current sessions */
3383 sd_get_sessions(&sessions);
3384 STRV_FOREACH(s, sessions) {
59164be4
LP
3385 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
3386
3387 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
3388 continue;
3389
3390 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
3391 continue;
3392
28abce5d 3393 if (sd_session_get_type(*s, &type) < 0 || !STR_IN_SET(type, "x11", "wayland", "tty", "mir"))
59164be4
LP
3394 continue;
3395
3396 sd_session_get_tty(*s, &tty);
3397 sd_session_get_seat(*s, &seat);
3398 sd_session_get_service(*s, &service);
3399 user = uid_to_name(uid);
3400
3401 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
3402 c++;
3403 }
3404
b37844d3
LP
3405 if (c <= 0)
3406 return 0;
3407
59164be4 3408 log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
47a0eaa6 3409 action_table[a].verb);
b37844d3
LP
3410
3411 return -EPERM;
3412#else
3413 return 0;
3414#endif
3415}
3416
4fbd7192 3417static int logind_prepare_firmware_setup(void) {
349cc4a5 3418#if ENABLE_LOGIND
4afd3348 3419 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192 3420 sd_bus *bus;
a4921cf4
JJ
3421 int r;
3422
4fbd7192
LP
3423 r = acquire_bus(BUS_FULL, &bus);
3424 if (r < 0)
3425 return r;
a4921cf4 3426
a4921cf4
JJ
3427 r = sd_bus_call_method(
3428 bus,
3429 "org.freedesktop.login1",
3430 "/org/freedesktop/login1",
3431 "org.freedesktop.login1.Manager",
3432 "SetRebootToFirmwareSetup",
3433 &error,
3434 NULL,
3435 "b", true);
4fbd7192
LP
3436 if (r < 0)
3437 return log_error_errno(r, "Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
a4921cf4
JJ
3438
3439 return 0;
3440#else
3441 log_error("Cannot remotely indicate to EFI to boot into setup mode.");
4fbd7192 3442 return -ENOSYS;
a4921cf4
JJ
3443#endif
3444}
3445
4fbd7192
LP
3446static int prepare_firmware_setup(void) {
3447 int r;
3448
3449 if (!arg_firmware_setup)
3450 return 0;
3451
3452 if (arg_transport == BUS_TRANSPORT_LOCAL) {
3453
3454 r = efi_set_reboot_to_firmware(true);
3455 if (r < 0)
3456 log_debug_errno(r, "Cannot indicate to EFI to boot into setup mode, will retry via logind: %m");
3457 else
3458 return r;
3459 }
3460
3461 return logind_prepare_firmware_setup();
3462}
3463
4bb2e9d4
ZJS
3464static int load_kexec_kernel(void) {
3465 _cleanup_(boot_config_free) BootConfig config = {};
5caa3167 3466 _cleanup_free_ char *where = NULL, *kernel = NULL, *initrd = NULL, *options = NULL;
4bb2e9d4
ZJS
3467 const BootEntry *e;
3468 pid_t pid;
3469 int r;
3470
3471 if (kexec_loaded()) {
3472 log_debug("Kexec kernel already loaded.");
3473 return 0;
3474 }
3475
c0d73214
ZJS
3476 if (access(KEXEC, X_OK) < 0)
3477 return log_error_errno(errno, KEXEC" is not available: %m");
3478
5caa3167
LP
3479 r = find_esp_and_warn(arg_esp_path, false, &where, NULL, NULL, NULL, NULL);
3480 if (r == -ENOKEY) /* find_esp_and_warn() doesn't warn about this case */
3481 return log_error_errno(r, "Cannot find the ESP partition mount point.");
3482 if (r < 0) /* But it logs about all these cases, hence don't log here again */
3483 return r;
4bb2e9d4 3484
5caa3167 3485 r = boot_entries_load_config(where, &config);
4bb2e9d4 3486 if (r < 0)
5caa3167 3487 return log_error_errno(r, "Failed to load bootspec config from \"%s/loader\": %m", where);
4bb2e9d4
ZJS
3488
3489 if (config.default_entry < 0) {
3490 log_error("No entry suitable as default, refusing to guess.");
3491 return -ENOENT;
3492 }
3493 e = &config.entries[config.default_entry];
3494
3495 if (strv_length(e->initrd) > 1) {
3496 log_error("Boot entry specifies multiple initrds, which is not supported currently.");
3497 return -EINVAL;
3498 }
3499
5caa3167 3500 kernel = path_join(NULL, where, e->kernel);
4bb2e9d4 3501 if (!strv_isempty(e->initrd))
5caa3167 3502 initrd = path_join(NULL, where, *e->initrd);
4bb2e9d4
ZJS
3503 options = strv_join(e->options, " ");
3504 if (!options)
3505 return log_oom();
3506
cd086a01
ZJS
3507 log_full(arg_quiet ? LOG_DEBUG : LOG_INFO,
3508 "%s "KEXEC" --load \"%s\" --append \"%s\"%s%s%s",
3509 arg_dry_run ? "Would run" : "Running",
3510 kernel,
3511 options,
3512 initrd ? " --initrd \"" : NULL, strempty(initrd), initrd ? "\"" : "");
4bb2e9d4
ZJS
3513 if (arg_dry_run)
3514 return 0;
3515
b6e1fff1 3516 r = safe_fork("(kexec)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
4c253ed1 3517 if (r < 0)
b6e1fff1 3518 return r;
4c253ed1 3519 if (r == 0) {
4bb2e9d4
ZJS
3520 const char* const args[] = {
3521 KEXEC,
3522 "--load", kernel,
3523 "--append", options,
3524 initrd ? "--initrd" : NULL, initrd,
3525 NULL };
3526
3527 /* Child */
4bb2e9d4
ZJS
3528 execv(args[0], (char * const *) args);
3529 _exit(EXIT_FAILURE);
4c253ed1
LP
3530 }
3531
df685d57
ZJS
3532 r = wait_for_terminate_and_check("kexec", pid, WAIT_LOG);
3533 if (r < 0)
3534 return r;
3535 if (r > 0)
3536 /* Command failed */
3537 return -EPROTO;
3538 return 0;
4bb2e9d4
ZJS
3539}
3540
57ab9006 3541static int set_exit_code(uint8_t code) {
4afd3348 3542 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
57ab9006
LP
3543 sd_bus *bus;
3544 int r;
3545
3546 r = acquire_bus(BUS_MANAGER, &bus);
3547 if (r < 0)
3548 return r;
3549
3550 r = sd_bus_call_method(
3551 bus,
3552 "org.freedesktop.systemd1",
3553 "/org/freedesktop/systemd1",
3554 "org.freedesktop.systemd1.Manager",
3555 "SetExitCode",
3556 &error,
3557 NULL,
3558 "y", code);
3559 if (r < 0)
af3d8113 3560 return log_error_errno(r, "Failed to set exit code: %s", bus_error_message(&error, r));
57ab9006
LP
3561
3562 return 0;
3563}
3564
e449de87 3565static int start_special(int argc, char *argv[], void *userdata) {
4c80c73c 3566 enum action a;
983d9c90 3567 int r;
2b0f4e6f
ZJS
3568 bool termination_action; /* an action that terminates the manager,
3569 * can be performed also by signal. */
983d9c90 3570
e449de87 3571 assert(argv);
514f4ef5 3572
e449de87 3573 a = verb_to_action(argv[0]);
4c80c73c 3574
4fbd7192 3575 r = logind_check_inhibitors(a);
748ebafa
LP
3576 if (r < 0)
3577 return r;
3578
fba868fa
LP
3579 if (arg_force >= 2) {
3580 r = must_be_root();
3581 if (r < 0)
3582 return r;
c32b90de
LP
3583 }
3584
4fbd7192 3585 r = prepare_firmware_setup();
a4921cf4
JJ
3586 if (r < 0)
3587 return r;
5bdf2243 3588
e449de87 3589 if (a == ACTION_REBOOT && argc > 1) {
27c06cb5 3590 r = update_reboot_parameter_and_warn(argv[1]);
b986229e
SW
3591 if (r < 0)
3592 return r;
57ab9006 3593
4bb2e9d4
ZJS
3594 } else if (a == ACTION_KEXEC) {
3595 r = load_kexec_kernel();
d23b5ce2
ZJS
3596 if (r < 0 && arg_force >= 1)
3597 log_notice("Failed to load kexec kernel, continuing without.");
3598 else if (r < 0)
4bb2e9d4
ZJS
3599 return r;
3600
e449de87 3601 } else if (a == ACTION_EXIT && argc > 1) {
7bbb5359 3602 uint8_t code;
287419c1 3603
57ab9006
LP
3604 /* If the exit code is not given on the command line,
3605 * don't reset it to zero: just keep it as it might
3606 * have been set previously. */
287419c1 3607
e449de87 3608 r = safe_atou8(argv[1], &code);
4fbd7192 3609 if (r < 0)
57ab9006 3610 return log_error_errno(r, "Invalid exit code.");
4fbd7192 3611
57ab9006 3612 r = set_exit_code(code);
691395d8 3613 if (r < 0)
57ab9006 3614 return r;
b986229e
SW
3615 }
3616
2b0f4e6f
ZJS
3617 termination_action = IN_SET(a,
3618 ACTION_HALT,
3619 ACTION_POWEROFF,
3620 ACTION_REBOOT);
3621 if (termination_action && arg_force >= 2)
477def80 3622 return halt_now(a);
e606bb61 3623
7e59bfcb 3624 if (arg_force >= 1 &&
5955df2c 3625 (termination_action || IN_SET(a, ACTION_KEXEC, ACTION_EXIT)))
2b0f4e6f
ZJS
3626 r = trivial_method(argc, argv, userdata);
3627 else {
3628 /* First try logind, to allow authentication with polkit */
3629 if (IN_SET(a,
3630 ACTION_POWEROFF,
3631 ACTION_REBOOT,
36b69c31 3632 ACTION_HALT,
2b0f4e6f
ZJS
3633 ACTION_SUSPEND,
3634 ACTION_HIBERNATE,
c58493c0 3635 ACTION_HYBRID_SLEEP,
e68c79db 3636 ACTION_SUSPEND_THEN_HIBERNATE)) {
2b0f4e6f
ZJS
3637
3638 r = logind_reboot(a);
3639 if (r >= 0)
3640 return r;
3641 if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
3642 /* requested operation is not supported or already in progress */
3643 return r;
20b09ca7 3644
130246d2
LP
3645 /* On all other errors, try low-level operation. In order to minimize the difference between
3646 * operation with and without logind, we explicitly enable non-blocking mode for this, as
3647 * logind's shutdown operations are always non-blocking. */
3648
3649 arg_no_block = true;
3650
3651 } else if (IN_SET(a, ACTION_EXIT, ACTION_KEXEC))
3652 /* Since exit/kexec are so close in behaviour to power-off/reboot, let's also make them
3653 * asynchronous, in order to not confuse the user needlessly with unexpected behaviour. */
3654 arg_no_block = true;
7089051f 3655
2b0f4e6f 3656 r = start_unit(argc, argv, userdata);
4c80c73c 3657 }
983d9c90 3658
2b0f4e6f
ZJS
3659 if (termination_action && arg_force < 2 &&
3660 IN_SET(r, -ENOENT, -ETIMEDOUT))
cc7de2ba 3661 log_notice("It is possible to perform action directly, see discussion of --force --force in man:systemctl(1).");
2b0f4e6f
ZJS
3662
3663 return r;
514f4ef5
LP
3664}
3665
988b3b17
ZJS
3666static int start_system_special(int argc, char *argv[], void *userdata) {
3667 /* Like start_special above, but raises an error when running in user mode */
3668
3669 if (arg_scope != UNIT_FILE_SYSTEM) {
3670 log_error("Bad action for %s mode.",
3671 arg_scope == UNIT_FILE_GLOBAL ? "--global" : "--user");
3672 return -EINVAL;
3673 }
3674
3675 return start_special(argc, argv, userdata);
3676}
3677
fa0d5878 3678static int check_unit_generic(int code, const UnitActiveState good_states[], int nb_states, char **args) {
e3e0314b 3679 _cleanup_strv_free_ char **names = NULL;
fa0d5878 3680 UnitActiveState active_state;
4fbd7192 3681 sd_bus *bus;
729e3769 3682 char **name;
fa0d5878 3683 int r, i;
d60f6ad0 3684 bool found = false;
0183528f 3685
4fbd7192
LP
3686 r = acquire_bus(BUS_MANAGER, &bus);
3687 if (r < 0)
3688 return r;
3689
e3e0314b 3690 r = expand_names(bus, args, NULL, &names);
f647962d
MS
3691 if (r < 0)
3692 return log_error_errno(r, "Failed to expand names: %m");
e3e0314b
ZJS
3693
3694 STRV_FOREACH(name, names) {
fa0d5878
BR
3695 r = get_state_one_unit(bus, *name, &active_state);
3696 if (r < 0)
3697 return r;
3698
3699 if (!arg_quiet)
3700 puts(unit_active_state_to_string(active_state));
60f9ba0b 3701
fa0d5878
BR
3702 for (i = 0; i < nb_states; ++i)
3703 if (good_states[i] == active_state)
3704 found = true;
1a0fce45
TA
3705 }
3706
d60f6ad0
LN
3707 /* use the given return code for the case that we won't find
3708 * any unit which matches the list */
3709 return found ? 0 : code;
1a0fce45
TA
3710}
3711
e449de87 3712static int check_unit_active(int argc, char *argv[], void *userdata) {
fa0d5878 3713 const UnitActiveState states[] = { UNIT_ACTIVE, UNIT_RELOADING };
e3e0314b 3714 /* According to LSB: 3, "program is not running" */
b613907e 3715 return check_unit_generic(EXIT_PROGRAM_NOT_RUNNING, states, ELEMENTSOF(states), strv_skip(argv, 1));
e3e0314b 3716}
0183528f 3717
e449de87 3718static int check_unit_failed(int argc, char *argv[], void *userdata) {
fa0d5878 3719 const UnitActiveState states[] = { UNIT_FAILED };
b613907e 3720 return check_unit_generic(EXIT_PROGRAM_DEAD_AND_PID_EXISTS, states, ELEMENTSOF(states), strv_skip(argv, 1));
48220598
LP
3721}
3722
e449de87 3723static int kill_unit(int argc, char *argv[], void *userdata) {
e3e0314b 3724 _cleanup_strv_free_ char **names = NULL;
ac5e3a50 3725 char *kill_who = NULL, **name;
4fbd7192 3726 sd_bus *bus;
e3e0314b 3727 int r, q;
8a0867d6 3728
4fbd7192
LP
3729 r = acquire_bus(BUS_MANAGER, &bus);
3730 if (r < 0)
3731 return r;
3732
8a4b13c5 3733 polkit_agent_open_maybe();
d2ad7e1b 3734
8a0867d6
LP
3735 if (!arg_kill_who)
3736 arg_kill_who = "all";
3737
ac5e3a50
JS
3738 /* --fail was specified */
3739 if (streq(arg_job_mode, "fail"))
81d62103 3740 kill_who = strjoina(arg_kill_who, "-fail");
ac5e3a50 3741
e449de87 3742 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
e3e0314b 3743 if (r < 0)
691395d8 3744 return log_error_errno(r, "Failed to expand names: %m");
60f9ba0b 3745
e3e0314b 3746 STRV_FOREACH(name, names) {
4afd3348 3747 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
342641fb 3748
6e646d22 3749 q = sd_bus_call_method(
f22f08cd 3750 bus,
b0193f1c
LP
3751 "org.freedesktop.systemd1",
3752 "/org/freedesktop/systemd1",
3753 "org.freedesktop.systemd1.Manager",
6e646d22
LP
3754 "KillUnit",
3755 &error,
3756 NULL,
169d7fb6 3757 "ssi", *name, kill_who ? kill_who : arg_kill_who, arg_signal);
e3e0314b 3758 if (q < 0) {
169d7fb6 3759 log_error_errno(q, "Failed to kill unit %s: %s", *name, bus_error_message(&error, q));
e3e0314b
ZJS
3760 if (r == 0)
3761 r = q;
f459b602 3762 }
8a0867d6 3763 }
f459b602 3764
e3e0314b 3765 return r;
8a0867d6
LP
3766}
3767
582a507f 3768typedef struct ExecStatusInfo {
0129173a
LP
3769 char *name;
3770
582a507f
LP
3771 char *path;
3772 char **argv;
3773
b708e7ce
LP
3774 bool ignore;
3775
582a507f
LP
3776 usec_t start_timestamp;
3777 usec_t exit_timestamp;
3778 pid_t pid;
3779 int code;
3780 int status;
3781
3782 LIST_FIELDS(struct ExecStatusInfo, exec);
3783} ExecStatusInfo;
3784
3785static void exec_status_info_free(ExecStatusInfo *i) {
3786 assert(i);
3787
0129173a 3788 free(i->name);
582a507f
LP
3789 free(i->path);
3790 strv_free(i->argv);
3791 free(i);
3792}
3793
f459b602 3794static int exec_status_info_deserialize(sd_bus_message *m, ExecStatusInfo *i) {
b21a0ef8 3795 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
f459b602 3796 const char *path;
582a507f
LP
3797 uint32_t pid;
3798 int32_t code, status;
f459b602 3799 int ignore, r;
582a507f 3800
f459b602 3801 assert(m);
582a507f 3802 assert(i);
582a507f 3803
f459b602
MAP
3804 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, "sasbttttuii");
3805 if (r < 0)
3806 return bus_log_parse_error(r);
3807 else if (r == 0)
3808 return 0;
582a507f 3809
f459b602
MAP
3810 r = sd_bus_message_read(m, "s", &path);
3811 if (r < 0)
3812 return bus_log_parse_error(r);
582a507f 3813
f84190d8
LP
3814 i->path = strdup(path);
3815 if (!i->path)
f459b602 3816 return log_oom();
582a507f 3817
f459b602
MAP
3818 r = sd_bus_message_read_strv(m, &i->argv);
3819 if (r < 0)
3820 return bus_log_parse_error(r);
3821
3822 r = sd_bus_message_read(m,
3823 "bttttuii",
3824 &ignore,
3825 &start_timestamp, &start_timestamp_monotonic,
3826 &exit_timestamp, &exit_timestamp_monotonic,
3827 &pid,
3828 &code, &status);
3829 if (r < 0)
3830 return bus_log_parse_error(r);
582a507f 3831
b708e7ce 3832 i->ignore = ignore;
582a507f
LP
3833 i->start_timestamp = (usec_t) start_timestamp;
3834 i->exit_timestamp = (usec_t) exit_timestamp;
3835 i->pid = (pid_t) pid;
3836 i->code = code;
3837 i->status = status;
3838
f459b602
MAP
3839 r = sd_bus_message_exit_container(m);
3840 if (r < 0)
3841 return bus_log_parse_error(r);
3842
3843 return 1;
582a507f
LP
3844}
3845
d5db7fe6
WC
3846typedef struct UnitCondition {
3847 char *name;
b1ed76ae 3848 char *param;
d5db7fe6
WC
3849 bool trigger;
3850 bool negate;
d5db7fe6
WC
3851 int tristate;
3852
b1ed76ae 3853 LIST_FIELDS(struct UnitCondition, conditions);
d5db7fe6
WC
3854} UnitCondition;
3855
3856static void unit_condition_free(UnitCondition *c) {
9bb71940
ZJS
3857 if (!c)
3858 return;
d5db7fe6
WC
3859
3860 free(c->name);
3861 free(c->param);
3862 free(c);
3863}
3864
9bb71940
ZJS
3865DEFINE_TRIVIAL_CLEANUP_FUNC(UnitCondition*, unit_condition_free);
3866
61cbdc4b
LP
3867typedef struct UnitStatusInfo {
3868 const char *id;
3869 const char *load_state;
3870 const char *active_state;
3871 const char *sub_state;
a4375746 3872 const char *unit_file_state;
d2dc52db 3873 const char *unit_file_preset;
61cbdc4b
LP
3874
3875 const char *description;
4a9e2fff 3876 const char *following;
61cbdc4b 3877
49dbfa7b
LP
3878 char **documentation;
3879
1b64d026
LP
3880 const char *fragment_path;
3881 const char *source_path;
4ad49000 3882 const char *control_group;
61cbdc4b 3883
76d14b87
OS
3884 char **dropin_paths;
3885
9f39404c 3886 const char *load_error;
f42806df 3887 const char *result;
9f39404c 3888
584be568 3889 usec_t inactive_exit_timestamp;
df50185b 3890 usec_t inactive_exit_timestamp_monotonic;
584be568
LP
3891 usec_t active_enter_timestamp;
3892 usec_t active_exit_timestamp;
3893 usec_t inactive_enter_timestamp;
3894
45fb0699 3895 bool need_daemon_reload;
055ef36b 3896 bool transient;
45fb0699 3897
61cbdc4b
LP
3898 /* Service */
3899 pid_t main_pid;
3900 pid_t control_pid;
3901 const char *status_text;
175728c4 3902 const char *pid_file;
d06dacd0 3903 bool running:1;
b4af5a80 3904 int status_errno;
61cbdc4b
LP
3905
3906 usec_t start_timestamp;
3907 usec_t exit_timestamp;
3908
3909 int exit_code, exit_status;
3910
90bbc946
LP
3911 usec_t condition_timestamp;
3912 bool condition_result;
b1ed76ae 3913 LIST_HEAD(UnitCondition, conditions);
59fccdc5
LP
3914
3915 usec_t assert_timestamp;
3916 bool assert_result;
3917 bool failed_assert_trigger;
3918 bool failed_assert_negate;
3919 const char *failed_assert;
3920 const char *failed_assert_parameter;
601b0842
GS
3921 usec_t next_elapse_real;
3922 usec_t next_elapse_monotonic;
90bbc946 3923
61cbdc4b
LP
3924 /* Socket */
3925 unsigned n_accepted;
3926 unsigned n_connections;
b8131a87 3927 bool accept;
61cbdc4b 3928
13160134 3929 /* Pairs of type, path */
67419600
OS
3930 char **listen;
3931
61cbdc4b
LP
3932 /* Device */
3933 const char *sysfs_path;
3934
3935 /* Mount, Automount */
3936 const char *where;
3937
3938 /* Swap */
3939 const char *what;
582a507f 3940
934277fe
LP
3941 /* CGroup */
3942 uint64_t memory_current;
da4d897e
TH
3943 uint64_t memory_low;
3944 uint64_t memory_high;
3945 uint64_t memory_max;
96e131ea 3946 uint64_t memory_swap_max;
934277fe 3947 uint64_t memory_limit;
5ad096b3 3948 uint64_t cpu_usage_nsec;
03a7b521
LP
3949 uint64_t tasks_current;
3950 uint64_t tasks_max;
934277fe 3951
0e97c93f
DM
3952 uint64_t ip_ingress_bytes;
3953 uint64_t ip_egress_bytes;
3954
582a507f 3955 LIST_HEAD(ExecStatusInfo, exec);
61cbdc4b
LP
3956} UnitStatusInfo;
3957
a7335518
ZJS
3958static void unit_status_info_free(UnitStatusInfo *info) {
3959 ExecStatusInfo *p;
3960 UnitCondition *c;
3961
3962 strv_free(info->documentation);
3963 strv_free(info->dropin_paths);
3964 strv_free(info->listen);
3965
3966 while ((c = info->conditions)) {
3967 LIST_REMOVE(conditions, info->conditions, c);
3968 unit_condition_free(c);
3969 }
3970
3971 while ((p = info->exec)) {
3972 LIST_REMOVE(exec, info->exec, p);
3973 exec_status_info_free(p);
3974 }
3975}
3976
f459b602 3977static void print_status_info(
291d565a 3978 sd_bus *bus,
f459b602
MAP
3979 UnitStatusInfo *i,
3980 bool *ellipsized) {
3981
582a507f 3982 ExecStatusInfo *p;
b0d14c69 3983 const char *active_on, *active_off, *on, *off, *ss;
584be568 3984 usec_t timestamp;
9185c8e6 3985 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
584be568 3986 char since2[FORMAT_TIMESTAMP_MAX], *s2;
1b64d026 3987 const char *path;
13160134 3988 char **t, **t2;
291d565a 3989 int r;
582a507f 3990
61cbdc4b
LP
3991 assert(i);
3992
3993 /* This shows pretty information about a unit. See
3994 * print_property() for a low-level property printer */
3995
b0d14c69
LP
3996 if (streq_ptr(i->active_state, "failed")) {
3997 active_on = ansi_highlight_red();
1fc464f6 3998 active_off = ansi_normal();
1cf03a4f 3999 } else if (STRPTR_IN_SET(i->active_state, "active", "reloading")) {
b0d14c69 4000 active_on = ansi_highlight_green();
1fc464f6 4001 active_off = ansi_normal();
b0d14c69
LP
4002 } else
4003 active_on = active_off = "";
4004
323b7dc9 4005 printf("%s%s%s %s", active_on, special_glyph(BLACK_CIRCLE), active_off, strna(i->id));
61cbdc4b
LP
4006
4007 if (i->description && !streq_ptr(i->id, i->description))
4008 printf(" - %s", i->description);
4009
4010 printf("\n");
4011
4a9e2fff 4012 if (i->following)
856323c9 4013 printf(" Follow: unit currently follows state of %s\n", i->following);
4a9e2fff 4014
f7b9e331 4015 if (streq_ptr(i->load_state, "error")) {
0b5a519c 4016 on = ansi_highlight_red();
1fc464f6 4017 off = ansi_normal();
c31b4423
LP
4018 } else
4019 on = off = "";
4020
1b64d026
LP
4021 path = i->source_path ? i->source_path : i->fragment_path;
4022
055ef36b 4023 if (i->load_error != 0)
856323c9
ZJS
4024 printf(" Loaded: %s%s%s (Reason: %s)\n",
4025 on, strna(i->load_state), off, i->load_error);
15ce1647
LP
4026 else if (path && !isempty(i->unit_file_state) && !isempty(i->unit_file_preset) &&
4027 !STR_IN_SET(i->unit_file_state, "generated", "transient"))
d2dc52db
LP
4028 printf(" Loaded: %s%s%s (%s; %s; vendor preset: %s)\n",
4029 on, strna(i->load_state), off, path, i->unit_file_state, i->unit_file_preset);
4030 else if (path && !isempty(i->unit_file_state))
856323c9
ZJS
4031 printf(" Loaded: %s%s%s (%s; %s)\n",
4032 on, strna(i->load_state), off, path, i->unit_file_state);
1b64d026 4033 else if (path)
856323c9
ZJS
4034 printf(" Loaded: %s%s%s (%s)\n",
4035 on, strna(i->load_state), off, path);
61cbdc4b 4036 else
856323c9
ZJS
4037 printf(" Loaded: %s%s%s\n",
4038 on, strna(i->load_state), off);
61cbdc4b 4039
055ef36b
LP
4040 if (i->transient)
4041 printf("Transient: yes\n");
4042
76d14b87 4043 if (!strv_isempty(i->dropin_paths)) {
f459b602 4044 _cleanup_free_ char *dir = NULL;
76d14b87 4045 bool last = false;
f459b602 4046 char ** dropin;
76d14b87
OS
4047
4048 STRV_FOREACH(dropin, i->dropin_paths) {
4049 if (! dir || last) {
856323c9 4050 printf(dir ? " " : " Drop-In: ");
76d14b87 4051
97b11eed 4052 dir = mfree(dir);
76d14b87 4053
5f311f8c
LP
4054 dir = dirname_malloc(*dropin);
4055 if (!dir) {
76d14b87
OS
4056 log_oom();
4057 return;
4058 }
4059
856323c9 4060 printf("%s\n %s", dir,
323b7dc9 4061 special_glyph(TREE_RIGHT));
76d14b87
OS
4062 }
4063
4064 last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
4065
2b6bf07d 4066 printf("%s%s", basename(*dropin), last ? "\n" : ", ");
76d14b87 4067 }
76d14b87
OS
4068 }
4069
2ee68f72 4070 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2ee68f72 4071 if (ss)
856323c9 4072 printf(" Active: %s%s (%s)%s",
b0d14c69 4073 active_on, strna(i->active_state), ss, active_off);
2ee68f72 4074 else
856323c9 4075 printf(" Active: %s%s%s",
b0d14c69 4076 active_on, strna(i->active_state), active_off);
61cbdc4b 4077
f42806df
LP
4078 if (!isempty(i->result) && !streq(i->result, "success"))
4079 printf(" (Result: %s)", i->result);
4080
1cf03a4f
ZJS
4081 timestamp = STRPTR_IN_SET(i->active_state, "active", "reloading") ? i->active_enter_timestamp :
4082 STRPTR_IN_SET(i->active_state, "inactive", "failed") ? i->inactive_enter_timestamp :
4083 STRPTR_IN_SET(i->active_state, "activating") ? i->inactive_exit_timestamp :
4084 i->active_exit_timestamp;
584be568 4085
bbb8486e 4086 s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
584be568
LP
4087 s2 = format_timestamp(since2, sizeof(since2), timestamp);
4088
4089 if (s1)
538da63d 4090 printf(" since %s; %s\n", s2, s1);
584be568 4091 else if (s2)
538da63d 4092 printf(" since %s\n", s2);
584be568
LP
4093 else
4094 printf("\n");
4095
601b0842
GS
4096 if (endswith(i->id, ".timer")) {
4097 char tstamp1[FORMAT_TIMESTAMP_RELATIVE_MAX],
4098 tstamp2[FORMAT_TIMESTAMP_MAX];
4099 char *next_rel_time, *next_time;
4100 dual_timestamp nw, next = {i->next_elapse_real,
4101 i->next_elapse_monotonic};
4102 usec_t next_elapse;
4103
4104 printf(" Trigger: ");
4105
4106 dual_timestamp_get(&nw);
4107 next_elapse = calc_next_elapse(&nw, &next);
4108 next_rel_time = format_timestamp_relative(tstamp1,
4109 sizeof(tstamp1),
4110 next_elapse);
4111 next_time = format_timestamp(tstamp2,
4112 sizeof(tstamp2),
4113 next_elapse);
4114
4115 if (next_time && next_rel_time)
4116 printf("%s; %s\n", next_time, next_rel_time);
4117 else
4118 printf("n/a\n");
4119 }
4120
90bbc946 4121 if (!i->condition_result && i->condition_timestamp > 0) {
d5db7fe6
WC
4122 UnitCondition *c;
4123 int n = 0;
4124
bbb8486e 4125 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
90bbc946
LP
4126 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
4127
59fccdc5 4128 printf("Condition: start %scondition failed%s at %s%s%s\n",
1fc464f6 4129 ansi_highlight_yellow(), ansi_normal(),
5cfee414 4130 s2, s1 ? "; " : "", strempty(s1));
d5db7fe6 4131
b1ed76ae 4132 LIST_FOREACH(conditions, c, i->conditions)
d5db7fe6
WC
4133 if (c->tristate < 0)
4134 n++;
d5db7fe6 4135
b1ed76ae
ZJS
4136 LIST_FOREACH(conditions, c, i->conditions)
4137 if (c->tristate < 0)
4138 printf(" %s %s=%s%s%s was not met\n",
4139 --n ? special_glyph(TREE_BRANCH) : special_glyph(TREE_RIGHT),
4140 c->name,
4141 c->trigger ? "|" : "",
4142 c->negate ? "!" : "",
4143 c->param);
59fccdc5
LP
4144 }
4145
4146 if (!i->assert_result && i->assert_timestamp > 0) {
4147 s1 = format_timestamp_relative(since1, sizeof(since1), i->assert_timestamp);
4148 s2 = format_timestamp(since2, sizeof(since2), i->assert_timestamp);
4149
4150 printf(" Assert: start %sassertion failed%s at %s%s%s\n",
1fc464f6 4151 ansi_highlight_red(), ansi_normal(),
5cfee414 4152 s2, s1 ? "; " : "", strempty(s1));
59fccdc5
LP
4153 if (i->failed_assert_trigger)
4154 printf(" none of the trigger assertions were met\n");
4155 else if (i->failed_assert)
4156 printf(" %s=%s%s was not met\n",
4157 i->failed_assert,
4158 i->failed_assert_negate ? "!" : "",
4159 i->failed_assert_parameter);
90bbc946
LP
4160 }
4161
61cbdc4b 4162 if (i->sysfs_path)
856323c9 4163 printf(" Device: %s\n", i->sysfs_path);
9feeba4b 4164 if (i->where)
856323c9 4165 printf(" Where: %s\n", i->where);
9feeba4b 4166 if (i->what)
856323c9 4167 printf(" What: %s\n", i->what);
49dbfa7b 4168
13160134 4169 STRV_FOREACH(t, i->documentation)
856323c9 4170 printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", *t);
49dbfa7b 4171
13160134 4172 STRV_FOREACH_PAIR(t, t2, i->listen)
856323c9 4173 printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
67419600 4174
b8131a87 4175 if (i->accept)
856323c9 4176 printf(" Accepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
61cbdc4b 4177
582a507f 4178 LIST_FOREACH(exec, p, i->exec) {
13160134 4179 _cleanup_free_ char *argv = NULL;
9a57c629 4180 bool good;
582a507f
LP
4181
4182 /* Only show exited processes here */
4183 if (p->code == 0)
4184 continue;
4185
13160134 4186 argv = strv_join(p->argv, " ");
1fa2f38f 4187 printf(" Process: "PID_FMT" %s=%s ", p->pid, p->name, strna(argv));
582a507f 4188
1f0958f6 4189 good = is_clean_exit(p->code, p->status, EXIT_CLEAN_DAEMON, NULL);
9a57c629 4190 if (!good) {
0b5a519c 4191 on = ansi_highlight_red();
1fc464f6 4192 off = ansi_normal();
9a57c629
LP
4193 } else
4194 on = off = "";
4195
4196 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
4197
d06dacd0
LP
4198 if (p->code == CLD_EXITED) {
4199 const char *c;
4200
582a507f 4201 printf("status=%i", p->status);
d06dacd0 4202
1b64d026
LP
4203 c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
4204 if (c)
d06dacd0
LP
4205 printf("/%s", c);
4206
4207 } else
582a507f 4208 printf("signal=%s", signal_to_string(p->status));
9a57c629
LP
4209
4210 printf(")%s\n", off);
4211
582a507f
LP
4212 if (i->main_pid == p->pid &&
4213 i->start_timestamp == p->start_timestamp &&
4214 i->exit_timestamp == p->start_timestamp)
4215 /* Let's not show this twice */
4216 i->main_pid = 0;
4217
4218 if (p->pid == i->control_pid)
4219 i->control_pid = 0;
4220 }
4221
61cbdc4b 4222 if (i->main_pid > 0 || i->control_pid > 0) {
61cbdc4b 4223 if (i->main_pid > 0) {
8c06592f 4224 printf(" Main PID: "PID_FMT, i->main_pid);
61cbdc4b
LP
4225
4226 if (i->running) {
a081b9ce
LP
4227
4228 if (arg_transport == BUS_TRANSPORT_LOCAL) {
4229 _cleanup_free_ char *comm = NULL;
4230
4231 (void) get_process_comm(i->main_pid, &comm);
4232 if (comm)
4233 printf(" (%s)", comm);
4234 }
4235
6d4fc029 4236 } else if (i->exit_code > 0) {
61cbdc4b
LP
4237 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
4238
d06dacd0
LP
4239 if (i->exit_code == CLD_EXITED) {
4240 const char *c;
4241
61cbdc4b 4242 printf("status=%i", i->exit_status);
d06dacd0 4243
1b64d026
LP
4244 c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
4245 if (c)
d06dacd0
LP
4246 printf("/%s", c);
4247
4248 } else
582a507f 4249 printf("signal=%s", signal_to_string(i->exit_status));
6d4fc029
LP
4250 printf(")");
4251 }
13160134 4252 }
61cbdc4b
LP
4253
4254 if (i->control_pid > 0) {
13160134 4255 _cleanup_free_ char *c = NULL;
61cbdc4b 4256
1089dcd4
LP
4257 if (i->main_pid > 0)
4258 fputs("; Control PID: ", stdout);
4259 else
4260 fputs("Cntrl PID: ", stdout); /* if first in column, abbreviated so it fits alignment */
4261
4262 printf(PID_FMT, i->control_pid);
61cbdc4b 4263
a081b9ce
LP
4264 if (arg_transport == BUS_TRANSPORT_LOCAL) {
4265 (void) get_process_comm(i->control_pid, &c);
4266 if (c)
4267 printf(" (%s)", c);
4268 }
61cbdc4b
LP
4269 }
4270
4271 printf("\n");
4272 }
4273
17bb7382 4274 if (i->status_text)
856323c9 4275 printf(" Status: \"%s\"\n", i->status_text);
b4af5a80
LP
4276 if (i->status_errno > 0)
4277 printf(" Error: %i (%s)\n", i->status_errno, strerror(i->status_errno));
17bb7382 4278
0e97c93f
DM
4279 if (i->ip_ingress_bytes != (uint64_t) -1 && i->ip_egress_bytes != (uint64_t) -1) {
4280 char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX];
4281
4282 printf(" IP: %s in, %s out\n",
4283 format_bytes(buf_in, sizeof(buf_in), i->ip_ingress_bytes),
4284 format_bytes(buf_out, sizeof(buf_out), i->ip_egress_bytes));
4285 }
4286
03a7b521
LP
4287 if (i->tasks_current != (uint64_t) -1) {
4288 printf(" Tasks: %" PRIu64, i->tasks_current);
4289
4290 if (i->tasks_max != (uint64_t) -1)
2a6736dd 4291 printf(" (limit: %" PRIu64 ")\n", i->tasks_max);
03a7b521
LP
4292 else
4293 printf("\n");
4294 }
4295
934277fe
LP
4296 if (i->memory_current != (uint64_t) -1) {
4297 char buf[FORMAT_BYTES_MAX];
4298
4299 printf(" Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current));
4300
96e131ea
WC
4301 if (i->memory_low > 0 || i->memory_high != CGROUP_LIMIT_MAX ||
4302 i->memory_max != CGROUP_LIMIT_MAX || i->memory_swap_max != CGROUP_LIMIT_MAX ||
da4d897e
TH
4303 i->memory_limit != CGROUP_LIMIT_MAX) {
4304 const char *prefix = "";
4305
4306 printf(" (");
4307 if (i->memory_low > 0) {
4308 printf("%slow: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_low));
4309 prefix = " ";
4310 }
4311 if (i->memory_high != CGROUP_LIMIT_MAX) {
4312 printf("%shigh: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_high));
4313 prefix = " ";
4314 }
4315 if (i->memory_max != CGROUP_LIMIT_MAX) {
4316 printf("%smax: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_max));
4317 prefix = " ";
4318 }
96e131ea
WC
4319 if (i->memory_swap_max != CGROUP_LIMIT_MAX) {
4320 printf("%sswap max: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_swap_max));
4321 prefix = " ";
4322 }
da4d897e
TH
4323 if (i->memory_limit != CGROUP_LIMIT_MAX) {
4324 printf("%slimit: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_limit));
4325 prefix = " ";
4326 }
4327 printf(")");
4328 }
4329 printf("\n");
934277fe
LP
4330 }
4331
5ad096b3
LP
4332 if (i->cpu_usage_nsec != (uint64_t) -1) {
4333 char buf[FORMAT_TIMESPAN_MAX];
4334 printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
4335 }
4336
51e22f88 4337 if (i->control_group) {
291d565a
LP
4338 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4339 static const char prefix[] = " ";
ab35fb1b
LP
4340 unsigned c;
4341
51e22f88
LP
4342 printf(" CGroup: %s\n", i->control_group);
4343
291d565a
LP
4344 c = columns();
4345 if (c > sizeof(prefix) - 1)
4346 c -= sizeof(prefix) - 1;
4347 else
4348 c = 0;
ab35fb1b 4349
291d565a
LP
4350 r = unit_show_processes(bus, i->id, i->control_group, prefix, c, get_output_flags(), &error);
4351 if (r == -EBADR) {
b69d29ce
LP
4352 unsigned k = 0;
4353 pid_t extra[2];
4354
291d565a 4355 /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
ab35fb1b 4356
b69d29ce
LP
4357 if (i->main_pid > 0)
4358 extra[k++] = i->main_pid;
4359
4360 if (i->control_pid > 0)
4361 extra[k++] = i->control_pid;
4362
0ff308c8 4363 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, extra, k, get_output_flags());
291d565a
LP
4364 } else if (r < 0)
4365 log_warning_errno(r, "Failed to dump process list, ignoring: %s", bus_error_message(&error, r));
c59760ee 4366 }
45fb0699 4367
ece174c5 4368 if (i->id && arg_transport == BUS_TRANSPORT_LOCAL)
3c756001
LP
4369 show_journal_by_unit(
4370 stdout,
4371 i->id,
4372 arg_output,
4373 0,
4374 i->inactive_exit_timestamp_monotonic,
4375 arg_lines,
4376 getuid(),
4377 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
4378 SD_JOURNAL_LOCAL_ONLY,
4379 arg_scope == UNIT_FILE_SYSTEM,
4380 ellipsized);
86aa7ba4 4381
45fb0699 4382 if (i->need_daemon_reload)
3f36991e 4383 warn_unit_file_changed(i->id);
61cbdc4b
LP
4384}
4385
b43f208f 4386static void show_unit_help(UnitStatusInfo *i) {
256425cc
LP
4387 char **p;
4388
4389 assert(i);
4390
4391 if (!i->documentation) {
4392 log_info("Documentation for %s not known.", i->id);
4393 return;
4394 }
4395
78002a67
ZJS
4396 STRV_FOREACH(p, i->documentation)
4397 if (startswith(*p, "man:"))
4398 show_man_page(*p + 4, false);
4399 else
0315fe37 4400 log_info("Can't show: %s", *p);
256425cc
LP
4401}
4402
4679a8c3
YW
4403static int map_main_pid(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
4404 UnitStatusInfo *i = userdata;
4405 uint32_t u;
f459b602 4406 int r;
61cbdc4b 4407
4679a8c3
YW
4408 r = sd_bus_message_read(m, "u", &u);
4409 if (r < 0)
4410 return r;
61cbdc4b 4411
4679a8c3
YW
4412 i->main_pid = (pid_t) u;
4413 i->running = u > 0;
b8131a87 4414
4679a8c3
YW
4415 return 0;
4416}
b8131a87 4417
4679a8c3
YW
4418static int map_load_error(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
4419 const char *n, *message;
4420 const char **p = userdata;
4421 int r;
b8131a87 4422
4679a8c3
YW
4423 r = sd_bus_message_read(m, "(ss)", &n, &message);
4424 if (r < 0)
4425 return r;
b8131a87 4426
4679a8c3
YW
4427 if (!isempty(message))
4428 *p = message;
61cbdc4b 4429
4679a8c3
YW
4430 return 0;
4431}
61cbdc4b 4432
4679a8c3
YW
4433static int map_listen(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
4434 const char *type, *path;
4435 char ***p = userdata;
4436 int r;
61cbdc4b 4437
4679a8c3
YW
4438 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4439 if (r < 0)
4440 return r;
61cbdc4b 4441
4679a8c3 4442 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0) {
61cbdc4b 4443
4679a8c3 4444 r = strv_extend(p, type);
f459b602 4445 if (r < 0)
4679a8c3 4446 return r;
61cbdc4b 4447
4679a8c3 4448 r = strv_extend(p, path);
f459b602 4449 if (r < 0)
4679a8c3 4450 return r;
61cbdc4b 4451 }
4679a8c3
YW
4452 if (r < 0)
4453 return r;
582a507f 4454
4679a8c3
YW
4455 r = sd_bus_message_exit_container(m);
4456 if (r < 0)
4457 return r;
49dbfa7b 4458
4679a8c3
YW
4459 return 0;
4460}
52990c2e 4461
4679a8c3
YW
4462static int map_conditions(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
4463 UnitStatusInfo *i = userdata;
4464 const char *cond, *param;
4465 int trigger, negate;
4466 int32_t state;
4467 int r;
52990c2e 4468
4679a8c3
YW
4469 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
4470 if (r < 0)
4471 return r;
f459b602 4472
4679a8c3
YW
4473 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
4474 _cleanup_(unit_condition_freep) UnitCondition *c = NULL;
d5db7fe6 4475
4679a8c3
YW
4476 c = new0(UnitCondition, 1);
4477 if (!c)
4478 return -ENOMEM;
d5db7fe6 4479
4679a8c3
YW
4480 c->name = strdup(cond);
4481 c->param = strdup(param);
4482 if (!c->name || !c->param)
4483 return -ENOMEM;
d5db7fe6 4484
4679a8c3
YW
4485 c->trigger = trigger;
4486 c->negate = negate;
4487 c->tristate = state;
d5db7fe6 4488
4679a8c3
YW
4489 LIST_PREPEND(conditions, i->conditions, c);
4490 c = NULL;
4491 }
4492 if (r < 0)
4493 return r;
d5db7fe6 4494
4679a8c3
YW
4495 r = sd_bus_message_exit_container(m);
4496 if (r < 0)
4497 return r;
59fccdc5 4498
4679a8c3
YW
4499 return 0;
4500}
59fccdc5 4501
4679a8c3
YW
4502static int map_asserts(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
4503 UnitStatusInfo *i = userdata;
4504 const char *cond, *param;
4505 int trigger, negate;
4506 int32_t state;
4507 int r;
59fccdc5 4508
4679a8c3
YW
4509 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
4510 if (r < 0)
4511 return r;
59fccdc5 4512
4679a8c3
YW
4513 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
4514 if (state < 0 && (!trigger || !i->failed_assert)) {
4515 i->failed_assert = cond;
4516 i->failed_assert_trigger = trigger;
4517 i->failed_assert_negate = negate;
4518 i->failed_assert_parameter = param;
4519 }
4520 }
4521 if (r < 0)
4522 return r;
f459b602 4523
4679a8c3
YW
4524 r = sd_bus_message_exit_container(m);
4525 if (r < 0)
4526 return r;
f459b602 4527
4679a8c3
YW
4528 return 0;
4529}
582a507f 4530
4679a8c3
YW
4531static int map_exec(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
4532 _cleanup_free_ ExecStatusInfo *info = NULL;
4533 UnitStatusInfo *i = userdata;
4534 int r;
9f39404c 4535
4679a8c3
YW
4536 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
4537 if (r < 0)
4538 return r;
9f39404c 4539
4679a8c3
YW
4540 info = new0(ExecStatusInfo, 1);
4541 if (!info)
4542 return -ENOMEM;
9f39404c 4543
4679a8c3 4544 while ((r = exec_status_info_deserialize(m, info)) > 0) {
9f39404c 4545
4679a8c3
YW
4546 info->name = strdup(member);
4547 if (!info->name)
4548 return -ENOMEM;
9f39404c 4549
4679a8c3 4550 LIST_PREPEND(exec, i->exec, info);
f459b602 4551
4679a8c3
YW
4552 info = new0(ExecStatusInfo, 1);
4553 if (!info)
4554 return -ENOMEM;
9f39404c 4555 }
4679a8c3
YW
4556 if (r < 0)
4557 return r;
f459b602 4558
4679a8c3 4559 r = sd_bus_message_exit_container(m);
f459b602 4560 if (r < 0)
4679a8c3 4561 return r;
61cbdc4b
LP
4562
4563 return 0;
4564}
4565
4f9a9105
ZJS
4566#define print_prop(name, fmt, ...) \
4567 do { \
4568 if (arg_value) \
4569 printf(fmt "\n", __VA_ARGS__); \
4570 else \
4571 printf("%s=" fmt "\n", name, __VA_ARGS__); \
508f63b4 4572 } while (0)
4f9a9105 4573
07636114
YW
4574static int print_property(const char *name, sd_bus_message *m, bool value, bool all) {
4575 char bus_type;
4576 const char *contents;
f459b602
MAP
4577 int r;
4578
48220598 4579 assert(name);
f459b602 4580 assert(m);
48220598 4581
61cbdc4b
LP
4582 /* This is a low-level property printer, see
4583 * print_status_info() for the nicer output */
4584
07636114
YW
4585 r = sd_bus_message_peek_type(m, &bus_type, &contents);
4586 if (r < 0)
852c1b4d 4587 return r;
48220598 4588
07636114 4589 switch (bus_type) {
48220598 4590
07636114 4591 case SD_BUS_TYPE_STRUCT:
48220598 4592
07636114 4593 if (contents[0] == SD_BUS_TYPE_UINT32 && streq(name, "Job")) {
48220598
LP
4594 uint32_t u;
4595
f459b602
MAP
4596 r = sd_bus_message_read(m, "(uo)", &u, NULL);
4597 if (r < 0)
4598 return bus_log_parse_error(r);
48220598 4599
f459b602 4600 if (u > 0)
4f9a9105 4601 print_prop(name, "%"PRIu32, u);
07636114 4602 else if (all)
4f9a9105 4603 print_prop(name, "%s", "");
48220598 4604
07636114 4605 return 1;
f459b602 4606
07636114 4607 } else if (contents[0] == SD_BUS_TYPE_STRING && streq(name, "Unit")) {
48220598
LP
4608 const char *s;
4609
f459b602
MAP
4610 r = sd_bus_message_read(m, "(so)", &s, NULL);
4611 if (r < 0)
4612 return bus_log_parse_error(r);
48220598 4613
07636114 4614 if (all || !isempty(s))
4f9a9105 4615 print_prop(name, "%s", s);
48220598 4616
07636114 4617 return 1;
f459b602 4618
07636114 4619 } else if (contents[0] == SD_BUS_TYPE_STRING && streq(name, "LoadError")) {
9f39404c
LP
4620 const char *a = NULL, *b = NULL;
4621
f459b602
MAP
4622 r = sd_bus_message_read(m, "(ss)", &a, &b);
4623 if (r < 0)
4624 return bus_log_parse_error(r);
9f39404c 4625
07636114 4626 if (all || !isempty(a) || !isempty(b))
4f9a9105 4627 print_prop(name, "%s \"%s\"", strempty(a), strempty(b));
f786e80d 4628
07636114 4629 return 1;
57183d11
LP
4630 } else if (streq_ptr(name, "SystemCallFilter")) {
4631 _cleanup_strv_free_ char **l = NULL;
4632 int whitelist;
4633
4634 r = sd_bus_message_enter_container(m, 'r', "bas");
4635 if (r < 0)
4636 return bus_log_parse_error(r);
4637
4638 r = sd_bus_message_read(m, "b", &whitelist);
4639 if (r < 0)
4640 return bus_log_parse_error(r);
4641
4642 r = sd_bus_message_read_strv(m, &l);
4643 if (r < 0)
4644 return bus_log_parse_error(r);
4645
4646 r = sd_bus_message_exit_container(m);
4647 if (r < 0)
4648 return bus_log_parse_error(r);
4649
07636114 4650 if (all || whitelist || !strv_isempty(l)) {
57183d11
LP
4651 bool first = true;
4652 char **i;
4653
07636114 4654 if (!value) {
4f9a9105
ZJS
4655 fputs(name, stdout);
4656 fputc('=', stdout);
4657 }
57183d11
LP
4658
4659 if (!whitelist)
4660 fputc('~', stdout);
4661
4662 STRV_FOREACH(i, l) {
4663 if (first)
4664 first = false;
4665 else
4666 fputc(' ', stdout);
4667
4668 fputs(*i, stdout);
4669 }
4670 fputc('\n', stdout);
4671 }
4672
07636114 4673 return 1;
48220598
LP
4674 }
4675
4676 break;
48220598 4677
f459b602 4678 case SD_BUS_TYPE_ARRAY:
48220598 4679
07636114 4680 if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "EnvironmentFiles")) {
f459b602
MAP
4681 const char *path;
4682 int ignore;
8c7be95e 4683
f459b602
MAP
4684 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sb)");
4685 if (r < 0)
4686 return bus_log_parse_error(r);
8c7be95e 4687
f459b602 4688 while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
009192bb 4689 print_prop(name, "%s (ignore_errors=%s)", path, yes_no(ignore));
8c7be95e 4690
f459b602
MAP
4691 if (r < 0)
4692 return bus_log_parse_error(r);
8c7be95e 4693
f459b602
MAP
4694 r = sd_bus_message_exit_container(m);
4695 if (r < 0)
4696 return bus_log_parse_error(r);
8c7be95e 4697
07636114 4698 return 1;
8c7be95e 4699
07636114 4700 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Paths")) {
f459b602 4701 const char *type, *path;
67419600 4702
f459b602
MAP
4703 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4704 if (r < 0)
4705 return bus_log_parse_error(r);
ebf57b80 4706
f459b602 4707 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
c7366cf1 4708 print_prop(name, "%s (%s)", path, type);
f459b602
MAP
4709 if (r < 0)
4710 return bus_log_parse_error(r);
ebf57b80 4711
f459b602
MAP
4712 r = sd_bus_message_exit_container(m);
4713 if (r < 0)
4714 return bus_log_parse_error(r);
ebf57b80 4715
07636114 4716 return 1;
582a507f 4717
07636114 4718 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
f459b602 4719 const char *type, *path;
67419600 4720
f459b602
MAP
4721 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4722 if (r < 0)
4723 return bus_log_parse_error(r);
67419600 4724
f459b602 4725 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
eabc13c7 4726 print_prop(name, "%s (%s)", path, type);
f459b602
MAP
4727 if (r < 0)
4728 return bus_log_parse_error(r);
67419600 4729
f459b602
MAP
4730 r = sd_bus_message_exit_container(m);
4731 if (r < 0)
4732 return bus_log_parse_error(r);
67419600 4733
07636114 4734 return 1;
67419600 4735
07636114 4736 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "TimersMonotonic")) {
f459b602 4737 const char *base;
07636114 4738 uint64_t v, next_elapse;
707e5e52 4739
f459b602
MAP
4740 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(stt)");
4741 if (r < 0)
4742 return bus_log_parse_error(r);
552e4331 4743
07636114 4744 while ((r = sd_bus_message_read(m, "(stt)", &base, &v, &next_elapse)) > 0) {
f459b602 4745 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
fe68089d 4746
fa6dee52 4747 print_prop(name, "{ %s=%s ; next_elapse=%s }", base,
07636114 4748 format_timespan(timespan1, sizeof(timespan1), v, 0),
4f9a9105 4749 format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
fe68089d 4750 }
f459b602
MAP
4751 if (r < 0)
4752 return bus_log_parse_error(r);
4753
4754 r = sd_bus_message_exit_container(m);
4755 if (r < 0)
4756 return bus_log_parse_error(r);
fe68089d 4757
07636114 4758 return 1;
fe68089d 4759
07636114 4760 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "TimersCalendar")) {
fa6dee52
YW
4761 const char *base, *spec;
4762 uint64_t next_elapse;
4763
4764 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sst)");
4765 if (r < 0)
4766 return bus_log_parse_error(r);
4767
4768 while ((r = sd_bus_message_read(m, "(sst)", &base, &spec, &next_elapse)) > 0) {
4769 char timestamp[FORMAT_TIMESTAMP_MAX];
4770
4771 print_prop(name, "{ %s=%s ; next_elapse=%s }", base, spec,
4772 format_timestamp(timestamp, sizeof(timestamp), next_elapse));
4773 }
4774 if (r < 0)
4775 return bus_log_parse_error(r);
4776
4777 r = sd_bus_message_exit_container(m);
4778 if (r < 0)
4779 return bus_log_parse_error(r);
4780
07636114 4781 return 1;
fa6dee52 4782
07636114 4783 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
f459b602
MAP
4784 ExecStatusInfo info = {};
4785
4786 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
4787 if (r < 0)
4788 return bus_log_parse_error(r);
4789
4790 while ((r = exec_status_info_deserialize(m, &info)) > 0) {
4791 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
4792 _cleanup_free_ char *tt;
4793
4794 tt = strv_join(info.argv, " ");
4795
4f9a9105
ZJS
4796 print_prop(name,
4797 "{ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
4798 strna(info.path),
4799 strna(tt),
4800 yes_no(info.ignore),
4801 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
4802 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
4803 info.pid,
4804 sigchld_code_to_string(info.code),
4805 info.status,
4806 info.code == CLD_EXITED ? "" : "/",
4807 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
fe68089d 4808
582a507f
LP
4809 free(info.path);
4810 strv_free(info.argv);
f459b602 4811 zero(info);
707e5e52
LP
4812 }
4813
f459b602
MAP
4814 r = sd_bus_message_exit_container(m);
4815 if (r < 0)
4816 return bus_log_parse_error(r);
4817
07636114 4818 return 1;
4ad49000 4819
07636114 4820 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "DeviceAllow")) {
f459b602 4821 const char *path, *rwm;
4ad49000 4822
f459b602
MAP
4823 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4824 if (r < 0)
4825 return bus_log_parse_error(r);
4ad49000 4826
f459b602 4827 while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0)
4f9a9105 4828 print_prop(name, "%s %s", strna(path), strna(rwm));
f459b602
MAP
4829 if (r < 0)
4830 return bus_log_parse_error(r);
4ad49000 4831
f459b602
MAP
4832 r = sd_bus_message_exit_container(m);
4833 if (r < 0)
4834 return bus_log_parse_error(r);
4ad49000 4835
07636114 4836 return 1;
4ad49000 4837
07636114 4838 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN &&
72240b52 4839 STR_IN_SET(name, "IODeviceWeight", "BlockIODeviceWeight")) {
f459b602
MAP
4840 const char *path;
4841 uint64_t weight;
b8ab2dc6 4842
f459b602
MAP
4843 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
4844 if (r < 0)
4845 return bus_log_parse_error(r);
b8ab2dc6 4846
f459b602 4847 while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0)
4f9a9105 4848 print_prop(name, "%s %"PRIu64, strna(path), weight);
f459b602
MAP
4849 if (r < 0)
4850 return bus_log_parse_error(r);
b8ab2dc6 4851
f459b602
MAP
4852 r = sd_bus_message_exit_container(m);
4853 if (r < 0)
4854 return bus_log_parse_error(r);
b8ab2dc6 4855
07636114 4856 return 1;
b8ab2dc6 4857
07636114 4858 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN &&
72240b52
ZJS
4859 (cgroup_io_limit_type_from_string(name) >= 0 ||
4860 STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth"))) {
f459b602
MAP
4861 const char *path;
4862 uint64_t bandwidth;
4ad49000 4863
f459b602
MAP
4864 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
4865 if (r < 0)
4866 return bus_log_parse_error(r);
4ad49000 4867
f459b602 4868 while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0)
4f9a9105 4869 print_prop(name, "%s %"PRIu64, strna(path), bandwidth);
f459b602
MAP
4870 if (r < 0)
4871 return bus_log_parse_error(r);
4ad49000 4872
f459b602
MAP
4873 r = sd_bus_message_exit_container(m);
4874 if (r < 0)
4875 return bus_log_parse_error(r);
4ad49000 4876
07636114 4877 return 1;
08f3be7a 4878
07636114 4879 } else if (contents[0] == SD_BUS_TYPE_BYTE && streq(name, "StandardInputData")) {
08f3be7a
LP
4880 _cleanup_free_ char *h = NULL;
4881 const void *p;
4882 size_t sz;
4883 ssize_t n;
4884
4885 r = sd_bus_message_read_array(m, 'y', &p, &sz);
4886 if (r < 0)
4887 return bus_log_parse_error(r);
4888
4889 n = base64mem(p, sz, &h);
4890 if (n < 0)
4891 return log_oom();
4892
4893 print_prop(name, "%s", h);
4894
07636114 4895 return 1;
48220598
LP
4896 }
4897
4898 break;
4899 }
4900
48220598
LP
4901 return 0;
4902}
4903
8559e61d
YW
4904typedef enum SystemctlShowMode{
4905 SYSTEMCTL_SHOW_PROPERTIES,
4906 SYSTEMCTL_SHOW_STATUS,
4907 SYSTEMCTL_SHOW_HELP,
4908 _SYSTEMCTL_SHOW_MODE_MAX,
4909 _SYSTEMCTL_SHOW_MODE_INVALID = -1,
4910} SystemctlShowMode;
4911
4912static const char* const systemctl_show_mode_table[] = {
4913 [SYSTEMCTL_SHOW_PROPERTIES] = "show",
4914 [SYSTEMCTL_SHOW_STATUS] = "status",
4915 [SYSTEMCTL_SHOW_HELP] = "help",
4916};
4917
4918DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(systemctl_show_mode, SystemctlShowMode);
4919
f459b602 4920static int show_one(
f459b602
MAP
4921 sd_bus *bus,
4922 const char *path,
3dced37b 4923 const char *unit,
8559e61d 4924 SystemctlShowMode show_mode,
f459b602
MAP
4925 bool *new_line,
4926 bool *ellipsized) {
4927
3dced37b 4928 static const struct bus_properties_map property_map[] = {
4679a8c3
YW
4929 { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) },
4930 { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) },
4931 { "Documentation", "as", NULL, offsetof(UnitStatusInfo, documentation) },
4932 {}
4933 }, status_map[] = {
4934 { "Id", "s", NULL, offsetof(UnitStatusInfo, id) },
4935 { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) },
4936 { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) },
4937 { "SubState", "s", NULL, offsetof(UnitStatusInfo, sub_state) },
4938 { "UnitFileState", "s", NULL, offsetof(UnitStatusInfo, unit_file_state) },
4939 { "UnitFilePreset", "s", NULL, offsetof(UnitStatusInfo, unit_file_preset) },
4940 { "Description", "s", NULL, offsetof(UnitStatusInfo, description) },
4941 { "Following", "s", NULL, offsetof(UnitStatusInfo, following) },
4942 { "Documentation", "as", NULL, offsetof(UnitStatusInfo, documentation) },
4943 { "FragmentPath", "s", NULL, offsetof(UnitStatusInfo, fragment_path) },
4944 { "SourcePath", "s", NULL, offsetof(UnitStatusInfo, source_path) },
4945 { "ControlGroup", "s", NULL, offsetof(UnitStatusInfo, control_group) },
4946 { "DropInPaths", "as", NULL, offsetof(UnitStatusInfo, dropin_paths) },
4947 { "LoadError", "(ss)", map_load_error, offsetof(UnitStatusInfo, load_error) },
4948 { "Result", "s", NULL, offsetof(UnitStatusInfo, result) },
4949 { "InactiveExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, inactive_exit_timestamp) },
4950 { "InactiveExitTimestampMonotonic", "t", NULL, offsetof(UnitStatusInfo, inactive_exit_timestamp_monotonic) },
4951 { "ActiveEnterTimestamp", "t", NULL, offsetof(UnitStatusInfo, active_enter_timestamp) },
4952 { "ActiveExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, active_exit_timestamp) },
4953 { "InactiveEnterTimestamp", "t", NULL, offsetof(UnitStatusInfo, inactive_enter_timestamp) },
4954 { "NeedDaemonReload", "b", NULL, offsetof(UnitStatusInfo, need_daemon_reload) },
4955 { "Transient", "b", NULL, offsetof(UnitStatusInfo, transient) },
4956 { "ExecMainPID", "u", NULL, offsetof(UnitStatusInfo, main_pid) },
4957 { "MainPID", "u", map_main_pid, 0 },
4958 { "ControlPID", "u", NULL, offsetof(UnitStatusInfo, control_pid) },
4959 { "StatusText", "s", NULL, offsetof(UnitStatusInfo, status_text) },
4960 { "PIDFile", "s", NULL, offsetof(UnitStatusInfo, pid_file) },
4961 { "StatusErrno", "i", NULL, offsetof(UnitStatusInfo, status_errno) },
4962 { "ExecMainStartTimestamp", "t", NULL, offsetof(UnitStatusInfo, start_timestamp) },
4963 { "ExecMainExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, exit_timestamp) },
4964 { "ExecMainCode", "i", NULL, offsetof(UnitStatusInfo, exit_code) },
4965 { "ExecMainStatus", "i", NULL, offsetof(UnitStatusInfo, exit_status) },
4966 { "ConditionTimestamp", "t", NULL, offsetof(UnitStatusInfo, condition_timestamp) },
4967 { "ConditionResult", "b", NULL, offsetof(UnitStatusInfo, condition_result) },
4968 { "Conditions", "a(sbbsi)", map_conditions, 0 },
4969 { "AssertTimestamp", "t", NULL, offsetof(UnitStatusInfo, assert_timestamp) },
4970 { "AssertResult", "b", NULL, offsetof(UnitStatusInfo, assert_result) },
4971 { "Asserts", "a(sbbsi)", map_asserts, 0 },
4972 { "NextElapseUSecRealtime", "t", NULL, offsetof(UnitStatusInfo, next_elapse_real) },
4973 { "NextElapseUSecMonotonic", "t", NULL, offsetof(UnitStatusInfo, next_elapse_monotonic) },
4974 { "NAccepted", "u", NULL, offsetof(UnitStatusInfo, n_accepted) },
4975 { "NConnections", "u", NULL, offsetof(UnitStatusInfo, n_connections) },
4976 { "Accept", "b", NULL, offsetof(UnitStatusInfo, accept) },
4977 { "Listen", "a(ss)", map_listen, offsetof(UnitStatusInfo, listen) },
4978 { "SysFSPath", "s", NULL, offsetof(UnitStatusInfo, sysfs_path) },
4979 { "Where", "s", NULL, offsetof(UnitStatusInfo, where) },
4980 { "What", "s", NULL, offsetof(UnitStatusInfo, what) },
4981 { "MemoryCurrent", "t", NULL, offsetof(UnitStatusInfo, memory_current) },
4982 { "MemoryLow", "t", NULL, offsetof(UnitStatusInfo, memory_low) },
4983 { "MemoryHigh", "t", NULL, offsetof(UnitStatusInfo, memory_high) },
4984 { "MemoryMax", "t", NULL, offsetof(UnitStatusInfo, memory_max) },
4985 { "MemorySwapMax", "t", NULL, offsetof(UnitStatusInfo, memory_swap_max) },
4986 { "MemoryLimit", "t", NULL, offsetof(UnitStatusInfo, memory_limit) },
4987 { "CPUUsageNSec", "t", NULL, offsetof(UnitStatusInfo, cpu_usage_nsec) },
4988 { "TasksCurrent", "t", NULL, offsetof(UnitStatusInfo, tasks_current) },
4989 { "TasksMax", "t", NULL, offsetof(UnitStatusInfo, tasks_max) },
4990 { "IPIngressBytes", "t", NULL, offsetof(UnitStatusInfo, ip_ingress_bytes) },
4991 { "IPEgressBytes", "t", NULL, offsetof(UnitStatusInfo, ip_egress_bytes) },
4992 { "ExecStartPre", "a(sasbttttuii)", map_exec, 0 },
4993 { "ExecStart", "a(sasbttttuii)", map_exec, 0 },
4994 { "ExecStartPost", "a(sasbttttuii)", map_exec, 0 },
4995 { "ExecReload", "a(sasbttttuii)", map_exec, 0 },
4996 { "ExecStopPre", "a(sasbttttuii)", map_exec, 0 },
4997 { "ExecStop", "a(sasbttttuii)", map_exec, 0 },
4998 { "ExecStopPost", "a(sasbttttuii)", map_exec, 0 },
3dced37b
LP
4999 {}
5000 };
5001
4afd3348
LP
5002 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
5003 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
3dced37b 5004 _cleanup_set_free_ Set *found_properties = NULL;
a7335518 5005 _cleanup_(unit_status_info_free) UnitStatusInfo info = {
934277fe 5006 .memory_current = (uint64_t) -1,
da4d897e
TH
5007 .memory_high = CGROUP_LIMIT_MAX,
5008 .memory_max = CGROUP_LIMIT_MAX,
96e131ea 5009 .memory_swap_max = CGROUP_LIMIT_MAX,
934277fe 5010 .memory_limit = (uint64_t) -1,
5ad096b3 5011 .cpu_usage_nsec = (uint64_t) -1,
03a7b521
LP
5012 .tasks_current = (uint64_t) -1,
5013 .tasks_max = (uint64_t) -1,
0e97c93f
DM
5014 .ip_ingress_bytes = (uint64_t) -1,
5015 .ip_egress_bytes = (uint64_t) -1,
934277fe 5016 };
4679a8c3 5017 char **pp;
f459b602 5018 int r;
48220598 5019
48220598 5020 assert(path);
61cbdc4b 5021 assert(new_line);
48220598 5022
e3e0314b
ZJS
5023 log_debug("Showing one %s", path);
5024
4679a8c3 5025 r = bus_map_all_properties(
f22f08cd
SP
5026 bus,
5027 "org.freedesktop.systemd1",
5028 path,
4679a8c3 5029 show_mode == SYSTEMCTL_SHOW_STATUS ? status_map : property_map,
a7e4861c 5030 BUS_MAP_BOOLEAN_AS_BOOL,
f459b602 5031 &error,
f22f08cd 5032 &reply,
4679a8c3 5033 &info);
4c3e8e39
LP
5034 if (r < 0)
5035 return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
48220598 5036
4679a8c3
YW
5037 if (unit && streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) {
5038 log_full(show_mode == SYSTEMCTL_SHOW_STATUS ? LOG_ERR : LOG_DEBUG,
5039 "Unit %s could not be found.", unit);
e33a06a1 5040
4679a8c3
YW
5041 if (show_mode == SYSTEMCTL_SHOW_STATUS)
5042 return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN;
5043 else if (show_mode == SYSTEMCTL_SHOW_HELP)
5044 return -ENOENT;
5045 }
e33a06a1 5046
4679a8c3
YW
5047 if (*new_line)
5048 printf("\n");
3dced37b 5049
4679a8c3
YW
5050 *new_line = true;
5051
5052 if (show_mode == SYSTEMCTL_SHOW_STATUS) {
5053 print_status_info(bus, &info, ellipsized);
5054
5055 if (info.active_state && !STR_IN_SET(info.active_state, "active", "reloading"))
5056 return EXIT_PROGRAM_NOT_RUNNING;
5057
5058 return EXIT_PROGRAM_RUNNING_OR_SERVICE_OK;
5059
5060 } else if (show_mode == SYSTEMCTL_SHOW_HELP) {
5061 show_unit_help(&info);
5062 return 0;
3dced37b 5063 }
e33a06a1 5064
4679a8c3
YW
5065 r = sd_bus_message_rewind(reply, true);
5066 if (r < 0)
5067 return log_error_errno(r, "Failed to rewind: %s", bus_error_message(&error, r));
5068
07636114 5069 r = bus_message_print_all_properties(reply, print_property, arg_properties, arg_value, arg_all, &found_properties);
f459b602
MAP
5070 if (r < 0)
5071 return bus_log_parse_error(r);
48220598 5072
4679a8c3
YW
5073 STRV_FOREACH(pp, arg_properties)
5074 if (!set_contains(found_properties, *pp))
5075 log_debug("Property %s does not exist.", *pp);
3dced37b 5076
4679a8c3 5077 return 0;
48220598
LP
5078}
5079
f74294c1 5080static int get_unit_dbus_path_by_pid(
f459b602
MAP
5081 sd_bus *bus,
5082 uint32_t pid,
f74294c1 5083 char **unit) {
f459b602 5084
4afd3348
LP
5085 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5086 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
373d32c9 5087 char *u;
a223b325
MS
5088 int r;
5089
f459b602 5090 r = sd_bus_call_method(
f22f08cd
SP
5091 bus,
5092 "org.freedesktop.systemd1",
5093 "/org/freedesktop/systemd1",
5094 "org.freedesktop.systemd1.Manager",
5095 "GetUnitByPID",
f459b602 5096 &error,
f22f08cd 5097 &reply,
f459b602 5098 "u", pid);
691395d8
LP
5099 if (r < 0)
5100 return log_error_errno(r, "Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
a223b325 5101
373d32c9 5102 r = sd_bus_message_read(reply, "o", &u);
f459b602
MAP
5103 if (r < 0)
5104 return bus_log_parse_error(r);
5105
373d32c9
LP
5106 u = strdup(u);
5107 if (!u)
5108 return log_oom();
5109
5110 *unit = u;
f74294c1 5111 return 0;
a223b325
MS
5112}
5113
f459b602 5114static int show_all(
f459b602 5115 sd_bus *bus,
f459b602
MAP
5116 bool *new_line,
5117 bool *ellipsized) {
5118
4afd3348 5119 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
f459b602
MAP
5120 _cleanup_free_ UnitInfo *unit_infos = NULL;
5121 const UnitInfo *u;
5122 unsigned c;
5bb75bc7 5123 int r, ret = 0;
265a7a2a 5124
1238ee09 5125 r = get_unit_list(bus, NULL, NULL, &unit_infos, 0, &reply);
265a7a2a
ZJS
5126 if (r < 0)
5127 return r;
5128
ee5324aa 5129 (void) pager_open(arg_no_pager, false);
dbed408b 5130
f459b602
MAP
5131 c = (unsigned) r;
5132
5133 qsort_safe(unit_infos, c, sizeof(UnitInfo), compare_unit_info);
991f2a39 5134
265a7a2a 5135 for (u = unit_infos; u < unit_infos + c; u++) {
7fd1b19b 5136 _cleanup_free_ char *p = NULL;
265a7a2a 5137
265a7a2a
ZJS
5138 p = unit_dbus_path_from_name(u->id);
5139 if (!p)
5140 return log_oom();
5141
8559e61d 5142 r = show_one(bus, p, u->id, SYSTEMCTL_SHOW_STATUS, new_line, ellipsized);
3df538da 5143 if (r < 0)
265a7a2a 5144 return r;
5bb75bc7
ZJS
5145 else if (r > 0 && ret == 0)
5146 ret = r;
265a7a2a
ZJS
5147 }
5148
5bb75bc7 5149 return ret;
265a7a2a
ZJS
5150}
5151
8fcf784d
LP
5152static int show_system_status(sd_bus *bus) {
5153 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
f9e0eefc 5154 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
e7e55dbd 5155 _cleanup_(machine_info_clear) struct machine_info mi = {};
f9e0eefc 5156 _cleanup_free_ char *hn = NULL;
8fcf784d
LP
5157 const char *on, *off;
5158 int r;
5159
5160 hn = gethostname_malloc();
5161 if (!hn)
5162 return log_oom();
5163
a7e4861c
YW
5164 r = bus_map_all_properties(
5165 bus,
5166 "org.freedesktop.systemd1",
5167 "/org/freedesktop/systemd1",
5168 machine_info_property_map,
5169 BUS_MAP_STRDUP,
5170 &error,
5171 NULL,
5172 &mi);
f647962d 5173 if (r < 0)
f9e0eefc 5174 return log_error_errno(r, "Failed to read server status: %s", bus_error_message(&error, r));
8fcf784d 5175
8fcf784d
LP
5176 if (streq_ptr(mi.state, "degraded")) {
5177 on = ansi_highlight_red();
1fc464f6 5178 off = ansi_normal();
92f34a9c
JR
5179 } else if (streq_ptr(mi.state, "running")) {
5180 on = ansi_highlight_green();
5181 off = ansi_normal();
5182 } else {
8fcf784d 5183 on = ansi_highlight_yellow();
1fc464f6 5184 off = ansi_normal();
92f34a9c 5185 }
8fcf784d 5186
323b7dc9 5187 printf("%s%s%s %s\n", on, special_glyph(BLACK_CIRCLE), off, arg_host ? arg_host : hn);
b0d14c69 5188
8fcf784d
LP
5189 printf(" State: %s%s%s\n",
5190 on, strna(mi.state), off);
5191
c6ba5b80
MP
5192 printf(" Jobs: %" PRIu32 " queued\n", mi.n_jobs);
5193 printf(" Failed: %" PRIu32 " units\n", mi.n_failed_units);
8fcf784d
LP
5194
5195 printf(" Since: %s; %s\n",
5196 format_timestamp(since2, sizeof(since2), mi.timestamp),
5197 format_timestamp_relative(since1, sizeof(since1), mi.timestamp));
5198
5199 printf(" CGroup: %s\n", mi.control_group ?: "/");
4c315c2c
IS
5200 if (IN_SET(arg_transport,
5201 BUS_TRANSPORT_LOCAL,
5202 BUS_TRANSPORT_MACHINE)) {
8fcf784d
LP
5203 static const char prefix[] = " ";
5204 unsigned c;
5205
5206 c = columns();
5207 if (c > sizeof(prefix) - 1)
5208 c -= sizeof(prefix) - 1;
5209 else
5210 c = 0;
5211
0ff308c8 5212 show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, get_output_flags());
8fcf784d
LP
5213 }
5214
8fcf784d
LP
5215 return 0;
5216}
5217
e449de87 5218static int show(int argc, char *argv[], void *userdata) {
8559e61d
YW
5219 bool new_line = false, ellipsized = false;
5220 SystemctlShowMode show_mode;
e3e0314b 5221 int r, ret = 0;
4fbd7192 5222 sd_bus *bus;
48220598 5223
e449de87 5224 assert(argv);
48220598 5225
8559e61d
YW
5226 show_mode = systemctl_show_mode_from_string(argv[0]);
5227 if (show_mode < 0) {
5228 log_error("Invalid argument.");
5229 return -EINVAL;
5230 }
e449de87 5231
8559e61d 5232 if (show_mode == SYSTEMCTL_SHOW_HELP && argc <= 1) {
e449de87
LP
5233 log_error("This command expects one or more unit names. Did you mean --help?");
5234 return -EINVAL;
5235 }
61cbdc4b 5236
d2ad7e1b
ZJS
5237 r = acquire_bus(BUS_MANAGER, &bus);
5238 if (r < 0)
5239 return r;
5240
ee5324aa 5241 (void) pager_open(arg_no_pager, false);
ec14911e 5242
8559e61d 5243 if (show_mode == SYSTEMCTL_SHOW_STATUS)
40acc203
ZJS
5244 /* Increase max number of open files to 16K if we can, we
5245 * might needs this when browsing journal files, which might
5246 * be split up into many files. */
5247 setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
5248
4fbd7192 5249 /* If no argument is specified inspect the manager itself */
8559e61d
YW
5250 if (show_mode == SYSTEMCTL_SHOW_PROPERTIES && argc <= 1)
5251 return show_one(bus, "/org/freedesktop/systemd1", NULL, show_mode, &new_line, &ellipsized);
48220598 5252
8559e61d 5253 if (show_mode == SYSTEMCTL_SHOW_STATUS && argc <= 1) {
8fcf784d 5254
8fcf784d
LP
5255 show_system_status(bus);
5256 new_line = true;
5257
5258 if (arg_all)
8559e61d 5259 ret = show_all(bus, &new_line, &ellipsized);
8fcf784d 5260 } else {
e3e0314b
ZJS
5261 _cleanup_free_ char **patterns = NULL;
5262 char **name;
5263
e449de87 5264 STRV_FOREACH(name, strv_skip(argv, 1)) {
3dced37b 5265 _cleanup_free_ char *path = NULL, *unit = NULL;
94e0bd7d 5266 uint32_t id;
48220598 5267
94e0bd7d 5268 if (safe_atou32(*name, &id) < 0) {
e3e0314b 5269 if (strv_push(&patterns, *name) < 0)
94e0bd7d 5270 return log_oom();
48220598 5271
e3e0314b 5272 continue;
8559e61d 5273 } else if (show_mode == SYSTEMCTL_SHOW_PROPERTIES) {
94e0bd7d 5274 /* Interpret as job id */
3dced37b 5275 if (asprintf(&path, "/org/freedesktop/systemd1/job/%u", id) < 0)
94e0bd7d 5276 return log_oom();
48220598 5277
94e0bd7d
ZJS
5278 } else {
5279 /* Interpret as PID */
3dced37b 5280 r = get_unit_dbus_path_by_pid(bus, id, &path);
373d32c9 5281 if (r < 0) {
94e0bd7d 5282 ret = r;
373d32c9
LP
5283 continue;
5284 }
3dced37b
LP
5285
5286 r = unit_name_from_dbus_path(path, &unit);
5287 if (r < 0)
5288 return log_oom();
94e0bd7d 5289 }
f74294c1 5290
8559e61d 5291 r = show_one(bus, path, unit, show_mode, &new_line, &ellipsized);
5bb75bc7
ZJS
5292 if (r < 0)
5293 return r;
5294 else if (r > 0 && ret == 0)
5295 ret = r;
48220598 5296 }
94e0bd7d 5297
e3e0314b
ZJS
5298 if (!strv_isempty(patterns)) {
5299 _cleanup_strv_free_ char **names = NULL;
5300
5301 r = expand_names(bus, patterns, NULL, &names);
5302 if (r < 0)
691395d8 5303 return log_error_errno(r, "Failed to expand names: %m");
e3e0314b
ZJS
5304
5305 STRV_FOREACH(name, names) {
3dced37b 5306 _cleanup_free_ char *path;
e3e0314b 5307
3dced37b
LP
5308 path = unit_dbus_path_from_name(*name);
5309 if (!path)
e3e0314b
ZJS
5310 return log_oom();
5311
8559e61d 5312 r = show_one(bus, path, *name, show_mode, &new_line, &ellipsized);
5bb75bc7
ZJS
5313 if (r < 0)
5314 return r;
3dced37b 5315 if (r > 0 && ret == 0)
5bb75bc7 5316 ret = r;
e3e0314b
ZJS
5317 }
5318 }
5319 }
5320
94e0bd7d
ZJS
5321 if (ellipsized && !arg_quiet)
5322 printf("Hint: Some lines were ellipsized, use -l to show in full.\n");
48220598 5323
22f4096c 5324 return ret;
0183528f
LP
5325}
5326
8527b07b
ZJS
5327static int cat_file(const char *filename, bool newline) {
5328 _cleanup_close_ int fd;
5329
5330 fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOCTTY);
5331 if (fd < 0)
5332 return -errno;
5333
5334 printf("%s%s# %s%s\n",
5335 newline ? "\n" : "",
5336 ansi_highlight_blue(),
5337 filename,
1fc464f6 5338 ansi_normal());
8527b07b
ZJS
5339 fflush(stdout);
5340
1c876927 5341 return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, 0);
8527b07b
ZJS
5342}
5343
e449de87 5344static int cat(int argc, char *argv[], void *userdata) {
ad2a0358 5345 _cleanup_lookup_paths_free_ LookupPaths lp = {};
15ef1144
LP
5346 _cleanup_strv_free_ char **names = NULL;
5347 char **name;
4fbd7192
LP
5348 sd_bus *bus;
5349 bool first = true;
25586912 5350 int r;
15ef1144 5351
3e7eed84 5352 if (arg_transport != BUS_TRANSPORT_LOCAL) {
4fbd7192 5353 log_error("Cannot remotely cat units.");
3e495a66
ZJS
5354 return -EINVAL;
5355 }
5356
4943d143 5357 r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
ad2a0358 5358 if (r < 0)
c51932be 5359 return log_error_errno(r, "Failed to determine unit paths: %m");
ad2a0358 5360
4fbd7192 5361 r = acquire_bus(BUS_MANAGER, &bus);
15ef1144 5362 if (r < 0)
4fbd7192 5363 return r;
15ef1144 5364
e449de87 5365 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
4fbd7192
LP
5366 if (r < 0)
5367 return log_error_errno(r, "Failed to expand names: %m");
ad2a0358 5368
ee5324aa 5369 (void) pager_open(arg_no_pager, false);
15ef1144
LP
5370
5371 STRV_FOREACH(name, names) {
ad2a0358 5372 _cleanup_free_ char *fragment_path = NULL;
15ef1144 5373 _cleanup_strv_free_ char **dropin_paths = NULL;
15ef1144
LP
5374 char **path;
5375
4fbd7192 5376 r = unit_find_paths(bus, *name, &lp, &fragment_path, &dropin_paths);
ad2a0358
ZJS
5377 if (r < 0)
5378 return r;
b5e6a600
IS
5379 else if (r == 0)
5380 return -ENOENT;
15ef1144
LP
5381
5382 if (first)
5383 first = false;
5384 else
5385 puts("");
5386
5b9635d1 5387 if (need_daemon_reload(bus, *name) > 0) /* ignore errors (<0), this is informational output */
e100155d
LW
5388 fprintf(stderr,
5389 "%s# Warning: %s changed on disk, the version systemd has loaded is outdated.\n"
5390 "%s# This output shows the current version of the unit's original fragment and drop-in files.\n"
5391 "%s# If fragments or drop-ins were added or removed, they are not properly reflected in this output.\n"
5392 "%s# Run 'systemctl%s daemon-reload' to reload units.%s\n",
5393 ansi_highlight_red(),
5394 *name,
5395 ansi_highlight_red(),
5396 ansi_highlight_red(),
5397 ansi_highlight_red(),
5398 arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
5399 ansi_normal());
5400
ad2a0358 5401 if (fragment_path) {
8527b07b
ZJS
5402 r = cat_file(fragment_path, false);
5403 if (r < 0)
5404 return log_warning_errno(r, "Failed to cat %s: %m", fragment_path);
15ef1144
LP
5405 }
5406
5407 STRV_FOREACH(path, dropin_paths) {
8527b07b
ZJS
5408 r = cat_file(*path, path == dropin_paths);
5409 if (r < 0)
5410 return log_warning_errno(r, "Failed to cat %s: %m", *path);
15ef1144
LP
5411 }
5412 }
5413
25586912 5414 return 0;
15ef1144
LP
5415}
5416
e449de87 5417static int set_property(int argc, char *argv[], void *userdata) {
4afd3348
LP
5418 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
5419 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
68372da6 5420 _cleanup_free_ char *n = NULL;
89ada3ba 5421 UnitType t;
4fbd7192 5422 sd_bus *bus;
8e2af478
LP
5423 int r;
5424
4fbd7192
LP
5425 r = acquire_bus(BUS_MANAGER, &bus);
5426 if (r < 0)
5427 return r;
5428
8a4b13c5 5429 polkit_agent_open_maybe();
d2ad7e1b 5430
f459b602
MAP
5431 r = sd_bus_message_new_method_call(
5432 bus,
151b9b96 5433 &m,
8e2af478
LP
5434 "org.freedesktop.systemd1",
5435 "/org/freedesktop/systemd1",
5436 "org.freedesktop.systemd1.Manager",
151b9b96 5437 "SetUnitProperties");
f459b602
MAP
5438 if (r < 0)
5439 return bus_log_create_error(r);
8e2af478 5440
37cbc1d5 5441 r = unit_name_mangle(argv[1], arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, &n);
7410616c
LP
5442 if (r < 0)
5443 return log_error_errno(r, "Failed to mangle unit name: %m");
68372da6 5444
89ada3ba
YW
5445 t = unit_name_to_type(n);
5446 if (t < 0) {
5447 log_error("Invalid unit type: %s", n);
5448 return -EINVAL;
5449 }
5450
f459b602
MAP
5451 r = sd_bus_message_append(m, "sb", n, arg_runtime);
5452 if (r < 0)
5453 return bus_log_create_error(r);
8e2af478 5454
f459b602
MAP
5455 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, "(sv)");
5456 if (r < 0)
5457 return bus_log_create_error(r);
8e2af478 5458
89ada3ba 5459 r = bus_append_unit_property_assignment_many(m, t, strv_skip(argv, 2));
8673cf13
LP
5460 if (r < 0)
5461 return r;
8e2af478 5462
f459b602
MAP
5463 r = sd_bus_message_close_container(m);
5464 if (r < 0)
5465 return bus_log_create_error(r);
8e2af478 5466
c49b30a2 5467 r = sd_bus_call(bus, m, 0, &error, NULL);
691395d8
LP
5468 if (r < 0)
5469 return log_error_errno(r, "Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
8e2af478
LP
5470
5471 return 0;
5472}
5473
e449de87 5474static int daemon_reload(int argc, char *argv[], void *userdata) {
4afd3348 5475 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2853b60a 5476 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
7e4249b9 5477 const char *method;
4fbd7192 5478 sd_bus *bus;
f459b602 5479 int r;
7e4249b9 5480
4fbd7192
LP
5481 r = acquire_bus(BUS_MANAGER, &bus);
5482 if (r < 0)
5483 return r;
5484
8a4b13c5 5485 polkit_agent_open_maybe();
d2ad7e1b 5486
2853b60a
LP
5487 switch (arg_action) {
5488
5489 case ACTION_RELOAD:
e4b61340 5490 method = "Reload";
2853b60a
LP
5491 break;
5492
5493 case ACTION_REEXEC:
e4b61340 5494 method = "Reexecute";
2853b60a
LP
5495 break;
5496
5497 case ACTION_SYSTEMCTL:
5498 method = streq(argv[0], "daemon-reexec") ? "Reexecute" :
5499 /* "daemon-reload" */ "Reload";
5500 break;
e4b61340 5501
2853b60a
LP
5502 default:
5503 assert_not_reached("Unexpected action");
e4b61340 5504 }
7e4249b9 5505
2853b60a
LP
5506 r = sd_bus_message_new_method_call(
5507 bus,
5508 &m,
5509 "org.freedesktop.systemd1",
5510 "/org/freedesktop/systemd1",
5511 "org.freedesktop.systemd1.Manager",
5512 method);
5513 if (r < 0)
5514 return bus_log_create_error(r);
5515
5516 /* Note we use an extra-long timeout here. This is because a reload or reexec means generators are rerun which
5517 * are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the generators can have
5518 * their timeout, and for everything else there's the same time budget in place. */
5519
5520 r = sd_bus_call(bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL);
5521
5522 /* On reexecution, we expect a disconnect, not a reply */
5523 if (IN_SET(r, -ETIMEDOUT, -ECONNRESET) && streq(method, "Reexecute"))
5524 r = 0;
5525
5526 if (r < 0 && arg_action == ACTION_SYSTEMCTL)
5527 return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
5528
5529 /* Note that for the legacy commands (i.e. those with action != ACTION_SYSTEMCTL) we support fallbacks to the
5530 * old ways of doing things, hence don't log any error in that case here. */
5531
5532 return r < 0 ? r : 0;
5533}
5534
5535static int trivial_method(int argc, char *argv[], void *userdata) {
5536 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5537 const char *method;
5538 sd_bus *bus;
5539 int r;
5540
1ae17672
ZJS
5541 if (arg_dry_run)
5542 return 0;
5543
2853b60a
LP
5544 r = acquire_bus(BUS_MANAGER, &bus);
5545 if (r < 0)
5546 return r;
5547
8a4b13c5 5548 polkit_agent_open_maybe();
d2ad7e1b 5549
2853b60a
LP
5550 method =
5551 streq(argv[0], "clear-jobs") ||
5552 streq(argv[0], "cancel") ? "ClearJobs" :
5553 streq(argv[0], "reset-failed") ? "ResetFailed" :
5554 streq(argv[0], "halt") ? "Halt" :
5555 streq(argv[0], "reboot") ? "Reboot" :
5556 streq(argv[0], "kexec") ? "KExec" :
5557 streq(argv[0], "exit") ? "Exit" :
5558 /* poweroff */ "PowerOff";
5559
6e646d22 5560 r = sd_bus_call_method(
f22f08cd
SP
5561 bus,
5562 "org.freedesktop.systemd1",
5563 "/org/freedesktop/systemd1",
5564 "org.freedesktop.systemd1.Manager",
6e646d22
LP
5565 method,
5566 &error,
5567 NULL,
5568 NULL);
2853b60a
LP
5569 if (r < 0 && arg_action == ACTION_SYSTEMCTL)
5570 return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
5571
5572 /* Note that for the legacy commands (i.e. those with action != ACTION_SYSTEMCTL) we support fallbacks to the
5573 * old ways of doing things, hence don't log any error in that case here. */
7e4249b9 5574
0a9776c2 5575 return r < 0 ? r : 0;
7e4249b9
LP
5576}
5577
e449de87 5578static int reset_failed(int argc, char *argv[], void *userdata) {
e3e0314b 5579 _cleanup_strv_free_ char **names = NULL;
4fbd7192 5580 sd_bus *bus;
f84190d8 5581 char **name;
e3e0314b 5582 int r, q;
5632e374 5583
e449de87 5584 if (argc <= 1)
2853b60a 5585 return trivial_method(argc, argv, userdata);
5632e374 5586
4fbd7192
LP
5587 r = acquire_bus(BUS_MANAGER, &bus);
5588 if (r < 0)
5589 return r;
5590
8a4b13c5 5591 polkit_agent_open_maybe();
d2ad7e1b 5592
e449de87 5593 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
e3e0314b 5594 if (r < 0)
691395d8 5595 return log_error_errno(r, "Failed to expand names: %m");
f84190d8 5596
e3e0314b 5597 STRV_FOREACH(name, names) {
4afd3348 5598 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
342641fb 5599
6e646d22 5600 q = sd_bus_call_method(
f22f08cd 5601 bus,
b0193f1c
LP
5602 "org.freedesktop.systemd1",
5603 "/org/freedesktop/systemd1",
5604 "org.freedesktop.systemd1.Manager",
6e646d22
LP
5605 "ResetFailedUnit",
5606 &error,
5607 NULL,
5608 "s", *name);
e3e0314b 5609 if (q < 0) {
691395d8 5610 log_error_errno(q, "Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
e3e0314b
ZJS
5611 if (r == 0)
5612 r = q;
f459b602 5613 }
5632e374
LP
5614 }
5615
e3e0314b 5616 return r;
5632e374
LP
5617}
5618
804ee07c
ZJS
5619static int print_variable(const char *s) {
5620 const char *sep;
5621 _cleanup_free_ char *esc = NULL;
5622
5623 sep = strchr(s, '=');
5624 if (!sep) {
5625 log_error("Invalid environment block");
5626 return -EUCLEAN;
5627 }
5628
5629 esc = shell_maybe_quote(sep + 1, ESCAPE_POSIX);
5630 if (!esc)
5631 return log_oom();
5632
5633 printf("%.*s=%s\n", (int)(sep-s), s, esc);
5634 return 0;
5635}
5636
e449de87 5637static int show_environment(int argc, char *argv[], void *userdata) {
4afd3348
LP
5638 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5639 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
f459b602 5640 const char *text;
4fbd7192 5641 sd_bus *bus;
7e4249b9 5642 int r;
7e4249b9 5643
4fbd7192
LP
5644 r = acquire_bus(BUS_MANAGER, &bus);
5645 if (r < 0)
5646 return r;
5647
ee5324aa 5648 (void) pager_open(arg_no_pager, false);
d2ad7e1b 5649
f459b602 5650 r = sd_bus_get_property(
f22f08cd
SP
5651 bus,
5652 "org.freedesktop.systemd1",
5653 "/org/freedesktop/systemd1",
f459b602
MAP
5654 "org.freedesktop.systemd1.Manager",
5655 "Environment",
5656 &error,
f22f08cd 5657 &reply,
f459b602 5658 "as");
691395d8
LP
5659 if (r < 0)
5660 return log_error_errno(r, "Failed to get environment: %s", bus_error_message(&error, r));
7e4249b9 5661
f459b602
MAP
5662 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
5663 if (r < 0)
5664 return bus_log_parse_error(r);
7e4249b9 5665
804ee07c
ZJS
5666 while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0) {
5667 r = print_variable(text);
5668 if (r < 0)
5669 return r;
5670 }
f459b602
MAP
5671 if (r < 0)
5672 return bus_log_parse_error(r);
7e4249b9 5673
f459b602
MAP
5674 r = sd_bus_message_exit_container(reply);
5675 if (r < 0)
5676 return bus_log_parse_error(r);
7e4249b9 5677
f84190d8 5678 return 0;
7e4249b9
LP
5679}
5680
e449de87 5681static int switch_root(int argc, char *argv[], void *userdata) {
4afd3348 5682 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
f39d4a08
HH
5683 _cleanup_free_ char *cmdline_init = NULL;
5684 const char *root, *init;
4fbd7192 5685 sd_bus *bus;
f459b602 5686 int r;
957eb8ca 5687
4fbd7192
LP
5688 if (arg_transport != BUS_TRANSPORT_LOCAL) {
5689 log_error("Cannot switch root remotely.");
5690 return -EINVAL;
5691 }
5692
e449de87 5693 if (argc < 2 || argc > 3) {
957eb8ca
LP
5694 log_error("Wrong number of arguments.");
5695 return -EINVAL;
5696 }
5697
e449de87 5698 root = argv[1];
13068da8 5699
e449de87
LP
5700 if (argc >= 3)
5701 init = argv[2];
13068da8 5702 else {
f39d4a08
HH
5703 r = parse_env_file("/proc/cmdline", WHITESPACE,
5704 "init", &cmdline_init,
5705 NULL);
5706 if (r < 0)
da927ba9 5707 log_debug_errno(r, "Failed to parse /proc/cmdline: %m");
13068da8 5708
f39d4a08 5709 init = cmdline_init;
13068da8 5710 }
f459b602 5711
3c6f7c34 5712 init = empty_to_null(init);
f39d4a08
HH
5713 if (init) {
5714 const char *root_systemd_path = NULL, *root_init_path = NULL;
5715
63c372cb
LP
5716 root_systemd_path = strjoina(root, "/" SYSTEMD_BINARY_PATH);
5717 root_init_path = strjoina(root, "/", init);
f39d4a08
HH
5718
5719 /* If the passed init is actually the same as the
5720 * systemd binary, then let's suppress it. */
e3f791a2 5721 if (files_same(root_init_path, root_systemd_path, 0) > 0)
f39d4a08
HH
5722 init = NULL;
5723 }
13068da8 5724
acc28e2e 5725 /* Instruct PID1 to exclude us from its killing spree applied during
b3ad0ff4
ZJS
5726 * the transition. Otherwise we would exit with a failure status even
5727 * though the switch to the new root has succeed. */
5728 argv_cmdline[0] = '@';
acc28e2e 5729
4fbd7192
LP
5730 r = acquire_bus(BUS_MANAGER, &bus);
5731 if (r < 0)
5732 return r;
5733
8a7a9cea
ZJS
5734 /* If we are slow to exit after the root switch, the new systemd instance
5735 * will send us a signal to terminate. Just ignore it and exit normally.
5736 * This way the unit does not end up as failed.
5737 */
5738 r = ignore_signals(SIGTERM, -1);
5739 if (r < 0)
5740 log_warning_errno(r, "Failed to change disposition of SIGTERM to ignore: %m");
5741
f39d4a08 5742 log_debug("Switching root - root: %s; init: %s", root, strna(init));
957eb8ca 5743
f459b602 5744 r = sd_bus_call_method(
f22f08cd 5745 bus,
957eb8ca
LP
5746 "org.freedesktop.systemd1",
5747 "/org/freedesktop/systemd1",
5748 "org.freedesktop.systemd1.Manager",
f22f08cd 5749 "SwitchRoot",
f459b602 5750 &error,
f22f08cd 5751 NULL,
f459b602 5752 "ss", root, init);
8a7a9cea
ZJS
5753 if (r < 0) {
5754 (void) default_signals(SIGTERM, -1);
5755
691395d8 5756 return log_error_errno(r, "Failed to switch root: %s", bus_error_message(&error, r));
8a7a9cea 5757 }
f459b602
MAP
5758
5759 return 0;
957eb8ca
LP
5760}
5761
e449de87 5762static int set_environment(int argc, char *argv[], void *userdata) {
4afd3348
LP
5763 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5764 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
7e4249b9 5765 const char *method;
4fbd7192 5766 sd_bus *bus;
31e767f7
LP
5767 int r;
5768
e449de87
LP
5769 assert(argc > 1);
5770 assert(argv);
7e4249b9 5771
4fbd7192
LP
5772 r = acquire_bus(BUS_MANAGER, &bus);
5773 if (r < 0)
5774 return r;
5775
8a4b13c5 5776 polkit_agent_open_maybe();
d2ad7e1b 5777
e449de87 5778 method = streq(argv[0], "set-environment")
7e4249b9
LP
5779 ? "SetEnvironment"
5780 : "UnsetEnvironment";
5781
f459b602
MAP
5782 r = sd_bus_message_new_method_call(
5783 bus,
151b9b96 5784 &m,
31e767f7
LP
5785 "org.freedesktop.systemd1",
5786 "/org/freedesktop/systemd1",
5787 "org.freedesktop.systemd1.Manager",
151b9b96 5788 method);
f459b602
MAP
5789 if (r < 0)
5790 return bus_log_create_error(r);
7e4249b9 5791
e449de87 5792 r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
31e767f7 5793 if (r < 0)
f459b602 5794 return bus_log_create_error(r);
7e4249b9 5795
c49b30a2 5796 r = sd_bus_call(bus, m, 0, &error, NULL);
691395d8
LP
5797 if (r < 0)
5798 return log_error_errno(r, "Failed to set environment: %s", bus_error_message(&error, r));
7e4249b9 5799
f84190d8 5800 return 0;
7e4249b9
LP
5801}
5802
e449de87 5803static int import_environment(int argc, char *argv[], void *userdata) {
4afd3348
LP
5804 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5805 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
4fbd7192 5806 sd_bus *bus;
ac3efa8a
LP
5807 int r;
5808
4fbd7192
LP
5809 r = acquire_bus(BUS_MANAGER, &bus);
5810 if (r < 0)
5811 return r;
5812
8a4b13c5 5813 polkit_agent_open_maybe();
d2ad7e1b 5814
ac3efa8a
LP
5815 r = sd_bus_message_new_method_call(
5816 bus,
151b9b96 5817 &m,
ac3efa8a
LP
5818 "org.freedesktop.systemd1",
5819 "/org/freedesktop/systemd1",
5820 "org.freedesktop.systemd1.Manager",
151b9b96 5821 "SetEnvironment");
ac3efa8a
LP
5822 if (r < 0)
5823 return bus_log_create_error(r);
5824
e449de87 5825 if (argc < 2)
ac3efa8a
LP
5826 r = sd_bus_message_append_strv(m, environ);
5827 else {
5828 char **a, **b;
5829
5830 r = sd_bus_message_open_container(m, 'a', "s");
5831 if (r < 0)
5832 return bus_log_create_error(r);
5833
e449de87 5834 STRV_FOREACH(a, strv_skip(argv, 1)) {
ac3efa8a
LP
5835
5836 if (!env_name_is_valid(*a)) {
5837 log_error("Not a valid environment variable name: %s", *a);
5838 return -EINVAL;
5839 }
5840
5841 STRV_FOREACH(b, environ) {
5842 const char *eq;
5843
5844 eq = startswith(*b, *a);
5845 if (eq && *eq == '=') {
5846
5847 r = sd_bus_message_append(m, "s", *b);
5848 if (r < 0)
5849 return bus_log_create_error(r);
5850
5851 break;
5852 }
5853 }
5854 }
5855
5856 r = sd_bus_message_close_container(m);
5857 }
5858 if (r < 0)
5859 return bus_log_create_error(r);
5860
5861 r = sd_bus_call(bus, m, 0, &error, NULL);
691395d8
LP
5862 if (r < 0)
5863 return log_error_errno(r, "Failed to import environment: %s", bus_error_message(&error, r));
ac3efa8a
LP
5864
5865 return 0;
5866}
5867
cbb13b2a 5868static int enable_sysv_units(const char *verb, char **args) {
729e3769 5869 int r = 0;
ee5762e3 5870
349cc4a5 5871#if HAVE_SYSV_COMPAT
fb15be83 5872 _cleanup_lookup_paths_free_ LookupPaths paths = {};
e735decc
LP
5873 unsigned f = 0;
5874
5875 /* Processes all SysV units, and reshuffles the array so that afterwards only the native units remain */
ee5762e3 5876
729e3769
LP
5877 if (arg_scope != UNIT_FILE_SYSTEM)
5878 return 0;
ee5762e3 5879
b41b9d2a
LP
5880 if (getenv_bool("SYSTEMCTL_SKIP_SYSV") > 0)
5881 return 0;
5882
4c315c2c
IS
5883 if (!STR_IN_SET(verb,
5884 "enable",
5885 "disable",
5886 "is-enabled"))
729e3769 5887 return 0;
ee5762e3 5888
4943d143 5889 r = lookup_paths_init(&paths, arg_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root);
729e3769
LP
5890 if (r < 0)
5891 return r;
ee5762e3 5892
729e3769 5893 r = 0;
a644abed 5894 while (args[f]) {
e735decc
LP
5895
5896 const char *argv[] = {
5897 ROOTLIBEXECDIR "/systemd-sysv-install",
5898 NULL,
5899 NULL,
5900 NULL,
5901 NULL,
5902 };
5903
05cae7f3 5904 _cleanup_free_ char *p = NULL, *q = NULL, *l = NULL;
729e3769 5905 bool found_native = false, found_sysv;
e735decc 5906 const char *name;
729e3769 5907 unsigned c = 1;
729e3769 5908 pid_t pid;
e735decc 5909 int j;
ee5762e3 5910
a644abed 5911 name = args[f++];
ee5762e3 5912
729e3769
LP
5913 if (!endswith(name, ".service"))
5914 continue;
ee5762e3 5915
729e3769
LP
5916 if (path_is_absolute(name))
5917 continue;
ee5762e3 5918
e735decc 5919 j = unit_file_exists(arg_scope, &paths, name);
76ec966f 5920 if (j < 0 && !IN_SET(j, -ELOOP, -ERFKILL, -EADDRNOTAVAIL))
e735decc 5921 return log_error_errno(j, "Failed to lookup unit file state: %m");
3c6d8e57 5922 found_native = j != 0;
ee5762e3 5923
e735decc
LP
5924 /* If we have both a native unit and a SysV script, enable/disable them both (below); for is-enabled,
5925 * prefer the native unit */
355ff449 5926 if (found_native && streq(verb, "is-enabled"))
729e3769 5927 continue;
ee5762e3 5928
0c6ea3a4
ZJS
5929 p = path_join(arg_root, SYSTEM_SYSVINIT_PATH, name);
5930 if (!p)
60731f32 5931 return log_oom();
ee5762e3 5932
fbd0b64f 5933 p[strlen(p) - STRLEN(".service")] = 0;
729e3769 5934 found_sysv = access(p, F_OK) >= 0;
4b6756a8 5935 if (!found_sysv)
729e3769 5936 continue;
71fad675 5937
689e4e6a
CR
5938 if (!arg_quiet) {
5939 if (found_native)
5940 log_info("Synchronizing state of %s with SysV service script with %s.", name, argv[0]);
5941 else
5942 log_info("%s is not a native service, redirecting to systemd-sysv-install.", name);
5943 }
ee5762e3 5944
729e3769
LP
5945 if (!isempty(arg_root))
5946 argv[c++] = q = strappend("--root=", arg_root);
ee5762e3 5947
0f0467e6 5948 argv[c++] = verb;
2b6bf07d 5949 argv[c++] = basename(p);
729e3769 5950 argv[c] = NULL;
ee5762e3 5951
729e3769 5952 l = strv_join((char**)argv, " ");
60731f32
ZJS
5953 if (!l)
5954 return log_oom();
ee5762e3 5955
8ecc68f4
LP
5956 if (!arg_quiet)
5957 log_info("Executing: %s", l);
ee5762e3 5958
d2e0ac3d 5959 j = safe_fork("(sysv-install)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
4c253ed1 5960 if (j < 0)
b6e1fff1 5961 return j;
4c253ed1 5962 if (j == 0) {
729e3769 5963 /* Child */
729e3769 5964 execv(argv[0], (char**) argv);
cc7cb0ca 5965 log_error_errno(errno, "Failed to execute %s: %m", argv[0]);
729e3769
LP
5966 _exit(EXIT_FAILURE);
5967 }
ee5762e3 5968
2e87a1fd 5969 j = wait_for_terminate_and_check("sysv-install", pid, WAIT_LOG_ABNORMAL);
d710aaf7 5970 if (j < 0)
2e87a1fd
LP
5971 return j;
5972 if (streq(verb, "is-enabled")) {
b4a34311 5973 if (j == EXIT_SUCCESS) {
2e87a1fd
LP
5974 if (!arg_quiet)
5975 puts("enabled");
5976 r = 1;
5977 } else {
5978 if (!arg_quiet)
5979 puts("disabled");
5980 }
ee5762e3 5981
b4a34311 5982 } else if (j != EXIT_SUCCESS)
2e87a1fd 5983 return -EBADE; /* We don't warn here, under the assumption the script already showed an explanation */
ee5762e3 5984
355ff449
MP
5985 if (found_native)
5986 continue;
5987
a644abed 5988 /* Remove this entry, so that we don't try enabling it as native unit */
aba84331
LP
5989 assert(f > 0);
5990 f--;
5991 assert(args[f] == name);
5992 strv_remove(args, name);
729e3769 5993 }
ee5762e3 5994
729e3769
LP
5995#endif
5996 return r;
5997}
ee5762e3 5998
37370d0c 5999static int mangle_names(char **original_names, char ***mangled_names) {
a33fdebb 6000 char **i, **l, **name;
7410616c 6001 int r;
37370d0c 6002
7410616c 6003 l = i = new(char*, strv_length(original_names) + 1);
a33fdebb 6004 if (!l)
37370d0c
VP
6005 return log_oom();
6006
37370d0c 6007 STRV_FOREACH(name, original_names) {
44386fc1
LN
6008
6009 /* When enabling units qualified path names are OK,
6010 * too, hence allow them explicitly. */
6011
7410616c 6012 if (is_path(*name)) {
44386fc1 6013 *i = strdup(*name);
7410616c
LP
6014 if (!*i) {
6015 strv_free(l);
6016 return log_oom();
6017 }
6018 } else {
37cbc1d5 6019 r = unit_name_mangle(*name, arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, i);
7410616c 6020 if (r < 0) {
523f8cde 6021 *i = NULL;
7410616c
LP
6022 strv_free(l);
6023 return log_error_errno(r, "Failed to mangle unit name: %m");
6024 }
a33fdebb
LP
6025 }
6026
6027 i++;
37370d0c 6028 }
a33fdebb
LP
6029
6030 *i = NULL;
6031 *mangled_names = l;
37370d0c
VP
6032
6033 return 0;
6034}
6035
decd7982
JR
6036static int normalize_filenames(char **names) {
6037 char **u;
6038 int r;
6039
6040 STRV_FOREACH(u, names)
6041 if (!path_is_absolute(*u)) {
6042 char* normalized_path;
6043
6044 if (!isempty(arg_root)) {
6045 log_error("Non-absolute paths are not allowed when --root is used: %s", *u);
6046 return -EINVAL;
6047 }
6048
6049 if (!strchr(*u,'/')) {
6050 log_error("Link argument does contain at least one directory separator: %s", *u);
6051 return -EINVAL;
6052 }
6053
6054 r = path_make_absolute_cwd(*u, &normalized_path);
6055 if (r < 0)
6056 return r;
6057
6058 free_and_replace(*u, normalized_path);
6059 }
6060
6061 return 0;
6062}
6063
1d3c86c0
MS
6064static int normalize_names(char **names, bool warn_if_path) {
6065 char **u;
6066 bool was_path = false;
6067
6068 STRV_FOREACH(u, names) {
6069 int r;
6070
6071 if (!is_path(*u))
6072 continue;
6073
6074 r = free_and_strdup(u, basename(*u));
6075 if (r < 0)
6076 return log_error_errno(r, "Failed to normalize unit file path: %m");
6077
6078 was_path = true;
6079 }
6080
6081 if (warn_if_path && was_path)
6082 log_warning("Warning: Can't execute disable on the unit file path. Proceeding with the unit name.");
6083
6084 return 0;
6085}
6086
173471b7 6087static int unit_exists(LookupPaths *lp, const char *unit) {
d6568222 6088 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
f37f8a61 6089 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
d6568222
SS
6090 _cleanup_free_ char *path = NULL;
6091 static const struct bus_properties_map property_map[] = {
f37f8a61
YW
6092 { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) },
6093 { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state)},
d6568222
SS
6094 {},
6095 };
6096 UnitStatusInfo info = {};
6097 sd_bus *bus;
6098 int r;
6099
173471b7
ZJS
6100 if (unit_name_is_valid(unit, UNIT_NAME_TEMPLATE))
6101 return unit_find_template_path(unit, lp, NULL, NULL);
6102
d6568222
SS
6103 path = unit_dbus_path_from_name(unit);
6104 if (!path)
6105 return log_oom();
6106
6107 r = acquire_bus(BUS_MANAGER, &bus);
6108 if (r < 0)
6109 return r;
6110
a7e4861c 6111 r = bus_map_all_properties(bus, "org.freedesktop.systemd1", path, property_map, 0, &error, &m, &info);
d6568222
SS
6112 if (r < 0)
6113 return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
6114
d6568222
SS
6115 return !streq_ptr(info.load_state, "not-found") || !streq_ptr(info.active_state, "inactive");
6116}
6117
e449de87 6118static int enable_unit(int argc, char *argv[], void *userdata) {
e3e0314b 6119 _cleanup_strv_free_ char **names = NULL;
e449de87 6120 const char *verb = argv[0];
729e3769 6121 UnitFileChange *changes = NULL;
718db961 6122 unsigned n_changes = 0;
729e3769 6123 int carries_install_info = -1;
35b132e8 6124 bool ignore_carries_install_info = arg_quiet;
729e3769 6125 int r;
ee5762e3 6126
e449de87 6127 if (!argv[1])
ab5919fa
MS
6128 return 0;
6129
e449de87 6130 r = mangle_names(strv_skip(argv, 1), &names);
3a05c0f9 6131 if (r < 0)
cbb13b2a
VP
6132 return r;
6133
e3e0314b 6134 r = enable_sysv_units(verb, names);
cbb13b2a
VP
6135 if (r < 0)
6136 return r;
3a05c0f9 6137
c61b443d 6138 /* If the operation was fully executed by the SysV compat, let's finish early */
823e5fab
FB
6139 if (strv_isempty(names)) {
6140 if (arg_no_reload || install_client_side())
6141 return 0;
6142 return daemon_reload(argc, argv, userdata);
6143 }
67d66210 6144
1d3c86c0
MS
6145 if (streq(verb, "disable")) {
6146 r = normalize_names(names, true);
6147 if (r < 0)
6148 return r;
6149 }
6150
decd7982
JR
6151 if (streq(verb, "link")) {
6152 r = normalize_filenames(names);
6153 if (r < 0)
6154 return r;
6155 }
6156
4fbd7192 6157 if (install_client_side()) {
b3796dd8
JS
6158 UnitFileFlags flags;
6159
6160 flags = args_to_flags();
729e3769 6161 if (streq(verb, "enable")) {
b3796dd8 6162 r = unit_file_enable(arg_scope, flags, arg_root, names, &changes, &n_changes);
729e3769
LP
6163 carries_install_info = r;
6164 } else if (streq(verb, "disable"))
b3796dd8 6165 r = unit_file_disable(arg_scope, flags, arg_root, names, &changes, &n_changes);
729e3769 6166 else if (streq(verb, "reenable")) {
b3796dd8 6167 r = unit_file_reenable(arg_scope, flags, arg_root, names, &changes, &n_changes);
729e3769
LP
6168 carries_install_info = r;
6169 } else if (streq(verb, "link"))
b3796dd8 6170 r = unit_file_link(arg_scope, flags, arg_root, names, &changes, &n_changes);
729e3769 6171 else if (streq(verb, "preset")) {
b3796dd8 6172 r = unit_file_preset(arg_scope, flags, arg_root, names, arg_preset_mode, &changes, &n_changes);
729e3769 6173 } else if (streq(verb, "mask"))
b3796dd8 6174 r = unit_file_mask(arg_scope, flags, arg_root, names, &changes, &n_changes);
729e3769 6175 else if (streq(verb, "unmask"))
b3796dd8 6176 r = unit_file_unmask(arg_scope, flags, arg_root, names, &changes, &n_changes);
344ca755
LP
6177 else if (streq(verb, "revert"))
6178 r = unit_file_revert(arg_scope, arg_root, names, &changes, &n_changes);
729e3769
LP
6179 else
6180 assert_not_reached("Unknown verb");
ee5762e3 6181
af3d8113 6182 unit_file_dump_changes(r, verb, changes, n_changes, arg_quiet);
d073dea0 6183 if (r < 0)
85b78539 6184 goto finish;
df77cdf0 6185 r = 0;
729e3769 6186 } else {
4afd3348
LP
6187 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
6188 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
39207373 6189 bool expect_carries_install_info = false;
344ca755 6190 bool send_runtime = true, send_force = true, send_preset_mode = false;
718db961 6191 const char *method;
4fbd7192 6192 sd_bus *bus;
729e3769 6193
d6568222 6194 if (STR_IN_SET(verb, "mask", "unmask")) {
f8d6cb48 6195 char **name;
173471b7
ZJS
6196 _cleanup_lookup_paths_free_ LookupPaths lp = {};
6197
6198 r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
d6568222
SS
6199 if (r < 0)
6200 return r;
f8d6cb48
ZJS
6201
6202 STRV_FOREACH(name, names) {
173471b7 6203 r = unit_exists(&lp, *name);
f8d6cb48
ZJS
6204 if (r < 0)
6205 return r;
6206 if (r == 0)
6207 log_notice("Unit %s does not exist, proceeding anyway.", *names);
6208 }
d6568222
SS
6209 }
6210
4fbd7192
LP
6211 r = acquire_bus(BUS_MANAGER, &bus);
6212 if (r < 0)
6213 return r;
6214
8a4b13c5 6215 polkit_agent_open_maybe();
d2ad7e1b 6216
729e3769
LP
6217 if (streq(verb, "enable")) {
6218 method = "EnableUnitFiles";
6219 expect_carries_install_info = true;
6220 } else if (streq(verb, "disable")) {
6221 method = "DisableUnitFiles";
6222 send_force = false;
6223 } else if (streq(verb, "reenable")) {
6224 method = "ReenableUnitFiles";
6225 expect_carries_install_info = true;
6226 } else if (streq(verb, "link"))
6227 method = "LinkUnitFiles";
6228 else if (streq(verb, "preset")) {
d309c1c3
LP
6229
6230 if (arg_preset_mode != UNIT_FILE_PRESET_FULL) {
6231 method = "PresetUnitFilesWithMode";
6232 send_preset_mode = true;
6233 } else
6234 method = "PresetUnitFiles";
6235
729e3769 6236 expect_carries_install_info = true;
39207373 6237 ignore_carries_install_info = true;
729e3769
LP
6238 } else if (streq(verb, "mask"))
6239 method = "MaskUnitFiles";
6240 else if (streq(verb, "unmask")) {
6241 method = "UnmaskUnitFiles";
6242 send_force = false;
344ca755
LP
6243 } else if (streq(verb, "revert")) {
6244 method = "RevertUnitFiles";
6245 send_runtime = send_force = false;
729e3769
LP
6246 } else
6247 assert_not_reached("Unknown verb");
6248
f459b602
MAP
6249 r = sd_bus_message_new_method_call(
6250 bus,
151b9b96 6251 &m,
729e3769
LP
6252 "org.freedesktop.systemd1",
6253 "/org/freedesktop/systemd1",
6254 "org.freedesktop.systemd1.Manager",
151b9b96 6255 method);
f459b602
MAP
6256 if (r < 0)
6257 return bus_log_create_error(r);
ee5762e3 6258
e3e0314b 6259 r = sd_bus_message_append_strv(m, names);
f459b602
MAP
6260 if (r < 0)
6261 return bus_log_create_error(r);
ee5762e3 6262
d309c1c3
LP
6263 if (send_preset_mode) {
6264 r = sd_bus_message_append(m, "s", unit_file_preset_mode_to_string(arg_preset_mode));
6265 if (r < 0)
6266 return bus_log_create_error(r);
6267 }
6268
344ca755
LP
6269 if (send_runtime) {
6270 r = sd_bus_message_append(m, "b", arg_runtime);
6271 if (r < 0)
6272 return bus_log_create_error(r);
6273 }
ee5762e3 6274
729e3769 6275 if (send_force) {
f459b602
MAP
6276 r = sd_bus_message_append(m, "b", arg_force);
6277 if (r < 0)
6278 return bus_log_create_error(r);
ee5762e3
LP
6279 }
6280
c49b30a2 6281 r = sd_bus_call(bus, m, 0, &error, &reply);
691395d8 6282 if (r < 0)
af3d8113 6283 return log_error_errno(r, "Failed to %s unit: %s", verb, bus_error_message(&error, r));
be394c48 6284
729e3769 6285 if (expect_carries_install_info) {
f459b602
MAP
6286 r = sd_bus_message_read(reply, "b", &carries_install_info);
6287 if (r < 0)
6288 return bus_log_parse_error(r);
ee5762e3
LP
6289 }
6290
57ab2eab 6291 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
f459b602 6292 if (r < 0)
85b78539 6293 goto finish;
b77398f7 6294
93c941e3 6295 /* Try to reload if enabled */
d6cb60c7 6296 if (!arg_no_reload)
e449de87 6297 r = daemon_reload(argc, argv, userdata);
f459b602
MAP
6298 else
6299 r = 0;
b647f10d 6300 }
3d3961f2 6301
39207373 6302 if (carries_install_info == 0 && !ignore_carries_install_info)
fe4aede9
ZJS
6303 log_warning("The unit files have no installation config (WantedBy, RequiredBy, Also, Alias\n"
6304 "settings in the [Install] section, and DefaultInstance for template units).\n"
6305 "This means they are not meant to be enabled using systemctl.\n"
416389f7
LP
6306 "Possible reasons for having this kind of units are:\n"
6307 "1) A unit may be statically enabled by being symlinked from another unit's\n"
6308 " .wants/ or .requires/ directory.\n"
6309 "2) A unit's purpose may be to act as a helper for some other unit which has\n"
6310 " a requirement dependency on it.\n"
6311 "3) A unit may be started when needed via activation (socket, path, timer,\n"
fe4aede9
ZJS
6312 " D-Bus, udev, scripted systemctl call, ...).\n"
6313 "4) In case of template units, the unit is meant to be enabled with some\n"
6314 " instance name specified.");
ee5762e3 6315
6bc30691 6316 if (arg_now && STR_IN_SET(argv[0], "enable", "disable", "mask")) {
4fbd7192 6317 sd_bus *bus;
6bc30691 6318 unsigned len, i;
57ab2eab 6319
4fbd7192
LP
6320 r = acquire_bus(BUS_MANAGER, &bus);
6321 if (r < 0)
d073dea0 6322 goto finish;
4fbd7192 6323
6bc30691
JS
6324 len = strv_length(names);
6325 {
6326 char *new_args[len + 2];
57ab2eab 6327
6bc30691
JS
6328 new_args[0] = (char*) (streq(argv[0], "enable") ? "start" : "stop");
6329 for (i = 0; i < len; i++)
6330 new_args[i + 1] = basename(names[i]);
6331 new_args[i + 1] = NULL;
6332
6333 r = start_unit(len + 1, new_args, userdata);
6334 }
57ab2eab
JS
6335 }
6336
729e3769 6337finish:
729e3769 6338 unit_file_changes_free(changes, n_changes);
ee5762e3 6339
729e3769 6340 return r;
ee5762e3
LP
6341}
6342
e449de87 6343static int add_dependency(int argc, char *argv[], void *userdata) {
e94937df
LN
6344 _cleanup_strv_free_ char **names = NULL;
6345 _cleanup_free_ char *target = NULL;
e449de87 6346 const char *verb = argv[0];
acc0269c
CH
6347 UnitFileChange *changes = NULL;
6348 unsigned n_changes = 0;
e94937df
LN
6349 UnitDependency dep;
6350 int r = 0;
6351
e449de87 6352 if (!argv[1])
e94937df
LN
6353 return 0;
6354
37cbc1d5 6355 r = unit_name_mangle_with_suffix(argv[1], arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, ".target", &target);
7410616c
LP
6356 if (r < 0)
6357 return log_error_errno(r, "Failed to mangle unit name: %m");
e94937df 6358
e449de87 6359 r = mangle_names(strv_skip(argv, 2), &names);
e94937df
LN
6360 if (r < 0)
6361 return r;
6362
6363 if (streq(verb, "add-wants"))
6364 dep = UNIT_WANTS;
6365 else if (streq(verb, "add-requires"))
6366 dep = UNIT_REQUIRES;
6367 else
6368 assert_not_reached("Unknown verb");
6369
4fbd7192 6370 if (install_client_side()) {
b3796dd8 6371 r = unit_file_add_dependency(arg_scope, args_to_flags(), arg_root, names, target, dep, &changes, &n_changes);
af3d8113 6372 unit_file_dump_changes(r, "add dependency on", changes, n_changes, arg_quiet);
5f056378
CH
6373
6374 if (r > 0)
6375 r = 0;
e94937df 6376 } else {
4afd3348
LP
6377 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
6378 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192 6379 sd_bus *bus;
e94937df 6380
4fbd7192
LP
6381 r = acquire_bus(BUS_MANAGER, &bus);
6382 if (r < 0)
6383 return r;
6384
8a4b13c5 6385 polkit_agent_open_maybe();
d2ad7e1b 6386
e94937df
LN
6387 r = sd_bus_message_new_method_call(
6388 bus,
6389 &m,
6390 "org.freedesktop.systemd1",
6391 "/org/freedesktop/systemd1",
6392 "org.freedesktop.systemd1.Manager",
6393 "AddDependencyUnitFiles");
6394 if (r < 0)
6395 return bus_log_create_error(r);
6396
342641fb 6397 r = sd_bus_message_append_strv(m, names);
e94937df
LN
6398 if (r < 0)
6399 return bus_log_create_error(r);
6400
342641fb 6401 r = sd_bus_message_append(m, "ssbb", target, unit_dependency_to_string(dep), arg_runtime, arg_force);
e94937df
LN
6402 if (r < 0)
6403 return bus_log_create_error(r);
6404
6405 r = sd_bus_call(bus, m, 0, &error, &reply);
691395d8 6406 if (r < 0)
af3d8113 6407 return log_error_errno(r, "Failed to add dependency: %s", bus_error_message(&error, r));
e94937df 6408
acc0269c 6409 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
e94937df 6410 if (r < 0)
acc0269c 6411 goto finish;
e94937df 6412
acc0269c
CH
6413 if (arg_no_reload) {
6414 r = 0;
6415 goto finish;
6416 }
6417
6418 r = daemon_reload(argc, argv, userdata);
e94937df 6419 }
acc0269c
CH
6420
6421finish:
6422 unit_file_changes_free(changes, n_changes);
6423
6424 return r;
e94937df
LN
6425}
6426
e449de87 6427static int preset_all(int argc, char *argv[], void *userdata) {
acc0269c
CH
6428 UnitFileChange *changes = NULL;
6429 unsigned n_changes = 0;
d309c1c3
LP
6430 int r;
6431
4fbd7192 6432 if (install_client_side()) {
b3796dd8 6433 r = unit_file_preset_all(arg_scope, args_to_flags(), arg_root, arg_preset_mode, &changes, &n_changes);
af3d8113 6434 unit_file_dump_changes(r, "preset", changes, n_changes, arg_quiet);
5f056378
CH
6435
6436 if (r > 0)
6437 r = 0;
d309c1c3 6438 } else {
4afd3348
LP
6439 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
6440 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
4fbd7192 6441 sd_bus *bus;
d309c1c3 6442
4fbd7192
LP
6443 r = acquire_bus(BUS_MANAGER, &bus);
6444 if (r < 0)
6445 return r;
6446
8a4b13c5 6447 polkit_agent_open_maybe();
d2ad7e1b 6448
6e646d22 6449 r = sd_bus_call_method(
d309c1c3
LP
6450 bus,
6451 "org.freedesktop.systemd1",
6452 "/org/freedesktop/systemd1",
6453 "org.freedesktop.systemd1.Manager",
6e646d22
LP
6454 "PresetAllUnitFiles",
6455 &error,
6456 &reply,
d309c1c3
LP
6457 "sbb",
6458 unit_file_preset_mode_to_string(arg_preset_mode),
6459 arg_runtime,
6460 arg_force);
691395d8 6461 if (r < 0)
af3d8113 6462 return log_error_errno(r, "Failed to preset all units: %s", bus_error_message(&error, r));
d309c1c3 6463
acc0269c 6464 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
d309c1c3 6465 if (r < 0)
acc0269c 6466 goto finish;
d309c1c3 6467
acc0269c
CH
6468 if (arg_no_reload) {
6469 r = 0;
6470 goto finish;
6471 }
6472
6473 r = daemon_reload(argc, argv, userdata);
d309c1c3 6474 }
acc0269c
CH
6475
6476finish:
6477 unit_file_changes_free(changes, n_changes);
6478
6479 return r;
d309c1c3
LP
6480}
6481
3b3557c4
JS
6482static int show_installation_targets_client_side(const char *name) {
6483 UnitFileChange *changes = NULL;
6484 unsigned n_changes = 0, i;
6485 UnitFileFlags flags;
6486 char **p;
6487 int r;
6488
6489 p = STRV_MAKE(name);
6490 flags = UNIT_FILE_DRY_RUN |
6491 (arg_runtime ? UNIT_FILE_RUNTIME : 0);
6492
6493 r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes);
6494 if (r < 0)
6495 return log_error_errno(r, "Failed to get file links for %s: %m", name);
6496
6497 for (i = 0; i < n_changes; i++)
6498 if (changes[i].type == UNIT_FILE_UNLINK)
6499 printf(" %s\n", changes[i].path);
6500
6501 return 0;
6502}
6503
6504static int show_installation_targets(sd_bus *bus, const char *name) {
6505 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
6506 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
6507 const char *link;
6508 int r;
6509
6510 r = sd_bus_call_method(
6511 bus,
6512 "org.freedesktop.systemd1",
6513 "/org/freedesktop/systemd1",
6514 "org.freedesktop.systemd1.Manager",
6515 "GetUnitFileLinks",
6516 &error,
6517 &reply,
6518 "sb", name, arg_runtime);
6519 if (r < 0)
6520 return log_error_errno(r, "Failed to get unit file links for %s: %s", name, bus_error_message(&error, r));
6521
6522 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
6523 if (r < 0)
6524 return bus_log_parse_error(r);
6525
6526 while ((r = sd_bus_message_read(reply, "s", &link)) > 0)
6527 printf(" %s\n", link);
6528
6529 if (r < 0)
6530 return bus_log_parse_error(r);
6531
6532 r = sd_bus_message_exit_container(reply);
6533 if (r < 0)
6534 return bus_log_parse_error(r);
6535
6536 return 0;
6537}
6538
e449de87 6539static int unit_is_enabled(int argc, char *argv[], void *userdata) {
f459b602 6540
e3e0314b 6541 _cleanup_strv_free_ char **names = NULL;
729e3769
LP
6542 bool enabled;
6543 char **name;
f459b602 6544 int r;
ee5762e3 6545
e449de87 6546 r = mangle_names(strv_skip(argv, 1), &names);
cbb13b2a
VP
6547 if (r < 0)
6548 return r;
6549
e449de87 6550 r = enable_sysv_units(argv[0], names);
729e3769
LP
6551 if (r < 0)
6552 return r;
ee5762e3 6553
729e3769 6554 enabled = r > 0;
ee5762e3 6555
4fbd7192 6556 if (install_client_side()) {
e3e0314b 6557 STRV_FOREACH(name, names) {
729e3769 6558 UnitFileState state;
ee5762e3 6559
0ec0deaa
LP
6560 r = unit_file_get_state(arg_scope, arg_root, *name, &state);
6561 if (r < 0)
c5024cd0 6562 return log_error_errno(r, "Failed to get unit file state for %s: %m", *name);
ee5762e3 6563
4c315c2c
IS
6564 if (IN_SET(state,
6565 UNIT_FILE_ENABLED,
6566 UNIT_FILE_ENABLED_RUNTIME,
6567 UNIT_FILE_STATIC,
f4139308
LP
6568 UNIT_FILE_INDIRECT,
6569 UNIT_FILE_GENERATED))
729e3769
LP
6570 enabled = true;
6571
3b3557c4 6572 if (!arg_quiet) {
729e3769 6573 puts(unit_file_state_to_string(state));
3b3557c4
JS
6574 if (arg_full) {
6575 r = show_installation_targets_client_side(*name);
6576 if (r < 0)
6577 return r;
6578 }
6579 }
71fad675 6580 }
ee5762e3 6581
5f056378 6582 r = 0;
729e3769 6583 } else {
4afd3348 6584 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192
LP
6585 sd_bus *bus;
6586
6587 r = acquire_bus(BUS_MANAGER, &bus);
6588 if (r < 0)
6589 return r;
6590
e3e0314b 6591 STRV_FOREACH(name, names) {
4afd3348 6592 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
729e3769 6593 const char *s;
63a723f3 6594
f459b602 6595 r = sd_bus_call_method(
f22f08cd 6596 bus,
729e3769
LP
6597 "org.freedesktop.systemd1",
6598 "/org/freedesktop/systemd1",
6599 "org.freedesktop.systemd1.Manager",
f22f08cd 6600 "GetUnitFileState",
f459b602 6601 &error,
f22f08cd 6602 &reply,
04504f93 6603 "s", *name);
691395d8
LP
6604 if (r < 0)
6605 return log_error_errno(r, "Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
ee5762e3 6606
f459b602
MAP
6607 r = sd_bus_message_read(reply, "s", &s);
6608 if (r < 0)
6609 return bus_log_parse_error(r);
ee5762e3 6610
f4139308 6611 if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect", "generated"))
729e3769
LP
6612 enabled = true;
6613
3b3557c4 6614 if (!arg_quiet) {
729e3769 6615 puts(s);
3b3557c4
JS
6616 if (arg_full) {
6617 r = show_installation_targets(bus, *name);
6618 if (r < 0)
6619 return r;
6620 }
6621 }
560d8f23 6622 }
ee5762e3
LP
6623 }
6624
f4139308 6625 return enabled ? EXIT_SUCCESS : EXIT_FAILURE;
ee5762e3
LP
6626}
6627
e449de87 6628static int is_system_running(int argc, char *argv[], void *userdata) {
99813a19 6629 _cleanup_free_ char *state = NULL;
4fbd7192 6630 sd_bus *bus;
99813a19
LP
6631 int r;
6632
040524b4 6633 if (running_in_chroot() > 0 || (arg_transport == BUS_TRANSPORT_LOCAL && !sd_booted())) {
94f099d8
LP
6634 if (!arg_quiet)
6635 puts("offline");
6636 return EXIT_FAILURE;
6637 }
6638
4fbd7192
LP
6639 r = acquire_bus(BUS_MANAGER, &bus);
6640 if (r < 0)
6641 return r;
6642
99813a19
LP
6643 r = sd_bus_get_property_string(
6644 bus,
6645 "org.freedesktop.systemd1",
6646 "/org/freedesktop/systemd1",
6647 "org.freedesktop.systemd1.Manager",
6648 "SystemState",
6649 NULL,
6650 &state);
6651 if (r < 0) {
6652 if (!arg_quiet)
6653 puts("unknown");
6654 return 0;
6655 }
6656
6657 if (!arg_quiet)
6658 puts(state);
6659
6660 return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE;
6661}
6662
7d4fb3b1 6663static int create_edit_temp_file(const char *new_path, const char *original_path, char **ret_tmp_fn) {
45519fd6 6664 _cleanup_free_ char *t = NULL;
ae6c3cc0 6665 int r;
7d4fb3b1
RC
6666
6667 assert(new_path);
6668 assert(original_path);
6669 assert(ret_tmp_fn);
6670
14bcf25c 6671 r = tempfn_random(new_path, NULL, &t);
ae6c3cc0 6672 if (r < 0)
029009d4 6673 return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", new_path);
7d4fb3b1
RC
6674
6675 r = mkdir_parents(new_path, 0755);
45519fd6 6676 if (r < 0)
691395d8 6677 return log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
7d4fb3b1 6678
1c876927 6679 r = copy_file(original_path, t, 0, 0644, 0, COPY_REFLINK);
7d4fb3b1 6680 if (r == -ENOENT) {
45519fd6 6681
7d4fb3b1 6682 r = touch(t);
45519fd6
LP
6683 if (r < 0)
6684 return log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
6685
6686 } else if (r < 0)
39c38ce1 6687 return log_error_errno(r, "Failed to create temporary file for \"%s\": %m", new_path);
7d4fb3b1 6688
ae2a15bc 6689 *ret_tmp_fn = TAKE_PTR(t);
7d4fb3b1
RC
6690
6691 return 0;
6692}
6693
c51932be
LP
6694static int get_file_to_edit(
6695 const LookupPaths *paths,
6696 const char *name,
6697 char **ret_path) {
6698
6699 _cleanup_free_ char *path = NULL, *run = NULL;
7d4fb3b1 6700
45519fd6
LP
6701 assert(name);
6702 assert(ret_path);
6703
605405c6 6704 path = strjoin(paths->persistent_config, "/", name);
c51932be 6705 if (!path)
7d4fb3b1
RC
6706 return log_oom();
6707
c51932be 6708 if (arg_runtime) {
605405c6 6709 run = strjoin(paths->runtime_config, "/", name);
c51932be
LP
6710 if (!run)
6711 return log_oom();
6712 }
6713
bc854dc7 6714 if (arg_runtime) {
691395d8
LP
6715 if (access(path, F_OK) >= 0) {
6716 log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path);
6717 return -EEXIST;
6718 }
6719
ae2a15bc
LP
6720 *ret_path = TAKE_PTR(run);
6721 } else
6722 *ret_path = TAKE_PTR(path);
7d4fb3b1
RC
6723
6724 return 0;
6725}
6726
39c38ce1 6727static int unit_file_create_new(
c51932be
LP
6728 const LookupPaths *paths,
6729 const char *unit_name,
39c38ce1 6730 const char *suffix,
c51932be
LP
6731 char **ret_new_path,
6732 char **ret_tmp_path) {
6733
45519fd6 6734 char *tmp_new_path, *tmp_tmp_path, *ending;
7d4fb3b1
RC
6735 int r;
6736
6737 assert(unit_name);
6738 assert(ret_new_path);
6739 assert(ret_tmp_path);
6740
39c38ce1 6741 ending = strjoina(unit_name, suffix);
c51932be 6742 r = get_file_to_edit(paths, ending, &tmp_new_path);
7d4fb3b1
RC
6743 if (r < 0)
6744 return r;
6745
6746 r = create_edit_temp_file(tmp_new_path, tmp_new_path, &tmp_tmp_path);
6747 if (r < 0) {
6748 free(tmp_new_path);
6749 return r;
6750 }
6751
6752 *ret_new_path = tmp_new_path;
6753 *ret_tmp_path = tmp_tmp_path;
6754
6755 return 0;
6756}
6757
1cfa9a4c 6758static int unit_file_create_copy(
c51932be 6759 const LookupPaths *paths,
1cfa9a4c
LP
6760 const char *unit_name,
6761 const char *fragment_path,
1cfa9a4c
LP
6762 char **ret_new_path,
6763 char **ret_tmp_path) {
6764
45519fd6 6765 char *tmp_new_path, *tmp_tmp_path;
7d4fb3b1
RC
6766 int r;
6767
6768 assert(fragment_path);
6769 assert(unit_name);
6770 assert(ret_new_path);
6771 assert(ret_tmp_path);
6772
c51932be 6773 r = get_file_to_edit(paths, unit_name, &tmp_new_path);
7d4fb3b1
RC
6774 if (r < 0)
6775 return r;
6776
6777 if (!path_equal(fragment_path, tmp_new_path) && access(tmp_new_path, F_OK) == 0) {
6778 char response;
6779
029009d4 6780 r = ask_char(&response, "yn", "\"%s\" already exists. Overwrite with \"%s\"? [(y)es, (n)o] ", tmp_new_path, fragment_path);
7d4fb3b1
RC
6781 if (r < 0) {
6782 free(tmp_new_path);
6783 return r;
6784 }
6785 if (response != 'y') {
6786 log_warning("%s ignored", unit_name);
6787 free(tmp_new_path);
dbf43a1b 6788 return -EKEYREJECTED;
7d4fb3b1
RC
6789 }
6790 }
6791
6792 r = create_edit_temp_file(tmp_new_path, fragment_path, &tmp_tmp_path);
6793 if (r < 0) {
7d4fb3b1
RC
6794 free(tmp_new_path);
6795 return r;
6796 }
6797
6798 *ret_new_path = tmp_new_path;
6799 *ret_tmp_path = tmp_tmp_path;
6800
6801 return 0;
6802}
6803
6804static int run_editor(char **paths) {
7d4fb3b1
RC
6805 int r;
6806
6807 assert(paths);
6808
1f5d1e02 6809 r = safe_fork("(editor)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
4c253ed1 6810 if (r < 0)
b6e1fff1 6811 return r;
4c253ed1 6812 if (r == 0) {
7d4fb3b1 6813 const char **args;
9ef5d8f2 6814 char *editor, **editor_args = NULL;
1cfa9a4c 6815 char **tmp_path, **original_path, *p;
9ef5d8f2 6816 unsigned n_editor_args = 0, i = 1;
7d4fb3b1
RC
6817 size_t argc;
6818
6819 argc = strv_length(paths)/2 + 1;
7d4fb3b1
RC
6820
6821 /* SYSTEMD_EDITOR takes precedence over EDITOR which takes precedence over VISUAL
6822 * If neither SYSTEMD_EDITOR nor EDITOR nor VISUAL are present,
6823 * we try to execute well known editors
6824 */
6825 editor = getenv("SYSTEMD_EDITOR");
6826 if (!editor)
6827 editor = getenv("EDITOR");
6828 if (!editor)
6829 editor = getenv("VISUAL");
6830
6831 if (!isempty(editor)) {
9ef5d8f2
JS
6832 editor_args = strv_split(editor, WHITESPACE);
6833 if (!editor_args) {
6834 (void) log_oom();
6835 _exit(EXIT_FAILURE);
6836 }
6837 n_editor_args = strv_length(editor_args);
6838 argc += n_editor_args - 1;
6839 }
6840 args = newa(const char*, argc + 1);
6841
6842 if (n_editor_args > 0) {
6843 args[0] = editor_args[0];
6844 for (; i < n_editor_args; i++)
6845 args[i] = editor_args[i];
6846 }
6847
6848 STRV_FOREACH_PAIR(original_path, tmp_path, paths) {
6849 args[i] = *tmp_path;
6850 i++;
7d4fb3b1 6851 }
9ef5d8f2
JS
6852 args[i] = NULL;
6853
6854 if (n_editor_args > 0)
6855 execvp(args[0], (char* const*) args);
7d4fb3b1 6856
9391a1c3 6857 FOREACH_STRING(p, "editor", "nano", "vim", "vi") {
1cfa9a4c
LP
6858 args[0] = p;
6859 execvp(p, (char* const*) args);
7d4fb3b1
RC
6860 /* We do not fail if the editor doesn't exist
6861 * because we want to try each one of them before
6862 * failing.
6863 */
6864 if (errno != ENOENT) {
691395d8 6865 log_error_errno(errno, "Failed to execute %s: %m", editor);
7d4fb3b1
RC
6866 _exit(EXIT_FAILURE);
6867 }
6868 }
6869
1cfa9a4c 6870 log_error("Cannot edit unit(s), no editor available. Please set either $SYSTEMD_EDITOR, $EDITOR or $VISUAL.");
7d4fb3b1
RC
6871 _exit(EXIT_FAILURE);
6872 }
6873
45519fd6 6874 return 0;
7d4fb3b1
RC
6875}
6876
6877static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
e9e310f8 6878 _cleanup_lookup_paths_free_ LookupPaths lp = {};
7d4fb3b1
RC
6879 char **name;
6880 int r;
6881
6882 assert(names);
6883 assert(paths);
6884
4943d143 6885 r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
5b013a2f 6886 if (r < 0)
8df18507 6887 return r;
7d4fb3b1 6888
e9e310f8 6889 STRV_FOREACH(name, names) {
b74df547
ZJS
6890 _cleanup_free_ char *path = NULL, *new_path = NULL, *tmp_path = NULL, *tmp_name = NULL;
6891 const char *unit_name;
7d4fb3b1 6892
4fbd7192 6893 r = unit_find_paths(bus, *name, &lp, &path, NULL);
e9e310f8
RC
6894 if (r < 0)
6895 return r;
b3734d98
ZJS
6896
6897 if (r == 0) {
6898 assert(!path);
6899
6900 if (!arg_force) {
0dcabf09
ZJS
6901 log_error("Run 'systemctl edit%s --force %s' to create a new unit.",
6902 arg_scope == UNIT_FILE_GLOBAL ? " --global" :
6903 arg_scope == UNIT_FILE_USER ? " --user" : "",
6904 *name);
39c38ce1
DC
6905 return -ENOENT;
6906 }
39c38ce1 6907
b3734d98
ZJS
6908 /* Create a new unit from scratch */
6909 unit_name = *name;
6910 r = unit_file_create_new(&lp, unit_name,
6911 arg_full ? NULL : ".d/override.conf",
6912 &new_path, &tmp_path);
6913 } else {
6914 assert(path);
b74df547 6915
b3734d98
ZJS
6916 unit_name = basename(path);
6917 /* We follow unit aliases, but we need to propagate the instance */
6918 if (unit_name_is_valid(*name, UNIT_NAME_INSTANCE) &&
6919 unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
6920 _cleanup_free_ char *instance = NULL;
b74df547 6921
b3734d98
ZJS
6922 r = unit_name_to_instance(*name, &instance);
6923 if (r < 0)
6924 return r;
b74df547 6925
b3734d98
ZJS
6926 r = unit_name_replace_instance(unit_name, instance, &tmp_name);
6927 if (r < 0)
6928 return r;
6929
6930 unit_name = tmp_name;
6931 }
b74df547 6932
39c38ce1 6933 if (arg_full)
b74df547 6934 r = unit_file_create_copy(&lp, unit_name, path, &new_path, &tmp_path);
39c38ce1 6935 else
b74df547 6936 r = unit_file_create_new(&lp, unit_name, ".d/override.conf", &new_path, &tmp_path);
b3734d98 6937 }
e9e310f8 6938 if (r < 0)
ad2a0358 6939 return r;
7d4fb3b1 6940
e9e310f8
RC
6941 r = strv_push_pair(paths, new_path, tmp_path);
6942 if (r < 0)
6943 return log_oom();
78df0edc 6944 new_path = tmp_path = NULL;
7d4fb3b1
RC
6945 }
6946
6947 return 0;
6948}
6949
e449de87 6950static int edit(int argc, char *argv[], void *userdata) {
7d4fb3b1
RC
6951 _cleanup_strv_free_ char **names = NULL;
6952 _cleanup_strv_free_ char **paths = NULL;
6953 char **original, **tmp;
4fbd7192 6954 sd_bus *bus;
7d4fb3b1
RC
6955 int r;
6956
7d4fb3b1 6957 if (!on_tty()) {
4fbd7192 6958 log_error("Cannot edit units if not on a tty.");
7d4fb3b1
RC
6959 return -EINVAL;
6960 }
6961
6962 if (arg_transport != BUS_TRANSPORT_LOCAL) {
4fbd7192 6963 log_error("Cannot edit units remotely.");
7d4fb3b1
RC
6964 return -EINVAL;
6965 }
6966
4fbd7192
LP
6967 r = acquire_bus(BUS_MANAGER, &bus);
6968 if (r < 0)
6969 return r;
6970
e449de87 6971 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
7d4fb3b1
RC
6972 if (r < 0)
6973 return log_error_errno(r, "Failed to expand names: %m");
6974
9d9dd746
ZJS
6975 STRV_FOREACH(tmp, names) {
6976 r = unit_is_masked(bus, *tmp);
6977 if (r < 0)
6978 return r;
6979
6980 if (r > 0) {
6981 log_error("Cannot edit %s: unit is masked.", *tmp);
6982 return -EINVAL;
6983 }
6984 }
6985
7d4fb3b1
RC
6986 r = find_paths_to_edit(bus, names, &paths);
6987 if (r < 0)
6988 return r;
6989
b5e6a600 6990 if (strv_isempty(paths))
7d4fb3b1 6991 return -ENOENT;
7d4fb3b1
RC
6992
6993 r = run_editor(paths);
6994 if (r < 0)
6995 goto end;
6996
6997 STRV_FOREACH_PAIR(original, tmp, paths) {
9d9dd746
ZJS
6998 /* If the temporary file is empty we ignore it.
6999 * This allows the user to cancel the modification.
7d4fb3b1
RC
7000 */
7001 if (null_or_empty_path(*tmp)) {
45519fd6 7002 log_warning("Editing \"%s\" canceled: temporary file is empty.", *original);
7d4fb3b1
RC
7003 continue;
7004 }
45519fd6 7005
7d4fb3b1
RC
7006 r = rename(*tmp, *original);
7007 if (r < 0) {
029009d4 7008 r = log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", *tmp, *original);
7d4fb3b1
RC
7009 goto end;
7010 }
7011 }
7012
45519fd6
LP
7013 r = 0;
7014
7015 if (!arg_no_reload && !install_client_side())
e449de87 7016 r = daemon_reload(argc, argv, userdata);
7d4fb3b1
RC
7017
7018end:
5f18271e 7019 STRV_FOREACH_PAIR(original, tmp, paths) {
45519fd6 7020 (void) unlink(*tmp);
7d4fb3b1 7021
5f18271e
RC
7022 /* Removing empty dropin dirs */
7023 if (!arg_full) {
043717f9
RC
7024 _cleanup_free_ char *dir;
7025
7026 dir = dirname_malloc(*original);
7027 if (!dir)
7028 return log_oom();
7029
5f18271e
RC
7030 /* no need to check if the dir is empty, rmdir
7031 * does nothing if it is not the case.
7032 */
7033 (void) rmdir(dir);
7034 }
7035 }
7036
7d4fb3b1
RC
7037 return r;
7038}
7039
601185b4 7040static void systemctl_help(void) {
7e4249b9 7041
ee5324aa 7042 (void) pager_open(arg_no_pager, false);
729e3769 7043
2e33c433 7044 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
729e3769 7045 "Query or send control commands to the systemd manager.\n\n"
8a0867d6
LP
7046 " -h --help Show this help\n"
7047 " --version Show package version\n"
f459b602
MAP
7048 " --system Connect to system manager\n"
7049 " --user Connect to user service manager\n"
7050 " -H --host=[USER@]HOST\n"
7051 " Operate on remote host\n"
7052 " -M --machine=CONTAINER\n"
7053 " Operate on local container\n"
3fb90db2
ZJS
7054 " -t --type=TYPE List units of a particular type\n"
7055 " --state=STATE List units with particular LOAD or SUB or ACTIVE state\n"
8a0867d6 7056 " -p --property=NAME Show only properties by this name\n"
2cdbbc9a
LP
7057 " -a --all Show all properties/all units currently in memory,\n"
7058 " including dead/empty ones. To list all units installed on\n"
7059 " the system, use the 'list-unit-files' command instead.\n"
bef19548 7060 " --failed Same as --state=failed\n"
98a6e132 7061 " -l --full Don't ellipsize unit names on output\n"
1238ee09 7062 " -r --recursive Show unit list of host and local containers\n"
4dc5b821
LP
7063 " --reverse Show reverse dependencies with 'list-dependencies'\n"
7064 " --job-mode=MODE Specify how to deal with already queued jobs, when\n"
7065 " queueing a new job\n"
a521ae4a 7066 " --show-types When showing sockets, explicitly show their type\n"
4f9a9105 7067 " --value When showing properties, only print the value\n"
b37844d3
LP
7068 " -i --ignore-inhibitors\n"
7069 " When shutting down or sleeping, ignore inhibitors\n"
a8f11321
LP
7070 " --kill-who=WHO Who to send signal to\n"
7071 " -s --signal=SIGNAL Which signal to send\n"
57ab2eab 7072 " --now Start or stop unit in addition to enabling or disabling it\n"
1ae17672 7073 " --dry-run Only print what would be done\n"
8a0867d6 7074 " -q --quiet Suppress output\n"
93a08841 7075 " --wait For (re)start, wait until service stopped again\n"
8a0867d6 7076 " --no-block Do not wait until operation finished\n"
8a0867d6 7077 " --no-wall Don't send wall message before halt/power-off/reboot\n"
3fb90db2 7078 " --no-reload Don't reload daemon after en-/dis-abling unit files\n"
ebed32bf 7079 " --no-legend Do not print a legend (column headers and hints)\n"
69fc152f 7080 " --no-pager Do not pipe output into a pager\n"
501fc174
LP
7081 " --no-ask-password\n"
7082 " Do not ask for system passwords\n"
4e93d369
LR
7083 " --global Enable/disable/mask unit files globally\n"
7084 " --runtime Enable/disable/mask unit files temporarily until next\n"
7085 " reboot\n"
8a0867d6
LP
7086 " -f --force When enabling unit files, override existing symlinks\n"
7087 " When shutting down, execute action immediately\n"
3fb90db2 7088 " --preset-mode= Apply only enable, only disable, or all presets\n"
4e93d369
LR
7089 " --root=PATH Enable/disable/mask unit files in the specified root\n"
7090 " directory\n"
76fdc966 7091 " -n --lines=INTEGER Number of journal entries to show\n"
584c6e70 7092 " -o --output=STRING Change journal output mode (short, short-precise,\n"
7e563bfc
IW
7093 " short-iso, short-iso-precise, short-full,\n"
7094 " short-monotonic, short-unix,\n"
584c6e70 7095 " verbose, export, json, json-pretty, json-sse, cat)\n"
5bdf2243 7096 " --firmware-setup Tell the firmware to show the setup menu on next boot\n"
815ebc54 7097 " --plain Print unit dependencies as a list instead of a tree\n\n"
34c4b47b 7098 "Unit Commands:\n"
fbf3283b
ZJS
7099 " list-units [PATTERN...] List units currently in memory\n"
7100 " list-sockets [PATTERN...] List socket units currently in memory,\n"
7101 " ordered by address\n"
7102 " list-timers [PATTERN...] List timer units currently in memory,\n"
7103 " ordered by next elapse\n"
7104 " start UNIT... Start (activate) one or more units\n"
7105 " stop UNIT... Stop (deactivate) one or more units\n"
7106 " reload UNIT... Reload one or more units\n"
7107 " restart UNIT... Start or restart one or more units\n"
7108 " try-restart UNIT... Restart one or more units if active\n"
7109 " reload-or-restart UNIT... Reload one or more units if possible,\n"
7110 " otherwise start or restart\n"
7111 " try-reload-or-restart UNIT... If active, reload one or more units,\n"
7112 " if supported, otherwise restart\n"
7113 " isolate UNIT Start one unit and stop all others\n"
7114 " kill UNIT... Send signal to processes of a unit\n"
7115 " is-active PATTERN... Check whether units are active\n"
7116 " is-failed PATTERN... Check whether units are failed\n"
7117 " status [PATTERN...|PID...] Show runtime status of one or more units\n"
7118 " show [PATTERN...|JOB...] Show properties of one or more\n"
7119 " units/jobs or the manager\n"
7120 " cat PATTERN... Show files and drop-ins of specified units\n"
7121 " set-property UNIT PROPERTY=VALUE... Sets one or more properties of a unit\n"
7122 " help PATTERN...|PID... Show manual for one or more units\n"
7123 " reset-failed [PATTERN...] Reset failed state for all, one, or more\n"
7124 " units\n"
7125 " list-dependencies [UNIT] Recursively show units which are required\n"
7126 " or wanted by this unit or by which this\n"
7127 " unit is required or wanted\n\n"
34c4b47b 7128 "Unit File Commands:\n"
fbf3283b
ZJS
7129 " list-unit-files [PATTERN...] List installed unit files\n"
7130 " enable [UNIT...|PATH...] Enable one or more unit files\n"
7131 " disable UNIT... Disable one or more unit files\n"
7132 " reenable UNIT... Reenable one or more unit files\n"
7133 " preset UNIT... Enable/disable one or more unit files\n"
7134 " based on preset configuration\n"
7135 " preset-all Enable/disable all unit files based on\n"
7136 " preset configuration\n"
7137 " is-enabled UNIT... Check whether unit files are enabled\n"
7138 " mask UNIT... Mask one or more units\n"
7139 " unmask UNIT... Unmask one or more units\n"
7140 " link PATH... Link one or more units files into\n"
7141 " the search path\n"
7142 " revert UNIT... Revert one or more unit files to vendor\n"
7143 " version\n"
7144 " add-wants TARGET UNIT... Add 'Wants' dependency for the target\n"
7145 " on specified one or more units\n"
7146 " add-requires TARGET UNIT... Add 'Requires' dependency for the target\n"
7147 " on specified one or more units\n"
7148 " edit UNIT... Edit one or more unit files\n"
7149 " get-default Get the name of the default target\n"
7150 " set-default TARGET Set the default target\n\n"
0d292f5e 7151 "Machine Commands:\n"
fbf3283b 7152 " list-machines [PATTERN...] List local containers and host\n\n"
34c4b47b 7153 "Job Commands:\n"
fbf3283b
ZJS
7154 " list-jobs [PATTERN...] List jobs\n"
7155 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
34c4b47b 7156 "Environment Commands:\n"
fbf3283b 7157 " show-environment Dump environment\n"
135775c1
ZJS
7158 " set-environment VARIABLE=VALUE... Set one or more environment variables\n"
7159 " unset-environment VARIABLE... Unset one or more environment variables\n"
7160 " import-environment [VARIABLE...] Import all or some environment variables\n\n"
34c4b47b 7161 "Manager Lifecycle Commands:\n"
fbf3283b
ZJS
7162 " daemon-reload Reload systemd manager configuration\n"
7163 " daemon-reexec Reexecute systemd manager\n\n"
34c4b47b 7164 "System Commands:\n"
fbf3283b
ZJS
7165 " is-system-running Check whether system is fully running\n"
7166 " default Enter system default mode\n"
7167 " rescue Enter system rescue mode\n"
7168 " emergency Enter system emergency mode\n"
7169 " halt Shut down and halt the system\n"
7170 " poweroff Shut down and power-off the system\n"
7171 " reboot [ARG] Shut down and reboot the system\n"
7172 " kexec Shut down and reboot the system with kexec\n"
7173 " exit [EXIT_CODE] Request user instance or container exit\n"
7174 " switch-root ROOT [INIT] Change to a different root file system\n"
7175 " suspend Suspend the system\n"
7176 " hibernate Hibernate the system\n"
c58493c0 7177 " hybrid-sleep Hibernate and suspend the system\n"
e68c79db 7178 " suspend-then-hibernate Suspend the system, wake after a period of\n"
c58493c0 7179 " time and put it into hibernate\n",
5b6319dc 7180 program_invocation_short_name);
7e4249b9
LP
7181}
7182
601185b4 7183static void halt_help(void) {
37185ec8 7184 printf("%s [OPTIONS...]%s\n\n"
e4b61340
LP
7185 "%s the system.\n\n"
7186 " --help Show this help\n"
7187 " --halt Halt the machine\n"
7188 " -p --poweroff Switch off the machine\n"
7189 " --reboot Reboot the machine\n"
2e33c433
LP
7190 " -f --force Force immediate halt/power-off/reboot\n"
7191 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
e4b61340 7192 " -d --no-wtmp Don't write wtmp record\n"
2e33c433 7193 " --no-wall Don't send wall message before halt/power-off/reboot\n",
e4b61340 7194 program_invocation_short_name,
37185ec8 7195 arg_action == ACTION_REBOOT ? " [ARG]" : "",
e4b61340
LP
7196 arg_action == ACTION_REBOOT ? "Reboot" :
7197 arg_action == ACTION_POWEROFF ? "Power off" :
7198 "Halt");
e4b61340
LP
7199}
7200
601185b4 7201static void shutdown_help(void) {
08e4b1c5 7202 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
e4b61340
LP
7203 "Shut down the system.\n\n"
7204 " --help Show this help\n"
7205 " -H --halt Halt the machine\n"
7206 " -P --poweroff Power-off the machine\n"
7207 " -r --reboot Reboot the machine\n"
386da858 7208 " -h Equivalent to --poweroff, overridden by --halt\n"
2e33c433 7209 " -k Don't halt/power-off/reboot, just send warnings\n"
f6144808 7210 " --no-wall Don't send wall message before halt/power-off/reboot\n"
f6144808 7211 " -c Cancel a pending shutdown\n",
e4b61340 7212 program_invocation_short_name);
e4b61340
LP
7213}
7214
601185b4 7215static void telinit_help(void) {
2e33c433 7216 printf("%s [OPTIONS...] {COMMAND}\n\n"
514f4ef5
LP
7217 "Send control commands to the init daemon.\n\n"
7218 " --help Show this help\n"
2e33c433 7219 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
e4b61340
LP
7220 "Commands:\n"
7221 " 0 Power-off the machine\n"
7222 " 6 Reboot the machine\n"
514f4ef5
LP
7223 " 2, 3, 4, 5 Start runlevelX.target unit\n"
7224 " 1, s, S Enter rescue mode\n"
7225 " q, Q Reload init daemon configuration\n"
7226 " u, U Reexecute init daemon\n",
e4b61340 7227 program_invocation_short_name);
e4b61340
LP
7228}
7229
601185b4 7230static void runlevel_help(void) {
2e33c433 7231 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
7232 "Prints the previous and current runlevel of the init system.\n\n"
7233 " --help Show this help\n",
7234 program_invocation_short_name);
e4b61340
LP
7235}
7236
b93312f5 7237static void help_types(void) {
45c0c61d
ZJS
7238 int i;
7239
b93312f5
ZJS
7240 if (!arg_no_legend)
7241 puts("Available unit types:");
e16972e6
ZJS
7242 for (i = 0; i < _UNIT_TYPE_MAX; i++)
7243 puts(unit_type_to_string(i));
7244}
7245
7246static void help_states(void) {
7247 int i;
7248
7249 if (!arg_no_legend)
7250 puts("Available unit load states:");
7251 for (i = 0; i < _UNIT_LOAD_STATE_MAX; i++)
7252 puts(unit_load_state_to_string(i));
7253
7254 if (!arg_no_legend)
7255 puts("\nAvailable unit active states:");
7256 for (i = 0; i < _UNIT_ACTIVE_STATE_MAX; i++)
7257 puts(unit_active_state_to_string(i));
7e55de3b
ZJS
7258
7259 if (!arg_no_legend)
7260 puts("\nAvailable automount unit substates:");
7261 for (i = 0; i < _AUTOMOUNT_STATE_MAX; i++)
7262 puts(automount_state_to_string(i));
7263
7e55de3b
ZJS
7264 if (!arg_no_legend)
7265 puts("\nAvailable device unit substates:");
7266 for (i = 0; i < _DEVICE_STATE_MAX; i++)
7267 puts(device_state_to_string(i));
7268
7269 if (!arg_no_legend)
7270 puts("\nAvailable mount unit substates:");
7271 for (i = 0; i < _MOUNT_STATE_MAX; i++)
7272 puts(mount_state_to_string(i));
7273
7274 if (!arg_no_legend)
7275 puts("\nAvailable path unit substates:");
7276 for (i = 0; i < _PATH_STATE_MAX; i++)
7277 puts(path_state_to_string(i));
7278
7279 if (!arg_no_legend)
7280 puts("\nAvailable scope unit substates:");
7281 for (i = 0; i < _SCOPE_STATE_MAX; i++)
7282 puts(scope_state_to_string(i));
7283
7284 if (!arg_no_legend)
7285 puts("\nAvailable service unit substates:");
7286 for (i = 0; i < _SERVICE_STATE_MAX; i++)
7287 puts(service_state_to_string(i));
7288
7289 if (!arg_no_legend)
7290 puts("\nAvailable slice unit substates:");
7291 for (i = 0; i < _SLICE_STATE_MAX; i++)
7292 puts(slice_state_to_string(i));
7293
7e55de3b
ZJS
7294 if (!arg_no_legend)
7295 puts("\nAvailable socket unit substates:");
7296 for (i = 0; i < _SOCKET_STATE_MAX; i++)
7297 puts(socket_state_to_string(i));
7298
7299 if (!arg_no_legend)
7300 puts("\nAvailable swap unit substates:");
7301 for (i = 0; i < _SWAP_STATE_MAX; i++)
7302 puts(swap_state_to_string(i));
7303
7304 if (!arg_no_legend)
7305 puts("\nAvailable target unit substates:");
7306 for (i = 0; i < _TARGET_STATE_MAX; i++)
7307 puts(target_state_to_string(i));
7308
7309 if (!arg_no_legend)
7310 puts("\nAvailable timer unit substates:");
7311 for (i = 0; i < _TIMER_STATE_MAX; i++)
7312 puts(timer_state_to_string(i));
45c0c61d
ZJS
7313}
7314
e4b61340 7315static int systemctl_parse_argv(int argc, char *argv[]) {
7e4249b9
LP
7316
7317 enum {
90d473a1 7318 ARG_FAIL = 0x100,
afba4199
ZJS
7319 ARG_REVERSE,
7320 ARG_AFTER,
7321 ARG_BEFORE,
1ae17672 7322 ARG_DRY_RUN,
991f2a39 7323 ARG_SHOW_TYPES,
23ade460 7324 ARG_IRREVERSIBLE,
e67c3609 7325 ARG_IGNORE_DEPENDENCIES,
4f9a9105 7326 ARG_VALUE,
35df8f27 7327 ARG_VERSION,
af2d49f7 7328 ARG_USER,
7e4249b9 7329 ARG_SYSTEM,
ee5762e3 7330 ARG_GLOBAL,
6e905d93 7331 ARG_NO_BLOCK,
ebed32bf 7332 ARG_NO_LEGEND,
611efaac 7333 ARG_NO_PAGER,
4445a875 7334 ARG_NO_WALL,
be394c48 7335 ARG_ROOT,
ee5762e3 7336 ARG_NO_RELOAD,
501fc174 7337 ARG_KILL_WHO,
30732560 7338 ARG_NO_ASK_PASSWORD,
729e3769 7339 ARG_FAILED,
df50185b 7340 ARG_RUNTIME,
9b9b3d36 7341 ARG_PLAIN,
4dc5b821 7342 ARG_STATE,
d309c1c3
LP
7343 ARG_JOB_MODE,
7344 ARG_PRESET_MODE,
5bdf2243 7345 ARG_FIRMWARE_SETUP,
57ab2eab 7346 ARG_NOW,
9ef15026 7347 ARG_MESSAGE,
93a08841 7348 ARG_WAIT,
7e4249b9
LP
7349 };
7350
7351 static const struct option options[] = {
9ea9d4cf
LP
7352 { "help", no_argument, NULL, 'h' },
7353 { "version", no_argument, NULL, ARG_VERSION },
7354 { "type", required_argument, NULL, 't' },
7355 { "property", required_argument, NULL, 'p' },
7356 { "all", no_argument, NULL, 'a' },
7357 { "reverse", no_argument, NULL, ARG_REVERSE },
7358 { "after", no_argument, NULL, ARG_AFTER },
7359 { "before", no_argument, NULL, ARG_BEFORE },
7360 { "show-types", no_argument, NULL, ARG_SHOW_TYPES },
7361 { "failed", no_argument, NULL, ARG_FAILED }, /* compatibility only */
7362 { "full", no_argument, NULL, 'l' },
4dc5b821
LP
7363 { "job-mode", required_argument, NULL, ARG_JOB_MODE },
7364 { "fail", no_argument, NULL, ARG_FAIL }, /* compatibility only */
7365 { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, /* compatibility only */
7366 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */
9ea9d4cf 7367 { "ignore-inhibitors", no_argument, NULL, 'i' },
4f9a9105 7368 { "value", no_argument, NULL, ARG_VALUE },
9ea9d4cf
LP
7369 { "user", no_argument, NULL, ARG_USER },
7370 { "system", no_argument, NULL, ARG_SYSTEM },
7371 { "global", no_argument, NULL, ARG_GLOBAL },
93a08841 7372 { "wait", no_argument, NULL, ARG_WAIT },
9ea9d4cf
LP
7373 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
7374 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
7375 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
7376 { "no-wall", no_argument, NULL, ARG_NO_WALL },
1ae17672 7377 { "dry-run", no_argument, NULL, ARG_DRY_RUN },
9ea9d4cf
LP
7378 { "quiet", no_argument, NULL, 'q' },
7379 { "root", required_argument, NULL, ARG_ROOT },
68da321f 7380 { "force", no_argument, NULL, 'f' },
9ea9d4cf
LP
7381 { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
7382 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
7383 { "signal", required_argument, NULL, 's' },
7384 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
7385 { "host", required_argument, NULL, 'H' },
f459b602 7386 { "machine", required_argument, NULL, 'M' },
9ea9d4cf
LP
7387 { "runtime", no_argument, NULL, ARG_RUNTIME },
7388 { "lines", required_argument, NULL, 'n' },
7389 { "output", required_argument, NULL, 'o' },
7390 { "plain", no_argument, NULL, ARG_PLAIN },
7391 { "state", required_argument, NULL, ARG_STATE },
1238ee09 7392 { "recursive", no_argument, NULL, 'r' },
d309c1c3 7393 { "preset-mode", required_argument, NULL, ARG_PRESET_MODE },
5bdf2243 7394 { "firmware-setup", no_argument, NULL, ARG_FIRMWARE_SETUP },
57ab2eab 7395 { "now", no_argument, NULL, ARG_NOW },
9ef15026 7396 { "message", required_argument, NULL, ARG_MESSAGE },
eb9da376 7397 {}
7e4249b9
LP
7398 };
7399
5ab22f33 7400 const char *p;
0f03c2a4 7401 int c, r;
7e4249b9 7402
e4b61340 7403 assert(argc >= 0);
7e4249b9
LP
7404 assert(argv);
7405
16f017fa
IS
7406 /* we default to allowing interactive authorization only in systemctl (not in the legacy commands) */
7407 arg_ask_password = true;
7408
601185b4 7409 while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir", options, NULL)) >= 0)
7e4249b9
LP
7410
7411 switch (c) {
7412
7413 case 'h':
601185b4
ZJS
7414 systemctl_help();
7415 return 0;
35df8f27
LP
7416
7417 case ARG_VERSION:
3f6fd1ba 7418 return version();
7e4249b9 7419
20b3f379 7420 case 't': {
bf409580 7421 if (isempty(optarg)) {
10ab1831 7422 log_error("--type= requires arguments.");
bf409580
TA
7423 return -EINVAL;
7424 }
45c0c61d 7425
c58bd76a 7426 for (p = optarg;;) {
5ab22f33 7427 _cleanup_free_ char *type = NULL;
20b3f379 7428
5ab22f33
SS
7429 r = extract_first_word(&p, &type, ",", 0);
7430 if (r < 0)
7431 return log_error_errno(r, "Failed to parse type: %s", optarg);
5ab22f33
SS
7432 if (r == 0)
7433 break;
20b3f379
ZJS
7434
7435 if (streq(type, "help")) {
7436 help_types();
7437 return 0;
7438 }
7439
7440 if (unit_type_from_string(type) >= 0) {
7e9d36e0 7441 if (strv_push(&arg_types, type) < 0)
20b3f379
ZJS
7442 return log_oom();
7443 type = NULL;
7444 continue;
7445 }
7446
9b9b3d36
MW
7447 /* It's much nicer to use --state= for
7448 * load states, but let's support this
7449 * in --types= too for compatibility
7450 * with old versions */
7e9d36e0 7451 if (unit_load_state_from_string(type) >= 0) {
9b9b3d36 7452 if (strv_push(&arg_states, type) < 0)
20b3f379
ZJS
7453 return log_oom();
7454 type = NULL;
7455 continue;
7456 }
7457
ab06eef8 7458 log_error("Unknown unit type or load state '%s'.", type);
20b3f379
ZJS
7459 log_info("Use -t help to see a list of allowed values.");
7460 return -EINVAL;
c147dc42 7461 }
20b3f379
ZJS
7462
7463 break;
7464 }
7465
ea4a240d 7466 case 'p': {
033a842c
ZJS
7467 /* Make sure that if the empty property list
7468 was specified, we won't show any properties. */
20b3f379 7469 if (isempty(optarg) && !arg_properties) {
cbc9fbd1 7470 arg_properties = new0(char*, 1);
20b3f379
ZJS
7471 if (!arg_properties)
7472 return log_oom();
c58bd76a
ZJS
7473 } else
7474 for (p = optarg;;) {
5ab22f33 7475 _cleanup_free_ char *prop = NULL;
033a842c 7476
5ab22f33
SS
7477 r = extract_first_word(&p, &prop, ",", 0);
7478 if (r < 0)
7479 return log_error_errno(r, "Failed to parse property: %s", optarg);
5ab22f33
SS
7480 if (r == 0)
7481 break;
ea4a240d 7482
5ab22f33 7483 if (strv_push(&arg_properties, prop) < 0)
20b3f379 7484 return log_oom();
5ab22f33
SS
7485
7486 prop = NULL;
20b3f379 7487 }
48220598
LP
7488
7489 /* If the user asked for a particular
7490 * property, show it to him, even if it is
7491 * empty. */
7492 arg_all = true;
033a842c 7493
48220598 7494 break;
ea4a240d 7495 }
48220598 7496
7e4249b9
LP
7497 case 'a':
7498 arg_all = true;
7499 break;
7500
afba4199
ZJS
7501 case ARG_REVERSE:
7502 arg_dependency = DEPENDENCY_REVERSE;
7503 break;
7504
7505 case ARG_AFTER:
7506 arg_dependency = DEPENDENCY_AFTER;
82948f6c 7507 arg_jobs_after = true;
afba4199
ZJS
7508 break;
7509
7510 case ARG_BEFORE:
7511 arg_dependency = DEPENDENCY_BEFORE;
82948f6c 7512 arg_jobs_before = true;
afba4199
ZJS
7513 break;
7514
991f2a39
ZJS
7515 case ARG_SHOW_TYPES:
7516 arg_show_types = true;
7517 break;
7518
4f9a9105
ZJS
7519 case ARG_VALUE:
7520 arg_value = true;
7521 break;
7522
4dc5b821
LP
7523 case ARG_JOB_MODE:
7524 arg_job_mode = optarg;
7525 break;
7526
90d473a1 7527 case ARG_FAIL:
e67c3609
LP
7528 arg_job_mode = "fail";
7529 break;
7530
23ade460
MS
7531 case ARG_IRREVERSIBLE:
7532 arg_job_mode = "replace-irreversibly";
7533 break;
7534
e67c3609
LP
7535 case ARG_IGNORE_DEPENDENCIES:
7536 arg_job_mode = "ignore-dependencies";
7e4249b9
LP
7537 break;
7538
af2d49f7 7539 case ARG_USER:
729e3769 7540 arg_scope = UNIT_FILE_USER;
7e4249b9
LP
7541 break;
7542
7543 case ARG_SYSTEM:
729e3769
LP
7544 arg_scope = UNIT_FILE_SYSTEM;
7545 break;
7546
7547 case ARG_GLOBAL:
7548 arg_scope = UNIT_FILE_GLOBAL;
7e4249b9
LP
7549 break;
7550
93a08841
MP
7551 case ARG_WAIT:
7552 arg_wait = true;
7553 break;
7554
6e905d93
LP
7555 case ARG_NO_BLOCK:
7556 arg_no_block = true;
7e4249b9
LP
7557 break;
7558
ebed32bf
MS
7559 case ARG_NO_LEGEND:
7560 arg_no_legend = true;
7561 break;
7562
611efaac
LP
7563 case ARG_NO_PAGER:
7564 arg_no_pager = true;
7565 break;
0736af98 7566
514f4ef5
LP
7567 case ARG_NO_WALL:
7568 arg_no_wall = true;
7569 break;
7570
be394c48 7571 case ARG_ROOT:
bac75eb3 7572 r = parse_path_argument_and_warn(optarg, false, &arg_root);
0f03c2a4
LP
7573 if (r < 0)
7574 return r;
be394c48
FC
7575 break;
7576
98a6e132 7577 case 'l':
8fe914ec
LP
7578 arg_full = true;
7579 break;
7580
30732560 7581 case ARG_FAILED:
9b9b3d36
MW
7582 if (strv_extend(&arg_states, "failed") < 0)
7583 return log_oom();
7584
30732560
LP
7585 break;
7586
1ae17672
ZJS
7587 case ARG_DRY_RUN:
7588 arg_dry_run = true;
7589 break;
7590
0183528f
LP
7591 case 'q':
7592 arg_quiet = true;
7593 break;
7594
b4f27ccc 7595 case 'f':
313cefa1 7596 arg_force++;
ee5762e3
LP
7597 break;
7598
7599 case ARG_NO_RELOAD:
7600 arg_no_reload = true;
7601 break;
7602
8a0867d6
LP
7603 case ARG_KILL_WHO:
7604 arg_kill_who = optarg;
7605 break;
7606
8a0867d6 7607 case 's':
691395d8
LP
7608 arg_signal = signal_from_string_try_harder(optarg);
7609 if (arg_signal < 0) {
8a0867d6
LP
7610 log_error("Failed to parse signal string %s.", optarg);
7611 return -EINVAL;
7612 }
7613 break;
7614
501fc174
LP
7615 case ARG_NO_ASK_PASSWORD:
7616 arg_ask_password = false;
7617 break;
7618
f459b602
MAP
7619 case 'H':
7620 arg_transport = BUS_TRANSPORT_REMOTE;
7621 arg_host = optarg;
a8f11321
LP
7622 break;
7623
f459b602 7624 case 'M':
de33fc62 7625 arg_transport = BUS_TRANSPORT_MACHINE;
f459b602 7626 arg_host = optarg;
a8f11321
LP
7627 break;
7628
729e3769
LP
7629 case ARG_RUNTIME:
7630 arg_runtime = true;
7631 break;
7632
df50185b
LP
7633 case 'n':
7634 if (safe_atou(optarg, &arg_lines) < 0) {
7635 log_error("Failed to parse lines '%s'", optarg);
7636 return -EINVAL;
7637 }
7638 break;
7639
df50185b
LP
7640 case 'o':
7641 arg_output = output_mode_from_string(optarg);
7642 if (arg_output < 0) {
7643 log_error("Unknown output '%s'.", optarg);
7644 return -EINVAL;
7645 }
7646 break;
7647
b37844d3
LP
7648 case 'i':
7649 arg_ignore_inhibitors = true;
7650 break;
7651
5d0c05e5
LN
7652 case ARG_PLAIN:
7653 arg_plain = true;
7654 break;
7655
5bdf2243
JJ
7656 case ARG_FIRMWARE_SETUP:
7657 arg_firmware_setup = true;
7658 break;
7659
9b9b3d36 7660 case ARG_STATE: {
bf409580 7661 if (isempty(optarg)) {
10ab1831 7662 log_error("--state= requires arguments.");
bf409580
TA
7663 return -EINVAL;
7664 }
9b9b3d36 7665
c58bd76a 7666 for (p = optarg;;) {
bc6c18fe 7667 _cleanup_free_ char *s = NULL;
9b9b3d36 7668
5ab22f33
SS
7669 r = extract_first_word(&p, &s, ",", 0);
7670 if (r < 0)
6862111e 7671 return log_error_errno(r, "Failed to parse state: %s", optarg);
5ab22f33
SS
7672 if (r == 0)
7673 break;
9b9b3d36 7674
e16972e6
ZJS
7675 if (streq(s, "help")) {
7676 help_states();
7677 return 0;
7678 }
7679
7e9d36e0 7680 if (strv_push(&arg_states, s) < 0)
9b9b3d36 7681 return log_oom();
7e9d36e0
LP
7682
7683 s = NULL;
9b9b3d36
MW
7684 }
7685 break;
7686 }
7687
1238ee09
LP
7688 case 'r':
7689 if (geteuid() != 0) {
f1721625 7690 log_error("--recursive requires root privileges.");
1238ee09
LP
7691 return -EPERM;
7692 }
7693
7694 arg_recursive = true;
7695 break;
7696
d309c1c3
LP
7697 case ARG_PRESET_MODE:
7698
7699 arg_preset_mode = unit_file_preset_mode_from_string(optarg);
7700 if (arg_preset_mode < 0) {
7701 log_error("Failed to parse preset mode: %s.", optarg);
7702 return -EINVAL;
7703 }
7704
7705 break;
7706
57ab2eab
JS
7707 case ARG_NOW:
7708 arg_now = true;
7709 break;
7710
9ef15026
JS
7711 case ARG_MESSAGE:
7712 if (strv_extend(&arg_wall, optarg) < 0)
7713 return log_oom();
7714 break;
7715
7e4249b9
LP
7716 case '?':
7717 return -EINVAL;
7718
7719 default:
eb9da376 7720 assert_not_reached("Unhandled option");
7e4249b9 7721 }
7e4249b9 7722
f459b602 7723 if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM) {
a8f11321
LP
7724 log_error("Cannot access user instance remotely.");
7725 return -EINVAL;
7726 }
7727
93a08841
MP
7728 if (arg_wait && arg_no_block) {
7729 log_error("--wait may not be combined with --no-block.");
7730 return -EINVAL;
7731 }
7732
7e4249b9
LP
7733 return 1;
7734}
7735
e4b61340
LP
7736static int halt_parse_argv(int argc, char *argv[]) {
7737
7738 enum {
7739 ARG_HELP = 0x100,
7740 ARG_HALT,
514f4ef5
LP
7741 ARG_REBOOT,
7742 ARG_NO_WALL
e4b61340
LP
7743 };
7744
7745 static const struct option options[] = {
7746 { "help", no_argument, NULL, ARG_HELP },
7747 { "halt", no_argument, NULL, ARG_HALT },
7748 { "poweroff", no_argument, NULL, 'p' },
7749 { "reboot", no_argument, NULL, ARG_REBOOT },
7750 { "force", no_argument, NULL, 'f' },
7751 { "wtmp-only", no_argument, NULL, 'w' },
7752 { "no-wtmp", no_argument, NULL, 'd' },
f3f054f0 7753 { "no-sync", no_argument, NULL, 'n' },
514f4ef5 7754 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 7755 {}
e4b61340
LP
7756 };
7757
37185ec8 7758 int c, r, runlevel;
e4b61340
LP
7759
7760 assert(argc >= 0);
7761 assert(argv);
7762
7763 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4c701096 7764 if (IN_SET(runlevel, '0', '6'))
65491fd8 7765 arg_force = 2;
e4b61340 7766
601185b4 7767 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0)
e4b61340
LP
7768 switch (c) {
7769
7770 case ARG_HELP:
601185b4
ZJS
7771 halt_help();
7772 return 0;
e4b61340
LP
7773
7774 case ARG_HALT:
7775 arg_action = ACTION_HALT;
7776 break;
7777
7778 case 'p':
a042efad
MS
7779 if (arg_action != ACTION_REBOOT)
7780 arg_action = ACTION_POWEROFF;
e4b61340
LP
7781 break;
7782
7783 case ARG_REBOOT:
7784 arg_action = ACTION_REBOOT;
7785 break;
7786
7787 case 'f':
65491fd8 7788 arg_force = 2;
e4b61340
LP
7789 break;
7790
7791 case 'w':
1ae17672 7792 arg_dry_run = true;
e4b61340
LP
7793 break;
7794
7795 case 'd':
7796 arg_no_wtmp = true;
7797 break;
7798
f3f054f0
TB
7799 case 'n':
7800 arg_no_sync = true;
7801 break;
7802
514f4ef5
LP
7803 case ARG_NO_WALL:
7804 arg_no_wall = true;
7805 break;
7806
e4b61340
LP
7807 case 'i':
7808 case 'h':
7809 /* Compatibility nops */
7810 break;
7811
7812 case '?':
7813 return -EINVAL;
7814
7815 default:
eb9da376 7816 assert_not_reached("Unhandled option");
e4b61340 7817 }
e4b61340 7818
c5220a94 7819 if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
27c06cb5 7820 r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL);
c5220a94 7821 if (r < 0)
37185ec8 7822 return r;
37185ec8 7823 } else if (optind < argc) {
e4b61340
LP
7824 log_error("Too many arguments.");
7825 return -EINVAL;
7826 }
7827
7828 return 1;
7829}
7830
2cc7b0a2 7831static int parse_shutdown_time_spec(const char *t, usec_t *_u) {
f6144808
LP
7832 assert(t);
7833 assert(_u);
7834
7835 if (streq(t, "now"))
7836 *_u = 0;
1a639877 7837 else if (!strchr(t, ':')) {
f6144808
LP
7838 uint64_t u;
7839
1a639877 7840 if (safe_atou64(t, &u) < 0)
f6144808
LP
7841 return -EINVAL;
7842
7843 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
7844 } else {
7845 char *e = NULL;
7846 long hour, minute;
b92bea5d 7847 struct tm tm = {};
f6144808
LP
7848 time_t s;
7849 usec_t n;
7850
7851 errno = 0;
7852 hour = strtol(t, &e, 10);
8333c77e 7853 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
f6144808
LP
7854 return -EINVAL;
7855
7856 minute = strtol(e+1, &e, 10);
8333c77e 7857 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
f6144808
LP
7858 return -EINVAL;
7859
7860 n = now(CLOCK_REALTIME);
08e4b1c5
LP
7861 s = (time_t) (n / USEC_PER_SEC);
7862
f6144808
LP
7863 assert_se(localtime_r(&s, &tm));
7864
7865 tm.tm_hour = (int) hour;
7866 tm.tm_min = (int) minute;
08e4b1c5 7867 tm.tm_sec = 0;
f6144808
LP
7868
7869 assert_se(s = mktime(&tm));
7870
7871 *_u = (usec_t) s * USEC_PER_SEC;
7872
7873 while (*_u <= n)
7874 *_u += USEC_PER_DAY;
7875 }
7876
7877 return 0;
7878}
7879
e4b61340
LP
7880static int shutdown_parse_argv(int argc, char *argv[]) {
7881
7882 enum {
7883 ARG_HELP = 0x100,
514f4ef5 7884 ARG_NO_WALL
e4b61340
LP
7885 };
7886
7887 static const struct option options[] = {
7888 { "help", no_argument, NULL, ARG_HELP },
7889 { "halt", no_argument, NULL, 'H' },
7890 { "poweroff", no_argument, NULL, 'P' },
7891 { "reboot", no_argument, NULL, 'r' },
04ebb595 7892 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
514f4ef5 7893 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 7894 {}
e4b61340
LP
7895 };
7896
172d7abf 7897 char **wall = NULL;
f6144808 7898 int c, r;
e4b61340
LP
7899
7900 assert(argc >= 0);
7901 assert(argv);
7902
b068c6f5 7903 while ((c = getopt_long(argc, argv, "HPrhkKat:fFc", options, NULL)) >= 0)
e4b61340
LP
7904 switch (c) {
7905
7906 case ARG_HELP:
601185b4
ZJS
7907 shutdown_help();
7908 return 0;
e4b61340
LP
7909
7910 case 'H':
7911 arg_action = ACTION_HALT;
7912 break;
7913
7914 case 'P':
7915 arg_action = ACTION_POWEROFF;
7916 break;
7917
7918 case 'r':
5622dde3
KS
7919 if (kexec_loaded())
7920 arg_action = ACTION_KEXEC;
7921 else
7922 arg_action = ACTION_REBOOT;
e4b61340
LP
7923 break;
7924
04ebb595
LP
7925 case 'K':
7926 arg_action = ACTION_KEXEC;
7927 break;
7928
e4b61340
LP
7929 case 'h':
7930 if (arg_action != ACTION_HALT)
7931 arg_action = ACTION_POWEROFF;
7932 break;
7933
7934 case 'k':
1ae17672 7935 arg_dry_run = true;
e4b61340
LP
7936 break;
7937
514f4ef5
LP
7938 case ARG_NO_WALL:
7939 arg_no_wall = true;
7940 break;
7941
e4b61340 7942 case 'a':
b068c6f5 7943 case 't': /* Note that we also ignore any passed argument to -t, not just the -t itself */
75836b9d
JS
7944 case 'f':
7945 case 'F':
e4b61340
LP
7946 /* Compatibility nops */
7947 break;
7948
f6144808
LP
7949 case 'c':
7950 arg_action = ACTION_CANCEL_SHUTDOWN;
7951 break;
7952
e4b61340
LP
7953 case '?':
7954 return -EINVAL;
7955
7956 default:
eb9da376 7957 assert_not_reached("Unhandled option");
e4b61340 7958 }
e4b61340 7959
dfcc5c33 7960 if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
2cc7b0a2 7961 r = parse_shutdown_time_spec(argv[optind], &arg_when);
7e59bfcb 7962 if (r < 0) {
f6144808
LP
7963 log_error("Failed to parse time specification: %s", argv[optind]);
7964 return r;
7965 }
6b5ad000 7966 } else
08e4b1c5 7967 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
442b9094 7968
dfcc5c33
MS
7969 if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
7970 /* No time argument for shutdown cancel */
172d7abf 7971 wall = argv + optind;
dfcc5c33
MS
7972 else if (argc > optind + 1)
7973 /* We skip the time argument */
172d7abf
LP
7974 wall = argv + optind + 1;
7975
7976 if (wall) {
7977 arg_wall = strv_copy(wall);
7978 if (!arg_wall)
7979 return log_oom();
7980 }
e4b61340
LP
7981
7982 optind = argc;
7983
7984 return 1;
e4b61340
LP
7985}
7986
7987static int telinit_parse_argv(int argc, char *argv[]) {
7988
7989 enum {
7990 ARG_HELP = 0x100,
514f4ef5 7991 ARG_NO_WALL
e4b61340
LP
7992 };
7993
7994 static const struct option options[] = {
7995 { "help", no_argument, NULL, ARG_HELP },
514f4ef5 7996 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 7997 {}
e4b61340
LP
7998 };
7999
8000 static const struct {
8001 char from;
8002 enum action to;
8003 } table[] = {
8004 { '0', ACTION_POWEROFF },
8005 { '6', ACTION_REBOOT },
ef2f1067 8006 { '1', ACTION_RESCUE },
e4b61340
LP
8007 { '2', ACTION_RUNLEVEL2 },
8008 { '3', ACTION_RUNLEVEL3 },
8009 { '4', ACTION_RUNLEVEL4 },
8010 { '5', ACTION_RUNLEVEL5 },
8011 { 's', ACTION_RESCUE },
8012 { 'S', ACTION_RESCUE },
8013 { 'q', ACTION_RELOAD },
8014 { 'Q', ACTION_RELOAD },
8015 { 'u', ACTION_REEXEC },
8016 { 'U', ACTION_REEXEC }
8017 };
8018
8019 unsigned i;
8020 int c;
8021
8022 assert(argc >= 0);
8023 assert(argv);
8024
601185b4 8025 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
8026 switch (c) {
8027
8028 case ARG_HELP:
601185b4
ZJS
8029 telinit_help();
8030 return 0;
e4b61340 8031
514f4ef5
LP
8032 case ARG_NO_WALL:
8033 arg_no_wall = true;
8034 break;
8035
e4b61340
LP
8036 case '?':
8037 return -EINVAL;
8038
8039 default:
eb9da376 8040 assert_not_reached("Unhandled option");
e4b61340 8041 }
e4b61340
LP
8042
8043 if (optind >= argc) {
691395d8 8044 log_error("%s: required argument missing.", program_invocation_short_name);
e4b61340
LP
8045 return -EINVAL;
8046 }
8047
8048 if (optind + 1 < argc) {
8049 log_error("Too many arguments.");
8050 return -EINVAL;
8051 }
8052
8053 if (strlen(argv[optind]) != 1) {
8054 log_error("Expected single character argument.");
8055 return -EINVAL;
8056 }
8057
8058 for (i = 0; i < ELEMENTSOF(table); i++)
8059 if (table[i].from == argv[optind][0])
8060 break;
8061
8062 if (i >= ELEMENTSOF(table)) {
b0193f1c 8063 log_error("Unknown command '%s'.", argv[optind]);
e4b61340
LP
8064 return -EINVAL;
8065 }
8066
8067 arg_action = table[i].to;
8068
313cefa1 8069 optind++;
e4b61340
LP
8070
8071 return 1;
8072}
8073
8074static int runlevel_parse_argv(int argc, char *argv[]) {
8075
8076 enum {
8077 ARG_HELP = 0x100,
8078 };
8079
8080 static const struct option options[] = {
8081 { "help", no_argument, NULL, ARG_HELP },
eb9da376 8082 {}
e4b61340
LP
8083 };
8084
8085 int c;
8086
8087 assert(argc >= 0);
8088 assert(argv);
8089
601185b4 8090 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
8091 switch (c) {
8092
8093 case ARG_HELP:
601185b4
ZJS
8094 runlevel_help();
8095 return 0;
e4b61340
LP
8096
8097 case '?':
8098 return -EINVAL;
8099
8100 default:
eb9da376 8101 assert_not_reached("Unhandled option");
e4b61340 8102 }
e4b61340
LP
8103
8104 if (optind < argc) {
8105 log_error("Too many arguments.");
8106 return -EINVAL;
8107 }
8108
8109 return 1;
8110}
8111
8112static int parse_argv(int argc, char *argv[]) {
8113 assert(argc >= 0);
8114 assert(argv);
8115
8116 if (program_invocation_short_name) {
8117
8118 if (strstr(program_invocation_short_name, "halt")) {
8119 arg_action = ACTION_HALT;
8120 return halt_parse_argv(argc, argv);
c54819ca 8121
e4b61340
LP
8122 } else if (strstr(program_invocation_short_name, "poweroff")) {
8123 arg_action = ACTION_POWEROFF;
8124 return halt_parse_argv(argc, argv);
c54819ca 8125
e4b61340 8126 } else if (strstr(program_invocation_short_name, "reboot")) {
5622dde3
KS
8127 if (kexec_loaded())
8128 arg_action = ACTION_KEXEC;
8129 else
8130 arg_action = ACTION_REBOOT;
e4b61340 8131 return halt_parse_argv(argc, argv);
c54819ca 8132
e4b61340
LP
8133 } else if (strstr(program_invocation_short_name, "shutdown")) {
8134 arg_action = ACTION_POWEROFF;
8135 return shutdown_parse_argv(argc, argv);
c54819ca 8136
e4b61340 8137 } else if (strstr(program_invocation_short_name, "init")) {
d5ca5f11 8138
c54819ca
LP
8139 /* Matches invocations as "init" as well as "telinit", which are synonymous when run as PID !=
8140 * 1 on SysV.
8141 *
8142 * On SysV "telinit" was the official command to communicate with PID 1, but "init" would
8143 * redirect itself to "telinit" if called with PID != 1. We follow the same logic here still,
8144 * though we add one level of indirection, as we implement "telinit" in "systemctl". Hence, for
8145 * us if you invoke "init" you get "systemd", but it will execve() "systemctl" immediately with
8146 * argv[] unmodified if PID is != 1. If you invoke "telinit" you directly get "systemctl". In
8147 * both cases we shall do the same thing, which is why we do strstr(p_i_s_n, "init") here, as a
8148 * quick way to match both.
8149 *
8150 * Also see redirect_telinit() in src/core/main.c. */
8151
d5ca5f11 8152 if (sd_booted() > 0) {
f459b602 8153 arg_action = _ACTION_INVALID;
d5ca5f11
LP
8154 return telinit_parse_argv(argc, argv);
8155 } else {
c54819ca
LP
8156 /* Hmm, so some other init system is running, we need to forward this request to
8157 * it. For now we simply guess that it is Upstart. */
d5ca5f11 8158
4ad61fd1 8159 execv(TELINIT, argv);
d5ca5f11
LP
8160
8161 log_error("Couldn't find an alternative telinit implementation to spawn.");
8162 return -EIO;
8163 }
8164
e4b61340
LP
8165 } else if (strstr(program_invocation_short_name, "runlevel")) {
8166 arg_action = ACTION_RUNLEVEL;
8167 return runlevel_parse_argv(argc, argv);
8168 }
8169 }
8170
8171 arg_action = ACTION_SYSTEMCTL;
8172 return systemctl_parse_argv(argc, argv);
8173}
8174
349cc4a5 8175#if HAVE_SYSV_COMPAT
44a6b1b6 8176_pure_ static int action_to_runlevel(void) {
eb22ac37
LP
8177
8178 static const char table[_ACTION_MAX] = {
8179 [ACTION_HALT] = '0',
8180 [ACTION_POWEROFF] = '0',
8181 [ACTION_REBOOT] = '6',
8182 [ACTION_RUNLEVEL2] = '2',
8183 [ACTION_RUNLEVEL3] = '3',
8184 [ACTION_RUNLEVEL4] = '4',
8185 [ACTION_RUNLEVEL5] = '5',
8186 [ACTION_RESCUE] = '1'
8187 };
8188
78ca9099 8189 assert(arg_action >= 0 && arg_action < _ACTION_MAX);
d55ae9e6
LP
8190
8191 return table[arg_action];
8192}
d2e79673 8193#endif
d55ae9e6 8194
d55ae9e6 8195static int talk_initctl(void) {
349cc4a5 8196#if HAVE_SYSV_COMPAT
cbc9fbd1
LP
8197 struct init_request request = {
8198 .magic = INIT_MAGIC,
8199 .sleeptime = 0,
8200 .cmd = INIT_CMD_RUNLVL
8201 };
8202
7fd1b19b 8203 _cleanup_close_ int fd = -1;
d55ae9e6 8204 char rl;
cbc9fbd1 8205 int r;
83c76e8c 8206 const char *p;
eb22ac37 8207
427b47c4
ZJS
8208 rl = action_to_runlevel();
8209 if (!rl)
eb22ac37
LP
8210 return 0;
8211
d55ae9e6
LP
8212 request.runlevel = rl;
8213
83c76e8c
MG
8214 FOREACH_STRING(p, "/run/initctl", "/dev/initctl") {
8215 fd = open(p, O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
8216 if (fd >= 0 || errno != ENOENT)
8217 break;
8218 }
427b47c4 8219 if (fd < 0) {
d55ae9e6
LP
8220 if (errno == ENOENT)
8221 return 0;
eb22ac37 8222
83c76e8c 8223 return log_error_errno(errno, "Failed to open initctl fifo: %m");
d55ae9e6 8224 }
eb22ac37 8225
553acb7b
ZJS
8226 r = loop_write(fd, &request, sizeof(request), false);
8227 if (r < 0)
83c76e8c 8228 return log_error_errno(r, "Failed to write to %s: %m", p);
eb22ac37
LP
8229
8230 return 1;
eca830be
LP
8231#else
8232 return 0;
8233#endif
e4b61340
LP
8234}
8235
e449de87
LP
8236static int systemctl_main(int argc, char *argv[]) {
8237
8238 static const Verb verbs[] = {
c56d1e2c
CW
8239 { "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_ONLINE_ONLY, list_units },
8240 { "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files },
8241 { "list-sockets", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, list_sockets },
8242 { "list-timers", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, list_timers },
8243 { "list-jobs", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, list_jobs },
8244 { "list-machines", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY|VERB_MUST_BE_ROOT, list_machines },
8245 { "clear-jobs", VERB_ANY, 1, VERB_ONLINE_ONLY, trivial_method },
8246 { "cancel", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, cancel_job },
8247 { "start", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
8248 { "stop", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
8249 { "condstop", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with ALTLinux */
8250 { "reload", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
8251 { "restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
8252 { "try-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
8253 { "reload-or-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
8254 { "reload-or-try-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatbility with old systemctl <= 228 */
8255 { "try-reload-or-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
8256 { "force-reload", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with SysV */
8257 { "condreload", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with ALTLinux */
8258 { "condrestart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with RH */
8259 { "isolate", 2, 2, VERB_ONLINE_ONLY, start_unit },
8260 { "kill", 2, VERB_ANY, VERB_ONLINE_ONLY, kill_unit },
8261 { "is-active", 2, VERB_ANY, VERB_ONLINE_ONLY, check_unit_active },
3e7e587d 8262 { "check", 2, VERB_ANY, VERB_ONLINE_ONLY, check_unit_active }, /* deprecated alias of is-active */
c56d1e2c
CW
8263 { "is-failed", 2, VERB_ANY, VERB_ONLINE_ONLY, check_unit_failed },
8264 { "show", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, show },
8265 { "cat", 2, VERB_ANY, VERB_ONLINE_ONLY, cat },
8266 { "status", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, show },
8267 { "help", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, show },
8268 { "daemon-reload", VERB_ANY, 1, VERB_ONLINE_ONLY, daemon_reload },
8269 { "daemon-reexec", VERB_ANY, 1, VERB_ONLINE_ONLY, daemon_reload },
8270 { "show-environment", VERB_ANY, 1, VERB_ONLINE_ONLY, show_environment },
8271 { "set-environment", 2, VERB_ANY, VERB_ONLINE_ONLY, set_environment },
8272 { "unset-environment", 2, VERB_ANY, VERB_ONLINE_ONLY, set_environment },
8273 { "import-environment", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, import_environment },
8274 { "halt", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special },
8275 { "poweroff", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special },
8276 { "reboot", VERB_ANY, 2, VERB_ONLINE_ONLY, start_system_special },
8277 { "kexec", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special },
8278 { "suspend", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special },
8279 { "hibernate", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special },
8280 { "hybrid-sleep", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special },
e68c79db 8281 { "suspend-then-hibernate",VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special },
c56d1e2c
CW
8282 { "default", VERB_ANY, 1, VERB_ONLINE_ONLY, start_special },
8283 { "rescue", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special },
8284 { "emergency", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special },
8285 { "exit", VERB_ANY, 2, VERB_ONLINE_ONLY, start_special },
8286 { "reset-failed", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, reset_failed },
8287 { "enable", 2, VERB_ANY, 0, enable_unit },
8288 { "disable", 2, VERB_ANY, 0, enable_unit },
8289 { "is-enabled", 2, VERB_ANY, 0, unit_is_enabled },
8290 { "reenable", 2, VERB_ANY, 0, enable_unit },
8291 { "preset", 2, VERB_ANY, 0, enable_unit },
8292 { "preset-all", VERB_ANY, 1, 0, preset_all },
8293 { "mask", 2, VERB_ANY, 0, enable_unit },
8294 { "unmask", 2, VERB_ANY, 0, enable_unit },
8295 { "link", 2, VERB_ANY, 0, enable_unit },
8296 { "revert", 2, VERB_ANY, 0, enable_unit },
8297 { "switch-root", 2, VERB_ANY, VERB_ONLINE_ONLY, switch_root },
8298 { "list-dependencies", VERB_ANY, 2, VERB_ONLINE_ONLY, list_dependencies },
8299 { "set-default", 2, 2, 0, set_default },
8300 { "get-default", VERB_ANY, 1, 0, get_default },
8301 { "set-property", 3, VERB_ANY, VERB_ONLINE_ONLY, set_property },
8302 { "is-system-running", VERB_ANY, 1, 0, is_system_running },
8303 { "add-wants", 3, VERB_ANY, 0, add_dependency },
8304 { "add-requires", 3, VERB_ANY, 0, add_dependency },
8305 { "edit", 2, VERB_ANY, VERB_ONLINE_ONLY, edit },
d08e75ed 8306 {}
e449de87 8307 };
7e4249b9 8308
e449de87 8309 return dispatch_verb(argc, argv, verbs, NULL);
e4b61340
LP
8310}
8311
4fbd7192 8312static int reload_with_fallback(void) {
e4b61340 8313
4fbd7192 8314 /* First, try systemd via D-Bus. */
e449de87 8315 if (daemon_reload(0, NULL, NULL) >= 0)
4fbd7192 8316 return 0;
e4b61340
LP
8317
8318 /* Nothing else worked, so let's try signals */
2853b60a 8319 assert(IN_SET(arg_action, ACTION_RELOAD, ACTION_REEXEC));
e4b61340 8320
4a62c710
MS
8321 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0)
8322 return log_error_errno(errno, "kill() failed: %m");
e4b61340
LP
8323
8324 return 0;
8325}
8326
4fbd7192 8327static int start_with_fallback(void) {
e4b61340 8328
4fbd7192 8329 /* First, try systemd via D-Bus. */
e449de87 8330 if (start_unit(0, NULL, NULL) >= 0)
4fbd7192 8331 return 0;
e4b61340 8332
2853b60a 8333 /* Nothing else worked, so let's try /dev/initctl */
fbc43921 8334 if (talk_initctl() > 0)
48ec22bc 8335 return 0;
d55ae9e6
LP
8336
8337 log_error("Failed to talk to init daemon.");
8338 return -EIO;
e4b61340
LP
8339}
8340
477def80 8341static int halt_now(enum action a) {
e606bb61 8342
c01dcddf
LP
8343 /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need to be
8344 * synce'd explicitly in advance. */
1ae17672 8345 if (!arg_no_sync && !arg_dry_run)
f3f054f0 8346 (void) sync();
4a3ad399 8347
1ae17672
ZJS
8348 /* Make sure C-A-D is handled by the kernel from this point on... */
8349 if (!arg_dry_run)
8350 (void) reboot(RB_ENABLE_CAD);
e606bb61 8351
4c80c73c 8352 switch (a) {
e606bb61
LP
8353
8354 case ACTION_HALT:
60675884
LP
8355 if (!arg_quiet)
8356 log_info("Halting.");
1ae17672
ZJS
8357 if (arg_dry_run)
8358 return 0;
19578bb2 8359 (void) reboot(RB_HALT_SYSTEM);
477def80 8360 return -errno;
e606bb61
LP
8361
8362 case ACTION_POWEROFF:
60675884
LP
8363 if (!arg_quiet)
8364 log_info("Powering off.");
1ae17672
ZJS
8365 if (arg_dry_run)
8366 return 0;
19578bb2 8367 (void) reboot(RB_POWER_OFF);
477def80 8368 return -errno;
e606bb61 8369
98d52feb 8370 case ACTION_KEXEC:
c01dcddf
LP
8371 case ACTION_REBOOT:
8372 return reboot_with_parameter(REBOOT_FALLBACK |
8373 (arg_quiet ? 0 : REBOOT_LOG) |
8374 (arg_dry_run ? REBOOT_DRY_RUN : 0));
e606bb61 8375
477def80
LP
8376 default:
8377 assert_not_reached("Unknown action.");
8378 }
e606bb61
LP
8379}
8380
56a730fa
LP
8381static int logind_schedule_shutdown(void) {
8382
349cc4a5 8383#if ENABLE_LOGIND
4afd3348 8384 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
56a730fa
LP
8385 char date[FORMAT_TIMESTAMP_MAX];
8386 const char *action;
4fbd7192 8387 sd_bus *bus;
56a730fa
LP
8388 int r;
8389
4fbd7192 8390 r = acquire_bus(BUS_FULL, &bus);
56a730fa 8391 if (r < 0)
4fbd7192 8392 return r;
56a730fa
LP
8393
8394 switch (arg_action) {
8395 case ACTION_HALT:
8396 action = "halt";
8397 break;
8398 case ACTION_POWEROFF:
8399 action = "poweroff";
8400 break;
8401 case ACTION_KEXEC:
8402 action = "kexec";
8403 break;
a4420f7b
LP
8404 case ACTION_EXIT:
8405 action = "exit";
8406 break;
8407 case ACTION_REBOOT:
56a730fa
LP
8408 default:
8409 action = "reboot";
8410 break;
8411 }
8412
1ae17672 8413 if (arg_dry_run)
56a730fa
LP
8414 action = strjoina("dry-", action);
8415
d2ad7e1b
ZJS
8416 (void) logind_set_wall_message();
8417
56a730fa 8418 r = sd_bus_call_method(
4fbd7192 8419 bus,
56a730fa
LP
8420 "org.freedesktop.login1",
8421 "/org/freedesktop/login1",
8422 "org.freedesktop.login1.Manager",
8423 "ScheduleShutdown",
8424 &error,
8425 NULL,
8426 "st",
8427 action,
8428 arg_when);
8429 if (r < 0)
8430 return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r));
8431
60675884
LP
8432 if (!arg_quiet)
8433 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.", format_timestamp(date, sizeof(date), arg_when));
56a730fa
LP
8434 return 0;
8435#else
8436 log_error("Cannot schedule shutdown without logind support, proceeding with immediate shutdown.");
8437 return -ENOSYS;
8438#endif
8439}
8440
4fbd7192 8441static int halt_main(void) {
e4b61340
LP
8442 int r;
8443
4fbd7192 8444 r = logind_check_inhibitors(arg_action);
748ebafa
LP
8445 if (r < 0)
8446 return r;
b37844d3 8447
7f96539d
LP
8448 if (arg_when > 0)
8449 return logind_schedule_shutdown();
8450
bc8c2f5c 8451 if (geteuid() != 0) {
1ae17672 8452 if (arg_dry_run || arg_force > 0) {
fba868fa 8453 (void) must_be_root();
2ac3930f
IS
8454 return -EPERM;
8455 }
8456
7e59bfcb
LP
8457 /* Try logind if we are a normal user and no special
8458 * mode applies. Maybe PolicyKit allows us to shutdown
8459 * the machine. */
36b69c31 8460 if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT, ACTION_HALT)) {
4fbd7192 8461 r = logind_reboot(arg_action);
4c80c73c
KS
8462 if (r >= 0)
8463 return r;
a9085ea3 8464 if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
7f96539d
LP
8465 /* requested operation is not
8466 * supported on the local system or
8467 * already in progress */
a9085ea3
IS
8468 return r;
8469 /* on all other errors, try low-level operation */
4c80c73c 8470 }
bc8c2f5c
LP
8471 }
8472
1ae17672 8473 if (!arg_dry_run && !arg_force)
4fbd7192 8474 return start_with_fallback();
e4b61340 8475
2ac3930f
IS
8476 assert(geteuid() == 0);
8477
d90e1a30
LP
8478 if (!arg_no_wtmp) {
8479 if (sd_booted() > 0)
8480 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
7e59bfcb
LP
8481 else {
8482 r = utmp_put_shutdown();
8483 if (r < 0)
da927ba9 8484 log_warning_errno(r, "Failed to write utmp record: %m");
7e59bfcb 8485 }
d90e1a30 8486 }
e4b61340 8487
1ae17672 8488 if (arg_dry_run)
e4b61340
LP
8489 return 0;
8490
477def80 8491 r = halt_now(arg_action);
691395d8 8492 return log_error_errno(r, "Failed to reboot: %m");
e4b61340
LP
8493}
8494
8495static int runlevel_main(void) {
8496 int r, runlevel, previous;
8497
729e3769
LP
8498 r = utmp_get_runlevel(&runlevel, &previous);
8499 if (r < 0) {
8500 puts("unknown");
e4b61340
LP
8501 return r;
8502 }
8503
8504 printf("%c %c\n",
8505 previous <= 0 ? 'N' : previous,
8506 runlevel <= 0 ? 'N' : runlevel);
8507
8508 return 0;
8509}
8510
2cf05793 8511static int logind_cancel_shutdown(void) {
349cc4a5 8512#if ENABLE_LOGIND
4afd3348 8513 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192 8514 sd_bus *bus;
949d9ce9
LP
8515 int r;
8516
4fbd7192 8517 r = acquire_bus(BUS_FULL, &bus);
949d9ce9 8518 if (r < 0)
4fbd7192 8519 return r;
949d9ce9 8520
4fbd7192 8521 (void) logind_set_wall_message();
949d9ce9
LP
8522
8523 r = sd_bus_call_method(
4fbd7192 8524 bus,
949d9ce9
LP
8525 "org.freedesktop.login1",
8526 "/org/freedesktop/login1",
8527 "org.freedesktop.login1.Manager",
8528 "CancelScheduledShutdown",
8529 &error,
8530 NULL, NULL);
8531 if (r < 0)
8532 return log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s", bus_error_message(&error, r));
8533
8534 return 0;
2cf05793
LP
8535#else
8536 log_error("Not compiled with logind support, cannot cancel scheduled shutdowns.");
8537 return -ENOSYS;
8538#endif
949d9ce9
LP
8539}
8540
e4b61340 8541int main(int argc, char*argv[]) {
f459b602 8542 int r;
e4b61340 8543
acc28e2e
FB
8544 argv_cmdline = argv[0];
8545
a9cdc94f 8546 setlocale(LC_ALL, "");
e4b61340 8547 log_parse_environment();
2396fb04 8548 log_open();
592705f2 8549 sigbus_install();
e4b61340 8550
184ecaf7
DR
8551 /* Explicitly not on_tty() to avoid setting cached value.
8552 * This becomes relevant for piping output which might be
8553 * ellipsized. */
8554 original_stdout_is_tty = isatty(STDOUT_FILENO);
8555
04ebb595 8556 r = parse_argv(argc, argv);
f459b602 8557 if (r <= 0)
e4b61340 8558 goto finish;
7e4249b9 8559
040524b4 8560 if (arg_action != ACTION_SYSTEMCTL && running_in_chroot() > 0) {
60675884
LP
8561
8562 if (!arg_quiet)
8563 log_info("Running in chroot, ignoring request.");
f459b602 8564 r = 0;
82e23ddd
LP
8565 goto finish;
8566 }
8567
41dd15e4
LP
8568 /* systemctl_main() will print an error message for the bus
8569 * connection, but only if it needs to */
e4b61340
LP
8570
8571 switch (arg_action) {
8572
22f4096c 8573 case ACTION_SYSTEMCTL:
e449de87 8574 r = systemctl_main(argc, argv);
e4b61340 8575 break;
e4b61340 8576
081dc638
AJ
8577 /* Legacy command aliases set arg_action. They provide some fallbacks,
8578 * e.g. to tell sysvinit to reboot after you have installed systemd
8579 * binaries. */
8580
e4b61340
LP
8581 case ACTION_HALT:
8582 case ACTION_POWEROFF:
8583 case ACTION_REBOOT:
5622dde3 8584 case ACTION_KEXEC:
4fbd7192 8585 r = halt_main();
e4b61340
LP
8586 break;
8587
e4b61340
LP
8588 case ACTION_RUNLEVEL2:
8589 case ACTION_RUNLEVEL3:
8590 case ACTION_RUNLEVEL4:
8591 case ACTION_RUNLEVEL5:
8592 case ACTION_RESCUE:
4fbd7192 8593 r = start_with_fallback();
e4b61340 8594 break;
7e4249b9 8595
e4b61340
LP
8596 case ACTION_RELOAD:
8597 case ACTION_REEXEC:
4fbd7192 8598 r = reload_with_fallback();
e4b61340
LP
8599 break;
8600
949d9ce9 8601 case ACTION_CANCEL_SHUTDOWN:
2cf05793 8602 r = logind_cancel_shutdown();
f6144808
LP
8603 break;
8604
eb22ac37 8605 case ACTION_RUNLEVEL:
4f16c1f4
LP
8606 r = runlevel_main();
8607 break;
8608
081dc638
AJ
8609 case ACTION_EXIT:
8610 case ACTION_SUSPEND:
8611 case ACTION_HIBERNATE:
8612 case ACTION_HYBRID_SLEEP:
e68c79db 8613 case ACTION_SUSPEND_THEN_HIBERNATE:
081dc638
AJ
8614 case ACTION_EMERGENCY:
8615 case ACTION_DEFAULT:
8616 /* systemctl verbs with no equivalent in the legacy commands.
8617 * These cannot appear in arg_action. Fall through. */
8618
f459b602 8619 case _ACTION_INVALID:
e4b61340
LP
8620 default:
8621 assert_not_reached("Unknown action");
8622 }
7e4249b9
LP
8623
8624finish:
cf647b69
LP
8625 release_busses();
8626
f459b602
MAP
8627 pager_close();
8628 ask_password_agent_close();
8629 polkit_agent_close();
7e4249b9 8630
20b3f379 8631 strv_free(arg_types);
9b9b3d36 8632 strv_free(arg_states);
20b3f379 8633 strv_free(arg_properties);
ea4a240d 8634
172d7abf 8635 strv_free(arg_wall);
0f03c2a4 8636 free(arg_root);
4bb2e9d4 8637 free(arg_esp_path);
172d7abf 8638
404f08d3 8639 /* Note that we return r here, not EXIT_SUCCESS, so that we can implement the LSB-like return codes */
9eb4a501 8640 return r < 0 ? EXIT_FAILURE : r;
7e4249b9 8641}