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