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