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