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