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