]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl.c
hwdb: add accelerometer mount matrix for Eve V (#8382)
[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) &&
5b464a18
ZJS
2945 !sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED) &&
2946 !sd_bus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE))
a6405ca2 2947 log_error("See %s logs and 'systemctl%s status%s %s' for details.",
0b8505b7
RC
2948 arg_scope == UNIT_FILE_SYSTEM ? "system" : "user",
2949 arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
a6405ca2 2950 name[0] == '-' ? " --" : "",
0b8505b7 2951 name);
ee87525c
FB
2952
2953 return r;
7e4249b9
LP
2954 }
2955
f459b602
MAP
2956 r = sd_bus_message_read(reply, "o", &path);
2957 if (r < 0)
2958 return bus_log_parse_error(r);
45fb0699 2959
e3e0314b 2960 if (need_daemon_reload(bus, name) > 0)
3f36991e 2961 warn_unit_file_changed(name);
45fb0699 2962
ebd011d9
LP
2963 if (w) {
2964 log_debug("Adding %s to the set", path);
2965 r = bus_wait_for_jobs_add(w, path);
cbc9fbd1
LP
2966 if (r < 0)
2967 return log_oom();
e4b61340 2968 }
7e4249b9 2969
46eddbb5 2970 return 0;
7e4249b9
LP
2971}
2972
e3e0314b 2973static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) {
e3e0314b
ZJS
2974 _cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
2975 char **name;
7410616c 2976 int r, i;
e3e0314b 2977
4fbd7192
LP
2978 assert(bus);
2979 assert(ret);
2980
e3e0314b
ZJS
2981 STRV_FOREACH(name, names) {
2982 char *t;
2983
e80733be 2984 if (suffix)
7410616c 2985 r = unit_name_mangle_with_suffix(*name, UNIT_NAME_GLOB, suffix, &t);
e80733be 2986 else
7410616c
LP
2987 r = unit_name_mangle(*name, UNIT_NAME_GLOB, &t);
2988 if (r < 0)
2989 return log_error_errno(r, "Failed to mangle name: %m");
e3e0314b
ZJS
2990
2991 if (string_is_glob(t))
6e18964d 2992 r = strv_consume(&globs, t);
e3e0314b 2993 else
6e18964d
ZJS
2994 r = strv_consume(&mangled, t);
2995 if (r < 0)
e3e0314b 2996 return log_oom();
e3e0314b
ZJS
2997 }
2998
2999 /* Query the manager only if any of the names are a glob, since
3000 * this is fairly expensive */
3001 if (!strv_isempty(globs)) {
4afd3348 3002 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
e3e0314b 3003 _cleanup_free_ UnitInfo *unit_infos = NULL;
1b53f64b 3004 size_t allocated, n;
e3e0314b 3005
1238ee09 3006 r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
e3e0314b
ZJS
3007 if (r < 0)
3008 return r;
3009
1b53f64b
LP
3010 n = strv_length(mangled);
3011 allocated = n + 1;
3012
3013 for (i = 0; i < r; i++) {
3014 if (!GREEDY_REALLOC(mangled, allocated, n+2))
3015 return log_oom();
3016
3017 mangled[n] = strdup(unit_infos[i].id);
3018 if (!mangled[n])
e3e0314b 3019 return log_oom();
1b53f64b
LP
3020
3021 mangled[++n] = NULL;
3022 }
e3e0314b
ZJS
3023 }
3024
3025 *ret = mangled;
3026 mangled = NULL; /* do not free */
1238ee09 3027
e3e0314b
ZJS
3028 return 0;
3029}
3030
47a0eaa6
MS
3031static const struct {
3032 const char *target;
3033 const char *verb;
3034 const char *mode;
3035} action_table[_ACTION_MAX] = {
3036 [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" },
3037 [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
3038 [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" },
3039 [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" },
d5d8429a
LP
3040 [ACTION_RUNLEVEL2] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
3041 [ACTION_RUNLEVEL3] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
3042 [ACTION_RUNLEVEL4] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
3043 [ACTION_RUNLEVEL5] = { SPECIAL_GRAPHICAL_TARGET, NULL, "isolate" },
47a0eaa6
MS
3044 [ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" },
3045 [ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" },
3046 [ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" },
3047 [ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" },
3048 [ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" },
3049 [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" },
3050 [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
3051};
3052
514f4ef5 3053static enum action verb_to_action(const char *verb) {
47a0eaa6
MS
3054 enum action i;
3055
913c1916 3056 for (i = 0; i < _ACTION_MAX; i++)
f459b602 3057 if (streq_ptr(action_table[i].verb, verb))
47a0eaa6 3058 return i;
514f4ef5 3059
f459b602
MAP
3060 return _ACTION_INVALID;
3061}
e4b61340 3062
e449de87 3063static int start_unit(int argc, char *argv[], void *userdata) {
ebd011d9 3064 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
08073121 3065 const char *method, *mode, *one_name, *suffix = NULL;
ebd011d9 3066 _cleanup_strv_free_ char **names = NULL;
4fbd7192 3067 sd_bus *bus;
93a08841 3068 _cleanup_(wait_context_free) WaitContext wait_context = {};
729e3769 3069 char **name;
b6520546 3070 int r = 0;
e4b61340 3071
f886603b
AJ
3072 if (arg_wait && !STR_IN_SET(argv[0], "start", "restart")) {
3073 log_error("--wait may only be used with the 'start' or 'restart' commands.");
93a08841
MP
3074 return -EINVAL;
3075 }
3076
3077 /* we cannot do sender tracking on the private bus, so we need the full
3078 * one for RefUnit to implement --wait */
3079 r = acquire_bus(arg_wait ? BUS_FULL : BUS_MANAGER, &bus);
4fbd7192
LP
3080 if (r < 0)
3081 return r;
3082
d2ad7e1b 3083 ask_password_agent_open_if_enabled();
8a4b13c5 3084 polkit_agent_open_maybe();
d2ad7e1b 3085
e4b61340 3086 if (arg_action == ACTION_SYSTEMCTL) {
47a0eaa6 3087 enum action action;
e4b61340 3088
e449de87
LP
3089 action = verb_to_action(argv[0]);
3090
913c1916
AJ
3091 if (action != _ACTION_INVALID) {
3092 method = "StartUnit";
3093 mode = action_table[action].mode;
3094 one_name = action_table[action].target;
3095 } else {
3096 if (streq(argv[0], "isolate")) {
3097 method = "StartUnit";
3098 mode = "isolate";
3099
3100 suffix = ".target";
3101 } else {
3102 method = verb_to_method(argv[0]);
3103 mode = arg_job_mode;
3104 }
3105 one_name = NULL;
3106 }
e4b61340 3107 } else {
78ca9099 3108 assert(arg_action >= 0 && arg_action < _ACTION_MAX);
47a0eaa6 3109 assert(action_table[arg_action].target);
913c1916 3110 assert(action_table[arg_action].mode);
e4b61340
LP
3111
3112 method = "StartUnit";
47a0eaa6 3113 mode = action_table[arg_action].mode;
e3e0314b 3114 one_name = action_table[arg_action].target;
514f4ef5
LP
3115 }
3116
e3e0314b
ZJS
3117 if (one_name)
3118 names = strv_new(one_name, NULL);
3119 else {
e449de87 3120 r = expand_names(bus, strv_skip(argv, 1), suffix, &names);
e3e0314b 3121 if (r < 0)
691395d8 3122 return log_error_errno(r, "Failed to expand names: %m");
e3e0314b 3123 }
b6520546 3124
6e905d93 3125 if (!arg_no_block) {
ebd011d9 3126 r = bus_wait_for_jobs_new(bus, &w);
f647962d
MS
3127 if (r < 0)
3128 return log_error_errno(r, "Could not watch jobs: %m");
e4b61340
LP
3129 }
3130
93a08841 3131 if (arg_wait) {
93a08841
MP
3132 wait_context.unit_paths = set_new(&string_hash_ops);
3133 if (!wait_context.unit_paths)
3134 return log_oom();
3135
31b2cd5d 3136 r = sd_bus_call_method_async(
93a08841 3137 bus,
31b2cd5d 3138 NULL,
93a08841
MP
3139 "org.freedesktop.systemd1",
3140 "/org/freedesktop/systemd1",
3141 "org.freedesktop.systemd1.Manager",
3142 "Subscribe",
31b2cd5d
LP
3143 NULL, NULL,
3144 NULL);
93a08841 3145 if (r < 0)
31b2cd5d 3146 return log_error_errno(r, "Failed to enable subscription: %m");
93a08841
MP
3147 r = sd_event_default(&wait_context.event);
3148 if (r < 0)
3149 return log_error_errno(r, "Failed to allocate event loop: %m");
3150 r = sd_bus_attach_event(bus, wait_context.event, 0);
3151 if (r < 0)
3152 return log_error_errno(r, "Failed to attach bus to event loop: %m");
3153 }
3154
b6520546 3155 STRV_FOREACH(name, names) {
4afd3348 3156 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
b6520546 3157 int q;
f459b602 3158
93a08841 3159 q = start_unit_one(bus, method, *name, mode, &error, w, arg_wait ? &wait_context : NULL);
e3e0314b 3160 if (r >= 0 && q < 0)
b6520546 3161 r = translate_bus_error_to_exit_status(q, &error);
e4b61340
LP
3162 }
3163
67f3c402 3164 if (!arg_no_block) {
c11bda1e
ZJS
3165 int q, arg_count = 0;
3166 const char* extra_args[4] = {};
4524439e 3167
4524439e
ZJS
3168 if (arg_scope != UNIT_FILE_SYSTEM)
3169 extra_args[arg_count++] = "--user";
3170
3171 assert(IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_REMOTE, BUS_TRANSPORT_MACHINE));
3172 if (arg_transport == BUS_TRANSPORT_REMOTE) {
3173 extra_args[arg_count++] = "-H";
3174 extra_args[arg_count++] = arg_host;
3175 } else if (arg_transport == BUS_TRANSPORT_MACHINE) {
3176 extra_args[arg_count++] = "-M";
3177 extra_args[arg_count++] = arg_host;
3178 }
f459b602 3179
4524439e 3180 q = bus_wait_for_jobs(w, arg_quiet, extra_args);
f459b602
MAP
3181 if (q < 0)
3182 return q;
49111a70
ZJS
3183
3184 /* When stopping units, warn if they can still be triggered by
3185 * another active unit (socket, path, timer) */
b6520546
ZJS
3186 if (!arg_quiet && streq(method, "StopUnit"))
3187 STRV_FOREACH(name, names)
3188 check_triggering_units(bus, *name);
67f3c402 3189 }
514f4ef5 3190
93a08841
MP
3191 if (r >= 0 && arg_wait) {
3192 int q;
3193 q = sd_event_loop(wait_context.event);
3194 if (q < 0)
3195 return log_error_errno(q, "Failed to run event loop: %m");
3196 if (wait_context.any_failed)
3197 r = EXIT_FAILURE;
3198 }
3199
f459b602 3200 return r;
e4b61340
LP
3201}
3202
349cc4a5 3203#if ENABLE_LOGIND
4fbd7192 3204static int logind_set_wall_message(void) {
4afd3348 3205 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192 3206 sd_bus *bus;
f2d11d35
LP
3207 _cleanup_free_ char *m = NULL;
3208 int r;
3209
4fbd7192
LP
3210 r = acquire_bus(BUS_FULL, &bus);
3211 if (r < 0)
3212 return r;
f2d11d35
LP
3213
3214 m = strv_join(arg_wall, " ");
3215 if (!m)
3216 return log_oom();
3217
3218 r = sd_bus_call_method(
3219 bus,
3220 "org.freedesktop.login1",
3221 "/org/freedesktop/login1",
3222 "org.freedesktop.login1.Manager",
3223 "SetWallMessage",
3224 &error,
3225 NULL,
3226 "sb",
3227 m,
3228 !arg_no_wall);
3229
3230 if (r < 0)
3231 return log_warning_errno(r, "Failed to set wall message, ignoring: %s", bus_error_message(&error, r));
f2d11d35
LP
3232 return 0;
3233}
79f1c8f6 3234#endif
f2d11d35 3235
7e59bfcb
LP
3236/* Ask systemd-logind, which might grant access to unprivileged users
3237 * through PolicyKit */
4fbd7192 3238static int logind_reboot(enum action a) {
349cc4a5 3239#if ENABLE_LOGIND
4afd3348 3240 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
58158dc7 3241 const char *method, *description;
4fbd7192 3242 sd_bus *bus;
f459b602 3243 int r;
4c80c73c 3244
4fbd7192
LP
3245 r = acquire_bus(BUS_FULL, &bus);
3246 if (r < 0)
3247 return r;
f2d11d35 3248
4c80c73c
KS
3249 switch (a) {
3250
36b69c31
LP
3251 case ACTION_POWEROFF:
3252 method = "PowerOff";
3253 description = "power off system";
3254 break;
3255
4c80c73c
KS
3256 case ACTION_REBOOT:
3257 method = "Reboot";
58158dc7 3258 description = "reboot system";
4c80c73c
KS
3259 break;
3260
36b69c31
LP
3261 case ACTION_HALT:
3262 method = "Halt";
3263 description = "halt system";
4c80c73c
KS
3264 break;
3265
d889a206
LP
3266 case ACTION_SUSPEND:
3267 method = "Suspend";
58158dc7 3268 description = "suspend system";
d889a206
LP
3269 break;
3270
3271 case ACTION_HIBERNATE:
3272 method = "Hibernate";
58158dc7 3273 description = "hibernate system";
d889a206
LP
3274 break;
3275
6524990f
LP
3276 case ACTION_HYBRID_SLEEP:
3277 method = "HybridSleep";
58158dc7 3278 description = "put system into hybrid sleep";
6524990f
LP
3279 break;
3280
4c80c73c
KS
3281 default:
3282 return -EINVAL;
3283 }
3284
8a4b13c5 3285 polkit_agent_open_maybe();
d2ad7e1b
ZJS
3286 (void) logind_set_wall_message();
3287
f459b602 3288 r = sd_bus_call_method(
f22f08cd
SP
3289 bus,
3290 "org.freedesktop.login1",
3291 "/org/freedesktop/login1",
3292 "org.freedesktop.login1.Manager",
3293 method,
f459b602 3294 &error,
f22f08cd 3295 NULL,
342641fb 3296 "b", arg_ask_password);
f459b602 3297 if (r < 0)
691395d8 3298 return log_error_errno(r, "Failed to %s via logind: %s", description, bus_error_message(&error, r));
f459b602 3299
691395d8 3300 return 0;
4c80c73c
KS
3301#else
3302 return -ENOSYS;
3303#endif
3304}
3305
4fbd7192 3306static int logind_check_inhibitors(enum action a) {
349cc4a5 3307#if ENABLE_LOGIND
4afd3348 3308 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
59164be4 3309 _cleanup_strv_free_ char **sessions = NULL;
f459b602
MAP
3310 const char *what, *who, *why, *mode;
3311 uint32_t uid, pid;
4fbd7192 3312 sd_bus *bus;
f459b602 3313 unsigned c = 0;
59164be4 3314 char **s;
f459b602 3315 int r;
b37844d3 3316
748ebafa
LP
3317 if (arg_ignore_inhibitors || arg_force > 0)
3318 return 0;
3319
3320 if (arg_when > 0)
3321 return 0;
3322
3323 if (geteuid() == 0)
b37844d3
LP
3324 return 0;
3325
3326 if (!on_tty())
3327 return 0;
e08ab379
LP
3328
3329 if (arg_transport != BUS_TRANSPORT_LOCAL)
3330 return 0;
b37844d3 3331
4fbd7192
LP
3332 r = acquire_bus(BUS_FULL, &bus);
3333 if (r < 0)
3334 return r;
3335
f459b602 3336 r = sd_bus_call_method(
b37844d3
LP
3337 bus,
3338 "org.freedesktop.login1",
3339 "/org/freedesktop/login1",
3340 "org.freedesktop.login1.Manager",
3341 "ListInhibitors",
b37844d3 3342 NULL,
f459b602
MAP
3343 &reply,
3344 NULL);
b37844d3
LP
3345 if (r < 0)
3346 /* If logind is not around, then there are no inhibitors... */
3347 return 0;
3348
4aa2beac 3349 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
f459b602
MAP
3350 if (r < 0)
3351 return bus_log_parse_error(r);
b37844d3 3352
4aa2beac 3353 while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
59164be4 3354 _cleanup_free_ char *comm = NULL, *user = NULL;
f459b602 3355 _cleanup_strv_free_ char **sv = NULL;
b37844d3
LP
3356
3357 if (!streq(mode, "block"))
f459b602 3358 continue;
b37844d3
LP
3359
3360 sv = strv_split(what, ":");
3361 if (!sv)
3362 return log_oom();
3363
ee043777 3364 if (!pid_is_valid((pid_t) pid)) {
72b3f82e 3365 log_error("Invalid PID "PID_FMT".", (pid_t) pid);
ee043777
LP
3366 return -ERANGE;
3367 }
d028e018 3368
b37844d3 3369 if (!strv_contains(sv,
4c315c2c
IS
3370 IN_SET(a,
3371 ACTION_HALT,
3372 ACTION_POWEROFF,
3373 ACTION_REBOOT,
3374 ACTION_KEXEC) ? "shutdown" : "sleep"))
f459b602 3375 continue;
b37844d3
LP
3376
3377 get_process_comm(pid, &comm);
59164be4 3378 user = uid_to_name(uid);
f459b602 3379
de0671ee 3380 log_warning("Operation inhibited by \"%s\" (PID "PID_FMT" \"%s\", user %s), reason is \"%s\".",
d028e018 3381 who, (pid_t) pid, strna(comm), strna(user), why);
b37844d3 3382
f459b602 3383 c++;
b37844d3 3384 }
f459b602
MAP
3385 if (r < 0)
3386 return bus_log_parse_error(r);
b37844d3 3387
f459b602
MAP
3388 r = sd_bus_message_exit_container(reply);
3389 if (r < 0)
3390 return bus_log_parse_error(r);
b37844d3 3391
59164be4
LP
3392 /* Check for current sessions */
3393 sd_get_sessions(&sessions);
3394 STRV_FOREACH(s, sessions) {
59164be4
LP
3395 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
3396
3397 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
3398 continue;
3399
3400 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
3401 continue;
3402
28abce5d 3403 if (sd_session_get_type(*s, &type) < 0 || !STR_IN_SET(type, "x11", "wayland", "tty", "mir"))
59164be4
LP
3404 continue;
3405
3406 sd_session_get_tty(*s, &tty);
3407 sd_session_get_seat(*s, &seat);
3408 sd_session_get_service(*s, &service);
3409 user = uid_to_name(uid);
3410
3411 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
3412 c++;
3413 }
3414
b37844d3
LP
3415 if (c <= 0)
3416 return 0;
3417
59164be4 3418 log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
47a0eaa6 3419 action_table[a].verb);
b37844d3
LP
3420
3421 return -EPERM;
3422#else
3423 return 0;
3424#endif
3425}
3426
4fbd7192 3427static int logind_prepare_firmware_setup(void) {
349cc4a5 3428#if ENABLE_LOGIND
4afd3348 3429 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192 3430 sd_bus *bus;
a4921cf4
JJ
3431 int r;
3432
4fbd7192
LP
3433 r = acquire_bus(BUS_FULL, &bus);
3434 if (r < 0)
3435 return r;
a4921cf4 3436
a4921cf4
JJ
3437 r = sd_bus_call_method(
3438 bus,
3439 "org.freedesktop.login1",
3440 "/org/freedesktop/login1",
3441 "org.freedesktop.login1.Manager",
3442 "SetRebootToFirmwareSetup",
3443 &error,
3444 NULL,
3445 "b", true);
4fbd7192
LP
3446 if (r < 0)
3447 return log_error_errno(r, "Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
a4921cf4
JJ
3448
3449 return 0;
3450#else
3451 log_error("Cannot remotely indicate to EFI to boot into setup mode.");
4fbd7192 3452 return -ENOSYS;
a4921cf4
JJ
3453#endif
3454}
3455
4fbd7192
LP
3456static int prepare_firmware_setup(void) {
3457 int r;
3458
3459 if (!arg_firmware_setup)
3460 return 0;
3461
3462 if (arg_transport == BUS_TRANSPORT_LOCAL) {
3463
3464 r = efi_set_reboot_to_firmware(true);
3465 if (r < 0)
3466 log_debug_errno(r, "Cannot indicate to EFI to boot into setup mode, will retry via logind: %m");
3467 else
3468 return r;
3469 }
3470
3471 return logind_prepare_firmware_setup();
3472}
3473
4bb2e9d4
ZJS
3474static int load_kexec_kernel(void) {
3475 _cleanup_(boot_config_free) BootConfig config = {};
5caa3167 3476 _cleanup_free_ char *where = NULL, *kernel = NULL, *initrd = NULL, *options = NULL;
4bb2e9d4
ZJS
3477 const BootEntry *e;
3478 pid_t pid;
3479 int r;
3480
3481 if (kexec_loaded()) {
3482 log_debug("Kexec kernel already loaded.");
3483 return 0;
3484 }
3485
5caa3167
LP
3486 r = find_esp_and_warn(arg_esp_path, false, &where, NULL, NULL, NULL, NULL);
3487 if (r == -ENOKEY) /* find_esp_and_warn() doesn't warn about this case */
3488 return log_error_errno(r, "Cannot find the ESP partition mount point.");
3489 if (r < 0) /* But it logs about all these cases, hence don't log here again */
3490 return r;
4bb2e9d4 3491
5caa3167 3492 r = boot_entries_load_config(where, &config);
4bb2e9d4 3493 if (r < 0)
5caa3167 3494 return log_error_errno(r, "Failed to load bootspec config from \"%s/loader\": %m", where);
4bb2e9d4
ZJS
3495
3496 if (config.default_entry < 0) {
3497 log_error("No entry suitable as default, refusing to guess.");
3498 return -ENOENT;
3499 }
3500 e = &config.entries[config.default_entry];
3501
3502 if (strv_length(e->initrd) > 1) {
3503 log_error("Boot entry specifies multiple initrds, which is not supported currently.");
3504 return -EINVAL;
3505 }
3506
5caa3167 3507 kernel = path_join(NULL, where, e->kernel);
4bb2e9d4 3508 if (!strv_isempty(e->initrd))
5caa3167 3509 initrd = path_join(NULL, where, *e->initrd);
4bb2e9d4
ZJS
3510 options = strv_join(e->options, " ");
3511 if (!options)
3512 return log_oom();
3513
3514 log_debug("%s kexec kernel %s initrd %s options \"%s\".",
3515 arg_dry_run ? "Would load" : "loading",
3516 kernel, initrd, options);
3517 if (arg_dry_run)
3518 return 0;
3519
b6e1fff1 3520 r = safe_fork("(kexec)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
4c253ed1 3521 if (r < 0)
b6e1fff1 3522 return r;
4c253ed1 3523 if (r == 0) {
4bb2e9d4
ZJS
3524
3525 const char* const args[] = {
3526 KEXEC,
3527 "--load", kernel,
3528 "--append", options,
3529 initrd ? "--initrd" : NULL, initrd,
3530 NULL };
3531
3532 /* Child */
4bb2e9d4
ZJS
3533 execv(args[0], (char * const *) args);
3534 _exit(EXIT_FAILURE);
4c253ed1
LP
3535 }
3536
7d4904fe 3537 return wait_for_terminate_and_check("kexec", pid, WAIT_LOG);
4bb2e9d4
ZJS
3538}
3539
57ab9006 3540static int set_exit_code(uint8_t code) {
4afd3348 3541 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
57ab9006
LP
3542 sd_bus *bus;
3543 int r;
3544
3545 r = acquire_bus(BUS_MANAGER, &bus);
3546 if (r < 0)
3547 return r;
3548
3549 r = sd_bus_call_method(
3550 bus,
3551 "org.freedesktop.systemd1",
3552 "/org/freedesktop/systemd1",
3553 "org.freedesktop.systemd1.Manager",
3554 "SetExitCode",
3555 &error,
3556 NULL,
3557 "y", code);
3558 if (r < 0)
af3d8113 3559 return log_error_errno(r, "Failed to set exit code: %s", bus_error_message(&error, r));
57ab9006
LP
3560
3561 return 0;
3562}
3563
e449de87 3564static int start_special(int argc, char *argv[], void *userdata) {
4c80c73c 3565 enum action a;
983d9c90 3566 int r;
2b0f4e6f
ZJS
3567 bool termination_action; /* an action that terminates the manager,
3568 * can be performed also by signal. */
983d9c90 3569
e449de87 3570 assert(argv);
514f4ef5 3571
e449de87 3572 a = verb_to_action(argv[0]);
4c80c73c 3573
4fbd7192 3574 r = logind_check_inhibitors(a);
748ebafa
LP
3575 if (r < 0)
3576 return r;
3577
fba868fa
LP
3578 if (arg_force >= 2) {
3579 r = must_be_root();
3580 if (r < 0)
3581 return r;
c32b90de
LP
3582 }
3583
4fbd7192 3584 r = prepare_firmware_setup();
a4921cf4
JJ
3585 if (r < 0)
3586 return r;
5bdf2243 3587
e449de87 3588 if (a == ACTION_REBOOT && argc > 1) {
27c06cb5 3589 r = update_reboot_parameter_and_warn(argv[1]);
b986229e
SW
3590 if (r < 0)
3591 return r;
57ab9006 3592
4bb2e9d4
ZJS
3593 } else if (a == ACTION_KEXEC) {
3594 r = load_kexec_kernel();
3595 if (r < 0)
3596 return r;
3597
e449de87 3598 } else if (a == ACTION_EXIT && argc > 1) {
7bbb5359 3599 uint8_t code;
287419c1 3600
57ab9006
LP
3601 /* If the exit code is not given on the command line,
3602 * don't reset it to zero: just keep it as it might
3603 * have been set previously. */
287419c1 3604
e449de87 3605 r = safe_atou8(argv[1], &code);
4fbd7192 3606 if (r < 0)
57ab9006 3607 return log_error_errno(r, "Invalid exit code.");
4fbd7192 3608
57ab9006 3609 r = set_exit_code(code);
691395d8 3610 if (r < 0)
57ab9006 3611 return r;
b986229e
SW
3612 }
3613
2b0f4e6f
ZJS
3614 termination_action = IN_SET(a,
3615 ACTION_HALT,
3616 ACTION_POWEROFF,
3617 ACTION_REBOOT);
3618 if (termination_action && arg_force >= 2)
477def80 3619 return halt_now(a);
e606bb61 3620
7e59bfcb 3621 if (arg_force >= 1 &&
5955df2c 3622 (termination_action || IN_SET(a, ACTION_KEXEC, ACTION_EXIT)))
2b0f4e6f
ZJS
3623 r = trivial_method(argc, argv, userdata);
3624 else {
3625 /* First try logind, to allow authentication with polkit */
3626 if (IN_SET(a,
3627 ACTION_POWEROFF,
3628 ACTION_REBOOT,
36b69c31 3629 ACTION_HALT,
2b0f4e6f
ZJS
3630 ACTION_SUSPEND,
3631 ACTION_HIBERNATE,
3632 ACTION_HYBRID_SLEEP)) {
3633
3634 r = logind_reboot(a);
3635 if (r >= 0)
3636 return r;
3637 if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
3638 /* requested operation is not supported or already in progress */
3639 return r;
20b09ca7 3640
130246d2
LP
3641 /* On all other errors, try low-level operation. In order to minimize the difference between
3642 * operation with and without logind, we explicitly enable non-blocking mode for this, as
3643 * logind's shutdown operations are always non-blocking. */
3644
3645 arg_no_block = true;
3646
3647 } else if (IN_SET(a, ACTION_EXIT, ACTION_KEXEC))
3648 /* Since exit/kexec are so close in behaviour to power-off/reboot, let's also make them
3649 * asynchronous, in order to not confuse the user needlessly with unexpected behaviour. */
3650 arg_no_block = true;
7089051f 3651
2b0f4e6f 3652 r = start_unit(argc, argv, userdata);
4c80c73c 3653 }
983d9c90 3654
2b0f4e6f
ZJS
3655 if (termination_action && arg_force < 2 &&
3656 IN_SET(r, -ENOENT, -ETIMEDOUT))
cc7de2ba 3657 log_notice("It is possible to perform action directly, see discussion of --force --force in man:systemctl(1).");
2b0f4e6f
ZJS
3658
3659 return r;
514f4ef5
LP
3660}
3661
988b3b17
ZJS
3662static int start_system_special(int argc, char *argv[], void *userdata) {
3663 /* Like start_special above, but raises an error when running in user mode */
3664
3665 if (arg_scope != UNIT_FILE_SYSTEM) {
3666 log_error("Bad action for %s mode.",
3667 arg_scope == UNIT_FILE_GLOBAL ? "--global" : "--user");
3668 return -EINVAL;
3669 }
3670
3671 return start_special(argc, argv, userdata);
3672}
3673
fa0d5878 3674static int check_unit_generic(int code, const UnitActiveState good_states[], int nb_states, char **args) {
e3e0314b 3675 _cleanup_strv_free_ char **names = NULL;
fa0d5878 3676 UnitActiveState active_state;
4fbd7192 3677 sd_bus *bus;
729e3769 3678 char **name;
fa0d5878 3679 int r, i;
d60f6ad0 3680 bool found = false;
0183528f 3681
4fbd7192
LP
3682 r = acquire_bus(BUS_MANAGER, &bus);
3683 if (r < 0)
3684 return r;
3685
e3e0314b 3686 r = expand_names(bus, args, NULL, &names);
f647962d
MS
3687 if (r < 0)
3688 return log_error_errno(r, "Failed to expand names: %m");
e3e0314b
ZJS
3689
3690 STRV_FOREACH(name, names) {
fa0d5878
BR
3691 r = get_state_one_unit(bus, *name, &active_state);
3692 if (r < 0)
3693 return r;
3694
3695 if (!arg_quiet)
3696 puts(unit_active_state_to_string(active_state));
60f9ba0b 3697
fa0d5878
BR
3698 for (i = 0; i < nb_states; ++i)
3699 if (good_states[i] == active_state)
3700 found = true;
1a0fce45
TA
3701 }
3702
d60f6ad0
LN
3703 /* use the given return code for the case that we won't find
3704 * any unit which matches the list */
3705 return found ? 0 : code;
1a0fce45
TA
3706}
3707
e449de87 3708static int check_unit_active(int argc, char *argv[], void *userdata) {
fa0d5878 3709 const UnitActiveState states[] = { UNIT_ACTIVE, UNIT_RELOADING };
e3e0314b 3710 /* According to LSB: 3, "program is not running" */
b613907e 3711 return check_unit_generic(EXIT_PROGRAM_NOT_RUNNING, states, ELEMENTSOF(states), strv_skip(argv, 1));
e3e0314b 3712}
0183528f 3713
e449de87 3714static int check_unit_failed(int argc, char *argv[], void *userdata) {
fa0d5878 3715 const UnitActiveState states[] = { UNIT_FAILED };
b613907e 3716 return check_unit_generic(EXIT_PROGRAM_DEAD_AND_PID_EXISTS, states, ELEMENTSOF(states), strv_skip(argv, 1));
48220598
LP
3717}
3718
e449de87 3719static int kill_unit(int argc, char *argv[], void *userdata) {
e3e0314b 3720 _cleanup_strv_free_ char **names = NULL;
ac5e3a50 3721 char *kill_who = NULL, **name;
4fbd7192 3722 sd_bus *bus;
e3e0314b 3723 int r, q;
8a0867d6 3724
4fbd7192
LP
3725 r = acquire_bus(BUS_MANAGER, &bus);
3726 if (r < 0)
3727 return r;
3728
8a4b13c5 3729 polkit_agent_open_maybe();
d2ad7e1b 3730
8a0867d6
LP
3731 if (!arg_kill_who)
3732 arg_kill_who = "all";
3733
ac5e3a50
JS
3734 /* --fail was specified */
3735 if (streq(arg_job_mode, "fail"))
81d62103 3736 kill_who = strjoina(arg_kill_who, "-fail");
ac5e3a50 3737
e449de87 3738 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
e3e0314b 3739 if (r < 0)
691395d8 3740 return log_error_errno(r, "Failed to expand names: %m");
60f9ba0b 3741
e3e0314b 3742 STRV_FOREACH(name, names) {
4afd3348 3743 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
342641fb 3744
6e646d22 3745 q = sd_bus_call_method(
f22f08cd 3746 bus,
b0193f1c
LP
3747 "org.freedesktop.systemd1",
3748 "/org/freedesktop/systemd1",
3749 "org.freedesktop.systemd1.Manager",
6e646d22
LP
3750 "KillUnit",
3751 &error,
3752 NULL,
169d7fb6 3753 "ssi", *name, kill_who ? kill_who : arg_kill_who, arg_signal);
e3e0314b 3754 if (q < 0) {
169d7fb6 3755 log_error_errno(q, "Failed to kill unit %s: %s", *name, bus_error_message(&error, q));
e3e0314b
ZJS
3756 if (r == 0)
3757 r = q;
f459b602 3758 }
8a0867d6 3759 }
f459b602 3760
e3e0314b 3761 return r;
8a0867d6
LP
3762}
3763
582a507f 3764typedef struct ExecStatusInfo {
0129173a
LP
3765 char *name;
3766
582a507f
LP
3767 char *path;
3768 char **argv;
3769
b708e7ce
LP
3770 bool ignore;
3771
582a507f
LP
3772 usec_t start_timestamp;
3773 usec_t exit_timestamp;
3774 pid_t pid;
3775 int code;
3776 int status;
3777
3778 LIST_FIELDS(struct ExecStatusInfo, exec);
3779} ExecStatusInfo;
3780
3781static void exec_status_info_free(ExecStatusInfo *i) {
3782 assert(i);
3783
0129173a 3784 free(i->name);
582a507f
LP
3785 free(i->path);
3786 strv_free(i->argv);
3787 free(i);
3788}
3789
f459b602 3790static int exec_status_info_deserialize(sd_bus_message *m, ExecStatusInfo *i) {
b21a0ef8 3791 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
f459b602 3792 const char *path;
582a507f
LP
3793 uint32_t pid;
3794 int32_t code, status;
f459b602 3795 int ignore, r;
582a507f 3796
f459b602 3797 assert(m);
582a507f 3798 assert(i);
582a507f 3799
f459b602
MAP
3800 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, "sasbttttuii");
3801 if (r < 0)
3802 return bus_log_parse_error(r);
3803 else if (r == 0)
3804 return 0;
582a507f 3805
f459b602
MAP
3806 r = sd_bus_message_read(m, "s", &path);
3807 if (r < 0)
3808 return bus_log_parse_error(r);
582a507f 3809
f84190d8
LP
3810 i->path = strdup(path);
3811 if (!i->path)
f459b602 3812 return log_oom();
582a507f 3813
f459b602
MAP
3814 r = sd_bus_message_read_strv(m, &i->argv);
3815 if (r < 0)
3816 return bus_log_parse_error(r);
3817
3818 r = sd_bus_message_read(m,
3819 "bttttuii",
3820 &ignore,
3821 &start_timestamp, &start_timestamp_monotonic,
3822 &exit_timestamp, &exit_timestamp_monotonic,
3823 &pid,
3824 &code, &status);
3825 if (r < 0)
3826 return bus_log_parse_error(r);
582a507f 3827
b708e7ce 3828 i->ignore = ignore;
582a507f
LP
3829 i->start_timestamp = (usec_t) start_timestamp;
3830 i->exit_timestamp = (usec_t) exit_timestamp;
3831 i->pid = (pid_t) pid;
3832 i->code = code;
3833 i->status = status;
3834
f459b602
MAP
3835 r = sd_bus_message_exit_container(m);
3836 if (r < 0)
3837 return bus_log_parse_error(r);
3838
3839 return 1;
582a507f
LP
3840}
3841
d5db7fe6
WC
3842typedef struct UnitCondition {
3843 char *name;
b1ed76ae 3844 char *param;
d5db7fe6
WC
3845 bool trigger;
3846 bool negate;
d5db7fe6
WC
3847 int tristate;
3848
b1ed76ae 3849 LIST_FIELDS(struct UnitCondition, conditions);
d5db7fe6
WC
3850} UnitCondition;
3851
3852static void unit_condition_free(UnitCondition *c) {
9bb71940
ZJS
3853 if (!c)
3854 return;
d5db7fe6
WC
3855
3856 free(c->name);
3857 free(c->param);
3858 free(c);
3859}
3860
9bb71940
ZJS
3861DEFINE_TRIVIAL_CLEANUP_FUNC(UnitCondition*, unit_condition_free);
3862
61cbdc4b
LP
3863typedef struct UnitStatusInfo {
3864 const char *id;
3865 const char *load_state;
3866 const char *active_state;
3867 const char *sub_state;
a4375746 3868 const char *unit_file_state;
d2dc52db 3869 const char *unit_file_preset;
61cbdc4b
LP
3870
3871 const char *description;
4a9e2fff 3872 const char *following;
61cbdc4b 3873
49dbfa7b
LP
3874 char **documentation;
3875
1b64d026
LP
3876 const char *fragment_path;
3877 const char *source_path;
4ad49000 3878 const char *control_group;
61cbdc4b 3879
76d14b87
OS
3880 char **dropin_paths;
3881
9f39404c 3882 const char *load_error;
f42806df 3883 const char *result;
9f39404c 3884
584be568 3885 usec_t inactive_exit_timestamp;
df50185b 3886 usec_t inactive_exit_timestamp_monotonic;
584be568
LP
3887 usec_t active_enter_timestamp;
3888 usec_t active_exit_timestamp;
3889 usec_t inactive_enter_timestamp;
3890
45fb0699 3891 bool need_daemon_reload;
055ef36b 3892 bool transient;
45fb0699 3893
61cbdc4b
LP
3894 /* Service */
3895 pid_t main_pid;
3896 pid_t control_pid;
3897 const char *status_text;
175728c4 3898 const char *pid_file;
d06dacd0 3899 bool running:1;
b4af5a80 3900 int status_errno;
61cbdc4b
LP
3901
3902 usec_t start_timestamp;
3903 usec_t exit_timestamp;
3904
3905 int exit_code, exit_status;
3906
90bbc946
LP
3907 usec_t condition_timestamp;
3908 bool condition_result;
b1ed76ae 3909 LIST_HEAD(UnitCondition, conditions);
59fccdc5
LP
3910
3911 usec_t assert_timestamp;
3912 bool assert_result;
3913 bool failed_assert_trigger;
3914 bool failed_assert_negate;
3915 const char *failed_assert;
3916 const char *failed_assert_parameter;
601b0842
GS
3917 usec_t next_elapse_real;
3918 usec_t next_elapse_monotonic;
90bbc946 3919
61cbdc4b
LP
3920 /* Socket */
3921 unsigned n_accepted;
3922 unsigned n_connections;
b8131a87 3923 bool accept;
61cbdc4b 3924
13160134 3925 /* Pairs of type, path */
67419600
OS
3926 char **listen;
3927
61cbdc4b
LP
3928 /* Device */
3929 const char *sysfs_path;
3930
3931 /* Mount, Automount */
3932 const char *where;
3933
3934 /* Swap */
3935 const char *what;
582a507f 3936
934277fe
LP
3937 /* CGroup */
3938 uint64_t memory_current;
da4d897e
TH
3939 uint64_t memory_low;
3940 uint64_t memory_high;
3941 uint64_t memory_max;
96e131ea 3942 uint64_t memory_swap_max;
934277fe 3943 uint64_t memory_limit;
5ad096b3 3944 uint64_t cpu_usage_nsec;
03a7b521
LP
3945 uint64_t tasks_current;
3946 uint64_t tasks_max;
934277fe 3947
0e97c93f
DM
3948 uint64_t ip_ingress_bytes;
3949 uint64_t ip_egress_bytes;
3950
582a507f 3951 LIST_HEAD(ExecStatusInfo, exec);
61cbdc4b
LP
3952} UnitStatusInfo;
3953
a7335518
ZJS
3954static void unit_status_info_free(UnitStatusInfo *info) {
3955 ExecStatusInfo *p;
3956 UnitCondition *c;
3957
3958 strv_free(info->documentation);
3959 strv_free(info->dropin_paths);
3960 strv_free(info->listen);
3961
3962 while ((c = info->conditions)) {
3963 LIST_REMOVE(conditions, info->conditions, c);
3964 unit_condition_free(c);
3965 }
3966
3967 while ((p = info->exec)) {
3968 LIST_REMOVE(exec, info->exec, p);
3969 exec_status_info_free(p);
3970 }
3971}
3972
f459b602 3973static void print_status_info(
291d565a 3974 sd_bus *bus,
f459b602
MAP
3975 UnitStatusInfo *i,
3976 bool *ellipsized) {
3977
582a507f 3978 ExecStatusInfo *p;
b0d14c69 3979 const char *active_on, *active_off, *on, *off, *ss;
584be568 3980 usec_t timestamp;
9185c8e6 3981 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
584be568 3982 char since2[FORMAT_TIMESTAMP_MAX], *s2;
1b64d026 3983 const char *path;
13160134 3984 char **t, **t2;
291d565a 3985 int r;
582a507f 3986
61cbdc4b
LP
3987 assert(i);
3988
3989 /* This shows pretty information about a unit. See
3990 * print_property() for a low-level property printer */
3991
b0d14c69
LP
3992 if (streq_ptr(i->active_state, "failed")) {
3993 active_on = ansi_highlight_red();
1fc464f6 3994 active_off = ansi_normal();
1cf03a4f 3995 } else if (STRPTR_IN_SET(i->active_state, "active", "reloading")) {
b0d14c69 3996 active_on = ansi_highlight_green();
1fc464f6 3997 active_off = ansi_normal();
b0d14c69
LP
3998 } else
3999 active_on = active_off = "";
4000
323b7dc9 4001 printf("%s%s%s %s", active_on, special_glyph(BLACK_CIRCLE), active_off, strna(i->id));
61cbdc4b
LP
4002
4003 if (i->description && !streq_ptr(i->id, i->description))
4004 printf(" - %s", i->description);
4005
4006 printf("\n");
4007
4a9e2fff 4008 if (i->following)
856323c9 4009 printf(" Follow: unit currently follows state of %s\n", i->following);
4a9e2fff 4010
f7b9e331 4011 if (streq_ptr(i->load_state, "error")) {
0b5a519c 4012 on = ansi_highlight_red();
1fc464f6 4013 off = ansi_normal();
c31b4423
LP
4014 } else
4015 on = off = "";
4016
1b64d026
LP
4017 path = i->source_path ? i->source_path : i->fragment_path;
4018
055ef36b 4019 if (i->load_error != 0)
856323c9
ZJS
4020 printf(" Loaded: %s%s%s (Reason: %s)\n",
4021 on, strna(i->load_state), off, i->load_error);
15ce1647
LP
4022 else if (path && !isempty(i->unit_file_state) && !isempty(i->unit_file_preset) &&
4023 !STR_IN_SET(i->unit_file_state, "generated", "transient"))
d2dc52db
LP
4024 printf(" Loaded: %s%s%s (%s; %s; vendor preset: %s)\n",
4025 on, strna(i->load_state), off, path, i->unit_file_state, i->unit_file_preset);
4026 else if (path && !isempty(i->unit_file_state))
856323c9
ZJS
4027 printf(" Loaded: %s%s%s (%s; %s)\n",
4028 on, strna(i->load_state), off, path, i->unit_file_state);
1b64d026 4029 else if (path)
856323c9
ZJS
4030 printf(" Loaded: %s%s%s (%s)\n",
4031 on, strna(i->load_state), off, path);
61cbdc4b 4032 else
856323c9
ZJS
4033 printf(" Loaded: %s%s%s\n",
4034 on, strna(i->load_state), off);
61cbdc4b 4035
055ef36b
LP
4036 if (i->transient)
4037 printf("Transient: yes\n");
4038
76d14b87 4039 if (!strv_isempty(i->dropin_paths)) {
f459b602 4040 _cleanup_free_ char *dir = NULL;
76d14b87 4041 bool last = false;
f459b602 4042 char ** dropin;
76d14b87
OS
4043
4044 STRV_FOREACH(dropin, i->dropin_paths) {
4045 if (! dir || last) {
856323c9 4046 printf(dir ? " " : " Drop-In: ");
76d14b87 4047
97b11eed 4048 dir = mfree(dir);
76d14b87 4049
5f311f8c
LP
4050 dir = dirname_malloc(*dropin);
4051 if (!dir) {
76d14b87
OS
4052 log_oom();
4053 return;
4054 }
4055
856323c9 4056 printf("%s\n %s", dir,
323b7dc9 4057 special_glyph(TREE_RIGHT));
76d14b87
OS
4058 }
4059
4060 last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
4061
2b6bf07d 4062 printf("%s%s", basename(*dropin), last ? "\n" : ", ");
76d14b87 4063 }
76d14b87
OS
4064 }
4065
2ee68f72 4066 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2ee68f72 4067 if (ss)
856323c9 4068 printf(" Active: %s%s (%s)%s",
b0d14c69 4069 active_on, strna(i->active_state), ss, active_off);
2ee68f72 4070 else
856323c9 4071 printf(" Active: %s%s%s",
b0d14c69 4072 active_on, strna(i->active_state), active_off);
61cbdc4b 4073
f42806df
LP
4074 if (!isempty(i->result) && !streq(i->result, "success"))
4075 printf(" (Result: %s)", i->result);
4076
1cf03a4f
ZJS
4077 timestamp = STRPTR_IN_SET(i->active_state, "active", "reloading") ? i->active_enter_timestamp :
4078 STRPTR_IN_SET(i->active_state, "inactive", "failed") ? i->inactive_enter_timestamp :
4079 STRPTR_IN_SET(i->active_state, "activating") ? i->inactive_exit_timestamp :
4080 i->active_exit_timestamp;
584be568 4081
bbb8486e 4082 s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
584be568
LP
4083 s2 = format_timestamp(since2, sizeof(since2), timestamp);
4084
4085 if (s1)
538da63d 4086 printf(" since %s; %s\n", s2, s1);
584be568 4087 else if (s2)
538da63d 4088 printf(" since %s\n", s2);
584be568
LP
4089 else
4090 printf("\n");
4091
601b0842
GS
4092 if (endswith(i->id, ".timer")) {
4093 char tstamp1[FORMAT_TIMESTAMP_RELATIVE_MAX],
4094 tstamp2[FORMAT_TIMESTAMP_MAX];
4095 char *next_rel_time, *next_time;
4096 dual_timestamp nw, next = {i->next_elapse_real,
4097 i->next_elapse_monotonic};
4098 usec_t next_elapse;
4099
4100 printf(" Trigger: ");
4101
4102 dual_timestamp_get(&nw);
4103 next_elapse = calc_next_elapse(&nw, &next);
4104 next_rel_time = format_timestamp_relative(tstamp1,
4105 sizeof(tstamp1),
4106 next_elapse);
4107 next_time = format_timestamp(tstamp2,
4108 sizeof(tstamp2),
4109 next_elapse);
4110
4111 if (next_time && next_rel_time)
4112 printf("%s; %s\n", next_time, next_rel_time);
4113 else
4114 printf("n/a\n");
4115 }
4116
90bbc946 4117 if (!i->condition_result && i->condition_timestamp > 0) {
d5db7fe6
WC
4118 UnitCondition *c;
4119 int n = 0;
4120
bbb8486e 4121 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
90bbc946
LP
4122 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
4123
59fccdc5 4124 printf("Condition: start %scondition failed%s at %s%s%s\n",
1fc464f6 4125 ansi_highlight_yellow(), ansi_normal(),
5cfee414 4126 s2, s1 ? "; " : "", strempty(s1));
d5db7fe6 4127
b1ed76ae 4128 LIST_FOREACH(conditions, c, i->conditions)
d5db7fe6
WC
4129 if (c->tristate < 0)
4130 n++;
d5db7fe6 4131
b1ed76ae
ZJS
4132 LIST_FOREACH(conditions, c, i->conditions)
4133 if (c->tristate < 0)
4134 printf(" %s %s=%s%s%s was not met\n",
4135 --n ? special_glyph(TREE_BRANCH) : special_glyph(TREE_RIGHT),
4136 c->name,
4137 c->trigger ? "|" : "",
4138 c->negate ? "!" : "",
4139 c->param);
59fccdc5
LP
4140 }
4141
4142 if (!i->assert_result && i->assert_timestamp > 0) {
4143 s1 = format_timestamp_relative(since1, sizeof(since1), i->assert_timestamp);
4144 s2 = format_timestamp(since2, sizeof(since2), i->assert_timestamp);
4145
4146 printf(" Assert: start %sassertion failed%s at %s%s%s\n",
1fc464f6 4147 ansi_highlight_red(), ansi_normal(),
5cfee414 4148 s2, s1 ? "; " : "", strempty(s1));
59fccdc5
LP
4149 if (i->failed_assert_trigger)
4150 printf(" none of the trigger assertions were met\n");
4151 else if (i->failed_assert)
4152 printf(" %s=%s%s was not met\n",
4153 i->failed_assert,
4154 i->failed_assert_negate ? "!" : "",
4155 i->failed_assert_parameter);
90bbc946
LP
4156 }
4157
61cbdc4b 4158 if (i->sysfs_path)
856323c9 4159 printf(" Device: %s\n", i->sysfs_path);
9feeba4b 4160 if (i->where)
856323c9 4161 printf(" Where: %s\n", i->where);
9feeba4b 4162 if (i->what)
856323c9 4163 printf(" What: %s\n", i->what);
49dbfa7b 4164
13160134 4165 STRV_FOREACH(t, i->documentation)
856323c9 4166 printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", *t);
49dbfa7b 4167
13160134 4168 STRV_FOREACH_PAIR(t, t2, i->listen)
856323c9 4169 printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
67419600 4170
b8131a87 4171 if (i->accept)
856323c9 4172 printf(" Accepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
61cbdc4b 4173
582a507f 4174 LIST_FOREACH(exec, p, i->exec) {
13160134 4175 _cleanup_free_ char *argv = NULL;
9a57c629 4176 bool good;
582a507f
LP
4177
4178 /* Only show exited processes here */
4179 if (p->code == 0)
4180 continue;
4181
13160134 4182 argv = strv_join(p->argv, " ");
1fa2f38f 4183 printf(" Process: "PID_FMT" %s=%s ", p->pid, p->name, strna(argv));
582a507f 4184
1f0958f6 4185 good = is_clean_exit(p->code, p->status, EXIT_CLEAN_DAEMON, NULL);
9a57c629 4186 if (!good) {
0b5a519c 4187 on = ansi_highlight_red();
1fc464f6 4188 off = ansi_normal();
9a57c629
LP
4189 } else
4190 on = off = "";
4191
4192 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
4193
d06dacd0
LP
4194 if (p->code == CLD_EXITED) {
4195 const char *c;
4196
582a507f 4197 printf("status=%i", p->status);
d06dacd0 4198
1b64d026
LP
4199 c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
4200 if (c)
d06dacd0
LP
4201 printf("/%s", c);
4202
4203 } else
582a507f 4204 printf("signal=%s", signal_to_string(p->status));
9a57c629
LP
4205
4206 printf(")%s\n", off);
4207
582a507f
LP
4208 if (i->main_pid == p->pid &&
4209 i->start_timestamp == p->start_timestamp &&
4210 i->exit_timestamp == p->start_timestamp)
4211 /* Let's not show this twice */
4212 i->main_pid = 0;
4213
4214 if (p->pid == i->control_pid)
4215 i->control_pid = 0;
4216 }
4217
61cbdc4b 4218 if (i->main_pid > 0 || i->control_pid > 0) {
61cbdc4b 4219 if (i->main_pid > 0) {
8c06592f 4220 printf(" Main PID: "PID_FMT, i->main_pid);
61cbdc4b
LP
4221
4222 if (i->running) {
a081b9ce
LP
4223
4224 if (arg_transport == BUS_TRANSPORT_LOCAL) {
4225 _cleanup_free_ char *comm = NULL;
4226
4227 (void) get_process_comm(i->main_pid, &comm);
4228 if (comm)
4229 printf(" (%s)", comm);
4230 }
4231
6d4fc029 4232 } else if (i->exit_code > 0) {
61cbdc4b
LP
4233 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
4234
d06dacd0
LP
4235 if (i->exit_code == CLD_EXITED) {
4236 const char *c;
4237
61cbdc4b 4238 printf("status=%i", i->exit_status);
d06dacd0 4239
1b64d026
LP
4240 c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
4241 if (c)
d06dacd0
LP
4242 printf("/%s", c);
4243
4244 } else
582a507f 4245 printf("signal=%s", signal_to_string(i->exit_status));
6d4fc029
LP
4246 printf(")");
4247 }
13160134 4248 }
61cbdc4b
LP
4249
4250 if (i->control_pid > 0) {
13160134 4251 _cleanup_free_ char *c = NULL;
61cbdc4b 4252
1089dcd4
LP
4253 if (i->main_pid > 0)
4254 fputs("; Control PID: ", stdout);
4255 else
4256 fputs("Cntrl PID: ", stdout); /* if first in column, abbreviated so it fits alignment */
4257
4258 printf(PID_FMT, i->control_pid);
61cbdc4b 4259
a081b9ce
LP
4260 if (arg_transport == BUS_TRANSPORT_LOCAL) {
4261 (void) get_process_comm(i->control_pid, &c);
4262 if (c)
4263 printf(" (%s)", c);
4264 }
61cbdc4b
LP
4265 }
4266
4267 printf("\n");
4268 }
4269
17bb7382 4270 if (i->status_text)
856323c9 4271 printf(" Status: \"%s\"\n", i->status_text);
b4af5a80
LP
4272 if (i->status_errno > 0)
4273 printf(" Error: %i (%s)\n", i->status_errno, strerror(i->status_errno));
17bb7382 4274
0e97c93f
DM
4275 if (i->ip_ingress_bytes != (uint64_t) -1 && i->ip_egress_bytes != (uint64_t) -1) {
4276 char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX];
4277
4278 printf(" IP: %s in, %s out\n",
4279 format_bytes(buf_in, sizeof(buf_in), i->ip_ingress_bytes),
4280 format_bytes(buf_out, sizeof(buf_out), i->ip_egress_bytes));
4281 }
4282
03a7b521
LP
4283 if (i->tasks_current != (uint64_t) -1) {
4284 printf(" Tasks: %" PRIu64, i->tasks_current);
4285
4286 if (i->tasks_max != (uint64_t) -1)
2a6736dd 4287 printf(" (limit: %" PRIu64 ")\n", i->tasks_max);
03a7b521
LP
4288 else
4289 printf("\n");
4290 }
4291
934277fe
LP
4292 if (i->memory_current != (uint64_t) -1) {
4293 char buf[FORMAT_BYTES_MAX];
4294
4295 printf(" Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current));
4296
96e131ea
WC
4297 if (i->memory_low > 0 || i->memory_high != CGROUP_LIMIT_MAX ||
4298 i->memory_max != CGROUP_LIMIT_MAX || i->memory_swap_max != CGROUP_LIMIT_MAX ||
da4d897e
TH
4299 i->memory_limit != CGROUP_LIMIT_MAX) {
4300 const char *prefix = "";
4301
4302 printf(" (");
4303 if (i->memory_low > 0) {
4304 printf("%slow: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_low));
4305 prefix = " ";
4306 }
4307 if (i->memory_high != CGROUP_LIMIT_MAX) {
4308 printf("%shigh: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_high));
4309 prefix = " ";
4310 }
4311 if (i->memory_max != CGROUP_LIMIT_MAX) {
4312 printf("%smax: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_max));
4313 prefix = " ";
4314 }
96e131ea
WC
4315 if (i->memory_swap_max != CGROUP_LIMIT_MAX) {
4316 printf("%sswap max: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_swap_max));
4317 prefix = " ";
4318 }
da4d897e
TH
4319 if (i->memory_limit != CGROUP_LIMIT_MAX) {
4320 printf("%slimit: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_limit));
4321 prefix = " ";
4322 }
4323 printf(")");
4324 }
4325 printf("\n");
934277fe
LP
4326 }
4327
5ad096b3
LP
4328 if (i->cpu_usage_nsec != (uint64_t) -1) {
4329 char buf[FORMAT_TIMESPAN_MAX];
4330 printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
4331 }
4332
51e22f88 4333 if (i->control_group) {
291d565a
LP
4334 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4335 static const char prefix[] = " ";
ab35fb1b
LP
4336 unsigned c;
4337
51e22f88
LP
4338 printf(" CGroup: %s\n", i->control_group);
4339
291d565a
LP
4340 c = columns();
4341 if (c > sizeof(prefix) - 1)
4342 c -= sizeof(prefix) - 1;
4343 else
4344 c = 0;
ab35fb1b 4345
291d565a
LP
4346 r = unit_show_processes(bus, i->id, i->control_group, prefix, c, get_output_flags(), &error);
4347 if (r == -EBADR) {
b69d29ce
LP
4348 unsigned k = 0;
4349 pid_t extra[2];
4350
291d565a 4351 /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
ab35fb1b 4352
b69d29ce
LP
4353 if (i->main_pid > 0)
4354 extra[k++] = i->main_pid;
4355
4356 if (i->control_pid > 0)
4357 extra[k++] = i->control_pid;
4358
0ff308c8 4359 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, extra, k, get_output_flags());
291d565a
LP
4360 } else if (r < 0)
4361 log_warning_errno(r, "Failed to dump process list, ignoring: %s", bus_error_message(&error, r));
c59760ee 4362 }
45fb0699 4363
ece174c5 4364 if (i->id && arg_transport == BUS_TRANSPORT_LOCAL)
3c756001
LP
4365 show_journal_by_unit(
4366 stdout,
4367 i->id,
4368 arg_output,
4369 0,
4370 i->inactive_exit_timestamp_monotonic,
4371 arg_lines,
4372 getuid(),
4373 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
4374 SD_JOURNAL_LOCAL_ONLY,
4375 arg_scope == UNIT_FILE_SYSTEM,
4376 ellipsized);
86aa7ba4 4377
45fb0699 4378 if (i->need_daemon_reload)
3f36991e 4379 warn_unit_file_changed(i->id);
61cbdc4b
LP
4380}
4381
b43f208f 4382static void show_unit_help(UnitStatusInfo *i) {
256425cc
LP
4383 char **p;
4384
4385 assert(i);
4386
4387 if (!i->documentation) {
4388 log_info("Documentation for %s not known.", i->id);
4389 return;
4390 }
4391
78002a67
ZJS
4392 STRV_FOREACH(p, i->documentation)
4393 if (startswith(*p, "man:"))
4394 show_man_page(*p + 4, false);
4395 else
0315fe37 4396 log_info("Can't show: %s", *p);
256425cc
LP
4397}
4398
f459b602
MAP
4399static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *i, const char *contents) {
4400 int r;
61cbdc4b 4401
a4c279f8 4402 assert(name);
f459b602 4403 assert(m);
a4c279f8
LP
4404 assert(i);
4405
f459b602 4406 switch (contents[0]) {
61cbdc4b 4407
f459b602 4408 case SD_BUS_TYPE_STRING: {
61cbdc4b
LP
4409 const char *s;
4410
f459b602
MAP
4411 r = sd_bus_message_read(m, "s", &s);
4412 if (r < 0)
4413 return bus_log_parse_error(r);
61cbdc4b 4414
37a0d5bf 4415 if (!isempty(s)) {
61cbdc4b
LP
4416 if (streq(name, "Id"))
4417 i->id = s;
4418 else if (streq(name, "LoadState"))
4419 i->load_state = s;
4420 else if (streq(name, "ActiveState"))
4421 i->active_state = s;
4422 else if (streq(name, "SubState"))
4423 i->sub_state = s;
4424 else if (streq(name, "Description"))
4425 i->description = s;
4426 else if (streq(name, "FragmentPath"))
1b64d026
LP
4427 i->fragment_path = s;
4428 else if (streq(name, "SourcePath"))
4429 i->source_path = s;
286ca485 4430#ifndef NOLEGACY
a00963a2
LP
4431 else if (streq(name, "DefaultControlGroup")) {
4432 const char *e;
4433 e = startswith(s, SYSTEMD_CGROUP_CONTROLLER ":");
4434 if (e)
4435 i->control_group = e;
4436 }
4ad49000 4437#endif
37a0d5bf
LP
4438 else if (streq(name, "ControlGroup"))
4439 i->control_group = s;
61cbdc4b
LP
4440 else if (streq(name, "StatusText"))
4441 i->status_text = s;
175728c4
HH
4442 else if (streq(name, "PIDFile"))
4443 i->pid_file = s;
61cbdc4b
LP
4444 else if (streq(name, "SysFSPath"))
4445 i->sysfs_path = s;
4446 else if (streq(name, "Where"))
4447 i->where = s;
4448 else if (streq(name, "What"))
4449 i->what = s;
4a9e2fff
LP
4450 else if (streq(name, "Following"))
4451 i->following = s;
a4375746
LP
4452 else if (streq(name, "UnitFileState"))
4453 i->unit_file_state = s;
d2dc52db
LP
4454 else if (streq(name, "UnitFilePreset"))
4455 i->unit_file_preset = s;
f42806df
LP
4456 else if (streq(name, "Result"))
4457 i->result = s;
61cbdc4b
LP
4458 }
4459
4460 break;
4461 }
4462
f459b602
MAP
4463 case SD_BUS_TYPE_BOOLEAN: {
4464 int b;
b8131a87 4465
f459b602
MAP
4466 r = sd_bus_message_read(m, "b", &b);
4467 if (r < 0)
4468 return bus_log_parse_error(r);
b8131a87
LP
4469
4470 if (streq(name, "Accept"))
4471 i->accept = b;
45fb0699
LP
4472 else if (streq(name, "NeedDaemonReload"))
4473 i->need_daemon_reload = b;
90bbc946
LP
4474 else if (streq(name, "ConditionResult"))
4475 i->condition_result = b;
59fccdc5
LP
4476 else if (streq(name, "AssertResult"))
4477 i->assert_result = b;
055ef36b
LP
4478 else if (streq(name, "Transient"))
4479 i->transient = b;
b8131a87
LP
4480
4481 break;
4482 }
4483
f459b602 4484 case SD_BUS_TYPE_UINT32: {
61cbdc4b
LP
4485 uint32_t u;
4486
f459b602
MAP
4487 r = sd_bus_message_read(m, "u", &u);
4488 if (r < 0)
4489 return bus_log_parse_error(r);
61cbdc4b
LP
4490
4491 if (streq(name, "MainPID")) {
4492 if (u > 0) {
4493 i->main_pid = (pid_t) u;
4494 i->running = true;
4495 }
4496 } else if (streq(name, "ControlPID"))
4497 i->control_pid = (pid_t) u;
4498 else if (streq(name, "ExecMainPID")) {
4499 if (u > 0)
4500 i->main_pid = (pid_t) u;
4501 } else if (streq(name, "NAccepted"))
4502 i->n_accepted = u;
4503 else if (streq(name, "NConnections"))
4504 i->n_connections = u;
4505
4506 break;
4507 }
4508
f459b602 4509 case SD_BUS_TYPE_INT32: {
61cbdc4b
LP
4510 int32_t j;
4511
f459b602
MAP
4512 r = sd_bus_message_read(m, "i", &j);
4513 if (r < 0)
4514 return bus_log_parse_error(r);
61cbdc4b
LP
4515
4516 if (streq(name, "ExecMainCode"))
4517 i->exit_code = (int) j;
4518 else if (streq(name, "ExecMainStatus"))
4519 i->exit_status = (int) j;
b4af5a80
LP
4520 else if (streq(name, "StatusErrno"))
4521 i->status_errno = (int) j;
61cbdc4b
LP
4522
4523 break;
4524 }
4525
f459b602 4526 case SD_BUS_TYPE_UINT64: {
61cbdc4b
LP
4527 uint64_t u;
4528
f459b602
MAP
4529 r = sd_bus_message_read(m, "t", &u);
4530 if (r < 0)
4531 return bus_log_parse_error(r);
61cbdc4b
LP
4532
4533 if (streq(name, "ExecMainStartTimestamp"))
4534 i->start_timestamp = (usec_t) u;
4535 else if (streq(name, "ExecMainExitTimestamp"))
4536 i->exit_timestamp = (usec_t) u;
584be568
LP
4537 else if (streq(name, "ActiveEnterTimestamp"))
4538 i->active_enter_timestamp = (usec_t) u;
4539 else if (streq(name, "InactiveEnterTimestamp"))
4540 i->inactive_enter_timestamp = (usec_t) u;
4541 else if (streq(name, "InactiveExitTimestamp"))
4542 i->inactive_exit_timestamp = (usec_t) u;
df50185b
LP
4543 else if (streq(name, "InactiveExitTimestampMonotonic"))
4544 i->inactive_exit_timestamp_monotonic = (usec_t) u;
584be568
LP
4545 else if (streq(name, "ActiveExitTimestamp"))
4546 i->active_exit_timestamp = (usec_t) u;
90bbc946
LP
4547 else if (streq(name, "ConditionTimestamp"))
4548 i->condition_timestamp = (usec_t) u;
59fccdc5
LP
4549 else if (streq(name, "AssertTimestamp"))
4550 i->assert_timestamp = (usec_t) u;
934277fe
LP
4551 else if (streq(name, "MemoryCurrent"))
4552 i->memory_current = u;
da4d897e
TH
4553 else if (streq(name, "MemoryLow"))
4554 i->memory_low = u;
4555 else if (streq(name, "MemoryHigh"))
4556 i->memory_high = u;
4557 else if (streq(name, "MemoryMax"))
4558 i->memory_max = u;
96e131ea
WC
4559 else if (streq(name, "MemorySwapMax"))
4560 i->memory_swap_max = u;
934277fe
LP
4561 else if (streq(name, "MemoryLimit"))
4562 i->memory_limit = u;
03a7b521
LP
4563 else if (streq(name, "TasksCurrent"))
4564 i->tasks_current = u;
4565 else if (streq(name, "TasksMax"))
4566 i->tasks_max = u;
5ad096b3
LP
4567 else if (streq(name, "CPUUsageNSec"))
4568 i->cpu_usage_nsec = u;
601b0842
GS
4569 else if (streq(name, "NextElapseUSecMonotonic"))
4570 i->next_elapse_monotonic = u;
4571 else if (streq(name, "NextElapseUSecRealtime"))
4572 i->next_elapse_real = u;
0e97c93f
DM
4573 else if (streq(name, "IPIngressBytes"))
4574 i->ip_ingress_bytes = u;
4575 else if (streq(name, "IPEgressBytes"))
4576 i->ip_egress_bytes = u;
61cbdc4b
LP
4577
4578 break;
4579 }
582a507f 4580
f459b602 4581 case SD_BUS_TYPE_ARRAY:
582a507f 4582
f459b602
MAP
4583 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
4584 _cleanup_free_ ExecStatusInfo *info = NULL;
582a507f 4585
f459b602
MAP
4586 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
4587 if (r < 0)
4588 return bus_log_parse_error(r);
582a507f 4589
f459b602
MAP
4590 info = new0(ExecStatusInfo, 1);
4591 if (!info)
4592 return log_oom();
582a507f 4593
f459b602 4594 while ((r = exec_status_info_deserialize(m, info)) > 0) {
0129173a 4595
f459b602
MAP
4596 info->name = strdup(name);
4597 if (!info->name)
691395d8 4598 return log_oom();
582a507f 4599
71fda00f 4600 LIST_PREPEND(exec, i->exec, info);
582a507f 4601
f459b602
MAP
4602 info = new0(ExecStatusInfo, 1);
4603 if (!info)
691395d8 4604 return log_oom();
49dbfa7b 4605 }
67419600 4606
f459b602
MAP
4607 if (r < 0)
4608 return bus_log_parse_error(r);
67419600 4609
f459b602
MAP
4610 r = sd_bus_message_exit_container(m);
4611 if (r < 0)
4612 return bus_log_parse_error(r);
67419600 4613
f459b602 4614 return 0;
67419600 4615
f459b602
MAP
4616 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
4617 const char *type, *path;
13160134 4618
f459b602
MAP
4619 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4620 if (r < 0)
4621 return bus_log_parse_error(r);
67419600 4622
f459b602 4623 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0) {
67419600 4624
f459b602
MAP
4625 r = strv_extend(&i->listen, type);
4626 if (r < 0)
4627 return r;
67419600 4628
f459b602
MAP
4629 r = strv_extend(&i->listen, path);
4630 if (r < 0)
4631 return r;
4632 }
76d14b87 4633 if (r < 0)
f459b602 4634 return bus_log_parse_error(r);
76d14b87 4635
f459b602
MAP
4636 r = sd_bus_message_exit_container(m);
4637 if (r < 0)
4638 return bus_log_parse_error(r);
49dbfa7b 4639
f459b602 4640 return 0;
49dbfa7b 4641
f459b602 4642 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "DropInPaths")) {
49dbfa7b 4643
f459b602
MAP
4644 r = sd_bus_message_read_strv(m, &i->dropin_paths);
4645 if (r < 0)
4646 return bus_log_parse_error(r);
49dbfa7b 4647
f459b602 4648 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "Documentation")) {
49dbfa7b 4649
f459b602
MAP
4650 r = sd_bus_message_read_strv(m, &i->documentation);
4651 if (r < 0)
4652 return bus_log_parse_error(r);
52990c2e 4653
f459b602
MAP
4654 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Conditions")) {
4655 const char *cond, *param;
4656 int trigger, negate;
4657 int32_t state;
52990c2e 4658
f459b602
MAP
4659 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
4660 if (r < 0)
4661 return bus_log_parse_error(r);
4662
4663 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
9bb71940 4664 _cleanup_(unit_condition_freep) UnitCondition *c = NULL;
d5db7fe6 4665
b1ed76ae 4666 log_debug("%s trigger=%d negate=%d %s →%d", cond, trigger, negate, param, state);
d5db7fe6
WC
4667
4668 c = new0(UnitCondition, 1);
4669 if (!c)
4670 return log_oom();
4671
4672 c->name = strdup(cond);
d5db7fe6 4673 c->param = strdup(param);
9bb71940 4674 if (!c->name || !c->param)
d5db7fe6 4675 return log_oom();
d5db7fe6
WC
4676
4677 c->trigger = trigger;
4678 c->negate = negate;
4679 c->tristate = state;
4680
b1ed76ae 4681 LIST_PREPEND(conditions, i->conditions, c);
9bb71940 4682 c = NULL;
59fccdc5
LP
4683 }
4684 if (r < 0)
4685 return bus_log_parse_error(r);
4686
4687 r = sd_bus_message_exit_container(m);
4688 if (r < 0)
4689 return bus_log_parse_error(r);
4690
4691 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Asserts")) {
4692 const char *cond, *param;
4693 int trigger, negate;
4694 int32_t state;
4695
4696 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
4697 if (r < 0)
4698 return bus_log_parse_error(r);
4699
4700 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
4701 log_debug("%s %d %d %s %d", cond, trigger, negate, param, state);
4702 if (state < 0 && (!trigger || !i->failed_assert)) {
4703 i->failed_assert = cond;
4704 i->failed_assert_trigger = trigger;
4705 i->failed_assert_negate = negate;
4706 i->failed_assert_parameter = param;
f459b602 4707 }
582a507f 4708 }
f459b602
MAP
4709 if (r < 0)
4710 return bus_log_parse_error(r);
4711
4712 r = sd_bus_message_exit_container(m);
4713 if (r < 0)
4714 return bus_log_parse_error(r);
4715
4716 } else
4717 goto skip;
582a507f
LP
4718
4719 break;
9f39404c 4720
f459b602 4721 case SD_BUS_TYPE_STRUCT_BEGIN:
9f39404c
LP
4722
4723 if (streq(name, "LoadError")) {
9f39404c 4724 const char *n, *message;
9f39404c 4725
f459b602 4726 r = sd_bus_message_read(m, "(ss)", &n, &message);
9f39404c 4727 if (r < 0)
f459b602 4728 return bus_log_parse_error(r);
9f39404c
LP
4729
4730 if (!isempty(message))
4731 i->load_error = message;
f459b602
MAP
4732 } else
4733 goto skip;
9f39404c
LP
4734
4735 break;
f459b602
MAP
4736
4737 default:
4738 goto skip;
9f39404c 4739 }
f459b602
MAP
4740
4741 return 0;
4742
4743skip:
4744 r = sd_bus_message_skip(m, contents);
4745 if (r < 0)
4746 return bus_log_parse_error(r);
61cbdc4b
LP
4747
4748 return 0;
4749}
4750
4f9a9105
ZJS
4751#define print_prop(name, fmt, ...) \
4752 do { \
4753 if (arg_value) \
4754 printf(fmt "\n", __VA_ARGS__); \
4755 else \
4756 printf("%s=" fmt "\n", name, __VA_ARGS__); \
508f63b4 4757 } while (0)
4f9a9105 4758
f459b602
MAP
4759static int print_property(const char *name, sd_bus_message *m, const char *contents) {
4760 int r;
4761
48220598 4762 assert(name);
f459b602 4763 assert(m);
48220598 4764
61cbdc4b
LP
4765 /* This is a low-level property printer, see
4766 * print_status_info() for the nicer output */
4767
852c1b4d
ZJS
4768 if (arg_properties && !strv_find(arg_properties, name)) {
4769 /* skip what we didn't read */
4770 r = sd_bus_message_skip(m, contents);
4771 return r;
4772 }
48220598 4773
f459b602 4774 switch (contents[0]) {
48220598 4775
f459b602 4776 case SD_BUS_TYPE_STRUCT_BEGIN:
48220598 4777
f459b602 4778 if (contents[1] == SD_BUS_TYPE_UINT32 && streq(name, "Job")) {
48220598
LP
4779 uint32_t u;
4780
f459b602
MAP
4781 r = sd_bus_message_read(m, "(uo)", &u, NULL);
4782 if (r < 0)
4783 return bus_log_parse_error(r);
48220598 4784
f459b602 4785 if (u > 0)
4f9a9105 4786 print_prop(name, "%"PRIu32, u);
48220598 4787 else if (arg_all)
4f9a9105 4788 print_prop(name, "%s", "");
48220598
LP
4789
4790 return 0;
f459b602
MAP
4791
4792 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "Unit")) {
48220598
LP
4793 const char *s;
4794
f459b602
MAP
4795 r = sd_bus_message_read(m, "(so)", &s, NULL);
4796 if (r < 0)
4797 return bus_log_parse_error(r);
48220598 4798
f459b602 4799 if (arg_all || !isempty(s))
4f9a9105 4800 print_prop(name, "%s", s);
48220598
LP
4801
4802 return 0;
f459b602
MAP
4803
4804 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "LoadError")) {
9f39404c
LP
4805 const char *a = NULL, *b = NULL;
4806
f459b602
MAP
4807 r = sd_bus_message_read(m, "(ss)", &a, &b);
4808 if (r < 0)
4809 return bus_log_parse_error(r);
9f39404c
LP
4810
4811 if (arg_all || !isempty(a) || !isempty(b))
4f9a9105 4812 print_prop(name, "%s \"%s\"", strempty(a), strempty(b));
f786e80d 4813
57183d11
LP
4814 return 0;
4815 } else if (streq_ptr(name, "SystemCallFilter")) {
4816 _cleanup_strv_free_ char **l = NULL;
4817 int whitelist;
4818
4819 r = sd_bus_message_enter_container(m, 'r', "bas");
4820 if (r < 0)
4821 return bus_log_parse_error(r);
4822
4823 r = sd_bus_message_read(m, "b", &whitelist);
4824 if (r < 0)
4825 return bus_log_parse_error(r);
4826
4827 r = sd_bus_message_read_strv(m, &l);
4828 if (r < 0)
4829 return bus_log_parse_error(r);
4830
4831 r = sd_bus_message_exit_container(m);
4832 if (r < 0)
4833 return bus_log_parse_error(r);
4834
4835 if (arg_all || whitelist || !strv_isempty(l)) {
4836 bool first = true;
4837 char **i;
4838
4f9a9105
ZJS
4839 if (!arg_value) {
4840 fputs(name, stdout);
4841 fputc('=', stdout);
4842 }
57183d11
LP
4843
4844 if (!whitelist)
4845 fputc('~', stdout);
4846
4847 STRV_FOREACH(i, l) {
4848 if (first)
4849 first = false;
4850 else
4851 fputc(' ', stdout);
4852
4853 fputs(*i, stdout);
4854 }
4855 fputc('\n', stdout);
4856 }
4857
f786e80d 4858 return 0;
48220598
LP
4859 }
4860
4861 break;
48220598 4862
f459b602 4863 case SD_BUS_TYPE_ARRAY:
48220598 4864
f459b602
MAP
4865 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "EnvironmentFiles")) {
4866 const char *path;
4867 int ignore;
8c7be95e 4868
f459b602
MAP
4869 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sb)");
4870 if (r < 0)
4871 return bus_log_parse_error(r);
8c7be95e 4872
f459b602 4873 while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
009192bb 4874 print_prop(name, "%s (ignore_errors=%s)", path, yes_no(ignore));
8c7be95e 4875
f459b602
MAP
4876 if (r < 0)
4877 return bus_log_parse_error(r);
8c7be95e 4878
f459b602
MAP
4879 r = sd_bus_message_exit_container(m);
4880 if (r < 0)
4881 return bus_log_parse_error(r);
8c7be95e
LP
4882
4883 return 0;
4884
f459b602
MAP
4885 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Paths")) {
4886 const char *type, *path;
67419600 4887
f459b602
MAP
4888 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4889 if (r < 0)
4890 return bus_log_parse_error(r);
ebf57b80 4891
f459b602 4892 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
c7366cf1 4893 print_prop(name, "%s (%s)", path, type);
f459b602
MAP
4894 if (r < 0)
4895 return bus_log_parse_error(r);
ebf57b80 4896
f459b602
MAP
4897 r = sd_bus_message_exit_container(m);
4898 if (r < 0)
4899 return bus_log_parse_error(r);
ebf57b80 4900
707e5e52 4901 return 0;
582a507f 4902
f459b602
MAP
4903 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
4904 const char *type, *path;
67419600 4905
f459b602
MAP
4906 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4907 if (r < 0)
4908 return bus_log_parse_error(r);
67419600 4909
f459b602 4910 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
eabc13c7 4911 print_prop(name, "%s (%s)", path, type);
f459b602
MAP
4912 if (r < 0)
4913 return bus_log_parse_error(r);
67419600 4914
f459b602
MAP
4915 r = sd_bus_message_exit_container(m);
4916 if (r < 0)
4917 return bus_log_parse_error(r);
67419600
OS
4918
4919 return 0;
4920
fa6dee52 4921 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "TimersMonotonic")) {
f459b602
MAP
4922 const char *base;
4923 uint64_t value, next_elapse;
707e5e52 4924
f459b602
MAP
4925 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(stt)");
4926 if (r < 0)
4927 return bus_log_parse_error(r);
552e4331 4928
f459b602
MAP
4929 while ((r = sd_bus_message_read(m, "(stt)", &base, &value, &next_elapse)) > 0) {
4930 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
fe68089d 4931
fa6dee52 4932 print_prop(name, "{ %s=%s ; next_elapse=%s }", base,
4f9a9105
ZJS
4933 format_timespan(timespan1, sizeof(timespan1), value, 0),
4934 format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
fe68089d 4935 }
f459b602
MAP
4936 if (r < 0)
4937 return bus_log_parse_error(r);
4938
4939 r = sd_bus_message_exit_container(m);
4940 if (r < 0)
4941 return bus_log_parse_error(r);
fe68089d
LP
4942
4943 return 0;
fe68089d 4944
fa6dee52
YW
4945 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "TimersCalendar")) {
4946 const char *base, *spec;
4947 uint64_t next_elapse;
4948
4949 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sst)");
4950 if (r < 0)
4951 return bus_log_parse_error(r);
4952
4953 while ((r = sd_bus_message_read(m, "(sst)", &base, &spec, &next_elapse)) > 0) {
4954 char timestamp[FORMAT_TIMESTAMP_MAX];
4955
4956 print_prop(name, "{ %s=%s ; next_elapse=%s }", base, spec,
4957 format_timestamp(timestamp, sizeof(timestamp), next_elapse));
4958 }
4959 if (r < 0)
4960 return bus_log_parse_error(r);
4961
4962 r = sd_bus_message_exit_container(m);
4963 if (r < 0)
4964 return bus_log_parse_error(r);
4965
4966 return 0;
4967
f459b602
MAP
4968 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
4969 ExecStatusInfo info = {};
4970
4971 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
4972 if (r < 0)
4973 return bus_log_parse_error(r);
4974
4975 while ((r = exec_status_info_deserialize(m, &info)) > 0) {
4976 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
4977 _cleanup_free_ char *tt;
4978
4979 tt = strv_join(info.argv, " ");
4980
4f9a9105
ZJS
4981 print_prop(name,
4982 "{ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
4983 strna(info.path),
4984 strna(tt),
4985 yes_no(info.ignore),
4986 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
4987 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
4988 info.pid,
4989 sigchld_code_to_string(info.code),
4990 info.status,
4991 info.code == CLD_EXITED ? "" : "/",
4992 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
fe68089d 4993
582a507f
LP
4994 free(info.path);
4995 strv_free(info.argv);
f459b602 4996 zero(info);
707e5e52
LP
4997 }
4998
f459b602
MAP
4999 r = sd_bus_message_exit_container(m);
5000 if (r < 0)
5001 return bus_log_parse_error(r);
5002
48220598 5003 return 0;
4ad49000 5004
f459b602
MAP
5005 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "DeviceAllow")) {
5006 const char *path, *rwm;
4ad49000 5007
f459b602
MAP
5008 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
5009 if (r < 0)
5010 return bus_log_parse_error(r);
4ad49000 5011
f459b602 5012 while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0)
4f9a9105 5013 print_prop(name, "%s %s", strna(path), strna(rwm));
f459b602
MAP
5014 if (r < 0)
5015 return bus_log_parse_error(r);
4ad49000 5016
f459b602
MAP
5017 r = sd_bus_message_exit_container(m);
5018 if (r < 0)
5019 return bus_log_parse_error(r);
4ad49000 5020
4ad49000
LP
5021 return 0;
5022
72240b52
ZJS
5023 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN &&
5024 STR_IN_SET(name, "IODeviceWeight", "BlockIODeviceWeight")) {
f459b602
MAP
5025 const char *path;
5026 uint64_t weight;
b8ab2dc6 5027
f459b602
MAP
5028 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
5029 if (r < 0)
5030 return bus_log_parse_error(r);
b8ab2dc6 5031
f459b602 5032 while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0)
4f9a9105 5033 print_prop(name, "%s %"PRIu64, strna(path), weight);
f459b602
MAP
5034 if (r < 0)
5035 return bus_log_parse_error(r);
b8ab2dc6 5036
f459b602
MAP
5037 r = sd_bus_message_exit_container(m);
5038 if (r < 0)
5039 return bus_log_parse_error(r);
b8ab2dc6 5040
b8ab2dc6
G
5041 return 0;
5042
72240b52
ZJS
5043 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN &&
5044 (cgroup_io_limit_type_from_string(name) >= 0 ||
5045 STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth"))) {
f459b602
MAP
5046 const char *path;
5047 uint64_t bandwidth;
4ad49000 5048
f459b602
MAP
5049 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
5050 if (r < 0)
5051 return bus_log_parse_error(r);
4ad49000 5052
f459b602 5053 while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0)
4f9a9105 5054 print_prop(name, "%s %"PRIu64, strna(path), bandwidth);
f459b602
MAP
5055 if (r < 0)
5056 return bus_log_parse_error(r);
4ad49000 5057
f459b602
MAP
5058 r = sd_bus_message_exit_container(m);
5059 if (r < 0)
5060 return bus_log_parse_error(r);
4ad49000 5061
4ad49000 5062 return 0;
08f3be7a
LP
5063
5064 } else if (contents[1] == SD_BUS_TYPE_BYTE && streq(name, "StandardInputData")) {
5065 _cleanup_free_ char *h = NULL;
5066 const void *p;
5067 size_t sz;
5068 ssize_t n;
5069
5070 r = sd_bus_message_read_array(m, 'y', &p, &sz);
5071 if (r < 0)
5072 return bus_log_parse_error(r);
5073
5074 n = base64mem(p, sz, &h);
5075 if (n < 0)
5076 return log_oom();
5077
5078 print_prop(name, "%s", h);
5079
5080 return 0;
48220598
LP
5081 }
5082
5083 break;
5084 }
5085
4f9a9105 5086 r = bus_print_property(name, m, arg_value, arg_all);
f459b602
MAP
5087 if (r < 0)
5088 return bus_log_parse_error(r);
5089
5090 if (r == 0) {
5091 r = sd_bus_message_skip(m, contents);
5092 if (r < 0)
5093 return bus_log_parse_error(r);
a4c279f8 5094
f459b602
MAP
5095 if (arg_all)
5096 printf("%s=[unprintable]\n", name);
5097 }
48220598
LP
5098
5099 return 0;
5100}
5101
f459b602
MAP
5102static int show_one(
5103 const char *verb,
5104 sd_bus *bus,
5105 const char *path,
3dced37b 5106 const char *unit,
f459b602
MAP
5107 bool show_properties,
5108 bool *new_line,
5109 bool *ellipsized) {
5110
3dced37b 5111 static const struct bus_properties_map property_map[] = {
662bea67
ZJS
5112 { "LoadState", "s", map_string_no_copy, offsetof(UnitStatusInfo, load_state) },
5113 { "ActiveState", "s", map_string_no_copy, offsetof(UnitStatusInfo, active_state) },
3dced37b
LP
5114 {}
5115 };
5116
4afd3348
LP
5117 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
5118 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
3dced37b 5119 _cleanup_set_free_ Set *found_properties = NULL;
a7335518 5120 _cleanup_(unit_status_info_free) UnitStatusInfo info = {
934277fe 5121 .memory_current = (uint64_t) -1,
da4d897e
TH
5122 .memory_high = CGROUP_LIMIT_MAX,
5123 .memory_max = CGROUP_LIMIT_MAX,
96e131ea 5124 .memory_swap_max = CGROUP_LIMIT_MAX,
934277fe 5125 .memory_limit = (uint64_t) -1,
5ad096b3 5126 .cpu_usage_nsec = (uint64_t) -1,
03a7b521
LP
5127 .tasks_current = (uint64_t) -1,
5128 .tasks_max = (uint64_t) -1,
0e97c93f
DM
5129 .ip_ingress_bytes = (uint64_t) -1,
5130 .ip_egress_bytes = (uint64_t) -1,
934277fe 5131 };
f459b602 5132 int r;
48220598 5133
48220598 5134 assert(path);
61cbdc4b 5135 assert(new_line);
48220598 5136
e3e0314b
ZJS
5137 log_debug("Showing one %s", path);
5138
f459b602 5139 r = sd_bus_call_method(
f22f08cd
SP
5140 bus,
5141 "org.freedesktop.systemd1",
5142 path,
5143 "org.freedesktop.DBus.Properties",
5144 "GetAll",
f459b602 5145 &error,
f22f08cd 5146 &reply,
f459b602 5147 "s", "");
4c3e8e39
LP
5148 if (r < 0)
5149 return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
48220598 5150
3dced37b 5151 if (unit) {
f9e0eefc 5152 r = bus_message_map_all_properties(reply, property_map, &error, &info);
3dced37b
LP
5153 if (r < 0)
5154 return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r));
e33a06a1 5155
3dced37b 5156 if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) {
bd5b9f0a
ZJS
5157 log_full(streq(verb, "status") ? LOG_ERR : LOG_DEBUG,
5158 "Unit %s could not be found.", unit);
e33a06a1 5159
3dced37b
LP
5160 if (streq(verb, "status"))
5161 return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN;
5162
bd5b9f0a
ZJS
5163 if (!streq(verb, "show"))
5164 return -ENOENT;
3dced37b
LP
5165 }
5166
5167 r = sd_bus_message_rewind(reply, true);
5168 if (r < 0)
5169 return log_error_errno(r, "Failed to rewind: %s", bus_error_message(&error, r));
5170 }
e33a06a1 5171
f459b602
MAP
5172 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
5173 if (r < 0)
5174 return bus_log_parse_error(r);
48220598 5175
61cbdc4b
LP
5176 if (*new_line)
5177 printf("\n");
5178
5179 *new_line = true;
5180
f459b602
MAP
5181 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
5182 const char *name, *contents;
0183528f 5183
f459b602
MAP
5184 r = sd_bus_message_read(reply, "s", &name);
5185 if (r < 0)
5186 return bus_log_parse_error(r);
48220598 5187
f459b602
MAP
5188 r = sd_bus_message_peek_type(reply, NULL, &contents);
5189 if (r < 0)
5190 return bus_log_parse_error(r);
5191
5192 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
5193 if (r < 0)
5194 return bus_log_parse_error(r);
48220598 5195
3dced37b
LP
5196 if (show_properties) {
5197 r = set_ensure_allocated(&found_properties, &string_hash_ops);
5198 if (r < 0)
5199 return log_oom();
5200
5201 r = set_put(found_properties, name);
5202 if (r < 0 && r != EEXIST)
5203 return log_oom();
5204
f459b602 5205 r = print_property(name, reply, contents);
3dced37b 5206 } else
f459b602
MAP
5207 r = status_property(name, reply, &info, contents);
5208 if (r < 0)
5209 return r;
48220598 5210
f459b602
MAP
5211 r = sd_bus_message_exit_container(reply);
5212 if (r < 0)
5213 return bus_log_parse_error(r);
5214
5215 r = sd_bus_message_exit_container(reply);
5216 if (r < 0)
5217 return bus_log_parse_error(r);
48220598 5218 }
f459b602
MAP
5219 if (r < 0)
5220 return bus_log_parse_error(r);
5221
5222 r = sd_bus_message_exit_container(reply);
5223 if (r < 0)
5224 return bus_log_parse_error(r);
48220598 5225
f1e36d67 5226 r = 0;
3dced37b
LP
5227 if (show_properties) {
5228 char **pp;
5229
a7335518 5230 STRV_FOREACH(pp, arg_properties)
f1669917
FB
5231 if (!set_contains(found_properties, *pp))
5232 log_debug("Property %s does not exist.", *pp);
a7335518 5233
3dced37b
LP
5234 } else if (streq(verb, "help"))
5235 show_unit_help(&info);
5236 else if (streq(verb, "status")) {
5237 print_status_info(bus, &info, ellipsized);
5238
7f5da8bd 5239 if (info.active_state && !STR_IN_SET(info.active_state, "active", "reloading"))
3dced37b 5240 r = EXIT_PROGRAM_NOT_RUNNING;
256425cc 5241 else
3dced37b 5242 r = EXIT_PROGRAM_RUNNING_OR_SERVICE_OK;
256425cc 5243 }
f1e36d67 5244
48220598
LP
5245 return r;
5246}
5247
f74294c1 5248static int get_unit_dbus_path_by_pid(
f459b602
MAP
5249 sd_bus *bus,
5250 uint32_t pid,
f74294c1 5251 char **unit) {
f459b602 5252
4afd3348
LP
5253 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5254 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
373d32c9 5255 char *u;
a223b325
MS
5256 int r;
5257
f459b602 5258 r = sd_bus_call_method(
f22f08cd
SP
5259 bus,
5260 "org.freedesktop.systemd1",
5261 "/org/freedesktop/systemd1",
5262 "org.freedesktop.systemd1.Manager",
5263 "GetUnitByPID",
f459b602 5264 &error,
f22f08cd 5265 &reply,
f459b602 5266 "u", pid);
691395d8
LP
5267 if (r < 0)
5268 return log_error_errno(r, "Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
a223b325 5269
373d32c9 5270 r = sd_bus_message_read(reply, "o", &u);
f459b602
MAP
5271 if (r < 0)
5272 return bus_log_parse_error(r);
5273
373d32c9
LP
5274 u = strdup(u);
5275 if (!u)
5276 return log_oom();
5277
5278 *unit = u;
f74294c1 5279 return 0;
a223b325
MS
5280}
5281
f459b602
MAP
5282static int show_all(
5283 const char* verb,
5284 sd_bus *bus,
5285 bool show_properties,
5286 bool *new_line,
5287 bool *ellipsized) {
5288
4afd3348 5289 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
f459b602
MAP
5290 _cleanup_free_ UnitInfo *unit_infos = NULL;
5291 const UnitInfo *u;
5292 unsigned c;
5bb75bc7 5293 int r, ret = 0;
265a7a2a 5294
1238ee09 5295 r = get_unit_list(bus, NULL, NULL, &unit_infos, 0, &reply);
265a7a2a
ZJS
5296 if (r < 0)
5297 return r;
5298
ea4b98e6 5299 pager_open(arg_no_pager, false);
dbed408b 5300
f459b602
MAP
5301 c = (unsigned) r;
5302
5303 qsort_safe(unit_infos, c, sizeof(UnitInfo), compare_unit_info);
991f2a39 5304
265a7a2a 5305 for (u = unit_infos; u < unit_infos + c; u++) {
7fd1b19b 5306 _cleanup_free_ char *p = NULL;
265a7a2a 5307
265a7a2a
ZJS
5308 p = unit_dbus_path_from_name(u->id);
5309 if (!p)
5310 return log_oom();
5311
3dced37b 5312 r = show_one(verb, bus, p, u->id, show_properties, new_line, ellipsized);
3df538da 5313 if (r < 0)
265a7a2a 5314 return r;
5bb75bc7
ZJS
5315 else if (r > 0 && ret == 0)
5316 ret = r;
265a7a2a
ZJS
5317 }
5318
5bb75bc7 5319 return ret;
265a7a2a
ZJS
5320}
5321
8fcf784d
LP
5322static int show_system_status(sd_bus *bus) {
5323 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
f9e0eefc 5324 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
e7e55dbd 5325 _cleanup_(machine_info_clear) struct machine_info mi = {};
f9e0eefc 5326 _cleanup_free_ char *hn = NULL;
8fcf784d
LP
5327 const char *on, *off;
5328 int r;
5329
5330 hn = gethostname_malloc();
5331 if (!hn)
5332 return log_oom();
5333
f9e0eefc 5334 r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, &error, &mi);
f647962d 5335 if (r < 0)
f9e0eefc 5336 return log_error_errno(r, "Failed to read server status: %s", bus_error_message(&error, r));
8fcf784d 5337
8fcf784d
LP
5338 if (streq_ptr(mi.state, "degraded")) {
5339 on = ansi_highlight_red();
1fc464f6 5340 off = ansi_normal();
92f34a9c
JR
5341 } else if (streq_ptr(mi.state, "running")) {
5342 on = ansi_highlight_green();
5343 off = ansi_normal();
5344 } else {
8fcf784d 5345 on = ansi_highlight_yellow();
1fc464f6 5346 off = ansi_normal();
92f34a9c 5347 }
8fcf784d 5348
323b7dc9 5349 printf("%s%s%s %s\n", on, special_glyph(BLACK_CIRCLE), off, arg_host ? arg_host : hn);
b0d14c69 5350
8fcf784d
LP
5351 printf(" State: %s%s%s\n",
5352 on, strna(mi.state), off);
5353
c6ba5b80
MP
5354 printf(" Jobs: %" PRIu32 " queued\n", mi.n_jobs);
5355 printf(" Failed: %" PRIu32 " units\n", mi.n_failed_units);
8fcf784d
LP
5356
5357 printf(" Since: %s; %s\n",
5358 format_timestamp(since2, sizeof(since2), mi.timestamp),
5359 format_timestamp_relative(since1, sizeof(since1), mi.timestamp));
5360
5361 printf(" CGroup: %s\n", mi.control_group ?: "/");
4c315c2c
IS
5362 if (IN_SET(arg_transport,
5363 BUS_TRANSPORT_LOCAL,
5364 BUS_TRANSPORT_MACHINE)) {
8fcf784d
LP
5365 static const char prefix[] = " ";
5366 unsigned c;
5367
5368 c = columns();
5369 if (c > sizeof(prefix) - 1)
5370 c -= sizeof(prefix) - 1;
5371 else
5372 c = 0;
5373
0ff308c8 5374 show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, get_output_flags());
8fcf784d
LP
5375 }
5376
8fcf784d
LP
5377 return 0;
5378}
5379
e449de87
LP
5380static int show(int argc, char *argv[], void *userdata) {
5381 bool show_properties, show_status, show_help, new_line = false;
94e0bd7d 5382 bool ellipsized = false;
e3e0314b 5383 int r, ret = 0;
4fbd7192 5384 sd_bus *bus;
48220598 5385
e449de87 5386 assert(argv);
48220598 5387
e449de87
LP
5388 show_properties = streq(argv[0], "show");
5389 show_status = streq(argv[0], "status");
5390 show_help = streq(argv[0], "help");
5391
5392 if (show_help && argc <= 1) {
5393 log_error("This command expects one or more unit names. Did you mean --help?");
5394 return -EINVAL;
5395 }
61cbdc4b 5396
d2ad7e1b
ZJS
5397 r = acquire_bus(BUS_MANAGER, &bus);
5398 if (r < 0)
5399 return r;
5400
ea4b98e6 5401 pager_open(arg_no_pager, false);
ec14911e 5402
40acc203
ZJS
5403 if (show_status)
5404 /* Increase max number of open files to 16K if we can, we
5405 * might needs this when browsing journal files, which might
5406 * be split up into many files. */
5407 setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
5408
4fbd7192 5409 /* If no argument is specified inspect the manager itself */
e449de87 5410 if (show_properties && argc <= 1)
3dced37b 5411 return show_one(argv[0], bus, "/org/freedesktop/systemd1", NULL, show_properties, &new_line, &ellipsized);
48220598 5412
e449de87 5413 if (show_status && argc <= 1) {
8fcf784d 5414
8fcf784d
LP
5415 show_system_status(bus);
5416 new_line = true;
5417
5418 if (arg_all)
e449de87 5419 ret = show_all(argv[0], bus, false, &new_line, &ellipsized);
8fcf784d 5420 } else {
e3e0314b
ZJS
5421 _cleanup_free_ char **patterns = NULL;
5422 char **name;
5423
e449de87 5424 STRV_FOREACH(name, strv_skip(argv, 1)) {
3dced37b 5425 _cleanup_free_ char *path = NULL, *unit = NULL;
94e0bd7d 5426 uint32_t id;
48220598 5427
94e0bd7d 5428 if (safe_atou32(*name, &id) < 0) {
e3e0314b 5429 if (strv_push(&patterns, *name) < 0)
94e0bd7d 5430 return log_oom();
48220598 5431
e3e0314b 5432 continue;
94e0bd7d 5433 } else if (show_properties) {
94e0bd7d 5434 /* Interpret as job id */
3dced37b 5435 if (asprintf(&path, "/org/freedesktop/systemd1/job/%u", id) < 0)
94e0bd7d 5436 return log_oom();
48220598 5437
94e0bd7d
ZJS
5438 } else {
5439 /* Interpret as PID */
3dced37b 5440 r = get_unit_dbus_path_by_pid(bus, id, &path);
373d32c9 5441 if (r < 0) {
94e0bd7d 5442 ret = r;
373d32c9
LP
5443 continue;
5444 }
3dced37b
LP
5445
5446 r = unit_name_from_dbus_path(path, &unit);
5447 if (r < 0)
5448 return log_oom();
94e0bd7d 5449 }
f74294c1 5450
3dced37b 5451 r = show_one(argv[0], bus, path, unit, show_properties, &new_line, &ellipsized);
5bb75bc7
ZJS
5452 if (r < 0)
5453 return r;
5454 else if (r > 0 && ret == 0)
5455 ret = r;
48220598 5456 }
94e0bd7d 5457
e3e0314b
ZJS
5458 if (!strv_isempty(patterns)) {
5459 _cleanup_strv_free_ char **names = NULL;
5460
5461 r = expand_names(bus, patterns, NULL, &names);
5462 if (r < 0)
691395d8 5463 return log_error_errno(r, "Failed to expand names: %m");
e3e0314b
ZJS
5464
5465 STRV_FOREACH(name, names) {
3dced37b 5466 _cleanup_free_ char *path;
e3e0314b 5467
3dced37b
LP
5468 path = unit_dbus_path_from_name(*name);
5469 if (!path)
e3e0314b
ZJS
5470 return log_oom();
5471
3dced37b 5472 r = show_one(argv[0], bus, path, *name, show_properties, &new_line, &ellipsized);
5bb75bc7
ZJS
5473 if (r < 0)
5474 return r;
3dced37b 5475 if (r > 0 && ret == 0)
5bb75bc7 5476 ret = r;
e3e0314b
ZJS
5477 }
5478 }
5479 }
5480
94e0bd7d
ZJS
5481 if (ellipsized && !arg_quiet)
5482 printf("Hint: Some lines were ellipsized, use -l to show in full.\n");
48220598 5483
22f4096c 5484 return ret;
0183528f
LP
5485}
5486
8527b07b
ZJS
5487static int cat_file(const char *filename, bool newline) {
5488 _cleanup_close_ int fd;
5489
5490 fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOCTTY);
5491 if (fd < 0)
5492 return -errno;
5493
5494 printf("%s%s# %s%s\n",
5495 newline ? "\n" : "",
5496 ansi_highlight_blue(),
5497 filename,
1fc464f6 5498 ansi_normal());
8527b07b
ZJS
5499 fflush(stdout);
5500
1c876927 5501 return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, 0);
8527b07b
ZJS
5502}
5503
e449de87 5504static int cat(int argc, char *argv[], void *userdata) {
ad2a0358 5505 _cleanup_lookup_paths_free_ LookupPaths lp = {};
15ef1144
LP
5506 _cleanup_strv_free_ char **names = NULL;
5507 char **name;
4fbd7192
LP
5508 sd_bus *bus;
5509 bool first = true;
25586912 5510 int r;
15ef1144 5511
3e7eed84 5512 if (arg_transport != BUS_TRANSPORT_LOCAL) {
4fbd7192 5513 log_error("Cannot remotely cat units.");
3e495a66
ZJS
5514 return -EINVAL;
5515 }
5516
4943d143 5517 r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
ad2a0358 5518 if (r < 0)
c51932be 5519 return log_error_errno(r, "Failed to determine unit paths: %m");
ad2a0358 5520
4fbd7192 5521 r = acquire_bus(BUS_MANAGER, &bus);
15ef1144 5522 if (r < 0)
4fbd7192 5523 return r;
15ef1144 5524
e449de87 5525 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
4fbd7192
LP
5526 if (r < 0)
5527 return log_error_errno(r, "Failed to expand names: %m");
ad2a0358 5528
ea4b98e6 5529 pager_open(arg_no_pager, false);
15ef1144
LP
5530
5531 STRV_FOREACH(name, names) {
ad2a0358 5532 _cleanup_free_ char *fragment_path = NULL;
15ef1144 5533 _cleanup_strv_free_ char **dropin_paths = NULL;
15ef1144
LP
5534 char **path;
5535
4fbd7192 5536 r = unit_find_paths(bus, *name, &lp, &fragment_path, &dropin_paths);
ad2a0358
ZJS
5537 if (r < 0)
5538 return r;
b5e6a600
IS
5539 else if (r == 0)
5540 return -ENOENT;
15ef1144
LP
5541
5542 if (first)
5543 first = false;
5544 else
5545 puts("");
5546
5b9635d1 5547 if (need_daemon_reload(bus, *name) > 0) /* ignore errors (<0), this is informational output */
e100155d
LW
5548 fprintf(stderr,
5549 "%s# Warning: %s changed on disk, the version systemd has loaded is outdated.\n"
5550 "%s# This output shows the current version of the unit's original fragment and drop-in files.\n"
5551 "%s# If fragments or drop-ins were added or removed, they are not properly reflected in this output.\n"
5552 "%s# Run 'systemctl%s daemon-reload' to reload units.%s\n",
5553 ansi_highlight_red(),
5554 *name,
5555 ansi_highlight_red(),
5556 ansi_highlight_red(),
5557 ansi_highlight_red(),
5558 arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
5559 ansi_normal());
5560
ad2a0358 5561 if (fragment_path) {
8527b07b
ZJS
5562 r = cat_file(fragment_path, false);
5563 if (r < 0)
5564 return log_warning_errno(r, "Failed to cat %s: %m", fragment_path);
15ef1144
LP
5565 }
5566
5567 STRV_FOREACH(path, dropin_paths) {
8527b07b
ZJS
5568 r = cat_file(*path, path == dropin_paths);
5569 if (r < 0)
5570 return log_warning_errno(r, "Failed to cat %s: %m", *path);
15ef1144
LP
5571 }
5572 }
5573
25586912 5574 return 0;
15ef1144
LP
5575}
5576
e449de87 5577static int set_property(int argc, char *argv[], void *userdata) {
4afd3348
LP
5578 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
5579 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
68372da6 5580 _cleanup_free_ char *n = NULL;
89ada3ba 5581 UnitType t;
4fbd7192 5582 sd_bus *bus;
8e2af478
LP
5583 int r;
5584
4fbd7192
LP
5585 r = acquire_bus(BUS_MANAGER, &bus);
5586 if (r < 0)
5587 return r;
5588
8a4b13c5 5589 polkit_agent_open_maybe();
d2ad7e1b 5590
f459b602
MAP
5591 r = sd_bus_message_new_method_call(
5592 bus,
151b9b96 5593 &m,
8e2af478
LP
5594 "org.freedesktop.systemd1",
5595 "/org/freedesktop/systemd1",
5596 "org.freedesktop.systemd1.Manager",
151b9b96 5597 "SetUnitProperties");
f459b602
MAP
5598 if (r < 0)
5599 return bus_log_create_error(r);
8e2af478 5600
e449de87 5601 r = unit_name_mangle(argv[1], UNIT_NAME_NOGLOB, &n);
7410616c
LP
5602 if (r < 0)
5603 return log_error_errno(r, "Failed to mangle unit name: %m");
68372da6 5604
89ada3ba
YW
5605 t = unit_name_to_type(n);
5606 if (t < 0) {
5607 log_error("Invalid unit type: %s", n);
5608 return -EINVAL;
5609 }
5610
f459b602
MAP
5611 r = sd_bus_message_append(m, "sb", n, arg_runtime);
5612 if (r < 0)
5613 return bus_log_create_error(r);
8e2af478 5614
f459b602
MAP
5615 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, "(sv)");
5616 if (r < 0)
5617 return bus_log_create_error(r);
8e2af478 5618
89ada3ba 5619 r = bus_append_unit_property_assignment_many(m, t, strv_skip(argv, 2));
8673cf13
LP
5620 if (r < 0)
5621 return r;
8e2af478 5622
f459b602
MAP
5623 r = sd_bus_message_close_container(m);
5624 if (r < 0)
5625 return bus_log_create_error(r);
8e2af478 5626
c49b30a2 5627 r = sd_bus_call(bus, m, 0, &error, NULL);
691395d8
LP
5628 if (r < 0)
5629 return log_error_errno(r, "Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
8e2af478
LP
5630
5631 return 0;
5632}
5633
e449de87 5634static int daemon_reload(int argc, char *argv[], void *userdata) {
4afd3348 5635 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2853b60a 5636 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
7e4249b9 5637 const char *method;
4fbd7192 5638 sd_bus *bus;
f459b602 5639 int r;
7e4249b9 5640
4fbd7192
LP
5641 r = acquire_bus(BUS_MANAGER, &bus);
5642 if (r < 0)
5643 return r;
5644
8a4b13c5 5645 polkit_agent_open_maybe();
d2ad7e1b 5646
2853b60a
LP
5647 switch (arg_action) {
5648
5649 case ACTION_RELOAD:
e4b61340 5650 method = "Reload";
2853b60a
LP
5651 break;
5652
5653 case ACTION_REEXEC:
e4b61340 5654 method = "Reexecute";
2853b60a
LP
5655 break;
5656
5657 case ACTION_SYSTEMCTL:
5658 method = streq(argv[0], "daemon-reexec") ? "Reexecute" :
5659 /* "daemon-reload" */ "Reload";
5660 break;
e4b61340 5661
2853b60a
LP
5662 default:
5663 assert_not_reached("Unexpected action");
e4b61340 5664 }
7e4249b9 5665
2853b60a
LP
5666 r = sd_bus_message_new_method_call(
5667 bus,
5668 &m,
5669 "org.freedesktop.systemd1",
5670 "/org/freedesktop/systemd1",
5671 "org.freedesktop.systemd1.Manager",
5672 method);
5673 if (r < 0)
5674 return bus_log_create_error(r);
5675
5676 /* Note we use an extra-long timeout here. This is because a reload or reexec means generators are rerun which
5677 * are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the generators can have
5678 * their timeout, and for everything else there's the same time budget in place. */
5679
5680 r = sd_bus_call(bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL);
5681
5682 /* On reexecution, we expect a disconnect, not a reply */
5683 if (IN_SET(r, -ETIMEDOUT, -ECONNRESET) && streq(method, "Reexecute"))
5684 r = 0;
5685
5686 if (r < 0 && arg_action == ACTION_SYSTEMCTL)
5687 return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
5688
5689 /* Note that for the legacy commands (i.e. those with action != ACTION_SYSTEMCTL) we support fallbacks to the
5690 * old ways of doing things, hence don't log any error in that case here. */
5691
5692 return r < 0 ? r : 0;
5693}
5694
5695static int trivial_method(int argc, char *argv[], void *userdata) {
5696 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5697 const char *method;
5698 sd_bus *bus;
5699 int r;
5700
1ae17672
ZJS
5701 if (arg_dry_run)
5702 return 0;
5703
2853b60a
LP
5704 r = acquire_bus(BUS_MANAGER, &bus);
5705 if (r < 0)
5706 return r;
5707
8a4b13c5 5708 polkit_agent_open_maybe();
d2ad7e1b 5709
2853b60a
LP
5710 method =
5711 streq(argv[0], "clear-jobs") ||
5712 streq(argv[0], "cancel") ? "ClearJobs" :
5713 streq(argv[0], "reset-failed") ? "ResetFailed" :
5714 streq(argv[0], "halt") ? "Halt" :
5715 streq(argv[0], "reboot") ? "Reboot" :
5716 streq(argv[0], "kexec") ? "KExec" :
5717 streq(argv[0], "exit") ? "Exit" :
5718 /* poweroff */ "PowerOff";
5719
6e646d22 5720 r = sd_bus_call_method(
f22f08cd
SP
5721 bus,
5722 "org.freedesktop.systemd1",
5723 "/org/freedesktop/systemd1",
5724 "org.freedesktop.systemd1.Manager",
6e646d22
LP
5725 method,
5726 &error,
5727 NULL,
5728 NULL);
2853b60a
LP
5729 if (r < 0 && arg_action == ACTION_SYSTEMCTL)
5730 return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
5731
5732 /* Note that for the legacy commands (i.e. those with action != ACTION_SYSTEMCTL) we support fallbacks to the
5733 * old ways of doing things, hence don't log any error in that case here. */
7e4249b9 5734
0a9776c2 5735 return r < 0 ? r : 0;
7e4249b9
LP
5736}
5737
e449de87 5738static int reset_failed(int argc, char *argv[], void *userdata) {
e3e0314b 5739 _cleanup_strv_free_ char **names = NULL;
4fbd7192 5740 sd_bus *bus;
f84190d8 5741 char **name;
e3e0314b 5742 int r, q;
5632e374 5743
e449de87 5744 if (argc <= 1)
2853b60a 5745 return trivial_method(argc, argv, userdata);
5632e374 5746
4fbd7192
LP
5747 r = acquire_bus(BUS_MANAGER, &bus);
5748 if (r < 0)
5749 return r;
5750
8a4b13c5 5751 polkit_agent_open_maybe();
d2ad7e1b 5752
e449de87 5753 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
e3e0314b 5754 if (r < 0)
691395d8 5755 return log_error_errno(r, "Failed to expand names: %m");
f84190d8 5756
e3e0314b 5757 STRV_FOREACH(name, names) {
4afd3348 5758 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
342641fb 5759
6e646d22 5760 q = sd_bus_call_method(
f22f08cd 5761 bus,
b0193f1c
LP
5762 "org.freedesktop.systemd1",
5763 "/org/freedesktop/systemd1",
5764 "org.freedesktop.systemd1.Manager",
6e646d22
LP
5765 "ResetFailedUnit",
5766 &error,
5767 NULL,
5768 "s", *name);
e3e0314b 5769 if (q < 0) {
691395d8 5770 log_error_errno(q, "Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
e3e0314b
ZJS
5771 if (r == 0)
5772 r = q;
f459b602 5773 }
5632e374
LP
5774 }
5775
e3e0314b 5776 return r;
5632e374
LP
5777}
5778
804ee07c
ZJS
5779static int print_variable(const char *s) {
5780 const char *sep;
5781 _cleanup_free_ char *esc = NULL;
5782
5783 sep = strchr(s, '=');
5784 if (!sep) {
5785 log_error("Invalid environment block");
5786 return -EUCLEAN;
5787 }
5788
5789 esc = shell_maybe_quote(sep + 1, ESCAPE_POSIX);
5790 if (!esc)
5791 return log_oom();
5792
5793 printf("%.*s=%s\n", (int)(sep-s), s, esc);
5794 return 0;
5795}
5796
e449de87 5797static int show_environment(int argc, char *argv[], void *userdata) {
4afd3348
LP
5798 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5799 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
f459b602 5800 const char *text;
4fbd7192 5801 sd_bus *bus;
7e4249b9 5802 int r;
7e4249b9 5803
4fbd7192
LP
5804 r = acquire_bus(BUS_MANAGER, &bus);
5805 if (r < 0)
5806 return r;
5807
d2ad7e1b
ZJS
5808 pager_open(arg_no_pager, false);
5809
f459b602 5810 r = sd_bus_get_property(
f22f08cd
SP
5811 bus,
5812 "org.freedesktop.systemd1",
5813 "/org/freedesktop/systemd1",
f459b602
MAP
5814 "org.freedesktop.systemd1.Manager",
5815 "Environment",
5816 &error,
f22f08cd 5817 &reply,
f459b602 5818 "as");
691395d8
LP
5819 if (r < 0)
5820 return log_error_errno(r, "Failed to get environment: %s", bus_error_message(&error, r));
7e4249b9 5821
f459b602
MAP
5822 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
5823 if (r < 0)
5824 return bus_log_parse_error(r);
7e4249b9 5825
804ee07c
ZJS
5826 while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0) {
5827 r = print_variable(text);
5828 if (r < 0)
5829 return r;
5830 }
f459b602
MAP
5831 if (r < 0)
5832 return bus_log_parse_error(r);
7e4249b9 5833
f459b602
MAP
5834 r = sd_bus_message_exit_container(reply);
5835 if (r < 0)
5836 return bus_log_parse_error(r);
7e4249b9 5837
f84190d8 5838 return 0;
7e4249b9
LP
5839}
5840
e449de87 5841static int switch_root(int argc, char *argv[], void *userdata) {
4afd3348 5842 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
f39d4a08
HH
5843 _cleanup_free_ char *cmdline_init = NULL;
5844 const char *root, *init;
4fbd7192 5845 sd_bus *bus;
f459b602 5846 int r;
957eb8ca 5847
4fbd7192
LP
5848 if (arg_transport != BUS_TRANSPORT_LOCAL) {
5849 log_error("Cannot switch root remotely.");
5850 return -EINVAL;
5851 }
5852
e449de87 5853 if (argc < 2 || argc > 3) {
957eb8ca
LP
5854 log_error("Wrong number of arguments.");
5855 return -EINVAL;
5856 }
5857
e449de87 5858 root = argv[1];
13068da8 5859
e449de87
LP
5860 if (argc >= 3)
5861 init = argv[2];
13068da8 5862 else {
f39d4a08
HH
5863 r = parse_env_file("/proc/cmdline", WHITESPACE,
5864 "init", &cmdline_init,
5865 NULL);
5866 if (r < 0)
da927ba9 5867 log_debug_errno(r, "Failed to parse /proc/cmdline: %m");
13068da8 5868
f39d4a08 5869 init = cmdline_init;
13068da8 5870 }
f459b602 5871
3c6f7c34 5872 init = empty_to_null(init);
f39d4a08
HH
5873 if (init) {
5874 const char *root_systemd_path = NULL, *root_init_path = NULL;
5875
63c372cb
LP
5876 root_systemd_path = strjoina(root, "/" SYSTEMD_BINARY_PATH);
5877 root_init_path = strjoina(root, "/", init);
f39d4a08
HH
5878
5879 /* If the passed init is actually the same as the
5880 * systemd binary, then let's suppress it. */
e3f791a2 5881 if (files_same(root_init_path, root_systemd_path, 0) > 0)
f39d4a08
HH
5882 init = NULL;
5883 }
13068da8 5884
acc28e2e 5885 /* Instruct PID1 to exclude us from its killing spree applied during
b3ad0ff4
ZJS
5886 * the transition. Otherwise we would exit with a failure status even
5887 * though the switch to the new root has succeed. */
5888 argv_cmdline[0] = '@';
acc28e2e 5889
4fbd7192
LP
5890 r = acquire_bus(BUS_MANAGER, &bus);
5891 if (r < 0)
5892 return r;
5893
8a7a9cea
ZJS
5894 /* If we are slow to exit after the root switch, the new systemd instance
5895 * will send us a signal to terminate. Just ignore it and exit normally.
5896 * This way the unit does not end up as failed.
5897 */
5898 r = ignore_signals(SIGTERM, -1);
5899 if (r < 0)
5900 log_warning_errno(r, "Failed to change disposition of SIGTERM to ignore: %m");
5901
f39d4a08 5902 log_debug("Switching root - root: %s; init: %s", root, strna(init));
957eb8ca 5903
f459b602 5904 r = sd_bus_call_method(
f22f08cd 5905 bus,
957eb8ca
LP
5906 "org.freedesktop.systemd1",
5907 "/org/freedesktop/systemd1",
5908 "org.freedesktop.systemd1.Manager",
f22f08cd 5909 "SwitchRoot",
f459b602 5910 &error,
f22f08cd 5911 NULL,
f459b602 5912 "ss", root, init);
8a7a9cea
ZJS
5913 if (r < 0) {
5914 (void) default_signals(SIGTERM, -1);
5915
691395d8 5916 return log_error_errno(r, "Failed to switch root: %s", bus_error_message(&error, r));
8a7a9cea 5917 }
f459b602
MAP
5918
5919 return 0;
957eb8ca
LP
5920}
5921
e449de87 5922static int set_environment(int argc, char *argv[], void *userdata) {
4afd3348
LP
5923 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5924 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
7e4249b9 5925 const char *method;
4fbd7192 5926 sd_bus *bus;
31e767f7
LP
5927 int r;
5928
e449de87
LP
5929 assert(argc > 1);
5930 assert(argv);
7e4249b9 5931
4fbd7192
LP
5932 r = acquire_bus(BUS_MANAGER, &bus);
5933 if (r < 0)
5934 return r;
5935
8a4b13c5 5936 polkit_agent_open_maybe();
d2ad7e1b 5937
e449de87 5938 method = streq(argv[0], "set-environment")
7e4249b9
LP
5939 ? "SetEnvironment"
5940 : "UnsetEnvironment";
5941
f459b602
MAP
5942 r = sd_bus_message_new_method_call(
5943 bus,
151b9b96 5944 &m,
31e767f7
LP
5945 "org.freedesktop.systemd1",
5946 "/org/freedesktop/systemd1",
5947 "org.freedesktop.systemd1.Manager",
151b9b96 5948 method);
f459b602
MAP
5949 if (r < 0)
5950 return bus_log_create_error(r);
7e4249b9 5951
e449de87 5952 r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
31e767f7 5953 if (r < 0)
f459b602 5954 return bus_log_create_error(r);
7e4249b9 5955
c49b30a2 5956 r = sd_bus_call(bus, m, 0, &error, NULL);
691395d8
LP
5957 if (r < 0)
5958 return log_error_errno(r, "Failed to set environment: %s", bus_error_message(&error, r));
7e4249b9 5959
f84190d8 5960 return 0;
7e4249b9
LP
5961}
5962
e449de87 5963static int import_environment(int argc, char *argv[], void *userdata) {
4afd3348
LP
5964 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5965 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
4fbd7192 5966 sd_bus *bus;
ac3efa8a
LP
5967 int r;
5968
4fbd7192
LP
5969 r = acquire_bus(BUS_MANAGER, &bus);
5970 if (r < 0)
5971 return r;
5972
8a4b13c5 5973 polkit_agent_open_maybe();
d2ad7e1b 5974
ac3efa8a
LP
5975 r = sd_bus_message_new_method_call(
5976 bus,
151b9b96 5977 &m,
ac3efa8a
LP
5978 "org.freedesktop.systemd1",
5979 "/org/freedesktop/systemd1",
5980 "org.freedesktop.systemd1.Manager",
151b9b96 5981 "SetEnvironment");
ac3efa8a
LP
5982 if (r < 0)
5983 return bus_log_create_error(r);
5984
e449de87 5985 if (argc < 2)
ac3efa8a
LP
5986 r = sd_bus_message_append_strv(m, environ);
5987 else {
5988 char **a, **b;
5989
5990 r = sd_bus_message_open_container(m, 'a', "s");
5991 if (r < 0)
5992 return bus_log_create_error(r);
5993
e449de87 5994 STRV_FOREACH(a, strv_skip(argv, 1)) {
ac3efa8a
LP
5995
5996 if (!env_name_is_valid(*a)) {
5997 log_error("Not a valid environment variable name: %s", *a);
5998 return -EINVAL;
5999 }
6000
6001 STRV_FOREACH(b, environ) {
6002 const char *eq;
6003
6004 eq = startswith(*b, *a);
6005 if (eq && *eq == '=') {
6006
6007 r = sd_bus_message_append(m, "s", *b);
6008 if (r < 0)
6009 return bus_log_create_error(r);
6010
6011 break;
6012 }
6013 }
6014 }
6015
6016 r = sd_bus_message_close_container(m);
6017 }
6018 if (r < 0)
6019 return bus_log_create_error(r);
6020
6021 r = sd_bus_call(bus, m, 0, &error, NULL);
691395d8
LP
6022 if (r < 0)
6023 return log_error_errno(r, "Failed to import environment: %s", bus_error_message(&error, r));
ac3efa8a
LP
6024
6025 return 0;
6026}
6027
cbb13b2a 6028static int enable_sysv_units(const char *verb, char **args) {
729e3769 6029 int r = 0;
ee5762e3 6030
349cc4a5 6031#if HAVE_SYSV_COMPAT
fb15be83 6032 _cleanup_lookup_paths_free_ LookupPaths paths = {};
e735decc
LP
6033 unsigned f = 0;
6034
6035 /* Processes all SysV units, and reshuffles the array so that afterwards only the native units remain */
ee5762e3 6036
729e3769
LP
6037 if (arg_scope != UNIT_FILE_SYSTEM)
6038 return 0;
ee5762e3 6039
b41b9d2a
LP
6040 if (getenv_bool("SYSTEMCTL_SKIP_SYSV") > 0)
6041 return 0;
6042
4c315c2c
IS
6043 if (!STR_IN_SET(verb,
6044 "enable",
6045 "disable",
6046 "is-enabled"))
729e3769 6047 return 0;
ee5762e3 6048
4943d143 6049 r = lookup_paths_init(&paths, arg_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root);
729e3769
LP
6050 if (r < 0)
6051 return r;
ee5762e3 6052
729e3769 6053 r = 0;
a644abed 6054 while (args[f]) {
e735decc
LP
6055
6056 const char *argv[] = {
6057 ROOTLIBEXECDIR "/systemd-sysv-install",
6058 NULL,
6059 NULL,
6060 NULL,
6061 NULL,
6062 };
6063
05cae7f3 6064 _cleanup_free_ char *p = NULL, *q = NULL, *l = NULL;
729e3769 6065 bool found_native = false, found_sysv;
e735decc 6066 const char *name;
729e3769 6067 unsigned c = 1;
729e3769 6068 pid_t pid;
e735decc 6069 int j;
ee5762e3 6070
a644abed 6071 name = args[f++];
ee5762e3 6072
729e3769
LP
6073 if (!endswith(name, ".service"))
6074 continue;
ee5762e3 6075
729e3769
LP
6076 if (path_is_absolute(name))
6077 continue;
ee5762e3 6078
e735decc 6079 j = unit_file_exists(arg_scope, &paths, name);
76ec966f 6080 if (j < 0 && !IN_SET(j, -ELOOP, -ERFKILL, -EADDRNOTAVAIL))
e735decc 6081 return log_error_errno(j, "Failed to lookup unit file state: %m");
3c6d8e57 6082 found_native = j != 0;
ee5762e3 6083
e735decc
LP
6084 /* If we have both a native unit and a SysV script, enable/disable them both (below); for is-enabled,
6085 * prefer the native unit */
355ff449 6086 if (found_native && streq(verb, "is-enabled"))
729e3769 6087 continue;
ee5762e3 6088
0c6ea3a4
ZJS
6089 p = path_join(arg_root, SYSTEM_SYSVINIT_PATH, name);
6090 if (!p)
60731f32 6091 return log_oom();
ee5762e3 6092
fbd0b64f 6093 p[strlen(p) - STRLEN(".service")] = 0;
729e3769 6094 found_sysv = access(p, F_OK) >= 0;
4b6756a8 6095 if (!found_sysv)
729e3769 6096 continue;
71fad675 6097
689e4e6a
CR
6098 if (!arg_quiet) {
6099 if (found_native)
6100 log_info("Synchronizing state of %s with SysV service script with %s.", name, argv[0]);
6101 else
6102 log_info("%s is not a native service, redirecting to systemd-sysv-install.", name);
6103 }
ee5762e3 6104
729e3769
LP
6105 if (!isempty(arg_root))
6106 argv[c++] = q = strappend("--root=", arg_root);
ee5762e3 6107
0f0467e6 6108 argv[c++] = verb;
2b6bf07d 6109 argv[c++] = basename(p);
729e3769 6110 argv[c] = NULL;
ee5762e3 6111
729e3769 6112 l = strv_join((char**)argv, " ");
60731f32
ZJS
6113 if (!l)
6114 return log_oom();
ee5762e3 6115
8ecc68f4
LP
6116 if (!arg_quiet)
6117 log_info("Executing: %s", l);
ee5762e3 6118
d2e0ac3d 6119 j = safe_fork("(sysv-install)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
4c253ed1 6120 if (j < 0)
b6e1fff1 6121 return j;
4c253ed1 6122 if (j == 0) {
729e3769 6123 /* Child */
729e3769 6124 execv(argv[0], (char**) argv);
cc7cb0ca 6125 log_error_errno(errno, "Failed to execute %s: %m", argv[0]);
729e3769
LP
6126 _exit(EXIT_FAILURE);
6127 }
ee5762e3 6128
2e87a1fd 6129 j = wait_for_terminate_and_check("sysv-install", pid, WAIT_LOG_ABNORMAL);
d710aaf7 6130 if (j < 0)
2e87a1fd
LP
6131 return j;
6132 if (streq(verb, "is-enabled")) {
b4a34311 6133 if (j == EXIT_SUCCESS) {
2e87a1fd
LP
6134 if (!arg_quiet)
6135 puts("enabled");
6136 r = 1;
6137 } else {
6138 if (!arg_quiet)
6139 puts("disabled");
6140 }
ee5762e3 6141
b4a34311 6142 } else if (j != EXIT_SUCCESS)
2e87a1fd 6143 return -EBADE; /* We don't warn here, under the assumption the script already showed an explanation */
ee5762e3 6144
355ff449
MP
6145 if (found_native)
6146 continue;
6147
a644abed 6148 /* Remove this entry, so that we don't try enabling it as native unit */
aba84331
LP
6149 assert(f > 0);
6150 f--;
6151 assert(args[f] == name);
6152 strv_remove(args, name);
729e3769 6153 }
ee5762e3 6154
729e3769
LP
6155#endif
6156 return r;
6157}
ee5762e3 6158
37370d0c 6159static int mangle_names(char **original_names, char ***mangled_names) {
a33fdebb 6160 char **i, **l, **name;
7410616c 6161 int r;
37370d0c 6162
7410616c 6163 l = i = new(char*, strv_length(original_names) + 1);
a33fdebb 6164 if (!l)
37370d0c
VP
6165 return log_oom();
6166
37370d0c 6167 STRV_FOREACH(name, original_names) {
44386fc1
LN
6168
6169 /* When enabling units qualified path names are OK,
6170 * too, hence allow them explicitly. */
6171
7410616c 6172 if (is_path(*name)) {
44386fc1 6173 *i = strdup(*name);
7410616c
LP
6174 if (!*i) {
6175 strv_free(l);
6176 return log_oom();
6177 }
6178 } else {
6179 r = unit_name_mangle(*name, UNIT_NAME_NOGLOB, i);
6180 if (r < 0) {
523f8cde 6181 *i = NULL;
7410616c
LP
6182 strv_free(l);
6183 return log_error_errno(r, "Failed to mangle unit name: %m");
6184 }
a33fdebb
LP
6185 }
6186
6187 i++;
37370d0c 6188 }
a33fdebb
LP
6189
6190 *i = NULL;
6191 *mangled_names = l;
37370d0c
VP
6192
6193 return 0;
6194}
6195
decd7982
JR
6196static int normalize_filenames(char **names) {
6197 char **u;
6198 int r;
6199
6200 STRV_FOREACH(u, names)
6201 if (!path_is_absolute(*u)) {
6202 char* normalized_path;
6203
6204 if (!isempty(arg_root)) {
6205 log_error("Non-absolute paths are not allowed when --root is used: %s", *u);
6206 return -EINVAL;
6207 }
6208
6209 if (!strchr(*u,'/')) {
6210 log_error("Link argument does contain at least one directory separator: %s", *u);
6211 return -EINVAL;
6212 }
6213
6214 r = path_make_absolute_cwd(*u, &normalized_path);
6215 if (r < 0)
6216 return r;
6217
6218 free_and_replace(*u, normalized_path);
6219 }
6220
6221 return 0;
6222}
6223
1d3c86c0
MS
6224static int normalize_names(char **names, bool warn_if_path) {
6225 char **u;
6226 bool was_path = false;
6227
6228 STRV_FOREACH(u, names) {
6229 int r;
6230
6231 if (!is_path(*u))
6232 continue;
6233
6234 r = free_and_strdup(u, basename(*u));
6235 if (r < 0)
6236 return log_error_errno(r, "Failed to normalize unit file path: %m");
6237
6238 was_path = true;
6239 }
6240
6241 if (warn_if_path && was_path)
6242 log_warning("Warning: Can't execute disable on the unit file path. Proceeding with the unit name.");
6243
6244 return 0;
6245}
6246
173471b7 6247static int unit_exists(LookupPaths *lp, const char *unit) {
d6568222
SS
6248 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
6249 _cleanup_free_ char *path = NULL;
6250 static const struct bus_properties_map property_map[] = {
662bea67
ZJS
6251 { "LoadState", "s", map_string_no_copy, offsetof(UnitStatusInfo, load_state) },
6252 { "ActiveState", "s", map_string_no_copy, offsetof(UnitStatusInfo, active_state)},
d6568222
SS
6253 {},
6254 };
6255 UnitStatusInfo info = {};
6256 sd_bus *bus;
6257 int r;
6258
173471b7
ZJS
6259 if (unit_name_is_valid(unit, UNIT_NAME_TEMPLATE))
6260 return unit_find_template_path(unit, lp, NULL, NULL);
6261
d6568222
SS
6262 path = unit_dbus_path_from_name(unit);
6263 if (!path)
6264 return log_oom();
6265
6266 r = acquire_bus(BUS_MANAGER, &bus);
6267 if (r < 0)
6268 return r;
6269
98f60936 6270 r = bus_map_all_properties(bus, "org.freedesktop.systemd1", path, property_map, &error, &info);
d6568222
SS
6271 if (r < 0)
6272 return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
6273
d6568222
SS
6274 return !streq_ptr(info.load_state, "not-found") || !streq_ptr(info.active_state, "inactive");
6275}
6276
e449de87 6277static int enable_unit(int argc, char *argv[], void *userdata) {
e3e0314b 6278 _cleanup_strv_free_ char **names = NULL;
e449de87 6279 const char *verb = argv[0];
729e3769 6280 UnitFileChange *changes = NULL;
718db961 6281 unsigned n_changes = 0;
729e3769 6282 int carries_install_info = -1;
35b132e8 6283 bool ignore_carries_install_info = arg_quiet;
729e3769 6284 int r;
ee5762e3 6285
e449de87 6286 if (!argv[1])
ab5919fa
MS
6287 return 0;
6288
e449de87 6289 r = mangle_names(strv_skip(argv, 1), &names);
3a05c0f9 6290 if (r < 0)
cbb13b2a
VP
6291 return r;
6292
e3e0314b 6293 r = enable_sysv_units(verb, names);
cbb13b2a
VP
6294 if (r < 0)
6295 return r;
3a05c0f9 6296
c61b443d 6297 /* If the operation was fully executed by the SysV compat, let's finish early */
823e5fab
FB
6298 if (strv_isempty(names)) {
6299 if (arg_no_reload || install_client_side())
6300 return 0;
6301 return daemon_reload(argc, argv, userdata);
6302 }
67d66210 6303
1d3c86c0
MS
6304 if (streq(verb, "disable")) {
6305 r = normalize_names(names, true);
6306 if (r < 0)
6307 return r;
6308 }
6309
decd7982
JR
6310 if (streq(verb, "link")) {
6311 r = normalize_filenames(names);
6312 if (r < 0)
6313 return r;
6314 }
6315
4fbd7192 6316 if (install_client_side()) {
b3796dd8
JS
6317 UnitFileFlags flags;
6318
6319 flags = args_to_flags();
729e3769 6320 if (streq(verb, "enable")) {
b3796dd8 6321 r = unit_file_enable(arg_scope, flags, arg_root, names, &changes, &n_changes);
729e3769
LP
6322 carries_install_info = r;
6323 } else if (streq(verb, "disable"))
b3796dd8 6324 r = unit_file_disable(arg_scope, flags, arg_root, names, &changes, &n_changes);
729e3769 6325 else if (streq(verb, "reenable")) {
b3796dd8 6326 r = unit_file_reenable(arg_scope, flags, arg_root, names, &changes, &n_changes);
729e3769
LP
6327 carries_install_info = r;
6328 } else if (streq(verb, "link"))
b3796dd8 6329 r = unit_file_link(arg_scope, flags, arg_root, names, &changes, &n_changes);
729e3769 6330 else if (streq(verb, "preset")) {
b3796dd8 6331 r = unit_file_preset(arg_scope, flags, arg_root, names, arg_preset_mode, &changes, &n_changes);
729e3769 6332 } else if (streq(verb, "mask"))
b3796dd8 6333 r = unit_file_mask(arg_scope, flags, arg_root, names, &changes, &n_changes);
729e3769 6334 else if (streq(verb, "unmask"))
b3796dd8 6335 r = unit_file_unmask(arg_scope, flags, arg_root, names, &changes, &n_changes);
344ca755
LP
6336 else if (streq(verb, "revert"))
6337 r = unit_file_revert(arg_scope, arg_root, names, &changes, &n_changes);
729e3769
LP
6338 else
6339 assert_not_reached("Unknown verb");
ee5762e3 6340
af3d8113 6341 unit_file_dump_changes(r, verb, changes, n_changes, arg_quiet);
d073dea0 6342 if (r < 0)
85b78539 6343 goto finish;
df77cdf0 6344 r = 0;
729e3769 6345 } else {
4afd3348
LP
6346 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
6347 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
39207373 6348 bool expect_carries_install_info = false;
344ca755 6349 bool send_runtime = true, send_force = true, send_preset_mode = false;
718db961 6350 const char *method;
4fbd7192 6351 sd_bus *bus;
729e3769 6352
d6568222 6353 if (STR_IN_SET(verb, "mask", "unmask")) {
f8d6cb48 6354 char **name;
173471b7
ZJS
6355 _cleanup_lookup_paths_free_ LookupPaths lp = {};
6356
6357 r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
d6568222
SS
6358 if (r < 0)
6359 return r;
f8d6cb48
ZJS
6360
6361 STRV_FOREACH(name, names) {
173471b7 6362 r = unit_exists(&lp, *name);
f8d6cb48
ZJS
6363 if (r < 0)
6364 return r;
6365 if (r == 0)
6366 log_notice("Unit %s does not exist, proceeding anyway.", *names);
6367 }
d6568222
SS
6368 }
6369
4fbd7192
LP
6370 r = acquire_bus(BUS_MANAGER, &bus);
6371 if (r < 0)
6372 return r;
6373
8a4b13c5 6374 polkit_agent_open_maybe();
d2ad7e1b 6375
729e3769
LP
6376 if (streq(verb, "enable")) {
6377 method = "EnableUnitFiles";
6378 expect_carries_install_info = true;
6379 } else if (streq(verb, "disable")) {
6380 method = "DisableUnitFiles";
6381 send_force = false;
6382 } else if (streq(verb, "reenable")) {
6383 method = "ReenableUnitFiles";
6384 expect_carries_install_info = true;
6385 } else if (streq(verb, "link"))
6386 method = "LinkUnitFiles";
6387 else if (streq(verb, "preset")) {
d309c1c3
LP
6388
6389 if (arg_preset_mode != UNIT_FILE_PRESET_FULL) {
6390 method = "PresetUnitFilesWithMode";
6391 send_preset_mode = true;
6392 } else
6393 method = "PresetUnitFiles";
6394
729e3769 6395 expect_carries_install_info = true;
39207373 6396 ignore_carries_install_info = true;
729e3769
LP
6397 } else if (streq(verb, "mask"))
6398 method = "MaskUnitFiles";
6399 else if (streq(verb, "unmask")) {
6400 method = "UnmaskUnitFiles";
6401 send_force = false;
344ca755
LP
6402 } else if (streq(verb, "revert")) {
6403 method = "RevertUnitFiles";
6404 send_runtime = send_force = false;
729e3769
LP
6405 } else
6406 assert_not_reached("Unknown verb");
6407
f459b602
MAP
6408 r = sd_bus_message_new_method_call(
6409 bus,
151b9b96 6410 &m,
729e3769
LP
6411 "org.freedesktop.systemd1",
6412 "/org/freedesktop/systemd1",
6413 "org.freedesktop.systemd1.Manager",
151b9b96 6414 method);
f459b602
MAP
6415 if (r < 0)
6416 return bus_log_create_error(r);
ee5762e3 6417
e3e0314b 6418 r = sd_bus_message_append_strv(m, names);
f459b602
MAP
6419 if (r < 0)
6420 return bus_log_create_error(r);
ee5762e3 6421
d309c1c3
LP
6422 if (send_preset_mode) {
6423 r = sd_bus_message_append(m, "s", unit_file_preset_mode_to_string(arg_preset_mode));
6424 if (r < 0)
6425 return bus_log_create_error(r);
6426 }
6427
344ca755
LP
6428 if (send_runtime) {
6429 r = sd_bus_message_append(m, "b", arg_runtime);
6430 if (r < 0)
6431 return bus_log_create_error(r);
6432 }
ee5762e3 6433
729e3769 6434 if (send_force) {
f459b602
MAP
6435 r = sd_bus_message_append(m, "b", arg_force);
6436 if (r < 0)
6437 return bus_log_create_error(r);
ee5762e3
LP
6438 }
6439
c49b30a2 6440 r = sd_bus_call(bus, m, 0, &error, &reply);
691395d8 6441 if (r < 0)
af3d8113 6442 return log_error_errno(r, "Failed to %s unit: %s", verb, bus_error_message(&error, r));
be394c48 6443
729e3769 6444 if (expect_carries_install_info) {
f459b602
MAP
6445 r = sd_bus_message_read(reply, "b", &carries_install_info);
6446 if (r < 0)
6447 return bus_log_parse_error(r);
ee5762e3
LP
6448 }
6449
57ab2eab 6450 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
f459b602 6451 if (r < 0)
85b78539 6452 goto finish;
b77398f7 6453
93c941e3 6454 /* Try to reload if enabled */
d6cb60c7 6455 if (!arg_no_reload)
e449de87 6456 r = daemon_reload(argc, argv, userdata);
f459b602
MAP
6457 else
6458 r = 0;
b647f10d 6459 }
3d3961f2 6460
39207373 6461 if (carries_install_info == 0 && !ignore_carries_install_info)
fe4aede9
ZJS
6462 log_warning("The unit files have no installation config (WantedBy, RequiredBy, Also, Alias\n"
6463 "settings in the [Install] section, and DefaultInstance for template units).\n"
6464 "This means they are not meant to be enabled using systemctl.\n"
416389f7
LP
6465 "Possible reasons for having this kind of units are:\n"
6466 "1) A unit may be statically enabled by being symlinked from another unit's\n"
6467 " .wants/ or .requires/ directory.\n"
6468 "2) A unit's purpose may be to act as a helper for some other unit which has\n"
6469 " a requirement dependency on it.\n"
6470 "3) A unit may be started when needed via activation (socket, path, timer,\n"
fe4aede9
ZJS
6471 " D-Bus, udev, scripted systemctl call, ...).\n"
6472 "4) In case of template units, the unit is meant to be enabled with some\n"
6473 " instance name specified.");
ee5762e3 6474
6bc30691 6475 if (arg_now && STR_IN_SET(argv[0], "enable", "disable", "mask")) {
4fbd7192 6476 sd_bus *bus;
6bc30691 6477 unsigned len, i;
57ab2eab 6478
4fbd7192
LP
6479 r = acquire_bus(BUS_MANAGER, &bus);
6480 if (r < 0)
d073dea0 6481 goto finish;
4fbd7192 6482
6bc30691
JS
6483 len = strv_length(names);
6484 {
6485 char *new_args[len + 2];
57ab2eab 6486
6bc30691
JS
6487 new_args[0] = (char*) (streq(argv[0], "enable") ? "start" : "stop");
6488 for (i = 0; i < len; i++)
6489 new_args[i + 1] = basename(names[i]);
6490 new_args[i + 1] = NULL;
6491
6492 r = start_unit(len + 1, new_args, userdata);
6493 }
57ab2eab
JS
6494 }
6495
729e3769 6496finish:
729e3769 6497 unit_file_changes_free(changes, n_changes);
ee5762e3 6498
729e3769 6499 return r;
ee5762e3
LP
6500}
6501
e449de87 6502static int add_dependency(int argc, char *argv[], void *userdata) {
e94937df
LN
6503 _cleanup_strv_free_ char **names = NULL;
6504 _cleanup_free_ char *target = NULL;
e449de87 6505 const char *verb = argv[0];
acc0269c
CH
6506 UnitFileChange *changes = NULL;
6507 unsigned n_changes = 0;
e94937df
LN
6508 UnitDependency dep;
6509 int r = 0;
6510
e449de87 6511 if (!argv[1])
e94937df
LN
6512 return 0;
6513
e449de87 6514 r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".target", &target);
7410616c
LP
6515 if (r < 0)
6516 return log_error_errno(r, "Failed to mangle unit name: %m");
e94937df 6517
e449de87 6518 r = mangle_names(strv_skip(argv, 2), &names);
e94937df
LN
6519 if (r < 0)
6520 return r;
6521
6522 if (streq(verb, "add-wants"))
6523 dep = UNIT_WANTS;
6524 else if (streq(verb, "add-requires"))
6525 dep = UNIT_REQUIRES;
6526 else
6527 assert_not_reached("Unknown verb");
6528
4fbd7192 6529 if (install_client_side()) {
b3796dd8 6530 r = unit_file_add_dependency(arg_scope, args_to_flags(), arg_root, names, target, dep, &changes, &n_changes);
af3d8113 6531 unit_file_dump_changes(r, "add dependency on", changes, n_changes, arg_quiet);
5f056378
CH
6532
6533 if (r > 0)
6534 r = 0;
e94937df 6535 } else {
4afd3348
LP
6536 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
6537 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192 6538 sd_bus *bus;
e94937df 6539
4fbd7192
LP
6540 r = acquire_bus(BUS_MANAGER, &bus);
6541 if (r < 0)
6542 return r;
6543
8a4b13c5 6544 polkit_agent_open_maybe();
d2ad7e1b 6545
e94937df
LN
6546 r = sd_bus_message_new_method_call(
6547 bus,
6548 &m,
6549 "org.freedesktop.systemd1",
6550 "/org/freedesktop/systemd1",
6551 "org.freedesktop.systemd1.Manager",
6552 "AddDependencyUnitFiles");
6553 if (r < 0)
6554 return bus_log_create_error(r);
6555
342641fb 6556 r = sd_bus_message_append_strv(m, names);
e94937df
LN
6557 if (r < 0)
6558 return bus_log_create_error(r);
6559
342641fb 6560 r = sd_bus_message_append(m, "ssbb", target, unit_dependency_to_string(dep), arg_runtime, arg_force);
e94937df
LN
6561 if (r < 0)
6562 return bus_log_create_error(r);
6563
6564 r = sd_bus_call(bus, m, 0, &error, &reply);
691395d8 6565 if (r < 0)
af3d8113 6566 return log_error_errno(r, "Failed to add dependency: %s", bus_error_message(&error, r));
e94937df 6567
acc0269c 6568 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
e94937df 6569 if (r < 0)
acc0269c 6570 goto finish;
e94937df 6571
acc0269c
CH
6572 if (arg_no_reload) {
6573 r = 0;
6574 goto finish;
6575 }
6576
6577 r = daemon_reload(argc, argv, userdata);
e94937df 6578 }
acc0269c
CH
6579
6580finish:
6581 unit_file_changes_free(changes, n_changes);
6582
6583 return r;
e94937df
LN
6584}
6585
e449de87 6586static int preset_all(int argc, char *argv[], void *userdata) {
acc0269c
CH
6587 UnitFileChange *changes = NULL;
6588 unsigned n_changes = 0;
d309c1c3
LP
6589 int r;
6590
4fbd7192 6591 if (install_client_side()) {
b3796dd8 6592 r = unit_file_preset_all(arg_scope, args_to_flags(), arg_root, arg_preset_mode, &changes, &n_changes);
af3d8113 6593 unit_file_dump_changes(r, "preset", changes, n_changes, arg_quiet);
5f056378
CH
6594
6595 if (r > 0)
6596 r = 0;
d309c1c3 6597 } else {
4afd3348
LP
6598 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
6599 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
4fbd7192 6600 sd_bus *bus;
d309c1c3 6601
4fbd7192
LP
6602 r = acquire_bus(BUS_MANAGER, &bus);
6603 if (r < 0)
6604 return r;
6605
8a4b13c5 6606 polkit_agent_open_maybe();
d2ad7e1b 6607
6e646d22 6608 r = sd_bus_call_method(
d309c1c3
LP
6609 bus,
6610 "org.freedesktop.systemd1",
6611 "/org/freedesktop/systemd1",
6612 "org.freedesktop.systemd1.Manager",
6e646d22
LP
6613 "PresetAllUnitFiles",
6614 &error,
6615 &reply,
d309c1c3
LP
6616 "sbb",
6617 unit_file_preset_mode_to_string(arg_preset_mode),
6618 arg_runtime,
6619 arg_force);
691395d8 6620 if (r < 0)
af3d8113 6621 return log_error_errno(r, "Failed to preset all units: %s", bus_error_message(&error, r));
d309c1c3 6622
acc0269c 6623 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
d309c1c3 6624 if (r < 0)
acc0269c 6625 goto finish;
d309c1c3 6626
acc0269c
CH
6627 if (arg_no_reload) {
6628 r = 0;
6629 goto finish;
6630 }
6631
6632 r = daemon_reload(argc, argv, userdata);
d309c1c3 6633 }
acc0269c
CH
6634
6635finish:
6636 unit_file_changes_free(changes, n_changes);
6637
6638 return r;
d309c1c3
LP
6639}
6640
3b3557c4
JS
6641static int show_installation_targets_client_side(const char *name) {
6642 UnitFileChange *changes = NULL;
6643 unsigned n_changes = 0, i;
6644 UnitFileFlags flags;
6645 char **p;
6646 int r;
6647
6648 p = STRV_MAKE(name);
6649 flags = UNIT_FILE_DRY_RUN |
6650 (arg_runtime ? UNIT_FILE_RUNTIME : 0);
6651
6652 r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes);
6653 if (r < 0)
6654 return log_error_errno(r, "Failed to get file links for %s: %m", name);
6655
6656 for (i = 0; i < n_changes; i++)
6657 if (changes[i].type == UNIT_FILE_UNLINK)
6658 printf(" %s\n", changes[i].path);
6659
6660 return 0;
6661}
6662
6663static int show_installation_targets(sd_bus *bus, const char *name) {
6664 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
6665 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
6666 const char *link;
6667 int r;
6668
6669 r = sd_bus_call_method(
6670 bus,
6671 "org.freedesktop.systemd1",
6672 "/org/freedesktop/systemd1",
6673 "org.freedesktop.systemd1.Manager",
6674 "GetUnitFileLinks",
6675 &error,
6676 &reply,
6677 "sb", name, arg_runtime);
6678 if (r < 0)
6679 return log_error_errno(r, "Failed to get unit file links for %s: %s", name, bus_error_message(&error, r));
6680
6681 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
6682 if (r < 0)
6683 return bus_log_parse_error(r);
6684
6685 while ((r = sd_bus_message_read(reply, "s", &link)) > 0)
6686 printf(" %s\n", link);
6687
6688 if (r < 0)
6689 return bus_log_parse_error(r);
6690
6691 r = sd_bus_message_exit_container(reply);
6692 if (r < 0)
6693 return bus_log_parse_error(r);
6694
6695 return 0;
6696}
6697
e449de87 6698static int unit_is_enabled(int argc, char *argv[], void *userdata) {
f459b602 6699
e3e0314b 6700 _cleanup_strv_free_ char **names = NULL;
729e3769
LP
6701 bool enabled;
6702 char **name;
f459b602 6703 int r;
ee5762e3 6704
e449de87 6705 r = mangle_names(strv_skip(argv, 1), &names);
cbb13b2a
VP
6706 if (r < 0)
6707 return r;
6708
e449de87 6709 r = enable_sysv_units(argv[0], names);
729e3769
LP
6710 if (r < 0)
6711 return r;
ee5762e3 6712
729e3769 6713 enabled = r > 0;
ee5762e3 6714
4fbd7192 6715 if (install_client_side()) {
e3e0314b 6716 STRV_FOREACH(name, names) {
729e3769 6717 UnitFileState state;
ee5762e3 6718
0ec0deaa
LP
6719 r = unit_file_get_state(arg_scope, arg_root, *name, &state);
6720 if (r < 0)
c5024cd0 6721 return log_error_errno(r, "Failed to get unit file state for %s: %m", *name);
ee5762e3 6722
4c315c2c
IS
6723 if (IN_SET(state,
6724 UNIT_FILE_ENABLED,
6725 UNIT_FILE_ENABLED_RUNTIME,
6726 UNIT_FILE_STATIC,
f4139308
LP
6727 UNIT_FILE_INDIRECT,
6728 UNIT_FILE_GENERATED))
729e3769
LP
6729 enabled = true;
6730
3b3557c4 6731 if (!arg_quiet) {
729e3769 6732 puts(unit_file_state_to_string(state));
3b3557c4
JS
6733 if (arg_full) {
6734 r = show_installation_targets_client_side(*name);
6735 if (r < 0)
6736 return r;
6737 }
6738 }
71fad675 6739 }
ee5762e3 6740
5f056378 6741 r = 0;
729e3769 6742 } else {
4afd3348 6743 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192
LP
6744 sd_bus *bus;
6745
6746 r = acquire_bus(BUS_MANAGER, &bus);
6747 if (r < 0)
6748 return r;
6749
e3e0314b 6750 STRV_FOREACH(name, names) {
4afd3348 6751 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
729e3769 6752 const char *s;
63a723f3 6753
f459b602 6754 r = sd_bus_call_method(
f22f08cd 6755 bus,
729e3769
LP
6756 "org.freedesktop.systemd1",
6757 "/org/freedesktop/systemd1",
6758 "org.freedesktop.systemd1.Manager",
f22f08cd 6759 "GetUnitFileState",
f459b602 6760 &error,
f22f08cd 6761 &reply,
04504f93 6762 "s", *name);
691395d8
LP
6763 if (r < 0)
6764 return log_error_errno(r, "Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
ee5762e3 6765
f459b602
MAP
6766 r = sd_bus_message_read(reply, "s", &s);
6767 if (r < 0)
6768 return bus_log_parse_error(r);
ee5762e3 6769
f4139308 6770 if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect", "generated"))
729e3769
LP
6771 enabled = true;
6772
3b3557c4 6773 if (!arg_quiet) {
729e3769 6774 puts(s);
3b3557c4
JS
6775 if (arg_full) {
6776 r = show_installation_targets(bus, *name);
6777 if (r < 0)
6778 return r;
6779 }
6780 }
560d8f23 6781 }
ee5762e3
LP
6782 }
6783
f4139308 6784 return enabled ? EXIT_SUCCESS : EXIT_FAILURE;
ee5762e3
LP
6785}
6786
e449de87 6787static int is_system_running(int argc, char *argv[], void *userdata) {
99813a19 6788 _cleanup_free_ char *state = NULL;
4fbd7192 6789 sd_bus *bus;
99813a19
LP
6790 int r;
6791
040524b4 6792 if (running_in_chroot() > 0 || (arg_transport == BUS_TRANSPORT_LOCAL && !sd_booted())) {
94f099d8
LP
6793 if (!arg_quiet)
6794 puts("offline");
6795 return EXIT_FAILURE;
6796 }
6797
4fbd7192
LP
6798 r = acquire_bus(BUS_MANAGER, &bus);
6799 if (r < 0)
6800 return r;
6801
99813a19
LP
6802 r = sd_bus_get_property_string(
6803 bus,
6804 "org.freedesktop.systemd1",
6805 "/org/freedesktop/systemd1",
6806 "org.freedesktop.systemd1.Manager",
6807 "SystemState",
6808 NULL,
6809 &state);
6810 if (r < 0) {
6811 if (!arg_quiet)
6812 puts("unknown");
6813 return 0;
6814 }
6815
6816 if (!arg_quiet)
6817 puts(state);
6818
6819 return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE;
6820}
6821
7d4fb3b1 6822static int create_edit_temp_file(const char *new_path, const char *original_path, char **ret_tmp_fn) {
45519fd6 6823 _cleanup_free_ char *t = NULL;
ae6c3cc0 6824 int r;
7d4fb3b1
RC
6825
6826 assert(new_path);
6827 assert(original_path);
6828 assert(ret_tmp_fn);
6829
14bcf25c 6830 r = tempfn_random(new_path, NULL, &t);
ae6c3cc0 6831 if (r < 0)
029009d4 6832 return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", new_path);
7d4fb3b1
RC
6833
6834 r = mkdir_parents(new_path, 0755);
45519fd6 6835 if (r < 0)
691395d8 6836 return log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
7d4fb3b1 6837
1c876927 6838 r = copy_file(original_path, t, 0, 0644, 0, COPY_REFLINK);
7d4fb3b1 6839 if (r == -ENOENT) {
45519fd6 6840
7d4fb3b1 6841 r = touch(t);
45519fd6
LP
6842 if (r < 0)
6843 return log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
6844
6845 } else if (r < 0)
39c38ce1 6846 return log_error_errno(r, "Failed to create temporary file for \"%s\": %m", new_path);
7d4fb3b1
RC
6847
6848 *ret_tmp_fn = t;
45519fd6 6849 t = NULL;
7d4fb3b1
RC
6850
6851 return 0;
6852}
6853
c51932be
LP
6854static int get_file_to_edit(
6855 const LookupPaths *paths,
6856 const char *name,
6857 char **ret_path) {
6858
6859 _cleanup_free_ char *path = NULL, *run = NULL;
7d4fb3b1 6860
45519fd6
LP
6861 assert(name);
6862 assert(ret_path);
6863
605405c6 6864 path = strjoin(paths->persistent_config, "/", name);
c51932be 6865 if (!path)
7d4fb3b1
RC
6866 return log_oom();
6867
c51932be 6868 if (arg_runtime) {
605405c6 6869 run = strjoin(paths->runtime_config, "/", name);
c51932be
LP
6870 if (!run)
6871 return log_oom();
6872 }
6873
bc854dc7 6874 if (arg_runtime) {
691395d8
LP
6875 if (access(path, F_OK) >= 0) {
6876 log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path);
6877 return -EEXIST;
6878 }
6879
bc854dc7
ZJS
6880 *ret_path = run;
6881 run = NULL;
6882 } else {
6883 *ret_path = path;
6884 path = NULL;
6885 }
7d4fb3b1
RC
6886
6887 return 0;
6888}
6889
39c38ce1 6890static int unit_file_create_new(
c51932be
LP
6891 const LookupPaths *paths,
6892 const char *unit_name,
39c38ce1 6893 const char *suffix,
c51932be
LP
6894 char **ret_new_path,
6895 char **ret_tmp_path) {
6896
45519fd6 6897 char *tmp_new_path, *tmp_tmp_path, *ending;
7d4fb3b1
RC
6898 int r;
6899
6900 assert(unit_name);
6901 assert(ret_new_path);
6902 assert(ret_tmp_path);
6903
39c38ce1 6904 ending = strjoina(unit_name, suffix);
c51932be 6905 r = get_file_to_edit(paths, ending, &tmp_new_path);
7d4fb3b1
RC
6906 if (r < 0)
6907 return r;
6908
6909 r = create_edit_temp_file(tmp_new_path, tmp_new_path, &tmp_tmp_path);
6910 if (r < 0) {
6911 free(tmp_new_path);
6912 return r;
6913 }
6914
6915 *ret_new_path = tmp_new_path;
6916 *ret_tmp_path = tmp_tmp_path;
6917
6918 return 0;
6919}
6920
1cfa9a4c 6921static int unit_file_create_copy(
c51932be 6922 const LookupPaths *paths,
1cfa9a4c
LP
6923 const char *unit_name,
6924 const char *fragment_path,
1cfa9a4c
LP
6925 char **ret_new_path,
6926 char **ret_tmp_path) {
6927
45519fd6 6928 char *tmp_new_path, *tmp_tmp_path;
7d4fb3b1
RC
6929 int r;
6930
6931 assert(fragment_path);
6932 assert(unit_name);
6933 assert(ret_new_path);
6934 assert(ret_tmp_path);
6935
c51932be 6936 r = get_file_to_edit(paths, unit_name, &tmp_new_path);
7d4fb3b1
RC
6937 if (r < 0)
6938 return r;
6939
6940 if (!path_equal(fragment_path, tmp_new_path) && access(tmp_new_path, F_OK) == 0) {
6941 char response;
6942
029009d4 6943 r = ask_char(&response, "yn", "\"%s\" already exists. Overwrite with \"%s\"? [(y)es, (n)o] ", tmp_new_path, fragment_path);
7d4fb3b1
RC
6944 if (r < 0) {
6945 free(tmp_new_path);
6946 return r;
6947 }
6948 if (response != 'y') {
6949 log_warning("%s ignored", unit_name);
6950 free(tmp_new_path);
dbf43a1b 6951 return -EKEYREJECTED;
7d4fb3b1
RC
6952 }
6953 }
6954
6955 r = create_edit_temp_file(tmp_new_path, fragment_path, &tmp_tmp_path);
6956 if (r < 0) {
7d4fb3b1
RC
6957 free(tmp_new_path);
6958 return r;
6959 }
6960
6961 *ret_new_path = tmp_new_path;
6962 *ret_tmp_path = tmp_tmp_path;
6963
6964 return 0;
6965}
6966
6967static int run_editor(char **paths) {
7d4fb3b1
RC
6968 int r;
6969
6970 assert(paths);
6971
1f5d1e02 6972 r = safe_fork("(editor)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
4c253ed1 6973 if (r < 0)
b6e1fff1 6974 return r;
4c253ed1 6975 if (r == 0) {
7d4fb3b1 6976 const char **args;
9ef5d8f2 6977 char *editor, **editor_args = NULL;
1cfa9a4c 6978 char **tmp_path, **original_path, *p;
9ef5d8f2 6979 unsigned n_editor_args = 0, i = 1;
7d4fb3b1
RC
6980 size_t argc;
6981
6982 argc = strv_length(paths)/2 + 1;
7d4fb3b1
RC
6983
6984 /* SYSTEMD_EDITOR takes precedence over EDITOR which takes precedence over VISUAL
6985 * If neither SYSTEMD_EDITOR nor EDITOR nor VISUAL are present,
6986 * we try to execute well known editors
6987 */
6988 editor = getenv("SYSTEMD_EDITOR");
6989 if (!editor)
6990 editor = getenv("EDITOR");
6991 if (!editor)
6992 editor = getenv("VISUAL");
6993
6994 if (!isempty(editor)) {
9ef5d8f2
JS
6995 editor_args = strv_split(editor, WHITESPACE);
6996 if (!editor_args) {
6997 (void) log_oom();
6998 _exit(EXIT_FAILURE);
6999 }
7000 n_editor_args = strv_length(editor_args);
7001 argc += n_editor_args - 1;
7002 }
7003 args = newa(const char*, argc + 1);
7004
7005 if (n_editor_args > 0) {
7006 args[0] = editor_args[0];
7007 for (; i < n_editor_args; i++)
7008 args[i] = editor_args[i];
7009 }
7010
7011 STRV_FOREACH_PAIR(original_path, tmp_path, paths) {
7012 args[i] = *tmp_path;
7013 i++;
7d4fb3b1 7014 }
9ef5d8f2
JS
7015 args[i] = NULL;
7016
7017 if (n_editor_args > 0)
7018 execvp(args[0], (char* const*) args);
7d4fb3b1 7019
9391a1c3 7020 FOREACH_STRING(p, "editor", "nano", "vim", "vi") {
1cfa9a4c
LP
7021 args[0] = p;
7022 execvp(p, (char* const*) args);
7d4fb3b1
RC
7023 /* We do not fail if the editor doesn't exist
7024 * because we want to try each one of them before
7025 * failing.
7026 */
7027 if (errno != ENOENT) {
691395d8 7028 log_error_errno(errno, "Failed to execute %s: %m", editor);
7d4fb3b1
RC
7029 _exit(EXIT_FAILURE);
7030 }
7031 }
7032
1cfa9a4c 7033 log_error("Cannot edit unit(s), no editor available. Please set either $SYSTEMD_EDITOR, $EDITOR or $VISUAL.");
7d4fb3b1
RC
7034 _exit(EXIT_FAILURE);
7035 }
7036
45519fd6 7037 return 0;
7d4fb3b1
RC
7038}
7039
7040static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
e9e310f8 7041 _cleanup_lookup_paths_free_ LookupPaths lp = {};
7d4fb3b1
RC
7042 char **name;
7043 int r;
7044
7045 assert(names);
7046 assert(paths);
7047
4943d143 7048 r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
5b013a2f 7049 if (r < 0)
8df18507 7050 return r;
7d4fb3b1 7051
e9e310f8 7052 STRV_FOREACH(name, names) {
b74df547
ZJS
7053 _cleanup_free_ char *path = NULL, *new_path = NULL, *tmp_path = NULL, *tmp_name = NULL;
7054 const char *unit_name;
7d4fb3b1 7055
4fbd7192 7056 r = unit_find_paths(bus, *name, &lp, &path, NULL);
e9e310f8
RC
7057 if (r < 0)
7058 return r;
b3734d98
ZJS
7059
7060 if (r == 0) {
7061 assert(!path);
7062
7063 if (!arg_force) {
0dcabf09
ZJS
7064 log_error("Run 'systemctl edit%s --force %s' to create a new unit.",
7065 arg_scope == UNIT_FILE_GLOBAL ? " --global" :
7066 arg_scope == UNIT_FILE_USER ? " --user" : "",
7067 *name);
39c38ce1
DC
7068 return -ENOENT;
7069 }
39c38ce1 7070
b3734d98
ZJS
7071 /* Create a new unit from scratch */
7072 unit_name = *name;
7073 r = unit_file_create_new(&lp, unit_name,
7074 arg_full ? NULL : ".d/override.conf",
7075 &new_path, &tmp_path);
7076 } else {
7077 assert(path);
b74df547 7078
b3734d98
ZJS
7079 unit_name = basename(path);
7080 /* We follow unit aliases, but we need to propagate the instance */
7081 if (unit_name_is_valid(*name, UNIT_NAME_INSTANCE) &&
7082 unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
7083 _cleanup_free_ char *instance = NULL;
b74df547 7084
b3734d98
ZJS
7085 r = unit_name_to_instance(*name, &instance);
7086 if (r < 0)
7087 return r;
b74df547 7088
b3734d98
ZJS
7089 r = unit_name_replace_instance(unit_name, instance, &tmp_name);
7090 if (r < 0)
7091 return r;
7092
7093 unit_name = tmp_name;
7094 }
b74df547 7095
39c38ce1 7096 if (arg_full)
b74df547 7097 r = unit_file_create_copy(&lp, unit_name, path, &new_path, &tmp_path);
39c38ce1 7098 else
b74df547 7099 r = unit_file_create_new(&lp, unit_name, ".d/override.conf", &new_path, &tmp_path);
b3734d98 7100 }
e9e310f8 7101 if (r < 0)
ad2a0358 7102 return r;
7d4fb3b1 7103
e9e310f8
RC
7104 r = strv_push_pair(paths, new_path, tmp_path);
7105 if (r < 0)
7106 return log_oom();
78df0edc 7107 new_path = tmp_path = NULL;
7d4fb3b1
RC
7108 }
7109
7110 return 0;
7111}
7112
e449de87 7113static int edit(int argc, char *argv[], void *userdata) {
7d4fb3b1
RC
7114 _cleanup_strv_free_ char **names = NULL;
7115 _cleanup_strv_free_ char **paths = NULL;
7116 char **original, **tmp;
4fbd7192 7117 sd_bus *bus;
7d4fb3b1
RC
7118 int r;
7119
7d4fb3b1 7120 if (!on_tty()) {
4fbd7192 7121 log_error("Cannot edit units if not on a tty.");
7d4fb3b1
RC
7122 return -EINVAL;
7123 }
7124
7125 if (arg_transport != BUS_TRANSPORT_LOCAL) {
4fbd7192 7126 log_error("Cannot edit units remotely.");
7d4fb3b1
RC
7127 return -EINVAL;
7128 }
7129
4fbd7192
LP
7130 r = acquire_bus(BUS_MANAGER, &bus);
7131 if (r < 0)
7132 return r;
7133
e449de87 7134 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
7d4fb3b1
RC
7135 if (r < 0)
7136 return log_error_errno(r, "Failed to expand names: %m");
7137
7d4fb3b1
RC
7138 r = find_paths_to_edit(bus, names, &paths);
7139 if (r < 0)
7140 return r;
7141
b5e6a600 7142 if (strv_isempty(paths))
7d4fb3b1 7143 return -ENOENT;
7d4fb3b1
RC
7144
7145 r = run_editor(paths);
7146 if (r < 0)
7147 goto end;
7148
7149 STRV_FOREACH_PAIR(original, tmp, paths) {
45519fd6
LP
7150 /* If the temporary file is empty we ignore it. It's
7151 * useful if the user wants to cancel its modification
7d4fb3b1
RC
7152 */
7153 if (null_or_empty_path(*tmp)) {
45519fd6 7154 log_warning("Editing \"%s\" canceled: temporary file is empty.", *original);
7d4fb3b1
RC
7155 continue;
7156 }
45519fd6 7157
7d4fb3b1
RC
7158 r = rename(*tmp, *original);
7159 if (r < 0) {
029009d4 7160 r = log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", *tmp, *original);
7d4fb3b1
RC
7161 goto end;
7162 }
7163 }
7164
45519fd6
LP
7165 r = 0;
7166
7167 if (!arg_no_reload && !install_client_side())
e449de87 7168 r = daemon_reload(argc, argv, userdata);
7d4fb3b1
RC
7169
7170end:
5f18271e 7171 STRV_FOREACH_PAIR(original, tmp, paths) {
45519fd6 7172 (void) unlink(*tmp);
7d4fb3b1 7173
5f18271e
RC
7174 /* Removing empty dropin dirs */
7175 if (!arg_full) {
043717f9
RC
7176 _cleanup_free_ char *dir;
7177
7178 dir = dirname_malloc(*original);
7179 if (!dir)
7180 return log_oom();
7181
5f18271e
RC
7182 /* no need to check if the dir is empty, rmdir
7183 * does nothing if it is not the case.
7184 */
7185 (void) rmdir(dir);
7186 }
7187 }
7188
7d4fb3b1
RC
7189 return r;
7190}
7191
601185b4 7192static void systemctl_help(void) {
7e4249b9 7193
ea4b98e6 7194 pager_open(arg_no_pager, false);
729e3769 7195
2e33c433 7196 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
729e3769 7197 "Query or send control commands to the systemd manager.\n\n"
8a0867d6
LP
7198 " -h --help Show this help\n"
7199 " --version Show package version\n"
f459b602
MAP
7200 " --system Connect to system manager\n"
7201 " --user Connect to user service manager\n"
7202 " -H --host=[USER@]HOST\n"
7203 " Operate on remote host\n"
7204 " -M --machine=CONTAINER\n"
7205 " Operate on local container\n"
3fb90db2
ZJS
7206 " -t --type=TYPE List units of a particular type\n"
7207 " --state=STATE List units with particular LOAD or SUB or ACTIVE state\n"
8a0867d6 7208 " -p --property=NAME Show only properties by this name\n"
2cdbbc9a
LP
7209 " -a --all Show all properties/all units currently in memory,\n"
7210 " including dead/empty ones. To list all units installed on\n"
7211 " the system, use the 'list-unit-files' command instead.\n"
bef19548 7212 " --failed Same as --state=failed\n"
98a6e132 7213 " -l --full Don't ellipsize unit names on output\n"
1238ee09 7214 " -r --recursive Show unit list of host and local containers\n"
4dc5b821
LP
7215 " --reverse Show reverse dependencies with 'list-dependencies'\n"
7216 " --job-mode=MODE Specify how to deal with already queued jobs, when\n"
7217 " queueing a new job\n"
a521ae4a 7218 " --show-types When showing sockets, explicitly show their type\n"
4f9a9105 7219 " --value When showing properties, only print the value\n"
b37844d3
LP
7220 " -i --ignore-inhibitors\n"
7221 " When shutting down or sleeping, ignore inhibitors\n"
a8f11321
LP
7222 " --kill-who=WHO Who to send signal to\n"
7223 " -s --signal=SIGNAL Which signal to send\n"
57ab2eab 7224 " --now Start or stop unit in addition to enabling or disabling it\n"
1ae17672 7225 " --dry-run Only print what would be done\n"
8a0867d6 7226 " -q --quiet Suppress output\n"
93a08841 7227 " --wait For (re)start, wait until service stopped again\n"
8a0867d6 7228 " --no-block Do not wait until operation finished\n"
8a0867d6 7229 " --no-wall Don't send wall message before halt/power-off/reboot\n"
3fb90db2 7230 " --no-reload Don't reload daemon after en-/dis-abling unit files\n"
ebed32bf 7231 " --no-legend Do not print a legend (column headers and hints)\n"
69fc152f 7232 " --no-pager Do not pipe output into a pager\n"
501fc174
LP
7233 " --no-ask-password\n"
7234 " Do not ask for system passwords\n"
4e93d369
LR
7235 " --global Enable/disable/mask unit files globally\n"
7236 " --runtime Enable/disable/mask unit files temporarily until next\n"
7237 " reboot\n"
8a0867d6
LP
7238 " -f --force When enabling unit files, override existing symlinks\n"
7239 " When shutting down, execute action immediately\n"
3fb90db2 7240 " --preset-mode= Apply only enable, only disable, or all presets\n"
4e93d369
LR
7241 " --root=PATH Enable/disable/mask unit files in the specified root\n"
7242 " directory\n"
76fdc966 7243 " -n --lines=INTEGER Number of journal entries to show\n"
584c6e70 7244 " -o --output=STRING Change journal output mode (short, short-precise,\n"
7e563bfc
IW
7245 " short-iso, short-iso-precise, short-full,\n"
7246 " short-monotonic, short-unix,\n"
584c6e70 7247 " verbose, export, json, json-pretty, json-sse, cat)\n"
5bdf2243 7248 " --firmware-setup Tell the firmware to show the setup menu on next boot\n"
815ebc54 7249 " --plain Print unit dependencies as a list instead of a tree\n\n"
34c4b47b 7250 "Unit Commands:\n"
fbf3283b
ZJS
7251 " list-units [PATTERN...] List units currently in memory\n"
7252 " list-sockets [PATTERN...] List socket units currently in memory,\n"
7253 " ordered by address\n"
7254 " list-timers [PATTERN...] List timer units currently in memory,\n"
7255 " ordered by next elapse\n"
7256 " start UNIT... Start (activate) one or more units\n"
7257 " stop UNIT... Stop (deactivate) one or more units\n"
7258 " reload UNIT... Reload one or more units\n"
7259 " restart UNIT... Start or restart one or more units\n"
7260 " try-restart UNIT... Restart one or more units if active\n"
7261 " reload-or-restart UNIT... Reload one or more units if possible,\n"
7262 " otherwise start or restart\n"
7263 " try-reload-or-restart UNIT... If active, reload one or more units,\n"
7264 " if supported, otherwise restart\n"
7265 " isolate UNIT Start one unit and stop all others\n"
7266 " kill UNIT... Send signal to processes of a unit\n"
7267 " is-active PATTERN... Check whether units are active\n"
7268 " is-failed PATTERN... Check whether units are failed\n"
7269 " status [PATTERN...|PID...] Show runtime status of one or more units\n"
7270 " show [PATTERN...|JOB...] Show properties of one or more\n"
7271 " units/jobs or the manager\n"
7272 " cat PATTERN... Show files and drop-ins of specified units\n"
7273 " set-property UNIT PROPERTY=VALUE... Sets one or more properties of a unit\n"
7274 " help PATTERN...|PID... Show manual for one or more units\n"
7275 " reset-failed [PATTERN...] Reset failed state for all, one, or more\n"
7276 " units\n"
7277 " list-dependencies [UNIT] Recursively show units which are required\n"
7278 " or wanted by this unit or by which this\n"
7279 " unit is required or wanted\n\n"
34c4b47b 7280 "Unit File Commands:\n"
fbf3283b
ZJS
7281 " list-unit-files [PATTERN...] List installed unit files\n"
7282 " enable [UNIT...|PATH...] Enable one or more unit files\n"
7283 " disable UNIT... Disable one or more unit files\n"
7284 " reenable UNIT... Reenable one or more unit files\n"
7285 " preset UNIT... Enable/disable one or more unit files\n"
7286 " based on preset configuration\n"
7287 " preset-all Enable/disable all unit files based on\n"
7288 " preset configuration\n"
7289 " is-enabled UNIT... Check whether unit files are enabled\n"
7290 " mask UNIT... Mask one or more units\n"
7291 " unmask UNIT... Unmask one or more units\n"
7292 " link PATH... Link one or more units files into\n"
7293 " the search path\n"
7294 " revert UNIT... Revert one or more unit files to vendor\n"
7295 " version\n"
7296 " add-wants TARGET UNIT... Add 'Wants' dependency for the target\n"
7297 " on specified one or more units\n"
7298 " add-requires TARGET UNIT... Add 'Requires' dependency for the target\n"
7299 " on specified one or more units\n"
7300 " edit UNIT... Edit one or more unit files\n"
7301 " get-default Get the name of the default target\n"
7302 " set-default TARGET Set the default target\n\n"
0d292f5e 7303 "Machine Commands:\n"
fbf3283b 7304 " list-machines [PATTERN...] List local containers and host\n\n"
34c4b47b 7305 "Job Commands:\n"
fbf3283b
ZJS
7306 " list-jobs [PATTERN...] List jobs\n"
7307 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
34c4b47b 7308 "Environment Commands:\n"
fbf3283b 7309 " show-environment Dump environment\n"
135775c1
ZJS
7310 " set-environment VARIABLE=VALUE... Set one or more environment variables\n"
7311 " unset-environment VARIABLE... Unset one or more environment variables\n"
7312 " import-environment [VARIABLE...] Import all or some environment variables\n\n"
34c4b47b 7313 "Manager Lifecycle Commands:\n"
fbf3283b
ZJS
7314 " daemon-reload Reload systemd manager configuration\n"
7315 " daemon-reexec Reexecute systemd manager\n\n"
34c4b47b 7316 "System Commands:\n"
fbf3283b
ZJS
7317 " is-system-running Check whether system is fully running\n"
7318 " default Enter system default mode\n"
7319 " rescue Enter system rescue mode\n"
7320 " emergency Enter system emergency mode\n"
7321 " halt Shut down and halt the system\n"
7322 " poweroff Shut down and power-off the system\n"
7323 " reboot [ARG] Shut down and reboot the system\n"
7324 " kexec Shut down and reboot the system with kexec\n"
7325 " exit [EXIT_CODE] Request user instance or container exit\n"
7326 " switch-root ROOT [INIT] Change to a different root file system\n"
7327 " suspend Suspend the system\n"
7328 " hibernate Hibernate the system\n"
7329 " hybrid-sleep Hibernate and suspend the system\n",
5b6319dc 7330 program_invocation_short_name);
7e4249b9
LP
7331}
7332
601185b4 7333static void halt_help(void) {
37185ec8 7334 printf("%s [OPTIONS...]%s\n\n"
e4b61340
LP
7335 "%s the system.\n\n"
7336 " --help Show this help\n"
7337 " --halt Halt the machine\n"
7338 " -p --poweroff Switch off the machine\n"
7339 " --reboot Reboot the machine\n"
2e33c433
LP
7340 " -f --force Force immediate halt/power-off/reboot\n"
7341 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
e4b61340 7342 " -d --no-wtmp Don't write wtmp record\n"
2e33c433 7343 " --no-wall Don't send wall message before halt/power-off/reboot\n",
e4b61340 7344 program_invocation_short_name,
37185ec8 7345 arg_action == ACTION_REBOOT ? " [ARG]" : "",
e4b61340
LP
7346 arg_action == ACTION_REBOOT ? "Reboot" :
7347 arg_action == ACTION_POWEROFF ? "Power off" :
7348 "Halt");
e4b61340
LP
7349}
7350
601185b4 7351static void shutdown_help(void) {
08e4b1c5 7352 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
e4b61340
LP
7353 "Shut down the system.\n\n"
7354 " --help Show this help\n"
7355 " -H --halt Halt the machine\n"
7356 " -P --poweroff Power-off the machine\n"
7357 " -r --reboot Reboot the machine\n"
386da858 7358 " -h Equivalent to --poweroff, overridden by --halt\n"
2e33c433 7359 " -k Don't halt/power-off/reboot, just send warnings\n"
f6144808 7360 " --no-wall Don't send wall message before halt/power-off/reboot\n"
f6144808 7361 " -c Cancel a pending shutdown\n",
e4b61340 7362 program_invocation_short_name);
e4b61340
LP
7363}
7364
601185b4 7365static void telinit_help(void) {
2e33c433 7366 printf("%s [OPTIONS...] {COMMAND}\n\n"
514f4ef5
LP
7367 "Send control commands to the init daemon.\n\n"
7368 " --help Show this help\n"
2e33c433 7369 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
e4b61340
LP
7370 "Commands:\n"
7371 " 0 Power-off the machine\n"
7372 " 6 Reboot the machine\n"
514f4ef5
LP
7373 " 2, 3, 4, 5 Start runlevelX.target unit\n"
7374 " 1, s, S Enter rescue mode\n"
7375 " q, Q Reload init daemon configuration\n"
7376 " u, U Reexecute init daemon\n",
e4b61340 7377 program_invocation_short_name);
e4b61340
LP
7378}
7379
601185b4 7380static void runlevel_help(void) {
2e33c433 7381 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
7382 "Prints the previous and current runlevel of the init system.\n\n"
7383 " --help Show this help\n",
7384 program_invocation_short_name);
e4b61340
LP
7385}
7386
b93312f5 7387static void help_types(void) {
45c0c61d
ZJS
7388 int i;
7389
b93312f5
ZJS
7390 if (!arg_no_legend)
7391 puts("Available unit types:");
e16972e6
ZJS
7392 for (i = 0; i < _UNIT_TYPE_MAX; i++)
7393 puts(unit_type_to_string(i));
7394}
7395
7396static void help_states(void) {
7397 int i;
7398
7399 if (!arg_no_legend)
7400 puts("Available unit load states:");
7401 for (i = 0; i < _UNIT_LOAD_STATE_MAX; i++)
7402 puts(unit_load_state_to_string(i));
7403
7404 if (!arg_no_legend)
7405 puts("\nAvailable unit active states:");
7406 for (i = 0; i < _UNIT_ACTIVE_STATE_MAX; i++)
7407 puts(unit_active_state_to_string(i));
7e55de3b
ZJS
7408
7409 if (!arg_no_legend)
7410 puts("\nAvailable automount unit substates:");
7411 for (i = 0; i < _AUTOMOUNT_STATE_MAX; i++)
7412 puts(automount_state_to_string(i));
7413
7e55de3b
ZJS
7414 if (!arg_no_legend)
7415 puts("\nAvailable device unit substates:");
7416 for (i = 0; i < _DEVICE_STATE_MAX; i++)
7417 puts(device_state_to_string(i));
7418
7419 if (!arg_no_legend)
7420 puts("\nAvailable mount unit substates:");
7421 for (i = 0; i < _MOUNT_STATE_MAX; i++)
7422 puts(mount_state_to_string(i));
7423
7424 if (!arg_no_legend)
7425 puts("\nAvailable path unit substates:");
7426 for (i = 0; i < _PATH_STATE_MAX; i++)
7427 puts(path_state_to_string(i));
7428
7429 if (!arg_no_legend)
7430 puts("\nAvailable scope unit substates:");
7431 for (i = 0; i < _SCOPE_STATE_MAX; i++)
7432 puts(scope_state_to_string(i));
7433
7434 if (!arg_no_legend)
7435 puts("\nAvailable service unit substates:");
7436 for (i = 0; i < _SERVICE_STATE_MAX; i++)
7437 puts(service_state_to_string(i));
7438
7439 if (!arg_no_legend)
7440 puts("\nAvailable slice unit substates:");
7441 for (i = 0; i < _SLICE_STATE_MAX; i++)
7442 puts(slice_state_to_string(i));
7443
7e55de3b
ZJS
7444 if (!arg_no_legend)
7445 puts("\nAvailable socket unit substates:");
7446 for (i = 0; i < _SOCKET_STATE_MAX; i++)
7447 puts(socket_state_to_string(i));
7448
7449 if (!arg_no_legend)
7450 puts("\nAvailable swap unit substates:");
7451 for (i = 0; i < _SWAP_STATE_MAX; i++)
7452 puts(swap_state_to_string(i));
7453
7454 if (!arg_no_legend)
7455 puts("\nAvailable target unit substates:");
7456 for (i = 0; i < _TARGET_STATE_MAX; i++)
7457 puts(target_state_to_string(i));
7458
7459 if (!arg_no_legend)
7460 puts("\nAvailable timer unit substates:");
7461 for (i = 0; i < _TIMER_STATE_MAX; i++)
7462 puts(timer_state_to_string(i));
45c0c61d
ZJS
7463}
7464
e4b61340 7465static int systemctl_parse_argv(int argc, char *argv[]) {
7e4249b9
LP
7466
7467 enum {
90d473a1 7468 ARG_FAIL = 0x100,
afba4199
ZJS
7469 ARG_REVERSE,
7470 ARG_AFTER,
7471 ARG_BEFORE,
1ae17672 7472 ARG_DRY_RUN,
991f2a39 7473 ARG_SHOW_TYPES,
23ade460 7474 ARG_IRREVERSIBLE,
e67c3609 7475 ARG_IGNORE_DEPENDENCIES,
4f9a9105 7476 ARG_VALUE,
35df8f27 7477 ARG_VERSION,
af2d49f7 7478 ARG_USER,
7e4249b9 7479 ARG_SYSTEM,
ee5762e3 7480 ARG_GLOBAL,
6e905d93 7481 ARG_NO_BLOCK,
ebed32bf 7482 ARG_NO_LEGEND,
611efaac 7483 ARG_NO_PAGER,
4445a875 7484 ARG_NO_WALL,
be394c48 7485 ARG_ROOT,
ee5762e3 7486 ARG_NO_RELOAD,
501fc174 7487 ARG_KILL_WHO,
30732560 7488 ARG_NO_ASK_PASSWORD,
729e3769 7489 ARG_FAILED,
df50185b 7490 ARG_RUNTIME,
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 },
68da321f 7530 { "force", no_argument, NULL, 'f' },
9ea9d4cf
LP
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
b4f27ccc 7745 case 'f':
313cefa1 7746 arg_force++;
ee5762e3
LP
7747 break;
7748
7749 case ARG_NO_RELOAD:
7750 arg_no_reload = true;
7751 break;
7752
8a0867d6
LP
7753 case ARG_KILL_WHO:
7754 arg_kill_who = optarg;
7755 break;
7756
8a0867d6 7757 case 's':
691395d8
LP
7758 arg_signal = signal_from_string_try_harder(optarg);
7759 if (arg_signal < 0) {
8a0867d6
LP
7760 log_error("Failed to parse signal string %s.", optarg);
7761 return -EINVAL;
7762 }
7763 break;
7764
501fc174
LP
7765 case ARG_NO_ASK_PASSWORD:
7766 arg_ask_password = false;
7767 break;
7768
f459b602
MAP
7769 case 'H':
7770 arg_transport = BUS_TRANSPORT_REMOTE;
7771 arg_host = optarg;
a8f11321
LP
7772 break;
7773
f459b602 7774 case 'M':
de33fc62 7775 arg_transport = BUS_TRANSPORT_MACHINE;
f459b602 7776 arg_host = optarg;
a8f11321
LP
7777 break;
7778
729e3769
LP
7779 case ARG_RUNTIME:
7780 arg_runtime = true;
7781 break;
7782
df50185b
LP
7783 case 'n':
7784 if (safe_atou(optarg, &arg_lines) < 0) {
7785 log_error("Failed to parse lines '%s'", optarg);
7786 return -EINVAL;
7787 }
7788 break;
7789
df50185b
LP
7790 case 'o':
7791 arg_output = output_mode_from_string(optarg);
7792 if (arg_output < 0) {
7793 log_error("Unknown output '%s'.", optarg);
7794 return -EINVAL;
7795 }
7796 break;
7797
b37844d3
LP
7798 case 'i':
7799 arg_ignore_inhibitors = true;
7800 break;
7801
5d0c05e5
LN
7802 case ARG_PLAIN:
7803 arg_plain = true;
7804 break;
7805
5bdf2243
JJ
7806 case ARG_FIRMWARE_SETUP:
7807 arg_firmware_setup = true;
7808 break;
7809
9b9b3d36 7810 case ARG_STATE: {
bf409580 7811 if (isempty(optarg)) {
10ab1831 7812 log_error("--state= requires arguments.");
bf409580
TA
7813 return -EINVAL;
7814 }
9b9b3d36 7815
c58bd76a 7816 for (p = optarg;;) {
bc6c18fe 7817 _cleanup_free_ char *s = NULL;
9b9b3d36 7818
5ab22f33
SS
7819 r = extract_first_word(&p, &s, ",", 0);
7820 if (r < 0)
6862111e 7821 return log_error_errno(r, "Failed to parse state: %s", optarg);
5ab22f33
SS
7822 if (r == 0)
7823 break;
9b9b3d36 7824
e16972e6
ZJS
7825 if (streq(s, "help")) {
7826 help_states();
7827 return 0;
7828 }
7829
7e9d36e0 7830 if (strv_push(&arg_states, s) < 0)
9b9b3d36 7831 return log_oom();
7e9d36e0
LP
7832
7833 s = NULL;
9b9b3d36
MW
7834 }
7835 break;
7836 }
7837
1238ee09
LP
7838 case 'r':
7839 if (geteuid() != 0) {
f1721625 7840 log_error("--recursive requires root privileges.");
1238ee09
LP
7841 return -EPERM;
7842 }
7843
7844 arg_recursive = true;
7845 break;
7846
d309c1c3
LP
7847 case ARG_PRESET_MODE:
7848
7849 arg_preset_mode = unit_file_preset_mode_from_string(optarg);
7850 if (arg_preset_mode < 0) {
7851 log_error("Failed to parse preset mode: %s.", optarg);
7852 return -EINVAL;
7853 }
7854
7855 break;
7856
57ab2eab
JS
7857 case ARG_NOW:
7858 arg_now = true;
7859 break;
7860
9ef15026
JS
7861 case ARG_MESSAGE:
7862 if (strv_extend(&arg_wall, optarg) < 0)
7863 return log_oom();
7864 break;
7865
7e4249b9
LP
7866 case '?':
7867 return -EINVAL;
7868
7869 default:
eb9da376 7870 assert_not_reached("Unhandled option");
7e4249b9 7871 }
7e4249b9 7872
f459b602 7873 if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM) {
a8f11321
LP
7874 log_error("Cannot access user instance remotely.");
7875 return -EINVAL;
7876 }
7877
93a08841
MP
7878 if (arg_wait && arg_no_block) {
7879 log_error("--wait may not be combined with --no-block.");
7880 return -EINVAL;
7881 }
7882
7e4249b9
LP
7883 return 1;
7884}
7885
e4b61340
LP
7886static int halt_parse_argv(int argc, char *argv[]) {
7887
7888 enum {
7889 ARG_HELP = 0x100,
7890 ARG_HALT,
514f4ef5
LP
7891 ARG_REBOOT,
7892 ARG_NO_WALL
e4b61340
LP
7893 };
7894
7895 static const struct option options[] = {
7896 { "help", no_argument, NULL, ARG_HELP },
7897 { "halt", no_argument, NULL, ARG_HALT },
7898 { "poweroff", no_argument, NULL, 'p' },
7899 { "reboot", no_argument, NULL, ARG_REBOOT },
7900 { "force", no_argument, NULL, 'f' },
7901 { "wtmp-only", no_argument, NULL, 'w' },
7902 { "no-wtmp", no_argument, NULL, 'd' },
f3f054f0 7903 { "no-sync", no_argument, NULL, 'n' },
514f4ef5 7904 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 7905 {}
e4b61340
LP
7906 };
7907
37185ec8 7908 int c, r, runlevel;
e4b61340
LP
7909
7910 assert(argc >= 0);
7911 assert(argv);
7912
7913 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4c701096 7914 if (IN_SET(runlevel, '0', '6'))
65491fd8 7915 arg_force = 2;
e4b61340 7916
601185b4 7917 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0)
e4b61340
LP
7918 switch (c) {
7919
7920 case ARG_HELP:
601185b4
ZJS
7921 halt_help();
7922 return 0;
e4b61340
LP
7923
7924 case ARG_HALT:
7925 arg_action = ACTION_HALT;
7926 break;
7927
7928 case 'p':
a042efad
MS
7929 if (arg_action != ACTION_REBOOT)
7930 arg_action = ACTION_POWEROFF;
e4b61340
LP
7931 break;
7932
7933 case ARG_REBOOT:
7934 arg_action = ACTION_REBOOT;
7935 break;
7936
7937 case 'f':
65491fd8 7938 arg_force = 2;
e4b61340
LP
7939 break;
7940
7941 case 'w':
1ae17672 7942 arg_dry_run = true;
e4b61340
LP
7943 break;
7944
7945 case 'd':
7946 arg_no_wtmp = true;
7947 break;
7948
f3f054f0
TB
7949 case 'n':
7950 arg_no_sync = true;
7951 break;
7952
514f4ef5
LP
7953 case ARG_NO_WALL:
7954 arg_no_wall = true;
7955 break;
7956
e4b61340
LP
7957 case 'i':
7958 case 'h':
7959 /* Compatibility nops */
7960 break;
7961
7962 case '?':
7963 return -EINVAL;
7964
7965 default:
eb9da376 7966 assert_not_reached("Unhandled option");
e4b61340 7967 }
e4b61340 7968
c5220a94 7969 if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
27c06cb5 7970 r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL);
c5220a94 7971 if (r < 0)
37185ec8 7972 return r;
37185ec8 7973 } else if (optind < argc) {
e4b61340
LP
7974 log_error("Too many arguments.");
7975 return -EINVAL;
7976 }
7977
7978 return 1;
7979}
7980
2cc7b0a2 7981static int parse_shutdown_time_spec(const char *t, usec_t *_u) {
f6144808
LP
7982 assert(t);
7983 assert(_u);
7984
7985 if (streq(t, "now"))
7986 *_u = 0;
1a639877 7987 else if (!strchr(t, ':')) {
f6144808
LP
7988 uint64_t u;
7989
1a639877 7990 if (safe_atou64(t, &u) < 0)
f6144808
LP
7991 return -EINVAL;
7992
7993 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
7994 } else {
7995 char *e = NULL;
7996 long hour, minute;
b92bea5d 7997 struct tm tm = {};
f6144808
LP
7998 time_t s;
7999 usec_t n;
8000
8001 errno = 0;
8002 hour = strtol(t, &e, 10);
8333c77e 8003 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
f6144808
LP
8004 return -EINVAL;
8005
8006 minute = strtol(e+1, &e, 10);
8333c77e 8007 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
f6144808
LP
8008 return -EINVAL;
8009
8010 n = now(CLOCK_REALTIME);
08e4b1c5
LP
8011 s = (time_t) (n / USEC_PER_SEC);
8012
f6144808
LP
8013 assert_se(localtime_r(&s, &tm));
8014
8015 tm.tm_hour = (int) hour;
8016 tm.tm_min = (int) minute;
08e4b1c5 8017 tm.tm_sec = 0;
f6144808
LP
8018
8019 assert_se(s = mktime(&tm));
8020
8021 *_u = (usec_t) s * USEC_PER_SEC;
8022
8023 while (*_u <= n)
8024 *_u += USEC_PER_DAY;
8025 }
8026
8027 return 0;
8028}
8029
e4b61340
LP
8030static int shutdown_parse_argv(int argc, char *argv[]) {
8031
8032 enum {
8033 ARG_HELP = 0x100,
514f4ef5 8034 ARG_NO_WALL
e4b61340
LP
8035 };
8036
8037 static const struct option options[] = {
8038 { "help", no_argument, NULL, ARG_HELP },
8039 { "halt", no_argument, NULL, 'H' },
8040 { "poweroff", no_argument, NULL, 'P' },
8041 { "reboot", no_argument, NULL, 'r' },
04ebb595 8042 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
514f4ef5 8043 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 8044 {}
e4b61340
LP
8045 };
8046
172d7abf 8047 char **wall = NULL;
f6144808 8048 int c, r;
e4b61340
LP
8049
8050 assert(argc >= 0);
8051 assert(argv);
8052
b068c6f5 8053 while ((c = getopt_long(argc, argv, "HPrhkKat:fFc", options, NULL)) >= 0)
e4b61340
LP
8054 switch (c) {
8055
8056 case ARG_HELP:
601185b4
ZJS
8057 shutdown_help();
8058 return 0;
e4b61340
LP
8059
8060 case 'H':
8061 arg_action = ACTION_HALT;
8062 break;
8063
8064 case 'P':
8065 arg_action = ACTION_POWEROFF;
8066 break;
8067
8068 case 'r':
5622dde3
KS
8069 if (kexec_loaded())
8070 arg_action = ACTION_KEXEC;
8071 else
8072 arg_action = ACTION_REBOOT;
e4b61340
LP
8073 break;
8074
04ebb595
LP
8075 case 'K':
8076 arg_action = ACTION_KEXEC;
8077 break;
8078
e4b61340
LP
8079 case 'h':
8080 if (arg_action != ACTION_HALT)
8081 arg_action = ACTION_POWEROFF;
8082 break;
8083
8084 case 'k':
1ae17672 8085 arg_dry_run = true;
e4b61340
LP
8086 break;
8087
514f4ef5
LP
8088 case ARG_NO_WALL:
8089 arg_no_wall = true;
8090 break;
8091
e4b61340 8092 case 'a':
b068c6f5 8093 case 't': /* Note that we also ignore any passed argument to -t, not just the -t itself */
75836b9d
JS
8094 case 'f':
8095 case 'F':
e4b61340
LP
8096 /* Compatibility nops */
8097 break;
8098
f6144808
LP
8099 case 'c':
8100 arg_action = ACTION_CANCEL_SHUTDOWN;
8101 break;
8102
e4b61340
LP
8103 case '?':
8104 return -EINVAL;
8105
8106 default:
eb9da376 8107 assert_not_reached("Unhandled option");
e4b61340 8108 }
e4b61340 8109
dfcc5c33 8110 if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
2cc7b0a2 8111 r = parse_shutdown_time_spec(argv[optind], &arg_when);
7e59bfcb 8112 if (r < 0) {
f6144808
LP
8113 log_error("Failed to parse time specification: %s", argv[optind]);
8114 return r;
8115 }
6b5ad000 8116 } else
08e4b1c5 8117 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
442b9094 8118
dfcc5c33
MS
8119 if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
8120 /* No time argument for shutdown cancel */
172d7abf 8121 wall = argv + optind;
dfcc5c33
MS
8122 else if (argc > optind + 1)
8123 /* We skip the time argument */
172d7abf
LP
8124 wall = argv + optind + 1;
8125
8126 if (wall) {
8127 arg_wall = strv_copy(wall);
8128 if (!arg_wall)
8129 return log_oom();
8130 }
e4b61340
LP
8131
8132 optind = argc;
8133
8134 return 1;
e4b61340
LP
8135}
8136
8137static int telinit_parse_argv(int argc, char *argv[]) {
8138
8139 enum {
8140 ARG_HELP = 0x100,
514f4ef5 8141 ARG_NO_WALL
e4b61340
LP
8142 };
8143
8144 static const struct option options[] = {
8145 { "help", no_argument, NULL, ARG_HELP },
514f4ef5 8146 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 8147 {}
e4b61340
LP
8148 };
8149
8150 static const struct {
8151 char from;
8152 enum action to;
8153 } table[] = {
8154 { '0', ACTION_POWEROFF },
8155 { '6', ACTION_REBOOT },
ef2f1067 8156 { '1', ACTION_RESCUE },
e4b61340
LP
8157 { '2', ACTION_RUNLEVEL2 },
8158 { '3', ACTION_RUNLEVEL3 },
8159 { '4', ACTION_RUNLEVEL4 },
8160 { '5', ACTION_RUNLEVEL5 },
8161 { 's', ACTION_RESCUE },
8162 { 'S', ACTION_RESCUE },
8163 { 'q', ACTION_RELOAD },
8164 { 'Q', ACTION_RELOAD },
8165 { 'u', ACTION_REEXEC },
8166 { 'U', ACTION_REEXEC }
8167 };
8168
8169 unsigned i;
8170 int c;
8171
8172 assert(argc >= 0);
8173 assert(argv);
8174
601185b4 8175 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
8176 switch (c) {
8177
8178 case ARG_HELP:
601185b4
ZJS
8179 telinit_help();
8180 return 0;
e4b61340 8181
514f4ef5
LP
8182 case ARG_NO_WALL:
8183 arg_no_wall = true;
8184 break;
8185
e4b61340
LP
8186 case '?':
8187 return -EINVAL;
8188
8189 default:
eb9da376 8190 assert_not_reached("Unhandled option");
e4b61340 8191 }
e4b61340
LP
8192
8193 if (optind >= argc) {
691395d8 8194 log_error("%s: required argument missing.", program_invocation_short_name);
e4b61340
LP
8195 return -EINVAL;
8196 }
8197
8198 if (optind + 1 < argc) {
8199 log_error("Too many arguments.");
8200 return -EINVAL;
8201 }
8202
8203 if (strlen(argv[optind]) != 1) {
8204 log_error("Expected single character argument.");
8205 return -EINVAL;
8206 }
8207
8208 for (i = 0; i < ELEMENTSOF(table); i++)
8209 if (table[i].from == argv[optind][0])
8210 break;
8211
8212 if (i >= ELEMENTSOF(table)) {
b0193f1c 8213 log_error("Unknown command '%s'.", argv[optind]);
e4b61340
LP
8214 return -EINVAL;
8215 }
8216
8217 arg_action = table[i].to;
8218
313cefa1 8219 optind++;
e4b61340
LP
8220
8221 return 1;
8222}
8223
8224static int runlevel_parse_argv(int argc, char *argv[]) {
8225
8226 enum {
8227 ARG_HELP = 0x100,
8228 };
8229
8230 static const struct option options[] = {
8231 { "help", no_argument, NULL, ARG_HELP },
eb9da376 8232 {}
e4b61340
LP
8233 };
8234
8235 int c;
8236
8237 assert(argc >= 0);
8238 assert(argv);
8239
601185b4 8240 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
8241 switch (c) {
8242
8243 case ARG_HELP:
601185b4
ZJS
8244 runlevel_help();
8245 return 0;
e4b61340
LP
8246
8247 case '?':
8248 return -EINVAL;
8249
8250 default:
eb9da376 8251 assert_not_reached("Unhandled option");
e4b61340 8252 }
e4b61340
LP
8253
8254 if (optind < argc) {
8255 log_error("Too many arguments.");
8256 return -EINVAL;
8257 }
8258
8259 return 1;
8260}
8261
8262static int parse_argv(int argc, char *argv[]) {
8263 assert(argc >= 0);
8264 assert(argv);
8265
8266 if (program_invocation_short_name) {
8267
8268 if (strstr(program_invocation_short_name, "halt")) {
8269 arg_action = ACTION_HALT;
8270 return halt_parse_argv(argc, argv);
c54819ca 8271
e4b61340
LP
8272 } else if (strstr(program_invocation_short_name, "poweroff")) {
8273 arg_action = ACTION_POWEROFF;
8274 return halt_parse_argv(argc, argv);
c54819ca 8275
e4b61340 8276 } else if (strstr(program_invocation_short_name, "reboot")) {
5622dde3
KS
8277 if (kexec_loaded())
8278 arg_action = ACTION_KEXEC;
8279 else
8280 arg_action = ACTION_REBOOT;
e4b61340 8281 return halt_parse_argv(argc, argv);
c54819ca 8282
e4b61340
LP
8283 } else if (strstr(program_invocation_short_name, "shutdown")) {
8284 arg_action = ACTION_POWEROFF;
8285 return shutdown_parse_argv(argc, argv);
c54819ca 8286
e4b61340 8287 } else if (strstr(program_invocation_short_name, "init")) {
d5ca5f11 8288
c54819ca
LP
8289 /* Matches invocations as "init" as well as "telinit", which are synonymous when run as PID !=
8290 * 1 on SysV.
8291 *
8292 * On SysV "telinit" was the official command to communicate with PID 1, but "init" would
8293 * redirect itself to "telinit" if called with PID != 1. We follow the same logic here still,
8294 * though we add one level of indirection, as we implement "telinit" in "systemctl". Hence, for
8295 * us if you invoke "init" you get "systemd", but it will execve() "systemctl" immediately with
8296 * argv[] unmodified if PID is != 1. If you invoke "telinit" you directly get "systemctl". In
8297 * both cases we shall do the same thing, which is why we do strstr(p_i_s_n, "init") here, as a
8298 * quick way to match both.
8299 *
8300 * Also see redirect_telinit() in src/core/main.c. */
8301
d5ca5f11 8302 if (sd_booted() > 0) {
f459b602 8303 arg_action = _ACTION_INVALID;
d5ca5f11
LP
8304 return telinit_parse_argv(argc, argv);
8305 } else {
c54819ca
LP
8306 /* Hmm, so some other init system is running, we need to forward this request to
8307 * it. For now we simply guess that it is Upstart. */
d5ca5f11 8308
4ad61fd1 8309 execv(TELINIT, argv);
d5ca5f11
LP
8310
8311 log_error("Couldn't find an alternative telinit implementation to spawn.");
8312 return -EIO;
8313 }
8314
e4b61340
LP
8315 } else if (strstr(program_invocation_short_name, "runlevel")) {
8316 arg_action = ACTION_RUNLEVEL;
8317 return runlevel_parse_argv(argc, argv);
8318 }
8319 }
8320
8321 arg_action = ACTION_SYSTEMCTL;
8322 return systemctl_parse_argv(argc, argv);
8323}
8324
349cc4a5 8325#if HAVE_SYSV_COMPAT
44a6b1b6 8326_pure_ static int action_to_runlevel(void) {
eb22ac37
LP
8327
8328 static const char table[_ACTION_MAX] = {
8329 [ACTION_HALT] = '0',
8330 [ACTION_POWEROFF] = '0',
8331 [ACTION_REBOOT] = '6',
8332 [ACTION_RUNLEVEL2] = '2',
8333 [ACTION_RUNLEVEL3] = '3',
8334 [ACTION_RUNLEVEL4] = '4',
8335 [ACTION_RUNLEVEL5] = '5',
8336 [ACTION_RESCUE] = '1'
8337 };
8338
78ca9099 8339 assert(arg_action >= 0 && arg_action < _ACTION_MAX);
d55ae9e6
LP
8340
8341 return table[arg_action];
8342}
d2e79673 8343#endif
d55ae9e6 8344
d55ae9e6 8345static int talk_initctl(void) {
349cc4a5 8346#if HAVE_SYSV_COMPAT
cbc9fbd1
LP
8347 struct init_request request = {
8348 .magic = INIT_MAGIC,
8349 .sleeptime = 0,
8350 .cmd = INIT_CMD_RUNLVL
8351 };
8352
7fd1b19b 8353 _cleanup_close_ int fd = -1;
d55ae9e6 8354 char rl;
cbc9fbd1 8355 int r;
eb22ac37 8356
427b47c4
ZJS
8357 rl = action_to_runlevel();
8358 if (!rl)
eb22ac37
LP
8359 return 0;
8360
d55ae9e6
LP
8361 request.runlevel = rl;
8362
db4a47e9 8363 fd = open(INIT_FIFO, O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
427b47c4 8364 if (fd < 0) {
d55ae9e6
LP
8365 if (errno == ENOENT)
8366 return 0;
eb22ac37 8367
eca830be 8368 return log_error_errno(errno, "Failed to open "INIT_FIFO": %m");
d55ae9e6 8369 }
eb22ac37 8370
553acb7b
ZJS
8371 r = loop_write(fd, &request, sizeof(request), false);
8372 if (r < 0)
8373 return log_error_errno(r, "Failed to write to "INIT_FIFO": %m");
eb22ac37
LP
8374
8375 return 1;
eca830be
LP
8376#else
8377 return 0;
8378#endif
e4b61340
LP
8379}
8380
e449de87
LP
8381static int systemctl_main(int argc, char *argv[]) {
8382
8383 static const Verb verbs[] = {
c56d1e2c
CW
8384 { "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_ONLINE_ONLY, list_units },
8385 { "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files },
8386 { "list-sockets", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, list_sockets },
8387 { "list-timers", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, list_timers },
8388 { "list-jobs", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, list_jobs },
8389 { "list-machines", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY|VERB_MUST_BE_ROOT, list_machines },
8390 { "clear-jobs", VERB_ANY, 1, VERB_ONLINE_ONLY, trivial_method },
8391 { "cancel", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, cancel_job },
8392 { "start", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
8393 { "stop", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
8394 { "condstop", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with ALTLinux */
8395 { "reload", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
8396 { "restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
8397 { "try-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
8398 { "reload-or-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
8399 { "reload-or-try-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatbility with old systemctl <= 228 */
8400 { "try-reload-or-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit },
8401 { "force-reload", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with SysV */
8402 { "condreload", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with ALTLinux */
8403 { "condrestart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with RH */
8404 { "isolate", 2, 2, VERB_ONLINE_ONLY, start_unit },
8405 { "kill", 2, VERB_ANY, VERB_ONLINE_ONLY, kill_unit },
8406 { "is-active", 2, VERB_ANY, VERB_ONLINE_ONLY, check_unit_active },
3e7e587d 8407 { "check", 2, VERB_ANY, VERB_ONLINE_ONLY, check_unit_active }, /* deprecated alias of is-active */
c56d1e2c
CW
8408 { "is-failed", 2, VERB_ANY, VERB_ONLINE_ONLY, check_unit_failed },
8409 { "show", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, show },
8410 { "cat", 2, VERB_ANY, VERB_ONLINE_ONLY, cat },
8411 { "status", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, show },
8412 { "help", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, show },
8413 { "daemon-reload", VERB_ANY, 1, VERB_ONLINE_ONLY, daemon_reload },
8414 { "daemon-reexec", VERB_ANY, 1, VERB_ONLINE_ONLY, daemon_reload },
8415 { "show-environment", VERB_ANY, 1, VERB_ONLINE_ONLY, show_environment },
8416 { "set-environment", 2, VERB_ANY, VERB_ONLINE_ONLY, set_environment },
8417 { "unset-environment", 2, VERB_ANY, VERB_ONLINE_ONLY, set_environment },
8418 { "import-environment", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, import_environment },
8419 { "halt", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special },
8420 { "poweroff", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special },
8421 { "reboot", VERB_ANY, 2, VERB_ONLINE_ONLY, start_system_special },
8422 { "kexec", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special },
8423 { "suspend", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special },
8424 { "hibernate", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special },
8425 { "hybrid-sleep", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special },
8426 { "default", VERB_ANY, 1, VERB_ONLINE_ONLY, start_special },
8427 { "rescue", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special },
8428 { "emergency", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special },
8429 { "exit", VERB_ANY, 2, VERB_ONLINE_ONLY, start_special },
8430 { "reset-failed", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, reset_failed },
8431 { "enable", 2, VERB_ANY, 0, enable_unit },
8432 { "disable", 2, VERB_ANY, 0, enable_unit },
8433 { "is-enabled", 2, VERB_ANY, 0, unit_is_enabled },
8434 { "reenable", 2, VERB_ANY, 0, enable_unit },
8435 { "preset", 2, VERB_ANY, 0, enable_unit },
8436 { "preset-all", VERB_ANY, 1, 0, preset_all },
8437 { "mask", 2, VERB_ANY, 0, enable_unit },
8438 { "unmask", 2, VERB_ANY, 0, enable_unit },
8439 { "link", 2, VERB_ANY, 0, enable_unit },
8440 { "revert", 2, VERB_ANY, 0, enable_unit },
8441 { "switch-root", 2, VERB_ANY, VERB_ONLINE_ONLY, switch_root },
8442 { "list-dependencies", VERB_ANY, 2, VERB_ONLINE_ONLY, list_dependencies },
8443 { "set-default", 2, 2, 0, set_default },
8444 { "get-default", VERB_ANY, 1, 0, get_default },
8445 { "set-property", 3, VERB_ANY, VERB_ONLINE_ONLY, set_property },
8446 { "is-system-running", VERB_ANY, 1, 0, is_system_running },
8447 { "add-wants", 3, VERB_ANY, 0, add_dependency },
8448 { "add-requires", 3, VERB_ANY, 0, add_dependency },
8449 { "edit", 2, VERB_ANY, VERB_ONLINE_ONLY, edit },
d08e75ed 8450 {}
e449de87 8451 };
7e4249b9 8452
e449de87 8453 return dispatch_verb(argc, argv, verbs, NULL);
e4b61340
LP
8454}
8455
4fbd7192 8456static int reload_with_fallback(void) {
e4b61340 8457
4fbd7192 8458 /* First, try systemd via D-Bus. */
e449de87 8459 if (daemon_reload(0, NULL, NULL) >= 0)
4fbd7192 8460 return 0;
e4b61340
LP
8461
8462 /* Nothing else worked, so let's try signals */
2853b60a 8463 assert(IN_SET(arg_action, ACTION_RELOAD, ACTION_REEXEC));
e4b61340 8464
4a62c710
MS
8465 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0)
8466 return log_error_errno(errno, "kill() failed: %m");
e4b61340
LP
8467
8468 return 0;
8469}
8470
4fbd7192 8471static int start_with_fallback(void) {
e4b61340 8472
4fbd7192 8473 /* First, try systemd via D-Bus. */
e449de87 8474 if (start_unit(0, NULL, NULL) >= 0)
4fbd7192 8475 return 0;
e4b61340 8476
2853b60a 8477 /* Nothing else worked, so let's try /dev/initctl */
fbc43921 8478 if (talk_initctl() > 0)
48ec22bc 8479 return 0;
d55ae9e6
LP
8480
8481 log_error("Failed to talk to init daemon.");
8482 return -EIO;
e4b61340
LP
8483}
8484
477def80 8485static int halt_now(enum action a) {
e606bb61 8486
c01dcddf
LP
8487 /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need to be
8488 * synce'd explicitly in advance. */
1ae17672 8489 if (!arg_no_sync && !arg_dry_run)
f3f054f0 8490 (void) sync();
4a3ad399 8491
1ae17672
ZJS
8492 /* Make sure C-A-D is handled by the kernel from this point on... */
8493 if (!arg_dry_run)
8494 (void) reboot(RB_ENABLE_CAD);
e606bb61 8495
4c80c73c 8496 switch (a) {
e606bb61
LP
8497
8498 case ACTION_HALT:
60675884
LP
8499 if (!arg_quiet)
8500 log_info("Halting.");
1ae17672
ZJS
8501 if (arg_dry_run)
8502 return 0;
19578bb2 8503 (void) reboot(RB_HALT_SYSTEM);
477def80 8504 return -errno;
e606bb61
LP
8505
8506 case ACTION_POWEROFF:
60675884
LP
8507 if (!arg_quiet)
8508 log_info("Powering off.");
1ae17672
ZJS
8509 if (arg_dry_run)
8510 return 0;
19578bb2 8511 (void) reboot(RB_POWER_OFF);
477def80 8512 return -errno;
e606bb61 8513
98d52feb 8514 case ACTION_KEXEC:
c01dcddf
LP
8515 case ACTION_REBOOT:
8516 return reboot_with_parameter(REBOOT_FALLBACK |
8517 (arg_quiet ? 0 : REBOOT_LOG) |
8518 (arg_dry_run ? REBOOT_DRY_RUN : 0));
e606bb61 8519
477def80
LP
8520 default:
8521 assert_not_reached("Unknown action.");
8522 }
e606bb61
LP
8523}
8524
56a730fa
LP
8525static int logind_schedule_shutdown(void) {
8526
349cc4a5 8527#if ENABLE_LOGIND
4afd3348 8528 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
56a730fa
LP
8529 char date[FORMAT_TIMESTAMP_MAX];
8530 const char *action;
4fbd7192 8531 sd_bus *bus;
56a730fa
LP
8532 int r;
8533
4fbd7192 8534 r = acquire_bus(BUS_FULL, &bus);
56a730fa 8535 if (r < 0)
4fbd7192 8536 return r;
56a730fa
LP
8537
8538 switch (arg_action) {
8539 case ACTION_HALT:
8540 action = "halt";
8541 break;
8542 case ACTION_POWEROFF:
8543 action = "poweroff";
8544 break;
8545 case ACTION_KEXEC:
8546 action = "kexec";
8547 break;
a4420f7b
LP
8548 case ACTION_EXIT:
8549 action = "exit";
8550 break;
8551 case ACTION_REBOOT:
56a730fa
LP
8552 default:
8553 action = "reboot";
8554 break;
8555 }
8556
1ae17672 8557 if (arg_dry_run)
56a730fa
LP
8558 action = strjoina("dry-", action);
8559
d2ad7e1b
ZJS
8560 (void) logind_set_wall_message();
8561
56a730fa 8562 r = sd_bus_call_method(
4fbd7192 8563 bus,
56a730fa
LP
8564 "org.freedesktop.login1",
8565 "/org/freedesktop/login1",
8566 "org.freedesktop.login1.Manager",
8567 "ScheduleShutdown",
8568 &error,
8569 NULL,
8570 "st",
8571 action,
8572 arg_when);
8573 if (r < 0)
8574 return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r));
8575
60675884
LP
8576 if (!arg_quiet)
8577 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.", format_timestamp(date, sizeof(date), arg_when));
56a730fa
LP
8578 return 0;
8579#else
8580 log_error("Cannot schedule shutdown without logind support, proceeding with immediate shutdown.");
8581 return -ENOSYS;
8582#endif
8583}
8584
4fbd7192 8585static int halt_main(void) {
e4b61340
LP
8586 int r;
8587
4fbd7192 8588 r = logind_check_inhibitors(arg_action);
748ebafa
LP
8589 if (r < 0)
8590 return r;
b37844d3 8591
7f96539d
LP
8592 if (arg_when > 0)
8593 return logind_schedule_shutdown();
8594
bc8c2f5c 8595 if (geteuid() != 0) {
1ae17672 8596 if (arg_dry_run || arg_force > 0) {
fba868fa 8597 (void) must_be_root();
2ac3930f
IS
8598 return -EPERM;
8599 }
8600
7e59bfcb
LP
8601 /* Try logind if we are a normal user and no special
8602 * mode applies. Maybe PolicyKit allows us to shutdown
8603 * the machine. */
36b69c31 8604 if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT, ACTION_HALT)) {
4fbd7192 8605 r = logind_reboot(arg_action);
4c80c73c
KS
8606 if (r >= 0)
8607 return r;
a9085ea3 8608 if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
7f96539d
LP
8609 /* requested operation is not
8610 * supported on the local system or
8611 * already in progress */
a9085ea3
IS
8612 return r;
8613 /* on all other errors, try low-level operation */
4c80c73c 8614 }
bc8c2f5c
LP
8615 }
8616
1ae17672 8617 if (!arg_dry_run && !arg_force)
4fbd7192 8618 return start_with_fallback();
e4b61340 8619
2ac3930f
IS
8620 assert(geteuid() == 0);
8621
d90e1a30
LP
8622 if (!arg_no_wtmp) {
8623 if (sd_booted() > 0)
8624 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
7e59bfcb
LP
8625 else {
8626 r = utmp_put_shutdown();
8627 if (r < 0)
da927ba9 8628 log_warning_errno(r, "Failed to write utmp record: %m");
7e59bfcb 8629 }
d90e1a30 8630 }
e4b61340 8631
1ae17672 8632 if (arg_dry_run)
e4b61340
LP
8633 return 0;
8634
477def80 8635 r = halt_now(arg_action);
691395d8 8636 return log_error_errno(r, "Failed to reboot: %m");
e4b61340
LP
8637}
8638
8639static int runlevel_main(void) {
8640 int r, runlevel, previous;
8641
729e3769
LP
8642 r = utmp_get_runlevel(&runlevel, &previous);
8643 if (r < 0) {
8644 puts("unknown");
e4b61340
LP
8645 return r;
8646 }
8647
8648 printf("%c %c\n",
8649 previous <= 0 ? 'N' : previous,
8650 runlevel <= 0 ? 'N' : runlevel);
8651
8652 return 0;
8653}
8654
2cf05793 8655static int logind_cancel_shutdown(void) {
349cc4a5 8656#if ENABLE_LOGIND
4afd3348 8657 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192 8658 sd_bus *bus;
949d9ce9
LP
8659 int r;
8660
4fbd7192 8661 r = acquire_bus(BUS_FULL, &bus);
949d9ce9 8662 if (r < 0)
4fbd7192 8663 return r;
949d9ce9 8664
4fbd7192 8665 (void) logind_set_wall_message();
949d9ce9
LP
8666
8667 r = sd_bus_call_method(
4fbd7192 8668 bus,
949d9ce9
LP
8669 "org.freedesktop.login1",
8670 "/org/freedesktop/login1",
8671 "org.freedesktop.login1.Manager",
8672 "CancelScheduledShutdown",
8673 &error,
8674 NULL, NULL);
8675 if (r < 0)
8676 return log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s", bus_error_message(&error, r));
8677
8678 return 0;
2cf05793
LP
8679#else
8680 log_error("Not compiled with logind support, cannot cancel scheduled shutdowns.");
8681 return -ENOSYS;
8682#endif
949d9ce9
LP
8683}
8684
e4b61340 8685int main(int argc, char*argv[]) {
f459b602 8686 int r;
e4b61340 8687
acc28e2e
FB
8688 argv_cmdline = argv[0];
8689
a9cdc94f 8690 setlocale(LC_ALL, "");
e4b61340 8691 log_parse_environment();
2396fb04 8692 log_open();
592705f2 8693 sigbus_install();
e4b61340 8694
184ecaf7
DR
8695 /* Explicitly not on_tty() to avoid setting cached value.
8696 * This becomes relevant for piping output which might be
8697 * ellipsized. */
8698 original_stdout_is_tty = isatty(STDOUT_FILENO);
8699
04ebb595 8700 r = parse_argv(argc, argv);
f459b602 8701 if (r <= 0)
e4b61340 8702 goto finish;
7e4249b9 8703
040524b4 8704 if (arg_action != ACTION_SYSTEMCTL && running_in_chroot() > 0) {
60675884
LP
8705
8706 if (!arg_quiet)
8707 log_info("Running in chroot, ignoring request.");
f459b602 8708 r = 0;
82e23ddd
LP
8709 goto finish;
8710 }
8711
41dd15e4
LP
8712 /* systemctl_main() will print an error message for the bus
8713 * connection, but only if it needs to */
e4b61340
LP
8714
8715 switch (arg_action) {
8716
22f4096c 8717 case ACTION_SYSTEMCTL:
e449de87 8718 r = systemctl_main(argc, argv);
e4b61340 8719 break;
e4b61340 8720
081dc638
AJ
8721 /* Legacy command aliases set arg_action. They provide some fallbacks,
8722 * e.g. to tell sysvinit to reboot after you have installed systemd
8723 * binaries. */
8724
e4b61340
LP
8725 case ACTION_HALT:
8726 case ACTION_POWEROFF:
8727 case ACTION_REBOOT:
5622dde3 8728 case ACTION_KEXEC:
4fbd7192 8729 r = halt_main();
e4b61340
LP
8730 break;
8731
e4b61340
LP
8732 case ACTION_RUNLEVEL2:
8733 case ACTION_RUNLEVEL3:
8734 case ACTION_RUNLEVEL4:
8735 case ACTION_RUNLEVEL5:
8736 case ACTION_RESCUE:
4fbd7192 8737 r = start_with_fallback();
e4b61340 8738 break;
7e4249b9 8739
e4b61340
LP
8740 case ACTION_RELOAD:
8741 case ACTION_REEXEC:
4fbd7192 8742 r = reload_with_fallback();
e4b61340
LP
8743 break;
8744
949d9ce9 8745 case ACTION_CANCEL_SHUTDOWN:
2cf05793 8746 r = logind_cancel_shutdown();
f6144808
LP
8747 break;
8748
eb22ac37 8749 case ACTION_RUNLEVEL:
4f16c1f4
LP
8750 r = runlevel_main();
8751 break;
8752
081dc638
AJ
8753 case ACTION_EXIT:
8754 case ACTION_SUSPEND:
8755 case ACTION_HIBERNATE:
8756 case ACTION_HYBRID_SLEEP:
8757 case ACTION_EMERGENCY:
8758 case ACTION_DEFAULT:
8759 /* systemctl verbs with no equivalent in the legacy commands.
8760 * These cannot appear in arg_action. Fall through. */
8761
f459b602 8762 case _ACTION_INVALID:
e4b61340
LP
8763 default:
8764 assert_not_reached("Unknown action");
8765 }
7e4249b9
LP
8766
8767finish:
cf647b69
LP
8768 release_busses();
8769
f459b602
MAP
8770 pager_close();
8771 ask_password_agent_close();
8772 polkit_agent_close();
7e4249b9 8773
20b3f379 8774 strv_free(arg_types);
9b9b3d36 8775 strv_free(arg_states);
20b3f379 8776 strv_free(arg_properties);
ea4a240d 8777
172d7abf 8778 strv_free(arg_wall);
0f03c2a4 8779 free(arg_root);
4bb2e9d4 8780 free(arg_esp_path);
172d7abf 8781
404f08d3 8782 /* Note that we return r here, not EXIT_SUCCESS, so that we can implement the LSB-like return codes */
9eb4a501 8783 return r < 0 ? EXIT_FAILURE : r;
7e4249b9 8784}