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