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