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