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