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