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