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