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