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