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