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