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