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