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