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