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