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