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