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