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