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