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