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