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