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