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