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