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