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