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