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