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