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