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