chiark / gitweb /
install: implement --start option
[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, *pids;
939         int r;
940         char *p;
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         r = read_one_line_file(fn, &pids);
949         free(fn);
950
951         if (r < 0)
952                 return;
953
954         p = pids;
955         while (p[0]) {
956                 unsigned long ul;
957                 char *t = NULL;
958
959                 p += strspn(p, WHITESPACE);
960
961                 errno = 0;
962                 ul = strtoul(p, &p, 0);
963                 if (errno != 0 || ul <= 0)
964                         break;
965
966                 get_process_cmdline((pid_t) ul, 60, &t);
967                 printf("\t\t%lu %s\n", ul, strna(t));
968                 free(t);
969         }
970
971         free(pids);
972 }
973
974 typedef struct UnitStatusInfo {
975         const char *id;
976         const char *load_state;
977         const char *active_state;
978         const char *sub_state;
979
980         const char *description;
981
982         const char *fragment_path;
983         const char *default_control_group;
984
985         /* Service */
986         pid_t main_pid;
987         pid_t control_pid;
988         const char *status_text;
989         bool running;
990
991         usec_t start_timestamp;
992         usec_t exit_timestamp;
993
994         int exit_code, exit_status;
995
996         /* Socket */
997         unsigned n_accepted;
998         unsigned n_connections;
999
1000         /* Device */
1001         const char *sysfs_path;
1002
1003         /* Mount, Automount */
1004         const char *where;
1005
1006         /* Swap */
1007         const char *what;
1008 } UnitStatusInfo;
1009
1010 static void print_status_info(UnitStatusInfo *i) {
1011         assert(i);
1012
1013         /* This shows pretty information about a unit. See
1014          * print_property() for a low-level property printer */
1015
1016         printf("%s", strna(i->id));
1017
1018         if (i->description && !streq_ptr(i->id, i->description))
1019                 printf(" - %s", i->description);
1020
1021         printf("\n");
1022
1023         if (i->fragment_path)
1024                 printf("\t  Loaded: %s (%s)\n", strna(i->load_state), i->fragment_path);
1025         else if (streq_ptr(i->load_state, "failed"))
1026                 printf("\t  Loaded: " ANSI_HIGHLIGHT_ON "%s" ANSI_HIGHLIGHT_OFF "\n", strna(i->load_state));
1027         else
1028                 printf("\t  Loaded: %s\n", strna(i->load_state));
1029
1030         if (streq_ptr(i->active_state, "maintenance"))
1031                 printf("\t  Active: " ANSI_HIGHLIGHT_ON "%s (%s)" ANSI_HIGHLIGHT_OFF "\n",
1032                        strna(i->active_state),
1033                        strna(i->sub_state));
1034         else
1035                 printf("\t  Active: %s (%s)\n",
1036                        strna(i->active_state),
1037                        strna(i->sub_state));
1038
1039         if (i->sysfs_path)
1040                 printf("\t  Device: %s\n", i->sysfs_path);
1041         else if (i->where)
1042                 printf("\t   Where: %s\n", i->where);
1043         else if (i->what)
1044                 printf("\t    What: %s\n", i->what);
1045
1046         if (i->status_text)
1047                 printf("\t  Status: \"%s\"\n", i->status_text);
1048
1049         if (i->id && endswith(i->id, ".socket"))
1050                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
1051
1052         if (i->main_pid > 0 || i->control_pid > 0) {
1053                 printf("\t");
1054
1055                 if (i->main_pid > 0) {
1056                         printf(" Process: %u", (unsigned) i->main_pid);
1057
1058                         if (i->running) {
1059                                 char *t = NULL;
1060                                 get_process_name(i->main_pid, &t);
1061                                 if (t) {
1062                                         printf(" (%s)", t);
1063                                         free(t);
1064                                 }
1065                         } else {
1066                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
1067
1068                                 if (i->exit_code == CLD_EXITED)
1069                                         printf("status=%i", i->exit_status);
1070                                 else
1071                                         printf("signal=%s", strsignal(i->exit_status));
1072                                 printf(")");
1073                         }
1074                 }
1075
1076                 if (i->main_pid > 0 && i->control_pid > 0)
1077                         printf(";");
1078
1079                 if (i->control_pid > 0) {
1080                         char *t = NULL;
1081
1082                         printf(" Control: %u", (unsigned) i->control_pid);
1083
1084                         get_process_name(i->control_pid, &t);
1085                         if (t) {
1086                                 printf(" (%s)", t);
1087                                 free(t);
1088                         }
1089                 }
1090
1091                 printf("\n");
1092         }
1093
1094         if (i->default_control_group) {
1095                 printf("\t  CGroup: %s\n", i->default_control_group);
1096                 show_cgroup(i->default_control_group);
1097         }
1098 }
1099
1100 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
1101
1102         switch (dbus_message_iter_get_arg_type(iter)) {
1103
1104         case DBUS_TYPE_STRING: {
1105                 const char *s;
1106
1107                 dbus_message_iter_get_basic(iter, &s);
1108
1109                 if (s[0]) {
1110                         if (streq(name, "Id"))
1111                                 i->id = s;
1112                         else if (streq(name, "LoadState"))
1113                                 i->load_state = s;
1114                         else if (streq(name, "ActiveState"))
1115                                 i->active_state = s;
1116                         else if (streq(name, "SubState"))
1117                                 i->sub_state = s;
1118                         else if (streq(name, "Description"))
1119                                 i->description = s;
1120                         else if (streq(name, "FragmentPath"))
1121                                 i->fragment_path = s;
1122                         else if (streq(name, "DefaultControlGroup"))
1123                                 i->default_control_group = s;
1124                         else if (streq(name, "StatusText"))
1125                                 i->status_text = s;
1126                         else if (streq(name, "SysFSPath"))
1127                                 i->sysfs_path = s;
1128                         else if (streq(name, "Where"))
1129                                 i->where = s;
1130                         else if (streq(name, "What"))
1131                                 i->what = s;
1132                 }
1133
1134                 break;
1135         }
1136
1137         case DBUS_TYPE_UINT32: {
1138                 uint32_t u;
1139
1140                 dbus_message_iter_get_basic(iter, &u);
1141
1142                 if (streq(name, "MainPID")) {
1143                         if (u > 0) {
1144                                 i->main_pid = (pid_t) u;
1145                                 i->running = true;
1146                         }
1147                 } else if (streq(name, "ControlPID"))
1148                         i->control_pid = (pid_t) u;
1149                 else if (streq(name, "ExecMainPID")) {
1150                         if (u > 0)
1151                                 i->main_pid = (pid_t) u;
1152                 } else if (streq(name, "NAccepted"))
1153                         i->n_accepted = u;
1154                 else if (streq(name, "NConnections"))
1155                         i->n_connections = u;
1156
1157                 break;
1158         }
1159
1160         case DBUS_TYPE_INT32: {
1161                 int32_t j;
1162
1163                 dbus_message_iter_get_basic(iter, &j);
1164
1165                 if (streq(name, "ExecMainCode"))
1166                         i->exit_code = (int) j;
1167                 else if (streq(name, "ExecMainStatus"))
1168                         i->exit_status = (int) j;
1169
1170                 break;
1171         }
1172
1173         case DBUS_TYPE_UINT64: {
1174                 uint64_t u;
1175
1176                 dbus_message_iter_get_basic(iter, &u);
1177
1178                 if (streq(name, "ExecMainStartTimestamp"))
1179                         i->start_timestamp = (usec_t) u;
1180                 else if (streq(name, "ExecMainExitTimestamp"))
1181                         i->exit_timestamp = (usec_t) u;
1182
1183                 break;
1184         }
1185         }
1186
1187         return 0;
1188 }
1189
1190 static int print_property(const char *name, DBusMessageIter *iter) {
1191         assert(name);
1192         assert(iter);
1193
1194         /* This is a low-level property printer, see
1195          * print_status_info() for the nicer output */
1196
1197         if (arg_property && !streq(name, arg_property))
1198                 return 0;
1199
1200         switch (dbus_message_iter_get_arg_type(iter)) {
1201
1202         case DBUS_TYPE_STRING: {
1203                 const char *s;
1204                 dbus_message_iter_get_basic(iter, &s);
1205
1206                 if (arg_all || s[0])
1207                         printf("%s=%s\n", name, s);
1208
1209                 return 0;
1210         }
1211
1212         case DBUS_TYPE_BOOLEAN: {
1213                 dbus_bool_t b;
1214                 dbus_message_iter_get_basic(iter, &b);
1215                 printf("%s=%s\n", name, yes_no(b));
1216
1217                 return 0;
1218         }
1219
1220         case DBUS_TYPE_UINT64: {
1221                 uint64_t u;
1222                 dbus_message_iter_get_basic(iter, &u);
1223
1224                 /* Yes, heuristics! But we can change this check
1225                  * should it turn out to not be sufficient */
1226
1227                 if (strstr(name, "Timestamp")) {
1228                         char timestamp[FORMAT_TIMESTAMP_MAX], *t;
1229
1230                         if ((t = format_timestamp(timestamp, sizeof(timestamp), u)) || arg_all)
1231                                 printf("%s=%s\n", name, strempty(t));
1232                 } else if (strstr(name, "USec")) {
1233                         char timespan[FORMAT_TIMESPAN_MAX];
1234
1235                         printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
1236                 } else
1237                         printf("%s=%llu\n", name, (unsigned long long) u);
1238
1239                 return 0;
1240         }
1241
1242         case DBUS_TYPE_UINT32: {
1243                 uint32_t u;
1244                 dbus_message_iter_get_basic(iter, &u);
1245
1246                 if (strstr(name, "UMask") || strstr(name, "Mode"))
1247                         printf("%s=%04o\n", name, u);
1248                 else
1249                         printf("%s=%u\n", name, (unsigned) u);
1250
1251                 return 0;
1252         }
1253
1254         case DBUS_TYPE_INT32: {
1255                 int32_t i;
1256                 dbus_message_iter_get_basic(iter, &i);
1257
1258                 printf("%s=%i\n", name, (int) i);
1259                 return 0;
1260         }
1261
1262         case DBUS_TYPE_STRUCT: {
1263                 DBusMessageIter sub;
1264                 dbus_message_iter_recurse(iter, &sub);
1265
1266                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
1267                         uint32_t u;
1268
1269                         dbus_message_iter_get_basic(&sub, &u);
1270
1271                         if (u)
1272                                 printf("%s=%u\n", name, (unsigned) u);
1273                         else if (arg_all)
1274                                 printf("%s=\n", name);
1275
1276                         return 0;
1277                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
1278                         const char *s;
1279
1280                         dbus_message_iter_get_basic(&sub, &s);
1281
1282                         if (arg_all || s[0])
1283                                 printf("%s=%s\n", name, s);
1284
1285                         return 0;
1286                 }
1287
1288                 break;
1289         }
1290
1291         case DBUS_TYPE_ARRAY:
1292
1293                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
1294                         DBusMessageIter sub;
1295                         bool space = false;
1296
1297                         dbus_message_iter_recurse(iter, &sub);
1298
1299                         if (arg_all ||
1300                             dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1301                                 printf("%s=", name);
1302
1303                                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1304                                         const char *s;
1305
1306                                         assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
1307                                         dbus_message_iter_get_basic(&sub, &s);
1308                                         printf("%s%s", space ? " " : "", s);
1309
1310                                         space = true;
1311                                         dbus_message_iter_next(&sub);
1312                                 }
1313
1314                                 puts("");
1315                         }
1316
1317                         return 0;
1318                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
1319                         DBusMessageIter sub;
1320
1321                         dbus_message_iter_recurse(iter, &sub);
1322
1323                         if (arg_all ||
1324                             dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1325                                 printf("%s=", name);
1326
1327                                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1328                                         uint8_t u;
1329
1330                                         assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
1331                                         dbus_message_iter_get_basic(&sub, &u);
1332                                         printf("%02x", u);
1333
1334                                         dbus_message_iter_next(&sub);
1335                                 }
1336
1337                                 puts("");
1338                         }
1339
1340                         return 0;
1341                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
1342                         DBusMessageIter sub, sub2;
1343
1344                         dbus_message_iter_recurse(iter, &sub);
1345
1346                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1347                                 const char *type, *path;
1348
1349                                 dbus_message_iter_recurse(&sub, &sub2);
1350
1351                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
1352                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
1353                                         printf("%s=%s\n", type, path);
1354
1355                                 dbus_message_iter_next(&sub);
1356                         }
1357
1358                         return 0;
1359                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
1360                         DBusMessageIter sub, sub2;
1361
1362                         dbus_message_iter_recurse(iter, &sub);
1363
1364                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1365                                 const char *base;
1366                                 uint64_t value, next_elapse;
1367
1368                                 dbus_message_iter_recurse(&sub, &sub2);
1369
1370                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
1371                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
1372                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
1373                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
1374
1375                                         printf("%s={ value=%s ; next_elapse=%s }\n",
1376                                                base,
1377                                                format_timespan(timespan1, sizeof(timespan1), value),
1378                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
1379                                 }
1380
1381                                 dbus_message_iter_next(&sub);
1382                         }
1383
1384                         return 0;
1385                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
1386
1387                         DBusMessageIter sub, sub2, sub3;
1388
1389                         dbus_message_iter_recurse(iter, &sub);
1390
1391                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1392                                 const char *path;
1393                                 uint64_t start_time, exit_time;
1394                                 uint32_t pid;
1395                                 int32_t code, status;
1396
1397                                 dbus_message_iter_recurse(&sub, &sub2);
1398
1399                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
1400                                         continue;
1401
1402                                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
1403                                     dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
1404                                         continue;
1405
1406                                 printf("%s={ path=%s ; argv[]=", name, path);
1407
1408                                 dbus_message_iter_recurse(&sub2, &sub3);
1409
1410                                 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
1411                                         const char *s;
1412
1413                                         assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
1414                                         dbus_message_iter_get_basic(&sub3, &s);
1415                                         printf("%s ", s);
1416                                         dbus_message_iter_next(&sub3);
1417                                 }
1418
1419                                 if (dbus_message_iter_next(&sub2) &&
1420                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_time, true) >= 0 &&
1421                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_time, true) >= 0 &&
1422                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) >= 0 &&
1423                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) >= 0 &&
1424                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) >= 0) {
1425
1426                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
1427
1428                                         printf("; start=%s ; stop=%s ; pid=%u ; code=%s ; status=%i/%s",
1429                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), start_time)),
1430                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), exit_time)),
1431                                                (unsigned) pid,
1432                                                sigchld_code_to_string(code),
1433                                                status,
1434                                                strempty(code == CLD_EXITED ? NULL : strsignal(status)));
1435                                 }
1436
1437                                 printf(" }\n");
1438
1439                                 dbus_message_iter_next(&sub);
1440                         }
1441
1442                         return 0;
1443                 }
1444
1445                 break;
1446         }
1447
1448         if (arg_all)
1449                 printf("%s=[unprintable]\n", name);
1450
1451         return 0;
1452 }
1453
1454 static int show_one(DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
1455         DBusMessage *m = NULL, *reply = NULL;
1456         const char *interface = "";
1457         int r;
1458         DBusError error;
1459         DBusMessageIter iter, sub, sub2, sub3;
1460         UnitStatusInfo info;
1461
1462         assert(bus);
1463         assert(path);
1464         assert(new_line);
1465
1466         zero(info);
1467         dbus_error_init(&error);
1468
1469         if (!(m = dbus_message_new_method_call(
1470                               "org.freedesktop.systemd1",
1471                               path,
1472                               "org.freedesktop.DBus.Properties",
1473                               "GetAll"))) {
1474                 log_error("Could not allocate message.");
1475                 r = -ENOMEM;
1476                 goto finish;
1477         }
1478
1479         if (!dbus_message_append_args(m,
1480                                       DBUS_TYPE_STRING, &interface,
1481                                       DBUS_TYPE_INVALID)) {
1482                 log_error("Could not append arguments to message.");
1483                 r = -ENOMEM;
1484                 goto finish;
1485         }
1486
1487         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1488                 log_error("Failed to issue method call: %s", error.message);
1489                 r = -EIO;
1490                 goto finish;
1491         }
1492
1493         if (!dbus_message_iter_init(reply, &iter) ||
1494             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1495             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
1496                 log_error("Failed to parse reply.");
1497                 r = -EIO;
1498                 goto finish;
1499         }
1500
1501         dbus_message_iter_recurse(&iter, &sub);
1502
1503         if (*new_line)
1504                 printf("\n");
1505
1506         *new_line = true;
1507
1508         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1509                 const char *name;
1510
1511                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
1512                         log_error("Failed to parse reply.");
1513                         r = -EIO;
1514                         goto finish;
1515                 }
1516
1517                 dbus_message_iter_recurse(&sub, &sub2);
1518
1519                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
1520                         log_error("Failed to parse reply.");
1521                         r = -EIO;
1522                         goto finish;
1523                 }
1524
1525                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
1526                         log_error("Failed to parse reply.");
1527                         r = -EIO;
1528                         goto finish;
1529                 }
1530
1531                 dbus_message_iter_recurse(&sub2, &sub3);
1532
1533                 if (show_properties)
1534                         r = print_property(name, &sub3);
1535                 else
1536                         r = status_property(name, &sub3, &info);
1537
1538                 if (r < 0) {
1539                         log_error("Failed to parse reply.");
1540                         r = -EIO;
1541                         goto finish;
1542                 }
1543
1544                 dbus_message_iter_next(&sub);
1545         }
1546
1547         if (!show_properties)
1548                 print_status_info(&info);
1549
1550         r = 0;
1551
1552 finish:
1553         if (m)
1554                 dbus_message_unref(m);
1555
1556         if (reply)
1557                 dbus_message_unref(reply);
1558
1559         dbus_error_free(&error);
1560
1561         return r;
1562 }
1563
1564 static int show(DBusConnection *bus, char **args, unsigned n) {
1565         DBusMessage *m = NULL, *reply = NULL;
1566         int r;
1567         DBusError error;
1568         unsigned i;
1569         bool show_properties, new_line = false;
1570
1571         assert(bus);
1572         assert(args);
1573
1574         dbus_error_init(&error);
1575
1576         show_properties = !streq(args[0], "status");
1577
1578         if (show_properties && n <= 1) {
1579                 /* If not argument is specified inspect the manager
1580                  * itself */
1581
1582                 r = show_one(bus, "/org/freedesktop/systemd1", show_properties, &new_line);
1583                 goto finish;
1584         }
1585
1586         for (i = 1; i < n; i++) {
1587                 const char *path = NULL;
1588                 uint32_t id;
1589
1590                 if (!show_properties || safe_atou32(args[i], &id) < 0) {
1591
1592                         if (!(m = dbus_message_new_method_call(
1593                                               "org.freedesktop.systemd1",
1594                                               "/org/freedesktop/systemd1",
1595                                               "org.freedesktop.systemd1.Manager",
1596                                               "LoadUnit"))) {
1597                                 log_error("Could not allocate message.");
1598                                 r = -ENOMEM;
1599                                 goto finish;
1600                         }
1601
1602                         if (!dbus_message_append_args(m,
1603                                                       DBUS_TYPE_STRING, &args[i],
1604                                                       DBUS_TYPE_INVALID)) {
1605                                 log_error("Could not append arguments to message.");
1606                                 r = -ENOMEM;
1607                                 goto finish;
1608                         }
1609
1610                 } else {
1611
1612                         if (!(m = dbus_message_new_method_call(
1613                                               "org.freedesktop.systemd1",
1614                                               "/org/freedesktop/systemd1",
1615                                               "org.freedesktop.systemd1.Manager",
1616                                               "GetJob"))) {
1617                                 log_error("Could not allocate message.");
1618                                 r = -ENOMEM;
1619                                 goto finish;
1620                         }
1621
1622                         if (!dbus_message_append_args(m,
1623                                                       DBUS_TYPE_UINT32, &id,
1624                                                       DBUS_TYPE_INVALID)) {
1625                                 log_error("Could not append arguments to message.");
1626                                 r = -ENOMEM;
1627                                 goto finish;
1628                         }
1629                 }
1630
1631                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1632                         log_error("Failed to issue method call: %s", error.message);
1633                         r = -EIO;
1634                         goto finish;
1635                 }
1636
1637                 if (!dbus_message_get_args(reply, &error,
1638                                            DBUS_TYPE_OBJECT_PATH, &path,
1639                                            DBUS_TYPE_INVALID)) {
1640                         log_error("Failed to parse reply: %s", error.message);
1641                         r = -EIO;
1642                         goto finish;
1643                 }
1644
1645                 if ((r = show_one(bus, path, show_properties, &new_line)) < 0)
1646                         goto finish;
1647
1648                 dbus_message_unref(m);
1649                 dbus_message_unref(reply);
1650                 m = reply = NULL;
1651         }
1652
1653         r = 0;
1654
1655 finish:
1656         if (m)
1657                 dbus_message_unref(m);
1658
1659         if (reply)
1660                 dbus_message_unref(reply);
1661
1662         dbus_error_free(&error);
1663
1664         return r;
1665 }
1666
1667 static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage *message, void *data) {
1668         DBusError error;
1669         DBusMessage *m = NULL, *reply = NULL;
1670
1671         assert(connection);
1672         assert(message);
1673
1674         dbus_error_init(&error);
1675
1676         /* log_debug("Got D-Bus request: %s.%s() on %s", */
1677         /*           dbus_message_get_interface(message), */
1678         /*           dbus_message_get_member(message), */
1679         /*           dbus_message_get_path(message)); */
1680
1681         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1682                 log_error("Warning! D-Bus connection terminated.");
1683                 dbus_connection_close(connection);
1684
1685         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitNew") ||
1686                    dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitRemoved")) {
1687                 const char *id, *path;
1688
1689                 if (!dbus_message_get_args(message, &error,
1690                                            DBUS_TYPE_STRING, &id,
1691                                            DBUS_TYPE_OBJECT_PATH, &path,
1692                                            DBUS_TYPE_INVALID))
1693                         log_error("Failed to parse message: %s", error.message);
1694                 else if (streq(dbus_message_get_member(message), "UnitNew"))
1695                         printf("Unit %s added.\n", id);
1696                 else
1697                         printf("Unit %s removed.\n", id);
1698
1699         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobNew") ||
1700                    dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1701                 uint32_t id;
1702                 const char *path;
1703
1704                 if (!dbus_message_get_args(message, &error,
1705                                            DBUS_TYPE_UINT32, &id,
1706                                            DBUS_TYPE_OBJECT_PATH, &path,
1707                                            DBUS_TYPE_INVALID))
1708                         log_error("Failed to parse message: %s", error.message);
1709                 else if (streq(dbus_message_get_member(message), "JobNew"))
1710                         printf("Job %u added.\n", id);
1711                 else
1712                         printf("Job %u removed.\n", id);
1713
1714
1715         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Unit", "Changed") ||
1716                    dbus_message_is_signal(message, "org.freedesktop.systemd1.Job", "Changed")) {
1717
1718                 const char *path, *interface, *property = "Id";
1719                 DBusMessageIter iter, sub;
1720
1721                 path = dbus_message_get_path(message);
1722                 interface = dbus_message_get_interface(message);
1723
1724                 if (!(m = dbus_message_new_method_call(
1725                               "org.freedesktop.systemd1",
1726                               path,
1727                               "org.freedesktop.DBus.Properties",
1728                               "Get"))) {
1729                         log_error("Could not allocate message.");
1730                         goto oom;
1731                 }
1732
1733                 if (!dbus_message_append_args(m,
1734                                               DBUS_TYPE_STRING, &interface,
1735                                               DBUS_TYPE_STRING, &property,
1736                                               DBUS_TYPE_INVALID)) {
1737                         log_error("Could not append arguments to message.");
1738                         goto finish;
1739                 }
1740
1741                 if (!(reply = dbus_connection_send_with_reply_and_block(connection, m, -1, &error))) {
1742                         log_error("Failed to issue method call: %s", error.message);
1743                         goto finish;
1744                 }
1745
1746                 if (!dbus_message_iter_init(reply, &iter) ||
1747                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
1748                         log_error("Failed to parse reply.");
1749                         goto finish;
1750                 }
1751
1752                 dbus_message_iter_recurse(&iter, &sub);
1753
1754                 if (streq(interface, "org.freedesktop.systemd1.Unit")) {
1755                         const char *id;
1756
1757                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1758                                 log_error("Failed to parse reply.");
1759                                 goto finish;
1760                         }
1761
1762                         dbus_message_iter_get_basic(&sub, &id);
1763                         printf("Unit %s changed.\n", id);
1764                 } else {
1765                         uint32_t id;
1766
1767                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32)  {
1768                                 log_error("Failed to parse reply.");
1769                                 goto finish;
1770                         }
1771
1772                         dbus_message_iter_get_basic(&sub, &id);
1773                         printf("Job %u changed.\n", id);
1774                 }
1775         }
1776
1777 finish:
1778         if (m)
1779                 dbus_message_unref(m);
1780
1781         if (reply)
1782                 dbus_message_unref(reply);
1783
1784         dbus_error_free(&error);
1785         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1786
1787 oom:
1788         if (m)
1789                 dbus_message_unref(m);
1790
1791         if (reply)
1792                 dbus_message_unref(reply);
1793
1794         dbus_error_free(&error);
1795         return DBUS_HANDLER_RESULT_NEED_MEMORY;
1796 }
1797
1798 static int monitor(DBusConnection *bus, char **args, unsigned n) {
1799         DBusMessage *m = NULL, *reply = NULL;
1800         DBusError error;
1801         int r;
1802
1803         dbus_error_init(&error);
1804
1805         dbus_bus_add_match(bus,
1806                            "type='signal',"
1807                            "sender='org.freedesktop.systemd1',"
1808                            "interface='org.freedesktop.systemd1.Manager',"
1809                            "path='/org/freedesktop/systemd1'",
1810                            &error);
1811
1812         if (dbus_error_is_set(&error)) {
1813                 log_error("Failed to add match: %s", error.message);
1814                 r = -EIO;
1815                 goto finish;
1816         }
1817
1818         dbus_bus_add_match(bus,
1819                            "type='signal',"
1820                            "sender='org.freedesktop.systemd1',"
1821                            "interface='org.freedesktop.systemd1.Unit',"
1822                            "member='Changed'",
1823                            &error);
1824
1825         if (dbus_error_is_set(&error)) {
1826                 log_error("Failed to add match: %s", error.message);
1827                 r = -EIO;
1828                 goto finish;
1829         }
1830
1831         dbus_bus_add_match(bus,
1832                            "type='signal',"
1833                            "sender='org.freedesktop.systemd1',"
1834                            "interface='org.freedesktop.systemd1.Job',"
1835                            "member='Changed'",
1836                            &error);
1837
1838         if (dbus_error_is_set(&error)) {
1839                 log_error("Failed to add match: %s", error.message);
1840                 r = -EIO;
1841                 goto finish;
1842         }
1843
1844         if (!dbus_connection_add_filter(bus, monitor_filter, NULL, NULL)) {
1845                 log_error("Failed to add filter.");
1846                 r = -ENOMEM;
1847                 goto finish;
1848         }
1849
1850         if (!(m = dbus_message_new_method_call(
1851                               "org.freedesktop.systemd1",
1852                               "/org/freedesktop/systemd1",
1853                               "org.freedesktop.systemd1.Manager",
1854                               "Subscribe"))) {
1855                 log_error("Could not allocate message.");
1856                 r = -ENOMEM;
1857                 goto finish;
1858         }
1859
1860         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1861                 log_error("Failed to issue method call: %s", error.message);
1862                 r = -EIO;
1863                 goto finish;
1864         }
1865
1866         while (dbus_connection_read_write_dispatch(bus, -1))
1867                 ;
1868
1869         r = 0;
1870
1871 finish:
1872
1873         /* This is slightly dirty, since we don't undo the filter or the matches. */
1874
1875         if (m)
1876                 dbus_message_unref(m);
1877
1878         if (reply)
1879                 dbus_message_unref(reply);
1880
1881         dbus_error_free(&error);
1882
1883         return r;
1884 }
1885
1886 static int dump(DBusConnection *bus, char **args, unsigned n) {
1887         DBusMessage *m = NULL, *reply = NULL;
1888         DBusError error;
1889         int r;
1890         const char *text;
1891
1892         dbus_error_init(&error);
1893
1894         if (!(m = dbus_message_new_method_call(
1895                               "org.freedesktop.systemd1",
1896                               "/org/freedesktop/systemd1",
1897                               "org.freedesktop.systemd1.Manager",
1898                               "Dump"))) {
1899                 log_error("Could not allocate message.");
1900                 return -ENOMEM;
1901         }
1902
1903         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1904                 log_error("Failed to issue method call: %s", error.message);
1905                 r = -EIO;
1906                 goto finish;
1907         }
1908
1909         if (!dbus_message_get_args(reply, &error,
1910                                    DBUS_TYPE_STRING, &text,
1911                                    DBUS_TYPE_INVALID)) {
1912                 log_error("Failed to parse reply: %s", error.message);
1913                 r = -EIO;
1914                 goto finish;
1915         }
1916
1917         fputs(text, stdout);
1918
1919         r = 0;
1920
1921 finish:
1922         if (m)
1923                 dbus_message_unref(m);
1924
1925         if (reply)
1926                 dbus_message_unref(reply);
1927
1928         dbus_error_free(&error);
1929
1930         return r;
1931 }
1932
1933 static int snapshot(DBusConnection *bus, char **args, unsigned n) {
1934         DBusMessage *m = NULL, *reply = NULL;
1935         DBusError error;
1936         int r;
1937         const char *name = "", *path, *id;
1938         dbus_bool_t cleanup = FALSE;
1939         DBusMessageIter iter, sub;
1940         const char
1941                 *interface = "org.freedesktop.systemd1.Unit",
1942                 *property = "Id";
1943
1944         dbus_error_init(&error);
1945
1946         if (!(m = dbus_message_new_method_call(
1947                               "org.freedesktop.systemd1",
1948                               "/org/freedesktop/systemd1",
1949                               "org.freedesktop.systemd1.Manager",
1950                               "CreateSnapshot"))) {
1951                 log_error("Could not allocate message.");
1952                 return -ENOMEM;
1953         }
1954
1955         if (n > 1)
1956                 name = args[1];
1957
1958         if (!dbus_message_append_args(m,
1959                                       DBUS_TYPE_STRING, &name,
1960                                       DBUS_TYPE_BOOLEAN, &cleanup,
1961                                       DBUS_TYPE_INVALID)) {
1962                 log_error("Could not append arguments to message.");
1963                 r = -ENOMEM;
1964                 goto finish;
1965         }
1966
1967         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1968                 log_error("Failed to issue method call: %s", error.message);
1969                 r = -EIO;
1970                 goto finish;
1971         }
1972
1973         if (!dbus_message_get_args(reply, &error,
1974                                    DBUS_TYPE_OBJECT_PATH, &path,
1975                                    DBUS_TYPE_INVALID)) {
1976                 log_error("Failed to parse reply: %s", error.message);
1977                 r = -EIO;
1978                 goto finish;
1979         }
1980
1981         dbus_message_unref(m);
1982         if (!(m = dbus_message_new_method_call(
1983                               "org.freedesktop.systemd1",
1984                               path,
1985                               "org.freedesktop.DBus.Properties",
1986                               "Get"))) {
1987                 log_error("Could not allocate message.");
1988                 return -ENOMEM;
1989         }
1990
1991         if (!dbus_message_append_args(m,
1992                                       DBUS_TYPE_STRING, &interface,
1993                                       DBUS_TYPE_STRING, &property,
1994                                       DBUS_TYPE_INVALID)) {
1995                 log_error("Could not append arguments to message.");
1996                 r = -ENOMEM;
1997                 goto finish;
1998         }
1999
2000         dbus_message_unref(reply);
2001         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2002                 log_error("Failed to issue method call: %s", error.message);
2003                 r = -EIO;
2004                 goto finish;
2005         }
2006
2007         if (!dbus_message_iter_init(reply, &iter) ||
2008             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
2009                 log_error("Failed to parse reply.");
2010                 r = -EIO;
2011                 goto finish;
2012         }
2013
2014         dbus_message_iter_recurse(&iter, &sub);
2015
2016         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
2017                 log_error("Failed to parse reply.");
2018                 r = -EIO;
2019                 goto finish;
2020         }
2021
2022         dbus_message_iter_get_basic(&sub, &id);
2023
2024         if (!arg_quiet)
2025                 puts(id);
2026         r = 0;
2027
2028 finish:
2029         if (m)
2030                 dbus_message_unref(m);
2031
2032         if (reply)
2033                 dbus_message_unref(reply);
2034
2035         dbus_error_free(&error);
2036
2037         return r;
2038 }
2039
2040 static int delete_snapshot(DBusConnection *bus, char **args, unsigned n) {
2041         DBusMessage *m = NULL, *reply = NULL;
2042         int r;
2043         DBusError error;
2044         unsigned i;
2045
2046         assert(bus);
2047         assert(args);
2048
2049         dbus_error_init(&error);
2050
2051         for (i = 1; i < n; i++) {
2052                 const char *path = NULL;
2053
2054                 if (!(m = dbus_message_new_method_call(
2055                                       "org.freedesktop.systemd1",
2056                                       "/org/freedesktop/systemd1",
2057                                       "org.freedesktop.systemd1.Manager",
2058                                       "GetUnit"))) {
2059                         log_error("Could not allocate message.");
2060                         r = -ENOMEM;
2061                         goto finish;
2062                 }
2063
2064                 if (!dbus_message_append_args(m,
2065                                               DBUS_TYPE_STRING, &args[i],
2066                                               DBUS_TYPE_INVALID)) {
2067                         log_error("Could not append arguments to message.");
2068                         r = -ENOMEM;
2069                         goto finish;
2070                 }
2071
2072                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2073                         log_error("Failed to issue method call: %s", error.message);
2074                         r = -EIO;
2075                         goto finish;
2076                 }
2077
2078                 if (!dbus_message_get_args(reply, &error,
2079                                            DBUS_TYPE_OBJECT_PATH, &path,
2080                                            DBUS_TYPE_INVALID)) {
2081                         log_error("Failed to parse reply: %s", error.message);
2082                         r = -EIO;
2083                         goto finish;
2084                 }
2085
2086                 dbus_message_unref(m);
2087                 if (!(m = dbus_message_new_method_call(
2088                                       "org.freedesktop.systemd1",
2089                                       path,
2090                                       "org.freedesktop.systemd1.Snapshot",
2091                                       "Remove"))) {
2092                         log_error("Could not allocate message.");
2093                         r = -ENOMEM;
2094                         goto finish;
2095                 }
2096
2097                 dbus_message_unref(reply);
2098                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2099                         log_error("Failed to issue method call: %s", error.message);
2100                         r = -EIO;
2101                         goto finish;
2102                 }
2103
2104                 dbus_message_unref(m);
2105                 dbus_message_unref(reply);
2106                 m = reply = NULL;
2107         }
2108
2109         r = 0;
2110
2111 finish:
2112         if (m)
2113                 dbus_message_unref(m);
2114
2115         if (reply)
2116                 dbus_message_unref(reply);
2117
2118         dbus_error_free(&error);
2119
2120         return r;
2121 }
2122
2123 static int clear_jobs(DBusConnection *bus, char **args, unsigned n) {
2124         DBusMessage *m = NULL, *reply = NULL;
2125         DBusError error;
2126         int r;
2127         const char *method;
2128
2129         dbus_error_init(&error);
2130
2131         if (arg_action == ACTION_RELOAD)
2132                 method = "Reload";
2133         else if (arg_action == ACTION_REEXEC)
2134                 method = "Reexecute";
2135         else {
2136                 assert(arg_action == ACTION_SYSTEMCTL);
2137
2138                 method =
2139                         streq(args[0], "clear-jobs")    ? "ClearJobs" :
2140                         streq(args[0], "daemon-reload") ? "Reload" :
2141                         streq(args[0], "daemon-reexec") ? "Reexecute" :
2142                                                           "Exit";
2143         }
2144
2145         if (!(m = dbus_message_new_method_call(
2146                               "org.freedesktop.systemd1",
2147                               "/org/freedesktop/systemd1",
2148                               "org.freedesktop.systemd1.Manager",
2149                               method))) {
2150                 log_error("Could not allocate message.");
2151                 return -ENOMEM;
2152         }
2153
2154         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2155
2156                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
2157                         /* There's always a fallback possible for
2158                          * legacy actions. */
2159                         r = 0;
2160                         goto finish;
2161                 }
2162
2163                 log_error("Failed to issue method call: %s", error.message);
2164                 r = -EIO;
2165                 goto finish;
2166         }
2167
2168         r = 1;
2169
2170 finish:
2171         if (m)
2172                 dbus_message_unref(m);
2173
2174         if (reply)
2175                 dbus_message_unref(reply);
2176
2177         dbus_error_free(&error);
2178
2179         return r;
2180 }
2181
2182 static int show_enviroment(DBusConnection *bus, char **args, unsigned n) {
2183         DBusMessage *m = NULL, *reply = NULL;
2184         DBusError error;
2185         DBusMessageIter iter, sub, sub2;
2186         int r;
2187         const char
2188                 *interface = "org.freedesktop.systemd1.Manager",
2189                 *property = "Environment";
2190
2191         dbus_error_init(&error);
2192
2193         if (!(m = dbus_message_new_method_call(
2194                               "org.freedesktop.systemd1",
2195                               "/org/freedesktop/systemd1",
2196                               "org.freedesktop.DBus.Properties",
2197                               "Get"))) {
2198                 log_error("Could not allocate message.");
2199                 return -ENOMEM;
2200         }
2201
2202         if (!dbus_message_append_args(m,
2203                                       DBUS_TYPE_STRING, &interface,
2204                                       DBUS_TYPE_STRING, &property,
2205                                       DBUS_TYPE_INVALID)) {
2206                 log_error("Could not append arguments to message.");
2207                 r = -ENOMEM;
2208                 goto finish;
2209         }
2210
2211         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2212                 log_error("Failed to issue method call: %s", error.message);
2213                 r = -EIO;
2214                 goto finish;
2215         }
2216
2217         if (!dbus_message_iter_init(reply, &iter) ||
2218             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
2219                 log_error("Failed to parse reply.");
2220                 r = -EIO;
2221                 goto finish;
2222         }
2223
2224         dbus_message_iter_recurse(&iter, &sub);
2225
2226         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
2227             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
2228                 log_error("Failed to parse reply.");
2229                 r = -EIO;
2230                 goto finish;
2231         }
2232
2233         dbus_message_iter_recurse(&sub, &sub2);
2234
2235         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
2236                 const char *text;
2237
2238                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
2239                         log_error("Failed to parse reply.");
2240                         r = -EIO;
2241                         goto finish;
2242                 }
2243
2244                 dbus_message_iter_get_basic(&sub2, &text);
2245                 printf("%s\n", text);
2246
2247                 dbus_message_iter_next(&sub2);
2248         }
2249
2250         r = 0;
2251
2252 finish:
2253         if (m)
2254                 dbus_message_unref(m);
2255
2256         if (reply)
2257                 dbus_message_unref(reply);
2258
2259         dbus_error_free(&error);
2260
2261         return r;
2262 }
2263
2264 static int set_environment(DBusConnection *bus, char **args, unsigned n) {
2265         DBusMessage *m = NULL, *reply = NULL;
2266         DBusError error;
2267         int r;
2268         const char *method;
2269         DBusMessageIter iter, sub;
2270         unsigned i;
2271
2272         dbus_error_init(&error);
2273
2274         method = streq(args[0], "set-environment")
2275                 ? "SetEnvironment"
2276                 : "UnsetEnvironment";
2277
2278         if (!(m = dbus_message_new_method_call(
2279                               "org.freedesktop.systemd1",
2280                               "/org/freedesktop/systemd1",
2281                               "org.freedesktop.systemd1.Manager",
2282                               method))) {
2283
2284                 log_error("Could not allocate message.");
2285                 return -ENOMEM;
2286         }
2287
2288         dbus_message_iter_init_append(m, &iter);
2289
2290         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
2291                 log_error("Could not append arguments to message.");
2292                 r = -ENOMEM;
2293                 goto finish;
2294         }
2295
2296         for (i = 1; i < n; i++)
2297                 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &args[i])) {
2298                         log_error("Could not append arguments to message.");
2299                         r = -ENOMEM;
2300                         goto finish;
2301                 }
2302
2303         if (!dbus_message_iter_close_container(&iter, &sub)) {
2304                 log_error("Could not append arguments to message.");
2305                 r = -ENOMEM;
2306                 goto finish;
2307         }
2308
2309         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2310                 log_error("Failed to issue method call: %s", error.message);
2311                 r = -EIO;
2312                 goto finish;
2313         }
2314
2315         r = 0;
2316
2317 finish:
2318         if (m)
2319                 dbus_message_unref(m);
2320
2321         if (reply)
2322                 dbus_message_unref(reply);
2323
2324         dbus_error_free(&error);
2325
2326         return r;
2327 }
2328
2329 static int systemctl_help(void) {
2330
2331         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
2332                "Send control commands to the systemd manager.\n\n"
2333                "  -h --help          Show this help\n"
2334                "  -t --type=TYPE     List only units of a particular type\n"
2335                "  -p --property=NAME Show only properties by this name\n"
2336                "  -a --all           Show all units/properties, including dead/empty ones\n"
2337                "     --replace       When installing a new job, replace existing conflicting ones\n"
2338                "     --system        Connect to system bus\n"
2339                "     --session       Connect to session bus\n"
2340                "  -q --quiet         Suppress output\n"
2341                "     --no-block      Do not wait until operation finished\n"
2342                "     --no-wall       Don't send wall message before halt/power-off/reboot\n\n"
2343                "Commands:\n"
2344                "  list-units                      List units\n"
2345                "  start [NAME...]                 Start one or more units\n"
2346                "  stop [NAME...]                  Stop one or more units\n"
2347                "  restart [NAME...]               Restart one or more units\n"
2348                "  reload [NAME...]                Reload one or more units\n"
2349                "  isolate [NAME]                  Start one unit and stop all others\n"
2350                "  check [NAME...]                 Check whether any of the passed units are active\n"
2351                "  status [NAME...]                Show status of one or more units\n"
2352                "  show [NAME...|JOB...]           Show properties of one or more units/jobs/manager\n"
2353                "  load [NAME...]                  Load one or more units\n"
2354                "  list-jobs                       List jobs\n"
2355                "  cancel [JOB...]                 Cancel one or more jobs\n"
2356                "  clear-jobs                      Cancel all jobs\n"
2357                "  monitor                         Monitor unit/job changes\n"
2358                "  dump                            Dump server status\n"
2359                "  snapshot [NAME]                 Create a snapshot\n"
2360                "  delete [NAME...]                Remove one or more snapshots\n"
2361                "  daemon-reload                   Reload systemd manager configuration\n"
2362                "  daemon-reexec                   Reexecute systemd manager\n"
2363                "  daemon-exit                     Ask the systemd manager to quit\n"
2364                "  show-environment                Dump environment\n"
2365                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
2366                "  unset-environment [NAME...]     Unset one or more environment variables\n"
2367                "  halt                            Shut down and halt the system\n"
2368                "  poweroff                        Shut down and power-off the system\n"
2369                "  reboot                          Shut down and reboot the system\n"
2370                "  default                         Enter default mode\n"
2371                "  rescue                          Enter rescue mode\n"
2372                "  emergency                       Enter emergency mode\n",
2373                program_invocation_short_name);
2374
2375         return 0;
2376 }
2377
2378 static int halt_help(void) {
2379
2380         printf("%s [OPTIONS...]\n\n"
2381                "%s the system.\n\n"
2382                "     --help      Show this help\n"
2383                "     --halt      Halt the machine\n"
2384                "  -p --poweroff  Switch off the machine\n"
2385                "     --reboot    Reboot the machine\n"
2386                "  -f --force     Force immediate halt/power-off/reboot\n"
2387                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
2388                "  -d --no-wtmp   Don't write wtmp record\n"
2389                "  -n --no-sync   Don't sync before halt/power-off/reboot\n"
2390                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
2391                program_invocation_short_name,
2392                arg_action == ACTION_REBOOT   ? "Reboot" :
2393                arg_action == ACTION_POWEROFF ? "Power off" :
2394                                                "Halt");
2395
2396         return 0;
2397 }
2398
2399 static int shutdown_help(void) {
2400
2401         printf("%s [OPTIONS...] [now] [WALL...]\n\n"
2402                "Shut down the system.\n\n"
2403                "     --help      Show this help\n"
2404                "  -H --halt      Halt the machine\n"
2405                "  -P --poweroff  Power-off the machine\n"
2406                "  -r --reboot    Reboot the machine\n"
2407                "  -h             Equivalent to --poweroff, overriden by --halt\n"
2408                "  -k             Don't halt/power-off/reboot, just send warnings\n"
2409                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
2410                program_invocation_short_name);
2411
2412         return 0;
2413 }
2414
2415 static int telinit_help(void) {
2416
2417         printf("%s [OPTIONS...] {COMMAND}\n\n"
2418                "Send control commands to the init daemon.\n\n"
2419                "     --help      Show this help\n"
2420                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
2421                "Commands:\n"
2422                "  0              Power-off the machine\n"
2423                "  6              Reboot the machine\n"
2424                "  2, 3, 4, 5     Start runlevelX.target unit\n"
2425                "  1, s, S        Enter rescue mode\n"
2426                "  q, Q           Reload init daemon configuration\n"
2427                "  u, U           Reexecute init daemon\n",
2428                program_invocation_short_name);
2429
2430         return 0;
2431 }
2432
2433 static int runlevel_help(void) {
2434
2435         printf("%s [OPTIONS...]\n\n"
2436                "Prints the previous and current runlevel of the init system.\n\n"
2437                "     --help      Show this help\n",
2438                program_invocation_short_name);
2439
2440         return 0;
2441 }
2442
2443 static int systemctl_parse_argv(int argc, char *argv[]) {
2444
2445         enum {
2446                 ARG_REPLACE = 0x100,
2447                 ARG_SESSION,
2448                 ARG_SYSTEM,
2449                 ARG_NO_BLOCK,
2450                 ARG_NO_WALL
2451         };
2452
2453         static const struct option options[] = {
2454                 { "help",      no_argument,       NULL, 'h'          },
2455                 { "type",      required_argument, NULL, 't'          },
2456                 { "property",  required_argument, NULL, 'p'          },
2457                 { "all",       no_argument,       NULL, 'a'          },
2458                 { "replace",   no_argument,       NULL, ARG_REPLACE  },
2459                 { "session",   no_argument,       NULL, ARG_SESSION  },
2460                 { "system",    no_argument,       NULL, ARG_SYSTEM   },
2461                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK },
2462                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL  },
2463                 { "quiet",     no_argument,       NULL, 'q'          },
2464                 { NULL,        0,                 NULL, 0            }
2465         };
2466
2467         int c;
2468
2469         assert(argc >= 0);
2470         assert(argv);
2471
2472         while ((c = getopt_long(argc, argv, "ht:p:aq", options, NULL)) >= 0) {
2473
2474                 switch (c) {
2475
2476                 case 'h':
2477                         systemctl_help();
2478                         return 0;
2479
2480                 case 't':
2481                         arg_type = optarg;
2482                         break;
2483
2484                 case 'p':
2485                         arg_property = optarg;
2486
2487                         /* If the user asked for a particular
2488                          * property, show it to him, even if it is
2489                          * empty. */
2490                         arg_all = true;
2491                         break;
2492
2493                 case 'a':
2494                         arg_all = true;
2495                         break;
2496
2497                 case ARG_REPLACE:
2498                         arg_replace = true;
2499                         break;
2500
2501                 case ARG_SESSION:
2502                         arg_session = true;
2503                         break;
2504
2505                 case ARG_SYSTEM:
2506                         arg_session = false;
2507                         break;
2508
2509                 case ARG_NO_BLOCK:
2510                         arg_no_block = true;
2511                         break;
2512
2513                 case ARG_NO_WALL:
2514                         arg_no_wall = true;
2515                         break;
2516
2517                 case 'q':
2518                         arg_quiet = true;
2519                         break;
2520
2521                 case '?':
2522                         return -EINVAL;
2523
2524                 default:
2525                         log_error("Unknown option code %c", c);
2526                         return -EINVAL;
2527                 }
2528         }
2529
2530         return 1;
2531 }
2532
2533 static int halt_parse_argv(int argc, char *argv[]) {
2534
2535         enum {
2536                 ARG_HELP = 0x100,
2537                 ARG_HALT,
2538                 ARG_REBOOT,
2539                 ARG_NO_WALL
2540         };
2541
2542         static const struct option options[] = {
2543                 { "help",      no_argument,       NULL, ARG_HELP    },
2544                 { "halt",      no_argument,       NULL, ARG_HALT    },
2545                 { "poweroff",  no_argument,       NULL, 'p'         },
2546                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
2547                 { "force",     no_argument,       NULL, 'f'         },
2548                 { "wtmp-only", no_argument,       NULL, 'w'         },
2549                 { "no-wtmp",   no_argument,       NULL, 'd'         },
2550                 { "no-sync",   no_argument,       NULL, 'n'         },
2551                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
2552                 { NULL,        0,                 NULL, 0           }
2553         };
2554
2555         int c, runlevel;
2556
2557         assert(argc >= 0);
2558         assert(argv);
2559
2560         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
2561                 if (runlevel == '0' || runlevel == '6')
2562                         arg_immediate = true;
2563
2564         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
2565                 switch (c) {
2566
2567                 case ARG_HELP:
2568                         halt_help();
2569                         return 0;
2570
2571                 case ARG_HALT:
2572                         arg_action = ACTION_HALT;
2573                         break;
2574
2575                 case 'p':
2576                         arg_action = ACTION_POWEROFF;
2577                         break;
2578
2579                 case ARG_REBOOT:
2580                         arg_action = ACTION_REBOOT;
2581                         break;
2582
2583                 case 'f':
2584                         arg_immediate = true;
2585                         break;
2586
2587                 case 'w':
2588                         arg_dry = true;
2589                         break;
2590
2591                 case 'd':
2592                         arg_no_wtmp = true;
2593                         break;
2594
2595                 case 'n':
2596                         arg_no_sync = true;
2597                         break;
2598
2599                 case ARG_NO_WALL:
2600                         arg_no_wall = true;
2601                         break;
2602
2603                 case 'i':
2604                 case 'h':
2605                         /* Compatibility nops */
2606                         break;
2607
2608                 case '?':
2609                         return -EINVAL;
2610
2611                 default:
2612                         log_error("Unknown option code %c", c);
2613                         return -EINVAL;
2614                 }
2615         }
2616
2617         if (optind < argc) {
2618                 log_error("Too many arguments.");
2619                 return -EINVAL;
2620         }
2621
2622         return 1;
2623 }
2624
2625 static int shutdown_parse_argv(int argc, char *argv[]) {
2626
2627         enum {
2628                 ARG_HELP = 0x100,
2629                 ARG_NO_WALL
2630         };
2631
2632         static const struct option options[] = {
2633                 { "help",      no_argument,       NULL, ARG_HELP    },
2634                 { "halt",      no_argument,       NULL, 'H'         },
2635                 { "poweroff",  no_argument,       NULL, 'P'         },
2636                 { "reboot",    no_argument,       NULL, 'r'         },
2637                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
2638                 { NULL,        0,                 NULL, 0           }
2639         };
2640
2641         int c;
2642
2643         assert(argc >= 0);
2644         assert(argv);
2645
2646         while ((c = getopt_long(argc, argv, "HPrhkt:a", options, NULL)) >= 0) {
2647                 switch (c) {
2648
2649                 case ARG_HELP:
2650                         shutdown_help();
2651                         return 0;
2652
2653                 case 'H':
2654                         arg_action = ACTION_HALT;
2655                         break;
2656
2657                 case 'P':
2658                         arg_action = ACTION_POWEROFF;
2659                         break;
2660
2661                 case 'r':
2662                         arg_action = ACTION_REBOOT;
2663                         break;
2664
2665                 case 'h':
2666                         if (arg_action != ACTION_HALT)
2667                                 arg_action = ACTION_POWEROFF;
2668                         break;
2669
2670                 case 'k':
2671                         arg_dry = true;
2672                         break;
2673
2674                 case ARG_NO_WALL:
2675                         arg_no_wall = true;
2676                         break;
2677
2678                 case 't':
2679                 case 'a':
2680                         /* Compatibility nops */
2681                         break;
2682
2683                 case '?':
2684                         return -EINVAL;
2685
2686                 default:
2687                         log_error("Unknown option code %c", c);
2688                         return -EINVAL;
2689                 }
2690         }
2691
2692         if (argc > optind && !streq(argv[optind], "now"))
2693                 log_warning("First argument '%s' isn't 'now'. Ignoring.", argv[optind]);
2694
2695         /* We ignore the time argument */
2696         if (argc > optind + 1)
2697                 arg_wall = argv + optind + 1;
2698
2699         optind = argc;
2700
2701         return 1;
2702 }
2703
2704 static int telinit_parse_argv(int argc, char *argv[]) {
2705
2706         enum {
2707                 ARG_HELP = 0x100,
2708                 ARG_NO_WALL
2709         };
2710
2711         static const struct option options[] = {
2712                 { "help",      no_argument,       NULL, ARG_HELP    },
2713                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
2714                 { NULL,        0,                 NULL, 0           }
2715         };
2716
2717         static const struct {
2718                 char from;
2719                 enum action to;
2720         } table[] = {
2721                 { '0', ACTION_POWEROFF },
2722                 { '6', ACTION_REBOOT },
2723                 { '1', ACTION_RESCUE },
2724                 { '2', ACTION_RUNLEVEL2 },
2725                 { '3', ACTION_RUNLEVEL3 },
2726                 { '4', ACTION_RUNLEVEL4 },
2727                 { '5', ACTION_RUNLEVEL5 },
2728                 { 's', ACTION_RESCUE },
2729                 { 'S', ACTION_RESCUE },
2730                 { 'q', ACTION_RELOAD },
2731                 { 'Q', ACTION_RELOAD },
2732                 { 'u', ACTION_REEXEC },
2733                 { 'U', ACTION_REEXEC }
2734         };
2735
2736         unsigned i;
2737         int c;
2738
2739         assert(argc >= 0);
2740         assert(argv);
2741
2742         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
2743                 switch (c) {
2744
2745                 case ARG_HELP:
2746                         telinit_help();
2747                         return 0;
2748
2749                 case ARG_NO_WALL:
2750                         arg_no_wall = true;
2751                         break;
2752
2753                 case '?':
2754                         return -EINVAL;
2755
2756                 default:
2757                         log_error("Unknown option code %c", c);
2758                         return -EINVAL;
2759                 }
2760         }
2761
2762         if (optind >= argc) {
2763                 telinit_help();
2764                 return -EINVAL;
2765         }
2766
2767         if (optind + 1 < argc) {
2768                 log_error("Too many arguments.");
2769                 return -EINVAL;
2770         }
2771
2772         if (strlen(argv[optind]) != 1) {
2773                 log_error("Expected single character argument.");
2774                 return -EINVAL;
2775         }
2776
2777         for (i = 0; i < ELEMENTSOF(table); i++)
2778                 if (table[i].from == argv[optind][0])
2779                         break;
2780
2781         if (i >= ELEMENTSOF(table)) {
2782                 log_error("Unknown command %s.", argv[optind]);
2783                 return -EINVAL;
2784         }
2785
2786         arg_action = table[i].to;
2787
2788         optind ++;
2789
2790         return 1;
2791 }
2792
2793 static int runlevel_parse_argv(int argc, char *argv[]) {
2794
2795         enum {
2796                 ARG_HELP = 0x100,
2797         };
2798
2799         static const struct option options[] = {
2800                 { "help",      no_argument,       NULL, ARG_HELP    },
2801                 { NULL,        0,                 NULL, 0           }
2802         };
2803
2804         int c;
2805
2806         assert(argc >= 0);
2807         assert(argv);
2808
2809         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
2810                 switch (c) {
2811
2812                 case ARG_HELP:
2813                         runlevel_help();
2814                         return 0;
2815
2816                 case '?':
2817                         return -EINVAL;
2818
2819                 default:
2820                         log_error("Unknown option code %c", c);
2821                         return -EINVAL;
2822                 }
2823         }
2824
2825         if (optind < argc) {
2826                 log_error("Too many arguments.");
2827                 return -EINVAL;
2828         }
2829
2830         return 1;
2831 }
2832
2833 static int parse_argv(int argc, char *argv[]) {
2834         assert(argc >= 0);
2835         assert(argv);
2836
2837         if (program_invocation_short_name) {
2838
2839                 if (strstr(program_invocation_short_name, "halt")) {
2840                         arg_action = ACTION_HALT;
2841                         return halt_parse_argv(argc, argv);
2842                 } else if (strstr(program_invocation_short_name, "poweroff")) {
2843                         arg_action = ACTION_POWEROFF;
2844                         return halt_parse_argv(argc, argv);
2845                 } else if (strstr(program_invocation_short_name, "reboot")) {
2846                         arg_action = ACTION_REBOOT;
2847                         return halt_parse_argv(argc, argv);
2848                 } else if (strstr(program_invocation_short_name, "shutdown")) {
2849                         arg_action = ACTION_POWEROFF;
2850                         return shutdown_parse_argv(argc, argv);
2851                 } else if (strstr(program_invocation_short_name, "init")) {
2852                         arg_action = ACTION_INVALID;
2853                         return telinit_parse_argv(argc, argv);
2854                 } else if (strstr(program_invocation_short_name, "runlevel")) {
2855                         arg_action = ACTION_RUNLEVEL;
2856                         return runlevel_parse_argv(argc, argv);
2857                 }
2858         }
2859
2860         arg_action = ACTION_SYSTEMCTL;
2861         return systemctl_parse_argv(argc, argv);
2862 }
2863
2864 static int action_to_runlevel(void) {
2865
2866         static const char table[_ACTION_MAX] = {
2867                 [ACTION_HALT] =      '0',
2868                 [ACTION_POWEROFF] =  '0',
2869                 [ACTION_REBOOT] =    '6',
2870                 [ACTION_RUNLEVEL2] = '2',
2871                 [ACTION_RUNLEVEL3] = '3',
2872                 [ACTION_RUNLEVEL4] = '4',
2873                 [ACTION_RUNLEVEL5] = '5',
2874                 [ACTION_RESCUE] =    '1'
2875         };
2876
2877         assert(arg_action < _ACTION_MAX);
2878
2879         return table[arg_action];
2880 }
2881
2882 static int talk_upstart(void) {
2883         DBusMessage *m = NULL, *reply = NULL;
2884         DBusError error;
2885         int previous, rl, r;
2886         char
2887                 env1_buf[] = "RUNLEVEL=X",
2888                 env2_buf[] = "PREVLEVEL=X";
2889         char *env1 = env1_buf, *env2 = env2_buf;
2890         const char *emit = "runlevel";
2891         dbus_bool_t b_false = FALSE;
2892         DBusMessageIter iter, sub;
2893         DBusConnection *bus;
2894
2895         dbus_error_init(&error);
2896
2897         if (!(rl = action_to_runlevel()))
2898                 return 0;
2899
2900         if (utmp_get_runlevel(&previous, NULL) < 0)
2901                 previous = 'N';
2902
2903         if (!(bus = dbus_connection_open("unix:abstract=/com/ubuntu/upstart", &error))) {
2904                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
2905                         r = 0;
2906                         goto finish;
2907                 }
2908
2909                 log_error("Failed to connect to Upstart bus: %s", error.message);
2910                 r = -EIO;
2911                 goto finish;
2912         }
2913
2914         if ((r = bus_check_peercred(bus)) < 0) {
2915                 log_error("Failed to verify owner of bus.");
2916                 goto finish;
2917         }
2918
2919         if (!(m = dbus_message_new_method_call(
2920                               "com.ubuntu.Upstart",
2921                               "/com/ubuntu/Upstart",
2922                               "com.ubuntu.Upstart0_6",
2923                               "EmitEvent"))) {
2924
2925                 log_error("Could not allocate message.");
2926                 r = -ENOMEM;
2927                 goto finish;
2928         }
2929
2930         dbus_message_iter_init_append(m, &iter);
2931
2932         env1_buf[sizeof(env1_buf)-2] = rl;
2933         env2_buf[sizeof(env2_buf)-2] = previous;
2934
2935         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
2936             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
2937             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
2938             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
2939             !dbus_message_iter_close_container(&iter, &sub) ||
2940             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
2941                 log_error("Could not append arguments to message.");
2942                 r = -ENOMEM;
2943                 goto finish;
2944         }
2945
2946         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2947
2948                 if (error_is_no_service(&error)) {
2949                         r = 0;
2950                         goto finish;
2951                 }
2952
2953                 log_error("Failed to issue method call: %s", error.message);
2954                 r = -EIO;
2955                 goto finish;
2956         }
2957
2958         r = 1;
2959
2960 finish:
2961         if (m)
2962                 dbus_message_unref(m);
2963
2964         if (reply)
2965                 dbus_message_unref(reply);
2966
2967         if (bus)
2968                 dbus_connection_unref(bus);
2969
2970         dbus_error_free(&error);
2971
2972         return r;
2973 }
2974
2975 static int talk_initctl(void) {
2976         struct init_request request;
2977         int r, fd;
2978         char rl;
2979
2980         if (!(rl = action_to_runlevel()))
2981                 return 0;
2982
2983         zero(request);
2984         request.magic = INIT_MAGIC;
2985         request.sleeptime = 0;
2986         request.cmd = INIT_CMD_RUNLVL;
2987         request.runlevel = rl;
2988
2989         if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
2990
2991                 if (errno == ENOENT)
2992                         return 0;
2993
2994                 log_error("Failed to open "INIT_FIFO": %m");
2995                 return -errno;
2996         }
2997
2998         errno = 0;
2999         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
3000         close_nointr_nofail(fd);
3001
3002         if (r < 0) {
3003                 log_error("Failed to write to "INIT_FIFO": %m");
3004                 return errno ? -errno : -EIO;
3005         }
3006
3007         return 1;
3008 }
3009
3010 static int systemctl_main(DBusConnection *bus, int argc, char *argv[]) {
3011
3012         static const struct {
3013                 const char* verb;
3014                 const enum {
3015                         MORE,
3016                         LESS,
3017                         EQUAL
3018                 } argc_cmp;
3019                 const int argc;
3020                 int (* const dispatch)(DBusConnection *bus, char **args, unsigned n);
3021         } verbs[] = {
3022                 { "list-units",        LESS,  1, list_units      },
3023                 { "list-jobs",         EQUAL, 1, list_jobs       },
3024                 { "clear-jobs",        EQUAL, 1, clear_jobs      },
3025                 { "load",              MORE,  2, load_unit       },
3026                 { "cancel",            MORE,  2, cancel_job      },
3027                 { "start",             MORE,  2, start_unit      },
3028                 { "stop",              MORE,  2, start_unit      },
3029                 { "reload",            MORE,  2, start_unit      },
3030                 { "restart",           MORE,  2, start_unit      },
3031                 { "isolate",           EQUAL, 2, start_unit      },
3032                 { "check",             MORE,  2, check_unit      },
3033                 { "show",              MORE,  1, show            },
3034                 { "status",            MORE,  2, show            },
3035                 { "monitor",           EQUAL, 1, monitor         },
3036                 { "dump",              EQUAL, 1, dump            },
3037                 { "snapshot",          LESS,  2, snapshot        },
3038                 { "delete",            MORE,  2, delete_snapshot },
3039                 { "daemon-reload",     EQUAL, 1, clear_jobs      },
3040                 { "daemon-reexec",     EQUAL, 1, clear_jobs      },
3041                 { "daemon-exit",       EQUAL, 1, clear_jobs      },
3042                 { "show-environment",  EQUAL, 1, show_enviroment },
3043                 { "set-environment",   MORE,  2, set_environment },
3044                 { "unset-environment", MORE,  2, set_environment },
3045                 { "halt",              EQUAL, 1, start_special   },
3046                 { "poweroff",          EQUAL, 1, start_special   },
3047                 { "reboot",            EQUAL, 1, start_special   },
3048                 { "default",           EQUAL, 1, start_special   },
3049                 { "rescue",            EQUAL, 1, start_special   },
3050                 { "emergency",         EQUAL, 1, start_special   },
3051         };
3052
3053         int left;
3054         unsigned i;
3055
3056         assert(bus);
3057         assert(argc >= 0);
3058         assert(argv);
3059
3060         left = argc - optind;
3061
3062         if (left <= 0)
3063                 /* Special rule: no arguments means "list-units" */
3064                 i = 0;
3065         else {
3066                 if (streq(argv[optind], "help")) {
3067                         systemctl_help();
3068                         return 0;
3069                 }
3070
3071                 for (i = 0; i < ELEMENTSOF(verbs); i++)
3072                         if (streq(argv[optind], verbs[i].verb))
3073                                 break;
3074
3075                 if (i >= ELEMENTSOF(verbs)) {
3076                         log_error("Unknown operation %s", argv[optind]);
3077                         return -EINVAL;
3078                 }
3079         }
3080
3081         switch (verbs[i].argc_cmp) {
3082
3083         case EQUAL:
3084                 if (left != verbs[i].argc) {
3085                         log_error("Invalid number of arguments.");
3086                         return -EINVAL;
3087                 }
3088
3089                 break;
3090
3091         case MORE:
3092                 if (left < verbs[i].argc) {
3093                         log_error("Too few arguments.");
3094                         return -EINVAL;
3095                 }
3096
3097                 break;
3098
3099         case LESS:
3100                 if (left > verbs[i].argc) {
3101                         log_error("Too many arguments.");
3102                         return -EINVAL;
3103                 }
3104
3105                 break;
3106
3107         default:
3108                 assert_not_reached("Unknown comparison operator.");
3109         }
3110
3111         return verbs[i].dispatch(bus, argv + optind, left);
3112 }
3113
3114 static int reload_with_fallback(DBusConnection *bus) {
3115         int r;
3116
3117         if (bus) {
3118                 /* First, try systemd via D-Bus. */
3119                 if ((r = clear_jobs(bus, NULL, 0)) > 0)
3120                         return 0;
3121         }
3122
3123         /* Nothing else worked, so let's try signals */
3124         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
3125
3126         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
3127                 log_error("kill() failed: %m");
3128                 return -errno;
3129         }
3130
3131         return 0;
3132 }
3133
3134 static int start_with_fallback(DBusConnection *bus) {
3135         int r;
3136
3137         warn_wall(arg_action);
3138
3139         if (bus) {
3140                 /* First, try systemd via D-Bus. */
3141                 if ((r = start_unit(bus, NULL, 0)) > 0)
3142                         return 0;
3143
3144                 /* Hmm, talking to systemd via D-Bus didn't work. Then
3145                  * let's try to talk to Upstart via D-Bus. */
3146                 if ((r = talk_upstart()) > 0)
3147                         return 0;
3148         }
3149
3150         /* Nothing else worked, so let's try
3151          * /dev/initctl */
3152         if ((r = talk_initctl()) != 0)
3153                 return 0;
3154
3155         log_error("Failed to talk to init daemon.");
3156         return -EIO;
3157 }
3158
3159 static int halt_main(DBusConnection *bus) {
3160         int r;
3161
3162         if (!arg_immediate)
3163                 return start_with_fallback(bus);
3164
3165         if (!arg_no_wtmp)
3166                 if ((r = utmp_put_shutdown(0)) < 0)
3167                         log_warning("Failed to write utmp record: %s", strerror(-r));
3168
3169         if (!arg_no_sync)
3170                 sync();
3171
3172         if (arg_dry)
3173                 return 0;
3174
3175         /* Make sure C-A-D is handled by the kernel from this
3176          * point on... */
3177         reboot(RB_ENABLE_CAD);
3178
3179         switch (arg_action) {
3180
3181         case ACTION_HALT:
3182                 log_info("Halting");
3183                 reboot(RB_HALT_SYSTEM);
3184                 break;
3185
3186         case ACTION_POWEROFF:
3187                 log_info("Powering off");
3188                 reboot(RB_POWER_OFF);
3189                 break;
3190
3191         case ACTION_REBOOT:
3192                 log_info("Rebooting");
3193                 reboot(RB_AUTOBOOT);
3194                 break;
3195
3196         default:
3197                 assert_not_reached("Unknown halt action.");
3198         }
3199
3200         /* We should never reach this. */
3201         return -ENOSYS;
3202 }
3203
3204 static int runlevel_main(void) {
3205         int r, runlevel, previous;
3206
3207         if ((r = utmp_get_runlevel(&runlevel, &previous)) < 0) {
3208                 printf("unknown");
3209                 return r;
3210         }
3211
3212         printf("%c %c\n",
3213                previous <= 0 ? 'N' : previous,
3214                runlevel <= 0 ? 'N' : runlevel);
3215
3216         return 0;
3217 }
3218
3219 int main(int argc, char*argv[]) {
3220         int r, retval = 1;
3221         DBusConnection *bus = NULL;
3222         DBusError error;
3223
3224         dbus_error_init(&error);
3225
3226         log_parse_environment();
3227
3228         if ((r = parse_argv(argc, argv)) < 0)
3229                 goto finish;
3230         else if (r == 0) {
3231                 retval = 0;
3232                 goto finish;
3233         }
3234
3235         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
3236          * let's shortcut this */
3237         if (arg_action == ACTION_RUNLEVEL) {
3238                 retval = runlevel_main() < 0;
3239                 goto finish;
3240         }
3241
3242         bus_connect(arg_session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, &error);
3243
3244         switch (arg_action) {
3245
3246         case ACTION_SYSTEMCTL: {
3247
3248                 if (!bus) {
3249                         log_error("Failed to get D-Bus connection: %s", error.message);
3250                         goto finish;
3251                 }
3252
3253                 retval = systemctl_main(bus, argc, argv) < 0;
3254                 break;
3255         }
3256
3257         case ACTION_HALT:
3258         case ACTION_POWEROFF:
3259         case ACTION_REBOOT:
3260                 retval = halt_main(bus) < 0;
3261                 break;
3262
3263         case ACTION_RUNLEVEL2:
3264         case ACTION_RUNLEVEL3:
3265         case ACTION_RUNLEVEL4:
3266         case ACTION_RUNLEVEL5:
3267         case ACTION_RESCUE:
3268         case ACTION_EMERGENCY:
3269         case ACTION_DEFAULT:
3270                 retval = start_with_fallback(bus) < 0;
3271                 break;
3272
3273         case ACTION_RELOAD:
3274         case ACTION_REEXEC:
3275                 retval = reload_with_fallback(bus) < 0;
3276                 break;
3277
3278         case ACTION_INVALID:
3279         case ACTION_RUNLEVEL:
3280         default:
3281                 assert_not_reached("Unknown action");
3282         }
3283
3284 finish:
3285
3286         if (bus)
3287                 dbus_connection_unref(bus);
3288
3289         dbus_error_free(&error);
3290
3291         dbus_shutdown();
3292
3293         return retval;
3294 }