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