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