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