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