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