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