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