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