]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl.c
kdbus: downgrade warning if we cannot patch kdbus attach mask to DEBUG if kdbus is...
[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"
718db961 75#include "bus-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
755 * values, so let's follow that.*/
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)
729e3769 5146 unsigned f = 1, t = 1;
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;
cbb13b2a 5165 for (f = 0; args[f]; 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
729e3769 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
LP
5208 /* Mark this entry, so that we don't try enabling it as native unit */
5209 args[f] = (char*) "";
ee5762e3 5210
729e3769 5211 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
ee5762e3 5212
729e3769
LP
5213 if (!isempty(arg_root))
5214 argv[c++] = q = strappend("--root=", arg_root);
ee5762e3 5215
2b6bf07d 5216 argv[c++] = basename(p);
729e3769
LP
5217 argv[c++] =
5218 streq(verb, "enable") ? "on" :
5219 streq(verb, "disable") ? "off" : "--level=5";
5220 argv[c] = NULL;
ee5762e3 5221
729e3769 5222 l = strv_join((char**)argv, " ");
60731f32
ZJS
5223 if (!l)
5224 return log_oom();
ee5762e3 5225
729e3769 5226 log_info("Executing %s", l);
ee5762e3 5227
729e3769 5228 pid = fork();
4a62c710
MS
5229 if (pid < 0)
5230 return log_error_errno(errno, "Failed to fork: %m");
5231 else if (pid == 0) {
729e3769 5232 /* Child */
ee5762e3 5233
729e3769
LP
5234 execv(argv[0], (char**) argv);
5235 _exit(EXIT_FAILURE);
5236 }
ee5762e3 5237
729e3769
LP
5238 j = wait_for_terminate(pid, &status);
5239 if (j < 0) {
da927ba9 5240 log_error_errno(r, "Failed to wait for child: %m");
60731f32 5241 return j;
729e3769 5242 }
ee5762e3 5243
729e3769
LP
5244 if (status.si_code == CLD_EXITED) {
5245 if (streq(verb, "is-enabled")) {
5246 if (status.si_status == 0) {
5247 if (!arg_quiet)
5248 puts("enabled");
5249 r = 1;
5250 } else {
5251 if (!arg_quiet)
5252 puts("disabled");
5253 }
ee5762e3 5254
60731f32
ZJS
5255 } else if (status.si_status != 0)
5256 return -EINVAL;
5257 } else
5258 return -EPROTO;
ee5762e3
LP
5259 }
5260
729e3769 5261 /* Drop all SysV units */
cbb13b2a 5262 for (f = 0, t = 0; args[f]; f++) {
ee5762e3 5263
729e3769 5264 if (isempty(args[f]))
ee5762e3
LP
5265 continue;
5266
729e3769
LP
5267 args[t++] = args[f];
5268 }
ee5762e3 5269
729e3769 5270 args[t] = NULL;
ee5762e3 5271
729e3769
LP
5272#endif
5273 return r;
5274}
ee5762e3 5275
37370d0c 5276static int mangle_names(char **original_names, char ***mangled_names) {
a33fdebb 5277 char **i, **l, **name;
37370d0c 5278
a33fdebb
LP
5279 l = new(char*, strv_length(original_names) + 1);
5280 if (!l)
37370d0c
VP
5281 return log_oom();
5282
a33fdebb 5283 i = l;
37370d0c 5284 STRV_FOREACH(name, original_names) {
44386fc1
LN
5285
5286 /* When enabling units qualified path names are OK,
5287 * too, hence allow them explicitly. */
5288
5289 if (is_path(*name))
5290 *i = strdup(*name);
5291 else
f78e6385 5292 *i = unit_name_mangle(*name, MANGLE_NOGLOB);
44386fc1 5293
a33fdebb
LP
5294 if (!*i) {
5295 strv_free(l);
37370d0c 5296 return log_oom();
a33fdebb
LP
5297 }
5298
5299 i++;
37370d0c 5300 }
a33fdebb
LP
5301
5302 *i = NULL;
5303 *mangled_names = l;
37370d0c
VP
5304
5305 return 0;
5306}
5307
f459b602 5308static int enable_unit(sd_bus *bus, char **args) {
e3e0314b 5309 _cleanup_strv_free_ char **names = NULL;
729e3769
LP
5310 const char *verb = args[0];
5311 UnitFileChange *changes = NULL;
718db961 5312 unsigned n_changes = 0;
729e3769 5313 int carries_install_info = -1;
729e3769 5314 int r;
ee5762e3 5315
ab5919fa
MS
5316 if (!args[1])
5317 return 0;
5318
e3e0314b 5319 r = mangle_names(args+1, &names);
3a05c0f9 5320 if (r < 0)
cbb13b2a
VP
5321 return r;
5322
e3e0314b 5323 r = enable_sysv_units(verb, names);
cbb13b2a
VP
5324 if (r < 0)
5325 return r;
3a05c0f9 5326
67d66210
LP
5327 /* If the operation was fully executed by the SysV compat,
5328 * let's finish early */
5329 if (strv_isempty(names))
5330 return 0;
5331
729e3769
LP
5332 if (!bus || avoid_bus()) {
5333 if (streq(verb, "enable")) {
e3e0314b 5334 r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769
LP
5335 carries_install_info = r;
5336 } else if (streq(verb, "disable"))
e3e0314b 5337 r = unit_file_disable(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
729e3769 5338 else if (streq(verb, "reenable")) {
e3e0314b 5339 r = unit_file_reenable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769
LP
5340 carries_install_info = r;
5341 } else if (streq(verb, "link"))
e3e0314b 5342 r = unit_file_link(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769 5343 else if (streq(verb, "preset")) {
d309c1c3 5344 r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_preset_mode, arg_force, &changes, &n_changes);
729e3769
LP
5345 carries_install_info = r;
5346 } else if (streq(verb, "mask"))
e3e0314b 5347 r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769 5348 else if (streq(verb, "unmask"))
e3e0314b 5349 r = unit_file_unmask(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
729e3769
LP
5350 else
5351 assert_not_reached("Unknown verb");
ee5762e3 5352
729e3769 5353 if (r < 0) {
da927ba9 5354 log_error_errno(r, "Operation failed: %m");
729e3769 5355 goto finish;
ee5762e3
LP
5356 }
5357
718db961
LP
5358 if (!arg_quiet)
5359 dump_unit_file_changes(changes, n_changes);
ee5762e3 5360
df77cdf0 5361 r = 0;
729e3769 5362 } else {
718db961
LP
5363 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
5364 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
f459b602 5365 int expect_carries_install_info = false;
d309c1c3 5366 bool send_force = true, send_preset_mode = false;
718db961 5367 const char *method;
729e3769
LP
5368
5369 if (streq(verb, "enable")) {
5370 method = "EnableUnitFiles";
5371 expect_carries_install_info = true;
5372 } else if (streq(verb, "disable")) {
5373 method = "DisableUnitFiles";
5374 send_force = false;
5375 } else if (streq(verb, "reenable")) {
5376 method = "ReenableUnitFiles";
5377 expect_carries_install_info = true;
5378 } else if (streq(verb, "link"))
5379 method = "LinkUnitFiles";
5380 else if (streq(verb, "preset")) {
d309c1c3
LP
5381
5382 if (arg_preset_mode != UNIT_FILE_PRESET_FULL) {
5383 method = "PresetUnitFilesWithMode";
5384 send_preset_mode = true;
5385 } else
5386 method = "PresetUnitFiles";
5387
729e3769
LP
5388 expect_carries_install_info = true;
5389 } else if (streq(verb, "mask"))
5390 method = "MaskUnitFiles";
5391 else if (streq(verb, "unmask")) {
5392 method = "UnmaskUnitFiles";
5393 send_force = false;
5394 } else
5395 assert_not_reached("Unknown verb");
5396
f459b602
MAP
5397 r = sd_bus_message_new_method_call(
5398 bus,
151b9b96 5399 &m,
729e3769
LP
5400 "org.freedesktop.systemd1",
5401 "/org/freedesktop/systemd1",
5402 "org.freedesktop.systemd1.Manager",
151b9b96 5403 method);
f459b602
MAP
5404 if (r < 0)
5405 return bus_log_create_error(r);
ee5762e3 5406
342641fb
LP
5407 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
5408 if (r < 0)
5409 return bus_log_create_error(r);
5410
e3e0314b 5411 r = sd_bus_message_append_strv(m, names);
f459b602
MAP
5412 if (r < 0)
5413 return bus_log_create_error(r);
ee5762e3 5414
d309c1c3
LP
5415 if (send_preset_mode) {
5416 r = sd_bus_message_append(m, "s", unit_file_preset_mode_to_string(arg_preset_mode));
5417 if (r < 0)
5418 return bus_log_create_error(r);
5419 }
5420
f459b602
MAP
5421 r = sd_bus_message_append(m, "b", arg_runtime);
5422 if (r < 0)
5423 return bus_log_create_error(r);
ee5762e3 5424
729e3769 5425 if (send_force) {
f459b602
MAP
5426 r = sd_bus_message_append(m, "b", arg_force);
5427 if (r < 0)
5428 return bus_log_create_error(r);
ee5762e3
LP
5429 }
5430
c49b30a2 5431 r = sd_bus_call(bus, m, 0, &error, &reply);
f459b602
MAP
5432 if (r < 0) {
5433 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
5434 return r;
729e3769 5435 }
be394c48 5436
729e3769 5437 if (expect_carries_install_info) {
f459b602
MAP
5438 r = sd_bus_message_read(reply, "b", &carries_install_info);
5439 if (r < 0)
5440 return bus_log_parse_error(r);
ee5762e3
LP
5441 }
5442
cc3f2093 5443 r = deserialize_and_dump_unit_file_changes(reply);
f459b602 5444 if (r < 0)
718db961 5445 return r;
b77398f7 5446
93c941e3 5447 /* Try to reload if enabled */
d6cb60c7 5448 if (!arg_no_reload)
729e3769 5449 r = daemon_reload(bus, args);
f459b602
MAP
5450 else
5451 r = 0;
b647f10d 5452 }
3d3961f2 5453
729e3769 5454 if (carries_install_info == 0)
416389f7
LP
5455 log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
5456 "using systemctl.\n"
5457 "Possible reasons for having this kind of units are:\n"
5458 "1) A unit may be statically enabled by being symlinked from another unit's\n"
5459 " .wants/ or .requires/ directory.\n"
5460 "2) A unit's purpose may be to act as a helper for some other unit which has\n"
5461 " a requirement dependency on it.\n"
5462 "3) A unit may be started when needed via activation (socket, path, timer,\n"
5463 " D-Bus, udev, scripted systemctl call, ...).\n");
ee5762e3 5464
729e3769 5465finish:
729e3769 5466 unit_file_changes_free(changes, n_changes);
ee5762e3 5467
729e3769 5468 return r;
ee5762e3
LP
5469}
5470
e94937df
LN
5471static int add_dependency(sd_bus *bus, char **args) {
5472 _cleanup_strv_free_ char **names = NULL;
5473 _cleanup_free_ char *target = NULL;
5474 const char *verb = args[0];
5475 UnitDependency dep;
5476 int r = 0;
5477
5478 if (!args[1])
5479 return 0;
5480
5481 target = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".target");
5482 if (!target)
5483 return log_oom();
5484
5485 r = mangle_names(args+2, &names);
5486 if (r < 0)
5487 return r;
5488
5489 if (streq(verb, "add-wants"))
5490 dep = UNIT_WANTS;
5491 else if (streq(verb, "add-requires"))
5492 dep = UNIT_REQUIRES;
5493 else
5494 assert_not_reached("Unknown verb");
5495
5496 if (!bus || avoid_bus()) {
5497 UnitFileChange *changes = NULL;
5498 unsigned n_changes = 0;
5499
5500 r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes);
5501
f647962d
MS
5502 if (r < 0)
5503 return log_error_errno(r, "Can't add dependency: %m");
e94937df
LN
5504
5505 if (!arg_quiet)
5506 dump_unit_file_changes(changes, n_changes);
5507
5508 unit_file_changes_free(changes, n_changes);
5509
5510 } else {
5511 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
5512 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
5513
5514 r = sd_bus_message_new_method_call(
5515 bus,
5516 &m,
5517 "org.freedesktop.systemd1",
5518 "/org/freedesktop/systemd1",
5519 "org.freedesktop.systemd1.Manager",
5520 "AddDependencyUnitFiles");
5521 if (r < 0)
5522 return bus_log_create_error(r);
5523
342641fb 5524 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
e94937df
LN
5525 if (r < 0)
5526 return bus_log_create_error(r);
5527
342641fb 5528 r = sd_bus_message_append_strv(m, names);
e94937df
LN
5529 if (r < 0)
5530 return bus_log_create_error(r);
5531
342641fb 5532 r = sd_bus_message_append(m, "ssbb", target, unit_dependency_to_string(dep), arg_runtime, arg_force);
e94937df
LN
5533 if (r < 0)
5534 return bus_log_create_error(r);
5535
5536 r = sd_bus_call(bus, m, 0, &error, &reply);
5537 if (r < 0) {
5538 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
5539 return r;
5540 }
5541
5542 r = deserialize_and_dump_unit_file_changes(reply);
5543 if (r < 0)
5544 return r;
5545
5546 if (!arg_no_reload)
5547 r = daemon_reload(bus, args);
5548 else
5549 r = 0;
5550 }
5551
5552 return r;
5553}
5554
d309c1c3
LP
5555static int preset_all(sd_bus *bus, char **args) {
5556 UnitFileChange *changes = NULL;
5557 unsigned n_changes = 0;
5558 int r;
5559
5560 if (!bus || avoid_bus()) {
5561
5562 r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes);
5563 if (r < 0) {
da927ba9 5564 log_error_errno(r, "Operation failed: %m");
d309c1c3
LP
5565 goto finish;
5566 }
5567
5568 if (!arg_quiet)
5569 dump_unit_file_changes(changes, n_changes);
5570
5571 r = 0;
5572
5573 } else {
342641fb 5574 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
d309c1c3
LP
5575 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
5576
342641fb 5577 r = sd_bus_message_new_method_call(
d309c1c3 5578 bus,
342641fb 5579 &m,
d309c1c3
LP
5580 "org.freedesktop.systemd1",
5581 "/org/freedesktop/systemd1",
5582 "org.freedesktop.systemd1.Manager",
342641fb
LP
5583 "PresetAllUnitFiles");
5584 if (r < 0)
5585 return bus_log_create_error(r);
5586
5587 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
5588 if (r < 0)
5589 return bus_log_create_error(r);
5590
5591 r = sd_bus_message_append(
5592 m,
d309c1c3
LP
5593 "sbb",
5594 unit_file_preset_mode_to_string(arg_preset_mode),
5595 arg_runtime,
5596 arg_force);
342641fb
LP
5597 if (r < 0)
5598 return bus_log_create_error(r);
5599
5600 r = sd_bus_call(bus, m, 0, &error, &reply);
d309c1c3
LP
5601 if (r < 0) {
5602 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
5603 return r;
5604 }
5605
5606 r = deserialize_and_dump_unit_file_changes(reply);
5607 if (r < 0)
5608 return r;
5609
5610 if (!arg_no_reload)
5611 r = daemon_reload(bus, args);
5612 else
5613 r = 0;
5614 }
5615
5616finish:
5617 unit_file_changes_free(changes, n_changes);
5618
5619 return r;
5620}
5621
f459b602
MAP
5622static int unit_is_enabled(sd_bus *bus, char **args) {
5623
5624 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
e3e0314b 5625 _cleanup_strv_free_ char **names = NULL;
729e3769
LP
5626 bool enabled;
5627 char **name;
f459b602 5628 int r;
ee5762e3 5629
e3e0314b 5630 r = mangle_names(args+1, &names);
cbb13b2a
VP
5631 if (r < 0)
5632 return r;
5633
e3e0314b 5634 r = enable_sysv_units(args[0], names);
729e3769
LP
5635 if (r < 0)
5636 return r;
ee5762e3 5637
729e3769 5638 enabled = r > 0;
ee5762e3 5639
729e3769 5640 if (!bus || avoid_bus()) {
ee5762e3 5641
e3e0314b 5642 STRV_FOREACH(name, names) {
729e3769 5643 UnitFileState state;
ee5762e3 5644
cbb13b2a 5645 state = unit_file_get_state(arg_scope, arg_root, *name);
f647962d
MS
5646 if (state < 0)
5647 return log_error_errno(state, "Failed to get unit file state for %s: %m", *name);
ee5762e3 5648
729e3769
LP
5649 if (state == UNIT_FILE_ENABLED ||
5650 state == UNIT_FILE_ENABLED_RUNTIME ||
aedd4012
JS
5651 state == UNIT_FILE_STATIC ||
5652 state == UNIT_FILE_INDIRECT)
729e3769
LP
5653 enabled = true;
5654
5655 if (!arg_quiet)
5656 puts(unit_file_state_to_string(state));
71fad675 5657 }
ee5762e3 5658
729e3769 5659 } else {
e3e0314b 5660 STRV_FOREACH(name, names) {
f459b602 5661 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
729e3769 5662 const char *s;
63a723f3 5663
f459b602 5664 r = sd_bus_call_method(
f22f08cd 5665 bus,
729e3769
LP
5666 "org.freedesktop.systemd1",
5667 "/org/freedesktop/systemd1",
5668 "org.freedesktop.systemd1.Manager",
f22f08cd 5669 "GetUnitFileState",
f459b602 5670 &error,
f22f08cd 5671 &reply,
04504f93 5672 "s", *name);
f459b602
MAP
5673 if (r < 0) {
5674 log_error("Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
cec7eda5 5675 return r;
ee5762e3
LP
5676 }
5677
f459b602
MAP
5678 r = sd_bus_message_read(reply, "s", &s);
5679 if (r < 0)
5680 return bus_log_parse_error(r);
ee5762e3 5681
aedd4012 5682 if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect"))
729e3769
LP
5683 enabled = true;
5684
5685 if (!arg_quiet)
5686 puts(s);
560d8f23 5687 }
ee5762e3
LP
5688 }
5689
f459b602 5690 return !enabled;
ee5762e3
LP
5691}
5692
99813a19
LP
5693static int is_system_running(sd_bus *bus, char **args) {
5694 _cleanup_free_ char *state = NULL;
5695 int r;
5696
5697 r = sd_bus_get_property_string(
5698 bus,
5699 "org.freedesktop.systemd1",
5700 "/org/freedesktop/systemd1",
5701 "org.freedesktop.systemd1.Manager",
5702 "SystemState",
5703 NULL,
5704 &state);
5705 if (r < 0) {
5706 if (!arg_quiet)
5707 puts("unknown");
5708 return 0;
5709 }
5710
5711 if (!arg_quiet)
5712 puts(state);
5713
5714 return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE;
5715}
5716
7d4fb3b1
RC
5717static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **unit_path) {
5718 char **p;
5719
5720 assert(lp);
5721 assert(unit_name);
5722 assert(unit_path);
5723
5724 STRV_FOREACH(p, lp->unit_path) {
5725 char *path;
5726
5727 path = path_join(arg_root, *p, unit_name);
5728 if (!path)
5729 return log_oom();
5730
5731 if (access(path, F_OK) == 0) {
5732 *unit_path = path;
5733 return 1;
5734 }
5735
5736 free(path);
5737 }
5738
5739 return 0;
5740}
5741
5742static int create_edit_temp_file(const char *new_path, const char *original_path, char **ret_tmp_fn) {
7d4fb3b1
RC
5743 int r;
5744 char *t;
5745
5746 assert(new_path);
5747 assert(original_path);
5748 assert(ret_tmp_fn);
5749
5750 t = tempfn_random(new_path);
5751 if (!t)
5752 return log_oom();
5753
5754 r = mkdir_parents(new_path, 0755);
652212b0
TA
5755 if (r < 0) {
5756 log_error_errno(r, "Failed to create directories for %s: %m", new_path);
5757 free(t);
5758 return r;
5759 }
7d4fb3b1
RC
5760
5761 r = copy_file(original_path, t, 0, 0644);
5762 if (r == -ENOENT) {
5763 r = touch(t);
5764 if (r < 0) {
5765 log_error_errno(r, "Failed to create temporary file %s: %m", t);
5766 free(t);
5767 return r;
5768 }
5769 } else if (r < 0) {
5770 log_error_errno(r, "Failed to copy %s to %s: %m", original_path, t);
5771 free(t);
5772 return r;
5773 }
5774
5775 *ret_tmp_fn = t;
5776
5777 return 0;
5778}
5779
5780static int get_drop_in_to_edit(const char *unit_name, const char *user_home, const char *user_runtime, char **ret_path) {
5781 char *tmp_new_path;
5782 char *tmp;
5783
5784 assert(unit_name);
5785 assert(ret_path);
5786
5787 switch (arg_scope) {
5788 case UNIT_FILE_SYSTEM:
5789 tmp = strappenda(arg_runtime ? "/run/systemd/system/" : SYSTEM_CONFIG_UNIT_PATH "/", unit_name, ".d/override.conf");
5790 break;
5791 case UNIT_FILE_GLOBAL:
5792 tmp = strappenda(arg_runtime ? "/run/systemd/user/" : USER_CONFIG_UNIT_PATH "/", unit_name, ".d/override.conf");
5793 break;
5794 case UNIT_FILE_USER:
5795 assert(user_home);
5796 assert(user_runtime);
5797
5798 tmp = strappenda(arg_runtime ? user_runtime : user_home, "/", unit_name, ".d/override.conf");
5799 break;
5800 default:
5801 assert_not_reached("Invalid scope");
5802 }
5803
5804 tmp_new_path = path_join(arg_root, tmp, NULL);
5805 if (!tmp_new_path)
5806 return log_oom();
5807
5808 *ret_path = tmp_new_path;
5809
5810 return 0;
5811}
5812
5813static 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) {
5814 char *tmp_new_path;
5815 char *tmp_tmp_path;
5816 int r;
5817
5818 assert(unit_name);
5819 assert(ret_new_path);
5820 assert(ret_tmp_path);
5821
5822 r = get_drop_in_to_edit(unit_name, user_home, user_runtime, &tmp_new_path);
5823 if (r < 0)
5824 return r;
5825
5826 r = create_edit_temp_file(tmp_new_path, tmp_new_path, &tmp_tmp_path);
5827 if (r < 0) {
5828 free(tmp_new_path);
5829 return r;
5830 }
5831
5832 *ret_new_path = tmp_new_path;
5833 *ret_tmp_path = tmp_tmp_path;
5834
5835 return 0;
5836}
5837
5838static bool unit_is_editable(const char *unit_name, const char *fragment_path, const char *user_home) {
5839 bool editable = true;
5840 const char *invalid_path;
5841
5842 assert(unit_name);
5843
5844 if (!arg_runtime)
5845 return true;
5846
5847 switch (arg_scope) {
5848 case UNIT_FILE_SYSTEM:
5849 if (path_startswith(fragment_path, "/etc/systemd/system")) {
5850 editable = false;
5851 invalid_path = "/etc/systemd/system";
5852 } else if (path_startswith(fragment_path, SYSTEM_CONFIG_UNIT_PATH)) {
5853 editable = false;
5854 invalid_path = SYSTEM_CONFIG_UNIT_PATH;
5855 }
5856 break;
5857 case UNIT_FILE_GLOBAL:
5858 if (path_startswith(fragment_path, "/etc/systemd/user")) {
5859 editable = false;
5860 invalid_path = "/etc/systemd/user";
5861 } else if (path_startswith(fragment_path, USER_CONFIG_UNIT_PATH)) {
5862 editable = false;
5863 invalid_path = USER_CONFIG_UNIT_PATH;
5864 }
5865 break;
5866 case UNIT_FILE_USER:
5867 assert(user_home);
5868
5869 if (path_startswith(fragment_path, "/etc/systemd/user")) {
5870 editable = false;
5871 invalid_path = "/etc/systemd/user";
5872 } else if (path_startswith(fragment_path, USER_CONFIG_UNIT_PATH)) {
5873 editable = false;
5874 invalid_path = USER_CONFIG_UNIT_PATH;
5875 } else if (path_startswith(fragment_path, user_home)) {
5876 editable = false;
5877 invalid_path = user_home;
5878 }
5879 break;
5880 default:
5881 assert_not_reached("Invalid scope");
5882 }
5883
5884 if (!editable)
5885 log_error("%s ignored: cannot temporarily edit units from %s", unit_name, invalid_path);
5886
5887 return editable;
5888}
5889
5890static int get_copy_to_edit(const char *unit_name, const char *fragment_path, const char *user_home, const char *user_runtime, char **ret_path) {
5891 char *tmp_new_path;
5892
5893 assert(unit_name);
5894 assert(ret_path);
5895
5896 if (!unit_is_editable(unit_name, fragment_path, user_home))
5897 return -EINVAL;
5898
5899 switch (arg_scope) {
5900 case UNIT_FILE_SYSTEM:
5901 tmp_new_path = path_join(arg_root, arg_runtime ? "/run/systemd/system/" : SYSTEM_CONFIG_UNIT_PATH, unit_name);
5902 break;
5903 case UNIT_FILE_GLOBAL:
5904 tmp_new_path = path_join(arg_root, arg_runtime ? "/run/systemd/user/" : USER_CONFIG_UNIT_PATH, unit_name);
5905 break;
5906 case UNIT_FILE_USER:
5907 assert(user_home);
5908 assert(user_runtime);
5909
5910 tmp_new_path = path_join(arg_root, arg_runtime ? user_runtime : user_home, unit_name);
5911 break;
5912 default:
5913 assert_not_reached("Invalid scope");
5914 }
5915 if (!tmp_new_path)
5916 return log_oom();
5917
5918 *ret_path = tmp_new_path;
5919
5920 return 0;
5921}
5922
5923static int unit_file_create_copy(const char *unit_name,
5924 const char *fragment_path,
5925 const char *user_home,
5926 const char *user_runtime,
5927 char **ret_new_path,
5928 char **ret_tmp_path) {
5929 char *tmp_new_path;
5930 char *tmp_tmp_path;
5931 int r;
5932
5933 assert(fragment_path);
5934 assert(unit_name);
5935 assert(ret_new_path);
5936 assert(ret_tmp_path);
5937
5938 r = get_copy_to_edit(unit_name, fragment_path, user_home, user_runtime, &tmp_new_path);
5939 if (r < 0)
5940 return r;
5941
5942 if (!path_equal(fragment_path, tmp_new_path) && access(tmp_new_path, F_OK) == 0) {
5943 char response;
5944
5945 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);
5946 if (r < 0) {
5947 free(tmp_new_path);
5948 return r;
5949 }
5950 if (response != 'y') {
5951 log_warning("%s ignored", unit_name);
5952 free(tmp_new_path);
5953 return -1;
5954 }
5955 }
5956
5957 r = create_edit_temp_file(tmp_new_path, fragment_path, &tmp_tmp_path);
5958 if (r < 0) {
5959 log_error_errno(r, "Failed to create temporary file for %s: %m", tmp_new_path);
5960 free(tmp_new_path);
5961 return r;
5962 }
5963
5964 *ret_new_path = tmp_new_path;
5965 *ret_tmp_path = tmp_tmp_path;
5966
5967 return 0;
5968}
5969
5970static int run_editor(char **paths) {
5971 pid_t pid;
5972 int r;
5973
5974 assert(paths);
5975
5976 pid = fork();
5977 if (pid < 0) {
5978 log_error_errno(errno, "Failed to fork: %m");
5979 return -errno;
5980 }
5981
5982 if (pid == 0) {
5983 const char **args;
5984 char **backup_editors = STRV_MAKE("nano", "vim", "vi");
5985 char *editor;
5986 char **tmp_path, **original_path, **p;
5987 unsigned i = 1;
5988 size_t argc;
5989
5990 argc = strv_length(paths)/2 + 1;
5991 args = newa(const char*, argc + 1);
5992
5993 args[0] = NULL;
5994 STRV_FOREACH_PAIR(original_path, tmp_path, paths) {
5995 args[i] = *tmp_path;
5996 i++;
5997 }
5998 args[argc] = NULL;
5999
6000 /* SYSTEMD_EDITOR takes precedence over EDITOR which takes precedence over VISUAL
6001 * If neither SYSTEMD_EDITOR nor EDITOR nor VISUAL are present,
6002 * we try to execute well known editors
6003 */
6004 editor = getenv("SYSTEMD_EDITOR");
6005 if (!editor)
6006 editor = getenv("EDITOR");
6007 if (!editor)
6008 editor = getenv("VISUAL");
6009
6010 if (!isempty(editor)) {
6011 args[0] = editor;
6012 execvp(editor, (char* const*) args);
6013 }
6014
6015 STRV_FOREACH(p, backup_editors) {
6016 args[0] = *p;
6017 execvp(*p, (char* const*) args);
6018 /* We do not fail if the editor doesn't exist
6019 * because we want to try each one of them before
6020 * failing.
6021 */
6022 if (errno != ENOENT) {
6023 log_error("Failed to execute %s: %m", editor);
6024 _exit(EXIT_FAILURE);
6025 }
6026 }
6027
6028 log_error("Cannot edit unit(s): No editor available. Please set either SYSTEMD_EDITOR or EDITOR or VISUAL environment variable");
6029 _exit(EXIT_FAILURE);
6030 }
6031
6032 r = wait_for_terminate_and_warn("editor", pid, true);
6033 if (r < 0)
6034 return log_error_errno(r, "Failed to wait for child: %m");
6035
6036 return r;
6037}
6038
6039static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
6040 _cleanup_free_ char *user_home = NULL;
6041 _cleanup_free_ char *user_runtime = NULL;
6042 char **name;
6043 int r;
6044
6045 assert(names);
6046 assert(paths);
6047
6048 if (arg_scope == UNIT_FILE_USER) {
6049 r = user_config_home(&user_home);
6050 if (r < 0)
6051 return log_oom();
6052 else if (r == 0) {
6053 log_error("Cannot edit units for the user instance: home directory unknown");
6054 return -1;
6055 }
6056
6057 r = user_runtime_dir(&user_runtime);
6058 if (r < 0)
6059 return log_oom();
6060 else if (r == 0) {
6061 log_error("Cannot edit units for the user instance: runtime directory unknown");
6062 return -1;
6063 }
6064 }
6065
6066 if (!bus || avoid_bus()) {
6067 _cleanup_lookup_paths_free_ LookupPaths lp = {};
6068
6069 /* If there is no bus, we try to find the units by testing each available directory
6070 * according to the scope.
6071 */
6072 r = lookup_paths_init(&lp,
6073 arg_scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER,
6074 arg_scope == UNIT_FILE_USER,
6075 arg_root,
6076 NULL, NULL, NULL);
6077 if (r < 0) {
6078 log_error_errno(r, "Failed get lookup paths: %m");
6079 return r;
6080 }
6081
6082 STRV_FOREACH(name, names) {
6083 _cleanup_free_ char *path = NULL;
6084 char *new_path, *tmp_path;
6085
6086 r = unit_file_find_path(&lp, *name, &path);
6087 if (r < 0)
6088 return r;
6089 if (r == 0) {
6090 log_warning("%s ignored: not found", *name);
6091 continue;
6092 }
6093
6094 if (arg_full)
6095 r = unit_file_create_copy(*name, path, user_home, user_runtime, &new_path, &tmp_path);
6096 else
6097 r = unit_file_create_drop_in(*name, user_home, user_runtime, &new_path, &tmp_path);
6098
6099 if (r < 0)
6100 continue;
6101
6102 r = strv_push(paths, new_path);
6103 if (r < 0)
6104 return log_oom();
6105
6106 r = strv_push(paths, tmp_path);
6107 if (r < 0)
6108 return log_oom();
6109 }
6110 } else {
6111 STRV_FOREACH(name, names) {
6112 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
6113 _cleanup_free_ char *fragment_path = NULL;
6114 _cleanup_free_ char *unit = NULL;
6115 char *new_path, *tmp_path;
6116
6117 unit = unit_dbus_path_from_name(*name);
6118 if (!unit)
6119 return log_oom();
6120
6121 if (need_daemon_reload(bus, *name) > 0) {
6122 log_warning("%s ignored: unit file changed on disk. Run 'systemctl%s daemon-reload'.",
6123 *name, arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
6124 continue;
6125 }
6126
6127 r = sd_bus_get_property_string(
6128 bus,
6129 "org.freedesktop.systemd1",
6130 unit,
6131 "org.freedesktop.systemd1.Unit",
6132 "FragmentPath",
6133 &error,
6134 &fragment_path);
6135 if (r < 0) {
6136 log_warning("Failed to get FragmentPath: %s", bus_error_message(&error, r));
6137 continue;
6138 }
6139
6140 if (isempty(fragment_path)) {
6141 log_warning("%s ignored: not found", *name);
6142 continue;
6143 }
6144
6145 if (arg_full)
6146 r = unit_file_create_copy(*name, fragment_path, user_home, user_runtime, &new_path, &tmp_path);
6147 else
6148 r = unit_file_create_drop_in(*name, user_home, user_runtime, &new_path, &tmp_path);
6149 if (r < 0)
6150 continue;
6151
6152 r = strv_push(paths, new_path);
6153 if (r < 0)
6154 return log_oom();
6155
6156 r = strv_push(paths, tmp_path);
6157 if (r < 0)
6158 return log_oom();
6159 }
6160 }
6161
6162 return 0;
6163}
6164
6165static int edit(sd_bus *bus, char **args) {
6166 _cleanup_strv_free_ char **names = NULL;
6167 _cleanup_strv_free_ char **paths = NULL;
6168 char **original, **tmp;
6169 int r;
6170
6171 assert(args);
6172
6173 if (!on_tty()) {
6174 log_error("Cannot edit units if we are not on a tty");
6175 return -EINVAL;
6176 }
6177
6178 if (arg_transport != BUS_TRANSPORT_LOCAL) {
6179 log_error("Cannot remotely edit units");
6180 return -EINVAL;
6181 }
6182
6183 r = expand_names(bus, args + 1, NULL, &names);
6184 if (r < 0)
6185 return log_error_errno(r, "Failed to expand names: %m");
6186
6187 if (!names) {
6188 log_error("No unit name found by expanding names");
6189 return -ENOENT;
6190 }
6191
6192 r = find_paths_to_edit(bus, names, &paths);
6193 if (r < 0)
6194 return r;
6195
6196 if (strv_isempty(paths)) {
6197 log_error("Cannot find any units to edit");
6198 return -ENOENT;
6199 }
6200
6201 r = run_editor(paths);
6202 if (r < 0)
6203 goto end;
6204
6205 STRV_FOREACH_PAIR(original, tmp, paths) {
6206 /* If the temporary file is empty we ignore it.
6207 * It's useful if the user wants to cancel its modification
6208 */
6209 if (null_or_empty_path(*tmp)) {
6210 log_warning("Edition of %s canceled: temporary file empty", *original);
6211 continue;
6212 }
6213 r = rename(*tmp, *original);
6214 if (r < 0) {
6215 r = log_error_errno(errno, "Failed to rename %s to %s: %m", *tmp, *original);
6216 goto end;
6217 }
6218 }
6219
6220 if (!arg_no_reload && bus && !avoid_bus())
6221 r = daemon_reload(bus, args);
6222
6223end:
6224 STRV_FOREACH_PAIR(original, tmp, paths)
6225 unlink_noerrno(*tmp);
6226
6227 return r;
6228}
6229
601185b4 6230static void systemctl_help(void) {
7e4249b9 6231
729e3769
LP
6232 pager_open_if_enabled();
6233
2e33c433 6234 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
729e3769 6235 "Query or send control commands to the systemd manager.\n\n"
8a0867d6
LP
6236 " -h --help Show this help\n"
6237 " --version Show package version\n"
f459b602
MAP
6238 " --system Connect to system manager\n"
6239 " --user Connect to user service manager\n"
6240 " -H --host=[USER@]HOST\n"
6241 " Operate on remote host\n"
6242 " -M --machine=CONTAINER\n"
6243 " Operate on local container\n"
8a0867d6 6244 " -t --type=TYPE List only units of a particular type\n"
a521ae4a 6245 " --state=STATE List only units with particular LOAD or SUB or ACTIVE state\n"
8a0867d6 6246 " -p --property=NAME Show only properties by this name\n"
a5e4972c
LP
6247 " -a --all Show all loaded units/properties, including dead/empty\n"
6248 " ones. To list all units installed on the system, use\n"
6249 " the 'list-unit-files' command instead.\n"
98a6e132 6250 " -l --full Don't ellipsize unit names on output\n"
1238ee09 6251 " -r --recursive Show unit list of host and local containers\n"
4dc5b821
LP
6252 " --reverse Show reverse dependencies with 'list-dependencies'\n"
6253 " --job-mode=MODE Specify how to deal with already queued jobs, when\n"
6254 " queueing a new job\n"
a521ae4a 6255 " --show-types When showing sockets, explicitly show their type\n"
b37844d3
LP
6256 " -i --ignore-inhibitors\n"
6257 " When shutting down or sleeping, ignore inhibitors\n"
a8f11321
LP
6258 " --kill-who=WHO Who to send signal to\n"
6259 " -s --signal=SIGNAL Which signal to send\n"
8a0867d6
LP
6260 " -q --quiet Suppress output\n"
6261 " --no-block Do not wait until operation finished\n"
8a0867d6 6262 " --no-wall Don't send wall message before halt/power-off/reboot\n"
8a0867d6
LP
6263 " --no-reload When enabling/disabling unit files, don't reload daemon\n"
6264 " configuration\n"
ebed32bf 6265 " --no-legend Do not print a legend (column headers and hints)\n"
69fc152f 6266 " --no-pager Do not pipe output into a pager\n"
501fc174
LP
6267 " --no-ask-password\n"
6268 " Do not ask for system passwords\n"
a8f11321 6269 " --global Enable/disable unit files globally\n"
a521ae4a 6270 " --runtime Enable unit files only temporarily until next reboot\n"
8a0867d6
LP
6271 " -f --force When enabling unit files, override existing symlinks\n"
6272 " When shutting down, execute action immediately\n"
d309c1c3
LP
6273 " --preset-mode= Specifies whether fully apply presets, or only enable,\n"
6274 " or only disable\n"
729e3769 6275 " --root=PATH Enable unit files in the specified root directory\n"
76fdc966 6276 " -n --lines=INTEGER Number of journal entries to show\n"
d3f2bdbf 6277 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
815ebc54
DH
6278 " verbose, export, json, json-pretty, json-sse, cat)\n"
6279 " --plain Print unit dependencies as a list instead of a tree\n\n"
34c4b47b 6280 "Unit Commands:\n"
d8fba7c6
ZJS
6281 " list-units [PATTERN...] List loaded units\n"
6282 " list-sockets [PATTERN...] List loaded sockets ordered by address\n"
6283 " list-timers [PATTERN...] List loaded timers ordered by next elapse\n"
4f8f66cb
ZJS
6284 " start NAME... Start (activate) one or more units\n"
6285 " stop NAME... Stop (deactivate) one or more units\n"
6286 " reload NAME... Reload one or more units\n"
6287 " restart NAME... Start or restart one or more units\n"
6288 " try-restart NAME... Restart one or more units if active\n"
6289 " reload-or-restart NAME... Reload one or more units if possible,\n"
6f28c033 6290 " otherwise start or restart\n"
4f8f66cb 6291 " reload-or-try-restart NAME... Reload one or more units if possible,\n"
6f28c033 6292 " otherwise restart if active\n"
4f8f66cb
ZJS
6293 " isolate NAME Start one unit and stop all others\n"
6294 " kill NAME... Send signal to processes of a unit\n"
b3ae710c
ZJS
6295 " is-active PATTERN... Check whether units are active\n"
6296 " is-failed PATTERN... Check whether units are failed\n"
6297 " status [PATTERN...|PID...] Show runtime status of one or more units\n"
6298 " show [PATTERN...|JOB...] Show properties of one or more\n"
ee5762e3 6299 " units/jobs or the manager\n"
b3ae710c 6300 " cat PATTERN... Show files and drop-ins of one or more units\n"
4f8f66cb 6301 " set-property NAME ASSIGNMENT... Sets one or more properties of a unit\n"
b3ae710c
ZJS
6302 " help PATTERN...|PID... Show manual for one or more units\n"
6303 " reset-failed [PATTERN...] Reset failed state for all, one, or more\n"
fdf20a31 6304 " units\n"
55c0b89c 6305 " list-dependencies [NAME] Recursively show units which are required\n"
afba4199
ZJS
6306 " or wanted by this unit or by which this\n"
6307 " unit is required or wanted\n\n"
34c4b47b 6308 "Unit File Commands:\n"
d8fba7c6 6309 " list-unit-files [PATTERN...] List installed unit files\n"
4f8f66cb
ZJS
6310 " enable NAME... Enable one or more unit files\n"
6311 " disable NAME... Disable one or more unit files\n"
6312 " reenable NAME... Reenable one or more unit files\n"
6313 " preset NAME... Enable/disable one or more unit files\n"
729e3769 6314 " based on preset configuration\n"
d309c1c3
LP
6315 " preset-all Enable/disable all unit files based on\n"
6316 " preset configuration\n"
4f8f66cb
ZJS
6317 " is-enabled NAME... Check whether unit files are enabled\n\n"
6318 " mask NAME... Mask one or more units\n"
6319 " unmask NAME... Unmask one or more units\n"
6320 " link PATH... Link one or more units files into\n"
729e3769 6321 " the search path\n"
e94937df
LN
6322 " add-wants TARGET NAME... Add 'Wants' dependency for the target\n"
6323 " on specified one or more units\n"
6324 " add-requires TARGET NAME... Add 'Requires' dependency for the target\n"
6325 " on specified one or more units\n"
99504dd4 6326 " get-default Get the name of the default target\n"
7d4fb3b1
RC
6327 " set-default NAME Set the default target\n"
6328 " edit NAME... Edit one or more unit files\n"
6329 "\n"
0d292f5e
LP
6330 "Machine Commands:\n"
6331 " list-machines [PATTERN...] List local containers and host\n\n"
34c4b47b 6332 "Job Commands:\n"
d8fba7c6 6333 " list-jobs [PATTERN...] List jobs\n"
34c4b47b 6334 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
34c4b47b 6335 "Snapshot Commands:\n"
7e4249b9 6336 " snapshot [NAME] Create a snapshot\n"
4f8f66cb 6337 " delete NAME... Remove one or more snapshots\n\n"
34c4b47b 6338 "Environment Commands:\n"
7e4249b9 6339 " show-environment Dump environment\n"
4f8f66cb 6340 " set-environment NAME=VALUE... Set one or more environment variables\n"
ac3efa8a
LP
6341 " unset-environment NAME... Unset one or more environment variables\n"
6342 " import-environment NAME... Import all, one or more environment variables\n\n"
34c4b47b
LP
6343 "Manager Lifecycle Commands:\n"
6344 " daemon-reload Reload systemd manager configuration\n"
6345 " daemon-reexec Reexecute systemd manager\n\n"
6346 "System Commands:\n"
99813a19 6347 " is-system-running Check whether system is fully running\n"
20b09ca7
LP
6348 " default Enter system default mode\n"
6349 " rescue Enter system rescue mode\n"
6350 " emergency Enter system emergency mode\n"
514f4ef5 6351 " halt Shut down and halt the system\n"
2e33c433 6352 " poweroff Shut down and power-off the system\n"
37185ec8 6353 " reboot [ARG] Shut down and reboot the system\n"
20b09ca7 6354 " kexec Shut down and reboot the system with kexec\n"
6edd7d0a 6355 " exit Request user instance exit\n"
4f8f66cb 6356 " switch-root ROOT [INIT] Change to a different root file system\n"
6edd7d0a 6357 " suspend Suspend the system\n"
6524990f
LP
6358 " hibernate Hibernate the system\n"
6359 " hybrid-sleep Hibernate and suspend the system\n",
5b6319dc 6360 program_invocation_short_name);
7e4249b9
LP
6361}
6362
601185b4 6363static void halt_help(void) {
37185ec8 6364 printf("%s [OPTIONS...]%s\n\n"
e4b61340
LP
6365 "%s the system.\n\n"
6366 " --help Show this help\n"
6367 " --halt Halt the machine\n"
6368 " -p --poweroff Switch off the machine\n"
6369 " --reboot Reboot the machine\n"
2e33c433
LP
6370 " -f --force Force immediate halt/power-off/reboot\n"
6371 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
e4b61340 6372 " -d --no-wtmp Don't write wtmp record\n"
2e33c433 6373 " --no-wall Don't send wall message before halt/power-off/reboot\n",
e4b61340 6374 program_invocation_short_name,
37185ec8 6375 arg_action == ACTION_REBOOT ? " [ARG]" : "",
e4b61340
LP
6376 arg_action == ACTION_REBOOT ? "Reboot" :
6377 arg_action == ACTION_POWEROFF ? "Power off" :
6378 "Halt");
e4b61340
LP
6379}
6380
601185b4 6381static void shutdown_help(void) {
08e4b1c5 6382 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
e4b61340
LP
6383 "Shut down the system.\n\n"
6384 " --help Show this help\n"
6385 " -H --halt Halt the machine\n"
6386 " -P --poweroff Power-off the machine\n"
6387 " -r --reboot Reboot the machine\n"
386da858 6388 " -h Equivalent to --poweroff, overridden by --halt\n"
2e33c433 6389 " -k Don't halt/power-off/reboot, just send warnings\n"
f6144808 6390 " --no-wall Don't send wall message before halt/power-off/reboot\n"
f6144808 6391 " -c Cancel a pending shutdown\n",
e4b61340 6392 program_invocation_short_name);
e4b61340
LP
6393}
6394
601185b4 6395static void telinit_help(void) {
2e33c433 6396 printf("%s [OPTIONS...] {COMMAND}\n\n"
514f4ef5
LP
6397 "Send control commands to the init daemon.\n\n"
6398 " --help Show this help\n"
2e33c433 6399 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
e4b61340
LP
6400 "Commands:\n"
6401 " 0 Power-off the machine\n"
6402 " 6 Reboot the machine\n"
514f4ef5
LP
6403 " 2, 3, 4, 5 Start runlevelX.target unit\n"
6404 " 1, s, S Enter rescue mode\n"
6405 " q, Q Reload init daemon configuration\n"
6406 " u, U Reexecute init daemon\n",
e4b61340 6407 program_invocation_short_name);
e4b61340
LP
6408}
6409
601185b4 6410static void runlevel_help(void) {
2e33c433 6411 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
6412 "Prints the previous and current runlevel of the init system.\n\n"
6413 " --help Show this help\n",
6414 program_invocation_short_name);
e4b61340
LP
6415}
6416
b93312f5 6417static void help_types(void) {
45c0c61d 6418 int i;
830f01f0 6419 const char *t;
45c0c61d 6420
b93312f5
ZJS
6421 if (!arg_no_legend)
6422 puts("Available unit types:");
f168c273 6423 for (i = 0; i < _UNIT_TYPE_MAX; i++) {
830f01f0
LP
6424 t = unit_type_to_string(i);
6425 if (t)
6426 puts(t);
6427 }
45c0c61d
ZJS
6428}
6429
e4b61340 6430static int systemctl_parse_argv(int argc, char *argv[]) {
7e4249b9
LP
6431
6432 enum {
90d473a1 6433 ARG_FAIL = 0x100,
afba4199
ZJS
6434 ARG_REVERSE,
6435 ARG_AFTER,
6436 ARG_BEFORE,
991f2a39 6437 ARG_SHOW_TYPES,
23ade460 6438 ARG_IRREVERSIBLE,
e67c3609 6439 ARG_IGNORE_DEPENDENCIES,
35df8f27 6440 ARG_VERSION,
af2d49f7 6441 ARG_USER,
7e4249b9 6442 ARG_SYSTEM,
ee5762e3 6443 ARG_GLOBAL,
6e905d93 6444 ARG_NO_BLOCK,
ebed32bf 6445 ARG_NO_LEGEND,
611efaac 6446 ARG_NO_PAGER,
4445a875 6447 ARG_NO_WALL,
be394c48 6448 ARG_ROOT,
ee5762e3 6449 ARG_NO_RELOAD,
501fc174 6450 ARG_KILL_WHO,
30732560 6451 ARG_NO_ASK_PASSWORD,
729e3769 6452 ARG_FAILED,
df50185b 6453 ARG_RUNTIME,
5d0c05e5 6454 ARG_FORCE,
9b9b3d36 6455 ARG_PLAIN,
4dc5b821 6456 ARG_STATE,
d309c1c3
LP
6457 ARG_JOB_MODE,
6458 ARG_PRESET_MODE,
7e4249b9
LP
6459 };
6460
6461 static const struct option options[] = {
9ea9d4cf
LP
6462 { "help", no_argument, NULL, 'h' },
6463 { "version", no_argument, NULL, ARG_VERSION },
6464 { "type", required_argument, NULL, 't' },
6465 { "property", required_argument, NULL, 'p' },
6466 { "all", no_argument, NULL, 'a' },
6467 { "reverse", no_argument, NULL, ARG_REVERSE },
6468 { "after", no_argument, NULL, ARG_AFTER },
6469 { "before", no_argument, NULL, ARG_BEFORE },
6470 { "show-types", no_argument, NULL, ARG_SHOW_TYPES },
6471 { "failed", no_argument, NULL, ARG_FAILED }, /* compatibility only */
6472 { "full", no_argument, NULL, 'l' },
4dc5b821
LP
6473 { "job-mode", required_argument, NULL, ARG_JOB_MODE },
6474 { "fail", no_argument, NULL, ARG_FAIL }, /* compatibility only */
6475 { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, /* compatibility only */
6476 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */
9ea9d4cf
LP
6477 { "ignore-inhibitors", no_argument, NULL, 'i' },
6478 { "user", no_argument, NULL, ARG_USER },
6479 { "system", no_argument, NULL, ARG_SYSTEM },
6480 { "global", no_argument, NULL, ARG_GLOBAL },
6481 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
6482 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
6483 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
6484 { "no-wall", no_argument, NULL, ARG_NO_WALL },
6485 { "quiet", no_argument, NULL, 'q' },
6486 { "root", required_argument, NULL, ARG_ROOT },
6487 { "force", no_argument, NULL, ARG_FORCE },
6488 { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
6489 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
6490 { "signal", required_argument, NULL, 's' },
6491 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
6492 { "host", required_argument, NULL, 'H' },
f459b602 6493 { "machine", required_argument, NULL, 'M' },
9ea9d4cf
LP
6494 { "runtime", no_argument, NULL, ARG_RUNTIME },
6495 { "lines", required_argument, NULL, 'n' },
6496 { "output", required_argument, NULL, 'o' },
6497 { "plain", no_argument, NULL, ARG_PLAIN },
6498 { "state", required_argument, NULL, ARG_STATE },
1238ee09 6499 { "recursive", no_argument, NULL, 'r' },
d309c1c3 6500 { "preset-mode", required_argument, NULL, ARG_PRESET_MODE },
eb9da376 6501 {}
7e4249b9
LP
6502 };
6503
6504 int c;
6505
e4b61340 6506 assert(argc >= 0);
7e4249b9
LP
6507 assert(argv);
6508
601185b4 6509 while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir", options, NULL)) >= 0)
7e4249b9
LP
6510
6511 switch (c) {
6512
6513 case 'h':
601185b4
ZJS
6514 systemctl_help();
6515 return 0;
35df8f27
LP
6516
6517 case ARG_VERSION:
6518 puts(PACKAGE_STRING);
7d568925 6519 puts(SYSTEMD_FEATURES);
35df8f27 6520 return 0;
7e4249b9 6521
20b3f379 6522 case 't': {
a2a5291b 6523 const char *word, *state;
20b3f379 6524 size_t size;
45c0c61d 6525
20b3f379 6526 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
7fd1b19b 6527 _cleanup_free_ char *type;
20b3f379
ZJS
6528
6529 type = strndup(word, size);
6530 if (!type)
6531 return -ENOMEM;
6532
6533 if (streq(type, "help")) {
6534 help_types();
6535 return 0;
6536 }
6537
6538 if (unit_type_from_string(type) >= 0) {
6539 if (strv_push(&arg_types, type))
6540 return log_oom();
6541 type = NULL;
6542 continue;
6543 }
6544
9b9b3d36
MW
6545 /* It's much nicer to use --state= for
6546 * load states, but let's support this
6547 * in --types= too for compatibility
6548 * with old versions */
20b3f379 6549 if (unit_load_state_from_string(optarg) >= 0) {
9b9b3d36 6550 if (strv_push(&arg_states, type) < 0)
20b3f379
ZJS
6551 return log_oom();
6552 type = NULL;
6553 continue;
6554 }
6555
ab06eef8 6556 log_error("Unknown unit type or load state '%s'.", type);
20b3f379
ZJS
6557 log_info("Use -t help to see a list of allowed values.");
6558 return -EINVAL;
c147dc42 6559 }
20b3f379
ZJS
6560
6561 break;
6562 }
6563
ea4a240d 6564 case 'p': {
033a842c
ZJS
6565 /* Make sure that if the empty property list
6566 was specified, we won't show any properties. */
20b3f379 6567 if (isempty(optarg) && !arg_properties) {
cbc9fbd1 6568 arg_properties = new0(char*, 1);
20b3f379
ZJS
6569 if (!arg_properties)
6570 return log_oom();
6571 } else {
a2a5291b 6572 const char *word, *state;
20b3f379 6573 size_t size;
033a842c 6574
20b3f379
ZJS
6575 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
6576 char *prop;
033a842c 6577
20b3f379
ZJS
6578 prop = strndup(word, size);
6579 if (!prop)
6580 return log_oom();
ea4a240d 6581
6e18964d 6582 if (strv_consume(&arg_properties, prop) < 0)
20b3f379 6583 return log_oom();
20b3f379 6584 }
033a842c 6585 }
48220598
LP
6586
6587 /* If the user asked for a particular
6588 * property, show it to him, even if it is
6589 * empty. */
6590 arg_all = true;
033a842c 6591
48220598 6592 break;
ea4a240d 6593 }
48220598 6594
7e4249b9
LP
6595 case 'a':
6596 arg_all = true;
6597 break;
6598
afba4199
ZJS
6599 case ARG_REVERSE:
6600 arg_dependency = DEPENDENCY_REVERSE;
6601 break;
6602
6603 case ARG_AFTER:
6604 arg_dependency = DEPENDENCY_AFTER;
6605 break;
6606
6607 case ARG_BEFORE:
6608 arg_dependency = DEPENDENCY_BEFORE;
6609 break;
6610
991f2a39
ZJS
6611 case ARG_SHOW_TYPES:
6612 arg_show_types = true;
6613 break;
6614
4dc5b821
LP
6615 case ARG_JOB_MODE:
6616 arg_job_mode = optarg;
6617 break;
6618
90d473a1 6619 case ARG_FAIL:
e67c3609
LP
6620 arg_job_mode = "fail";
6621 break;
6622
23ade460
MS
6623 case ARG_IRREVERSIBLE:
6624 arg_job_mode = "replace-irreversibly";
6625 break;
6626
e67c3609
LP
6627 case ARG_IGNORE_DEPENDENCIES:
6628 arg_job_mode = "ignore-dependencies";
7e4249b9
LP
6629 break;
6630
af2d49f7 6631 case ARG_USER:
729e3769 6632 arg_scope = UNIT_FILE_USER;
7e4249b9
LP
6633 break;
6634
6635 case ARG_SYSTEM:
729e3769
LP
6636 arg_scope = UNIT_FILE_SYSTEM;
6637 break;
6638
6639 case ARG_GLOBAL:
6640 arg_scope = UNIT_FILE_GLOBAL;
7e4249b9
LP
6641 break;
6642
6e905d93
LP
6643 case ARG_NO_BLOCK:
6644 arg_no_block = true;
7e4249b9
LP
6645 break;
6646
ebed32bf
MS
6647 case ARG_NO_LEGEND:
6648 arg_no_legend = true;
6649 break;
6650
611efaac
LP
6651 case ARG_NO_PAGER:
6652 arg_no_pager = true;
6653 break;
0736af98 6654
514f4ef5
LP
6655 case ARG_NO_WALL:
6656 arg_no_wall = true;
6657 break;
6658
be394c48
FC
6659 case ARG_ROOT:
6660 arg_root = optarg;
6661 break;
6662
98a6e132 6663 case 'l':
8fe914ec
LP
6664 arg_full = true;
6665 break;
6666
30732560 6667 case ARG_FAILED:
9b9b3d36
MW
6668 if (strv_extend(&arg_states, "failed") < 0)
6669 return log_oom();
6670
30732560
LP
6671 break;
6672
0183528f
LP
6673 case 'q':
6674 arg_quiet = true;
6675 break;
6676
568b679f
LP
6677 case ARG_FORCE:
6678 arg_force ++;
6679 break;
6680
b4f27ccc 6681 case 'f':
e606bb61 6682 arg_force ++;
ee5762e3
LP
6683 break;
6684
6685 case ARG_NO_RELOAD:
6686 arg_no_reload = true;
6687 break;
6688
8a0867d6
LP
6689 case ARG_KILL_WHO:
6690 arg_kill_who = optarg;
6691 break;
6692
8a0867d6
LP
6693 case 's':
6694 if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
6695 log_error("Failed to parse signal string %s.", optarg);
6696 return -EINVAL;
6697 }
6698 break;
6699
501fc174
LP
6700 case ARG_NO_ASK_PASSWORD:
6701 arg_ask_password = false;
6702 break;
6703
f459b602
MAP
6704 case 'H':
6705 arg_transport = BUS_TRANSPORT_REMOTE;
6706 arg_host = optarg;
a8f11321
LP
6707 break;
6708
f459b602
MAP
6709 case 'M':
6710 arg_transport = BUS_TRANSPORT_CONTAINER;
6711 arg_host = optarg;
a8f11321
LP
6712 break;
6713
729e3769
LP
6714 case ARG_RUNTIME:
6715 arg_runtime = true;
6716 break;
6717
df50185b
LP
6718 case 'n':
6719 if (safe_atou(optarg, &arg_lines) < 0) {
6720 log_error("Failed to parse lines '%s'", optarg);
6721 return -EINVAL;
6722 }
6723 break;
6724
df50185b
LP
6725 case 'o':
6726 arg_output = output_mode_from_string(optarg);
6727 if (arg_output < 0) {
6728 log_error("Unknown output '%s'.", optarg);
6729 return -EINVAL;
6730 }
6731 break;
6732
b37844d3
LP
6733 case 'i':
6734 arg_ignore_inhibitors = true;
6735 break;
6736
5d0c05e5
LN
6737 case ARG_PLAIN:
6738 arg_plain = true;
6739 break;
6740
9b9b3d36 6741 case ARG_STATE: {
a2a5291b 6742 const char *word, *state;
9b9b3d36
MW
6743 size_t size;
6744
6745 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
6746 char *s;
6747
6748 s = strndup(word, size);
6749 if (!s)
6750 return log_oom();
6751
6e18964d 6752 if (strv_consume(&arg_states, s) < 0)
9b9b3d36 6753 return log_oom();
9b9b3d36
MW
6754 }
6755 break;
6756 }
6757
1238ee09
LP
6758 case 'r':
6759 if (geteuid() != 0) {
f1721625 6760 log_error("--recursive requires root privileges.");
1238ee09
LP
6761 return -EPERM;
6762 }
6763
6764 arg_recursive = true;
6765 break;
6766
d309c1c3
LP
6767 case ARG_PRESET_MODE:
6768
6769 arg_preset_mode = unit_file_preset_mode_from_string(optarg);
6770 if (arg_preset_mode < 0) {
6771 log_error("Failed to parse preset mode: %s.", optarg);
6772 return -EINVAL;
6773 }
6774
6775 break;
6776
7e4249b9
LP
6777 case '?':
6778 return -EINVAL;
6779
6780 default:
eb9da376 6781 assert_not_reached("Unhandled option");
7e4249b9 6782 }
7e4249b9 6783
f459b602 6784 if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM) {
a8f11321
LP
6785 log_error("Cannot access user instance remotely.");
6786 return -EINVAL;
6787 }
6788
7e4249b9
LP
6789 return 1;
6790}
6791
e4b61340
LP
6792static int halt_parse_argv(int argc, char *argv[]) {
6793
6794 enum {
6795 ARG_HELP = 0x100,
6796 ARG_HALT,
514f4ef5
LP
6797 ARG_REBOOT,
6798 ARG_NO_WALL
e4b61340
LP
6799 };
6800
6801 static const struct option options[] = {
6802 { "help", no_argument, NULL, ARG_HELP },
6803 { "halt", no_argument, NULL, ARG_HALT },
6804 { "poweroff", no_argument, NULL, 'p' },
6805 { "reboot", no_argument, NULL, ARG_REBOOT },
6806 { "force", no_argument, NULL, 'f' },
6807 { "wtmp-only", no_argument, NULL, 'w' },
6808 { "no-wtmp", no_argument, NULL, 'd' },
514f4ef5 6809 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 6810 {}
e4b61340
LP
6811 };
6812
37185ec8 6813 int c, r, runlevel;
e4b61340
LP
6814
6815 assert(argc >= 0);
6816 assert(argv);
6817
6818 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
6819 if (runlevel == '0' || runlevel == '6')
65491fd8 6820 arg_force = 2;
e4b61340 6821
601185b4 6822 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0)
e4b61340
LP
6823 switch (c) {
6824
6825 case ARG_HELP:
601185b4
ZJS
6826 halt_help();
6827 return 0;
e4b61340
LP
6828
6829 case ARG_HALT:
6830 arg_action = ACTION_HALT;
6831 break;
6832
6833 case 'p':
a042efad
MS
6834 if (arg_action != ACTION_REBOOT)
6835 arg_action = ACTION_POWEROFF;
e4b61340
LP
6836 break;
6837
6838 case ARG_REBOOT:
6839 arg_action = ACTION_REBOOT;
6840 break;
6841
6842 case 'f':
65491fd8 6843 arg_force = 2;
e4b61340
LP
6844 break;
6845
6846 case 'w':
6847 arg_dry = true;
6848 break;
6849
6850 case 'd':
6851 arg_no_wtmp = true;
6852 break;
6853
514f4ef5
LP
6854 case ARG_NO_WALL:
6855 arg_no_wall = true;
6856 break;
6857
e4b61340
LP
6858 case 'i':
6859 case 'h':
57371e58 6860 case 'n':
e4b61340
LP
6861 /* Compatibility nops */
6862 break;
6863
6864 case '?':
6865 return -EINVAL;
6866
6867 default:
eb9da376 6868 assert_not_reached("Unhandled option");
e4b61340 6869 }
e4b61340 6870
c5220a94
MO
6871 if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
6872 r = update_reboot_param_file(argc == optind + 1 ? argv[optind] : NULL);
6873 if (r < 0)
37185ec8 6874 return r;
37185ec8 6875 } else if (optind < argc) {
e4b61340
LP
6876 log_error("Too many arguments.");
6877 return -EINVAL;
6878 }
6879
6880 return 1;
6881}
6882
f6144808
LP
6883static int parse_time_spec(const char *t, usec_t *_u) {
6884 assert(t);
6885 assert(_u);
6886
6887 if (streq(t, "now"))
6888 *_u = 0;
1a639877 6889 else if (!strchr(t, ':')) {
f6144808
LP
6890 uint64_t u;
6891
1a639877 6892 if (safe_atou64(t, &u) < 0)
f6144808
LP
6893 return -EINVAL;
6894
6895 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
6896 } else {
6897 char *e = NULL;
6898 long hour, minute;
b92bea5d 6899 struct tm tm = {};
f6144808
LP
6900 time_t s;
6901 usec_t n;
6902
6903 errno = 0;
6904 hour = strtol(t, &e, 10);
8333c77e 6905 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
f6144808
LP
6906 return -EINVAL;
6907
6908 minute = strtol(e+1, &e, 10);
8333c77e 6909 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
f6144808
LP
6910 return -EINVAL;
6911
6912 n = now(CLOCK_REALTIME);
08e4b1c5
LP
6913 s = (time_t) (n / USEC_PER_SEC);
6914
f6144808
LP
6915 assert_se(localtime_r(&s, &tm));
6916
6917 tm.tm_hour = (int) hour;
6918 tm.tm_min = (int) minute;
08e4b1c5 6919 tm.tm_sec = 0;
f6144808
LP
6920
6921 assert_se(s = mktime(&tm));
6922
6923 *_u = (usec_t) s * USEC_PER_SEC;
6924
6925 while (*_u <= n)
6926 *_u += USEC_PER_DAY;
6927 }
6928
6929 return 0;
6930}
6931
e4b61340
LP
6932static int shutdown_parse_argv(int argc, char *argv[]) {
6933
6934 enum {
6935 ARG_HELP = 0x100,
514f4ef5 6936 ARG_NO_WALL
e4b61340
LP
6937 };
6938
6939 static const struct option options[] = {
6940 { "help", no_argument, NULL, ARG_HELP },
6941 { "halt", no_argument, NULL, 'H' },
6942 { "poweroff", no_argument, NULL, 'P' },
6943 { "reboot", no_argument, NULL, 'r' },
04ebb595 6944 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
514f4ef5 6945 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 6946 {}
e4b61340
LP
6947 };
6948
f6144808 6949 int c, r;
e4b61340
LP
6950
6951 assert(argc >= 0);
6952 assert(argv);
6953
601185b4 6954 while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0)
e4b61340
LP
6955 switch (c) {
6956
6957 case ARG_HELP:
601185b4
ZJS
6958 shutdown_help();
6959 return 0;
e4b61340
LP
6960
6961 case 'H':
6962 arg_action = ACTION_HALT;
6963 break;
6964
6965 case 'P':
6966 arg_action = ACTION_POWEROFF;
6967 break;
6968
6969 case 'r':
5622dde3
KS
6970 if (kexec_loaded())
6971 arg_action = ACTION_KEXEC;
6972 else
6973 arg_action = ACTION_REBOOT;
e4b61340
LP
6974 break;
6975
04ebb595
LP
6976 case 'K':
6977 arg_action = ACTION_KEXEC;
6978 break;
6979
e4b61340
LP
6980 case 'h':
6981 if (arg_action != ACTION_HALT)
6982 arg_action = ACTION_POWEROFF;
6983 break;
6984
6985 case 'k':
6986 arg_dry = true;
6987 break;
6988
514f4ef5
LP
6989 case ARG_NO_WALL:
6990 arg_no_wall = true;
6991 break;
6992
e4b61340
LP
6993 case 't':
6994 case 'a':
6995 /* Compatibility nops */
6996 break;
6997
f6144808
LP
6998 case 'c':
6999 arg_action = ACTION_CANCEL_SHUTDOWN;
7000 break;
7001
e4b61340
LP
7002 case '?':
7003 return -EINVAL;
7004
7005 default:
eb9da376 7006 assert_not_reached("Unhandled option");
e4b61340 7007 }
e4b61340 7008
dfcc5c33 7009 if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
7e59bfcb
LP
7010 r = parse_time_spec(argv[optind], &arg_when);
7011 if (r < 0) {
f6144808
LP
7012 log_error("Failed to parse time specification: %s", argv[optind]);
7013 return r;
7014 }
6b5ad000 7015 } else
08e4b1c5 7016 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
442b9094 7017
dfcc5c33
MS
7018 if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
7019 /* No time argument for shutdown cancel */
7020 arg_wall = argv + optind;
7021 else if (argc > optind + 1)
7022 /* We skip the time argument */
e4b61340
LP
7023 arg_wall = argv + optind + 1;
7024
7025 optind = argc;
7026
7027 return 1;
e4b61340
LP
7028}
7029
7030static int telinit_parse_argv(int argc, char *argv[]) {
7031
7032 enum {
7033 ARG_HELP = 0x100,
514f4ef5 7034 ARG_NO_WALL
e4b61340
LP
7035 };
7036
7037 static const struct option options[] = {
7038 { "help", no_argument, NULL, ARG_HELP },
514f4ef5 7039 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 7040 {}
e4b61340
LP
7041 };
7042
7043 static const struct {
7044 char from;
7045 enum action to;
7046 } table[] = {
7047 { '0', ACTION_POWEROFF },
7048 { '6', ACTION_REBOOT },
ef2f1067 7049 { '1', ACTION_RESCUE },
e4b61340
LP
7050 { '2', ACTION_RUNLEVEL2 },
7051 { '3', ACTION_RUNLEVEL3 },
7052 { '4', ACTION_RUNLEVEL4 },
7053 { '5', ACTION_RUNLEVEL5 },
7054 { 's', ACTION_RESCUE },
7055 { 'S', ACTION_RESCUE },
7056 { 'q', ACTION_RELOAD },
7057 { 'Q', ACTION_RELOAD },
7058 { 'u', ACTION_REEXEC },
7059 { 'U', ACTION_REEXEC }
7060 };
7061
7062 unsigned i;
7063 int c;
7064
7065 assert(argc >= 0);
7066 assert(argv);
7067
601185b4 7068 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
7069 switch (c) {
7070
7071 case ARG_HELP:
601185b4
ZJS
7072 telinit_help();
7073 return 0;
e4b61340 7074
514f4ef5
LP
7075 case ARG_NO_WALL:
7076 arg_no_wall = true;
7077 break;
7078
e4b61340
LP
7079 case '?':
7080 return -EINVAL;
7081
7082 default:
eb9da376 7083 assert_not_reached("Unhandled option");
e4b61340 7084 }
e4b61340
LP
7085
7086 if (optind >= argc) {
601185b4
ZJS
7087 log_error("%s: required argument missing.",
7088 program_invocation_short_name);
e4b61340
LP
7089 return -EINVAL;
7090 }
7091
7092 if (optind + 1 < argc) {
7093 log_error("Too many arguments.");
7094 return -EINVAL;
7095 }
7096
7097 if (strlen(argv[optind]) != 1) {
7098 log_error("Expected single character argument.");
7099 return -EINVAL;
7100 }
7101
7102 for (i = 0; i < ELEMENTSOF(table); i++)
7103 if (table[i].from == argv[optind][0])
7104 break;
7105
7106 if (i >= ELEMENTSOF(table)) {
b0193f1c 7107 log_error("Unknown command '%s'.", argv[optind]);
e4b61340
LP
7108 return -EINVAL;
7109 }
7110
7111 arg_action = table[i].to;
7112
7113 optind ++;
7114
7115 return 1;
7116}
7117
7118static int runlevel_parse_argv(int argc, char *argv[]) {
7119
7120 enum {
7121 ARG_HELP = 0x100,
7122 };
7123
7124 static const struct option options[] = {
7125 { "help", no_argument, NULL, ARG_HELP },
eb9da376 7126 {}
e4b61340
LP
7127 };
7128
7129 int c;
7130
7131 assert(argc >= 0);
7132 assert(argv);
7133
601185b4 7134 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
7135 switch (c) {
7136
7137 case ARG_HELP:
601185b4
ZJS
7138 runlevel_help();
7139 return 0;
e4b61340
LP
7140
7141 case '?':
7142 return -EINVAL;
7143
7144 default:
eb9da376 7145 assert_not_reached("Unhandled option");
e4b61340 7146 }
e4b61340
LP
7147
7148 if (optind < argc) {
7149 log_error("Too many arguments.");
7150 return -EINVAL;
7151 }
7152
7153 return 1;
7154}
7155
7156static int parse_argv(int argc, char *argv[]) {
7157 assert(argc >= 0);
7158 assert(argv);
7159
7160 if (program_invocation_short_name) {
7161
7162 if (strstr(program_invocation_short_name, "halt")) {
7163 arg_action = ACTION_HALT;
7164 return halt_parse_argv(argc, argv);
7165 } else if (strstr(program_invocation_short_name, "poweroff")) {
7166 arg_action = ACTION_POWEROFF;
7167 return halt_parse_argv(argc, argv);
7168 } else if (strstr(program_invocation_short_name, "reboot")) {
5622dde3
KS
7169 if (kexec_loaded())
7170 arg_action = ACTION_KEXEC;
7171 else
7172 arg_action = ACTION_REBOOT;
e4b61340
LP
7173 return halt_parse_argv(argc, argv);
7174 } else if (strstr(program_invocation_short_name, "shutdown")) {
7175 arg_action = ACTION_POWEROFF;
7176 return shutdown_parse_argv(argc, argv);
7177 } else if (strstr(program_invocation_short_name, "init")) {
d5ca5f11
LP
7178
7179 if (sd_booted() > 0) {
f459b602 7180 arg_action = _ACTION_INVALID;
d5ca5f11
LP
7181 return telinit_parse_argv(argc, argv);
7182 } else {
7183 /* Hmm, so some other init system is
7184 * running, we need to forward this
7185 * request to it. For now we simply
7186 * guess that it is Upstart. */
7187
4ad61fd1 7188 execv(TELINIT, argv);
d5ca5f11
LP
7189
7190 log_error("Couldn't find an alternative telinit implementation to spawn.");
7191 return -EIO;
7192 }
7193
e4b61340
LP
7194 } else if (strstr(program_invocation_short_name, "runlevel")) {
7195 arg_action = ACTION_RUNLEVEL;
7196 return runlevel_parse_argv(argc, argv);
7197 }
7198 }
7199
7200 arg_action = ACTION_SYSTEMCTL;
7201 return systemctl_parse_argv(argc, argv);
7202}
7203
44a6b1b6 7204_pure_ static int action_to_runlevel(void) {
eb22ac37
LP
7205
7206 static const char table[_ACTION_MAX] = {
7207 [ACTION_HALT] = '0',
7208 [ACTION_POWEROFF] = '0',
7209 [ACTION_REBOOT] = '6',
7210 [ACTION_RUNLEVEL2] = '2',
7211 [ACTION_RUNLEVEL3] = '3',
7212 [ACTION_RUNLEVEL4] = '4',
7213 [ACTION_RUNLEVEL5] = '5',
7214 [ACTION_RESCUE] = '1'
7215 };
7216
d55ae9e6
LP
7217 assert(arg_action < _ACTION_MAX);
7218
7219 return table[arg_action];
7220}
7221
d55ae9e6 7222static int talk_initctl(void) {
cbc9fbd1
LP
7223
7224 struct init_request request = {
7225 .magic = INIT_MAGIC,
7226 .sleeptime = 0,
7227 .cmd = INIT_CMD_RUNLVL
7228 };
7229
7fd1b19b 7230 _cleanup_close_ int fd = -1;
d55ae9e6 7231 char rl;
cbc9fbd1 7232 int r;
eb22ac37 7233
427b47c4
ZJS
7234 rl = action_to_runlevel();
7235 if (!rl)
eb22ac37
LP
7236 return 0;
7237
d55ae9e6
LP
7238 request.runlevel = rl;
7239
427b47c4
ZJS
7240 fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
7241 if (fd < 0) {
d55ae9e6
LP
7242 if (errno == ENOENT)
7243 return 0;
eb22ac37 7244
56f64d95 7245 log_error_errno(errno, "Failed to open "INIT_FIFO": %m");
eb22ac37 7246 return -errno;
d55ae9e6 7247 }
eb22ac37 7248
d55ae9e6 7249 errno = 0;
eb22ac37 7250 r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
427b47c4 7251 if (r) {
56f64d95 7252 log_error_errno(errno, "Failed to write to "INIT_FIFO": %m");
bcb161b0 7253 return errno > 0 ? -errno : -EIO;
d55ae9e6 7254 }
eb22ac37
LP
7255
7256 return 1;
e4b61340
LP
7257}
7258
41dd15e4 7259static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
7e4249b9 7260
7e4249b9
LP
7261 static const struct {
7262 const char* verb;
7263 const enum {
7264 MORE,
7265 LESS,
7266 EQUAL
7267 } argc_cmp;
7268 const int argc;
f459b602 7269 int (* const dispatch)(sd_bus *bus, char **args);
d08e75ed
ZJS
7270 const enum {
7271 NOBUS = 1,
7272 FORCE,
7273 } bus;
7e4249b9 7274 } verbs[] = {
d8fba7c6 7275 { "list-units", MORE, 0, list_units },
d08e75ed 7276 { "list-unit-files", MORE, 1, list_unit_files, NOBUS },
d8fba7c6
ZJS
7277 { "list-sockets", MORE, 1, list_sockets },
7278 { "list-timers", MORE, 1, list_timers },
7279 { "list-jobs", MORE, 1, list_jobs },
0d292f5e 7280 { "list-machines", MORE, 1, list_machines },
ee5762e3 7281 { "clear-jobs", EQUAL, 1, daemon_reload },
ee5762e3
LP
7282 { "cancel", MORE, 2, cancel_job },
7283 { "start", MORE, 2, start_unit },
7284 { "stop", MORE, 2, start_unit },
a76f7be2 7285 { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
7286 { "reload", MORE, 2, start_unit },
7287 { "restart", MORE, 2, start_unit },
7288 { "try-restart", MORE, 2, start_unit },
7289 { "reload-or-restart", MORE, 2, start_unit },
7290 { "reload-or-try-restart", MORE, 2, start_unit },
7291 { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */
64e5f1b7 7292 { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
7293 { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
7294 { "isolate", EQUAL, 2, start_unit },
8a0867d6 7295 { "kill", MORE, 2, kill_unit },
1a0fce45
TA
7296 { "is-active", MORE, 2, check_unit_active },
7297 { "check", MORE, 2, check_unit_active },
7298 { "is-failed", MORE, 2, check_unit_failed },
ee5762e3 7299 { "show", MORE, 1, show },
e93c33d4 7300 { "cat", MORE, 2, cat },
265a7a2a 7301 { "status", MORE, 1, show },
b43f208f 7302 { "help", MORE, 2, show },
ee5762e3
LP
7303 { "snapshot", LESS, 2, snapshot },
7304 { "delete", MORE, 2, delete_snapshot },
7305 { "daemon-reload", EQUAL, 1, daemon_reload },
7306 { "daemon-reexec", EQUAL, 1, daemon_reload },
f459b602 7307 { "show-environment", EQUAL, 1, show_environment },
ee5762e3
LP
7308 { "set-environment", MORE, 2, set_environment },
7309 { "unset-environment", MORE, 2, set_environment },
ac3efa8a 7310 { "import-environment", MORE, 1, import_environment},
d08e75ed
ZJS
7311 { "halt", EQUAL, 1, start_special, FORCE },
7312 { "poweroff", EQUAL, 1, start_special, FORCE },
7313 { "reboot", EQUAL, 1, start_special, FORCE },
20b09ca7 7314 { "kexec", EQUAL, 1, start_special },
6edd7d0a
LP
7315 { "suspend", EQUAL, 1, start_special },
7316 { "hibernate", EQUAL, 1, start_special },
6524990f 7317 { "hybrid-sleep", EQUAL, 1, start_special },
ee5762e3
LP
7318 { "default", EQUAL, 1, start_special },
7319 { "rescue", EQUAL, 1, start_special },
7320 { "emergency", EQUAL, 1, start_special },
20b09ca7 7321 { "exit", EQUAL, 1, start_special },
fdf20a31 7322 { "reset-failed", MORE, 1, reset_failed },
d08e75ed
ZJS
7323 { "enable", MORE, 2, enable_unit, NOBUS },
7324 { "disable", MORE, 2, enable_unit, NOBUS },
7325 { "is-enabled", MORE, 2, unit_is_enabled, NOBUS },
7326 { "reenable", MORE, 2, enable_unit, NOBUS },
7327 { "preset", MORE, 2, enable_unit, NOBUS },
d309c1c3 7328 { "preset-all", EQUAL, 1, preset_all, NOBUS },
d08e75ed
ZJS
7329 { "mask", MORE, 2, enable_unit, NOBUS },
7330 { "unmask", MORE, 2, enable_unit, NOBUS },
7331 { "link", MORE, 2, enable_unit, NOBUS },
957eb8ca 7332 { "switch-root", MORE, 2, switch_root },
e31165b2 7333 { "list-dependencies", LESS, 2, list_dependencies },
d08e75ed
ZJS
7334 { "set-default", EQUAL, 2, set_default, NOBUS },
7335 { "get-default", EQUAL, 1, get_default, NOBUS },
8e2af478 7336 { "set-property", MORE, 3, set_property },
99813a19 7337 { "is-system-running", EQUAL, 1, is_system_running },
7d4fb3b1
RC
7338 { "add-wants", MORE, 3, add_dependency, NOBUS },
7339 { "add-requires", MORE, 3, add_dependency, NOBUS },
7340 { "edit", MORE, 2, edit, NOBUS },
d08e75ed
ZJS
7341 {}
7342 }, *verb = verbs;
7e4249b9 7343
e4b61340 7344 int left;
7e4249b9 7345
e4b61340
LP
7346 assert(argc >= 0);
7347 assert(argv);
7e4249b9
LP
7348
7349 left = argc - optind;
7350
d08e75ed
ZJS
7351 /* Special rule: no arguments (left == 0) means "list-units" */
7352 if (left > 0) {
b43f208f
KS
7353 if (streq(argv[optind], "help") && !argv[optind+1]) {
7354 log_error("This command expects one or more "
7355 "unit names. Did you mean --help?");
7356 return -EINVAL;
0183528f
LP
7357 }
7358
d08e75ed
ZJS
7359 for (; verb->verb; verb++)
7360 if (streq(argv[optind], verb->verb))
7361 goto found;
7e4249b9 7362
d08e75ed
ZJS
7363 log_error("Unknown operation '%s'.", argv[optind]);
7364 return -EINVAL;
7e4249b9 7365 }
d08e75ed 7366found:
7e4249b9 7367
d08e75ed 7368 switch (verb->argc_cmp) {
7e4249b9
LP
7369
7370 case EQUAL:
d08e75ed 7371 if (left != verb->argc) {
7e4249b9 7372 log_error("Invalid number of arguments.");
e4b61340 7373 return -EINVAL;
7e4249b9
LP
7374 }
7375
7376 break;
7377
7378 case MORE:
d08e75ed 7379 if (left < verb->argc) {
7e4249b9 7380 log_error("Too few arguments.");
e4b61340 7381 return -EINVAL;
7e4249b9
LP
7382 }
7383
7384 break;
7385
7386 case LESS:
d08e75ed 7387 if (left > verb->argc) {
7e4249b9 7388 log_error("Too many arguments.");
e4b61340 7389 return -EINVAL;
7e4249b9
LP
7390 }
7391
7392 break;
7393
7394 default:
7395 assert_not_reached("Unknown comparison operator.");
7396 }
7397
ee5762e3
LP
7398 /* Require a bus connection for all operations but
7399 * enable/disable */
d08e75ed
ZJS
7400 if (verb->bus == NOBUS) {
7401 if (!bus && !avoid_bus()) {
da927ba9 7402 log_error_errno(bus_error, "Failed to get D-Bus connection: %m");
d08e75ed
ZJS
7403 return -EIO;
7404 }
82e23ddd 7405
d08e75ed 7406 } else {
82e23ddd
LP
7407 if (running_in_chroot() > 0) {
7408 log_info("Running in chroot, ignoring request.");
7409 return 0;
7410 }
7411
d08e75ed 7412 if ((verb->bus != FORCE || arg_force <= 0) && !bus) {
da927ba9 7413 log_error_errno(bus_error, "Failed to get D-Bus connection: %m");
82e23ddd
LP
7414 return -EIO;
7415 }
ee5762e3
LP
7416 }
7417
d08e75ed 7418 return verb->dispatch(bus, argv + optind);
e4b61340
LP
7419}
7420
52c00215 7421static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
cbc9fbd1 7422
b92bea5d
ZJS
7423 struct sd_shutdown_command c = {
7424 .usec = t,
7425 .mode = mode,
7426 .dry_run = dry_run,
7427 .warn_wall = warn,
7428 };
cbc9fbd1 7429
b92bea5d
ZJS
7430 union sockaddr_union sockaddr = {
7431 .un.sun_family = AF_UNIX,
7432 .un.sun_path = "/run/systemd/shutdownd",
7433 };
cbc9fbd1
LP
7434
7435 struct iovec iovec[2] = {{
7436 .iov_base = (char*) &c,
b92bea5d 7437 .iov_len = offsetof(struct sd_shutdown_command, wall_message),
cbc9fbd1
LP
7438 }};
7439
b92bea5d
ZJS
7440 struct msghdr msghdr = {
7441 .msg_name = &sockaddr,
7442 .msg_namelen = offsetof(struct sockaddr_un, sun_path)
f8294e41 7443 + strlen("/run/systemd/shutdownd"),
b92bea5d
ZJS
7444 .msg_iov = iovec,
7445 .msg_iovlen = 1,
7446 };
04ebb595 7447
cbc9fbd1
LP
7448 _cleanup_close_ int fd;
7449
04ebb595
LP
7450 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
7451 if (fd < 0)
7452 return -errno;
f6144808 7453
b92bea5d 7454 if (!isempty(message)) {
04ebb595
LP
7455 iovec[1].iov_base = (char*) message;
7456 iovec[1].iov_len = strlen(message);
b92bea5d 7457 msghdr.msg_iovlen++;
04ebb595 7458 }
f6144808 7459
cec7eda5 7460 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
f6144808 7461 return -errno;
f6144808 7462
f6144808
LP
7463 return 0;
7464}
7465
f459b602 7466static int reload_with_fallback(sd_bus *bus) {
e4b61340
LP
7467
7468 if (bus) {
7469 /* First, try systemd via D-Bus. */
d76702a7 7470 if (daemon_reload(bus, NULL) >= 0)
e4b61340
LP
7471 return 0;
7472 }
7473
7474 /* Nothing else worked, so let's try signals */
7475 assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
7476
4a62c710
MS
7477 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0)
7478 return log_error_errno(errno, "kill() failed: %m");
e4b61340
LP
7479
7480 return 0;
7481}
7482
f459b602 7483static int start_with_fallback(sd_bus *bus) {
e4b61340
LP
7484
7485 if (bus) {
7486 /* First, try systemd via D-Bus. */
729e3769 7487 if (start_unit(bus, NULL) >= 0)
983d9c90 7488 goto done;
e4b61340
LP
7489 }
7490
7491 /* Nothing else worked, so let's try
7492 * /dev/initctl */
fbc43921 7493 if (talk_initctl() > 0)
983d9c90 7494 goto done;
d55ae9e6
LP
7495
7496 log_error("Failed to talk to init daemon.");
7497 return -EIO;
983d9c90
LP
7498
7499done:
7500 warn_wall(arg_action);
7501 return 0;
e4b61340
LP
7502}
7503
477def80 7504static int halt_now(enum action a) {
e606bb61 7505
4a3ad399
LP
7506 /* The kernel will automaticall flush ATA disks and suchlike
7507 * on reboot(), but the file systems need to be synce'd
7508 * explicitly in advance. */
7509 sync();
7510
7511 /* Make sure C-A-D is handled by the kernel from this point
7512 * on... */
e606bb61
LP
7513 reboot(RB_ENABLE_CAD);
7514
4c80c73c 7515 switch (a) {
e606bb61
LP
7516
7517 case ACTION_HALT:
7518 log_info("Halting.");
7519 reboot(RB_HALT_SYSTEM);
477def80 7520 return -errno;
e606bb61
LP
7521
7522 case ACTION_POWEROFF:
7523 log_info("Powering off.");
7524 reboot(RB_POWER_OFF);
477def80 7525 return -errno;
e606bb61 7526
477def80
LP
7527 case ACTION_REBOOT: {
7528 _cleanup_free_ char *param = NULL;
cbc9fbd1 7529
477def80
LP
7530 if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
7531 log_info("Rebooting with argument '%s'.", param);
37185ec8
WC
7532 syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
7533 LINUX_REBOOT_CMD_RESTART2, param);
37185ec8 7534 }
e606bb61 7535
477def80
LP
7536 log_info("Rebooting.");
7537 reboot(RB_AUTOBOOT);
7538 return -errno;
e606bb61
LP
7539 }
7540
477def80
LP
7541 default:
7542 assert_not_reached("Unknown action.");
7543 }
e606bb61
LP
7544}
7545
f459b602 7546static int halt_main(sd_bus *bus) {
e4b61340
LP
7547 int r;
7548
748ebafa
LP
7549 r = check_inhibitors(bus, arg_action);
7550 if (r < 0)
7551 return r;
b37844d3 7552
bc8c2f5c 7553 if (geteuid() != 0) {
7e59bfcb
LP
7554 /* Try logind if we are a normal user and no special
7555 * mode applies. Maybe PolicyKit allows us to shutdown
7556 * the machine. */
7557
7558 if (arg_when <= 0 &&
7559 !arg_dry &&
b37844d3 7560 arg_force <= 0 &&
7e59bfcb
LP
7561 (arg_action == ACTION_POWEROFF ||
7562 arg_action == ACTION_REBOOT)) {
4c80c73c
KS
7563 r = reboot_with_logind(bus, arg_action);
7564 if (r >= 0)
7565 return r;
7566 }
7567
cc8a7a61 7568 log_error("Must be root.");
bc8c2f5c
LP
7569 return -EPERM;
7570 }
7571
f6144808 7572 if (arg_when > 0) {
7fd1b19b 7573 _cleanup_free_ char *m;
9be9828c
LP
7574
7575 m = strv_join(arg_wall, " ");
cbc9fbd1
LP
7576 if (!m)
7577 return log_oom();
7578
9be9828c
LP
7579 r = send_shutdownd(arg_when,
7580 arg_action == ACTION_HALT ? 'H' :
7581 arg_action == ACTION_POWEROFF ? 'P' :
04ebb595 7582 arg_action == ACTION_KEXEC ? 'K' :
9be9828c 7583 'r',
52c00215 7584 arg_dry,
9be9828c
LP
7585 !arg_no_wall,
7586 m);
9be9828c
LP
7587
7588 if (r < 0)
da927ba9 7589 log_warning_errno(r, "Failed to talk to shutdownd, proceeding with immediate shutdown: %m");
08e4b1c5 7590 else {
7e59bfcb
LP
7591 char date[FORMAT_TIMESTAMP_MAX];
7592
08e4b1c5
LP
7593 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
7594 format_timestamp(date, sizeof(date), arg_when));
f6144808 7595 return 0;
08e4b1c5 7596 }
f6144808
LP
7597 }
7598
65491fd8 7599 if (!arg_dry && !arg_force)
e4b61340
LP
7600 return start_with_fallback(bus);
7601
d90e1a30
LP
7602 if (!arg_no_wtmp) {
7603 if (sd_booted() > 0)
7604 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
7e59bfcb
LP
7605 else {
7606 r = utmp_put_shutdown();
7607 if (r < 0)
da927ba9 7608 log_warning_errno(r, "Failed to write utmp record: %m");
7e59bfcb 7609 }
d90e1a30 7610 }
e4b61340 7611
e4b61340
LP
7612 if (arg_dry)
7613 return 0;
7614
477def80 7615 r = halt_now(arg_action);
da927ba9 7616 log_error_errno(r, "Failed to reboot: %m");
477def80
LP
7617
7618 return r;
e4b61340
LP
7619}
7620
7621static int runlevel_main(void) {
7622 int r, runlevel, previous;
7623
729e3769
LP
7624 r = utmp_get_runlevel(&runlevel, &previous);
7625 if (r < 0) {
7626 puts("unknown");
e4b61340
LP
7627 return r;
7628 }
7629
7630 printf("%c %c\n",
7631 previous <= 0 ? 'N' : previous,
7632 runlevel <= 0 ? 'N' : runlevel);
7633
7634 return 0;
7635}
7636
7637int main(int argc, char*argv[]) {
24996861 7638 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
f459b602 7639 int r;
e4b61340 7640
a9cdc94f 7641 setlocale(LC_ALL, "");
e4b61340 7642 log_parse_environment();
2396fb04 7643 log_open();
e4b61340 7644
184ecaf7
DR
7645 /* Explicitly not on_tty() to avoid setting cached value.
7646 * This becomes relevant for piping output which might be
7647 * ellipsized. */
7648 original_stdout_is_tty = isatty(STDOUT_FILENO);
7649
04ebb595 7650 r = parse_argv(argc, argv);
f459b602 7651 if (r <= 0)
e4b61340 7652 goto finish;
7e4249b9 7653
e4b61340
LP
7654 /* /sbin/runlevel doesn't need to communicate via D-Bus, so
7655 * let's shortcut this */
7656 if (arg_action == ACTION_RUNLEVEL) {
22f4096c 7657 r = runlevel_main();
e4b61340
LP
7658 goto finish;
7659 }
7660
82e23ddd
LP
7661 if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
7662 log_info("Running in chroot, ignoring request.");
f459b602 7663 r = 0;
82e23ddd
LP
7664 goto finish;
7665 }
7666
41dd15e4
LP
7667 if (!avoid_bus())
7668 r = bus_open_transport_systemd(arg_transport, arg_host, arg_scope != UNIT_FILE_SYSTEM, &bus);
7669
7670 /* systemctl_main() will print an error message for the bus
7671 * connection, but only if it needs to */
e4b61340
LP
7672
7673 switch (arg_action) {
7674
22f4096c 7675 case ACTION_SYSTEMCTL:
f459b602 7676 r = systemctl_main(bus, argc, argv, r);
e4b61340 7677 break;
e4b61340
LP
7678
7679 case ACTION_HALT:
7680 case ACTION_POWEROFF:
7681 case ACTION_REBOOT:
5622dde3 7682 case ACTION_KEXEC:
22f4096c 7683 r = halt_main(bus);
e4b61340
LP
7684 break;
7685
e4b61340
LP
7686 case ACTION_RUNLEVEL2:
7687 case ACTION_RUNLEVEL3:
7688 case ACTION_RUNLEVEL4:
7689 case ACTION_RUNLEVEL5:
7690 case ACTION_RESCUE:
514f4ef5 7691 case ACTION_EMERGENCY:
eb22ac37 7692 case ACTION_DEFAULT:
22f4096c 7693 r = start_with_fallback(bus);
e4b61340 7694 break;
7e4249b9 7695
e4b61340
LP
7696 case ACTION_RELOAD:
7697 case ACTION_REEXEC:
22f4096c 7698 r = reload_with_fallback(bus);
e4b61340
LP
7699 break;
7700
dfcc5c33 7701 case ACTION_CANCEL_SHUTDOWN: {
f459b602 7702 _cleanup_free_ char *m = NULL;
dfcc5c33
MS
7703
7704 if (arg_wall) {
7705 m = strv_join(arg_wall, " ");
7706 if (!m) {
f459b602 7707 r = log_oom();
dfcc5c33
MS
7708 goto finish;
7709 }
7710 }
f459b602 7711
dfcc5c33
MS
7712 r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
7713 if (r < 0)
da927ba9 7714 log_warning_errno(r, "Failed to talk to shutdownd, shutdown hasn't been cancelled: %m");
f6144808 7715 break;
dfcc5c33 7716 }
f6144808 7717
eb22ac37 7718 case ACTION_RUNLEVEL:
f459b602 7719 case _ACTION_INVALID:
e4b61340
LP
7720 default:
7721 assert_not_reached("Unknown action");
7722 }
7e4249b9
LP
7723
7724finish:
f459b602
MAP
7725 pager_close();
7726 ask_password_agent_close();
7727 polkit_agent_close();
7e4249b9 7728
20b3f379 7729 strv_free(arg_types);
9b9b3d36 7730 strv_free(arg_states);
20b3f379 7731 strv_free(arg_properties);
ea4a240d 7732
f459b602 7733 return r < 0 ? EXIT_FAILURE : r;
7e4249b9 7734}