]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl.c
systemctl: also color filenames of drop-ins in cat
[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;
373d32c9 3681 char *u;
a223b325
MS
3682 int r;
3683
f459b602 3684 r = sd_bus_call_method(
f22f08cd
SP
3685 bus,
3686 "org.freedesktop.systemd1",
3687 "/org/freedesktop/systemd1",
3688 "org.freedesktop.systemd1.Manager",
3689 "GetUnitByPID",
f459b602 3690 &error,
f22f08cd 3691 &reply,
f459b602
MAP
3692 "u", pid);
3693 if (r < 0) {
3694 log_error("Failed to get unit for PID %lu: %s", (unsigned long) pid, bus_error_message(&error, r));
cec7eda5 3695 return r;
a223b325
MS
3696 }
3697
373d32c9 3698 r = sd_bus_message_read(reply, "o", &u);
f459b602
MAP
3699 if (r < 0)
3700 return bus_log_parse_error(r);
3701
373d32c9
LP
3702 u = strdup(u);
3703 if (!u)
3704 return log_oom();
3705
3706 *unit = u;
f74294c1 3707 return 0;
a223b325
MS
3708}
3709
f459b602
MAP
3710static int show_all(
3711 const char* verb,
3712 sd_bus *bus,
3713 bool show_properties,
3714 bool *new_line,
3715 bool *ellipsized) {
3716
f459b602
MAP
3717 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
3718 _cleanup_free_ UnitInfo *unit_infos = NULL;
3719 const UnitInfo *u;
3720 unsigned c;
265a7a2a
ZJS
3721 int r;
3722
f459b602 3723 r = get_unit_list(bus, &reply, &unit_infos);
265a7a2a
ZJS
3724 if (r < 0)
3725 return r;
3726
dbed408b
LP
3727 pager_open_if_enabled();
3728
f459b602
MAP
3729 c = (unsigned) r;
3730
3731 qsort_safe(unit_infos, c, sizeof(UnitInfo), compare_unit_info);
991f2a39 3732
265a7a2a 3733 for (u = unit_infos; u < unit_infos + c; u++) {
7fd1b19b 3734 _cleanup_free_ char *p = NULL;
265a7a2a 3735
d8fba7c6 3736 if (!output_show_unit(u, NULL))
265a7a2a
ZJS
3737 continue;
3738
3739 p = unit_dbus_path_from_name(u->id);
3740 if (!p)
3741 return log_oom();
3742
94e0bd7d 3743 r = show_one(verb, bus, p, show_properties, new_line, ellipsized);
265a7a2a
ZJS
3744 if (r != 0)
3745 return r;
3746 }
3747
3748 return 0;
3749}
3750
e93c33d4 3751static int cat(sd_bus *bus, char **args) {
999b6003 3752 _cleanup_free_ char *unit = NULL, *n = NULL;
e93c33d4
SL
3753 int r = 0;
3754 char **name;
a669d622 3755 bool first = true;
e93c33d4 3756
e93c33d4
SL
3757 assert(bus);
3758 assert(args);
3759
3760 pager_open_if_enabled();
3761
3762 STRV_FOREACH(name, args+1) {
999b6003 3763 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
e93c33d4 3764 _cleanup_strv_free_ char **dropin_paths = NULL;
999b6003 3765 _cleanup_free_ char *fragment_path = NULL;
e93c33d4
SL
3766 char **path;
3767
3768 n = unit_name_mangle(*name);
3769 if (!n)
3770 return log_oom();
3771
3772 unit = unit_dbus_path_from_name(n);
3773 if (!unit)
3774 return log_oom();
3775
3776 if (need_daemon_reload(bus, n) > 0)
3777 log_warning("Unit file of %s changed on disk. Run 'systemctl%s daemon-reload'.",
3778 n, arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
3779
3780 r = sd_bus_get_property_string(
3781 bus,
3782 "org.freedesktop.systemd1",
3783 unit,
3784 "org.freedesktop.systemd1.Unit",
3785 "FragmentPath",
3786 &error,
3787 &fragment_path);
3788 if (r < 0) {
3789 log_warning("Failed to get FragmentPath: %s", bus_error_message(&error, r));
3790 continue;
3791 }
3792
e93c33d4
SL
3793 r = sd_bus_get_property_strv(
3794 bus,
3795 "org.freedesktop.systemd1",
3796 unit,
3797 "org.freedesktop.systemd1.Unit",
3798 "DropInPaths",
3799 &error,
3800 &dropin_paths);
3801 if (r < 0) {
3802 log_warning("Failed to get DropInPaths: %s", bus_error_message(&error, r));
3803 continue;
3804 }
3805
a669d622
ZJS
3806 if (first)
3807 first = false;
3808 else
3809 puts("");
3810
e93c33d4 3811 if (!isempty(fragment_path)) {
a669d622
ZJS
3812 printf("%s# %s%s\n",
3813 ansi_highlight_blue(),
3814 fragment_path,
3815 ansi_highlight_off());
e93c33d4 3816 fflush(stdout);
999b6003 3817
e93c33d4
SL
3818 r = sendfile_full(STDOUT_FILENO, fragment_path);
3819 if (r < 0) {
3820 log_warning("Failed to cat %s: %s", fragment_path, strerror(-r));
3821 continue;
3822 }
3823 }
3824
3825 STRV_FOREACH(path, dropin_paths) {
58684be9 3826 printf("%s%s# %s%s\n",
a669d622 3827 isempty(fragment_path) && path == dropin_paths ? "" : "\n",
58684be9
ZJS
3828 ansi_highlight_blue(),
3829 *path,
3830 ansi_highlight_off());
e93c33d4 3831 fflush(stdout);
999b6003 3832
e93c33d4
SL
3833 r = sendfile_full(STDOUT_FILENO, *path);
3834 if (r < 0) {
3835 log_warning("Failed to cat %s: %s", *path, strerror(-r));
3836 continue;
3837 }
3838 }
3839 }
3840
c0ea486f 3841 return r < 0 ? r : 0;
e93c33d4
SL
3842}
3843
f459b602 3844static int show(sd_bus *bus, char **args) {
a223b325 3845 int r, ret = 0;
265a7a2a 3846 bool show_properties, show_status, new_line = false;
729e3769 3847 char **name;
94e0bd7d 3848 bool ellipsized = false;
48220598
LP
3849
3850 assert(bus);
3851 assert(args);
3852
256425cc 3853 show_properties = streq(args[0], "show");
265a7a2a 3854 show_status = streq(args[0], "status");
61cbdc4b 3855
ec14911e 3856 if (show_properties)
1968a360 3857 pager_open_if_enabled();
ec14911e 3858
f84190d8 3859 /* If no argument is specified inspect the manager itself */
48220598 3860
f84190d8 3861 if (show_properties && strv_length(args) <= 1)
94e0bd7d 3862 return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized);
48220598 3863
265a7a2a 3864 if (show_status && strv_length(args) <= 1)
94e0bd7d
ZJS
3865 ret = show_all(args[0], bus, false, &new_line, &ellipsized);
3866 else
3867 STRV_FOREACH(name, args+1) {
f74294c1 3868 _cleanup_free_ char *unit = NULL;
94e0bd7d 3869 uint32_t id;
48220598 3870
94e0bd7d 3871 if (safe_atou32(*name, &id) < 0) {
f74294c1 3872 _cleanup_free_ char *n = NULL;
94e0bd7d 3873 /* Interpret as unit name */
48220598 3874
94e0bd7d
ZJS
3875 n = unit_name_mangle(*name);
3876 if (!n)
3877 return log_oom();
f84190d8 3878
f74294c1
SL
3879 unit = unit_dbus_path_from_name(n);
3880 if (!unit)
94e0bd7d 3881 return log_oom();
48220598 3882
94e0bd7d 3883 } else if (show_properties) {
94e0bd7d 3884 /* Interpret as job id */
f74294c1 3885 if (asprintf(&unit, "/org/freedesktop/systemd1/job/%u", id) < 0)
94e0bd7d 3886 return log_oom();
48220598 3887
94e0bd7d
ZJS
3888 } else {
3889 /* Interpret as PID */
f74294c1 3890 r = get_unit_dbus_path_by_pid(bus, id, &unit);
373d32c9 3891 if (r < 0) {
94e0bd7d 3892 ret = r;
373d32c9
LP
3893 continue;
3894 }
94e0bd7d 3895 }
f74294c1
SL
3896
3897 show_one(args[0], bus, unit, show_properties, &new_line, &ellipsized);
48220598 3898 }
94e0bd7d
ZJS
3899
3900 if (ellipsized && !arg_quiet)
3901 printf("Hint: Some lines were ellipsized, use -l to show in full.\n");
48220598 3902
22f4096c 3903 return ret;
0183528f
LP
3904}
3905
f459b602 3906static int append_assignment(sd_bus_message *m, const char *assignment) {
8e2af478
LP
3907 const char *eq;
3908 char *field;
8e2af478
LP
3909 int r;
3910
f459b602 3911 assert(m);
8e2af478
LP
3912 assert(assignment);
3913
3914 eq = strchr(assignment, '=');
3915 if (!eq) {
3916 log_error("Not an assignment: %s", assignment);
3917 return -EINVAL;
3918 }
3919
3920 field = strndupa(assignment, eq - assignment);
3921 eq ++;
3922
f459b602
MAP
3923 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
3924 if (r < 0)
3925 return bus_log_create_error(r);
8e2af478
LP
3926
3927 if (streq(field, "CPUAccounting") ||
3928 streq(field, "MemoryAccounting") ||
3929 streq(field, "BlockIOAccounting")) {
8e2af478
LP
3930
3931 r = parse_boolean(eq);
3932 if (r < 0) {
3933 log_error("Failed to parse boolean assignment %s.", assignment);
3934 return -EINVAL;
3935 }
3936
f459b602 3937 r = sd_bus_message_append(m, "v", "b", r);
b42defe3 3938
ddca82ac 3939 } else if (streq(field, "MemoryLimit")) {
b42defe3 3940 off_t bytes;
b42defe3
LP
3941
3942 r = parse_bytes(eq, &bytes);
3943 if (r < 0) {
3944 log_error("Failed to parse bytes specification %s", assignment);
3945 return -EINVAL;
3946 }
3947
f459b602 3948 r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
b42defe3
LP
3949
3950 } else if (streq(field, "CPUShares") || streq(field, "BlockIOWeight")) {
3951 uint64_t u;
3952
3953 r = safe_atou64(eq, &u);
3954 if (r < 0) {
3955 log_error("Failed to parse %s value %s.", field, eq);
3956 return -EINVAL;
3957 }
3958
f459b602 3959 r = sd_bus_message_append(m, "v", "t", u);
7041efe9 3960
f459b602
MAP
3961 } else if (streq(field, "DevicePolicy"))
3962 r = sd_bus_message_append(m, "v", "s", eq);
7041efe9 3963
f459b602 3964 else if (streq(field, "DeviceAllow")) {
7041efe9 3965
f459b602
MAP
3966 if (isempty(eq))
3967 r = sd_bus_message_append(m, "v", "a(ss)", 0);
3968 else {
7041efe9 3969 const char *path, *rwm;
7041efe9
LP
3970 char *e;
3971
3972 e = strchr(eq, ' ');
3973 if (e) {
3974 path = strndupa(eq, e - eq);
3975 rwm = e+1;
3976 } else {
3977 path = eq;
3978 rwm = "";
3979 }
3980
67061256
G
3981 if (!path_startswith(path, "/dev")) {
3982 log_error("%s is not a device file in /dev.", path);
3983 return -EINVAL;
3984 }
3985
f459b602 3986 r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
7041efe9
LP
3987 }
3988
67061256 3989 } else if (streq(field, "BlockIOReadBandwidth") || streq(field, "BlockIOWriteBandwidth")) {
67061256 3990
f459b602
MAP
3991 if (isempty(eq))
3992 r = sd_bus_message_append(m, "v", "a(st)", 0);
3993 else {
67061256 3994 const char *path, *bandwidth;
67061256
G
3995 off_t bytes;
3996 char *e;
3997
3998 e = strchr(eq, ' ');
3999 if (e) {
4000 path = strndupa(eq, e - eq);
4001 bandwidth = e+1;
4002 } else {
4003 log_error("Failed to parse %s value %s.", field, eq);
4004 return -EINVAL;
4005 }
4006
4007 if (!path_startswith(path, "/dev")) {
4008 log_error("%s is not a device file in /dev.", path);
4009 return -EINVAL;
4010 }
4011
4012 r = parse_bytes(bandwidth, &bytes);
4013 if (r < 0) {
4014 log_error("Failed to parse byte value %s.", bandwidth);
4015 return -EINVAL;
4016 }
4017
f459b602 4018 r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes);
67061256
G
4019 }
4020
7239c170 4021 } else if (streq(field, "BlockIODeviceWeight")) {
7239c170 4022
f459b602
MAP
4023 if (isempty(eq))
4024 r = sd_bus_message_append(m, "v", "a(st)", 0);
4025 else {
7239c170 4026 const char *path, *weight;
7239c170
G
4027 uint64_t u;
4028 char *e;
4029
4030 e = strchr(eq, ' ');
4031 if (e) {
4032 path = strndupa(eq, e - eq);
4033 weight = e+1;
4034 } else {
4035 log_error("Failed to parse %s value %s.", field, eq);
4036 return -EINVAL;
4037 }
4038
4039 if (!path_startswith(path, "/dev")) {
4040 log_error("%s is not a device file in /dev.", path);
4041 return -EINVAL;
4042 }
4043
4044 r = safe_atou64(weight, &u);
4045 if (r < 0) {
4046 log_error("Failed to parse %s value %s.", field, weight);
4047 return -EINVAL;
4048 }
f459b602 4049 r = sd_bus_message_append(m, "v", "a(st)", path, u);
7239c170
G
4050 }
4051
8e2af478
LP
4052 } else {
4053 log_error("Unknown assignment %s.", assignment);
4054 return -EINVAL;
4055 }
4056
f459b602
MAP
4057 if (r < 0)
4058 return bus_log_create_error(r);
8e2af478
LP
4059
4060 return 0;
4061}
4062
f459b602
MAP
4063static int set_property(sd_bus *bus, char **args) {
4064 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
4065 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
68372da6 4066 _cleanup_free_ char *n = NULL;
8e2af478
LP
4067 char **i;
4068 int r;
4069
f459b602
MAP
4070 r = sd_bus_message_new_method_call(
4071 bus,
8e2af478
LP
4072 "org.freedesktop.systemd1",
4073 "/org/freedesktop/systemd1",
4074 "org.freedesktop.systemd1.Manager",
f459b602
MAP
4075 "SetUnitProperties",
4076 &m);
4077 if (r < 0)
4078 return bus_log_create_error(r);
8e2af478 4079
68372da6
LP
4080 n = unit_name_mangle(args[1]);
4081 if (!n)
4082 return log_oom();
4083
f459b602
MAP
4084 r = sd_bus_message_append(m, "sb", n, arg_runtime);
4085 if (r < 0)
4086 return bus_log_create_error(r);
8e2af478 4087
f459b602
MAP
4088 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, "(sv)");
4089 if (r < 0)
4090 return bus_log_create_error(r);
8e2af478 4091
f459b602
MAP
4092 STRV_FOREACH(i, args + 2) {
4093 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
4094 if (r < 0)
4095 return bus_log_create_error(r);
8e2af478 4096
f459b602 4097 r = append_assignment(m, *i);
8e2af478
LP
4098 if (r < 0)
4099 return r;
4100
f459b602
MAP
4101 r = sd_bus_message_close_container(m);
4102 if (r < 0)
4103 return bus_log_create_error(r);
8e2af478
LP
4104 }
4105
f459b602
MAP
4106 r = sd_bus_message_close_container(m);
4107 if (r < 0)
4108 return bus_log_create_error(r);
8e2af478 4109
c49b30a2 4110 r = sd_bus_call(bus, m, 0, &error, NULL);
f459b602
MAP
4111 if (r < 0) {
4112 log_error("Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
4113 return r;
8e2af478
LP
4114 }
4115
4116 return 0;
4117}
4118
f459b602
MAP
4119static int snapshot(sd_bus *bus, char **args) {
4120 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4121 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4122 _cleanup_free_ char *n = NULL, *id = NULL;
4123 const char *path;
7e4249b9 4124 int r;
7e4249b9 4125
1dcf6065 4126 if (strv_length(args) > 1)
a016b922 4127 n = unit_name_mangle_with_suffix(args[1], ".snapshot");
1dcf6065
LP
4128 else
4129 n = strdup("");
4130 if (!n)
4131 return log_oom();
7e4249b9 4132
f459b602 4133 r = sd_bus_call_method(
f22f08cd
SP
4134 bus,
4135 "org.freedesktop.systemd1",
4136 "/org/freedesktop/systemd1",
4137 "org.freedesktop.systemd1.Manager",
4138 "CreateSnapshot",
f459b602 4139 &error,
f22f08cd 4140 &reply,
f459b602
MAP
4141 "sb", n, false);
4142 if (r < 0) {
4143 log_error("Failed to create snapshot: %s", bus_error_message(&error, r));
1dcf6065 4144 return r;
7e4249b9
LP
4145 }
4146
f459b602
MAP
4147 r = sd_bus_message_read(reply, "o", &path);
4148 if (r < 0)
4149 return bus_log_parse_error(r);
5dd9014f 4150
f459b602 4151 r = sd_bus_get_property_string(
f22f08cd
SP
4152 bus,
4153 "org.freedesktop.systemd1",
4154 path,
f459b602
MAP
4155 "org.freedesktop.systemd1.Unit",
4156 "Id",
4157 &error,
4158 &id);
4159 if (r < 0) {
4160 log_error("Failed to get ID of snapshot: %s", bus_error_message(&error, r));
1dcf6065 4161 return r;
7e4249b9
LP
4162 }
4163
0183528f
LP
4164 if (!arg_quiet)
4165 puts(id);
7e4249b9 4166
1dcf6065 4167 return 0;
7e4249b9
LP
4168}
4169
f459b602
MAP
4170static int delete_snapshot(sd_bus *bus, char **args) {
4171 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
729e3769 4172 char **name;
f459b602 4173 int r;
6759e7a7 4174
6759e7a7
LP
4175 assert(args);
4176
729e3769 4177 STRV_FOREACH(name, args+1) {
5dd9014f 4178 _cleanup_free_ char *n = NULL;
6759e7a7 4179
a016b922 4180 n = unit_name_mangle_with_suffix(*name, ".snapshot");
1dcf6065
LP
4181 if (!n)
4182 return log_oom();
4183
f459b602 4184 r = sd_bus_call_method(
f22f08cd 4185 bus,
b0193f1c
LP
4186 "org.freedesktop.systemd1",
4187 "/org/freedesktop/systemd1",
4188 "org.freedesktop.systemd1.Manager",
5dd9014f 4189 "RemoveSnapshot",
f459b602 4190 &error,
f22f08cd 4191 NULL,
f459b602
MAP
4192 "s", n);
4193 if (r < 0) {
4194 log_error("Failed to remove snapshot %s: %s", n, bus_error_message(&error, r));
5dd9014f 4195 return r;
f459b602 4196 }
6759e7a7
LP
4197 }
4198
5dd9014f 4199 return 0;
6759e7a7
LP
4200}
4201
f459b602
MAP
4202static int daemon_reload(sd_bus *bus, char **args) {
4203 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
7e4249b9 4204 const char *method;
f459b602 4205 int r;
7e4249b9 4206
e4b61340
LP
4207 if (arg_action == ACTION_RELOAD)
4208 method = "Reload";
4209 else if (arg_action == ACTION_REEXEC)
4210 method = "Reexecute";
4211 else {
4212 assert(arg_action == ACTION_SYSTEMCTL);
4213
4214 method =
20b09ca7
LP
4215 streq(args[0], "clear-jobs") ||
4216 streq(args[0], "cancel") ? "ClearJobs" :
4217 streq(args[0], "daemon-reexec") ? "Reexecute" :
4218 streq(args[0], "reset-failed") ? "ResetFailed" :
4219 streq(args[0], "halt") ? "Halt" :
4220 streq(args[0], "poweroff") ? "PowerOff" :
4221 streq(args[0], "reboot") ? "Reboot" :
4222 streq(args[0], "kexec") ? "KExec" :
4223 streq(args[0], "exit") ? "Exit" :
4224 /* "daemon-reload" */ "Reload";
e4b61340 4225 }
7e4249b9 4226
f459b602 4227 r = sd_bus_call_method(
f22f08cd
SP
4228 bus,
4229 "org.freedesktop.systemd1",
4230 "/org/freedesktop/systemd1",
4231 "org.freedesktop.systemd1.Manager",
4232 method,
c516c8d1 4233 &error,
f459b602
MAP
4234 NULL,
4235 NULL);
f22f08cd
SP
4236
4237 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
4238 /* There's always a fallback possible for
4239 * legacy actions. */
4240 r = -EADDRNOTAVAIL;
d0ede8f1
LP
4241 else if ((r == -ETIMEDOUT || r == -ECONNRESET) && streq(method, "Reexecute"))
4242 /* On reexecution, we expect a disconnect, not a
4243 * reply */
f22f08cd 4244 r = 0;
1dcf6065 4245 else if (r < 0)
f459b602 4246 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
7e4249b9 4247
0a9776c2 4248 return r < 0 ? r : 0;
7e4249b9
LP
4249}
4250
f459b602
MAP
4251static int reset_failed(sd_bus *bus, char **args) {
4252 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
f84190d8 4253 char **name;
f459b602 4254 int r;
5632e374 4255
729e3769
LP
4256 if (strv_length(args) <= 1)
4257 return daemon_reload(bus, args);
5632e374 4258
729e3769 4259 STRV_FOREACH(name, args+1) {
f84190d8
LP
4260 _cleanup_free_ char *n;
4261
f22f08cd 4262 n = unit_name_mangle(*name);
f84190d8
LP
4263 if (!n)
4264 return log_oom();
4265
f459b602 4266 r = sd_bus_call_method(
f22f08cd 4267 bus,
b0193f1c
LP
4268 "org.freedesktop.systemd1",
4269 "/org/freedesktop/systemd1",
4270 "org.freedesktop.systemd1.Manager",
f22f08cd 4271 "ResetFailedUnit",
f459b602 4272 &error,
f22f08cd 4273 NULL,
f459b602
MAP
4274 "s", n);
4275 if (r < 0) {
4276 log_error("Failed to reset failed state of unit %s: %s", n, bus_error_message(&error, r));
f84190d8 4277 return r;
f459b602 4278 }
5632e374
LP
4279 }
4280
f84190d8 4281 return 0;
5632e374
LP
4282}
4283
f459b602
MAP
4284static int show_environment(sd_bus *bus, char **args) {
4285 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4286 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4287 const char *text;
7e4249b9 4288 int r;
7e4249b9 4289
1968a360 4290 pager_open_if_enabled();
ec14911e 4291
f459b602 4292 r = sd_bus_get_property(
f22f08cd
SP
4293 bus,
4294 "org.freedesktop.systemd1",
4295 "/org/freedesktop/systemd1",
f459b602
MAP
4296 "org.freedesktop.systemd1.Manager",
4297 "Environment",
4298 &error,
f22f08cd 4299 &reply,
f459b602
MAP
4300 "as");
4301 if (r < 0) {
4302 log_error("Failed to get environment: %s", bus_error_message(&error, r));
f84190d8 4303 return r;
7e4249b9
LP
4304 }
4305
f459b602
MAP
4306 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
4307 if (r < 0)
4308 return bus_log_parse_error(r);
7e4249b9 4309
f459b602 4310 while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0)
f84190d8 4311 puts(text);
f459b602
MAP
4312 if (r < 0)
4313 return bus_log_parse_error(r);
7e4249b9 4314
f459b602
MAP
4315 r = sd_bus_message_exit_container(reply);
4316 if (r < 0)
4317 return bus_log_parse_error(r);
7e4249b9 4318
f84190d8 4319 return 0;
7e4249b9
LP
4320}
4321
f459b602
MAP
4322static int switch_root(sd_bus *bus, char **args) {
4323 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
13068da8 4324 _cleanup_free_ char *init = NULL;
f459b602
MAP
4325 const char *root;
4326 unsigned l;
4327 int r;
957eb8ca
LP
4328
4329 l = strv_length(args);
4330 if (l < 2 || l > 3) {
4331 log_error("Wrong number of arguments.");
4332 return -EINVAL;
4333 }
4334
4335 root = args[1];
13068da8
TG
4336
4337 if (l >= 3)
4338 init = strdup(args[2]);
4339 else {
4340 parse_env_file("/proc/cmdline", WHITESPACE,
4341 "init", &init,
4342 NULL);
4343
4344 if (!init)
4345 init = strdup("");
13068da8 4346 }
f459b602 4347
f84190d8
LP
4348 if (!init)
4349 return log_oom();
13068da8
TG
4350
4351 log_debug("switching root - root: %s; init: %s", root, init);
957eb8ca 4352
f459b602 4353 r = sd_bus_call_method(
f22f08cd 4354 bus,
957eb8ca
LP
4355 "org.freedesktop.systemd1",
4356 "/org/freedesktop/systemd1",
4357 "org.freedesktop.systemd1.Manager",
f22f08cd 4358 "SwitchRoot",
f459b602 4359 &error,
f22f08cd 4360 NULL,
f459b602
MAP
4361 "ss", root, init);
4362 if (r < 0) {
4363 log_error("Failed to switch root: %s", bus_error_message(&error, r));
4364 return r;
4365 }
4366
4367 return 0;
957eb8ca
LP
4368}
4369
f459b602
MAP
4370static int set_environment(sd_bus *bus, char **args) {
4371 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4372 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
7e4249b9 4373 const char *method;
31e767f7
LP
4374 int r;
4375
4376 assert(bus);
60f9ba0b 4377 assert(args);
7e4249b9 4378
7e4249b9
LP
4379 method = streq(args[0], "set-environment")
4380 ? "SetEnvironment"
4381 : "UnsetEnvironment";
4382
f459b602
MAP
4383 r = sd_bus_message_new_method_call(
4384 bus,
31e767f7
LP
4385 "org.freedesktop.systemd1",
4386 "/org/freedesktop/systemd1",
4387 "org.freedesktop.systemd1.Manager",
f459b602
MAP
4388 method,
4389 &m);
4390 if (r < 0)
4391 return bus_log_create_error(r);
7e4249b9 4392
f459b602 4393 r = sd_bus_message_append_strv(m, args + 1);
31e767f7 4394 if (r < 0)
f459b602 4395 return bus_log_create_error(r);
7e4249b9 4396
c49b30a2 4397 r = sd_bus_call(bus, m, 0, &error, NULL);
f459b602
MAP
4398 if (r < 0) {
4399 log_error("Failed to set environment: %s", bus_error_message(&error, r));
4400 return r;
7e4249b9
LP
4401 }
4402
f84190d8 4403 return 0;
7e4249b9
LP
4404}
4405
cbb13b2a 4406static int enable_sysv_units(const char *verb, char **args) {
729e3769 4407 int r = 0;
ee5762e3 4408
77e68fa2 4409#if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
729e3769 4410 unsigned f = 1, t = 1;
fb15be83 4411 _cleanup_lookup_paths_free_ LookupPaths paths = {};
ee5762e3 4412
729e3769
LP
4413 if (arg_scope != UNIT_FILE_SYSTEM)
4414 return 0;
ee5762e3 4415
729e3769
LP
4416 if (!streq(verb, "enable") &&
4417 !streq(verb, "disable") &&
4418 !streq(verb, "is-enabled"))
4419 return 0;
ee5762e3 4420
729e3769
LP
4421 /* Processes all SysV units, and reshuffles the array so that
4422 * afterwards only the native units remain */
ee5762e3 4423
67445f4e 4424 r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL);
729e3769
LP
4425 if (r < 0)
4426 return r;
ee5762e3 4427
729e3769 4428 r = 0;
cbb13b2a 4429 for (f = 0; args[f]; f++) {
729e3769 4430 const char *name;
7fd1b19b 4431 _cleanup_free_ char *p = NULL, *q = NULL;
729e3769
LP
4432 bool found_native = false, found_sysv;
4433 unsigned c = 1;
4434 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
4b6756a8 4435 char **k, *l;
729e3769
LP
4436 int j;
4437 pid_t pid;
4438 siginfo_t status;
ee5762e3 4439
729e3769 4440 name = args[f];
ee5762e3 4441
729e3769
LP
4442 if (!endswith(name, ".service"))
4443 continue;
ee5762e3 4444
729e3769
LP
4445 if (path_is_absolute(name))
4446 continue;
ee5762e3 4447
729e3769 4448 STRV_FOREACH(k, paths.unit_path) {
729e3769
LP
4449 if (!isempty(arg_root))
4450 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
4451 else
4452 asprintf(&p, "%s/%s", *k, name);
ee5762e3 4453
729e3769 4454 if (!p) {
0d0f0c50 4455 r = log_oom();
729e3769
LP
4456 goto finish;
4457 }
ee5762e3 4458
729e3769
LP
4459 found_native = access(p, F_OK) >= 0;
4460 free(p);
4b6756a8 4461 p = NULL;
ee5762e3 4462
729e3769
LP
4463 if (found_native)
4464 break;
4465 }
ee5762e3 4466
729e3769
LP
4467 if (found_native)
4468 continue;
ee5762e3 4469
729e3769
LP
4470 if (!isempty(arg_root))
4471 asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
4472 else
4473 asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
4474 if (!p) {
0d0f0c50 4475 r = log_oom();
729e3769
LP
4476 goto finish;
4477 }
ee5762e3 4478
729e3769
LP
4479 p[strlen(p) - sizeof(".service") + 1] = 0;
4480 found_sysv = access(p, F_OK) >= 0;
ee5762e3 4481
4b6756a8 4482 if (!found_sysv)
729e3769 4483 continue;
71fad675 4484
729e3769
LP
4485 /* Mark this entry, so that we don't try enabling it as native unit */
4486 args[f] = (char*) "";
ee5762e3 4487
729e3769 4488 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
ee5762e3 4489
729e3769
LP
4490 if (!isempty(arg_root))
4491 argv[c++] = q = strappend("--root=", arg_root);
ee5762e3 4492
2b6bf07d 4493 argv[c++] = basename(p);
729e3769
LP
4494 argv[c++] =
4495 streq(verb, "enable") ? "on" :
4496 streq(verb, "disable") ? "off" : "--level=5";
4497 argv[c] = NULL;
ee5762e3 4498
729e3769
LP
4499 l = strv_join((char**)argv, " ");
4500 if (!l) {
0d0f0c50 4501 r = log_oom();
729e3769
LP
4502 goto finish;
4503 }
ee5762e3 4504
729e3769
LP
4505 log_info("Executing %s", l);
4506 free(l);
ee5762e3 4507
729e3769
LP
4508 pid = fork();
4509 if (pid < 0) {
4510 log_error("Failed to fork: %m");
729e3769
LP
4511 r = -errno;
4512 goto finish;
4513 } else if (pid == 0) {
4514 /* Child */
ee5762e3 4515
729e3769
LP
4516 execv(argv[0], (char**) argv);
4517 _exit(EXIT_FAILURE);
4518 }
ee5762e3 4519
729e3769
LP
4520 j = wait_for_terminate(pid, &status);
4521 if (j < 0) {
4522 log_error("Failed to wait for child: %s", strerror(-r));
4523 r = j;
4524 goto finish;
4525 }
ee5762e3 4526
729e3769
LP
4527 if (status.si_code == CLD_EXITED) {
4528 if (streq(verb, "is-enabled")) {
4529 if (status.si_status == 0) {
4530 if (!arg_quiet)
4531 puts("enabled");
4532 r = 1;
4533 } else {
4534 if (!arg_quiet)
4535 puts("disabled");
4536 }
ee5762e3 4537
729e3769
LP
4538 } else if (status.si_status != 0) {
4539 r = -EINVAL;
4540 goto finish;
4541 }
4542 } else {
4543 r = -EPROTO;
4544 goto finish;
4545 }
ee5762e3
LP
4546 }
4547
729e3769 4548finish:
729e3769 4549 /* Drop all SysV units */
cbb13b2a 4550 for (f = 0, t = 0; args[f]; f++) {
ee5762e3 4551
729e3769 4552 if (isempty(args[f]))
ee5762e3
LP
4553 continue;
4554
729e3769
LP
4555 args[t++] = args[f];
4556 }
ee5762e3 4557
729e3769 4558 args[t] = NULL;
ee5762e3 4559
729e3769
LP
4560#endif
4561 return r;
4562}
ee5762e3 4563
37370d0c 4564static int mangle_names(char **original_names, char ***mangled_names) {
a33fdebb 4565 char **i, **l, **name;
37370d0c 4566
a33fdebb
LP
4567 l = new(char*, strv_length(original_names) + 1);
4568 if (!l)
37370d0c
VP
4569 return log_oom();
4570
a33fdebb 4571 i = l;
37370d0c 4572 STRV_FOREACH(name, original_names) {
44386fc1
LN
4573
4574 /* When enabling units qualified path names are OK,
4575 * too, hence allow them explicitly. */
4576
4577 if (is_path(*name))
4578 *i = strdup(*name);
4579 else
4580 *i = unit_name_mangle(*name);
4581
a33fdebb
LP
4582 if (!*i) {
4583 strv_free(l);
37370d0c 4584 return log_oom();
a33fdebb
LP
4585 }
4586
4587 i++;
37370d0c 4588 }
a33fdebb
LP
4589
4590 *i = NULL;
4591 *mangled_names = l;
37370d0c
VP
4592
4593 return 0;
4594}
4595
f459b602 4596static int enable_unit(sd_bus *bus, char **args) {
f459b602 4597 _cleanup_strv_free_ char **mangled_names = NULL;
729e3769
LP
4598 const char *verb = args[0];
4599 UnitFileChange *changes = NULL;
718db961 4600 unsigned n_changes = 0;
729e3769 4601 int carries_install_info = -1;
729e3769 4602 int r;
ee5762e3 4603
ab5919fa
MS
4604 if (!args[1])
4605 return 0;
4606
3a05c0f9
VP
4607 r = mangle_names(args+1, &mangled_names);
4608 if (r < 0)
cbb13b2a
VP
4609 return r;
4610
4611 r = enable_sysv_units(verb, mangled_names);
4612 if (r < 0)
4613 return r;
3a05c0f9 4614
729e3769
LP
4615 if (!bus || avoid_bus()) {
4616 if (streq(verb, "enable")) {
3a05c0f9 4617 r = unit_file_enable(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
729e3769
LP
4618 carries_install_info = r;
4619 } else if (streq(verb, "disable"))
3a05c0f9 4620 r = unit_file_disable(arg_scope, arg_runtime, arg_root, mangled_names, &changes, &n_changes);
729e3769 4621 else if (streq(verb, "reenable")) {
3a05c0f9 4622 r = unit_file_reenable(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
729e3769
LP
4623 carries_install_info = r;
4624 } else if (streq(verb, "link"))
3a05c0f9 4625 r = unit_file_link(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
729e3769 4626 else if (streq(verb, "preset")) {
3a05c0f9 4627 r = unit_file_preset(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
729e3769
LP
4628 carries_install_info = r;
4629 } else if (streq(verb, "mask"))
3a05c0f9 4630 r = unit_file_mask(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
729e3769 4631 else if (streq(verb, "unmask"))
3a05c0f9 4632 r = unit_file_unmask(arg_scope, arg_runtime, arg_root, mangled_names, &changes, &n_changes);
729e3769
LP
4633 else
4634 assert_not_reached("Unknown verb");
ee5762e3 4635
729e3769
LP
4636 if (r < 0) {
4637 log_error("Operation failed: %s", strerror(-r));
4638 goto finish;
ee5762e3
LP
4639 }
4640
718db961
LP
4641 if (!arg_quiet)
4642 dump_unit_file_changes(changes, n_changes);
ee5762e3 4643
df77cdf0 4644 r = 0;
729e3769 4645 } else {
718db961
LP
4646 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
4647 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
f459b602
MAP
4648 int expect_carries_install_info = false;
4649 bool send_force = true;
718db961 4650 const char *method;
729e3769
LP
4651
4652 if (streq(verb, "enable")) {
4653 method = "EnableUnitFiles";
4654 expect_carries_install_info = true;
4655 } else if (streq(verb, "disable")) {
4656 method = "DisableUnitFiles";
4657 send_force = false;
4658 } else if (streq(verb, "reenable")) {
4659 method = "ReenableUnitFiles";
4660 expect_carries_install_info = true;
4661 } else if (streq(verb, "link"))
4662 method = "LinkUnitFiles";
4663 else if (streq(verb, "preset")) {
4664 method = "PresetUnitFiles";
4665 expect_carries_install_info = true;
4666 } else if (streq(verb, "mask"))
4667 method = "MaskUnitFiles";
4668 else if (streq(verb, "unmask")) {
4669 method = "UnmaskUnitFiles";
4670 send_force = false;
4671 } else
4672 assert_not_reached("Unknown verb");
4673
f459b602
MAP
4674 r = sd_bus_message_new_method_call(
4675 bus,
729e3769
LP
4676 "org.freedesktop.systemd1",
4677 "/org/freedesktop/systemd1",
4678 "org.freedesktop.systemd1.Manager",
f459b602
MAP
4679 method,
4680 &m);
4681 if (r < 0)
4682 return bus_log_create_error(r);
ee5762e3 4683
f459b602
MAP
4684 r = sd_bus_message_append_strv(m, mangled_names);
4685 if (r < 0)
4686 return bus_log_create_error(r);
ee5762e3 4687
f459b602
MAP
4688 r = sd_bus_message_append(m, "b", arg_runtime);
4689 if (r < 0)
4690 return bus_log_create_error(r);
ee5762e3 4691
729e3769 4692 if (send_force) {
f459b602
MAP
4693 r = sd_bus_message_append(m, "b", arg_force);
4694 if (r < 0)
4695 return bus_log_create_error(r);
ee5762e3
LP
4696 }
4697
c49b30a2 4698 r = sd_bus_call(bus, m, 0, &error, &reply);
f459b602
MAP
4699 if (r < 0) {
4700 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
4701 return r;
729e3769 4702 }
be394c48 4703
729e3769 4704 if (expect_carries_install_info) {
f459b602
MAP
4705 r = sd_bus_message_read(reply, "b", &carries_install_info);
4706 if (r < 0)
4707 return bus_log_parse_error(r);
ee5762e3
LP
4708 }
4709
cc3f2093 4710 r = deserialize_and_dump_unit_file_changes(reply);
f459b602 4711 if (r < 0)
718db961 4712 return r;
b77398f7 4713
729e3769 4714 /* Try to reload if enabeld */
d6cb60c7 4715 if (!arg_no_reload)
729e3769 4716 r = daemon_reload(bus, args);
f459b602
MAP
4717 else
4718 r = 0;
b647f10d 4719 }
3d3961f2 4720
729e3769 4721 if (carries_install_info == 0)
416389f7
LP
4722 log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
4723 "using systemctl.\n"
4724 "Possible reasons for having this kind of units are:\n"
4725 "1) A unit may be statically enabled by being symlinked from another unit's\n"
4726 " .wants/ or .requires/ directory.\n"
4727 "2) A unit's purpose may be to act as a helper for some other unit which has\n"
4728 " a requirement dependency on it.\n"
4729 "3) A unit may be started when needed via activation (socket, path, timer,\n"
4730 " D-Bus, udev, scripted systemctl call, ...).\n");
ee5762e3 4731
729e3769 4732finish:
729e3769 4733 unit_file_changes_free(changes, n_changes);
ee5762e3 4734
729e3769 4735 return r;
ee5762e3
LP
4736}
4737
f459b602
MAP
4738static int unit_is_enabled(sd_bus *bus, char **args) {
4739
4740 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4741 _cleanup_strv_free_ char **mangled_names = NULL;
729e3769
LP
4742 bool enabled;
4743 char **name;
f459b602 4744 int r;
ee5762e3 4745
cbb13b2a
VP
4746 r = mangle_names(args+1, &mangled_names);
4747 if (r < 0)
4748 return r;
4749
4750 r = enable_sysv_units(args[0], mangled_names);
729e3769
LP
4751 if (r < 0)
4752 return r;
ee5762e3 4753
729e3769 4754 enabled = r > 0;
ee5762e3 4755
729e3769 4756 if (!bus || avoid_bus()) {
ee5762e3 4757
cbb13b2a 4758 STRV_FOREACH(name, mangled_names) {
729e3769 4759 UnitFileState state;
ee5762e3 4760
cbb13b2a 4761 state = unit_file_get_state(arg_scope, arg_root, *name);
cbc9fbd1
LP
4762 if (state < 0) {
4763 log_error("Failed to get unit file state for %s: %s", *name, strerror(-state));
cec7eda5 4764 return state;
cbc9fbd1 4765 }
ee5762e3 4766
729e3769
LP
4767 if (state == UNIT_FILE_ENABLED ||
4768 state == UNIT_FILE_ENABLED_RUNTIME ||
4769 state == UNIT_FILE_STATIC)
4770 enabled = true;
4771
4772 if (!arg_quiet)
4773 puts(unit_file_state_to_string(state));
71fad675 4774 }
ee5762e3 4775
729e3769 4776 } else {
cbb13b2a 4777 STRV_FOREACH(name, mangled_names) {
f459b602 4778 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
729e3769 4779 const char *s;
63a723f3 4780
f459b602 4781 r = sd_bus_call_method(
f22f08cd 4782 bus,
729e3769
LP
4783 "org.freedesktop.systemd1",
4784 "/org/freedesktop/systemd1",
4785 "org.freedesktop.systemd1.Manager",
f22f08cd 4786 "GetUnitFileState",
f459b602 4787 &error,
f22f08cd 4788 &reply,
04504f93 4789 "s", *name);
f459b602
MAP
4790 if (r < 0) {
4791 log_error("Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
cec7eda5 4792 return r;
ee5762e3
LP
4793 }
4794
f459b602
MAP
4795 r = sd_bus_message_read(reply, "s", &s);
4796 if (r < 0)
4797 return bus_log_parse_error(r);
ee5762e3 4798
729e3769
LP
4799 if (streq(s, "enabled") ||
4800 streq(s, "enabled-runtime") ||
4801 streq(s, "static"))
4802 enabled = true;
4803
4804 if (!arg_quiet)
4805 puts(s);
560d8f23 4806 }
ee5762e3
LP
4807 }
4808
f459b602 4809 return !enabled;
ee5762e3
LP
4810}
4811
e4b61340 4812static int systemctl_help(void) {
7e4249b9 4813
729e3769
LP
4814 pager_open_if_enabled();
4815
2e33c433 4816 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
729e3769 4817 "Query or send control commands to the systemd manager.\n\n"
8a0867d6
LP
4818 " -h --help Show this help\n"
4819 " --version Show package version\n"
f459b602
MAP
4820 " --system Connect to system manager\n"
4821 " --user Connect to user service manager\n"
4822 " -H --host=[USER@]HOST\n"
4823 " Operate on remote host\n"
4824 " -M --machine=CONTAINER\n"
4825 " Operate on local container\n"
8a0867d6 4826 " -t --type=TYPE List only units of a particular type\n"
a521ae4a 4827 " --state=STATE List only units with particular LOAD or SUB or ACTIVE state\n"
8a0867d6 4828 " -p --property=NAME Show only properties by this name\n"
a5e4972c
LP
4829 " -a --all Show all loaded units/properties, including dead/empty\n"
4830 " ones. To list all units installed on the system, use\n"
4831 " the 'list-unit-files' command instead.\n"
98a6e132 4832 " -l --full Don't ellipsize unit names on output\n"
4dc5b821
LP
4833 " --reverse Show reverse dependencies with 'list-dependencies'\n"
4834 " --job-mode=MODE Specify how to deal with already queued jobs, when\n"
4835 " queueing a new job\n"
a521ae4a 4836 " --show-types When showing sockets, explicitly show their type\n"
b37844d3
LP
4837 " -i --ignore-inhibitors\n"
4838 " When shutting down or sleeping, ignore inhibitors\n"
a8f11321
LP
4839 " --kill-who=WHO Who to send signal to\n"
4840 " -s --signal=SIGNAL Which signal to send\n"
8a0867d6
LP
4841 " -q --quiet Suppress output\n"
4842 " --no-block Do not wait until operation finished\n"
8a0867d6 4843 " --no-wall Don't send wall message before halt/power-off/reboot\n"
8a0867d6
LP
4844 " --no-reload When enabling/disabling unit files, don't reload daemon\n"
4845 " configuration\n"
ebed32bf 4846 " --no-legend Do not print a legend (column headers and hints)\n"
69fc152f 4847 " --no-pager Do not pipe output into a pager\n"
501fc174
LP
4848 " --no-ask-password\n"
4849 " Do not ask for system passwords\n"
a8f11321 4850 " --global Enable/disable unit files globally\n"
a521ae4a 4851 " --runtime Enable unit files only temporarily until next reboot\n"
8a0867d6
LP
4852 " -f --force When enabling unit files, override existing symlinks\n"
4853 " When shutting down, execute action immediately\n"
729e3769 4854 " --root=PATH Enable unit files in the specified root directory\n"
76fdc966 4855 " -n --lines=INTEGER Number of journal entries to show\n"
d3f2bdbf 4856 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
815ebc54
DH
4857 " verbose, export, json, json-pretty, json-sse, cat)\n"
4858 " --plain Print unit dependencies as a list instead of a tree\n\n"
34c4b47b 4859 "Unit Commands:\n"
d8fba7c6
ZJS
4860 " list-units [PATTERN...] List loaded units\n"
4861 " list-sockets [PATTERN...] List loaded sockets ordered by address\n"
4862 " list-timers [PATTERN...] List loaded timers ordered by next elapse\n"
4f8f66cb
ZJS
4863 " start NAME... Start (activate) one or more units\n"
4864 " stop NAME... Stop (deactivate) one or more units\n"
4865 " reload NAME... Reload one or more units\n"
4866 " restart NAME... Start or restart one or more units\n"
4867 " try-restart NAME... Restart one or more units if active\n"
4868 " reload-or-restart NAME... Reload one or more units if possible,\n"
6f28c033 4869 " otherwise start or restart\n"
4f8f66cb 4870 " reload-or-try-restart NAME... Reload one or more units if possible,\n"
6f28c033 4871 " otherwise restart if active\n"
4f8f66cb
ZJS
4872 " isolate NAME Start one unit and stop all others\n"
4873 " kill NAME... Send signal to processes of a unit\n"
4874 " is-active NAME... Check whether units are active\n"
4875 " is-failed NAME... Check whether units are failed\n"
75676b72 4876 " status [NAME...|PID...] Show runtime status of one or more units\n"
6f28c033 4877 " show [NAME...|JOB...] Show properties of one or more\n"
ee5762e3 4878 " units/jobs or the manager\n"
4f8f66cb
ZJS
4879 " cat NAME... Show files and drop-ins of one or more units\n"
4880 " set-property NAME ASSIGNMENT... Sets one or more properties of a unit\n"
4881 " help NAME...|PID... Show manual for one or more units\n"
fdf20a31
MM
4882 " reset-failed [NAME...] Reset failed state for all, one, or more\n"
4883 " units\n"
55c0b89c 4884 " list-dependencies [NAME] Recursively show units which are required\n"
afba4199
ZJS
4885 " or wanted by this unit or by which this\n"
4886 " unit is required or wanted\n\n"
34c4b47b 4887 "Unit File Commands:\n"
d8fba7c6 4888 " list-unit-files [PATTERN...] List installed unit files\n"
4f8f66cb
ZJS
4889 " enable NAME... Enable one or more unit files\n"
4890 " disable NAME... Disable one or more unit files\n"
4891 " reenable NAME... Reenable one or more unit files\n"
4892 " preset NAME... Enable/disable one or more unit files\n"
729e3769 4893 " based on preset configuration\n"
4f8f66cb
ZJS
4894 " is-enabled NAME... Check whether unit files are enabled\n\n"
4895 " mask NAME... Mask one or more units\n"
4896 " unmask NAME... Unmask one or more units\n"
4897 " link PATH... Link one or more units files into\n"
729e3769 4898 " the search path\n"
99504dd4 4899 " get-default Get the name of the default target\n"
f535088e 4900 " set-default NAME Set the default target\n\n"
34c4b47b 4901 "Job Commands:\n"
d8fba7c6 4902 " list-jobs [PATTERN...] List jobs\n"
34c4b47b 4903 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
34c4b47b 4904 "Snapshot Commands:\n"
7e4249b9 4905 " snapshot [NAME] Create a snapshot\n"
4f8f66cb 4906 " delete NAME... Remove one or more snapshots\n\n"
34c4b47b 4907 "Environment Commands:\n"
7e4249b9 4908 " show-environment Dump environment\n"
4f8f66cb
ZJS
4909 " set-environment NAME=VALUE... Set one or more environment variables\n"
4910 " unset-environment NAME... Unset one or more environment variables\n\n"
34c4b47b
LP
4911 "Manager Lifecycle Commands:\n"
4912 " daemon-reload Reload systemd manager configuration\n"
4913 " daemon-reexec Reexecute systemd manager\n\n"
4914 "System Commands:\n"
20b09ca7
LP
4915 " default Enter system default mode\n"
4916 " rescue Enter system rescue mode\n"
4917 " emergency Enter system emergency mode\n"
514f4ef5 4918 " halt Shut down and halt the system\n"
2e33c433 4919 " poweroff Shut down and power-off the system\n"
37185ec8 4920 " reboot [ARG] Shut down and reboot the system\n"
20b09ca7 4921 " kexec Shut down and reboot the system with kexec\n"
6edd7d0a 4922 " exit Request user instance exit\n"
4f8f66cb 4923 " switch-root ROOT [INIT] Change to a different root file system\n"
6edd7d0a 4924 " suspend Suspend the system\n"
6524990f
LP
4925 " hibernate Hibernate the system\n"
4926 " hybrid-sleep Hibernate and suspend the system\n",
5b6319dc 4927 program_invocation_short_name);
7e4249b9
LP
4928
4929 return 0;
4930}
4931
e4b61340
LP
4932static int halt_help(void) {
4933
37185ec8 4934 printf("%s [OPTIONS...]%s\n\n"
e4b61340
LP
4935 "%s the system.\n\n"
4936 " --help Show this help\n"
4937 " --halt Halt the machine\n"
4938 " -p --poweroff Switch off the machine\n"
4939 " --reboot Reboot the machine\n"
2e33c433
LP
4940 " -f --force Force immediate halt/power-off/reboot\n"
4941 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
e4b61340 4942 " -d --no-wtmp Don't write wtmp record\n"
2e33c433 4943 " --no-wall Don't send wall message before halt/power-off/reboot\n",
e4b61340 4944 program_invocation_short_name,
37185ec8 4945 arg_action == ACTION_REBOOT ? " [ARG]" : "",
e4b61340
LP
4946 arg_action == ACTION_REBOOT ? "Reboot" :
4947 arg_action == ACTION_POWEROFF ? "Power off" :
4948 "Halt");
4949
4950 return 0;
4951}
4952
4953static int shutdown_help(void) {
4954
08e4b1c5 4955 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
e4b61340
LP
4956 "Shut down the system.\n\n"
4957 " --help Show this help\n"
4958 " -H --halt Halt the machine\n"
4959 " -P --poweroff Power-off the machine\n"
4960 " -r --reboot Reboot the machine\n"
386da858 4961 " -h Equivalent to --poweroff, overridden by --halt\n"
2e33c433 4962 " -k Don't halt/power-off/reboot, just send warnings\n"
f6144808 4963 " --no-wall Don't send wall message before halt/power-off/reboot\n"
f6144808 4964 " -c Cancel a pending shutdown\n",
e4b61340
LP
4965 program_invocation_short_name);
4966
4967 return 0;
4968}
4969
4970static int telinit_help(void) {
4971
2e33c433 4972 printf("%s [OPTIONS...] {COMMAND}\n\n"
514f4ef5
LP
4973 "Send control commands to the init daemon.\n\n"
4974 " --help Show this help\n"
2e33c433 4975 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
e4b61340
LP
4976 "Commands:\n"
4977 " 0 Power-off the machine\n"
4978 " 6 Reboot the machine\n"
514f4ef5
LP
4979 " 2, 3, 4, 5 Start runlevelX.target unit\n"
4980 " 1, s, S Enter rescue mode\n"
4981 " q, Q Reload init daemon configuration\n"
4982 " u, U Reexecute init daemon\n",
e4b61340
LP
4983 program_invocation_short_name);
4984
4985 return 0;
4986}
4987
4988static int runlevel_help(void) {
4989
2e33c433 4990 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
4991 "Prints the previous and current runlevel of the init system.\n\n"
4992 " --help Show this help\n",
4993 program_invocation_short_name);
4994
4995 return 0;
4996}
4997
45c0c61d
ZJS
4998static int help_types(void) {
4999 int i;
830f01f0 5000 const char *t;
45c0c61d
ZJS
5001
5002 puts("Available unit types:");
f168c273 5003 for (i = 0; i < _UNIT_TYPE_MAX; i++) {
830f01f0
LP
5004 t = unit_type_to_string(i);
5005 if (t)
5006 puts(t);
5007 }
45c0c61d 5008
45c0c61d
ZJS
5009 return 0;
5010}
5011
e4b61340 5012static int systemctl_parse_argv(int argc, char *argv[]) {
7e4249b9
LP
5013
5014 enum {
90d473a1 5015 ARG_FAIL = 0x100,
afba4199
ZJS
5016 ARG_REVERSE,
5017 ARG_AFTER,
5018 ARG_BEFORE,
991f2a39 5019 ARG_SHOW_TYPES,
23ade460 5020 ARG_IRREVERSIBLE,
e67c3609 5021 ARG_IGNORE_DEPENDENCIES,
35df8f27 5022 ARG_VERSION,
af2d49f7 5023 ARG_USER,
7e4249b9 5024 ARG_SYSTEM,
ee5762e3 5025 ARG_GLOBAL,
6e905d93 5026 ARG_NO_BLOCK,
ebed32bf 5027 ARG_NO_LEGEND,
611efaac 5028 ARG_NO_PAGER,
4445a875 5029 ARG_NO_WALL,
be394c48 5030 ARG_ROOT,
ee5762e3 5031 ARG_NO_RELOAD,
501fc174 5032 ARG_KILL_WHO,
30732560 5033 ARG_NO_ASK_PASSWORD,
729e3769 5034 ARG_FAILED,
df50185b 5035 ARG_RUNTIME,
5d0c05e5 5036 ARG_FORCE,
9b9b3d36 5037 ARG_PLAIN,
4dc5b821
LP
5038 ARG_STATE,
5039 ARG_JOB_MODE
7e4249b9
LP
5040 };
5041
5042 static const struct option options[] = {
9ea9d4cf
LP
5043 { "help", no_argument, NULL, 'h' },
5044 { "version", no_argument, NULL, ARG_VERSION },
5045 { "type", required_argument, NULL, 't' },
5046 { "property", required_argument, NULL, 'p' },
5047 { "all", no_argument, NULL, 'a' },
5048 { "reverse", no_argument, NULL, ARG_REVERSE },
5049 { "after", no_argument, NULL, ARG_AFTER },
5050 { "before", no_argument, NULL, ARG_BEFORE },
5051 { "show-types", no_argument, NULL, ARG_SHOW_TYPES },
5052 { "failed", no_argument, NULL, ARG_FAILED }, /* compatibility only */
5053 { "full", no_argument, NULL, 'l' },
4dc5b821
LP
5054 { "job-mode", required_argument, NULL, ARG_JOB_MODE },
5055 { "fail", no_argument, NULL, ARG_FAIL }, /* compatibility only */
5056 { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, /* compatibility only */
5057 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */
9ea9d4cf
LP
5058 { "ignore-inhibitors", no_argument, NULL, 'i' },
5059 { "user", no_argument, NULL, ARG_USER },
5060 { "system", no_argument, NULL, ARG_SYSTEM },
5061 { "global", no_argument, NULL, ARG_GLOBAL },
5062 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
5063 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
5064 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
5065 { "no-wall", no_argument, NULL, ARG_NO_WALL },
5066 { "quiet", no_argument, NULL, 'q' },
5067 { "root", required_argument, NULL, ARG_ROOT },
5068 { "force", no_argument, NULL, ARG_FORCE },
5069 { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
5070 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
5071 { "signal", required_argument, NULL, 's' },
5072 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
5073 { "host", required_argument, NULL, 'H' },
f459b602 5074 { "machine", required_argument, NULL, 'M' },
9ea9d4cf
LP
5075 { "runtime", no_argument, NULL, ARG_RUNTIME },
5076 { "lines", required_argument, NULL, 'n' },
5077 { "output", required_argument, NULL, 'o' },
5078 { "plain", no_argument, NULL, ARG_PLAIN },
5079 { "state", required_argument, NULL, ARG_STATE },
eb9da376 5080 {}
7e4249b9
LP
5081 };
5082
5083 int c;
5084
e4b61340 5085 assert(argc >= 0);
7e4249b9
LP
5086 assert(argv);
5087
f459b602 5088 while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:i", options, NULL)) >= 0) {
7e4249b9
LP
5089
5090 switch (c) {
5091
5092 case 'h':
eb9da376 5093 return systemctl_help();
35df8f27
LP
5094
5095 case ARG_VERSION:
5096 puts(PACKAGE_STRING);
7d568925 5097 puts(SYSTEMD_FEATURES);
35df8f27 5098 return 0;
7e4249b9 5099
20b3f379
ZJS
5100 case 't': {
5101 char *word, *state;
5102 size_t size;
45c0c61d 5103
20b3f379 5104 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
7fd1b19b 5105 _cleanup_free_ char *type;
20b3f379
ZJS
5106
5107 type = strndup(word, size);
5108 if (!type)
5109 return -ENOMEM;
5110
5111 if (streq(type, "help")) {
5112 help_types();
5113 return 0;
5114 }
5115
5116 if (unit_type_from_string(type) >= 0) {
5117 if (strv_push(&arg_types, type))
5118 return log_oom();
5119 type = NULL;
5120 continue;
5121 }
5122
9b9b3d36
MW
5123 /* It's much nicer to use --state= for
5124 * load states, but let's support this
5125 * in --types= too for compatibility
5126 * with old versions */
20b3f379 5127 if (unit_load_state_from_string(optarg) >= 0) {
9b9b3d36 5128 if (strv_push(&arg_states, type) < 0)
20b3f379
ZJS
5129 return log_oom();
5130 type = NULL;
5131 continue;
5132 }
5133
ab06eef8 5134 log_error("Unknown unit type or load state '%s'.", type);
20b3f379
ZJS
5135 log_info("Use -t help to see a list of allowed values.");
5136 return -EINVAL;
c147dc42 5137 }
20b3f379
ZJS
5138
5139 break;
5140 }
5141
ea4a240d 5142 case 'p': {
033a842c
ZJS
5143 /* Make sure that if the empty property list
5144 was specified, we won't show any properties. */
20b3f379 5145 if (isempty(optarg) && !arg_properties) {
cbc9fbd1 5146 arg_properties = new0(char*, 1);
20b3f379
ZJS
5147 if (!arg_properties)
5148 return log_oom();
5149 } else {
5150 char *word, *state;
5151 size_t size;
033a842c 5152
20b3f379
ZJS
5153 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
5154 char *prop;
033a842c 5155
20b3f379
ZJS
5156 prop = strndup(word, size);
5157 if (!prop)
5158 return log_oom();
ea4a240d 5159
9b9b3d36 5160 if (strv_push(&arg_properties, prop) < 0) {
20b3f379
ZJS
5161 free(prop);
5162 return log_oom();
5163 }
5164 }
033a842c 5165 }
48220598
LP
5166
5167 /* If the user asked for a particular
5168 * property, show it to him, even if it is
5169 * empty. */
5170 arg_all = true;
033a842c 5171
48220598 5172 break;
ea4a240d 5173 }
48220598 5174
7e4249b9
LP
5175 case 'a':
5176 arg_all = true;
5177 break;
5178
afba4199
ZJS
5179 case ARG_REVERSE:
5180 arg_dependency = DEPENDENCY_REVERSE;
5181 break;
5182
5183 case ARG_AFTER:
5184 arg_dependency = DEPENDENCY_AFTER;
5185 break;
5186
5187 case ARG_BEFORE:
5188 arg_dependency = DEPENDENCY_BEFORE;
5189 break;
5190
991f2a39
ZJS
5191 case ARG_SHOW_TYPES:
5192 arg_show_types = true;
5193 break;
5194
4dc5b821
LP
5195 case ARG_JOB_MODE:
5196 arg_job_mode = optarg;
5197 break;
5198
90d473a1 5199 case ARG_FAIL:
e67c3609
LP
5200 arg_job_mode = "fail";
5201 break;
5202
23ade460
MS
5203 case ARG_IRREVERSIBLE:
5204 arg_job_mode = "replace-irreversibly";
5205 break;
5206
e67c3609
LP
5207 case ARG_IGNORE_DEPENDENCIES:
5208 arg_job_mode = "ignore-dependencies";
7e4249b9
LP
5209 break;
5210
af2d49f7 5211 case ARG_USER:
729e3769 5212 arg_scope = UNIT_FILE_USER;
7e4249b9
LP
5213 break;
5214
5215 case ARG_SYSTEM:
729e3769
LP
5216 arg_scope = UNIT_FILE_SYSTEM;
5217 break;
5218
5219 case ARG_GLOBAL:
5220 arg_scope = UNIT_FILE_GLOBAL;
7e4249b9
LP
5221 break;
5222
6e905d93
LP
5223 case ARG_NO_BLOCK:
5224 arg_no_block = true;
7e4249b9
LP
5225 break;
5226
ebed32bf
MS
5227 case ARG_NO_LEGEND:
5228 arg_no_legend = true;
5229 break;
5230
611efaac
LP
5231 case ARG_NO_PAGER:
5232 arg_no_pager = true;
5233 break;
0736af98 5234
514f4ef5
LP
5235 case ARG_NO_WALL:
5236 arg_no_wall = true;
5237 break;
5238
be394c48
FC
5239 case ARG_ROOT:
5240 arg_root = optarg;
5241 break;
5242
98a6e132 5243 case 'l':
8fe914ec
LP
5244 arg_full = true;
5245 break;
5246
30732560 5247 case ARG_FAILED:
9b9b3d36
MW
5248 if (strv_extend(&arg_states, "failed") < 0)
5249 return log_oom();
5250
30732560
LP
5251 break;
5252
0183528f
LP
5253 case 'q':
5254 arg_quiet = true;
5255 break;
5256
568b679f
LP
5257 case ARG_FORCE:
5258 arg_force ++;
5259 break;
5260
b4f27ccc 5261 case 'f':
e606bb61 5262 arg_force ++;
ee5762e3
LP
5263 break;
5264
5265 case ARG_NO_RELOAD:
5266 arg_no_reload = true;
5267 break;
5268
8a0867d6
LP
5269 case ARG_KILL_WHO:
5270 arg_kill_who = optarg;
5271 break;
5272
8a0867d6
LP
5273 case 's':
5274 if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
5275 log_error("Failed to parse signal string %s.", optarg);
5276 return -EINVAL;
5277 }
5278 break;
5279
501fc174
LP
5280 case ARG_NO_ASK_PASSWORD:
5281 arg_ask_password = false;
5282 break;
5283
f459b602
MAP
5284 case 'H':
5285 arg_transport = BUS_TRANSPORT_REMOTE;
5286 arg_host = optarg;
a8f11321
LP
5287 break;
5288
f459b602
MAP
5289 case 'M':
5290 arg_transport = BUS_TRANSPORT_CONTAINER;
5291 arg_host = optarg;
a8f11321
LP
5292 break;
5293
729e3769
LP
5294 case ARG_RUNTIME:
5295 arg_runtime = true;
5296 break;
5297
df50185b
LP
5298 case 'n':
5299 if (safe_atou(optarg, &arg_lines) < 0) {
5300 log_error("Failed to parse lines '%s'", optarg);
5301 return -EINVAL;
5302 }
5303 break;
5304
df50185b
LP
5305 case 'o':
5306 arg_output = output_mode_from_string(optarg);
5307 if (arg_output < 0) {
5308 log_error("Unknown output '%s'.", optarg);
5309 return -EINVAL;
5310 }
5311 break;
5312
b37844d3
LP
5313 case 'i':
5314 arg_ignore_inhibitors = true;
5315 break;
5316
5d0c05e5
LN
5317 case ARG_PLAIN:
5318 arg_plain = true;
5319 break;
5320
9b9b3d36
MW
5321 case ARG_STATE: {
5322 char *word, *state;
5323 size_t size;
5324
5325 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
5326 char *s;
5327
5328 s = strndup(word, size);
5329 if (!s)
5330 return log_oom();
5331
5332 if (strv_push(&arg_states, s) < 0) {
5333 free(s);
5334 return log_oom();
5335 }
5336 }
5337 break;
5338 }
5339
7e4249b9
LP
5340 case '?':
5341 return -EINVAL;
5342
5343 default:
eb9da376 5344 assert_not_reached("Unhandled option");
7e4249b9
LP
5345 }
5346 }
5347
f459b602 5348 if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM) {
a8f11321
LP
5349 log_error("Cannot access user instance remotely.");
5350 return -EINVAL;
5351 }
5352
7e4249b9
LP
5353 return 1;
5354}
5355
e4b61340
LP
5356static int halt_parse_argv(int argc, char *argv[]) {
5357
5358 enum {
5359 ARG_HELP = 0x100,
5360 ARG_HALT,
514f4ef5
LP
5361 ARG_REBOOT,
5362 ARG_NO_WALL
e4b61340
LP
5363 };
5364
5365 static const struct option options[] = {
5366 { "help", no_argument, NULL, ARG_HELP },
5367 { "halt", no_argument, NULL, ARG_HALT },
5368 { "poweroff", no_argument, NULL, 'p' },
5369 { "reboot", no_argument, NULL, ARG_REBOOT },
5370 { "force", no_argument, NULL, 'f' },
5371 { "wtmp-only", no_argument, NULL, 'w' },
5372 { "no-wtmp", no_argument, NULL, 'd' },
514f4ef5 5373 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 5374 {}
e4b61340
LP
5375 };
5376
37185ec8 5377 int c, r, runlevel;
e4b61340
LP
5378
5379 assert(argc >= 0);
5380 assert(argv);
5381
5382 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
5383 if (runlevel == '0' || runlevel == '6')
65491fd8 5384 arg_force = 2;
e4b61340
LP
5385
5386 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
5387 switch (c) {
5388
5389 case ARG_HELP:
eb9da376 5390 return halt_help();
e4b61340
LP
5391
5392 case ARG_HALT:
5393 arg_action = ACTION_HALT;
5394 break;
5395
5396 case 'p':
a042efad
MS
5397 if (arg_action != ACTION_REBOOT)
5398 arg_action = ACTION_POWEROFF;
e4b61340
LP
5399 break;
5400
5401 case ARG_REBOOT:
5402 arg_action = ACTION_REBOOT;
5403 break;
5404
5405 case 'f':
65491fd8 5406 arg_force = 2;
e4b61340
LP
5407 break;
5408
5409 case 'w':
5410 arg_dry = true;
5411 break;
5412
5413 case 'd':
5414 arg_no_wtmp = true;
5415 break;
5416
514f4ef5
LP
5417 case ARG_NO_WALL:
5418 arg_no_wall = true;
5419 break;
5420
e4b61340
LP
5421 case 'i':
5422 case 'h':
57371e58 5423 case 'n':
e4b61340
LP
5424 /* Compatibility nops */
5425 break;
5426
5427 case '?':
5428 return -EINVAL;
5429
5430 default:
eb9da376 5431 assert_not_reached("Unhandled option");
e4b61340
LP
5432 }
5433 }
5434
37185ec8
WC
5435 if (arg_action == ACTION_REBOOT && argc == optind + 1) {
5436 r = write_string_file(REBOOT_PARAM_FILE, argv[optind]);
5437 if (r < 0) {
5438 log_error("Failed to write reboot param to "
5439 REBOOT_PARAM_FILE": %s", strerror(-r));
5440 return r;
5441 }
5442 } else if (optind < argc) {
e4b61340
LP
5443 log_error("Too many arguments.");
5444 return -EINVAL;
5445 }
5446
5447 return 1;
5448}
5449
f6144808
LP
5450static int parse_time_spec(const char *t, usec_t *_u) {
5451 assert(t);
5452 assert(_u);
5453
5454 if (streq(t, "now"))
5455 *_u = 0;
1a639877 5456 else if (!strchr(t, ':')) {
f6144808
LP
5457 uint64_t u;
5458
1a639877 5459 if (safe_atou64(t, &u) < 0)
f6144808
LP
5460 return -EINVAL;
5461
5462 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
5463 } else {
5464 char *e = NULL;
5465 long hour, minute;
b92bea5d 5466 struct tm tm = {};
f6144808
LP
5467 time_t s;
5468 usec_t n;
5469
5470 errno = 0;
5471 hour = strtol(t, &e, 10);
8333c77e 5472 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
f6144808
LP
5473 return -EINVAL;
5474
5475 minute = strtol(e+1, &e, 10);
8333c77e 5476 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
f6144808
LP
5477 return -EINVAL;
5478
5479 n = now(CLOCK_REALTIME);
08e4b1c5
LP
5480 s = (time_t) (n / USEC_PER_SEC);
5481
f6144808
LP
5482 assert_se(localtime_r(&s, &tm));
5483
5484 tm.tm_hour = (int) hour;
5485 tm.tm_min = (int) minute;
08e4b1c5 5486 tm.tm_sec = 0;
f6144808
LP
5487
5488 assert_se(s = mktime(&tm));
5489
5490 *_u = (usec_t) s * USEC_PER_SEC;
5491
5492 while (*_u <= n)
5493 *_u += USEC_PER_DAY;
5494 }
5495
5496 return 0;
5497}
5498
e4b61340
LP
5499static int shutdown_parse_argv(int argc, char *argv[]) {
5500
5501 enum {
5502 ARG_HELP = 0x100,
514f4ef5 5503 ARG_NO_WALL
e4b61340
LP
5504 };
5505
5506 static const struct option options[] = {
5507 { "help", no_argument, NULL, ARG_HELP },
5508 { "halt", no_argument, NULL, 'H' },
5509 { "poweroff", no_argument, NULL, 'P' },
5510 { "reboot", no_argument, NULL, 'r' },
04ebb595 5511 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
514f4ef5 5512 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 5513 {}
e4b61340
LP
5514 };
5515
f6144808 5516 int c, r;
e4b61340
LP
5517
5518 assert(argc >= 0);
5519 assert(argv);
5520
f6144808 5521 while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
e4b61340
LP
5522 switch (c) {
5523
5524 case ARG_HELP:
eb9da376 5525 return shutdown_help();
e4b61340
LP
5526
5527 case 'H':
5528 arg_action = ACTION_HALT;
5529 break;
5530
5531 case 'P':
5532 arg_action = ACTION_POWEROFF;
5533 break;
5534
5535 case 'r':
5622dde3
KS
5536 if (kexec_loaded())
5537 arg_action = ACTION_KEXEC;
5538 else
5539 arg_action = ACTION_REBOOT;
e4b61340
LP
5540 break;
5541
04ebb595
LP
5542 case 'K':
5543 arg_action = ACTION_KEXEC;
5544 break;
5545
e4b61340
LP
5546 case 'h':
5547 if (arg_action != ACTION_HALT)
5548 arg_action = ACTION_POWEROFF;
5549 break;
5550
5551 case 'k':
5552 arg_dry = true;
5553 break;
5554
514f4ef5
LP
5555 case ARG_NO_WALL:
5556 arg_no_wall = true;
5557 break;
5558
e4b61340
LP
5559 case 't':
5560 case 'a':
5561 /* Compatibility nops */
5562 break;
5563
f6144808
LP
5564 case 'c':
5565 arg_action = ACTION_CANCEL_SHUTDOWN;
5566 break;
5567
e4b61340
LP
5568 case '?':
5569 return -EINVAL;
5570
5571 default:
eb9da376 5572 assert_not_reached("Unhandled option");
e4b61340
LP
5573 }
5574 }
5575
dfcc5c33 5576 if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
7e59bfcb
LP
5577 r = parse_time_spec(argv[optind], &arg_when);
5578 if (r < 0) {
f6144808
LP
5579 log_error("Failed to parse time specification: %s", argv[optind]);
5580 return r;
5581 }
6b5ad000 5582 } else
08e4b1c5 5583 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
442b9094 5584
dfcc5c33
MS
5585 if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
5586 /* No time argument for shutdown cancel */
5587 arg_wall = argv + optind;
5588 else if (argc > optind + 1)
5589 /* We skip the time argument */
e4b61340
LP
5590 arg_wall = argv + optind + 1;
5591
5592 optind = argc;
5593
5594 return 1;
e4b61340
LP
5595}
5596
5597static int telinit_parse_argv(int argc, char *argv[]) {
5598
5599 enum {
5600 ARG_HELP = 0x100,
514f4ef5 5601 ARG_NO_WALL
e4b61340
LP
5602 };
5603
5604 static const struct option options[] = {
5605 { "help", no_argument, NULL, ARG_HELP },
514f4ef5 5606 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 5607 {}
e4b61340
LP
5608 };
5609
5610 static const struct {
5611 char from;
5612 enum action to;
5613 } table[] = {
5614 { '0', ACTION_POWEROFF },
5615 { '6', ACTION_REBOOT },
ef2f1067 5616 { '1', ACTION_RESCUE },
e4b61340
LP
5617 { '2', ACTION_RUNLEVEL2 },
5618 { '3', ACTION_RUNLEVEL3 },
5619 { '4', ACTION_RUNLEVEL4 },
5620 { '5', ACTION_RUNLEVEL5 },
5621 { 's', ACTION_RESCUE },
5622 { 'S', ACTION_RESCUE },
5623 { 'q', ACTION_RELOAD },
5624 { 'Q', ACTION_RELOAD },
5625 { 'u', ACTION_REEXEC },
5626 { 'U', ACTION_REEXEC }
5627 };
5628
5629 unsigned i;
5630 int c;
5631
5632 assert(argc >= 0);
5633 assert(argv);
5634
5635 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5636 switch (c) {
5637
5638 case ARG_HELP:
eb9da376 5639 return telinit_help();
e4b61340 5640
514f4ef5
LP
5641 case ARG_NO_WALL:
5642 arg_no_wall = true;
5643 break;
5644
e4b61340
LP
5645 case '?':
5646 return -EINVAL;
5647
5648 default:
eb9da376 5649 assert_not_reached("Unhandled option");
e4b61340
LP
5650 }
5651 }
5652
5653 if (optind >= argc) {
2f02ce40 5654 telinit_help();
e4b61340
LP
5655 return -EINVAL;
5656 }
5657
5658 if (optind + 1 < argc) {
5659 log_error("Too many arguments.");
5660 return -EINVAL;
5661 }
5662
5663 if (strlen(argv[optind]) != 1) {
5664 log_error("Expected single character argument.");
5665 return -EINVAL;
5666 }
5667
5668 for (i = 0; i < ELEMENTSOF(table); i++)
5669 if (table[i].from == argv[optind][0])
5670 break;
5671
5672 if (i >= ELEMENTSOF(table)) {
b0193f1c 5673 log_error("Unknown command '%s'.", argv[optind]);
e4b61340
LP
5674 return -EINVAL;
5675 }
5676
5677 arg_action = table[i].to;
5678
5679 optind ++;
5680
5681 return 1;
5682}
5683
5684static int runlevel_parse_argv(int argc, char *argv[]) {
5685
5686 enum {
5687 ARG_HELP = 0x100,
5688 };
5689
5690 static const struct option options[] = {
5691 { "help", no_argument, NULL, ARG_HELP },
eb9da376 5692 {}
e4b61340
LP
5693 };
5694
5695 int c;
5696
5697 assert(argc >= 0);
5698 assert(argv);
5699
5700 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5701 switch (c) {
5702
5703 case ARG_HELP:
eb9da376 5704 return runlevel_help();
e4b61340
LP
5705 return 0;
5706
5707 case '?':
5708 return -EINVAL;
5709
5710 default:
eb9da376 5711 assert_not_reached("Unhandled option");
e4b61340
LP
5712 }
5713 }
5714
5715 if (optind < argc) {
5716 log_error("Too many arguments.");
5717 return -EINVAL;
5718 }
5719
5720 return 1;
5721}
5722
5723static int parse_argv(int argc, char *argv[]) {
5724 assert(argc >= 0);
5725 assert(argv);
5726
5727 if (program_invocation_short_name) {
5728
5729 if (strstr(program_invocation_short_name, "halt")) {
5730 arg_action = ACTION_HALT;
5731 return halt_parse_argv(argc, argv);
5732 } else if (strstr(program_invocation_short_name, "poweroff")) {
5733 arg_action = ACTION_POWEROFF;
5734 return halt_parse_argv(argc, argv);
5735 } else if (strstr(program_invocation_short_name, "reboot")) {
5622dde3
KS
5736 if (kexec_loaded())
5737 arg_action = ACTION_KEXEC;
5738 else
5739 arg_action = ACTION_REBOOT;
e4b61340
LP
5740 return halt_parse_argv(argc, argv);
5741 } else if (strstr(program_invocation_short_name, "shutdown")) {
5742 arg_action = ACTION_POWEROFF;
5743 return shutdown_parse_argv(argc, argv);
5744 } else if (strstr(program_invocation_short_name, "init")) {
d5ca5f11
LP
5745
5746 if (sd_booted() > 0) {
f459b602 5747 arg_action = _ACTION_INVALID;
d5ca5f11
LP
5748 return telinit_parse_argv(argc, argv);
5749 } else {
5750 /* Hmm, so some other init system is
5751 * running, we need to forward this
5752 * request to it. For now we simply
5753 * guess that it is Upstart. */
5754
4ad61fd1 5755 execv(TELINIT, argv);
d5ca5f11
LP
5756
5757 log_error("Couldn't find an alternative telinit implementation to spawn.");
5758 return -EIO;
5759 }
5760
e4b61340
LP
5761 } else if (strstr(program_invocation_short_name, "runlevel")) {
5762 arg_action = ACTION_RUNLEVEL;
5763 return runlevel_parse_argv(argc, argv);
5764 }
5765 }
5766
5767 arg_action = ACTION_SYSTEMCTL;
5768 return systemctl_parse_argv(argc, argv);
5769}
5770
44a6b1b6 5771_pure_ static int action_to_runlevel(void) {
eb22ac37
LP
5772
5773 static const char table[_ACTION_MAX] = {
5774 [ACTION_HALT] = '0',
5775 [ACTION_POWEROFF] = '0',
5776 [ACTION_REBOOT] = '6',
5777 [ACTION_RUNLEVEL2] = '2',
5778 [ACTION_RUNLEVEL3] = '3',
5779 [ACTION_RUNLEVEL4] = '4',
5780 [ACTION_RUNLEVEL5] = '5',
5781 [ACTION_RESCUE] = '1'
5782 };
5783
d55ae9e6
LP
5784 assert(arg_action < _ACTION_MAX);
5785
5786 return table[arg_action];
5787}
5788
d55ae9e6 5789static int talk_initctl(void) {
cbc9fbd1
LP
5790
5791 struct init_request request = {
5792 .magic = INIT_MAGIC,
5793 .sleeptime = 0,
5794 .cmd = INIT_CMD_RUNLVL
5795 };
5796
7fd1b19b 5797 _cleanup_close_ int fd = -1;
d55ae9e6 5798 char rl;
cbc9fbd1 5799 int r;
eb22ac37 5800
427b47c4
ZJS
5801 rl = action_to_runlevel();
5802 if (!rl)
eb22ac37
LP
5803 return 0;
5804
d55ae9e6
LP
5805 request.runlevel = rl;
5806
427b47c4
ZJS
5807 fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
5808 if (fd < 0) {
d55ae9e6
LP
5809 if (errno == ENOENT)
5810 return 0;
eb22ac37 5811
d55ae9e6 5812 log_error("Failed to open "INIT_FIFO": %m");
eb22ac37 5813 return -errno;
d55ae9e6 5814 }
eb22ac37 5815
d55ae9e6 5816 errno = 0;
eb22ac37 5817 r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
427b47c4 5818 if (r) {
d55ae9e6 5819 log_error("Failed to write to "INIT_FIFO": %m");
bcb161b0 5820 return errno > 0 ? -errno : -EIO;
d55ae9e6 5821 }
eb22ac37
LP
5822
5823 return 1;
e4b61340
LP
5824}
5825
41dd15e4 5826static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
7e4249b9 5827
7e4249b9
LP
5828 static const struct {
5829 const char* verb;
5830 const enum {
5831 MORE,
5832 LESS,
5833 EQUAL
5834 } argc_cmp;
5835 const int argc;
f459b602 5836 int (* const dispatch)(sd_bus *bus, char **args);
d08e75ed
ZJS
5837 const enum {
5838 NOBUS = 1,
5839 FORCE,
5840 } bus;
7e4249b9 5841 } verbs[] = {
d8fba7c6 5842 { "list-units", MORE, 0, list_units },
d08e75ed 5843 { "list-unit-files", MORE, 1, list_unit_files, NOBUS },
d8fba7c6
ZJS
5844 { "list-sockets", MORE, 1, list_sockets },
5845 { "list-timers", MORE, 1, list_timers },
5846 { "list-jobs", MORE, 1, list_jobs },
ee5762e3 5847 { "clear-jobs", EQUAL, 1, daemon_reload },
ee5762e3
LP
5848 { "cancel", MORE, 2, cancel_job },
5849 { "start", MORE, 2, start_unit },
5850 { "stop", MORE, 2, start_unit },
a76f7be2 5851 { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
5852 { "reload", MORE, 2, start_unit },
5853 { "restart", MORE, 2, start_unit },
5854 { "try-restart", MORE, 2, start_unit },
5855 { "reload-or-restart", MORE, 2, start_unit },
5856 { "reload-or-try-restart", MORE, 2, start_unit },
5857 { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */
64e5f1b7 5858 { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
5859 { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
5860 { "isolate", EQUAL, 2, start_unit },
8a0867d6 5861 { "kill", MORE, 2, kill_unit },
1a0fce45
TA
5862 { "is-active", MORE, 2, check_unit_active },
5863 { "check", MORE, 2, check_unit_active },
5864 { "is-failed", MORE, 2, check_unit_failed },
ee5762e3 5865 { "show", MORE, 1, show },
e93c33d4 5866 { "cat", MORE, 2, cat },
265a7a2a 5867 { "status", MORE, 1, show },
b43f208f 5868 { "help", MORE, 2, show },
ee5762e3
LP
5869 { "snapshot", LESS, 2, snapshot },
5870 { "delete", MORE, 2, delete_snapshot },
5871 { "daemon-reload", EQUAL, 1, daemon_reload },
5872 { "daemon-reexec", EQUAL, 1, daemon_reload },
f459b602 5873 { "show-environment", EQUAL, 1, show_environment },
ee5762e3
LP
5874 { "set-environment", MORE, 2, set_environment },
5875 { "unset-environment", MORE, 2, set_environment },
d08e75ed
ZJS
5876 { "halt", EQUAL, 1, start_special, FORCE },
5877 { "poweroff", EQUAL, 1, start_special, FORCE },
5878 { "reboot", EQUAL, 1, start_special, FORCE },
20b09ca7 5879 { "kexec", EQUAL, 1, start_special },
6edd7d0a
LP
5880 { "suspend", EQUAL, 1, start_special },
5881 { "hibernate", EQUAL, 1, start_special },
6524990f 5882 { "hybrid-sleep", EQUAL, 1, start_special },
ee5762e3
LP
5883 { "default", EQUAL, 1, start_special },
5884 { "rescue", EQUAL, 1, start_special },
5885 { "emergency", EQUAL, 1, start_special },
20b09ca7 5886 { "exit", EQUAL, 1, start_special },
fdf20a31 5887 { "reset-failed", MORE, 1, reset_failed },
d08e75ed
ZJS
5888 { "enable", MORE, 2, enable_unit, NOBUS },
5889 { "disable", MORE, 2, enable_unit, NOBUS },
5890 { "is-enabled", MORE, 2, unit_is_enabled, NOBUS },
5891 { "reenable", MORE, 2, enable_unit, NOBUS },
5892 { "preset", MORE, 2, enable_unit, NOBUS },
5893 { "mask", MORE, 2, enable_unit, NOBUS },
5894 { "unmask", MORE, 2, enable_unit, NOBUS },
5895 { "link", MORE, 2, enable_unit, NOBUS },
957eb8ca 5896 { "switch-root", MORE, 2, switch_root },
e31165b2 5897 { "list-dependencies", LESS, 2, list_dependencies },
d08e75ed
ZJS
5898 { "set-default", EQUAL, 2, set_default, NOBUS },
5899 { "get-default", EQUAL, 1, get_default, NOBUS },
8e2af478 5900 { "set-property", MORE, 3, set_property },
d08e75ed
ZJS
5901 {}
5902 }, *verb = verbs;
7e4249b9 5903
e4b61340 5904 int left;
7e4249b9 5905
e4b61340
LP
5906 assert(argc >= 0);
5907 assert(argv);
7e4249b9
LP
5908
5909 left = argc - optind;
5910
d08e75ed
ZJS
5911 /* Special rule: no arguments (left == 0) means "list-units" */
5912 if (left > 0) {
b43f208f
KS
5913 if (streq(argv[optind], "help") && !argv[optind+1]) {
5914 log_error("This command expects one or more "
5915 "unit names. Did you mean --help?");
5916 return -EINVAL;
0183528f
LP
5917 }
5918
d08e75ed
ZJS
5919 for (; verb->verb; verb++)
5920 if (streq(argv[optind], verb->verb))
5921 goto found;
7e4249b9 5922
d08e75ed
ZJS
5923 log_error("Unknown operation '%s'.", argv[optind]);
5924 return -EINVAL;
7e4249b9 5925 }
d08e75ed 5926found:
7e4249b9 5927
d08e75ed 5928 switch (verb->argc_cmp) {
7e4249b9
LP
5929
5930 case EQUAL:
d08e75ed 5931 if (left != verb->argc) {
7e4249b9 5932 log_error("Invalid number of arguments.");
e4b61340 5933 return -EINVAL;
7e4249b9
LP
5934 }
5935
5936 break;
5937
5938 case MORE:
d08e75ed 5939 if (left < verb->argc) {
7e4249b9 5940 log_error("Too few arguments.");
e4b61340 5941 return -EINVAL;
7e4249b9
LP
5942 }
5943
5944 break;
5945
5946 case LESS:
d08e75ed 5947 if (left > verb->argc) {
7e4249b9 5948 log_error("Too many arguments.");
e4b61340 5949 return -EINVAL;
7e4249b9
LP
5950 }
5951
5952 break;
5953
5954 default:
5955 assert_not_reached("Unknown comparison operator.");
5956 }
5957
ee5762e3
LP
5958 /* Require a bus connection for all operations but
5959 * enable/disable */
d08e75ed
ZJS
5960 if (verb->bus == NOBUS) {
5961 if (!bus && !avoid_bus()) {
5962 log_error("Failed to get D-Bus connection: %s", strerror(-bus_error));
5963 return -EIO;
5964 }
82e23ddd 5965
d08e75ed 5966 } else {
82e23ddd
LP
5967 if (running_in_chroot() > 0) {
5968 log_info("Running in chroot, ignoring request.");
5969 return 0;
5970 }
5971
d08e75ed
ZJS
5972 if ((verb->bus != FORCE || arg_force <= 0) && !bus) {
5973 log_error("Failed to get D-Bus connection: %s", strerror(-bus_error));
82e23ddd
LP
5974 return -EIO;
5975 }
ee5762e3
LP
5976 }
5977
d08e75ed 5978 return verb->dispatch(bus, argv + optind);
e4b61340
LP
5979}
5980
52c00215 5981static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
cbc9fbd1 5982
b92bea5d
ZJS
5983 struct sd_shutdown_command c = {
5984 .usec = t,
5985 .mode = mode,
5986 .dry_run = dry_run,
5987 .warn_wall = warn,
5988 };
cbc9fbd1 5989
b92bea5d
ZJS
5990 union sockaddr_union sockaddr = {
5991 .un.sun_family = AF_UNIX,
5992 .un.sun_path = "/run/systemd/shutdownd",
5993 };
cbc9fbd1
LP
5994
5995 struct iovec iovec[2] = {{
5996 .iov_base = (char*) &c,
b92bea5d 5997 .iov_len = offsetof(struct sd_shutdown_command, wall_message),
cbc9fbd1
LP
5998 }};
5999
b92bea5d
ZJS
6000 struct msghdr msghdr = {
6001 .msg_name = &sockaddr,
6002 .msg_namelen = offsetof(struct sockaddr_un, sun_path)
6003 + sizeof("/run/systemd/shutdownd") - 1,
6004 .msg_iov = iovec,
6005 .msg_iovlen = 1,
6006 };
04ebb595 6007
cbc9fbd1
LP
6008 _cleanup_close_ int fd;
6009
04ebb595
LP
6010 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
6011 if (fd < 0)
6012 return -errno;
f6144808 6013
b92bea5d 6014 if (!isempty(message)) {
04ebb595
LP
6015 iovec[1].iov_base = (char*) message;
6016 iovec[1].iov_len = strlen(message);
b92bea5d 6017 msghdr.msg_iovlen++;
04ebb595 6018 }
f6144808 6019
cec7eda5 6020 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
f6144808 6021 return -errno;
f6144808 6022
f6144808
LP
6023 return 0;
6024}
6025
f459b602 6026static int reload_with_fallback(sd_bus *bus) {
e4b61340
LP
6027
6028 if (bus) {
6029 /* First, try systemd via D-Bus. */
d76702a7 6030 if (daemon_reload(bus, NULL) >= 0)
e4b61340
LP
6031 return 0;
6032 }
6033
6034 /* Nothing else worked, so let's try signals */
6035 assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
6036
6037 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
6038 log_error("kill() failed: %m");
6039 return -errno;
6040 }
6041
6042 return 0;
6043}
6044
f459b602 6045static int start_with_fallback(sd_bus *bus) {
e4b61340
LP
6046
6047 if (bus) {
6048 /* First, try systemd via D-Bus. */
729e3769 6049 if (start_unit(bus, NULL) >= 0)
983d9c90 6050 goto done;
e4b61340
LP
6051 }
6052
6053 /* Nothing else worked, so let's try
6054 * /dev/initctl */
fbc43921 6055 if (talk_initctl() > 0)
983d9c90 6056 goto done;
d55ae9e6
LP
6057
6058 log_error("Failed to talk to init daemon.");
6059 return -EIO;
983d9c90
LP
6060
6061done:
6062 warn_wall(arg_action);
6063 return 0;
e4b61340
LP
6064}
6065
477def80 6066static int halt_now(enum action a) {
e606bb61 6067
477def80 6068/* Make sure C-A-D is handled by the kernel from this
e606bb61
LP
6069 * point on... */
6070 reboot(RB_ENABLE_CAD);
6071
4c80c73c 6072 switch (a) {
e606bb61
LP
6073
6074 case ACTION_HALT:
6075 log_info("Halting.");
6076 reboot(RB_HALT_SYSTEM);
477def80 6077 return -errno;
e606bb61
LP
6078
6079 case ACTION_POWEROFF:
6080 log_info("Powering off.");
6081 reboot(RB_POWER_OFF);
477def80 6082 return -errno;
e606bb61 6083
477def80
LP
6084 case ACTION_REBOOT: {
6085 _cleanup_free_ char *param = NULL;
cbc9fbd1 6086
477def80
LP
6087 if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
6088 log_info("Rebooting with argument '%s'.", param);
37185ec8
WC
6089 syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
6090 LINUX_REBOOT_CMD_RESTART2, param);
37185ec8 6091 }
e606bb61 6092
477def80
LP
6093 log_info("Rebooting.");
6094 reboot(RB_AUTOBOOT);
6095 return -errno;
e606bb61
LP
6096 }
6097
477def80
LP
6098 default:
6099 assert_not_reached("Unknown action.");
6100 }
e606bb61
LP
6101}
6102
f459b602 6103static int halt_main(sd_bus *bus) {
e4b61340
LP
6104 int r;
6105
748ebafa
LP
6106 r = check_inhibitors(bus, arg_action);
6107 if (r < 0)
6108 return r;
b37844d3 6109
bc8c2f5c 6110 if (geteuid() != 0) {
7e59bfcb
LP
6111 /* Try logind if we are a normal user and no special
6112 * mode applies. Maybe PolicyKit allows us to shutdown
6113 * the machine. */
6114
6115 if (arg_when <= 0 &&
6116 !arg_dry &&
b37844d3 6117 arg_force <= 0 &&
7e59bfcb
LP
6118 (arg_action == ACTION_POWEROFF ||
6119 arg_action == ACTION_REBOOT)) {
4c80c73c
KS
6120 r = reboot_with_logind(bus, arg_action);
6121 if (r >= 0)
6122 return r;
6123 }
6124
cc8a7a61 6125 log_error("Must be root.");
bc8c2f5c
LP
6126 return -EPERM;
6127 }
6128
f6144808 6129 if (arg_when > 0) {
7fd1b19b 6130 _cleanup_free_ char *m;
9be9828c
LP
6131
6132 m = strv_join(arg_wall, " ");
cbc9fbd1
LP
6133 if (!m)
6134 return log_oom();
6135
9be9828c
LP
6136 r = send_shutdownd(arg_when,
6137 arg_action == ACTION_HALT ? 'H' :
6138 arg_action == ACTION_POWEROFF ? 'P' :
04ebb595 6139 arg_action == ACTION_KEXEC ? 'K' :
9be9828c 6140 'r',
52c00215 6141 arg_dry,
9be9828c
LP
6142 !arg_no_wall,
6143 m);
9be9828c
LP
6144
6145 if (r < 0)
f6144808 6146 log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
08e4b1c5 6147 else {
7e59bfcb
LP
6148 char date[FORMAT_TIMESTAMP_MAX];
6149
08e4b1c5
LP
6150 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
6151 format_timestamp(date, sizeof(date), arg_when));
f6144808 6152 return 0;
08e4b1c5 6153 }
f6144808
LP
6154 }
6155
65491fd8 6156 if (!arg_dry && !arg_force)
e4b61340
LP
6157 return start_with_fallback(bus);
6158
d90e1a30
LP
6159 if (!arg_no_wtmp) {
6160 if (sd_booted() > 0)
6161 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
7e59bfcb
LP
6162 else {
6163 r = utmp_put_shutdown();
6164 if (r < 0)
6165 log_warning("Failed to write utmp record: %s", strerror(-r));
6166 }
d90e1a30 6167 }
e4b61340 6168
e4b61340
LP
6169 if (arg_dry)
6170 return 0;
6171
477def80
LP
6172 r = halt_now(arg_action);
6173 log_error("Failed to reboot: %s", strerror(-r));
6174
6175 return r;
e4b61340
LP
6176}
6177
6178static int runlevel_main(void) {
6179 int r, runlevel, previous;
6180
729e3769
LP
6181 r = utmp_get_runlevel(&runlevel, &previous);
6182 if (r < 0) {
6183 puts("unknown");
e4b61340
LP
6184 return r;
6185 }
6186
6187 printf("%c %c\n",
6188 previous <= 0 ? 'N' : previous,
6189 runlevel <= 0 ? 'N' : runlevel);
6190
6191 return 0;
6192}
6193
6194int main(int argc, char*argv[]) {
f459b602
MAP
6195 _cleanup_bus_unref_ sd_bus *bus = NULL;
6196 int r;
e4b61340 6197
a9cdc94f 6198 setlocale(LC_ALL, "");
e4b61340 6199 log_parse_environment();
2396fb04 6200 log_open();
e4b61340 6201
184ecaf7
DR
6202 /* Explicitly not on_tty() to avoid setting cached value.
6203 * This becomes relevant for piping output which might be
6204 * ellipsized. */
6205 original_stdout_is_tty = isatty(STDOUT_FILENO);
6206
04ebb595 6207 r = parse_argv(argc, argv);
f459b602 6208 if (r <= 0)
e4b61340 6209 goto finish;
7e4249b9 6210
e4b61340
LP
6211 /* /sbin/runlevel doesn't need to communicate via D-Bus, so
6212 * let's shortcut this */
6213 if (arg_action == ACTION_RUNLEVEL) {
22f4096c 6214 r = runlevel_main();
e4b61340
LP
6215 goto finish;
6216 }
6217
82e23ddd
LP
6218 if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
6219 log_info("Running in chroot, ignoring request.");
f459b602 6220 r = 0;
82e23ddd
LP
6221 goto finish;
6222 }
6223
41dd15e4
LP
6224 if (!avoid_bus())
6225 r = bus_open_transport_systemd(arg_transport, arg_host, arg_scope != UNIT_FILE_SYSTEM, &bus);
6226
6227 /* systemctl_main() will print an error message for the bus
6228 * connection, but only if it needs to */
e4b61340
LP
6229
6230 switch (arg_action) {
6231
22f4096c 6232 case ACTION_SYSTEMCTL:
f459b602 6233 r = systemctl_main(bus, argc, argv, r);
e4b61340 6234 break;
e4b61340
LP
6235
6236 case ACTION_HALT:
6237 case ACTION_POWEROFF:
6238 case ACTION_REBOOT:
5622dde3 6239 case ACTION_KEXEC:
22f4096c 6240 r = halt_main(bus);
e4b61340
LP
6241 break;
6242
e4b61340
LP
6243 case ACTION_RUNLEVEL2:
6244 case ACTION_RUNLEVEL3:
6245 case ACTION_RUNLEVEL4:
6246 case ACTION_RUNLEVEL5:
6247 case ACTION_RESCUE:
514f4ef5 6248 case ACTION_EMERGENCY:
eb22ac37 6249 case ACTION_DEFAULT:
22f4096c 6250 r = start_with_fallback(bus);
e4b61340 6251 break;
7e4249b9 6252
e4b61340
LP
6253 case ACTION_RELOAD:
6254 case ACTION_REEXEC:
22f4096c 6255 r = reload_with_fallback(bus);
e4b61340
LP
6256 break;
6257
dfcc5c33 6258 case ACTION_CANCEL_SHUTDOWN: {
f459b602 6259 _cleanup_free_ char *m = NULL;
dfcc5c33
MS
6260
6261 if (arg_wall) {
6262 m = strv_join(arg_wall, " ");
6263 if (!m) {
f459b602 6264 r = log_oom();
dfcc5c33
MS
6265 goto finish;
6266 }
6267 }
f459b602 6268
dfcc5c33
MS
6269 r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
6270 if (r < 0)
6271 log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
f6144808 6272 break;
dfcc5c33 6273 }
f6144808 6274
eb22ac37 6275 case ACTION_RUNLEVEL:
f459b602 6276 case _ACTION_INVALID:
e4b61340
LP
6277 default:
6278 assert_not_reached("Unknown action");
6279 }
7e4249b9
LP
6280
6281finish:
f459b602
MAP
6282 pager_close();
6283 ask_password_agent_close();
6284 polkit_agent_close();
7e4249b9 6285
20b3f379 6286 strv_free(arg_types);
9b9b3d36 6287 strv_free(arg_states);
20b3f379 6288 strv_free(arg_properties);
ea4a240d 6289
f459b602 6290 return r < 0 ? EXIT_FAILURE : r;
7e4249b9 6291}