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