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