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