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