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