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