]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl.c
util-lib: split string parsing related calls from util.[ch] into parse-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
OS
3481
3482 if (path_get_parent(*dropin, &dir) < 0) {
3483 log_oom();
3484 return;
3485 }
3486
856323c9 3487 printf("%s\n %s", dir,
76d14b87
OS
3488 draw_special_char(DRAW_TREE_RIGHT));
3489 }
3490
3491 last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
3492
2b6bf07d 3493 printf("%s%s", basename(*dropin), last ? "\n" : ", ");
76d14b87 3494 }
76d14b87
OS
3495 }
3496
2ee68f72 3497 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2ee68f72 3498 if (ss)
856323c9 3499 printf(" Active: %s%s (%s)%s",
b0d14c69 3500 active_on, strna(i->active_state), ss, active_off);
2ee68f72 3501 else
856323c9 3502 printf(" Active: %s%s%s",
b0d14c69 3503 active_on, strna(i->active_state), active_off);
61cbdc4b 3504
f42806df
LP
3505 if (!isempty(i->result) && !streq(i->result, "success"))
3506 printf(" (Result: %s)", i->result);
3507
584be568
LP
3508 timestamp = (streq_ptr(i->active_state, "active") ||
3509 streq_ptr(i->active_state, "reloading")) ? i->active_enter_timestamp :
3510 (streq_ptr(i->active_state, "inactive") ||
fdf20a31 3511 streq_ptr(i->active_state, "failed")) ? i->inactive_enter_timestamp :
584be568
LP
3512 streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp :
3513 i->active_exit_timestamp;
3514
bbb8486e 3515 s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
584be568
LP
3516 s2 = format_timestamp(since2, sizeof(since2), timestamp);
3517
3518 if (s1)
538da63d 3519 printf(" since %s; %s\n", s2, s1);
584be568 3520 else if (s2)
538da63d 3521 printf(" since %s\n", s2);
584be568
LP
3522 else
3523 printf("\n");
3524
90bbc946 3525 if (!i->condition_result && i->condition_timestamp > 0) {
bbb8486e 3526 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
90bbc946
LP
3527 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
3528
59fccdc5 3529 printf("Condition: start %scondition failed%s at %s%s%s\n",
1fc464f6 3530 ansi_highlight_yellow(), ansi_normal(),
5cfee414 3531 s2, s1 ? "; " : "", strempty(s1));
52990c2e
ZJS
3532 if (i->failed_condition_trigger)
3533 printf(" none of the trigger conditions were met\n");
3534 else if (i->failed_condition)
3535 printf(" %s=%s%s was not met\n",
3536 i->failed_condition,
3537 i->failed_condition_negate ? "!" : "",
59fccdc5
LP
3538 i->failed_condition_parameter);
3539 }
3540
3541 if (!i->assert_result && i->assert_timestamp > 0) {
3542 s1 = format_timestamp_relative(since1, sizeof(since1), i->assert_timestamp);
3543 s2 = format_timestamp(since2, sizeof(since2), i->assert_timestamp);
3544
3545 printf(" Assert: start %sassertion failed%s at %s%s%s\n",
1fc464f6 3546 ansi_highlight_red(), ansi_normal(),
5cfee414 3547 s2, s1 ? "; " : "", strempty(s1));
59fccdc5
LP
3548 if (i->failed_assert_trigger)
3549 printf(" none of the trigger assertions were met\n");
3550 else if (i->failed_assert)
3551 printf(" %s=%s%s was not met\n",
3552 i->failed_assert,
3553 i->failed_assert_negate ? "!" : "",
3554 i->failed_assert_parameter);
90bbc946
LP
3555 }
3556
61cbdc4b 3557 if (i->sysfs_path)
856323c9 3558 printf(" Device: %s\n", i->sysfs_path);
9feeba4b 3559 if (i->where)
856323c9 3560 printf(" Where: %s\n", i->where);
9feeba4b 3561 if (i->what)
856323c9 3562 printf(" What: %s\n", i->what);
49dbfa7b 3563
13160134 3564 STRV_FOREACH(t, i->documentation)
856323c9 3565 printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", *t);
49dbfa7b 3566
13160134 3567 STRV_FOREACH_PAIR(t, t2, i->listen)
856323c9 3568 printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
67419600 3569
b8131a87 3570 if (i->accept)
856323c9 3571 printf(" Accepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
61cbdc4b 3572
582a507f 3573 LIST_FOREACH(exec, p, i->exec) {
13160134 3574 _cleanup_free_ char *argv = NULL;
9a57c629 3575 bool good;
582a507f
LP
3576
3577 /* Only show exited processes here */
3578 if (p->code == 0)
3579 continue;
3580
13160134 3581 argv = strv_join(p->argv, " ");
1fa2f38f 3582 printf(" Process: "PID_FMT" %s=%s ", p->pid, p->name, strna(argv));
582a507f 3583
96342de6 3584 good = is_clean_exit_lsb(p->code, p->status, NULL);
9a57c629 3585 if (!good) {
0b5a519c 3586 on = ansi_highlight_red();
1fc464f6 3587 off = ansi_normal();
9a57c629
LP
3588 } else
3589 on = off = "";
3590
3591 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
3592
d06dacd0
LP
3593 if (p->code == CLD_EXITED) {
3594 const char *c;
3595
582a507f 3596 printf("status=%i", p->status);
d06dacd0 3597
1b64d026
LP
3598 c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
3599 if (c)
d06dacd0
LP
3600 printf("/%s", c);
3601
3602 } else
582a507f 3603 printf("signal=%s", signal_to_string(p->status));
9a57c629
LP
3604
3605 printf(")%s\n", off);
3606
582a507f
LP
3607 if (i->main_pid == p->pid &&
3608 i->start_timestamp == p->start_timestamp &&
3609 i->exit_timestamp == p->start_timestamp)
3610 /* Let's not show this twice */
3611 i->main_pid = 0;
3612
3613 if (p->pid == i->control_pid)
3614 i->control_pid = 0;
3615 }
3616
61cbdc4b 3617 if (i->main_pid > 0 || i->control_pid > 0) {
61cbdc4b 3618 if (i->main_pid > 0) {
8c06592f 3619 printf(" Main PID: "PID_FMT, i->main_pid);
61cbdc4b
LP
3620
3621 if (i->running) {
13160134
ZJS
3622 _cleanup_free_ char *comm = NULL;
3623 get_process_comm(i->main_pid, &comm);
3624 if (comm)
3625 printf(" (%s)", comm);
6d4fc029 3626 } else if (i->exit_code > 0) {
61cbdc4b
LP
3627 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
3628
d06dacd0
LP
3629 if (i->exit_code == CLD_EXITED) {
3630 const char *c;
3631
61cbdc4b 3632 printf("status=%i", i->exit_status);
d06dacd0 3633
1b64d026
LP
3634 c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
3635 if (c)
d06dacd0
LP
3636 printf("/%s", c);
3637
3638 } else
582a507f 3639 printf("signal=%s", signal_to_string(i->exit_status));
6d4fc029
LP
3640 printf(")");
3641 }
61cbdc4b 3642
13160134
ZJS
3643 if (i->control_pid > 0)
3644 printf(";");
3645 }
61cbdc4b
LP
3646
3647 if (i->control_pid > 0) {
13160134 3648 _cleanup_free_ char *c = NULL;
61cbdc4b 3649
8c06592f 3650 printf(" %8s: "PID_FMT, i->main_pid ? "" : " Control", i->control_pid);
61cbdc4b 3651
13160134
ZJS
3652 get_process_comm(i->control_pid, &c);
3653 if (c)
3654 printf(" (%s)", c);
61cbdc4b
LP
3655 }
3656
3657 printf("\n");
3658 }
3659
17bb7382 3660 if (i->status_text)
856323c9 3661 printf(" Status: \"%s\"\n", i->status_text);
b4af5a80
LP
3662 if (i->status_errno > 0)
3663 printf(" Error: %i (%s)\n", i->status_errno, strerror(i->status_errno));
17bb7382 3664
03a7b521
LP
3665 if (i->tasks_current != (uint64_t) -1) {
3666 printf(" Tasks: %" PRIu64, i->tasks_current);
3667
3668 if (i->tasks_max != (uint64_t) -1)
3669 printf(" (limit: %" PRIi64 ")\n", i->tasks_max);
3670 else
3671 printf("\n");
3672 }
3673
934277fe
LP
3674 if (i->memory_current != (uint64_t) -1) {
3675 char buf[FORMAT_BYTES_MAX];
3676
3677 printf(" Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current));
3678
3679 if (i->memory_limit != (uint64_t) -1)
3680 printf(" (limit: %s)\n", format_bytes(buf, sizeof(buf), i->memory_limit));
3681 else
3682 printf("\n");
3683 }
3684
5ad096b3
LP
3685 if (i->cpu_usage_nsec != (uint64_t) -1) {
3686 char buf[FORMAT_TIMESPAN_MAX];
3687 printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
3688 }
3689
4ad49000 3690 if (i->control_group &&
8fcf784d 3691 (i->main_pid > 0 || i->control_pid > 0 ||
4c315c2c 3692 (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE) || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group) == 0))) {
ab35fb1b
LP
3693 unsigned c;
3694
4ad49000 3695 printf(" CGroup: %s\n", i->control_group);
ab35fb1b 3696
4c315c2c
IS
3697 if (IN_SET(arg_transport,
3698 BUS_TRANSPORT_LOCAL,
3699 BUS_TRANSPORT_MACHINE)) {
b69d29ce
LP
3700 unsigned k = 0;
3701 pid_t extra[2];
8fcf784d 3702 static const char prefix[] = " ";
b69d29ce
LP
3703
3704 c = columns();
e8853816
ZJS
3705 if (c > sizeof(prefix) - 1)
3706 c -= sizeof(prefix) - 1;
a8f11321
LP
3707 else
3708 c = 0;
ab35fb1b 3709
b69d29ce
LP
3710 if (i->main_pid > 0)
3711 extra[k++] = i->main_pid;
3712
3713 if (i->control_pid > 0)
3714 extra[k++] = i->control_pid;
3715
3c756001 3716 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, false, extra, k, get_output_flags());
a8f11321 3717 }
c59760ee 3718 }
45fb0699 3719
ece174c5 3720 if (i->id && arg_transport == BUS_TRANSPORT_LOCAL)
3c756001
LP
3721 show_journal_by_unit(
3722 stdout,
3723 i->id,
3724 arg_output,
3725 0,
3726 i->inactive_exit_timestamp_monotonic,
3727 arg_lines,
3728 getuid(),
3729 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
3730 SD_JOURNAL_LOCAL_ONLY,
3731 arg_scope == UNIT_FILE_SYSTEM,
3732 ellipsized);
86aa7ba4 3733
45fb0699 3734 if (i->need_daemon_reload)
3f36991e 3735 warn_unit_file_changed(i->id);
61cbdc4b
LP
3736}
3737
b43f208f 3738static void show_unit_help(UnitStatusInfo *i) {
256425cc
LP
3739 char **p;
3740
3741 assert(i);
3742
3743 if (!i->documentation) {
3744 log_info("Documentation for %s not known.", i->id);
3745 return;
3746 }
3747
78002a67
ZJS
3748 STRV_FOREACH(p, i->documentation)
3749 if (startswith(*p, "man:"))
3750 show_man_page(*p + 4, false);
3751 else
0315fe37 3752 log_info("Can't show: %s", *p);
256425cc
LP
3753}
3754
f459b602
MAP
3755static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *i, const char *contents) {
3756 int r;
61cbdc4b 3757
a4c279f8 3758 assert(name);
f459b602 3759 assert(m);
a4c279f8
LP
3760 assert(i);
3761
f459b602 3762 switch (contents[0]) {
61cbdc4b 3763
f459b602 3764 case SD_BUS_TYPE_STRING: {
61cbdc4b
LP
3765 const char *s;
3766
f459b602
MAP
3767 r = sd_bus_message_read(m, "s", &s);
3768 if (r < 0)
3769 return bus_log_parse_error(r);
61cbdc4b 3770
37a0d5bf 3771 if (!isempty(s)) {
61cbdc4b
LP
3772 if (streq(name, "Id"))
3773 i->id = s;
3774 else if (streq(name, "LoadState"))
3775 i->load_state = s;
3776 else if (streq(name, "ActiveState"))
3777 i->active_state = s;
3778 else if (streq(name, "SubState"))
3779 i->sub_state = s;
3780 else if (streq(name, "Description"))
3781 i->description = s;
3782 else if (streq(name, "FragmentPath"))
1b64d026
LP
3783 i->fragment_path = s;
3784 else if (streq(name, "SourcePath"))
3785 i->source_path = s;
286ca485 3786#ifndef NOLEGACY
a00963a2
LP
3787 else if (streq(name, "DefaultControlGroup")) {
3788 const char *e;
3789 e = startswith(s, SYSTEMD_CGROUP_CONTROLLER ":");
3790 if (e)
3791 i->control_group = e;
3792 }
4ad49000 3793#endif
37a0d5bf
LP
3794 else if (streq(name, "ControlGroup"))
3795 i->control_group = s;
61cbdc4b
LP
3796 else if (streq(name, "StatusText"))
3797 i->status_text = s;
175728c4
HH
3798 else if (streq(name, "PIDFile"))
3799 i->pid_file = s;
61cbdc4b
LP
3800 else if (streq(name, "SysFSPath"))
3801 i->sysfs_path = s;
3802 else if (streq(name, "Where"))
3803 i->where = s;
3804 else if (streq(name, "What"))
3805 i->what = s;
4a9e2fff
LP
3806 else if (streq(name, "Following"))
3807 i->following = s;
a4375746
LP
3808 else if (streq(name, "UnitFileState"))
3809 i->unit_file_state = s;
d2dc52db
LP
3810 else if (streq(name, "UnitFilePreset"))
3811 i->unit_file_preset = s;
f42806df
LP
3812 else if (streq(name, "Result"))
3813 i->result = s;
61cbdc4b
LP
3814 }
3815
3816 break;
3817 }
3818
f459b602
MAP
3819 case SD_BUS_TYPE_BOOLEAN: {
3820 int b;
b8131a87 3821
f459b602
MAP
3822 r = sd_bus_message_read(m, "b", &b);
3823 if (r < 0)
3824 return bus_log_parse_error(r);
b8131a87
LP
3825
3826 if (streq(name, "Accept"))
3827 i->accept = b;
45fb0699
LP
3828 else if (streq(name, "NeedDaemonReload"))
3829 i->need_daemon_reload = b;
90bbc946
LP
3830 else if (streq(name, "ConditionResult"))
3831 i->condition_result = b;
59fccdc5
LP
3832 else if (streq(name, "AssertResult"))
3833 i->assert_result = b;
b8131a87
LP
3834
3835 break;
3836 }
3837
f459b602 3838 case SD_BUS_TYPE_UINT32: {
61cbdc4b
LP
3839 uint32_t u;
3840
f459b602
MAP
3841 r = sd_bus_message_read(m, "u", &u);
3842 if (r < 0)
3843 return bus_log_parse_error(r);
61cbdc4b
LP
3844
3845 if (streq(name, "MainPID")) {
3846 if (u > 0) {
3847 i->main_pid = (pid_t) u;
3848 i->running = true;
3849 }
3850 } else if (streq(name, "ControlPID"))
3851 i->control_pid = (pid_t) u;
3852 else if (streq(name, "ExecMainPID")) {
3853 if (u > 0)
3854 i->main_pid = (pid_t) u;
3855 } else if (streq(name, "NAccepted"))
3856 i->n_accepted = u;
3857 else if (streq(name, "NConnections"))
3858 i->n_connections = u;
3859
3860 break;
3861 }
3862
f459b602 3863 case SD_BUS_TYPE_INT32: {
61cbdc4b
LP
3864 int32_t j;
3865
f459b602
MAP
3866 r = sd_bus_message_read(m, "i", &j);
3867 if (r < 0)
3868 return bus_log_parse_error(r);
61cbdc4b
LP
3869
3870 if (streq(name, "ExecMainCode"))
3871 i->exit_code = (int) j;
3872 else if (streq(name, "ExecMainStatus"))
3873 i->exit_status = (int) j;
b4af5a80
LP
3874 else if (streq(name, "StatusErrno"))
3875 i->status_errno = (int) j;
61cbdc4b
LP
3876
3877 break;
3878 }
3879
f459b602 3880 case SD_BUS_TYPE_UINT64: {
61cbdc4b
LP
3881 uint64_t u;
3882
f459b602
MAP
3883 r = sd_bus_message_read(m, "t", &u);
3884 if (r < 0)
3885 return bus_log_parse_error(r);
61cbdc4b
LP
3886
3887 if (streq(name, "ExecMainStartTimestamp"))
3888 i->start_timestamp = (usec_t) u;
3889 else if (streq(name, "ExecMainExitTimestamp"))
3890 i->exit_timestamp = (usec_t) u;
584be568
LP
3891 else if (streq(name, "ActiveEnterTimestamp"))
3892 i->active_enter_timestamp = (usec_t) u;
3893 else if (streq(name, "InactiveEnterTimestamp"))
3894 i->inactive_enter_timestamp = (usec_t) u;
3895 else if (streq(name, "InactiveExitTimestamp"))
3896 i->inactive_exit_timestamp = (usec_t) u;
df50185b
LP
3897 else if (streq(name, "InactiveExitTimestampMonotonic"))
3898 i->inactive_exit_timestamp_monotonic = (usec_t) u;
584be568
LP
3899 else if (streq(name, "ActiveExitTimestamp"))
3900 i->active_exit_timestamp = (usec_t) u;
90bbc946
LP
3901 else if (streq(name, "ConditionTimestamp"))
3902 i->condition_timestamp = (usec_t) u;
59fccdc5
LP
3903 else if (streq(name, "AssertTimestamp"))
3904 i->assert_timestamp = (usec_t) u;
934277fe
LP
3905 else if (streq(name, "MemoryCurrent"))
3906 i->memory_current = u;
3907 else if (streq(name, "MemoryLimit"))
3908 i->memory_limit = u;
03a7b521
LP
3909 else if (streq(name, "TasksCurrent"))
3910 i->tasks_current = u;
3911 else if (streq(name, "TasksMax"))
3912 i->tasks_max = u;
5ad096b3
LP
3913 else if (streq(name, "CPUUsageNSec"))
3914 i->cpu_usage_nsec = u;
61cbdc4b
LP
3915
3916 break;
3917 }
582a507f 3918
f459b602 3919 case SD_BUS_TYPE_ARRAY:
582a507f 3920
f459b602
MAP
3921 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
3922 _cleanup_free_ ExecStatusInfo *info = NULL;
582a507f 3923
f459b602
MAP
3924 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
3925 if (r < 0)
3926 return bus_log_parse_error(r);
582a507f 3927
f459b602
MAP
3928 info = new0(ExecStatusInfo, 1);
3929 if (!info)
3930 return log_oom();
582a507f 3931
f459b602 3932 while ((r = exec_status_info_deserialize(m, info)) > 0) {
0129173a 3933
f459b602
MAP
3934 info->name = strdup(name);
3935 if (!info->name)
691395d8 3936 return log_oom();
582a507f 3937
71fda00f 3938 LIST_PREPEND(exec, i->exec, info);
582a507f 3939
f459b602
MAP
3940 info = new0(ExecStatusInfo, 1);
3941 if (!info)
691395d8 3942 return log_oom();
49dbfa7b 3943 }
67419600 3944
f459b602
MAP
3945 if (r < 0)
3946 return bus_log_parse_error(r);
67419600 3947
f459b602
MAP
3948 r = sd_bus_message_exit_container(m);
3949 if (r < 0)
3950 return bus_log_parse_error(r);
67419600 3951
f459b602 3952 return 0;
67419600 3953
f459b602
MAP
3954 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
3955 const char *type, *path;
13160134 3956
f459b602
MAP
3957 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
3958 if (r < 0)
3959 return bus_log_parse_error(r);
67419600 3960
f459b602 3961 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0) {
67419600 3962
f459b602
MAP
3963 r = strv_extend(&i->listen, type);
3964 if (r < 0)
3965 return r;
67419600 3966
f459b602
MAP
3967 r = strv_extend(&i->listen, path);
3968 if (r < 0)
3969 return r;
3970 }
76d14b87 3971 if (r < 0)
f459b602 3972 return bus_log_parse_error(r);
76d14b87 3973
f459b602
MAP
3974 r = sd_bus_message_exit_container(m);
3975 if (r < 0)
3976 return bus_log_parse_error(r);
49dbfa7b 3977
f459b602 3978 return 0;
49dbfa7b 3979
f459b602 3980 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "DropInPaths")) {
49dbfa7b 3981
f459b602
MAP
3982 r = sd_bus_message_read_strv(m, &i->dropin_paths);
3983 if (r < 0)
3984 return bus_log_parse_error(r);
49dbfa7b 3985
f459b602 3986 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "Documentation")) {
49dbfa7b 3987
f459b602
MAP
3988 r = sd_bus_message_read_strv(m, &i->documentation);
3989 if (r < 0)
3990 return bus_log_parse_error(r);
52990c2e 3991
f459b602
MAP
3992 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Conditions")) {
3993 const char *cond, *param;
3994 int trigger, negate;
3995 int32_t state;
52990c2e 3996
f459b602
MAP
3997 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
3998 if (r < 0)
3999 return bus_log_parse_error(r);
4000
4001 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
4002 log_debug("%s %d %d %s %d", cond, trigger, negate, param, state);
4003 if (state < 0 && (!trigger || !i->failed_condition)) {
4004 i->failed_condition = cond;
4005 i->failed_condition_trigger = trigger;
4006 i->failed_condition_negate = negate;
59fccdc5
LP
4007 i->failed_condition_parameter = param;
4008 }
4009 }
4010 if (r < 0)
4011 return bus_log_parse_error(r);
4012
4013 r = sd_bus_message_exit_container(m);
4014 if (r < 0)
4015 return bus_log_parse_error(r);
4016
4017 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Asserts")) {
4018 const char *cond, *param;
4019 int trigger, negate;
4020 int32_t state;
4021
4022 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
4023 if (r < 0)
4024 return bus_log_parse_error(r);
4025
4026 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
4027 log_debug("%s %d %d %s %d", cond, trigger, negate, param, state);
4028 if (state < 0 && (!trigger || !i->failed_assert)) {
4029 i->failed_assert = cond;
4030 i->failed_assert_trigger = trigger;
4031 i->failed_assert_negate = negate;
4032 i->failed_assert_parameter = param;
f459b602 4033 }
582a507f 4034 }
f459b602
MAP
4035 if (r < 0)
4036 return bus_log_parse_error(r);
4037
4038 r = sd_bus_message_exit_container(m);
4039 if (r < 0)
4040 return bus_log_parse_error(r);
4041
4042 } else
4043 goto skip;
582a507f
LP
4044
4045 break;
9f39404c 4046
f459b602 4047 case SD_BUS_TYPE_STRUCT_BEGIN:
9f39404c
LP
4048
4049 if (streq(name, "LoadError")) {
9f39404c 4050 const char *n, *message;
9f39404c 4051
f459b602 4052 r = sd_bus_message_read(m, "(ss)", &n, &message);
9f39404c 4053 if (r < 0)
f459b602 4054 return bus_log_parse_error(r);
9f39404c
LP
4055
4056 if (!isempty(message))
4057 i->load_error = message;
f459b602
MAP
4058 } else
4059 goto skip;
9f39404c
LP
4060
4061 break;
f459b602
MAP
4062
4063 default:
4064 goto skip;
9f39404c 4065 }
f459b602
MAP
4066
4067 return 0;
4068
4069skip:
4070 r = sd_bus_message_skip(m, contents);
4071 if (r < 0)
4072 return bus_log_parse_error(r);
61cbdc4b
LP
4073
4074 return 0;
4075}
4076
f459b602
MAP
4077static int print_property(const char *name, sd_bus_message *m, const char *contents) {
4078 int r;
4079
48220598 4080 assert(name);
f459b602 4081 assert(m);
48220598 4082
61cbdc4b
LP
4083 /* This is a low-level property printer, see
4084 * print_status_info() for the nicer output */
4085
852c1b4d
ZJS
4086 if (arg_properties && !strv_find(arg_properties, name)) {
4087 /* skip what we didn't read */
4088 r = sd_bus_message_skip(m, contents);
4089 return r;
4090 }
48220598 4091
f459b602 4092 switch (contents[0]) {
48220598 4093
f459b602 4094 case SD_BUS_TYPE_STRUCT_BEGIN:
48220598 4095
f459b602 4096 if (contents[1] == SD_BUS_TYPE_UINT32 && streq(name, "Job")) {
48220598
LP
4097 uint32_t u;
4098
f459b602
MAP
4099 r = sd_bus_message_read(m, "(uo)", &u, NULL);
4100 if (r < 0)
4101 return bus_log_parse_error(r);
48220598 4102
f459b602 4103 if (u > 0)
8c06592f 4104 printf("%s=%"PRIu32"\n", name, u);
48220598
LP
4105 else if (arg_all)
4106 printf("%s=\n", name);
4107
4108 return 0;
f459b602
MAP
4109
4110 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "Unit")) {
48220598
LP
4111 const char *s;
4112
f459b602
MAP
4113 r = sd_bus_message_read(m, "(so)", &s, NULL);
4114 if (r < 0)
4115 return bus_log_parse_error(r);
48220598 4116
f459b602 4117 if (arg_all || !isempty(s))
48220598
LP
4118 printf("%s=%s\n", name, s);
4119
4120 return 0;
f459b602
MAP
4121
4122 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "LoadError")) {
9f39404c
LP
4123 const char *a = NULL, *b = NULL;
4124
f459b602
MAP
4125 r = sd_bus_message_read(m, "(ss)", &a, &b);
4126 if (r < 0)
4127 return bus_log_parse_error(r);
9f39404c
LP
4128
4129 if (arg_all || !isempty(a) || !isempty(b))
4130 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
f786e80d 4131
57183d11
LP
4132 return 0;
4133 } else if (streq_ptr(name, "SystemCallFilter")) {
4134 _cleanup_strv_free_ char **l = NULL;
4135 int whitelist;
4136
4137 r = sd_bus_message_enter_container(m, 'r', "bas");
4138 if (r < 0)
4139 return bus_log_parse_error(r);
4140
4141 r = sd_bus_message_read(m, "b", &whitelist);
4142 if (r < 0)
4143 return bus_log_parse_error(r);
4144
4145 r = sd_bus_message_read_strv(m, &l);
4146 if (r < 0)
4147 return bus_log_parse_error(r);
4148
4149 r = sd_bus_message_exit_container(m);
4150 if (r < 0)
4151 return bus_log_parse_error(r);
4152
4153 if (arg_all || whitelist || !strv_isempty(l)) {
4154 bool first = true;
4155 char **i;
4156
4157 fputs(name, stdout);
4158 fputc('=', stdout);
4159
4160 if (!whitelist)
4161 fputc('~', stdout);
4162
4163 STRV_FOREACH(i, l) {
4164 if (first)
4165 first = false;
4166 else
4167 fputc(' ', stdout);
4168
4169 fputs(*i, stdout);
4170 }
4171 fputc('\n', stdout);
4172 }
4173
f786e80d 4174 return 0;
48220598
LP
4175 }
4176
4177 break;
48220598 4178
f459b602 4179 case SD_BUS_TYPE_ARRAY:
48220598 4180
f459b602
MAP
4181 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "EnvironmentFiles")) {
4182 const char *path;
4183 int ignore;
8c7be95e 4184
f459b602
MAP
4185 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sb)");
4186 if (r < 0)
4187 return bus_log_parse_error(r);
8c7be95e 4188
f459b602
MAP
4189 while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
4190 printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
8c7be95e 4191
f459b602
MAP
4192 if (r < 0)
4193 return bus_log_parse_error(r);
8c7be95e 4194
f459b602
MAP
4195 r = sd_bus_message_exit_container(m);
4196 if (r < 0)
4197 return bus_log_parse_error(r);
8c7be95e
LP
4198
4199 return 0;
4200
f459b602
MAP
4201 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Paths")) {
4202 const char *type, *path;
67419600 4203
f459b602
MAP
4204 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4205 if (r < 0)
4206 return bus_log_parse_error(r);
ebf57b80 4207
f459b602
MAP
4208 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
4209 printf("%s=%s\n", type, path);
4210 if (r < 0)
4211 return bus_log_parse_error(r);
ebf57b80 4212
f459b602
MAP
4213 r = sd_bus_message_exit_container(m);
4214 if (r < 0)
4215 return bus_log_parse_error(r);
ebf57b80 4216
707e5e52 4217 return 0;
582a507f 4218
f459b602
MAP
4219 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
4220 const char *type, *path;
67419600 4221
f459b602
MAP
4222 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4223 if (r < 0)
4224 return bus_log_parse_error(r);
67419600 4225
f459b602
MAP
4226 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
4227 printf("Listen%s=%s\n", type, path);
4228 if (r < 0)
4229 return bus_log_parse_error(r);
67419600 4230
f459b602
MAP
4231 r = sd_bus_message_exit_container(m);
4232 if (r < 0)
4233 return bus_log_parse_error(r);
67419600
OS
4234
4235 return 0;
4236
f459b602
MAP
4237 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Timers")) {
4238 const char *base;
4239 uint64_t value, next_elapse;
707e5e52 4240
f459b602
MAP
4241 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(stt)");
4242 if (r < 0)
4243 return bus_log_parse_error(r);
552e4331 4244
f459b602
MAP
4245 while ((r = sd_bus_message_read(m, "(stt)", &base, &value, &next_elapse)) > 0) {
4246 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
fe68089d 4247
f459b602
MAP
4248 printf("%s={ value=%s ; next_elapse=%s }\n",
4249 base,
4250 format_timespan(timespan1, sizeof(timespan1), value, 0),
4251 format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
fe68089d 4252 }
f459b602
MAP
4253 if (r < 0)
4254 return bus_log_parse_error(r);
4255
4256 r = sd_bus_message_exit_container(m);
4257 if (r < 0)
4258 return bus_log_parse_error(r);
fe68089d
LP
4259
4260 return 0;
fe68089d 4261
f459b602
MAP
4262 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
4263 ExecStatusInfo info = {};
4264
4265 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
4266 if (r < 0)
4267 return bus_log_parse_error(r);
4268
4269 while ((r = exec_status_info_deserialize(m, &info)) > 0) {
4270 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
4271 _cleanup_free_ char *tt;
4272
4273 tt = strv_join(info.argv, " ");
4274
8c06592f 4275 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
4276 name,
4277 strna(info.path),
4278 strna(tt),
4279 yes_no(info.ignore),
4280 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
4281 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
8c06592f 4282 info.pid,
f459b602
MAP
4283 sigchld_code_to_string(info.code),
4284 info.status,
4285 info.code == CLD_EXITED ? "" : "/",
4286 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
fe68089d 4287
582a507f
LP
4288 free(info.path);
4289 strv_free(info.argv);
f459b602 4290 zero(info);
707e5e52
LP
4291 }
4292
f459b602
MAP
4293 r = sd_bus_message_exit_container(m);
4294 if (r < 0)
4295 return bus_log_parse_error(r);
4296
48220598 4297 return 0;
4ad49000 4298
f459b602
MAP
4299 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "DeviceAllow")) {
4300 const char *path, *rwm;
4ad49000 4301
f459b602
MAP
4302 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4303 if (r < 0)
4304 return bus_log_parse_error(r);
4ad49000 4305
f459b602
MAP
4306 while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0)
4307 printf("%s=%s %s\n", name, strna(path), strna(rwm));
4308 if (r < 0)
4309 return bus_log_parse_error(r);
4ad49000 4310
f459b602
MAP
4311 r = sd_bus_message_exit_container(m);
4312 if (r < 0)
4313 return bus_log_parse_error(r);
4ad49000 4314
4ad49000
LP
4315 return 0;
4316
f459b602
MAP
4317 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "BlockIODeviceWeight")) {
4318 const char *path;
4319 uint64_t weight;
b8ab2dc6 4320
f459b602
MAP
4321 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
4322 if (r < 0)
4323 return bus_log_parse_error(r);
b8ab2dc6 4324
f459b602
MAP
4325 while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0)
4326 printf("%s=%s %" PRIu64 "\n", name, strna(path), weight);
4327 if (r < 0)
4328 return bus_log_parse_error(r);
b8ab2dc6 4329
f459b602
MAP
4330 r = sd_bus_message_exit_container(m);
4331 if (r < 0)
4332 return bus_log_parse_error(r);
b8ab2dc6 4333
b8ab2dc6
G
4334 return 0;
4335
f459b602
MAP
4336 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) {
4337 const char *path;
4338 uint64_t bandwidth;
4ad49000 4339
f459b602
MAP
4340 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
4341 if (r < 0)
4342 return bus_log_parse_error(r);
4ad49000 4343
f459b602
MAP
4344 while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0)
4345 printf("%s=%s %" PRIu64 "\n", name, strna(path), bandwidth);
4346 if (r < 0)
4347 return bus_log_parse_error(r);
4ad49000 4348
f459b602
MAP
4349 r = sd_bus_message_exit_container(m);
4350 if (r < 0)
4351 return bus_log_parse_error(r);
4ad49000 4352
4ad49000 4353 return 0;
48220598
LP
4354 }
4355
4356 break;
4357 }
4358
f459b602
MAP
4359 r = bus_print_property(name, m, arg_all);
4360 if (r < 0)
4361 return bus_log_parse_error(r);
4362
4363 if (r == 0) {
4364 r = sd_bus_message_skip(m, contents);
4365 if (r < 0)
4366 return bus_log_parse_error(r);
a4c279f8 4367
f459b602
MAP
4368 if (arg_all)
4369 printf("%s=[unprintable]\n", name);
4370 }
48220598
LP
4371
4372 return 0;
4373}
4374
f459b602
MAP
4375static int show_one(
4376 const char *verb,
4377 sd_bus *bus,
4378 const char *path,
4379 bool show_properties,
4380 bool *new_line,
4381 bool *ellipsized) {
4382
4383 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4384 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
934277fe
LP
4385 UnitStatusInfo info = {
4386 .memory_current = (uint64_t) -1,
4387 .memory_limit = (uint64_t) -1,
5ad096b3 4388 .cpu_usage_nsec = (uint64_t) -1,
03a7b521
LP
4389 .tasks_current = (uint64_t) -1,
4390 .tasks_max = (uint64_t) -1,
934277fe 4391 };
582a507f 4392 ExecStatusInfo *p;
f459b602 4393 int r;
48220598 4394
48220598 4395 assert(path);
61cbdc4b 4396 assert(new_line);
48220598 4397
e3e0314b
ZJS
4398 log_debug("Showing one %s", path);
4399
f459b602 4400 r = sd_bus_call_method(
f22f08cd
SP
4401 bus,
4402 "org.freedesktop.systemd1",
4403 path,
4404 "org.freedesktop.DBus.Properties",
4405 "GetAll",
f459b602 4406 &error,
f22f08cd 4407 &reply,
f459b602 4408 "s", "");
4c3e8e39
LP
4409 if (r < 0)
4410 return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
48220598 4411
f459b602
MAP
4412 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
4413 if (r < 0)
4414 return bus_log_parse_error(r);
48220598 4415
61cbdc4b
LP
4416 if (*new_line)
4417 printf("\n");
4418
4419 *new_line = true;
4420
f459b602
MAP
4421 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
4422 const char *name, *contents;
0183528f 4423
f459b602
MAP
4424 r = sd_bus_message_read(reply, "s", &name);
4425 if (r < 0)
4426 return bus_log_parse_error(r);
48220598 4427
f459b602
MAP
4428 r = sd_bus_message_peek_type(reply, NULL, &contents);
4429 if (r < 0)
4430 return bus_log_parse_error(r);
4431
4432 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
4433 if (r < 0)
4434 return bus_log_parse_error(r);
48220598 4435
61cbdc4b 4436 if (show_properties)
f459b602 4437 r = print_property(name, reply, contents);
61cbdc4b 4438 else
f459b602
MAP
4439 r = status_property(name, reply, &info, contents);
4440 if (r < 0)
4441 return r;
48220598 4442
f459b602
MAP
4443 r = sd_bus_message_exit_container(reply);
4444 if (r < 0)
4445 return bus_log_parse_error(r);
4446
4447 r = sd_bus_message_exit_container(reply);
4448 if (r < 0)
4449 return bus_log_parse_error(r);
48220598 4450 }
f459b602
MAP
4451 if (r < 0)
4452 return bus_log_parse_error(r);
4453
4454 r = sd_bus_message_exit_container(reply);
4455 if (r < 0)
4456 return bus_log_parse_error(r);
48220598 4457
f1e36d67
LP
4458 r = 0;
4459
256425cc 4460 if (!show_properties) {
b43f208f
KS
4461 if (streq(verb, "help"))
4462 show_unit_help(&info);
256425cc 4463 else
94e0bd7d 4464 print_status_info(&info, ellipsized);
256425cc 4465 }
f1e36d67 4466
49dbfa7b 4467 strv_free(info.documentation);
76d14b87 4468 strv_free(info.dropin_paths);
67419600 4469 strv_free(info.listen);
49dbfa7b 4470
22f4096c 4471 if (!streq_ptr(info.active_state, "active") &&
be8088a2 4472 !streq_ptr(info.active_state, "reloading") &&
3b05b8b3 4473 streq(verb, "status")) {
22f4096c 4474 /* According to LSB: "program not running" */
175728c4 4475 /* 0: program is running or service is OK
41a55c46
ZJS
4476 * 1: program is dead and /run PID file exists
4477 * 2: program is dead and /run/lock lock file exists
175728c4
HH
4478 * 3: program is not running
4479 * 4: program or service status is unknown
4480 */
3b05b8b3 4481 if (info.pid_file && access(info.pid_file, F_OK) == 0)
175728c4
HH
4482 r = 1;
4483 else
4484 r = 3;
e9c1ea9d 4485 }
61cbdc4b 4486
582a507f 4487 while ((p = info.exec)) {
71fda00f 4488 LIST_REMOVE(exec, info.exec, p);
582a507f
LP
4489 exec_status_info_free(p);
4490 }
4491
48220598
LP
4492 return r;
4493}
4494
f74294c1 4495static int get_unit_dbus_path_by_pid(
f459b602
MAP
4496 sd_bus *bus,
4497 uint32_t pid,
f74294c1 4498 char **unit) {
f459b602
MAP
4499
4500 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4501 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
373d32c9 4502 char *u;
a223b325
MS
4503 int r;
4504
f459b602 4505 r = sd_bus_call_method(
f22f08cd
SP
4506 bus,
4507 "org.freedesktop.systemd1",
4508 "/org/freedesktop/systemd1",
4509 "org.freedesktop.systemd1.Manager",
4510 "GetUnitByPID",
f459b602 4511 &error,
f22f08cd 4512 &reply,
f459b602 4513 "u", pid);
691395d8
LP
4514 if (r < 0)
4515 return log_error_errno(r, "Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
a223b325 4516
373d32c9 4517 r = sd_bus_message_read(reply, "o", &u);
f459b602
MAP
4518 if (r < 0)
4519 return bus_log_parse_error(r);
4520
373d32c9
LP
4521 u = strdup(u);
4522 if (!u)
4523 return log_oom();
4524
4525 *unit = u;
f74294c1 4526 return 0;
a223b325
MS
4527}
4528
f459b602
MAP
4529static int show_all(
4530 const char* verb,
4531 sd_bus *bus,
4532 bool show_properties,
4533 bool *new_line,
4534 bool *ellipsized) {
4535
f459b602
MAP
4536 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4537 _cleanup_free_ UnitInfo *unit_infos = NULL;
4538 const UnitInfo *u;
4539 unsigned c;
5bb75bc7 4540 int r, ret = 0;
265a7a2a 4541
1238ee09 4542 r = get_unit_list(bus, NULL, NULL, &unit_infos, 0, &reply);
265a7a2a
ZJS
4543 if (r < 0)
4544 return r;
4545
dbed408b
LP
4546 pager_open_if_enabled();
4547
f459b602
MAP
4548 c = (unsigned) r;
4549
4550 qsort_safe(unit_infos, c, sizeof(UnitInfo), compare_unit_info);
991f2a39 4551
265a7a2a 4552 for (u = unit_infos; u < unit_infos + c; u++) {
7fd1b19b 4553 _cleanup_free_ char *p = NULL;
265a7a2a 4554
265a7a2a
ZJS
4555 p = unit_dbus_path_from_name(u->id);
4556 if (!p)
4557 return log_oom();
4558
94e0bd7d 4559 r = show_one(verb, bus, p, show_properties, new_line, ellipsized);
3df538da 4560 if (r < 0)
265a7a2a 4561 return r;
5bb75bc7
ZJS
4562 else if (r > 0 && ret == 0)
4563 ret = r;
265a7a2a
ZJS
4564 }
4565
5bb75bc7 4566 return ret;
265a7a2a
ZJS
4567}
4568
8fcf784d
LP
4569static int show_system_status(sd_bus *bus) {
4570 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
4571 _cleanup_free_ char *hn = NULL;
e7e55dbd 4572 _cleanup_(machine_info_clear) struct machine_info mi = {};
8fcf784d
LP
4573 const char *on, *off;
4574 int r;
4575
4576 hn = gethostname_malloc();
4577 if (!hn)
4578 return log_oom();
4579
4580 r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, &mi);
f647962d
MS
4581 if (r < 0)
4582 return log_error_errno(r, "Failed to read server status: %m");
8fcf784d 4583
8fcf784d
LP
4584 if (streq_ptr(mi.state, "degraded")) {
4585 on = ansi_highlight_red();
1fc464f6 4586 off = ansi_normal();
8fcf784d
LP
4587 } else if (!streq_ptr(mi.state, "running")) {
4588 on = ansi_highlight_yellow();
1fc464f6 4589 off = ansi_normal();
8fcf784d
LP
4590 } else
4591 on = off = "";
4592
6b01f1d3 4593 printf("%s%s%s %s\n", on, draw_special_char(DRAW_BLACK_CIRCLE), off, arg_host ? arg_host : hn);
b0d14c69 4594
8fcf784d
LP
4595 printf(" State: %s%s%s\n",
4596 on, strna(mi.state), off);
4597
4598 printf(" Jobs: %u queued\n", mi.n_jobs);
4599 printf(" Failed: %u units\n", mi.n_failed_units);
4600
4601 printf(" Since: %s; %s\n",
4602 format_timestamp(since2, sizeof(since2), mi.timestamp),
4603 format_timestamp_relative(since1, sizeof(since1), mi.timestamp));
4604
4605 printf(" CGroup: %s\n", mi.control_group ?: "/");
4c315c2c
IS
4606 if (IN_SET(arg_transport,
4607 BUS_TRANSPORT_LOCAL,
4608 BUS_TRANSPORT_MACHINE)) {
8fcf784d
LP
4609 static const char prefix[] = " ";
4610 unsigned c;
4611
4612 c = columns();
4613 if (c > sizeof(prefix) - 1)
4614 c -= sizeof(prefix) - 1;
4615 else
4616 c = 0;
4617
3c756001 4618 show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, false, get_output_flags());
8fcf784d
LP
4619 }
4620
8fcf784d
LP
4621 return 0;
4622}
4623
e449de87
LP
4624static int show(int argc, char *argv[], void *userdata) {
4625 bool show_properties, show_status, show_help, new_line = false;
94e0bd7d 4626 bool ellipsized = false;
e3e0314b 4627 int r, ret = 0;
4fbd7192 4628 sd_bus *bus;
48220598 4629
e449de87 4630 assert(argv);
48220598 4631
e449de87
LP
4632 show_properties = streq(argv[0], "show");
4633 show_status = streq(argv[0], "status");
4634 show_help = streq(argv[0], "help");
4635
4636 if (show_help && argc <= 1) {
4637 log_error("This command expects one or more unit names. Did you mean --help?");
4638 return -EINVAL;
4639 }
61cbdc4b 4640
ec14911e 4641 if (show_properties)
1968a360 4642 pager_open_if_enabled();
ec14911e 4643
40acc203
ZJS
4644 if (show_status)
4645 /* Increase max number of open files to 16K if we can, we
4646 * might needs this when browsing journal files, which might
4647 * be split up into many files. */
4648 setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
4649
4fbd7192
LP
4650 r = acquire_bus(BUS_MANAGER, &bus);
4651 if (r < 0)
4652 return r;
48220598 4653
4fbd7192 4654 /* If no argument is specified inspect the manager itself */
e449de87
LP
4655 if (show_properties && argc <= 1)
4656 return show_one(argv[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized);
48220598 4657
e449de87 4658 if (show_status && argc <= 1) {
8fcf784d 4659
c3441de0 4660 pager_open_if_enabled();
8fcf784d
LP
4661 show_system_status(bus);
4662 new_line = true;
4663
4664 if (arg_all)
e449de87 4665 ret = show_all(argv[0], bus, false, &new_line, &ellipsized);
8fcf784d 4666 } else {
e3e0314b
ZJS
4667 _cleanup_free_ char **patterns = NULL;
4668 char **name;
4669
e449de87 4670 STRV_FOREACH(name, strv_skip(argv, 1)) {
f74294c1 4671 _cleanup_free_ char *unit = NULL;
94e0bd7d 4672 uint32_t id;
48220598 4673
94e0bd7d 4674 if (safe_atou32(*name, &id) < 0) {
e3e0314b 4675 if (strv_push(&patterns, *name) < 0)
94e0bd7d 4676 return log_oom();
48220598 4677
e3e0314b 4678 continue;
94e0bd7d 4679 } else if (show_properties) {
94e0bd7d 4680 /* Interpret as job id */
f74294c1 4681 if (asprintf(&unit, "/org/freedesktop/systemd1/job/%u", id) < 0)
94e0bd7d 4682 return log_oom();
48220598 4683
94e0bd7d
ZJS
4684 } else {
4685 /* Interpret as PID */
f74294c1 4686 r = get_unit_dbus_path_by_pid(bus, id, &unit);
373d32c9 4687 if (r < 0) {
94e0bd7d 4688 ret = r;
373d32c9
LP
4689 continue;
4690 }
94e0bd7d 4691 }
f74294c1 4692
e449de87 4693 r = show_one(argv[0], bus, unit, show_properties, &new_line, &ellipsized);
5bb75bc7
ZJS
4694 if (r < 0)
4695 return r;
4696 else if (r > 0 && ret == 0)
4697 ret = r;
48220598 4698 }
94e0bd7d 4699
e3e0314b
ZJS
4700 if (!strv_isempty(patterns)) {
4701 _cleanup_strv_free_ char **names = NULL;
4702
4703 r = expand_names(bus, patterns, NULL, &names);
4704 if (r < 0)
691395d8 4705 return log_error_errno(r, "Failed to expand names: %m");
e3e0314b
ZJS
4706
4707 STRV_FOREACH(name, names) {
4708 _cleanup_free_ char *unit;
4709
4710 unit = unit_dbus_path_from_name(*name);
4711 if (!unit)
4712 return log_oom();
4713
e449de87 4714 r = show_one(argv[0], bus, unit, show_properties, &new_line, &ellipsized);
5bb75bc7
ZJS
4715 if (r < 0)
4716 return r;
4717 else if (r > 0 && ret == 0)
4718 ret = r;
e3e0314b
ZJS
4719 }
4720 }
4721 }
4722
94e0bd7d
ZJS
4723 if (ellipsized && !arg_quiet)
4724 printf("Hint: Some lines were ellipsized, use -l to show in full.\n");
48220598 4725
22f4096c 4726 return ret;
0183528f
LP
4727}
4728
8df18507
ZJS
4729static int init_home_and_lookup_paths(char **user_home, char **user_runtime, LookupPaths *lp) {
4730 int r;
4731
4732 assert(user_home);
4733 assert(user_runtime);
4734 assert(lp);
4735
4736 if (arg_scope == UNIT_FILE_USER) {
4737 r = user_config_home(user_home);
4738 if (r < 0)
4739 return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m");
4740 else if (r == 0)
4741 return log_error_errno(ENOTDIR, "Cannot find units: $XDG_CONFIG_HOME and $HOME are not set.");
4742
4743 r = user_runtime_dir(user_runtime);
4744 if (r < 0)
4745 return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m");
4746 else if (r == 0)
4747 return log_error_errno(ENOTDIR, "Cannot find units: $XDG_RUNTIME_DIR is not set.");
4748 }
4749
60d27f19 4750 r = lookup_paths_init_from_scope(lp, arg_scope, arg_root);
8df18507 4751 if (r < 0)
029009d4 4752 return log_error_errno(r, "Failed to query unit lookup paths: %m");
8df18507
ZJS
4753
4754 return 0;
4755}
4756
8527b07b
ZJS
4757static int cat_file(const char *filename, bool newline) {
4758 _cleanup_close_ int fd;
4759
4760 fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOCTTY);
4761 if (fd < 0)
4762 return -errno;
4763
4764 printf("%s%s# %s%s\n",
4765 newline ? "\n" : "",
4766 ansi_highlight_blue(),
4767 filename,
1fc464f6 4768 ansi_normal());
8527b07b
ZJS
4769 fflush(stdout);
4770
59f448cf 4771 return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, false);
8527b07b
ZJS
4772}
4773
e449de87 4774static int cat(int argc, char *argv[], void *userdata) {
ad2a0358
ZJS
4775 _cleanup_free_ char *user_home = NULL;
4776 _cleanup_free_ char *user_runtime = NULL;
4777 _cleanup_lookup_paths_free_ LookupPaths lp = {};
15ef1144
LP
4778 _cleanup_strv_free_ char **names = NULL;
4779 char **name;
4fbd7192
LP
4780 sd_bus *bus;
4781 bool first = true;
25586912 4782 int r;
15ef1144 4783
3e7eed84 4784 if (arg_transport != BUS_TRANSPORT_LOCAL) {
4fbd7192 4785 log_error("Cannot remotely cat units.");
3e495a66
ZJS
4786 return -EINVAL;
4787 }
4788
ad2a0358
ZJS
4789 r = init_home_and_lookup_paths(&user_home, &user_runtime, &lp);
4790 if (r < 0)
4791 return r;
4792
4fbd7192 4793 r = acquire_bus(BUS_MANAGER, &bus);
15ef1144 4794 if (r < 0)
4fbd7192 4795 return r;
15ef1144 4796
e449de87 4797 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
4fbd7192
LP
4798 if (r < 0)
4799 return log_error_errno(r, "Failed to expand names: %m");
ad2a0358 4800
15ef1144
LP
4801 pager_open_if_enabled();
4802
4803 STRV_FOREACH(name, names) {
ad2a0358 4804 _cleanup_free_ char *fragment_path = NULL;
15ef1144 4805 _cleanup_strv_free_ char **dropin_paths = NULL;
15ef1144
LP
4806 char **path;
4807
4fbd7192 4808 r = unit_find_paths(bus, *name, &lp, &fragment_path, &dropin_paths);
ad2a0358
ZJS
4809 if (r < 0)
4810 return r;
b5e6a600
IS
4811 else if (r == 0)
4812 return -ENOENT;
15ef1144
LP
4813
4814 if (first)
4815 first = false;
4816 else
4817 puts("");
4818
ad2a0358 4819 if (fragment_path) {
8527b07b
ZJS
4820 r = cat_file(fragment_path, false);
4821 if (r < 0)
4822 return log_warning_errno(r, "Failed to cat %s: %m", fragment_path);
15ef1144
LP
4823 }
4824
4825 STRV_FOREACH(path, dropin_paths) {
8527b07b
ZJS
4826 r = cat_file(*path, path == dropin_paths);
4827 if (r < 0)
4828 return log_warning_errno(r, "Failed to cat %s: %m", *path);
15ef1144
LP
4829 }
4830 }
4831
25586912 4832 return 0;
15ef1144
LP
4833}
4834
e449de87 4835static int set_property(int argc, char *argv[], void *userdata) {
f459b602
MAP
4836 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
4837 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
68372da6 4838 _cleanup_free_ char *n = NULL;
4fbd7192 4839 sd_bus *bus;
8e2af478
LP
4840 char **i;
4841 int r;
4842
079dac08
LP
4843 polkit_agent_open_if_enabled();
4844
4fbd7192
LP
4845 r = acquire_bus(BUS_MANAGER, &bus);
4846 if (r < 0)
4847 return r;
4848
f459b602
MAP
4849 r = sd_bus_message_new_method_call(
4850 bus,
151b9b96 4851 &m,
8e2af478
LP
4852 "org.freedesktop.systemd1",
4853 "/org/freedesktop/systemd1",
4854 "org.freedesktop.systemd1.Manager",
151b9b96 4855 "SetUnitProperties");
f459b602
MAP
4856 if (r < 0)
4857 return bus_log_create_error(r);
8e2af478 4858
e449de87 4859 r = unit_name_mangle(argv[1], UNIT_NAME_NOGLOB, &n);
7410616c
LP
4860 if (r < 0)
4861 return log_error_errno(r, "Failed to mangle unit name: %m");
68372da6 4862
f459b602
MAP
4863 r = sd_bus_message_append(m, "sb", n, arg_runtime);
4864 if (r < 0)
4865 return bus_log_create_error(r);
8e2af478 4866
f459b602
MAP
4867 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, "(sv)");
4868 if (r < 0)
4869 return bus_log_create_error(r);
8e2af478 4870
e449de87 4871 STRV_FOREACH(i, strv_skip(argv, 2)) {
f459b602
MAP
4872 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
4873 if (r < 0)
4874 return bus_log_create_error(r);
8e2af478 4875
df31a6c0 4876 r = bus_append_unit_property_assignment(m, *i);
8e2af478
LP
4877 if (r < 0)
4878 return r;
4879
f459b602
MAP
4880 r = sd_bus_message_close_container(m);
4881 if (r < 0)
4882 return bus_log_create_error(r);
8e2af478
LP
4883 }
4884
f459b602
MAP
4885 r = sd_bus_message_close_container(m);
4886 if (r < 0)
4887 return bus_log_create_error(r);
8e2af478 4888
c49b30a2 4889 r = sd_bus_call(bus, m, 0, &error, NULL);
691395d8
LP
4890 if (r < 0)
4891 return log_error_errno(r, "Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
8e2af478
LP
4892
4893 return 0;
4894}
4895
e449de87 4896static int snapshot(int argc, char *argv[], void *userdata) {
f459b602 4897 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
6e646d22 4898 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
f459b602
MAP
4899 _cleanup_free_ char *n = NULL, *id = NULL;
4900 const char *path;
4fbd7192 4901 sd_bus *bus;
7e4249b9 4902 int r;
7e4249b9 4903
079dac08
LP
4904 polkit_agent_open_if_enabled();
4905
e449de87
LP
4906 if (argc > 1) {
4907 r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".snapshot", &n);
7410616c
LP
4908 if (r < 0)
4909 return log_error_errno(r, "Failed to generate unit name: %m");
4910 } else {
1dcf6065 4911 n = strdup("");
7410616c
LP
4912 if (!n)
4913 return log_oom();
4914 }
7e4249b9 4915
4fbd7192
LP
4916 r = acquire_bus(BUS_MANAGER, &bus);
4917 if (r < 0)
4918 return r;
4919
6e646d22 4920 r = sd_bus_call_method(
f22f08cd
SP
4921 bus,
4922 "org.freedesktop.systemd1",
4923 "/org/freedesktop/systemd1",
4924 "org.freedesktop.systemd1.Manager",
6e646d22
LP
4925 "CreateSnapshot",
4926 &error,
4927 &reply,
4928 "sb", n, false);
691395d8
LP
4929 if (r < 0)
4930 return log_error_errno(r, "Failed to create snapshot: %s", bus_error_message(&error, r));
7e4249b9 4931
f459b602
MAP
4932 r = sd_bus_message_read(reply, "o", &path);
4933 if (r < 0)
4934 return bus_log_parse_error(r);
5dd9014f 4935
f459b602 4936 r = sd_bus_get_property_string(
f22f08cd
SP
4937 bus,
4938 "org.freedesktop.systemd1",
4939 path,
f459b602
MAP
4940 "org.freedesktop.systemd1.Unit",
4941 "Id",
4942 &error,
4943 &id);
691395d8
LP
4944 if (r < 0)
4945 return log_error_errno(r, "Failed to get ID of snapshot: %s", bus_error_message(&error, r));
7e4249b9 4946
0183528f
LP
4947 if (!arg_quiet)
4948 puts(id);
7e4249b9 4949
1dcf6065 4950 return 0;
7e4249b9
LP
4951}
4952
e449de87 4953static int delete_snapshot(int argc, char *argv[], void *userdata) {
e3e0314b 4954 _cleanup_strv_free_ char **names = NULL;
4fbd7192 4955 sd_bus *bus;
729e3769 4956 char **name;
342641fb 4957 int r;
6759e7a7 4958
079dac08
LP
4959 polkit_agent_open_if_enabled();
4960
4fbd7192 4961 r = acquire_bus(BUS_MANAGER, &bus);
e3e0314b 4962 if (r < 0)
4fbd7192
LP
4963 return r;
4964
e449de87 4965 r = expand_names(bus, strv_skip(argv, 1), ".snapshot", &names);
4fbd7192
LP
4966 if (r < 0)
4967 return log_error_errno(r, "Failed to expand names: %m");
1dcf6065 4968
e3e0314b 4969 STRV_FOREACH(name, names) {
6e646d22 4970 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
342641fb
LP
4971 int q;
4972
6e646d22 4973 q = sd_bus_call_method(
f22f08cd 4974 bus,
b0193f1c
LP
4975 "org.freedesktop.systemd1",
4976 "/org/freedesktop/systemd1",
4977 "org.freedesktop.systemd1.Manager",
6e646d22
LP
4978 "RemoveSnapshot",
4979 &error,
4980 NULL,
4981 "s", *name);
e3e0314b 4982 if (q < 0) {
691395d8 4983 log_error_errno(q, "Failed to remove snapshot %s: %s", *name, bus_error_message(&error, q));
e3e0314b
ZJS
4984 if (r == 0)
4985 r = q;
f459b602 4986 }
6759e7a7
LP
4987 }
4988
e3e0314b 4989 return r;
6759e7a7
LP
4990}
4991
e449de87 4992static int daemon_reload(int argc, char *argv[], void *userdata) {
f459b602 4993 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
7e4249b9 4994 const char *method;
4fbd7192 4995 sd_bus *bus;
f459b602 4996 int r;
7e4249b9 4997
079dac08
LP
4998 polkit_agent_open_if_enabled();
4999
4fbd7192
LP
5000 r = acquire_bus(BUS_MANAGER, &bus);
5001 if (r < 0)
5002 return r;
5003
e4b61340
LP
5004 if (arg_action == ACTION_RELOAD)
5005 method = "Reload";
5006 else if (arg_action == ACTION_REEXEC)
5007 method = "Reexecute";
5008 else {
5009 assert(arg_action == ACTION_SYSTEMCTL);
5010
5011 method =
e449de87
LP
5012 streq(argv[0], "clear-jobs") ||
5013 streq(argv[0], "cancel") ? "ClearJobs" :
5014 streq(argv[0], "daemon-reexec") ? "Reexecute" :
5015 streq(argv[0], "reset-failed") ? "ResetFailed" :
5016 streq(argv[0], "halt") ? "Halt" :
5017 streq(argv[0], "poweroff") ? "PowerOff" :
5018 streq(argv[0], "reboot") ? "Reboot" :
5019 streq(argv[0], "kexec") ? "KExec" :
5020 streq(argv[0], "exit") ? "Exit" :
20b09ca7 5021 /* "daemon-reload" */ "Reload";
e4b61340 5022 }
7e4249b9 5023
6e646d22 5024 r = sd_bus_call_method(
f22f08cd
SP
5025 bus,
5026 "org.freedesktop.systemd1",
5027 "/org/freedesktop/systemd1",
5028 "org.freedesktop.systemd1.Manager",
6e646d22
LP
5029 method,
5030 &error,
5031 NULL,
5032 NULL);
f22f08cd
SP
5033 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
5034 /* There's always a fallback possible for
5035 * legacy actions. */
5036 r = -EADDRNOTAVAIL;
d0ede8f1
LP
5037 else if ((r == -ETIMEDOUT || r == -ECONNRESET) && streq(method, "Reexecute"))
5038 /* On reexecution, we expect a disconnect, not a
5039 * reply */
f22f08cd 5040 r = 0;
1dcf6065 5041 else if (r < 0)
691395d8 5042 return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
7e4249b9 5043
0a9776c2 5044 return r < 0 ? r : 0;
7e4249b9
LP
5045}
5046
e449de87 5047static int reset_failed(int argc, char *argv[], void *userdata) {
e3e0314b 5048 _cleanup_strv_free_ char **names = NULL;
4fbd7192 5049 sd_bus *bus;
f84190d8 5050 char **name;
e3e0314b 5051 int r, q;
5632e374 5052
e449de87
LP
5053 if (argc <= 1)
5054 return daemon_reload(argc, argv, userdata);
5632e374 5055
079dac08
LP
5056 polkit_agent_open_if_enabled();
5057
4fbd7192
LP
5058 r = acquire_bus(BUS_MANAGER, &bus);
5059 if (r < 0)
5060 return r;
5061
e449de87 5062 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
e3e0314b 5063 if (r < 0)
691395d8 5064 return log_error_errno(r, "Failed to expand names: %m");
f84190d8 5065
e3e0314b 5066 STRV_FOREACH(name, names) {
6e646d22 5067 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
342641fb 5068
6e646d22 5069 q = sd_bus_call_method(
f22f08cd 5070 bus,
b0193f1c
LP
5071 "org.freedesktop.systemd1",
5072 "/org/freedesktop/systemd1",
5073 "org.freedesktop.systemd1.Manager",
6e646d22
LP
5074 "ResetFailedUnit",
5075 &error,
5076 NULL,
5077 "s", *name);
e3e0314b 5078 if (q < 0) {
691395d8 5079 log_error_errno(q, "Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
e3e0314b
ZJS
5080 if (r == 0)
5081 r = q;
f459b602 5082 }
5632e374
LP
5083 }
5084
e3e0314b 5085 return r;
5632e374
LP
5086}
5087
e449de87 5088static int show_environment(int argc, char *argv[], void *userdata) {
f459b602
MAP
5089 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
5090 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
5091 const char *text;
4fbd7192 5092 sd_bus *bus;
7e4249b9 5093 int r;
7e4249b9 5094
1968a360 5095 pager_open_if_enabled();
ec14911e 5096
4fbd7192
LP
5097 r = acquire_bus(BUS_MANAGER, &bus);
5098 if (r < 0)
5099 return r;
5100
f459b602 5101 r = sd_bus_get_property(
f22f08cd
SP
5102 bus,
5103 "org.freedesktop.systemd1",
5104 "/org/freedesktop/systemd1",
f459b602
MAP
5105 "org.freedesktop.systemd1.Manager",
5106 "Environment",
5107 &error,
f22f08cd 5108 &reply,
f459b602 5109 "as");
691395d8
LP
5110 if (r < 0)
5111 return log_error_errno(r, "Failed to get environment: %s", bus_error_message(&error, r));
7e4249b9 5112
f459b602
MAP
5113 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
5114 if (r < 0)
5115 return bus_log_parse_error(r);
7e4249b9 5116
f459b602 5117 while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0)
f84190d8 5118 puts(text);
f459b602
MAP
5119 if (r < 0)
5120 return bus_log_parse_error(r);
7e4249b9 5121
f459b602
MAP
5122 r = sd_bus_message_exit_container(reply);
5123 if (r < 0)
5124 return bus_log_parse_error(r);
7e4249b9 5125
f84190d8 5126 return 0;
7e4249b9
LP
5127}
5128
e449de87 5129static int switch_root(int argc, char *argv[], void *userdata) {
f459b602 5130 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
f39d4a08
HH
5131 _cleanup_free_ char *cmdline_init = NULL;
5132 const char *root, *init;
4fbd7192 5133 sd_bus *bus;
f459b602 5134 int r;
957eb8ca 5135
4fbd7192
LP
5136 if (arg_transport != BUS_TRANSPORT_LOCAL) {
5137 log_error("Cannot switch root remotely.");
5138 return -EINVAL;
5139 }
5140
e449de87 5141 if (argc < 2 || argc > 3) {
957eb8ca
LP
5142 log_error("Wrong number of arguments.");
5143 return -EINVAL;
5144 }
5145
e449de87 5146 root = argv[1];
13068da8 5147
e449de87
LP
5148 if (argc >= 3)
5149 init = argv[2];
13068da8 5150 else {
f39d4a08
HH
5151 r = parse_env_file("/proc/cmdline", WHITESPACE,
5152 "init", &cmdline_init,
5153 NULL);
5154 if (r < 0)
da927ba9 5155 log_debug_errno(r, "Failed to parse /proc/cmdline: %m");
13068da8 5156
f39d4a08 5157 init = cmdline_init;
13068da8 5158 }
f459b602 5159
f39d4a08
HH
5160 if (isempty(init))
5161 init = NULL;
5162
5163 if (init) {
5164 const char *root_systemd_path = NULL, *root_init_path = NULL;
5165
63c372cb
LP
5166 root_systemd_path = strjoina(root, "/" SYSTEMD_BINARY_PATH);
5167 root_init_path = strjoina(root, "/", init);
f39d4a08
HH
5168
5169 /* If the passed init is actually the same as the
5170 * systemd binary, then let's suppress it. */
5171 if (files_same(root_init_path, root_systemd_path) > 0)
5172 init = NULL;
5173 }
13068da8 5174
4fbd7192
LP
5175 r = acquire_bus(BUS_MANAGER, &bus);
5176 if (r < 0)
5177 return r;
5178
f39d4a08 5179 log_debug("Switching root - root: %s; init: %s", root, strna(init));
957eb8ca 5180
f459b602 5181 r = sd_bus_call_method(
f22f08cd 5182 bus,
957eb8ca
LP
5183 "org.freedesktop.systemd1",
5184 "/org/freedesktop/systemd1",
5185 "org.freedesktop.systemd1.Manager",
f22f08cd 5186 "SwitchRoot",
f459b602 5187 &error,
f22f08cd 5188 NULL,
f459b602 5189 "ss", root, init);
691395d8
LP
5190 if (r < 0)
5191 return log_error_errno(r, "Failed to switch root: %s", bus_error_message(&error, r));
f459b602
MAP
5192
5193 return 0;
957eb8ca
LP
5194}
5195
e449de87 5196static int set_environment(int argc, char *argv[], void *userdata) {
f459b602
MAP
5197 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
5198 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
7e4249b9 5199 const char *method;
4fbd7192 5200 sd_bus *bus;
31e767f7
LP
5201 int r;
5202
e449de87
LP
5203 assert(argc > 1);
5204 assert(argv);
7e4249b9 5205
6e646d22
LP
5206 polkit_agent_open_if_enabled();
5207
4fbd7192
LP
5208 r = acquire_bus(BUS_MANAGER, &bus);
5209 if (r < 0)
5210 return r;
5211
e449de87 5212 method = streq(argv[0], "set-environment")
7e4249b9
LP
5213 ? "SetEnvironment"
5214 : "UnsetEnvironment";
5215
f459b602
MAP
5216 r = sd_bus_message_new_method_call(
5217 bus,
151b9b96 5218 &m,
31e767f7
LP
5219 "org.freedesktop.systemd1",
5220 "/org/freedesktop/systemd1",
5221 "org.freedesktop.systemd1.Manager",
151b9b96 5222 method);
f459b602
MAP
5223 if (r < 0)
5224 return bus_log_create_error(r);
7e4249b9 5225
e449de87 5226 r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
31e767f7 5227 if (r < 0)
f459b602 5228 return bus_log_create_error(r);
7e4249b9 5229
c49b30a2 5230 r = sd_bus_call(bus, m, 0, &error, NULL);
691395d8
LP
5231 if (r < 0)
5232 return log_error_errno(r, "Failed to set environment: %s", bus_error_message(&error, r));
7e4249b9 5233
f84190d8 5234 return 0;
7e4249b9
LP
5235}
5236
e449de87 5237static int import_environment(int argc, char *argv[], void *userdata) {
ac3efa8a
LP
5238 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
5239 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
4fbd7192 5240 sd_bus *bus;
ac3efa8a
LP
5241 int r;
5242
6e646d22
LP
5243 polkit_agent_open_if_enabled();
5244
4fbd7192
LP
5245 r = acquire_bus(BUS_MANAGER, &bus);
5246 if (r < 0)
5247 return r;
5248
ac3efa8a
LP
5249 r = sd_bus_message_new_method_call(
5250 bus,
151b9b96 5251 &m,
ac3efa8a
LP
5252 "org.freedesktop.systemd1",
5253 "/org/freedesktop/systemd1",
5254 "org.freedesktop.systemd1.Manager",
151b9b96 5255 "SetEnvironment");
ac3efa8a
LP
5256 if (r < 0)
5257 return bus_log_create_error(r);
5258
e449de87 5259 if (argc < 2)
ac3efa8a
LP
5260 r = sd_bus_message_append_strv(m, environ);
5261 else {
5262 char **a, **b;
5263
5264 r = sd_bus_message_open_container(m, 'a', "s");
5265 if (r < 0)
5266 return bus_log_create_error(r);
5267
e449de87 5268 STRV_FOREACH(a, strv_skip(argv, 1)) {
ac3efa8a
LP
5269
5270 if (!env_name_is_valid(*a)) {
5271 log_error("Not a valid environment variable name: %s", *a);
5272 return -EINVAL;
5273 }
5274
5275 STRV_FOREACH(b, environ) {
5276 const char *eq;
5277
5278 eq = startswith(*b, *a);
5279 if (eq && *eq == '=') {
5280
5281 r = sd_bus_message_append(m, "s", *b);
5282 if (r < 0)
5283 return bus_log_create_error(r);
5284
5285 break;
5286 }
5287 }
5288 }
5289
5290 r = sd_bus_message_close_container(m);
5291 }
5292 if (r < 0)
5293 return bus_log_create_error(r);
5294
5295 r = sd_bus_call(bus, m, 0, &error, NULL);
691395d8
LP
5296 if (r < 0)
5297 return log_error_errno(r, "Failed to import environment: %s", bus_error_message(&error, r));
ac3efa8a
LP
5298
5299 return 0;
5300}
5301
cbb13b2a 5302static int enable_sysv_units(const char *verb, char **args) {
729e3769 5303 int r = 0;
ee5762e3 5304
0f0467e6 5305#if defined(HAVE_SYSV_COMPAT)
a644abed 5306 unsigned f = 0;
fb15be83 5307 _cleanup_lookup_paths_free_ LookupPaths paths = {};
ee5762e3 5308
729e3769
LP
5309 if (arg_scope != UNIT_FILE_SYSTEM)
5310 return 0;
ee5762e3 5311
4c315c2c
IS
5312 if (!STR_IN_SET(verb,
5313 "enable",
5314 "disable",
5315 "is-enabled"))
729e3769 5316 return 0;
ee5762e3 5317
729e3769
LP
5318 /* Processes all SysV units, and reshuffles the array so that
5319 * afterwards only the native units remain */
ee5762e3 5320
b2c23da8 5321 r = lookup_paths_init(&paths, MANAGER_SYSTEM, false, arg_root, NULL, NULL, NULL);
729e3769
LP
5322 if (r < 0)
5323 return r;
ee5762e3 5324
729e3769 5325 r = 0;
a644abed 5326 while (args[f]) {
729e3769 5327 const char *name;
05cae7f3 5328 _cleanup_free_ char *p = NULL, *q = NULL, *l = NULL;
729e3769
LP
5329 bool found_native = false, found_sysv;
5330 unsigned c = 1;
0f0467e6 5331 const char *argv[6] = { ROOTLIBEXECDIR "/systemd-sysv-install", NULL, NULL, NULL, NULL };
05cae7f3 5332 char **k;
729e3769
LP
5333 int j;
5334 pid_t pid;
5335 siginfo_t status;
ee5762e3 5336
a644abed 5337 name = args[f++];
ee5762e3 5338
729e3769
LP
5339 if (!endswith(name, ".service"))
5340 continue;
ee5762e3 5341
729e3769
LP
5342 if (path_is_absolute(name))
5343 continue;
ee5762e3 5344
729e3769 5345 STRV_FOREACH(k, paths.unit_path) {
05cae7f3
ZJS
5346 _cleanup_free_ char *path = NULL;
5347
0c6ea3a4
ZJS
5348 path = path_join(arg_root, *k, name);
5349 if (!path)
60731f32 5350 return log_oom();
ee5762e3 5351
4723e4b2 5352 found_native = access(path, F_OK) >= 0;
729e3769
LP
5353 if (found_native)
5354 break;
5355 }
ee5762e3 5356
355ff449
MP
5357 /* If we have both a native unit and a SysV script,
5358 * enable/disable them both (below); for is-enabled, prefer the
5359 * native unit */
5360 if (found_native && streq(verb, "is-enabled"))
729e3769 5361 continue;
ee5762e3 5362
0c6ea3a4
ZJS
5363 p = path_join(arg_root, SYSTEM_SYSVINIT_PATH, name);
5364 if (!p)
60731f32 5365 return log_oom();
ee5762e3 5366
05cae7f3 5367 p[strlen(p) - strlen(".service")] = 0;
729e3769 5368 found_sysv = access(p, F_OK) >= 0;
4b6756a8 5369 if (!found_sysv)
729e3769 5370 continue;
71fad675 5371
355ff449
MP
5372 if (found_native)
5373 log_info("Synchronizing state of %s with SysV init with %s...", name, argv[0]);
5374 else
5375 log_info("%s is not a native service, redirecting to systemd-sysv-install", name);
ee5762e3 5376
729e3769
LP
5377 if (!isempty(arg_root))
5378 argv[c++] = q = strappend("--root=", arg_root);
ee5762e3 5379
0f0467e6 5380 argv[c++] = verb;
2b6bf07d 5381 argv[c++] = basename(p);
729e3769 5382 argv[c] = NULL;
ee5762e3 5383
729e3769 5384 l = strv_join((char**)argv, " ");
60731f32
ZJS
5385 if (!l)
5386 return log_oom();
ee5762e3 5387
729e3769 5388 log_info("Executing %s", l);
ee5762e3 5389
729e3769 5390 pid = fork();
4a62c710
MS
5391 if (pid < 0)
5392 return log_error_errno(errno, "Failed to fork: %m");
5393 else if (pid == 0) {
729e3769 5394 /* Child */
ee5762e3 5395
ce30c8dc
LP
5396 (void) reset_all_signal_handlers();
5397 (void) reset_signal_mask();
5398
729e3769 5399 execv(argv[0], (char**) argv);
691395d8 5400 log_error_errno(r, "Failed to execute %s: %m", argv[0]);
729e3769
LP
5401 _exit(EXIT_FAILURE);
5402 }
ee5762e3 5403
729e3769
LP
5404 j = wait_for_terminate(pid, &status);
5405 if (j < 0) {
691395d8 5406 log_error_errno(j, "Failed to wait for child: %m");
60731f32 5407 return j;
729e3769 5408 }
ee5762e3 5409
729e3769
LP
5410 if (status.si_code == CLD_EXITED) {
5411 if (streq(verb, "is-enabled")) {
5412 if (status.si_status == 0) {
5413 if (!arg_quiet)
5414 puts("enabled");
5415 r = 1;
5416 } else {
5417 if (!arg_quiet)
5418 puts("disabled");
5419 }
ee5762e3 5420
60731f32
ZJS
5421 } else if (status.si_status != 0)
5422 return -EINVAL;
5423 } else
5424 return -EPROTO;
ee5762e3 5425
355ff449
MP
5426 if (found_native)
5427 continue;
5428
a644abed 5429 /* Remove this entry, so that we don't try enabling it as native unit */
aba84331
LP
5430 assert(f > 0);
5431 f--;
5432 assert(args[f] == name);
5433 strv_remove(args, name);
729e3769 5434 }
ee5762e3 5435
729e3769
LP
5436#endif
5437 return r;
5438}
ee5762e3 5439
37370d0c 5440static int mangle_names(char **original_names, char ***mangled_names) {
a33fdebb 5441 char **i, **l, **name;
7410616c 5442 int r;
37370d0c 5443
7410616c 5444 l = i = new(char*, strv_length(original_names) + 1);
a33fdebb 5445 if (!l)
37370d0c
VP
5446 return log_oom();
5447
37370d0c 5448 STRV_FOREACH(name, original_names) {
44386fc1
LN
5449
5450 /* When enabling units qualified path names are OK,
5451 * too, hence allow them explicitly. */
5452
7410616c 5453 if (is_path(*name)) {
44386fc1 5454 *i = strdup(*name);
7410616c
LP
5455 if (!*i) {
5456 strv_free(l);
5457 return log_oom();
5458 }
5459 } else {
5460 r = unit_name_mangle(*name, UNIT_NAME_NOGLOB, i);
5461 if (r < 0) {
5462 strv_free(l);
5463 return log_error_errno(r, "Failed to mangle unit name: %m");
5464 }
a33fdebb
LP
5465 }
5466
5467 i++;
37370d0c 5468 }
a33fdebb
LP
5469
5470 *i = NULL;
5471 *mangled_names = l;
37370d0c
VP
5472
5473 return 0;
5474}
5475
e449de87 5476static int enable_unit(int argc, char *argv[], void *userdata) {
e3e0314b 5477 _cleanup_strv_free_ char **names = NULL;
e449de87 5478 const char *verb = argv[0];
729e3769 5479 UnitFileChange *changes = NULL;
718db961 5480 unsigned n_changes = 0;
729e3769 5481 int carries_install_info = -1;
729e3769 5482 int r;
ee5762e3 5483
e449de87 5484 if (!argv[1])
ab5919fa
MS
5485 return 0;
5486
e449de87 5487 r = mangle_names(strv_skip(argv, 1), &names);
3a05c0f9 5488 if (r < 0)
cbb13b2a
VP
5489 return r;
5490
e3e0314b 5491 r = enable_sysv_units(verb, names);
cbb13b2a
VP
5492 if (r < 0)
5493 return r;
3a05c0f9 5494
67d66210
LP
5495 /* If the operation was fully executed by the SysV compat,
5496 * let's finish early */
5497 if (strv_isempty(names))
5498 return 0;
5499
4fbd7192 5500 if (install_client_side()) {
729e3769 5501 if (streq(verb, "enable")) {
e3e0314b 5502 r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769
LP
5503 carries_install_info = r;
5504 } else if (streq(verb, "disable"))
e3e0314b 5505 r = unit_file_disable(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
729e3769 5506 else if (streq(verb, "reenable")) {
e3e0314b 5507 r = unit_file_reenable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769
LP
5508 carries_install_info = r;
5509 } else if (streq(verb, "link"))
e3e0314b 5510 r = unit_file_link(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769 5511 else if (streq(verb, "preset")) {
d309c1c3 5512 r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_preset_mode, arg_force, &changes, &n_changes);
729e3769
LP
5513 carries_install_info = r;
5514 } else if (streq(verb, "mask"))
e3e0314b 5515 r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769 5516 else if (streq(verb, "unmask"))
e3e0314b 5517 r = unit_file_unmask(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
729e3769
LP
5518 else
5519 assert_not_reached("Unknown verb");
ee5762e3 5520
729e3769 5521 if (r < 0) {
da927ba9 5522 log_error_errno(r, "Operation failed: %m");
729e3769 5523 goto finish;
ee5762e3
LP
5524 }
5525
718db961
LP
5526 if (!arg_quiet)
5527 dump_unit_file_changes(changes, n_changes);
ee5762e3 5528
df77cdf0 5529 r = 0;
729e3769 5530 } else {
718db961
LP
5531 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
5532 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
f459b602 5533 int expect_carries_install_info = false;
d309c1c3 5534 bool send_force = true, send_preset_mode = false;
718db961 5535 const char *method;
4fbd7192 5536 sd_bus *bus;
729e3769 5537
079dac08
LP
5538 polkit_agent_open_if_enabled();
5539
4fbd7192
LP
5540 r = acquire_bus(BUS_MANAGER, &bus);
5541 if (r < 0)
5542 return r;
5543
729e3769
LP
5544 if (streq(verb, "enable")) {
5545 method = "EnableUnitFiles";
5546 expect_carries_install_info = true;
5547 } else if (streq(verb, "disable")) {
5548 method = "DisableUnitFiles";
5549 send_force = false;
5550 } else if (streq(verb, "reenable")) {
5551 method = "ReenableUnitFiles";
5552 expect_carries_install_info = true;
5553 } else if (streq(verb, "link"))
5554 method = "LinkUnitFiles";
5555 else if (streq(verb, "preset")) {
d309c1c3
LP
5556
5557 if (arg_preset_mode != UNIT_FILE_PRESET_FULL) {
5558 method = "PresetUnitFilesWithMode";
5559 send_preset_mode = true;
5560 } else
5561 method = "PresetUnitFiles";
5562
729e3769
LP
5563 expect_carries_install_info = true;
5564 } else if (streq(verb, "mask"))
5565 method = "MaskUnitFiles";
5566 else if (streq(verb, "unmask")) {
5567 method = "UnmaskUnitFiles";
5568 send_force = false;
5569 } else
5570 assert_not_reached("Unknown verb");
5571
f459b602
MAP
5572 r = sd_bus_message_new_method_call(
5573 bus,
151b9b96 5574 &m,
729e3769
LP
5575 "org.freedesktop.systemd1",
5576 "/org/freedesktop/systemd1",
5577 "org.freedesktop.systemd1.Manager",
151b9b96 5578 method);
f459b602
MAP
5579 if (r < 0)
5580 return bus_log_create_error(r);
ee5762e3 5581
e3e0314b 5582 r = sd_bus_message_append_strv(m, names);
f459b602
MAP
5583 if (r < 0)
5584 return bus_log_create_error(r);
ee5762e3 5585
d309c1c3
LP
5586 if (send_preset_mode) {
5587 r = sd_bus_message_append(m, "s", unit_file_preset_mode_to_string(arg_preset_mode));
5588 if (r < 0)
5589 return bus_log_create_error(r);
5590 }
5591
f459b602
MAP
5592 r = sd_bus_message_append(m, "b", arg_runtime);
5593 if (r < 0)
5594 return bus_log_create_error(r);
ee5762e3 5595
729e3769 5596 if (send_force) {
f459b602
MAP
5597 r = sd_bus_message_append(m, "b", arg_force);
5598 if (r < 0)
5599 return bus_log_create_error(r);
ee5762e3
LP
5600 }
5601
c49b30a2 5602 r = sd_bus_call(bus, m, 0, &error, &reply);
691395d8
LP
5603 if (r < 0)
5604 return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
be394c48 5605
729e3769 5606 if (expect_carries_install_info) {
f459b602
MAP
5607 r = sd_bus_message_read(reply, "b", &carries_install_info);
5608 if (r < 0)
5609 return bus_log_parse_error(r);
ee5762e3
LP
5610 }
5611
57ab2eab 5612 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
f459b602 5613 if (r < 0)
718db961 5614 return r;
b77398f7 5615
93c941e3 5616 /* Try to reload if enabled */
d6cb60c7 5617 if (!arg_no_reload)
e449de87 5618 r = daemon_reload(argc, argv, userdata);
f459b602
MAP
5619 else
5620 r = 0;
b647f10d 5621 }
3d3961f2 5622
729e3769 5623 if (carries_install_info == 0)
416389f7
LP
5624 log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
5625 "using systemctl.\n"
5626 "Possible reasons for having this kind of units are:\n"
5627 "1) A unit may be statically enabled by being symlinked from another unit's\n"
5628 " .wants/ or .requires/ directory.\n"
5629 "2) A unit's purpose may be to act as a helper for some other unit which has\n"
5630 " a requirement dependency on it.\n"
5631 "3) A unit may be started when needed via activation (socket, path, timer,\n"
5632 " D-Bus, udev, scripted systemctl call, ...).\n");
ee5762e3 5633
e449de87 5634 if (arg_now && n_changes > 0 && STR_IN_SET(argv[0], "enable", "disable", "mask")) {
57ab2eab 5635 char *new_args[n_changes + 2];
4fbd7192 5636 sd_bus *bus;
57ab2eab
JS
5637 unsigned i;
5638
4fbd7192
LP
5639 r = acquire_bus(BUS_MANAGER, &bus);
5640 if (r < 0)
5641 return r;
5642
e449de87 5643 new_args[0] = (char*) (streq(argv[0], "enable") ? "start" : "stop");
57ab2eab
JS
5644 for (i = 0; i < n_changes; i++)
5645 new_args[i + 1] = basename(changes[i].path);
5646 new_args[i + 1] = NULL;
5647
e449de87 5648 r = start_unit(strv_length(new_args), new_args, userdata);
57ab2eab
JS
5649 }
5650
729e3769 5651finish:
729e3769 5652 unit_file_changes_free(changes, n_changes);
ee5762e3 5653
729e3769 5654 return r;
ee5762e3
LP
5655}
5656
e449de87 5657static int add_dependency(int argc, char *argv[], void *userdata) {
e94937df
LN
5658 _cleanup_strv_free_ char **names = NULL;
5659 _cleanup_free_ char *target = NULL;
e449de87 5660 const char *verb = argv[0];
e94937df
LN
5661 UnitDependency dep;
5662 int r = 0;
5663
e449de87 5664 if (!argv[1])
e94937df
LN
5665 return 0;
5666
e449de87 5667 r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".target", &target);
7410616c
LP
5668 if (r < 0)
5669 return log_error_errno(r, "Failed to mangle unit name: %m");
e94937df 5670
e449de87 5671 r = mangle_names(strv_skip(argv, 2), &names);
e94937df
LN
5672 if (r < 0)
5673 return r;
5674
5675 if (streq(verb, "add-wants"))
5676 dep = UNIT_WANTS;
5677 else if (streq(verb, "add-requires"))
5678 dep = UNIT_REQUIRES;
5679 else
5680 assert_not_reached("Unknown verb");
5681
4fbd7192 5682 if (install_client_side()) {
e94937df
LN
5683 UnitFileChange *changes = NULL;
5684 unsigned n_changes = 0;
5685
5686 r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes);
5687
f647962d
MS
5688 if (r < 0)
5689 return log_error_errno(r, "Can't add dependency: %m");
e94937df
LN
5690
5691 if (!arg_quiet)
5692 dump_unit_file_changes(changes, n_changes);
5693
5694 unit_file_changes_free(changes, n_changes);
5695
5696 } else {
5697 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
5698 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192 5699 sd_bus *bus;
e94937df 5700
079dac08
LP
5701 polkit_agent_open_if_enabled();
5702
4fbd7192
LP
5703 r = acquire_bus(BUS_MANAGER, &bus);
5704 if (r < 0)
5705 return r;
5706
e94937df
LN
5707 r = sd_bus_message_new_method_call(
5708 bus,
5709 &m,
5710 "org.freedesktop.systemd1",
5711 "/org/freedesktop/systemd1",
5712 "org.freedesktop.systemd1.Manager",
5713 "AddDependencyUnitFiles");
5714 if (r < 0)
5715 return bus_log_create_error(r);
5716
342641fb 5717 r = sd_bus_message_append_strv(m, names);
e94937df
LN
5718 if (r < 0)
5719 return bus_log_create_error(r);
5720
342641fb 5721 r = sd_bus_message_append(m, "ssbb", target, unit_dependency_to_string(dep), arg_runtime, arg_force);
e94937df
LN
5722 if (r < 0)
5723 return bus_log_create_error(r);
5724
5725 r = sd_bus_call(bus, m, 0, &error, &reply);
691395d8
LP
5726 if (r < 0)
5727 return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
e94937df 5728
57ab2eab 5729 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
e94937df
LN
5730 if (r < 0)
5731 return r;
5732
5733 if (!arg_no_reload)
e449de87 5734 r = daemon_reload(argc, argv, userdata);
e94937df
LN
5735 else
5736 r = 0;
5737 }
5738
5739 return r;
5740}
5741
e449de87 5742static int preset_all(int argc, char *argv[], void *userdata) {
d309c1c3
LP
5743 UnitFileChange *changes = NULL;
5744 unsigned n_changes = 0;
5745 int r;
5746
4fbd7192 5747 if (install_client_side()) {
d309c1c3
LP
5748
5749 r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes);
5750 if (r < 0) {
da927ba9 5751 log_error_errno(r, "Operation failed: %m");
d309c1c3
LP
5752 goto finish;
5753 }
5754
5755 if (!arg_quiet)
5756 dump_unit_file_changes(changes, n_changes);
5757
5758 r = 0;
5759
5760 } else {
d309c1c3 5761 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
6e646d22 5762 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4fbd7192 5763 sd_bus *bus;
d309c1c3 5764
079dac08
LP
5765 polkit_agent_open_if_enabled();
5766
4fbd7192
LP
5767 r = acquire_bus(BUS_MANAGER, &bus);
5768 if (r < 0)
5769 return r;
5770
6e646d22 5771 r = sd_bus_call_method(
d309c1c3
LP
5772 bus,
5773 "org.freedesktop.systemd1",
5774 "/org/freedesktop/systemd1",
5775 "org.freedesktop.systemd1.Manager",
6e646d22
LP
5776 "PresetAllUnitFiles",
5777 &error,
5778 &reply,
d309c1c3
LP
5779 "sbb",
5780 unit_file_preset_mode_to_string(arg_preset_mode),
5781 arg_runtime,
5782 arg_force);
691395d8
LP
5783 if (r < 0)
5784 return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
d309c1c3 5785
57ab2eab 5786 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
d309c1c3
LP
5787 if (r < 0)
5788 return r;
5789
5790 if (!arg_no_reload)
e449de87 5791 r = daemon_reload(argc, argv, userdata);
d309c1c3
LP
5792 else
5793 r = 0;
5794 }
5795
5796finish:
5797 unit_file_changes_free(changes, n_changes);
5798
5799 return r;
5800}
5801
e449de87 5802static int unit_is_enabled(int argc, char *argv[], void *userdata) {
f459b602 5803
e3e0314b 5804 _cleanup_strv_free_ char **names = NULL;
729e3769
LP
5805 bool enabled;
5806 char **name;
f459b602 5807 int r;
ee5762e3 5808
e449de87 5809 r = mangle_names(strv_skip(argv, 1), &names);
cbb13b2a
VP
5810 if (r < 0)
5811 return r;
5812
e449de87 5813 r = enable_sysv_units(argv[0], names);
729e3769
LP
5814 if (r < 0)
5815 return r;
ee5762e3 5816
729e3769 5817 enabled = r > 0;
ee5762e3 5818
4fbd7192 5819 if (install_client_side()) {
ee5762e3 5820
e3e0314b 5821 STRV_FOREACH(name, names) {
729e3769 5822 UnitFileState state;
ee5762e3 5823
cbb13b2a 5824 state = unit_file_get_state(arg_scope, arg_root, *name);
f647962d
MS
5825 if (state < 0)
5826 return log_error_errno(state, "Failed to get unit file state for %s: %m", *name);
ee5762e3 5827
4c315c2c
IS
5828 if (IN_SET(state,
5829 UNIT_FILE_ENABLED,
5830 UNIT_FILE_ENABLED_RUNTIME,
5831 UNIT_FILE_STATIC,
5832 UNIT_FILE_INDIRECT))
729e3769
LP
5833 enabled = true;
5834
5835 if (!arg_quiet)
5836 puts(unit_file_state_to_string(state));
71fad675 5837 }
ee5762e3 5838
729e3769 5839 } else {
4fbd7192
LP
5840 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
5841 sd_bus *bus;
5842
5843 r = acquire_bus(BUS_MANAGER, &bus);
5844 if (r < 0)
5845 return r;
5846
e3e0314b 5847 STRV_FOREACH(name, names) {
f459b602 5848 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
729e3769 5849 const char *s;
63a723f3 5850
f459b602 5851 r = sd_bus_call_method(
f22f08cd 5852 bus,
729e3769
LP
5853 "org.freedesktop.systemd1",
5854 "/org/freedesktop/systemd1",
5855 "org.freedesktop.systemd1.Manager",
f22f08cd 5856 "GetUnitFileState",
f459b602 5857 &error,
f22f08cd 5858 &reply,
04504f93 5859 "s", *name);
691395d8
LP
5860 if (r < 0)
5861 return log_error_errno(r, "Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
ee5762e3 5862
f459b602
MAP
5863 r = sd_bus_message_read(reply, "s", &s);
5864 if (r < 0)
5865 return bus_log_parse_error(r);
ee5762e3 5866
aedd4012 5867 if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect"))
729e3769
LP
5868 enabled = true;
5869
5870 if (!arg_quiet)
5871 puts(s);
560d8f23 5872 }
ee5762e3
LP
5873 }
5874
f459b602 5875 return !enabled;
ee5762e3
LP
5876}
5877
e449de87 5878static int is_system_running(int argc, char *argv[], void *userdata) {
99813a19 5879 _cleanup_free_ char *state = NULL;
4fbd7192 5880 sd_bus *bus;
99813a19
LP
5881 int r;
5882
94f099d8
LP
5883 if (arg_transport == BUS_TRANSPORT_LOCAL && !sd_booted()) {
5884 if (!arg_quiet)
5885 puts("offline");
5886 return EXIT_FAILURE;
5887 }
5888
4fbd7192
LP
5889 r = acquire_bus(BUS_MANAGER, &bus);
5890 if (r < 0)
5891 return r;
5892
99813a19
LP
5893 r = sd_bus_get_property_string(
5894 bus,
5895 "org.freedesktop.systemd1",
5896 "/org/freedesktop/systemd1",
5897 "org.freedesktop.systemd1.Manager",
5898 "SystemState",
5899 NULL,
5900 &state);
5901 if (r < 0) {
5902 if (!arg_quiet)
5903 puts("unknown");
5904 return 0;
5905 }
5906
5907 if (!arg_quiet)
5908 puts(state);
5909
5910 return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE;
5911}
5912
7d4fb3b1 5913static int create_edit_temp_file(const char *new_path, const char *original_path, char **ret_tmp_fn) {
45519fd6 5914 _cleanup_free_ char *t = NULL;
ae6c3cc0 5915 int r;
7d4fb3b1
RC
5916
5917 assert(new_path);
5918 assert(original_path);
5919 assert(ret_tmp_fn);
5920
14bcf25c 5921 r = tempfn_random(new_path, NULL, &t);
ae6c3cc0 5922 if (r < 0)
029009d4 5923 return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", new_path);
7d4fb3b1
RC
5924
5925 r = mkdir_parents(new_path, 0755);
45519fd6 5926 if (r < 0)
691395d8 5927 return log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
7d4fb3b1 5928
f2068bcc 5929 r = copy_file(original_path, t, 0, 0644, 0);
7d4fb3b1 5930 if (r == -ENOENT) {
45519fd6 5931
7d4fb3b1 5932 r = touch(t);
45519fd6
LP
5933 if (r < 0)
5934 return log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
5935
5936 } else if (r < 0)
5937 return log_error_errno(r, "Failed to copy \"%s\" to \"%s\": %m", original_path, t);
7d4fb3b1
RC
5938
5939 *ret_tmp_fn = t;
45519fd6 5940 t = NULL;
7d4fb3b1
RC
5941
5942 return 0;
5943}
5944
bc854dc7
ZJS
5945static int get_file_to_edit(const char *name, const char *user_home, const char *user_runtime, char **ret_path) {
5946 _cleanup_free_ char *path = NULL, *path2 = NULL, *run = NULL;
7d4fb3b1 5947
45519fd6
LP
5948 assert(name);
5949 assert(ret_path);
5950
7d4fb3b1
RC
5951 switch (arg_scope) {
5952 case UNIT_FILE_SYSTEM:
bc854dc7
ZJS
5953 path = path_join(arg_root, SYSTEM_CONFIG_UNIT_PATH, name);
5954 if (arg_runtime)
5955 run = path_join(arg_root, "/run/systemd/system/", name);
7d4fb3b1
RC
5956 break;
5957 case UNIT_FILE_GLOBAL:
bc854dc7
ZJS
5958 path = path_join(arg_root, USER_CONFIG_UNIT_PATH, name);
5959 if (arg_runtime)
5960 run = path_join(arg_root, "/run/systemd/user/", name);
7d4fb3b1
RC
5961 break;
5962 case UNIT_FILE_USER:
5963 assert(user_home);
5964 assert(user_runtime);
5965
bc854dc7
ZJS
5966 path = path_join(arg_root, user_home, name);
5967 if (arg_runtime) {
5968 path2 = path_join(arg_root, USER_CONFIG_UNIT_PATH, name);
5969 if (!path2)
5970 return log_oom();
5971 run = path_join(arg_root, user_runtime, name);
5972 }
7d4fb3b1
RC
5973 break;
5974 default:
5975 assert_not_reached("Invalid scope");
5976 }
bc854dc7 5977 if (!path || (arg_runtime && !run))
7d4fb3b1
RC
5978 return log_oom();
5979
bc854dc7 5980 if (arg_runtime) {
691395d8
LP
5981 if (access(path, F_OK) >= 0) {
5982 log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path);
5983 return -EEXIST;
5984 }
5985
5986 if (path2 && access(path2, F_OK) >= 0) {
5987 log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path2);
5988 return -EEXIST;
5989 }
5990
bc854dc7
ZJS
5991 *ret_path = run;
5992 run = NULL;
5993 } else {
5994 *ret_path = path;
5995 path = NULL;
5996 }
7d4fb3b1
RC
5997
5998 return 0;
5999}
6000
bc854dc7 6001static 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 6002 char *tmp_new_path, *tmp_tmp_path, *ending;
7d4fb3b1
RC
6003 int r;
6004
6005 assert(unit_name);
6006 assert(ret_new_path);
6007 assert(ret_tmp_path);
6008
63c372cb 6009 ending = strjoina(unit_name, ".d/override.conf");
bc854dc7 6010 r = get_file_to_edit(ending, user_home, user_runtime, &tmp_new_path);
7d4fb3b1
RC
6011 if (r < 0)
6012 return r;
6013
6014 r = create_edit_temp_file(tmp_new_path, tmp_new_path, &tmp_tmp_path);
6015 if (r < 0) {
6016 free(tmp_new_path);
6017 return r;
6018 }
6019
6020 *ret_new_path = tmp_new_path;
6021 *ret_tmp_path = tmp_tmp_path;
6022
6023 return 0;
6024}
6025
1cfa9a4c
LP
6026static int unit_file_create_copy(
6027 const char *unit_name,
6028 const char *fragment_path,
6029 const char *user_home,
6030 const char *user_runtime,
6031 char **ret_new_path,
6032 char **ret_tmp_path) {
6033
45519fd6 6034 char *tmp_new_path, *tmp_tmp_path;
7d4fb3b1
RC
6035 int r;
6036
6037 assert(fragment_path);
6038 assert(unit_name);
6039 assert(ret_new_path);
6040 assert(ret_tmp_path);
6041
bc854dc7 6042 r = get_file_to_edit(unit_name, user_home, user_runtime, &tmp_new_path);
7d4fb3b1
RC
6043 if (r < 0)
6044 return r;
6045
6046 if (!path_equal(fragment_path, tmp_new_path) && access(tmp_new_path, F_OK) == 0) {
6047 char response;
6048
029009d4 6049 r = ask_char(&response, "yn", "\"%s\" already exists. Overwrite with \"%s\"? [(y)es, (n)o] ", tmp_new_path, fragment_path);
7d4fb3b1
RC
6050 if (r < 0) {
6051 free(tmp_new_path);
6052 return r;
6053 }
6054 if (response != 'y') {
6055 log_warning("%s ignored", unit_name);
6056 free(tmp_new_path);
6057 return -1;
6058 }
6059 }
6060
6061 r = create_edit_temp_file(tmp_new_path, fragment_path, &tmp_tmp_path);
6062 if (r < 0) {
029009d4 6063 log_error_errno(r, "Failed to create temporary file for \"%s\": %m", tmp_new_path);
7d4fb3b1
RC
6064 free(tmp_new_path);
6065 return r;
6066 }
6067
6068 *ret_new_path = tmp_new_path;
6069 *ret_tmp_path = tmp_tmp_path;
6070
6071 return 0;
6072}
6073
6074static int run_editor(char **paths) {
6075 pid_t pid;
6076 int r;
6077
6078 assert(paths);
6079
6080 pid = fork();
691395d8
LP
6081 if (pid < 0)
6082 return log_error_errno(errno, "Failed to fork: %m");
7d4fb3b1
RC
6083
6084 if (pid == 0) {
6085 const char **args;
9ef5d8f2 6086 char *editor, **editor_args = NULL;
1cfa9a4c 6087 char **tmp_path, **original_path, *p;
9ef5d8f2 6088 unsigned n_editor_args = 0, i = 1;
7d4fb3b1
RC
6089 size_t argc;
6090
ce30c8dc
LP
6091 (void) reset_all_signal_handlers();
6092 (void) reset_signal_mask();
6093
7d4fb3b1 6094 argc = strv_length(paths)/2 + 1;
7d4fb3b1
RC
6095
6096 /* SYSTEMD_EDITOR takes precedence over EDITOR which takes precedence over VISUAL
6097 * If neither SYSTEMD_EDITOR nor EDITOR nor VISUAL are present,
6098 * we try to execute well known editors
6099 */
6100 editor = getenv("SYSTEMD_EDITOR");
6101 if (!editor)
6102 editor = getenv("EDITOR");
6103 if (!editor)
6104 editor = getenv("VISUAL");
6105
6106 if (!isempty(editor)) {
9ef5d8f2
JS
6107 editor_args = strv_split(editor, WHITESPACE);
6108 if (!editor_args) {
6109 (void) log_oom();
6110 _exit(EXIT_FAILURE);
6111 }
6112 n_editor_args = strv_length(editor_args);
6113 argc += n_editor_args - 1;
6114 }
6115 args = newa(const char*, argc + 1);
6116
6117 if (n_editor_args > 0) {
6118 args[0] = editor_args[0];
6119 for (; i < n_editor_args; i++)
6120 args[i] = editor_args[i];
6121 }
6122
6123 STRV_FOREACH_PAIR(original_path, tmp_path, paths) {
6124 args[i] = *tmp_path;
6125 i++;
7d4fb3b1 6126 }
9ef5d8f2
JS
6127 args[i] = NULL;
6128
6129 if (n_editor_args > 0)
6130 execvp(args[0], (char* const*) args);
7d4fb3b1 6131
9391a1c3 6132 FOREACH_STRING(p, "editor", "nano", "vim", "vi") {
1cfa9a4c
LP
6133 args[0] = p;
6134 execvp(p, (char* const*) args);
7d4fb3b1
RC
6135 /* We do not fail if the editor doesn't exist
6136 * because we want to try each one of them before
6137 * failing.
6138 */
6139 if (errno != ENOENT) {
691395d8 6140 log_error_errno(errno, "Failed to execute %s: %m", editor);
7d4fb3b1
RC
6141 _exit(EXIT_FAILURE);
6142 }
6143 }
6144
1cfa9a4c 6145 log_error("Cannot edit unit(s), no editor available. Please set either $SYSTEMD_EDITOR, $EDITOR or $VISUAL.");
7d4fb3b1
RC
6146 _exit(EXIT_FAILURE);
6147 }
6148
6149 r = wait_for_terminate_and_warn("editor", pid, true);
6150 if (r < 0)
6151 return log_error_errno(r, "Failed to wait for child: %m");
6152
45519fd6 6153 return 0;
7d4fb3b1
RC
6154}
6155
6156static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
6157 _cleanup_free_ char *user_home = NULL;
6158 _cleanup_free_ char *user_runtime = NULL;
e9e310f8 6159 _cleanup_lookup_paths_free_ LookupPaths lp = {};
7d4fb3b1
RC
6160 char **name;
6161 int r;
6162
6163 assert(names);
6164 assert(paths);
6165
8df18507 6166 r = init_home_and_lookup_paths(&user_home, &user_runtime, &lp);
5b013a2f 6167 if (r < 0)
8df18507 6168 return r;
7d4fb3b1 6169
e9e310f8
RC
6170 STRV_FOREACH(name, names) {
6171 _cleanup_free_ char *path = NULL;
e9e310f8 6172 char *new_path, *tmp_path;
7d4fb3b1 6173
4fbd7192 6174 r = unit_find_paths(bus, *name, &lp, &path, NULL);
e9e310f8
RC
6175 if (r < 0)
6176 return r;
b5e6a600
IS
6177 else if (r == 0)
6178 return -ENOENT;
6179 else if (!path) {
ad2a0358 6180 // FIXME: support units with path==NULL (no FragmentPath)
b5e6a600
IS
6181 log_error("No fragment exists for %s.", *name);
6182 return -ENOENT;
6183 }
7d4fb3b1 6184
e9e310f8 6185 if (arg_full)
ad2a0358 6186 r = unit_file_create_copy(*name, path, user_home, user_runtime, &new_path, &tmp_path);
e9e310f8 6187 else
bc854dc7 6188 r = unit_file_create_dropin(*name, user_home, user_runtime, &new_path, &tmp_path);
e9e310f8 6189 if (r < 0)
ad2a0358 6190 return r;
7d4fb3b1 6191
e9e310f8
RC
6192 r = strv_push_pair(paths, new_path, tmp_path);
6193 if (r < 0)
6194 return log_oom();
7d4fb3b1
RC
6195 }
6196
6197 return 0;
6198}
6199
e449de87 6200static int edit(int argc, char *argv[], void *userdata) {
7d4fb3b1
RC
6201 _cleanup_strv_free_ char **names = NULL;
6202 _cleanup_strv_free_ char **paths = NULL;
6203 char **original, **tmp;
4fbd7192 6204 sd_bus *bus;
7d4fb3b1
RC
6205 int r;
6206
7d4fb3b1 6207 if (!on_tty()) {
4fbd7192 6208 log_error("Cannot edit units if not on a tty.");
7d4fb3b1
RC
6209 return -EINVAL;
6210 }
6211
6212 if (arg_transport != BUS_TRANSPORT_LOCAL) {
4fbd7192 6213 log_error("Cannot edit units remotely.");
7d4fb3b1
RC
6214 return -EINVAL;
6215 }
6216
4fbd7192
LP
6217 r = acquire_bus(BUS_MANAGER, &bus);
6218 if (r < 0)
6219 return r;
6220
e449de87 6221 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
7d4fb3b1
RC
6222 if (r < 0)
6223 return log_error_errno(r, "Failed to expand names: %m");
6224
7d4fb3b1
RC
6225 r = find_paths_to_edit(bus, names, &paths);
6226 if (r < 0)
6227 return r;
6228
b5e6a600 6229 if (strv_isempty(paths))
7d4fb3b1 6230 return -ENOENT;
7d4fb3b1
RC
6231
6232 r = run_editor(paths);
6233 if (r < 0)
6234 goto end;
6235
6236 STRV_FOREACH_PAIR(original, tmp, paths) {
45519fd6
LP
6237 /* If the temporary file is empty we ignore it. It's
6238 * useful if the user wants to cancel its modification
7d4fb3b1
RC
6239 */
6240 if (null_or_empty_path(*tmp)) {
45519fd6 6241 log_warning("Editing \"%s\" canceled: temporary file is empty.", *original);
7d4fb3b1
RC
6242 continue;
6243 }
45519fd6 6244
7d4fb3b1
RC
6245 r = rename(*tmp, *original);
6246 if (r < 0) {
029009d4 6247 r = log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", *tmp, *original);
7d4fb3b1
RC
6248 goto end;
6249 }
6250 }
6251
45519fd6
LP
6252 r = 0;
6253
6254 if (!arg_no_reload && !install_client_side())
e449de87 6255 r = daemon_reload(argc, argv, userdata);
7d4fb3b1
RC
6256
6257end:
6258 STRV_FOREACH_PAIR(original, tmp, paths)
45519fd6 6259 (void) unlink(*tmp);
7d4fb3b1
RC
6260
6261 return r;
6262}
6263
601185b4 6264static void systemctl_help(void) {
7e4249b9 6265
729e3769
LP
6266 pager_open_if_enabled();
6267
2e33c433 6268 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
729e3769 6269 "Query or send control commands to the systemd manager.\n\n"
8a0867d6
LP
6270 " -h --help Show this help\n"
6271 " --version Show package version\n"
f459b602
MAP
6272 " --system Connect to system manager\n"
6273 " --user Connect to user service manager\n"
6274 " -H --host=[USER@]HOST\n"
6275 " Operate on remote host\n"
6276 " -M --machine=CONTAINER\n"
6277 " Operate on local container\n"
3fb90db2
ZJS
6278 " -t --type=TYPE List units of a particular type\n"
6279 " --state=STATE List units with particular LOAD or SUB or ACTIVE state\n"
8a0867d6 6280 " -p --property=NAME Show only properties by this name\n"
a5e4972c
LP
6281 " -a --all Show all loaded units/properties, including dead/empty\n"
6282 " ones. To list all units installed on the system, use\n"
6283 " the 'list-unit-files' command instead.\n"
98a6e132 6284 " -l --full Don't ellipsize unit names on output\n"
1238ee09 6285 " -r --recursive Show unit list of host and local containers\n"
4dc5b821
LP
6286 " --reverse Show reverse dependencies with 'list-dependencies'\n"
6287 " --job-mode=MODE Specify how to deal with already queued jobs, when\n"
6288 " queueing a new job\n"
a521ae4a 6289 " --show-types When showing sockets, explicitly show their type\n"
b37844d3
LP
6290 " -i --ignore-inhibitors\n"
6291 " When shutting down or sleeping, ignore inhibitors\n"
a8f11321
LP
6292 " --kill-who=WHO Who to send signal to\n"
6293 " -s --signal=SIGNAL Which signal to send\n"
57ab2eab 6294 " --now Start or stop unit in addition to enabling or disabling it\n"
8a0867d6
LP
6295 " -q --quiet Suppress output\n"
6296 " --no-block Do not wait until operation finished\n"
8a0867d6 6297 " --no-wall Don't send wall message before halt/power-off/reboot\n"
3fb90db2 6298 " --no-reload Don't reload daemon after en-/dis-abling unit files\n"
ebed32bf 6299 " --no-legend Do not print a legend (column headers and hints)\n"
69fc152f 6300 " --no-pager Do not pipe output into a pager\n"
501fc174
LP
6301 " --no-ask-password\n"
6302 " Do not ask for system passwords\n"
a8f11321 6303 " --global Enable/disable unit files globally\n"
a521ae4a 6304 " --runtime Enable unit files only temporarily until next reboot\n"
8a0867d6
LP
6305 " -f --force When enabling unit files, override existing symlinks\n"
6306 " When shutting down, execute action immediately\n"
3fb90db2 6307 " --preset-mode= Apply only enable, only disable, or all presets\n"
729e3769 6308 " --root=PATH Enable unit files in the specified root directory\n"
76fdc966 6309 " -n --lines=INTEGER Number of journal entries to show\n"
86d81e50
RC
6310 " -o --output=STRING Change journal output mode (short, short-iso,\n"
6311 " short-precise, short-monotonic, verbose,\n"
6312 " export, json, json-pretty, json-sse, cat)\n"
5bdf2243 6313 " --firmware-setup Tell the firmware to show the setup menu on next boot\n"
815ebc54 6314 " --plain Print unit dependencies as a list instead of a tree\n\n"
34c4b47b 6315 "Unit Commands:\n"
d8fba7c6
ZJS
6316 " list-units [PATTERN...] List loaded units\n"
6317 " list-sockets [PATTERN...] List loaded sockets ordered by address\n"
6318 " list-timers [PATTERN...] List loaded timers ordered by next elapse\n"
4f8f66cb
ZJS
6319 " start NAME... Start (activate) one or more units\n"
6320 " stop NAME... Stop (deactivate) one or more units\n"
6321 " reload NAME... Reload one or more units\n"
6322 " restart NAME... Start or restart one or more units\n"
6323 " try-restart NAME... Restart one or more units if active\n"
6324 " reload-or-restart NAME... Reload one or more units if possible,\n"
6f28c033 6325 " otherwise start or restart\n"
4f8f66cb 6326 " reload-or-try-restart NAME... Reload one or more units if possible,\n"
6f28c033 6327 " otherwise restart if active\n"
4f8f66cb
ZJS
6328 " isolate NAME Start one unit and stop all others\n"
6329 " kill NAME... Send signal to processes of a unit\n"
b3ae710c
ZJS
6330 " is-active PATTERN... Check whether units are active\n"
6331 " is-failed PATTERN... Check whether units are failed\n"
6332 " status [PATTERN...|PID...] Show runtime status of one or more units\n"
6333 " show [PATTERN...|JOB...] Show properties of one or more\n"
ee5762e3 6334 " units/jobs or the manager\n"
b3ae710c 6335 " cat PATTERN... Show files and drop-ins of one or more units\n"
4f8f66cb 6336 " set-property NAME ASSIGNMENT... Sets one or more properties of a unit\n"
b3ae710c
ZJS
6337 " help PATTERN...|PID... Show manual for one or more units\n"
6338 " reset-failed [PATTERN...] Reset failed state for all, one, or more\n"
fdf20a31 6339 " units\n"
55c0b89c 6340 " list-dependencies [NAME] Recursively show units which are required\n"
afba4199
ZJS
6341 " or wanted by this unit or by which this\n"
6342 " unit is required or wanted\n\n"
34c4b47b 6343 "Unit File Commands:\n"
d8fba7c6 6344 " list-unit-files [PATTERN...] List installed unit files\n"
4f8f66cb
ZJS
6345 " enable NAME... Enable one or more unit files\n"
6346 " disable NAME... Disable one or more unit files\n"
6347 " reenable NAME... Reenable one or more unit files\n"
6348 " preset NAME... Enable/disable one or more unit files\n"
729e3769 6349 " based on preset configuration\n"
d309c1c3
LP
6350 " preset-all Enable/disable all unit files based on\n"
6351 " preset configuration\n"
b619ec8f 6352 " is-enabled NAME... Check whether unit files are enabled\n"
4f8f66cb
ZJS
6353 " mask NAME... Mask one or more units\n"
6354 " unmask NAME... Unmask one or more units\n"
6355 " link PATH... Link one or more units files into\n"
729e3769 6356 " the search path\n"
e94937df
LN
6357 " add-wants TARGET NAME... Add 'Wants' dependency for the target\n"
6358 " on specified one or more units\n"
6359 " add-requires TARGET NAME... Add 'Requires' dependency for the target\n"
6360 " on specified one or more units\n"
7d4fb3b1 6361 " edit NAME... Edit one or more unit files\n"
b619ec8f
LP
6362 " get-default Get the name of the default target\n"
6363 " set-default NAME Set the default target\n\n"
0d292f5e
LP
6364 "Machine Commands:\n"
6365 " list-machines [PATTERN...] List local containers and host\n\n"
34c4b47b 6366 "Job Commands:\n"
d8fba7c6 6367 " list-jobs [PATTERN...] List jobs\n"
34c4b47b 6368 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
34c4b47b 6369 "Snapshot Commands:\n"
7e4249b9 6370 " snapshot [NAME] Create a snapshot\n"
4f8f66cb 6371 " delete NAME... Remove one or more snapshots\n\n"
34c4b47b 6372 "Environment Commands:\n"
7e4249b9 6373 " show-environment Dump environment\n"
4f8f66cb 6374 " set-environment NAME=VALUE... Set one or more environment variables\n"
ac3efa8a 6375 " unset-environment NAME... Unset one or more environment variables\n"
3fb90db2 6376 " import-environment [NAME...] Import all or some environment variables\n\n"
34c4b47b
LP
6377 "Manager Lifecycle Commands:\n"
6378 " daemon-reload Reload systemd manager configuration\n"
6379 " daemon-reexec Reexecute systemd manager\n\n"
6380 "System Commands:\n"
99813a19 6381 " is-system-running Check whether system is fully running\n"
20b09ca7
LP
6382 " default Enter system default mode\n"
6383 " rescue Enter system rescue mode\n"
6384 " emergency Enter system emergency mode\n"
514f4ef5 6385 " halt Shut down and halt the system\n"
2e33c433 6386 " poweroff Shut down and power-off the system\n"
37185ec8 6387 " reboot [ARG] Shut down and reboot the system\n"
20b09ca7 6388 " kexec Shut down and reboot the system with kexec\n"
287419c1 6389 " exit [EXIT_CODE] Request user instance or container exit\n"
4f8f66cb 6390 " switch-root ROOT [INIT] Change to a different root file system\n"
6edd7d0a 6391 " suspend Suspend the system\n"
6524990f
LP
6392 " hibernate Hibernate the system\n"
6393 " hybrid-sleep Hibernate and suspend the system\n",
5b6319dc 6394 program_invocation_short_name);
7e4249b9
LP
6395}
6396
601185b4 6397static void halt_help(void) {
37185ec8 6398 printf("%s [OPTIONS...]%s\n\n"
e4b61340
LP
6399 "%s the system.\n\n"
6400 " --help Show this help\n"
6401 " --halt Halt the machine\n"
6402 " -p --poweroff Switch off the machine\n"
6403 " --reboot Reboot the machine\n"
2e33c433
LP
6404 " -f --force Force immediate halt/power-off/reboot\n"
6405 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
e4b61340 6406 " -d --no-wtmp Don't write wtmp record\n"
2e33c433 6407 " --no-wall Don't send wall message before halt/power-off/reboot\n",
e4b61340 6408 program_invocation_short_name,
37185ec8 6409 arg_action == ACTION_REBOOT ? " [ARG]" : "",
e4b61340
LP
6410 arg_action == ACTION_REBOOT ? "Reboot" :
6411 arg_action == ACTION_POWEROFF ? "Power off" :
6412 "Halt");
e4b61340
LP
6413}
6414
601185b4 6415static void shutdown_help(void) {
08e4b1c5 6416 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
e4b61340
LP
6417 "Shut down the system.\n\n"
6418 " --help Show this help\n"
6419 " -H --halt Halt the machine\n"
6420 " -P --poweroff Power-off the machine\n"
6421 " -r --reboot Reboot the machine\n"
386da858 6422 " -h Equivalent to --poweroff, overridden by --halt\n"
2e33c433 6423 " -k Don't halt/power-off/reboot, just send warnings\n"
f6144808 6424 " --no-wall Don't send wall message before halt/power-off/reboot\n"
f6144808 6425 " -c Cancel a pending shutdown\n",
e4b61340 6426 program_invocation_short_name);
e4b61340
LP
6427}
6428
601185b4 6429static void telinit_help(void) {
2e33c433 6430 printf("%s [OPTIONS...] {COMMAND}\n\n"
514f4ef5
LP
6431 "Send control commands to the init daemon.\n\n"
6432 " --help Show this help\n"
2e33c433 6433 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
e4b61340
LP
6434 "Commands:\n"
6435 " 0 Power-off the machine\n"
6436 " 6 Reboot the machine\n"
514f4ef5
LP
6437 " 2, 3, 4, 5 Start runlevelX.target unit\n"
6438 " 1, s, S Enter rescue mode\n"
6439 " q, Q Reload init daemon configuration\n"
6440 " u, U Reexecute init daemon\n",
e4b61340 6441 program_invocation_short_name);
e4b61340
LP
6442}
6443
601185b4 6444static void runlevel_help(void) {
2e33c433 6445 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
6446 "Prints the previous and current runlevel of the init system.\n\n"
6447 " --help Show this help\n",
6448 program_invocation_short_name);
e4b61340
LP
6449}
6450
b93312f5 6451static void help_types(void) {
45c0c61d
ZJS
6452 int i;
6453
b93312f5
ZJS
6454 if (!arg_no_legend)
6455 puts("Available unit types:");
e16972e6
ZJS
6456 for (i = 0; i < _UNIT_TYPE_MAX; i++)
6457 puts(unit_type_to_string(i));
6458}
6459
6460static void help_states(void) {
6461 int i;
6462
6463 if (!arg_no_legend)
6464 puts("Available unit load states:");
6465 for (i = 0; i < _UNIT_LOAD_STATE_MAX; i++)
6466 puts(unit_load_state_to_string(i));
6467
6468 if (!arg_no_legend)
6469 puts("\nAvailable unit active states:");
6470 for (i = 0; i < _UNIT_ACTIVE_STATE_MAX; i++)
6471 puts(unit_active_state_to_string(i));
7e55de3b
ZJS
6472
6473 if (!arg_no_legend)
6474 puts("\nAvailable automount unit substates:");
6475 for (i = 0; i < _AUTOMOUNT_STATE_MAX; i++)
6476 puts(automount_state_to_string(i));
6477
6478 if (!arg_no_legend)
6479 puts("\nAvailable busname unit substates:");
6480 for (i = 0; i < _BUSNAME_STATE_MAX; i++)
6481 puts(busname_state_to_string(i));
6482
6483 if (!arg_no_legend)
6484 puts("\nAvailable device unit substates:");
6485 for (i = 0; i < _DEVICE_STATE_MAX; i++)
6486 puts(device_state_to_string(i));
6487
6488 if (!arg_no_legend)
6489 puts("\nAvailable mount unit substates:");
6490 for (i = 0; i < _MOUNT_STATE_MAX; i++)
6491 puts(mount_state_to_string(i));
6492
6493 if (!arg_no_legend)
6494 puts("\nAvailable path unit substates:");
6495 for (i = 0; i < _PATH_STATE_MAX; i++)
6496 puts(path_state_to_string(i));
6497
6498 if (!arg_no_legend)
6499 puts("\nAvailable scope unit substates:");
6500 for (i = 0; i < _SCOPE_STATE_MAX; i++)
6501 puts(scope_state_to_string(i));
6502
6503 if (!arg_no_legend)
6504 puts("\nAvailable service unit substates:");
6505 for (i = 0; i < _SERVICE_STATE_MAX; i++)
6506 puts(service_state_to_string(i));
6507
6508 if (!arg_no_legend)
6509 puts("\nAvailable slice unit substates:");
6510 for (i = 0; i < _SLICE_STATE_MAX; i++)
6511 puts(slice_state_to_string(i));
6512
6513 if (!arg_no_legend)
6514 puts("\nAvailable snapshot unit substates:");
6515 for (i = 0; i < _SNAPSHOT_STATE_MAX; i++)
6516 puts(snapshot_state_to_string(i));
6517
6518 if (!arg_no_legend)
6519 puts("\nAvailable socket unit substates:");
6520 for (i = 0; i < _SOCKET_STATE_MAX; i++)
6521 puts(socket_state_to_string(i));
6522
6523 if (!arg_no_legend)
6524 puts("\nAvailable swap unit substates:");
6525 for (i = 0; i < _SWAP_STATE_MAX; i++)
6526 puts(swap_state_to_string(i));
6527
6528 if (!arg_no_legend)
6529 puts("\nAvailable target unit substates:");
6530 for (i = 0; i < _TARGET_STATE_MAX; i++)
6531 puts(target_state_to_string(i));
6532
6533 if (!arg_no_legend)
6534 puts("\nAvailable timer unit substates:");
6535 for (i = 0; i < _TIMER_STATE_MAX; i++)
6536 puts(timer_state_to_string(i));
45c0c61d
ZJS
6537}
6538
e4b61340 6539static int systemctl_parse_argv(int argc, char *argv[]) {
7e4249b9
LP
6540
6541 enum {
90d473a1 6542 ARG_FAIL = 0x100,
afba4199
ZJS
6543 ARG_REVERSE,
6544 ARG_AFTER,
6545 ARG_BEFORE,
991f2a39 6546 ARG_SHOW_TYPES,
23ade460 6547 ARG_IRREVERSIBLE,
e67c3609 6548 ARG_IGNORE_DEPENDENCIES,
35df8f27 6549 ARG_VERSION,
af2d49f7 6550 ARG_USER,
7e4249b9 6551 ARG_SYSTEM,
ee5762e3 6552 ARG_GLOBAL,
6e905d93 6553 ARG_NO_BLOCK,
ebed32bf 6554 ARG_NO_LEGEND,
611efaac 6555 ARG_NO_PAGER,
4445a875 6556 ARG_NO_WALL,
be394c48 6557 ARG_ROOT,
ee5762e3 6558 ARG_NO_RELOAD,
501fc174 6559 ARG_KILL_WHO,
30732560 6560 ARG_NO_ASK_PASSWORD,
729e3769 6561 ARG_FAILED,
df50185b 6562 ARG_RUNTIME,
5d0c05e5 6563 ARG_FORCE,
9b9b3d36 6564 ARG_PLAIN,
4dc5b821 6565 ARG_STATE,
d309c1c3
LP
6566 ARG_JOB_MODE,
6567 ARG_PRESET_MODE,
5bdf2243 6568 ARG_FIRMWARE_SETUP,
57ab2eab 6569 ARG_NOW,
9ef15026 6570 ARG_MESSAGE,
7e4249b9
LP
6571 };
6572
6573 static const struct option options[] = {
9ea9d4cf
LP
6574 { "help", no_argument, NULL, 'h' },
6575 { "version", no_argument, NULL, ARG_VERSION },
6576 { "type", required_argument, NULL, 't' },
6577 { "property", required_argument, NULL, 'p' },
6578 { "all", no_argument, NULL, 'a' },
6579 { "reverse", no_argument, NULL, ARG_REVERSE },
6580 { "after", no_argument, NULL, ARG_AFTER },
6581 { "before", no_argument, NULL, ARG_BEFORE },
6582 { "show-types", no_argument, NULL, ARG_SHOW_TYPES },
6583 { "failed", no_argument, NULL, ARG_FAILED }, /* compatibility only */
6584 { "full", no_argument, NULL, 'l' },
4dc5b821
LP
6585 { "job-mode", required_argument, NULL, ARG_JOB_MODE },
6586 { "fail", no_argument, NULL, ARG_FAIL }, /* compatibility only */
6587 { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, /* compatibility only */
6588 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */
9ea9d4cf
LP
6589 { "ignore-inhibitors", no_argument, NULL, 'i' },
6590 { "user", no_argument, NULL, ARG_USER },
6591 { "system", no_argument, NULL, ARG_SYSTEM },
6592 { "global", no_argument, NULL, ARG_GLOBAL },
6593 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
6594 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
6595 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
6596 { "no-wall", no_argument, NULL, ARG_NO_WALL },
6597 { "quiet", no_argument, NULL, 'q' },
6598 { "root", required_argument, NULL, ARG_ROOT },
6599 { "force", no_argument, NULL, ARG_FORCE },
6600 { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
6601 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
6602 { "signal", required_argument, NULL, 's' },
6603 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
6604 { "host", required_argument, NULL, 'H' },
f459b602 6605 { "machine", required_argument, NULL, 'M' },
9ea9d4cf
LP
6606 { "runtime", no_argument, NULL, ARG_RUNTIME },
6607 { "lines", required_argument, NULL, 'n' },
6608 { "output", required_argument, NULL, 'o' },
6609 { "plain", no_argument, NULL, ARG_PLAIN },
6610 { "state", required_argument, NULL, ARG_STATE },
1238ee09 6611 { "recursive", no_argument, NULL, 'r' },
d309c1c3 6612 { "preset-mode", required_argument, NULL, ARG_PRESET_MODE },
5bdf2243 6613 { "firmware-setup", no_argument, NULL, ARG_FIRMWARE_SETUP },
57ab2eab 6614 { "now", no_argument, NULL, ARG_NOW },
9ef15026 6615 { "message", required_argument, NULL, ARG_MESSAGE },
eb9da376 6616 {}
7e4249b9
LP
6617 };
6618
0f03c2a4 6619 int c, r;
7e4249b9 6620
e4b61340 6621 assert(argc >= 0);
7e4249b9
LP
6622 assert(argv);
6623
16f017fa
IS
6624 /* we default to allowing interactive authorization only in systemctl (not in the legacy commands) */
6625 arg_ask_password = true;
6626
601185b4 6627 while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir", options, NULL)) >= 0)
7e4249b9
LP
6628
6629 switch (c) {
6630
6631 case 'h':
601185b4
ZJS
6632 systemctl_help();
6633 return 0;
35df8f27
LP
6634
6635 case ARG_VERSION:
3f6fd1ba 6636 return version();
7e4249b9 6637
20b3f379 6638 case 't': {
a2a5291b 6639 const char *word, *state;
20b3f379 6640 size_t size;
45c0c61d 6641
20b3f379 6642 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
7fd1b19b 6643 _cleanup_free_ char *type;
20b3f379
ZJS
6644
6645 type = strndup(word, size);
6646 if (!type)
6647 return -ENOMEM;
6648
6649 if (streq(type, "help")) {
6650 help_types();
6651 return 0;
6652 }
6653
6654 if (unit_type_from_string(type) >= 0) {
7e9d36e0 6655 if (strv_push(&arg_types, type) < 0)
20b3f379
ZJS
6656 return log_oom();
6657 type = NULL;
6658 continue;
6659 }
6660
9b9b3d36
MW
6661 /* It's much nicer to use --state= for
6662 * load states, but let's support this
6663 * in --types= too for compatibility
6664 * with old versions */
7e9d36e0 6665 if (unit_load_state_from_string(type) >= 0) {
9b9b3d36 6666 if (strv_push(&arg_states, type) < 0)
20b3f379
ZJS
6667 return log_oom();
6668 type = NULL;
6669 continue;
6670 }
6671
ab06eef8 6672 log_error("Unknown unit type or load state '%s'.", type);
20b3f379
ZJS
6673 log_info("Use -t help to see a list of allowed values.");
6674 return -EINVAL;
c147dc42 6675 }
20b3f379
ZJS
6676
6677 break;
6678 }
6679
ea4a240d 6680 case 'p': {
033a842c
ZJS
6681 /* Make sure that if the empty property list
6682 was specified, we won't show any properties. */
20b3f379 6683 if (isempty(optarg) && !arg_properties) {
cbc9fbd1 6684 arg_properties = new0(char*, 1);
20b3f379
ZJS
6685 if (!arg_properties)
6686 return log_oom();
6687 } else {
a2a5291b 6688 const char *word, *state;
20b3f379 6689 size_t size;
033a842c 6690
20b3f379
ZJS
6691 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
6692 char *prop;
033a842c 6693
20b3f379
ZJS
6694 prop = strndup(word, size);
6695 if (!prop)
6696 return log_oom();
ea4a240d 6697
6e18964d 6698 if (strv_consume(&arg_properties, prop) < 0)
20b3f379 6699 return log_oom();
20b3f379 6700 }
033a842c 6701 }
48220598
LP
6702
6703 /* If the user asked for a particular
6704 * property, show it to him, even if it is
6705 * empty. */
6706 arg_all = true;
033a842c 6707
48220598 6708 break;
ea4a240d 6709 }
48220598 6710
7e4249b9
LP
6711 case 'a':
6712 arg_all = true;
6713 break;
6714
afba4199
ZJS
6715 case ARG_REVERSE:
6716 arg_dependency = DEPENDENCY_REVERSE;
6717 break;
6718
6719 case ARG_AFTER:
6720 arg_dependency = DEPENDENCY_AFTER;
6721 break;
6722
6723 case ARG_BEFORE:
6724 arg_dependency = DEPENDENCY_BEFORE;
6725 break;
6726
991f2a39
ZJS
6727 case ARG_SHOW_TYPES:
6728 arg_show_types = true;
6729 break;
6730
4dc5b821
LP
6731 case ARG_JOB_MODE:
6732 arg_job_mode = optarg;
6733 break;
6734
90d473a1 6735 case ARG_FAIL:
e67c3609
LP
6736 arg_job_mode = "fail";
6737 break;
6738
23ade460
MS
6739 case ARG_IRREVERSIBLE:
6740 arg_job_mode = "replace-irreversibly";
6741 break;
6742
e67c3609
LP
6743 case ARG_IGNORE_DEPENDENCIES:
6744 arg_job_mode = "ignore-dependencies";
7e4249b9
LP
6745 break;
6746
af2d49f7 6747 case ARG_USER:
729e3769 6748 arg_scope = UNIT_FILE_USER;
7e4249b9
LP
6749 break;
6750
6751 case ARG_SYSTEM:
729e3769
LP
6752 arg_scope = UNIT_FILE_SYSTEM;
6753 break;
6754
6755 case ARG_GLOBAL:
6756 arg_scope = UNIT_FILE_GLOBAL;
7e4249b9
LP
6757 break;
6758
6e905d93
LP
6759 case ARG_NO_BLOCK:
6760 arg_no_block = true;
7e4249b9
LP
6761 break;
6762
ebed32bf
MS
6763 case ARG_NO_LEGEND:
6764 arg_no_legend = true;
6765 break;
6766
611efaac
LP
6767 case ARG_NO_PAGER:
6768 arg_no_pager = true;
6769 break;
0736af98 6770
514f4ef5
LP
6771 case ARG_NO_WALL:
6772 arg_no_wall = true;
6773 break;
6774
be394c48 6775 case ARG_ROOT:
0f03c2a4
LP
6776 r = parse_path_argument_and_warn(optarg, true, &arg_root);
6777 if (r < 0)
6778 return r;
be394c48
FC
6779 break;
6780
98a6e132 6781 case 'l':
8fe914ec
LP
6782 arg_full = true;
6783 break;
6784
30732560 6785 case ARG_FAILED:
9b9b3d36
MW
6786 if (strv_extend(&arg_states, "failed") < 0)
6787 return log_oom();
6788
30732560
LP
6789 break;
6790
0183528f
LP
6791 case 'q':
6792 arg_quiet = true;
6793 break;
6794
568b679f
LP
6795 case ARG_FORCE:
6796 arg_force ++;
6797 break;
6798
b4f27ccc 6799 case 'f':
e606bb61 6800 arg_force ++;
ee5762e3
LP
6801 break;
6802
6803 case ARG_NO_RELOAD:
6804 arg_no_reload = true;
6805 break;
6806
8a0867d6
LP
6807 case ARG_KILL_WHO:
6808 arg_kill_who = optarg;
6809 break;
6810
8a0867d6 6811 case 's':
691395d8
LP
6812 arg_signal = signal_from_string_try_harder(optarg);
6813 if (arg_signal < 0) {
8a0867d6
LP
6814 log_error("Failed to parse signal string %s.", optarg);
6815 return -EINVAL;
6816 }
6817 break;
6818
501fc174
LP
6819 case ARG_NO_ASK_PASSWORD:
6820 arg_ask_password = false;
6821 break;
6822
f459b602
MAP
6823 case 'H':
6824 arg_transport = BUS_TRANSPORT_REMOTE;
6825 arg_host = optarg;
a8f11321
LP
6826 break;
6827
f459b602 6828 case 'M':
de33fc62 6829 arg_transport = BUS_TRANSPORT_MACHINE;
f459b602 6830 arg_host = optarg;
a8f11321
LP
6831 break;
6832
729e3769
LP
6833 case ARG_RUNTIME:
6834 arg_runtime = true;
6835 break;
6836
df50185b
LP
6837 case 'n':
6838 if (safe_atou(optarg, &arg_lines) < 0) {
6839 log_error("Failed to parse lines '%s'", optarg);
6840 return -EINVAL;
6841 }
6842 break;
6843
df50185b
LP
6844 case 'o':
6845 arg_output = output_mode_from_string(optarg);
6846 if (arg_output < 0) {
6847 log_error("Unknown output '%s'.", optarg);
6848 return -EINVAL;
6849 }
6850 break;
6851
b37844d3
LP
6852 case 'i':
6853 arg_ignore_inhibitors = true;
6854 break;
6855
5d0c05e5
LN
6856 case ARG_PLAIN:
6857 arg_plain = true;
6858 break;
6859
5bdf2243
JJ
6860 case ARG_FIRMWARE_SETUP:
6861 arg_firmware_setup = true;
6862 break;
6863
9b9b3d36 6864 case ARG_STATE: {
a2a5291b 6865 const char *word, *state;
9b9b3d36
MW
6866 size_t size;
6867
6868 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
bc6c18fe 6869 _cleanup_free_ char *s = NULL;
9b9b3d36
MW
6870
6871 s = strndup(word, size);
6872 if (!s)
6873 return log_oom();
6874
e16972e6
ZJS
6875 if (streq(s, "help")) {
6876 help_states();
6877 return 0;
6878 }
6879
7e9d36e0 6880 if (strv_push(&arg_states, s) < 0)
9b9b3d36 6881 return log_oom();
7e9d36e0
LP
6882
6883 s = NULL;
9b9b3d36
MW
6884 }
6885 break;
6886 }
6887
1238ee09
LP
6888 case 'r':
6889 if (geteuid() != 0) {
f1721625 6890 log_error("--recursive requires root privileges.");
1238ee09
LP
6891 return -EPERM;
6892 }
6893
6894 arg_recursive = true;
6895 break;
6896
d309c1c3
LP
6897 case ARG_PRESET_MODE:
6898
6899 arg_preset_mode = unit_file_preset_mode_from_string(optarg);
6900 if (arg_preset_mode < 0) {
6901 log_error("Failed to parse preset mode: %s.", optarg);
6902 return -EINVAL;
6903 }
6904
6905 break;
6906
57ab2eab
JS
6907 case ARG_NOW:
6908 arg_now = true;
6909 break;
6910
9ef15026
JS
6911 case ARG_MESSAGE:
6912 if (strv_extend(&arg_wall, optarg) < 0)
6913 return log_oom();
6914 break;
6915
7e4249b9
LP
6916 case '?':
6917 return -EINVAL;
6918
6919 default:
eb9da376 6920 assert_not_reached("Unhandled option");
7e4249b9 6921 }
7e4249b9 6922
f459b602 6923 if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM) {
a8f11321
LP
6924 log_error("Cannot access user instance remotely.");
6925 return -EINVAL;
6926 }
6927
7e4249b9
LP
6928 return 1;
6929}
6930
e4b61340
LP
6931static int halt_parse_argv(int argc, char *argv[]) {
6932
6933 enum {
6934 ARG_HELP = 0x100,
6935 ARG_HALT,
514f4ef5
LP
6936 ARG_REBOOT,
6937 ARG_NO_WALL
e4b61340
LP
6938 };
6939
6940 static const struct option options[] = {
6941 { "help", no_argument, NULL, ARG_HELP },
6942 { "halt", no_argument, NULL, ARG_HALT },
6943 { "poweroff", no_argument, NULL, 'p' },
6944 { "reboot", no_argument, NULL, ARG_REBOOT },
6945 { "force", no_argument, NULL, 'f' },
6946 { "wtmp-only", no_argument, NULL, 'w' },
6947 { "no-wtmp", no_argument, NULL, 'd' },
514f4ef5 6948 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 6949 {}
e4b61340
LP
6950 };
6951
37185ec8 6952 int c, r, runlevel;
e4b61340
LP
6953
6954 assert(argc >= 0);
6955 assert(argv);
6956
6957 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
6958 if (runlevel == '0' || runlevel == '6')
65491fd8 6959 arg_force = 2;
e4b61340 6960
601185b4 6961 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0)
e4b61340
LP
6962 switch (c) {
6963
6964 case ARG_HELP:
601185b4
ZJS
6965 halt_help();
6966 return 0;
e4b61340
LP
6967
6968 case ARG_HALT:
6969 arg_action = ACTION_HALT;
6970 break;
6971
6972 case 'p':
a042efad
MS
6973 if (arg_action != ACTION_REBOOT)
6974 arg_action = ACTION_POWEROFF;
e4b61340
LP
6975 break;
6976
6977 case ARG_REBOOT:
6978 arg_action = ACTION_REBOOT;
6979 break;
6980
6981 case 'f':
65491fd8 6982 arg_force = 2;
e4b61340
LP
6983 break;
6984
6985 case 'w':
6986 arg_dry = true;
6987 break;
6988
6989 case 'd':
6990 arg_no_wtmp = true;
6991 break;
6992
514f4ef5
LP
6993 case ARG_NO_WALL:
6994 arg_no_wall = true;
6995 break;
6996
e4b61340
LP
6997 case 'i':
6998 case 'h':
57371e58 6999 case 'n':
e4b61340
LP
7000 /* Compatibility nops */
7001 break;
7002
7003 case '?':
7004 return -EINVAL;
7005
7006 default:
eb9da376 7007 assert_not_reached("Unhandled option");
e4b61340 7008 }
e4b61340 7009
c5220a94
MO
7010 if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
7011 r = update_reboot_param_file(argc == optind + 1 ? argv[optind] : NULL);
7012 if (r < 0)
37185ec8 7013 return r;
37185ec8 7014 } else if (optind < argc) {
e4b61340
LP
7015 log_error("Too many arguments.");
7016 return -EINVAL;
7017 }
7018
7019 return 1;
7020}
7021
2cc7b0a2 7022static int parse_shutdown_time_spec(const char *t, usec_t *_u) {
f6144808
LP
7023 assert(t);
7024 assert(_u);
7025
7026 if (streq(t, "now"))
7027 *_u = 0;
1a639877 7028 else if (!strchr(t, ':')) {
f6144808
LP
7029 uint64_t u;
7030
1a639877 7031 if (safe_atou64(t, &u) < 0)
f6144808
LP
7032 return -EINVAL;
7033
7034 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
7035 } else {
7036 char *e = NULL;
7037 long hour, minute;
b92bea5d 7038 struct tm tm = {};
f6144808
LP
7039 time_t s;
7040 usec_t n;
7041
7042 errno = 0;
7043 hour = strtol(t, &e, 10);
8333c77e 7044 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
f6144808
LP
7045 return -EINVAL;
7046
7047 minute = strtol(e+1, &e, 10);
8333c77e 7048 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
f6144808
LP
7049 return -EINVAL;
7050
7051 n = now(CLOCK_REALTIME);
08e4b1c5
LP
7052 s = (time_t) (n / USEC_PER_SEC);
7053
f6144808
LP
7054 assert_se(localtime_r(&s, &tm));
7055
7056 tm.tm_hour = (int) hour;
7057 tm.tm_min = (int) minute;
08e4b1c5 7058 tm.tm_sec = 0;
f6144808
LP
7059
7060 assert_se(s = mktime(&tm));
7061
7062 *_u = (usec_t) s * USEC_PER_SEC;
7063
7064 while (*_u <= n)
7065 *_u += USEC_PER_DAY;
7066 }
7067
7068 return 0;
7069}
7070
e4b61340
LP
7071static int shutdown_parse_argv(int argc, char *argv[]) {
7072
7073 enum {
7074 ARG_HELP = 0x100,
514f4ef5 7075 ARG_NO_WALL
e4b61340
LP
7076 };
7077
7078 static const struct option options[] = {
7079 { "help", no_argument, NULL, ARG_HELP },
7080 { "halt", no_argument, NULL, 'H' },
7081 { "poweroff", no_argument, NULL, 'P' },
7082 { "reboot", no_argument, NULL, 'r' },
04ebb595 7083 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
514f4ef5 7084 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 7085 {}
e4b61340
LP
7086 };
7087
172d7abf 7088 char **wall = NULL;
f6144808 7089 int c, r;
e4b61340
LP
7090
7091 assert(argc >= 0);
7092 assert(argv);
7093
a4420f7b 7094 while ((c = getopt_long(argc, argv, "HPrhkKtafFc", options, NULL)) >= 0)
e4b61340
LP
7095 switch (c) {
7096
7097 case ARG_HELP:
601185b4
ZJS
7098 shutdown_help();
7099 return 0;
e4b61340
LP
7100
7101 case 'H':
7102 arg_action = ACTION_HALT;
7103 break;
7104
7105 case 'P':
7106 arg_action = ACTION_POWEROFF;
7107 break;
7108
7109 case 'r':
5622dde3
KS
7110 if (kexec_loaded())
7111 arg_action = ACTION_KEXEC;
7112 else
7113 arg_action = ACTION_REBOOT;
e4b61340
LP
7114 break;
7115
04ebb595
LP
7116 case 'K':
7117 arg_action = ACTION_KEXEC;
7118 break;
7119
e4b61340
LP
7120 case 'h':
7121 if (arg_action != ACTION_HALT)
7122 arg_action = ACTION_POWEROFF;
7123 break;
7124
7125 case 'k':
7126 arg_dry = true;
7127 break;
7128
514f4ef5
LP
7129 case ARG_NO_WALL:
7130 arg_no_wall = true;
7131 break;
7132
e4b61340
LP
7133 case 't':
7134 case 'a':
75836b9d
JS
7135 case 'f':
7136 case 'F':
e4b61340
LP
7137 /* Compatibility nops */
7138 break;
7139
f6144808
LP
7140 case 'c':
7141 arg_action = ACTION_CANCEL_SHUTDOWN;
7142 break;
7143
e4b61340
LP
7144 case '?':
7145 return -EINVAL;
7146
7147 default:
eb9da376 7148 assert_not_reached("Unhandled option");
e4b61340 7149 }
e4b61340 7150
dfcc5c33 7151 if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
2cc7b0a2 7152 r = parse_shutdown_time_spec(argv[optind], &arg_when);
7e59bfcb 7153 if (r < 0) {
f6144808
LP
7154 log_error("Failed to parse time specification: %s", argv[optind]);
7155 return r;
7156 }
6b5ad000 7157 } else
08e4b1c5 7158 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
442b9094 7159
dfcc5c33
MS
7160 if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
7161 /* No time argument for shutdown cancel */
172d7abf 7162 wall = argv + optind;
dfcc5c33
MS
7163 else if (argc > optind + 1)
7164 /* We skip the time argument */
172d7abf
LP
7165 wall = argv + optind + 1;
7166
7167 if (wall) {
7168 arg_wall = strv_copy(wall);
7169 if (!arg_wall)
7170 return log_oom();
7171 }
e4b61340
LP
7172
7173 optind = argc;
7174
7175 return 1;
e4b61340
LP
7176}
7177
7178static int telinit_parse_argv(int argc, char *argv[]) {
7179
7180 enum {
7181 ARG_HELP = 0x100,
514f4ef5 7182 ARG_NO_WALL
e4b61340
LP
7183 };
7184
7185 static const struct option options[] = {
7186 { "help", no_argument, NULL, ARG_HELP },
514f4ef5 7187 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 7188 {}
e4b61340
LP
7189 };
7190
7191 static const struct {
7192 char from;
7193 enum action to;
7194 } table[] = {
7195 { '0', ACTION_POWEROFF },
7196 { '6', ACTION_REBOOT },
ef2f1067 7197 { '1', ACTION_RESCUE },
e4b61340
LP
7198 { '2', ACTION_RUNLEVEL2 },
7199 { '3', ACTION_RUNLEVEL3 },
7200 { '4', ACTION_RUNLEVEL4 },
7201 { '5', ACTION_RUNLEVEL5 },
7202 { 's', ACTION_RESCUE },
7203 { 'S', ACTION_RESCUE },
7204 { 'q', ACTION_RELOAD },
7205 { 'Q', ACTION_RELOAD },
7206 { 'u', ACTION_REEXEC },
7207 { 'U', ACTION_REEXEC }
7208 };
7209
7210 unsigned i;
7211 int c;
7212
7213 assert(argc >= 0);
7214 assert(argv);
7215
601185b4 7216 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
7217 switch (c) {
7218
7219 case ARG_HELP:
601185b4
ZJS
7220 telinit_help();
7221 return 0;
e4b61340 7222
514f4ef5
LP
7223 case ARG_NO_WALL:
7224 arg_no_wall = true;
7225 break;
7226
e4b61340
LP
7227 case '?':
7228 return -EINVAL;
7229
7230 default:
eb9da376 7231 assert_not_reached("Unhandled option");
e4b61340 7232 }
e4b61340
LP
7233
7234 if (optind >= argc) {
691395d8 7235 log_error("%s: required argument missing.", program_invocation_short_name);
e4b61340
LP
7236 return -EINVAL;
7237 }
7238
7239 if (optind + 1 < argc) {
7240 log_error("Too many arguments.");
7241 return -EINVAL;
7242 }
7243
7244 if (strlen(argv[optind]) != 1) {
7245 log_error("Expected single character argument.");
7246 return -EINVAL;
7247 }
7248
7249 for (i = 0; i < ELEMENTSOF(table); i++)
7250 if (table[i].from == argv[optind][0])
7251 break;
7252
7253 if (i >= ELEMENTSOF(table)) {
b0193f1c 7254 log_error("Unknown command '%s'.", argv[optind]);
e4b61340
LP
7255 return -EINVAL;
7256 }
7257
7258 arg_action = table[i].to;
7259
7260 optind ++;
7261
7262 return 1;
7263}
7264
7265static int runlevel_parse_argv(int argc, char *argv[]) {
7266
7267 enum {
7268 ARG_HELP = 0x100,
7269 };
7270
7271 static const struct option options[] = {
7272 { "help", no_argument, NULL, ARG_HELP },
eb9da376 7273 {}
e4b61340
LP
7274 };
7275
7276 int c;
7277
7278 assert(argc >= 0);
7279 assert(argv);
7280
601185b4 7281 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
7282 switch (c) {
7283
7284 case ARG_HELP:
601185b4
ZJS
7285 runlevel_help();
7286 return 0;
e4b61340
LP
7287
7288 case '?':
7289 return -EINVAL;
7290
7291 default:
eb9da376 7292 assert_not_reached("Unhandled option");
e4b61340 7293 }
e4b61340
LP
7294
7295 if (optind < argc) {
7296 log_error("Too many arguments.");
7297 return -EINVAL;
7298 }
7299
7300 return 1;
7301}
7302
7303static int parse_argv(int argc, char *argv[]) {
7304 assert(argc >= 0);
7305 assert(argv);
7306
7307 if (program_invocation_short_name) {
7308
7309 if (strstr(program_invocation_short_name, "halt")) {
7310 arg_action = ACTION_HALT;
7311 return halt_parse_argv(argc, argv);
7312 } else if (strstr(program_invocation_short_name, "poweroff")) {
7313 arg_action = ACTION_POWEROFF;
7314 return halt_parse_argv(argc, argv);
7315 } else if (strstr(program_invocation_short_name, "reboot")) {
5622dde3
KS
7316 if (kexec_loaded())
7317 arg_action = ACTION_KEXEC;
7318 else
7319 arg_action = ACTION_REBOOT;
e4b61340
LP
7320 return halt_parse_argv(argc, argv);
7321 } else if (strstr(program_invocation_short_name, "shutdown")) {
7322 arg_action = ACTION_POWEROFF;
7323 return shutdown_parse_argv(argc, argv);
7324 } else if (strstr(program_invocation_short_name, "init")) {
d5ca5f11
LP
7325
7326 if (sd_booted() > 0) {
f459b602 7327 arg_action = _ACTION_INVALID;
d5ca5f11
LP
7328 return telinit_parse_argv(argc, argv);
7329 } else {
7330 /* Hmm, so some other init system is
7331 * running, we need to forward this
7332 * request to it. For now we simply
7333 * guess that it is Upstart. */
7334
4ad61fd1 7335 execv(TELINIT, argv);
d5ca5f11
LP
7336
7337 log_error("Couldn't find an alternative telinit implementation to spawn.");
7338 return -EIO;
7339 }
7340
e4b61340
LP
7341 } else if (strstr(program_invocation_short_name, "runlevel")) {
7342 arg_action = ACTION_RUNLEVEL;
7343 return runlevel_parse_argv(argc, argv);
7344 }
7345 }
7346
7347 arg_action = ACTION_SYSTEMCTL;
7348 return systemctl_parse_argv(argc, argv);
7349}
7350
44a6b1b6 7351_pure_ static int action_to_runlevel(void) {
eb22ac37
LP
7352
7353 static const char table[_ACTION_MAX] = {
7354 [ACTION_HALT] = '0',
7355 [ACTION_POWEROFF] = '0',
7356 [ACTION_REBOOT] = '6',
7357 [ACTION_RUNLEVEL2] = '2',
7358 [ACTION_RUNLEVEL3] = '3',
7359 [ACTION_RUNLEVEL4] = '4',
7360 [ACTION_RUNLEVEL5] = '5',
7361 [ACTION_RESCUE] = '1'
7362 };
7363
d55ae9e6
LP
7364 assert(arg_action < _ACTION_MAX);
7365
7366 return table[arg_action];
7367}
7368
d55ae9e6 7369static int talk_initctl(void) {
eca830be 7370#ifdef HAVE_SYSV_COMPAT
cbc9fbd1
LP
7371 struct init_request request = {
7372 .magic = INIT_MAGIC,
7373 .sleeptime = 0,
7374 .cmd = INIT_CMD_RUNLVL
7375 };
7376
7fd1b19b 7377 _cleanup_close_ int fd = -1;
d55ae9e6 7378 char rl;
cbc9fbd1 7379 int r;
eb22ac37 7380
427b47c4
ZJS
7381 rl = action_to_runlevel();
7382 if (!rl)
eb22ac37
LP
7383 return 0;
7384
d55ae9e6
LP
7385 request.runlevel = rl;
7386
427b47c4
ZJS
7387 fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
7388 if (fd < 0) {
d55ae9e6
LP
7389 if (errno == ENOENT)
7390 return 0;
eb22ac37 7391
eca830be 7392 return log_error_errno(errno, "Failed to open "INIT_FIFO": %m");
d55ae9e6 7393 }
eb22ac37 7394
553acb7b
ZJS
7395 r = loop_write(fd, &request, sizeof(request), false);
7396 if (r < 0)
7397 return log_error_errno(r, "Failed to write to "INIT_FIFO": %m");
eb22ac37
LP
7398
7399 return 1;
eca830be
LP
7400#else
7401 return 0;
7402#endif
e4b61340
LP
7403}
7404
e449de87
LP
7405static int systemctl_main(int argc, char *argv[]) {
7406
7407 static const Verb verbs[] = {
5b748163
LP
7408 { "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_units },
7409 { "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files },
7410 { "list-sockets", VERB_ANY, VERB_ANY, 0, list_sockets },
7411 { "list-timers", VERB_ANY, VERB_ANY, 0, list_timers },
7412 { "list-jobs", VERB_ANY, VERB_ANY, 0, list_jobs },
7413 { "list-machines", VERB_ANY, VERB_ANY, 0, list_machines },
e449de87
LP
7414 { "clear-jobs", VERB_ANY, 1, 0, daemon_reload },
7415 { "cancel", 2, VERB_ANY, 0, cancel_job },
7416 { "start", 2, VERB_ANY, 0, start_unit },
7417 { "stop", 2, VERB_ANY, 0, start_unit },
7418 { "condstop", 2, VERB_ANY, 0, start_unit }, /* For compatibility with ALTLinux */
7419 { "reload", 2, VERB_ANY, 0, start_unit },
7420 { "restart", 2, VERB_ANY, 0, start_unit },
7421 { "try-restart", 2, VERB_ANY, 0, start_unit },
7422 { "reload-or-restart", 2, VERB_ANY, 0, start_unit },
7423 { "reload-or-try-restart", 2, VERB_ANY, 0, start_unit },
7424 { "force-reload", 2, VERB_ANY, 0, start_unit }, /* For compatibility with SysV */
7425 { "condreload", 2, VERB_ANY, 0, start_unit }, /* For compatibility with ALTLinux */
7426 { "condrestart", 2, VERB_ANY, 0, start_unit }, /* For compatibility with RH */
7427 { "isolate", 2, 2, 0, start_unit },
7428 { "kill", 2, VERB_ANY, 0, kill_unit },
7429 { "is-active", 2, VERB_ANY, 0, check_unit_active },
7430 { "check", 2, VERB_ANY, 0, check_unit_active },
7431 { "is-failed", 2, VERB_ANY, 0, check_unit_failed },
7432 { "show", VERB_ANY, VERB_ANY, 0, show },
7433 { "cat", 2, VERB_ANY, 0, cat },
7434 { "status", VERB_ANY, VERB_ANY, 0, show },
7435 { "help", VERB_ANY, VERB_ANY, 0, show },
7436 { "snapshot", VERB_ANY, 2, 0, snapshot },
7437 { "delete", 2, VERB_ANY, 0, delete_snapshot },
7438 { "daemon-reload", VERB_ANY, 1, 0, daemon_reload },
7439 { "daemon-reexec", VERB_ANY, 1, 0, daemon_reload },
7440 { "show-environment", VERB_ANY, 1, 0, show_environment },
7441 { "set-environment", 2, VERB_ANY, 0, set_environment },
7442 { "unset-environment", 2, VERB_ANY, 0, set_environment },
7443 { "import-environment", VERB_ANY, VERB_ANY, 0, import_environment},
7444 { "halt", VERB_ANY, 1, 0, start_special },
7445 { "poweroff", VERB_ANY, 1, 0, start_special },
7446 { "reboot", VERB_ANY, 2, 0, start_special },
7447 { "kexec", VERB_ANY, 1, 0, start_special },
7448 { "suspend", VERB_ANY, 1, 0, start_special },
7449 { "hibernate", VERB_ANY, 1, 0, start_special },
7450 { "hybrid-sleep", VERB_ANY, 1, 0, start_special },
7451 { "default", VERB_ANY, 1, 0, start_special },
7452 { "rescue", VERB_ANY, 1, 0, start_special },
7453 { "emergency", VERB_ANY, 1, 0, start_special },
7454 { "exit", VERB_ANY, 2, 0, start_special },
7455 { "reset-failed", VERB_ANY, VERB_ANY, 0, reset_failed },
7456 { "enable", 2, VERB_ANY, 0, enable_unit },
7457 { "disable", 2, VERB_ANY, 0, enable_unit },
7458 { "is-enabled", 2, VERB_ANY, 0, unit_is_enabled },
7459 { "reenable", 2, VERB_ANY, 0, enable_unit },
7460 { "preset", 2, VERB_ANY, 0, enable_unit },
7461 { "preset-all", VERB_ANY, 1, 0, preset_all },
7462 { "mask", 2, VERB_ANY, 0, enable_unit },
7463 { "unmask", 2, VERB_ANY, 0, enable_unit },
7464 { "link", 2, VERB_ANY, 0, enable_unit },
7465 { "switch-root", 2, VERB_ANY, 0, switch_root },
7466 { "list-dependencies", VERB_ANY, 2, 0, list_dependencies },
7467 { "set-default", 2, 2, 0, set_default },
7468 { "get-default", VERB_ANY, 1, 0, get_default, },
7469 { "set-property", 3, VERB_ANY, 0, set_property },
7470 { "is-system-running", VERB_ANY, 1, 0, is_system_running },
7471 { "add-wants", 3, VERB_ANY, 0, add_dependency },
7472 { "add-requires", 3, VERB_ANY, 0, add_dependency },
7473 { "edit", 2, VERB_ANY, 0, edit },
d08e75ed 7474 {}
e449de87 7475 };
7e4249b9 7476
e449de87 7477 return dispatch_verb(argc, argv, verbs, NULL);
e4b61340
LP
7478}
7479
4fbd7192 7480static int reload_with_fallback(void) {
e4b61340 7481
4fbd7192 7482 /* First, try systemd via D-Bus. */
e449de87 7483 if (daemon_reload(0, NULL, NULL) >= 0)
4fbd7192 7484 return 0;
e4b61340
LP
7485
7486 /* Nothing else worked, so let's try signals */
7487 assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
7488
4a62c710
MS
7489 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0)
7490 return log_error_errno(errno, "kill() failed: %m");
e4b61340
LP
7491
7492 return 0;
7493}
7494
4fbd7192 7495static int start_with_fallback(void) {
e4b61340 7496
4fbd7192 7497 /* First, try systemd via D-Bus. */
e449de87 7498 if (start_unit(0, NULL, NULL) >= 0)
4fbd7192 7499 return 0;
e4b61340
LP
7500
7501 /* Nothing else worked, so let's try
7502 * /dev/initctl */
fbc43921 7503 if (talk_initctl() > 0)
48ec22bc 7504 return 0;
d55ae9e6
LP
7505
7506 log_error("Failed to talk to init daemon.");
7507 return -EIO;
e4b61340
LP
7508}
7509
477def80 7510static int halt_now(enum action a) {
e606bb61 7511
4a3ad399
LP
7512 /* The kernel will automaticall flush ATA disks and suchlike
7513 * on reboot(), but the file systems need to be synce'd
7514 * explicitly in advance. */
19578bb2 7515 (void) sync();
4a3ad399
LP
7516
7517 /* Make sure C-A-D is handled by the kernel from this point
7518 * on... */
19578bb2 7519 (void) reboot(RB_ENABLE_CAD);
e606bb61 7520
4c80c73c 7521 switch (a) {
e606bb61
LP
7522
7523 case ACTION_HALT:
7524 log_info("Halting.");
19578bb2 7525 (void) reboot(RB_HALT_SYSTEM);
477def80 7526 return -errno;
e606bb61
LP
7527
7528 case ACTION_POWEROFF:
7529 log_info("Powering off.");
19578bb2 7530 (void) reboot(RB_POWER_OFF);
477def80 7531 return -errno;
e606bb61 7532
98d52feb 7533 case ACTION_KEXEC:
477def80
LP
7534 case ACTION_REBOOT: {
7535 _cleanup_free_ char *param = NULL;
cbc9fbd1 7536
477def80
LP
7537 if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
7538 log_info("Rebooting with argument '%s'.", param);
19578bb2 7539 (void) syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
37185ec8 7540 }
e606bb61 7541
477def80 7542 log_info("Rebooting.");
19578bb2 7543 (void) reboot(RB_AUTOBOOT);
477def80 7544 return -errno;
e606bb61
LP
7545 }
7546
477def80
LP
7547 default:
7548 assert_not_reached("Unknown action.");
7549 }
e606bb61
LP
7550}
7551
56a730fa
LP
7552static int logind_schedule_shutdown(void) {
7553
7554#ifdef HAVE_LOGIND
7555 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
56a730fa
LP
7556 char date[FORMAT_TIMESTAMP_MAX];
7557 const char *action;
4fbd7192 7558 sd_bus *bus;
56a730fa
LP
7559 int r;
7560
4fbd7192 7561 (void) logind_set_wall_message();
56a730fa 7562
4fbd7192 7563 r = acquire_bus(BUS_FULL, &bus);
56a730fa 7564 if (r < 0)
4fbd7192 7565 return r;
56a730fa
LP
7566
7567 switch (arg_action) {
7568 case ACTION_HALT:
7569 action = "halt";
7570 break;
7571 case ACTION_POWEROFF:
7572 action = "poweroff";
7573 break;
7574 case ACTION_KEXEC:
7575 action = "kexec";
7576 break;
a4420f7b
LP
7577 case ACTION_EXIT:
7578 action = "exit";
7579 break;
7580 case ACTION_REBOOT:
56a730fa
LP
7581 default:
7582 action = "reboot";
7583 break;
7584 }
7585
7586 if (arg_dry)
7587 action = strjoina("dry-", action);
7588
7589 r = sd_bus_call_method(
4fbd7192 7590 bus,
56a730fa
LP
7591 "org.freedesktop.login1",
7592 "/org/freedesktop/login1",
7593 "org.freedesktop.login1.Manager",
7594 "ScheduleShutdown",
7595 &error,
7596 NULL,
7597 "st",
7598 action,
7599 arg_when);
7600 if (r < 0)
7601 return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r));
7602
7603 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.", format_timestamp(date, sizeof(date), arg_when));
7604 return 0;
7605#else
7606 log_error("Cannot schedule shutdown without logind support, proceeding with immediate shutdown.");
7607 return -ENOSYS;
7608#endif
7609}
7610
4fbd7192 7611static int halt_main(void) {
e4b61340
LP
7612 int r;
7613
4fbd7192 7614 r = logind_check_inhibitors(arg_action);
748ebafa
LP
7615 if (r < 0)
7616 return r;
b37844d3 7617
7f96539d
LP
7618 if (arg_when > 0)
7619 return logind_schedule_shutdown();
7620
bc8c2f5c 7621 if (geteuid() != 0) {
7f96539d 7622 if (arg_dry || arg_force > 0) {
2ac3930f
IS
7623 log_error("Must be root.");
7624 return -EPERM;
7625 }
7626
7e59bfcb
LP
7627 /* Try logind if we are a normal user and no special
7628 * mode applies. Maybe PolicyKit allows us to shutdown
7629 * the machine. */
7f96539d 7630 if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT)) {
4fbd7192 7631 r = logind_reboot(arg_action);
4c80c73c
KS
7632 if (r >= 0)
7633 return r;
a9085ea3 7634 if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
7f96539d
LP
7635 /* requested operation is not
7636 * supported on the local system or
7637 * already in progress */
a9085ea3
IS
7638 return r;
7639 /* on all other errors, try low-level operation */
4c80c73c 7640 }
bc8c2f5c
LP
7641 }
7642
65491fd8 7643 if (!arg_dry && !arg_force)
4fbd7192 7644 return start_with_fallback();
e4b61340 7645
2ac3930f
IS
7646 assert(geteuid() == 0);
7647
d90e1a30
LP
7648 if (!arg_no_wtmp) {
7649 if (sd_booted() > 0)
7650 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
7e59bfcb
LP
7651 else {
7652 r = utmp_put_shutdown();
7653 if (r < 0)
da927ba9 7654 log_warning_errno(r, "Failed to write utmp record: %m");
7e59bfcb 7655 }
d90e1a30 7656 }
e4b61340 7657
e4b61340
LP
7658 if (arg_dry)
7659 return 0;
7660
477def80 7661 r = halt_now(arg_action);
691395d8 7662 return log_error_errno(r, "Failed to reboot: %m");
e4b61340
LP
7663}
7664
7665static int runlevel_main(void) {
7666 int r, runlevel, previous;
7667
729e3769
LP
7668 r = utmp_get_runlevel(&runlevel, &previous);
7669 if (r < 0) {
7670 puts("unknown");
e4b61340
LP
7671 return r;
7672 }
7673
7674 printf("%c %c\n",
7675 previous <= 0 ? 'N' : previous,
7676 runlevel <= 0 ? 'N' : runlevel);
7677
7678 return 0;
7679}
7680
2cf05793
LP
7681static int logind_cancel_shutdown(void) {
7682#ifdef HAVE_LOGIND
949d9ce9 7683 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192 7684 sd_bus *bus;
949d9ce9
LP
7685 int r;
7686
4fbd7192 7687 r = acquire_bus(BUS_FULL, &bus);
949d9ce9 7688 if (r < 0)
4fbd7192 7689 return r;
949d9ce9 7690
4fbd7192 7691 (void) logind_set_wall_message();
949d9ce9
LP
7692
7693 r = sd_bus_call_method(
4fbd7192 7694 bus,
949d9ce9
LP
7695 "org.freedesktop.login1",
7696 "/org/freedesktop/login1",
7697 "org.freedesktop.login1.Manager",
7698 "CancelScheduledShutdown",
7699 &error,
7700 NULL, NULL);
7701 if (r < 0)
7702 return log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s", bus_error_message(&error, r));
7703
7704 return 0;
2cf05793
LP
7705#else
7706 log_error("Not compiled with logind support, cannot cancel scheduled shutdowns.");
7707 return -ENOSYS;
7708#endif
949d9ce9
LP
7709}
7710
e4b61340 7711int main(int argc, char*argv[]) {
f459b602 7712 int r;
e4b61340 7713
a9cdc94f 7714 setlocale(LC_ALL, "");
e4b61340 7715 log_parse_environment();
2396fb04 7716 log_open();
e4b61340 7717
184ecaf7
DR
7718 /* Explicitly not on_tty() to avoid setting cached value.
7719 * This becomes relevant for piping output which might be
7720 * ellipsized. */
7721 original_stdout_is_tty = isatty(STDOUT_FILENO);
7722
04ebb595 7723 r = parse_argv(argc, argv);
f459b602 7724 if (r <= 0)
e4b61340 7725 goto finish;
7e4249b9 7726
82e23ddd
LP
7727 if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
7728 log_info("Running in chroot, ignoring request.");
f459b602 7729 r = 0;
82e23ddd
LP
7730 goto finish;
7731 }
7732
41dd15e4
LP
7733 /* systemctl_main() will print an error message for the bus
7734 * connection, but only if it needs to */
e4b61340
LP
7735
7736 switch (arg_action) {
7737
22f4096c 7738 case ACTION_SYSTEMCTL:
e449de87 7739 r = systemctl_main(argc, argv);
e4b61340 7740 break;
e4b61340
LP
7741
7742 case ACTION_HALT:
7743 case ACTION_POWEROFF:
7744 case ACTION_REBOOT:
5622dde3 7745 case ACTION_KEXEC:
4fbd7192 7746 r = halt_main();
e4b61340
LP
7747 break;
7748
e4b61340
LP
7749 case ACTION_RUNLEVEL2:
7750 case ACTION_RUNLEVEL3:
7751 case ACTION_RUNLEVEL4:
7752 case ACTION_RUNLEVEL5:
7753 case ACTION_RESCUE:
514f4ef5 7754 case ACTION_EMERGENCY:
eb22ac37 7755 case ACTION_DEFAULT:
4fbd7192 7756 r = start_with_fallback();
e4b61340 7757 break;
7e4249b9 7758
e4b61340
LP
7759 case ACTION_RELOAD:
7760 case ACTION_REEXEC:
4fbd7192 7761 r = reload_with_fallback();
e4b61340
LP
7762 break;
7763
949d9ce9 7764 case ACTION_CANCEL_SHUTDOWN:
2cf05793 7765 r = logind_cancel_shutdown();
f6144808
LP
7766 break;
7767
eb22ac37 7768 case ACTION_RUNLEVEL:
4f16c1f4
LP
7769 r = runlevel_main();
7770 break;
7771
f459b602 7772 case _ACTION_INVALID:
e4b61340
LP
7773 default:
7774 assert_not_reached("Unknown action");
7775 }
7e4249b9
LP
7776
7777finish:
f459b602
MAP
7778 pager_close();
7779 ask_password_agent_close();
7780 polkit_agent_close();
7e4249b9 7781
20b3f379 7782 strv_free(arg_types);
9b9b3d36 7783 strv_free(arg_states);
20b3f379 7784 strv_free(arg_properties);
ea4a240d 7785
172d7abf 7786 strv_free(arg_wall);
0f03c2a4 7787 free(arg_root);
172d7abf 7788
4fbd7192 7789 release_busses();
fa2f8973 7790
f459b602 7791 return r < 0 ? EXIT_FAILURE : r;
7e4249b9 7792}