]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl.c
Merge pull request #4729 from martinpitt/hwdb
[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
76d8ca22 2200static int output_waiting_jobs(sd_bus *bus, uint32_t id, const char *method, const char *prefix) {
82948f6c
LP
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);
76d8ca22
ZJS
2218 if (r < 0)
2219 return log_debug_errno(r, "Failed to get waiting jobs for job %" PRIu32, id);
82948f6c
LP
2220
2221 r = sd_bus_message_enter_container(reply, 'a', "(usssoo)");
76d8ca22
ZJS
2222 if (r < 0)
2223 return bus_log_parse_error(r);
82948f6c
LP
2224
2225 while ((r = sd_bus_message_read(reply, "(usssoo)", &other_id, &name, &type, &state, &job_path, &unit_path)) > 0)
bc357ce5 2226 printf("%s %u (%s/%s)\n", prefix, other_id, name, type);
76d8ca22
ZJS
2227 if (r < 0)
2228 return bus_log_parse_error(r);
82948f6c
LP
2229
2230 r = sd_bus_message_exit_container(reply);
76d8ca22
ZJS
2231 if (r < 0)
2232 return bus_log_parse_error(r);
2233
2234 return 0;
82948f6c
LP
2235}
2236
75add28a
ZJS
2237struct job_info {
2238 uint32_t id;
f459b602 2239 const char *name, *type, *state;
75add28a
ZJS
2240};
2241
82948f6c 2242static void output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n, bool skipped) {
f459b602
MAP
2243 unsigned id_len, unit_len, type_len, state_len;
2244 const struct job_info *j;
75add28a
ZJS
2245 const char *on, *off;
2246 bool shorten = false;
2247
2248 assert(n == 0 || jobs);
2249
2250 if (n == 0) {
250ba664
ZJS
2251 if (!arg_no_legend) {
2252 on = ansi_highlight_green();
1fc464f6 2253 off = ansi_normal();
75add28a 2254
250ba664
ZJS
2255 printf("%sNo jobs %s.%s\n", on, skipped ? "listed" : "running", off);
2256 }
75add28a
ZJS
2257 return;
2258 }
2259
ea4b98e6 2260 pager_open(arg_no_pager, false);
75add28a 2261
f8294e41
JT
2262 id_len = strlen("JOB");
2263 unit_len = strlen("UNIT");
2264 type_len = strlen("TYPE");
2265 state_len = strlen("STATE");
6d6d40c9 2266
f459b602
MAP
2267 for (j = jobs; j < jobs + n; j++) {
2268 uint32_t id = j->id;
2269 assert(j->name && j->type && j->state);
75add28a 2270
f459b602
MAP
2271 id_len = MAX(id_len, DECIMAL_STR_WIDTH(id));
2272 unit_len = MAX(unit_len, strlen(j->name));
2273 type_len = MAX(type_len, strlen(j->type));
2274 state_len = MAX(state_len, strlen(j->state));
2275 }
75add28a 2276
f459b602
MAP
2277 if (!arg_full && id_len + 1 + unit_len + type_len + 1 + state_len > columns()) {
2278 unit_len = MAX(33u, columns() - id_len - type_len - state_len - 3);
2279 shorten = true;
2280 }
75add28a 2281
6ce774fd
MM
2282 if (!arg_no_legend)
2283 printf("%*s %-*s %-*s %-*s\n",
2284 id_len, "JOB",
2285 unit_len, "UNIT",
2286 type_len, "TYPE",
2287 state_len, "STATE");
75add28a 2288
f459b602
MAP
2289 for (j = jobs; j < jobs + n; j++) {
2290 _cleanup_free_ char *e = NULL;
75add28a 2291
f459b602
MAP
2292 if (streq(j->state, "running")) {
2293 on = ansi_highlight();
1fc464f6 2294 off = ansi_normal();
f459b602
MAP
2295 } else
2296 on = off = "";
2297
2298 e = shorten ? ellipsize(j->name, unit_len, 33) : NULL;
2299 printf("%*u %s%-*s%s %-*s %s%-*s%s\n",
2300 id_len, j->id,
2301 on, unit_len, e ? e : j->name, off,
2302 type_len, j->type,
2303 on, state_len, j->state, off);
82948f6c
LP
2304
2305 if (arg_jobs_after)
bc357ce5 2306 output_waiting_jobs(bus, j->id, "GetJobAfter", "\twaiting for job");
82948f6c 2307 if (arg_jobs_before)
bc357ce5 2308 output_waiting_jobs(bus, j->id, "GetJobBefore", "\tblocking job");
75add28a
ZJS
2309 }
2310
6ce774fd
MM
2311 if (!arg_no_legend) {
2312 on = ansi_highlight();
1fc464f6 2313 off = ansi_normal();
75add28a 2314
6ce774fd
MM
2315 printf("\n%s%u jobs listed%s.\n", on, n, off);
2316 }
75add28a
ZJS
2317}
2318
d8fba7c6 2319static bool output_show_job(struct job_info *job, char **patterns) {
2404701e 2320 return strv_fnmatch_or_empty(patterns, job->name, FNM_NOESCAPE);
d8fba7c6
ZJS
2321}
2322
e449de87 2323static int list_jobs(int argc, char *argv[], void *userdata) {
4afd3348
LP
2324 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2325 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
f459b602
MAP
2326 const char *name, *type, *state, *job_path, *unit_path;
2327 _cleanup_free_ struct job_info *jobs = NULL;
2328 size_t size = 0;
2329 unsigned c = 0;
4fbd7192 2330 sd_bus *bus;
f459b602 2331 uint32_t id;
f84190d8 2332 int r;
d8fba7c6 2333 bool skipped = false;
ec14911e 2334
4fbd7192
LP
2335 r = acquire_bus(BUS_MANAGER, &bus);
2336 if (r < 0)
2337 return r;
2338
f459b602 2339 r = sd_bus_call_method(
f22f08cd
SP
2340 bus,
2341 "org.freedesktop.systemd1",
2342 "/org/freedesktop/systemd1",
2343 "org.freedesktop.systemd1.Manager",
2344 "ListJobs",
f459b602 2345 &error,
f22f08cd 2346 &reply,
f459b602 2347 NULL);
691395d8
LP
2348 if (r < 0)
2349 return log_error_errno(r, "Failed to list jobs: %s", bus_error_message(&error, r));
7e4249b9 2350
f459b602
MAP
2351 r = sd_bus_message_enter_container(reply, 'a', "(usssoo)");
2352 if (r < 0)
2353 return bus_log_parse_error(r);
7e4249b9 2354
f459b602 2355 while ((r = sd_bus_message_read(reply, "(usssoo)", &id, &name, &type, &state, &job_path, &unit_path)) > 0) {
d8fba7c6
ZJS
2356 struct job_info job = { id, name, type, state };
2357
e449de87 2358 if (!output_show_job(&job, strv_skip(argv, 1))) {
d8fba7c6
ZJS
2359 skipped = true;
2360 continue;
2361 }
8fe914ec 2362
f459b602
MAP
2363 if (!GREEDY_REALLOC(jobs, size, c + 1))
2364 return log_oom();
7e4249b9 2365
d8fba7c6 2366 jobs[c++] = job;
7e4249b9 2367 }
f459b602
MAP
2368 if (r < 0)
2369 return bus_log_parse_error(r);
7e4249b9 2370
f459b602
MAP
2371 r = sd_bus_message_exit_container(reply);
2372 if (r < 0)
2373 return bus_log_parse_error(r);
f73e33d9 2374
d2ad7e1b
ZJS
2375 pager_open(arg_no_pager, false);
2376
82948f6c 2377 output_jobs_list(bus, jobs, c, skipped);
91d0f17e 2378 return 0;
7e4249b9
LP
2379}
2380
e449de87 2381static int cancel_job(int argc, char *argv[], void *userdata) {
4fbd7192 2382 sd_bus *bus;
729e3769 2383 char **name;
342641fb 2384 int r = 0;
7e4249b9 2385
e449de87 2386 if (argc <= 1)
2853b60a 2387 return trivial_method(argc, argv, userdata);
ee5762e3 2388
4fbd7192
LP
2389 r = acquire_bus(BUS_MANAGER, &bus);
2390 if (r < 0)
2391 return r;
2392
d2ad7e1b
ZJS
2393 polkit_agent_open_if_enabled();
2394
e449de87 2395 STRV_FOREACH(name, strv_skip(argv, 1)) {
4afd3348 2396 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5dd9014f 2397 uint32_t id;
342641fb 2398 int q;
7e4249b9 2399
342641fb 2400 q = safe_atou32(*name, &id);
f647962d
MS
2401 if (q < 0)
2402 return log_error_errno(q, "Failed to parse job id \"%s\": %m", *name);
7e4249b9 2403
6e646d22 2404 q = sd_bus_call_method(
f22f08cd
SP
2405 bus,
2406 "org.freedesktop.systemd1",
2407 "/org/freedesktop/systemd1",
2408 "org.freedesktop.systemd1.Manager",
6e646d22
LP
2409 "CancelJob",
2410 &error,
2411 NULL,
2412 "u", id);
342641fb 2413 if (q < 0) {
691395d8 2414 log_error_errno(q, "Failed to cancel job %"PRIu32": %s", id, bus_error_message(&error, q));
342641fb
LP
2415 if (r == 0)
2416 r = q;
f459b602 2417 }
7e4249b9
LP
2418 }
2419
342641fb 2420 return r;
7e4249b9
LP
2421}
2422
f459b602 2423static int need_daemon_reload(sd_bus *bus, const char *unit) {
4afd3348 2424 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
f459b602
MAP
2425 const char *path;
2426 int b, r;
94c01aeb 2427
f459b602
MAP
2428 /* We ignore all errors here, since this is used to show a
2429 * warning only */
45fb0699 2430
f459b602
MAP
2431 /* We don't use unit_dbus_path_from_name() directly since we
2432 * don't want to load the unit if it isn't loaded. */
f84190d8 2433
f459b602 2434 r = sd_bus_call_method(
f22f08cd
SP
2435 bus,
2436 "org.freedesktop.systemd1",
2437 "/org/freedesktop/systemd1",
2438 "org.freedesktop.systemd1.Manager",
2439 "GetUnit",
f459b602 2440 NULL,
f22f08cd 2441 &reply,
e3e0314b 2442 "s", unit);
f84190d8
LP
2443 if (r < 0)
2444 return r;
45fb0699 2445
f459b602
MAP
2446 r = sd_bus_message_read(reply, "o", &path);
2447 if (r < 0)
2448 return r;
f84190d8 2449
f459b602 2450 r = sd_bus_get_property_trivial(
f22f08cd 2451 bus,
b0193f1c
LP
2452 "org.freedesktop.systemd1",
2453 path,
f459b602
MAP
2454 "org.freedesktop.systemd1.Unit",
2455 "NeedDaemonReload",
2456 NULL,
2457 'b', &b);
f84190d8
LP
2458 if (r < 0)
2459 return r;
45fb0699 2460
45fb0699
LP
2461 return b;
2462}
2463
3f36991e 2464static void warn_unit_file_changed(const char *name) {
87ec20ef
LP
2465 assert(name);
2466
3f36991e
ZJS
2467 log_warning("%sWarning:%s %s changed on disk. Run 'systemctl%s daemon-reload' to reload units.",
2468 ansi_highlight_red(),
1fc464f6 2469 ansi_normal(),
3f36991e
ZJS
2470 name,
2471 arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
2472}
2473
33f6c497
ZJS
2474static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **unit_path) {
2475 char **p;
2476
2477 assert(lp);
2478 assert(unit_name);
2479 assert(unit_path);
2480
a3c4eb07 2481 STRV_FOREACH(p, lp->search_path) {
c6dd36b6
FS
2482 _cleanup_free_ char *path = NULL, *lpath = NULL;
2483 int r;
33f6c497
ZJS
2484
2485 path = path_join(arg_root, *p, unit_name);
2486 if (!path)
2487 return log_oom();
2488
c6dd36b6
FS
2489 r = chase_symlinks(path, arg_root, &lpath);
2490 if (r == -ENOENT)
2491 continue;
2492 if (r == -ENOMEM)
2493 return log_oom();
2494 if (r < 0)
2495 return log_error_errno(r, "Failed to access path '%s': %m", path);
2496
2497 *unit_path = lpath;
2498 lpath = NULL;
2499 return 1;
33f6c497
ZJS
2500 }
2501
2502 return 0;
2503}
2504
6e646d22
LP
2505static int unit_find_paths(
2506 sd_bus *bus,
2507 const char *unit_name,
6e646d22
LP
2508 LookupPaths *lp,
2509 char **fragment_path,
2510 char ***dropin_paths) {
dab2bce8
IS
2511
2512 _cleanup_free_ char *path = NULL;
2513 _cleanup_strv_free_ char **dropins = NULL;
33f6c497
ZJS
2514 int r;
2515
ad2a0358
ZJS
2516 /**
2517 * Finds where the unit is defined on disk. Returns 0 if the unit
2518 * is not found. Returns 1 if it is found, and sets
2519 * - the path to the unit in *path, if it exists on disk,
2520 * - and a strv of existing drop-ins in *dropins,
2521 * if the arg is not NULL and any dropins were found.
2522 */
2523
33f6c497 2524 assert(unit_name);
ad2a0358 2525 assert(fragment_path);
33f6c497
ZJS
2526 assert(lp);
2527
4fbd7192 2528 if (!install_client_side() && !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
4afd3348 2529 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
33f6c497 2530 _cleanup_free_ char *unit = NULL;
33f6c497
ZJS
2531
2532 unit = unit_dbus_path_from_name(unit_name);
2533 if (!unit)
2534 return log_oom();
2535
33f6c497
ZJS
2536 r = sd_bus_get_property_string(
2537 bus,
2538 "org.freedesktop.systemd1",
2539 unit,
2540 "org.freedesktop.systemd1.Unit",
2541 "FragmentPath",
2542 &error,
ad2a0358
ZJS
2543 &path);
2544 if (r < 0)
2545 return log_error_errno(r, "Failed to get FragmentPath: %s", bus_error_message(&error, r));
2546
dab2bce8
IS
2547 if (dropin_paths) {
2548 r = sd_bus_get_property_strv(
2549 bus,
2550 "org.freedesktop.systemd1",
2551 unit,
2552 "org.freedesktop.systemd1.Unit",
2553 "DropInPaths",
2554 &error,
2555 &dropins);
2556 if (r < 0)
2557 return log_error_errno(r, "Failed to get DropInPaths: %s", bus_error_message(&error, r));
33f6c497 2558 }
ad2a0358
ZJS
2559 } else {
2560 _cleanup_set_free_ Set *names;
33f6c497 2561
ad2a0358
ZJS
2562 names = set_new(NULL);
2563 if (!names)
7410616c 2564 return log_oom();
33f6c497 2565
dab2bce8 2566 r = unit_file_find_path(lp, unit_name, &path);
ad2a0358
ZJS
2567 if (r < 0)
2568 return r;
2569
2570 if (r == 0) {
7410616c 2571 _cleanup_free_ char *template = NULL;
ad2a0358 2572
7410616c 2573 r = unit_name_template(unit_name, &template);
eacd8534 2574 if (r < 0 && r != -EINVAL)
7410616c
LP
2575 return log_error_errno(r, "Failed to determine template name: %m");
2576 if (r >= 0) {
dab2bce8 2577 r = unit_file_find_path(lp, template, &path);
ad2a0358
ZJS
2578 if (r < 0)
2579 return r;
2580 }
2581 }
2582
c6dd36b6
FS
2583 r = set_put(names, basename(path));
2584 if (r < 0)
2585 return log_error_errno(r, "Failed to add unit name: %m");
2586
dab2bce8 2587 if (dropin_paths) {
a3c4eb07 2588 r = unit_file_find_dropin_paths(lp->search_path, NULL, names, &dropins);
dab2bce8
IS
2589 if (r < 0)
2590 return r;
2591 }
2592 }
2593
2594 r = 0;
2595
2596 if (!isempty(path)) {
2597 *fragment_path = path;
2598 path = NULL;
2599 r = 1;
2600 }
2601
2602 if (dropin_paths && !strv_isempty(dropins)) {
2603 *dropin_paths = dropins;
2604 dropins = NULL;
2605 r = 1;
33f6c497
ZJS
2606 }
2607
39c38ce1 2608 if (r == 0 && !arg_force)
b5e6a600
IS
2609 log_error("No files found for %s.", unit_name);
2610
ad2a0358 2611 return r;
33f6c497
ZJS
2612}
2613
fa0d5878 2614static int get_state_one_unit(sd_bus *bus, const char *name, UnitActiveState *active_state) {
b430f85f 2615 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4afd3348 2616 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
b430f85f 2617 _cleanup_free_ char *buf = NULL;
fa0d5878
BR
2618 UnitActiveState state;
2619 const char *path;
f22f08cd 2620 int r;
701cdcb9 2621
31be1221 2622 assert(name);
fa0d5878 2623 assert(active_state);
701cdcb9 2624
b430f85f
LP
2625 /* We don't use unit_dbus_path_from_name() directly since we don't want to load the unit unnecessarily, if it
2626 * isn't loaded. */
f459b602 2627 r = sd_bus_call_method(
f22f08cd
SP
2628 bus,
2629 "org.freedesktop.systemd1",
2630 "/org/freedesktop/systemd1",
2631 "org.freedesktop.systemd1.Manager",
2632 "GetUnit",
b430f85f 2633 &error,
f22f08cd 2634 &reply,
6233b902 2635 "s", name);
60f9ba0b 2636 if (r < 0) {
b430f85f
LP
2637 if (!sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT))
2638 return log_error_errno(r, "Failed to retrieve unit: %s", bus_error_message(&error, r));
e61a3135 2639
b430f85f
LP
2640 /* The unit is currently not loaded, hence say it's "inactive", since all units that aren't loaded are
2641 * considered inactive. */
fa0d5878 2642 state = UNIT_INACTIVE;
60f9ba0b 2643
b430f85f
LP
2644 } else {
2645 r = sd_bus_message_read(reply, "o", &path);
2646 if (r < 0)
2647 return bus_log_parse_error(r);
2648
2649 r = sd_bus_get_property_string(
2650 bus,
2651 "org.freedesktop.systemd1",
2652 path,
2653 "org.freedesktop.systemd1.Unit",
2654 "ActiveState",
2655 &error,
2656 &buf);
2657 if (r < 0)
2658 return log_error_errno(r, "Failed to retrieve unit state: %s", bus_error_message(&error, r));
2659
fa0d5878
BR
2660 state = unit_active_state_from_string(buf);
2661 if (state == _UNIT_ACTIVE_STATE_INVALID) {
2662 log_error("Invalid unit state '%s' for: %s", buf, name);
2663 return -EINVAL;
2664 }
60f9ba0b 2665 }
701cdcb9 2666
fa0d5878
BR
2667 *active_state = state;
2668 return 0;
701cdcb9
MS
2669}
2670
f459b602
MAP
2671static int check_triggering_units(
2672 sd_bus *bus,
2673 const char *name) {
2674
4afd3348 2675 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
fa0d5878 2676 _cleanup_free_ char *path = NULL, *n = NULL, *load_state = NULL;
f459b602 2677 _cleanup_strv_free_ char **triggered_by = NULL;
e61a3135 2678 bool print_warning_label = true;
fa0d5878 2679 UnitActiveState active_state;
f459b602 2680 char **i;
f22f08cd 2681 int r;
701cdcb9 2682
7410616c
LP
2683 r = unit_name_mangle(name, UNIT_NAME_NOGLOB, &n);
2684 if (r < 0)
2685 return log_error_errno(r, "Failed to mangle unit name: %m");
d3b52baf 2686
f459b602
MAP
2687 path = unit_dbus_path_from_name(n);
2688 if (!path)
2689 return log_oom();
701cdcb9 2690
f459b602 2691 r = sd_bus_get_property_string(
d0a5cdb2
JJ
2692 bus,
2693 "org.freedesktop.systemd1",
f459b602
MAP
2694 path,
2695 "org.freedesktop.systemd1.Unit",
2696 "LoadState",
2697 &error,
fa0d5878 2698 &load_state);
691395d8
LP
2699 if (r < 0)
2700 return log_error_errno(r, "Failed to get load state of %s: %s", n, bus_error_message(&error, r));
d0a5cdb2 2701
fa0d5878 2702 if (streq(load_state, "masked"))
f459b602 2703 return 0;
701cdcb9 2704
f459b602
MAP
2705 r = sd_bus_get_property_strv(
2706 bus,
2707 "org.freedesktop.systemd1",
2708 path,
2709 "org.freedesktop.systemd1.Unit",
2710 "TriggeredBy",
2711 &error,
2712 &triggered_by);
691395d8
LP
2713 if (r < 0)
2714 return log_error_errno(r, "Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r));
701cdcb9 2715
f459b602 2716 STRV_FOREACH(i, triggered_by) {
fa0d5878 2717 r = get_state_one_unit(bus, *i, &active_state);
f647962d 2718 if (r < 0)
fa0d5878 2719 return r;
701cdcb9 2720
fa0d5878 2721 if (!IN_SET(active_state, UNIT_ACTIVE, UNIT_RELOADING))
f459b602 2722 continue;
60f9ba0b 2723
f459b602
MAP
2724 if (print_warning_label) {
2725 log_warning("Warning: Stopping %s, but it can still be activated by:", n);
2726 print_warning_label = false;
701cdcb9 2727 }
1c291cf3 2728
f459b602 2729 log_warning(" %s", *i);
701cdcb9 2730 }
f459b602
MAP
2731
2732 return 0;
701cdcb9
MS
2733}
2734
2fc9a280
LP
2735static const struct {
2736 const char *verb;
2737 const char *method;
2738} unit_actions[] = {
2739 { "start", "StartUnit" },
2740 { "stop", "StopUnit" },
2741 { "condstop", "StopUnit" },
2742 { "reload", "ReloadUnit" },
2743 { "restart", "RestartUnit" },
2744 { "try-restart", "TryRestartUnit" },
2745 { "condrestart", "TryRestartUnit" },
2746 { "reload-or-restart", "ReloadOrRestartUnit" },
aabf5d42 2747 { "try-reload-or-restart", "ReloadOrTryRestartUnit" },
2fc9a280
LP
2748 { "reload-or-try-restart", "ReloadOrTryRestartUnit" },
2749 { "condreload", "ReloadOrTryRestartUnit" },
2750 { "force-reload", "ReloadOrTryRestartUnit" }
2751};
2752
39602c39
TA
2753static const char *verb_to_method(const char *verb) {
2754 uint i;
2755
2756 for (i = 0; i < ELEMENTSOF(unit_actions); i++)
2757 if (streq_ptr(unit_actions[i].verb, verb))
2758 return unit_actions[i].method;
2759
2760 return "StartUnit";
2761}
2762
2763static const char *method_to_verb(const char *method) {
2764 uint i;
2765
2766 for (i = 0; i < ELEMENTSOF(unit_actions); i++)
2767 if (streq_ptr(unit_actions[i].method, method))
2768 return unit_actions[i].verb;
2769
2770 return "n/a";
2771}
2772
93a08841
MP
2773typedef struct {
2774 sd_bus_slot *match;
2775 sd_event *event;
2776 Set *unit_paths;
2777 bool any_failed;
2778} WaitContext;
2779
2780static void wait_context_free(WaitContext *c) {
2781 c->match = sd_bus_slot_unref(c->match);
2782 c->event = sd_event_unref(c->event);
6fa4160d 2783 c->unit_paths = set_free_free(c->unit_paths);
93a08841
MP
2784}
2785
2786static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
2787 WaitContext *c = userdata;
2788 const char *path;
2789 int r;
2790
2791 path = sd_bus_message_get_path(m);
2792 if (!set_contains(c->unit_paths, path))
2793 return 0;
2794
2795 /* Check if ActiveState changed to inactive/failed */
2796 /* (s interface, a{sv} changed_properties, as invalidated_properties) */
2797 r = sd_bus_message_skip(m, "s");
2798 if (r < 0)
2799 return bus_log_parse_error(r);
6fa4160d 2800
93a08841
MP
2801 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
2802 if (r < 0)
2803 return bus_log_parse_error(r);
2804
2805 while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
2806 const char *s;
93a08841
MP
2807
2808 r = sd_bus_message_read(m, "s", &s);
2809 if (r < 0)
2810 return bus_log_parse_error(r);
6fa4160d 2811
93a08841 2812 if (streq(s, "ActiveState")) {
6fa4160d
LP
2813 bool is_failed;
2814
93a08841
MP
2815 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "s");
2816 if (r < 0)
2817 return bus_log_parse_error(r);
6fa4160d 2818
93a08841
MP
2819 r = sd_bus_message_read(m, "s", &s);
2820 if (r < 0)
2821 return bus_log_parse_error(r);
6fa4160d 2822
93a08841
MP
2823 is_failed = streq(s, "failed");
2824 if (streq(s, "inactive") || is_failed) {
2825 log_debug("%s became %s, dropping from --wait tracking", path, s);
6fa4160d
LP
2826 free(set_remove(c->unit_paths, path));
2827 c->any_failed = c->any_failed || is_failed;
93a08841
MP
2828 } else
2829 log_debug("ActiveState on %s changed to %s", path, s);
6fa4160d 2830
93a08841
MP
2831 break; /* no need to dissect the rest of the message */
2832 } else {
2833 /* other property */
2834 r = sd_bus_message_skip(m, "v");
2835 if (r < 0)
2836 return bus_log_parse_error(r);
2837 }
2838 r = sd_bus_message_exit_container(m);
2839 if (r < 0)
2840 return bus_log_parse_error(r);
2841 }
2842 if (r < 0)
2843 return bus_log_parse_error(r);
2844
2845 if (set_isempty(c->unit_paths))
2846 sd_event_exit(c->event, EXIT_SUCCESS);
2847
2848 return 0;
2849}
2850
e4b61340 2851static int start_unit_one(
f459b602 2852 sd_bus *bus,
e4b61340
LP
2853 const char *method,
2854 const char *name,
2855 const char *mode,
f459b602 2856 sd_bus_error *error,
93a08841
MP
2857 BusWaitForJobs *w,
2858 WaitContext *wait_context) {
7e4249b9 2859
4afd3348 2860 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
45fb0699 2861 const char *path;
7e4249b9 2862 int r;
7e4249b9 2863
e4b61340
LP
2864 assert(method);
2865 assert(name);
2866 assert(mode);
22f4096c 2867 assert(error);
7e4249b9 2868
93a08841
MP
2869 if (wait_context) {
2870 _cleanup_free_ char *unit_path = NULL;
2871 const char* mt;
2872
2873 log_debug("Watching for property changes of %s", name);
2874 r = sd_bus_call_method(
2875 bus,
2876 "org.freedesktop.systemd1",
2877 "/org/freedesktop/systemd1",
2878 "org.freedesktop.systemd1.Manager",
2879 "RefUnit",
2880 error,
2881 NULL,
2882 "s", name);
2883 if (r < 0)
2884 return log_error_errno(r, "Failed to RefUnit %s: %s", name, bus_error_message(error, r));
2885
2886 unit_path = unit_dbus_path_from_name(name);
2887 if (!unit_path)
2888 return log_oom();
2889
2890 r = set_put_strdup(wait_context->unit_paths, unit_path);
2891 if (r < 0)
2892 return log_error_errno(r, "Failed to add unit path %s to set: %m", unit_path);
2893
2894 mt = strjoina("type='signal',"
2895 "interface='org.freedesktop.DBus.Properties',"
2896 "path='", unit_path, "',"
2897 "member='PropertiesChanged'");
2898 r = sd_bus_add_match(bus, &wait_context->match, mt, on_properties_changed, wait_context);
2899 if (r < 0)
2900 return log_error_errno(r, "Failed to add match for PropertiesChanged signal: %m");
2901 }
2902
e3e0314b 2903 log_debug("Calling manager for %s on %s, %s", method, name, mode);
342641fb 2904
6e646d22 2905 r = sd_bus_call_method(
f22f08cd 2906 bus,
b0193f1c
LP
2907 "org.freedesktop.systemd1",
2908 "/org/freedesktop/systemd1",
2909 "org.freedesktop.systemd1.Manager",
6e646d22
LP
2910 method,
2911 error,
2912 &reply,
2913 "ss", name, mode);
f459b602 2914 if (r < 0) {
39602c39
TA
2915 const char *verb;
2916
033f0ab8
LP
2917 /* There's always a fallback possible for legacy actions. */
2918 if (arg_action != ACTION_SYSTEMCTL)
2919 return r;
67f3c402 2920
39602c39
TA
2921 verb = method_to_verb(method);
2922
ee87525c
FB
2923 log_error("Failed to %s %s: %s", verb, name, bus_error_message(error, r));
2924
2925 if (!sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) &&
2926 !sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED))
a6405ca2 2927 log_error("See %s logs and 'systemctl%s status%s %s' for details.",
0b8505b7
RC
2928 arg_scope == UNIT_FILE_SYSTEM ? "system" : "user",
2929 arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
a6405ca2 2930 name[0] == '-' ? " --" : "",
0b8505b7 2931 name);
ee87525c
FB
2932
2933 return r;
7e4249b9
LP
2934 }
2935
f459b602
MAP
2936 r = sd_bus_message_read(reply, "o", &path);
2937 if (r < 0)
2938 return bus_log_parse_error(r);
45fb0699 2939
e3e0314b 2940 if (need_daemon_reload(bus, name) > 0)
3f36991e 2941 warn_unit_file_changed(name);
45fb0699 2942
ebd011d9
LP
2943 if (w) {
2944 log_debug("Adding %s to the set", path);
2945 r = bus_wait_for_jobs_add(w, path);
cbc9fbd1
LP
2946 if (r < 0)
2947 return log_oom();
e4b61340 2948 }
7e4249b9 2949
46eddbb5 2950 return 0;
7e4249b9
LP
2951}
2952
e3e0314b 2953static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) {
e3e0314b
ZJS
2954 _cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
2955 char **name;
7410616c 2956 int r, i;
e3e0314b 2957
4fbd7192
LP
2958 assert(bus);
2959 assert(ret);
2960
e3e0314b
ZJS
2961 STRV_FOREACH(name, names) {
2962 char *t;
2963
e80733be 2964 if (suffix)
7410616c 2965 r = unit_name_mangle_with_suffix(*name, UNIT_NAME_GLOB, suffix, &t);
e80733be 2966 else
7410616c
LP
2967 r = unit_name_mangle(*name, UNIT_NAME_GLOB, &t);
2968 if (r < 0)
2969 return log_error_errno(r, "Failed to mangle name: %m");
e3e0314b
ZJS
2970
2971 if (string_is_glob(t))
6e18964d 2972 r = strv_consume(&globs, t);
e3e0314b 2973 else
6e18964d
ZJS
2974 r = strv_consume(&mangled, t);
2975 if (r < 0)
e3e0314b 2976 return log_oom();
e3e0314b
ZJS
2977 }
2978
2979 /* Query the manager only if any of the names are a glob, since
2980 * this is fairly expensive */
2981 if (!strv_isempty(globs)) {
4afd3348 2982 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
e3e0314b 2983 _cleanup_free_ UnitInfo *unit_infos = NULL;
1b53f64b 2984 size_t allocated, n;
e3e0314b 2985
1238ee09 2986 r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
e3e0314b
ZJS
2987 if (r < 0)
2988 return r;
2989
1b53f64b
LP
2990 n = strv_length(mangled);
2991 allocated = n + 1;
2992
2993 for (i = 0; i < r; i++) {
2994 if (!GREEDY_REALLOC(mangled, allocated, n+2))
2995 return log_oom();
2996
2997 mangled[n] = strdup(unit_infos[i].id);
2998 if (!mangled[n])
e3e0314b 2999 return log_oom();
1b53f64b
LP
3000
3001 mangled[++n] = NULL;
3002 }
e3e0314b
ZJS
3003 }
3004
3005 *ret = mangled;
3006 mangled = NULL; /* do not free */
1238ee09 3007
e3e0314b
ZJS
3008 return 0;
3009}
3010
47a0eaa6
MS
3011static const struct {
3012 const char *target;
3013 const char *verb;
3014 const char *mode;
3015} action_table[_ACTION_MAX] = {
3016 [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" },
3017 [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
3018 [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" },
3019 [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" },
d5d8429a
LP
3020 [ACTION_RUNLEVEL2] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
3021 [ACTION_RUNLEVEL3] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
3022 [ACTION_RUNLEVEL4] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
3023 [ACTION_RUNLEVEL5] = { SPECIAL_GRAPHICAL_TARGET, NULL, "isolate" },
47a0eaa6
MS
3024 [ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" },
3025 [ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" },
3026 [ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" },
3027 [ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" },
3028 [ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" },
3029 [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" },
3030 [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
3031};
3032
514f4ef5 3033static enum action verb_to_action(const char *verb) {
47a0eaa6
MS
3034 enum action i;
3035
f459b602
MAP
3036 for (i = _ACTION_INVALID; i < _ACTION_MAX; i++)
3037 if (streq_ptr(action_table[i].verb, verb))
47a0eaa6 3038 return i;
514f4ef5 3039
f459b602
MAP
3040 return _ACTION_INVALID;
3041}
e4b61340 3042
e449de87 3043static int start_unit(int argc, char *argv[], void *userdata) {
ebd011d9 3044 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
08073121 3045 const char *method, *mode, *one_name, *suffix = NULL;
ebd011d9 3046 _cleanup_strv_free_ char **names = NULL;
4fbd7192 3047 sd_bus *bus;
93a08841 3048 _cleanup_(wait_context_free) WaitContext wait_context = {};
729e3769 3049 char **name;
b6520546 3050 int r = 0;
e4b61340 3051
93a08841
MP
3052 if (arg_wait && !strstr(argv[0], "start")) {
3053 log_error("--wait may only be used with a command that starts units.");
3054 return -EINVAL;
3055 }
3056
3057 /* we cannot do sender tracking on the private bus, so we need the full
3058 * one for RefUnit to implement --wait */
3059 r = acquire_bus(arg_wait ? BUS_FULL : BUS_MANAGER, &bus);
4fbd7192
LP
3060 if (r < 0)
3061 return r;
3062
d2ad7e1b
ZJS
3063 ask_password_agent_open_if_enabled();
3064 polkit_agent_open_if_enabled();
3065
e4b61340 3066 if (arg_action == ACTION_SYSTEMCTL) {
47a0eaa6 3067 enum action action;
e4b61340 3068
e449de87
LP
3069 method = verb_to_method(argv[0]);
3070 action = verb_to_action(argv[0]);
3071
3072 if (streq(argv[0], "isolate")) {
08073121
LP
3073 mode = "isolate";
3074 suffix = ".target";
3075 } else
3076 mode = action_table[action].mode ?: arg_job_mode;
e4b61340 3077
e3e0314b 3078 one_name = action_table[action].target;
e4b61340 3079 } else {
47a0eaa6
MS
3080 assert(arg_action < ELEMENTSOF(action_table));
3081 assert(action_table[arg_action].target);
e4b61340
LP
3082
3083 method = "StartUnit";
514f4ef5 3084
47a0eaa6 3085 mode = action_table[arg_action].mode;
e3e0314b 3086 one_name = action_table[arg_action].target;
514f4ef5
LP
3087 }
3088
e3e0314b
ZJS
3089 if (one_name)
3090 names = strv_new(one_name, NULL);
3091 else {
e449de87 3092 r = expand_names(bus, strv_skip(argv, 1), suffix, &names);
e3e0314b 3093 if (r < 0)
691395d8 3094 return log_error_errno(r, "Failed to expand names: %m");
e3e0314b 3095 }
b6520546 3096
6e905d93 3097 if (!arg_no_block) {
ebd011d9 3098 r = bus_wait_for_jobs_new(bus, &w);
f647962d
MS
3099 if (r < 0)
3100 return log_error_errno(r, "Could not watch jobs: %m");
e4b61340
LP
3101 }
3102
93a08841
MP
3103 if (arg_wait) {
3104 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
3105
3106 wait_context.unit_paths = set_new(&string_hash_ops);
3107 if (!wait_context.unit_paths)
3108 return log_oom();
3109
3110 r = sd_bus_call_method(
3111 bus,
3112 "org.freedesktop.systemd1",
3113 "/org/freedesktop/systemd1",
3114 "org.freedesktop.systemd1.Manager",
3115 "Subscribe",
3116 &error,
3117 NULL, NULL);
3118 if (r < 0)
3119 return log_error_errno(r, "Failed to enable subscription: %s", bus_error_message(&error, r));
3120 r = sd_event_default(&wait_context.event);
3121 if (r < 0)
3122 return log_error_errno(r, "Failed to allocate event loop: %m");
3123 r = sd_bus_attach_event(bus, wait_context.event, 0);
3124 if (r < 0)
3125 return log_error_errno(r, "Failed to attach bus to event loop: %m");
3126 }
3127
b6520546 3128 STRV_FOREACH(name, names) {
4afd3348 3129 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
b6520546 3130 int q;
f459b602 3131
93a08841 3132 q = start_unit_one(bus, method, *name, mode, &error, w, arg_wait ? &wait_context : NULL);
e3e0314b 3133 if (r >= 0 && q < 0)
b6520546 3134 r = translate_bus_error_to_exit_status(q, &error);
e4b61340
LP
3135 }
3136
67f3c402 3137 if (!arg_no_block) {
c11bda1e
ZJS
3138 int q, arg_count = 0;
3139 const char* extra_args[4] = {};
4524439e 3140
4524439e
ZJS
3141 if (arg_scope != UNIT_FILE_SYSTEM)
3142 extra_args[arg_count++] = "--user";
3143
3144 assert(IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_REMOTE, BUS_TRANSPORT_MACHINE));
3145 if (arg_transport == BUS_TRANSPORT_REMOTE) {
3146 extra_args[arg_count++] = "-H";
3147 extra_args[arg_count++] = arg_host;
3148 } else if (arg_transport == BUS_TRANSPORT_MACHINE) {
3149 extra_args[arg_count++] = "-M";
3150 extra_args[arg_count++] = arg_host;
3151 }
f459b602 3152
4524439e 3153 q = bus_wait_for_jobs(w, arg_quiet, extra_args);
f459b602
MAP
3154 if (q < 0)
3155 return q;
49111a70
ZJS
3156
3157 /* When stopping units, warn if they can still be triggered by
3158 * another active unit (socket, path, timer) */
b6520546
ZJS
3159 if (!arg_quiet && streq(method, "StopUnit"))
3160 STRV_FOREACH(name, names)
3161 check_triggering_units(bus, *name);
67f3c402 3162 }
514f4ef5 3163
93a08841
MP
3164 if (r >= 0 && arg_wait) {
3165 int q;
3166 q = sd_event_loop(wait_context.event);
3167 if (q < 0)
3168 return log_error_errno(q, "Failed to run event loop: %m");
3169 if (wait_context.any_failed)
3170 r = EXIT_FAILURE;
3171 }
3172
f459b602 3173 return r;
e4b61340
LP
3174}
3175
4fbd7192 3176static int logind_set_wall_message(void) {
f2d11d35 3177#ifdef HAVE_LOGIND
4afd3348 3178 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192 3179 sd_bus *bus;
f2d11d35
LP
3180 _cleanup_free_ char *m = NULL;
3181 int r;
3182
4fbd7192
LP
3183 r = acquire_bus(BUS_FULL, &bus);
3184 if (r < 0)
3185 return r;
f2d11d35
LP
3186
3187 m = strv_join(arg_wall, " ");
3188 if (!m)
3189 return log_oom();
3190
3191 r = sd_bus_call_method(
3192 bus,
3193 "org.freedesktop.login1",
3194 "/org/freedesktop/login1",
3195 "org.freedesktop.login1.Manager",
3196 "SetWallMessage",
3197 &error,
3198 NULL,
3199 "sb",
3200 m,
3201 !arg_no_wall);
3202
3203 if (r < 0)
3204 return log_warning_errno(r, "Failed to set wall message, ignoring: %s", bus_error_message(&error, r));
3205
3206#endif
3207 return 0;
3208}
3209
7e59bfcb
LP
3210/* Ask systemd-logind, which might grant access to unprivileged users
3211 * through PolicyKit */
4fbd7192 3212static int logind_reboot(enum action a) {
4c80c73c 3213#ifdef HAVE_LOGIND
4afd3348 3214 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
58158dc7 3215 const char *method, *description;
4fbd7192 3216 sd_bus *bus;
f459b602 3217 int r;
4c80c73c 3218
4fbd7192
LP
3219 r = acquire_bus(BUS_FULL, &bus);
3220 if (r < 0)
3221 return r;
f2d11d35 3222
4c80c73c
KS
3223 switch (a) {
3224
3225 case ACTION_REBOOT:
3226 method = "Reboot";
58158dc7 3227 description = "reboot system";
4c80c73c
KS
3228 break;
3229
3230 case ACTION_POWEROFF:
3231 method = "PowerOff";
58158dc7 3232 description = "power off system";
4c80c73c
KS
3233 break;
3234
d889a206
LP
3235 case ACTION_SUSPEND:
3236 method = "Suspend";
58158dc7 3237 description = "suspend system";
d889a206
LP
3238 break;
3239
3240 case ACTION_HIBERNATE:
3241 method = "Hibernate";
58158dc7 3242 description = "hibernate system";
d889a206
LP
3243 break;
3244
6524990f
LP
3245 case ACTION_HYBRID_SLEEP:
3246 method = "HybridSleep";
58158dc7 3247 description = "put system into hybrid sleep";
6524990f
LP
3248 break;
3249
4c80c73c
KS
3250 default:
3251 return -EINVAL;
3252 }
3253
d2ad7e1b
ZJS
3254 polkit_agent_open_if_enabled();
3255 (void) logind_set_wall_message();
3256
f459b602 3257 r = sd_bus_call_method(
f22f08cd
SP
3258 bus,
3259 "org.freedesktop.login1",
3260 "/org/freedesktop/login1",
3261 "org.freedesktop.login1.Manager",
3262 method,
f459b602 3263 &error,
f22f08cd 3264 NULL,
342641fb 3265 "b", arg_ask_password);
f459b602 3266 if (r < 0)
691395d8 3267 return log_error_errno(r, "Failed to %s via logind: %s", description, bus_error_message(&error, r));
f459b602 3268
691395d8 3269 return 0;
4c80c73c
KS
3270#else
3271 return -ENOSYS;
3272#endif
3273}
3274
4fbd7192 3275static int logind_check_inhibitors(enum action a) {
b37844d3 3276#ifdef HAVE_LOGIND
4afd3348 3277 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
59164be4 3278 _cleanup_strv_free_ char **sessions = NULL;
f459b602
MAP
3279 const char *what, *who, *why, *mode;
3280 uint32_t uid, pid;
4fbd7192 3281 sd_bus *bus;
f459b602 3282 unsigned c = 0;
59164be4 3283 char **s;
f459b602 3284 int r;
b37844d3 3285
748ebafa
LP
3286 if (arg_ignore_inhibitors || arg_force > 0)
3287 return 0;
3288
3289 if (arg_when > 0)
3290 return 0;
3291
3292 if (geteuid() == 0)
b37844d3
LP
3293 return 0;
3294
3295 if (!on_tty())
3296 return 0;
e08ab379
LP
3297
3298 if (arg_transport != BUS_TRANSPORT_LOCAL)
3299 return 0;
b37844d3 3300
4fbd7192
LP
3301 r = acquire_bus(BUS_FULL, &bus);
3302 if (r < 0)
3303 return r;
3304
f459b602 3305 r = sd_bus_call_method(
b37844d3
LP
3306 bus,
3307 "org.freedesktop.login1",
3308 "/org/freedesktop/login1",
3309 "org.freedesktop.login1.Manager",
3310 "ListInhibitors",
b37844d3 3311 NULL,
f459b602
MAP
3312 &reply,
3313 NULL);
b37844d3
LP
3314 if (r < 0)
3315 /* If logind is not around, then there are no inhibitors... */
3316 return 0;
3317
4aa2beac 3318 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
f459b602
MAP
3319 if (r < 0)
3320 return bus_log_parse_error(r);
b37844d3 3321
4aa2beac 3322 while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
59164be4 3323 _cleanup_free_ char *comm = NULL, *user = NULL;
f459b602 3324 _cleanup_strv_free_ char **sv = NULL;
b37844d3
LP
3325
3326 if (!streq(mode, "block"))
f459b602 3327 continue;
b37844d3
LP
3328
3329 sv = strv_split(what, ":");
3330 if (!sv)
3331 return log_oom();
3332
d028e018
ZJS
3333 if ((pid_t) pid < 0)
3334 return log_error_errno(ERANGE, "Bad PID %"PRIu32": %m", pid);
3335
b37844d3 3336 if (!strv_contains(sv,
4c315c2c
IS
3337 IN_SET(a,
3338 ACTION_HALT,
3339 ACTION_POWEROFF,
3340 ACTION_REBOOT,
3341 ACTION_KEXEC) ? "shutdown" : "sleep"))
f459b602 3342 continue;
b37844d3
LP
3343
3344 get_process_comm(pid, &comm);
59164be4 3345 user = uid_to_name(uid);
f459b602 3346
de0671ee 3347 log_warning("Operation inhibited by \"%s\" (PID "PID_FMT" \"%s\", user %s), reason is \"%s\".",
d028e018 3348 who, (pid_t) pid, strna(comm), strna(user), why);
b37844d3 3349
f459b602 3350 c++;
b37844d3 3351 }
f459b602
MAP
3352 if (r < 0)
3353 return bus_log_parse_error(r);
b37844d3 3354
f459b602
MAP
3355 r = sd_bus_message_exit_container(reply);
3356 if (r < 0)
3357 return bus_log_parse_error(r);
b37844d3 3358
59164be4
LP
3359 /* Check for current sessions */
3360 sd_get_sessions(&sessions);
3361 STRV_FOREACH(s, sessions) {
59164be4
LP
3362 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
3363
3364 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
3365 continue;
3366
3367 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
3368 continue;
3369
72240b52 3370 if (sd_session_get_type(*s, &type) < 0 || !STR_IN_SET(type, "x11", "tty"))
59164be4
LP
3371 continue;
3372
3373 sd_session_get_tty(*s, &tty);
3374 sd_session_get_seat(*s, &seat);
3375 sd_session_get_service(*s, &service);
3376 user = uid_to_name(uid);
3377
3378 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
3379 c++;
3380 }
3381
b37844d3
LP
3382 if (c <= 0)
3383 return 0;
3384
59164be4 3385 log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
47a0eaa6 3386 action_table[a].verb);
b37844d3
LP
3387
3388 return -EPERM;
3389#else
3390 return 0;
3391#endif
3392}
3393
4fbd7192 3394static int logind_prepare_firmware_setup(void) {
a4921cf4 3395#ifdef HAVE_LOGIND
4afd3348 3396 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192 3397 sd_bus *bus;
a4921cf4
JJ
3398 int r;
3399
4fbd7192
LP
3400 r = acquire_bus(BUS_FULL, &bus);
3401 if (r < 0)
3402 return r;
a4921cf4 3403
a4921cf4
JJ
3404 r = sd_bus_call_method(
3405 bus,
3406 "org.freedesktop.login1",
3407 "/org/freedesktop/login1",
3408 "org.freedesktop.login1.Manager",
3409 "SetRebootToFirmwareSetup",
3410 &error,
3411 NULL,
3412 "b", true);
4fbd7192
LP
3413 if (r < 0)
3414 return log_error_errno(r, "Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
a4921cf4
JJ
3415
3416 return 0;
3417#else
3418 log_error("Cannot remotely indicate to EFI to boot into setup mode.");
4fbd7192 3419 return -ENOSYS;
a4921cf4
JJ
3420#endif
3421}
3422
4fbd7192
LP
3423static int prepare_firmware_setup(void) {
3424 int r;
3425
3426 if (!arg_firmware_setup)
3427 return 0;
3428
3429 if (arg_transport == BUS_TRANSPORT_LOCAL) {
3430
3431 r = efi_set_reboot_to_firmware(true);
3432 if (r < 0)
3433 log_debug_errno(r, "Cannot indicate to EFI to boot into setup mode, will retry via logind: %m");
3434 else
3435 return r;
3436 }
3437
3438 return logind_prepare_firmware_setup();
3439}
3440
57ab9006 3441static int set_exit_code(uint8_t code) {
4afd3348 3442 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
57ab9006
LP
3443 sd_bus *bus;
3444 int r;
3445
3446 r = acquire_bus(BUS_MANAGER, &bus);
3447 if (r < 0)
3448 return r;
3449
3450 r = sd_bus_call_method(
3451 bus,
3452 "org.freedesktop.systemd1",
3453 "/org/freedesktop/systemd1",
3454 "org.freedesktop.systemd1.Manager",
3455 "SetExitCode",
3456 &error,
3457 NULL,
3458 "y", code);
3459 if (r < 0)
af3d8113 3460 return log_error_errno(r, "Failed to set exit code: %s", bus_error_message(&error, r));
57ab9006
LP
3461
3462 return 0;
3463}
3464
e449de87 3465static int start_special(int argc, char *argv[], void *userdata) {
4c80c73c 3466 enum action a;
983d9c90
LP
3467 int r;
3468
e449de87 3469 assert(argv);
514f4ef5 3470
e449de87 3471 a = verb_to_action(argv[0]);
4c80c73c 3472
4fbd7192 3473 r = logind_check_inhibitors(a);
748ebafa
LP
3474 if (r < 0)
3475 return r;
3476
c32b90de
LP
3477 if (arg_force >= 2 && geteuid() != 0) {
3478 log_error("Must be root.");
3479 return -EPERM;
3480 }
3481
4fbd7192 3482 r = prepare_firmware_setup();
a4921cf4
JJ
3483 if (r < 0)
3484 return r;
5bdf2243 3485
e449de87 3486 if (a == ACTION_REBOOT && argc > 1) {
27c06cb5 3487 r = update_reboot_parameter_and_warn(argv[1]);
b986229e
SW
3488 if (r < 0)
3489 return r;
57ab9006 3490
e449de87 3491 } else if (a == ACTION_EXIT && argc > 1) {
7bbb5359 3492 uint8_t code;
287419c1 3493
57ab9006
LP
3494 /* If the exit code is not given on the command line,
3495 * don't reset it to zero: just keep it as it might
3496 * have been set previously. */
287419c1 3497
e449de87 3498 r = safe_atou8(argv[1], &code);
4fbd7192 3499 if (r < 0)
57ab9006 3500 return log_error_errno(r, "Invalid exit code.");
4fbd7192 3501
57ab9006 3502 r = set_exit_code(code);
691395d8 3503 if (r < 0)
57ab9006 3504 return r;
b986229e
SW
3505 }
3506
7e59bfcb 3507 if (arg_force >= 2 &&
4c315c2c
IS
3508 IN_SET(a,
3509 ACTION_HALT,
3510 ACTION_POWEROFF,
3511 ACTION_REBOOT))
477def80 3512 return halt_now(a);
e606bb61 3513
7e59bfcb 3514 if (arg_force >= 1 &&
4c315c2c
IS
3515 IN_SET(a,
3516 ACTION_HALT,
3517 ACTION_POWEROFF,
3518 ACTION_REBOOT,
3519 ACTION_KEXEC,
3520 ACTION_EXIT))
2853b60a 3521 return trivial_method(argc, argv, userdata);
20b09ca7 3522
7089051f
LP
3523 /* First try logind, to allow authentication with polkit */
3524 if (IN_SET(a,
4c315c2c
IS
3525 ACTION_POWEROFF,
3526 ACTION_REBOOT,
3527 ACTION_SUSPEND,
3528 ACTION_HIBERNATE,
3529 ACTION_HYBRID_SLEEP)) {
4fbd7192 3530 r = logind_reboot(a);
a9085ea3 3531 if (r >= 0)
7e59bfcb 3532 return r;
a9085ea3
IS
3533 if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
3534 /* requested operation is not supported or already in progress */
3535 return r;
7089051f
LP
3536
3537 /* On all other errors, try low-level operation */
4c80c73c 3538 }
983d9c90 3539
e449de87 3540 return start_unit(argc, argv, userdata);
514f4ef5
LP
3541}
3542
988b3b17
ZJS
3543static int start_system_special(int argc, char *argv[], void *userdata) {
3544 /* Like start_special above, but raises an error when running in user mode */
3545
3546 if (arg_scope != UNIT_FILE_SYSTEM) {
3547 log_error("Bad action for %s mode.",
3548 arg_scope == UNIT_FILE_GLOBAL ? "--global" : "--user");
3549 return -EINVAL;
3550 }
3551
3552 return start_special(argc, argv, userdata);
3553}
3554
fa0d5878 3555static int check_unit_generic(int code, const UnitActiveState good_states[], int nb_states, char **args) {
e3e0314b 3556 _cleanup_strv_free_ char **names = NULL;
fa0d5878 3557 UnitActiveState active_state;
4fbd7192 3558 sd_bus *bus;
729e3769 3559 char **name;
fa0d5878 3560 int r, i;
d60f6ad0 3561 bool found = false;
0183528f 3562
4fbd7192
LP
3563 r = acquire_bus(BUS_MANAGER, &bus);
3564 if (r < 0)
3565 return r;
3566
e3e0314b 3567 r = expand_names(bus, args, NULL, &names);
f647962d
MS
3568 if (r < 0)
3569 return log_error_errno(r, "Failed to expand names: %m");
e3e0314b
ZJS
3570
3571 STRV_FOREACH(name, names) {
fa0d5878
BR
3572 r = get_state_one_unit(bus, *name, &active_state);
3573 if (r < 0)
3574 return r;
3575
3576 if (!arg_quiet)
3577 puts(unit_active_state_to_string(active_state));
60f9ba0b 3578
fa0d5878
BR
3579 for (i = 0; i < nb_states; ++i)
3580 if (good_states[i] == active_state)
3581 found = true;
1a0fce45
TA
3582 }
3583
d60f6ad0
LN
3584 /* use the given return code for the case that we won't find
3585 * any unit which matches the list */
3586 return found ? 0 : code;
1a0fce45
TA
3587}
3588
e449de87 3589static int check_unit_active(int argc, char *argv[], void *userdata) {
fa0d5878 3590 const UnitActiveState states[] = { UNIT_ACTIVE, UNIT_RELOADING };
e3e0314b 3591 /* According to LSB: 3, "program is not running" */
b613907e 3592 return check_unit_generic(EXIT_PROGRAM_NOT_RUNNING, states, ELEMENTSOF(states), strv_skip(argv, 1));
e3e0314b 3593}
0183528f 3594
e449de87 3595static int check_unit_failed(int argc, char *argv[], void *userdata) {
fa0d5878 3596 const UnitActiveState states[] = { UNIT_FAILED };
b613907e 3597 return check_unit_generic(EXIT_PROGRAM_DEAD_AND_PID_EXISTS, states, ELEMENTSOF(states), strv_skip(argv, 1));
48220598
LP
3598}
3599
e449de87 3600static int kill_unit(int argc, char *argv[], void *userdata) {
e3e0314b 3601 _cleanup_strv_free_ char **names = NULL;
ac5e3a50 3602 char *kill_who = NULL, **name;
4fbd7192 3603 sd_bus *bus;
e3e0314b 3604 int r, q;
8a0867d6 3605
4fbd7192
LP
3606 r = acquire_bus(BUS_MANAGER, &bus);
3607 if (r < 0)
3608 return r;
3609
d2ad7e1b
ZJS
3610 polkit_agent_open_if_enabled();
3611
8a0867d6
LP
3612 if (!arg_kill_who)
3613 arg_kill_who = "all";
3614
ac5e3a50
JS
3615 /* --fail was specified */
3616 if (streq(arg_job_mode, "fail"))
81d62103 3617 kill_who = strjoina(arg_kill_who, "-fail");
ac5e3a50 3618
e449de87 3619 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
e3e0314b 3620 if (r < 0)
691395d8 3621 return log_error_errno(r, "Failed to expand names: %m");
60f9ba0b 3622
e3e0314b 3623 STRV_FOREACH(name, names) {
4afd3348 3624 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
342641fb 3625
6e646d22 3626 q = sd_bus_call_method(
f22f08cd 3627 bus,
b0193f1c
LP
3628 "org.freedesktop.systemd1",
3629 "/org/freedesktop/systemd1",
3630 "org.freedesktop.systemd1.Manager",
6e646d22
LP
3631 "KillUnit",
3632 &error,
3633 NULL,
169d7fb6 3634 "ssi", *name, kill_who ? kill_who : arg_kill_who, arg_signal);
e3e0314b 3635 if (q < 0) {
169d7fb6 3636 log_error_errno(q, "Failed to kill unit %s: %s", *name, bus_error_message(&error, q));
e3e0314b
ZJS
3637 if (r == 0)
3638 r = q;
f459b602 3639 }
8a0867d6 3640 }
f459b602 3641
e3e0314b 3642 return r;
8a0867d6
LP
3643}
3644
582a507f 3645typedef struct ExecStatusInfo {
0129173a
LP
3646 char *name;
3647
582a507f
LP
3648 char *path;
3649 char **argv;
3650
b708e7ce
LP
3651 bool ignore;
3652
582a507f
LP
3653 usec_t start_timestamp;
3654 usec_t exit_timestamp;
3655 pid_t pid;
3656 int code;
3657 int status;
3658
3659 LIST_FIELDS(struct ExecStatusInfo, exec);
3660} ExecStatusInfo;
3661
3662static void exec_status_info_free(ExecStatusInfo *i) {
3663 assert(i);
3664
0129173a 3665 free(i->name);
582a507f
LP
3666 free(i->path);
3667 strv_free(i->argv);
3668 free(i);
3669}
3670
f459b602 3671static int exec_status_info_deserialize(sd_bus_message *m, ExecStatusInfo *i) {
b21a0ef8 3672 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
f459b602 3673 const char *path;
582a507f
LP
3674 uint32_t pid;
3675 int32_t code, status;
f459b602 3676 int ignore, r;
582a507f 3677
f459b602 3678 assert(m);
582a507f 3679 assert(i);
582a507f 3680
f459b602
MAP
3681 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, "sasbttttuii");
3682 if (r < 0)
3683 return bus_log_parse_error(r);
3684 else if (r == 0)
3685 return 0;
582a507f 3686
f459b602
MAP
3687 r = sd_bus_message_read(m, "s", &path);
3688 if (r < 0)
3689 return bus_log_parse_error(r);
582a507f 3690
f84190d8
LP
3691 i->path = strdup(path);
3692 if (!i->path)
f459b602 3693 return log_oom();
582a507f 3694
f459b602
MAP
3695 r = sd_bus_message_read_strv(m, &i->argv);
3696 if (r < 0)
3697 return bus_log_parse_error(r);
3698
3699 r = sd_bus_message_read(m,
3700 "bttttuii",
3701 &ignore,
3702 &start_timestamp, &start_timestamp_monotonic,
3703 &exit_timestamp, &exit_timestamp_monotonic,
3704 &pid,
3705 &code, &status);
3706 if (r < 0)
3707 return bus_log_parse_error(r);
582a507f 3708
b708e7ce 3709 i->ignore = ignore;
582a507f
LP
3710 i->start_timestamp = (usec_t) start_timestamp;
3711 i->exit_timestamp = (usec_t) exit_timestamp;
3712 i->pid = (pid_t) pid;
3713 i->code = code;
3714 i->status = status;
3715
f459b602
MAP
3716 r = sd_bus_message_exit_container(m);
3717 if (r < 0)
3718 return bus_log_parse_error(r);
3719
3720 return 1;
582a507f
LP
3721}
3722
d5db7fe6
WC
3723typedef struct UnitCondition {
3724 char *name;
b1ed76ae 3725 char *param;
d5db7fe6
WC
3726 bool trigger;
3727 bool negate;
d5db7fe6
WC
3728 int tristate;
3729
b1ed76ae 3730 LIST_FIELDS(struct UnitCondition, conditions);
d5db7fe6
WC
3731} UnitCondition;
3732
3733static void unit_condition_free(UnitCondition *c) {
9bb71940
ZJS
3734 if (!c)
3735 return;
d5db7fe6
WC
3736
3737 free(c->name);
3738 free(c->param);
3739 free(c);
3740}
3741
9bb71940
ZJS
3742DEFINE_TRIVIAL_CLEANUP_FUNC(UnitCondition*, unit_condition_free);
3743
61cbdc4b
LP
3744typedef struct UnitStatusInfo {
3745 const char *id;
3746 const char *load_state;
3747 const char *active_state;
3748 const char *sub_state;
a4375746 3749 const char *unit_file_state;
d2dc52db 3750 const char *unit_file_preset;
61cbdc4b
LP
3751
3752 const char *description;
4a9e2fff 3753 const char *following;
61cbdc4b 3754
49dbfa7b
LP
3755 char **documentation;
3756
1b64d026
LP
3757 const char *fragment_path;
3758 const char *source_path;
4ad49000 3759 const char *control_group;
61cbdc4b 3760
76d14b87
OS
3761 char **dropin_paths;
3762
9f39404c 3763 const char *load_error;
f42806df 3764 const char *result;
9f39404c 3765
584be568 3766 usec_t inactive_exit_timestamp;
df50185b 3767 usec_t inactive_exit_timestamp_monotonic;
584be568
LP
3768 usec_t active_enter_timestamp;
3769 usec_t active_exit_timestamp;
3770 usec_t inactive_enter_timestamp;
3771
45fb0699 3772 bool need_daemon_reload;
055ef36b 3773 bool transient;
45fb0699 3774
61cbdc4b
LP
3775 /* Service */
3776 pid_t main_pid;
3777 pid_t control_pid;
3778 const char *status_text;
175728c4 3779 const char *pid_file;
d06dacd0 3780 bool running:1;
b4af5a80 3781 int status_errno;
61cbdc4b
LP
3782
3783 usec_t start_timestamp;
3784 usec_t exit_timestamp;
3785
3786 int exit_code, exit_status;
3787
90bbc946
LP
3788 usec_t condition_timestamp;
3789 bool condition_result;
b1ed76ae 3790 LIST_HEAD(UnitCondition, conditions);
59fccdc5
LP
3791
3792 usec_t assert_timestamp;
3793 bool assert_result;
3794 bool failed_assert_trigger;
3795 bool failed_assert_negate;
3796 const char *failed_assert;
3797 const char *failed_assert_parameter;
90bbc946 3798
61cbdc4b
LP
3799 /* Socket */
3800 unsigned n_accepted;
3801 unsigned n_connections;
b8131a87 3802 bool accept;
61cbdc4b 3803
13160134 3804 /* Pairs of type, path */
67419600
OS
3805 char **listen;
3806
61cbdc4b
LP
3807 /* Device */
3808 const char *sysfs_path;
3809
3810 /* Mount, Automount */
3811 const char *where;
3812
3813 /* Swap */
3814 const char *what;
582a507f 3815
934277fe
LP
3816 /* CGroup */
3817 uint64_t memory_current;
da4d897e
TH
3818 uint64_t memory_low;
3819 uint64_t memory_high;
3820 uint64_t memory_max;
96e131ea 3821 uint64_t memory_swap_max;
934277fe 3822 uint64_t memory_limit;
5ad096b3 3823 uint64_t cpu_usage_nsec;
03a7b521
LP
3824 uint64_t tasks_current;
3825 uint64_t tasks_max;
934277fe 3826
582a507f 3827 LIST_HEAD(ExecStatusInfo, exec);
61cbdc4b
LP
3828} UnitStatusInfo;
3829
a7335518
ZJS
3830static void unit_status_info_free(UnitStatusInfo *info) {
3831 ExecStatusInfo *p;
3832 UnitCondition *c;
3833
3834 strv_free(info->documentation);
3835 strv_free(info->dropin_paths);
3836 strv_free(info->listen);
3837
3838 while ((c = info->conditions)) {
3839 LIST_REMOVE(conditions, info->conditions, c);
3840 unit_condition_free(c);
3841 }
3842
3843 while ((p = info->exec)) {
3844 LIST_REMOVE(exec, info->exec, p);
3845 exec_status_info_free(p);
3846 }
3847}
3848
f459b602 3849static void print_status_info(
291d565a 3850 sd_bus *bus,
f459b602
MAP
3851 UnitStatusInfo *i,
3852 bool *ellipsized) {
3853
582a507f 3854 ExecStatusInfo *p;
b0d14c69 3855 const char *active_on, *active_off, *on, *off, *ss;
584be568 3856 usec_t timestamp;
9185c8e6 3857 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
584be568 3858 char since2[FORMAT_TIMESTAMP_MAX], *s2;
1b64d026 3859 const char *path;
13160134 3860 char **t, **t2;
291d565a 3861 int r;
582a507f 3862
61cbdc4b
LP
3863 assert(i);
3864
3865 /* This shows pretty information about a unit. See
3866 * print_property() for a low-level property printer */
3867
b0d14c69
LP
3868 if (streq_ptr(i->active_state, "failed")) {
3869 active_on = ansi_highlight_red();
1fc464f6 3870 active_off = ansi_normal();
1cf03a4f 3871 } else if (STRPTR_IN_SET(i->active_state, "active", "reloading")) {
b0d14c69 3872 active_on = ansi_highlight_green();
1fc464f6 3873 active_off = ansi_normal();
b0d14c69
LP
3874 } else
3875 active_on = active_off = "";
3876
323b7dc9 3877 printf("%s%s%s %s", active_on, special_glyph(BLACK_CIRCLE), active_off, strna(i->id));
61cbdc4b
LP
3878
3879 if (i->description && !streq_ptr(i->id, i->description))
3880 printf(" - %s", i->description);
3881
3882 printf("\n");
3883
4a9e2fff 3884 if (i->following)
856323c9 3885 printf(" Follow: unit currently follows state of %s\n", i->following);
4a9e2fff 3886
f7b9e331 3887 if (streq_ptr(i->load_state, "error")) {
0b5a519c 3888 on = ansi_highlight_red();
1fc464f6 3889 off = ansi_normal();
c31b4423
LP
3890 } else
3891 on = off = "";
3892
1b64d026
LP
3893 path = i->source_path ? i->source_path : i->fragment_path;
3894
055ef36b 3895 if (i->load_error != 0)
856323c9
ZJS
3896 printf(" Loaded: %s%s%s (Reason: %s)\n",
3897 on, strna(i->load_state), off, i->load_error);
d2dc52db
LP
3898 else if (path && !isempty(i->unit_file_state) && !isempty(i->unit_file_preset))
3899 printf(" Loaded: %s%s%s (%s; %s; vendor preset: %s)\n",
3900 on, strna(i->load_state), off, path, i->unit_file_state, i->unit_file_preset);
3901 else if (path && !isempty(i->unit_file_state))
856323c9
ZJS
3902 printf(" Loaded: %s%s%s (%s; %s)\n",
3903 on, strna(i->load_state), off, path, i->unit_file_state);
1b64d026 3904 else if (path)
856323c9
ZJS
3905 printf(" Loaded: %s%s%s (%s)\n",
3906 on, strna(i->load_state), off, path);
61cbdc4b 3907 else
856323c9
ZJS
3908 printf(" Loaded: %s%s%s\n",
3909 on, strna(i->load_state), off);
61cbdc4b 3910
055ef36b
LP
3911 if (i->transient)
3912 printf("Transient: yes\n");
3913
76d14b87 3914 if (!strv_isempty(i->dropin_paths)) {
f459b602 3915 _cleanup_free_ char *dir = NULL;
76d14b87 3916 bool last = false;
f459b602 3917 char ** dropin;
76d14b87
OS
3918
3919 STRV_FOREACH(dropin, i->dropin_paths) {
3920 if (! dir || last) {
856323c9 3921 printf(dir ? " " : " Drop-In: ");
76d14b87 3922
97b11eed 3923 dir = mfree(dir);
76d14b87 3924
5f311f8c
LP
3925 dir = dirname_malloc(*dropin);
3926 if (!dir) {
76d14b87
OS
3927 log_oom();
3928 return;
3929 }
3930
856323c9 3931 printf("%s\n %s", dir,
323b7dc9 3932 special_glyph(TREE_RIGHT));
76d14b87
OS
3933 }
3934
3935 last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
3936
2b6bf07d 3937 printf("%s%s", basename(*dropin), last ? "\n" : ", ");
76d14b87 3938 }
76d14b87
OS
3939 }
3940
2ee68f72 3941 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2ee68f72 3942 if (ss)
856323c9 3943 printf(" Active: %s%s (%s)%s",
b0d14c69 3944 active_on, strna(i->active_state), ss, active_off);
2ee68f72 3945 else
856323c9 3946 printf(" Active: %s%s%s",
b0d14c69 3947 active_on, strna(i->active_state), active_off);
61cbdc4b 3948
f42806df
LP
3949 if (!isempty(i->result) && !streq(i->result, "success"))
3950 printf(" (Result: %s)", i->result);
3951
1cf03a4f
ZJS
3952 timestamp = STRPTR_IN_SET(i->active_state, "active", "reloading") ? i->active_enter_timestamp :
3953 STRPTR_IN_SET(i->active_state, "inactive", "failed") ? i->inactive_enter_timestamp :
3954 STRPTR_IN_SET(i->active_state, "activating") ? i->inactive_exit_timestamp :
3955 i->active_exit_timestamp;
584be568 3956
bbb8486e 3957 s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
584be568
LP
3958 s2 = format_timestamp(since2, sizeof(since2), timestamp);
3959
3960 if (s1)
538da63d 3961 printf(" since %s; %s\n", s2, s1);
584be568 3962 else if (s2)
538da63d 3963 printf(" since %s\n", s2);
584be568
LP
3964 else
3965 printf("\n");
3966
90bbc946 3967 if (!i->condition_result && i->condition_timestamp > 0) {
d5db7fe6
WC
3968 UnitCondition *c;
3969 int n = 0;
3970
bbb8486e 3971 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
90bbc946
LP
3972 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
3973
59fccdc5 3974 printf("Condition: start %scondition failed%s at %s%s%s\n",
1fc464f6 3975 ansi_highlight_yellow(), ansi_normal(),
5cfee414 3976 s2, s1 ? "; " : "", strempty(s1));
d5db7fe6 3977
b1ed76ae 3978 LIST_FOREACH(conditions, c, i->conditions)
d5db7fe6
WC
3979 if (c->tristate < 0)
3980 n++;
d5db7fe6 3981
b1ed76ae
ZJS
3982 LIST_FOREACH(conditions, c, i->conditions)
3983 if (c->tristate < 0)
3984 printf(" %s %s=%s%s%s was not met\n",
3985 --n ? special_glyph(TREE_BRANCH) : special_glyph(TREE_RIGHT),
3986 c->name,
3987 c->trigger ? "|" : "",
3988 c->negate ? "!" : "",
3989 c->param);
59fccdc5
LP
3990 }
3991
3992 if (!i->assert_result && i->assert_timestamp > 0) {
3993 s1 = format_timestamp_relative(since1, sizeof(since1), i->assert_timestamp);
3994 s2 = format_timestamp(since2, sizeof(since2), i->assert_timestamp);
3995
3996 printf(" Assert: start %sassertion failed%s at %s%s%s\n",
1fc464f6 3997 ansi_highlight_red(), ansi_normal(),
5cfee414 3998 s2, s1 ? "; " : "", strempty(s1));
59fccdc5
LP
3999 if (i->failed_assert_trigger)
4000 printf(" none of the trigger assertions were met\n");
4001 else if (i->failed_assert)
4002 printf(" %s=%s%s was not met\n",
4003 i->failed_assert,
4004 i->failed_assert_negate ? "!" : "",
4005 i->failed_assert_parameter);
90bbc946
LP
4006 }
4007
61cbdc4b 4008 if (i->sysfs_path)
856323c9 4009 printf(" Device: %s\n", i->sysfs_path);
9feeba4b 4010 if (i->where)
856323c9 4011 printf(" Where: %s\n", i->where);
9feeba4b 4012 if (i->what)
856323c9 4013 printf(" What: %s\n", i->what);
49dbfa7b 4014
13160134 4015 STRV_FOREACH(t, i->documentation)
856323c9 4016 printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", *t);
49dbfa7b 4017
13160134 4018 STRV_FOREACH_PAIR(t, t2, i->listen)
856323c9 4019 printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
67419600 4020
b8131a87 4021 if (i->accept)
856323c9 4022 printf(" Accepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
61cbdc4b 4023
582a507f 4024 LIST_FOREACH(exec, p, i->exec) {
13160134 4025 _cleanup_free_ char *argv = NULL;
9a57c629 4026 bool good;
582a507f
LP
4027
4028 /* Only show exited processes here */
4029 if (p->code == 0)
4030 continue;
4031
13160134 4032 argv = strv_join(p->argv, " ");
1fa2f38f 4033 printf(" Process: "PID_FMT" %s=%s ", p->pid, p->name, strna(argv));
582a507f 4034
1f0958f6 4035 good = is_clean_exit(p->code, p->status, EXIT_CLEAN_DAEMON, NULL);
9a57c629 4036 if (!good) {
0b5a519c 4037 on = ansi_highlight_red();
1fc464f6 4038 off = ansi_normal();
9a57c629
LP
4039 } else
4040 on = off = "";
4041
4042 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
4043
d06dacd0
LP
4044 if (p->code == CLD_EXITED) {
4045 const char *c;
4046
582a507f 4047 printf("status=%i", p->status);
d06dacd0 4048
1b64d026
LP
4049 c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
4050 if (c)
d06dacd0
LP
4051 printf("/%s", c);
4052
4053 } else
582a507f 4054 printf("signal=%s", signal_to_string(p->status));
9a57c629
LP
4055
4056 printf(")%s\n", off);
4057
582a507f
LP
4058 if (i->main_pid == p->pid &&
4059 i->start_timestamp == p->start_timestamp &&
4060 i->exit_timestamp == p->start_timestamp)
4061 /* Let's not show this twice */
4062 i->main_pid = 0;
4063
4064 if (p->pid == i->control_pid)
4065 i->control_pid = 0;
4066 }
4067
61cbdc4b 4068 if (i->main_pid > 0 || i->control_pid > 0) {
61cbdc4b 4069 if (i->main_pid > 0) {
8c06592f 4070 printf(" Main PID: "PID_FMT, i->main_pid);
61cbdc4b
LP
4071
4072 if (i->running) {
13160134 4073 _cleanup_free_ char *comm = NULL;
1089dcd4 4074 (void) get_process_comm(i->main_pid, &comm);
13160134
ZJS
4075 if (comm)
4076 printf(" (%s)", comm);
6d4fc029 4077 } else if (i->exit_code > 0) {
61cbdc4b
LP
4078 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
4079
d06dacd0
LP
4080 if (i->exit_code == CLD_EXITED) {
4081 const char *c;
4082
61cbdc4b 4083 printf("status=%i", i->exit_status);
d06dacd0 4084
1b64d026
LP
4085 c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
4086 if (c)
d06dacd0
LP
4087 printf("/%s", c);
4088
4089 } else
582a507f 4090 printf("signal=%s", signal_to_string(i->exit_status));
6d4fc029
LP
4091 printf(")");
4092 }
13160134 4093 }
61cbdc4b
LP
4094
4095 if (i->control_pid > 0) {
13160134 4096 _cleanup_free_ char *c = NULL;
61cbdc4b 4097
1089dcd4
LP
4098 if (i->main_pid > 0)
4099 fputs("; Control PID: ", stdout);
4100 else
4101 fputs("Cntrl PID: ", stdout); /* if first in column, abbreviated so it fits alignment */
4102
4103 printf(PID_FMT, i->control_pid);
61cbdc4b 4104
1089dcd4 4105 (void) get_process_comm(i->control_pid, &c);
13160134
ZJS
4106 if (c)
4107 printf(" (%s)", c);
61cbdc4b
LP
4108 }
4109
4110 printf("\n");
4111 }
4112
17bb7382 4113 if (i->status_text)
856323c9 4114 printf(" Status: \"%s\"\n", i->status_text);
b4af5a80
LP
4115 if (i->status_errno > 0)
4116 printf(" Error: %i (%s)\n", i->status_errno, strerror(i->status_errno));
17bb7382 4117
03a7b521
LP
4118 if (i->tasks_current != (uint64_t) -1) {
4119 printf(" Tasks: %" PRIu64, i->tasks_current);
4120
4121 if (i->tasks_max != (uint64_t) -1)
2a6736dd 4122 printf(" (limit: %" PRIu64 ")\n", i->tasks_max);
03a7b521
LP
4123 else
4124 printf("\n");
4125 }
4126
934277fe
LP
4127 if (i->memory_current != (uint64_t) -1) {
4128 char buf[FORMAT_BYTES_MAX];
4129
4130 printf(" Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current));
4131
96e131ea
WC
4132 if (i->memory_low > 0 || i->memory_high != CGROUP_LIMIT_MAX ||
4133 i->memory_max != CGROUP_LIMIT_MAX || i->memory_swap_max != CGROUP_LIMIT_MAX ||
da4d897e
TH
4134 i->memory_limit != CGROUP_LIMIT_MAX) {
4135 const char *prefix = "";
4136
4137 printf(" (");
4138 if (i->memory_low > 0) {
4139 printf("%slow: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_low));
4140 prefix = " ";
4141 }
4142 if (i->memory_high != CGROUP_LIMIT_MAX) {
4143 printf("%shigh: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_high));
4144 prefix = " ";
4145 }
4146 if (i->memory_max != CGROUP_LIMIT_MAX) {
4147 printf("%smax: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_max));
4148 prefix = " ";
4149 }
96e131ea
WC
4150 if (i->memory_swap_max != CGROUP_LIMIT_MAX) {
4151 printf("%sswap max: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_swap_max));
4152 prefix = " ";
4153 }
da4d897e
TH
4154 if (i->memory_limit != CGROUP_LIMIT_MAX) {
4155 printf("%slimit: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_limit));
4156 prefix = " ";
4157 }
4158 printf(")");
4159 }
4160 printf("\n");
934277fe
LP
4161 }
4162
5ad096b3
LP
4163 if (i->cpu_usage_nsec != (uint64_t) -1) {
4164 char buf[FORMAT_TIMESPAN_MAX];
4165 printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
4166 }
4167
51e22f88 4168 if (i->control_group) {
291d565a
LP
4169 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4170 static const char prefix[] = " ";
ab35fb1b
LP
4171 unsigned c;
4172
51e22f88
LP
4173 printf(" CGroup: %s\n", i->control_group);
4174
291d565a
LP
4175 c = columns();
4176 if (c > sizeof(prefix) - 1)
4177 c -= sizeof(prefix) - 1;
4178 else
4179 c = 0;
ab35fb1b 4180
291d565a
LP
4181 r = unit_show_processes(bus, i->id, i->control_group, prefix, c, get_output_flags(), &error);
4182 if (r == -EBADR) {
b69d29ce
LP
4183 unsigned k = 0;
4184 pid_t extra[2];
4185
291d565a 4186 /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
ab35fb1b 4187
b69d29ce
LP
4188 if (i->main_pid > 0)
4189 extra[k++] = i->main_pid;
4190
4191 if (i->control_pid > 0)
4192 extra[k++] = i->control_pid;
4193
0ff308c8 4194 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, extra, k, get_output_flags());
291d565a
LP
4195 } else if (r < 0)
4196 log_warning_errno(r, "Failed to dump process list, ignoring: %s", bus_error_message(&error, r));
c59760ee 4197 }
45fb0699 4198
ece174c5 4199 if (i->id && arg_transport == BUS_TRANSPORT_LOCAL)
3c756001
LP
4200 show_journal_by_unit(
4201 stdout,
4202 i->id,
4203 arg_output,
4204 0,
4205 i->inactive_exit_timestamp_monotonic,
4206 arg_lines,
4207 getuid(),
4208 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
4209 SD_JOURNAL_LOCAL_ONLY,
4210 arg_scope == UNIT_FILE_SYSTEM,
4211 ellipsized);
86aa7ba4 4212
45fb0699 4213 if (i->need_daemon_reload)
3f36991e 4214 warn_unit_file_changed(i->id);
61cbdc4b
LP
4215}
4216
b43f208f 4217static void show_unit_help(UnitStatusInfo *i) {
256425cc
LP
4218 char **p;
4219
4220 assert(i);
4221
4222 if (!i->documentation) {
4223 log_info("Documentation for %s not known.", i->id);
4224 return;
4225 }
4226
78002a67
ZJS
4227 STRV_FOREACH(p, i->documentation)
4228 if (startswith(*p, "man:"))
4229 show_man_page(*p + 4, false);
4230 else
0315fe37 4231 log_info("Can't show: %s", *p);
256425cc
LP
4232}
4233
f459b602
MAP
4234static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *i, const char *contents) {
4235 int r;
61cbdc4b 4236
a4c279f8 4237 assert(name);
f459b602 4238 assert(m);
a4c279f8
LP
4239 assert(i);
4240
f459b602 4241 switch (contents[0]) {
61cbdc4b 4242
f459b602 4243 case SD_BUS_TYPE_STRING: {
61cbdc4b
LP
4244 const char *s;
4245
f459b602
MAP
4246 r = sd_bus_message_read(m, "s", &s);
4247 if (r < 0)
4248 return bus_log_parse_error(r);
61cbdc4b 4249
37a0d5bf 4250 if (!isempty(s)) {
61cbdc4b
LP
4251 if (streq(name, "Id"))
4252 i->id = s;
4253 else if (streq(name, "LoadState"))
4254 i->load_state = s;
4255 else if (streq(name, "ActiveState"))
4256 i->active_state = s;
4257 else if (streq(name, "SubState"))
4258 i->sub_state = s;
4259 else if (streq(name, "Description"))
4260 i->description = s;
4261 else if (streq(name, "FragmentPath"))
1b64d026
LP
4262 i->fragment_path = s;
4263 else if (streq(name, "SourcePath"))
4264 i->source_path = s;
286ca485 4265#ifndef NOLEGACY
a00963a2
LP
4266 else if (streq(name, "DefaultControlGroup")) {
4267 const char *e;
4268 e = startswith(s, SYSTEMD_CGROUP_CONTROLLER ":");
4269 if (e)
4270 i->control_group = e;
4271 }
4ad49000 4272#endif
37a0d5bf
LP
4273 else if (streq(name, "ControlGroup"))
4274 i->control_group = s;
61cbdc4b
LP
4275 else if (streq(name, "StatusText"))
4276 i->status_text = s;
175728c4
HH
4277 else if (streq(name, "PIDFile"))
4278 i->pid_file = s;
61cbdc4b
LP
4279 else if (streq(name, "SysFSPath"))
4280 i->sysfs_path = s;
4281 else if (streq(name, "Where"))
4282 i->where = s;
4283 else if (streq(name, "What"))
4284 i->what = s;
4a9e2fff
LP
4285 else if (streq(name, "Following"))
4286 i->following = s;
a4375746
LP
4287 else if (streq(name, "UnitFileState"))
4288 i->unit_file_state = s;
d2dc52db
LP
4289 else if (streq(name, "UnitFilePreset"))
4290 i->unit_file_preset = s;
f42806df
LP
4291 else if (streq(name, "Result"))
4292 i->result = s;
61cbdc4b
LP
4293 }
4294
4295 break;
4296 }
4297
f459b602
MAP
4298 case SD_BUS_TYPE_BOOLEAN: {
4299 int b;
b8131a87 4300
f459b602
MAP
4301 r = sd_bus_message_read(m, "b", &b);
4302 if (r < 0)
4303 return bus_log_parse_error(r);
b8131a87
LP
4304
4305 if (streq(name, "Accept"))
4306 i->accept = b;
45fb0699
LP
4307 else if (streq(name, "NeedDaemonReload"))
4308 i->need_daemon_reload = b;
90bbc946
LP
4309 else if (streq(name, "ConditionResult"))
4310 i->condition_result = b;
59fccdc5
LP
4311 else if (streq(name, "AssertResult"))
4312 i->assert_result = b;
055ef36b
LP
4313 else if (streq(name, "Transient"))
4314 i->transient = b;
b8131a87
LP
4315
4316 break;
4317 }
4318
f459b602 4319 case SD_BUS_TYPE_UINT32: {
61cbdc4b
LP
4320 uint32_t u;
4321
f459b602
MAP
4322 r = sd_bus_message_read(m, "u", &u);
4323 if (r < 0)
4324 return bus_log_parse_error(r);
61cbdc4b
LP
4325
4326 if (streq(name, "MainPID")) {
4327 if (u > 0) {
4328 i->main_pid = (pid_t) u;
4329 i->running = true;
4330 }
4331 } else if (streq(name, "ControlPID"))
4332 i->control_pid = (pid_t) u;
4333 else if (streq(name, "ExecMainPID")) {
4334 if (u > 0)
4335 i->main_pid = (pid_t) u;
4336 } else if (streq(name, "NAccepted"))
4337 i->n_accepted = u;
4338 else if (streq(name, "NConnections"))
4339 i->n_connections = u;
4340
4341 break;
4342 }
4343
f459b602 4344 case SD_BUS_TYPE_INT32: {
61cbdc4b
LP
4345 int32_t j;
4346
f459b602
MAP
4347 r = sd_bus_message_read(m, "i", &j);
4348 if (r < 0)
4349 return bus_log_parse_error(r);
61cbdc4b
LP
4350
4351 if (streq(name, "ExecMainCode"))
4352 i->exit_code = (int) j;
4353 else if (streq(name, "ExecMainStatus"))
4354 i->exit_status = (int) j;
b4af5a80
LP
4355 else if (streq(name, "StatusErrno"))
4356 i->status_errno = (int) j;
61cbdc4b
LP
4357
4358 break;
4359 }
4360
f459b602 4361 case SD_BUS_TYPE_UINT64: {
61cbdc4b
LP
4362 uint64_t u;
4363
f459b602
MAP
4364 r = sd_bus_message_read(m, "t", &u);
4365 if (r < 0)
4366 return bus_log_parse_error(r);
61cbdc4b
LP
4367
4368 if (streq(name, "ExecMainStartTimestamp"))
4369 i->start_timestamp = (usec_t) u;
4370 else if (streq(name, "ExecMainExitTimestamp"))
4371 i->exit_timestamp = (usec_t) u;
584be568
LP
4372 else if (streq(name, "ActiveEnterTimestamp"))
4373 i->active_enter_timestamp = (usec_t) u;
4374 else if (streq(name, "InactiveEnterTimestamp"))
4375 i->inactive_enter_timestamp = (usec_t) u;
4376 else if (streq(name, "InactiveExitTimestamp"))
4377 i->inactive_exit_timestamp = (usec_t) u;
df50185b
LP
4378 else if (streq(name, "InactiveExitTimestampMonotonic"))
4379 i->inactive_exit_timestamp_monotonic = (usec_t) u;
584be568
LP
4380 else if (streq(name, "ActiveExitTimestamp"))
4381 i->active_exit_timestamp = (usec_t) u;
90bbc946
LP
4382 else if (streq(name, "ConditionTimestamp"))
4383 i->condition_timestamp = (usec_t) u;
59fccdc5
LP
4384 else if (streq(name, "AssertTimestamp"))
4385 i->assert_timestamp = (usec_t) u;
934277fe
LP
4386 else if (streq(name, "MemoryCurrent"))
4387 i->memory_current = u;
da4d897e
TH
4388 else if (streq(name, "MemoryLow"))
4389 i->memory_low = u;
4390 else if (streq(name, "MemoryHigh"))
4391 i->memory_high = u;
4392 else if (streq(name, "MemoryMax"))
4393 i->memory_max = u;
96e131ea
WC
4394 else if (streq(name, "MemorySwapMax"))
4395 i->memory_swap_max = u;
934277fe
LP
4396 else if (streq(name, "MemoryLimit"))
4397 i->memory_limit = u;
03a7b521
LP
4398 else if (streq(name, "TasksCurrent"))
4399 i->tasks_current = u;
4400 else if (streq(name, "TasksMax"))
4401 i->tasks_max = u;
5ad096b3
LP
4402 else if (streq(name, "CPUUsageNSec"))
4403 i->cpu_usage_nsec = u;
61cbdc4b
LP
4404
4405 break;
4406 }
582a507f 4407
f459b602 4408 case SD_BUS_TYPE_ARRAY:
582a507f 4409
f459b602
MAP
4410 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
4411 _cleanup_free_ ExecStatusInfo *info = NULL;
582a507f 4412
f459b602
MAP
4413 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
4414 if (r < 0)
4415 return bus_log_parse_error(r);
582a507f 4416
f459b602
MAP
4417 info = new0(ExecStatusInfo, 1);
4418 if (!info)
4419 return log_oom();
582a507f 4420
f459b602 4421 while ((r = exec_status_info_deserialize(m, info)) > 0) {
0129173a 4422
f459b602
MAP
4423 info->name = strdup(name);
4424 if (!info->name)
691395d8 4425 return log_oom();
582a507f 4426
71fda00f 4427 LIST_PREPEND(exec, i->exec, info);
582a507f 4428
f459b602
MAP
4429 info = new0(ExecStatusInfo, 1);
4430 if (!info)
691395d8 4431 return log_oom();
49dbfa7b 4432 }
67419600 4433
f459b602
MAP
4434 if (r < 0)
4435 return bus_log_parse_error(r);
67419600 4436
f459b602
MAP
4437 r = sd_bus_message_exit_container(m);
4438 if (r < 0)
4439 return bus_log_parse_error(r);
67419600 4440
f459b602 4441 return 0;
67419600 4442
f459b602
MAP
4443 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
4444 const char *type, *path;
13160134 4445
f459b602
MAP
4446 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4447 if (r < 0)
4448 return bus_log_parse_error(r);
67419600 4449
f459b602 4450 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0) {
67419600 4451
f459b602
MAP
4452 r = strv_extend(&i->listen, type);
4453 if (r < 0)
4454 return r;
67419600 4455
f459b602
MAP
4456 r = strv_extend(&i->listen, path);
4457 if (r < 0)
4458 return r;
4459 }
76d14b87 4460 if (r < 0)
f459b602 4461 return bus_log_parse_error(r);
76d14b87 4462
f459b602
MAP
4463 r = sd_bus_message_exit_container(m);
4464 if (r < 0)
4465 return bus_log_parse_error(r);
49dbfa7b 4466
f459b602 4467 return 0;
49dbfa7b 4468
f459b602 4469 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "DropInPaths")) {
49dbfa7b 4470
f459b602
MAP
4471 r = sd_bus_message_read_strv(m, &i->dropin_paths);
4472 if (r < 0)
4473 return bus_log_parse_error(r);
49dbfa7b 4474
f459b602 4475 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "Documentation")) {
49dbfa7b 4476
f459b602
MAP
4477 r = sd_bus_message_read_strv(m, &i->documentation);
4478 if (r < 0)
4479 return bus_log_parse_error(r);
52990c2e 4480
f459b602
MAP
4481 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Conditions")) {
4482 const char *cond, *param;
4483 int trigger, negate;
4484 int32_t state;
52990c2e 4485
f459b602
MAP
4486 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
4487 if (r < 0)
4488 return bus_log_parse_error(r);
4489
4490 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
9bb71940 4491 _cleanup_(unit_condition_freep) UnitCondition *c = NULL;
d5db7fe6 4492
b1ed76ae 4493 log_debug("%s trigger=%d negate=%d %s →%d", cond, trigger, negate, param, state);
d5db7fe6
WC
4494
4495 c = new0(UnitCondition, 1);
4496 if (!c)
4497 return log_oom();
4498
4499 c->name = strdup(cond);
d5db7fe6 4500 c->param = strdup(param);
9bb71940 4501 if (!c->name || !c->param)
d5db7fe6 4502 return log_oom();
d5db7fe6
WC
4503
4504 c->trigger = trigger;
4505 c->negate = negate;
4506 c->tristate = state;
4507
b1ed76ae 4508 LIST_PREPEND(conditions, i->conditions, c);
9bb71940 4509 c = NULL;
59fccdc5
LP
4510 }
4511 if (r < 0)
4512 return bus_log_parse_error(r);
4513
4514 r = sd_bus_message_exit_container(m);
4515 if (r < 0)
4516 return bus_log_parse_error(r);
4517
4518 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Asserts")) {
4519 const char *cond, *param;
4520 int trigger, negate;
4521 int32_t state;
4522
4523 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
4524 if (r < 0)
4525 return bus_log_parse_error(r);
4526
4527 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
4528 log_debug("%s %d %d %s %d", cond, trigger, negate, param, state);
4529 if (state < 0 && (!trigger || !i->failed_assert)) {
4530 i->failed_assert = cond;
4531 i->failed_assert_trigger = trigger;
4532 i->failed_assert_negate = negate;
4533 i->failed_assert_parameter = param;
f459b602 4534 }
582a507f 4535 }
f459b602
MAP
4536 if (r < 0)
4537 return bus_log_parse_error(r);
4538
4539 r = sd_bus_message_exit_container(m);
4540 if (r < 0)
4541 return bus_log_parse_error(r);
4542
4543 } else
4544 goto skip;
582a507f
LP
4545
4546 break;
9f39404c 4547
f459b602 4548 case SD_BUS_TYPE_STRUCT_BEGIN:
9f39404c
LP
4549
4550 if (streq(name, "LoadError")) {
9f39404c 4551 const char *n, *message;
9f39404c 4552
f459b602 4553 r = sd_bus_message_read(m, "(ss)", &n, &message);
9f39404c 4554 if (r < 0)
f459b602 4555 return bus_log_parse_error(r);
9f39404c
LP
4556
4557 if (!isempty(message))
4558 i->load_error = message;
f459b602
MAP
4559 } else
4560 goto skip;
9f39404c
LP
4561
4562 break;
f459b602
MAP
4563
4564 default:
4565 goto skip;
9f39404c 4566 }
f459b602
MAP
4567
4568 return 0;
4569
4570skip:
4571 r = sd_bus_message_skip(m, contents);
4572 if (r < 0)
4573 return bus_log_parse_error(r);
61cbdc4b
LP
4574
4575 return 0;
4576}
4577
4f9a9105
ZJS
4578#define print_prop(name, fmt, ...) \
4579 do { \
4580 if (arg_value) \
4581 printf(fmt "\n", __VA_ARGS__); \
4582 else \
4583 printf("%s=" fmt "\n", name, __VA_ARGS__); \
4584 } while(0)
4585
f459b602
MAP
4586static int print_property(const char *name, sd_bus_message *m, const char *contents) {
4587 int r;
4588
48220598 4589 assert(name);
f459b602 4590 assert(m);
48220598 4591
61cbdc4b
LP
4592 /* This is a low-level property printer, see
4593 * print_status_info() for the nicer output */
4594
852c1b4d
ZJS
4595 if (arg_properties && !strv_find(arg_properties, name)) {
4596 /* skip what we didn't read */
4597 r = sd_bus_message_skip(m, contents);
4598 return r;
4599 }
48220598 4600
f459b602 4601 switch (contents[0]) {
48220598 4602
f459b602 4603 case SD_BUS_TYPE_STRUCT_BEGIN:
48220598 4604
f459b602 4605 if (contents[1] == SD_BUS_TYPE_UINT32 && streq(name, "Job")) {
48220598
LP
4606 uint32_t u;
4607
f459b602
MAP
4608 r = sd_bus_message_read(m, "(uo)", &u, NULL);
4609 if (r < 0)
4610 return bus_log_parse_error(r);
48220598 4611
f459b602 4612 if (u > 0)
4f9a9105 4613 print_prop(name, "%"PRIu32, u);
48220598 4614 else if (arg_all)
4f9a9105 4615 print_prop(name, "%s", "");
48220598
LP
4616
4617 return 0;
f459b602
MAP
4618
4619 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "Unit")) {
48220598
LP
4620 const char *s;
4621
f459b602
MAP
4622 r = sd_bus_message_read(m, "(so)", &s, NULL);
4623 if (r < 0)
4624 return bus_log_parse_error(r);
48220598 4625
f459b602 4626 if (arg_all || !isempty(s))
4f9a9105 4627 print_prop(name, "%s", s);
48220598
LP
4628
4629 return 0;
f459b602
MAP
4630
4631 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "LoadError")) {
9f39404c
LP
4632 const char *a = NULL, *b = NULL;
4633
f459b602
MAP
4634 r = sd_bus_message_read(m, "(ss)", &a, &b);
4635 if (r < 0)
4636 return bus_log_parse_error(r);
9f39404c
LP
4637
4638 if (arg_all || !isempty(a) || !isempty(b))
4f9a9105 4639 print_prop(name, "%s \"%s\"", strempty(a), strempty(b));
f786e80d 4640
57183d11
LP
4641 return 0;
4642 } else if (streq_ptr(name, "SystemCallFilter")) {
4643 _cleanup_strv_free_ char **l = NULL;
4644 int whitelist;
4645
4646 r = sd_bus_message_enter_container(m, 'r', "bas");
4647 if (r < 0)
4648 return bus_log_parse_error(r);
4649
4650 r = sd_bus_message_read(m, "b", &whitelist);
4651 if (r < 0)
4652 return bus_log_parse_error(r);
4653
4654 r = sd_bus_message_read_strv(m, &l);
4655 if (r < 0)
4656 return bus_log_parse_error(r);
4657
4658 r = sd_bus_message_exit_container(m);
4659 if (r < 0)
4660 return bus_log_parse_error(r);
4661
4662 if (arg_all || whitelist || !strv_isempty(l)) {
4663 bool first = true;
4664 char **i;
4665
4f9a9105
ZJS
4666 if (!arg_value) {
4667 fputs(name, stdout);
4668 fputc('=', stdout);
4669 }
57183d11
LP
4670
4671 if (!whitelist)
4672 fputc('~', stdout);
4673
4674 STRV_FOREACH(i, l) {
4675 if (first)
4676 first = false;
4677 else
4678 fputc(' ', stdout);
4679
4680 fputs(*i, stdout);
4681 }
4682 fputc('\n', stdout);
4683 }
4684
f786e80d 4685 return 0;
48220598
LP
4686 }
4687
4688 break;
48220598 4689
f459b602 4690 case SD_BUS_TYPE_ARRAY:
48220598 4691
f459b602
MAP
4692 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "EnvironmentFiles")) {
4693 const char *path;
4694 int ignore;
8c7be95e 4695
f459b602
MAP
4696 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sb)");
4697 if (r < 0)
4698 return bus_log_parse_error(r);
8c7be95e 4699
f459b602 4700 while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
a1abf5ea 4701 print_prop("EnvironmentFile", "%s (ignore_errors=%s)", path, yes_no(ignore));
8c7be95e 4702
f459b602
MAP
4703 if (r < 0)
4704 return bus_log_parse_error(r);
8c7be95e 4705
f459b602
MAP
4706 r = sd_bus_message_exit_container(m);
4707 if (r < 0)
4708 return bus_log_parse_error(r);
8c7be95e
LP
4709
4710 return 0;
4711
f459b602
MAP
4712 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Paths")) {
4713 const char *type, *path;
67419600 4714
f459b602
MAP
4715 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4716 if (r < 0)
4717 return bus_log_parse_error(r);
ebf57b80 4718
f459b602 4719 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
4f9a9105 4720 print_prop(type, "%s", path);
f459b602
MAP
4721 if (r < 0)
4722 return bus_log_parse_error(r);
ebf57b80 4723
f459b602
MAP
4724 r = sd_bus_message_exit_container(m);
4725 if (r < 0)
4726 return bus_log_parse_error(r);
ebf57b80 4727
707e5e52 4728 return 0;
582a507f 4729
f459b602
MAP
4730 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
4731 const char *type, *path;
67419600 4732
f459b602
MAP
4733 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4734 if (r < 0)
4735 return bus_log_parse_error(r);
67419600 4736
f459b602 4737 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
4f9a9105
ZJS
4738 if (arg_value)
4739 puts(path);
4740 else
4741 printf("Listen%s=%s\n", type, path);
f459b602
MAP
4742 if (r < 0)
4743 return bus_log_parse_error(r);
67419600 4744
f459b602
MAP
4745 r = sd_bus_message_exit_container(m);
4746 if (r < 0)
4747 return bus_log_parse_error(r);
67419600
OS
4748
4749 return 0;
4750
f459b602
MAP
4751 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Timers")) {
4752 const char *base;
4753 uint64_t value, next_elapse;
707e5e52 4754
f459b602
MAP
4755 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(stt)");
4756 if (r < 0)
4757 return bus_log_parse_error(r);
552e4331 4758
f459b602
MAP
4759 while ((r = sd_bus_message_read(m, "(stt)", &base, &value, &next_elapse)) > 0) {
4760 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
fe68089d 4761
4f9a9105
ZJS
4762 print_prop(base, "{ value=%s ; next_elapse=%s }",
4763 format_timespan(timespan1, sizeof(timespan1), value, 0),
4764 format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
fe68089d 4765 }
f459b602
MAP
4766 if (r < 0)
4767 return bus_log_parse_error(r);
4768
4769 r = sd_bus_message_exit_container(m);
4770 if (r < 0)
4771 return bus_log_parse_error(r);
fe68089d
LP
4772
4773 return 0;
fe68089d 4774
f459b602
MAP
4775 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
4776 ExecStatusInfo info = {};
4777
4778 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
4779 if (r < 0)
4780 return bus_log_parse_error(r);
4781
4782 while ((r = exec_status_info_deserialize(m, &info)) > 0) {
4783 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
4784 _cleanup_free_ char *tt;
4785
4786 tt = strv_join(info.argv, " ");
4787
4f9a9105
ZJS
4788 print_prop(name,
4789 "{ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
4790 strna(info.path),
4791 strna(tt),
4792 yes_no(info.ignore),
4793 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
4794 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
4795 info.pid,
4796 sigchld_code_to_string(info.code),
4797 info.status,
4798 info.code == CLD_EXITED ? "" : "/",
4799 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
fe68089d 4800
582a507f
LP
4801 free(info.path);
4802 strv_free(info.argv);
f459b602 4803 zero(info);
707e5e52
LP
4804 }
4805
f459b602
MAP
4806 r = sd_bus_message_exit_container(m);
4807 if (r < 0)
4808 return bus_log_parse_error(r);
4809
48220598 4810 return 0;
4ad49000 4811
f459b602
MAP
4812 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "DeviceAllow")) {
4813 const char *path, *rwm;
4ad49000 4814
f459b602
MAP
4815 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4816 if (r < 0)
4817 return bus_log_parse_error(r);
4ad49000 4818
f459b602 4819 while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0)
4f9a9105 4820 print_prop(name, "%s %s", strna(path), strna(rwm));
f459b602
MAP
4821 if (r < 0)
4822 return bus_log_parse_error(r);
4ad49000 4823
f459b602
MAP
4824 r = sd_bus_message_exit_container(m);
4825 if (r < 0)
4826 return bus_log_parse_error(r);
4ad49000 4827
4ad49000
LP
4828 return 0;
4829
72240b52
ZJS
4830 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN &&
4831 STR_IN_SET(name, "IODeviceWeight", "BlockIODeviceWeight")) {
f459b602
MAP
4832 const char *path;
4833 uint64_t weight;
b8ab2dc6 4834
f459b602
MAP
4835 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
4836 if (r < 0)
4837 return bus_log_parse_error(r);
b8ab2dc6 4838
f459b602 4839 while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0)
4f9a9105 4840 print_prop(name, "%s %"PRIu64, strna(path), weight);
f459b602
MAP
4841 if (r < 0)
4842 return bus_log_parse_error(r);
b8ab2dc6 4843
f459b602
MAP
4844 r = sd_bus_message_exit_container(m);
4845 if (r < 0)
4846 return bus_log_parse_error(r);
b8ab2dc6 4847
b8ab2dc6
G
4848 return 0;
4849
72240b52
ZJS
4850 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN &&
4851 (cgroup_io_limit_type_from_string(name) >= 0 ||
4852 STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth"))) {
f459b602
MAP
4853 const char *path;
4854 uint64_t bandwidth;
4ad49000 4855
f459b602
MAP
4856 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
4857 if (r < 0)
4858 return bus_log_parse_error(r);
4ad49000 4859
f459b602 4860 while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0)
4f9a9105 4861 print_prop(name, "%s %"PRIu64, strna(path), bandwidth);
f459b602
MAP
4862 if (r < 0)
4863 return bus_log_parse_error(r);
4ad49000 4864
f459b602
MAP
4865 r = sd_bus_message_exit_container(m);
4866 if (r < 0)
4867 return bus_log_parse_error(r);
4ad49000 4868
4ad49000 4869 return 0;
48220598
LP
4870 }
4871
4872 break;
4873 }
4874
4f9a9105 4875 r = bus_print_property(name, m, arg_value, arg_all);
f459b602
MAP
4876 if (r < 0)
4877 return bus_log_parse_error(r);
4878
4879 if (r == 0) {
4880 r = sd_bus_message_skip(m, contents);
4881 if (r < 0)
4882 return bus_log_parse_error(r);
a4c279f8 4883
f459b602
MAP
4884 if (arg_all)
4885 printf("%s=[unprintable]\n", name);
4886 }
48220598
LP
4887
4888 return 0;
4889}
4890
f459b602
MAP
4891static int show_one(
4892 const char *verb,
4893 sd_bus *bus,
4894 const char *path,
3dced37b 4895 const char *unit,
f459b602
MAP
4896 bool show_properties,
4897 bool *new_line,
4898 bool *ellipsized) {
4899
3dced37b 4900 static const struct bus_properties_map property_map[] = {
662bea67
ZJS
4901 { "LoadState", "s", map_string_no_copy, offsetof(UnitStatusInfo, load_state) },
4902 { "ActiveState", "s", map_string_no_copy, offsetof(UnitStatusInfo, active_state) },
3dced37b
LP
4903 {}
4904 };
4905
4afd3348
LP
4906 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
4907 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
3dced37b 4908 _cleanup_set_free_ Set *found_properties = NULL;
a7335518 4909 _cleanup_(unit_status_info_free) UnitStatusInfo info = {
934277fe 4910 .memory_current = (uint64_t) -1,
da4d897e
TH
4911 .memory_high = CGROUP_LIMIT_MAX,
4912 .memory_max = CGROUP_LIMIT_MAX,
96e131ea 4913 .memory_swap_max = CGROUP_LIMIT_MAX,
934277fe 4914 .memory_limit = (uint64_t) -1,
5ad096b3 4915 .cpu_usage_nsec = (uint64_t) -1,
03a7b521
LP
4916 .tasks_current = (uint64_t) -1,
4917 .tasks_max = (uint64_t) -1,
934277fe 4918 };
f459b602 4919 int r;
48220598 4920
48220598 4921 assert(path);
61cbdc4b 4922 assert(new_line);
48220598 4923
e3e0314b
ZJS
4924 log_debug("Showing one %s", path);
4925
f459b602 4926 r = sd_bus_call_method(
f22f08cd
SP
4927 bus,
4928 "org.freedesktop.systemd1",
4929 path,
4930 "org.freedesktop.DBus.Properties",
4931 "GetAll",
f459b602 4932 &error,
f22f08cd 4933 &reply,
f459b602 4934 "s", "");
4c3e8e39
LP
4935 if (r < 0)
4936 return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
48220598 4937
3dced37b
LP
4938 if (unit) {
4939 r = bus_message_map_all_properties(reply, property_map, &info);
4940 if (r < 0)
4941 return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r));
e33a06a1 4942
3dced37b 4943 if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) {
bd5b9f0a
ZJS
4944 log_full(streq(verb, "status") ? LOG_ERR : LOG_DEBUG,
4945 "Unit %s could not be found.", unit);
e33a06a1 4946
3dced37b
LP
4947 if (streq(verb, "status"))
4948 return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN;
4949
bd5b9f0a
ZJS
4950 if (!streq(verb, "show"))
4951 return -ENOENT;
3dced37b
LP
4952 }
4953
4954 r = sd_bus_message_rewind(reply, true);
4955 if (r < 0)
4956 return log_error_errno(r, "Failed to rewind: %s", bus_error_message(&error, r));
4957 }
e33a06a1 4958
f459b602
MAP
4959 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
4960 if (r < 0)
4961 return bus_log_parse_error(r);
48220598 4962
61cbdc4b
LP
4963 if (*new_line)
4964 printf("\n");
4965
4966 *new_line = true;
4967
f459b602
MAP
4968 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
4969 const char *name, *contents;
0183528f 4970
f459b602
MAP
4971 r = sd_bus_message_read(reply, "s", &name);
4972 if (r < 0)
4973 return bus_log_parse_error(r);
48220598 4974
f459b602
MAP
4975 r = sd_bus_message_peek_type(reply, NULL, &contents);
4976 if (r < 0)
4977 return bus_log_parse_error(r);
4978
4979 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
4980 if (r < 0)
4981 return bus_log_parse_error(r);
48220598 4982
3dced37b
LP
4983 if (show_properties) {
4984 r = set_ensure_allocated(&found_properties, &string_hash_ops);
4985 if (r < 0)
4986 return log_oom();
4987
4988 r = set_put(found_properties, name);
4989 if (r < 0 && r != EEXIST)
4990 return log_oom();
4991
f459b602 4992 r = print_property(name, reply, contents);
3dced37b 4993 } else
f459b602
MAP
4994 r = status_property(name, reply, &info, contents);
4995 if (r < 0)
4996 return r;
48220598 4997
f459b602
MAP
4998 r = sd_bus_message_exit_container(reply);
4999 if (r < 0)
5000 return bus_log_parse_error(r);
5001
5002 r = sd_bus_message_exit_container(reply);
5003 if (r < 0)
5004 return bus_log_parse_error(r);
48220598 5005 }
f459b602
MAP
5006 if (r < 0)
5007 return bus_log_parse_error(r);
5008
5009 r = sd_bus_message_exit_container(reply);
5010 if (r < 0)
5011 return bus_log_parse_error(r);
48220598 5012
f1e36d67 5013 r = 0;
3dced37b
LP
5014 if (show_properties) {
5015 char **pp;
bd5b9f0a 5016 int not_found_level = streq(verb, "show") ? LOG_DEBUG : LOG_WARNING;
3dced37b 5017
a7335518 5018 STRV_FOREACH(pp, arg_properties)
3dced37b 5019 if (!set_contains(found_properties, *pp)) {
bd5b9f0a 5020 log_full(not_found_level, "Property %s does not exist.", *pp);
3dced37b
LP
5021 r = -ENXIO;
5022 }
a7335518 5023
3dced37b
LP
5024 } else if (streq(verb, "help"))
5025 show_unit_help(&info);
5026 else if (streq(verb, "status")) {
5027 print_status_info(bus, &info, ellipsized);
5028
7f5da8bd 5029 if (info.active_state && !STR_IN_SET(info.active_state, "active", "reloading"))
3dced37b 5030 r = EXIT_PROGRAM_NOT_RUNNING;
256425cc 5031 else
3dced37b 5032 r = EXIT_PROGRAM_RUNNING_OR_SERVICE_OK;
256425cc 5033 }
f1e36d67 5034
48220598
LP
5035 return r;
5036}
5037
f74294c1 5038static int get_unit_dbus_path_by_pid(
f459b602
MAP
5039 sd_bus *bus,
5040 uint32_t pid,
f74294c1 5041 char **unit) {
f459b602 5042
4afd3348
LP
5043 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5044 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
373d32c9 5045 char *u;
a223b325
MS
5046 int r;
5047
f459b602 5048 r = sd_bus_call_method(
f22f08cd
SP
5049 bus,
5050 "org.freedesktop.systemd1",
5051 "/org/freedesktop/systemd1",
5052 "org.freedesktop.systemd1.Manager",
5053 "GetUnitByPID",
f459b602 5054 &error,
f22f08cd 5055 &reply,
f459b602 5056 "u", pid);
691395d8
LP
5057 if (r < 0)
5058 return log_error_errno(r, "Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
a223b325 5059
373d32c9 5060 r = sd_bus_message_read(reply, "o", &u);
f459b602
MAP
5061 if (r < 0)
5062 return bus_log_parse_error(r);
5063
373d32c9
LP
5064 u = strdup(u);
5065 if (!u)
5066 return log_oom();
5067
5068 *unit = u;
f74294c1 5069 return 0;
a223b325
MS
5070}
5071
f459b602
MAP
5072static int show_all(
5073 const char* verb,
5074 sd_bus *bus,
5075 bool show_properties,
5076 bool *new_line,
5077 bool *ellipsized) {
5078
4afd3348 5079 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
f459b602
MAP
5080 _cleanup_free_ UnitInfo *unit_infos = NULL;
5081 const UnitInfo *u;
5082 unsigned c;
5bb75bc7 5083 int r, ret = 0;
265a7a2a 5084
1238ee09 5085 r = get_unit_list(bus, NULL, NULL, &unit_infos, 0, &reply);
265a7a2a
ZJS
5086 if (r < 0)
5087 return r;
5088
ea4b98e6 5089 pager_open(arg_no_pager, false);
dbed408b 5090
f459b602
MAP
5091 c = (unsigned) r;
5092
5093 qsort_safe(unit_infos, c, sizeof(UnitInfo), compare_unit_info);
991f2a39 5094
265a7a2a 5095 for (u = unit_infos; u < unit_infos + c; u++) {
7fd1b19b 5096 _cleanup_free_ char *p = NULL;
265a7a2a 5097
265a7a2a
ZJS
5098 p = unit_dbus_path_from_name(u->id);
5099 if (!p)
5100 return log_oom();
5101
3dced37b 5102 r = show_one(verb, bus, p, u->id, show_properties, new_line, ellipsized);
3df538da 5103 if (r < 0)
265a7a2a 5104 return r;
5bb75bc7
ZJS
5105 else if (r > 0 && ret == 0)
5106 ret = r;
265a7a2a
ZJS
5107 }
5108
5bb75bc7 5109 return ret;
265a7a2a
ZJS
5110}
5111
8fcf784d
LP
5112static int show_system_status(sd_bus *bus) {
5113 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
5114 _cleanup_free_ char *hn = NULL;
e7e55dbd 5115 _cleanup_(machine_info_clear) struct machine_info mi = {};
8fcf784d
LP
5116 const char *on, *off;
5117 int r;
5118
5119 hn = gethostname_malloc();
5120 if (!hn)
5121 return log_oom();
5122
5123 r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, &mi);
f647962d
MS
5124 if (r < 0)
5125 return log_error_errno(r, "Failed to read server status: %m");
8fcf784d 5126
8fcf784d
LP
5127 if (streq_ptr(mi.state, "degraded")) {
5128 on = ansi_highlight_red();
1fc464f6 5129 off = ansi_normal();
8fcf784d
LP
5130 } else if (!streq_ptr(mi.state, "running")) {
5131 on = ansi_highlight_yellow();
1fc464f6 5132 off = ansi_normal();
8fcf784d
LP
5133 } else
5134 on = off = "";
5135
323b7dc9 5136 printf("%s%s%s %s\n", on, special_glyph(BLACK_CIRCLE), off, arg_host ? arg_host : hn);
b0d14c69 5137
8fcf784d
LP
5138 printf(" State: %s%s%s\n",
5139 on, strna(mi.state), off);
5140
c6ba5b80
MP
5141 printf(" Jobs: %" PRIu32 " queued\n", mi.n_jobs);
5142 printf(" Failed: %" PRIu32 " units\n", mi.n_failed_units);
8fcf784d
LP
5143
5144 printf(" Since: %s; %s\n",
5145 format_timestamp(since2, sizeof(since2), mi.timestamp),
5146 format_timestamp_relative(since1, sizeof(since1), mi.timestamp));
5147
5148 printf(" CGroup: %s\n", mi.control_group ?: "/");
4c315c2c
IS
5149 if (IN_SET(arg_transport,
5150 BUS_TRANSPORT_LOCAL,
5151 BUS_TRANSPORT_MACHINE)) {
8fcf784d
LP
5152 static const char prefix[] = " ";
5153 unsigned c;
5154
5155 c = columns();
5156 if (c > sizeof(prefix) - 1)
5157 c -= sizeof(prefix) - 1;
5158 else
5159 c = 0;
5160
0ff308c8 5161 show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, get_output_flags());
8fcf784d
LP
5162 }
5163
8fcf784d
LP
5164 return 0;
5165}
5166
e449de87
LP
5167static int show(int argc, char *argv[], void *userdata) {
5168 bool show_properties, show_status, show_help, new_line = false;
94e0bd7d 5169 bool ellipsized = false;
e3e0314b 5170 int r, ret = 0;
4fbd7192 5171 sd_bus *bus;
48220598 5172
e449de87 5173 assert(argv);
48220598 5174
e449de87
LP
5175 show_properties = streq(argv[0], "show");
5176 show_status = streq(argv[0], "status");
5177 show_help = streq(argv[0], "help");
5178
5179 if (show_help && argc <= 1) {
5180 log_error("This command expects one or more unit names. Did you mean --help?");
5181 return -EINVAL;
5182 }
61cbdc4b 5183
d2ad7e1b
ZJS
5184 r = acquire_bus(BUS_MANAGER, &bus);
5185 if (r < 0)
5186 return r;
5187
ea4b98e6 5188 pager_open(arg_no_pager, false);
ec14911e 5189
40acc203
ZJS
5190 if (show_status)
5191 /* Increase max number of open files to 16K if we can, we
5192 * might needs this when browsing journal files, which might
5193 * be split up into many files. */
5194 setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
5195
4fbd7192 5196 /* If no argument is specified inspect the manager itself */
e449de87 5197 if (show_properties && argc <= 1)
3dced37b 5198 return show_one(argv[0], bus, "/org/freedesktop/systemd1", NULL, show_properties, &new_line, &ellipsized);
48220598 5199
e449de87 5200 if (show_status && argc <= 1) {
8fcf784d 5201
8fcf784d
LP
5202 show_system_status(bus);
5203 new_line = true;
5204
5205 if (arg_all)
e449de87 5206 ret = show_all(argv[0], bus, false, &new_line, &ellipsized);
8fcf784d 5207 } else {
e3e0314b
ZJS
5208 _cleanup_free_ char **patterns = NULL;
5209 char **name;
5210
e449de87 5211 STRV_FOREACH(name, strv_skip(argv, 1)) {
3dced37b 5212 _cleanup_free_ char *path = NULL, *unit = NULL;
94e0bd7d 5213 uint32_t id;
48220598 5214
94e0bd7d 5215 if (safe_atou32(*name, &id) < 0) {
e3e0314b 5216 if (strv_push(&patterns, *name) < 0)
94e0bd7d 5217 return log_oom();
48220598 5218
e3e0314b 5219 continue;
94e0bd7d 5220 } else if (show_properties) {
94e0bd7d 5221 /* Interpret as job id */
3dced37b 5222 if (asprintf(&path, "/org/freedesktop/systemd1/job/%u", id) < 0)
94e0bd7d 5223 return log_oom();
48220598 5224
94e0bd7d
ZJS
5225 } else {
5226 /* Interpret as PID */
3dced37b 5227 r = get_unit_dbus_path_by_pid(bus, id, &path);
373d32c9 5228 if (r < 0) {
94e0bd7d 5229 ret = r;
373d32c9
LP
5230 continue;
5231 }
3dced37b
LP
5232
5233 r = unit_name_from_dbus_path(path, &unit);
5234 if (r < 0)
5235 return log_oom();
94e0bd7d 5236 }
f74294c1 5237
3dced37b 5238 r = show_one(argv[0], bus, path, unit, show_properties, &new_line, &ellipsized);
5bb75bc7
ZJS
5239 if (r < 0)
5240 return r;
5241 else if (r > 0 && ret == 0)
5242 ret = r;
48220598 5243 }
94e0bd7d 5244
e3e0314b
ZJS
5245 if (!strv_isempty(patterns)) {
5246 _cleanup_strv_free_ char **names = NULL;
5247
5248 r = expand_names(bus, patterns, NULL, &names);
5249 if (r < 0)
691395d8 5250 return log_error_errno(r, "Failed to expand names: %m");
e3e0314b
ZJS
5251
5252 STRV_FOREACH(name, names) {
3dced37b 5253 _cleanup_free_ char *path;
e3e0314b 5254
3dced37b
LP
5255 path = unit_dbus_path_from_name(*name);
5256 if (!path)
e3e0314b
ZJS
5257 return log_oom();
5258
3dced37b 5259 r = show_one(argv[0], bus, path, *name, show_properties, &new_line, &ellipsized);
5bb75bc7
ZJS
5260 if (r < 0)
5261 return r;
3dced37b 5262 if (r > 0 && ret == 0)
5bb75bc7 5263 ret = r;
e3e0314b
ZJS
5264 }
5265 }
5266 }
5267
94e0bd7d
ZJS
5268 if (ellipsized && !arg_quiet)
5269 printf("Hint: Some lines were ellipsized, use -l to show in full.\n");
48220598 5270
22f4096c 5271 return ret;
0183528f
LP
5272}
5273
8527b07b
ZJS
5274static int cat_file(const char *filename, bool newline) {
5275 _cleanup_close_ int fd;
5276
5277 fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOCTTY);
5278 if (fd < 0)
5279 return -errno;
5280
5281 printf("%s%s# %s%s\n",
5282 newline ? "\n" : "",
5283 ansi_highlight_blue(),
5284 filename,
1fc464f6 5285 ansi_normal());
8527b07b
ZJS
5286 fflush(stdout);
5287
59f448cf 5288 return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, false);
8527b07b
ZJS
5289}
5290
e449de87 5291static int cat(int argc, char *argv[], void *userdata) {
ad2a0358 5292 _cleanup_lookup_paths_free_ LookupPaths lp = {};
15ef1144
LP
5293 _cleanup_strv_free_ char **names = NULL;
5294 char **name;
4fbd7192
LP
5295 sd_bus *bus;
5296 bool first = true;
25586912 5297 int r;
15ef1144 5298
3e7eed84 5299 if (arg_transport != BUS_TRANSPORT_LOCAL) {
4fbd7192 5300 log_error("Cannot remotely cat units.");
3e495a66
ZJS
5301 return -EINVAL;
5302 }
5303
4943d143 5304 r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
ad2a0358 5305 if (r < 0)
c51932be 5306 return log_error_errno(r, "Failed to determine unit paths: %m");
ad2a0358 5307
4fbd7192 5308 r = acquire_bus(BUS_MANAGER, &bus);
15ef1144 5309 if (r < 0)
4fbd7192 5310 return r;
15ef1144 5311
e449de87 5312 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
4fbd7192
LP
5313 if (r < 0)
5314 return log_error_errno(r, "Failed to expand names: %m");
ad2a0358 5315
ea4b98e6 5316 pager_open(arg_no_pager, false);
15ef1144
LP
5317
5318 STRV_FOREACH(name, names) {
ad2a0358 5319 _cleanup_free_ char *fragment_path = NULL;
15ef1144 5320 _cleanup_strv_free_ char **dropin_paths = NULL;
15ef1144
LP
5321 char **path;
5322
4fbd7192 5323 r = unit_find_paths(bus, *name, &lp, &fragment_path, &dropin_paths);
ad2a0358
ZJS
5324 if (r < 0)
5325 return r;
b5e6a600
IS
5326 else if (r == 0)
5327 return -ENOENT;
15ef1144
LP
5328
5329 if (first)
5330 first = false;
5331 else
5332 puts("");
5333
5b9635d1 5334 if (need_daemon_reload(bus, *name) > 0) /* ignore errors (<0), this is informational output */
e100155d
LW
5335 fprintf(stderr,
5336 "%s# Warning: %s changed on disk, the version systemd has loaded is outdated.\n"
5337 "%s# This output shows the current version of the unit's original fragment and drop-in files.\n"
5338 "%s# If fragments or drop-ins were added or removed, they are not properly reflected in this output.\n"
5339 "%s# Run 'systemctl%s daemon-reload' to reload units.%s\n",
5340 ansi_highlight_red(),
5341 *name,
5342 ansi_highlight_red(),
5343 ansi_highlight_red(),
5344 ansi_highlight_red(),
5345 arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
5346 ansi_normal());
5347
ad2a0358 5348 if (fragment_path) {
8527b07b
ZJS
5349 r = cat_file(fragment_path, false);
5350 if (r < 0)
5351 return log_warning_errno(r, "Failed to cat %s: %m", fragment_path);
15ef1144
LP
5352 }
5353
5354 STRV_FOREACH(path, dropin_paths) {
8527b07b
ZJS
5355 r = cat_file(*path, path == dropin_paths);
5356 if (r < 0)
5357 return log_warning_errno(r, "Failed to cat %s: %m", *path);
15ef1144
LP
5358 }
5359 }
5360
25586912 5361 return 0;
15ef1144
LP
5362}
5363
e449de87 5364static int set_property(int argc, char *argv[], void *userdata) {
4afd3348
LP
5365 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
5366 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
68372da6 5367 _cleanup_free_ char *n = NULL;
4fbd7192 5368 sd_bus *bus;
8e2af478
LP
5369 int r;
5370
4fbd7192
LP
5371 r = acquire_bus(BUS_MANAGER, &bus);
5372 if (r < 0)
5373 return r;
5374
d2ad7e1b
ZJS
5375 polkit_agent_open_if_enabled();
5376
f459b602
MAP
5377 r = sd_bus_message_new_method_call(
5378 bus,
151b9b96 5379 &m,
8e2af478
LP
5380 "org.freedesktop.systemd1",
5381 "/org/freedesktop/systemd1",
5382 "org.freedesktop.systemd1.Manager",
151b9b96 5383 "SetUnitProperties");
f459b602
MAP
5384 if (r < 0)
5385 return bus_log_create_error(r);
8e2af478 5386
e449de87 5387 r = unit_name_mangle(argv[1], UNIT_NAME_NOGLOB, &n);
7410616c
LP
5388 if (r < 0)
5389 return log_error_errno(r, "Failed to mangle unit name: %m");
68372da6 5390
f459b602
MAP
5391 r = sd_bus_message_append(m, "sb", n, arg_runtime);
5392 if (r < 0)
5393 return bus_log_create_error(r);
8e2af478 5394
f459b602
MAP
5395 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, "(sv)");
5396 if (r < 0)
5397 return bus_log_create_error(r);
8e2af478 5398
8673cf13
LP
5399 r = bus_append_unit_property_assignment_many(m, strv_skip(argv, 2));
5400 if (r < 0)
5401 return r;
8e2af478 5402
f459b602
MAP
5403 r = sd_bus_message_close_container(m);
5404 if (r < 0)
5405 return bus_log_create_error(r);
8e2af478 5406
c49b30a2 5407 r = sd_bus_call(bus, m, 0, &error, NULL);
691395d8
LP
5408 if (r < 0)
5409 return log_error_errno(r, "Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
8e2af478
LP
5410
5411 return 0;
5412}
5413
e449de87 5414static int daemon_reload(int argc, char *argv[], void *userdata) {
4afd3348 5415 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2853b60a 5416 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
7e4249b9 5417 const char *method;
4fbd7192 5418 sd_bus *bus;
f459b602 5419 int r;
7e4249b9 5420
4fbd7192
LP
5421 r = acquire_bus(BUS_MANAGER, &bus);
5422 if (r < 0)
5423 return r;
5424
d2ad7e1b
ZJS
5425 polkit_agent_open_if_enabled();
5426
2853b60a
LP
5427 switch (arg_action) {
5428
5429 case ACTION_RELOAD:
e4b61340 5430 method = "Reload";
2853b60a
LP
5431 break;
5432
5433 case ACTION_REEXEC:
e4b61340 5434 method = "Reexecute";
2853b60a
LP
5435 break;
5436
5437 case ACTION_SYSTEMCTL:
5438 method = streq(argv[0], "daemon-reexec") ? "Reexecute" :
5439 /* "daemon-reload" */ "Reload";
5440 break;
e4b61340 5441
2853b60a
LP
5442 default:
5443 assert_not_reached("Unexpected action");
e4b61340 5444 }
7e4249b9 5445
2853b60a
LP
5446 r = sd_bus_message_new_method_call(
5447 bus,
5448 &m,
5449 "org.freedesktop.systemd1",
5450 "/org/freedesktop/systemd1",
5451 "org.freedesktop.systemd1.Manager",
5452 method);
5453 if (r < 0)
5454 return bus_log_create_error(r);
5455
5456 /* Note we use an extra-long timeout here. This is because a reload or reexec means generators are rerun which
5457 * are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the generators can have
5458 * their timeout, and for everything else there's the same time budget in place. */
5459
5460 r = sd_bus_call(bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL);
5461
5462 /* On reexecution, we expect a disconnect, not a reply */
5463 if (IN_SET(r, -ETIMEDOUT, -ECONNRESET) && streq(method, "Reexecute"))
5464 r = 0;
5465
5466 if (r < 0 && arg_action == ACTION_SYSTEMCTL)
5467 return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
5468
5469 /* Note that for the legacy commands (i.e. those with action != ACTION_SYSTEMCTL) we support fallbacks to the
5470 * old ways of doing things, hence don't log any error in that case here. */
5471
5472 return r < 0 ? r : 0;
5473}
5474
5475static int trivial_method(int argc, char *argv[], void *userdata) {
5476 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5477 const char *method;
5478 sd_bus *bus;
5479 int r;
5480
2853b60a
LP
5481 r = acquire_bus(BUS_MANAGER, &bus);
5482 if (r < 0)
5483 return r;
5484
d2ad7e1b
ZJS
5485 polkit_agent_open_if_enabled();
5486
2853b60a
LP
5487 method =
5488 streq(argv[0], "clear-jobs") ||
5489 streq(argv[0], "cancel") ? "ClearJobs" :
5490 streq(argv[0], "reset-failed") ? "ResetFailed" :
5491 streq(argv[0], "halt") ? "Halt" :
5492 streq(argv[0], "reboot") ? "Reboot" :
5493 streq(argv[0], "kexec") ? "KExec" :
5494 streq(argv[0], "exit") ? "Exit" :
5495 /* poweroff */ "PowerOff";
5496
6e646d22 5497 r = sd_bus_call_method(
f22f08cd
SP
5498 bus,
5499 "org.freedesktop.systemd1",
5500 "/org/freedesktop/systemd1",
5501 "org.freedesktop.systemd1.Manager",
6e646d22
LP
5502 method,
5503 &error,
5504 NULL,
5505 NULL);
2853b60a
LP
5506 if (r < 0 && arg_action == ACTION_SYSTEMCTL)
5507 return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
5508
5509 /* Note that for the legacy commands (i.e. those with action != ACTION_SYSTEMCTL) we support fallbacks to the
5510 * old ways of doing things, hence don't log any error in that case here. */
7e4249b9 5511
0a9776c2 5512 return r < 0 ? r : 0;
7e4249b9
LP
5513}
5514
e449de87 5515static int reset_failed(int argc, char *argv[], void *userdata) {
e3e0314b 5516 _cleanup_strv_free_ char **names = NULL;
4fbd7192 5517 sd_bus *bus;
f84190d8 5518 char **name;
e3e0314b 5519 int r, q;
5632e374 5520
e449de87 5521 if (argc <= 1)
2853b60a 5522 return trivial_method(argc, argv, userdata);
5632e374 5523
4fbd7192
LP
5524 r = acquire_bus(BUS_MANAGER, &bus);
5525 if (r < 0)
5526 return r;
5527
d2ad7e1b
ZJS
5528 polkit_agent_open_if_enabled();
5529
e449de87 5530 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
e3e0314b 5531 if (r < 0)
691395d8 5532 return log_error_errno(r, "Failed to expand names: %m");
f84190d8 5533
e3e0314b 5534 STRV_FOREACH(name, names) {
4afd3348 5535 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
342641fb 5536
6e646d22 5537 q = sd_bus_call_method(
f22f08cd 5538 bus,
b0193f1c
LP
5539 "org.freedesktop.systemd1",
5540 "/org/freedesktop/systemd1",
5541 "org.freedesktop.systemd1.Manager",
6e646d22
LP
5542 "ResetFailedUnit",
5543 &error,
5544 NULL,
5545 "s", *name);
e3e0314b 5546 if (q < 0) {
691395d8 5547 log_error_errno(q, "Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
e3e0314b
ZJS
5548 if (r == 0)
5549 r = q;
f459b602 5550 }
5632e374
LP
5551 }
5552
e3e0314b 5553 return r;
5632e374
LP
5554}
5555
e449de87 5556static int show_environment(int argc, char *argv[], void *userdata) {
4afd3348
LP
5557 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5558 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
f459b602 5559 const char *text;
4fbd7192 5560 sd_bus *bus;
7e4249b9 5561 int r;
7e4249b9 5562
4fbd7192
LP
5563 r = acquire_bus(BUS_MANAGER, &bus);
5564 if (r < 0)
5565 return r;
5566
d2ad7e1b
ZJS
5567 pager_open(arg_no_pager, false);
5568
f459b602 5569 r = sd_bus_get_property(
f22f08cd
SP
5570 bus,
5571 "org.freedesktop.systemd1",
5572 "/org/freedesktop/systemd1",
f459b602
MAP
5573 "org.freedesktop.systemd1.Manager",
5574 "Environment",
5575 &error,
f22f08cd 5576 &reply,
f459b602 5577 "as");
691395d8
LP
5578 if (r < 0)
5579 return log_error_errno(r, "Failed to get environment: %s", bus_error_message(&error, r));
7e4249b9 5580
f459b602
MAP
5581 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
5582 if (r < 0)
5583 return bus_log_parse_error(r);
7e4249b9 5584
f459b602 5585 while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0)
f84190d8 5586 puts(text);
f459b602
MAP
5587 if (r < 0)
5588 return bus_log_parse_error(r);
7e4249b9 5589
f459b602
MAP
5590 r = sd_bus_message_exit_container(reply);
5591 if (r < 0)
5592 return bus_log_parse_error(r);
7e4249b9 5593
f84190d8 5594 return 0;
7e4249b9
LP
5595}
5596
e449de87 5597static int switch_root(int argc, char *argv[], void *userdata) {
4afd3348 5598 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
f39d4a08
HH
5599 _cleanup_free_ char *cmdline_init = NULL;
5600 const char *root, *init;
4fbd7192 5601 sd_bus *bus;
f459b602 5602 int r;
957eb8ca 5603
4fbd7192
LP
5604 if (arg_transport != BUS_TRANSPORT_LOCAL) {
5605 log_error("Cannot switch root remotely.");
5606 return -EINVAL;
5607 }
5608
e449de87 5609 if (argc < 2 || argc > 3) {
957eb8ca
LP
5610 log_error("Wrong number of arguments.");
5611 return -EINVAL;
5612 }
5613
e449de87 5614 root = argv[1];
13068da8 5615
e449de87
LP
5616 if (argc >= 3)
5617 init = argv[2];
13068da8 5618 else {
f39d4a08
HH
5619 r = parse_env_file("/proc/cmdline", WHITESPACE,
5620 "init", &cmdline_init,
5621 NULL);
5622 if (r < 0)
da927ba9 5623 log_debug_errno(r, "Failed to parse /proc/cmdline: %m");
13068da8 5624
f39d4a08 5625 init = cmdline_init;
13068da8 5626 }
f459b602 5627
3c6f7c34 5628 init = empty_to_null(init);
f39d4a08
HH
5629 if (init) {
5630 const char *root_systemd_path = NULL, *root_init_path = NULL;
5631
63c372cb
LP
5632 root_systemd_path = strjoina(root, "/" SYSTEMD_BINARY_PATH);
5633 root_init_path = strjoina(root, "/", init);
f39d4a08
HH
5634
5635 /* If the passed init is actually the same as the
5636 * systemd binary, then let's suppress it. */
5637 if (files_same(root_init_path, root_systemd_path) > 0)
5638 init = NULL;
5639 }
13068da8 5640
4fbd7192
LP
5641 r = acquire_bus(BUS_MANAGER, &bus);
5642 if (r < 0)
5643 return r;
5644
f39d4a08 5645 log_debug("Switching root - root: %s; init: %s", root, strna(init));
957eb8ca 5646
f459b602 5647 r = sd_bus_call_method(
f22f08cd 5648 bus,
957eb8ca
LP
5649 "org.freedesktop.systemd1",
5650 "/org/freedesktop/systemd1",
5651 "org.freedesktop.systemd1.Manager",
f22f08cd 5652 "SwitchRoot",
f459b602 5653 &error,
f22f08cd 5654 NULL,
f459b602 5655 "ss", root, init);
691395d8
LP
5656 if (r < 0)
5657 return log_error_errno(r, "Failed to switch root: %s", bus_error_message(&error, r));
f459b602
MAP
5658
5659 return 0;
957eb8ca
LP
5660}
5661
e449de87 5662static int set_environment(int argc, char *argv[], void *userdata) {
4afd3348
LP
5663 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5664 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
7e4249b9 5665 const char *method;
4fbd7192 5666 sd_bus *bus;
31e767f7
LP
5667 int r;
5668
e449de87
LP
5669 assert(argc > 1);
5670 assert(argv);
7e4249b9 5671
4fbd7192
LP
5672 r = acquire_bus(BUS_MANAGER, &bus);
5673 if (r < 0)
5674 return r;
5675
d2ad7e1b
ZJS
5676 polkit_agent_open_if_enabled();
5677
e449de87 5678 method = streq(argv[0], "set-environment")
7e4249b9
LP
5679 ? "SetEnvironment"
5680 : "UnsetEnvironment";
5681
f459b602
MAP
5682 r = sd_bus_message_new_method_call(
5683 bus,
151b9b96 5684 &m,
31e767f7
LP
5685 "org.freedesktop.systemd1",
5686 "/org/freedesktop/systemd1",
5687 "org.freedesktop.systemd1.Manager",
151b9b96 5688 method);
f459b602
MAP
5689 if (r < 0)
5690 return bus_log_create_error(r);
7e4249b9 5691
e449de87 5692 r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
31e767f7 5693 if (r < 0)
f459b602 5694 return bus_log_create_error(r);
7e4249b9 5695
c49b30a2 5696 r = sd_bus_call(bus, m, 0, &error, NULL);
691395d8
LP
5697 if (r < 0)
5698 return log_error_errno(r, "Failed to set environment: %s", bus_error_message(&error, r));
7e4249b9 5699
f84190d8 5700 return 0;
7e4249b9
LP
5701}
5702
e449de87 5703static int import_environment(int argc, char *argv[], void *userdata) {
4afd3348
LP
5704 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5705 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
4fbd7192 5706 sd_bus *bus;
ac3efa8a
LP
5707 int r;
5708
4fbd7192
LP
5709 r = acquire_bus(BUS_MANAGER, &bus);
5710 if (r < 0)
5711 return r;
5712
d2ad7e1b
ZJS
5713 polkit_agent_open_if_enabled();
5714
ac3efa8a
LP
5715 r = sd_bus_message_new_method_call(
5716 bus,
151b9b96 5717 &m,
ac3efa8a
LP
5718 "org.freedesktop.systemd1",
5719 "/org/freedesktop/systemd1",
5720 "org.freedesktop.systemd1.Manager",
151b9b96 5721 "SetEnvironment");
ac3efa8a
LP
5722 if (r < 0)
5723 return bus_log_create_error(r);
5724
e449de87 5725 if (argc < 2)
ac3efa8a
LP
5726 r = sd_bus_message_append_strv(m, environ);
5727 else {
5728 char **a, **b;
5729
5730 r = sd_bus_message_open_container(m, 'a', "s");
5731 if (r < 0)
5732 return bus_log_create_error(r);
5733
e449de87 5734 STRV_FOREACH(a, strv_skip(argv, 1)) {
ac3efa8a
LP
5735
5736 if (!env_name_is_valid(*a)) {
5737 log_error("Not a valid environment variable name: %s", *a);
5738 return -EINVAL;
5739 }
5740
5741 STRV_FOREACH(b, environ) {
5742 const char *eq;
5743
5744 eq = startswith(*b, *a);
5745 if (eq && *eq == '=') {
5746
5747 r = sd_bus_message_append(m, "s", *b);
5748 if (r < 0)
5749 return bus_log_create_error(r);
5750
5751 break;
5752 }
5753 }
5754 }
5755
5756 r = sd_bus_message_close_container(m);
5757 }
5758 if (r < 0)
5759 return bus_log_create_error(r);
5760
5761 r = sd_bus_call(bus, m, 0, &error, NULL);
691395d8
LP
5762 if (r < 0)
5763 return log_error_errno(r, "Failed to import environment: %s", bus_error_message(&error, r));
ac3efa8a
LP
5764
5765 return 0;
5766}
5767
cbb13b2a 5768static int enable_sysv_units(const char *verb, char **args) {
729e3769 5769 int r = 0;
ee5762e3 5770
0f0467e6 5771#if defined(HAVE_SYSV_COMPAT)
fb15be83 5772 _cleanup_lookup_paths_free_ LookupPaths paths = {};
e735decc
LP
5773 unsigned f = 0;
5774
5775 /* Processes all SysV units, and reshuffles the array so that afterwards only the native units remain */
ee5762e3 5776
729e3769
LP
5777 if (arg_scope != UNIT_FILE_SYSTEM)
5778 return 0;
ee5762e3 5779
b41b9d2a
LP
5780 if (getenv_bool("SYSTEMCTL_SKIP_SYSV") > 0)
5781 return 0;
5782
4c315c2c
IS
5783 if (!STR_IN_SET(verb,
5784 "enable",
5785 "disable",
5786 "is-enabled"))
729e3769 5787 return 0;
ee5762e3 5788
4943d143 5789 r = lookup_paths_init(&paths, arg_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root);
729e3769
LP
5790 if (r < 0)
5791 return r;
ee5762e3 5792
729e3769 5793 r = 0;
a644abed 5794 while (args[f]) {
e735decc
LP
5795
5796 const char *argv[] = {
5797 ROOTLIBEXECDIR "/systemd-sysv-install",
5798 NULL,
5799 NULL,
5800 NULL,
5801 NULL,
5802 };
5803
05cae7f3 5804 _cleanup_free_ char *p = NULL, *q = NULL, *l = NULL;
729e3769 5805 bool found_native = false, found_sysv;
e735decc
LP
5806 siginfo_t status;
5807 const char *name;
729e3769 5808 unsigned c = 1;
729e3769 5809 pid_t pid;
e735decc 5810 int j;
ee5762e3 5811
a644abed 5812 name = args[f++];
ee5762e3 5813
729e3769
LP
5814 if (!endswith(name, ".service"))
5815 continue;
ee5762e3 5816
729e3769
LP
5817 if (path_is_absolute(name))
5818 continue;
ee5762e3 5819
e735decc 5820 j = unit_file_exists(arg_scope, &paths, name);
76ec966f 5821 if (j < 0 && !IN_SET(j, -ELOOP, -ERFKILL, -EADDRNOTAVAIL))
e735decc 5822 return log_error_errno(j, "Failed to lookup unit file state: %m");
3c6d8e57 5823 found_native = j != 0;
ee5762e3 5824
e735decc
LP
5825 /* If we have both a native unit and a SysV script, enable/disable them both (below); for is-enabled,
5826 * prefer the native unit */
355ff449 5827 if (found_native && streq(verb, "is-enabled"))
729e3769 5828 continue;
ee5762e3 5829
0c6ea3a4
ZJS
5830 p = path_join(arg_root, SYSTEM_SYSVINIT_PATH, name);
5831 if (!p)
60731f32 5832 return log_oom();
ee5762e3 5833
05cae7f3 5834 p[strlen(p) - strlen(".service")] = 0;
729e3769 5835 found_sysv = access(p, F_OK) >= 0;
4b6756a8 5836 if (!found_sysv)
729e3769 5837 continue;
71fad675 5838
689e4e6a
CR
5839 if (!arg_quiet) {
5840 if (found_native)
5841 log_info("Synchronizing state of %s with SysV service script with %s.", name, argv[0]);
5842 else
5843 log_info("%s is not a native service, redirecting to systemd-sysv-install.", name);
5844 }
ee5762e3 5845
729e3769
LP
5846 if (!isempty(arg_root))
5847 argv[c++] = q = strappend("--root=", arg_root);
ee5762e3 5848
0f0467e6 5849 argv[c++] = verb;
2b6bf07d 5850 argv[c++] = basename(p);
729e3769 5851 argv[c] = NULL;
ee5762e3 5852
729e3769 5853 l = strv_join((char**)argv, " ");
60731f32
ZJS
5854 if (!l)
5855 return log_oom();
ee5762e3 5856
e735decc 5857 log_info("Executing: %s", l);
ee5762e3 5858
729e3769 5859 pid = fork();
4a62c710
MS
5860 if (pid < 0)
5861 return log_error_errno(errno, "Failed to fork: %m");
5862 else if (pid == 0) {
729e3769 5863 /* Child */
ee5762e3 5864
ce30c8dc
LP
5865 (void) reset_all_signal_handlers();
5866 (void) reset_signal_mask();
5867
729e3769 5868 execv(argv[0], (char**) argv);
cc7cb0ca 5869 log_error_errno(errno, "Failed to execute %s: %m", argv[0]);
729e3769
LP
5870 _exit(EXIT_FAILURE);
5871 }
ee5762e3 5872
729e3769 5873 j = wait_for_terminate(pid, &status);
d710aaf7
ZJS
5874 if (j < 0)
5875 return log_error_errno(j, "Failed to wait for child: %m");
ee5762e3 5876
729e3769
LP
5877 if (status.si_code == CLD_EXITED) {
5878 if (streq(verb, "is-enabled")) {
5879 if (status.si_status == 0) {
5880 if (!arg_quiet)
5881 puts("enabled");
5882 r = 1;
5883 } else {
5884 if (!arg_quiet)
5885 puts("disabled");
5886 }
ee5762e3 5887
60731f32 5888 } else if (status.si_status != 0)
c61b443d
LP
5889 return -EBADE; /* We don't warn here, under the assumption the script already showed an explanation */
5890 } else {
5891 log_error("Unexpected waitid() result.");
60731f32 5892 return -EPROTO;
c61b443d 5893 }
ee5762e3 5894
355ff449
MP
5895 if (found_native)
5896 continue;
5897
a644abed 5898 /* Remove this entry, so that we don't try enabling it as native unit */
aba84331
LP
5899 assert(f > 0);
5900 f--;
5901 assert(args[f] == name);
5902 strv_remove(args, name);
729e3769 5903 }
ee5762e3 5904
729e3769
LP
5905#endif
5906 return r;
5907}
ee5762e3 5908
37370d0c 5909static int mangle_names(char **original_names, char ***mangled_names) {
a33fdebb 5910 char **i, **l, **name;
7410616c 5911 int r;
37370d0c 5912
7410616c 5913 l = i = new(char*, strv_length(original_names) + 1);
a33fdebb 5914 if (!l)
37370d0c
VP
5915 return log_oom();
5916
37370d0c 5917 STRV_FOREACH(name, original_names) {
44386fc1
LN
5918
5919 /* When enabling units qualified path names are OK,
5920 * too, hence allow them explicitly. */
5921
7410616c 5922 if (is_path(*name)) {
44386fc1 5923 *i = strdup(*name);
7410616c
LP
5924 if (!*i) {
5925 strv_free(l);
5926 return log_oom();
5927 }
5928 } else {
5929 r = unit_name_mangle(*name, UNIT_NAME_NOGLOB, i);
5930 if (r < 0) {
5931 strv_free(l);
5932 return log_error_errno(r, "Failed to mangle unit name: %m");
5933 }
a33fdebb
LP
5934 }
5935
5936 i++;
37370d0c 5937 }
a33fdebb
LP
5938
5939 *i = NULL;
5940 *mangled_names = l;
37370d0c
VP
5941
5942 return 0;
5943}
5944
1d3c86c0
MS
5945static int normalize_names(char **names, bool warn_if_path) {
5946 char **u;
5947 bool was_path = false;
5948
5949 STRV_FOREACH(u, names) {
5950 int r;
5951
5952 if (!is_path(*u))
5953 continue;
5954
5955 r = free_and_strdup(u, basename(*u));
5956 if (r < 0)
5957 return log_error_errno(r, "Failed to normalize unit file path: %m");
5958
5959 was_path = true;
5960 }
5961
5962 if (warn_if_path && was_path)
5963 log_warning("Warning: Can't execute disable on the unit file path. Proceeding with the unit name.");
5964
5965 return 0;
5966}
5967
d6568222 5968static int unit_exists(const char *unit) {
ba19c6e1 5969 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
d6568222
SS
5970 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5971 _cleanup_free_ char *path = NULL;
5972 static const struct bus_properties_map property_map[] = {
662bea67
ZJS
5973 { "LoadState", "s", map_string_no_copy, offsetof(UnitStatusInfo, load_state) },
5974 { "ActiveState", "s", map_string_no_copy, offsetof(UnitStatusInfo, active_state)},
d6568222
SS
5975 {},
5976 };
5977 UnitStatusInfo info = {};
5978 sd_bus *bus;
5979 int r;
5980
5981 path = unit_dbus_path_from_name(unit);
5982 if (!path)
5983 return log_oom();
5984
5985 r = acquire_bus(BUS_MANAGER, &bus);
5986 if (r < 0)
5987 return r;
5988
5989 r = sd_bus_call_method(
5990 bus,
5991 "org.freedesktop.systemd1",
5992 path,
5993 "org.freedesktop.DBus.Properties",
5994 "GetAll",
5995 &error,
5996 &reply,
5997 "s", "");
5998 if (r < 0)
5999 return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
6000
6001 r = bus_message_map_all_properties(reply, property_map, &info);
6002 if (r < 0)
6003 return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r));
6004
6005 return !streq_ptr(info.load_state, "not-found") || !streq_ptr(info.active_state, "inactive");
6006}
6007
e449de87 6008static int enable_unit(int argc, char *argv[], void *userdata) {
e3e0314b 6009 _cleanup_strv_free_ char **names = NULL;
e449de87 6010 const char *verb = argv[0];
729e3769 6011 UnitFileChange *changes = NULL;
718db961 6012 unsigned n_changes = 0;
729e3769 6013 int carries_install_info = -1;
35b132e8 6014 bool ignore_carries_install_info = arg_quiet;
729e3769 6015 int r;
ee5762e3 6016
e449de87 6017 if (!argv[1])
ab5919fa
MS
6018 return 0;
6019
e449de87 6020 r = mangle_names(strv_skip(argv, 1), &names);
3a05c0f9 6021 if (r < 0)
cbb13b2a
VP
6022 return r;
6023
e3e0314b 6024 r = enable_sysv_units(verb, names);
cbb13b2a
VP
6025 if (r < 0)
6026 return r;
3a05c0f9 6027
c61b443d 6028 /* If the operation was fully executed by the SysV compat, let's finish early */
823e5fab
FB
6029 if (strv_isempty(names)) {
6030 if (arg_no_reload || install_client_side())
6031 return 0;
6032 return daemon_reload(argc, argv, userdata);
6033 }
67d66210 6034
1d3c86c0
MS
6035 if (streq(verb, "disable")) {
6036 r = normalize_names(names, true);
6037 if (r < 0)
6038 return r;
6039 }
6040
4fbd7192 6041 if (install_client_side()) {
b3796dd8
JS
6042 UnitFileFlags flags;
6043
6044 flags = args_to_flags();
729e3769 6045 if (streq(verb, "enable")) {
b3796dd8 6046 r = unit_file_enable(arg_scope, flags, arg_root, names, &changes, &n_changes);
729e3769
LP
6047 carries_install_info = r;
6048 } else if (streq(verb, "disable"))
b3796dd8 6049 r = unit_file_disable(arg_scope, flags, arg_root, names, &changes, &n_changes);
729e3769 6050 else if (streq(verb, "reenable")) {
b3796dd8 6051 r = unit_file_reenable(arg_scope, flags, arg_root, names, &changes, &n_changes);
729e3769
LP
6052 carries_install_info = r;
6053 } else if (streq(verb, "link"))
b3796dd8 6054 r = unit_file_link(arg_scope, flags, arg_root, names, &changes, &n_changes);
729e3769 6055 else if (streq(verb, "preset")) {
b3796dd8 6056 r = unit_file_preset(arg_scope, flags, arg_root, names, arg_preset_mode, &changes, &n_changes);
729e3769 6057 } else if (streq(verb, "mask"))
b3796dd8 6058 r = unit_file_mask(arg_scope, flags, arg_root, names, &changes, &n_changes);
729e3769 6059 else if (streq(verb, "unmask"))
b3796dd8 6060 r = unit_file_unmask(arg_scope, flags, arg_root, names, &changes, &n_changes);
344ca755
LP
6061 else if (streq(verb, "revert"))
6062 r = unit_file_revert(arg_scope, arg_root, names, &changes, &n_changes);
729e3769
LP
6063 else
6064 assert_not_reached("Unknown verb");
ee5762e3 6065
af3d8113 6066 unit_file_dump_changes(r, verb, changes, n_changes, arg_quiet);
d073dea0 6067 if (r < 0)
85b78539 6068 goto finish;
df77cdf0 6069 r = 0;
729e3769 6070 } else {
4afd3348
LP
6071 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
6072 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
39207373 6073 bool expect_carries_install_info = false;
344ca755 6074 bool send_runtime = true, send_force = true, send_preset_mode = false;
718db961 6075 const char *method;
4fbd7192 6076 sd_bus *bus;
729e3769 6077
d6568222
SS
6078 if (STR_IN_SET(verb, "mask", "unmask")) {
6079 r = unit_exists(*names);
6080 if (r < 0)
6081 return r;
6082 if (r == 0)
6083 log_notice("Unit %s does not exist, proceeding anyway.", *names);
6084 }
6085
4fbd7192
LP
6086 r = acquire_bus(BUS_MANAGER, &bus);
6087 if (r < 0)
6088 return r;
6089
d2ad7e1b
ZJS
6090 polkit_agent_open_if_enabled();
6091
729e3769
LP
6092 if (streq(verb, "enable")) {
6093 method = "EnableUnitFiles";
6094 expect_carries_install_info = true;
6095 } else if (streq(verb, "disable")) {
6096 method = "DisableUnitFiles";
6097 send_force = false;
6098 } else if (streq(verb, "reenable")) {
6099 method = "ReenableUnitFiles";
6100 expect_carries_install_info = true;
6101 } else if (streq(verb, "link"))
6102 method = "LinkUnitFiles";
6103 else if (streq(verb, "preset")) {
d309c1c3
LP
6104
6105 if (arg_preset_mode != UNIT_FILE_PRESET_FULL) {
6106 method = "PresetUnitFilesWithMode";
6107 send_preset_mode = true;
6108 } else
6109 method = "PresetUnitFiles";
6110
729e3769 6111 expect_carries_install_info = true;
39207373 6112 ignore_carries_install_info = true;
729e3769
LP
6113 } else if (streq(verb, "mask"))
6114 method = "MaskUnitFiles";
6115 else if (streq(verb, "unmask")) {
6116 method = "UnmaskUnitFiles";
6117 send_force = false;
344ca755
LP
6118 } else if (streq(verb, "revert")) {
6119 method = "RevertUnitFiles";
6120 send_runtime = send_force = false;
729e3769
LP
6121 } else
6122 assert_not_reached("Unknown verb");
6123
f459b602
MAP
6124 r = sd_bus_message_new_method_call(
6125 bus,
151b9b96 6126 &m,
729e3769
LP
6127 "org.freedesktop.systemd1",
6128 "/org/freedesktop/systemd1",
6129 "org.freedesktop.systemd1.Manager",
151b9b96 6130 method);
f459b602
MAP
6131 if (r < 0)
6132 return bus_log_create_error(r);
ee5762e3 6133
e3e0314b 6134 r = sd_bus_message_append_strv(m, names);
f459b602
MAP
6135 if (r < 0)
6136 return bus_log_create_error(r);
ee5762e3 6137
d309c1c3
LP
6138 if (send_preset_mode) {
6139 r = sd_bus_message_append(m, "s", unit_file_preset_mode_to_string(arg_preset_mode));
6140 if (r < 0)
6141 return bus_log_create_error(r);
6142 }
6143
344ca755
LP
6144 if (send_runtime) {
6145 r = sd_bus_message_append(m, "b", arg_runtime);
6146 if (r < 0)
6147 return bus_log_create_error(r);
6148 }
ee5762e3 6149
729e3769 6150 if (send_force) {
f459b602
MAP
6151 r = sd_bus_message_append(m, "b", arg_force);
6152 if (r < 0)
6153 return bus_log_create_error(r);
ee5762e3
LP
6154 }
6155
c49b30a2 6156 r = sd_bus_call(bus, m, 0, &error, &reply);
691395d8 6157 if (r < 0)
af3d8113 6158 return log_error_errno(r, "Failed to %s unit: %s", verb, bus_error_message(&error, r));
be394c48 6159
729e3769 6160 if (expect_carries_install_info) {
f459b602
MAP
6161 r = sd_bus_message_read(reply, "b", &carries_install_info);
6162 if (r < 0)
6163 return bus_log_parse_error(r);
ee5762e3
LP
6164 }
6165
57ab2eab 6166 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
f459b602 6167 if (r < 0)
85b78539 6168 goto finish;
b77398f7 6169
93c941e3 6170 /* Try to reload if enabled */
d6cb60c7 6171 if (!arg_no_reload)
e449de87 6172 r = daemon_reload(argc, argv, userdata);
f459b602
MAP
6173 else
6174 r = 0;
b647f10d 6175 }
3d3961f2 6176
39207373 6177 if (carries_install_info == 0 && !ignore_carries_install_info)
fe4aede9
ZJS
6178 log_warning("The unit files have no installation config (WantedBy, RequiredBy, Also, Alias\n"
6179 "settings in the [Install] section, and DefaultInstance for template units).\n"
6180 "This means they are not meant to be enabled using systemctl.\n"
416389f7
LP
6181 "Possible reasons for having this kind of units are:\n"
6182 "1) A unit may be statically enabled by being symlinked from another unit's\n"
6183 " .wants/ or .requires/ directory.\n"
6184 "2) A unit's purpose may be to act as a helper for some other unit which has\n"
6185 " a requirement dependency on it.\n"
6186 "3) A unit may be started when needed via activation (socket, path, timer,\n"
fe4aede9
ZJS
6187 " D-Bus, udev, scripted systemctl call, ...).\n"
6188 "4) In case of template units, the unit is meant to be enabled with some\n"
6189 " instance name specified.");
ee5762e3 6190
e449de87 6191 if (arg_now && n_changes > 0 && STR_IN_SET(argv[0], "enable", "disable", "mask")) {
57ab2eab 6192 char *new_args[n_changes + 2];
4fbd7192 6193 sd_bus *bus;
57ab2eab
JS
6194 unsigned i;
6195
4fbd7192
LP
6196 r = acquire_bus(BUS_MANAGER, &bus);
6197 if (r < 0)
d073dea0 6198 goto finish;
4fbd7192 6199
e449de87 6200 new_args[0] = (char*) (streq(argv[0], "enable") ? "start" : "stop");
57ab2eab
JS
6201 for (i = 0; i < n_changes; i++)
6202 new_args[i + 1] = basename(changes[i].path);
6203 new_args[i + 1] = NULL;
6204
e449de87 6205 r = start_unit(strv_length(new_args), new_args, userdata);
57ab2eab
JS
6206 }
6207
729e3769 6208finish:
729e3769 6209 unit_file_changes_free(changes, n_changes);
ee5762e3 6210
729e3769 6211 return r;
ee5762e3
LP
6212}
6213
e449de87 6214static int add_dependency(int argc, char *argv[], void *userdata) {
e94937df
LN
6215 _cleanup_strv_free_ char **names = NULL;
6216 _cleanup_free_ char *target = NULL;
e449de87 6217 const char *verb = argv[0];
acc0269c
CH
6218 UnitFileChange *changes = NULL;
6219 unsigned n_changes = 0;
e94937df
LN
6220 UnitDependency dep;
6221 int r = 0;
6222
e449de87 6223 if (!argv[1])
e94937df
LN
6224 return 0;
6225
e449de87 6226 r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".target", &target);
7410616c
LP
6227 if (r < 0)
6228 return log_error_errno(r, "Failed to mangle unit name: %m");
e94937df 6229
e449de87 6230 r = mangle_names(strv_skip(argv, 2), &names);
e94937df
LN
6231 if (r < 0)
6232 return r;
6233
6234 if (streq(verb, "add-wants"))
6235 dep = UNIT_WANTS;
6236 else if (streq(verb, "add-requires"))
6237 dep = UNIT_REQUIRES;
6238 else
6239 assert_not_reached("Unknown verb");
6240
4fbd7192 6241 if (install_client_side()) {
b3796dd8 6242 r = unit_file_add_dependency(arg_scope, args_to_flags(), arg_root, names, target, dep, &changes, &n_changes);
af3d8113 6243 unit_file_dump_changes(r, "add dependency on", changes, n_changes, arg_quiet);
5f056378
CH
6244
6245 if (r > 0)
6246 r = 0;
e94937df 6247 } else {
4afd3348
LP
6248 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
6249 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192 6250 sd_bus *bus;
e94937df 6251
4fbd7192
LP
6252 r = acquire_bus(BUS_MANAGER, &bus);
6253 if (r < 0)
6254 return r;
6255
d2ad7e1b
ZJS
6256 polkit_agent_open_if_enabled();
6257
e94937df
LN
6258 r = sd_bus_message_new_method_call(
6259 bus,
6260 &m,
6261 "org.freedesktop.systemd1",
6262 "/org/freedesktop/systemd1",
6263 "org.freedesktop.systemd1.Manager",
6264 "AddDependencyUnitFiles");
6265 if (r < 0)
6266 return bus_log_create_error(r);
6267
342641fb 6268 r = sd_bus_message_append_strv(m, names);
e94937df
LN
6269 if (r < 0)
6270 return bus_log_create_error(r);
6271
342641fb 6272 r = sd_bus_message_append(m, "ssbb", target, unit_dependency_to_string(dep), arg_runtime, arg_force);
e94937df
LN
6273 if (r < 0)
6274 return bus_log_create_error(r);
6275
6276 r = sd_bus_call(bus, m, 0, &error, &reply);
691395d8 6277 if (r < 0)
af3d8113 6278 return log_error_errno(r, "Failed to add dependency: %s", bus_error_message(&error, r));
e94937df 6279
acc0269c 6280 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
e94937df 6281 if (r < 0)
acc0269c 6282 goto finish;
e94937df 6283
acc0269c
CH
6284 if (arg_no_reload) {
6285 r = 0;
6286 goto finish;
6287 }
6288
6289 r = daemon_reload(argc, argv, userdata);
e94937df 6290 }
acc0269c
CH
6291
6292finish:
6293 unit_file_changes_free(changes, n_changes);
6294
6295 return r;
e94937df
LN
6296}
6297
e449de87 6298static int preset_all(int argc, char *argv[], void *userdata) {
acc0269c
CH
6299 UnitFileChange *changes = NULL;
6300 unsigned n_changes = 0;
d309c1c3
LP
6301 int r;
6302
4fbd7192 6303 if (install_client_side()) {
b3796dd8 6304 r = unit_file_preset_all(arg_scope, args_to_flags(), arg_root, arg_preset_mode, &changes, &n_changes);
af3d8113 6305 unit_file_dump_changes(r, "preset", changes, n_changes, arg_quiet);
5f056378
CH
6306
6307 if (r > 0)
6308 r = 0;
d309c1c3 6309 } else {
4afd3348
LP
6310 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
6311 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
4fbd7192 6312 sd_bus *bus;
d309c1c3 6313
4fbd7192
LP
6314 r = acquire_bus(BUS_MANAGER, &bus);
6315 if (r < 0)
6316 return r;
6317
d2ad7e1b
ZJS
6318 polkit_agent_open_if_enabled();
6319
6e646d22 6320 r = sd_bus_call_method(
d309c1c3
LP
6321 bus,
6322 "org.freedesktop.systemd1",
6323 "/org/freedesktop/systemd1",
6324 "org.freedesktop.systemd1.Manager",
6e646d22
LP
6325 "PresetAllUnitFiles",
6326 &error,
6327 &reply,
d309c1c3
LP
6328 "sbb",
6329 unit_file_preset_mode_to_string(arg_preset_mode),
6330 arg_runtime,
6331 arg_force);
691395d8 6332 if (r < 0)
af3d8113 6333 return log_error_errno(r, "Failed to preset all units: %s", bus_error_message(&error, r));
d309c1c3 6334
acc0269c 6335 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
d309c1c3 6336 if (r < 0)
acc0269c 6337 goto finish;
d309c1c3 6338
acc0269c
CH
6339 if (arg_no_reload) {
6340 r = 0;
6341 goto finish;
6342 }
6343
6344 r = daemon_reload(argc, argv, userdata);
d309c1c3 6345 }
acc0269c
CH
6346
6347finish:
6348 unit_file_changes_free(changes, n_changes);
6349
6350 return r;
d309c1c3
LP
6351}
6352
3b3557c4
JS
6353static int show_installation_targets_client_side(const char *name) {
6354 UnitFileChange *changes = NULL;
6355 unsigned n_changes = 0, i;
6356 UnitFileFlags flags;
6357 char **p;
6358 int r;
6359
6360 p = STRV_MAKE(name);
6361 flags = UNIT_FILE_DRY_RUN |
6362 (arg_runtime ? UNIT_FILE_RUNTIME : 0);
6363
6364 r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes);
6365 if (r < 0)
6366 return log_error_errno(r, "Failed to get file links for %s: %m", name);
6367
6368 for (i = 0; i < n_changes; i++)
6369 if (changes[i].type == UNIT_FILE_UNLINK)
6370 printf(" %s\n", changes[i].path);
6371
6372 return 0;
6373}
6374
6375static int show_installation_targets(sd_bus *bus, const char *name) {
6376 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
6377 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
6378 const char *link;
6379 int r;
6380
6381 r = sd_bus_call_method(
6382 bus,
6383 "org.freedesktop.systemd1",
6384 "/org/freedesktop/systemd1",
6385 "org.freedesktop.systemd1.Manager",
6386 "GetUnitFileLinks",
6387 &error,
6388 &reply,
6389 "sb", name, arg_runtime);
6390 if (r < 0)
6391 return log_error_errno(r, "Failed to get unit file links for %s: %s", name, bus_error_message(&error, r));
6392
6393 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
6394 if (r < 0)
6395 return bus_log_parse_error(r);
6396
6397 while ((r = sd_bus_message_read(reply, "s", &link)) > 0)
6398 printf(" %s\n", link);
6399
6400 if (r < 0)
6401 return bus_log_parse_error(r);
6402
6403 r = sd_bus_message_exit_container(reply);
6404 if (r < 0)
6405 return bus_log_parse_error(r);
6406
6407 return 0;
6408}
6409
e449de87 6410static int unit_is_enabled(int argc, char *argv[], void *userdata) {
f459b602 6411
e3e0314b 6412 _cleanup_strv_free_ char **names = NULL;
729e3769
LP
6413 bool enabled;
6414 char **name;
f459b602 6415 int r;
ee5762e3 6416
e449de87 6417 r = mangle_names(strv_skip(argv, 1), &names);
cbb13b2a
VP
6418 if (r < 0)
6419 return r;
6420
e449de87 6421 r = enable_sysv_units(argv[0], names);
729e3769
LP
6422 if (r < 0)
6423 return r;
ee5762e3 6424
729e3769 6425 enabled = r > 0;
ee5762e3 6426
4fbd7192 6427 if (install_client_side()) {
e3e0314b 6428 STRV_FOREACH(name, names) {
729e3769 6429 UnitFileState state;
ee5762e3 6430
0ec0deaa
LP
6431 r = unit_file_get_state(arg_scope, arg_root, *name, &state);
6432 if (r < 0)
f647962d 6433 return log_error_errno(state, "Failed to get unit file state for %s: %m", *name);
ee5762e3 6434
4c315c2c
IS
6435 if (IN_SET(state,
6436 UNIT_FILE_ENABLED,
6437 UNIT_FILE_ENABLED_RUNTIME,
6438 UNIT_FILE_STATIC,
f4139308
LP
6439 UNIT_FILE_INDIRECT,
6440 UNIT_FILE_GENERATED))
729e3769
LP
6441 enabled = true;
6442
3b3557c4 6443 if (!arg_quiet) {
729e3769 6444 puts(unit_file_state_to_string(state));
3b3557c4
JS
6445 if (arg_full) {
6446 r = show_installation_targets_client_side(*name);
6447 if (r < 0)
6448 return r;
6449 }
6450 }
71fad675 6451 }
ee5762e3 6452
5f056378 6453 r = 0;
729e3769 6454 } else {
4afd3348 6455 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192
LP
6456 sd_bus *bus;
6457
6458 r = acquire_bus(BUS_MANAGER, &bus);
6459 if (r < 0)
6460 return r;
6461
e3e0314b 6462 STRV_FOREACH(name, names) {
4afd3348 6463 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
729e3769 6464 const char *s;
63a723f3 6465
f459b602 6466 r = sd_bus_call_method(
f22f08cd 6467 bus,
729e3769
LP
6468 "org.freedesktop.systemd1",
6469 "/org/freedesktop/systemd1",
6470 "org.freedesktop.systemd1.Manager",
f22f08cd 6471 "GetUnitFileState",
f459b602 6472 &error,
f22f08cd 6473 &reply,
04504f93 6474 "s", *name);
691395d8
LP
6475 if (r < 0)
6476 return log_error_errno(r, "Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
ee5762e3 6477
f459b602
MAP
6478 r = sd_bus_message_read(reply, "s", &s);
6479 if (r < 0)
6480 return bus_log_parse_error(r);
ee5762e3 6481
f4139308 6482 if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect", "generated"))
729e3769
LP
6483 enabled = true;
6484
3b3557c4 6485 if (!arg_quiet) {
729e3769 6486 puts(s);
3b3557c4
JS
6487 if (arg_full) {
6488 r = show_installation_targets(bus, *name);
6489 if (r < 0)
6490 return r;
6491 }
6492 }
560d8f23 6493 }
ee5762e3
LP
6494 }
6495
f4139308 6496 return enabled ? EXIT_SUCCESS : EXIT_FAILURE;
ee5762e3
LP
6497}
6498
e449de87 6499static int is_system_running(int argc, char *argv[], void *userdata) {
99813a19 6500 _cleanup_free_ char *state = NULL;
4fbd7192 6501 sd_bus *bus;
99813a19
LP
6502 int r;
6503
040524b4 6504 if (running_in_chroot() > 0 || (arg_transport == BUS_TRANSPORT_LOCAL && !sd_booted())) {
94f099d8
LP
6505 if (!arg_quiet)
6506 puts("offline");
6507 return EXIT_FAILURE;
6508 }
6509
4fbd7192
LP
6510 r = acquire_bus(BUS_MANAGER, &bus);
6511 if (r < 0)
6512 return r;
6513
99813a19
LP
6514 r = sd_bus_get_property_string(
6515 bus,
6516 "org.freedesktop.systemd1",
6517 "/org/freedesktop/systemd1",
6518 "org.freedesktop.systemd1.Manager",
6519 "SystemState",
6520 NULL,
6521 &state);
6522 if (r < 0) {
6523 if (!arg_quiet)
6524 puts("unknown");
6525 return 0;
6526 }
6527
6528 if (!arg_quiet)
6529 puts(state);
6530
6531 return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE;
6532}
6533
7d4fb3b1 6534static int create_edit_temp_file(const char *new_path, const char *original_path, char **ret_tmp_fn) {
45519fd6 6535 _cleanup_free_ char *t = NULL;
ae6c3cc0 6536 int r;
7d4fb3b1
RC
6537
6538 assert(new_path);
6539 assert(original_path);
6540 assert(ret_tmp_fn);
6541
14bcf25c 6542 r = tempfn_random(new_path, NULL, &t);
ae6c3cc0 6543 if (r < 0)
029009d4 6544 return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", new_path);
7d4fb3b1
RC
6545
6546 r = mkdir_parents(new_path, 0755);
45519fd6 6547 if (r < 0)
691395d8 6548 return log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
7d4fb3b1 6549
f2068bcc 6550 r = copy_file(original_path, t, 0, 0644, 0);
7d4fb3b1 6551 if (r == -ENOENT) {
45519fd6 6552
7d4fb3b1 6553 r = touch(t);
45519fd6
LP
6554 if (r < 0)
6555 return log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
6556
6557 } else if (r < 0)
39c38ce1 6558 return log_error_errno(r, "Failed to create temporary file for \"%s\": %m", new_path);
7d4fb3b1
RC
6559
6560 *ret_tmp_fn = t;
45519fd6 6561 t = NULL;
7d4fb3b1
RC
6562
6563 return 0;
6564}
6565
c51932be
LP
6566static int get_file_to_edit(
6567 const LookupPaths *paths,
6568 const char *name,
6569 char **ret_path) {
6570
6571 _cleanup_free_ char *path = NULL, *run = NULL;
7d4fb3b1 6572
45519fd6
LP
6573 assert(name);
6574 assert(ret_path);
6575
605405c6 6576 path = strjoin(paths->persistent_config, "/", name);
c51932be 6577 if (!path)
7d4fb3b1
RC
6578 return log_oom();
6579
c51932be 6580 if (arg_runtime) {
605405c6 6581 run = strjoin(paths->runtime_config, "/", name);
c51932be
LP
6582 if (!run)
6583 return log_oom();
6584 }
6585
bc854dc7 6586 if (arg_runtime) {
691395d8
LP
6587 if (access(path, F_OK) >= 0) {
6588 log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path);
6589 return -EEXIST;
6590 }
6591
bc854dc7
ZJS
6592 *ret_path = run;
6593 run = NULL;
6594 } else {
6595 *ret_path = path;
6596 path = NULL;
6597 }
7d4fb3b1
RC
6598
6599 return 0;
6600}
6601
39c38ce1 6602static int unit_file_create_new(
c51932be
LP
6603 const LookupPaths *paths,
6604 const char *unit_name,
39c38ce1 6605 const char *suffix,
c51932be
LP
6606 char **ret_new_path,
6607 char **ret_tmp_path) {
6608
45519fd6 6609 char *tmp_new_path, *tmp_tmp_path, *ending;
7d4fb3b1
RC
6610 int r;
6611
6612 assert(unit_name);
6613 assert(ret_new_path);
6614 assert(ret_tmp_path);
6615
39c38ce1 6616 ending = strjoina(unit_name, suffix);
c51932be 6617 r = get_file_to_edit(paths, ending, &tmp_new_path);
7d4fb3b1
RC
6618 if (r < 0)
6619 return r;
6620
6621 r = create_edit_temp_file(tmp_new_path, tmp_new_path, &tmp_tmp_path);
6622 if (r < 0) {
6623 free(tmp_new_path);
6624 return r;
6625 }
6626
6627 *ret_new_path = tmp_new_path;
6628 *ret_tmp_path = tmp_tmp_path;
6629
6630 return 0;
6631}
6632
1cfa9a4c 6633static int unit_file_create_copy(
c51932be 6634 const LookupPaths *paths,
1cfa9a4c
LP
6635 const char *unit_name,
6636 const char *fragment_path,
1cfa9a4c
LP
6637 char **ret_new_path,
6638 char **ret_tmp_path) {
6639
45519fd6 6640 char *tmp_new_path, *tmp_tmp_path;
7d4fb3b1
RC
6641 int r;
6642
6643 assert(fragment_path);
6644 assert(unit_name);
6645 assert(ret_new_path);
6646 assert(ret_tmp_path);
6647
c51932be 6648 r = get_file_to_edit(paths, unit_name, &tmp_new_path);
7d4fb3b1
RC
6649 if (r < 0)
6650 return r;
6651
6652 if (!path_equal(fragment_path, tmp_new_path) && access(tmp_new_path, F_OK) == 0) {
6653 char response;
6654
029009d4 6655 r = ask_char(&response, "yn", "\"%s\" already exists. Overwrite with \"%s\"? [(y)es, (n)o] ", tmp_new_path, fragment_path);
7d4fb3b1
RC
6656 if (r < 0) {
6657 free(tmp_new_path);
6658 return r;
6659 }
6660 if (response != 'y') {
6661 log_warning("%s ignored", unit_name);
6662 free(tmp_new_path);
dbf43a1b 6663 return -EKEYREJECTED;
7d4fb3b1
RC
6664 }
6665 }
6666
6667 r = create_edit_temp_file(tmp_new_path, fragment_path, &tmp_tmp_path);
6668 if (r < 0) {
7d4fb3b1
RC
6669 free(tmp_new_path);
6670 return r;
6671 }
6672
6673 *ret_new_path = tmp_new_path;
6674 *ret_tmp_path = tmp_tmp_path;
6675
6676 return 0;
6677}
6678
6679static int run_editor(char **paths) {
6680 pid_t pid;
6681 int r;
6682
6683 assert(paths);
6684
6685 pid = fork();
691395d8
LP
6686 if (pid < 0)
6687 return log_error_errno(errno, "Failed to fork: %m");
7d4fb3b1
RC
6688
6689 if (pid == 0) {
6690 const char **args;
9ef5d8f2 6691 char *editor, **editor_args = NULL;
1cfa9a4c 6692 char **tmp_path, **original_path, *p;
9ef5d8f2 6693 unsigned n_editor_args = 0, i = 1;
7d4fb3b1
RC
6694 size_t argc;
6695
ce30c8dc
LP
6696 (void) reset_all_signal_handlers();
6697 (void) reset_signal_mask();
6698
7d4fb3b1 6699 argc = strv_length(paths)/2 + 1;
7d4fb3b1
RC
6700
6701 /* SYSTEMD_EDITOR takes precedence over EDITOR which takes precedence over VISUAL
6702 * If neither SYSTEMD_EDITOR nor EDITOR nor VISUAL are present,
6703 * we try to execute well known editors
6704 */
6705 editor = getenv("SYSTEMD_EDITOR");
6706 if (!editor)
6707 editor = getenv("EDITOR");
6708 if (!editor)
6709 editor = getenv("VISUAL");
6710
6711 if (!isempty(editor)) {
9ef5d8f2
JS
6712 editor_args = strv_split(editor, WHITESPACE);
6713 if (!editor_args) {
6714 (void) log_oom();
6715 _exit(EXIT_FAILURE);
6716 }
6717 n_editor_args = strv_length(editor_args);
6718 argc += n_editor_args - 1;
6719 }
6720 args = newa(const char*, argc + 1);
6721
6722 if (n_editor_args > 0) {
6723 args[0] = editor_args[0];
6724 for (; i < n_editor_args; i++)
6725 args[i] = editor_args[i];
6726 }
6727
6728 STRV_FOREACH_PAIR(original_path, tmp_path, paths) {
6729 args[i] = *tmp_path;
6730 i++;
7d4fb3b1 6731 }
9ef5d8f2
JS
6732 args[i] = NULL;
6733
6734 if (n_editor_args > 0)
6735 execvp(args[0], (char* const*) args);
7d4fb3b1 6736
9391a1c3 6737 FOREACH_STRING(p, "editor", "nano", "vim", "vi") {
1cfa9a4c
LP
6738 args[0] = p;
6739 execvp(p, (char* const*) args);
7d4fb3b1
RC
6740 /* We do not fail if the editor doesn't exist
6741 * because we want to try each one of them before
6742 * failing.
6743 */
6744 if (errno != ENOENT) {
691395d8 6745 log_error_errno(errno, "Failed to execute %s: %m", editor);
7d4fb3b1
RC
6746 _exit(EXIT_FAILURE);
6747 }
6748 }
6749
1cfa9a4c 6750 log_error("Cannot edit unit(s), no editor available. Please set either $SYSTEMD_EDITOR, $EDITOR or $VISUAL.");
7d4fb3b1
RC
6751 _exit(EXIT_FAILURE);
6752 }
6753
6754 r = wait_for_terminate_and_warn("editor", pid, true);
6755 if (r < 0)
6756 return log_error_errno(r, "Failed to wait for child: %m");
6757
45519fd6 6758 return 0;
7d4fb3b1
RC
6759}
6760
6761static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
e9e310f8 6762 _cleanup_lookup_paths_free_ LookupPaths lp = {};
7d4fb3b1
RC
6763 char **name;
6764 int r;
6765
6766 assert(names);
6767 assert(paths);
6768
4943d143 6769 r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
5b013a2f 6770 if (r < 0)
8df18507 6771 return r;
7d4fb3b1 6772
e9e310f8 6773 STRV_FOREACH(name, names) {
78df0edc 6774 _cleanup_free_ char *path = NULL, *new_path = NULL, *tmp_path = NULL;
7d4fb3b1 6775
4fbd7192 6776 r = unit_find_paths(bus, *name, &lp, &path, NULL);
e9e310f8
RC
6777 if (r < 0)
6778 return r;
39c38ce1
DC
6779 else if (!arg_force) {
6780 if (r == 0) {
6781 log_error("Run 'systemctl edit --force %s' to create a new unit.", *name);
6782 return -ENOENT;
6783 } else if (!path) {
6784 // FIXME: support units with path==NULL (no FragmentPath)
6785 log_error("No fragment exists for %s.", *name);
6786 return -ENOENT;
6787 }
6788 }
6789
6790 if (path) {
6791 if (arg_full)
c6dd36b6 6792 r = unit_file_create_copy(&lp, basename(path), path, &new_path, &tmp_path);
39c38ce1 6793 else
c6dd36b6 6794 r = unit_file_create_new(&lp, basename(path), ".d/override.conf", &new_path, &tmp_path);
dbf43a1b 6795 } else
39c38ce1 6796 r = unit_file_create_new(&lp, *name, NULL, &new_path, &tmp_path);
e9e310f8 6797 if (r < 0)
ad2a0358 6798 return r;
7d4fb3b1 6799
e9e310f8
RC
6800 r = strv_push_pair(paths, new_path, tmp_path);
6801 if (r < 0)
6802 return log_oom();
78df0edc 6803 new_path = tmp_path = NULL;
7d4fb3b1
RC
6804 }
6805
6806 return 0;
6807}
6808
e449de87 6809static int edit(int argc, char *argv[], void *userdata) {
7d4fb3b1
RC
6810 _cleanup_strv_free_ char **names = NULL;
6811 _cleanup_strv_free_ char **paths = NULL;
6812 char **original, **tmp;
4fbd7192 6813 sd_bus *bus;
7d4fb3b1
RC
6814 int r;
6815
7d4fb3b1 6816 if (!on_tty()) {
4fbd7192 6817 log_error("Cannot edit units if not on a tty.");
7d4fb3b1
RC
6818 return -EINVAL;
6819 }
6820
6821 if (arg_transport != BUS_TRANSPORT_LOCAL) {
4fbd7192 6822 log_error("Cannot edit units remotely.");
7d4fb3b1
RC
6823 return -EINVAL;
6824 }
6825
4fbd7192
LP
6826 r = acquire_bus(BUS_MANAGER, &bus);
6827 if (r < 0)
6828 return r;
6829
e449de87 6830 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
7d4fb3b1
RC
6831 if (r < 0)
6832 return log_error_errno(r, "Failed to expand names: %m");
6833
7d4fb3b1
RC
6834 r = find_paths_to_edit(bus, names, &paths);
6835 if (r < 0)
6836 return r;
6837
b5e6a600 6838 if (strv_isempty(paths))
7d4fb3b1 6839 return -ENOENT;
7d4fb3b1
RC
6840
6841 r = run_editor(paths);
6842 if (r < 0)
6843 goto end;
6844
6845 STRV_FOREACH_PAIR(original, tmp, paths) {
45519fd6
LP
6846 /* If the temporary file is empty we ignore it. It's
6847 * useful if the user wants to cancel its modification
7d4fb3b1
RC
6848 */
6849 if (null_or_empty_path(*tmp)) {
45519fd6 6850 log_warning("Editing \"%s\" canceled: temporary file is empty.", *original);
7d4fb3b1
RC
6851 continue;
6852 }
45519fd6 6853
7d4fb3b1
RC
6854 r = rename(*tmp, *original);
6855 if (r < 0) {
029009d4 6856 r = log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", *tmp, *original);
7d4fb3b1
RC
6857 goto end;
6858 }
6859 }
6860
45519fd6
LP
6861 r = 0;
6862
6863 if (!arg_no_reload && !install_client_side())
e449de87 6864 r = daemon_reload(argc, argv, userdata);
7d4fb3b1
RC
6865
6866end:
5f18271e 6867 STRV_FOREACH_PAIR(original, tmp, paths) {
45519fd6 6868 (void) unlink(*tmp);
7d4fb3b1 6869
5f18271e
RC
6870 /* Removing empty dropin dirs */
6871 if (!arg_full) {
043717f9
RC
6872 _cleanup_free_ char *dir;
6873
6874 dir = dirname_malloc(*original);
6875 if (!dir)
6876 return log_oom();
6877
5f18271e
RC
6878 /* no need to check if the dir is empty, rmdir
6879 * does nothing if it is not the case.
6880 */
6881 (void) rmdir(dir);
6882 }
6883 }
6884
7d4fb3b1
RC
6885 return r;
6886}
6887
601185b4 6888static void systemctl_help(void) {
7e4249b9 6889
ea4b98e6 6890 pager_open(arg_no_pager, false);
729e3769 6891
2e33c433 6892 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
729e3769 6893 "Query or send control commands to the systemd manager.\n\n"
8a0867d6
LP
6894 " -h --help Show this help\n"
6895 " --version Show package version\n"
f459b602
MAP
6896 " --system Connect to system manager\n"
6897 " --user Connect to user service manager\n"
6898 " -H --host=[USER@]HOST\n"
6899 " Operate on remote host\n"
6900 " -M --machine=CONTAINER\n"
6901 " Operate on local container\n"
3fb90db2
ZJS
6902 " -t --type=TYPE List units of a particular type\n"
6903 " --state=STATE List units with particular LOAD or SUB or ACTIVE state\n"
8a0867d6 6904 " -p --property=NAME Show only properties by this name\n"
2cdbbc9a
LP
6905 " -a --all Show all properties/all units currently in memory,\n"
6906 " including dead/empty ones. To list all units installed on\n"
6907 " the system, use the 'list-unit-files' command instead.\n"
98a6e132 6908 " -l --full Don't ellipsize unit names on output\n"
1238ee09 6909 " -r --recursive Show unit list of host and local containers\n"
4dc5b821
LP
6910 " --reverse Show reverse dependencies with 'list-dependencies'\n"
6911 " --job-mode=MODE Specify how to deal with already queued jobs, when\n"
6912 " queueing a new job\n"
a521ae4a 6913 " --show-types When showing sockets, explicitly show their type\n"
4f9a9105 6914 " --value When showing properties, only print the value\n"
b37844d3
LP
6915 " -i --ignore-inhibitors\n"
6916 " When shutting down or sleeping, ignore inhibitors\n"
a8f11321
LP
6917 " --kill-who=WHO Who to send signal to\n"
6918 " -s --signal=SIGNAL Which signal to send\n"
57ab2eab 6919 " --now Start or stop unit in addition to enabling or disabling it\n"
8a0867d6 6920 " -q --quiet Suppress output\n"
93a08841 6921 " --wait For (re)start, wait until service stopped again\n"
8a0867d6 6922 " --no-block Do not wait until operation finished\n"
8a0867d6 6923 " --no-wall Don't send wall message before halt/power-off/reboot\n"
3fb90db2 6924 " --no-reload Don't reload daemon after en-/dis-abling unit files\n"
ebed32bf 6925 " --no-legend Do not print a legend (column headers and hints)\n"
69fc152f 6926 " --no-pager Do not pipe output into a pager\n"
501fc174
LP
6927 " --no-ask-password\n"
6928 " Do not ask for system passwords\n"
a8f11321 6929 " --global Enable/disable unit files globally\n"
a521ae4a 6930 " --runtime Enable unit files only temporarily until next reboot\n"
8a0867d6
LP
6931 " -f --force When enabling unit files, override existing symlinks\n"
6932 " When shutting down, execute action immediately\n"
3fb90db2 6933 " --preset-mode= Apply only enable, only disable, or all presets\n"
729e3769 6934 " --root=PATH Enable unit files in the specified root directory\n"
76fdc966 6935 " -n --lines=INTEGER Number of journal entries to show\n"
584c6e70
ZJS
6936 " -o --output=STRING Change journal output mode (short, short-precise,\n"
6937 " short-iso, short-full, short-monotonic, short-unix,\n"
6938 " verbose, export, json, json-pretty, json-sse, cat)\n"
5bdf2243 6939 " --firmware-setup Tell the firmware to show the setup menu on next boot\n"
815ebc54 6940 " --plain Print unit dependencies as a list instead of a tree\n\n"
34c4b47b 6941 "Unit Commands:\n"
2cdbbc9a
LP
6942 " list-units [PATTERN...] List units currently in memory\n"
6943 " list-sockets [PATTERN...] List socket units currently in memory, ordered\n"
6944 " by address\n"
6945 " list-timers [PATTERN...] List timer units currently in memory, ordered\n"
6946 " by next elapse\n"
4f8f66cb
ZJS
6947 " start NAME... Start (activate) one or more units\n"
6948 " stop NAME... Stop (deactivate) one or more units\n"
6949 " reload NAME... Reload one or more units\n"
6950 " restart NAME... Start or restart one or more units\n"
6951 " try-restart NAME... Restart one or more units if active\n"
6952 " reload-or-restart NAME... Reload one or more units if possible,\n"
6f28c033 6953 " otherwise start or restart\n"
aabf5d42
LP
6954 " try-reload-or-restart NAME... If active, reload one or more units,\n"
6955 " if supported, otherwise restart\n"
4f8f66cb
ZJS
6956 " isolate NAME Start one unit and stop all others\n"
6957 " kill NAME... Send signal to processes of a unit\n"
b3ae710c
ZJS
6958 " is-active PATTERN... Check whether units are active\n"
6959 " is-failed PATTERN... Check whether units are failed\n"
6960 " status [PATTERN...|PID...] Show runtime status of one or more units\n"
6961 " show [PATTERN...|JOB...] Show properties of one or more\n"
ee5762e3 6962 " units/jobs or the manager\n"
b3ae710c 6963 " cat PATTERN... Show files and drop-ins of one or more units\n"
4f8f66cb 6964 " set-property NAME ASSIGNMENT... Sets one or more properties of a unit\n"
b3ae710c
ZJS
6965 " help PATTERN...|PID... Show manual for one or more units\n"
6966 " reset-failed [PATTERN...] Reset failed state for all, one, or more\n"
fdf20a31 6967 " units\n"
55c0b89c 6968 " list-dependencies [NAME] Recursively show units which are required\n"
afba4199
ZJS
6969 " or wanted by this unit or by which this\n"
6970 " unit is required or wanted\n\n"
34c4b47b 6971 "Unit File Commands:\n"
d8fba7c6 6972 " list-unit-files [PATTERN...] List installed unit files\n"
3990961d 6973 " enable [NAME...|PATH...] Enable one or more unit files\n"
4f8f66cb
ZJS
6974 " disable NAME... Disable one or more unit files\n"
6975 " reenable NAME... Reenable one or more unit files\n"
6976 " preset NAME... Enable/disable one or more unit files\n"
729e3769 6977 " based on preset configuration\n"
d309c1c3
LP
6978 " preset-all Enable/disable all unit files based on\n"
6979 " preset configuration\n"
b619ec8f 6980 " is-enabled NAME... Check whether unit files are enabled\n"
4f8f66cb
ZJS
6981 " mask NAME... Mask one or more units\n"
6982 " unmask NAME... Unmask one or more units\n"
6983 " link PATH... Link one or more units files into\n"
729e3769 6984 " the search path\n"
344ca755
LP
6985 " revert NAME... Revert one or more unit files to vendor\n"
6986 " version\n"
e94937df
LN
6987 " add-wants TARGET NAME... Add 'Wants' dependency for the target\n"
6988 " on specified one or more units\n"
6989 " add-requires TARGET NAME... Add 'Requires' dependency for the target\n"
6990 " on specified one or more units\n"
7d4fb3b1 6991 " edit NAME... Edit one or more unit files\n"
b619ec8f
LP
6992 " get-default Get the name of the default target\n"
6993 " set-default NAME Set the default target\n\n"
0d292f5e
LP
6994 "Machine Commands:\n"
6995 " list-machines [PATTERN...] List local containers and host\n\n"
34c4b47b 6996 "Job Commands:\n"
d8fba7c6 6997 " list-jobs [PATTERN...] List jobs\n"
34c4b47b 6998 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
34c4b47b 6999 "Environment Commands:\n"
7e4249b9 7000 " show-environment Dump environment\n"
4f8f66cb 7001 " set-environment NAME=VALUE... Set one or more environment variables\n"
ac3efa8a 7002 " unset-environment NAME... Unset one or more environment variables\n"
3fb90db2 7003 " import-environment [NAME...] Import all or some environment variables\n\n"
34c4b47b
LP
7004 "Manager Lifecycle Commands:\n"
7005 " daemon-reload Reload systemd manager configuration\n"
7006 " daemon-reexec Reexecute systemd manager\n\n"
7007 "System Commands:\n"
99813a19 7008 " is-system-running Check whether system is fully running\n"
20b09ca7
LP
7009 " default Enter system default mode\n"
7010 " rescue Enter system rescue mode\n"
7011 " emergency Enter system emergency mode\n"
514f4ef5 7012 " halt Shut down and halt the system\n"
2e33c433 7013 " poweroff Shut down and power-off the system\n"
37185ec8 7014 " reboot [ARG] Shut down and reboot the system\n"
20b09ca7 7015 " kexec Shut down and reboot the system with kexec\n"
287419c1 7016 " exit [EXIT_CODE] Request user instance or container exit\n"
4f8f66cb 7017 " switch-root ROOT [INIT] Change to a different root file system\n"
6edd7d0a 7018 " suspend Suspend the system\n"
6524990f
LP
7019 " hibernate Hibernate the system\n"
7020 " hybrid-sleep Hibernate and suspend the system\n",
5b6319dc 7021 program_invocation_short_name);
7e4249b9
LP
7022}
7023
601185b4 7024static void halt_help(void) {
37185ec8 7025 printf("%s [OPTIONS...]%s\n\n"
e4b61340
LP
7026 "%s the system.\n\n"
7027 " --help Show this help\n"
7028 " --halt Halt the machine\n"
7029 " -p --poweroff Switch off the machine\n"
7030 " --reboot Reboot the machine\n"
2e33c433
LP
7031 " -f --force Force immediate halt/power-off/reboot\n"
7032 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
e4b61340 7033 " -d --no-wtmp Don't write wtmp record\n"
2e33c433 7034 " --no-wall Don't send wall message before halt/power-off/reboot\n",
e4b61340 7035 program_invocation_short_name,
37185ec8 7036 arg_action == ACTION_REBOOT ? " [ARG]" : "",
e4b61340
LP
7037 arg_action == ACTION_REBOOT ? "Reboot" :
7038 arg_action == ACTION_POWEROFF ? "Power off" :
7039 "Halt");
e4b61340
LP
7040}
7041
601185b4 7042static void shutdown_help(void) {
08e4b1c5 7043 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
e4b61340
LP
7044 "Shut down the system.\n\n"
7045 " --help Show this help\n"
7046 " -H --halt Halt the machine\n"
7047 " -P --poweroff Power-off the machine\n"
7048 " -r --reboot Reboot the machine\n"
386da858 7049 " -h Equivalent to --poweroff, overridden by --halt\n"
2e33c433 7050 " -k Don't halt/power-off/reboot, just send warnings\n"
f6144808 7051 " --no-wall Don't send wall message before halt/power-off/reboot\n"
f6144808 7052 " -c Cancel a pending shutdown\n",
e4b61340 7053 program_invocation_short_name);
e4b61340
LP
7054}
7055
601185b4 7056static void telinit_help(void) {
2e33c433 7057 printf("%s [OPTIONS...] {COMMAND}\n\n"
514f4ef5
LP
7058 "Send control commands to the init daemon.\n\n"
7059 " --help Show this help\n"
2e33c433 7060 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
e4b61340
LP
7061 "Commands:\n"
7062 " 0 Power-off the machine\n"
7063 " 6 Reboot the machine\n"
514f4ef5
LP
7064 " 2, 3, 4, 5 Start runlevelX.target unit\n"
7065 " 1, s, S Enter rescue mode\n"
7066 " q, Q Reload init daemon configuration\n"
7067 " u, U Reexecute init daemon\n",
e4b61340 7068 program_invocation_short_name);
e4b61340
LP
7069}
7070
601185b4 7071static void runlevel_help(void) {
2e33c433 7072 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
7073 "Prints the previous and current runlevel of the init system.\n\n"
7074 " --help Show this help\n",
7075 program_invocation_short_name);
e4b61340
LP
7076}
7077
b93312f5 7078static void help_types(void) {
45c0c61d
ZJS
7079 int i;
7080
b93312f5
ZJS
7081 if (!arg_no_legend)
7082 puts("Available unit types:");
e16972e6
ZJS
7083 for (i = 0; i < _UNIT_TYPE_MAX; i++)
7084 puts(unit_type_to_string(i));
7085}
7086
7087static void help_states(void) {
7088 int i;
7089
7090 if (!arg_no_legend)
7091 puts("Available unit load states:");
7092 for (i = 0; i < _UNIT_LOAD_STATE_MAX; i++)
7093 puts(unit_load_state_to_string(i));
7094
7095 if (!arg_no_legend)
7096 puts("\nAvailable unit active states:");
7097 for (i = 0; i < _UNIT_ACTIVE_STATE_MAX; i++)
7098 puts(unit_active_state_to_string(i));
7e55de3b
ZJS
7099
7100 if (!arg_no_legend)
7101 puts("\nAvailable automount unit substates:");
7102 for (i = 0; i < _AUTOMOUNT_STATE_MAX; i++)
7103 puts(automount_state_to_string(i));
7104
7105 if (!arg_no_legend)
7106 puts("\nAvailable busname unit substates:");
7107 for (i = 0; i < _BUSNAME_STATE_MAX; i++)
7108 puts(busname_state_to_string(i));
7109
7110 if (!arg_no_legend)
7111 puts("\nAvailable device unit substates:");
7112 for (i = 0; i < _DEVICE_STATE_MAX; i++)
7113 puts(device_state_to_string(i));
7114
7115 if (!arg_no_legend)
7116 puts("\nAvailable mount unit substates:");
7117 for (i = 0; i < _MOUNT_STATE_MAX; i++)
7118 puts(mount_state_to_string(i));
7119
7120 if (!arg_no_legend)
7121 puts("\nAvailable path unit substates:");
7122 for (i = 0; i < _PATH_STATE_MAX; i++)
7123 puts(path_state_to_string(i));
7124
7125 if (!arg_no_legend)
7126 puts("\nAvailable scope unit substates:");
7127 for (i = 0; i < _SCOPE_STATE_MAX; i++)
7128 puts(scope_state_to_string(i));
7129
7130 if (!arg_no_legend)
7131 puts("\nAvailable service unit substates:");
7132 for (i = 0; i < _SERVICE_STATE_MAX; i++)
7133 puts(service_state_to_string(i));
7134
7135 if (!arg_no_legend)
7136 puts("\nAvailable slice unit substates:");
7137 for (i = 0; i < _SLICE_STATE_MAX; i++)
7138 puts(slice_state_to_string(i));
7139
7e55de3b
ZJS
7140 if (!arg_no_legend)
7141 puts("\nAvailable socket unit substates:");
7142 for (i = 0; i < _SOCKET_STATE_MAX; i++)
7143 puts(socket_state_to_string(i));
7144
7145 if (!arg_no_legend)
7146 puts("\nAvailable swap unit substates:");
7147 for (i = 0; i < _SWAP_STATE_MAX; i++)
7148 puts(swap_state_to_string(i));
7149
7150 if (!arg_no_legend)
7151 puts("\nAvailable target unit substates:");
7152 for (i = 0; i < _TARGET_STATE_MAX; i++)
7153 puts(target_state_to_string(i));
7154
7155 if (!arg_no_legend)
7156 puts("\nAvailable timer unit substates:");
7157 for (i = 0; i < _TIMER_STATE_MAX; i++)
7158 puts(timer_state_to_string(i));
45c0c61d
ZJS
7159}
7160
e4b61340 7161static int systemctl_parse_argv(int argc, char *argv[]) {
7e4249b9
LP
7162
7163 enum {
90d473a1 7164 ARG_FAIL = 0x100,
afba4199
ZJS
7165 ARG_REVERSE,
7166 ARG_AFTER,
7167 ARG_BEFORE,
991f2a39 7168 ARG_SHOW_TYPES,
23ade460 7169 ARG_IRREVERSIBLE,
e67c3609 7170 ARG_IGNORE_DEPENDENCIES,
4f9a9105 7171 ARG_VALUE,
35df8f27 7172 ARG_VERSION,
af2d49f7 7173 ARG_USER,
7e4249b9 7174 ARG_SYSTEM,
ee5762e3 7175 ARG_GLOBAL,
6e905d93 7176 ARG_NO_BLOCK,
ebed32bf 7177 ARG_NO_LEGEND,
611efaac 7178 ARG_NO_PAGER,
4445a875 7179 ARG_NO_WALL,
be394c48 7180 ARG_ROOT,
ee5762e3 7181 ARG_NO_RELOAD,
501fc174 7182 ARG_KILL_WHO,
30732560 7183 ARG_NO_ASK_PASSWORD,
729e3769 7184 ARG_FAILED,
df50185b 7185 ARG_RUNTIME,
5d0c05e5 7186 ARG_FORCE,
9b9b3d36 7187 ARG_PLAIN,
4dc5b821 7188 ARG_STATE,
d309c1c3
LP
7189 ARG_JOB_MODE,
7190 ARG_PRESET_MODE,
5bdf2243 7191 ARG_FIRMWARE_SETUP,
57ab2eab 7192 ARG_NOW,
9ef15026 7193 ARG_MESSAGE,
93a08841 7194 ARG_WAIT,
7e4249b9
LP
7195 };
7196
7197 static const struct option options[] = {
9ea9d4cf
LP
7198 { "help", no_argument, NULL, 'h' },
7199 { "version", no_argument, NULL, ARG_VERSION },
7200 { "type", required_argument, NULL, 't' },
7201 { "property", required_argument, NULL, 'p' },
7202 { "all", no_argument, NULL, 'a' },
7203 { "reverse", no_argument, NULL, ARG_REVERSE },
7204 { "after", no_argument, NULL, ARG_AFTER },
7205 { "before", no_argument, NULL, ARG_BEFORE },
7206 { "show-types", no_argument, NULL, ARG_SHOW_TYPES },
7207 { "failed", no_argument, NULL, ARG_FAILED }, /* compatibility only */
7208 { "full", no_argument, NULL, 'l' },
4dc5b821
LP
7209 { "job-mode", required_argument, NULL, ARG_JOB_MODE },
7210 { "fail", no_argument, NULL, ARG_FAIL }, /* compatibility only */
7211 { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, /* compatibility only */
7212 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */
9ea9d4cf 7213 { "ignore-inhibitors", no_argument, NULL, 'i' },
4f9a9105 7214 { "value", no_argument, NULL, ARG_VALUE },
9ea9d4cf
LP
7215 { "user", no_argument, NULL, ARG_USER },
7216 { "system", no_argument, NULL, ARG_SYSTEM },
7217 { "global", no_argument, NULL, ARG_GLOBAL },
93a08841 7218 { "wait", no_argument, NULL, ARG_WAIT },
9ea9d4cf
LP
7219 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
7220 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
7221 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
7222 { "no-wall", no_argument, NULL, ARG_NO_WALL },
7223 { "quiet", no_argument, NULL, 'q' },
7224 { "root", required_argument, NULL, ARG_ROOT },
7225 { "force", no_argument, NULL, ARG_FORCE },
7226 { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
7227 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
7228 { "signal", required_argument, NULL, 's' },
7229 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
7230 { "host", required_argument, NULL, 'H' },
f459b602 7231 { "machine", required_argument, NULL, 'M' },
9ea9d4cf
LP
7232 { "runtime", no_argument, NULL, ARG_RUNTIME },
7233 { "lines", required_argument, NULL, 'n' },
7234 { "output", required_argument, NULL, 'o' },
7235 { "plain", no_argument, NULL, ARG_PLAIN },
7236 { "state", required_argument, NULL, ARG_STATE },
1238ee09 7237 { "recursive", no_argument, NULL, 'r' },
d309c1c3 7238 { "preset-mode", required_argument, NULL, ARG_PRESET_MODE },
5bdf2243 7239 { "firmware-setup", no_argument, NULL, ARG_FIRMWARE_SETUP },
57ab2eab 7240 { "now", no_argument, NULL, ARG_NOW },
9ef15026 7241 { "message", required_argument, NULL, ARG_MESSAGE },
eb9da376 7242 {}
7e4249b9
LP
7243 };
7244
5ab22f33 7245 const char *p;
0f03c2a4 7246 int c, r;
7e4249b9 7247
e4b61340 7248 assert(argc >= 0);
7e4249b9
LP
7249 assert(argv);
7250
16f017fa
IS
7251 /* we default to allowing interactive authorization only in systemctl (not in the legacy commands) */
7252 arg_ask_password = true;
7253
601185b4 7254 while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir", options, NULL)) >= 0)
7e4249b9
LP
7255
7256 switch (c) {
7257
7258 case 'h':
601185b4
ZJS
7259 systemctl_help();
7260 return 0;
35df8f27
LP
7261
7262 case ARG_VERSION:
3f6fd1ba 7263 return version();
7e4249b9 7264
20b3f379 7265 case 't': {
bf409580
TA
7266 if (isempty(optarg)) {
7267 log_error("--type requires arguments.");
7268 return -EINVAL;
7269 }
45c0c61d 7270
c58bd76a 7271 for (p = optarg;;) {
5ab22f33 7272 _cleanup_free_ char *type = NULL;
20b3f379 7273
5ab22f33
SS
7274 r = extract_first_word(&p, &type, ",", 0);
7275 if (r < 0)
7276 return log_error_errno(r, "Failed to parse type: %s", optarg);
5ab22f33
SS
7277 if (r == 0)
7278 break;
20b3f379
ZJS
7279
7280 if (streq(type, "help")) {
7281 help_types();
7282 return 0;
7283 }
7284
7285 if (unit_type_from_string(type) >= 0) {
7e9d36e0 7286 if (strv_push(&arg_types, type) < 0)
20b3f379
ZJS
7287 return log_oom();
7288 type = NULL;
7289 continue;
7290 }
7291
9b9b3d36
MW
7292 /* It's much nicer to use --state= for
7293 * load states, but let's support this
7294 * in --types= too for compatibility
7295 * with old versions */
7e9d36e0 7296 if (unit_load_state_from_string(type) >= 0) {
9b9b3d36 7297 if (strv_push(&arg_states, type) < 0)
20b3f379
ZJS
7298 return log_oom();
7299 type = NULL;
7300 continue;
7301 }
7302
ab06eef8 7303 log_error("Unknown unit type or load state '%s'.", type);
20b3f379
ZJS
7304 log_info("Use -t help to see a list of allowed values.");
7305 return -EINVAL;
c147dc42 7306 }
20b3f379
ZJS
7307
7308 break;
7309 }
7310
ea4a240d 7311 case 'p': {
033a842c
ZJS
7312 /* Make sure that if the empty property list
7313 was specified, we won't show any properties. */
20b3f379 7314 if (isempty(optarg) && !arg_properties) {
cbc9fbd1 7315 arg_properties = new0(char*, 1);
20b3f379
ZJS
7316 if (!arg_properties)
7317 return log_oom();
c58bd76a
ZJS
7318 } else
7319 for (p = optarg;;) {
5ab22f33 7320 _cleanup_free_ char *prop = NULL;
033a842c 7321
5ab22f33
SS
7322 r = extract_first_word(&p, &prop, ",", 0);
7323 if (r < 0)
7324 return log_error_errno(r, "Failed to parse property: %s", optarg);
5ab22f33
SS
7325 if (r == 0)
7326 break;
ea4a240d 7327
5ab22f33 7328 if (strv_push(&arg_properties, prop) < 0)
20b3f379 7329 return log_oom();
5ab22f33
SS
7330
7331 prop = NULL;
20b3f379 7332 }
48220598
LP
7333
7334 /* If the user asked for a particular
7335 * property, show it to him, even if it is
7336 * empty. */
7337 arg_all = true;
033a842c 7338
48220598 7339 break;
ea4a240d 7340 }
48220598 7341
7e4249b9
LP
7342 case 'a':
7343 arg_all = true;
7344 break;
7345
afba4199
ZJS
7346 case ARG_REVERSE:
7347 arg_dependency = DEPENDENCY_REVERSE;
7348 break;
7349
7350 case ARG_AFTER:
7351 arg_dependency = DEPENDENCY_AFTER;
82948f6c 7352 arg_jobs_after = true;
afba4199
ZJS
7353 break;
7354
7355 case ARG_BEFORE:
7356 arg_dependency = DEPENDENCY_BEFORE;
82948f6c 7357 arg_jobs_before = true;
afba4199
ZJS
7358 break;
7359
991f2a39
ZJS
7360 case ARG_SHOW_TYPES:
7361 arg_show_types = true;
7362 break;
7363
4f9a9105
ZJS
7364 case ARG_VALUE:
7365 arg_value = true;
7366 break;
7367
4dc5b821
LP
7368 case ARG_JOB_MODE:
7369 arg_job_mode = optarg;
7370 break;
7371
90d473a1 7372 case ARG_FAIL:
e67c3609
LP
7373 arg_job_mode = "fail";
7374 break;
7375
23ade460
MS
7376 case ARG_IRREVERSIBLE:
7377 arg_job_mode = "replace-irreversibly";
7378 break;
7379
e67c3609
LP
7380 case ARG_IGNORE_DEPENDENCIES:
7381 arg_job_mode = "ignore-dependencies";
7e4249b9
LP
7382 break;
7383
af2d49f7 7384 case ARG_USER:
729e3769 7385 arg_scope = UNIT_FILE_USER;
7e4249b9
LP
7386 break;
7387
7388 case ARG_SYSTEM:
729e3769
LP
7389 arg_scope = UNIT_FILE_SYSTEM;
7390 break;
7391
7392 case ARG_GLOBAL:
7393 arg_scope = UNIT_FILE_GLOBAL;
7e4249b9
LP
7394 break;
7395
93a08841
MP
7396 case ARG_WAIT:
7397 arg_wait = true;
7398 break;
7399
6e905d93
LP
7400 case ARG_NO_BLOCK:
7401 arg_no_block = true;
7e4249b9
LP
7402 break;
7403
ebed32bf
MS
7404 case ARG_NO_LEGEND:
7405 arg_no_legend = true;
7406 break;
7407
611efaac
LP
7408 case ARG_NO_PAGER:
7409 arg_no_pager = true;
7410 break;
0736af98 7411
514f4ef5
LP
7412 case ARG_NO_WALL:
7413 arg_no_wall = true;
7414 break;
7415
be394c48 7416 case ARG_ROOT:
bac75eb3 7417 r = parse_path_argument_and_warn(optarg, false, &arg_root);
0f03c2a4
LP
7418 if (r < 0)
7419 return r;
be394c48
FC
7420 break;
7421
98a6e132 7422 case 'l':
8fe914ec
LP
7423 arg_full = true;
7424 break;
7425
30732560 7426 case ARG_FAILED:
9b9b3d36
MW
7427 if (strv_extend(&arg_states, "failed") < 0)
7428 return log_oom();
7429
30732560
LP
7430 break;
7431
0183528f
LP
7432 case 'q':
7433 arg_quiet = true;
7434 break;
7435
568b679f 7436 case ARG_FORCE:
313cefa1 7437 arg_force++;
568b679f
LP
7438 break;
7439
b4f27ccc 7440 case 'f':
313cefa1 7441 arg_force++;
ee5762e3
LP
7442 break;
7443
7444 case ARG_NO_RELOAD:
7445 arg_no_reload = true;
7446 break;
7447
8a0867d6
LP
7448 case ARG_KILL_WHO:
7449 arg_kill_who = optarg;
7450 break;
7451
8a0867d6 7452 case 's':
691395d8
LP
7453 arg_signal = signal_from_string_try_harder(optarg);
7454 if (arg_signal < 0) {
8a0867d6
LP
7455 log_error("Failed to parse signal string %s.", optarg);
7456 return -EINVAL;
7457 }
7458 break;
7459
501fc174
LP
7460 case ARG_NO_ASK_PASSWORD:
7461 arg_ask_password = false;
7462 break;
7463
f459b602
MAP
7464 case 'H':
7465 arg_transport = BUS_TRANSPORT_REMOTE;
7466 arg_host = optarg;
a8f11321
LP
7467 break;
7468
f459b602 7469 case 'M':
de33fc62 7470 arg_transport = BUS_TRANSPORT_MACHINE;
f459b602 7471 arg_host = optarg;
a8f11321
LP
7472 break;
7473
729e3769
LP
7474 case ARG_RUNTIME:
7475 arg_runtime = true;
7476 break;
7477
df50185b
LP
7478 case 'n':
7479 if (safe_atou(optarg, &arg_lines) < 0) {
7480 log_error("Failed to parse lines '%s'", optarg);
7481 return -EINVAL;
7482 }
7483 break;
7484
df50185b
LP
7485 case 'o':
7486 arg_output = output_mode_from_string(optarg);
7487 if (arg_output < 0) {
7488 log_error("Unknown output '%s'.", optarg);
7489 return -EINVAL;
7490 }
7491 break;
7492
b37844d3
LP
7493 case 'i':
7494 arg_ignore_inhibitors = true;
7495 break;
7496
5d0c05e5
LN
7497 case ARG_PLAIN:
7498 arg_plain = true;
7499 break;
7500
5bdf2243
JJ
7501 case ARG_FIRMWARE_SETUP:
7502 arg_firmware_setup = true;
7503 break;
7504
9b9b3d36 7505 case ARG_STATE: {
bf409580
TA
7506 if (isempty(optarg)) {
7507 log_error("--signal requires arguments.");
7508 return -EINVAL;
7509 }
9b9b3d36 7510
c58bd76a 7511 for (p = optarg;;) {
bc6c18fe 7512 _cleanup_free_ char *s = NULL;
9b9b3d36 7513
5ab22f33
SS
7514 r = extract_first_word(&p, &s, ",", 0);
7515 if (r < 0)
7516 return log_error_errno(r, "Failed to parse signal: %s", optarg);
5ab22f33
SS
7517 if (r == 0)
7518 break;
9b9b3d36 7519
e16972e6
ZJS
7520 if (streq(s, "help")) {
7521 help_states();
7522 return 0;
7523 }
7524
7e9d36e0 7525 if (strv_push(&arg_states, s) < 0)
9b9b3d36 7526 return log_oom();
7e9d36e0
LP
7527
7528 s = NULL;
9b9b3d36
MW
7529 }
7530 break;
7531 }
7532
1238ee09
LP
7533 case 'r':
7534 if (geteuid() != 0) {
f1721625 7535 log_error("--recursive requires root privileges.");
1238ee09
LP
7536 return -EPERM;
7537 }
7538
7539 arg_recursive = true;
7540 break;
7541
d309c1c3
LP
7542 case ARG_PRESET_MODE:
7543
7544 arg_preset_mode = unit_file_preset_mode_from_string(optarg);
7545 if (arg_preset_mode < 0) {
7546 log_error("Failed to parse preset mode: %s.", optarg);
7547 return -EINVAL;
7548 }
7549
7550 break;
7551
57ab2eab
JS
7552 case ARG_NOW:
7553 arg_now = true;
7554 break;
7555
9ef15026
JS
7556 case ARG_MESSAGE:
7557 if (strv_extend(&arg_wall, optarg) < 0)
7558 return log_oom();
7559 break;
7560
7e4249b9
LP
7561 case '?':
7562 return -EINVAL;
7563
7564 default:
eb9da376 7565 assert_not_reached("Unhandled option");
7e4249b9 7566 }
7e4249b9 7567
f459b602 7568 if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM) {
a8f11321
LP
7569 log_error("Cannot access user instance remotely.");
7570 return -EINVAL;
7571 }
7572
93a08841
MP
7573 if (arg_wait && arg_no_block) {
7574 log_error("--wait may not be combined with --no-block.");
7575 return -EINVAL;
7576 }
7577
7e4249b9
LP
7578 return 1;
7579}
7580
e4b61340
LP
7581static int halt_parse_argv(int argc, char *argv[]) {
7582
7583 enum {
7584 ARG_HELP = 0x100,
7585 ARG_HALT,
514f4ef5
LP
7586 ARG_REBOOT,
7587 ARG_NO_WALL
e4b61340
LP
7588 };
7589
7590 static const struct option options[] = {
7591 { "help", no_argument, NULL, ARG_HELP },
7592 { "halt", no_argument, NULL, ARG_HALT },
7593 { "poweroff", no_argument, NULL, 'p' },
7594 { "reboot", no_argument, NULL, ARG_REBOOT },
7595 { "force", no_argument, NULL, 'f' },
7596 { "wtmp-only", no_argument, NULL, 'w' },
7597 { "no-wtmp", no_argument, NULL, 'd' },
f3f054f0 7598 { "no-sync", no_argument, NULL, 'n' },
514f4ef5 7599 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 7600 {}
e4b61340
LP
7601 };
7602
37185ec8 7603 int c, r, runlevel;
e4b61340
LP
7604
7605 assert(argc >= 0);
7606 assert(argv);
7607
7608 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
7609 if (runlevel == '0' || runlevel == '6')
65491fd8 7610 arg_force = 2;
e4b61340 7611
601185b4 7612 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0)
e4b61340
LP
7613 switch (c) {
7614
7615 case ARG_HELP:
601185b4
ZJS
7616 halt_help();
7617 return 0;
e4b61340
LP
7618
7619 case ARG_HALT:
7620 arg_action = ACTION_HALT;
7621 break;
7622
7623 case 'p':
a042efad
MS
7624 if (arg_action != ACTION_REBOOT)
7625 arg_action = ACTION_POWEROFF;
e4b61340
LP
7626 break;
7627
7628 case ARG_REBOOT:
7629 arg_action = ACTION_REBOOT;
7630 break;
7631
7632 case 'f':
65491fd8 7633 arg_force = 2;
e4b61340
LP
7634 break;
7635
7636 case 'w':
7637 arg_dry = true;
7638 break;
7639
7640 case 'd':
7641 arg_no_wtmp = true;
7642 break;
7643
f3f054f0
TB
7644 case 'n':
7645 arg_no_sync = true;
7646 break;
7647
514f4ef5
LP
7648 case ARG_NO_WALL:
7649 arg_no_wall = true;
7650 break;
7651
e4b61340
LP
7652 case 'i':
7653 case 'h':
7654 /* Compatibility nops */
7655 break;
7656
7657 case '?':
7658 return -EINVAL;
7659
7660 default:
eb9da376 7661 assert_not_reached("Unhandled option");
e4b61340 7662 }
e4b61340 7663
c5220a94 7664 if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
27c06cb5 7665 r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL);
c5220a94 7666 if (r < 0)
37185ec8 7667 return r;
37185ec8 7668 } else if (optind < argc) {
e4b61340
LP
7669 log_error("Too many arguments.");
7670 return -EINVAL;
7671 }
7672
7673 return 1;
7674}
7675
2cc7b0a2 7676static int parse_shutdown_time_spec(const char *t, usec_t *_u) {
f6144808
LP
7677 assert(t);
7678 assert(_u);
7679
7680 if (streq(t, "now"))
7681 *_u = 0;
1a639877 7682 else if (!strchr(t, ':')) {
f6144808
LP
7683 uint64_t u;
7684
1a639877 7685 if (safe_atou64(t, &u) < 0)
f6144808
LP
7686 return -EINVAL;
7687
7688 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
7689 } else {
7690 char *e = NULL;
7691 long hour, minute;
b92bea5d 7692 struct tm tm = {};
f6144808
LP
7693 time_t s;
7694 usec_t n;
7695
7696 errno = 0;
7697 hour = strtol(t, &e, 10);
8333c77e 7698 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
f6144808
LP
7699 return -EINVAL;
7700
7701 minute = strtol(e+1, &e, 10);
8333c77e 7702 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
f6144808
LP
7703 return -EINVAL;
7704
7705 n = now(CLOCK_REALTIME);
08e4b1c5
LP
7706 s = (time_t) (n / USEC_PER_SEC);
7707
f6144808
LP
7708 assert_se(localtime_r(&s, &tm));
7709
7710 tm.tm_hour = (int) hour;
7711 tm.tm_min = (int) minute;
08e4b1c5 7712 tm.tm_sec = 0;
f6144808
LP
7713
7714 assert_se(s = mktime(&tm));
7715
7716 *_u = (usec_t) s * USEC_PER_SEC;
7717
7718 while (*_u <= n)
7719 *_u += USEC_PER_DAY;
7720 }
7721
7722 return 0;
7723}
7724
e4b61340
LP
7725static int shutdown_parse_argv(int argc, char *argv[]) {
7726
7727 enum {
7728 ARG_HELP = 0x100,
514f4ef5 7729 ARG_NO_WALL
e4b61340
LP
7730 };
7731
7732 static const struct option options[] = {
7733 { "help", no_argument, NULL, ARG_HELP },
7734 { "halt", no_argument, NULL, 'H' },
7735 { "poweroff", no_argument, NULL, 'P' },
7736 { "reboot", no_argument, NULL, 'r' },
04ebb595 7737 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
514f4ef5 7738 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 7739 {}
e4b61340
LP
7740 };
7741
172d7abf 7742 char **wall = NULL;
f6144808 7743 int c, r;
e4b61340
LP
7744
7745 assert(argc >= 0);
7746 assert(argv);
7747
a4420f7b 7748 while ((c = getopt_long(argc, argv, "HPrhkKtafFc", options, NULL)) >= 0)
e4b61340
LP
7749 switch (c) {
7750
7751 case ARG_HELP:
601185b4
ZJS
7752 shutdown_help();
7753 return 0;
e4b61340
LP
7754
7755 case 'H':
7756 arg_action = ACTION_HALT;
7757 break;
7758
7759 case 'P':
7760 arg_action = ACTION_POWEROFF;
7761 break;
7762
7763 case 'r':
5622dde3
KS
7764 if (kexec_loaded())
7765 arg_action = ACTION_KEXEC;
7766 else
7767 arg_action = ACTION_REBOOT;
e4b61340
LP
7768 break;
7769
04ebb595
LP
7770 case 'K':
7771 arg_action = ACTION_KEXEC;
7772 break;
7773
e4b61340
LP
7774 case 'h':
7775 if (arg_action != ACTION_HALT)
7776 arg_action = ACTION_POWEROFF;
7777 break;
7778
7779 case 'k':
7780 arg_dry = true;
7781 break;
7782
514f4ef5
LP
7783 case ARG_NO_WALL:
7784 arg_no_wall = true;
7785 break;
7786
e4b61340
LP
7787 case 't':
7788 case 'a':
75836b9d
JS
7789 case 'f':
7790 case 'F':
e4b61340
LP
7791 /* Compatibility nops */
7792 break;
7793
f6144808
LP
7794 case 'c':
7795 arg_action = ACTION_CANCEL_SHUTDOWN;
7796 break;
7797
e4b61340
LP
7798 case '?':
7799 return -EINVAL;
7800
7801 default:
eb9da376 7802 assert_not_reached("Unhandled option");
e4b61340 7803 }
e4b61340 7804
dfcc5c33 7805 if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
2cc7b0a2 7806 r = parse_shutdown_time_spec(argv[optind], &arg_when);
7e59bfcb 7807 if (r < 0) {
f6144808
LP
7808 log_error("Failed to parse time specification: %s", argv[optind]);
7809 return r;
7810 }
6b5ad000 7811 } else
08e4b1c5 7812 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
442b9094 7813
dfcc5c33
MS
7814 if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
7815 /* No time argument for shutdown cancel */
172d7abf 7816 wall = argv + optind;
dfcc5c33
MS
7817 else if (argc > optind + 1)
7818 /* We skip the time argument */
172d7abf
LP
7819 wall = argv + optind + 1;
7820
7821 if (wall) {
7822 arg_wall = strv_copy(wall);
7823 if (!arg_wall)
7824 return log_oom();
7825 }
e4b61340
LP
7826
7827 optind = argc;
7828
7829 return 1;
e4b61340
LP
7830}
7831
7832static int telinit_parse_argv(int argc, char *argv[]) {
7833
7834 enum {
7835 ARG_HELP = 0x100,
514f4ef5 7836 ARG_NO_WALL
e4b61340
LP
7837 };
7838
7839 static const struct option options[] = {
7840 { "help", no_argument, NULL, ARG_HELP },
514f4ef5 7841 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 7842 {}
e4b61340
LP
7843 };
7844
7845 static const struct {
7846 char from;
7847 enum action to;
7848 } table[] = {
7849 { '0', ACTION_POWEROFF },
7850 { '6', ACTION_REBOOT },
ef2f1067 7851 { '1', ACTION_RESCUE },
e4b61340
LP
7852 { '2', ACTION_RUNLEVEL2 },
7853 { '3', ACTION_RUNLEVEL3 },
7854 { '4', ACTION_RUNLEVEL4 },
7855 { '5', ACTION_RUNLEVEL5 },
7856 { 's', ACTION_RESCUE },
7857 { 'S', ACTION_RESCUE },
7858 { 'q', ACTION_RELOAD },
7859 { 'Q', ACTION_RELOAD },
7860 { 'u', ACTION_REEXEC },
7861 { 'U', ACTION_REEXEC }
7862 };
7863
7864 unsigned i;
7865 int c;
7866
7867 assert(argc >= 0);
7868 assert(argv);
7869
601185b4 7870 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
7871 switch (c) {
7872
7873 case ARG_HELP:
601185b4
ZJS
7874 telinit_help();
7875 return 0;
e4b61340 7876
514f4ef5
LP
7877 case ARG_NO_WALL:
7878 arg_no_wall = true;
7879 break;
7880
e4b61340
LP
7881 case '?':
7882 return -EINVAL;
7883
7884 default:
eb9da376 7885 assert_not_reached("Unhandled option");
e4b61340 7886 }
e4b61340
LP
7887
7888 if (optind >= argc) {
691395d8 7889 log_error("%s: required argument missing.", program_invocation_short_name);
e4b61340
LP
7890 return -EINVAL;
7891 }
7892
7893 if (optind + 1 < argc) {
7894 log_error("Too many arguments.");
7895 return -EINVAL;
7896 }
7897
7898 if (strlen(argv[optind]) != 1) {
7899 log_error("Expected single character argument.");
7900 return -EINVAL;
7901 }
7902
7903 for (i = 0; i < ELEMENTSOF(table); i++)
7904 if (table[i].from == argv[optind][0])
7905 break;
7906
7907 if (i >= ELEMENTSOF(table)) {
b0193f1c 7908 log_error("Unknown command '%s'.", argv[optind]);
e4b61340
LP
7909 return -EINVAL;
7910 }
7911
7912 arg_action = table[i].to;
7913
313cefa1 7914 optind++;
e4b61340
LP
7915
7916 return 1;
7917}
7918
7919static int runlevel_parse_argv(int argc, char *argv[]) {
7920
7921 enum {
7922 ARG_HELP = 0x100,
7923 };
7924
7925 static const struct option options[] = {
7926 { "help", no_argument, NULL, ARG_HELP },
eb9da376 7927 {}
e4b61340
LP
7928 };
7929
7930 int c;
7931
7932 assert(argc >= 0);
7933 assert(argv);
7934
601185b4 7935 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
7936 switch (c) {
7937
7938 case ARG_HELP:
601185b4
ZJS
7939 runlevel_help();
7940 return 0;
e4b61340
LP
7941
7942 case '?':
7943 return -EINVAL;
7944
7945 default:
eb9da376 7946 assert_not_reached("Unhandled option");
e4b61340 7947 }
e4b61340
LP
7948
7949 if (optind < argc) {
7950 log_error("Too many arguments.");
7951 return -EINVAL;
7952 }
7953
7954 return 1;
7955}
7956
7957static int parse_argv(int argc, char *argv[]) {
7958 assert(argc >= 0);
7959 assert(argv);
7960
7961 if (program_invocation_short_name) {
7962
7963 if (strstr(program_invocation_short_name, "halt")) {
7964 arg_action = ACTION_HALT;
7965 return halt_parse_argv(argc, argv);
7966 } else if (strstr(program_invocation_short_name, "poweroff")) {
7967 arg_action = ACTION_POWEROFF;
7968 return halt_parse_argv(argc, argv);
7969 } else if (strstr(program_invocation_short_name, "reboot")) {
5622dde3
KS
7970 if (kexec_loaded())
7971 arg_action = ACTION_KEXEC;
7972 else
7973 arg_action = ACTION_REBOOT;
e4b61340
LP
7974 return halt_parse_argv(argc, argv);
7975 } else if (strstr(program_invocation_short_name, "shutdown")) {
7976 arg_action = ACTION_POWEROFF;
7977 return shutdown_parse_argv(argc, argv);
7978 } else if (strstr(program_invocation_short_name, "init")) {
d5ca5f11
LP
7979
7980 if (sd_booted() > 0) {
f459b602 7981 arg_action = _ACTION_INVALID;
d5ca5f11
LP
7982 return telinit_parse_argv(argc, argv);
7983 } else {
7984 /* Hmm, so some other init system is
7985 * running, we need to forward this
7986 * request to it. For now we simply
7987 * guess that it is Upstart. */
7988
4ad61fd1 7989 execv(TELINIT, argv);
d5ca5f11
LP
7990
7991 log_error("Couldn't find an alternative telinit implementation to spawn.");
7992 return -EIO;
7993 }
7994
e4b61340
LP
7995 } else if (strstr(program_invocation_short_name, "runlevel")) {
7996 arg_action = ACTION_RUNLEVEL;
7997 return runlevel_parse_argv(argc, argv);
7998 }
7999 }
8000
8001 arg_action = ACTION_SYSTEMCTL;
8002 return systemctl_parse_argv(argc, argv);
8003}
8004
d2e79673 8005#ifdef HAVE_SYSV_COMPAT
44a6b1b6 8006_pure_ static int action_to_runlevel(void) {
eb22ac37
LP
8007
8008 static const char table[_ACTION_MAX] = {
8009 [ACTION_HALT] = '0',
8010 [ACTION_POWEROFF] = '0',
8011 [ACTION_REBOOT] = '6',
8012 [ACTION_RUNLEVEL2] = '2',
8013 [ACTION_RUNLEVEL3] = '3',
8014 [ACTION_RUNLEVEL4] = '4',
8015 [ACTION_RUNLEVEL5] = '5',
8016 [ACTION_RESCUE] = '1'
8017 };
8018
d55ae9e6
LP
8019 assert(arg_action < _ACTION_MAX);
8020
8021 return table[arg_action];
8022}
d2e79673 8023#endif
d55ae9e6 8024
d55ae9e6 8025static int talk_initctl(void) {
eca830be 8026#ifdef HAVE_SYSV_COMPAT
cbc9fbd1
LP
8027 struct init_request request = {
8028 .magic = INIT_MAGIC,
8029 .sleeptime = 0,
8030 .cmd = INIT_CMD_RUNLVL
8031 };
8032
7fd1b19b 8033 _cleanup_close_ int fd = -1;
d55ae9e6 8034 char rl;
cbc9fbd1 8035 int r;
eb22ac37 8036
427b47c4
ZJS
8037 rl = action_to_runlevel();
8038 if (!rl)
eb22ac37
LP
8039 return 0;
8040
d55ae9e6
LP
8041 request.runlevel = rl;
8042
427b47c4
ZJS
8043 fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
8044 if (fd < 0) {
d55ae9e6
LP
8045 if (errno == ENOENT)
8046 return 0;
eb22ac37 8047
eca830be 8048 return log_error_errno(errno, "Failed to open "INIT_FIFO": %m");
d55ae9e6 8049 }
eb22ac37 8050
553acb7b
ZJS
8051 r = loop_write(fd, &request, sizeof(request), false);
8052 if (r < 0)
8053 return log_error_errno(r, "Failed to write to "INIT_FIFO": %m");
eb22ac37
LP
8054
8055 return 1;
eca830be
LP
8056#else
8057 return 0;
8058#endif
e4b61340
LP
8059}
8060
e449de87
LP
8061static int systemctl_main(int argc, char *argv[]) {
8062
8063 static const Verb verbs[] = {
1e726cc9 8064 { "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_NOCHROOT, list_units },
988b3b17
ZJS
8065 { "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files },
8066 { "list-sockets", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_sockets },
8067 { "list-timers", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_timers },
8068 { "list-jobs", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_jobs },
8069 { "list-machines", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_machines },
8070 { "clear-jobs", VERB_ANY, 1, VERB_NOCHROOT, trivial_method },
8071 { "cancel", VERB_ANY, VERB_ANY, VERB_NOCHROOT, cancel_job },
8072 { "start", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
8073 { "stop", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
8074 { "condstop", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with ALTLinux */
8075 { "reload", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
8076 { "restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
8077 { "try-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
8078 { "reload-or-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
8079 { "reload-or-try-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatbility with old systemctl <= 228 */
8080 { "try-reload-or-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
8081 { "force-reload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with SysV */
8082 { "condreload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with ALTLinux */
8083 { "condrestart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with RH */
8084 { "isolate", 2, 2, VERB_NOCHROOT, start_unit },
8085 { "kill", 2, VERB_ANY, VERB_NOCHROOT, kill_unit },
8086 { "is-active", 2, VERB_ANY, VERB_NOCHROOT, check_unit_active },
8087 { "check", 2, VERB_ANY, VERB_NOCHROOT, check_unit_active },
8088 { "is-failed", 2, VERB_ANY, VERB_NOCHROOT, check_unit_failed },
8089 { "show", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show },
8090 { "cat", 2, VERB_ANY, VERB_NOCHROOT, cat },
8091 { "status", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show },
8092 { "help", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show },
8093 { "daemon-reload", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload },
8094 { "daemon-reexec", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload },
8095 { "show-environment", VERB_ANY, 1, VERB_NOCHROOT, show_environment },
8096 { "set-environment", 2, VERB_ANY, VERB_NOCHROOT, set_environment },
8097 { "unset-environment", 2, VERB_ANY, VERB_NOCHROOT, set_environment },
8098 { "import-environment", VERB_ANY, VERB_ANY, VERB_NOCHROOT, import_environment },
8099 { "halt", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
8100 { "poweroff", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
8101 { "reboot", VERB_ANY, 2, VERB_NOCHROOT, start_system_special },
8102 { "kexec", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
8103 { "suspend", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
8104 { "hibernate", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
8105 { "hybrid-sleep", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
8106 { "default", VERB_ANY, 1, VERB_NOCHROOT, start_special },
8107 { "rescue", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
8108 { "emergency", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
8109 { "exit", VERB_ANY, 2, VERB_NOCHROOT, start_special },
8110 { "reset-failed", VERB_ANY, VERB_ANY, VERB_NOCHROOT, reset_failed },
8111 { "enable", 2, VERB_ANY, 0, enable_unit },
8112 { "disable", 2, VERB_ANY, 0, enable_unit },
8113 { "is-enabled", 2, VERB_ANY, 0, unit_is_enabled },
8114 { "reenable", 2, VERB_ANY, 0, enable_unit },
8115 { "preset", 2, VERB_ANY, 0, enable_unit },
8116 { "preset-all", VERB_ANY, 1, 0, preset_all },
8117 { "mask", 2, VERB_ANY, 0, enable_unit },
8118 { "unmask", 2, VERB_ANY, 0, enable_unit },
8119 { "link", 2, VERB_ANY, 0, enable_unit },
8120 { "revert", 2, VERB_ANY, 0, enable_unit },
8121 { "switch-root", 2, VERB_ANY, VERB_NOCHROOT, switch_root },
8122 { "list-dependencies", VERB_ANY, 2, VERB_NOCHROOT, list_dependencies },
8123 { "set-default", 2, 2, 0, set_default },
8124 { "get-default", VERB_ANY, 1, 0, get_default },
8125 { "set-property", 3, VERB_ANY, VERB_NOCHROOT, set_property },
8126 { "is-system-running", VERB_ANY, 1, 0, is_system_running },
8127 { "add-wants", 3, VERB_ANY, 0, add_dependency },
8128 { "add-requires", 3, VERB_ANY, 0, add_dependency },
8129 { "edit", 2, VERB_ANY, VERB_NOCHROOT, edit },
d08e75ed 8130 {}
e449de87 8131 };
7e4249b9 8132
e449de87 8133 return dispatch_verb(argc, argv, verbs, NULL);
e4b61340
LP
8134}
8135
4fbd7192 8136static int reload_with_fallback(void) {
e4b61340 8137
4fbd7192 8138 /* First, try systemd via D-Bus. */
e449de87 8139 if (daemon_reload(0, NULL, NULL) >= 0)
4fbd7192 8140 return 0;
e4b61340
LP
8141
8142 /* Nothing else worked, so let's try signals */
2853b60a 8143 assert(IN_SET(arg_action, ACTION_RELOAD, ACTION_REEXEC));
e4b61340 8144
4a62c710
MS
8145 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0)
8146 return log_error_errno(errno, "kill() failed: %m");
e4b61340
LP
8147
8148 return 0;
8149}
8150
4fbd7192 8151static int start_with_fallback(void) {
e4b61340 8152
4fbd7192 8153 /* First, try systemd via D-Bus. */
e449de87 8154 if (start_unit(0, NULL, NULL) >= 0)
4fbd7192 8155 return 0;
e4b61340 8156
2853b60a 8157 /* Nothing else worked, so let's try /dev/initctl */
fbc43921 8158 if (talk_initctl() > 0)
48ec22bc 8159 return 0;
d55ae9e6
LP
8160
8161 log_error("Failed to talk to init daemon.");
8162 return -EIO;
e4b61340
LP
8163}
8164
477def80 8165static int halt_now(enum action a) {
27c06cb5 8166 int r;
e606bb61 8167
4a3ad399
LP
8168 /* The kernel will automaticall flush ATA disks and suchlike
8169 * on reboot(), but the file systems need to be synce'd
8170 * explicitly in advance. */
f3f054f0
TB
8171 if (!arg_no_sync)
8172 (void) sync();
4a3ad399
LP
8173
8174 /* Make sure C-A-D is handled by the kernel from this point
8175 * on... */
19578bb2 8176 (void) reboot(RB_ENABLE_CAD);
e606bb61 8177
4c80c73c 8178 switch (a) {
e606bb61
LP
8179
8180 case ACTION_HALT:
8181 log_info("Halting.");
19578bb2 8182 (void) reboot(RB_HALT_SYSTEM);
477def80 8183 return -errno;
e606bb61
LP
8184
8185 case ACTION_POWEROFF:
8186 log_info("Powering off.");
19578bb2 8187 (void) reboot(RB_POWER_OFF);
477def80 8188 return -errno;
e606bb61 8189
98d52feb 8190 case ACTION_KEXEC:
477def80
LP
8191 case ACTION_REBOOT: {
8192 _cleanup_free_ char *param = NULL;
cbc9fbd1 8193
27c06cb5
LP
8194 r = read_one_line_file("/run/systemd/reboot-param", &param);
8195 if (r < 0)
8196 log_warning_errno(r, "Failed to read reboot parameter file: %m");
8197
8198 if (!isempty(param)) {
477def80 8199 log_info("Rebooting with argument '%s'.", param);
19578bb2 8200 (void) syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
27c06cb5 8201 log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m");
37185ec8 8202 }
e606bb61 8203
477def80 8204 log_info("Rebooting.");
19578bb2 8205 (void) reboot(RB_AUTOBOOT);
477def80 8206 return -errno;
e606bb61
LP
8207 }
8208
477def80
LP
8209 default:
8210 assert_not_reached("Unknown action.");
8211 }
e606bb61
LP
8212}
8213
56a730fa
LP
8214static int logind_schedule_shutdown(void) {
8215
8216#ifdef HAVE_LOGIND
4afd3348 8217 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
56a730fa
LP
8218 char date[FORMAT_TIMESTAMP_MAX];
8219 const char *action;
4fbd7192 8220 sd_bus *bus;
56a730fa
LP
8221 int r;
8222
4fbd7192 8223 r = acquire_bus(BUS_FULL, &bus);
56a730fa 8224 if (r < 0)
4fbd7192 8225 return r;
56a730fa
LP
8226
8227 switch (arg_action) {
8228 case ACTION_HALT:
8229 action = "halt";
8230 break;
8231 case ACTION_POWEROFF:
8232 action = "poweroff";
8233 break;
8234 case ACTION_KEXEC:
8235 action = "kexec";
8236 break;
a4420f7b
LP
8237 case ACTION_EXIT:
8238 action = "exit";
8239 break;
8240 case ACTION_REBOOT:
56a730fa
LP
8241 default:
8242 action = "reboot";
8243 break;
8244 }
8245
8246 if (arg_dry)
8247 action = strjoina("dry-", action);
8248
d2ad7e1b
ZJS
8249 (void) logind_set_wall_message();
8250
56a730fa 8251 r = sd_bus_call_method(
4fbd7192 8252 bus,
56a730fa
LP
8253 "org.freedesktop.login1",
8254 "/org/freedesktop/login1",
8255 "org.freedesktop.login1.Manager",
8256 "ScheduleShutdown",
8257 &error,
8258 NULL,
8259 "st",
8260 action,
8261 arg_when);
8262 if (r < 0)
8263 return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r));
8264
8265 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.", format_timestamp(date, sizeof(date), arg_when));
8266 return 0;
8267#else
8268 log_error("Cannot schedule shutdown without logind support, proceeding with immediate shutdown.");
8269 return -ENOSYS;
8270#endif
8271}
8272
4fbd7192 8273static int halt_main(void) {
e4b61340
LP
8274 int r;
8275
4fbd7192 8276 r = logind_check_inhibitors(arg_action);
748ebafa
LP
8277 if (r < 0)
8278 return r;
b37844d3 8279
7f96539d
LP
8280 if (arg_when > 0)
8281 return logind_schedule_shutdown();
8282
bc8c2f5c 8283 if (geteuid() != 0) {
7f96539d 8284 if (arg_dry || arg_force > 0) {
2ac3930f
IS
8285 log_error("Must be root.");
8286 return -EPERM;
8287 }
8288
7e59bfcb
LP
8289 /* Try logind if we are a normal user and no special
8290 * mode applies. Maybe PolicyKit allows us to shutdown
8291 * the machine. */
7f96539d 8292 if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT)) {
4fbd7192 8293 r = logind_reboot(arg_action);
4c80c73c
KS
8294 if (r >= 0)
8295 return r;
a9085ea3 8296 if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
7f96539d
LP
8297 /* requested operation is not
8298 * supported on the local system or
8299 * already in progress */
a9085ea3
IS
8300 return r;
8301 /* on all other errors, try low-level operation */
4c80c73c 8302 }
bc8c2f5c
LP
8303 }
8304
65491fd8 8305 if (!arg_dry && !arg_force)
4fbd7192 8306 return start_with_fallback();
e4b61340 8307
2ac3930f
IS
8308 assert(geteuid() == 0);
8309
d90e1a30
LP
8310 if (!arg_no_wtmp) {
8311 if (sd_booted() > 0)
8312 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
7e59bfcb
LP
8313 else {
8314 r = utmp_put_shutdown();
8315 if (r < 0)
da927ba9 8316 log_warning_errno(r, "Failed to write utmp record: %m");
7e59bfcb 8317 }
d90e1a30 8318 }
e4b61340 8319
e4b61340
LP
8320 if (arg_dry)
8321 return 0;
8322
477def80 8323 r = halt_now(arg_action);
691395d8 8324 return log_error_errno(r, "Failed to reboot: %m");
e4b61340
LP
8325}
8326
8327static int runlevel_main(void) {
8328 int r, runlevel, previous;
8329
729e3769
LP
8330 r = utmp_get_runlevel(&runlevel, &previous);
8331 if (r < 0) {
8332 puts("unknown");
e4b61340
LP
8333 return r;
8334 }
8335
8336 printf("%c %c\n",
8337 previous <= 0 ? 'N' : previous,
8338 runlevel <= 0 ? 'N' : runlevel);
8339
8340 return 0;
8341}
8342
2cf05793
LP
8343static int logind_cancel_shutdown(void) {
8344#ifdef HAVE_LOGIND
4afd3348 8345 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192 8346 sd_bus *bus;
949d9ce9
LP
8347 int r;
8348
4fbd7192 8349 r = acquire_bus(BUS_FULL, &bus);
949d9ce9 8350 if (r < 0)
4fbd7192 8351 return r;
949d9ce9 8352
4fbd7192 8353 (void) logind_set_wall_message();
949d9ce9
LP
8354
8355 r = sd_bus_call_method(
4fbd7192 8356 bus,
949d9ce9
LP
8357 "org.freedesktop.login1",
8358 "/org/freedesktop/login1",
8359 "org.freedesktop.login1.Manager",
8360 "CancelScheduledShutdown",
8361 &error,
8362 NULL, NULL);
8363 if (r < 0)
8364 return log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s", bus_error_message(&error, r));
8365
8366 return 0;
2cf05793
LP
8367#else
8368 log_error("Not compiled with logind support, cannot cancel scheduled shutdowns.");
8369 return -ENOSYS;
8370#endif
949d9ce9
LP
8371}
8372
e4b61340 8373int main(int argc, char*argv[]) {
f459b602 8374 int r;
e4b61340 8375
a9cdc94f 8376 setlocale(LC_ALL, "");
e4b61340 8377 log_parse_environment();
2396fb04 8378 log_open();
592705f2 8379 sigbus_install();
e4b61340 8380
184ecaf7
DR
8381 /* Explicitly not on_tty() to avoid setting cached value.
8382 * This becomes relevant for piping output which might be
8383 * ellipsized. */
8384 original_stdout_is_tty = isatty(STDOUT_FILENO);
8385
04ebb595 8386 r = parse_argv(argc, argv);
f459b602 8387 if (r <= 0)
e4b61340 8388 goto finish;
7e4249b9 8389
040524b4 8390 if (arg_action != ACTION_SYSTEMCTL && running_in_chroot() > 0) {
82e23ddd 8391 log_info("Running in chroot, ignoring request.");
f459b602 8392 r = 0;
82e23ddd
LP
8393 goto finish;
8394 }
8395
41dd15e4
LP
8396 /* systemctl_main() will print an error message for the bus
8397 * connection, but only if it needs to */
e4b61340
LP
8398
8399 switch (arg_action) {
8400
22f4096c 8401 case ACTION_SYSTEMCTL:
e449de87 8402 r = systemctl_main(argc, argv);
e4b61340 8403 break;
e4b61340
LP
8404
8405 case ACTION_HALT:
8406 case ACTION_POWEROFF:
8407 case ACTION_REBOOT:
5622dde3 8408 case ACTION_KEXEC:
4fbd7192 8409 r = halt_main();
e4b61340
LP
8410 break;
8411
e4b61340
LP
8412 case ACTION_RUNLEVEL2:
8413 case ACTION_RUNLEVEL3:
8414 case ACTION_RUNLEVEL4:
8415 case ACTION_RUNLEVEL5:
8416 case ACTION_RESCUE:
514f4ef5 8417 case ACTION_EMERGENCY:
eb22ac37 8418 case ACTION_DEFAULT:
4fbd7192 8419 r = start_with_fallback();
e4b61340 8420 break;
7e4249b9 8421
e4b61340
LP
8422 case ACTION_RELOAD:
8423 case ACTION_REEXEC:
4fbd7192 8424 r = reload_with_fallback();
e4b61340
LP
8425 break;
8426
949d9ce9 8427 case ACTION_CANCEL_SHUTDOWN:
2cf05793 8428 r = logind_cancel_shutdown();
f6144808
LP
8429 break;
8430
eb22ac37 8431 case ACTION_RUNLEVEL:
4f16c1f4
LP
8432 r = runlevel_main();
8433 break;
8434
f459b602 8435 case _ACTION_INVALID:
e4b61340
LP
8436 default:
8437 assert_not_reached("Unknown action");
8438 }
7e4249b9
LP
8439
8440finish:
cf647b69
LP
8441 release_busses();
8442
f459b602
MAP
8443 pager_close();
8444 ask_password_agent_close();
8445 polkit_agent_close();
7e4249b9 8446
20b3f379 8447 strv_free(arg_types);
9b9b3d36 8448 strv_free(arg_states);
20b3f379 8449 strv_free(arg_properties);
ea4a240d 8450
172d7abf 8451 strv_free(arg_wall);
0f03c2a4 8452 free(arg_root);
172d7abf 8453
404f08d3 8454 /* Note that we return r here, not EXIT_SUCCESS, so that we can implement the LSB-like return codes */
9eb4a501 8455 return r < 0 ? EXIT_FAILURE : r;
7e4249b9 8456}