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