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