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