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