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