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