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