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