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