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