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