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