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