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