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