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