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