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