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