]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl.c
build: colorize gcc only if on tty
[thirdparty/systemd.git] / src / systemctl / systemctl.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
7e4249b9
LP
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
f459b602 7 Copyright 2013 Marc-Antoine Perennou
7e4249b9
LP
8
9 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
7e4249b9
LP
12 (at your option) any later version.
13
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 17 Lesser General Public License for more details.
7e4249b9 18
5430f7f2 19 You should have received a copy of the GNU Lesser General Public License
7e4249b9
LP
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21***/
22
e4b61340 23#include <sys/reboot.h>
37185ec8
WC
24#include <linux/reboot.h>
25#include <sys/syscall.h>
7e4249b9
LP
26#include <stdio.h>
27#include <getopt.h>
a9cdc94f 28#include <locale.h>
7e4249b9
LP
29#include <stdbool.h>
30#include <string.h>
31#include <errno.h>
32#include <sys/ioctl.h>
33#include <termios.h>
34#include <unistd.h>
eb22ac37 35#include <fcntl.h>
f1c5860b 36#include <sys/socket.h>
ee5762e3 37#include <sys/stat.h>
0e098b15 38#include <stddef.h>
501fc174 39#include <sys/prctl.h>
d8fba7c6 40#include <fnmatch.h>
81527be1 41
f459b602
MAP
42#include "sd-daemon.h"
43#include "sd-shutdown.h"
44#include "sd-login.h"
45#include "sd-bus.h"
7e4249b9
LP
46#include "log.h"
47#include "util.h"
48#include "macro.h"
49#include "set.h"
e4b61340 50#include "utmp-wtmp.h"
514f4ef5 51#include "special.h"
eb22ac37 52#include "initreq.h"
9eb977db 53#include "path-util.h"
e4a9373f 54#include "strv.h"
ab35fb1b 55#include "cgroup-show.h"
c6c18be3 56#include "cgroup-util.h"
582a507f 57#include "list.h"
ee5762e3
LP
58#include "path-lookup.h"
59#include "conf-parser.h"
d06dacd0 60#include "exit-status.h"
7d568925 61#include "build.h"
71fad675 62#include "unit-name.h"
1968a360 63#include "pager.h"
6bb92a16
LP
64#include "spawn-ask-password-agent.h"
65#include "spawn-polkit-agent.h"
729e3769 66#include "install.h"
86aa7ba4 67#include "logs-show.h"
67445f4e 68#include "socket-util.h"
a5c32cff 69#include "fileio.h"
ac3efa8a 70#include "env-util.h"
f459b602
MAP
71#include "bus-util.h"
72#include "bus-message.h"
73#include "bus-error.h"
718db961 74#include "bus-errors.h"
7e4249b9 75
20b3f379 76static char **arg_types = NULL;
9b9b3d36 77static char **arg_states = NULL;
20b3f379 78static char **arg_properties = NULL;
7e4249b9 79static bool arg_all = false;
afba4199
ZJS
80static enum dependency {
81 DEPENDENCY_FORWARD,
82 DEPENDENCY_REVERSE,
83 DEPENDENCY_AFTER,
84 DEPENDENCY_BEFORE,
071066a5 85 _DEPENDENCY_MAX
afba4199 86} arg_dependency = DEPENDENCY_FORWARD;
e67c3609 87static const char *arg_job_mode = "replace";
729e3769 88static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
ee5762e3 89static bool arg_no_block = false;
ebed32bf 90static bool arg_no_legend = false;
0736af98 91static bool arg_no_pager = false;
e4b61340 92static bool arg_no_wtmp = false;
514f4ef5 93static bool arg_no_wall = false;
ee5762e3 94static bool arg_no_reload = false;
991f2a39 95static bool arg_show_types = false;
b37844d3 96static bool arg_ignore_inhibitors = false;
e4b61340 97static bool arg_dry = false;
0183528f 98static bool arg_quiet = false;
ee5762e3 99static bool arg_full = false;
1238ee09 100static bool arg_recursive = false;
e606bb61 101static int arg_force = 0;
6bb92a16 102static bool arg_ask_password = true;
729e3769 103static bool arg_runtime = false;
d309c1c3 104static UnitFilePresetMode arg_preset_mode = UNIT_FILE_PRESET_FULL;
e4b61340 105static char **arg_wall = NULL;
8a0867d6 106static const char *arg_kill_who = NULL;
8a0867d6 107static int arg_signal = SIGTERM;
69fc152f 108static const char *arg_root = NULL;
f6144808 109static usec_t arg_when = 0;
4445a875 110static enum action {
f459b602 111 _ACTION_INVALID,
e4b61340
LP
112 ACTION_SYSTEMCTL,
113 ACTION_HALT,
114 ACTION_POWEROFF,
115 ACTION_REBOOT,
20b09ca7
LP
116 ACTION_KEXEC,
117 ACTION_EXIT,
6edd7d0a
LP
118 ACTION_SUSPEND,
119 ACTION_HIBERNATE,
6524990f 120 ACTION_HYBRID_SLEEP,
e4b61340
LP
121 ACTION_RUNLEVEL2,
122 ACTION_RUNLEVEL3,
123 ACTION_RUNLEVEL4,
124 ACTION_RUNLEVEL5,
125 ACTION_RESCUE,
514f4ef5
LP
126 ACTION_EMERGENCY,
127 ACTION_DEFAULT,
e4b61340
LP
128 ACTION_RELOAD,
129 ACTION_REEXEC,
130 ACTION_RUNLEVEL,
f6144808 131 ACTION_CANCEL_SHUTDOWN,
e4b61340
LP
132 _ACTION_MAX
133} arg_action = ACTION_SYSTEMCTL;
f459b602 134static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
7085053a 135static char *arg_host = NULL;
df50185b
LP
136static unsigned arg_lines = 10;
137static OutputMode arg_output = OUTPUT_SHORT;
5d0c05e5 138static bool arg_plain = false;
1238ee09 139
39602c39
TA
140static const struct {
141 const char *verb;
142 const char *method;
143} unit_actions[] = {
144 { "start", "StartUnit" },
145 { "stop", "StopUnit" },
146 { "condstop", "StopUnit" },
147 { "reload", "ReloadUnit" },
148 { "restart", "RestartUnit" },
149 { "try-restart", "TryRestartUnit" },
150 { "condrestart", "TryRestartUnit" },
151 { "reload-or-restart", "ReloadOrRestartUnit" },
152 { "reload-or-try-restart", "ReloadOrTryRestartUnit" },
153 { "condreload", "ReloadOrTryRestartUnit" },
154 { "force-reload", "ReloadOrTryRestartUnit" }
155};
e4b61340 156
1238ee09
LP
157static bool original_stdout_is_tty;
158
f459b602 159static int daemon_reload(sd_bus *bus, char **args);
477def80 160static int halt_now(enum action a);
dbc2c080
LP
161static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet);
162
d8fba7c6
ZJS
163static char** strv_skip_first(char **strv) {
164 if (strv_length(strv) > 0)
165 return strv + 1;
166 return NULL;
167}
168
3b0727f5 169static void pager_open_if_enabled(void) {
f8440af5 170
729e3769
LP
171 if (arg_no_pager)
172 return;
3b0727f5 173
1b12a7b5 174 pager_open(false);
729e3769 175}
c0f9c7da 176
6bb92a16 177static void ask_password_agent_open_if_enabled(void) {
501fc174 178
729e3769 179 /* Open the password agent as a child process if necessary */
501fc174
LP
180
181 if (!arg_ask_password)
182 return;
715554e7 183
729e3769 184 if (arg_scope != UNIT_FILE_SYSTEM)
501fc174
LP
185 return;
186
cbc9fbd1
LP
187 if (arg_transport != BUS_TRANSPORT_LOCAL)
188 return;
189
6bb92a16
LP
190 ask_password_agent_open();
191}
192
ba1261bc 193#ifdef HAVE_LOGIND
6bb92a16
LP
194static void polkit_agent_open_if_enabled(void) {
195
196 /* Open the polkit agent as a child process if necessary */
197
198 if (!arg_ask_password)
199 return;
200
201 if (arg_scope != UNIT_FILE_SYSTEM)
202 return;
203
f459b602
MAP
204 if (arg_transport != BUS_TRANSPORT_LOCAL)
205 return;
206
6bb92a16 207 polkit_agent_open();
501fc174 208}
ba1261bc 209#endif
501fc174 210
f459b602 211static int translate_bus_error_to_exit_status(int r, const sd_bus_error *error) {
22f4096c
LP
212 assert(error);
213
f459b602 214 if (!sd_bus_error_is_set(error))
22f4096c
LP
215 return r;
216
f459b602
MAP
217 if (sd_bus_error_has_name(error, SD_BUS_ERROR_ACCESS_DENIED) ||
218 sd_bus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) ||
219 sd_bus_error_has_name(error, BUS_ERROR_NO_ISOLATION) ||
220 sd_bus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
22f4096c
LP
221 return EXIT_NOPERMISSION;
222
f459b602 223 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
22f4096c
LP
224 return EXIT_NOTINSTALLED;
225
f459b602 226 if (sd_bus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) ||
718db961 227 sd_bus_error_has_name(error, SD_BUS_ERROR_NOT_SUPPORTED))
22f4096c
LP
228 return EXIT_NOTIMPLEMENTED;
229
f459b602 230 if (sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
22f4096c
LP
231 return EXIT_NOTCONFIGURED;
232
233 if (r != 0)
234 return r;
235
236 return EXIT_FAILURE;
237}
238
4c80c73c 239static void warn_wall(enum action a) {
ef2f1067 240 static const char *table[_ACTION_MAX] = {
dfcc5c33
MS
241 [ACTION_HALT] = "The system is going down for system halt NOW!",
242 [ACTION_REBOOT] = "The system is going down for reboot NOW!",
243 [ACTION_POWEROFF] = "The system is going down for power-off NOW!",
244 [ACTION_KEXEC] = "The system is going down for kexec reboot NOW!",
245 [ACTION_RESCUE] = "The system is going down to rescue mode NOW!",
246 [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!",
247 [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!"
ef2f1067
LP
248 };
249
514f4ef5
LP
250 if (arg_no_wall)
251 return;
252
e4a9373f 253 if (arg_wall) {
f84190d8 254 _cleanup_free_ char *p;
e4a9373f 255
7e59bfcb
LP
256 p = strv_join(arg_wall, " ");
257 if (!p) {
f84190d8 258 log_oom();
e4a9373f
LP
259 return;
260 }
261
262 if (*p) {
9003d9b0 263 utmp_wall(p, NULL, NULL);
e4a9373f
LP
264 return;
265 }
e4a9373f
LP
266 }
267
4c80c73c 268 if (!table[a])
ef2f1067
LP
269 return;
270
9003d9b0 271 utmp_wall(table[a], NULL, NULL);
ef2f1067
LP
272}
273
729e3769
LP
274static bool avoid_bus(void) {
275
276 if (running_in_chroot() > 0)
277 return true;
278
279 if (sd_booted() <= 0)
280 return true;
281
282 if (!isempty(arg_root))
283 return true;
284
285 if (arg_scope == UNIT_FILE_GLOBAL)
286 return true;
287
288 return false;
289}
290
36c32ba2 291static int compare_unit_info(const void *a, const void *b) {
f459b602 292 const UnitInfo *u = a, *v = b;
36c32ba2 293 const char *d1, *d2;
1238ee09
LP
294 int r;
295
296 /* First, order by machine */
297 if (!u->machine && v->machine)
298 return -1;
299 if (u->machine && !v->machine)
300 return 1;
301 if (u->machine && v->machine) {
302 r = strcasecmp(u->machine, v->machine);
303 if (r != 0)
304 return r;
305 }
36c32ba2 306
1238ee09 307 /* Second, order by unit type */
36c32ba2
LP
308 d1 = strrchr(u->id, '.');
309 d2 = strrchr(v->id, '.');
36c32ba2 310 if (d1 && d2) {
f84190d8
LP
311 r = strcasecmp(d1, d2);
312 if (r != 0)
36c32ba2
LP
313 return r;
314 }
315
1238ee09 316 /* Third, order by name */
a2a3a5b9 317 return strcasecmp(u->id, v->id);
36c32ba2
LP
318}
319
d8fba7c6 320static bool output_show_unit(const UnitInfo *u, char **patterns) {
33330222 321 const char *dot;
b036fc00 322
d8fba7c6
ZJS
323 if (!strv_isempty(patterns)) {
324 char **pattern;
325
326 STRV_FOREACH(pattern, patterns)
327 if (fnmatch(*pattern, u->id, FNM_NOESCAPE) == 0)
328 return true;
329 return false;
330 }
331
20b3f379
ZJS
332 return (!arg_types || ((dot = strrchr(u->id, '.')) &&
333 strv_find(arg_types, dot+1))) &&
c147dc42
ZJS
334 (arg_all || !(streq(u->active_state, "inactive")
335 || u->following[0]) || u->job_id > 0);
33330222
ZJS
336}
337
1238ee09 338static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
90c3f79d 339 unsigned circle_len = 0, id_len, max_id_len, load_len, active_len, sub_len, job_len, desc_len;
f459b602 340 const UnitInfo *u;
a1074881 341 unsigned n_shown = 0;
ccd41387 342 int job_count = 0;
33330222 343
f8294e41
JT
344 max_id_len = strlen("UNIT");
345 load_len = strlen("LOAD");
346 active_len = strlen("ACTIVE");
347 sub_len = strlen("SUB");
348 job_len = strlen("JOB");
4deb3b93 349 desc_len = 0;
b036fc00
LP
350
351 for (u = unit_infos; u < unit_infos + c; u++) {
1238ee09 352 max_id_len = MAX(max_id_len, strlen(u->id) + (u->machine ? strlen(u->machine)+1 : 0));
a1074881 353 load_len = MAX(load_len, strlen(u->load_state));
b036fc00
LP
354 active_len = MAX(active_len, strlen(u->active_state));
355 sub_len = MAX(sub_len, strlen(u->sub_state));
f459b602 356
ccd41387 357 if (u->job_id != 0) {
b036fc00 358 job_len = MAX(job_len, strlen(u->job_type));
ccd41387
ZJS
359 job_count++;
360 }
90c3f79d
LP
361
362 if (!arg_no_legend &&
363 (streq(u->active_state, "failed") ||
364 STR_IN_SET(u->load_state, "error", "not-found", "masked")))
365 circle_len = 2;
33330222
ZJS
366 }
367
184ecaf7 368 if (!arg_full && original_stdout_is_tty) {
4deb3b93 369 unsigned basic_len;
cbc9fbd1 370
9607d947 371 id_len = MIN(max_id_len, 25u);
90c3f79d 372 basic_len = circle_len + 5 + id_len + 5 + active_len + sub_len;
cbc9fbd1 373
ccd41387
ZJS
374 if (job_count)
375 basic_len += job_len + 1;
cbc9fbd1 376
4deb3b93
MS
377 if (basic_len < (unsigned) columns()) {
378 unsigned extra_len, incr;
379 extra_len = columns() - basic_len;
cbc9fbd1 380
4deb3b93
MS
381 /* Either UNIT already got 25, or is fully satisfied.
382 * Grant up to 25 to DESC now. */
9607d947 383 incr = MIN(extra_len, 25u);
4deb3b93
MS
384 desc_len += incr;
385 extra_len -= incr;
cbc9fbd1 386
4deb3b93
MS
387 /* split the remaining space between UNIT and DESC,
388 * but do not give UNIT more than it needs. */
389 if (extra_len > 0) {
390 incr = MIN(extra_len / 2, max_id_len - id_len);
391 id_len += incr;
392 desc_len += extra_len - incr;
393 }
394 }
395 } else
396 id_len = max_id_len;
397
b036fc00 398 for (u = unit_infos; u < unit_infos + c; u++) {
1238ee09 399 _cleanup_free_ char *e = NULL, *j = NULL;
90c3f79d
LP
400 const char *on_loaded = "", *off_loaded = "";
401 const char *on_active = "", *off_active = "";
402 const char *on_circle = "", *off_circle = "";
1238ee09 403 const char *id;
90c3f79d 404 bool circle = false;
b036fc00 405
ad94ad63 406 if (!n_shown && !arg_no_legend) {
90c3f79d
LP
407
408 if (circle_len > 0)
409 fputs(" ", stdout);
410
cbc9fbd1
LP
411 printf("%-*s %-*s %-*s %-*s ",
412 id_len, "UNIT",
413 load_len, "LOAD",
414 active_len, "ACTIVE",
415 sub_len, "SUB");
416
ccd41387
ZJS
417 if (job_count)
418 printf("%-*s ", job_len, "JOB");
cbc9fbd1 419
ad94ad63
ZJS
420 if (!arg_full && arg_no_pager)
421 printf("%.*s\n", desc_len, "DESCRIPTION");
422 else
423 printf("%s\n", "DESCRIPTION");
424 }
425
688c6725
LP
426 n_shown++;
427
90c3f79d
LP
428 if (STR_IN_SET(u->load_state, "error", "not-found", "masked")) {
429 on_loaded = ansi_highlight_red();
430 on_circle = ansi_highlight_yellow();
431 off_loaded = off_circle = ansi_highlight_off();
432 circle = true;
433 }
b036fc00
LP
434
435 if (streq(u->active_state, "failed")) {
90c3f79d
LP
436 on_circle = on_active = ansi_highlight_red();
437 off_circle = off_active = ansi_highlight_off();
438 circle = true;
439 }
eb68c413 440
1238ee09
LP
441 if (u->machine) {
442 j = strjoin(u->machine, ":", u->id, NULL);
443 if (!j)
444 return log_oom();
445
446 id = j;
447 } else
448 id = u->id;
449
450 if (arg_full) {
451 e = ellipsize(id, id_len, 33);
452 if (!e)
453 return log_oom();
454
455 id = e;
456 }
eb68c413 457
90c3f79d 458 if (circle_len > 0)
b7bbdabe 459 printf("%s%s%s ", on_circle, circle ? draw_special_char(DRAW_BLACK_CIRCLE) : " ", off_circle);
90c3f79d 460
a1074881 461 printf("%s%-*s%s %s%-*s%s %s%-*s %-*s%s %-*s",
90c3f79d 462 on_active, id_len, id, off_active,
a1074881 463 on_loaded, load_len, u->load_state, off_loaded,
b036fc00
LP
464 on_active, active_len, u->active_state,
465 sub_len, u->sub_state, off_active,
ccd41387 466 job_count ? job_len + 1 : 0, u->job_id ? u->job_type : "");
cbc9fbd1 467
184ecaf7 468 if (desc_len > 0)
798e258d
MS
469 printf("%.*s\n", desc_len, u->description);
470 else
471 printf("%s\n", u->description);
eb68c413
ZJS
472 }
473
ebed32bf 474 if (!arg_no_legend) {
57f7ae4f
ZJS
475 const char *on, *off;
476
477 if (n_shown) {
90c3f79d
LP
478 puts("\n"
479 "LOAD = Reflects whether the unit definition was properly loaded.\n"
e3e0314b
ZJS
480 "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
481 "SUB = The low-level unit activation state, values depend on unit type.");
482 puts(job_count ? "JOB = Pending job for the unit.\n" : "");
0b5a519c
DS
483 on = ansi_highlight();
484 off = ansi_highlight_off();
57f7ae4f 485 } else {
0b5a519c
DS
486 on = ansi_highlight_red();
487 off = ansi_highlight_off();
57f7ae4f 488 }
eb68c413
ZJS
489
490 if (arg_all)
48c2826b 491 printf("%s%u loaded units listed.%s\n"
57f7ae4f
ZJS
492 "To show all installed unit files use 'systemctl list-unit-files'.\n",
493 on, n_shown, off);
eb68c413 494 else
48c2826b 495 printf("%s%u loaded units listed.%s Pass --all to see loaded but inactive units, too.\n"
57f7ae4f
ZJS
496 "To show all installed unit files use 'systemctl list-unit-files'.\n",
497 on, n_shown, off);
eb68c413 498 }
1238ee09
LP
499
500 return 0;
eb68c413
ZJS
501}
502
a00963a2 503static int get_unit_list(
f459b602 504 sd_bus *bus,
1238ee09
LP
505 const char *machine,
506 char **patterns,
507 UnitInfo **unit_infos,
508 int c,
509 sd_bus_message **_reply) {
a00963a2 510
cdc06ed7 511 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
f459b602
MAP
512 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
513 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
ca2d3784 514 size_t size = c;
1238ee09 515 int r;
f459b602 516 UnitInfo u;
7e4249b9 517
265a7a2a 518 assert(bus);
1238ee09 519 assert(unit_infos);
f459b602 520 assert(_reply);
1238ee09 521
cdc06ed7 522 r = sd_bus_message_new_method_call(
f22f08cd 523 bus,
cdc06ed7 524 &m,
f22f08cd
SP
525 "org.freedesktop.systemd1",
526 "/org/freedesktop/systemd1",
527 "org.freedesktop.systemd1.Manager",
cdc06ed7
DS
528 "ListUnitsFiltered");
529
530 if (r < 0)
531 return bus_log_create_error(r);
532
533 r = sd_bus_message_append_strv(m, arg_states);
534 if (r < 0)
535 return bus_log_create_error(r);
536
537 r = sd_bus_call(bus, m, 0, &error, &reply);
f459b602
MAP
538 if (r < 0) {
539 log_error("Failed to list units: %s", bus_error_message(&error, r));
f84190d8 540 return r;
7e4249b9
LP
541 }
542
f459b602
MAP
543 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
544 if (r < 0)
545 return bus_log_parse_error(r);
7e4249b9 546
f459b602 547 while ((r = bus_parse_unit_info(reply, &u)) > 0) {
1238ee09
LP
548 u.machine = machine;
549
8d5ba5a9
ZJS
550 if (!output_show_unit(&u, patterns))
551 continue;
7e4249b9 552
1238ee09 553 if (!GREEDY_REALLOC(*unit_infos, size, c+1))
f459b602 554 return log_oom();
36c32ba2 555
1238ee09 556 (*unit_infos)[c++] = u;
991f2a39 557 }
f459b602
MAP
558 if (r < 0)
559 return bus_log_parse_error(r);
991f2a39 560
f459b602
MAP
561 r = sd_bus_message_exit_container(reply);
562 if (r < 0)
563 return bus_log_parse_error(r);
564
565 *_reply = reply;
566 reply = NULL;
567
1238ee09
LP
568 return c;
569}
570
571static void message_set_freep(Set **set) {
572 sd_bus_message *m;
573
574 while ((m = set_steal_first(*set)))
575 sd_bus_message_unref(m);
576
577 set_free(*set);
578}
579
580static int get_unit_list_recursive(
581 sd_bus *bus,
582 char **patterns,
583 UnitInfo **_unit_infos,
584 Set **_replies,
585 char ***_machines) {
586
587 _cleanup_free_ UnitInfo *unit_infos = NULL;
588 _cleanup_(message_set_freep) Set *replies;
589 sd_bus_message *reply;
590 int c, r;
591
592 assert(bus);
593 assert(_replies);
594 assert(_unit_infos);
595 assert(_machines);
596
597 replies = set_new(NULL, NULL);
598 if (!replies)
599 return log_oom();
600
601 c = get_unit_list(bus, NULL, patterns, &unit_infos, 0, &reply);
602 if (c < 0)
603 return c;
604
605 r = set_put(replies, reply);
606 if (r < 0) {
607 sd_bus_message_unref(reply);
608 return r;
609 }
610
611 if (arg_recursive) {
612 _cleanup_strv_free_ char **machines = NULL;
613 char **i;
614
615 r = sd_get_machine_names(&machines);
616 if (r < 0)
617 return r;
618
619 STRV_FOREACH(i, machines) {
24996861 620 _cleanup_bus_close_unref_ sd_bus *container = NULL;
1238ee09
LP
621 int k;
622
623 r = sd_bus_open_system_container(&container, *i);
624 if (r < 0) {
625 log_error("Failed to connect to container %s: %s", *i, strerror(-r));
626 continue;
627 }
628
629 k = get_unit_list(container, *i, patterns, &unit_infos, c, &reply);
630 if (k < 0)
631 return k;
632
633 c = k;
634
635 r = set_put(replies, reply);
636 if (r < 0) {
637 sd_bus_message_unref(reply);
638 return r;
639 }
640 }
641
642 *_machines = machines;
643 machines = NULL;
644 } else
645 *_machines = NULL;
646
f459b602
MAP
647 *_unit_infos = unit_infos;
648 unit_infos = NULL;
649
1238ee09
LP
650 *_replies = replies;
651 replies = NULL;
652
f459b602 653 return c;
991f2a39
ZJS
654}
655
f459b602 656static int list_units(sd_bus *bus, char **args) {
f459b602 657 _cleanup_free_ UnitInfo *unit_infos = NULL;
1238ee09
LP
658 _cleanup_(message_set_freep) Set *replies = NULL;
659 _cleanup_strv_free_ char **machines = NULL;
991f2a39
ZJS
660 int r;
661
662 pager_open_if_enabled();
663
1238ee09 664 r = get_unit_list_recursive(bus, strv_skip_first(args), &unit_infos, &replies, &machines);
991f2a39
ZJS
665 if (r < 0)
666 return r;
667
f459b602 668 qsort_safe(unit_infos, r, sizeof(UnitInfo), compare_unit_info);
1238ee09 669 return output_units_list(unit_infos, r);
991f2a39
ZJS
670}
671
a00963a2 672static int get_triggered_units(
f459b602
MAP
673 sd_bus *bus,
674 const char* path,
675 char*** ret) {
a00963a2 676
f459b602 677 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
991f2a39
ZJS
678 int r;
679
f459b602
MAP
680 r = sd_bus_get_property_strv(
681 bus,
682 "org.freedesktop.systemd1",
683 path,
684 "org.freedesktop.systemd1.Unit",
685 "Triggers",
686 &error,
687 ret);
991f2a39 688
f459b602
MAP
689 if (r < 0)
690 log_error("Failed to determine triggers: %s", bus_error_message(&error, r));
991f2a39
ZJS
691
692 return 0;
693}
694
f459b602
MAP
695static int get_listening(
696 sd_bus *bus,
697 const char* unit_path,
cbb76c29 698 char*** listening) {
f459b602 699
f459b602 700 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
cbb76c29 701 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
f459b602 702 const char *type, *path;
cbb76c29 703 int r, n = 0;
991f2a39 704
f459b602
MAP
705 r = sd_bus_get_property(
706 bus,
707 "org.freedesktop.systemd1",
708 unit_path,
709 "org.freedesktop.systemd1.Socket",
710 "Listen",
711 &error,
712 &reply,
713 "a(ss)");
714 if (r < 0) {
715 log_error("Failed to get list of listening sockets: %s", bus_error_message(&error, r));
991f2a39 716 return r;
991f2a39
ZJS
717 }
718
f459b602
MAP
719 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)");
720 if (r < 0)
721 return bus_log_parse_error(r);
991f2a39 722
f459b602 723 while ((r = sd_bus_message_read(reply, "(ss)", &type, &path)) > 0) {
36c32ba2 724
0d95178e 725 r = strv_extend(listening, type);
f459b602
MAP
726 if (r < 0)
727 return log_oom();
991f2a39 728
0d95178e 729 r = strv_extend(listening, path);
f459b602
MAP
730 if (r < 0)
731 return log_oom();
7e4249b9 732
cbb76c29 733 n++;
36c32ba2 734 }
f459b602
MAP
735 if (r < 0)
736 return bus_log_parse_error(r);
737
738 r = sd_bus_message_exit_container(reply);
739 if (r < 0)
740 return bus_log_parse_error(r);
36c32ba2 741
cbb76c29 742 return n;
991f2a39
ZJS
743}
744
745struct socket_info {
0cfc3525 746 const char *machine;
991f2a39
ZJS
747 const char* id;
748
749 char* type;
750 char* path;
751
752 /* Note: triggered is a list here, although it almost certainly
753 * will always be one unit. Nevertheless, dbus API allows for multiple
754 * values, so let's follow that.*/
755 char** triggered;
756
757 /* The strv above is shared. free is set only in the first one. */
758 bool own_triggered;
759};
760
cbb76c29 761static int socket_info_compare(const struct socket_info *a, const struct socket_info *b) {
cbc9fbd1
LP
762 int o;
763
cbb76c29
LP
764 assert(a);
765 assert(b);
766
0cfc3525
TA
767 if (!a->machine && b->machine)
768 return -1;
769 if (a->machine && !b->machine)
770 return 1;
771 if (a->machine && b->machine) {
772 o = strcasecmp(a->machine, b->machine);
773 if (o != 0)
774 return o;
775 }
776
cbc9fbd1 777 o = strcmp(a->path, b->path);
991f2a39
ZJS
778 if (o == 0)
779 o = strcmp(a->type, b->type);
cbc9fbd1 780
991f2a39
ZJS
781 return o;
782}
783
784static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
785 struct socket_info *s;
f8294e41
JT
786 unsigned pathlen = strlen("LISTEN"),
787 typelen = strlen("TYPE") * arg_show_types,
788 socklen = strlen("UNIT"),
789 servlen = strlen("ACTIVATES");
991f2a39
ZJS
790 const char *on, *off;
791
792 for (s = socket_infos; s < socket_infos + cs; s++) {
991f2a39 793 unsigned tmp = 0;
cbc9fbd1 794 char **a;
991f2a39
ZJS
795
796 socklen = MAX(socklen, strlen(s->id));
797 if (arg_show_types)
798 typelen = MAX(typelen, strlen(s->type));
0cfc3525 799 pathlen = MAX(pathlen, strlen(s->path) + (s->machine ? strlen(s->machine)+1 : 0));
991f2a39
ZJS
800
801 STRV_FOREACH(a, s->triggered)
802 tmp += strlen(*a) + 2*(a != s->triggered);
803 servlen = MAX(servlen, tmp);
804 }
805
806 if (cs) {
571bfc6c
MM
807 if (!arg_no_legend)
808 printf("%-*s %-*.*s%-*s %s\n",
809 pathlen, "LISTEN",
810 typelen + arg_show_types, typelen + arg_show_types, "TYPE ",
811 socklen, "UNIT",
812 "ACTIVATES");
991f2a39
ZJS
813
814 for (s = socket_infos; s < socket_infos + cs; s++) {
0cfc3525
TA
815 _cleanup_free_ char *j = NULL;
816 const char *path;
991f2a39
ZJS
817 char **a;
818
0cfc3525
TA
819 if (s->machine) {
820 j = strjoin(s->machine, ":", s->path, NULL);
821 if (!j)
822 return log_oom();
823 path = j;
824 } else
825 path = s->path;
826
991f2a39
ZJS
827 if (arg_show_types)
828 printf("%-*s %-*s %-*s",
0cfc3525 829 pathlen, path, typelen, s->type, socklen, s->id);
991f2a39
ZJS
830 else
831 printf("%-*s %-*s",
0cfc3525 832 pathlen, path, socklen, s->id);
991f2a39
ZJS
833 STRV_FOREACH(a, s->triggered)
834 printf("%s %s",
835 a == s->triggered ? "" : ",", *a);
836 printf("\n");
837 }
838
0b5a519c
DS
839 on = ansi_highlight();
840 off = ansi_highlight_off();
571bfc6c
MM
841 if (!arg_no_legend)
842 printf("\n");
991f2a39 843 } else {
0b5a519c
DS
844 on = ansi_highlight_red();
845 off = ansi_highlight_off();
991f2a39
ZJS
846 }
847
571bfc6c
MM
848 if (!arg_no_legend) {
849 printf("%s%u sockets listed.%s\n", on, cs, off);
850 if (!arg_all)
851 printf("Pass --all to see loaded but inactive sockets, too.\n");
852 }
265a7a2a
ZJS
853
854 return 0;
855}
856
f459b602 857static int list_sockets(sd_bus *bus, char **args) {
0cfc3525
TA
858 _cleanup_(message_set_freep) Set *replies = NULL;
859 _cleanup_strv_free_ char **machines = NULL;
f459b602 860 _cleanup_free_ UnitInfo *unit_infos = NULL;
8d5ba5a9 861 _cleanup_free_ struct socket_info *socket_infos = NULL;
f459b602 862 const UnitInfo *u;
991f2a39 863 struct socket_info *s;
cbb76c29 864 unsigned cs = 0;
991f2a39 865 size_t size = 0;
ad83b4c4 866 int r = 0, n;
265a7a2a
ZJS
867
868 pager_open_if_enabled();
869
0cfc3525 870 n = get_unit_list_recursive(bus, strv_skip_first(args), &unit_infos, &replies, &machines);
cbb76c29
LP
871 if (n < 0)
872 return n;
265a7a2a 873
cbb76c29 874 for (u = unit_infos; u < unit_infos + n; u++) {
0d95178e 875 _cleanup_strv_free_ char **listening = NULL, **triggered = NULL;
cbb76c29 876 int i, c;
991f2a39 877
cbc9fbd1 878 if (!endswith(u->id, ".socket"))
991f2a39
ZJS
879 continue;
880
881 r = get_triggered_units(bus, u->unit_path, &triggered);
882 if (r < 0)
883 goto cleanup;
884
cbb76c29
LP
885 c = get_listening(bus, u->unit_path, &listening);
886 if (c < 0) {
887 r = c;
991f2a39 888 goto cleanup;
cbb76c29 889 }
991f2a39
ZJS
890
891 if (!GREEDY_REALLOC(socket_infos, size, cs + c)) {
892 r = log_oom();
893 goto cleanup;
894 }
895
896 for (i = 0; i < c; i++)
897 socket_infos[cs + i] = (struct socket_info) {
0cfc3525 898 .machine = u->machine,
991f2a39 899 .id = u->id,
0d95178e
KS
900 .type = listening[i*2],
901 .path = listening[i*2 + 1],
991f2a39
ZJS
902 .triggered = triggered,
903 .own_triggered = i==0,
904 };
905
906 /* from this point on we will cleanup those socket_infos */
907 cs += c;
0d95178e
KS
908 free(listening);
909 listening = triggered = NULL; /* avoid cleanup */
991f2a39
ZJS
910 }
911
7ff7394d
ZJS
912 qsort_safe(socket_infos, cs, sizeof(struct socket_info),
913 (__compar_fn_t) socket_info_compare);
991f2a39
ZJS
914
915 output_sockets_list(socket_infos, cs);
916
917 cleanup:
918 assert(cs == 0 || socket_infos);
919 for (s = socket_infos; s < socket_infos + cs; s++) {
920 free(s->type);
921 free(s->path);
922 if (s->own_triggered)
923 strv_free(s->triggered);
924 }
4445a875 925
872c8faa 926 return r;
4445a875
LP
927}
928
cbb76c29
LP
929static int get_next_elapse(
930 sd_bus *bus,
931 const char *path,
932 dual_timestamp *next) {
933
934 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
cbb76c29
LP
935 dual_timestamp t;
936 int r;
937
938 assert(bus);
939 assert(path);
940 assert(next);
941
942 r = sd_bus_get_property_trivial(
943 bus,
944 "org.freedesktop.systemd1",
945 path,
946 "org.freedesktop.systemd1.Timer",
947 "NextElapseUSecMonotonic",
948 &error,
949 't',
950 &t.monotonic);
951 if (r < 0) {
952 log_error("Failed to get next elapsation time: %s", bus_error_message(&error, r));
953 return r;
954 }
955
956 r = sd_bus_get_property_trivial(
957 bus,
958 "org.freedesktop.systemd1",
959 path,
960 "org.freedesktop.systemd1.Timer",
961 "NextElapseUSecRealtime",
962 &error,
963 't',
964 &t.realtime);
965 if (r < 0) {
966 log_error("Failed to get next elapsation time: %s", bus_error_message(&error, r));
967 return r;
968 }
969
970 *next = t;
971 return 0;
972}
973
d784e2db
LP
974static int get_last_trigger(
975 sd_bus *bus,
976 const char *path,
977 usec_t *last) {
978
979 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
980 int r;
981
982 assert(bus);
983 assert(path);
984 assert(last);
985
986 r = sd_bus_get_property_trivial(
987 bus,
988 "org.freedesktop.systemd1",
989 path,
990 "org.freedesktop.systemd1.Timer",
dedabea4 991 "LastTriggerUSec",
d784e2db
LP
992 &error,
993 't',
994 last);
995 if (r < 0) {
996 log_error("Failed to get last trigger time: %s", bus_error_message(&error, r));
997 return r;
998 }
999
1000 return 0;
1001}
1002
cbb76c29 1003struct timer_info {
806a37e7 1004 const char* machine;
cbb76c29
LP
1005 const char* id;
1006 usec_t next_elapse;
d784e2db 1007 usec_t last_trigger;
cbb76c29
LP
1008 char** triggered;
1009};
1010
1011static int timer_info_compare(const struct timer_info *a, const struct timer_info *b) {
806a37e7
TA
1012 int o;
1013
cbb76c29
LP
1014 assert(a);
1015 assert(b);
1016
806a37e7
TA
1017 if (!a->machine && b->machine)
1018 return -1;
1019 if (a->machine && !b->machine)
1020 return 1;
1021 if (a->machine && b->machine) {
1022 o = strcasecmp(a->machine, b->machine);
1023 if (o != 0)
1024 return o;
1025 }
1026
cbb76c29
LP
1027 if (a->next_elapse < b->next_elapse)
1028 return -1;
1029 if (a->next_elapse > b->next_elapse)
1030 return 1;
1031
1032 return strcmp(a->id, b->id);
1033}
1034
1035static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
1036 struct timer_info *t;
1037 unsigned
f8294e41
JT
1038 nextlen = strlen("NEXT"),
1039 leftlen = strlen("LEFT"),
d784e2db
LP
1040 lastlen = strlen("LAST"),
1041 passedlen = strlen("PASSED"),
f8294e41
JT
1042 unitlen = strlen("UNIT"),
1043 activatelen = strlen("ACTIVATES");
cbb76c29
LP
1044
1045 const char *on, *off;
1046
1047 assert(timer_infos || n == 0);
1048
1049 for (t = timer_infos; t < timer_infos + n; t++) {
1050 unsigned ul = 0;
1051 char **a;
1052
1053 if (t->next_elapse > 0) {
1054 char tstamp[FORMAT_TIMESTAMP_MAX] = "", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = "";
1055
1056 format_timestamp(tstamp, sizeof(tstamp), t->next_elapse);
1057 nextlen = MAX(nextlen, strlen(tstamp) + 1);
1058
1059 format_timestamp_relative(trel, sizeof(trel), t->next_elapse);
1060 leftlen = MAX(leftlen, strlen(trel));
1061 }
1062
d784e2db
LP
1063 if (t->last_trigger > 0) {
1064 char tstamp[FORMAT_TIMESTAMP_MAX] = "", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = "";
1065
1066 format_timestamp(tstamp, sizeof(tstamp), t->last_trigger);
1067 lastlen = MAX(lastlen, strlen(tstamp) + 1);
1068
1069 format_timestamp_relative(trel, sizeof(trel), t->last_trigger);
1070 passedlen = MAX(passedlen, strlen(trel));
1071 }
1072
806a37e7 1073 unitlen = MAX(unitlen, strlen(t->id) + (t->machine ? strlen(t->machine)+1 : 0));
cbb76c29
LP
1074
1075 STRV_FOREACH(a, t->triggered)
1076 ul += strlen(*a) + 2*(a != t->triggered);
d784e2db 1077
cbb76c29
LP
1078 activatelen = MAX(activatelen, ul);
1079 }
1080
1081 if (n > 0) {
1082 if (!arg_no_legend)
d784e2db
LP
1083 printf("%-*s %-*s %-*s %-*s %-*s %s\n",
1084 nextlen, "NEXT",
1085 leftlen, "LEFT",
1086 lastlen, "LAST",
1087 passedlen, "PASSED",
1088 unitlen, "UNIT",
1089 "ACTIVATES");
cbb76c29
LP
1090
1091 for (t = timer_infos; t < timer_infos + n; t++) {
806a37e7
TA
1092 _cleanup_free_ char *j = NULL;
1093 const char *unit;
d784e2db
LP
1094 char tstamp1[FORMAT_TIMESTAMP_MAX] = "n/a", trel1[FORMAT_TIMESTAMP_RELATIVE_MAX] = "n/a";
1095 char tstamp2[FORMAT_TIMESTAMP_MAX] = "n/a", trel2[FORMAT_TIMESTAMP_RELATIVE_MAX] = "n/a";
cbb76c29
LP
1096 char **a;
1097
d784e2db
LP
1098 format_timestamp(tstamp1, sizeof(tstamp1), t->next_elapse);
1099 format_timestamp_relative(trel1, sizeof(trel1), t->next_elapse);
cbb76c29 1100
d784e2db
LP
1101 format_timestamp(tstamp2, sizeof(tstamp2), t->last_trigger);
1102 format_timestamp_relative(trel2, sizeof(trel2), t->last_trigger);
1103
806a37e7
TA
1104 if (t->machine) {
1105 j = strjoin(t->machine, ":", t->id, NULL);
1106 if (!j)
1107 return log_oom();
1108 unit = j;
1109 } else
1110 unit = t->id;
1111
d784e2db 1112 printf("%-*s %-*s %-*s %-*s %-*s",
806a37e7 1113 nextlen, tstamp1, leftlen, trel1, lastlen, tstamp2, passedlen, trel2, unitlen, unit);
cbb76c29
LP
1114
1115 STRV_FOREACH(a, t->triggered)
1116 printf("%s %s",
1117 a == t->triggered ? "" : ",", *a);
1118 printf("\n");
1119 }
1120
1121 on = ansi_highlight();
1122 off = ansi_highlight_off();
1123 if (!arg_no_legend)
1124 printf("\n");
1125 } else {
1126 on = ansi_highlight_red();
1127 off = ansi_highlight_off();
1128 }
1129
1130 if (!arg_no_legend) {
1131 printf("%s%u timers listed.%s\n", on, n, off);
1132 if (!arg_all)
1133 printf("Pass --all to see loaded but inactive timers, too.\n");
1134 }
1135
1136 return 0;
1137}
1138
f5080e73
DH
1139static usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next) {
1140 usec_t next_elapse;
1141
1142 assert(nw);
1143 assert(next);
1144
3a43da28 1145 if (next->monotonic != USEC_INFINITY && next->monotonic > 0) {
f5080e73
DH
1146 usec_t converted;
1147
1148 if (next->monotonic > nw->monotonic)
1149 converted = nw->realtime + (next->monotonic - nw->monotonic);
1150 else
1151 converted = nw->realtime - (nw->monotonic - next->monotonic);
1152
3a43da28 1153 if (next->realtime != USEC_INFINITY && next->realtime > 0)
f5080e73
DH
1154 next_elapse = MIN(converted, next->realtime);
1155 else
1156 next_elapse = converted;
1157
1158 } else
1159 next_elapse = next->realtime;
1160
1161 return next_elapse;
1162}
1163
cbb76c29 1164static int list_timers(sd_bus *bus, char **args) {
806a37e7
TA
1165 _cleanup_(message_set_freep) Set *replies = NULL;
1166 _cleanup_strv_free_ char **machines = NULL;
cbb76c29
LP
1167 _cleanup_free_ struct timer_info *timer_infos = NULL;
1168 _cleanup_free_ UnitInfo *unit_infos = NULL;
1169 struct timer_info *t;
1170 const UnitInfo *u;
1171 size_t size = 0;
1823b86e 1172 int n, c = 0;
cbb76c29 1173 dual_timestamp nw;
1823b86e 1174 int r = 0;
cbb76c29
LP
1175
1176 pager_open_if_enabled();
1177
806a37e7 1178 n = get_unit_list_recursive(bus, strv_skip_first(args), &unit_infos, &replies, &machines);
cbb76c29
LP
1179 if (n < 0)
1180 return n;
1181
1182 dual_timestamp_get(&nw);
1183
1184 for (u = unit_infos; u < unit_infos + n; u++) {
1185 _cleanup_strv_free_ char **triggered = NULL;
9e82ffa0 1186 dual_timestamp next = {};
d784e2db 1187 usec_t m, last = 0;
cbb76c29 1188
cbb76c29
LP
1189 if (!endswith(u->id, ".timer"))
1190 continue;
1191
1192 r = get_triggered_units(bus, u->unit_path, &triggered);
1193 if (r < 0)
1194 goto cleanup;
1195
1196 r = get_next_elapse(bus, u->unit_path, &next);
1197 if (r < 0)
1198 goto cleanup;
1199
d784e2db
LP
1200 get_last_trigger(bus, u->unit_path, &last);
1201
cbb76c29
LP
1202 if (!GREEDY_REALLOC(timer_infos, size, c+1)) {
1203 r = log_oom();
1204 goto cleanup;
1205 }
1206
f5080e73
DH
1207 m = calc_next_elapse(&nw, &next);
1208
cbb76c29 1209 timer_infos[c++] = (struct timer_info) {
806a37e7 1210 .machine = u->machine,
cbb76c29
LP
1211 .id = u->id,
1212 .next_elapse = m,
d784e2db 1213 .last_trigger = last,
cbb76c29
LP
1214 .triggered = triggered,
1215 };
1216
1217 triggered = NULL; /* avoid cleanup */
1218 }
1219
1220 qsort_safe(timer_infos, c, sizeof(struct timer_info),
1221 (__compar_fn_t) timer_info_compare);
1222
1223 output_timers_list(timer_infos, c);
1224
1225 cleanup:
1226 for (t = timer_infos; t < timer_infos + c; t++)
1227 strv_free(t->triggered);
1228
1229 return r;
1230}
1231
729e3769
LP
1232static int compare_unit_file_list(const void *a, const void *b) {
1233 const char *d1, *d2;
1234 const UnitFileList *u = a, *v = b;
1235
1236 d1 = strrchr(u->path, '.');
1237 d2 = strrchr(v->path, '.');
1238
1239 if (d1 && d2) {
1240 int r;
1241
1242 r = strcasecmp(d1, d2);
1243 if (r != 0)
1244 return r;
1245 }
1246
2b6bf07d 1247 return strcasecmp(basename(u->path), basename(v->path));
729e3769
LP
1248}
1249
d8fba7c6 1250static bool output_show_unit_file(const UnitFileList *u, char **patterns) {
729e3769
LP
1251 const char *dot;
1252
d8fba7c6
ZJS
1253 if (!strv_isempty(patterns)) {
1254 char **pattern;
1255
1256 STRV_FOREACH(pattern, patterns)
1257 if (fnmatch(*pattern, basename(u->path), FNM_NOESCAPE) == 0)
1258 return true;
1259 return false;
1260 }
1261
20b3f379 1262 return !arg_types || ((dot = strrchr(u->path, '.')) && strv_find(arg_types, dot+1));
729e3769
LP
1263}
1264
8d5ba5a9 1265static void output_unit_file_list(const UnitFileList *units, unsigned c) {
0d292f5e 1266 unsigned max_id_len, id_cols, state_cols;
729e3769
LP
1267 const UnitFileList *u;
1268
f8294e41
JT
1269 max_id_len = strlen("UNIT FILE");
1270 state_cols = strlen("STATE");
cbc9fbd1 1271
1c0a113f 1272 for (u = units; u < units + c; u++) {
2b6bf07d 1273 max_id_len = MAX(max_id_len, strlen(basename(u->path)));
1c0a113f
ZJS
1274 state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state)));
1275 }
1276
1277 if (!arg_full) {
1278 unsigned basic_cols;
cbc9fbd1 1279
9607d947 1280 id_cols = MIN(max_id_len, 25u);
1c0a113f
ZJS
1281 basic_cols = 1 + id_cols + state_cols;
1282 if (basic_cols < (unsigned) columns())
1283 id_cols += MIN(columns() - basic_cols, max_id_len - id_cols);
1284 } else
1285 id_cols = max_id_len;
1286
1287 if (!arg_no_legend)
cbc9fbd1
LP
1288 printf("%-*s %-*s\n",
1289 id_cols, "UNIT FILE",
1290 state_cols, "STATE");
729e3769
LP
1291
1292 for (u = units; u < units + c; u++) {
7fd1b19b 1293 _cleanup_free_ char *e = NULL;
729e3769
LP
1294 const char *on, *off;
1295 const char *id;
1296
729e3769
LP
1297 if (u->state == UNIT_FILE_MASKED ||
1298 u->state == UNIT_FILE_MASKED_RUNTIME ||
b5b46d59
LP
1299 u->state == UNIT_FILE_DISABLED ||
1300 u->state == UNIT_FILE_INVALID) {
0b5a519c
DS
1301 on = ansi_highlight_red();
1302 off = ansi_highlight_off();
729e3769 1303 } else if (u->state == UNIT_FILE_ENABLED) {
0b5a519c
DS
1304 on = ansi_highlight_green();
1305 off = ansi_highlight_off();
729e3769
LP
1306 } else
1307 on = off = "";
1308
2b6bf07d 1309 id = basename(u->path);
729e3769 1310
1c0a113f 1311 e = arg_full ? NULL : ellipsize(id, id_cols, 33);
729e3769 1312
1c0a113f
ZJS
1313 printf("%-*s %s%-*s%s\n",
1314 id_cols, e ? e : id,
1315 on, state_cols, unit_file_state_to_string(u->state), off);
729e3769
LP
1316 }
1317
1c0a113f 1318 if (!arg_no_legend)
0d292f5e 1319 printf("\n%u unit files listed.\n", c);
729e3769
LP
1320}
1321
f459b602
MAP
1322static int list_unit_files(sd_bus *bus, char **args) {
1323 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1324 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
f84190d8 1325 _cleanup_free_ UnitFileList *units = NULL;
8d5ba5a9
ZJS
1326 UnitFileList *unit;
1327 size_t size = 0;
f459b602
MAP
1328 unsigned c = 0;
1329 const char *state;
1330 char *path;
f84190d8 1331 int r;
729e3769 1332
729e3769
LP
1333 pager_open_if_enabled();
1334
1335 if (avoid_bus()) {
1336 Hashmap *h;
1337 UnitFileList *u;
1338 Iterator i;
f459b602 1339 unsigned n_units;
729e3769
LP
1340
1341 h = hashmap_new(string_hash_func, string_compare_func);
0d0f0c50
SL
1342 if (!h)
1343 return log_oom();
729e3769
LP
1344
1345 r = unit_file_get_list(arg_scope, arg_root, h);
1346 if (r < 0) {
8ea913b2 1347 unit_file_list_free(h);
729e3769
LP
1348 log_error("Failed to get unit file list: %s", strerror(-r));
1349 return r;
1350 }
1351
1352 n_units = hashmap_size(h);
fdbdf6ec 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"))
2353 log_error("A dependency job for %s failed. See 'journalctl -xn' 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
2360 log_error("Job for %s failed. See \"systemctl status %s%s%s\" and \"journalctl -xn\" for details.",
2361 d->name,
2362 quotes ? "'" : "", d->name, quotes ? "'" : "");
2363 } else
2364 log_error("Job failed. See \"journalctl -xn\" for details.");
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
67f3c402 2749 s = set_new(string_hash_func, string_compare_func);
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
LP
4451static int cat(sd_bus *bus, char **args) {
4452 _cleanup_free_ char *unit = NULL;
4453 _cleanup_strv_free_ char **names = NULL;
4454 char **name;
4455 bool first = true;
4456 int r = 0;
4457
4458 assert(bus);
4459 assert(args);
4460
4461 r = expand_names(bus, args + 1, NULL, &names);
4462 if (r < 0)
4463 log_error("Failed to expand names: %s", strerror(-r));
4464
4465 pager_open_if_enabled();
4466
4467 STRV_FOREACH(name, names) {
4468 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4469 _cleanup_strv_free_ char **dropin_paths = NULL;
4470 _cleanup_free_ char *fragment_path = NULL;
4471 char **path;
4472
4473 unit = unit_dbus_path_from_name(*name);
4474 if (!unit)
4475 return log_oom();
4476
4477 if (need_daemon_reload(bus, *name) > 0)
4478 log_warning("Unit file of %s changed on disk. Run 'systemctl%s daemon-reload'.",
4479 *name, arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
4480
4481 r = sd_bus_get_property_string(
4482 bus,
4483 "org.freedesktop.systemd1",
4484 unit,
4485 "org.freedesktop.systemd1.Unit",
4486 "FragmentPath",
4487 &error,
4488 &fragment_path);
4489 if (r < 0) {
4490 log_warning("Failed to get FragmentPath: %s", bus_error_message(&error, r));
4491 continue;
4492 }
4493
4494 r = sd_bus_get_property_strv(
4495 bus,
4496 "org.freedesktop.systemd1",
4497 unit,
4498 "org.freedesktop.systemd1.Unit",
4499 "DropInPaths",
4500 &error,
4501 &dropin_paths);
4502 if (r < 0) {
4503 log_warning("Failed to get DropInPaths: %s", bus_error_message(&error, r));
4504 continue;
4505 }
4506
4507 if (first)
4508 first = false;
4509 else
4510 puts("");
4511
4512 if (!isempty(fragment_path)) {
4513 printf("%s# %s%s\n",
4514 ansi_highlight_blue(),
4515 fragment_path,
4516 ansi_highlight_off());
4517 fflush(stdout);
4518
4519 r = sendfile_full(STDOUT_FILENO, fragment_path);
4520 if (r < 0) {
4521 log_warning("Failed to cat %s: %s", fragment_path, strerror(-r));
4522 continue;
4523 }
4524 }
4525
4526 STRV_FOREACH(path, dropin_paths) {
4527 printf("%s%s# %s%s\n",
4528 isempty(fragment_path) && path == dropin_paths ? "" : "\n",
4529 ansi_highlight_blue(),
4530 *path,
4531 ansi_highlight_off());
4532 fflush(stdout);
4533
4534 r = sendfile_full(STDOUT_FILENO, *path);
4535 if (r < 0) {
4536 log_warning("Failed to cat %s: %s", *path, strerror(-r));
4537 continue;
4538 }
4539 }
4540 }
4541
4542 return r < 0 ? r : 0;
4543}
4544
f459b602
MAP
4545static int set_property(sd_bus *bus, char **args) {
4546 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
4547 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
68372da6 4548 _cleanup_free_ char *n = NULL;
8e2af478
LP
4549 char **i;
4550 int r;
4551
f459b602
MAP
4552 r = sd_bus_message_new_method_call(
4553 bus,
151b9b96 4554 &m,
8e2af478
LP
4555 "org.freedesktop.systemd1",
4556 "/org/freedesktop/systemd1",
4557 "org.freedesktop.systemd1.Manager",
151b9b96 4558 "SetUnitProperties");
f459b602
MAP
4559 if (r < 0)
4560 return bus_log_create_error(r);
8e2af478 4561
f78e6385 4562 n = unit_name_mangle(args[1], MANGLE_NOGLOB);
68372da6
LP
4563 if (!n)
4564 return log_oom();
4565
f459b602
MAP
4566 r = sd_bus_message_append(m, "sb", n, arg_runtime);
4567 if (r < 0)
4568 return bus_log_create_error(r);
8e2af478 4569
f459b602
MAP
4570 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, "(sv)");
4571 if (r < 0)
4572 return bus_log_create_error(r);
8e2af478 4573
f459b602
MAP
4574 STRV_FOREACH(i, args + 2) {
4575 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
4576 if (r < 0)
4577 return bus_log_create_error(r);
8e2af478 4578
df31a6c0 4579 r = bus_append_unit_property_assignment(m, *i);
8e2af478
LP
4580 if (r < 0)
4581 return r;
4582
f459b602
MAP
4583 r = sd_bus_message_close_container(m);
4584 if (r < 0)
4585 return bus_log_create_error(r);
8e2af478
LP
4586 }
4587
f459b602
MAP
4588 r = sd_bus_message_close_container(m);
4589 if (r < 0)
4590 return bus_log_create_error(r);
8e2af478 4591
c49b30a2 4592 r = sd_bus_call(bus, m, 0, &error, NULL);
f459b602
MAP
4593 if (r < 0) {
4594 log_error("Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
4595 return r;
8e2af478
LP
4596 }
4597
4598 return 0;
4599}
4600
f459b602
MAP
4601static int snapshot(sd_bus *bus, char **args) {
4602 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4603 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4604 _cleanup_free_ char *n = NULL, *id = NULL;
4605 const char *path;
7e4249b9 4606 int r;
7e4249b9 4607
1dcf6065 4608 if (strv_length(args) > 1)
f78e6385 4609 n = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".snapshot");
1dcf6065
LP
4610 else
4611 n = strdup("");
4612 if (!n)
4613 return log_oom();
7e4249b9 4614
f459b602 4615 r = sd_bus_call_method(
f22f08cd
SP
4616 bus,
4617 "org.freedesktop.systemd1",
4618 "/org/freedesktop/systemd1",
4619 "org.freedesktop.systemd1.Manager",
4620 "CreateSnapshot",
f459b602 4621 &error,
f22f08cd 4622 &reply,
f459b602
MAP
4623 "sb", n, false);
4624 if (r < 0) {
4625 log_error("Failed to create snapshot: %s", bus_error_message(&error, r));
1dcf6065 4626 return r;
7e4249b9
LP
4627 }
4628
f459b602
MAP
4629 r = sd_bus_message_read(reply, "o", &path);
4630 if (r < 0)
4631 return bus_log_parse_error(r);
5dd9014f 4632
f459b602 4633 r = sd_bus_get_property_string(
f22f08cd
SP
4634 bus,
4635 "org.freedesktop.systemd1",
4636 path,
f459b602
MAP
4637 "org.freedesktop.systemd1.Unit",
4638 "Id",
4639 &error,
4640 &id);
4641 if (r < 0) {
4642 log_error("Failed to get ID of snapshot: %s", bus_error_message(&error, r));
1dcf6065 4643 return r;
7e4249b9
LP
4644 }
4645
0183528f
LP
4646 if (!arg_quiet)
4647 puts(id);
7e4249b9 4648
1dcf6065 4649 return 0;
7e4249b9
LP
4650}
4651
f459b602
MAP
4652static int delete_snapshot(sd_bus *bus, char **args) {
4653 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
e3e0314b 4654 _cleanup_strv_free_ char **names = NULL;
729e3769 4655 char **name;
e3e0314b 4656 int r, q;
6759e7a7 4657
6759e7a7
LP
4658 assert(args);
4659
e3e0314b
ZJS
4660 r = expand_names(bus, args + 1, ".snapshot", &names);
4661 if (r < 0)
4662 log_error("Failed to expand names: %s", strerror(-r));
1dcf6065 4663
e3e0314b
ZJS
4664 STRV_FOREACH(name, names) {
4665 q = sd_bus_call_method(
f22f08cd 4666 bus,
b0193f1c
LP
4667 "org.freedesktop.systemd1",
4668 "/org/freedesktop/systemd1",
4669 "org.freedesktop.systemd1.Manager",
5dd9014f 4670 "RemoveSnapshot",
f459b602 4671 &error,
f22f08cd 4672 NULL,
e3e0314b
ZJS
4673 "s", *name);
4674 if (q < 0) {
4675 log_error("Failed to remove snapshot %s: %s",
4676 *name, bus_error_message(&error, r));
4677 if (r == 0)
4678 r = q;
f459b602 4679 }
6759e7a7
LP
4680 }
4681
e3e0314b 4682 return r;
6759e7a7
LP
4683}
4684
f459b602
MAP
4685static int daemon_reload(sd_bus *bus, char **args) {
4686 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
7e4249b9 4687 const char *method;
f459b602 4688 int r;
7e4249b9 4689
e4b61340
LP
4690 if (arg_action == ACTION_RELOAD)
4691 method = "Reload";
4692 else if (arg_action == ACTION_REEXEC)
4693 method = "Reexecute";
4694 else {
4695 assert(arg_action == ACTION_SYSTEMCTL);
4696
4697 method =
20b09ca7
LP
4698 streq(args[0], "clear-jobs") ||
4699 streq(args[0], "cancel") ? "ClearJobs" :
4700 streq(args[0], "daemon-reexec") ? "Reexecute" :
4701 streq(args[0], "reset-failed") ? "ResetFailed" :
4702 streq(args[0], "halt") ? "Halt" :
4703 streq(args[0], "poweroff") ? "PowerOff" :
4704 streq(args[0], "reboot") ? "Reboot" :
4705 streq(args[0], "kexec") ? "KExec" :
4706 streq(args[0], "exit") ? "Exit" :
4707 /* "daemon-reload" */ "Reload";
e4b61340 4708 }
7e4249b9 4709
f459b602 4710 r = sd_bus_call_method(
f22f08cd
SP
4711 bus,
4712 "org.freedesktop.systemd1",
4713 "/org/freedesktop/systemd1",
4714 "org.freedesktop.systemd1.Manager",
4715 method,
c516c8d1 4716 &error,
f459b602
MAP
4717 NULL,
4718 NULL);
f22f08cd
SP
4719
4720 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
4721 /* There's always a fallback possible for
4722 * legacy actions. */
4723 r = -EADDRNOTAVAIL;
d0ede8f1
LP
4724 else if ((r == -ETIMEDOUT || r == -ECONNRESET) && streq(method, "Reexecute"))
4725 /* On reexecution, we expect a disconnect, not a
4726 * reply */
f22f08cd 4727 r = 0;
1dcf6065 4728 else if (r < 0)
f459b602 4729 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
7e4249b9 4730
0a9776c2 4731 return r < 0 ? r : 0;
7e4249b9
LP
4732}
4733
f459b602
MAP
4734static int reset_failed(sd_bus *bus, char **args) {
4735 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
e3e0314b 4736 _cleanup_strv_free_ char **names = NULL;
f84190d8 4737 char **name;
e3e0314b 4738 int r, q;
5632e374 4739
729e3769
LP
4740 if (strv_length(args) <= 1)
4741 return daemon_reload(bus, args);
5632e374 4742
e3e0314b
ZJS
4743 r = expand_names(bus, args + 1, NULL, &names);
4744 if (r < 0)
4745 log_error("Failed to expand names: %s", strerror(-r));
f84190d8 4746
e3e0314b
ZJS
4747 STRV_FOREACH(name, names) {
4748 q = sd_bus_call_method(
f22f08cd 4749 bus,
b0193f1c
LP
4750 "org.freedesktop.systemd1",
4751 "/org/freedesktop/systemd1",
4752 "org.freedesktop.systemd1.Manager",
f22f08cd 4753 "ResetFailedUnit",
f459b602 4754 &error,
f22f08cd 4755 NULL,
e3e0314b
ZJS
4756 "s", *name);
4757 if (q < 0) {
4758 log_error("Failed to reset failed state of unit %s: %s",
4759 *name, bus_error_message(&error, r));
4760 if (r == 0)
4761 r = q;
f459b602 4762 }
5632e374
LP
4763 }
4764
e3e0314b 4765 return r;
5632e374
LP
4766}
4767
f459b602
MAP
4768static int show_environment(sd_bus *bus, char **args) {
4769 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4770 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4771 const char *text;
7e4249b9 4772 int r;
7e4249b9 4773
1968a360 4774 pager_open_if_enabled();
ec14911e 4775
f459b602 4776 r = sd_bus_get_property(
f22f08cd
SP
4777 bus,
4778 "org.freedesktop.systemd1",
4779 "/org/freedesktop/systemd1",
f459b602
MAP
4780 "org.freedesktop.systemd1.Manager",
4781 "Environment",
4782 &error,
f22f08cd 4783 &reply,
f459b602
MAP
4784 "as");
4785 if (r < 0) {
4786 log_error("Failed to get environment: %s", bus_error_message(&error, r));
f84190d8 4787 return r;
7e4249b9
LP
4788 }
4789
f459b602
MAP
4790 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
4791 if (r < 0)
4792 return bus_log_parse_error(r);
7e4249b9 4793
f459b602 4794 while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0)
f84190d8 4795 puts(text);
f459b602
MAP
4796 if (r < 0)
4797 return bus_log_parse_error(r);
7e4249b9 4798
f459b602
MAP
4799 r = sd_bus_message_exit_container(reply);
4800 if (r < 0)
4801 return bus_log_parse_error(r);
7e4249b9 4802
f84190d8 4803 return 0;
7e4249b9
LP
4804}
4805
f459b602
MAP
4806static int switch_root(sd_bus *bus, char **args) {
4807 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
f39d4a08
HH
4808 _cleanup_free_ char *cmdline_init = NULL;
4809 const char *root, *init;
f459b602
MAP
4810 unsigned l;
4811 int r;
957eb8ca
LP
4812
4813 l = strv_length(args);
4814 if (l < 2 || l > 3) {
4815 log_error("Wrong number of arguments.");
4816 return -EINVAL;
4817 }
4818
4819 root = args[1];
13068da8
TG
4820
4821 if (l >= 3)
f39d4a08 4822 init = args[2];
13068da8 4823 else {
f39d4a08
HH
4824 r = parse_env_file("/proc/cmdline", WHITESPACE,
4825 "init", &cmdline_init,
4826 NULL);
4827 if (r < 0)
4828 log_debug("Failed to parse /proc/cmdline: %s", strerror(-r));
13068da8 4829
f39d4a08 4830 init = cmdline_init;
13068da8 4831 }
f459b602 4832
f39d4a08
HH
4833 if (isempty(init))
4834 init = NULL;
4835
4836 if (init) {
4837 const char *root_systemd_path = NULL, *root_init_path = NULL;
4838
4839 root_systemd_path = strappenda(root, "/" SYSTEMD_BINARY_PATH);
8085f163 4840 root_init_path = strappenda(root, "/", init);
f39d4a08
HH
4841
4842 /* If the passed init is actually the same as the
4843 * systemd binary, then let's suppress it. */
4844 if (files_same(root_init_path, root_systemd_path) > 0)
4845 init = NULL;
4846 }
13068da8 4847
f39d4a08 4848 log_debug("Switching root - root: %s; init: %s", root, strna(init));
957eb8ca 4849
f459b602 4850 r = sd_bus_call_method(
f22f08cd 4851 bus,
957eb8ca
LP
4852 "org.freedesktop.systemd1",
4853 "/org/freedesktop/systemd1",
4854 "org.freedesktop.systemd1.Manager",
f22f08cd 4855 "SwitchRoot",
f459b602 4856 &error,
f22f08cd 4857 NULL,
f459b602
MAP
4858 "ss", root, init);
4859 if (r < 0) {
4860 log_error("Failed to switch root: %s", bus_error_message(&error, r));
4861 return r;
4862 }
4863
4864 return 0;
957eb8ca
LP
4865}
4866
f459b602
MAP
4867static int set_environment(sd_bus *bus, char **args) {
4868 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4869 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
7e4249b9 4870 const char *method;
31e767f7
LP
4871 int r;
4872
4873 assert(bus);
60f9ba0b 4874 assert(args);
7e4249b9 4875
7e4249b9
LP
4876 method = streq(args[0], "set-environment")
4877 ? "SetEnvironment"
4878 : "UnsetEnvironment";
4879
f459b602
MAP
4880 r = sd_bus_message_new_method_call(
4881 bus,
151b9b96 4882 &m,
31e767f7
LP
4883 "org.freedesktop.systemd1",
4884 "/org/freedesktop/systemd1",
4885 "org.freedesktop.systemd1.Manager",
151b9b96 4886 method);
f459b602
MAP
4887 if (r < 0)
4888 return bus_log_create_error(r);
7e4249b9 4889
f459b602 4890 r = sd_bus_message_append_strv(m, args + 1);
31e767f7 4891 if (r < 0)
f459b602 4892 return bus_log_create_error(r);
7e4249b9 4893
c49b30a2 4894 r = sd_bus_call(bus, m, 0, &error, NULL);
f459b602
MAP
4895 if (r < 0) {
4896 log_error("Failed to set environment: %s", bus_error_message(&error, r));
4897 return r;
7e4249b9
LP
4898 }
4899
f84190d8 4900 return 0;
7e4249b9
LP
4901}
4902
ac3efa8a
LP
4903static int import_environment(sd_bus *bus, char **args) {
4904 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4905 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
4906 int r;
4907
4908 assert(bus);
4909 assert(args);
4910
4911 r = sd_bus_message_new_method_call(
4912 bus,
151b9b96 4913 &m,
ac3efa8a
LP
4914 "org.freedesktop.systemd1",
4915 "/org/freedesktop/systemd1",
4916 "org.freedesktop.systemd1.Manager",
151b9b96 4917 "SetEnvironment");
ac3efa8a
LP
4918 if (r < 0)
4919 return bus_log_create_error(r);
4920
4921 if (strv_isempty(args + 1))
4922 r = sd_bus_message_append_strv(m, environ);
4923 else {
4924 char **a, **b;
4925
4926 r = sd_bus_message_open_container(m, 'a', "s");
4927 if (r < 0)
4928 return bus_log_create_error(r);
4929
4930 STRV_FOREACH(a, args + 1) {
4931
4932 if (!env_name_is_valid(*a)) {
4933 log_error("Not a valid environment variable name: %s", *a);
4934 return -EINVAL;
4935 }
4936
4937 STRV_FOREACH(b, environ) {
4938 const char *eq;
4939
4940 eq = startswith(*b, *a);
4941 if (eq && *eq == '=') {
4942
4943 r = sd_bus_message_append(m, "s", *b);
4944 if (r < 0)
4945 return bus_log_create_error(r);
4946
4947 break;
4948 }
4949 }
4950 }
4951
4952 r = sd_bus_message_close_container(m);
4953 }
4954 if (r < 0)
4955 return bus_log_create_error(r);
4956
4957 r = sd_bus_call(bus, m, 0, &error, NULL);
4958 if (r < 0) {
4959 log_error("Failed to import environment: %s", bus_error_message(&error, r));
4960 return r;
4961 }
4962
4963 return 0;
4964}
4965
cbb13b2a 4966static int enable_sysv_units(const char *verb, char **args) {
729e3769 4967 int r = 0;
ee5762e3 4968
77e68fa2 4969#if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
729e3769 4970 unsigned f = 1, t = 1;
fb15be83 4971 _cleanup_lookup_paths_free_ LookupPaths paths = {};
ee5762e3 4972
729e3769
LP
4973 if (arg_scope != UNIT_FILE_SYSTEM)
4974 return 0;
ee5762e3 4975
729e3769
LP
4976 if (!streq(verb, "enable") &&
4977 !streq(verb, "disable") &&
4978 !streq(verb, "is-enabled"))
4979 return 0;
ee5762e3 4980
729e3769
LP
4981 /* Processes all SysV units, and reshuffles the array so that
4982 * afterwards only the native units remain */
ee5762e3 4983
12ed81d9 4984 r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, arg_root, NULL, NULL, NULL);
729e3769
LP
4985 if (r < 0)
4986 return r;
ee5762e3 4987
729e3769 4988 r = 0;
cbb13b2a 4989 for (f = 0; args[f]; f++) {
729e3769 4990 const char *name;
05cae7f3 4991 _cleanup_free_ char *p = NULL, *q = NULL, *l = NULL;
729e3769
LP
4992 bool found_native = false, found_sysv;
4993 unsigned c = 1;
4994 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
05cae7f3 4995 char **k;
729e3769
LP
4996 int j;
4997 pid_t pid;
4998 siginfo_t status;
ee5762e3 4999
729e3769 5000 name = args[f];
ee5762e3 5001
729e3769
LP
5002 if (!endswith(name, ".service"))
5003 continue;
ee5762e3 5004
729e3769
LP
5005 if (path_is_absolute(name))
5006 continue;
ee5762e3 5007
729e3769 5008 STRV_FOREACH(k, paths.unit_path) {
05cae7f3
ZJS
5009 _cleanup_free_ char *path = NULL;
5010
0c6ea3a4
ZJS
5011 path = path_join(arg_root, *k, name);
5012 if (!path)
60731f32 5013 return log_oom();
ee5762e3 5014
4723e4b2 5015 found_native = access(path, F_OK) >= 0;
729e3769
LP
5016 if (found_native)
5017 break;
5018 }
ee5762e3 5019
729e3769
LP
5020 if (found_native)
5021 continue;
ee5762e3 5022
0c6ea3a4
ZJS
5023 p = path_join(arg_root, SYSTEM_SYSVINIT_PATH, name);
5024 if (!p)
60731f32 5025 return log_oom();
ee5762e3 5026
05cae7f3 5027 p[strlen(p) - strlen(".service")] = 0;
729e3769 5028 found_sysv = access(p, F_OK) >= 0;
4b6756a8 5029 if (!found_sysv)
729e3769 5030 continue;
71fad675 5031
729e3769
LP
5032 /* Mark this entry, so that we don't try enabling it as native unit */
5033 args[f] = (char*) "";
ee5762e3 5034
729e3769 5035 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
ee5762e3 5036
729e3769
LP
5037 if (!isempty(arg_root))
5038 argv[c++] = q = strappend("--root=", arg_root);
ee5762e3 5039
2b6bf07d 5040 argv[c++] = basename(p);
729e3769
LP
5041 argv[c++] =
5042 streq(verb, "enable") ? "on" :
5043 streq(verb, "disable") ? "off" : "--level=5";
5044 argv[c] = NULL;
ee5762e3 5045
729e3769 5046 l = strv_join((char**)argv, " ");
60731f32
ZJS
5047 if (!l)
5048 return log_oom();
ee5762e3 5049
729e3769 5050 log_info("Executing %s", l);
ee5762e3 5051
729e3769
LP
5052 pid = fork();
5053 if (pid < 0) {
5054 log_error("Failed to fork: %m");
60731f32 5055 return -errno;
729e3769
LP
5056 } else if (pid == 0) {
5057 /* Child */
ee5762e3 5058
729e3769
LP
5059 execv(argv[0], (char**) argv);
5060 _exit(EXIT_FAILURE);
5061 }
ee5762e3 5062
729e3769
LP
5063 j = wait_for_terminate(pid, &status);
5064 if (j < 0) {
5065 log_error("Failed to wait for child: %s", strerror(-r));
60731f32 5066 return j;
729e3769 5067 }
ee5762e3 5068
729e3769
LP
5069 if (status.si_code == CLD_EXITED) {
5070 if (streq(verb, "is-enabled")) {
5071 if (status.si_status == 0) {
5072 if (!arg_quiet)
5073 puts("enabled");
5074 r = 1;
5075 } else {
5076 if (!arg_quiet)
5077 puts("disabled");
5078 }
ee5762e3 5079
60731f32
ZJS
5080 } else if (status.si_status != 0)
5081 return -EINVAL;
5082 } else
5083 return -EPROTO;
ee5762e3
LP
5084 }
5085
729e3769 5086 /* Drop all SysV units */
cbb13b2a 5087 for (f = 0, t = 0; args[f]; f++) {
ee5762e3 5088
729e3769 5089 if (isempty(args[f]))
ee5762e3
LP
5090 continue;
5091
729e3769
LP
5092 args[t++] = args[f];
5093 }
ee5762e3 5094
729e3769 5095 args[t] = NULL;
ee5762e3 5096
729e3769
LP
5097#endif
5098 return r;
5099}
ee5762e3 5100
37370d0c 5101static int mangle_names(char **original_names, char ***mangled_names) {
a33fdebb 5102 char **i, **l, **name;
37370d0c 5103
a33fdebb
LP
5104 l = new(char*, strv_length(original_names) + 1);
5105 if (!l)
37370d0c
VP
5106 return log_oom();
5107
a33fdebb 5108 i = l;
37370d0c 5109 STRV_FOREACH(name, original_names) {
44386fc1
LN
5110
5111 /* When enabling units qualified path names are OK,
5112 * too, hence allow them explicitly. */
5113
5114 if (is_path(*name))
5115 *i = strdup(*name);
5116 else
f78e6385 5117 *i = unit_name_mangle(*name, MANGLE_NOGLOB);
44386fc1 5118
a33fdebb
LP
5119 if (!*i) {
5120 strv_free(l);
37370d0c 5121 return log_oom();
a33fdebb
LP
5122 }
5123
5124 i++;
37370d0c 5125 }
a33fdebb
LP
5126
5127 *i = NULL;
5128 *mangled_names = l;
37370d0c
VP
5129
5130 return 0;
5131}
5132
f459b602 5133static int enable_unit(sd_bus *bus, char **args) {
e3e0314b 5134 _cleanup_strv_free_ char **names = NULL;
729e3769
LP
5135 const char *verb = args[0];
5136 UnitFileChange *changes = NULL;
718db961 5137 unsigned n_changes = 0;
729e3769 5138 int carries_install_info = -1;
729e3769 5139 int r;
ee5762e3 5140
ab5919fa
MS
5141 if (!args[1])
5142 return 0;
5143
e3e0314b 5144 r = mangle_names(args+1, &names);
3a05c0f9 5145 if (r < 0)
cbb13b2a
VP
5146 return r;
5147
e3e0314b 5148 r = enable_sysv_units(verb, names);
cbb13b2a
VP
5149 if (r < 0)
5150 return r;
3a05c0f9 5151
67d66210
LP
5152 /* If the operation was fully executed by the SysV compat,
5153 * let's finish early */
5154 if (strv_isempty(names))
5155 return 0;
5156
729e3769
LP
5157 if (!bus || avoid_bus()) {
5158 if (streq(verb, "enable")) {
e3e0314b 5159 r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769
LP
5160 carries_install_info = r;
5161 } else if (streq(verb, "disable"))
e3e0314b 5162 r = unit_file_disable(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
729e3769 5163 else if (streq(verb, "reenable")) {
e3e0314b 5164 r = unit_file_reenable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769
LP
5165 carries_install_info = r;
5166 } else if (streq(verb, "link"))
e3e0314b 5167 r = unit_file_link(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769 5168 else if (streq(verb, "preset")) {
d309c1c3 5169 r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_preset_mode, arg_force, &changes, &n_changes);
729e3769
LP
5170 carries_install_info = r;
5171 } else if (streq(verb, "mask"))
e3e0314b 5172 r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769 5173 else if (streq(verb, "unmask"))
e3e0314b 5174 r = unit_file_unmask(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
729e3769
LP
5175 else
5176 assert_not_reached("Unknown verb");
ee5762e3 5177
729e3769
LP
5178 if (r < 0) {
5179 log_error("Operation failed: %s", strerror(-r));
5180 goto finish;
ee5762e3
LP
5181 }
5182
718db961
LP
5183 if (!arg_quiet)
5184 dump_unit_file_changes(changes, n_changes);
ee5762e3 5185
df77cdf0 5186 r = 0;
729e3769 5187 } else {
718db961
LP
5188 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
5189 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
f459b602 5190 int expect_carries_install_info = false;
d309c1c3 5191 bool send_force = true, send_preset_mode = false;
718db961 5192 const char *method;
729e3769
LP
5193
5194 if (streq(verb, "enable")) {
5195 method = "EnableUnitFiles";
5196 expect_carries_install_info = true;
5197 } else if (streq(verb, "disable")) {
5198 method = "DisableUnitFiles";
5199 send_force = false;
5200 } else if (streq(verb, "reenable")) {
5201 method = "ReenableUnitFiles";
5202 expect_carries_install_info = true;
5203 } else if (streq(verb, "link"))
5204 method = "LinkUnitFiles";
5205 else if (streq(verb, "preset")) {
d309c1c3
LP
5206
5207 if (arg_preset_mode != UNIT_FILE_PRESET_FULL) {
5208 method = "PresetUnitFilesWithMode";
5209 send_preset_mode = true;
5210 } else
5211 method = "PresetUnitFiles";
5212
729e3769
LP
5213 expect_carries_install_info = true;
5214 } else if (streq(verb, "mask"))
5215 method = "MaskUnitFiles";
5216 else if (streq(verb, "unmask")) {
5217 method = "UnmaskUnitFiles";
5218 send_force = false;
5219 } else
5220 assert_not_reached("Unknown verb");
5221
f459b602
MAP
5222 r = sd_bus_message_new_method_call(
5223 bus,
151b9b96 5224 &m,
729e3769
LP
5225 "org.freedesktop.systemd1",
5226 "/org/freedesktop/systemd1",
5227 "org.freedesktop.systemd1.Manager",
151b9b96 5228 method);
f459b602
MAP
5229 if (r < 0)
5230 return bus_log_create_error(r);
ee5762e3 5231
e3e0314b 5232 r = sd_bus_message_append_strv(m, names);
f459b602
MAP
5233 if (r < 0)
5234 return bus_log_create_error(r);
ee5762e3 5235
d309c1c3
LP
5236 if (send_preset_mode) {
5237 r = sd_bus_message_append(m, "s", unit_file_preset_mode_to_string(arg_preset_mode));
5238 if (r < 0)
5239 return bus_log_create_error(r);
5240 }
5241
f459b602
MAP
5242 r = sd_bus_message_append(m, "b", arg_runtime);
5243 if (r < 0)
5244 return bus_log_create_error(r);
ee5762e3 5245
729e3769 5246 if (send_force) {
f459b602
MAP
5247 r = sd_bus_message_append(m, "b", arg_force);
5248 if (r < 0)
5249 return bus_log_create_error(r);
ee5762e3
LP
5250 }
5251
c49b30a2 5252 r = sd_bus_call(bus, m, 0, &error, &reply);
f459b602
MAP
5253 if (r < 0) {
5254 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
5255 return r;
729e3769 5256 }
be394c48 5257
729e3769 5258 if (expect_carries_install_info) {
f459b602
MAP
5259 r = sd_bus_message_read(reply, "b", &carries_install_info);
5260 if (r < 0)
5261 return bus_log_parse_error(r);
ee5762e3
LP
5262 }
5263
cc3f2093 5264 r = deserialize_and_dump_unit_file_changes(reply);
f459b602 5265 if (r < 0)
718db961 5266 return r;
b77398f7 5267
93c941e3 5268 /* Try to reload if enabled */
d6cb60c7 5269 if (!arg_no_reload)
729e3769 5270 r = daemon_reload(bus, args);
f459b602
MAP
5271 else
5272 r = 0;
b647f10d 5273 }
3d3961f2 5274
729e3769 5275 if (carries_install_info == 0)
416389f7
LP
5276 log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
5277 "using systemctl.\n"
5278 "Possible reasons for having this kind of units are:\n"
5279 "1) A unit may be statically enabled by being symlinked from another unit's\n"
5280 " .wants/ or .requires/ directory.\n"
5281 "2) A unit's purpose may be to act as a helper for some other unit which has\n"
5282 " a requirement dependency on it.\n"
5283 "3) A unit may be started when needed via activation (socket, path, timer,\n"
5284 " D-Bus, udev, scripted systemctl call, ...).\n");
ee5762e3 5285
729e3769 5286finish:
729e3769 5287 unit_file_changes_free(changes, n_changes);
ee5762e3 5288
729e3769 5289 return r;
ee5762e3
LP
5290}
5291
d309c1c3
LP
5292static int preset_all(sd_bus *bus, char **args) {
5293 UnitFileChange *changes = NULL;
5294 unsigned n_changes = 0;
5295 int r;
5296
5297 if (!bus || avoid_bus()) {
5298
5299 r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes);
5300 if (r < 0) {
5301 log_error("Operation failed: %s", strerror(-r));
5302 goto finish;
5303 }
5304
5305 if (!arg_quiet)
5306 dump_unit_file_changes(changes, n_changes);
5307
5308 r = 0;
5309
5310 } else {
5311 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
5312 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
5313
5314 r = sd_bus_call_method(
5315 bus,
5316 "org.freedesktop.systemd1",
5317 "/org/freedesktop/systemd1",
5318 "org.freedesktop.systemd1.Manager",
5319 "PresetAllUnitFiles",
5320 &error,
5321 &reply,
5322 "sbb",
5323 unit_file_preset_mode_to_string(arg_preset_mode),
5324 arg_runtime,
5325 arg_force);
5326 if (r < 0) {
5327 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
5328 return r;
5329 }
5330
5331 r = deserialize_and_dump_unit_file_changes(reply);
5332 if (r < 0)
5333 return r;
5334
5335 if (!arg_no_reload)
5336 r = daemon_reload(bus, args);
5337 else
5338 r = 0;
5339 }
5340
5341finish:
5342 unit_file_changes_free(changes, n_changes);
5343
5344 return r;
5345}
5346
f459b602
MAP
5347static int unit_is_enabled(sd_bus *bus, char **args) {
5348
5349 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
e3e0314b 5350 _cleanup_strv_free_ char **names = NULL;
729e3769
LP
5351 bool enabled;
5352 char **name;
f459b602 5353 int r;
ee5762e3 5354
e3e0314b 5355 r = mangle_names(args+1, &names);
cbb13b2a
VP
5356 if (r < 0)
5357 return r;
5358
e3e0314b 5359 r = enable_sysv_units(args[0], names);
729e3769
LP
5360 if (r < 0)
5361 return r;
ee5762e3 5362
729e3769 5363 enabled = r > 0;
ee5762e3 5364
729e3769 5365 if (!bus || avoid_bus()) {
ee5762e3 5366
e3e0314b 5367 STRV_FOREACH(name, names) {
729e3769 5368 UnitFileState state;
ee5762e3 5369
cbb13b2a 5370 state = unit_file_get_state(arg_scope, arg_root, *name);
cbc9fbd1
LP
5371 if (state < 0) {
5372 log_error("Failed to get unit file state for %s: %s", *name, strerror(-state));
cec7eda5 5373 return state;
cbc9fbd1 5374 }
ee5762e3 5375
729e3769
LP
5376 if (state == UNIT_FILE_ENABLED ||
5377 state == UNIT_FILE_ENABLED_RUNTIME ||
5378 state == UNIT_FILE_STATIC)
5379 enabled = true;
5380
5381 if (!arg_quiet)
5382 puts(unit_file_state_to_string(state));
71fad675 5383 }
ee5762e3 5384
729e3769 5385 } else {
e3e0314b 5386 STRV_FOREACH(name, names) {
f459b602 5387 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
729e3769 5388 const char *s;
63a723f3 5389
f459b602 5390 r = sd_bus_call_method(
f22f08cd 5391 bus,
729e3769
LP
5392 "org.freedesktop.systemd1",
5393 "/org/freedesktop/systemd1",
5394 "org.freedesktop.systemd1.Manager",
f22f08cd 5395 "GetUnitFileState",
f459b602 5396 &error,
f22f08cd 5397 &reply,
04504f93 5398 "s", *name);
f459b602
MAP
5399 if (r < 0) {
5400 log_error("Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
cec7eda5 5401 return r;
ee5762e3
LP
5402 }
5403
f459b602
MAP
5404 r = sd_bus_message_read(reply, "s", &s);
5405 if (r < 0)
5406 return bus_log_parse_error(r);
ee5762e3 5407
729e3769
LP
5408 if (streq(s, "enabled") ||
5409 streq(s, "enabled-runtime") ||
5410 streq(s, "static"))
5411 enabled = true;
5412
5413 if (!arg_quiet)
5414 puts(s);
560d8f23 5415 }
ee5762e3
LP
5416 }
5417
f459b602 5418 return !enabled;
ee5762e3
LP
5419}
5420
99813a19
LP
5421static int is_system_running(sd_bus *bus, char **args) {
5422 _cleanup_free_ char *state = NULL;
5423 int r;
5424
5425 r = sd_bus_get_property_string(
5426 bus,
5427 "org.freedesktop.systemd1",
5428 "/org/freedesktop/systemd1",
5429 "org.freedesktop.systemd1.Manager",
5430 "SystemState",
5431 NULL,
5432 &state);
5433 if (r < 0) {
5434 if (!arg_quiet)
5435 puts("unknown");
5436 return 0;
5437 }
5438
5439 if (!arg_quiet)
5440 puts(state);
5441
5442 return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE;
5443}
5444
601185b4 5445static void systemctl_help(void) {
7e4249b9 5446
729e3769
LP
5447 pager_open_if_enabled();
5448
2e33c433 5449 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
729e3769 5450 "Query or send control commands to the systemd manager.\n\n"
8a0867d6
LP
5451 " -h --help Show this help\n"
5452 " --version Show package version\n"
f459b602
MAP
5453 " --system Connect to system manager\n"
5454 " --user Connect to user service manager\n"
5455 " -H --host=[USER@]HOST\n"
5456 " Operate on remote host\n"
5457 " -M --machine=CONTAINER\n"
5458 " Operate on local container\n"
8a0867d6 5459 " -t --type=TYPE List only units of a particular type\n"
a521ae4a 5460 " --state=STATE List only units with particular LOAD or SUB or ACTIVE state\n"
8a0867d6 5461 " -p --property=NAME Show only properties by this name\n"
a5e4972c
LP
5462 " -a --all Show all loaded units/properties, including dead/empty\n"
5463 " ones. To list all units installed on the system, use\n"
5464 " the 'list-unit-files' command instead.\n"
98a6e132 5465 " -l --full Don't ellipsize unit names on output\n"
1238ee09 5466 " -r --recursive Show unit list of host and local containers\n"
4dc5b821
LP
5467 " --reverse Show reverse dependencies with 'list-dependencies'\n"
5468 " --job-mode=MODE Specify how to deal with already queued jobs, when\n"
5469 " queueing a new job\n"
a521ae4a 5470 " --show-types When showing sockets, explicitly show their type\n"
b37844d3
LP
5471 " -i --ignore-inhibitors\n"
5472 " When shutting down or sleeping, ignore inhibitors\n"
a8f11321
LP
5473 " --kill-who=WHO Who to send signal to\n"
5474 " -s --signal=SIGNAL Which signal to send\n"
8a0867d6
LP
5475 " -q --quiet Suppress output\n"
5476 " --no-block Do not wait until operation finished\n"
8a0867d6 5477 " --no-wall Don't send wall message before halt/power-off/reboot\n"
8a0867d6
LP
5478 " --no-reload When enabling/disabling unit files, don't reload daemon\n"
5479 " configuration\n"
ebed32bf 5480 " --no-legend Do not print a legend (column headers and hints)\n"
69fc152f 5481 " --no-pager Do not pipe output into a pager\n"
501fc174
LP
5482 " --no-ask-password\n"
5483 " Do not ask for system passwords\n"
a8f11321 5484 " --global Enable/disable unit files globally\n"
a521ae4a 5485 " --runtime Enable unit files only temporarily until next reboot\n"
8a0867d6
LP
5486 " -f --force When enabling unit files, override existing symlinks\n"
5487 " When shutting down, execute action immediately\n"
d309c1c3
LP
5488 " --preset-mode= Specifies whether fully apply presets, or only enable,\n"
5489 " or only disable\n"
729e3769 5490 " --root=PATH Enable unit files in the specified root directory\n"
76fdc966 5491 " -n --lines=INTEGER Number of journal entries to show\n"
d3f2bdbf 5492 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
815ebc54
DH
5493 " verbose, export, json, json-pretty, json-sse, cat)\n"
5494 " --plain Print unit dependencies as a list instead of a tree\n\n"
34c4b47b 5495 "Unit Commands:\n"
d8fba7c6
ZJS
5496 " list-units [PATTERN...] List loaded units\n"
5497 " list-sockets [PATTERN...] List loaded sockets ordered by address\n"
5498 " list-timers [PATTERN...] List loaded timers ordered by next elapse\n"
4f8f66cb
ZJS
5499 " start NAME... Start (activate) one or more units\n"
5500 " stop NAME... Stop (deactivate) one or more units\n"
5501 " reload NAME... Reload one or more units\n"
5502 " restart NAME... Start or restart one or more units\n"
5503 " try-restart NAME... Restart one or more units if active\n"
5504 " reload-or-restart NAME... Reload one or more units if possible,\n"
6f28c033 5505 " otherwise start or restart\n"
4f8f66cb 5506 " reload-or-try-restart NAME... Reload one or more units if possible,\n"
6f28c033 5507 " otherwise restart if active\n"
4f8f66cb
ZJS
5508 " isolate NAME Start one unit and stop all others\n"
5509 " kill NAME... Send signal to processes of a unit\n"
b3ae710c
ZJS
5510 " is-active PATTERN... Check whether units are active\n"
5511 " is-failed PATTERN... Check whether units are failed\n"
5512 " status [PATTERN...|PID...] Show runtime status of one or more units\n"
5513 " show [PATTERN...|JOB...] Show properties of one or more\n"
ee5762e3 5514 " units/jobs or the manager\n"
b3ae710c 5515 " cat PATTERN... Show files and drop-ins of one or more units\n"
4f8f66cb 5516 " set-property NAME ASSIGNMENT... Sets one or more properties of a unit\n"
b3ae710c
ZJS
5517 " help PATTERN...|PID... Show manual for one or more units\n"
5518 " reset-failed [PATTERN...] Reset failed state for all, one, or more\n"
fdf20a31 5519 " units\n"
55c0b89c 5520 " list-dependencies [NAME] Recursively show units which are required\n"
afba4199
ZJS
5521 " or wanted by this unit or by which this\n"
5522 " unit is required or wanted\n\n"
34c4b47b 5523 "Unit File Commands:\n"
d8fba7c6 5524 " list-unit-files [PATTERN...] List installed unit files\n"
4f8f66cb
ZJS
5525 " enable NAME... Enable one or more unit files\n"
5526 " disable NAME... Disable one or more unit files\n"
5527 " reenable NAME... Reenable one or more unit files\n"
5528 " preset NAME... Enable/disable one or more unit files\n"
729e3769 5529 " based on preset configuration\n"
d309c1c3
LP
5530 " preset-all Enable/disable all unit files based on\n"
5531 " preset configuration\n"
4f8f66cb
ZJS
5532 " is-enabled NAME... Check whether unit files are enabled\n\n"
5533 " mask NAME... Mask one or more units\n"
5534 " unmask NAME... Unmask one or more units\n"
5535 " link PATH... Link one or more units files into\n"
729e3769 5536 " the search path\n"
99504dd4 5537 " get-default Get the name of the default target\n"
f535088e 5538 " set-default NAME Set the default target\n\n"
0d292f5e
LP
5539 "Machine Commands:\n"
5540 " list-machines [PATTERN...] List local containers and host\n\n"
34c4b47b 5541 "Job Commands:\n"
d8fba7c6 5542 " list-jobs [PATTERN...] List jobs\n"
34c4b47b 5543 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
34c4b47b 5544 "Snapshot Commands:\n"
7e4249b9 5545 " snapshot [NAME] Create a snapshot\n"
4f8f66cb 5546 " delete NAME... Remove one or more snapshots\n\n"
34c4b47b 5547 "Environment Commands:\n"
7e4249b9 5548 " show-environment Dump environment\n"
4f8f66cb 5549 " set-environment NAME=VALUE... Set one or more environment variables\n"
ac3efa8a
LP
5550 " unset-environment NAME... Unset one or more environment variables\n"
5551 " import-environment NAME... Import all, one or more environment variables\n\n"
34c4b47b
LP
5552 "Manager Lifecycle Commands:\n"
5553 " daemon-reload Reload systemd manager configuration\n"
5554 " daemon-reexec Reexecute systemd manager\n\n"
5555 "System Commands:\n"
99813a19 5556 " is-system-running Check whether system is fully running\n"
20b09ca7
LP
5557 " default Enter system default mode\n"
5558 " rescue Enter system rescue mode\n"
5559 " emergency Enter system emergency mode\n"
514f4ef5 5560 " halt Shut down and halt the system\n"
2e33c433 5561 " poweroff Shut down and power-off the system\n"
37185ec8 5562 " reboot [ARG] Shut down and reboot the system\n"
20b09ca7 5563 " kexec Shut down and reboot the system with kexec\n"
6edd7d0a 5564 " exit Request user instance exit\n"
4f8f66cb 5565 " switch-root ROOT [INIT] Change to a different root file system\n"
6edd7d0a 5566 " suspend Suspend the system\n"
6524990f
LP
5567 " hibernate Hibernate the system\n"
5568 " hybrid-sleep Hibernate and suspend the system\n",
5b6319dc 5569 program_invocation_short_name);
7e4249b9
LP
5570}
5571
601185b4 5572static void halt_help(void) {
37185ec8 5573 printf("%s [OPTIONS...]%s\n\n"
e4b61340
LP
5574 "%s the system.\n\n"
5575 " --help Show this help\n"
5576 " --halt Halt the machine\n"
5577 " -p --poweroff Switch off the machine\n"
5578 " --reboot Reboot the machine\n"
2e33c433
LP
5579 " -f --force Force immediate halt/power-off/reboot\n"
5580 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
e4b61340 5581 " -d --no-wtmp Don't write wtmp record\n"
2e33c433 5582 " --no-wall Don't send wall message before halt/power-off/reboot\n",
e4b61340 5583 program_invocation_short_name,
37185ec8 5584 arg_action == ACTION_REBOOT ? " [ARG]" : "",
e4b61340
LP
5585 arg_action == ACTION_REBOOT ? "Reboot" :
5586 arg_action == ACTION_POWEROFF ? "Power off" :
5587 "Halt");
e4b61340
LP
5588}
5589
601185b4 5590static void shutdown_help(void) {
08e4b1c5 5591 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
e4b61340
LP
5592 "Shut down the system.\n\n"
5593 " --help Show this help\n"
5594 " -H --halt Halt the machine\n"
5595 " -P --poweroff Power-off the machine\n"
5596 " -r --reboot Reboot the machine\n"
386da858 5597 " -h Equivalent to --poweroff, overridden by --halt\n"
2e33c433 5598 " -k Don't halt/power-off/reboot, just send warnings\n"
f6144808 5599 " --no-wall Don't send wall message before halt/power-off/reboot\n"
f6144808 5600 " -c Cancel a pending shutdown\n",
e4b61340 5601 program_invocation_short_name);
e4b61340
LP
5602}
5603
601185b4 5604static void telinit_help(void) {
2e33c433 5605 printf("%s [OPTIONS...] {COMMAND}\n\n"
514f4ef5
LP
5606 "Send control commands to the init daemon.\n\n"
5607 " --help Show this help\n"
2e33c433 5608 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
e4b61340
LP
5609 "Commands:\n"
5610 " 0 Power-off the machine\n"
5611 " 6 Reboot the machine\n"
514f4ef5
LP
5612 " 2, 3, 4, 5 Start runlevelX.target unit\n"
5613 " 1, s, S Enter rescue mode\n"
5614 " q, Q Reload init daemon configuration\n"
5615 " u, U Reexecute init daemon\n",
e4b61340 5616 program_invocation_short_name);
e4b61340
LP
5617}
5618
601185b4 5619static void runlevel_help(void) {
2e33c433 5620 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
5621 "Prints the previous and current runlevel of the init system.\n\n"
5622 " --help Show this help\n",
5623 program_invocation_short_name);
e4b61340
LP
5624}
5625
b93312f5 5626static void help_types(void) {
45c0c61d 5627 int i;
830f01f0 5628 const char *t;
45c0c61d 5629
b93312f5
ZJS
5630 if (!arg_no_legend)
5631 puts("Available unit types:");
f168c273 5632 for (i = 0; i < _UNIT_TYPE_MAX; i++) {
830f01f0
LP
5633 t = unit_type_to_string(i);
5634 if (t)
5635 puts(t);
5636 }
45c0c61d
ZJS
5637}
5638
e4b61340 5639static int systemctl_parse_argv(int argc, char *argv[]) {
7e4249b9
LP
5640
5641 enum {
90d473a1 5642 ARG_FAIL = 0x100,
afba4199
ZJS
5643 ARG_REVERSE,
5644 ARG_AFTER,
5645 ARG_BEFORE,
991f2a39 5646 ARG_SHOW_TYPES,
23ade460 5647 ARG_IRREVERSIBLE,
e67c3609 5648 ARG_IGNORE_DEPENDENCIES,
35df8f27 5649 ARG_VERSION,
af2d49f7 5650 ARG_USER,
7e4249b9 5651 ARG_SYSTEM,
ee5762e3 5652 ARG_GLOBAL,
6e905d93 5653 ARG_NO_BLOCK,
ebed32bf 5654 ARG_NO_LEGEND,
611efaac 5655 ARG_NO_PAGER,
4445a875 5656 ARG_NO_WALL,
be394c48 5657 ARG_ROOT,
ee5762e3 5658 ARG_NO_RELOAD,
501fc174 5659 ARG_KILL_WHO,
30732560 5660 ARG_NO_ASK_PASSWORD,
729e3769 5661 ARG_FAILED,
df50185b 5662 ARG_RUNTIME,
5d0c05e5 5663 ARG_FORCE,
9b9b3d36 5664 ARG_PLAIN,
4dc5b821 5665 ARG_STATE,
d309c1c3
LP
5666 ARG_JOB_MODE,
5667 ARG_PRESET_MODE,
7e4249b9
LP
5668 };
5669
5670 static const struct option options[] = {
9ea9d4cf
LP
5671 { "help", no_argument, NULL, 'h' },
5672 { "version", no_argument, NULL, ARG_VERSION },
5673 { "type", required_argument, NULL, 't' },
5674 { "property", required_argument, NULL, 'p' },
5675 { "all", no_argument, NULL, 'a' },
5676 { "reverse", no_argument, NULL, ARG_REVERSE },
5677 { "after", no_argument, NULL, ARG_AFTER },
5678 { "before", no_argument, NULL, ARG_BEFORE },
5679 { "show-types", no_argument, NULL, ARG_SHOW_TYPES },
5680 { "failed", no_argument, NULL, ARG_FAILED }, /* compatibility only */
5681 { "full", no_argument, NULL, 'l' },
4dc5b821
LP
5682 { "job-mode", required_argument, NULL, ARG_JOB_MODE },
5683 { "fail", no_argument, NULL, ARG_FAIL }, /* compatibility only */
5684 { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, /* compatibility only */
5685 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */
9ea9d4cf
LP
5686 { "ignore-inhibitors", no_argument, NULL, 'i' },
5687 { "user", no_argument, NULL, ARG_USER },
5688 { "system", no_argument, NULL, ARG_SYSTEM },
5689 { "global", no_argument, NULL, ARG_GLOBAL },
5690 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
5691 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
5692 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
5693 { "no-wall", no_argument, NULL, ARG_NO_WALL },
5694 { "quiet", no_argument, NULL, 'q' },
5695 { "root", required_argument, NULL, ARG_ROOT },
5696 { "force", no_argument, NULL, ARG_FORCE },
5697 { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
5698 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
5699 { "signal", required_argument, NULL, 's' },
5700 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
5701 { "host", required_argument, NULL, 'H' },
f459b602 5702 { "machine", required_argument, NULL, 'M' },
9ea9d4cf
LP
5703 { "runtime", no_argument, NULL, ARG_RUNTIME },
5704 { "lines", required_argument, NULL, 'n' },
5705 { "output", required_argument, NULL, 'o' },
5706 { "plain", no_argument, NULL, ARG_PLAIN },
5707 { "state", required_argument, NULL, ARG_STATE },
1238ee09 5708 { "recursive", no_argument, NULL, 'r' },
d309c1c3 5709 { "preset-mode", required_argument, NULL, ARG_PRESET_MODE },
eb9da376 5710 {}
7e4249b9
LP
5711 };
5712
5713 int c;
5714
e4b61340 5715 assert(argc >= 0);
7e4249b9
LP
5716 assert(argv);
5717
601185b4 5718 while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir", options, NULL)) >= 0)
7e4249b9
LP
5719
5720 switch (c) {
5721
5722 case 'h':
601185b4
ZJS
5723 systemctl_help();
5724 return 0;
35df8f27
LP
5725
5726 case ARG_VERSION:
5727 puts(PACKAGE_STRING);
7d568925 5728 puts(SYSTEMD_FEATURES);
35df8f27 5729 return 0;
7e4249b9 5730
20b3f379 5731 case 't': {
a2a5291b 5732 const char *word, *state;
20b3f379 5733 size_t size;
45c0c61d 5734
20b3f379 5735 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
7fd1b19b 5736 _cleanup_free_ char *type;
20b3f379
ZJS
5737
5738 type = strndup(word, size);
5739 if (!type)
5740 return -ENOMEM;
5741
5742 if (streq(type, "help")) {
5743 help_types();
5744 return 0;
5745 }
5746
5747 if (unit_type_from_string(type) >= 0) {
5748 if (strv_push(&arg_types, type))
5749 return log_oom();
5750 type = NULL;
5751 continue;
5752 }
5753
9b9b3d36
MW
5754 /* It's much nicer to use --state= for
5755 * load states, but let's support this
5756 * in --types= too for compatibility
5757 * with old versions */
20b3f379 5758 if (unit_load_state_from_string(optarg) >= 0) {
9b9b3d36 5759 if (strv_push(&arg_states, type) < 0)
20b3f379
ZJS
5760 return log_oom();
5761 type = NULL;
5762 continue;
5763 }
5764
ab06eef8 5765 log_error("Unknown unit type or load state '%s'.", type);
20b3f379
ZJS
5766 log_info("Use -t help to see a list of allowed values.");
5767 return -EINVAL;
c147dc42 5768 }
20b3f379
ZJS
5769
5770 break;
5771 }
5772
ea4a240d 5773 case 'p': {
033a842c
ZJS
5774 /* Make sure that if the empty property list
5775 was specified, we won't show any properties. */
20b3f379 5776 if (isempty(optarg) && !arg_properties) {
cbc9fbd1 5777 arg_properties = new0(char*, 1);
20b3f379
ZJS
5778 if (!arg_properties)
5779 return log_oom();
5780 } else {
a2a5291b 5781 const char *word, *state;
20b3f379 5782 size_t size;
033a842c 5783
20b3f379
ZJS
5784 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
5785 char *prop;
033a842c 5786
20b3f379
ZJS
5787 prop = strndup(word, size);
5788 if (!prop)
5789 return log_oom();
ea4a240d 5790
6e18964d 5791 if (strv_consume(&arg_properties, prop) < 0)
20b3f379 5792 return log_oom();
20b3f379 5793 }
033a842c 5794 }
48220598
LP
5795
5796 /* If the user asked for a particular
5797 * property, show it to him, even if it is
5798 * empty. */
5799 arg_all = true;
033a842c 5800
48220598 5801 break;
ea4a240d 5802 }
48220598 5803
7e4249b9
LP
5804 case 'a':
5805 arg_all = true;
5806 break;
5807
afba4199
ZJS
5808 case ARG_REVERSE:
5809 arg_dependency = DEPENDENCY_REVERSE;
5810 break;
5811
5812 case ARG_AFTER:
5813 arg_dependency = DEPENDENCY_AFTER;
5814 break;
5815
5816 case ARG_BEFORE:
5817 arg_dependency = DEPENDENCY_BEFORE;
5818 break;
5819
991f2a39
ZJS
5820 case ARG_SHOW_TYPES:
5821 arg_show_types = true;
5822 break;
5823
4dc5b821
LP
5824 case ARG_JOB_MODE:
5825 arg_job_mode = optarg;
5826 break;
5827
90d473a1 5828 case ARG_FAIL:
e67c3609
LP
5829 arg_job_mode = "fail";
5830 break;
5831
23ade460
MS
5832 case ARG_IRREVERSIBLE:
5833 arg_job_mode = "replace-irreversibly";
5834 break;
5835
e67c3609
LP
5836 case ARG_IGNORE_DEPENDENCIES:
5837 arg_job_mode = "ignore-dependencies";
7e4249b9
LP
5838 break;
5839
af2d49f7 5840 case ARG_USER:
729e3769 5841 arg_scope = UNIT_FILE_USER;
7e4249b9
LP
5842 break;
5843
5844 case ARG_SYSTEM:
729e3769
LP
5845 arg_scope = UNIT_FILE_SYSTEM;
5846 break;
5847
5848 case ARG_GLOBAL:
5849 arg_scope = UNIT_FILE_GLOBAL;
7e4249b9
LP
5850 break;
5851
6e905d93
LP
5852 case ARG_NO_BLOCK:
5853 arg_no_block = true;
7e4249b9
LP
5854 break;
5855
ebed32bf
MS
5856 case ARG_NO_LEGEND:
5857 arg_no_legend = true;
5858 break;
5859
611efaac
LP
5860 case ARG_NO_PAGER:
5861 arg_no_pager = true;
5862 break;
0736af98 5863
514f4ef5
LP
5864 case ARG_NO_WALL:
5865 arg_no_wall = true;
5866 break;
5867
be394c48
FC
5868 case ARG_ROOT:
5869 arg_root = optarg;
5870 break;
5871
98a6e132 5872 case 'l':
8fe914ec
LP
5873 arg_full = true;
5874 break;
5875
30732560 5876 case ARG_FAILED:
9b9b3d36
MW
5877 if (strv_extend(&arg_states, "failed") < 0)
5878 return log_oom();
5879
30732560
LP
5880 break;
5881
0183528f
LP
5882 case 'q':
5883 arg_quiet = true;
5884 break;
5885
568b679f
LP
5886 case ARG_FORCE:
5887 arg_force ++;
5888 break;
5889
b4f27ccc 5890 case 'f':
e606bb61 5891 arg_force ++;
ee5762e3
LP
5892 break;
5893
5894 case ARG_NO_RELOAD:
5895 arg_no_reload = true;
5896 break;
5897
8a0867d6
LP
5898 case ARG_KILL_WHO:
5899 arg_kill_who = optarg;
5900 break;
5901
8a0867d6
LP
5902 case 's':
5903 if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
5904 log_error("Failed to parse signal string %s.", optarg);
5905 return -EINVAL;
5906 }
5907 break;
5908
501fc174
LP
5909 case ARG_NO_ASK_PASSWORD:
5910 arg_ask_password = false;
5911 break;
5912
f459b602
MAP
5913 case 'H':
5914 arg_transport = BUS_TRANSPORT_REMOTE;
5915 arg_host = optarg;
a8f11321
LP
5916 break;
5917
f459b602
MAP
5918 case 'M':
5919 arg_transport = BUS_TRANSPORT_CONTAINER;
5920 arg_host = optarg;
a8f11321
LP
5921 break;
5922
729e3769
LP
5923 case ARG_RUNTIME:
5924 arg_runtime = true;
5925 break;
5926
df50185b
LP
5927 case 'n':
5928 if (safe_atou(optarg, &arg_lines) < 0) {
5929 log_error("Failed to parse lines '%s'", optarg);
5930 return -EINVAL;
5931 }
5932 break;
5933
df50185b
LP
5934 case 'o':
5935 arg_output = output_mode_from_string(optarg);
5936 if (arg_output < 0) {
5937 log_error("Unknown output '%s'.", optarg);
5938 return -EINVAL;
5939 }
5940 break;
5941
b37844d3
LP
5942 case 'i':
5943 arg_ignore_inhibitors = true;
5944 break;
5945
5d0c05e5
LN
5946 case ARG_PLAIN:
5947 arg_plain = true;
5948 break;
5949
9b9b3d36 5950 case ARG_STATE: {
a2a5291b 5951 const char *word, *state;
9b9b3d36
MW
5952 size_t size;
5953
5954 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
5955 char *s;
5956
5957 s = strndup(word, size);
5958 if (!s)
5959 return log_oom();
5960
6e18964d 5961 if (strv_consume(&arg_states, s) < 0)
9b9b3d36 5962 return log_oom();
9b9b3d36
MW
5963 }
5964 break;
5965 }
5966
1238ee09
LP
5967 case 'r':
5968 if (geteuid() != 0) {
f1721625 5969 log_error("--recursive requires root privileges.");
1238ee09
LP
5970 return -EPERM;
5971 }
5972
5973 arg_recursive = true;
5974 break;
5975
d309c1c3
LP
5976 case ARG_PRESET_MODE:
5977
5978 arg_preset_mode = unit_file_preset_mode_from_string(optarg);
5979 if (arg_preset_mode < 0) {
5980 log_error("Failed to parse preset mode: %s.", optarg);
5981 return -EINVAL;
5982 }
5983
5984 break;
5985
7e4249b9
LP
5986 case '?':
5987 return -EINVAL;
5988
5989 default:
eb9da376 5990 assert_not_reached("Unhandled option");
7e4249b9 5991 }
7e4249b9 5992
f459b602 5993 if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM) {
a8f11321
LP
5994 log_error("Cannot access user instance remotely.");
5995 return -EINVAL;
5996 }
5997
7e4249b9
LP
5998 return 1;
5999}
6000
e4b61340
LP
6001static int halt_parse_argv(int argc, char *argv[]) {
6002
6003 enum {
6004 ARG_HELP = 0x100,
6005 ARG_HALT,
514f4ef5
LP
6006 ARG_REBOOT,
6007 ARG_NO_WALL
e4b61340
LP
6008 };
6009
6010 static const struct option options[] = {
6011 { "help", no_argument, NULL, ARG_HELP },
6012 { "halt", no_argument, NULL, ARG_HALT },
6013 { "poweroff", no_argument, NULL, 'p' },
6014 { "reboot", no_argument, NULL, ARG_REBOOT },
6015 { "force", no_argument, NULL, 'f' },
6016 { "wtmp-only", no_argument, NULL, 'w' },
6017 { "no-wtmp", no_argument, NULL, 'd' },
514f4ef5 6018 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 6019 {}
e4b61340
LP
6020 };
6021
37185ec8 6022 int c, r, runlevel;
e4b61340
LP
6023
6024 assert(argc >= 0);
6025 assert(argv);
6026
6027 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
6028 if (runlevel == '0' || runlevel == '6')
65491fd8 6029 arg_force = 2;
e4b61340 6030
601185b4 6031 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0)
e4b61340
LP
6032 switch (c) {
6033
6034 case ARG_HELP:
601185b4
ZJS
6035 halt_help();
6036 return 0;
e4b61340
LP
6037
6038 case ARG_HALT:
6039 arg_action = ACTION_HALT;
6040 break;
6041
6042 case 'p':
a042efad
MS
6043 if (arg_action != ACTION_REBOOT)
6044 arg_action = ACTION_POWEROFF;
e4b61340
LP
6045 break;
6046
6047 case ARG_REBOOT:
6048 arg_action = ACTION_REBOOT;
6049 break;
6050
6051 case 'f':
65491fd8 6052 arg_force = 2;
e4b61340
LP
6053 break;
6054
6055 case 'w':
6056 arg_dry = true;
6057 break;
6058
6059 case 'd':
6060 arg_no_wtmp = true;
6061 break;
6062
514f4ef5
LP
6063 case ARG_NO_WALL:
6064 arg_no_wall = true;
6065 break;
6066
e4b61340
LP
6067 case 'i':
6068 case 'h':
57371e58 6069 case 'n':
e4b61340
LP
6070 /* Compatibility nops */
6071 break;
6072
6073 case '?':
6074 return -EINVAL;
6075
6076 default:
eb9da376 6077 assert_not_reached("Unhandled option");
e4b61340 6078 }
e4b61340 6079
c5220a94
MO
6080 if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
6081 r = update_reboot_param_file(argc == optind + 1 ? argv[optind] : NULL);
6082 if (r < 0)
37185ec8 6083 return r;
37185ec8 6084 } else if (optind < argc) {
e4b61340
LP
6085 log_error("Too many arguments.");
6086 return -EINVAL;
6087 }
6088
6089 return 1;
6090}
6091
f6144808
LP
6092static int parse_time_spec(const char *t, usec_t *_u) {
6093 assert(t);
6094 assert(_u);
6095
6096 if (streq(t, "now"))
6097 *_u = 0;
1a639877 6098 else if (!strchr(t, ':')) {
f6144808
LP
6099 uint64_t u;
6100
1a639877 6101 if (safe_atou64(t, &u) < 0)
f6144808
LP
6102 return -EINVAL;
6103
6104 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
6105 } else {
6106 char *e = NULL;
6107 long hour, minute;
b92bea5d 6108 struct tm tm = {};
f6144808
LP
6109 time_t s;
6110 usec_t n;
6111
6112 errno = 0;
6113 hour = strtol(t, &e, 10);
8333c77e 6114 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
f6144808
LP
6115 return -EINVAL;
6116
6117 minute = strtol(e+1, &e, 10);
8333c77e 6118 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
f6144808
LP
6119 return -EINVAL;
6120
6121 n = now(CLOCK_REALTIME);
08e4b1c5
LP
6122 s = (time_t) (n / USEC_PER_SEC);
6123
f6144808
LP
6124 assert_se(localtime_r(&s, &tm));
6125
6126 tm.tm_hour = (int) hour;
6127 tm.tm_min = (int) minute;
08e4b1c5 6128 tm.tm_sec = 0;
f6144808
LP
6129
6130 assert_se(s = mktime(&tm));
6131
6132 *_u = (usec_t) s * USEC_PER_SEC;
6133
6134 while (*_u <= n)
6135 *_u += USEC_PER_DAY;
6136 }
6137
6138 return 0;
6139}
6140
e4b61340
LP
6141static int shutdown_parse_argv(int argc, char *argv[]) {
6142
6143 enum {
6144 ARG_HELP = 0x100,
514f4ef5 6145 ARG_NO_WALL
e4b61340
LP
6146 };
6147
6148 static const struct option options[] = {
6149 { "help", no_argument, NULL, ARG_HELP },
6150 { "halt", no_argument, NULL, 'H' },
6151 { "poweroff", no_argument, NULL, 'P' },
6152 { "reboot", no_argument, NULL, 'r' },
04ebb595 6153 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
514f4ef5 6154 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 6155 {}
e4b61340
LP
6156 };
6157
f6144808 6158 int c, r;
e4b61340
LP
6159
6160 assert(argc >= 0);
6161 assert(argv);
6162
601185b4 6163 while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0)
e4b61340
LP
6164 switch (c) {
6165
6166 case ARG_HELP:
601185b4
ZJS
6167 shutdown_help();
6168 return 0;
e4b61340
LP
6169
6170 case 'H':
6171 arg_action = ACTION_HALT;
6172 break;
6173
6174 case 'P':
6175 arg_action = ACTION_POWEROFF;
6176 break;
6177
6178 case 'r':
5622dde3
KS
6179 if (kexec_loaded())
6180 arg_action = ACTION_KEXEC;
6181 else
6182 arg_action = ACTION_REBOOT;
e4b61340
LP
6183 break;
6184
04ebb595
LP
6185 case 'K':
6186 arg_action = ACTION_KEXEC;
6187 break;
6188
e4b61340
LP
6189 case 'h':
6190 if (arg_action != ACTION_HALT)
6191 arg_action = ACTION_POWEROFF;
6192 break;
6193
6194 case 'k':
6195 arg_dry = true;
6196 break;
6197
514f4ef5
LP
6198 case ARG_NO_WALL:
6199 arg_no_wall = true;
6200 break;
6201
e4b61340
LP
6202 case 't':
6203 case 'a':
6204 /* Compatibility nops */
6205 break;
6206
f6144808
LP
6207 case 'c':
6208 arg_action = ACTION_CANCEL_SHUTDOWN;
6209 break;
6210
e4b61340
LP
6211 case '?':
6212 return -EINVAL;
6213
6214 default:
eb9da376 6215 assert_not_reached("Unhandled option");
e4b61340 6216 }
e4b61340 6217
dfcc5c33 6218 if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
7e59bfcb
LP
6219 r = parse_time_spec(argv[optind], &arg_when);
6220 if (r < 0) {
f6144808
LP
6221 log_error("Failed to parse time specification: %s", argv[optind]);
6222 return r;
6223 }
6b5ad000 6224 } else
08e4b1c5 6225 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
442b9094 6226
dfcc5c33
MS
6227 if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
6228 /* No time argument for shutdown cancel */
6229 arg_wall = argv + optind;
6230 else if (argc > optind + 1)
6231 /* We skip the time argument */
e4b61340
LP
6232 arg_wall = argv + optind + 1;
6233
6234 optind = argc;
6235
6236 return 1;
e4b61340
LP
6237}
6238
6239static int telinit_parse_argv(int argc, char *argv[]) {
6240
6241 enum {
6242 ARG_HELP = 0x100,
514f4ef5 6243 ARG_NO_WALL
e4b61340
LP
6244 };
6245
6246 static const struct option options[] = {
6247 { "help", no_argument, NULL, ARG_HELP },
514f4ef5 6248 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 6249 {}
e4b61340
LP
6250 };
6251
6252 static const struct {
6253 char from;
6254 enum action to;
6255 } table[] = {
6256 { '0', ACTION_POWEROFF },
6257 { '6', ACTION_REBOOT },
ef2f1067 6258 { '1', ACTION_RESCUE },
e4b61340
LP
6259 { '2', ACTION_RUNLEVEL2 },
6260 { '3', ACTION_RUNLEVEL3 },
6261 { '4', ACTION_RUNLEVEL4 },
6262 { '5', ACTION_RUNLEVEL5 },
6263 { 's', ACTION_RESCUE },
6264 { 'S', ACTION_RESCUE },
6265 { 'q', ACTION_RELOAD },
6266 { 'Q', ACTION_RELOAD },
6267 { 'u', ACTION_REEXEC },
6268 { 'U', ACTION_REEXEC }
6269 };
6270
6271 unsigned i;
6272 int c;
6273
6274 assert(argc >= 0);
6275 assert(argv);
6276
601185b4 6277 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
6278 switch (c) {
6279
6280 case ARG_HELP:
601185b4
ZJS
6281 telinit_help();
6282 return 0;
e4b61340 6283
514f4ef5
LP
6284 case ARG_NO_WALL:
6285 arg_no_wall = true;
6286 break;
6287
e4b61340
LP
6288 case '?':
6289 return -EINVAL;
6290
6291 default:
eb9da376 6292 assert_not_reached("Unhandled option");
e4b61340 6293 }
e4b61340
LP
6294
6295 if (optind >= argc) {
601185b4
ZJS
6296 log_error("%s: required argument missing.",
6297 program_invocation_short_name);
e4b61340
LP
6298 return -EINVAL;
6299 }
6300
6301 if (optind + 1 < argc) {
6302 log_error("Too many arguments.");
6303 return -EINVAL;
6304 }
6305
6306 if (strlen(argv[optind]) != 1) {
6307 log_error("Expected single character argument.");
6308 return -EINVAL;
6309 }
6310
6311 for (i = 0; i < ELEMENTSOF(table); i++)
6312 if (table[i].from == argv[optind][0])
6313 break;
6314
6315 if (i >= ELEMENTSOF(table)) {
b0193f1c 6316 log_error("Unknown command '%s'.", argv[optind]);
e4b61340
LP
6317 return -EINVAL;
6318 }
6319
6320 arg_action = table[i].to;
6321
6322 optind ++;
6323
6324 return 1;
6325}
6326
6327static int runlevel_parse_argv(int argc, char *argv[]) {
6328
6329 enum {
6330 ARG_HELP = 0x100,
6331 };
6332
6333 static const struct option options[] = {
6334 { "help", no_argument, NULL, ARG_HELP },
eb9da376 6335 {}
e4b61340
LP
6336 };
6337
6338 int c;
6339
6340 assert(argc >= 0);
6341 assert(argv);
6342
601185b4 6343 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
6344 switch (c) {
6345
6346 case ARG_HELP:
601185b4
ZJS
6347 runlevel_help();
6348 return 0;
e4b61340
LP
6349
6350 case '?':
6351 return -EINVAL;
6352
6353 default:
eb9da376 6354 assert_not_reached("Unhandled option");
e4b61340 6355 }
e4b61340
LP
6356
6357 if (optind < argc) {
6358 log_error("Too many arguments.");
6359 return -EINVAL;
6360 }
6361
6362 return 1;
6363}
6364
6365static int parse_argv(int argc, char *argv[]) {
6366 assert(argc >= 0);
6367 assert(argv);
6368
6369 if (program_invocation_short_name) {
6370
6371 if (strstr(program_invocation_short_name, "halt")) {
6372 arg_action = ACTION_HALT;
6373 return halt_parse_argv(argc, argv);
6374 } else if (strstr(program_invocation_short_name, "poweroff")) {
6375 arg_action = ACTION_POWEROFF;
6376 return halt_parse_argv(argc, argv);
6377 } else if (strstr(program_invocation_short_name, "reboot")) {
5622dde3
KS
6378 if (kexec_loaded())
6379 arg_action = ACTION_KEXEC;
6380 else
6381 arg_action = ACTION_REBOOT;
e4b61340
LP
6382 return halt_parse_argv(argc, argv);
6383 } else if (strstr(program_invocation_short_name, "shutdown")) {
6384 arg_action = ACTION_POWEROFF;
6385 return shutdown_parse_argv(argc, argv);
6386 } else if (strstr(program_invocation_short_name, "init")) {
d5ca5f11
LP
6387
6388 if (sd_booted() > 0) {
f459b602 6389 arg_action = _ACTION_INVALID;
d5ca5f11
LP
6390 return telinit_parse_argv(argc, argv);
6391 } else {
6392 /* Hmm, so some other init system is
6393 * running, we need to forward this
6394 * request to it. For now we simply
6395 * guess that it is Upstart. */
6396
4ad61fd1 6397 execv(TELINIT, argv);
d5ca5f11
LP
6398
6399 log_error("Couldn't find an alternative telinit implementation to spawn.");
6400 return -EIO;
6401 }
6402
e4b61340
LP
6403 } else if (strstr(program_invocation_short_name, "runlevel")) {
6404 arg_action = ACTION_RUNLEVEL;
6405 return runlevel_parse_argv(argc, argv);
6406 }
6407 }
6408
6409 arg_action = ACTION_SYSTEMCTL;
6410 return systemctl_parse_argv(argc, argv);
6411}
6412
44a6b1b6 6413_pure_ static int action_to_runlevel(void) {
eb22ac37
LP
6414
6415 static const char table[_ACTION_MAX] = {
6416 [ACTION_HALT] = '0',
6417 [ACTION_POWEROFF] = '0',
6418 [ACTION_REBOOT] = '6',
6419 [ACTION_RUNLEVEL2] = '2',
6420 [ACTION_RUNLEVEL3] = '3',
6421 [ACTION_RUNLEVEL4] = '4',
6422 [ACTION_RUNLEVEL5] = '5',
6423 [ACTION_RESCUE] = '1'
6424 };
6425
d55ae9e6
LP
6426 assert(arg_action < _ACTION_MAX);
6427
6428 return table[arg_action];
6429}
6430
d55ae9e6 6431static int talk_initctl(void) {
cbc9fbd1
LP
6432
6433 struct init_request request = {
6434 .magic = INIT_MAGIC,
6435 .sleeptime = 0,
6436 .cmd = INIT_CMD_RUNLVL
6437 };
6438
7fd1b19b 6439 _cleanup_close_ int fd = -1;
d55ae9e6 6440 char rl;
cbc9fbd1 6441 int r;
eb22ac37 6442
427b47c4
ZJS
6443 rl = action_to_runlevel();
6444 if (!rl)
eb22ac37
LP
6445 return 0;
6446
d55ae9e6
LP
6447 request.runlevel = rl;
6448
427b47c4
ZJS
6449 fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
6450 if (fd < 0) {
d55ae9e6
LP
6451 if (errno == ENOENT)
6452 return 0;
eb22ac37 6453
d55ae9e6 6454 log_error("Failed to open "INIT_FIFO": %m");
eb22ac37 6455 return -errno;
d55ae9e6 6456 }
eb22ac37 6457
d55ae9e6 6458 errno = 0;
eb22ac37 6459 r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
427b47c4 6460 if (r) {
d55ae9e6 6461 log_error("Failed to write to "INIT_FIFO": %m");
bcb161b0 6462 return errno > 0 ? -errno : -EIO;
d55ae9e6 6463 }
eb22ac37
LP
6464
6465 return 1;
e4b61340
LP
6466}
6467
41dd15e4 6468static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
7e4249b9 6469
7e4249b9
LP
6470 static const struct {
6471 const char* verb;
6472 const enum {
6473 MORE,
6474 LESS,
6475 EQUAL
6476 } argc_cmp;
6477 const int argc;
f459b602 6478 int (* const dispatch)(sd_bus *bus, char **args);
d08e75ed
ZJS
6479 const enum {
6480 NOBUS = 1,
6481 FORCE,
6482 } bus;
7e4249b9 6483 } verbs[] = {
d8fba7c6 6484 { "list-units", MORE, 0, list_units },
d08e75ed 6485 { "list-unit-files", MORE, 1, list_unit_files, NOBUS },
d8fba7c6
ZJS
6486 { "list-sockets", MORE, 1, list_sockets },
6487 { "list-timers", MORE, 1, list_timers },
6488 { "list-jobs", MORE, 1, list_jobs },
0d292f5e 6489 { "list-machines", MORE, 1, list_machines },
ee5762e3 6490 { "clear-jobs", EQUAL, 1, daemon_reload },
ee5762e3
LP
6491 { "cancel", MORE, 2, cancel_job },
6492 { "start", MORE, 2, start_unit },
6493 { "stop", MORE, 2, start_unit },
a76f7be2 6494 { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
6495 { "reload", MORE, 2, start_unit },
6496 { "restart", MORE, 2, start_unit },
6497 { "try-restart", MORE, 2, start_unit },
6498 { "reload-or-restart", MORE, 2, start_unit },
6499 { "reload-or-try-restart", MORE, 2, start_unit },
6500 { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */
64e5f1b7 6501 { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
6502 { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
6503 { "isolate", EQUAL, 2, start_unit },
8a0867d6 6504 { "kill", MORE, 2, kill_unit },
1a0fce45
TA
6505 { "is-active", MORE, 2, check_unit_active },
6506 { "check", MORE, 2, check_unit_active },
6507 { "is-failed", MORE, 2, check_unit_failed },
ee5762e3 6508 { "show", MORE, 1, show },
e93c33d4 6509 { "cat", MORE, 2, cat },
265a7a2a 6510 { "status", MORE, 1, show },
b43f208f 6511 { "help", MORE, 2, show },
ee5762e3
LP
6512 { "snapshot", LESS, 2, snapshot },
6513 { "delete", MORE, 2, delete_snapshot },
6514 { "daemon-reload", EQUAL, 1, daemon_reload },
6515 { "daemon-reexec", EQUAL, 1, daemon_reload },
f459b602 6516 { "show-environment", EQUAL, 1, show_environment },
ee5762e3
LP
6517 { "set-environment", MORE, 2, set_environment },
6518 { "unset-environment", MORE, 2, set_environment },
ac3efa8a 6519 { "import-environment", MORE, 1, import_environment},
d08e75ed
ZJS
6520 { "halt", EQUAL, 1, start_special, FORCE },
6521 { "poweroff", EQUAL, 1, start_special, FORCE },
6522 { "reboot", EQUAL, 1, start_special, FORCE },
20b09ca7 6523 { "kexec", EQUAL, 1, start_special },
6edd7d0a
LP
6524 { "suspend", EQUAL, 1, start_special },
6525 { "hibernate", EQUAL, 1, start_special },
6524990f 6526 { "hybrid-sleep", EQUAL, 1, start_special },
ee5762e3
LP
6527 { "default", EQUAL, 1, start_special },
6528 { "rescue", EQUAL, 1, start_special },
6529 { "emergency", EQUAL, 1, start_special },
20b09ca7 6530 { "exit", EQUAL, 1, start_special },
fdf20a31 6531 { "reset-failed", MORE, 1, reset_failed },
d08e75ed
ZJS
6532 { "enable", MORE, 2, enable_unit, NOBUS },
6533 { "disable", MORE, 2, enable_unit, NOBUS },
6534 { "is-enabled", MORE, 2, unit_is_enabled, NOBUS },
6535 { "reenable", MORE, 2, enable_unit, NOBUS },
6536 { "preset", MORE, 2, enable_unit, NOBUS },
d309c1c3 6537 { "preset-all", EQUAL, 1, preset_all, NOBUS },
d08e75ed
ZJS
6538 { "mask", MORE, 2, enable_unit, NOBUS },
6539 { "unmask", MORE, 2, enable_unit, NOBUS },
6540 { "link", MORE, 2, enable_unit, NOBUS },
957eb8ca 6541 { "switch-root", MORE, 2, switch_root },
e31165b2 6542 { "list-dependencies", LESS, 2, list_dependencies },
d08e75ed
ZJS
6543 { "set-default", EQUAL, 2, set_default, NOBUS },
6544 { "get-default", EQUAL, 1, get_default, NOBUS },
8e2af478 6545 { "set-property", MORE, 3, set_property },
99813a19 6546 { "is-system-running", EQUAL, 1, is_system_running },
d08e75ed
ZJS
6547 {}
6548 }, *verb = verbs;
7e4249b9 6549
e4b61340 6550 int left;
7e4249b9 6551
e4b61340
LP
6552 assert(argc >= 0);
6553 assert(argv);
7e4249b9
LP
6554
6555 left = argc - optind;
6556
d08e75ed
ZJS
6557 /* Special rule: no arguments (left == 0) means "list-units" */
6558 if (left > 0) {
b43f208f
KS
6559 if (streq(argv[optind], "help") && !argv[optind+1]) {
6560 log_error("This command expects one or more "
6561 "unit names. Did you mean --help?");
6562 return -EINVAL;
0183528f
LP
6563 }
6564
d08e75ed
ZJS
6565 for (; verb->verb; verb++)
6566 if (streq(argv[optind], verb->verb))
6567 goto found;
7e4249b9 6568
d08e75ed
ZJS
6569 log_error("Unknown operation '%s'.", argv[optind]);
6570 return -EINVAL;
7e4249b9 6571 }
d08e75ed 6572found:
7e4249b9 6573
d08e75ed 6574 switch (verb->argc_cmp) {
7e4249b9
LP
6575
6576 case EQUAL:
d08e75ed 6577 if (left != verb->argc) {
7e4249b9 6578 log_error("Invalid number of arguments.");
e4b61340 6579 return -EINVAL;
7e4249b9
LP
6580 }
6581
6582 break;
6583
6584 case MORE:
d08e75ed 6585 if (left < verb->argc) {
7e4249b9 6586 log_error("Too few arguments.");
e4b61340 6587 return -EINVAL;
7e4249b9
LP
6588 }
6589
6590 break;
6591
6592 case LESS:
d08e75ed 6593 if (left > verb->argc) {
7e4249b9 6594 log_error("Too many arguments.");
e4b61340 6595 return -EINVAL;
7e4249b9
LP
6596 }
6597
6598 break;
6599
6600 default:
6601 assert_not_reached("Unknown comparison operator.");
6602 }
6603
ee5762e3
LP
6604 /* Require a bus connection for all operations but
6605 * enable/disable */
d08e75ed
ZJS
6606 if (verb->bus == NOBUS) {
6607 if (!bus && !avoid_bus()) {
6608 log_error("Failed to get D-Bus connection: %s", strerror(-bus_error));
6609 return -EIO;
6610 }
82e23ddd 6611
d08e75ed 6612 } else {
82e23ddd
LP
6613 if (running_in_chroot() > 0) {
6614 log_info("Running in chroot, ignoring request.");
6615 return 0;
6616 }
6617
d08e75ed
ZJS
6618 if ((verb->bus != FORCE || arg_force <= 0) && !bus) {
6619 log_error("Failed to get D-Bus connection: %s", strerror(-bus_error));
82e23ddd
LP
6620 return -EIO;
6621 }
ee5762e3
LP
6622 }
6623
d08e75ed 6624 return verb->dispatch(bus, argv + optind);
e4b61340
LP
6625}
6626
52c00215 6627static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
cbc9fbd1 6628
b92bea5d
ZJS
6629 struct sd_shutdown_command c = {
6630 .usec = t,
6631 .mode = mode,
6632 .dry_run = dry_run,
6633 .warn_wall = warn,
6634 };
cbc9fbd1 6635
b92bea5d
ZJS
6636 union sockaddr_union sockaddr = {
6637 .un.sun_family = AF_UNIX,
6638 .un.sun_path = "/run/systemd/shutdownd",
6639 };
cbc9fbd1
LP
6640
6641 struct iovec iovec[2] = {{
6642 .iov_base = (char*) &c,
b92bea5d 6643 .iov_len = offsetof(struct sd_shutdown_command, wall_message),
cbc9fbd1
LP
6644 }};
6645
b92bea5d
ZJS
6646 struct msghdr msghdr = {
6647 .msg_name = &sockaddr,
6648 .msg_namelen = offsetof(struct sockaddr_un, sun_path)
f8294e41 6649 + strlen("/run/systemd/shutdownd"),
b92bea5d
ZJS
6650 .msg_iov = iovec,
6651 .msg_iovlen = 1,
6652 };
04ebb595 6653
cbc9fbd1
LP
6654 _cleanup_close_ int fd;
6655
04ebb595
LP
6656 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
6657 if (fd < 0)
6658 return -errno;
f6144808 6659
b92bea5d 6660 if (!isempty(message)) {
04ebb595
LP
6661 iovec[1].iov_base = (char*) message;
6662 iovec[1].iov_len = strlen(message);
b92bea5d 6663 msghdr.msg_iovlen++;
04ebb595 6664 }
f6144808 6665
cec7eda5 6666 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
f6144808 6667 return -errno;
f6144808 6668
f6144808
LP
6669 return 0;
6670}
6671
f459b602 6672static int reload_with_fallback(sd_bus *bus) {
e4b61340
LP
6673
6674 if (bus) {
6675 /* First, try systemd via D-Bus. */
d76702a7 6676 if (daemon_reload(bus, NULL) >= 0)
e4b61340
LP
6677 return 0;
6678 }
6679
6680 /* Nothing else worked, so let's try signals */
6681 assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
6682
6683 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
6684 log_error("kill() failed: %m");
6685 return -errno;
6686 }
6687
6688 return 0;
6689}
6690
f459b602 6691static int start_with_fallback(sd_bus *bus) {
e4b61340
LP
6692
6693 if (bus) {
6694 /* First, try systemd via D-Bus. */
729e3769 6695 if (start_unit(bus, NULL) >= 0)
983d9c90 6696 goto done;
e4b61340
LP
6697 }
6698
6699 /* Nothing else worked, so let's try
6700 * /dev/initctl */
fbc43921 6701 if (talk_initctl() > 0)
983d9c90 6702 goto done;
d55ae9e6
LP
6703
6704 log_error("Failed to talk to init daemon.");
6705 return -EIO;
983d9c90
LP
6706
6707done:
6708 warn_wall(arg_action);
6709 return 0;
e4b61340
LP
6710}
6711
477def80 6712static int halt_now(enum action a) {
e606bb61 6713
477def80 6714/* Make sure C-A-D is handled by the kernel from this
e606bb61
LP
6715 * point on... */
6716 reboot(RB_ENABLE_CAD);
6717
4c80c73c 6718 switch (a) {
e606bb61
LP
6719
6720 case ACTION_HALT:
6721 log_info("Halting.");
6722 reboot(RB_HALT_SYSTEM);
477def80 6723 return -errno;
e606bb61
LP
6724
6725 case ACTION_POWEROFF:
6726 log_info("Powering off.");
6727 reboot(RB_POWER_OFF);
477def80 6728 return -errno;
e606bb61 6729
477def80
LP
6730 case ACTION_REBOOT: {
6731 _cleanup_free_ char *param = NULL;
cbc9fbd1 6732
477def80
LP
6733 if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
6734 log_info("Rebooting with argument '%s'.", param);
37185ec8
WC
6735 syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
6736 LINUX_REBOOT_CMD_RESTART2, param);
37185ec8 6737 }
e606bb61 6738
477def80
LP
6739 log_info("Rebooting.");
6740 reboot(RB_AUTOBOOT);
6741 return -errno;
e606bb61
LP
6742 }
6743
477def80
LP
6744 default:
6745 assert_not_reached("Unknown action.");
6746 }
e606bb61
LP
6747}
6748
f459b602 6749static int halt_main(sd_bus *bus) {
e4b61340
LP
6750 int r;
6751
748ebafa
LP
6752 r = check_inhibitors(bus, arg_action);
6753 if (r < 0)
6754 return r;
b37844d3 6755
bc8c2f5c 6756 if (geteuid() != 0) {
7e59bfcb
LP
6757 /* Try logind if we are a normal user and no special
6758 * mode applies. Maybe PolicyKit allows us to shutdown
6759 * the machine. */
6760
6761 if (arg_when <= 0 &&
6762 !arg_dry &&
b37844d3 6763 arg_force <= 0 &&
7e59bfcb
LP
6764 (arg_action == ACTION_POWEROFF ||
6765 arg_action == ACTION_REBOOT)) {
4c80c73c
KS
6766 r = reboot_with_logind(bus, arg_action);
6767 if (r >= 0)
6768 return r;
6769 }
6770
cc8a7a61 6771 log_error("Must be root.");
bc8c2f5c
LP
6772 return -EPERM;
6773 }
6774
f6144808 6775 if (arg_when > 0) {
7fd1b19b 6776 _cleanup_free_ char *m;
9be9828c
LP
6777
6778 m = strv_join(arg_wall, " ");
cbc9fbd1
LP
6779 if (!m)
6780 return log_oom();
6781
9be9828c
LP
6782 r = send_shutdownd(arg_when,
6783 arg_action == ACTION_HALT ? 'H' :
6784 arg_action == ACTION_POWEROFF ? 'P' :
04ebb595 6785 arg_action == ACTION_KEXEC ? 'K' :
9be9828c 6786 'r',
52c00215 6787 arg_dry,
9be9828c
LP
6788 !arg_no_wall,
6789 m);
9be9828c
LP
6790
6791 if (r < 0)
f6144808 6792 log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
08e4b1c5 6793 else {
7e59bfcb
LP
6794 char date[FORMAT_TIMESTAMP_MAX];
6795
08e4b1c5
LP
6796 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
6797 format_timestamp(date, sizeof(date), arg_when));
f6144808 6798 return 0;
08e4b1c5 6799 }
f6144808
LP
6800 }
6801
65491fd8 6802 if (!arg_dry && !arg_force)
e4b61340
LP
6803 return start_with_fallback(bus);
6804
d90e1a30
LP
6805 if (!arg_no_wtmp) {
6806 if (sd_booted() > 0)
6807 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
7e59bfcb
LP
6808 else {
6809 r = utmp_put_shutdown();
6810 if (r < 0)
6811 log_warning("Failed to write utmp record: %s", strerror(-r));
6812 }
d90e1a30 6813 }
e4b61340 6814
e4b61340
LP
6815 if (arg_dry)
6816 return 0;
6817
477def80
LP
6818 r = halt_now(arg_action);
6819 log_error("Failed to reboot: %s", strerror(-r));
6820
6821 return r;
e4b61340
LP
6822}
6823
6824static int runlevel_main(void) {
6825 int r, runlevel, previous;
6826
729e3769
LP
6827 r = utmp_get_runlevel(&runlevel, &previous);
6828 if (r < 0) {
6829 puts("unknown");
e4b61340
LP
6830 return r;
6831 }
6832
6833 printf("%c %c\n",
6834 previous <= 0 ? 'N' : previous,
6835 runlevel <= 0 ? 'N' : runlevel);
6836
6837 return 0;
6838}
6839
6840int main(int argc, char*argv[]) {
24996861 6841 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
f459b602 6842 int r;
e4b61340 6843
a9cdc94f 6844 setlocale(LC_ALL, "");
e4b61340 6845 log_parse_environment();
2396fb04 6846 log_open();
e4b61340 6847
184ecaf7
DR
6848 /* Explicitly not on_tty() to avoid setting cached value.
6849 * This becomes relevant for piping output which might be
6850 * ellipsized. */
6851 original_stdout_is_tty = isatty(STDOUT_FILENO);
6852
04ebb595 6853 r = parse_argv(argc, argv);
f459b602 6854 if (r <= 0)
e4b61340 6855 goto finish;
7e4249b9 6856
e4b61340
LP
6857 /* /sbin/runlevel doesn't need to communicate via D-Bus, so
6858 * let's shortcut this */
6859 if (arg_action == ACTION_RUNLEVEL) {
22f4096c 6860 r = runlevel_main();
e4b61340
LP
6861 goto finish;
6862 }
6863
82e23ddd
LP
6864 if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
6865 log_info("Running in chroot, ignoring request.");
f459b602 6866 r = 0;
82e23ddd
LP
6867 goto finish;
6868 }
6869
41dd15e4
LP
6870 if (!avoid_bus())
6871 r = bus_open_transport_systemd(arg_transport, arg_host, arg_scope != UNIT_FILE_SYSTEM, &bus);
6872
6873 /* systemctl_main() will print an error message for the bus
6874 * connection, but only if it needs to */
e4b61340
LP
6875
6876 switch (arg_action) {
6877
22f4096c 6878 case ACTION_SYSTEMCTL:
f459b602 6879 r = systemctl_main(bus, argc, argv, r);
e4b61340 6880 break;
e4b61340
LP
6881
6882 case ACTION_HALT:
6883 case ACTION_POWEROFF:
6884 case ACTION_REBOOT:
5622dde3 6885 case ACTION_KEXEC:
22f4096c 6886 r = halt_main(bus);
e4b61340
LP
6887 break;
6888
e4b61340
LP
6889 case ACTION_RUNLEVEL2:
6890 case ACTION_RUNLEVEL3:
6891 case ACTION_RUNLEVEL4:
6892 case ACTION_RUNLEVEL5:
6893 case ACTION_RESCUE:
514f4ef5 6894 case ACTION_EMERGENCY:
eb22ac37 6895 case ACTION_DEFAULT:
22f4096c 6896 r = start_with_fallback(bus);
e4b61340 6897 break;
7e4249b9 6898
e4b61340
LP
6899 case ACTION_RELOAD:
6900 case ACTION_REEXEC:
22f4096c 6901 r = reload_with_fallback(bus);
e4b61340
LP
6902 break;
6903
dfcc5c33 6904 case ACTION_CANCEL_SHUTDOWN: {
f459b602 6905 _cleanup_free_ char *m = NULL;
dfcc5c33
MS
6906
6907 if (arg_wall) {
6908 m = strv_join(arg_wall, " ");
6909 if (!m) {
f459b602 6910 r = log_oom();
dfcc5c33
MS
6911 goto finish;
6912 }
6913 }
f459b602 6914
dfcc5c33
MS
6915 r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
6916 if (r < 0)
6917 log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
f6144808 6918 break;
dfcc5c33 6919 }
f6144808 6920
eb22ac37 6921 case ACTION_RUNLEVEL:
f459b602 6922 case _ACTION_INVALID:
e4b61340
LP
6923 default:
6924 assert_not_reached("Unknown action");
6925 }
7e4249b9
LP
6926
6927finish:
f459b602
MAP
6928 pager_close();
6929 ask_password_agent_close();
6930 polkit_agent_close();
7e4249b9 6931
20b3f379 6932 strv_free(arg_types);
9b9b3d36 6933 strv_free(arg_states);
20b3f379 6934 strv_free(arg_properties);
ea4a240d 6935
f459b602 6936 return r < 0 ? EXIT_FAILURE : r;
7e4249b9 6937}