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