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