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