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