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