chiark / gitweb /
systemctl: introduce reset-maintenance command
[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                         streq(args[0], "reset-maintenance") ? "ResetMaintenance" :
2646                                                               "Exit";
2647         }
2648
2649         if (!(m = dbus_message_new_method_call(
2650                               "org.freedesktop.systemd1",
2651                               "/org/freedesktop/systemd1",
2652                               "org.freedesktop.systemd1.Manager",
2653                               method))) {
2654                 log_error("Could not allocate message.");
2655                 return -ENOMEM;
2656         }
2657
2658         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2659
2660                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
2661                         /* There's always a fallback possible for
2662                          * legacy actions. */
2663                         r = 0;
2664                         goto finish;
2665                 }
2666
2667                 log_error("Failed to issue method call: %s", error.message);
2668                 r = -EIO;
2669                 goto finish;
2670         }
2671
2672         r = 1;
2673
2674 finish:
2675         if (m)
2676                 dbus_message_unref(m);
2677
2678         if (reply)
2679                 dbus_message_unref(reply);
2680
2681         dbus_error_free(&error);
2682
2683         return r;
2684 }
2685
2686 static int reset_maintenance(DBusConnection *bus, char **args, unsigned n) {
2687         DBusMessage *m = NULL, *reply = NULL;
2688         unsigned i;
2689         int r;
2690         DBusError error;
2691
2692         assert(bus);
2693         dbus_error_init(&error);
2694
2695         if (n <= 1)
2696                 return clear_jobs(bus, args, n);
2697
2698         for (i = 1; i < n; i++) {
2699
2700                 if (!(m = dbus_message_new_method_call(
2701                                       "org.freedesktop.systemd1",
2702                                       "/org/freedesktop/systemd1",
2703                                       "org.freedesktop.systemd1.Manager",
2704                                       "ResetMaintenanceUnit"))) {
2705                         log_error("Could not allocate message.");
2706                         r = -ENOMEM;
2707                         goto finish;
2708                 }
2709
2710                 if (!dbus_message_append_args(m,
2711                                               DBUS_TYPE_STRING, args + i,
2712                                               DBUS_TYPE_INVALID)) {
2713                         log_error("Could not append arguments to message.");
2714                         r = -ENOMEM;
2715                         goto finish;
2716                 }
2717
2718                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2719                         log_error("Failed to issue method call: %s", error.message);
2720                         r = -EIO;
2721                         goto finish;
2722                 }
2723
2724                 dbus_message_unref(m);
2725                 dbus_message_unref(reply);
2726                 m = reply = NULL;
2727         }
2728
2729         r = 0;
2730
2731 finish:
2732         if (m)
2733                 dbus_message_unref(m);
2734
2735         if (reply)
2736                 dbus_message_unref(reply);
2737
2738         dbus_error_free(&error);
2739
2740         return r;
2741 }
2742
2743 static int show_enviroment(DBusConnection *bus, char **args, unsigned n) {
2744         DBusMessage *m = NULL, *reply = NULL;
2745         DBusError error;
2746         DBusMessageIter iter, sub, sub2;
2747         int r;
2748         const char
2749                 *interface = "org.freedesktop.systemd1.Manager",
2750                 *property = "Environment";
2751
2752         dbus_error_init(&error);
2753
2754         if (!(m = dbus_message_new_method_call(
2755                               "org.freedesktop.systemd1",
2756                               "/org/freedesktop/systemd1",
2757                               "org.freedesktop.DBus.Properties",
2758                               "Get"))) {
2759                 log_error("Could not allocate message.");
2760                 return -ENOMEM;
2761         }
2762
2763         if (!dbus_message_append_args(m,
2764                                       DBUS_TYPE_STRING, &interface,
2765                                       DBUS_TYPE_STRING, &property,
2766                                       DBUS_TYPE_INVALID)) {
2767                 log_error("Could not append arguments to message.");
2768                 r = -ENOMEM;
2769                 goto finish;
2770         }
2771
2772         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2773                 log_error("Failed to issue method call: %s", error.message);
2774                 r = -EIO;
2775                 goto finish;
2776         }
2777
2778         if (!dbus_message_iter_init(reply, &iter) ||
2779             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
2780                 log_error("Failed to parse reply.");
2781                 r = -EIO;
2782                 goto finish;
2783         }
2784
2785         dbus_message_iter_recurse(&iter, &sub);
2786
2787         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
2788             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
2789                 log_error("Failed to parse reply.");
2790                 r = -EIO;
2791                 goto finish;
2792         }
2793
2794         dbus_message_iter_recurse(&sub, &sub2);
2795
2796         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
2797                 const char *text;
2798
2799                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
2800                         log_error("Failed to parse reply.");
2801                         r = -EIO;
2802                         goto finish;
2803                 }
2804
2805                 dbus_message_iter_get_basic(&sub2, &text);
2806                 printf("%s\n", text);
2807
2808                 dbus_message_iter_next(&sub2);
2809         }
2810
2811         r = 0;
2812
2813 finish:
2814         if (m)
2815                 dbus_message_unref(m);
2816
2817         if (reply)
2818                 dbus_message_unref(reply);
2819
2820         dbus_error_free(&error);
2821
2822         return r;
2823 }
2824
2825 static int set_environment(DBusConnection *bus, char **args, unsigned n) {
2826         DBusMessage *m = NULL, *reply = NULL;
2827         DBusError error;
2828         int r;
2829         const char *method;
2830         DBusMessageIter iter, sub;
2831         unsigned i;
2832
2833         dbus_error_init(&error);
2834
2835         method = streq(args[0], "set-environment")
2836                 ? "SetEnvironment"
2837                 : "UnsetEnvironment";
2838
2839         if (!(m = dbus_message_new_method_call(
2840                               "org.freedesktop.systemd1",
2841                               "/org/freedesktop/systemd1",
2842                               "org.freedesktop.systemd1.Manager",
2843                               method))) {
2844
2845                 log_error("Could not allocate message.");
2846                 return -ENOMEM;
2847         }
2848
2849         dbus_message_iter_init_append(m, &iter);
2850
2851         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
2852                 log_error("Could not append arguments to message.");
2853                 r = -ENOMEM;
2854                 goto finish;
2855         }
2856
2857         for (i = 1; i < n; i++)
2858                 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &args[i])) {
2859                         log_error("Could not append arguments to message.");
2860                         r = -ENOMEM;
2861                         goto finish;
2862                 }
2863
2864         if (!dbus_message_iter_close_container(&iter, &sub)) {
2865                 log_error("Could not append arguments to message.");
2866                 r = -ENOMEM;
2867                 goto finish;
2868         }
2869
2870         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2871                 log_error("Failed to issue method call: %s", error.message);
2872                 r = -EIO;
2873                 goto finish;
2874         }
2875
2876         r = 0;
2877
2878 finish:
2879         if (m)
2880                 dbus_message_unref(m);
2881
2882         if (reply)
2883                 dbus_message_unref(reply);
2884
2885         dbus_error_free(&error);
2886
2887         return r;
2888 }
2889
2890 static int systemctl_help(void) {
2891
2892         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
2893                "Send control commands to or query the systemd manager.\n\n"
2894                "  -h --help          Show this help\n"
2895                "  -t --type=TYPE     List only units of a particular type\n"
2896                "  -p --property=NAME Show only properties by this name\n"
2897                "  -a --all           Show all units/properties, including dead/empty ones\n"
2898                "     --fail          When installing a new job, fail if conflicting jobs are\n"
2899                "                     pending\n"
2900                "     --system        Connect to system bus\n"
2901                "     --session       Connect to session bus\n"
2902                "     --order         When generating graph for dot, show only order\n"
2903                "     --require        When generating graph for dot, show only requirement\n"
2904                "  -q --quiet         Suppress output\n"
2905                "     --no-block      Do not wait until operation finished\n"
2906                "     --no-wall       Don't send wall message before halt/power-off/reboot\n\n"
2907                "Commands:\n"
2908                "  list-units                      List units\n"
2909                "  start [NAME...]                 Start one or more units\n"
2910                "  stop [NAME...]                  Stop one or more units\n"
2911                "  reload [NAME...]                Reload one or more units\n"
2912                "  restart [NAME...]               Start or restart one or more units\n"
2913                "  try-restart [NAME...]           Restart one or more units if active\n"
2914                "  reload-or-restart [NAME...]     Reload one or more units is possible,\n"
2915                "                                  otherwise start or restart\n"
2916                "  reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
2917                "                                  otherwise restart if active\n"
2918                "  isolate [NAME]                  Start one unit and stop all others\n"
2919                "  check [NAME...]                 Check whether units are active\n"
2920                "  status [NAME...]                Show status of one or more units\n"
2921                "  show [NAME...|JOB...]           Show properties of one or more\n"
2922                "                                  units/jobs/manager\n"
2923                "  reset-maintenance [NAME...]     Reset maintenance state for all, one\n"
2924                "                                  or more units\n"
2925                "  load [NAME...]                  Load one or more units\n"
2926                "  list-jobs                       List jobs\n"
2927                "  cancel [JOB...]                 Cancel one or more jobs\n"
2928                "  clear-jobs                      Cancel all jobs\n"
2929                "  monitor                         Monitor unit/job changes\n"
2930                "  dump                            Dump server status\n"
2931                "  dot                             Dump dependency graph for dot(1)\n"
2932                "  snapshot [NAME]                 Create a snapshot\n"
2933                "  delete [NAME...]                Remove one or more snapshots\n"
2934                "  daemon-reload                   Reload systemd manager configuration\n"
2935                "  daemon-reexec                   Reexecute systemd manager\n"
2936                "  daemon-exit                     Ask the systemd manager to quit\n"
2937                "  show-environment                Dump environment\n"
2938                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
2939                "  unset-environment [NAME...]     Unset one or more environment variables\n"
2940                "  halt                            Shut down and halt the system\n"
2941                "  poweroff                        Shut down and power-off the system\n"
2942                "  reboot                          Shut down and reboot the system\n"
2943                "  rescue                          Enter system rescue mode\n"
2944                "  emergency                       Enter system emergency mode\n"
2945                "  default                         Enter system default mode\n",
2946                program_invocation_short_name);
2947
2948         return 0;
2949 }
2950
2951 static int halt_help(void) {
2952
2953         printf("%s [OPTIONS...]\n\n"
2954                "%s the system.\n\n"
2955                "     --help      Show this help\n"
2956                "     --halt      Halt the machine\n"
2957                "  -p --poweroff  Switch off the machine\n"
2958                "     --reboot    Reboot the machine\n"
2959                "  -f --force     Force immediate halt/power-off/reboot\n"
2960                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
2961                "  -d --no-wtmp   Don't write wtmp record\n"
2962                "  -n --no-sync   Don't sync before halt/power-off/reboot\n"
2963                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
2964                program_invocation_short_name,
2965                arg_action == ACTION_REBOOT   ? "Reboot" :
2966                arg_action == ACTION_POWEROFF ? "Power off" :
2967                                                "Halt");
2968
2969         return 0;
2970 }
2971
2972 static int shutdown_help(void) {
2973
2974         printf("%s [OPTIONS...] [now] [WALL...]\n\n"
2975                "Shut down the system.\n\n"
2976                "     --help      Show this help\n"
2977                "  -H --halt      Halt the machine\n"
2978                "  -P --poweroff  Power-off the machine\n"
2979                "  -r --reboot    Reboot the machine\n"
2980                "  -h             Equivalent to --poweroff, overriden by --halt\n"
2981                "  -k             Don't halt/power-off/reboot, just send warnings\n"
2982                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
2983                program_invocation_short_name);
2984
2985         return 0;
2986 }
2987
2988 static int telinit_help(void) {
2989
2990         printf("%s [OPTIONS...] {COMMAND}\n\n"
2991                "Send control commands to the init daemon.\n\n"
2992                "     --help      Show this help\n"
2993                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
2994                "Commands:\n"
2995                "  0              Power-off the machine\n"
2996                "  6              Reboot the machine\n"
2997                "  2, 3, 4, 5     Start runlevelX.target unit\n"
2998                "  1, s, S        Enter rescue mode\n"
2999                "  q, Q           Reload init daemon configuration\n"
3000                "  u, U           Reexecute init daemon\n",
3001                program_invocation_short_name);
3002
3003         return 0;
3004 }
3005
3006 static int runlevel_help(void) {
3007
3008         printf("%s [OPTIONS...]\n\n"
3009                "Prints the previous and current runlevel of the init system.\n\n"
3010                "     --help      Show this help\n",
3011                program_invocation_short_name);
3012
3013         return 0;
3014 }
3015
3016 static int systemctl_parse_argv(int argc, char *argv[]) {
3017
3018         enum {
3019                 ARG_FAIL = 0x100,
3020                 ARG_SESSION,
3021                 ARG_SYSTEM,
3022                 ARG_NO_BLOCK,
3023                 ARG_NO_WALL,
3024                 ARG_ORDER,
3025                 ARG_REQUIRE
3026         };
3027
3028         static const struct option options[] = {
3029                 { "help",      no_argument,       NULL, 'h'          },
3030                 { "type",      required_argument, NULL, 't'          },
3031                 { "property",  required_argument, NULL, 'p'          },
3032                 { "all",       no_argument,       NULL, 'a'          },
3033                 { "fail",      no_argument,       NULL, ARG_FAIL     },
3034                 { "session",   no_argument,       NULL, ARG_SESSION  },
3035                 { "system",    no_argument,       NULL, ARG_SYSTEM   },
3036                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK },
3037                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL  },
3038                 { "quiet",     no_argument,       NULL, 'q'          },
3039                 { "order",     no_argument,       NULL, ARG_ORDER    },
3040                 { "require",   no_argument,       NULL, ARG_REQUIRE  },
3041                 { NULL,        0,                 NULL, 0            }
3042         };
3043
3044         int c;
3045
3046         assert(argc >= 0);
3047         assert(argv);
3048
3049         while ((c = getopt_long(argc, argv, "ht:p:aq", options, NULL)) >= 0) {
3050
3051                 switch (c) {
3052
3053                 case 'h':
3054                         systemctl_help();
3055                         return 0;
3056
3057                 case 't':
3058                         arg_type = optarg;
3059                         break;
3060
3061                 case 'p':
3062                         arg_property = optarg;
3063
3064                         /* If the user asked for a particular
3065                          * property, show it to him, even if it is
3066                          * empty. */
3067                         arg_all = true;
3068                         break;
3069
3070                 case 'a':
3071                         arg_all = true;
3072                         break;
3073
3074                 case ARG_FAIL:
3075                         arg_fail = true;
3076                         break;
3077
3078                 case ARG_SESSION:
3079                         arg_session = true;
3080                         break;
3081
3082                 case ARG_SYSTEM:
3083                         arg_session = false;
3084                         break;
3085
3086                 case ARG_NO_BLOCK:
3087                         arg_no_block = true;
3088                         break;
3089
3090                 case ARG_NO_WALL:
3091                         arg_no_wall = true;
3092                         break;
3093
3094                 case ARG_ORDER:
3095                         arg_dot = DOT_ORDER;
3096                         break;
3097
3098                 case ARG_REQUIRE:
3099                         arg_dot = DOT_REQUIRE;
3100                         break;
3101
3102                 case 'q':
3103                         arg_quiet = true;
3104                         break;
3105
3106                 case '?':
3107                         return -EINVAL;
3108
3109                 default:
3110                         log_error("Unknown option code %c", c);
3111                         return -EINVAL;
3112                 }
3113         }
3114
3115         return 1;
3116 }
3117
3118 static int halt_parse_argv(int argc, char *argv[]) {
3119
3120         enum {
3121                 ARG_HELP = 0x100,
3122                 ARG_HALT,
3123                 ARG_REBOOT,
3124                 ARG_NO_WALL
3125         };
3126
3127         static const struct option options[] = {
3128                 { "help",      no_argument,       NULL, ARG_HELP    },
3129                 { "halt",      no_argument,       NULL, ARG_HALT    },
3130                 { "poweroff",  no_argument,       NULL, 'p'         },
3131                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
3132                 { "force",     no_argument,       NULL, 'f'         },
3133                 { "wtmp-only", no_argument,       NULL, 'w'         },
3134                 { "no-wtmp",   no_argument,       NULL, 'd'         },
3135                 { "no-sync",   no_argument,       NULL, 'n'         },
3136                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
3137                 { NULL,        0,                 NULL, 0           }
3138         };
3139
3140         int c, runlevel;
3141
3142         assert(argc >= 0);
3143         assert(argv);
3144
3145         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
3146                 if (runlevel == '0' || runlevel == '6')
3147                         arg_immediate = true;
3148
3149         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
3150                 switch (c) {
3151
3152                 case ARG_HELP:
3153                         halt_help();
3154                         return 0;
3155
3156                 case ARG_HALT:
3157                         arg_action = ACTION_HALT;
3158                         break;
3159
3160                 case 'p':
3161                         arg_action = ACTION_POWEROFF;
3162                         break;
3163
3164                 case ARG_REBOOT:
3165                         arg_action = ACTION_REBOOT;
3166                         break;
3167
3168                 case 'f':
3169                         arg_immediate = true;
3170                         break;
3171
3172                 case 'w':
3173                         arg_dry = true;
3174                         break;
3175
3176                 case 'd':
3177                         arg_no_wtmp = true;
3178                         break;
3179
3180                 case 'n':
3181                         arg_no_sync = true;
3182                         break;
3183
3184                 case ARG_NO_WALL:
3185                         arg_no_wall = true;
3186                         break;
3187
3188                 case 'i':
3189                 case 'h':
3190                         /* Compatibility nops */
3191                         break;
3192
3193                 case '?':
3194                         return -EINVAL;
3195
3196                 default:
3197                         log_error("Unknown option code %c", c);
3198                         return -EINVAL;
3199                 }
3200         }
3201
3202         if (optind < argc) {
3203                 log_error("Too many arguments.");
3204                 return -EINVAL;
3205         }
3206
3207         return 1;
3208 }
3209
3210 static int shutdown_parse_argv(int argc, char *argv[]) {
3211
3212         enum {
3213                 ARG_HELP = 0x100,
3214                 ARG_NO_WALL
3215         };
3216
3217         static const struct option options[] = {
3218                 { "help",      no_argument,       NULL, ARG_HELP    },
3219                 { "halt",      no_argument,       NULL, 'H'         },
3220                 { "poweroff",  no_argument,       NULL, 'P'         },
3221                 { "reboot",    no_argument,       NULL, 'r'         },
3222                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
3223                 { NULL,        0,                 NULL, 0           }
3224         };
3225
3226         int c;
3227
3228         assert(argc >= 0);
3229         assert(argv);
3230
3231         while ((c = getopt_long(argc, argv, "HPrhkt:a", options, NULL)) >= 0) {
3232                 switch (c) {
3233
3234                 case ARG_HELP:
3235                         shutdown_help();
3236                         return 0;
3237
3238                 case 'H':
3239                         arg_action = ACTION_HALT;
3240                         break;
3241
3242                 case 'P':
3243                         arg_action = ACTION_POWEROFF;
3244                         break;
3245
3246                 case 'r':
3247                         arg_action = ACTION_REBOOT;
3248                         break;
3249
3250                 case 'h':
3251                         if (arg_action != ACTION_HALT)
3252                                 arg_action = ACTION_POWEROFF;
3253                         break;
3254
3255                 case 'k':
3256                         arg_dry = true;
3257                         break;
3258
3259                 case ARG_NO_WALL:
3260                         arg_no_wall = true;
3261                         break;
3262
3263                 case 't':
3264                 case 'a':
3265                         /* Compatibility nops */
3266                         break;
3267
3268                 case '?':
3269                         return -EINVAL;
3270
3271                 default:
3272                         log_error("Unknown option code %c", c);
3273                         return -EINVAL;
3274                 }
3275         }
3276
3277         if (argc > optind && !streq(argv[optind], "now"))
3278                 log_warning("First argument '%s' isn't 'now'. Ignoring.", argv[optind]);
3279
3280         /* We ignore the time argument */
3281         if (argc > optind + 1)
3282                 arg_wall = argv + optind + 1;
3283
3284         optind = argc;
3285
3286         return 1;
3287 }
3288
3289 static int telinit_parse_argv(int argc, char *argv[]) {
3290
3291         enum {
3292                 ARG_HELP = 0x100,
3293                 ARG_NO_WALL
3294         };
3295
3296         static const struct option options[] = {
3297                 { "help",      no_argument,       NULL, ARG_HELP    },
3298                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
3299                 { NULL,        0,                 NULL, 0           }
3300         };
3301
3302         static const struct {
3303                 char from;
3304                 enum action to;
3305         } table[] = {
3306                 { '0', ACTION_POWEROFF },
3307                 { '6', ACTION_REBOOT },
3308                 { '1', ACTION_RESCUE },
3309                 { '2', ACTION_RUNLEVEL2 },
3310                 { '3', ACTION_RUNLEVEL3 },
3311                 { '4', ACTION_RUNLEVEL4 },
3312                 { '5', ACTION_RUNLEVEL5 },
3313                 { 's', ACTION_RESCUE },
3314                 { 'S', ACTION_RESCUE },
3315                 { 'q', ACTION_RELOAD },
3316                 { 'Q', ACTION_RELOAD },
3317                 { 'u', ACTION_REEXEC },
3318                 { 'U', ACTION_REEXEC }
3319         };
3320
3321         unsigned i;
3322         int c;
3323
3324         assert(argc >= 0);
3325         assert(argv);
3326
3327         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
3328                 switch (c) {
3329
3330                 case ARG_HELP:
3331                         telinit_help();
3332                         return 0;
3333
3334                 case ARG_NO_WALL:
3335                         arg_no_wall = true;
3336                         break;
3337
3338                 case '?':
3339                         return -EINVAL;
3340
3341                 default:
3342                         log_error("Unknown option code %c", c);
3343                         return -EINVAL;
3344                 }
3345         }
3346
3347         if (optind >= argc) {
3348                 telinit_help();
3349                 return -EINVAL;
3350         }
3351
3352         if (optind + 1 < argc) {
3353                 log_error("Too many arguments.");
3354                 return -EINVAL;
3355         }
3356
3357         if (strlen(argv[optind]) != 1) {
3358                 log_error("Expected single character argument.");
3359                 return -EINVAL;
3360         }
3361
3362         for (i = 0; i < ELEMENTSOF(table); i++)
3363                 if (table[i].from == argv[optind][0])
3364                         break;
3365
3366         if (i >= ELEMENTSOF(table)) {
3367                 log_error("Unknown command %s.", argv[optind]);
3368                 return -EINVAL;
3369         }
3370
3371         arg_action = table[i].to;
3372
3373         optind ++;
3374
3375         return 1;
3376 }
3377
3378 static int runlevel_parse_argv(int argc, char *argv[]) {
3379
3380         enum {
3381                 ARG_HELP = 0x100,
3382         };
3383
3384         static const struct option options[] = {
3385                 { "help",      no_argument,       NULL, ARG_HELP    },
3386                 { NULL,        0,                 NULL, 0           }
3387         };
3388
3389         int c;
3390
3391         assert(argc >= 0);
3392         assert(argv);
3393
3394         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
3395                 switch (c) {
3396
3397                 case ARG_HELP:
3398                         runlevel_help();
3399                         return 0;
3400
3401                 case '?':
3402                         return -EINVAL;
3403
3404                 default:
3405                         log_error("Unknown option code %c", c);
3406                         return -EINVAL;
3407                 }
3408         }
3409
3410         if (optind < argc) {
3411                 log_error("Too many arguments.");
3412                 return -EINVAL;
3413         }
3414
3415         return 1;
3416 }
3417
3418 static int parse_argv(int argc, char *argv[]) {
3419         assert(argc >= 0);
3420         assert(argv);
3421
3422         if (program_invocation_short_name) {
3423
3424                 if (strstr(program_invocation_short_name, "halt")) {
3425                         arg_action = ACTION_HALT;
3426                         return halt_parse_argv(argc, argv);
3427                 } else if (strstr(program_invocation_short_name, "poweroff")) {
3428                         arg_action = ACTION_POWEROFF;
3429                         return halt_parse_argv(argc, argv);
3430                 } else if (strstr(program_invocation_short_name, "reboot")) {
3431                         arg_action = ACTION_REBOOT;
3432                         return halt_parse_argv(argc, argv);
3433                 } else if (strstr(program_invocation_short_name, "shutdown")) {
3434                         arg_action = ACTION_POWEROFF;
3435                         return shutdown_parse_argv(argc, argv);
3436                 } else if (strstr(program_invocation_short_name, "init")) {
3437                         arg_action = ACTION_INVALID;
3438                         return telinit_parse_argv(argc, argv);
3439                 } else if (strstr(program_invocation_short_name, "runlevel")) {
3440                         arg_action = ACTION_RUNLEVEL;
3441                         return runlevel_parse_argv(argc, argv);
3442                 }
3443         }
3444
3445         arg_action = ACTION_SYSTEMCTL;
3446         return systemctl_parse_argv(argc, argv);
3447 }
3448
3449 static int action_to_runlevel(void) {
3450
3451         static const char table[_ACTION_MAX] = {
3452                 [ACTION_HALT] =      '0',
3453                 [ACTION_POWEROFF] =  '0',
3454                 [ACTION_REBOOT] =    '6',
3455                 [ACTION_RUNLEVEL2] = '2',
3456                 [ACTION_RUNLEVEL3] = '3',
3457                 [ACTION_RUNLEVEL4] = '4',
3458                 [ACTION_RUNLEVEL5] = '5',
3459                 [ACTION_RESCUE] =    '1'
3460         };
3461
3462         assert(arg_action < _ACTION_MAX);
3463
3464         return table[arg_action];
3465 }
3466
3467 static int talk_upstart(void) {
3468         DBusMessage *m = NULL, *reply = NULL;
3469         DBusError error;
3470         int previous, rl, r;
3471         char
3472                 env1_buf[] = "RUNLEVEL=X",
3473                 env2_buf[] = "PREVLEVEL=X";
3474         char *env1 = env1_buf, *env2 = env2_buf;
3475         const char *emit = "runlevel";
3476         dbus_bool_t b_false = FALSE;
3477         DBusMessageIter iter, sub;
3478         DBusConnection *bus;
3479
3480         dbus_error_init(&error);
3481
3482         if (!(rl = action_to_runlevel()))
3483                 return 0;
3484
3485         if (utmp_get_runlevel(&previous, NULL) < 0)
3486                 previous = 'N';
3487
3488         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
3489                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
3490                         r = 0;
3491                         goto finish;
3492                 }
3493
3494                 log_error("Failed to connect to Upstart bus: %s", error.message);
3495                 r = -EIO;
3496                 goto finish;
3497         }
3498
3499         if ((r = bus_check_peercred(bus)) < 0) {
3500                 log_error("Failed to verify owner of bus.");
3501                 goto finish;
3502         }
3503
3504         if (!(m = dbus_message_new_method_call(
3505                               "com.ubuntu.Upstart",
3506                               "/com/ubuntu/Upstart",
3507                               "com.ubuntu.Upstart0_6",
3508                               "EmitEvent"))) {
3509
3510                 log_error("Could not allocate message.");
3511                 r = -ENOMEM;
3512                 goto finish;
3513         }
3514
3515         dbus_message_iter_init_append(m, &iter);
3516
3517         env1_buf[sizeof(env1_buf)-2] = rl;
3518         env2_buf[sizeof(env2_buf)-2] = previous;
3519
3520         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
3521             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
3522             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
3523             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
3524             !dbus_message_iter_close_container(&iter, &sub) ||
3525             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
3526                 log_error("Could not append arguments to message.");
3527                 r = -ENOMEM;
3528                 goto finish;
3529         }
3530
3531         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3532
3533                 if (error_is_no_service(&error)) {
3534                         r = 0;
3535                         goto finish;
3536                 }
3537
3538                 log_error("Failed to issue method call: %s", error.message);
3539                 r = -EIO;
3540                 goto finish;
3541         }
3542
3543         r = 1;
3544
3545 finish:
3546         if (m)
3547                 dbus_message_unref(m);
3548
3549         if (reply)
3550                 dbus_message_unref(reply);
3551
3552         if (bus) {
3553                 dbus_connection_close(bus);
3554                 dbus_connection_unref(bus);
3555         }
3556
3557         dbus_error_free(&error);
3558
3559         return r;
3560 }
3561
3562 static int talk_initctl(void) {
3563         struct init_request request;
3564         int r, fd;
3565         char rl;
3566
3567         if (!(rl = action_to_runlevel()))
3568                 return 0;
3569
3570         zero(request);
3571         request.magic = INIT_MAGIC;
3572         request.sleeptime = 0;
3573         request.cmd = INIT_CMD_RUNLVL;
3574         request.runlevel = rl;
3575
3576         if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
3577
3578                 if (errno == ENOENT)
3579                         return 0;
3580
3581                 log_error("Failed to open "INIT_FIFO": %m");
3582                 return -errno;
3583         }
3584
3585         errno = 0;
3586         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
3587         close_nointr_nofail(fd);
3588
3589         if (r < 0) {
3590                 log_error("Failed to write to "INIT_FIFO": %m");
3591                 return errno ? -errno : -EIO;
3592         }
3593
3594         return 1;
3595 }
3596
3597 static int systemctl_main(DBusConnection *bus, int argc, char *argv[]) {
3598
3599         static const struct {
3600                 const char* verb;
3601                 const enum {
3602                         MORE,
3603                         LESS,
3604                         EQUAL
3605                 } argc_cmp;
3606                 const int argc;
3607                 int (* const dispatch)(DBusConnection *bus, char **args, unsigned n);
3608         } verbs[] = {
3609                 { "list-units",        LESS,  1, list_units      },
3610                 { "list-jobs",         EQUAL, 1, list_jobs       },
3611                 { "clear-jobs",        EQUAL, 1, clear_jobs      },
3612                 { "load",              MORE,  2, load_unit       },
3613                 { "cancel",            MORE,  2, cancel_job      },
3614                 { "start",             MORE,  2, start_unit      },
3615                 { "stop",              MORE,  2, start_unit      },
3616                 { "reload",            MORE,  2, start_unit      },
3617                 { "restart",           MORE,  2, start_unit      },
3618                 { "try-restart",       MORE,  2, start_unit      },
3619                 { "reload-or-restart", MORE,  2, start_unit      },
3620                 { "reload-or-try-restart", MORE, 2, start_unit   },
3621                 { "isolate",           EQUAL, 2, start_unit      },
3622                 { "check",             MORE,  2, check_unit      },
3623                 { "show",              MORE,  1, show            },
3624                 { "status",            MORE,  2, show            },
3625                 { "monitor",           EQUAL, 1, monitor         },
3626                 { "dump",              EQUAL, 1, dump            },
3627                 { "dot",               EQUAL, 1, dot             },
3628                 { "snapshot",          LESS,  2, snapshot        },
3629                 { "delete",            MORE,  2, delete_snapshot },
3630                 { "daemon-reload",     EQUAL, 1, clear_jobs      },
3631                 { "daemon-reexec",     EQUAL, 1, clear_jobs      },
3632                 { "daemon-exit",       EQUAL, 1, clear_jobs      },
3633                 { "show-environment",  EQUAL, 1, show_enviroment },
3634                 { "set-environment",   MORE,  2, set_environment },
3635                 { "unset-environment", MORE,  2, set_environment },
3636                 { "halt",              EQUAL, 1, start_special   },
3637                 { "poweroff",          EQUAL, 1, start_special   },
3638                 { "reboot",            EQUAL, 1, start_special   },
3639                 { "default",           EQUAL, 1, start_special   },
3640                 { "rescue",            EQUAL, 1, start_special   },
3641                 { "emergency",         EQUAL, 1, start_special   },
3642                 { "reset-maintenance", MORE,  1, reset_maintenance },
3643         };
3644
3645         int left;
3646         unsigned i;
3647
3648         assert(bus);
3649         assert(argc >= 0);
3650         assert(argv);
3651
3652         left = argc - optind;
3653
3654         if (left <= 0)
3655                 /* Special rule: no arguments means "list-units" */
3656                 i = 0;
3657         else {
3658                 if (streq(argv[optind], "help")) {
3659                         systemctl_help();
3660                         return 0;
3661                 }
3662
3663                 for (i = 0; i < ELEMENTSOF(verbs); i++)
3664                         if (streq(argv[optind], verbs[i].verb))
3665                                 break;
3666
3667                 if (i >= ELEMENTSOF(verbs)) {
3668                         log_error("Unknown operation %s", argv[optind]);
3669                         return -EINVAL;
3670                 }
3671         }
3672
3673         switch (verbs[i].argc_cmp) {
3674
3675         case EQUAL:
3676                 if (left != verbs[i].argc) {
3677                         log_error("Invalid number of arguments.");
3678                         return -EINVAL;
3679                 }
3680
3681                 break;
3682
3683         case MORE:
3684                 if (left < verbs[i].argc) {
3685                         log_error("Too few arguments.");
3686                         return -EINVAL;
3687                 }
3688
3689                 break;
3690
3691         case LESS:
3692                 if (left > verbs[i].argc) {
3693                         log_error("Too many arguments.");
3694                         return -EINVAL;
3695                 }
3696
3697                 break;
3698
3699         default:
3700                 assert_not_reached("Unknown comparison operator.");
3701         }
3702
3703         return verbs[i].dispatch(bus, argv + optind, left);
3704 }
3705
3706 static int reload_with_fallback(DBusConnection *bus) {
3707         int r;
3708
3709         if (bus) {
3710                 /* First, try systemd via D-Bus. */
3711                 if ((r = clear_jobs(bus, NULL, 0)) > 0)
3712                         return 0;
3713         }
3714
3715         /* Nothing else worked, so let's try signals */
3716         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
3717
3718         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
3719                 log_error("kill() failed: %m");
3720                 return -errno;
3721         }
3722
3723         return 0;
3724 }
3725
3726 static int start_with_fallback(DBusConnection *bus) {
3727         int r;
3728
3729
3730         if (bus) {
3731                 /* First, try systemd via D-Bus. */
3732                 if ((r = start_unit(bus, NULL, 0)) > 0)
3733                         goto done;
3734
3735                 /* Hmm, talking to systemd via D-Bus didn't work. Then
3736                  * let's try to talk to Upstart via D-Bus. */
3737                 if ((r = talk_upstart()) > 0)
3738                         goto done;
3739         }
3740
3741         /* Nothing else worked, so let's try
3742          * /dev/initctl */
3743         if ((r = talk_initctl()) != 0)
3744                 goto done;
3745
3746         log_error("Failed to talk to init daemon.");
3747         return -EIO;
3748
3749 done:
3750         warn_wall(arg_action);
3751         return 0;
3752 }
3753
3754 static int halt_main(DBusConnection *bus) {
3755         int r;
3756
3757         if (geteuid() != 0) {
3758                 log_error("Must to be root.");
3759                 return -EPERM;
3760         }
3761
3762         if (!arg_dry && !arg_immediate)
3763                 return start_with_fallback(bus);
3764
3765         if (!arg_no_wtmp)
3766                 if ((r = utmp_put_shutdown(0)) < 0)
3767                         log_warning("Failed to write utmp record: %s", strerror(-r));
3768
3769         if (!arg_no_sync)
3770                 sync();
3771
3772         if (arg_dry)
3773                 return 0;
3774
3775         /* Make sure C-A-D is handled by the kernel from this
3776          * point on... */
3777         reboot(RB_ENABLE_CAD);
3778
3779         switch (arg_action) {
3780
3781         case ACTION_HALT:
3782                 log_info("Halting");
3783                 reboot(RB_HALT_SYSTEM);
3784                 break;
3785
3786         case ACTION_POWEROFF:
3787                 log_info("Powering off");
3788                 reboot(RB_POWER_OFF);
3789                 break;
3790
3791         case ACTION_REBOOT:
3792                 log_info("Rebooting");
3793                 reboot(RB_AUTOBOOT);
3794                 break;
3795
3796         default:
3797                 assert_not_reached("Unknown halt action.");
3798         }
3799
3800         /* We should never reach this. */
3801         return -ENOSYS;
3802 }
3803
3804 static int runlevel_main(void) {
3805         int r, runlevel, previous;
3806
3807         if ((r = utmp_get_runlevel(&runlevel, &previous)) < 0) {
3808                 printf("unknown");
3809                 return r;
3810         }
3811
3812         printf("%c %c\n",
3813                previous <= 0 ? 'N' : previous,
3814                runlevel <= 0 ? 'N' : runlevel);
3815
3816         return 0;
3817 }
3818
3819 int main(int argc, char*argv[]) {
3820         int r, retval = 1;
3821         DBusConnection *bus = NULL;
3822         DBusError error;
3823
3824         dbus_error_init(&error);
3825
3826         log_parse_environment();
3827
3828         if ((r = parse_argv(argc, argv)) < 0)
3829                 goto finish;
3830         else if (r == 0) {
3831                 retval = 0;
3832                 goto finish;
3833         }
3834
3835         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
3836          * let's shortcut this */
3837         if (arg_action == ACTION_RUNLEVEL) {
3838                 retval = runlevel_main() < 0;
3839                 goto finish;
3840         }
3841
3842         bus_connect(arg_session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, &private_bus, &error);
3843
3844         switch (arg_action) {
3845
3846         case ACTION_SYSTEMCTL: {
3847
3848                 if (!bus) {
3849                         log_error("Failed to get D-Bus connection: %s", error.message);
3850                         goto finish;
3851                 }
3852
3853                 retval = systemctl_main(bus, argc, argv) < 0;
3854                 break;
3855         }
3856
3857         case ACTION_HALT:
3858         case ACTION_POWEROFF:
3859         case ACTION_REBOOT:
3860                 retval = halt_main(bus) < 0;
3861                 break;
3862
3863         case ACTION_RUNLEVEL2:
3864         case ACTION_RUNLEVEL3:
3865         case ACTION_RUNLEVEL4:
3866         case ACTION_RUNLEVEL5:
3867         case ACTION_RESCUE:
3868         case ACTION_EMERGENCY:
3869         case ACTION_DEFAULT:
3870                 retval = start_with_fallback(bus) < 0;
3871                 break;
3872
3873         case ACTION_RELOAD:
3874         case ACTION_REEXEC:
3875                 retval = reload_with_fallback(bus) < 0;
3876                 break;
3877
3878         case ACTION_INVALID:
3879         case ACTION_RUNLEVEL:
3880         default:
3881                 assert_not_reached("Unknown action");
3882         }
3883
3884 finish:
3885
3886         if (bus) {
3887                 dbus_connection_close(bus);
3888                 dbus_connection_unref(bus);
3889         }
3890
3891         dbus_error_free(&error);
3892
3893         dbus_shutdown();
3894
3895         return retval;
3896 }