]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl.c
sd-login: add a sd_pid_get_user_unit() call
[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);
1181 l0 = MAX(l0, decimal_str_max(j->id));
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;
4012 char *p;
4013 bool found_native = false, found_sysv;
4014 unsigned c = 1;
4015 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
4016 char **k, *l, *q = NULL;
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
LP
4029 STRV_FOREACH(k, paths.unit_path) {
4030 p = NULL;
ee5762e3 4031
729e3769
LP
4032 if (!isempty(arg_root))
4033 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
4034 else
4035 asprintf(&p, "%s/%s", *k, name);
ee5762e3 4036
729e3769 4037 if (!p) {
0d0f0c50 4038 r = log_oom();
729e3769
LP
4039 goto finish;
4040 }
ee5762e3 4041
729e3769
LP
4042 found_native = access(p, F_OK) >= 0;
4043 free(p);
ee5762e3 4044
729e3769
LP
4045 if (found_native)
4046 break;
4047 }
ee5762e3 4048
729e3769
LP
4049 if (found_native)
4050 continue;
ee5762e3 4051
729e3769
LP
4052 p = NULL;
4053 if (!isempty(arg_root))
4054 asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
4055 else
4056 asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
4057 if (!p) {
0d0f0c50 4058 r = log_oom();
729e3769
LP
4059 goto finish;
4060 }
ee5762e3 4061
729e3769
LP
4062 p[strlen(p) - sizeof(".service") + 1] = 0;
4063 found_sysv = access(p, F_OK) >= 0;
ee5762e3 4064
729e3769
LP
4065 if (!found_sysv) {
4066 free(p);
4067 continue;
71fad675
LP
4068 }
4069
729e3769
LP
4070 /* Mark this entry, so that we don't try enabling it as native unit */
4071 args[f] = (char*) "";
ee5762e3 4072
729e3769 4073 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
ee5762e3 4074
729e3769
LP
4075 if (!isempty(arg_root))
4076 argv[c++] = q = strappend("--root=", arg_root);
ee5762e3 4077
9eb977db 4078 argv[c++] = path_get_file_name(p);
729e3769
LP
4079 argv[c++] =
4080 streq(verb, "enable") ? "on" :
4081 streq(verb, "disable") ? "off" : "--level=5";
4082 argv[c] = NULL;
ee5762e3 4083
729e3769
LP
4084 l = strv_join((char**)argv, " ");
4085 if (!l) {
729e3769
LP
4086 free(q);
4087 free(p);
0d0f0c50 4088 r = log_oom();
729e3769
LP
4089 goto finish;
4090 }
ee5762e3 4091
729e3769
LP
4092 log_info("Executing %s", l);
4093 free(l);
ee5762e3 4094
729e3769
LP
4095 pid = fork();
4096 if (pid < 0) {
4097 log_error("Failed to fork: %m");
4098 free(p);
4099 free(q);
4100 r = -errno;
4101 goto finish;
4102 } else if (pid == 0) {
4103 /* Child */
ee5762e3 4104
729e3769
LP
4105 execv(argv[0], (char**) argv);
4106 _exit(EXIT_FAILURE);
4107 }
ee5762e3 4108
729e3769
LP
4109 free(p);
4110 free(q);
ee5762e3 4111
729e3769
LP
4112 j = wait_for_terminate(pid, &status);
4113 if (j < 0) {
4114 log_error("Failed to wait for child: %s", strerror(-r));
4115 r = j;
4116 goto finish;
4117 }
ee5762e3 4118
729e3769
LP
4119 if (status.si_code == CLD_EXITED) {
4120 if (streq(verb, "is-enabled")) {
4121 if (status.si_status == 0) {
4122 if (!arg_quiet)
4123 puts("enabled");
4124 r = 1;
4125 } else {
4126 if (!arg_quiet)
4127 puts("disabled");
4128 }
ee5762e3 4129
729e3769
LP
4130 } else if (status.si_status != 0) {
4131 r = -EINVAL;
4132 goto finish;
4133 }
4134 } else {
4135 r = -EPROTO;
4136 goto finish;
4137 }
ee5762e3
LP
4138 }
4139
729e3769
LP
4140finish:
4141 lookup_paths_free(&paths);
ee5762e3 4142
729e3769
LP
4143 /* Drop all SysV units */
4144 for (f = 1, t = 1; args[f]; f++) {
ee5762e3 4145
729e3769 4146 if (isempty(args[f]))
ee5762e3
LP
4147 continue;
4148
729e3769
LP
4149 args[t++] = args[f];
4150 }
ee5762e3 4151
729e3769 4152 args[t] = NULL;
ee5762e3 4153
729e3769
LP
4154#endif
4155 return r;
4156}
ee5762e3 4157
37370d0c 4158static int mangle_names(char **original_names, char ***mangled_names) {
a33fdebb 4159 char **i, **l, **name;
37370d0c 4160
a33fdebb
LP
4161 l = new(char*, strv_length(original_names) + 1);
4162 if (!l)
37370d0c
VP
4163 return log_oom();
4164
a33fdebb 4165 i = l;
37370d0c 4166 STRV_FOREACH(name, original_names) {
44386fc1
LN
4167
4168 /* When enabling units qualified path names are OK,
4169 * too, hence allow them explicitly. */
4170
4171 if (is_path(*name))
4172 *i = strdup(*name);
4173 else
4174 *i = unit_name_mangle(*name);
4175
a33fdebb
LP
4176 if (!*i) {
4177 strv_free(l);
37370d0c 4178 return log_oom();
a33fdebb
LP
4179 }
4180
4181 i++;
37370d0c 4182 }
a33fdebb
LP
4183
4184 *i = NULL;
4185 *mangled_names = l;
37370d0c
VP
4186
4187 return 0;
4188}
4189
729e3769
LP
4190static int enable_unit(DBusConnection *bus, char **args) {
4191 const char *verb = args[0];
4192 UnitFileChange *changes = NULL;
4193 unsigned n_changes = 0, i;
4194 int carries_install_info = -1;
cec7eda5 4195 DBusMessage _cleanup_dbus_message_unref_ *m = NULL, *reply = NULL;
729e3769 4196 int r;
cec7eda5
ZJS
4197 DBusError _cleanup_dbus_error_free_ error;
4198 char _cleanup_strv_free_ **mangled_names = NULL;
4199
4200 dbus_error_init(&error);
ee5762e3 4201
729e3769
LP
4202 r = enable_sysv_units(args);
4203 if (r < 0)
4204 return r;
ee5762e3 4205
ab5919fa
MS
4206 if (!args[1])
4207 return 0;
4208
729e3769
LP
4209 if (!bus || avoid_bus()) {
4210 if (streq(verb, "enable")) {
4211 r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4212 carries_install_info = r;
4213 } else if (streq(verb, "disable"))
4214 r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
4215 else if (streq(verb, "reenable")) {
4216 r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4217 carries_install_info = r;
4218 } else if (streq(verb, "link"))
4219 r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4220 else if (streq(verb, "preset")) {
4221 r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4222 carries_install_info = r;
4223 } else if (streq(verb, "mask"))
4224 r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
4225 else if (streq(verb, "unmask"))
4226 r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
4227 else
4228 assert_not_reached("Unknown verb");
ee5762e3 4229
729e3769
LP
4230 if (r < 0) {
4231 log_error("Operation failed: %s", strerror(-r));
4232 goto finish;
ee5762e3
LP
4233 }
4234
d1f262fa
LP
4235 if (!arg_quiet) {
4236 for (i = 0; i < n_changes; i++) {
4237 if (changes[i].type == UNIT_FILE_SYMLINK)
4238 log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
4239 else
4240 log_info("rm '%s'", changes[i].path);
4241 }
ee5762e3
LP
4242 }
4243
df77cdf0 4244 r = 0;
729e3769
LP
4245 } else {
4246 const char *method;
4247 bool send_force = true, expect_carries_install_info = false;
4248 dbus_bool_t a, b;
4249 DBusMessageIter iter, sub, sub2;
4250
4251 if (streq(verb, "enable")) {
4252 method = "EnableUnitFiles";
4253 expect_carries_install_info = true;
4254 } else if (streq(verb, "disable")) {
4255 method = "DisableUnitFiles";
4256 send_force = false;
4257 } else if (streq(verb, "reenable")) {
4258 method = "ReenableUnitFiles";
4259 expect_carries_install_info = true;
4260 } else if (streq(verb, "link"))
4261 method = "LinkUnitFiles";
4262 else if (streq(verb, "preset")) {
4263 method = "PresetUnitFiles";
4264 expect_carries_install_info = true;
4265 } else if (streq(verb, "mask"))
4266 method = "MaskUnitFiles";
4267 else if (streq(verb, "unmask")) {
4268 method = "UnmaskUnitFiles";
4269 send_force = false;
4270 } else
4271 assert_not_reached("Unknown verb");
4272
4273 m = dbus_message_new_method_call(
4274 "org.freedesktop.systemd1",
4275 "/org/freedesktop/systemd1",
4276 "org.freedesktop.systemd1.Manager",
4277 method);
4278 if (!m) {
0d0f0c50 4279 r = log_oom();
ee5762e3
LP
4280 goto finish;
4281 }
4282
729e3769 4283 dbus_message_iter_init_append(m, &iter);
ee5762e3 4284
37370d0c
VP
4285 r = mangle_names(args+1, &mangled_names);
4286 if(r < 0)
4287 goto finish;
4288
4289 r = bus_append_strv_iter(&iter, mangled_names);
729e3769
LP
4290 if (r < 0) {
4291 log_error("Failed to append unit files.");
ee5762e3
LP
4292 goto finish;
4293 }
4294
729e3769
LP
4295 a = arg_runtime;
4296 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
4297 log_error("Failed to append runtime boolean.");
ee5762e3
LP
4298 r = -ENOMEM;
4299 goto finish;
4300 }
4301
729e3769
LP
4302 if (send_force) {
4303 b = arg_force;
be394c48 4304
729e3769
LP
4305 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
4306 log_error("Failed to append force boolean.");
4307 r = -ENOMEM;
4308 goto finish;
4309 }
09adcdf7 4310 }
ee5762e3 4311
729e3769
LP
4312 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4313 if (!reply) {
4314 log_error("Failed to issue method call: %s", bus_error_message(&error));
4315 r = -EIO;
4316 goto finish;
ee5762e3
LP
4317 }
4318
729e3769
LP
4319 if (!dbus_message_iter_init(reply, &iter)) {
4320 log_error("Failed to initialize iterator.");
4321 goto finish;
4322 }
be394c48 4323
729e3769
LP
4324 if (expect_carries_install_info) {
4325 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
4326 if (r < 0) {
4327 log_error("Failed to parse reply.");
4328 goto finish;
4329 }
ee5762e3 4330
729e3769 4331 carries_install_info = b;
ee5762e3
LP
4332 }
4333
729e3769
LP
4334 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
4335 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
4336 log_error("Failed to parse reply.");
4337 r = -EIO;
4338 goto finish;
ee5762e3
LP
4339 }
4340
729e3769
LP
4341 dbus_message_iter_recurse(&iter, &sub);
4342 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
4343 const char *type, *path, *source;
c8b2e52c 4344
729e3769
LP
4345 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
4346 log_error("Failed to parse reply.");
4347 r = -EIO;
4348 goto finish;
c8b2e52c
LP
4349 }
4350
729e3769 4351 dbus_message_iter_recurse(&sub, &sub2);
c8b2e52c 4352
729e3769
LP
4353 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
4354 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
4355 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
4356 log_error("Failed to parse reply.");
4357 r = -EIO;
4358 goto finish;
c8b2e52c
LP
4359 }
4360
d1f262fa
LP
4361 if (!arg_quiet) {
4362 if (streq(type, "symlink"))
4363 log_info("ln -s '%s' '%s'", source, path);
4364 else
4365 log_info("rm '%s'", path);
4366 }
b77398f7 4367
729e3769
LP
4368 dbus_message_iter_next(&sub);
4369 }
b77398f7 4370
729e3769 4371 /* Try to reload if enabeld */
d6cb60c7 4372 if (!arg_no_reload)
729e3769 4373 r = daemon_reload(bus, args);
b647f10d 4374 }
3d3961f2 4375
729e3769 4376 if (carries_install_info == 0)
416389f7
LP
4377 log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
4378 "using systemctl.\n"
4379 "Possible reasons for having this kind of units are:\n"
4380 "1) A unit may be statically enabled by being symlinked from another unit's\n"
4381 " .wants/ or .requires/ directory.\n"
4382 "2) A unit's purpose may be to act as a helper for some other unit which has\n"
4383 " a requirement dependency on it.\n"
4384 "3) A unit may be started when needed via activation (socket, path, timer,\n"
4385 " D-Bus, udev, scripted systemctl call, ...).\n");
ee5762e3 4386
729e3769 4387finish:
729e3769 4388 unit_file_changes_free(changes, n_changes);
ee5762e3 4389
729e3769 4390 return r;
ee5762e3
LP
4391}
4392
729e3769 4393static int unit_is_enabled(DBusConnection *bus, char **args) {
cec7eda5 4394 DBusError _cleanup_dbus_error_free_ error;
ee5762e3 4395 int r;
cec7eda5 4396 DBusMessage _cleanup_dbus_message_unref_ *reply = NULL;
729e3769
LP
4397 bool enabled;
4398 char **name;
dec49d88 4399 char *n;
ee5762e3
LP
4400
4401 dbus_error_init(&error);
4402
729e3769
LP
4403 r = enable_sysv_units(args);
4404 if (r < 0)
4405 return r;
ee5762e3 4406
729e3769 4407 enabled = r > 0;
ee5762e3 4408
729e3769 4409 if (!bus || avoid_bus()) {
ee5762e3 4410
729e3769
LP
4411 STRV_FOREACH(name, args+1) {
4412 UnitFileState state;
ee5762e3 4413
dec49d88
LN
4414 n = unit_name_mangle(*name);
4415 if (!n)
4416 return log_oom();
4417
4418 state = unit_file_get_state(arg_scope, arg_root, n);
4419
4420 free(n);
4421
cec7eda5
ZJS
4422 if (state < 0)
4423 return state;
ee5762e3 4424
729e3769
LP
4425 if (state == UNIT_FILE_ENABLED ||
4426 state == UNIT_FILE_ENABLED_RUNTIME ||
4427 state == UNIT_FILE_STATIC)
4428 enabled = true;
4429
4430 if (!arg_quiet)
4431 puts(unit_file_state_to_string(state));
71fad675 4432 }
ee5762e3 4433
729e3769
LP
4434 } else {
4435 STRV_FOREACH(name, args+1) {
4436 const char *s;
63a723f3 4437
dec49d88
LN
4438 n = unit_name_mangle(*name);
4439 if (!n)
4440 return log_oom();
4441
f22f08cd
SP
4442 r = bus_method_call_with_reply (
4443 bus,
729e3769
LP
4444 "org.freedesktop.systemd1",
4445 "/org/freedesktop/systemd1",
4446 "org.freedesktop.systemd1.Manager",
f22f08cd
SP
4447 "GetUnitFileState",
4448 &reply,
4449 NULL,
dec49d88 4450 DBUS_TYPE_STRING, &n,
f22f08cd 4451 DBUS_TYPE_INVALID);
dec49d88
LN
4452
4453 free(n);
4454
f22f08cd 4455 if (r)
cec7eda5 4456 return r;
ee5762e3 4457
729e3769
LP
4458 if (!dbus_message_get_args(reply, &error,
4459 DBUS_TYPE_STRING, &s,
4460 DBUS_TYPE_INVALID)) {
4461 log_error("Failed to parse reply: %s", bus_error_message(&error));
cec7eda5 4462 return -EIO;
ee5762e3
LP
4463 }
4464
729e3769 4465 dbus_message_unref(reply);
f22f08cd 4466 reply = NULL;
ee5762e3 4467
729e3769
LP
4468 if (streq(s, "enabled") ||
4469 streq(s, "enabled-runtime") ||
4470 streq(s, "static"))
4471 enabled = true;
4472
4473 if (!arg_quiet)
4474 puts(s);
560d8f23 4475 }
ee5762e3
LP
4476 }
4477
cec7eda5 4478 return enabled ? 0 : 1;
ee5762e3
LP
4479}
4480
e4b61340 4481static int systemctl_help(void) {
7e4249b9 4482
729e3769
LP
4483 pager_open_if_enabled();
4484
2e33c433 4485 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
729e3769 4486 "Query or send control commands to the systemd manager.\n\n"
8a0867d6
LP
4487 " -h --help Show this help\n"
4488 " --version Show package version\n"
4489 " -t --type=TYPE List only units of a particular type\n"
4490 " -p --property=NAME Show only properties by this name\n"
4491 " -a --all Show all units/properties, including dead/empty ones\n"
30732560 4492 " --failed Show only failed units\n"
8a0867d6
LP
4493 " --full Don't ellipsize unit names on output\n"
4494 " --fail When queueing a new job, fail if conflicting jobs are\n"
4495 " pending\n"
991f2a39
ZJS
4496 " --irreversible Create jobs which cannot be implicitly cancelled\n"
4497 " --show-types When showing sockets, explictly show their type\n"
e67c3609
LP
4498 " --ignore-dependencies\n"
4499 " When queueing a new job, ignore all its dependencies\n"
b37844d3
LP
4500 " -i --ignore-inhibitors\n"
4501 " When shutting down or sleeping, ignore inhibitors\n"
a8f11321
LP
4502 " --kill-who=WHO Who to send signal to\n"
4503 " -s --signal=SIGNAL Which signal to send\n"
aca4c786 4504 " -H --host=[USER@]HOST\n"
a8f11321
LP
4505 " Show information for remote host\n"
4506 " -P --privileged Acquire privileges before execution\n"
8a0867d6
LP
4507 " -q --quiet Suppress output\n"
4508 " --no-block Do not wait until operation finished\n"
8a0867d6 4509 " --no-wall Don't send wall message before halt/power-off/reboot\n"
8a0867d6
LP
4510 " --no-reload When enabling/disabling unit files, don't reload daemon\n"
4511 " configuration\n"
ebed32bf 4512 " --no-legend Do not print a legend (column headers and hints)\n"
69fc152f 4513 " --no-pager Do not pipe output into a pager\n"
501fc174
LP
4514 " --no-ask-password\n"
4515 " Do not ask for system passwords\n"
a8f11321
LP
4516 " --system Connect to system manager\n"
4517 " --user Connect to user service manager\n"
4518 " --global Enable/disable unit files globally\n"
8a0867d6
LP
4519 " -f --force When enabling unit files, override existing symlinks\n"
4520 " When shutting down, execute action immediately\n"
729e3769 4521 " --root=PATH Enable unit files in the specified root directory\n"
df50185b
LP
4522 " --runtime Enable unit files only temporarily until next reboot\n"
4523 " -n --lines=INTEGER Journal entries to show\n"
d3f2bdbf 4524 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
48383c25 4525 " verbose, export, json, json-pretty, json-sse, cat)\n\n"
34c4b47b 4526 "Unit Commands:\n"
729e3769 4527 " list-units List loaded units\n"
ee5762e3
LP
4528 " start [NAME...] Start (activate) one or more units\n"
4529 " stop [NAME...] Stop (deactivate) one or more units\n"
7e4249b9 4530 " reload [NAME...] Reload one or more units\n"
6f28c033
LP
4531 " restart [NAME...] Start or restart one or more units\n"
4532 " try-restart [NAME...] Restart one or more units if active\n"
d9847b32 4533 " reload-or-restart [NAME...] Reload one or more units if possible,\n"
6f28c033 4534 " otherwise start or restart\n"
d9847b32 4535 " reload-or-try-restart [NAME...] Reload one or more units if possible,\n"
6f28c033 4536 " otherwise restart if active\n"
7e4249b9 4537 " isolate [NAME] Start one unit and stop all others\n"
8a0867d6 4538 " kill [NAME...] Send signal to processes of a unit\n"
ee5762e3 4539 " is-active [NAME...] Check whether units are active\n"
1a0fce45 4540 " is-failed [NAME...] Check whether units are failed\n"
75676b72 4541 " status [NAME...|PID...] Show runtime status of one or more units\n"
6f28c033 4542 " show [NAME...|JOB...] Show properties of one or more\n"
ee5762e3 4543 " units/jobs or the manager\n"
55c0b89c 4544 " help [NAME...|PID...] Show manual for one or more units\n"
fdf20a31
MM
4545 " reset-failed [NAME...] Reset failed state for all, one, or more\n"
4546 " units\n"
d2a30975
LP
4547 " get-cgroup-attr [NAME] [ATTR] ...\n"
4548 " Get control group attrubute\n"
246aa6dd
LP
4549 " set-cgroup-attr [NAME] [ATTR] [VALUE] ...\n"
4550 " Set control group attribute\n"
4551 " unset-cgroup-attr [NAME] [ATTR...]\n"
4552 " Unset control group attribute\n"
d2a30975
LP
4553 " set-cgroup [NAME] [CGROUP...] Add unit to a control group\n"
4554 " unset-cgroup [NAME] [CGROUP...] Remove unit from a control group\n"
55c0b89c
LN
4555 " load [NAME...] Load one or more units\n"
4556 " list-dependencies [NAME] Recursively show units which are required\n"
4557 " or wanted by this unit\n\n"
34c4b47b 4558 "Unit File Commands:\n"
729e3769 4559 " list-unit-files List installed unit files\n"
ee5762e3
LP
4560 " enable [NAME...] Enable one or more unit files\n"
4561 " disable [NAME...] Disable one or more unit files\n"
729e3769
LP
4562 " reenable [NAME...] Reenable one or more unit files\n"
4563 " preset [NAME...] Enable/disable one or more unit files\n"
4564 " based on preset configuration\n"
4565 " mask [NAME...] Mask one or more units\n"
4566 " unmask [NAME...] Unmask one or more units\n"
4567 " link [PATH...] Link one or more units files into\n"
4568 " the search path\n"
34c4b47b
LP
4569 " is-enabled [NAME...] Check whether unit files are enabled\n\n"
4570 "Job Commands:\n"
48220598 4571 " list-jobs List jobs\n"
34c4b47b
LP
4572 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
4573 "Status Commands:\n"
7e4249b9 4574 " dump Dump server status\n"
34c4b47b 4575 "Snapshot Commands:\n"
7e4249b9 4576 " snapshot [NAME] Create a snapshot\n"
34c4b47b
LP
4577 " delete [NAME...] Remove one or more snapshots\n\n"
4578 "Environment Commands:\n"
7e4249b9
LP
4579 " show-environment Dump environment\n"
4580 " set-environment [NAME=VALUE...] Set one or more environment variables\n"
34c4b47b
LP
4581 " unset-environment [NAME...] Unset one or more environment variables\n\n"
4582 "Manager Lifecycle Commands:\n"
4583 " daemon-reload Reload systemd manager configuration\n"
4584 " daemon-reexec Reexecute systemd manager\n\n"
4585 "System Commands:\n"
20b09ca7
LP
4586 " default Enter system default mode\n"
4587 " rescue Enter system rescue mode\n"
4588 " emergency Enter system emergency mode\n"
514f4ef5 4589 " halt Shut down and halt the system\n"
2e33c433 4590 " poweroff Shut down and power-off the system\n"
514f4ef5 4591 " reboot Shut down and reboot the system\n"
20b09ca7 4592 " kexec Shut down and reboot the system with kexec\n"
6edd7d0a 4593 " exit Request user instance exit\n"
957eb8ca 4594 " switch-root [ROOT] [INIT] Change to a different root file system\n"
6edd7d0a 4595 " suspend Suspend the system\n"
6524990f
LP
4596 " hibernate Hibernate the system\n"
4597 " hybrid-sleep Hibernate and suspend the system\n",
5b6319dc 4598 program_invocation_short_name);
7e4249b9
LP
4599
4600 return 0;
4601}
4602
e4b61340
LP
4603static int halt_help(void) {
4604
2e33c433 4605 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
4606 "%s the system.\n\n"
4607 " --help Show this help\n"
4608 " --halt Halt the machine\n"
4609 " -p --poweroff Switch off the machine\n"
4610 " --reboot Reboot the machine\n"
2e33c433
LP
4611 " -f --force Force immediate halt/power-off/reboot\n"
4612 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
e4b61340 4613 " -d --no-wtmp Don't write wtmp record\n"
2e33c433 4614 " --no-wall Don't send wall message before halt/power-off/reboot\n",
e4b61340
LP
4615 program_invocation_short_name,
4616 arg_action == ACTION_REBOOT ? "Reboot" :
4617 arg_action == ACTION_POWEROFF ? "Power off" :
4618 "Halt");
4619
4620 return 0;
4621}
4622
4623static int shutdown_help(void) {
4624
08e4b1c5 4625 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
e4b61340
LP
4626 "Shut down the system.\n\n"
4627 " --help Show this help\n"
4628 " -H --halt Halt the machine\n"
4629 " -P --poweroff Power-off the machine\n"
4630 " -r --reboot Reboot the machine\n"
386da858 4631 " -h Equivalent to --poweroff, overridden by --halt\n"
2e33c433 4632 " -k Don't halt/power-off/reboot, just send warnings\n"
f6144808 4633 " --no-wall Don't send wall message before halt/power-off/reboot\n"
f6144808 4634 " -c Cancel a pending shutdown\n",
e4b61340
LP
4635 program_invocation_short_name);
4636
4637 return 0;
4638}
4639
4640static int telinit_help(void) {
4641
2e33c433 4642 printf("%s [OPTIONS...] {COMMAND}\n\n"
514f4ef5
LP
4643 "Send control commands to the init daemon.\n\n"
4644 " --help Show this help\n"
2e33c433 4645 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
e4b61340
LP
4646 "Commands:\n"
4647 " 0 Power-off the machine\n"
4648 " 6 Reboot the machine\n"
514f4ef5
LP
4649 " 2, 3, 4, 5 Start runlevelX.target unit\n"
4650 " 1, s, S Enter rescue mode\n"
4651 " q, Q Reload init daemon configuration\n"
4652 " u, U Reexecute init daemon\n",
e4b61340
LP
4653 program_invocation_short_name);
4654
4655 return 0;
4656}
4657
4658static int runlevel_help(void) {
4659
2e33c433 4660 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
4661 "Prints the previous and current runlevel of the init system.\n\n"
4662 " --help Show this help\n",
4663 program_invocation_short_name);
4664
4665 return 0;
4666}
4667
45c0c61d
ZJS
4668static int help_types(void) {
4669 int i;
830f01f0 4670 const char *t;
45c0c61d
ZJS
4671
4672 puts("Available unit types:");
830f01f0
LP
4673 for(i = 0; i < _UNIT_TYPE_MAX; i++) {
4674 t = unit_type_to_string(i);
4675 if (t)
4676 puts(t);
4677 }
45c0c61d
ZJS
4678
4679 puts("\nAvailable unit load states: ");
830f01f0
LP
4680 for(i = 0; i < _UNIT_LOAD_STATE_MAX; i++) {
4681 t = unit_load_state_to_string(i);
4682 if (t)
4683 puts(t);
4684 }
45c0c61d
ZJS
4685
4686 return 0;
4687}
4688
e4b61340 4689static int systemctl_parse_argv(int argc, char *argv[]) {
7e4249b9
LP
4690
4691 enum {
90d473a1 4692 ARG_FAIL = 0x100,
991f2a39 4693 ARG_SHOW_TYPES,
23ade460 4694 ARG_IRREVERSIBLE,
e67c3609 4695 ARG_IGNORE_DEPENDENCIES,
35df8f27 4696 ARG_VERSION,
af2d49f7 4697 ARG_USER,
7e4249b9 4698 ARG_SYSTEM,
ee5762e3 4699 ARG_GLOBAL,
6e905d93 4700 ARG_NO_BLOCK,
ebed32bf 4701 ARG_NO_LEGEND,
611efaac 4702 ARG_NO_PAGER,
4445a875 4703 ARG_NO_WALL,
be394c48 4704 ARG_ROOT,
ee5762e3 4705 ARG_FULL,
ee5762e3 4706 ARG_NO_RELOAD,
501fc174 4707 ARG_KILL_WHO,
30732560 4708 ARG_NO_ASK_PASSWORD,
729e3769 4709 ARG_FAILED,
df50185b 4710 ARG_RUNTIME,
568b679f 4711 ARG_FORCE
7e4249b9
LP
4712 };
4713
4714 static const struct option options[] = {
ee5762e3 4715 { "help", no_argument, NULL, 'h' },
35df8f27 4716 { "version", no_argument, NULL, ARG_VERSION },
ee5762e3
LP
4717 { "type", required_argument, NULL, 't' },
4718 { "property", required_argument, NULL, 'p' },
4719 { "all", no_argument, NULL, 'a' },
991f2a39 4720 { "show-types", no_argument, NULL, ARG_SHOW_TYPES },
30732560 4721 { "failed", no_argument, NULL, ARG_FAILED },
ee5762e3
LP
4722 { "full", no_argument, NULL, ARG_FULL },
4723 { "fail", no_argument, NULL, ARG_FAIL },
23ade460 4724 { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE },
e67c3609 4725 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
b37844d3 4726 { "ignore-inhibitors", no_argument, NULL, 'i' },
af2d49f7 4727 { "user", no_argument, NULL, ARG_USER },
ee5762e3
LP
4728 { "system", no_argument, NULL, ARG_SYSTEM },
4729 { "global", no_argument, NULL, ARG_GLOBAL },
4730 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
ebed32bf 4731 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
0736af98 4732 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
ee5762e3
LP
4733 { "no-wall", no_argument, NULL, ARG_NO_WALL },
4734 { "quiet", no_argument, NULL, 'q' },
be394c48 4735 { "root", required_argument, NULL, ARG_ROOT },
568b679f 4736 { "force", no_argument, NULL, ARG_FORCE },
ee5762e3 4737 { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
8a0867d6
LP
4738 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
4739 { "signal", required_argument, NULL, 's' },
501fc174 4740 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
a8f11321
LP
4741 { "host", required_argument, NULL, 'H' },
4742 { "privileged",no_argument, NULL, 'P' },
729e3769 4743 { "runtime", no_argument, NULL, ARG_RUNTIME },
df50185b 4744 { "lines", required_argument, NULL, 'n' },
df50185b 4745 { "output", required_argument, NULL, 'o' },
ee5762e3 4746 { NULL, 0, NULL, 0 }
7e4249b9
LP
4747 };
4748
4749 int c;
4750
e4b61340 4751 assert(argc >= 0);
7e4249b9
LP
4752 assert(argv);
4753
b37844d3 4754 while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:i", options, NULL)) >= 0) {
7e4249b9
LP
4755
4756 switch (c) {
4757
4758 case 'h':
e4b61340 4759 systemctl_help();
7e4249b9 4760 return 0;
35df8f27
LP
4761
4762 case ARG_VERSION:
4763 puts(PACKAGE_STRING);
7d568925 4764 puts(SYSTEMD_FEATURES);
35df8f27 4765 return 0;
7e4249b9 4766
20b3f379
ZJS
4767 case 't': {
4768 char *word, *state;
4769 size_t size;
45c0c61d 4770
20b3f379
ZJS
4771 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
4772 char _cleanup_free_ *type;
4773
4774 type = strndup(word, size);
4775 if (!type)
4776 return -ENOMEM;
4777
4778 if (streq(type, "help")) {
4779 help_types();
4780 return 0;
4781 }
4782
4783 if (unit_type_from_string(type) >= 0) {
4784 if (strv_push(&arg_types, type))
4785 return log_oom();
4786 type = NULL;
4787 continue;
4788 }
4789
4790 if (unit_load_state_from_string(optarg) >= 0) {
4791 if (strv_push(&arg_load_states, type))
4792 return log_oom();
4793 type = NULL;
4794 continue;
4795 }
4796
4797 log_error("Unkown unit type or load state '%s'.", type);
4798 log_info("Use -t help to see a list of allowed values.");
4799 return -EINVAL;
c147dc42 4800 }
20b3f379
ZJS
4801
4802 break;
4803 }
4804
ea4a240d 4805 case 'p': {
033a842c
ZJS
4806 /* Make sure that if the empty property list
4807 was specified, we won't show any properties. */
20b3f379
ZJS
4808 if (isempty(optarg) && !arg_properties) {
4809 arg_properties = strv_new(NULL, NULL);
4810 if (!arg_properties)
4811 return log_oom();
4812 } else {
4813 char *word, *state;
4814 size_t size;
033a842c 4815
20b3f379
ZJS
4816 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
4817 char *prop;
033a842c 4818
20b3f379
ZJS
4819 prop = strndup(word, size);
4820 if (!prop)
4821 return log_oom();
ea4a240d 4822
20b3f379
ZJS
4823 if (strv_push(&arg_properties, prop)) {
4824 free(prop);
4825 return log_oom();
4826 }
4827 }
033a842c 4828 }
48220598
LP
4829
4830 /* If the user asked for a particular
4831 * property, show it to him, even if it is
4832 * empty. */
4833 arg_all = true;
033a842c 4834
48220598 4835 break;
ea4a240d 4836 }
48220598 4837
7e4249b9
LP
4838 case 'a':
4839 arg_all = true;
4840 break;
4841
991f2a39
ZJS
4842 case ARG_SHOW_TYPES:
4843 arg_show_types = true;
4844 break;
4845
90d473a1 4846 case ARG_FAIL:
e67c3609
LP
4847 arg_job_mode = "fail";
4848 break;
4849
23ade460
MS
4850 case ARG_IRREVERSIBLE:
4851 arg_job_mode = "replace-irreversibly";
4852 break;
4853
e67c3609
LP
4854 case ARG_IGNORE_DEPENDENCIES:
4855 arg_job_mode = "ignore-dependencies";
7e4249b9
LP
4856 break;
4857
af2d49f7 4858 case ARG_USER:
729e3769 4859 arg_scope = UNIT_FILE_USER;
7e4249b9
LP
4860 break;
4861
4862 case ARG_SYSTEM:
729e3769
LP
4863 arg_scope = UNIT_FILE_SYSTEM;
4864 break;
4865
4866 case ARG_GLOBAL:
4867 arg_scope = UNIT_FILE_GLOBAL;
7e4249b9
LP
4868 break;
4869
6e905d93
LP
4870 case ARG_NO_BLOCK:
4871 arg_no_block = true;
7e4249b9
LP
4872 break;
4873
ebed32bf
MS
4874 case ARG_NO_LEGEND:
4875 arg_no_legend = true;
4876 break;
4877
611efaac
LP
4878 case ARG_NO_PAGER:
4879 arg_no_pager = true;
4880 break;
0736af98 4881
514f4ef5
LP
4882 case ARG_NO_WALL:
4883 arg_no_wall = true;
4884 break;
4885
be394c48
FC
4886 case ARG_ROOT:
4887 arg_root = optarg;
4888 break;
4889
8fe914ec
LP
4890 case ARG_FULL:
4891 arg_full = true;
4892 break;
4893
30732560
LP
4894 case ARG_FAILED:
4895 arg_failed = true;
4896 break;
4897
0183528f
LP
4898 case 'q':
4899 arg_quiet = true;
4900 break;
4901
568b679f
LP
4902 case ARG_FORCE:
4903 arg_force ++;
4904 break;
4905
b4f27ccc 4906 case 'f':
e606bb61 4907 arg_force ++;
ee5762e3
LP
4908 break;
4909
4910 case ARG_NO_RELOAD:
4911 arg_no_reload = true;
4912 break;
4913
8a0867d6
LP
4914 case ARG_KILL_WHO:
4915 arg_kill_who = optarg;
4916 break;
4917
8a0867d6
LP
4918 case 's':
4919 if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
4920 log_error("Failed to parse signal string %s.", optarg);
4921 return -EINVAL;
4922 }
4923 break;
4924
501fc174
LP
4925 case ARG_NO_ASK_PASSWORD:
4926 arg_ask_password = false;
4927 break;
4928
a8f11321
LP
4929 case 'P':
4930 arg_transport = TRANSPORT_POLKIT;
4931 break;
4932
4933 case 'H':
4934 arg_transport = TRANSPORT_SSH;
4935 arg_host = optarg;
4936 break;
4937
729e3769
LP
4938 case ARG_RUNTIME:
4939 arg_runtime = true;
4940 break;
4941
df50185b
LP
4942 case 'n':
4943 if (safe_atou(optarg, &arg_lines) < 0) {
4944 log_error("Failed to parse lines '%s'", optarg);
4945 return -EINVAL;
4946 }
4947 break;
4948
df50185b
LP
4949 case 'o':
4950 arg_output = output_mode_from_string(optarg);
4951 if (arg_output < 0) {
4952 log_error("Unknown output '%s'.", optarg);
4953 return -EINVAL;
4954 }
4955 break;
4956
b37844d3
LP
4957 case 'i':
4958 arg_ignore_inhibitors = true;
4959 break;
4960
7e4249b9
LP
4961 case '?':
4962 return -EINVAL;
4963
4964 default:
b0193f1c 4965 log_error("Unknown option code '%c'.", c);
7e4249b9
LP
4966 return -EINVAL;
4967 }
4968 }
4969
729e3769 4970 if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
a8f11321
LP
4971 log_error("Cannot access user instance remotely.");
4972 return -EINVAL;
4973 }
4974
7e4249b9
LP
4975 return 1;
4976}
4977
e4b61340
LP
4978static int halt_parse_argv(int argc, char *argv[]) {
4979
4980 enum {
4981 ARG_HELP = 0x100,
4982 ARG_HALT,
514f4ef5
LP
4983 ARG_REBOOT,
4984 ARG_NO_WALL
e4b61340
LP
4985 };
4986
4987 static const struct option options[] = {
4988 { "help", no_argument, NULL, ARG_HELP },
4989 { "halt", no_argument, NULL, ARG_HALT },
4990 { "poweroff", no_argument, NULL, 'p' },
4991 { "reboot", no_argument, NULL, ARG_REBOOT },
4992 { "force", no_argument, NULL, 'f' },
4993 { "wtmp-only", no_argument, NULL, 'w' },
4994 { "no-wtmp", no_argument, NULL, 'd' },
514f4ef5 4995 { "no-wall", no_argument, NULL, ARG_NO_WALL },
e4b61340
LP
4996 { NULL, 0, NULL, 0 }
4997 };
4998
4999 int c, runlevel;
5000
5001 assert(argc >= 0);
5002 assert(argv);
5003
5004 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
5005 if (runlevel == '0' || runlevel == '6')
65491fd8 5006 arg_force = 2;
e4b61340
LP
5007
5008 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
5009 switch (c) {
5010
5011 case ARG_HELP:
5012 halt_help();
5013 return 0;
5014
5015 case ARG_HALT:
5016 arg_action = ACTION_HALT;
5017 break;
5018
5019 case 'p':
a042efad
MS
5020 if (arg_action != ACTION_REBOOT)
5021 arg_action = ACTION_POWEROFF;
e4b61340
LP
5022 break;
5023
5024 case ARG_REBOOT:
5025 arg_action = ACTION_REBOOT;
5026 break;
5027
5028 case 'f':
65491fd8 5029 arg_force = 2;
e4b61340
LP
5030 break;
5031
5032 case 'w':
5033 arg_dry = true;
5034 break;
5035
5036 case 'd':
5037 arg_no_wtmp = true;
5038 break;
5039
514f4ef5
LP
5040 case ARG_NO_WALL:
5041 arg_no_wall = true;
5042 break;
5043
e4b61340
LP
5044 case 'i':
5045 case 'h':
57371e58 5046 case 'n':
e4b61340
LP
5047 /* Compatibility nops */
5048 break;
5049
5050 case '?':
5051 return -EINVAL;
5052
5053 default:
b0193f1c 5054 log_error("Unknown option code '%c'.", c);
e4b61340
LP
5055 return -EINVAL;
5056 }
5057 }
5058
5059 if (optind < argc) {
5060 log_error("Too many arguments.");
5061 return -EINVAL;
5062 }
5063
5064 return 1;
5065}
5066
f6144808
LP
5067static int parse_time_spec(const char *t, usec_t *_u) {
5068 assert(t);
5069 assert(_u);
5070
5071 if (streq(t, "now"))
5072 *_u = 0;
1a639877 5073 else if (!strchr(t, ':')) {
f6144808
LP
5074 uint64_t u;
5075
1a639877 5076 if (safe_atou64(t, &u) < 0)
f6144808
LP
5077 return -EINVAL;
5078
5079 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
5080 } else {
5081 char *e = NULL;
5082 long hour, minute;
b92bea5d 5083 struct tm tm = {};
f6144808
LP
5084 time_t s;
5085 usec_t n;
5086
5087 errno = 0;
5088 hour = strtol(t, &e, 10);
8333c77e 5089 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
f6144808
LP
5090 return -EINVAL;
5091
5092 minute = strtol(e+1, &e, 10);
8333c77e 5093 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
f6144808
LP
5094 return -EINVAL;
5095
5096 n = now(CLOCK_REALTIME);
08e4b1c5
LP
5097 s = (time_t) (n / USEC_PER_SEC);
5098
f6144808
LP
5099 assert_se(localtime_r(&s, &tm));
5100
5101 tm.tm_hour = (int) hour;
5102 tm.tm_min = (int) minute;
08e4b1c5 5103 tm.tm_sec = 0;
f6144808
LP
5104
5105 assert_se(s = mktime(&tm));
5106
5107 *_u = (usec_t) s * USEC_PER_SEC;
5108
5109 while (*_u <= n)
5110 *_u += USEC_PER_DAY;
5111 }
5112
5113 return 0;
5114}
5115
e4b61340
LP
5116static int shutdown_parse_argv(int argc, char *argv[]) {
5117
5118 enum {
5119 ARG_HELP = 0x100,
514f4ef5 5120 ARG_NO_WALL
e4b61340
LP
5121 };
5122
5123 static const struct option options[] = {
5124 { "help", no_argument, NULL, ARG_HELP },
5125 { "halt", no_argument, NULL, 'H' },
5126 { "poweroff", no_argument, NULL, 'P' },
5127 { "reboot", no_argument, NULL, 'r' },
04ebb595 5128 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
514f4ef5 5129 { "no-wall", no_argument, NULL, ARG_NO_WALL },
e4b61340
LP
5130 { NULL, 0, NULL, 0 }
5131 };
5132
f6144808 5133 int c, r;
e4b61340
LP
5134
5135 assert(argc >= 0);
5136 assert(argv);
5137
f6144808 5138 while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
e4b61340
LP
5139 switch (c) {
5140
5141 case ARG_HELP:
5142 shutdown_help();
5143 return 0;
5144
5145 case 'H':
5146 arg_action = ACTION_HALT;
5147 break;
5148
5149 case 'P':
5150 arg_action = ACTION_POWEROFF;
5151 break;
5152
5153 case 'r':
5622dde3
KS
5154 if (kexec_loaded())
5155 arg_action = ACTION_KEXEC;
5156 else
5157 arg_action = ACTION_REBOOT;
e4b61340
LP
5158 break;
5159
04ebb595
LP
5160 case 'K':
5161 arg_action = ACTION_KEXEC;
5162 break;
5163
e4b61340
LP
5164 case 'h':
5165 if (arg_action != ACTION_HALT)
5166 arg_action = ACTION_POWEROFF;
5167 break;
5168
5169 case 'k':
5170 arg_dry = true;
5171 break;
5172
514f4ef5
LP
5173 case ARG_NO_WALL:
5174 arg_no_wall = true;
5175 break;
5176
e4b61340
LP
5177 case 't':
5178 case 'a':
5179 /* Compatibility nops */
5180 break;
5181
f6144808
LP
5182 case 'c':
5183 arg_action = ACTION_CANCEL_SHUTDOWN;
5184 break;
5185
e4b61340
LP
5186 case '?':
5187 return -EINVAL;
5188
5189 default:
b0193f1c 5190 log_error("Unknown option code '%c'.", c);
e4b61340
LP
5191 return -EINVAL;
5192 }
5193 }
5194
dfcc5c33 5195 if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
7e59bfcb
LP
5196 r = parse_time_spec(argv[optind], &arg_when);
5197 if (r < 0) {
f6144808
LP
5198 log_error("Failed to parse time specification: %s", argv[optind]);
5199 return r;
5200 }
6b5ad000 5201 } else
08e4b1c5 5202 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
442b9094 5203
dfcc5c33
MS
5204 if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
5205 /* No time argument for shutdown cancel */
5206 arg_wall = argv + optind;
5207 else if (argc > optind + 1)
5208 /* We skip the time argument */
e4b61340
LP
5209 arg_wall = argv + optind + 1;
5210
5211 optind = argc;
5212
5213 return 1;
e4b61340
LP
5214}
5215
5216static int telinit_parse_argv(int argc, char *argv[]) {
5217
5218 enum {
5219 ARG_HELP = 0x100,
514f4ef5 5220 ARG_NO_WALL
e4b61340
LP
5221 };
5222
5223 static const struct option options[] = {
5224 { "help", no_argument, NULL, ARG_HELP },
514f4ef5 5225 { "no-wall", no_argument, NULL, ARG_NO_WALL },
e4b61340
LP
5226 { NULL, 0, NULL, 0 }
5227 };
5228
5229 static const struct {
5230 char from;
5231 enum action to;
5232 } table[] = {
5233 { '0', ACTION_POWEROFF },
5234 { '6', ACTION_REBOOT },
ef2f1067 5235 { '1', ACTION_RESCUE },
e4b61340
LP
5236 { '2', ACTION_RUNLEVEL2 },
5237 { '3', ACTION_RUNLEVEL3 },
5238 { '4', ACTION_RUNLEVEL4 },
5239 { '5', ACTION_RUNLEVEL5 },
5240 { 's', ACTION_RESCUE },
5241 { 'S', ACTION_RESCUE },
5242 { 'q', ACTION_RELOAD },
5243 { 'Q', ACTION_RELOAD },
5244 { 'u', ACTION_REEXEC },
5245 { 'U', ACTION_REEXEC }
5246 };
5247
5248 unsigned i;
5249 int c;
5250
5251 assert(argc >= 0);
5252 assert(argv);
5253
5254 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5255 switch (c) {
5256
5257 case ARG_HELP:
5258 telinit_help();
5259 return 0;
5260
514f4ef5
LP
5261 case ARG_NO_WALL:
5262 arg_no_wall = true;
5263 break;
5264
e4b61340
LP
5265 case '?':
5266 return -EINVAL;
5267
5268 default:
b0193f1c 5269 log_error("Unknown option code '%c'.", c);
e4b61340
LP
5270 return -EINVAL;
5271 }
5272 }
5273
5274 if (optind >= argc) {
2f02ce40 5275 telinit_help();
e4b61340
LP
5276 return -EINVAL;
5277 }
5278
5279 if (optind + 1 < argc) {
5280 log_error("Too many arguments.");
5281 return -EINVAL;
5282 }
5283
5284 if (strlen(argv[optind]) != 1) {
5285 log_error("Expected single character argument.");
5286 return -EINVAL;
5287 }
5288
5289 for (i = 0; i < ELEMENTSOF(table); i++)
5290 if (table[i].from == argv[optind][0])
5291 break;
5292
5293 if (i >= ELEMENTSOF(table)) {
b0193f1c 5294 log_error("Unknown command '%s'.", argv[optind]);
e4b61340
LP
5295 return -EINVAL;
5296 }
5297
5298 arg_action = table[i].to;
5299
5300 optind ++;
5301
5302 return 1;
5303}
5304
5305static int runlevel_parse_argv(int argc, char *argv[]) {
5306
5307 enum {
5308 ARG_HELP = 0x100,
5309 };
5310
5311 static const struct option options[] = {
5312 { "help", no_argument, NULL, ARG_HELP },
5313 { NULL, 0, NULL, 0 }
5314 };
5315
5316 int c;
5317
5318 assert(argc >= 0);
5319 assert(argv);
5320
5321 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5322 switch (c) {
5323
5324 case ARG_HELP:
5325 runlevel_help();
5326 return 0;
5327
5328 case '?':
5329 return -EINVAL;
5330
5331 default:
b0193f1c 5332 log_error("Unknown option code '%c'.", c);
e4b61340
LP
5333 return -EINVAL;
5334 }
5335 }
5336
5337 if (optind < argc) {
5338 log_error("Too many arguments.");
5339 return -EINVAL;
5340 }
5341
5342 return 1;
5343}
5344
5345static int parse_argv(int argc, char *argv[]) {
5346 assert(argc >= 0);
5347 assert(argv);
5348
5349 if (program_invocation_short_name) {
5350
5351 if (strstr(program_invocation_short_name, "halt")) {
5352 arg_action = ACTION_HALT;
5353 return halt_parse_argv(argc, argv);
5354 } else if (strstr(program_invocation_short_name, "poweroff")) {
5355 arg_action = ACTION_POWEROFF;
5356 return halt_parse_argv(argc, argv);
5357 } else if (strstr(program_invocation_short_name, "reboot")) {
5622dde3
KS
5358 if (kexec_loaded())
5359 arg_action = ACTION_KEXEC;
5360 else
5361 arg_action = ACTION_REBOOT;
e4b61340
LP
5362 return halt_parse_argv(argc, argv);
5363 } else if (strstr(program_invocation_short_name, "shutdown")) {
5364 arg_action = ACTION_POWEROFF;
5365 return shutdown_parse_argv(argc, argv);
5366 } else if (strstr(program_invocation_short_name, "init")) {
d5ca5f11
LP
5367
5368 if (sd_booted() > 0) {
5369 arg_action = ACTION_INVALID;
5370 return telinit_parse_argv(argc, argv);
5371 } else {
5372 /* Hmm, so some other init system is
5373 * running, we need to forward this
5374 * request to it. For now we simply
5375 * guess that it is Upstart. */
5376
4ad61fd1 5377 execv(TELINIT, argv);
d5ca5f11
LP
5378
5379 log_error("Couldn't find an alternative telinit implementation to spawn.");
5380 return -EIO;
5381 }
5382
e4b61340
LP
5383 } else if (strstr(program_invocation_short_name, "runlevel")) {
5384 arg_action = ACTION_RUNLEVEL;
5385 return runlevel_parse_argv(argc, argv);
5386 }
5387 }
5388
5389 arg_action = ACTION_SYSTEMCTL;
5390 return systemctl_parse_argv(argc, argv);
5391}
5392
d55ae9e6 5393static int action_to_runlevel(void) {
eb22ac37
LP
5394
5395 static const char table[_ACTION_MAX] = {
5396 [ACTION_HALT] = '0',
5397 [ACTION_POWEROFF] = '0',
5398 [ACTION_REBOOT] = '6',
5399 [ACTION_RUNLEVEL2] = '2',
5400 [ACTION_RUNLEVEL3] = '3',
5401 [ACTION_RUNLEVEL4] = '4',
5402 [ACTION_RUNLEVEL5] = '5',
5403 [ACTION_RESCUE] = '1'
5404 };
5405
d55ae9e6
LP
5406 assert(arg_action < _ACTION_MAX);
5407
5408 return table[arg_action];
5409}
5410
f1c5860b 5411static int talk_upstart(void) {
cec7eda5
ZJS
5412 DBusMessage _cleanup_dbus_message_unref_ *m = NULL, *reply = NULL;
5413 DBusError _cleanup_dbus_error_free_ error;
d55ae9e6
LP
5414 int previous, rl, r;
5415 char
5416 env1_buf[] = "RUNLEVEL=X",
5417 env2_buf[] = "PREVLEVEL=X";
5418 char *env1 = env1_buf, *env2 = env2_buf;
5419 const char *emit = "runlevel";
5420 dbus_bool_t b_false = FALSE;
5421 DBusMessageIter iter, sub;
f1c5860b 5422 DBusConnection *bus;
d55ae9e6
LP
5423
5424 dbus_error_init(&error);
5425
5426 if (!(rl = action_to_runlevel()))
5427 return 0;
5428
5429 if (utmp_get_runlevel(&previous, NULL) < 0)
5430 previous = 'N';
5431
b574246b 5432 if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
f1c5860b
LP
5433 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
5434 r = 0;
5435 goto finish;
5436 }
5437
4cf5d675 5438 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
f1c5860b
LP
5439 r = -EIO;
5440 goto finish;
5441 }
5442
5443 if ((r = bus_check_peercred(bus)) < 0) {
5444 log_error("Failed to verify owner of bus.");
5445 goto finish;
5446 }
5447
d55ae9e6
LP
5448 if (!(m = dbus_message_new_method_call(
5449 "com.ubuntu.Upstart",
5450 "/com/ubuntu/Upstart",
5451 "com.ubuntu.Upstart0_6",
5452 "EmitEvent"))) {
5453
5454 log_error("Could not allocate message.");
f1c5860b
LP
5455 r = -ENOMEM;
5456 goto finish;
d55ae9e6
LP
5457 }
5458
5459 dbus_message_iter_init_append(m, &iter);
5460
5461 env1_buf[sizeof(env1_buf)-2] = rl;
5462 env2_buf[sizeof(env2_buf)-2] = previous;
5463
5464 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
5465 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
5466 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
5467 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
5468 !dbus_message_iter_close_container(&iter, &sub) ||
5469 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
5470 log_error("Could not append arguments to message.");
5471 r = -ENOMEM;
5472 goto finish;
5473 }
5474
5475 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
5476
c67de56f 5477 if (bus_error_is_no_service(&error)) {
aabd9b11 5478 r = -EADDRNOTAVAIL;
d55ae9e6
LP
5479 goto finish;
5480 }
5481
4cf5d675 5482 log_error("Failed to issue method call: %s", bus_error_message(&error));
d55ae9e6
LP
5483 r = -EIO;
5484 goto finish;
5485 }
5486
0a55b298 5487 r = 1;
d55ae9e6
LP
5488
5489finish:
b574246b 5490 if (bus) {
5d452f9c 5491 dbus_connection_flush(bus);
b574246b 5492 dbus_connection_close(bus);
f1c5860b 5493 dbus_connection_unref(bus);
b574246b 5494 }
f1c5860b 5495
d55ae9e6
LP
5496 return r;
5497}
5498
5499static int talk_initctl(void) {
b92bea5d 5500 struct init_request request = {};
427b47c4
ZJS
5501 int r;
5502 int _cleanup_close_ fd = -1;
d55ae9e6 5503 char rl;
eb22ac37 5504
427b47c4
ZJS
5505 rl = action_to_runlevel();
5506 if (!rl)
eb22ac37
LP
5507 return 0;
5508
eb22ac37
LP
5509 request.magic = INIT_MAGIC;
5510 request.sleeptime = 0;
5511 request.cmd = INIT_CMD_RUNLVL;
d55ae9e6
LP
5512 request.runlevel = rl;
5513
427b47c4
ZJS
5514 fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
5515 if (fd < 0) {
d55ae9e6
LP
5516 if (errno == ENOENT)
5517 return 0;
eb22ac37 5518
d55ae9e6 5519 log_error("Failed to open "INIT_FIFO": %m");
eb22ac37 5520 return -errno;
d55ae9e6 5521 }
eb22ac37 5522
d55ae9e6 5523 errno = 0;
eb22ac37 5524 r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
427b47c4 5525 if (r) {
d55ae9e6 5526 log_error("Failed to write to "INIT_FIFO": %m");
bcb161b0 5527 return errno > 0 ? -errno : -EIO;
d55ae9e6 5528 }
eb22ac37
LP
5529
5530 return 1;
e4b61340
LP
5531}
5532
ee5762e3 5533static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
7e4249b9 5534
7e4249b9
LP
5535 static const struct {
5536 const char* verb;
5537 const enum {
5538 MORE,
5539 LESS,
5540 EQUAL
5541 } argc_cmp;
5542 const int argc;
729e3769 5543 int (* const dispatch)(DBusConnection *bus, char **args);
7e4249b9 5544 } verbs[] = {
ee5762e3 5545 { "list-units", LESS, 1, list_units },
729e3769 5546 { "list-unit-files", EQUAL, 1, list_unit_files },
991f2a39 5547 { "list-sockets", LESS, 1, list_sockets },
ee5762e3
LP
5548 { "list-jobs", EQUAL, 1, list_jobs },
5549 { "clear-jobs", EQUAL, 1, daemon_reload },
5550 { "load", MORE, 2, load_unit },
5551 { "cancel", MORE, 2, cancel_job },
5552 { "start", MORE, 2, start_unit },
5553 { "stop", MORE, 2, start_unit },
a76f7be2 5554 { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
5555 { "reload", MORE, 2, start_unit },
5556 { "restart", MORE, 2, start_unit },
5557 { "try-restart", MORE, 2, start_unit },
5558 { "reload-or-restart", MORE, 2, start_unit },
5559 { "reload-or-try-restart", MORE, 2, start_unit },
5560 { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */
64e5f1b7 5561 { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
5562 { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
5563 { "isolate", EQUAL, 2, start_unit },
1f4cadad
LP
5564 { "set-cgroup", MORE, 3, set_cgroup },
5565 { "unset-cgroup", MORE, 3, set_cgroup },
5566 { "get-cgroup-attr", MORE, 3, get_cgroup_attr },
5567 { "set-cgroup-attr", MORE, 4, set_cgroup_attr },
5568 { "unset-cgroup-attr", MORE, 3, set_cgroup },
8a0867d6 5569 { "kill", MORE, 2, kill_unit },
1a0fce45
TA
5570 { "is-active", MORE, 2, check_unit_active },
5571 { "check", MORE, 2, check_unit_active },
5572 { "is-failed", MORE, 2, check_unit_failed },
ee5762e3 5573 { "show", MORE, 1, show },
265a7a2a 5574 { "status", MORE, 1, show },
b43f208f 5575 { "help", MORE, 2, show },
ee5762e3 5576 { "dump", EQUAL, 1, dump },
ee5762e3
LP
5577 { "snapshot", LESS, 2, snapshot },
5578 { "delete", MORE, 2, delete_snapshot },
5579 { "daemon-reload", EQUAL, 1, daemon_reload },
5580 { "daemon-reexec", EQUAL, 1, daemon_reload },
ee5762e3
LP
5581 { "show-environment", EQUAL, 1, show_enviroment },
5582 { "set-environment", MORE, 2, set_environment },
5583 { "unset-environment", MORE, 2, set_environment },
5584 { "halt", EQUAL, 1, start_special },
5585 { "poweroff", EQUAL, 1, start_special },
5586 { "reboot", EQUAL, 1, start_special },
20b09ca7 5587 { "kexec", EQUAL, 1, start_special },
6edd7d0a
LP
5588 { "suspend", EQUAL, 1, start_special },
5589 { "hibernate", EQUAL, 1, start_special },
6524990f 5590 { "hybrid-sleep", EQUAL, 1, start_special },
ee5762e3
LP
5591 { "default", EQUAL, 1, start_special },
5592 { "rescue", EQUAL, 1, start_special },
5593 { "emergency", EQUAL, 1, start_special },
20b09ca7 5594 { "exit", EQUAL, 1, start_special },
fdf20a31 5595 { "reset-failed", MORE, 1, reset_failed },
ee5762e3
LP
5596 { "enable", MORE, 2, enable_unit },
5597 { "disable", MORE, 2, enable_unit },
729e3769
LP
5598 { "is-enabled", MORE, 2, unit_is_enabled },
5599 { "reenable", MORE, 2, enable_unit },
5600 { "preset", MORE, 2, enable_unit },
5601 { "mask", MORE, 2, enable_unit },
5602 { "unmask", MORE, 2, enable_unit },
957eb8ca
LP
5603 { "link", MORE, 2, enable_unit },
5604 { "switch-root", MORE, 2, switch_root },
e31165b2 5605 { "list-dependencies", LESS, 2, list_dependencies },
7e4249b9
LP
5606 };
5607
e4b61340 5608 int left;
7e4249b9 5609 unsigned i;
7e4249b9 5610
e4b61340
LP
5611 assert(argc >= 0);
5612 assert(argv);
ee5762e3 5613 assert(error);
7e4249b9
LP
5614
5615 left = argc - optind;
5616
5617 if (left <= 0)
5618 /* Special rule: no arguments means "list-units" */
5619 i = 0;
5620 else {
b43f208f
KS
5621 if (streq(argv[optind], "help") && !argv[optind+1]) {
5622 log_error("This command expects one or more "
5623 "unit names. Did you mean --help?");
5624 return -EINVAL;
0183528f
LP
5625 }
5626
7e4249b9
LP
5627 for (i = 0; i < ELEMENTSOF(verbs); i++)
5628 if (streq(argv[optind], verbs[i].verb))
5629 break;
5630
5631 if (i >= ELEMENTSOF(verbs)) {
b0193f1c 5632 log_error("Unknown operation '%s'.", argv[optind]);
e4b61340 5633 return -EINVAL;
7e4249b9
LP
5634 }
5635 }
5636
5637 switch (verbs[i].argc_cmp) {
5638
5639 case EQUAL:
5640 if (left != verbs[i].argc) {
5641 log_error("Invalid number of arguments.");
e4b61340 5642 return -EINVAL;
7e4249b9
LP
5643 }
5644
5645 break;
5646
5647 case MORE:
5648 if (left < verbs[i].argc) {
5649 log_error("Too few arguments.");
e4b61340 5650 return -EINVAL;
7e4249b9
LP
5651 }
5652
5653 break;
5654
5655 case LESS:
5656 if (left > verbs[i].argc) {
5657 log_error("Too many arguments.");
e4b61340 5658 return -EINVAL;
7e4249b9
LP
5659 }
5660
5661 break;
5662
5663 default:
5664 assert_not_reached("Unknown comparison operator.");
5665 }
5666
ee5762e3
LP
5667 /* Require a bus connection for all operations but
5668 * enable/disable */
729e3769
LP
5669 if (!streq(verbs[i].verb, "enable") &&
5670 !streq(verbs[i].verb, "disable") &&
c971700e 5671 !streq(verbs[i].verb, "is-enabled") &&
d380a3bc 5672 !streq(verbs[i].verb, "list-unit-files") &&
729e3769
LP
5673 !streq(verbs[i].verb, "reenable") &&
5674 !streq(verbs[i].verb, "preset") &&
5675 !streq(verbs[i].verb, "mask") &&
5676 !streq(verbs[i].verb, "unmask") &&
5677 !streq(verbs[i].verb, "link")) {
82e23ddd
LP
5678
5679 if (running_in_chroot() > 0) {
5680 log_info("Running in chroot, ignoring request.");
5681 return 0;
5682 }
5683
3beddc78 5684 if (((!streq(verbs[i].verb, "reboot") &&
59ddae9f
LP
5685 !streq(verbs[i].verb, "halt") &&
5686 !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
f176b5c2
LP
5687 log_error("Failed to get D-Bus connection: %s",
5688 dbus_error_is_set(error) ? error->message : "No connection to service manager.");
8185a509
LP
5689 return -EIO;
5690 }
5691
5692 } else {
5693
729e3769 5694 if (!bus && !avoid_bus()) {
f176b5c2
LP
5695 log_error("Failed to get D-Bus connection: %s",
5696 dbus_error_is_set(error) ? error->message : "No connection to service manager.");
82e23ddd
LP
5697 return -EIO;
5698 }
ee5762e3
LP
5699 }
5700
729e3769 5701 return verbs[i].dispatch(bus, argv + optind);
e4b61340
LP
5702}
5703
52c00215 5704static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
cec7eda5 5705 int _cleanup_close_ fd;
b92bea5d
ZJS
5706 struct sd_shutdown_command c = {
5707 .usec = t,
5708 .mode = mode,
5709 .dry_run = dry_run,
5710 .warn_wall = warn,
5711 };
5712 union sockaddr_union sockaddr = {
5713 .un.sun_family = AF_UNIX,
5714 .un.sun_path = "/run/systemd/shutdownd",
5715 };
5716 struct iovec iovec[2] = {
5717 {.iov_base = (char*) &c,
5718 .iov_len = offsetof(struct sd_shutdown_command, wall_message),
5719 }
5720 };
5721 struct msghdr msghdr = {
5722 .msg_name = &sockaddr,
5723 .msg_namelen = offsetof(struct sockaddr_un, sun_path)
5724 + sizeof("/run/systemd/shutdownd") - 1,
5725 .msg_iov = iovec,
5726 .msg_iovlen = 1,
5727 };
04ebb595
LP
5728
5729 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5730 if (fd < 0)
5731 return -errno;
f6144808 5732
b92bea5d 5733 if (!isempty(message)) {
04ebb595
LP
5734 iovec[1].iov_base = (char*) message;
5735 iovec[1].iov_len = strlen(message);
b92bea5d 5736 msghdr.msg_iovlen++;
04ebb595 5737 }
f6144808 5738
cec7eda5 5739 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
f6144808 5740 return -errno;
f6144808 5741
f6144808
LP
5742 return 0;
5743}
5744
e4b61340 5745static int reload_with_fallback(DBusConnection *bus) {
e4b61340
LP
5746
5747 if (bus) {
5748 /* First, try systemd via D-Bus. */
d76702a7 5749 if (daemon_reload(bus, NULL) >= 0)
e4b61340
LP
5750 return 0;
5751 }
5752
5753 /* Nothing else worked, so let's try signals */
5754 assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5755
5756 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5757 log_error("kill() failed: %m");
5758 return -errno;
5759 }
5760
5761 return 0;
5762}
5763
5764static int start_with_fallback(DBusConnection *bus) {
e4b61340
LP
5765
5766 if (bus) {
5767 /* First, try systemd via D-Bus. */
729e3769 5768 if (start_unit(bus, NULL) >= 0)
983d9c90 5769 goto done;
e4b61340
LP
5770 }
5771
ec7f7f20
LP
5772 /* Hmm, talking to systemd via D-Bus didn't work. Then
5773 * let's try to talk to Upstart via D-Bus. */
e364ad06 5774 if (talk_upstart() > 0)
ec7f7f20
LP
5775 goto done;
5776
e4b61340
LP
5777 /* Nothing else worked, so let's try
5778 * /dev/initctl */
fbc43921 5779 if (talk_initctl() > 0)
983d9c90 5780 goto done;
d55ae9e6
LP
5781
5782 log_error("Failed to talk to init daemon.");
5783 return -EIO;
983d9c90
LP
5784
5785done:
5786 warn_wall(arg_action);
5787 return 0;
e4b61340
LP
5788}
5789
d91b8841 5790static _noreturn_ void halt_now(enum action a) {
e606bb61
LP
5791
5792 /* Make sure C-A-D is handled by the kernel from this
5793 * point on... */
5794 reboot(RB_ENABLE_CAD);
5795
4c80c73c 5796 switch (a) {
e606bb61
LP
5797
5798 case ACTION_HALT:
5799 log_info("Halting.");
5800 reboot(RB_HALT_SYSTEM);
5801 break;
5802
5803 case ACTION_POWEROFF:
5804 log_info("Powering off.");
5805 reboot(RB_POWER_OFF);
5806 break;
5807
5808 case ACTION_REBOOT:
5809 log_info("Rebooting.");
5810 reboot(RB_AUTOBOOT);
5811 break;
5812
5813 default:
5814 assert_not_reached("Unknown halt action.");
5815 }
5816
5817 assert_not_reached("Uh? This shouldn't happen.");
5818}
5819
e4b61340
LP
5820static int halt_main(DBusConnection *bus) {
5821 int r;
5822
748ebafa
LP
5823 r = check_inhibitors(bus, arg_action);
5824 if (r < 0)
5825 return r;
b37844d3 5826
bc8c2f5c 5827 if (geteuid() != 0) {
7e59bfcb
LP
5828 /* Try logind if we are a normal user and no special
5829 * mode applies. Maybe PolicyKit allows us to shutdown
5830 * the machine. */
5831
5832 if (arg_when <= 0 &&
5833 !arg_dry &&
b37844d3 5834 arg_force <= 0 &&
7e59bfcb
LP
5835 (arg_action == ACTION_POWEROFF ||
5836 arg_action == ACTION_REBOOT)) {
4c80c73c
KS
5837 r = reboot_with_logind(bus, arg_action);
5838 if (r >= 0)
5839 return r;
5840 }
5841
cc8a7a61 5842 log_error("Must be root.");
bc8c2f5c
LP
5843 return -EPERM;
5844 }
5845
f6144808 5846 if (arg_when > 0) {
cec7eda5 5847 char _cleanup_free_ *m;
9be9828c
LP
5848
5849 m = strv_join(arg_wall, " ");
5850 r = send_shutdownd(arg_when,
5851 arg_action == ACTION_HALT ? 'H' :
5852 arg_action == ACTION_POWEROFF ? 'P' :
04ebb595 5853 arg_action == ACTION_KEXEC ? 'K' :
9be9828c 5854 'r',
52c00215 5855 arg_dry,
9be9828c
LP
5856 !arg_no_wall,
5857 m);
9be9828c
LP
5858
5859 if (r < 0)
f6144808 5860 log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
08e4b1c5 5861 else {
7e59bfcb
LP
5862 char date[FORMAT_TIMESTAMP_MAX];
5863
08e4b1c5
LP
5864 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5865 format_timestamp(date, sizeof(date), arg_when));
f6144808 5866 return 0;
08e4b1c5 5867 }
f6144808
LP
5868 }
5869
65491fd8 5870 if (!arg_dry && !arg_force)
e4b61340
LP
5871 return start_with_fallback(bus);
5872
d90e1a30
LP
5873 if (!arg_no_wtmp) {
5874 if (sd_booted() > 0)
5875 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
7e59bfcb
LP
5876 else {
5877 r = utmp_put_shutdown();
5878 if (r < 0)
5879 log_warning("Failed to write utmp record: %s", strerror(-r));
5880 }
d90e1a30 5881 }
e4b61340 5882
e4b61340
LP
5883 if (arg_dry)
5884 return 0;
5885
e606bb61 5886 halt_now(arg_action);
e4b61340
LP
5887 /* We should never reach this. */
5888 return -ENOSYS;
5889}
5890
5891static int runlevel_main(void) {
5892 int r, runlevel, previous;
5893
729e3769
LP
5894 r = utmp_get_runlevel(&runlevel, &previous);
5895 if (r < 0) {
5896 puts("unknown");
e4b61340
LP
5897 return r;
5898 }
5899
5900 printf("%c %c\n",
5901 previous <= 0 ? 'N' : previous,
5902 runlevel <= 0 ? 'N' : runlevel);
5903
5904 return 0;
5905}
5906
5907int main(int argc, char*argv[]) {
22f4096c 5908 int r, retval = EXIT_FAILURE;
e4b61340 5909 DBusConnection *bus = NULL;
cec7eda5 5910 DBusError _cleanup_dbus_error_free_ error;
e4b61340
LP
5911
5912 dbus_error_init(&error);
5913
a9cdc94f 5914 setlocale(LC_ALL, "");
e4b61340 5915 log_parse_environment();
2396fb04 5916 log_open();
e4b61340 5917
04ebb595
LP
5918 r = parse_argv(argc, argv);
5919 if (r < 0)
e4b61340
LP
5920 goto finish;
5921 else if (r == 0) {
22f4096c 5922 retval = EXIT_SUCCESS;
7e4249b9
LP
5923 goto finish;
5924 }
5925
e4b61340
LP
5926 /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5927 * let's shortcut this */
5928 if (arg_action == ACTION_RUNLEVEL) {
22f4096c
LP
5929 r = runlevel_main();
5930 retval = r < 0 ? EXIT_FAILURE : r;
e4b61340
LP
5931 goto finish;
5932 }
5933
82e23ddd
LP
5934 if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
5935 log_info("Running in chroot, ignoring request.");
5936 retval = 0;
5937 goto finish;
5938 }
5939
729e3769
LP
5940 if (!avoid_bus()) {
5941 if (arg_transport == TRANSPORT_NORMAL)
5942 bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
5943 else if (arg_transport == TRANSPORT_POLKIT) {
5944 bus_connect_system_polkit(&bus, &error);
5945 private_bus = false;
5946 } else if (arg_transport == TRANSPORT_SSH) {
5947 bus_connect_system_ssh(NULL, arg_host, &bus, &error);
5948 private_bus = false;
5949 } else
5950 assert_not_reached("Uh, invalid transport...");
5951 }
e4b61340
LP
5952
5953 switch (arg_action) {
5954
22f4096c
LP
5955 case ACTION_SYSTEMCTL:
5956 r = systemctl_main(bus, argc, argv, &error);
e4b61340 5957 break;
e4b61340
LP
5958
5959 case ACTION_HALT:
5960 case ACTION_POWEROFF:
5961 case ACTION_REBOOT:
5622dde3 5962 case ACTION_KEXEC:
22f4096c 5963 r = halt_main(bus);
e4b61340
LP
5964 break;
5965
e4b61340
LP
5966 case ACTION_RUNLEVEL2:
5967 case ACTION_RUNLEVEL3:
5968 case ACTION_RUNLEVEL4:
5969 case ACTION_RUNLEVEL5:
5970 case ACTION_RESCUE:
514f4ef5 5971 case ACTION_EMERGENCY:
eb22ac37 5972 case ACTION_DEFAULT:
22f4096c 5973 r = start_with_fallback(bus);
e4b61340 5974 break;
7e4249b9 5975
e4b61340
LP
5976 case ACTION_RELOAD:
5977 case ACTION_REEXEC:
22f4096c 5978 r = reload_with_fallback(bus);
e4b61340
LP
5979 break;
5980
dfcc5c33
MS
5981 case ACTION_CANCEL_SHUTDOWN: {
5982 char *m = NULL;
5983
5984 if (arg_wall) {
5985 m = strv_join(arg_wall, " ");
5986 if (!m) {
5987 retval = EXIT_FAILURE;
5988 goto finish;
5989 }
5990 }
5991 r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
5992 if (r < 0)
5993 log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
5994 free(m);
f6144808 5995 break;
dfcc5c33 5996 }
f6144808 5997
eb22ac37
LP
5998 case ACTION_INVALID:
5999 case ACTION_RUNLEVEL:
e4b61340
LP
6000 default:
6001 assert_not_reached("Unknown action");
6002 }
7e4249b9 6003
22f4096c
LP
6004 retval = r < 0 ? EXIT_FAILURE : r;
6005
7e4249b9 6006finish:
b574246b 6007 if (bus) {
5d452f9c 6008 dbus_connection_flush(bus);
b574246b 6009 dbus_connection_close(bus);
7e4249b9 6010 dbus_connection_unref(bus);
b574246b 6011 }
7e4249b9
LP
6012
6013 dbus_shutdown();
6014
20b3f379
ZJS
6015 strv_free(arg_types);
6016 strv_free(arg_load_states);
6017 strv_free(arg_properties);
ea4a240d 6018
1888c907 6019 pager_close();
6bb92a16
LP
6020 ask_password_agent_close();
6021 polkit_agent_close();
1888c907 6022
7e4249b9
LP
6023 return retval;
6024}