]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl.c
systemctl: simplify start_unit
[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;
b6520546 2149 const char *method, *mode;
729e3769 2150 char **name;
b6520546
ZJS
2151 int r = 0;
2152 char **names, *strv[] = {NULL, NULL}; /* at most one name */
e4b61340 2153
514f4ef5
LP
2154 assert(bus);
2155
6bb92a16 2156 ask_password_agent_open_if_enabled();
501fc174 2157
e4b61340 2158 if (arg_action == ACTION_SYSTEMCTL) {
47a0eaa6 2159 enum action action;
e4b61340 2160 method =
a76f7be2
LP
2161 streq(args[0], "stop") ||
2162 streq(args[0], "condstop") ? "StopUnit" :
6f28c033
LP
2163 streq(args[0], "reload") ? "ReloadUnit" :
2164 streq(args[0], "restart") ? "RestartUnit" :
d68201e9 2165
aa5939a3
MS
2166 streq(args[0], "try-restart") ||
2167 streq(args[0], "condrestart") ? "TryRestartUnit" :
d68201e9 2168
6f28c033 2169 streq(args[0], "reload-or-restart") ? "ReloadOrRestartUnit" :
d68201e9 2170
9d8a57ff 2171 streq(args[0], "reload-or-try-restart") ||
cbc9fbd1 2172 streq(args[0], "condreload") ||
aa5939a3 2173 streq(args[0], "force-reload") ? "ReloadOrTryRestartUnit" :
6f28c033 2174 "StartUnit";
47a0eaa6 2175 action = verb_to_action(args[0]);
e4b61340 2176
47a0eaa6
MS
2177 mode = streq(args[0], "isolate") ? "isolate" :
2178 action_table[action].mode ?: arg_job_mode;
e4b61340 2179
b6520546 2180 strv[0] = (char*) action_table[action].target;
e4b61340 2181 } else {
47a0eaa6
MS
2182 assert(arg_action < ELEMENTSOF(action_table));
2183 assert(action_table[arg_action].target);
e4b61340
LP
2184
2185 method = "StartUnit";
514f4ef5 2186
47a0eaa6 2187 mode = action_table[arg_action].mode;
b6520546 2188 strv[0] = (char*) action_table[arg_action].target;
514f4ef5
LP
2189 }
2190
b6520546
ZJS
2191 if (strv[0])
2192 names = strv;
2193 else
2194 names = args + 1;
2195
6e905d93 2196 if (!arg_no_block) {
f459b602
MAP
2197 r = enable_wait_for_jobs(bus);
2198 if (r < 0) {
2199 log_error("Could not watch jobs: %s", strerror(-r));
2200 return r;
514f4ef5
LP
2201 }
2202
67f3c402 2203 s = set_new(string_hash_func, string_compare_func);
cec7eda5
ZJS
2204 if (!s)
2205 return log_oom();
e4b61340
LP
2206 }
2207
b6520546
ZJS
2208 STRV_FOREACH(name, names) {
2209 int q;
f459b602 2210
b6520546
ZJS
2211 q = start_unit_one(bus, method, *name, mode, &error, s);
2212 if (r == 0 && q < 0) {
2213 r = translate_bus_error_to_exit_status(q, &error);
2214 sd_bus_error_free(&error);
67f3c402 2215 }
e4b61340
LP
2216 }
2217
67f3c402 2218 if (!arg_no_block) {
f459b602
MAP
2219 int q;
2220
2221 q = wait_for_jobs(bus, s);
2222 if (q < 0)
2223 return q;
49111a70
ZJS
2224
2225 /* When stopping units, warn if they can still be triggered by
2226 * another active unit (socket, path, timer) */
b6520546
ZJS
2227 if (!arg_quiet && streq(method, "StopUnit"))
2228 STRV_FOREACH(name, names)
2229 check_triggering_units(bus, *name);
67f3c402 2230 }
514f4ef5 2231
f459b602 2232 return r;
e4b61340
LP
2233}
2234
7e59bfcb
LP
2235/* Ask systemd-logind, which might grant access to unprivileged users
2236 * through PolicyKit */
f459b602 2237static int reboot_with_logind(sd_bus *bus, enum action a) {
4c80c73c 2238#ifdef HAVE_LOGIND
f459b602 2239 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4c80c73c 2240 const char *method;
f459b602 2241 int r;
4c80c73c 2242
d255133d
LP
2243 if (!bus)
2244 return -EIO;
2245
6bb92a16
LP
2246 polkit_agent_open_if_enabled();
2247
4c80c73c
KS
2248 switch (a) {
2249
2250 case ACTION_REBOOT:
2251 method = "Reboot";
2252 break;
2253
2254 case ACTION_POWEROFF:
2255 method = "PowerOff";
2256 break;
2257
d889a206
LP
2258 case ACTION_SUSPEND:
2259 method = "Suspend";
2260 break;
2261
2262 case ACTION_HIBERNATE:
2263 method = "Hibernate";
2264 break;
2265
6524990f
LP
2266 case ACTION_HYBRID_SLEEP:
2267 method = "HybridSleep";
2268 break;
2269
4c80c73c
KS
2270 default:
2271 return -EINVAL;
2272 }
2273
f459b602 2274 r = sd_bus_call_method(
f22f08cd
SP
2275 bus,
2276 "org.freedesktop.login1",
2277 "/org/freedesktop/login1",
2278 "org.freedesktop.login1.Manager",
2279 method,
f459b602 2280 &error,
f22f08cd 2281 NULL,
f459b602
MAP
2282 "b", true);
2283 if (r < 0)
2284 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
2285
2286 return r;
4c80c73c
KS
2287#else
2288 return -ENOSYS;
2289#endif
2290}
2291
f459b602 2292static int check_inhibitors(sd_bus *bus, enum action a) {
b37844d3 2293#ifdef HAVE_LOGIND
f459b602 2294 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
59164be4 2295 _cleanup_strv_free_ char **sessions = NULL;
f459b602
MAP
2296 const char *what, *who, *why, *mode;
2297 uint32_t uid, pid;
2298 unsigned c = 0;
59164be4 2299 char **s;
f459b602 2300 int r;
b37844d3 2301
748ebafa
LP
2302 if (!bus)
2303 return 0;
2304
2305 if (arg_ignore_inhibitors || arg_force > 0)
2306 return 0;
2307
2308 if (arg_when > 0)
2309 return 0;
2310
2311 if (geteuid() == 0)
b37844d3
LP
2312 return 0;
2313
2314 if (!on_tty())
2315 return 0;
2316
f459b602 2317 r = sd_bus_call_method(
b37844d3
LP
2318 bus,
2319 "org.freedesktop.login1",
2320 "/org/freedesktop/login1",
2321 "org.freedesktop.login1.Manager",
2322 "ListInhibitors",
b37844d3 2323 NULL,
f459b602
MAP
2324 &reply,
2325 NULL);
b37844d3
LP
2326 if (r < 0)
2327 /* If logind is not around, then there are no inhibitors... */
2328 return 0;
2329
4aa2beac 2330 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
f459b602
MAP
2331 if (r < 0)
2332 return bus_log_parse_error(r);
b37844d3 2333
4aa2beac 2334 while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
59164be4 2335 _cleanup_free_ char *comm = NULL, *user = NULL;
f459b602 2336 _cleanup_strv_free_ char **sv = NULL;
b37844d3
LP
2337
2338 if (!streq(mode, "block"))
f459b602 2339 continue;
b37844d3
LP
2340
2341 sv = strv_split(what, ":");
2342 if (!sv)
2343 return log_oom();
2344
2345 if (!strv_contains(sv,
2346 a == ACTION_HALT ||
2347 a == ACTION_POWEROFF ||
2348 a == ACTION_REBOOT ||
2349 a == ACTION_KEXEC ? "shutdown" : "sleep"))
f459b602 2350 continue;
b37844d3
LP
2351
2352 get_process_comm(pid, &comm);
59164be4 2353 user = uid_to_name(uid);
f459b602 2354
59164be4
LP
2355 log_warning("Operation inhibited by \"%s\" (PID %lu \"%s\", user %s), reason is \"%s\".",
2356 who, (unsigned long) pid, strna(comm), strna(user), why);
b37844d3 2357
f459b602 2358 c++;
b37844d3 2359 }
f459b602
MAP
2360 if (r < 0)
2361 return bus_log_parse_error(r);
b37844d3 2362
f459b602
MAP
2363 r = sd_bus_message_exit_container(reply);
2364 if (r < 0)
2365 return bus_log_parse_error(r);
b37844d3 2366
59164be4
LP
2367 /* Check for current sessions */
2368 sd_get_sessions(&sessions);
2369 STRV_FOREACH(s, sessions) {
59164be4
LP
2370 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
2371
2372 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
2373 continue;
2374
2375 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
2376 continue;
2377
2378 if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
2379 continue;
2380
2381 sd_session_get_tty(*s, &tty);
2382 sd_session_get_seat(*s, &seat);
2383 sd_session_get_service(*s, &service);
2384 user = uid_to_name(uid);
2385
2386 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
2387 c++;
2388 }
2389
b37844d3
LP
2390 if (c <= 0)
2391 return 0;
2392
59164be4 2393 log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
47a0eaa6 2394 action_table[a].verb);
b37844d3
LP
2395
2396 return -EPERM;
2397#else
2398 return 0;
2399#endif
2400}
2401
f459b602 2402static int start_special(sd_bus *bus, char **args) {
4c80c73c 2403 enum action a;
983d9c90
LP
2404 int r;
2405
514f4ef5
LP
2406 assert(args);
2407
4c80c73c
KS
2408 a = verb_to_action(args[0]);
2409
748ebafa
LP
2410 r = check_inhibitors(bus, a);
2411 if (r < 0)
2412 return r;
2413
c32b90de
LP
2414 if (arg_force >= 2 && geteuid() != 0) {
2415 log_error("Must be root.");
2416 return -EPERM;
2417 }
2418
7e59bfcb
LP
2419 if (arg_force >= 2 &&
2420 (a == ACTION_HALT ||
2421 a == ACTION_POWEROFF ||
2422 a == ACTION_REBOOT))
477def80 2423 return halt_now(a);
e606bb61 2424
7e59bfcb 2425 if (arg_force >= 1 &&
4c80c73c
KS
2426 (a == ACTION_HALT ||
2427 a == ACTION_POWEROFF ||
2428 a == ACTION_REBOOT ||
2429 a == ACTION_KEXEC ||
2430 a == ACTION_EXIT))
729e3769 2431 return daemon_reload(bus, args);
20b09ca7 2432
7e59bfcb
LP
2433 /* first try logind, to allow authentication with polkit */
2434 if (geteuid() != 0 &&
2435 (a == ACTION_POWEROFF ||
d889a206
LP
2436 a == ACTION_REBOOT ||
2437 a == ACTION_SUSPEND ||
6524990f
LP
2438 a == ACTION_HIBERNATE ||
2439 a == ACTION_HYBRID_SLEEP)) {
7e59bfcb
LP
2440 r = reboot_with_logind(bus, a);
2441 if (r >= 0)
2442 return r;
4c80c73c 2443 }
983d9c90 2444
4c80c73c 2445 r = start_unit(bus, args);
f6bb13ab 2446 if (r == EXIT_SUCCESS)
4c80c73c 2447 warn_wall(a);
514f4ef5 2448
983d9c90 2449 return r;
514f4ef5
LP
2450}
2451
f459b602 2452static int check_unit_active(sd_bus *bus, char **args) {
729e3769 2453 char **name;
31be1221 2454 int r = 3; /* According to LSB: "program is not running" */
0183528f
LP
2455
2456 assert(bus);
2457 assert(args);
2458
729e3769 2459 STRV_FOREACH(name, args+1) {
60f9ba0b
LP
2460 int state;
2461
f459b602 2462 state = check_one_unit(bus, *name, "active\0reloading\0", arg_quiet);
1a0fce45
TA
2463 if (state < 0)
2464 return state;
60f9ba0b 2465 if (state > 0)
1a0fce45
TA
2466 r = 0;
2467 }
2468
2469 return r;
2470}
2471
f459b602 2472static int check_unit_failed(sd_bus *bus, char **args) {
1a0fce45
TA
2473 char **name;
2474 int r = 1;
2475
2476 assert(bus);
2477 assert(args);
2478
2479 STRV_FOREACH(name, args+1) {
60f9ba0b
LP
2480 int state;
2481
f459b602 2482 state = check_one_unit(bus, *name, "failed\0", arg_quiet);
31be1221
MS
2483 if (state < 0)
2484 return state;
60f9ba0b 2485 if (state > 0)
0183528f 2486 r = 0;
0183528f
LP
2487 }
2488
0183528f 2489 return r;
48220598
LP
2490}
2491
f459b602
MAP
2492static int kill_unit(sd_bus *bus, char **args) {
2493 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
60f9ba0b 2494 char **name;
8a0867d6 2495 int r = 0;
8a0867d6 2496
60f9ba0b 2497 assert(bus);
8a0867d6
LP
2498 assert(args);
2499
8a0867d6
LP
2500 if (!arg_kill_who)
2501 arg_kill_who = "all";
2502
729e3769 2503 STRV_FOREACH(name, args+1) {
60f9ba0b
LP
2504 _cleanup_free_ char *n = NULL;
2505
f22f08cd 2506 n = unit_name_mangle(*name);
f84190d8
LP
2507 if (!n)
2508 return log_oom();
60f9ba0b 2509
f459b602 2510 r = sd_bus_call_method(
f22f08cd 2511 bus,
b0193f1c
LP
2512 "org.freedesktop.systemd1",
2513 "/org/freedesktop/systemd1",
2514 "org.freedesktop.systemd1.Manager",
f22f08cd 2515 "KillUnit",
f459b602 2516 &error,
f22f08cd 2517 NULL,
f459b602
MAP
2518 "ssi", n, arg_kill_who, arg_signal);
2519 if (r < 0) {
2520 log_error("Failed to kill unit %s: %s", n, bus_error_message(&error, r));
f22f08cd 2521 return r;
f459b602 2522 }
8a0867d6 2523 }
f459b602 2524
f22f08cd 2525 return 0;
8a0867d6
LP
2526}
2527
582a507f 2528typedef struct ExecStatusInfo {
0129173a
LP
2529 char *name;
2530
582a507f
LP
2531 char *path;
2532 char **argv;
2533
b708e7ce
LP
2534 bool ignore;
2535
582a507f
LP
2536 usec_t start_timestamp;
2537 usec_t exit_timestamp;
2538 pid_t pid;
2539 int code;
2540 int status;
2541
2542 LIST_FIELDS(struct ExecStatusInfo, exec);
2543} ExecStatusInfo;
2544
2545static void exec_status_info_free(ExecStatusInfo *i) {
2546 assert(i);
2547
0129173a 2548 free(i->name);
582a507f
LP
2549 free(i->path);
2550 strv_free(i->argv);
2551 free(i);
2552}
2553
f459b602 2554static int exec_status_info_deserialize(sd_bus_message *m, ExecStatusInfo *i) {
b21a0ef8 2555 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
f459b602 2556 const char *path;
582a507f
LP
2557 uint32_t pid;
2558 int32_t code, status;
f459b602 2559 int ignore, r;
582a507f 2560
f459b602 2561 assert(m);
582a507f 2562 assert(i);
582a507f 2563
f459b602
MAP
2564 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, "sasbttttuii");
2565 if (r < 0)
2566 return bus_log_parse_error(r);
2567 else if (r == 0)
2568 return 0;
582a507f 2569
f459b602
MAP
2570 r = sd_bus_message_read(m, "s", &path);
2571 if (r < 0)
2572 return bus_log_parse_error(r);
582a507f 2573
f84190d8
LP
2574 i->path = strdup(path);
2575 if (!i->path)
f459b602 2576 return log_oom();
582a507f 2577
f459b602
MAP
2578 r = sd_bus_message_read_strv(m, &i->argv);
2579 if (r < 0)
2580 return bus_log_parse_error(r);
2581
2582 r = sd_bus_message_read(m,
2583 "bttttuii",
2584 &ignore,
2585 &start_timestamp, &start_timestamp_monotonic,
2586 &exit_timestamp, &exit_timestamp_monotonic,
2587 &pid,
2588 &code, &status);
2589 if (r < 0)
2590 return bus_log_parse_error(r);
582a507f 2591
b708e7ce 2592 i->ignore = ignore;
582a507f
LP
2593 i->start_timestamp = (usec_t) start_timestamp;
2594 i->exit_timestamp = (usec_t) exit_timestamp;
2595 i->pid = (pid_t) pid;
2596 i->code = code;
2597 i->status = status;
2598
f459b602
MAP
2599 r = sd_bus_message_exit_container(m);
2600 if (r < 0)
2601 return bus_log_parse_error(r);
2602
2603 return 1;
582a507f
LP
2604}
2605
61cbdc4b
LP
2606typedef struct UnitStatusInfo {
2607 const char *id;
2608 const char *load_state;
2609 const char *active_state;
2610 const char *sub_state;
a4375746 2611 const char *unit_file_state;
61cbdc4b
LP
2612
2613 const char *description;
4a9e2fff 2614 const char *following;
61cbdc4b 2615
49dbfa7b
LP
2616 char **documentation;
2617
1b64d026
LP
2618 const char *fragment_path;
2619 const char *source_path;
4ad49000 2620 const char *control_group;
61cbdc4b 2621
76d14b87
OS
2622 char **dropin_paths;
2623
9f39404c 2624 const char *load_error;
f42806df 2625 const char *result;
9f39404c 2626
584be568 2627 usec_t inactive_exit_timestamp;
df50185b 2628 usec_t inactive_exit_timestamp_monotonic;
584be568
LP
2629 usec_t active_enter_timestamp;
2630 usec_t active_exit_timestamp;
2631 usec_t inactive_enter_timestamp;
2632
45fb0699
LP
2633 bool need_daemon_reload;
2634
61cbdc4b
LP
2635 /* Service */
2636 pid_t main_pid;
2637 pid_t control_pid;
2638 const char *status_text;
175728c4 2639 const char *pid_file;
d06dacd0 2640 bool running:1;
61cbdc4b
LP
2641
2642 usec_t start_timestamp;
2643 usec_t exit_timestamp;
2644
2645 int exit_code, exit_status;
2646
90bbc946
LP
2647 usec_t condition_timestamp;
2648 bool condition_result;
52990c2e
ZJS
2649 bool failed_condition_trigger;
2650 bool failed_condition_negate;
2651 const char *failed_condition;
2652 const char *failed_condition_param;
90bbc946 2653
61cbdc4b
LP
2654 /* Socket */
2655 unsigned n_accepted;
2656 unsigned n_connections;
b8131a87 2657 bool accept;
61cbdc4b 2658
13160134 2659 /* Pairs of type, path */
67419600
OS
2660 char **listen;
2661
61cbdc4b
LP
2662 /* Device */
2663 const char *sysfs_path;
2664
2665 /* Mount, Automount */
2666 const char *where;
2667
2668 /* Swap */
2669 const char *what;
582a507f
LP
2670
2671 LIST_HEAD(ExecStatusInfo, exec);
61cbdc4b
LP
2672} UnitStatusInfo;
2673
f459b602
MAP
2674static void print_status_info(
2675 UnitStatusInfo *i,
2676 bool *ellipsized) {
2677
582a507f 2678 ExecStatusInfo *p;
2ee68f72 2679 const char *on, *off, *ss;
584be568 2680 usec_t timestamp;
9185c8e6 2681 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
584be568 2682 char since2[FORMAT_TIMESTAMP_MAX], *s2;
1b64d026 2683 const char *path;
9bdbc2e2
LN
2684 int flags =
2685 arg_all * OUTPUT_SHOW_ALL |
2686 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
2687 on_tty() * OUTPUT_COLOR |
2688 !arg_quiet * OUTPUT_WARN_CUTOFF |
2689 arg_full * OUTPUT_FULL_WIDTH;
13160134 2690 char **t, **t2;
582a507f 2691
61cbdc4b
LP
2692 assert(i);
2693
2694 /* This shows pretty information about a unit. See
2695 * print_property() for a low-level property printer */
2696
2697 printf("%s", strna(i->id));
2698
2699 if (i->description && !streq_ptr(i->id, i->description))
2700 printf(" - %s", i->description);
2701
2702 printf("\n");
2703
4a9e2fff 2704 if (i->following)
856323c9 2705 printf(" Follow: unit currently follows state of %s\n", i->following);
4a9e2fff 2706
f7b9e331 2707 if (streq_ptr(i->load_state, "error")) {
0b5a519c
DS
2708 on = ansi_highlight_red();
2709 off = ansi_highlight_off();
c31b4423
LP
2710 } else
2711 on = off = "";
2712
1b64d026
LP
2713 path = i->source_path ? i->source_path : i->fragment_path;
2714
9f39404c 2715 if (i->load_error)
856323c9
ZJS
2716 printf(" Loaded: %s%s%s (Reason: %s)\n",
2717 on, strna(i->load_state), off, i->load_error);
1b64d026 2718 else if (path && i->unit_file_state)
856323c9
ZJS
2719 printf(" Loaded: %s%s%s (%s; %s)\n",
2720 on, strna(i->load_state), off, path, i->unit_file_state);
1b64d026 2721 else if (path)
856323c9
ZJS
2722 printf(" Loaded: %s%s%s (%s)\n",
2723 on, strna(i->load_state), off, path);
61cbdc4b 2724 else
856323c9
ZJS
2725 printf(" Loaded: %s%s%s\n",
2726 on, strna(i->load_state), off);
61cbdc4b 2727
76d14b87 2728 if (!strv_isempty(i->dropin_paths)) {
f459b602 2729 _cleanup_free_ char *dir = NULL;
76d14b87 2730 bool last = false;
f459b602 2731 char ** dropin;
76d14b87
OS
2732
2733 STRV_FOREACH(dropin, i->dropin_paths) {
2734 if (! dir || last) {
856323c9 2735 printf(dir ? " " : " Drop-In: ");
76d14b87
OS
2736
2737 free(dir);
f459b602 2738 dir = NULL;
76d14b87
OS
2739
2740 if (path_get_parent(*dropin, &dir) < 0) {
2741 log_oom();
2742 return;
2743 }
2744
856323c9 2745 printf("%s\n %s", dir,
76d14b87
OS
2746 draw_special_char(DRAW_TREE_RIGHT));
2747 }
2748
2749 last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
2750
2b6bf07d 2751 printf("%s%s", basename(*dropin), last ? "\n" : ", ");
76d14b87 2752 }
76d14b87
OS
2753 }
2754
2ee68f72
LP
2755 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2756
fdf20a31 2757 if (streq_ptr(i->active_state, "failed")) {
0b5a519c
DS
2758 on = ansi_highlight_red();
2759 off = ansi_highlight_off();
2ee68f72 2760 } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
0b5a519c
DS
2761 on = ansi_highlight_green();
2762 off = ansi_highlight_off();
2ee68f72
LP
2763 } else
2764 on = off = "";
2765
2766 if (ss)
856323c9
ZJS
2767 printf(" Active: %s%s (%s)%s",
2768 on, strna(i->active_state), ss, off);
2ee68f72 2769 else
856323c9
ZJS
2770 printf(" Active: %s%s%s",
2771 on, strna(i->active_state), off);
61cbdc4b 2772
f42806df
LP
2773 if (!isempty(i->result) && !streq(i->result, "success"))
2774 printf(" (Result: %s)", i->result);
2775
584be568
LP
2776 timestamp = (streq_ptr(i->active_state, "active") ||
2777 streq_ptr(i->active_state, "reloading")) ? i->active_enter_timestamp :
2778 (streq_ptr(i->active_state, "inactive") ||
fdf20a31 2779 streq_ptr(i->active_state, "failed")) ? i->inactive_enter_timestamp :
584be568
LP
2780 streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp :
2781 i->active_exit_timestamp;
2782
bbb8486e 2783 s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
584be568
LP
2784 s2 = format_timestamp(since2, sizeof(since2), timestamp);
2785
2786 if (s1)
538da63d 2787 printf(" since %s; %s\n", s2, s1);
584be568 2788 else if (s2)
538da63d 2789 printf(" since %s\n", s2);
584be568
LP
2790 else
2791 printf("\n");
2792
90bbc946 2793 if (!i->condition_result && i->condition_timestamp > 0) {
bbb8486e 2794 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
90bbc946
LP
2795 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2796
52990c2e
ZJS
2797 printf(" start condition failed at %s%s%s\n",
2798 s2, s1 ? "; " : "", s1 ? s1 : "");
2799 if (i->failed_condition_trigger)
2800 printf(" none of the trigger conditions were met\n");
2801 else if (i->failed_condition)
2802 printf(" %s=%s%s was not met\n",
2803 i->failed_condition,
2804 i->failed_condition_negate ? "!" : "",
2805 i->failed_condition_param);
90bbc946
LP
2806 }
2807
61cbdc4b 2808 if (i->sysfs_path)
856323c9 2809 printf(" Device: %s\n", i->sysfs_path);
9feeba4b 2810 if (i->where)
856323c9 2811 printf(" Where: %s\n", i->where);
9feeba4b 2812 if (i->what)
856323c9 2813 printf(" What: %s\n", i->what);
49dbfa7b 2814
13160134 2815 STRV_FOREACH(t, i->documentation)
856323c9 2816 printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", *t);
49dbfa7b 2817
13160134 2818 STRV_FOREACH_PAIR(t, t2, i->listen)
856323c9 2819 printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
67419600 2820
b8131a87 2821 if (i->accept)
856323c9 2822 printf(" Accepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
61cbdc4b 2823
582a507f 2824 LIST_FOREACH(exec, p, i->exec) {
13160134 2825 _cleanup_free_ char *argv = NULL;
9a57c629 2826 bool good;
582a507f
LP
2827
2828 /* Only show exited processes here */
2829 if (p->code == 0)
2830 continue;
2831
13160134 2832 argv = strv_join(p->argv, " ");
856323c9 2833 printf(" Process: %u %s=%s ", p->pid, p->name, strna(argv));
582a507f 2834
96342de6 2835 good = is_clean_exit_lsb(p->code, p->status, NULL);
9a57c629 2836 if (!good) {
0b5a519c
DS
2837 on = ansi_highlight_red();
2838 off = ansi_highlight_off();
9a57c629
LP
2839 } else
2840 on = off = "";
2841
2842 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2843
d06dacd0
LP
2844 if (p->code == CLD_EXITED) {
2845 const char *c;
2846
582a507f 2847 printf("status=%i", p->status);
d06dacd0 2848
1b64d026
LP
2849 c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2850 if (c)
d06dacd0
LP
2851 printf("/%s", c);
2852
2853 } else
582a507f 2854 printf("signal=%s", signal_to_string(p->status));
9a57c629
LP
2855
2856 printf(")%s\n", off);
2857
582a507f
LP
2858 if (i->main_pid == p->pid &&
2859 i->start_timestamp == p->start_timestamp &&
2860 i->exit_timestamp == p->start_timestamp)
2861 /* Let's not show this twice */
2862 i->main_pid = 0;
2863
2864 if (p->pid == i->control_pid)
2865 i->control_pid = 0;
2866 }
2867
61cbdc4b 2868 if (i->main_pid > 0 || i->control_pid > 0) {
61cbdc4b 2869 if (i->main_pid > 0) {
856323c9 2870 printf(" Main PID: %u", (unsigned) i->main_pid);
61cbdc4b
LP
2871
2872 if (i->running) {
13160134
ZJS
2873 _cleanup_free_ char *comm = NULL;
2874 get_process_comm(i->main_pid, &comm);
2875 if (comm)
2876 printf(" (%s)", comm);
6d4fc029 2877 } else if (i->exit_code > 0) {
61cbdc4b
LP
2878 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2879
d06dacd0
LP
2880 if (i->exit_code == CLD_EXITED) {
2881 const char *c;
2882
61cbdc4b 2883 printf("status=%i", i->exit_status);
d06dacd0 2884
1b64d026
LP
2885 c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2886 if (c)
d06dacd0
LP
2887 printf("/%s", c);
2888
2889 } else
582a507f 2890 printf("signal=%s", signal_to_string(i->exit_status));
6d4fc029
LP
2891 printf(")");
2892 }
61cbdc4b 2893
13160134
ZJS
2894 if (i->control_pid > 0)
2895 printf(";");
2896 }
61cbdc4b
LP
2897
2898 if (i->control_pid > 0) {
13160134 2899 _cleanup_free_ char *c = NULL;
61cbdc4b 2900
856323c9 2901 printf(" %8s: %u", i->main_pid ? "" : " Control", (unsigned) i->control_pid);
61cbdc4b 2902
13160134
ZJS
2903 get_process_comm(i->control_pid, &c);
2904 if (c)
2905 printf(" (%s)", c);
61cbdc4b
LP
2906 }
2907
2908 printf("\n");
2909 }
2910
17bb7382 2911 if (i->status_text)
856323c9 2912 printf(" Status: \"%s\"\n", i->status_text);
17bb7382 2913
4ad49000 2914 if (i->control_group &&
042f9f5e 2915 (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group, false) == 0)) {
ab35fb1b
LP
2916 unsigned c;
2917
4ad49000 2918 printf(" CGroup: %s\n", i->control_group);
ab35fb1b 2919
7af5a806 2920 if (arg_transport == BUS_TRANSPORT_LOCAL || arg_transport == BUS_TRANSPORT_CONTAINER) {
b69d29ce
LP
2921 unsigned k = 0;
2922 pid_t extra[2];
856323c9 2923 char prefix[] = " ";
b69d29ce
LP
2924
2925 c = columns();
e8853816
ZJS
2926 if (c > sizeof(prefix) - 1)
2927 c -= sizeof(prefix) - 1;
a8f11321
LP
2928 else
2929 c = 0;
ab35fb1b 2930
b69d29ce
LP
2931 if (i->main_pid > 0)
2932 extra[k++] = i->main_pid;
2933
2934 if (i->control_pid > 0)
2935 extra[k++] = i->control_pid;
2936
a00963a2 2937 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix,
e8853816 2938 c, false, extra, k, flags);
a8f11321 2939 }
c59760ee 2940 }
45fb0699 2941
f459b602 2942 if (i->id && arg_transport == BUS_TRANSPORT_LOCAL) {
6f003b43 2943 printf("\n");
886a64fe
ZJS
2944 show_journal_by_unit(stdout,
2945 i->id,
2946 arg_output,
2947 0,
2948 i->inactive_exit_timestamp_monotonic,
2949 arg_lines,
2950 getuid(),
2951 flags,
94e0bd7d
ZJS
2952 arg_scope == UNIT_FILE_SYSTEM,
2953 ellipsized);
6f003b43 2954 }
86aa7ba4 2955
45fb0699 2956 if (i->need_daemon_reload)
1058cbf2 2957 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %sdaemon-reload' recommended.\n",
0b5a519c
DS
2958 ansi_highlight_red(),
2959 ansi_highlight_off(),
1058cbf2 2960 arg_scope == UNIT_FILE_SYSTEM ? "" : "--user ");
61cbdc4b
LP
2961}
2962
b43f208f 2963static void show_unit_help(UnitStatusInfo *i) {
256425cc
LP
2964 char **p;
2965
2966 assert(i);
2967
2968 if (!i->documentation) {
2969 log_info("Documentation for %s not known.", i->id);
2970 return;
2971 }
2972
2973 STRV_FOREACH(p, i->documentation) {
2974
2975 if (startswith(*p, "man:")) {
256425cc 2976 const char *args[4] = { "man", NULL, NULL, NULL };
cbc9fbd1
LP
2977 _cleanup_free_ char *page = NULL, *section = NULL;
2978 char *e = NULL;
256425cc 2979 pid_t pid;
cbc9fbd1 2980 size_t k;
256425cc
LP
2981
2982 k = strlen(*p);
2983
2984 if ((*p)[k-1] == ')')
2985 e = strrchr(*p, '(');
2986
2987 if (e) {
2988 page = strndup((*p) + 4, e - *p - 4);
256425cc 2989 section = strndup(e + 1, *p + k - e - 2);
cec7eda5 2990 if (!page || !section) {
0d0f0c50 2991 log_oom();
256425cc
LP
2992 return;
2993 }
2994
2995 args[1] = section;
2996 args[2] = page;
2997 } else
2998 args[1] = *p + 4;
2999
3000 pid = fork();
3001 if (pid < 0) {
3002 log_error("Failed to fork: %m");
256425cc
LP
3003 continue;
3004 }
3005
3006 if (pid == 0) {
3007 /* Child */
3008 execvp(args[0], (char**) args);
3009 log_error("Failed to execute man: %m");
3010 _exit(EXIT_FAILURE);
3011 }
3012
256425cc
LP
3013 wait_for_terminate(pid, NULL);
3014 } else
0315fe37 3015 log_info("Can't show: %s", *p);
256425cc
LP
3016 }
3017}
3018
f459b602
MAP
3019static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *i, const char *contents) {
3020 int r;
61cbdc4b 3021
a4c279f8 3022 assert(name);
f459b602 3023 assert(m);
a4c279f8
LP
3024 assert(i);
3025
f459b602 3026 switch (contents[0]) {
61cbdc4b 3027
f459b602 3028 case SD_BUS_TYPE_STRING: {
61cbdc4b
LP
3029 const char *s;
3030
f459b602
MAP
3031 r = sd_bus_message_read(m, "s", &s);
3032 if (r < 0)
3033 return bus_log_parse_error(r);
61cbdc4b 3034
a4c279f8 3035 if (!isempty(s)) {
61cbdc4b
LP
3036 if (streq(name, "Id"))
3037 i->id = s;
3038 else if (streq(name, "LoadState"))
3039 i->load_state = s;
3040 else if (streq(name, "ActiveState"))
3041 i->active_state = s;
3042 else if (streq(name, "SubState"))
3043 i->sub_state = s;
3044 else if (streq(name, "Description"))
3045 i->description = s;
3046 else if (streq(name, "FragmentPath"))
1b64d026
LP
3047 i->fragment_path = s;
3048 else if (streq(name, "SourcePath"))
3049 i->source_path = s;
286ca485 3050#ifndef NOLEGACY
a00963a2
LP
3051 else if (streq(name, "DefaultControlGroup")) {
3052 const char *e;
3053 e = startswith(s, SYSTEMD_CGROUP_CONTROLLER ":");
3054 if (e)
3055 i->control_group = e;
3056 }
4ad49000
LP
3057#endif
3058 else if (streq(name, "ControlGroup"))
3059 i->control_group = s;
61cbdc4b
LP
3060 else if (streq(name, "StatusText"))
3061 i->status_text = s;
175728c4
HH
3062 else if (streq(name, "PIDFile"))
3063 i->pid_file = s;
61cbdc4b
LP
3064 else if (streq(name, "SysFSPath"))
3065 i->sysfs_path = s;
3066 else if (streq(name, "Where"))
3067 i->where = s;
3068 else if (streq(name, "What"))
3069 i->what = s;
4a9e2fff
LP
3070 else if (streq(name, "Following"))
3071 i->following = s;
a4375746
LP
3072 else if (streq(name, "UnitFileState"))
3073 i->unit_file_state = s;
f42806df
LP
3074 else if (streq(name, "Result"))
3075 i->result = s;
61cbdc4b
LP
3076 }
3077
3078 break;
3079 }
3080
f459b602
MAP
3081 case SD_BUS_TYPE_BOOLEAN: {
3082 int b;
b8131a87 3083
f459b602
MAP
3084 r = sd_bus_message_read(m, "b", &b);
3085 if (r < 0)
3086 return bus_log_parse_error(r);
b8131a87
LP
3087
3088 if (streq(name, "Accept"))
3089 i->accept = b;
45fb0699
LP
3090 else if (streq(name, "NeedDaemonReload"))
3091 i->need_daemon_reload = b;
90bbc946
LP
3092 else if (streq(name, "ConditionResult"))
3093 i->condition_result = b;
b8131a87
LP
3094
3095 break;
3096 }
3097
f459b602 3098 case SD_BUS_TYPE_UINT32: {
61cbdc4b
LP
3099 uint32_t u;
3100
f459b602
MAP
3101 r = sd_bus_message_read(m, "u", &u);
3102 if (r < 0)
3103 return bus_log_parse_error(r);
61cbdc4b
LP
3104
3105 if (streq(name, "MainPID")) {
3106 if (u > 0) {
3107 i->main_pid = (pid_t) u;
3108 i->running = true;
3109 }
3110 } else if (streq(name, "ControlPID"))
3111 i->control_pid = (pid_t) u;
3112 else if (streq(name, "ExecMainPID")) {
3113 if (u > 0)
3114 i->main_pid = (pid_t) u;
3115 } else if (streq(name, "NAccepted"))
3116 i->n_accepted = u;
3117 else if (streq(name, "NConnections"))
3118 i->n_connections = u;
3119
3120 break;
3121 }
3122
f459b602 3123 case SD_BUS_TYPE_INT32: {
61cbdc4b
LP
3124 int32_t j;
3125
f459b602
MAP
3126 r = sd_bus_message_read(m, "i", &j);
3127 if (r < 0)
3128 return bus_log_parse_error(r);
61cbdc4b
LP
3129
3130 if (streq(name, "ExecMainCode"))
3131 i->exit_code = (int) j;
3132 else if (streq(name, "ExecMainStatus"))
3133 i->exit_status = (int) j;
3134
3135 break;
3136 }
3137
f459b602 3138 case SD_BUS_TYPE_UINT64: {
61cbdc4b
LP
3139 uint64_t u;
3140
f459b602
MAP
3141 r = sd_bus_message_read(m, "t", &u);
3142 if (r < 0)
3143 return bus_log_parse_error(r);
61cbdc4b
LP
3144
3145 if (streq(name, "ExecMainStartTimestamp"))
3146 i->start_timestamp = (usec_t) u;
3147 else if (streq(name, "ExecMainExitTimestamp"))
3148 i->exit_timestamp = (usec_t) u;
584be568
LP
3149 else if (streq(name, "ActiveEnterTimestamp"))
3150 i->active_enter_timestamp = (usec_t) u;
3151 else if (streq(name, "InactiveEnterTimestamp"))
3152 i->inactive_enter_timestamp = (usec_t) u;
3153 else if (streq(name, "InactiveExitTimestamp"))
3154 i->inactive_exit_timestamp = (usec_t) u;
df50185b
LP
3155 else if (streq(name, "InactiveExitTimestampMonotonic"))
3156 i->inactive_exit_timestamp_monotonic = (usec_t) u;
584be568
LP
3157 else if (streq(name, "ActiveExitTimestamp"))
3158 i->active_exit_timestamp = (usec_t) u;
90bbc946
LP
3159 else if (streq(name, "ConditionTimestamp"))
3160 i->condition_timestamp = (usec_t) u;
61cbdc4b
LP
3161
3162 break;
3163 }
582a507f 3164
f459b602 3165 case SD_BUS_TYPE_ARRAY:
582a507f 3166
f459b602
MAP
3167 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
3168 _cleanup_free_ ExecStatusInfo *info = NULL;
582a507f 3169
f459b602
MAP
3170 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
3171 if (r < 0)
3172 return bus_log_parse_error(r);
582a507f 3173
f459b602
MAP
3174 info = new0(ExecStatusInfo, 1);
3175 if (!info)
3176 return log_oom();
582a507f 3177
f459b602 3178 while ((r = exec_status_info_deserialize(m, info)) > 0) {
0129173a 3179
f459b602
MAP
3180 info->name = strdup(name);
3181 if (!info->name)
3182 log_oom();
582a507f 3183
71fda00f 3184 LIST_PREPEND(exec, i->exec, info);
582a507f 3185
f459b602
MAP
3186 info = new0(ExecStatusInfo, 1);
3187 if (!info)
3188 log_oom();
49dbfa7b 3189 }
67419600 3190
f459b602
MAP
3191 if (r < 0)
3192 return bus_log_parse_error(r);
67419600 3193
f459b602
MAP
3194 r = sd_bus_message_exit_container(m);
3195 if (r < 0)
3196 return bus_log_parse_error(r);
67419600 3197
f459b602 3198 return 0;
67419600 3199
f459b602
MAP
3200 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
3201 const char *type, *path;
13160134 3202
f459b602
MAP
3203 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
3204 if (r < 0)
3205 return bus_log_parse_error(r);
67419600 3206
f459b602 3207 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0) {
67419600 3208
f459b602
MAP
3209 r = strv_extend(&i->listen, type);
3210 if (r < 0)
3211 return r;
67419600 3212
f459b602
MAP
3213 r = strv_extend(&i->listen, path);
3214 if (r < 0)
3215 return r;
3216 }
76d14b87 3217 if (r < 0)
f459b602 3218 return bus_log_parse_error(r);
76d14b87 3219
f459b602
MAP
3220 r = sd_bus_message_exit_container(m);
3221 if (r < 0)
3222 return bus_log_parse_error(r);
49dbfa7b 3223
f459b602 3224 return 0;
49dbfa7b 3225
f459b602 3226 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "DropInPaths")) {
49dbfa7b 3227
f459b602
MAP
3228 r = sd_bus_message_read_strv(m, &i->dropin_paths);
3229 if (r < 0)
3230 return bus_log_parse_error(r);
49dbfa7b 3231
f459b602 3232 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "Documentation")) {
49dbfa7b 3233
f459b602
MAP
3234 r = sd_bus_message_read_strv(m, &i->documentation);
3235 if (r < 0)
3236 return bus_log_parse_error(r);
52990c2e 3237
f459b602
MAP
3238 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Conditions")) {
3239 const char *cond, *param;
3240 int trigger, negate;
3241 int32_t state;
52990c2e 3242
f459b602
MAP
3243 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
3244 if (r < 0)
3245 return bus_log_parse_error(r);
3246
3247 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
3248 log_debug("%s %d %d %s %d", cond, trigger, negate, param, state);
3249 if (state < 0 && (!trigger || !i->failed_condition)) {
3250 i->failed_condition = cond;
3251 i->failed_condition_trigger = trigger;
3252 i->failed_condition_negate = negate;
3253 i->failed_condition_param = param;
3254 }
582a507f 3255 }
f459b602
MAP
3256 if (r < 0)
3257 return bus_log_parse_error(r);
3258
3259 r = sd_bus_message_exit_container(m);
3260 if (r < 0)
3261 return bus_log_parse_error(r);
3262
3263 } else
3264 goto skip;
582a507f
LP
3265
3266 break;
9f39404c 3267
f459b602 3268 case SD_BUS_TYPE_STRUCT_BEGIN:
9f39404c
LP
3269
3270 if (streq(name, "LoadError")) {
9f39404c 3271 const char *n, *message;
9f39404c 3272
f459b602 3273 r = sd_bus_message_read(m, "(ss)", &n, &message);
9f39404c 3274 if (r < 0)
f459b602 3275 return bus_log_parse_error(r);
9f39404c
LP
3276
3277 if (!isempty(message))
3278 i->load_error = message;
f459b602
MAP
3279 } else
3280 goto skip;
9f39404c
LP
3281
3282 break;
f459b602
MAP
3283
3284 default:
3285 goto skip;
9f39404c 3286 }
f459b602
MAP
3287
3288 return 0;
3289
3290skip:
3291 r = sd_bus_message_skip(m, contents);
3292 if (r < 0)
3293 return bus_log_parse_error(r);
61cbdc4b
LP
3294
3295 return 0;
3296}
3297
f459b602
MAP
3298static int print_property(const char *name, sd_bus_message *m, const char *contents) {
3299 int r;
3300
48220598 3301 assert(name);
f459b602 3302 assert(m);
48220598 3303
61cbdc4b
LP
3304 /* This is a low-level property printer, see
3305 * print_status_info() for the nicer output */
3306
852c1b4d
ZJS
3307 if (arg_properties && !strv_find(arg_properties, name)) {
3308 /* skip what we didn't read */
3309 r = sd_bus_message_skip(m, contents);
3310 return r;
3311 }
48220598 3312
f459b602 3313 switch (contents[0]) {
48220598 3314
f459b602 3315 case SD_BUS_TYPE_STRUCT_BEGIN:
48220598 3316
f459b602 3317 if (contents[1] == SD_BUS_TYPE_UINT32 && streq(name, "Job")) {
48220598
LP
3318 uint32_t u;
3319
f459b602
MAP
3320 r = sd_bus_message_read(m, "(uo)", &u, NULL);
3321 if (r < 0)
3322 return bus_log_parse_error(r);
48220598 3323
f459b602 3324 if (u > 0)
48220598
LP
3325 printf("%s=%u\n", name, (unsigned) u);
3326 else if (arg_all)
3327 printf("%s=\n", name);
3328
3329 return 0;
f459b602
MAP
3330
3331 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "Unit")) {
48220598
LP
3332 const char *s;
3333
f459b602
MAP
3334 r = sd_bus_message_read(m, "(so)", &s, NULL);
3335 if (r < 0)
3336 return bus_log_parse_error(r);
48220598 3337
f459b602 3338 if (arg_all || !isempty(s))
48220598
LP
3339 printf("%s=%s\n", name, s);
3340
3341 return 0;
f459b602
MAP
3342
3343 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "LoadError")) {
9f39404c
LP
3344 const char *a = NULL, *b = NULL;
3345
f459b602
MAP
3346 r = sd_bus_message_read(m, "(ss)", &a, &b);
3347 if (r < 0)
3348 return bus_log_parse_error(r);
9f39404c
LP
3349
3350 if (arg_all || !isempty(a) || !isempty(b))
3351 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
f786e80d
LP
3352
3353 return 0;
48220598
LP
3354 }
3355
3356 break;
48220598 3357
f459b602 3358 case SD_BUS_TYPE_ARRAY:
48220598 3359
f459b602
MAP
3360 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "EnvironmentFiles")) {
3361 const char *path;
3362 int ignore;
8c7be95e 3363
f459b602
MAP
3364 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sb)");
3365 if (r < 0)
3366 return bus_log_parse_error(r);
8c7be95e 3367
f459b602
MAP
3368 while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
3369 printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
8c7be95e 3370
f459b602
MAP
3371 if (r < 0)
3372 return bus_log_parse_error(r);
8c7be95e 3373
f459b602
MAP
3374 r = sd_bus_message_exit_container(m);
3375 if (r < 0)
3376 return bus_log_parse_error(r);
8c7be95e
LP
3377
3378 return 0;
3379
f459b602
MAP
3380 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Paths")) {
3381 const char *type, *path;
67419600 3382
f459b602
MAP
3383 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
3384 if (r < 0)
3385 return bus_log_parse_error(r);
ebf57b80 3386
f459b602
MAP
3387 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
3388 printf("%s=%s\n", type, path);
3389 if (r < 0)
3390 return bus_log_parse_error(r);
ebf57b80 3391
f459b602
MAP
3392 r = sd_bus_message_exit_container(m);
3393 if (r < 0)
3394 return bus_log_parse_error(r);
ebf57b80 3395
707e5e52 3396 return 0;
582a507f 3397
f459b602
MAP
3398 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
3399 const char *type, *path;
67419600 3400
f459b602
MAP
3401 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
3402 if (r < 0)
3403 return bus_log_parse_error(r);
67419600 3404
f459b602
MAP
3405 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
3406 printf("Listen%s=%s\n", type, path);
3407 if (r < 0)
3408 return bus_log_parse_error(r);
67419600 3409
f459b602
MAP
3410 r = sd_bus_message_exit_container(m);
3411 if (r < 0)
3412 return bus_log_parse_error(r);
67419600
OS
3413
3414 return 0;
3415
f459b602
MAP
3416 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Timers")) {
3417 const char *base;
3418 uint64_t value, next_elapse;
707e5e52 3419
f459b602
MAP
3420 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(stt)");
3421 if (r < 0)
3422 return bus_log_parse_error(r);
552e4331 3423
f459b602
MAP
3424 while ((r = sd_bus_message_read(m, "(stt)", &base, &value, &next_elapse)) > 0) {
3425 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
fe68089d 3426
f459b602
MAP
3427 printf("%s={ value=%s ; next_elapse=%s }\n",
3428 base,
3429 format_timespan(timespan1, sizeof(timespan1), value, 0),
3430 format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
fe68089d 3431 }
f459b602
MAP
3432 if (r < 0)
3433 return bus_log_parse_error(r);
3434
3435 r = sd_bus_message_exit_container(m);
3436 if (r < 0)
3437 return bus_log_parse_error(r);
fe68089d
LP
3438
3439 return 0;
fe68089d 3440
f459b602
MAP
3441 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
3442 ExecStatusInfo info = {};
3443
3444 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
3445 if (r < 0)
3446 return bus_log_parse_error(r);
3447
3448 while ((r = exec_status_info_deserialize(m, &info)) > 0) {
3449 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
3450 _cleanup_free_ char *tt;
3451
3452 tt = strv_join(info.argv, " ");
3453
3454 printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
3455 name,
3456 strna(info.path),
3457 strna(tt),
3458 yes_no(info.ignore),
3459 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
3460 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
3461 (unsigned) info. pid,
3462 sigchld_code_to_string(info.code),
3463 info.status,
3464 info.code == CLD_EXITED ? "" : "/",
3465 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
fe68089d 3466
582a507f
LP
3467 free(info.path);
3468 strv_free(info.argv);
f459b602 3469 zero(info);
707e5e52
LP
3470 }
3471
f459b602
MAP
3472 r = sd_bus_message_exit_container(m);
3473 if (r < 0)
3474 return bus_log_parse_error(r);
3475
48220598 3476 return 0;
4ad49000 3477
f459b602
MAP
3478 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "DeviceAllow")) {
3479 const char *path, *rwm;
4ad49000 3480
f459b602
MAP
3481 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
3482 if (r < 0)
3483 return bus_log_parse_error(r);
4ad49000 3484
f459b602
MAP
3485 while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0)
3486 printf("%s=%s %s\n", name, strna(path), strna(rwm));
3487 if (r < 0)
3488 return bus_log_parse_error(r);
4ad49000 3489
f459b602
MAP
3490 r = sd_bus_message_exit_container(m);
3491 if (r < 0)
3492 return bus_log_parse_error(r);
4ad49000 3493
4ad49000
LP
3494 return 0;
3495
f459b602
MAP
3496 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "BlockIODeviceWeight")) {
3497 const char *path;
3498 uint64_t weight;
b8ab2dc6 3499
f459b602
MAP
3500 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
3501 if (r < 0)
3502 return bus_log_parse_error(r);
b8ab2dc6 3503
f459b602
MAP
3504 while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0)
3505 printf("%s=%s %" PRIu64 "\n", name, strna(path), weight);
3506 if (r < 0)
3507 return bus_log_parse_error(r);
b8ab2dc6 3508
f459b602
MAP
3509 r = sd_bus_message_exit_container(m);
3510 if (r < 0)
3511 return bus_log_parse_error(r);
b8ab2dc6 3512
b8ab2dc6
G
3513 return 0;
3514
f459b602
MAP
3515 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) {
3516 const char *path;
3517 uint64_t bandwidth;
4ad49000 3518
f459b602
MAP
3519 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
3520 if (r < 0)
3521 return bus_log_parse_error(r);
4ad49000 3522
f459b602
MAP
3523 while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0)
3524 printf("%s=%s %" PRIu64 "\n", name, strna(path), bandwidth);
3525 if (r < 0)
3526 return bus_log_parse_error(r);
4ad49000 3527
f459b602
MAP
3528 r = sd_bus_message_exit_container(m);
3529 if (r < 0)
3530 return bus_log_parse_error(r);
4ad49000 3531
4ad49000 3532 return 0;
48220598
LP
3533 }
3534
3535 break;
3536 }
3537
f459b602
MAP
3538 r = bus_print_property(name, m, arg_all);
3539 if (r < 0)
3540 return bus_log_parse_error(r);
3541
3542 if (r == 0) {
3543 r = sd_bus_message_skip(m, contents);
3544 if (r < 0)
3545 return bus_log_parse_error(r);
a4c279f8 3546
f459b602
MAP
3547 if (arg_all)
3548 printf("%s=[unprintable]\n", name);
3549 }
48220598
LP
3550
3551 return 0;
3552}
3553
f459b602
MAP
3554static int show_one(
3555 const char *verb,
3556 sd_bus *bus,
3557 const char *path,
3558 bool show_properties,
3559 bool *new_line,
3560 bool *ellipsized) {
3561
3562 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
3563 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
b92bea5d 3564 UnitStatusInfo info = {};
582a507f 3565 ExecStatusInfo *p;
f459b602 3566 int r;
48220598 3567
48220598 3568 assert(path);
61cbdc4b 3569 assert(new_line);
48220598 3570
f459b602 3571 r = sd_bus_call_method(
f22f08cd
SP
3572 bus,
3573 "org.freedesktop.systemd1",
3574 path,
3575 "org.freedesktop.DBus.Properties",
3576 "GetAll",
f459b602 3577 &error,
f22f08cd 3578 &reply,
f459b602
MAP
3579 "s", "");
3580 if (r < 0) {
3581 log_error("Failed to get properties: %s", bus_error_message(&error, r));
f84190d8 3582 return r;
48220598
LP
3583 }
3584
f459b602
MAP
3585 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
3586 if (r < 0)
3587 return bus_log_parse_error(r);
48220598 3588
61cbdc4b
LP
3589 if (*new_line)
3590 printf("\n");
3591
3592 *new_line = true;
3593
f459b602
MAP
3594 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
3595 const char *name, *contents;
0183528f 3596
f459b602
MAP
3597 r = sd_bus_message_read(reply, "s", &name);
3598 if (r < 0)
3599 return bus_log_parse_error(r);
48220598 3600
f459b602
MAP
3601 r = sd_bus_message_peek_type(reply, NULL, &contents);
3602 if (r < 0)
3603 return bus_log_parse_error(r);
3604
3605 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
3606 if (r < 0)
3607 return bus_log_parse_error(r);
48220598 3608
61cbdc4b 3609 if (show_properties)
f459b602 3610 r = print_property(name, reply, contents);
61cbdc4b 3611 else
f459b602
MAP
3612 r = status_property(name, reply, &info, contents);
3613 if (r < 0)
3614 return r;
48220598 3615
f459b602
MAP
3616 r = sd_bus_message_exit_container(reply);
3617 if (r < 0)
3618 return bus_log_parse_error(r);
3619
3620 r = sd_bus_message_exit_container(reply);
3621 if (r < 0)
3622 return bus_log_parse_error(r);
48220598 3623 }
f459b602
MAP
3624 if (r < 0)
3625 return bus_log_parse_error(r);
3626
3627 r = sd_bus_message_exit_container(reply);
3628 if (r < 0)
3629 return bus_log_parse_error(r);
48220598 3630
f1e36d67
LP
3631 r = 0;
3632
256425cc 3633 if (!show_properties) {
b43f208f
KS
3634 if (streq(verb, "help"))
3635 show_unit_help(&info);
256425cc 3636 else
94e0bd7d 3637 print_status_info(&info, ellipsized);
256425cc 3638 }
f1e36d67 3639
49dbfa7b 3640 strv_free(info.documentation);
76d14b87 3641 strv_free(info.dropin_paths);
67419600 3642 strv_free(info.listen);
49dbfa7b 3643
22f4096c 3644 if (!streq_ptr(info.active_state, "active") &&
be8088a2 3645 !streq_ptr(info.active_state, "reloading") &&
3b05b8b3 3646 streq(verb, "status")) {
22f4096c 3647 /* According to LSB: "program not running" */
175728c4
HH
3648 /* 0: program is running or service is OK
3649 * 1: program is dead and /var/run pid file exists
3650 * 2: program is dead and /var/lock lock file exists
3651 * 3: program is not running
3652 * 4: program or service status is unknown
3653 */
3b05b8b3 3654 if (info.pid_file && access(info.pid_file, F_OK) == 0)
175728c4
HH
3655 r = 1;
3656 else
3657 r = 3;
e9c1ea9d 3658 }
61cbdc4b 3659
582a507f 3660 while ((p = info.exec)) {
71fda00f 3661 LIST_REMOVE(exec, info.exec, p);
582a507f
LP
3662 exec_status_info_free(p);
3663 }
3664
48220598
LP
3665 return r;
3666}
3667
f74294c1 3668static int get_unit_dbus_path_by_pid(
f459b602
MAP
3669 sd_bus *bus,
3670 uint32_t pid,
f74294c1 3671 char **unit) {
f459b602
MAP
3672
3673 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
3674 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
373d32c9 3675 char *u;
a223b325
MS
3676 int r;
3677
f459b602 3678 r = sd_bus_call_method(
f22f08cd
SP
3679 bus,
3680 "org.freedesktop.systemd1",
3681 "/org/freedesktop/systemd1",
3682 "org.freedesktop.systemd1.Manager",
3683 "GetUnitByPID",
f459b602 3684 &error,
f22f08cd 3685 &reply,
f459b602
MAP
3686 "u", pid);
3687 if (r < 0) {
3688 log_error("Failed to get unit for PID %lu: %s", (unsigned long) pid, bus_error_message(&error, r));
cec7eda5 3689 return r;
a223b325
MS
3690 }
3691
373d32c9 3692 r = sd_bus_message_read(reply, "o", &u);
f459b602
MAP
3693 if (r < 0)
3694 return bus_log_parse_error(r);
3695
373d32c9
LP
3696 u = strdup(u);
3697 if (!u)
3698 return log_oom();
3699
3700 *unit = u;
f74294c1 3701 return 0;
a223b325
MS
3702}
3703
f459b602
MAP
3704static int show_all(
3705 const char* verb,
3706 sd_bus *bus,
3707 bool show_properties,
3708 bool *new_line,
3709 bool *ellipsized) {
3710
f459b602
MAP
3711 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
3712 _cleanup_free_ UnitInfo *unit_infos = NULL;
3713 const UnitInfo *u;
3714 unsigned c;
265a7a2a
ZJS
3715 int r;
3716
f459b602 3717 r = get_unit_list(bus, &reply, &unit_infos);
265a7a2a
ZJS
3718 if (r < 0)
3719 return r;
3720
dbed408b
LP
3721 pager_open_if_enabled();
3722
f459b602
MAP
3723 c = (unsigned) r;
3724
3725 qsort_safe(unit_infos, c, sizeof(UnitInfo), compare_unit_info);
991f2a39 3726
265a7a2a 3727 for (u = unit_infos; u < unit_infos + c; u++) {
7fd1b19b 3728 _cleanup_free_ char *p = NULL;
265a7a2a 3729
d8fba7c6 3730 if (!output_show_unit(u, NULL))
265a7a2a
ZJS
3731 continue;
3732
3733 p = unit_dbus_path_from_name(u->id);
3734 if (!p)
3735 return log_oom();
3736
94e0bd7d 3737 r = show_one(verb, bus, p, show_properties, new_line, ellipsized);
265a7a2a
ZJS
3738 if (r != 0)
3739 return r;
3740 }
3741
3742 return 0;
3743}
3744
e93c33d4 3745static int cat(sd_bus *bus, char **args) {
999b6003 3746 _cleanup_free_ char *unit = NULL, *n = NULL;
e93c33d4
SL
3747 int r = 0;
3748 char **name;
a669d622 3749 bool first = true;
e93c33d4 3750
e93c33d4
SL
3751 assert(bus);
3752 assert(args);
3753
3754 pager_open_if_enabled();
3755
3756 STRV_FOREACH(name, args+1) {
999b6003 3757 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
e93c33d4 3758 _cleanup_strv_free_ char **dropin_paths = NULL;
999b6003 3759 _cleanup_free_ char *fragment_path = NULL;
e93c33d4
SL
3760 char **path;
3761
3762 n = unit_name_mangle(*name);
3763 if (!n)
3764 return log_oom();
3765
3766 unit = unit_dbus_path_from_name(n);
3767 if (!unit)
3768 return log_oom();
3769
3770 if (need_daemon_reload(bus, n) > 0)
3771 log_warning("Unit file of %s changed on disk. Run 'systemctl%s daemon-reload'.",
3772 n, arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
3773
3774 r = sd_bus_get_property_string(
3775 bus,
3776 "org.freedesktop.systemd1",
3777 unit,
3778 "org.freedesktop.systemd1.Unit",
3779 "FragmentPath",
3780 &error,
3781 &fragment_path);
3782 if (r < 0) {
3783 log_warning("Failed to get FragmentPath: %s", bus_error_message(&error, r));
3784 continue;
3785 }
3786
e93c33d4
SL
3787 r = sd_bus_get_property_strv(
3788 bus,
3789 "org.freedesktop.systemd1",
3790 unit,
3791 "org.freedesktop.systemd1.Unit",
3792 "DropInPaths",
3793 &error,
3794 &dropin_paths);
3795 if (r < 0) {
3796 log_warning("Failed to get DropInPaths: %s", bus_error_message(&error, r));
3797 continue;
3798 }
3799
a669d622
ZJS
3800 if (first)
3801 first = false;
3802 else
3803 puts("");
3804
e93c33d4 3805 if (!isempty(fragment_path)) {
a669d622
ZJS
3806 printf("%s# %s%s\n",
3807 ansi_highlight_blue(),
3808 fragment_path,
3809 ansi_highlight_off());
e93c33d4 3810 fflush(stdout);
999b6003 3811
e93c33d4
SL
3812 r = sendfile_full(STDOUT_FILENO, fragment_path);
3813 if (r < 0) {
3814 log_warning("Failed to cat %s: %s", fragment_path, strerror(-r));
3815 continue;
3816 }
3817 }
3818
3819 STRV_FOREACH(path, dropin_paths) {
58684be9 3820 printf("%s%s# %s%s\n",
a669d622 3821 isempty(fragment_path) && path == dropin_paths ? "" : "\n",
58684be9
ZJS
3822 ansi_highlight_blue(),
3823 *path,
3824 ansi_highlight_off());
e93c33d4 3825 fflush(stdout);
999b6003 3826
e93c33d4
SL
3827 r = sendfile_full(STDOUT_FILENO, *path);
3828 if (r < 0) {
3829 log_warning("Failed to cat %s: %s", *path, strerror(-r));
3830 continue;
3831 }
3832 }
3833 }
3834
c0ea486f 3835 return r < 0 ? r : 0;
e93c33d4
SL
3836}
3837
f459b602 3838static int show(sd_bus *bus, char **args) {
a223b325 3839 int r, ret = 0;
265a7a2a 3840 bool show_properties, show_status, new_line = false;
729e3769 3841 char **name;
94e0bd7d 3842 bool ellipsized = false;
48220598
LP
3843
3844 assert(bus);
3845 assert(args);
3846
256425cc 3847 show_properties = streq(args[0], "show");
265a7a2a 3848 show_status = streq(args[0], "status");
61cbdc4b 3849
ec14911e 3850 if (show_properties)
1968a360 3851 pager_open_if_enabled();
ec14911e 3852
f84190d8 3853 /* If no argument is specified inspect the manager itself */
48220598 3854
f84190d8 3855 if (show_properties && strv_length(args) <= 1)
94e0bd7d 3856 return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized);
48220598 3857
265a7a2a 3858 if (show_status && strv_length(args) <= 1)
94e0bd7d
ZJS
3859 ret = show_all(args[0], bus, false, &new_line, &ellipsized);
3860 else
3861 STRV_FOREACH(name, args+1) {
f74294c1 3862 _cleanup_free_ char *unit = NULL;
94e0bd7d 3863 uint32_t id;
48220598 3864
94e0bd7d 3865 if (safe_atou32(*name, &id) < 0) {
f74294c1 3866 _cleanup_free_ char *n = NULL;
94e0bd7d 3867 /* Interpret as unit name */
48220598 3868
94e0bd7d
ZJS
3869 n = unit_name_mangle(*name);
3870 if (!n)
3871 return log_oom();
f84190d8 3872
f74294c1
SL
3873 unit = unit_dbus_path_from_name(n);
3874 if (!unit)
94e0bd7d 3875 return log_oom();
48220598 3876
94e0bd7d 3877 } else if (show_properties) {
94e0bd7d 3878 /* Interpret as job id */
f74294c1 3879 if (asprintf(&unit, "/org/freedesktop/systemd1/job/%u", id) < 0)
94e0bd7d 3880 return log_oom();
48220598 3881
94e0bd7d
ZJS
3882 } else {
3883 /* Interpret as PID */
f74294c1 3884 r = get_unit_dbus_path_by_pid(bus, id, &unit);
373d32c9 3885 if (r < 0) {
94e0bd7d 3886 ret = r;
373d32c9
LP
3887 continue;
3888 }
94e0bd7d 3889 }
f74294c1
SL
3890
3891 show_one(args[0], bus, unit, show_properties, &new_line, &ellipsized);
48220598 3892 }
94e0bd7d
ZJS
3893
3894 if (ellipsized && !arg_quiet)
3895 printf("Hint: Some lines were ellipsized, use -l to show in full.\n");
48220598 3896
22f4096c 3897 return ret;
0183528f
LP
3898}
3899
f459b602 3900static int append_assignment(sd_bus_message *m, const char *assignment) {
8e2af478
LP
3901 const char *eq;
3902 char *field;
8e2af478
LP
3903 int r;
3904
f459b602 3905 assert(m);
8e2af478
LP
3906 assert(assignment);
3907
3908 eq = strchr(assignment, '=');
3909 if (!eq) {
3910 log_error("Not an assignment: %s", assignment);
3911 return -EINVAL;
3912 }
3913
3914 field = strndupa(assignment, eq - assignment);
3915 eq ++;
3916
f459b602
MAP
3917 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
3918 if (r < 0)
3919 return bus_log_create_error(r);
8e2af478
LP
3920
3921 if (streq(field, "CPUAccounting") ||
3922 streq(field, "MemoryAccounting") ||
3923 streq(field, "BlockIOAccounting")) {
8e2af478
LP
3924
3925 r = parse_boolean(eq);
3926 if (r < 0) {
3927 log_error("Failed to parse boolean assignment %s.", assignment);
3928 return -EINVAL;
3929 }
3930
f459b602 3931 r = sd_bus_message_append(m, "v", "b", r);
b42defe3 3932
ddca82ac 3933 } else if (streq(field, "MemoryLimit")) {
b42defe3 3934 off_t bytes;
b42defe3
LP
3935
3936 r = parse_bytes(eq, &bytes);
3937 if (r < 0) {
3938 log_error("Failed to parse bytes specification %s", assignment);
3939 return -EINVAL;
3940 }
3941
f459b602 3942 r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
b42defe3
LP
3943
3944 } else if (streq(field, "CPUShares") || streq(field, "BlockIOWeight")) {
3945 uint64_t u;
3946
3947 r = safe_atou64(eq, &u);
3948 if (r < 0) {
3949 log_error("Failed to parse %s value %s.", field, eq);
3950 return -EINVAL;
3951 }
3952
f459b602 3953 r = sd_bus_message_append(m, "v", "t", u);
7041efe9 3954
f459b602
MAP
3955 } else if (streq(field, "DevicePolicy"))
3956 r = sd_bus_message_append(m, "v", "s", eq);
7041efe9 3957
f459b602 3958 else if (streq(field, "DeviceAllow")) {
7041efe9 3959
f459b602
MAP
3960 if (isempty(eq))
3961 r = sd_bus_message_append(m, "v", "a(ss)", 0);
3962 else {
7041efe9 3963 const char *path, *rwm;
7041efe9
LP
3964 char *e;
3965
3966 e = strchr(eq, ' ');
3967 if (e) {
3968 path = strndupa(eq, e - eq);
3969 rwm = e+1;
3970 } else {
3971 path = eq;
3972 rwm = "";
3973 }
3974
67061256
G
3975 if (!path_startswith(path, "/dev")) {
3976 log_error("%s is not a device file in /dev.", path);
3977 return -EINVAL;
3978 }
3979
f459b602 3980 r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
7041efe9
LP
3981 }
3982
67061256 3983 } else if (streq(field, "BlockIOReadBandwidth") || streq(field, "BlockIOWriteBandwidth")) {
67061256 3984
f459b602
MAP
3985 if (isempty(eq))
3986 r = sd_bus_message_append(m, "v", "a(st)", 0);
3987 else {
67061256 3988 const char *path, *bandwidth;
67061256
G
3989 off_t bytes;
3990 char *e;
3991
3992 e = strchr(eq, ' ');
3993 if (e) {
3994 path = strndupa(eq, e - eq);
3995 bandwidth = e+1;
3996 } else {
3997 log_error("Failed to parse %s value %s.", field, eq);
3998 return -EINVAL;
3999 }
4000
4001 if (!path_startswith(path, "/dev")) {
4002 log_error("%s is not a device file in /dev.", path);
4003 return -EINVAL;
4004 }
4005
4006 r = parse_bytes(bandwidth, &bytes);
4007 if (r < 0) {
4008 log_error("Failed to parse byte value %s.", bandwidth);
4009 return -EINVAL;
4010 }
4011
f459b602 4012 r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes);
67061256
G
4013 }
4014
7239c170 4015 } else if (streq(field, "BlockIODeviceWeight")) {
7239c170 4016
f459b602
MAP
4017 if (isempty(eq))
4018 r = sd_bus_message_append(m, "v", "a(st)", 0);
4019 else {
7239c170 4020 const char *path, *weight;
7239c170
G
4021 uint64_t u;
4022 char *e;
4023
4024 e = strchr(eq, ' ');
4025 if (e) {
4026 path = strndupa(eq, e - eq);
4027 weight = e+1;
4028 } else {
4029 log_error("Failed to parse %s value %s.", field, eq);
4030 return -EINVAL;
4031 }
4032
4033 if (!path_startswith(path, "/dev")) {
4034 log_error("%s is not a device file in /dev.", path);
4035 return -EINVAL;
4036 }
4037
4038 r = safe_atou64(weight, &u);
4039 if (r < 0) {
4040 log_error("Failed to parse %s value %s.", field, weight);
4041 return -EINVAL;
4042 }
f459b602 4043 r = sd_bus_message_append(m, "v", "a(st)", path, u);
7239c170
G
4044 }
4045
8e2af478
LP
4046 } else {
4047 log_error("Unknown assignment %s.", assignment);
4048 return -EINVAL;
4049 }
4050
f459b602
MAP
4051 if (r < 0)
4052 return bus_log_create_error(r);
8e2af478
LP
4053
4054 return 0;
4055}
4056
f459b602
MAP
4057static int set_property(sd_bus *bus, char **args) {
4058 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
4059 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
68372da6 4060 _cleanup_free_ char *n = NULL;
8e2af478
LP
4061 char **i;
4062 int r;
4063
f459b602
MAP
4064 r = sd_bus_message_new_method_call(
4065 bus,
8e2af478
LP
4066 "org.freedesktop.systemd1",
4067 "/org/freedesktop/systemd1",
4068 "org.freedesktop.systemd1.Manager",
f459b602
MAP
4069 "SetUnitProperties",
4070 &m);
4071 if (r < 0)
4072 return bus_log_create_error(r);
8e2af478 4073
68372da6
LP
4074 n = unit_name_mangle(args[1]);
4075 if (!n)
4076 return log_oom();
4077
f459b602
MAP
4078 r = sd_bus_message_append(m, "sb", n, arg_runtime);
4079 if (r < 0)
4080 return bus_log_create_error(r);
8e2af478 4081
f459b602
MAP
4082 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, "(sv)");
4083 if (r < 0)
4084 return bus_log_create_error(r);
8e2af478 4085
f459b602
MAP
4086 STRV_FOREACH(i, args + 2) {
4087 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
4088 if (r < 0)
4089 return bus_log_create_error(r);
8e2af478 4090
f459b602 4091 r = append_assignment(m, *i);
8e2af478
LP
4092 if (r < 0)
4093 return r;
4094
f459b602
MAP
4095 r = sd_bus_message_close_container(m);
4096 if (r < 0)
4097 return bus_log_create_error(r);
8e2af478
LP
4098 }
4099
f459b602
MAP
4100 r = sd_bus_message_close_container(m);
4101 if (r < 0)
4102 return bus_log_create_error(r);
8e2af478 4103
c49b30a2 4104 r = sd_bus_call(bus, m, 0, &error, NULL);
f459b602
MAP
4105 if (r < 0) {
4106 log_error("Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
4107 return r;
8e2af478
LP
4108 }
4109
4110 return 0;
4111}
4112
f459b602
MAP
4113static int snapshot(sd_bus *bus, char **args) {
4114 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4115 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4116 _cleanup_free_ char *n = NULL, *id = NULL;
4117 const char *path;
7e4249b9 4118 int r;
7e4249b9 4119
1dcf6065 4120 if (strv_length(args) > 1)
a016b922 4121 n = unit_name_mangle_with_suffix(args[1], ".snapshot");
1dcf6065
LP
4122 else
4123 n = strdup("");
4124 if (!n)
4125 return log_oom();
7e4249b9 4126
f459b602 4127 r = sd_bus_call_method(
f22f08cd
SP
4128 bus,
4129 "org.freedesktop.systemd1",
4130 "/org/freedesktop/systemd1",
4131 "org.freedesktop.systemd1.Manager",
4132 "CreateSnapshot",
f459b602 4133 &error,
f22f08cd 4134 &reply,
f459b602
MAP
4135 "sb", n, false);
4136 if (r < 0) {
4137 log_error("Failed to create snapshot: %s", bus_error_message(&error, r));
1dcf6065 4138 return r;
7e4249b9
LP
4139 }
4140
f459b602
MAP
4141 r = sd_bus_message_read(reply, "o", &path);
4142 if (r < 0)
4143 return bus_log_parse_error(r);
5dd9014f 4144
f459b602 4145 r = sd_bus_get_property_string(
f22f08cd
SP
4146 bus,
4147 "org.freedesktop.systemd1",
4148 path,
f459b602
MAP
4149 "org.freedesktop.systemd1.Unit",
4150 "Id",
4151 &error,
4152 &id);
4153 if (r < 0) {
4154 log_error("Failed to get ID of snapshot: %s", bus_error_message(&error, r));
1dcf6065 4155 return r;
7e4249b9
LP
4156 }
4157
0183528f
LP
4158 if (!arg_quiet)
4159 puts(id);
7e4249b9 4160
1dcf6065 4161 return 0;
7e4249b9
LP
4162}
4163
f459b602
MAP
4164static int delete_snapshot(sd_bus *bus, char **args) {
4165 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
729e3769 4166 char **name;
f459b602 4167 int r;
6759e7a7 4168
6759e7a7
LP
4169 assert(args);
4170
729e3769 4171 STRV_FOREACH(name, args+1) {
5dd9014f 4172 _cleanup_free_ char *n = NULL;
6759e7a7 4173
a016b922 4174 n = unit_name_mangle_with_suffix(*name, ".snapshot");
1dcf6065
LP
4175 if (!n)
4176 return log_oom();
4177
f459b602 4178 r = sd_bus_call_method(
f22f08cd 4179 bus,
b0193f1c
LP
4180 "org.freedesktop.systemd1",
4181 "/org/freedesktop/systemd1",
4182 "org.freedesktop.systemd1.Manager",
5dd9014f 4183 "RemoveSnapshot",
f459b602 4184 &error,
f22f08cd 4185 NULL,
f459b602
MAP
4186 "s", n);
4187 if (r < 0) {
4188 log_error("Failed to remove snapshot %s: %s", n, bus_error_message(&error, r));
5dd9014f 4189 return r;
f459b602 4190 }
6759e7a7
LP
4191 }
4192
5dd9014f 4193 return 0;
6759e7a7
LP
4194}
4195
f459b602
MAP
4196static int daemon_reload(sd_bus *bus, char **args) {
4197 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
7e4249b9 4198 const char *method;
f459b602 4199 int r;
7e4249b9 4200
e4b61340
LP
4201 if (arg_action == ACTION_RELOAD)
4202 method = "Reload";
4203 else if (arg_action == ACTION_REEXEC)
4204 method = "Reexecute";
4205 else {
4206 assert(arg_action == ACTION_SYSTEMCTL);
4207
4208 method =
20b09ca7
LP
4209 streq(args[0], "clear-jobs") ||
4210 streq(args[0], "cancel") ? "ClearJobs" :
4211 streq(args[0], "daemon-reexec") ? "Reexecute" :
4212 streq(args[0], "reset-failed") ? "ResetFailed" :
4213 streq(args[0], "halt") ? "Halt" :
4214 streq(args[0], "poweroff") ? "PowerOff" :
4215 streq(args[0], "reboot") ? "Reboot" :
4216 streq(args[0], "kexec") ? "KExec" :
4217 streq(args[0], "exit") ? "Exit" :
4218 /* "daemon-reload" */ "Reload";
e4b61340 4219 }
7e4249b9 4220
f459b602 4221 r = sd_bus_call_method(
f22f08cd
SP
4222 bus,
4223 "org.freedesktop.systemd1",
4224 "/org/freedesktop/systemd1",
4225 "org.freedesktop.systemd1.Manager",
4226 method,
c516c8d1 4227 &error,
f459b602
MAP
4228 NULL,
4229 NULL);
f22f08cd
SP
4230
4231 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
4232 /* There's always a fallback possible for
4233 * legacy actions. */
4234 r = -EADDRNOTAVAIL;
d0ede8f1
LP
4235 else if ((r == -ETIMEDOUT || r == -ECONNRESET) && streq(method, "Reexecute"))
4236 /* On reexecution, we expect a disconnect, not a
4237 * reply */
f22f08cd 4238 r = 0;
1dcf6065 4239 else if (r < 0)
f459b602 4240 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
7e4249b9 4241
0a9776c2 4242 return r < 0 ? r : 0;
7e4249b9
LP
4243}
4244
f459b602
MAP
4245static int reset_failed(sd_bus *bus, char **args) {
4246 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
f84190d8 4247 char **name;
f459b602 4248 int r;
5632e374 4249
729e3769
LP
4250 if (strv_length(args) <= 1)
4251 return daemon_reload(bus, args);
5632e374 4252
729e3769 4253 STRV_FOREACH(name, args+1) {
f84190d8
LP
4254 _cleanup_free_ char *n;
4255
f22f08cd 4256 n = unit_name_mangle(*name);
f84190d8
LP
4257 if (!n)
4258 return log_oom();
4259
f459b602 4260 r = sd_bus_call_method(
f22f08cd 4261 bus,
b0193f1c
LP
4262 "org.freedesktop.systemd1",
4263 "/org/freedesktop/systemd1",
4264 "org.freedesktop.systemd1.Manager",
f22f08cd 4265 "ResetFailedUnit",
f459b602 4266 &error,
f22f08cd 4267 NULL,
f459b602
MAP
4268 "s", n);
4269 if (r < 0) {
4270 log_error("Failed to reset failed state of unit %s: %s", n, bus_error_message(&error, r));
f84190d8 4271 return r;
f459b602 4272 }
5632e374
LP
4273 }
4274
f84190d8 4275 return 0;
5632e374
LP
4276}
4277
f459b602
MAP
4278static int show_environment(sd_bus *bus, char **args) {
4279 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4280 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4281 const char *text;
7e4249b9 4282 int r;
7e4249b9 4283
1968a360 4284 pager_open_if_enabled();
ec14911e 4285
f459b602 4286 r = sd_bus_get_property(
f22f08cd
SP
4287 bus,
4288 "org.freedesktop.systemd1",
4289 "/org/freedesktop/systemd1",
f459b602
MAP
4290 "org.freedesktop.systemd1.Manager",
4291 "Environment",
4292 &error,
f22f08cd 4293 &reply,
f459b602
MAP
4294 "as");
4295 if (r < 0) {
4296 log_error("Failed to get environment: %s", bus_error_message(&error, r));
f84190d8 4297 return r;
7e4249b9
LP
4298 }
4299
f459b602
MAP
4300 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
4301 if (r < 0)
4302 return bus_log_parse_error(r);
7e4249b9 4303
f459b602 4304 while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0)
f84190d8 4305 puts(text);
f459b602
MAP
4306 if (r < 0)
4307 return bus_log_parse_error(r);
7e4249b9 4308
f459b602
MAP
4309 r = sd_bus_message_exit_container(reply);
4310 if (r < 0)
4311 return bus_log_parse_error(r);
7e4249b9 4312
f84190d8 4313 return 0;
7e4249b9
LP
4314}
4315
f459b602
MAP
4316static int switch_root(sd_bus *bus, char **args) {
4317 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
13068da8 4318 _cleanup_free_ char *init = NULL;
f459b602
MAP
4319 const char *root;
4320 unsigned l;
4321 int r;
957eb8ca
LP
4322
4323 l = strv_length(args);
4324 if (l < 2 || l > 3) {
4325 log_error("Wrong number of arguments.");
4326 return -EINVAL;
4327 }
4328
4329 root = args[1];
13068da8
TG
4330
4331 if (l >= 3)
4332 init = strdup(args[2]);
4333 else {
4334 parse_env_file("/proc/cmdline", WHITESPACE,
4335 "init", &init,
4336 NULL);
4337
4338 if (!init)
4339 init = strdup("");
13068da8 4340 }
f459b602 4341
f84190d8
LP
4342 if (!init)
4343 return log_oom();
13068da8
TG
4344
4345 log_debug("switching root - root: %s; init: %s", root, init);
957eb8ca 4346
f459b602 4347 r = sd_bus_call_method(
f22f08cd 4348 bus,
957eb8ca
LP
4349 "org.freedesktop.systemd1",
4350 "/org/freedesktop/systemd1",
4351 "org.freedesktop.systemd1.Manager",
f22f08cd 4352 "SwitchRoot",
f459b602 4353 &error,
f22f08cd 4354 NULL,
f459b602
MAP
4355 "ss", root, init);
4356 if (r < 0) {
4357 log_error("Failed to switch root: %s", bus_error_message(&error, r));
4358 return r;
4359 }
4360
4361 return 0;
957eb8ca
LP
4362}
4363
f459b602
MAP
4364static int set_environment(sd_bus *bus, char **args) {
4365 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4366 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
7e4249b9 4367 const char *method;
31e767f7
LP
4368 int r;
4369
4370 assert(bus);
60f9ba0b 4371 assert(args);
7e4249b9 4372
7e4249b9
LP
4373 method = streq(args[0], "set-environment")
4374 ? "SetEnvironment"
4375 : "UnsetEnvironment";
4376
f459b602
MAP
4377 r = sd_bus_message_new_method_call(
4378 bus,
31e767f7
LP
4379 "org.freedesktop.systemd1",
4380 "/org/freedesktop/systemd1",
4381 "org.freedesktop.systemd1.Manager",
f459b602
MAP
4382 method,
4383 &m);
4384 if (r < 0)
4385 return bus_log_create_error(r);
7e4249b9 4386
f459b602 4387 r = sd_bus_message_append_strv(m, args + 1);
31e767f7 4388 if (r < 0)
f459b602 4389 return bus_log_create_error(r);
7e4249b9 4390
c49b30a2 4391 r = sd_bus_call(bus, m, 0, &error, NULL);
f459b602
MAP
4392 if (r < 0) {
4393 log_error("Failed to set environment: %s", bus_error_message(&error, r));
4394 return r;
7e4249b9
LP
4395 }
4396
f84190d8 4397 return 0;
7e4249b9
LP
4398}
4399
cbb13b2a 4400static int enable_sysv_units(const char *verb, char **args) {
729e3769 4401 int r = 0;
ee5762e3 4402
77e68fa2 4403#if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
729e3769 4404 unsigned f = 1, t = 1;
fb15be83 4405 _cleanup_lookup_paths_free_ LookupPaths paths = {};
ee5762e3 4406
729e3769
LP
4407 if (arg_scope != UNIT_FILE_SYSTEM)
4408 return 0;
ee5762e3 4409
729e3769
LP
4410 if (!streq(verb, "enable") &&
4411 !streq(verb, "disable") &&
4412 !streq(verb, "is-enabled"))
4413 return 0;
ee5762e3 4414
729e3769
LP
4415 /* Processes all SysV units, and reshuffles the array so that
4416 * afterwards only the native units remain */
ee5762e3 4417
67445f4e 4418 r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL);
729e3769
LP
4419 if (r < 0)
4420 return r;
ee5762e3 4421
729e3769 4422 r = 0;
cbb13b2a 4423 for (f = 0; args[f]; f++) {
729e3769 4424 const char *name;
7fd1b19b 4425 _cleanup_free_ char *p = NULL, *q = NULL;
729e3769
LP
4426 bool found_native = false, found_sysv;
4427 unsigned c = 1;
4428 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
4b6756a8 4429 char **k, *l;
729e3769
LP
4430 int j;
4431 pid_t pid;
4432 siginfo_t status;
ee5762e3 4433
729e3769 4434 name = args[f];
ee5762e3 4435
729e3769
LP
4436 if (!endswith(name, ".service"))
4437 continue;
ee5762e3 4438
729e3769
LP
4439 if (path_is_absolute(name))
4440 continue;
ee5762e3 4441
729e3769 4442 STRV_FOREACH(k, paths.unit_path) {
729e3769
LP
4443 if (!isempty(arg_root))
4444 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
4445 else
4446 asprintf(&p, "%s/%s", *k, name);
ee5762e3 4447
729e3769 4448 if (!p) {
0d0f0c50 4449 r = log_oom();
729e3769
LP
4450 goto finish;
4451 }
ee5762e3 4452
729e3769
LP
4453 found_native = access(p, F_OK) >= 0;
4454 free(p);
4b6756a8 4455 p = NULL;
ee5762e3 4456
729e3769
LP
4457 if (found_native)
4458 break;
4459 }
ee5762e3 4460
729e3769
LP
4461 if (found_native)
4462 continue;
ee5762e3 4463
729e3769
LP
4464 if (!isempty(arg_root))
4465 asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
4466 else
4467 asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
4468 if (!p) {
0d0f0c50 4469 r = log_oom();
729e3769
LP
4470 goto finish;
4471 }
ee5762e3 4472
729e3769
LP
4473 p[strlen(p) - sizeof(".service") + 1] = 0;
4474 found_sysv = access(p, F_OK) >= 0;
ee5762e3 4475
4b6756a8 4476 if (!found_sysv)
729e3769 4477 continue;
71fad675 4478
729e3769
LP
4479 /* Mark this entry, so that we don't try enabling it as native unit */
4480 args[f] = (char*) "";
ee5762e3 4481
729e3769 4482 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
ee5762e3 4483
729e3769
LP
4484 if (!isempty(arg_root))
4485 argv[c++] = q = strappend("--root=", arg_root);
ee5762e3 4486
2b6bf07d 4487 argv[c++] = basename(p);
729e3769
LP
4488 argv[c++] =
4489 streq(verb, "enable") ? "on" :
4490 streq(verb, "disable") ? "off" : "--level=5";
4491 argv[c] = NULL;
ee5762e3 4492
729e3769
LP
4493 l = strv_join((char**)argv, " ");
4494 if (!l) {
0d0f0c50 4495 r = log_oom();
729e3769
LP
4496 goto finish;
4497 }
ee5762e3 4498
729e3769
LP
4499 log_info("Executing %s", l);
4500 free(l);
ee5762e3 4501
729e3769
LP
4502 pid = fork();
4503 if (pid < 0) {
4504 log_error("Failed to fork: %m");
729e3769
LP
4505 r = -errno;
4506 goto finish;
4507 } else if (pid == 0) {
4508 /* Child */
ee5762e3 4509
729e3769
LP
4510 execv(argv[0], (char**) argv);
4511 _exit(EXIT_FAILURE);
4512 }
ee5762e3 4513
729e3769
LP
4514 j = wait_for_terminate(pid, &status);
4515 if (j < 0) {
4516 log_error("Failed to wait for child: %s", strerror(-r));
4517 r = j;
4518 goto finish;
4519 }
ee5762e3 4520
729e3769
LP
4521 if (status.si_code == CLD_EXITED) {
4522 if (streq(verb, "is-enabled")) {
4523 if (status.si_status == 0) {
4524 if (!arg_quiet)
4525 puts("enabled");
4526 r = 1;
4527 } else {
4528 if (!arg_quiet)
4529 puts("disabled");
4530 }
ee5762e3 4531
729e3769
LP
4532 } else if (status.si_status != 0) {
4533 r = -EINVAL;
4534 goto finish;
4535 }
4536 } else {
4537 r = -EPROTO;
4538 goto finish;
4539 }
ee5762e3
LP
4540 }
4541
729e3769 4542finish:
729e3769 4543 /* Drop all SysV units */
cbb13b2a 4544 for (f = 0, t = 0; args[f]; f++) {
ee5762e3 4545
729e3769 4546 if (isempty(args[f]))
ee5762e3
LP
4547 continue;
4548
729e3769
LP
4549 args[t++] = args[f];
4550 }
ee5762e3 4551
729e3769 4552 args[t] = NULL;
ee5762e3 4553
729e3769
LP
4554#endif
4555 return r;
4556}
ee5762e3 4557
37370d0c 4558static int mangle_names(char **original_names, char ***mangled_names) {
a33fdebb 4559 char **i, **l, **name;
37370d0c 4560
a33fdebb
LP
4561 l = new(char*, strv_length(original_names) + 1);
4562 if (!l)
37370d0c
VP
4563 return log_oom();
4564
a33fdebb 4565 i = l;
37370d0c 4566 STRV_FOREACH(name, original_names) {
44386fc1
LN
4567
4568 /* When enabling units qualified path names are OK,
4569 * too, hence allow them explicitly. */
4570
4571 if (is_path(*name))
4572 *i = strdup(*name);
4573 else
4574 *i = unit_name_mangle(*name);
4575
a33fdebb
LP
4576 if (!*i) {
4577 strv_free(l);
37370d0c 4578 return log_oom();
a33fdebb
LP
4579 }
4580
4581 i++;
37370d0c 4582 }
a33fdebb
LP
4583
4584 *i = NULL;
4585 *mangled_names = l;
37370d0c
VP
4586
4587 return 0;
4588}
4589
f459b602 4590static int enable_unit(sd_bus *bus, char **args) {
f459b602 4591 _cleanup_strv_free_ char **mangled_names = NULL;
729e3769
LP
4592 const char *verb = args[0];
4593 UnitFileChange *changes = NULL;
718db961 4594 unsigned n_changes = 0;
729e3769 4595 int carries_install_info = -1;
729e3769 4596 int r;
ee5762e3 4597
ab5919fa
MS
4598 if (!args[1])
4599 return 0;
4600
3a05c0f9
VP
4601 r = mangle_names(args+1, &mangled_names);
4602 if (r < 0)
cbb13b2a
VP
4603 return r;
4604
4605 r = enable_sysv_units(verb, mangled_names);
4606 if (r < 0)
4607 return r;
3a05c0f9 4608
729e3769
LP
4609 if (!bus || avoid_bus()) {
4610 if (streq(verb, "enable")) {
3a05c0f9 4611 r = unit_file_enable(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
729e3769
LP
4612 carries_install_info = r;
4613 } else if (streq(verb, "disable"))
3a05c0f9 4614 r = unit_file_disable(arg_scope, arg_runtime, arg_root, mangled_names, &changes, &n_changes);
729e3769 4615 else if (streq(verb, "reenable")) {
3a05c0f9 4616 r = unit_file_reenable(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
729e3769
LP
4617 carries_install_info = r;
4618 } else if (streq(verb, "link"))
3a05c0f9 4619 r = unit_file_link(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
729e3769 4620 else if (streq(verb, "preset")) {
3a05c0f9 4621 r = unit_file_preset(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
729e3769
LP
4622 carries_install_info = r;
4623 } else if (streq(verb, "mask"))
3a05c0f9 4624 r = unit_file_mask(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
729e3769 4625 else if (streq(verb, "unmask"))
3a05c0f9 4626 r = unit_file_unmask(arg_scope, arg_runtime, arg_root, mangled_names, &changes, &n_changes);
729e3769
LP
4627 else
4628 assert_not_reached("Unknown verb");
ee5762e3 4629
729e3769
LP
4630 if (r < 0) {
4631 log_error("Operation failed: %s", strerror(-r));
4632 goto finish;
ee5762e3
LP
4633 }
4634
718db961
LP
4635 if (!arg_quiet)
4636 dump_unit_file_changes(changes, n_changes);
ee5762e3 4637
df77cdf0 4638 r = 0;
729e3769 4639 } else {
718db961
LP
4640 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
4641 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
f459b602
MAP
4642 int expect_carries_install_info = false;
4643 bool send_force = true;
718db961 4644 const char *method;
729e3769
LP
4645
4646 if (streq(verb, "enable")) {
4647 method = "EnableUnitFiles";
4648 expect_carries_install_info = true;
4649 } else if (streq(verb, "disable")) {
4650 method = "DisableUnitFiles";
4651 send_force = false;
4652 } else if (streq(verb, "reenable")) {
4653 method = "ReenableUnitFiles";
4654 expect_carries_install_info = true;
4655 } else if (streq(verb, "link"))
4656 method = "LinkUnitFiles";
4657 else if (streq(verb, "preset")) {
4658 method = "PresetUnitFiles";
4659 expect_carries_install_info = true;
4660 } else if (streq(verb, "mask"))
4661 method = "MaskUnitFiles";
4662 else if (streq(verb, "unmask")) {
4663 method = "UnmaskUnitFiles";
4664 send_force = false;
4665 } else
4666 assert_not_reached("Unknown verb");
4667
f459b602
MAP
4668 r = sd_bus_message_new_method_call(
4669 bus,
729e3769
LP
4670 "org.freedesktop.systemd1",
4671 "/org/freedesktop/systemd1",
4672 "org.freedesktop.systemd1.Manager",
f459b602
MAP
4673 method,
4674 &m);
4675 if (r < 0)
4676 return bus_log_create_error(r);
ee5762e3 4677
f459b602
MAP
4678 r = sd_bus_message_append_strv(m, mangled_names);
4679 if (r < 0)
4680 return bus_log_create_error(r);
ee5762e3 4681
f459b602
MAP
4682 r = sd_bus_message_append(m, "b", arg_runtime);
4683 if (r < 0)
4684 return bus_log_create_error(r);
ee5762e3 4685
729e3769 4686 if (send_force) {
f459b602
MAP
4687 r = sd_bus_message_append(m, "b", arg_force);
4688 if (r < 0)
4689 return bus_log_create_error(r);
ee5762e3
LP
4690 }
4691
c49b30a2 4692 r = sd_bus_call(bus, m, 0, &error, &reply);
f459b602
MAP
4693 if (r < 0) {
4694 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
4695 return r;
729e3769 4696 }
be394c48 4697
729e3769 4698 if (expect_carries_install_info) {
f459b602
MAP
4699 r = sd_bus_message_read(reply, "b", &carries_install_info);
4700 if (r < 0)
4701 return bus_log_parse_error(r);
ee5762e3
LP
4702 }
4703
cc3f2093 4704 r = deserialize_and_dump_unit_file_changes(reply);
f459b602 4705 if (r < 0)
718db961 4706 return r;
b77398f7 4707
729e3769 4708 /* Try to reload if enabeld */
d6cb60c7 4709 if (!arg_no_reload)
729e3769 4710 r = daemon_reload(bus, args);
f459b602
MAP
4711 else
4712 r = 0;
b647f10d 4713 }
3d3961f2 4714
729e3769 4715 if (carries_install_info == 0)
416389f7
LP
4716 log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
4717 "using systemctl.\n"
4718 "Possible reasons for having this kind of units are:\n"
4719 "1) A unit may be statically enabled by being symlinked from another unit's\n"
4720 " .wants/ or .requires/ directory.\n"
4721 "2) A unit's purpose may be to act as a helper for some other unit which has\n"
4722 " a requirement dependency on it.\n"
4723 "3) A unit may be started when needed via activation (socket, path, timer,\n"
4724 " D-Bus, udev, scripted systemctl call, ...).\n");
ee5762e3 4725
729e3769 4726finish:
729e3769 4727 unit_file_changes_free(changes, n_changes);
ee5762e3 4728
729e3769 4729 return r;
ee5762e3
LP
4730}
4731
f459b602
MAP
4732static int unit_is_enabled(sd_bus *bus, char **args) {
4733
4734 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4735 _cleanup_strv_free_ char **mangled_names = NULL;
729e3769
LP
4736 bool enabled;
4737 char **name;
f459b602 4738 int r;
ee5762e3 4739
cbb13b2a
VP
4740 r = mangle_names(args+1, &mangled_names);
4741 if (r < 0)
4742 return r;
4743
4744 r = enable_sysv_units(args[0], mangled_names);
729e3769
LP
4745 if (r < 0)
4746 return r;
ee5762e3 4747
729e3769 4748 enabled = r > 0;
ee5762e3 4749
729e3769 4750 if (!bus || avoid_bus()) {
ee5762e3 4751
cbb13b2a 4752 STRV_FOREACH(name, mangled_names) {
729e3769 4753 UnitFileState state;
ee5762e3 4754
cbb13b2a 4755 state = unit_file_get_state(arg_scope, arg_root, *name);
cbc9fbd1
LP
4756 if (state < 0) {
4757 log_error("Failed to get unit file state for %s: %s", *name, strerror(-state));
cec7eda5 4758 return state;
cbc9fbd1 4759 }
ee5762e3 4760
729e3769
LP
4761 if (state == UNIT_FILE_ENABLED ||
4762 state == UNIT_FILE_ENABLED_RUNTIME ||
4763 state == UNIT_FILE_STATIC)
4764 enabled = true;
4765
4766 if (!arg_quiet)
4767 puts(unit_file_state_to_string(state));
71fad675 4768 }
ee5762e3 4769
729e3769 4770 } else {
cbb13b2a 4771 STRV_FOREACH(name, mangled_names) {
f459b602 4772 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
729e3769 4773 const char *s;
63a723f3 4774
f459b602 4775 r = sd_bus_call_method(
f22f08cd 4776 bus,
729e3769
LP
4777 "org.freedesktop.systemd1",
4778 "/org/freedesktop/systemd1",
4779 "org.freedesktop.systemd1.Manager",
f22f08cd 4780 "GetUnitFileState",
f459b602 4781 &error,
f22f08cd 4782 &reply,
04504f93 4783 "s", *name);
f459b602
MAP
4784 if (r < 0) {
4785 log_error("Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
cec7eda5 4786 return r;
ee5762e3
LP
4787 }
4788
f459b602
MAP
4789 r = sd_bus_message_read(reply, "s", &s);
4790 if (r < 0)
4791 return bus_log_parse_error(r);
ee5762e3 4792
729e3769
LP
4793 if (streq(s, "enabled") ||
4794 streq(s, "enabled-runtime") ||
4795 streq(s, "static"))
4796 enabled = true;
4797
4798 if (!arg_quiet)
4799 puts(s);
560d8f23 4800 }
ee5762e3
LP
4801 }
4802
f459b602 4803 return !enabled;
ee5762e3
LP
4804}
4805
e4b61340 4806static int systemctl_help(void) {
7e4249b9 4807
729e3769
LP
4808 pager_open_if_enabled();
4809
2e33c433 4810 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
729e3769 4811 "Query or send control commands to the systemd manager.\n\n"
8a0867d6
LP
4812 " -h --help Show this help\n"
4813 " --version Show package version\n"
f459b602
MAP
4814 " --system Connect to system manager\n"
4815 " --user Connect to user service manager\n"
4816 " -H --host=[USER@]HOST\n"
4817 " Operate on remote host\n"
4818 " -M --machine=CONTAINER\n"
4819 " Operate on local container\n"
8a0867d6 4820 " -t --type=TYPE List only units of a particular type\n"
a521ae4a 4821 " --state=STATE List only units with particular LOAD or SUB or ACTIVE state\n"
8a0867d6 4822 " -p --property=NAME Show only properties by this name\n"
a5e4972c
LP
4823 " -a --all Show all loaded units/properties, including dead/empty\n"
4824 " ones. To list all units installed on the system, use\n"
4825 " the 'list-unit-files' command instead.\n"
98a6e132 4826 " -l --full Don't ellipsize unit names on output\n"
4dc5b821
LP
4827 " --reverse Show reverse dependencies with 'list-dependencies'\n"
4828 " --job-mode=MODE Specify how to deal with already queued jobs, when\n"
4829 " queueing a new job\n"
a521ae4a 4830 " --show-types When showing sockets, explicitly show their type\n"
b37844d3
LP
4831 " -i --ignore-inhibitors\n"
4832 " When shutting down or sleeping, ignore inhibitors\n"
a8f11321
LP
4833 " --kill-who=WHO Who to send signal to\n"
4834 " -s --signal=SIGNAL Which signal to send\n"
8a0867d6
LP
4835 " -q --quiet Suppress output\n"
4836 " --no-block Do not wait until operation finished\n"
8a0867d6 4837 " --no-wall Don't send wall message before halt/power-off/reboot\n"
8a0867d6
LP
4838 " --no-reload When enabling/disabling unit files, don't reload daemon\n"
4839 " configuration\n"
ebed32bf 4840 " --no-legend Do not print a legend (column headers and hints)\n"
69fc152f 4841 " --no-pager Do not pipe output into a pager\n"
501fc174
LP
4842 " --no-ask-password\n"
4843 " Do not ask for system passwords\n"
a8f11321 4844 " --global Enable/disable unit files globally\n"
a521ae4a 4845 " --runtime Enable unit files only temporarily until next reboot\n"
8a0867d6
LP
4846 " -f --force When enabling unit files, override existing symlinks\n"
4847 " When shutting down, execute action immediately\n"
729e3769 4848 " --root=PATH Enable unit files in the specified root directory\n"
76fdc966 4849 " -n --lines=INTEGER Number of journal entries to show\n"
d3f2bdbf 4850 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
815ebc54
DH
4851 " verbose, export, json, json-pretty, json-sse, cat)\n"
4852 " --plain Print unit dependencies as a list instead of a tree\n\n"
34c4b47b 4853 "Unit Commands:\n"
d8fba7c6
ZJS
4854 " list-units [PATTERN...] List loaded units\n"
4855 " list-sockets [PATTERN...] List loaded sockets ordered by address\n"
4856 " list-timers [PATTERN...] List loaded timers ordered by next elapse\n"
4f8f66cb
ZJS
4857 " start NAME... Start (activate) one or more units\n"
4858 " stop NAME... Stop (deactivate) one or more units\n"
4859 " reload NAME... Reload one or more units\n"
4860 " restart NAME... Start or restart one or more units\n"
4861 " try-restart NAME... Restart one or more units if active\n"
4862 " reload-or-restart NAME... Reload one or more units if possible,\n"
6f28c033 4863 " otherwise start or restart\n"
4f8f66cb 4864 " reload-or-try-restart NAME... Reload one or more units if possible,\n"
6f28c033 4865 " otherwise restart if active\n"
4f8f66cb
ZJS
4866 " isolate NAME Start one unit and stop all others\n"
4867 " kill NAME... Send signal to processes of a unit\n"
4868 " is-active NAME... Check whether units are active\n"
4869 " is-failed NAME... Check whether units are failed\n"
75676b72 4870 " status [NAME...|PID...] Show runtime status of one or more units\n"
6f28c033 4871 " show [NAME...|JOB...] Show properties of one or more\n"
ee5762e3 4872 " units/jobs or the manager\n"
4f8f66cb
ZJS
4873 " cat NAME... Show files and drop-ins of one or more units\n"
4874 " set-property NAME ASSIGNMENT... Sets one or more properties of a unit\n"
4875 " help NAME...|PID... Show manual for one or more units\n"
fdf20a31
MM
4876 " reset-failed [NAME...] Reset failed state for all, one, or more\n"
4877 " units\n"
55c0b89c 4878 " list-dependencies [NAME] Recursively show units which are required\n"
afba4199
ZJS
4879 " or wanted by this unit or by which this\n"
4880 " unit is required or wanted\n\n"
34c4b47b 4881 "Unit File Commands:\n"
d8fba7c6 4882 " list-unit-files [PATTERN...] List installed unit files\n"
4f8f66cb
ZJS
4883 " enable NAME... Enable one or more unit files\n"
4884 " disable NAME... Disable one or more unit files\n"
4885 " reenable NAME... Reenable one or more unit files\n"
4886 " preset NAME... Enable/disable one or more unit files\n"
729e3769 4887 " based on preset configuration\n"
4f8f66cb
ZJS
4888 " is-enabled NAME... Check whether unit files are enabled\n\n"
4889 " mask NAME... Mask one or more units\n"
4890 " unmask NAME... Unmask one or more units\n"
4891 " link PATH... Link one or more units files into\n"
729e3769 4892 " the search path\n"
99504dd4 4893 " get-default Get the name of the default target\n"
f535088e 4894 " set-default NAME Set the default target\n\n"
34c4b47b 4895 "Job Commands:\n"
d8fba7c6 4896 " list-jobs [PATTERN...] List jobs\n"
34c4b47b 4897 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
34c4b47b 4898 "Snapshot Commands:\n"
7e4249b9 4899 " snapshot [NAME] Create a snapshot\n"
4f8f66cb 4900 " delete NAME... Remove one or more snapshots\n\n"
34c4b47b 4901 "Environment Commands:\n"
7e4249b9 4902 " show-environment Dump environment\n"
4f8f66cb
ZJS
4903 " set-environment NAME=VALUE... Set one or more environment variables\n"
4904 " unset-environment NAME... Unset one or more environment variables\n\n"
34c4b47b
LP
4905 "Manager Lifecycle Commands:\n"
4906 " daemon-reload Reload systemd manager configuration\n"
4907 " daemon-reexec Reexecute systemd manager\n\n"
4908 "System Commands:\n"
20b09ca7
LP
4909 " default Enter system default mode\n"
4910 " rescue Enter system rescue mode\n"
4911 " emergency Enter system emergency mode\n"
514f4ef5 4912 " halt Shut down and halt the system\n"
2e33c433 4913 " poweroff Shut down and power-off the system\n"
37185ec8 4914 " reboot [ARG] Shut down and reboot the system\n"
20b09ca7 4915 " kexec Shut down and reboot the system with kexec\n"
6edd7d0a 4916 " exit Request user instance exit\n"
4f8f66cb 4917 " switch-root ROOT [INIT] Change to a different root file system\n"
6edd7d0a 4918 " suspend Suspend the system\n"
6524990f
LP
4919 " hibernate Hibernate the system\n"
4920 " hybrid-sleep Hibernate and suspend the system\n",
5b6319dc 4921 program_invocation_short_name);
7e4249b9
LP
4922
4923 return 0;
4924}
4925
e4b61340
LP
4926static int halt_help(void) {
4927
37185ec8 4928 printf("%s [OPTIONS...]%s\n\n"
e4b61340
LP
4929 "%s the system.\n\n"
4930 " --help Show this help\n"
4931 " --halt Halt the machine\n"
4932 " -p --poweroff Switch off the machine\n"
4933 " --reboot Reboot the machine\n"
2e33c433
LP
4934 " -f --force Force immediate halt/power-off/reboot\n"
4935 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
e4b61340 4936 " -d --no-wtmp Don't write wtmp record\n"
2e33c433 4937 " --no-wall Don't send wall message before halt/power-off/reboot\n",
e4b61340 4938 program_invocation_short_name,
37185ec8 4939 arg_action == ACTION_REBOOT ? " [ARG]" : "",
e4b61340
LP
4940 arg_action == ACTION_REBOOT ? "Reboot" :
4941 arg_action == ACTION_POWEROFF ? "Power off" :
4942 "Halt");
4943
4944 return 0;
4945}
4946
4947static int shutdown_help(void) {
4948
08e4b1c5 4949 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
e4b61340
LP
4950 "Shut down the system.\n\n"
4951 " --help Show this help\n"
4952 " -H --halt Halt the machine\n"
4953 " -P --poweroff Power-off the machine\n"
4954 " -r --reboot Reboot the machine\n"
386da858 4955 " -h Equivalent to --poweroff, overridden by --halt\n"
2e33c433 4956 " -k Don't halt/power-off/reboot, just send warnings\n"
f6144808 4957 " --no-wall Don't send wall message before halt/power-off/reboot\n"
f6144808 4958 " -c Cancel a pending shutdown\n",
e4b61340
LP
4959 program_invocation_short_name);
4960
4961 return 0;
4962}
4963
4964static int telinit_help(void) {
4965
2e33c433 4966 printf("%s [OPTIONS...] {COMMAND}\n\n"
514f4ef5
LP
4967 "Send control commands to the init daemon.\n\n"
4968 " --help Show this help\n"
2e33c433 4969 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
e4b61340
LP
4970 "Commands:\n"
4971 " 0 Power-off the machine\n"
4972 " 6 Reboot the machine\n"
514f4ef5
LP
4973 " 2, 3, 4, 5 Start runlevelX.target unit\n"
4974 " 1, s, S Enter rescue mode\n"
4975 " q, Q Reload init daemon configuration\n"
4976 " u, U Reexecute init daemon\n",
e4b61340
LP
4977 program_invocation_short_name);
4978
4979 return 0;
4980}
4981
4982static int runlevel_help(void) {
4983
2e33c433 4984 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
4985 "Prints the previous and current runlevel of the init system.\n\n"
4986 " --help Show this help\n",
4987 program_invocation_short_name);
4988
4989 return 0;
4990}
4991
45c0c61d
ZJS
4992static int help_types(void) {
4993 int i;
830f01f0 4994 const char *t;
45c0c61d
ZJS
4995
4996 puts("Available unit types:");
f168c273 4997 for (i = 0; i < _UNIT_TYPE_MAX; i++) {
830f01f0
LP
4998 t = unit_type_to_string(i);
4999 if (t)
5000 puts(t);
5001 }
45c0c61d 5002
45c0c61d
ZJS
5003 return 0;
5004}
5005
e4b61340 5006static int systemctl_parse_argv(int argc, char *argv[]) {
7e4249b9
LP
5007
5008 enum {
90d473a1 5009 ARG_FAIL = 0x100,
afba4199
ZJS
5010 ARG_REVERSE,
5011 ARG_AFTER,
5012 ARG_BEFORE,
991f2a39 5013 ARG_SHOW_TYPES,
23ade460 5014 ARG_IRREVERSIBLE,
e67c3609 5015 ARG_IGNORE_DEPENDENCIES,
35df8f27 5016 ARG_VERSION,
af2d49f7 5017 ARG_USER,
7e4249b9 5018 ARG_SYSTEM,
ee5762e3 5019 ARG_GLOBAL,
6e905d93 5020 ARG_NO_BLOCK,
ebed32bf 5021 ARG_NO_LEGEND,
611efaac 5022 ARG_NO_PAGER,
4445a875 5023 ARG_NO_WALL,
be394c48 5024 ARG_ROOT,
ee5762e3 5025 ARG_NO_RELOAD,
501fc174 5026 ARG_KILL_WHO,
30732560 5027 ARG_NO_ASK_PASSWORD,
729e3769 5028 ARG_FAILED,
df50185b 5029 ARG_RUNTIME,
5d0c05e5 5030 ARG_FORCE,
9b9b3d36 5031 ARG_PLAIN,
4dc5b821
LP
5032 ARG_STATE,
5033 ARG_JOB_MODE
7e4249b9
LP
5034 };
5035
5036 static const struct option options[] = {
9ea9d4cf
LP
5037 { "help", no_argument, NULL, 'h' },
5038 { "version", no_argument, NULL, ARG_VERSION },
5039 { "type", required_argument, NULL, 't' },
5040 { "property", required_argument, NULL, 'p' },
5041 { "all", no_argument, NULL, 'a' },
5042 { "reverse", no_argument, NULL, ARG_REVERSE },
5043 { "after", no_argument, NULL, ARG_AFTER },
5044 { "before", no_argument, NULL, ARG_BEFORE },
5045 { "show-types", no_argument, NULL, ARG_SHOW_TYPES },
5046 { "failed", no_argument, NULL, ARG_FAILED }, /* compatibility only */
5047 { "full", no_argument, NULL, 'l' },
4dc5b821
LP
5048 { "job-mode", required_argument, NULL, ARG_JOB_MODE },
5049 { "fail", no_argument, NULL, ARG_FAIL }, /* compatibility only */
5050 { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, /* compatibility only */
5051 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */
9ea9d4cf
LP
5052 { "ignore-inhibitors", no_argument, NULL, 'i' },
5053 { "user", no_argument, NULL, ARG_USER },
5054 { "system", no_argument, NULL, ARG_SYSTEM },
5055 { "global", no_argument, NULL, ARG_GLOBAL },
5056 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
5057 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
5058 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
5059 { "no-wall", no_argument, NULL, ARG_NO_WALL },
5060 { "quiet", no_argument, NULL, 'q' },
5061 { "root", required_argument, NULL, ARG_ROOT },
5062 { "force", no_argument, NULL, ARG_FORCE },
5063 { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
5064 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
5065 { "signal", required_argument, NULL, 's' },
5066 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
5067 { "host", required_argument, NULL, 'H' },
f459b602 5068 { "machine", required_argument, NULL, 'M' },
9ea9d4cf
LP
5069 { "runtime", no_argument, NULL, ARG_RUNTIME },
5070 { "lines", required_argument, NULL, 'n' },
5071 { "output", required_argument, NULL, 'o' },
5072 { "plain", no_argument, NULL, ARG_PLAIN },
5073 { "state", required_argument, NULL, ARG_STATE },
eb9da376 5074 {}
7e4249b9
LP
5075 };
5076
5077 int c;
5078
e4b61340 5079 assert(argc >= 0);
7e4249b9
LP
5080 assert(argv);
5081
f459b602 5082 while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:i", options, NULL)) >= 0) {
7e4249b9
LP
5083
5084 switch (c) {
5085
5086 case 'h':
eb9da376 5087 return systemctl_help();
35df8f27
LP
5088
5089 case ARG_VERSION:
5090 puts(PACKAGE_STRING);
7d568925 5091 puts(SYSTEMD_FEATURES);
35df8f27 5092 return 0;
7e4249b9 5093
20b3f379
ZJS
5094 case 't': {
5095 char *word, *state;
5096 size_t size;
45c0c61d 5097
20b3f379 5098 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
7fd1b19b 5099 _cleanup_free_ char *type;
20b3f379
ZJS
5100
5101 type = strndup(word, size);
5102 if (!type)
5103 return -ENOMEM;
5104
5105 if (streq(type, "help")) {
5106 help_types();
5107 return 0;
5108 }
5109
5110 if (unit_type_from_string(type) >= 0) {
5111 if (strv_push(&arg_types, type))
5112 return log_oom();
5113 type = NULL;
5114 continue;
5115 }
5116
9b9b3d36
MW
5117 /* It's much nicer to use --state= for
5118 * load states, but let's support this
5119 * in --types= too for compatibility
5120 * with old versions */
20b3f379 5121 if (unit_load_state_from_string(optarg) >= 0) {
9b9b3d36 5122 if (strv_push(&arg_states, type) < 0)
20b3f379
ZJS
5123 return log_oom();
5124 type = NULL;
5125 continue;
5126 }
5127
ab06eef8 5128 log_error("Unknown unit type or load state '%s'.", type);
20b3f379
ZJS
5129 log_info("Use -t help to see a list of allowed values.");
5130 return -EINVAL;
c147dc42 5131 }
20b3f379
ZJS
5132
5133 break;
5134 }
5135
ea4a240d 5136 case 'p': {
033a842c
ZJS
5137 /* Make sure that if the empty property list
5138 was specified, we won't show any properties. */
20b3f379 5139 if (isempty(optarg) && !arg_properties) {
cbc9fbd1 5140 arg_properties = new0(char*, 1);
20b3f379
ZJS
5141 if (!arg_properties)
5142 return log_oom();
5143 } else {
5144 char *word, *state;
5145 size_t size;
033a842c 5146
20b3f379
ZJS
5147 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
5148 char *prop;
033a842c 5149
20b3f379
ZJS
5150 prop = strndup(word, size);
5151 if (!prop)
5152 return log_oom();
ea4a240d 5153
9b9b3d36 5154 if (strv_push(&arg_properties, prop) < 0) {
20b3f379
ZJS
5155 free(prop);
5156 return log_oom();
5157 }
5158 }
033a842c 5159 }
48220598
LP
5160
5161 /* If the user asked for a particular
5162 * property, show it to him, even if it is
5163 * empty. */
5164 arg_all = true;
033a842c 5165
48220598 5166 break;
ea4a240d 5167 }
48220598 5168
7e4249b9
LP
5169 case 'a':
5170 arg_all = true;
5171 break;
5172
afba4199
ZJS
5173 case ARG_REVERSE:
5174 arg_dependency = DEPENDENCY_REVERSE;
5175 break;
5176
5177 case ARG_AFTER:
5178 arg_dependency = DEPENDENCY_AFTER;
5179 break;
5180
5181 case ARG_BEFORE:
5182 arg_dependency = DEPENDENCY_BEFORE;
5183 break;
5184
991f2a39
ZJS
5185 case ARG_SHOW_TYPES:
5186 arg_show_types = true;
5187 break;
5188
4dc5b821
LP
5189 case ARG_JOB_MODE:
5190 arg_job_mode = optarg;
5191 break;
5192
90d473a1 5193 case ARG_FAIL:
e67c3609
LP
5194 arg_job_mode = "fail";
5195 break;
5196
23ade460
MS
5197 case ARG_IRREVERSIBLE:
5198 arg_job_mode = "replace-irreversibly";
5199 break;
5200
e67c3609
LP
5201 case ARG_IGNORE_DEPENDENCIES:
5202 arg_job_mode = "ignore-dependencies";
7e4249b9
LP
5203 break;
5204
af2d49f7 5205 case ARG_USER:
729e3769 5206 arg_scope = UNIT_FILE_USER;
7e4249b9
LP
5207 break;
5208
5209 case ARG_SYSTEM:
729e3769
LP
5210 arg_scope = UNIT_FILE_SYSTEM;
5211 break;
5212
5213 case ARG_GLOBAL:
5214 arg_scope = UNIT_FILE_GLOBAL;
7e4249b9
LP
5215 break;
5216
6e905d93
LP
5217 case ARG_NO_BLOCK:
5218 arg_no_block = true;
7e4249b9
LP
5219 break;
5220
ebed32bf
MS
5221 case ARG_NO_LEGEND:
5222 arg_no_legend = true;
5223 break;
5224
611efaac
LP
5225 case ARG_NO_PAGER:
5226 arg_no_pager = true;
5227 break;
0736af98 5228
514f4ef5
LP
5229 case ARG_NO_WALL:
5230 arg_no_wall = true;
5231 break;
5232
be394c48
FC
5233 case ARG_ROOT:
5234 arg_root = optarg;
5235 break;
5236
98a6e132 5237 case 'l':
8fe914ec
LP
5238 arg_full = true;
5239 break;
5240
30732560 5241 case ARG_FAILED:
9b9b3d36
MW
5242 if (strv_extend(&arg_states, "failed") < 0)
5243 return log_oom();
5244
30732560
LP
5245 break;
5246
0183528f
LP
5247 case 'q':
5248 arg_quiet = true;
5249 break;
5250
568b679f
LP
5251 case ARG_FORCE:
5252 arg_force ++;
5253 break;
5254
b4f27ccc 5255 case 'f':
e606bb61 5256 arg_force ++;
ee5762e3
LP
5257 break;
5258
5259 case ARG_NO_RELOAD:
5260 arg_no_reload = true;
5261 break;
5262
8a0867d6
LP
5263 case ARG_KILL_WHO:
5264 arg_kill_who = optarg;
5265 break;
5266
8a0867d6
LP
5267 case 's':
5268 if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
5269 log_error("Failed to parse signal string %s.", optarg);
5270 return -EINVAL;
5271 }
5272 break;
5273
501fc174
LP
5274 case ARG_NO_ASK_PASSWORD:
5275 arg_ask_password = false;
5276 break;
5277
f459b602
MAP
5278 case 'H':
5279 arg_transport = BUS_TRANSPORT_REMOTE;
5280 arg_host = optarg;
a8f11321
LP
5281 break;
5282
f459b602
MAP
5283 case 'M':
5284 arg_transport = BUS_TRANSPORT_CONTAINER;
5285 arg_host = optarg;
a8f11321
LP
5286 break;
5287
729e3769
LP
5288 case ARG_RUNTIME:
5289 arg_runtime = true;
5290 break;
5291
df50185b
LP
5292 case 'n':
5293 if (safe_atou(optarg, &arg_lines) < 0) {
5294 log_error("Failed to parse lines '%s'", optarg);
5295 return -EINVAL;
5296 }
5297 break;
5298
df50185b
LP
5299 case 'o':
5300 arg_output = output_mode_from_string(optarg);
5301 if (arg_output < 0) {
5302 log_error("Unknown output '%s'.", optarg);
5303 return -EINVAL;
5304 }
5305 break;
5306
b37844d3
LP
5307 case 'i':
5308 arg_ignore_inhibitors = true;
5309 break;
5310
5d0c05e5
LN
5311 case ARG_PLAIN:
5312 arg_plain = true;
5313 break;
5314
9b9b3d36
MW
5315 case ARG_STATE: {
5316 char *word, *state;
5317 size_t size;
5318
5319 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
5320 char *s;
5321
5322 s = strndup(word, size);
5323 if (!s)
5324 return log_oom();
5325
5326 if (strv_push(&arg_states, s) < 0) {
5327 free(s);
5328 return log_oom();
5329 }
5330 }
5331 break;
5332 }
5333
7e4249b9
LP
5334 case '?':
5335 return -EINVAL;
5336
5337 default:
eb9da376 5338 assert_not_reached("Unhandled option");
7e4249b9
LP
5339 }
5340 }
5341
f459b602 5342 if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM) {
a8f11321
LP
5343 log_error("Cannot access user instance remotely.");
5344 return -EINVAL;
5345 }
5346
7e4249b9
LP
5347 return 1;
5348}
5349
e4b61340
LP
5350static int halt_parse_argv(int argc, char *argv[]) {
5351
5352 enum {
5353 ARG_HELP = 0x100,
5354 ARG_HALT,
514f4ef5
LP
5355 ARG_REBOOT,
5356 ARG_NO_WALL
e4b61340
LP
5357 };
5358
5359 static const struct option options[] = {
5360 { "help", no_argument, NULL, ARG_HELP },
5361 { "halt", no_argument, NULL, ARG_HALT },
5362 { "poweroff", no_argument, NULL, 'p' },
5363 { "reboot", no_argument, NULL, ARG_REBOOT },
5364 { "force", no_argument, NULL, 'f' },
5365 { "wtmp-only", no_argument, NULL, 'w' },
5366 { "no-wtmp", no_argument, NULL, 'd' },
514f4ef5 5367 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 5368 {}
e4b61340
LP
5369 };
5370
37185ec8 5371 int c, r, runlevel;
e4b61340
LP
5372
5373 assert(argc >= 0);
5374 assert(argv);
5375
5376 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
5377 if (runlevel == '0' || runlevel == '6')
65491fd8 5378 arg_force = 2;
e4b61340
LP
5379
5380 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
5381 switch (c) {
5382
5383 case ARG_HELP:
eb9da376 5384 return halt_help();
e4b61340
LP
5385
5386 case ARG_HALT:
5387 arg_action = ACTION_HALT;
5388 break;
5389
5390 case 'p':
a042efad
MS
5391 if (arg_action != ACTION_REBOOT)
5392 arg_action = ACTION_POWEROFF;
e4b61340
LP
5393 break;
5394
5395 case ARG_REBOOT:
5396 arg_action = ACTION_REBOOT;
5397 break;
5398
5399 case 'f':
65491fd8 5400 arg_force = 2;
e4b61340
LP
5401 break;
5402
5403 case 'w':
5404 arg_dry = true;
5405 break;
5406
5407 case 'd':
5408 arg_no_wtmp = true;
5409 break;
5410
514f4ef5
LP
5411 case ARG_NO_WALL:
5412 arg_no_wall = true;
5413 break;
5414
e4b61340
LP
5415 case 'i':
5416 case 'h':
57371e58 5417 case 'n':
e4b61340
LP
5418 /* Compatibility nops */
5419 break;
5420
5421 case '?':
5422 return -EINVAL;
5423
5424 default:
eb9da376 5425 assert_not_reached("Unhandled option");
e4b61340
LP
5426 }
5427 }
5428
37185ec8
WC
5429 if (arg_action == ACTION_REBOOT && argc == optind + 1) {
5430 r = write_string_file(REBOOT_PARAM_FILE, argv[optind]);
5431 if (r < 0) {
5432 log_error("Failed to write reboot param to "
5433 REBOOT_PARAM_FILE": %s", strerror(-r));
5434 return r;
5435 }
5436 } else if (optind < argc) {
e4b61340
LP
5437 log_error("Too many arguments.");
5438 return -EINVAL;
5439 }
5440
5441 return 1;
5442}
5443
f6144808
LP
5444static int parse_time_spec(const char *t, usec_t *_u) {
5445 assert(t);
5446 assert(_u);
5447
5448 if (streq(t, "now"))
5449 *_u = 0;
1a639877 5450 else if (!strchr(t, ':')) {
f6144808
LP
5451 uint64_t u;
5452
1a639877 5453 if (safe_atou64(t, &u) < 0)
f6144808
LP
5454 return -EINVAL;
5455
5456 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
5457 } else {
5458 char *e = NULL;
5459 long hour, minute;
b92bea5d 5460 struct tm tm = {};
f6144808
LP
5461 time_t s;
5462 usec_t n;
5463
5464 errno = 0;
5465 hour = strtol(t, &e, 10);
8333c77e 5466 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
f6144808
LP
5467 return -EINVAL;
5468
5469 minute = strtol(e+1, &e, 10);
8333c77e 5470 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
f6144808
LP
5471 return -EINVAL;
5472
5473 n = now(CLOCK_REALTIME);
08e4b1c5
LP
5474 s = (time_t) (n / USEC_PER_SEC);
5475
f6144808
LP
5476 assert_se(localtime_r(&s, &tm));
5477
5478 tm.tm_hour = (int) hour;
5479 tm.tm_min = (int) minute;
08e4b1c5 5480 tm.tm_sec = 0;
f6144808
LP
5481
5482 assert_se(s = mktime(&tm));
5483
5484 *_u = (usec_t) s * USEC_PER_SEC;
5485
5486 while (*_u <= n)
5487 *_u += USEC_PER_DAY;
5488 }
5489
5490 return 0;
5491}
5492
e4b61340
LP
5493static int shutdown_parse_argv(int argc, char *argv[]) {
5494
5495 enum {
5496 ARG_HELP = 0x100,
514f4ef5 5497 ARG_NO_WALL
e4b61340
LP
5498 };
5499
5500 static const struct option options[] = {
5501 { "help", no_argument, NULL, ARG_HELP },
5502 { "halt", no_argument, NULL, 'H' },
5503 { "poweroff", no_argument, NULL, 'P' },
5504 { "reboot", no_argument, NULL, 'r' },
04ebb595 5505 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
514f4ef5 5506 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 5507 {}
e4b61340
LP
5508 };
5509
f6144808 5510 int c, r;
e4b61340
LP
5511
5512 assert(argc >= 0);
5513 assert(argv);
5514
f6144808 5515 while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
e4b61340
LP
5516 switch (c) {
5517
5518 case ARG_HELP:
eb9da376 5519 return shutdown_help();
e4b61340
LP
5520
5521 case 'H':
5522 arg_action = ACTION_HALT;
5523 break;
5524
5525 case 'P':
5526 arg_action = ACTION_POWEROFF;
5527 break;
5528
5529 case 'r':
5622dde3
KS
5530 if (kexec_loaded())
5531 arg_action = ACTION_KEXEC;
5532 else
5533 arg_action = ACTION_REBOOT;
e4b61340
LP
5534 break;
5535
04ebb595
LP
5536 case 'K':
5537 arg_action = ACTION_KEXEC;
5538 break;
5539
e4b61340
LP
5540 case 'h':
5541 if (arg_action != ACTION_HALT)
5542 arg_action = ACTION_POWEROFF;
5543 break;
5544
5545 case 'k':
5546 arg_dry = true;
5547 break;
5548
514f4ef5
LP
5549 case ARG_NO_WALL:
5550 arg_no_wall = true;
5551 break;
5552
e4b61340
LP
5553 case 't':
5554 case 'a':
5555 /* Compatibility nops */
5556 break;
5557
f6144808
LP
5558 case 'c':
5559 arg_action = ACTION_CANCEL_SHUTDOWN;
5560 break;
5561
e4b61340
LP
5562 case '?':
5563 return -EINVAL;
5564
5565 default:
eb9da376 5566 assert_not_reached("Unhandled option");
e4b61340
LP
5567 }
5568 }
5569
dfcc5c33 5570 if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
7e59bfcb
LP
5571 r = parse_time_spec(argv[optind], &arg_when);
5572 if (r < 0) {
f6144808
LP
5573 log_error("Failed to parse time specification: %s", argv[optind]);
5574 return r;
5575 }
6b5ad000 5576 } else
08e4b1c5 5577 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
442b9094 5578
dfcc5c33
MS
5579 if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
5580 /* No time argument for shutdown cancel */
5581 arg_wall = argv + optind;
5582 else if (argc > optind + 1)
5583 /* We skip the time argument */
e4b61340
LP
5584 arg_wall = argv + optind + 1;
5585
5586 optind = argc;
5587
5588 return 1;
e4b61340
LP
5589}
5590
5591static int telinit_parse_argv(int argc, char *argv[]) {
5592
5593 enum {
5594 ARG_HELP = 0x100,
514f4ef5 5595 ARG_NO_WALL
e4b61340
LP
5596 };
5597
5598 static const struct option options[] = {
5599 { "help", no_argument, NULL, ARG_HELP },
514f4ef5 5600 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 5601 {}
e4b61340
LP
5602 };
5603
5604 static const struct {
5605 char from;
5606 enum action to;
5607 } table[] = {
5608 { '0', ACTION_POWEROFF },
5609 { '6', ACTION_REBOOT },
ef2f1067 5610 { '1', ACTION_RESCUE },
e4b61340
LP
5611 { '2', ACTION_RUNLEVEL2 },
5612 { '3', ACTION_RUNLEVEL3 },
5613 { '4', ACTION_RUNLEVEL4 },
5614 { '5', ACTION_RUNLEVEL5 },
5615 { 's', ACTION_RESCUE },
5616 { 'S', ACTION_RESCUE },
5617 { 'q', ACTION_RELOAD },
5618 { 'Q', ACTION_RELOAD },
5619 { 'u', ACTION_REEXEC },
5620 { 'U', ACTION_REEXEC }
5621 };
5622
5623 unsigned i;
5624 int c;
5625
5626 assert(argc >= 0);
5627 assert(argv);
5628
5629 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5630 switch (c) {
5631
5632 case ARG_HELP:
eb9da376 5633 return telinit_help();
e4b61340 5634
514f4ef5
LP
5635 case ARG_NO_WALL:
5636 arg_no_wall = true;
5637 break;
5638
e4b61340
LP
5639 case '?':
5640 return -EINVAL;
5641
5642 default:
eb9da376 5643 assert_not_reached("Unhandled option");
e4b61340
LP
5644 }
5645 }
5646
5647 if (optind >= argc) {
2f02ce40 5648 telinit_help();
e4b61340
LP
5649 return -EINVAL;
5650 }
5651
5652 if (optind + 1 < argc) {
5653 log_error("Too many arguments.");
5654 return -EINVAL;
5655 }
5656
5657 if (strlen(argv[optind]) != 1) {
5658 log_error("Expected single character argument.");
5659 return -EINVAL;
5660 }
5661
5662 for (i = 0; i < ELEMENTSOF(table); i++)
5663 if (table[i].from == argv[optind][0])
5664 break;
5665
5666 if (i >= ELEMENTSOF(table)) {
b0193f1c 5667 log_error("Unknown command '%s'.", argv[optind]);
e4b61340
LP
5668 return -EINVAL;
5669 }
5670
5671 arg_action = table[i].to;
5672
5673 optind ++;
5674
5675 return 1;
5676}
5677
5678static int runlevel_parse_argv(int argc, char *argv[]) {
5679
5680 enum {
5681 ARG_HELP = 0x100,
5682 };
5683
5684 static const struct option options[] = {
5685 { "help", no_argument, NULL, ARG_HELP },
eb9da376 5686 {}
e4b61340
LP
5687 };
5688
5689 int c;
5690
5691 assert(argc >= 0);
5692 assert(argv);
5693
5694 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5695 switch (c) {
5696
5697 case ARG_HELP:
eb9da376 5698 return runlevel_help();
e4b61340
LP
5699 return 0;
5700
5701 case '?':
5702 return -EINVAL;
5703
5704 default:
eb9da376 5705 assert_not_reached("Unhandled option");
e4b61340
LP
5706 }
5707 }
5708
5709 if (optind < argc) {
5710 log_error("Too many arguments.");
5711 return -EINVAL;
5712 }
5713
5714 return 1;
5715}
5716
5717static int parse_argv(int argc, char *argv[]) {
5718 assert(argc >= 0);
5719 assert(argv);
5720
5721 if (program_invocation_short_name) {
5722
5723 if (strstr(program_invocation_short_name, "halt")) {
5724 arg_action = ACTION_HALT;
5725 return halt_parse_argv(argc, argv);
5726 } else if (strstr(program_invocation_short_name, "poweroff")) {
5727 arg_action = ACTION_POWEROFF;
5728 return halt_parse_argv(argc, argv);
5729 } else if (strstr(program_invocation_short_name, "reboot")) {
5622dde3
KS
5730 if (kexec_loaded())
5731 arg_action = ACTION_KEXEC;
5732 else
5733 arg_action = ACTION_REBOOT;
e4b61340
LP
5734 return halt_parse_argv(argc, argv);
5735 } else if (strstr(program_invocation_short_name, "shutdown")) {
5736 arg_action = ACTION_POWEROFF;
5737 return shutdown_parse_argv(argc, argv);
5738 } else if (strstr(program_invocation_short_name, "init")) {
d5ca5f11
LP
5739
5740 if (sd_booted() > 0) {
f459b602 5741 arg_action = _ACTION_INVALID;
d5ca5f11
LP
5742 return telinit_parse_argv(argc, argv);
5743 } else {
5744 /* Hmm, so some other init system is
5745 * running, we need to forward this
5746 * request to it. For now we simply
5747 * guess that it is Upstart. */
5748
4ad61fd1 5749 execv(TELINIT, argv);
d5ca5f11
LP
5750
5751 log_error("Couldn't find an alternative telinit implementation to spawn.");
5752 return -EIO;
5753 }
5754
e4b61340
LP
5755 } else if (strstr(program_invocation_short_name, "runlevel")) {
5756 arg_action = ACTION_RUNLEVEL;
5757 return runlevel_parse_argv(argc, argv);
5758 }
5759 }
5760
5761 arg_action = ACTION_SYSTEMCTL;
5762 return systemctl_parse_argv(argc, argv);
5763}
5764
44a6b1b6 5765_pure_ static int action_to_runlevel(void) {
eb22ac37
LP
5766
5767 static const char table[_ACTION_MAX] = {
5768 [ACTION_HALT] = '0',
5769 [ACTION_POWEROFF] = '0',
5770 [ACTION_REBOOT] = '6',
5771 [ACTION_RUNLEVEL2] = '2',
5772 [ACTION_RUNLEVEL3] = '3',
5773 [ACTION_RUNLEVEL4] = '4',
5774 [ACTION_RUNLEVEL5] = '5',
5775 [ACTION_RESCUE] = '1'
5776 };
5777
d55ae9e6
LP
5778 assert(arg_action < _ACTION_MAX);
5779
5780 return table[arg_action];
5781}
5782
d55ae9e6 5783static int talk_initctl(void) {
cbc9fbd1
LP
5784
5785 struct init_request request = {
5786 .magic = INIT_MAGIC,
5787 .sleeptime = 0,
5788 .cmd = INIT_CMD_RUNLVL
5789 };
5790
7fd1b19b 5791 _cleanup_close_ int fd = -1;
d55ae9e6 5792 char rl;
cbc9fbd1 5793 int r;
eb22ac37 5794
427b47c4
ZJS
5795 rl = action_to_runlevel();
5796 if (!rl)
eb22ac37
LP
5797 return 0;
5798
d55ae9e6
LP
5799 request.runlevel = rl;
5800
427b47c4
ZJS
5801 fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
5802 if (fd < 0) {
d55ae9e6
LP
5803 if (errno == ENOENT)
5804 return 0;
eb22ac37 5805
d55ae9e6 5806 log_error("Failed to open "INIT_FIFO": %m");
eb22ac37 5807 return -errno;
d55ae9e6 5808 }
eb22ac37 5809
d55ae9e6 5810 errno = 0;
eb22ac37 5811 r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
427b47c4 5812 if (r) {
d55ae9e6 5813 log_error("Failed to write to "INIT_FIFO": %m");
bcb161b0 5814 return errno > 0 ? -errno : -EIO;
d55ae9e6 5815 }
eb22ac37
LP
5816
5817 return 1;
e4b61340
LP
5818}
5819
41dd15e4 5820static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
7e4249b9 5821
7e4249b9
LP
5822 static const struct {
5823 const char* verb;
5824 const enum {
5825 MORE,
5826 LESS,
5827 EQUAL
5828 } argc_cmp;
5829 const int argc;
f459b602 5830 int (* const dispatch)(sd_bus *bus, char **args);
d08e75ed
ZJS
5831 const enum {
5832 NOBUS = 1,
5833 FORCE,
5834 } bus;
7e4249b9 5835 } verbs[] = {
d8fba7c6 5836 { "list-units", MORE, 0, list_units },
d08e75ed 5837 { "list-unit-files", MORE, 1, list_unit_files, NOBUS },
d8fba7c6
ZJS
5838 { "list-sockets", MORE, 1, list_sockets },
5839 { "list-timers", MORE, 1, list_timers },
5840 { "list-jobs", MORE, 1, list_jobs },
ee5762e3 5841 { "clear-jobs", EQUAL, 1, daemon_reload },
ee5762e3
LP
5842 { "cancel", MORE, 2, cancel_job },
5843 { "start", MORE, 2, start_unit },
5844 { "stop", MORE, 2, start_unit },
a76f7be2 5845 { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
5846 { "reload", MORE, 2, start_unit },
5847 { "restart", MORE, 2, start_unit },
5848 { "try-restart", MORE, 2, start_unit },
5849 { "reload-or-restart", MORE, 2, start_unit },
5850 { "reload-or-try-restart", MORE, 2, start_unit },
5851 { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */
64e5f1b7 5852 { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
5853 { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
5854 { "isolate", EQUAL, 2, start_unit },
8a0867d6 5855 { "kill", MORE, 2, kill_unit },
1a0fce45
TA
5856 { "is-active", MORE, 2, check_unit_active },
5857 { "check", MORE, 2, check_unit_active },
5858 { "is-failed", MORE, 2, check_unit_failed },
ee5762e3 5859 { "show", MORE, 1, show },
e93c33d4 5860 { "cat", MORE, 2, cat },
265a7a2a 5861 { "status", MORE, 1, show },
b43f208f 5862 { "help", MORE, 2, show },
ee5762e3
LP
5863 { "snapshot", LESS, 2, snapshot },
5864 { "delete", MORE, 2, delete_snapshot },
5865 { "daemon-reload", EQUAL, 1, daemon_reload },
5866 { "daemon-reexec", EQUAL, 1, daemon_reload },
f459b602 5867 { "show-environment", EQUAL, 1, show_environment },
ee5762e3
LP
5868 { "set-environment", MORE, 2, set_environment },
5869 { "unset-environment", MORE, 2, set_environment },
d08e75ed
ZJS
5870 { "halt", EQUAL, 1, start_special, FORCE },
5871 { "poweroff", EQUAL, 1, start_special, FORCE },
5872 { "reboot", EQUAL, 1, start_special, FORCE },
20b09ca7 5873 { "kexec", EQUAL, 1, start_special },
6edd7d0a
LP
5874 { "suspend", EQUAL, 1, start_special },
5875 { "hibernate", EQUAL, 1, start_special },
6524990f 5876 { "hybrid-sleep", EQUAL, 1, start_special },
ee5762e3
LP
5877 { "default", EQUAL, 1, start_special },
5878 { "rescue", EQUAL, 1, start_special },
5879 { "emergency", EQUAL, 1, start_special },
20b09ca7 5880 { "exit", EQUAL, 1, start_special },
fdf20a31 5881 { "reset-failed", MORE, 1, reset_failed },
d08e75ed
ZJS
5882 { "enable", MORE, 2, enable_unit, NOBUS },
5883 { "disable", MORE, 2, enable_unit, NOBUS },
5884 { "is-enabled", MORE, 2, unit_is_enabled, NOBUS },
5885 { "reenable", MORE, 2, enable_unit, NOBUS },
5886 { "preset", MORE, 2, enable_unit, NOBUS },
5887 { "mask", MORE, 2, enable_unit, NOBUS },
5888 { "unmask", MORE, 2, enable_unit, NOBUS },
5889 { "link", MORE, 2, enable_unit, NOBUS },
957eb8ca 5890 { "switch-root", MORE, 2, switch_root },
e31165b2 5891 { "list-dependencies", LESS, 2, list_dependencies },
d08e75ed
ZJS
5892 { "set-default", EQUAL, 2, set_default, NOBUS },
5893 { "get-default", EQUAL, 1, get_default, NOBUS },
8e2af478 5894 { "set-property", MORE, 3, set_property },
d08e75ed
ZJS
5895 {}
5896 }, *verb = verbs;
7e4249b9 5897
e4b61340 5898 int left;
7e4249b9 5899
e4b61340
LP
5900 assert(argc >= 0);
5901 assert(argv);
7e4249b9
LP
5902
5903 left = argc - optind;
5904
d08e75ed
ZJS
5905 /* Special rule: no arguments (left == 0) means "list-units" */
5906 if (left > 0) {
b43f208f
KS
5907 if (streq(argv[optind], "help") && !argv[optind+1]) {
5908 log_error("This command expects one or more "
5909 "unit names. Did you mean --help?");
5910 return -EINVAL;
0183528f
LP
5911 }
5912
d08e75ed
ZJS
5913 for (; verb->verb; verb++)
5914 if (streq(argv[optind], verb->verb))
5915 goto found;
7e4249b9 5916
d08e75ed
ZJS
5917 log_error("Unknown operation '%s'.", argv[optind]);
5918 return -EINVAL;
7e4249b9 5919 }
d08e75ed 5920found:
7e4249b9 5921
d08e75ed 5922 switch (verb->argc_cmp) {
7e4249b9
LP
5923
5924 case EQUAL:
d08e75ed 5925 if (left != verb->argc) {
7e4249b9 5926 log_error("Invalid number of arguments.");
e4b61340 5927 return -EINVAL;
7e4249b9
LP
5928 }
5929
5930 break;
5931
5932 case MORE:
d08e75ed 5933 if (left < verb->argc) {
7e4249b9 5934 log_error("Too few arguments.");
e4b61340 5935 return -EINVAL;
7e4249b9
LP
5936 }
5937
5938 break;
5939
5940 case LESS:
d08e75ed 5941 if (left > verb->argc) {
7e4249b9 5942 log_error("Too many arguments.");
e4b61340 5943 return -EINVAL;
7e4249b9
LP
5944 }
5945
5946 break;
5947
5948 default:
5949 assert_not_reached("Unknown comparison operator.");
5950 }
5951
ee5762e3
LP
5952 /* Require a bus connection for all operations but
5953 * enable/disable */
d08e75ed
ZJS
5954 if (verb->bus == NOBUS) {
5955 if (!bus && !avoid_bus()) {
5956 log_error("Failed to get D-Bus connection: %s", strerror(-bus_error));
5957 return -EIO;
5958 }
82e23ddd 5959
d08e75ed 5960 } else {
82e23ddd
LP
5961 if (running_in_chroot() > 0) {
5962 log_info("Running in chroot, ignoring request.");
5963 return 0;
5964 }
5965
d08e75ed
ZJS
5966 if ((verb->bus != FORCE || arg_force <= 0) && !bus) {
5967 log_error("Failed to get D-Bus connection: %s", strerror(-bus_error));
82e23ddd
LP
5968 return -EIO;
5969 }
ee5762e3
LP
5970 }
5971
d08e75ed 5972 return verb->dispatch(bus, argv + optind);
e4b61340
LP
5973}
5974
52c00215 5975static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
cbc9fbd1 5976
b92bea5d
ZJS
5977 struct sd_shutdown_command c = {
5978 .usec = t,
5979 .mode = mode,
5980 .dry_run = dry_run,
5981 .warn_wall = warn,
5982 };
cbc9fbd1 5983
b92bea5d
ZJS
5984 union sockaddr_union sockaddr = {
5985 .un.sun_family = AF_UNIX,
5986 .un.sun_path = "/run/systemd/shutdownd",
5987 };
cbc9fbd1
LP
5988
5989 struct iovec iovec[2] = {{
5990 .iov_base = (char*) &c,
b92bea5d 5991 .iov_len = offsetof(struct sd_shutdown_command, wall_message),
cbc9fbd1
LP
5992 }};
5993
b92bea5d
ZJS
5994 struct msghdr msghdr = {
5995 .msg_name = &sockaddr,
5996 .msg_namelen = offsetof(struct sockaddr_un, sun_path)
5997 + sizeof("/run/systemd/shutdownd") - 1,
5998 .msg_iov = iovec,
5999 .msg_iovlen = 1,
6000 };
04ebb595 6001
cbc9fbd1
LP
6002 _cleanup_close_ int fd;
6003
04ebb595
LP
6004 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
6005 if (fd < 0)
6006 return -errno;
f6144808 6007
b92bea5d 6008 if (!isempty(message)) {
04ebb595
LP
6009 iovec[1].iov_base = (char*) message;
6010 iovec[1].iov_len = strlen(message);
b92bea5d 6011 msghdr.msg_iovlen++;
04ebb595 6012 }
f6144808 6013
cec7eda5 6014 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
f6144808 6015 return -errno;
f6144808 6016
f6144808
LP
6017 return 0;
6018}
6019
f459b602 6020static int reload_with_fallback(sd_bus *bus) {
e4b61340
LP
6021
6022 if (bus) {
6023 /* First, try systemd via D-Bus. */
d76702a7 6024 if (daemon_reload(bus, NULL) >= 0)
e4b61340
LP
6025 return 0;
6026 }
6027
6028 /* Nothing else worked, so let's try signals */
6029 assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
6030
6031 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
6032 log_error("kill() failed: %m");
6033 return -errno;
6034 }
6035
6036 return 0;
6037}
6038
f459b602 6039static int start_with_fallback(sd_bus *bus) {
e4b61340
LP
6040
6041 if (bus) {
6042 /* First, try systemd via D-Bus. */
729e3769 6043 if (start_unit(bus, NULL) >= 0)
983d9c90 6044 goto done;
e4b61340
LP
6045 }
6046
6047 /* Nothing else worked, so let's try
6048 * /dev/initctl */
fbc43921 6049 if (talk_initctl() > 0)
983d9c90 6050 goto done;
d55ae9e6
LP
6051
6052 log_error("Failed to talk to init daemon.");
6053 return -EIO;
983d9c90
LP
6054
6055done:
6056 warn_wall(arg_action);
6057 return 0;
e4b61340
LP
6058}
6059
477def80 6060static int halt_now(enum action a) {
e606bb61 6061
477def80 6062/* Make sure C-A-D is handled by the kernel from this
e606bb61
LP
6063 * point on... */
6064 reboot(RB_ENABLE_CAD);
6065
4c80c73c 6066 switch (a) {
e606bb61
LP
6067
6068 case ACTION_HALT:
6069 log_info("Halting.");
6070 reboot(RB_HALT_SYSTEM);
477def80 6071 return -errno;
e606bb61
LP
6072
6073 case ACTION_POWEROFF:
6074 log_info("Powering off.");
6075 reboot(RB_POWER_OFF);
477def80 6076 return -errno;
e606bb61 6077
477def80
LP
6078 case ACTION_REBOOT: {
6079 _cleanup_free_ char *param = NULL;
cbc9fbd1 6080
477def80
LP
6081 if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
6082 log_info("Rebooting with argument '%s'.", param);
37185ec8
WC
6083 syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
6084 LINUX_REBOOT_CMD_RESTART2, param);
37185ec8 6085 }
e606bb61 6086
477def80
LP
6087 log_info("Rebooting.");
6088 reboot(RB_AUTOBOOT);
6089 return -errno;
e606bb61
LP
6090 }
6091
477def80
LP
6092 default:
6093 assert_not_reached("Unknown action.");
6094 }
e606bb61
LP
6095}
6096
f459b602 6097static int halt_main(sd_bus *bus) {
e4b61340
LP
6098 int r;
6099
748ebafa
LP
6100 r = check_inhibitors(bus, arg_action);
6101 if (r < 0)
6102 return r;
b37844d3 6103
bc8c2f5c 6104 if (geteuid() != 0) {
7e59bfcb
LP
6105 /* Try logind if we are a normal user and no special
6106 * mode applies. Maybe PolicyKit allows us to shutdown
6107 * the machine. */
6108
6109 if (arg_when <= 0 &&
6110 !arg_dry &&
b37844d3 6111 arg_force <= 0 &&
7e59bfcb
LP
6112 (arg_action == ACTION_POWEROFF ||
6113 arg_action == ACTION_REBOOT)) {
4c80c73c
KS
6114 r = reboot_with_logind(bus, arg_action);
6115 if (r >= 0)
6116 return r;
6117 }
6118
cc8a7a61 6119 log_error("Must be root.");
bc8c2f5c
LP
6120 return -EPERM;
6121 }
6122
f6144808 6123 if (arg_when > 0) {
7fd1b19b 6124 _cleanup_free_ char *m;
9be9828c
LP
6125
6126 m = strv_join(arg_wall, " ");
cbc9fbd1
LP
6127 if (!m)
6128 return log_oom();
6129
9be9828c
LP
6130 r = send_shutdownd(arg_when,
6131 arg_action == ACTION_HALT ? 'H' :
6132 arg_action == ACTION_POWEROFF ? 'P' :
04ebb595 6133 arg_action == ACTION_KEXEC ? 'K' :
9be9828c 6134 'r',
52c00215 6135 arg_dry,
9be9828c
LP
6136 !arg_no_wall,
6137 m);
9be9828c
LP
6138
6139 if (r < 0)
f6144808 6140 log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
08e4b1c5 6141 else {
7e59bfcb
LP
6142 char date[FORMAT_TIMESTAMP_MAX];
6143
08e4b1c5
LP
6144 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
6145 format_timestamp(date, sizeof(date), arg_when));
f6144808 6146 return 0;
08e4b1c5 6147 }
f6144808
LP
6148 }
6149
65491fd8 6150 if (!arg_dry && !arg_force)
e4b61340
LP
6151 return start_with_fallback(bus);
6152
d90e1a30
LP
6153 if (!arg_no_wtmp) {
6154 if (sd_booted() > 0)
6155 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
7e59bfcb
LP
6156 else {
6157 r = utmp_put_shutdown();
6158 if (r < 0)
6159 log_warning("Failed to write utmp record: %s", strerror(-r));
6160 }
d90e1a30 6161 }
e4b61340 6162
e4b61340
LP
6163 if (arg_dry)
6164 return 0;
6165
477def80
LP
6166 r = halt_now(arg_action);
6167 log_error("Failed to reboot: %s", strerror(-r));
6168
6169 return r;
e4b61340
LP
6170}
6171
6172static int runlevel_main(void) {
6173 int r, runlevel, previous;
6174
729e3769
LP
6175 r = utmp_get_runlevel(&runlevel, &previous);
6176 if (r < 0) {
6177 puts("unknown");
e4b61340
LP
6178 return r;
6179 }
6180
6181 printf("%c %c\n",
6182 previous <= 0 ? 'N' : previous,
6183 runlevel <= 0 ? 'N' : runlevel);
6184
6185 return 0;
6186}
6187
6188int main(int argc, char*argv[]) {
f459b602
MAP
6189 _cleanup_bus_unref_ sd_bus *bus = NULL;
6190 int r;
e4b61340 6191
a9cdc94f 6192 setlocale(LC_ALL, "");
e4b61340 6193 log_parse_environment();
2396fb04 6194 log_open();
e4b61340 6195
184ecaf7
DR
6196 /* Explicitly not on_tty() to avoid setting cached value.
6197 * This becomes relevant for piping output which might be
6198 * ellipsized. */
6199 original_stdout_is_tty = isatty(STDOUT_FILENO);
6200
04ebb595 6201 r = parse_argv(argc, argv);
f459b602 6202 if (r <= 0)
e4b61340 6203 goto finish;
7e4249b9 6204
e4b61340
LP
6205 /* /sbin/runlevel doesn't need to communicate via D-Bus, so
6206 * let's shortcut this */
6207 if (arg_action == ACTION_RUNLEVEL) {
22f4096c 6208 r = runlevel_main();
e4b61340
LP
6209 goto finish;
6210 }
6211
82e23ddd
LP
6212 if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
6213 log_info("Running in chroot, ignoring request.");
f459b602 6214 r = 0;
82e23ddd
LP
6215 goto finish;
6216 }
6217
41dd15e4
LP
6218 if (!avoid_bus())
6219 r = bus_open_transport_systemd(arg_transport, arg_host, arg_scope != UNIT_FILE_SYSTEM, &bus);
6220
6221 /* systemctl_main() will print an error message for the bus
6222 * connection, but only if it needs to */
e4b61340
LP
6223
6224 switch (arg_action) {
6225
22f4096c 6226 case ACTION_SYSTEMCTL:
f459b602 6227 r = systemctl_main(bus, argc, argv, r);
e4b61340 6228 break;
e4b61340
LP
6229
6230 case ACTION_HALT:
6231 case ACTION_POWEROFF:
6232 case ACTION_REBOOT:
5622dde3 6233 case ACTION_KEXEC:
22f4096c 6234 r = halt_main(bus);
e4b61340
LP
6235 break;
6236
e4b61340
LP
6237 case ACTION_RUNLEVEL2:
6238 case ACTION_RUNLEVEL3:
6239 case ACTION_RUNLEVEL4:
6240 case ACTION_RUNLEVEL5:
6241 case ACTION_RESCUE:
514f4ef5 6242 case ACTION_EMERGENCY:
eb22ac37 6243 case ACTION_DEFAULT:
22f4096c 6244 r = start_with_fallback(bus);
e4b61340 6245 break;
7e4249b9 6246
e4b61340
LP
6247 case ACTION_RELOAD:
6248 case ACTION_REEXEC:
22f4096c 6249 r = reload_with_fallback(bus);
e4b61340
LP
6250 break;
6251
dfcc5c33 6252 case ACTION_CANCEL_SHUTDOWN: {
f459b602 6253 _cleanup_free_ char *m = NULL;
dfcc5c33
MS
6254
6255 if (arg_wall) {
6256 m = strv_join(arg_wall, " ");
6257 if (!m) {
f459b602 6258 r = log_oom();
dfcc5c33
MS
6259 goto finish;
6260 }
6261 }
f459b602 6262
dfcc5c33
MS
6263 r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
6264 if (r < 0)
6265 log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
f6144808 6266 break;
dfcc5c33 6267 }
f6144808 6268
eb22ac37 6269 case ACTION_RUNLEVEL:
f459b602 6270 case _ACTION_INVALID:
e4b61340
LP
6271 default:
6272 assert_not_reached("Unknown action");
6273 }
7e4249b9
LP
6274
6275finish:
f459b602
MAP
6276 pager_close();
6277 ask_password_agent_close();
6278 polkit_agent_close();
7e4249b9 6279
20b3f379 6280 strv_free(arg_types);
9b9b3d36 6281 strv_free(arg_states);
20b3f379 6282 strv_free(arg_properties);
ea4a240d 6283
f459b602 6284 return r < 0 ? EXIT_FAILURE : r;
7e4249b9 6285}