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