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