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