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