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