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