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