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