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