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