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