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