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