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