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