chiark / gitweb /
systemctl: warn when operating on service files that changed on disk but haven't...
[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 static bool unit_need_daemon_reload(DBusConnection *bus, const char *unit) {
746         DBusMessage *m, *reply;
747         dbus_bool_t b = FALSE;
748         DBusMessageIter iter, sub;
749         const char
750                 *interface = "org.freedesktop.systemd1.Unit",
751                 *property = "NeedDaemonReload",
752                 *path;
753
754         /* We ignore all errors here, since this is used to show a warning only */
755
756         if (!(m = dbus_message_new_method_call(
757                               "org.freedesktop.systemd1",
758                               "/org/freedesktop/systemd1",
759                               "org.freedesktop.systemd1.Manager",
760                               "GetUnit")))
761                 goto finish;
762
763         if (!dbus_message_append_args(m,
764                                       DBUS_TYPE_STRING, &unit,
765                                       DBUS_TYPE_INVALID))
766                 goto finish;
767
768         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL)))
769                 goto finish;
770
771         if (!dbus_message_get_args(reply, NULL,
772                                    DBUS_TYPE_OBJECT_PATH, &path,
773                                    DBUS_TYPE_INVALID))
774                 goto finish;
775
776         dbus_message_unref(m);
777         if (!(m = dbus_message_new_method_call(
778                               "org.freedesktop.systemd1",
779                               path,
780                               "org.freedesktop.DBus.Properties",
781                               "Get")))
782                 goto finish;
783
784         if (!dbus_message_append_args(m,
785                                       DBUS_TYPE_STRING, &interface,
786                                       DBUS_TYPE_STRING, &property,
787                                       DBUS_TYPE_INVALID)) {
788                 goto finish;
789         }
790
791         dbus_message_unref(reply);
792         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL)))
793                 goto finish;
794
795         if (!dbus_message_iter_init(reply, &iter) ||
796             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
797                 goto finish;
798
799         dbus_message_iter_recurse(&iter, &sub);
800
801         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
802                 goto finish;
803
804         dbus_message_iter_get_basic(&sub, &b);
805
806 finish:
807         if (m)
808                 dbus_message_unref(m);
809
810         if (reply)
811                 dbus_message_unref(reply);
812
813         return b;
814 }
815
816 typedef struct WaitData {
817         Set *set;
818         bool failed;
819 } WaitData;
820
821 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
822         DBusError error;
823         WaitData *d = data;
824
825         assert(connection);
826         assert(message);
827         assert(d);
828
829         dbus_error_init(&error);
830
831         log_debug("Got D-Bus request: %s.%s() on %s",
832                   dbus_message_get_interface(message),
833                   dbus_message_get_member(message),
834                   dbus_message_get_path(message));
835
836         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
837                 log_error("Warning! D-Bus connection terminated.");
838                 dbus_connection_close(connection);
839
840         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
841                 uint32_t id;
842                 const char *path;
843                 dbus_bool_t success = true;
844
845                 if (!dbus_message_get_args(message, &error,
846                                            DBUS_TYPE_UINT32, &id,
847                                            DBUS_TYPE_OBJECT_PATH, &path,
848                                            DBUS_TYPE_BOOLEAN, &success,
849                                            DBUS_TYPE_INVALID))
850                         log_error("Failed to parse message: %s", error.message);
851                 else {
852                         char *p;
853
854                         if ((p = set_remove(d->set, (char*) path)))
855                                 free(p);
856
857                         if (!success)
858                                 d->failed = true;
859                 }
860         }
861
862         dbus_error_free(&error);
863         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
864 }
865
866 static int enable_wait_for_jobs(DBusConnection *bus) {
867         DBusError error;
868
869         assert(bus);
870
871         if (private_bus)
872                 return 0;
873
874         dbus_error_init(&error);
875         dbus_bus_add_match(bus,
876                            "type='signal',"
877                            "sender='org.freedesktop.systemd1',"
878                            "interface='org.freedesktop.systemd1.Manager',"
879                            "member='JobRemoved',"
880                            "path='/org/freedesktop/systemd1'",
881                            &error);
882
883         if (dbus_error_is_set(&error)) {
884                 log_error("Failed to add match: %s", error.message);
885                 dbus_error_free(&error);
886                 return -EIO;
887         }
888
889         /* This is slightly dirty, since we don't undo the match registrations. */
890         return 0;
891 }
892
893 static int wait_for_jobs(DBusConnection *bus, Set *s) {
894         int r;
895         WaitData d;
896
897         assert(bus);
898         assert(s);
899
900         zero(d);
901         d.set = s;
902         d.failed = false;
903
904         if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) {
905                 log_error("Failed to add filter.");
906                 r = -ENOMEM;
907                 goto finish;
908         }
909
910         while (!set_isempty(s) &&
911                dbus_connection_read_write_dispatch(bus, -1))
912                 ;
913
914         if (!arg_quiet && d.failed)
915                 log_error("Job failed, see logs for details.");
916
917         r = d.failed ? -EIO : 0;
918
919 finish:
920         /* This is slightly dirty, since we don't undo the filter registration. */
921
922         return r;
923 }
924
925 static int start_unit_one(
926                 DBusConnection *bus,
927                 const char *method,
928                 const char *name,
929                 const char *mode,
930                 Set *s) {
931
932         DBusMessage *m = NULL, *reply = NULL;
933         DBusError error;
934         const char *path;
935         int r;
936
937         assert(bus);
938         assert(method);
939         assert(name);
940         assert(mode);
941         assert(arg_no_block || s);
942
943         dbus_error_init(&error);
944
945         if (!(m = dbus_message_new_method_call(
946                               "org.freedesktop.systemd1",
947                               "/org/freedesktop/systemd1",
948                               "org.freedesktop.systemd1.Manager",
949                               method))) {
950                 log_error("Could not allocate message.");
951                 r = -ENOMEM;
952                 goto finish;
953         }
954
955         if (!dbus_message_append_args(m,
956                                       DBUS_TYPE_STRING, &name,
957                                       DBUS_TYPE_STRING, &mode,
958                                       DBUS_TYPE_INVALID)) {
959                 log_error("Could not append arguments to message.");
960                 r = -ENOMEM;
961                 goto finish;
962         }
963
964         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
965
966                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
967                         /* There's always a fallback possible for
968                          * legacy actions. */
969                         r = 0;
970                         goto finish;
971                 }
972
973                 log_error("Failed to issue method call: %s", error.message);
974                 r = -EIO;
975                 goto finish;
976         }
977
978         if (!dbus_message_get_args(reply, &error,
979                                    DBUS_TYPE_OBJECT_PATH, &path,
980                                    DBUS_TYPE_INVALID)) {
981                 log_error("Failed to parse reply: %s", error.message);
982                 r = -EIO;
983                 goto finish;
984         }
985
986         if (unit_need_daemon_reload(bus, name))
987                 log_warning("Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.",
988                             arg_session ? "--session" : "--system");
989
990         if (!arg_no_block) {
991                 char *p;
992
993                 if (!(p = strdup(path))) {
994                         log_error("Failed to duplicate path.");
995                         r = -ENOMEM;
996                         goto finish;
997                 }
998
999                 if ((r = set_put(s, p)) < 0) {
1000                         free(p);
1001                         log_error("Failed to add path to set.");
1002                         goto finish;
1003                 }
1004         }
1005
1006         r = 1;
1007
1008 finish:
1009         if (m)
1010                 dbus_message_unref(m);
1011
1012         if (reply)
1013                 dbus_message_unref(reply);
1014
1015         dbus_error_free(&error);
1016
1017         return r;
1018 }
1019
1020 static enum action verb_to_action(const char *verb) {
1021         if (streq(verb, "halt"))
1022                 return ACTION_HALT;
1023         else if (streq(verb, "poweroff"))
1024                 return ACTION_POWEROFF;
1025         else if (streq(verb, "reboot"))
1026                 return ACTION_REBOOT;
1027         else if (streq(verb, "rescue"))
1028                 return ACTION_RESCUE;
1029         else if (streq(verb, "emergency"))
1030                 return ACTION_EMERGENCY;
1031         else if (streq(verb, "default"))
1032                 return ACTION_DEFAULT;
1033         else
1034                 return ACTION_INVALID;
1035 }
1036
1037 static int start_unit(DBusConnection *bus, char **args, unsigned n) {
1038
1039         static const char * const table[_ACTION_MAX] = {
1040                 [ACTION_HALT] = SPECIAL_HALT_TARGET,
1041                 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
1042                 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
1043                 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
1044                 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
1045                 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
1046                 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
1047                 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
1048                 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
1049                 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET
1050         };
1051
1052         int r;
1053         unsigned i;
1054         const char *method, *mode, *one_name;
1055         Set *s = NULL;
1056
1057         assert(bus);
1058
1059         if (arg_action == ACTION_SYSTEMCTL) {
1060                 method =
1061                         streq(args[0], "stop")                  ? "StopUnit" :
1062                         streq(args[0], "reload")                ? "ReloadUnit" :
1063                         streq(args[0], "restart")               ? "RestartUnit" :
1064                         streq(args[0], "try-restart")           ? "TryRestartUnit" :
1065                         streq(args[0], "reload-or-restart")     ? "ReloadOrRestartUnit" :
1066                         streq(args[0], "reload-or-try-restart") ? "ReloadOrTryRestartUnit" :
1067                                                                   "StartUnit";
1068
1069                 mode =
1070                         (streq(args[0], "isolate") ||
1071                          streq(args[0], "rescue")  ||
1072                          streq(args[0], "emergency")) ? "isolate" :
1073                                              arg_fail ? "fail" :
1074                                                         "replace";
1075
1076                 one_name = table[verb_to_action(args[0])];
1077
1078         } else {
1079                 assert(arg_action < ELEMENTSOF(table));
1080                 assert(table[arg_action]);
1081
1082                 method = "StartUnit";
1083
1084                 mode = (arg_action == ACTION_EMERGENCY ||
1085                         arg_action == ACTION_RESCUE) ? "isolate" : "replace";
1086
1087                 one_name = table[arg_action];
1088         }
1089
1090         if (!arg_no_block) {
1091                 if ((r = enable_wait_for_jobs(bus)) < 0) {
1092                         log_error("Could not watch jobs: %s", strerror(-r));
1093                         goto finish;
1094                 }
1095
1096                 if (!(s = set_new(string_hash_func, string_compare_func))) {
1097                         log_error("Failed to allocate set.");
1098                         r = -ENOMEM;
1099                         goto finish;
1100                 }
1101         }
1102
1103         r = 0;
1104
1105         if (one_name) {
1106                 if ((r = start_unit_one(bus, method, one_name, mode, s)) <= 0)
1107                         goto finish;
1108         } else {
1109                 for (i = 1; i < n; i++)
1110                         if ((r = start_unit_one(bus, method, args[i], mode, s)) < 0)
1111                                 goto finish;
1112         }
1113
1114         if (!arg_no_block)
1115                 r = wait_for_jobs(bus, s);
1116
1117 finish:
1118         if (s)
1119                 set_free_free(s);
1120
1121         return r;
1122 }
1123
1124 static int start_special(DBusConnection *bus, char **args, unsigned n) {
1125         int r;
1126
1127         assert(bus);
1128         assert(args);
1129
1130         r = start_unit(bus, args, n);
1131
1132         if (r >= 0)
1133                 warn_wall(verb_to_action(args[0]));
1134
1135         return r;
1136 }
1137
1138 static int check_unit(DBusConnection *bus, char **args, unsigned n) {
1139         DBusMessage *m = NULL, *reply = NULL;
1140         const char
1141                 *interface = "org.freedesktop.systemd1.Unit",
1142                 *property = "ActiveState";
1143         int r = -EADDRNOTAVAIL;
1144         DBusError error;
1145         unsigned i;
1146
1147         assert(bus);
1148         assert(args);
1149
1150         dbus_error_init(&error);
1151
1152         for (i = 1; i < n; i++) {
1153                 const char *path = NULL;
1154                 const char *state;
1155                 DBusMessageIter iter, sub;
1156
1157                 if (!(m = dbus_message_new_method_call(
1158                                       "org.freedesktop.systemd1",
1159                                       "/org/freedesktop/systemd1",
1160                                       "org.freedesktop.systemd1.Manager",
1161                                       "GetUnit"))) {
1162                         log_error("Could not allocate message.");
1163                         r = -ENOMEM;
1164                         goto finish;
1165                 }
1166
1167                 if (!dbus_message_append_args(m,
1168                                               DBUS_TYPE_STRING, &args[i],
1169                                               DBUS_TYPE_INVALID)) {
1170                         log_error("Could not append arguments to message.");
1171                         r = -ENOMEM;
1172                         goto finish;
1173                 }
1174
1175                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1176
1177                         /* Hmm, cannot figure out anything about this unit... */
1178                         if (!arg_quiet)
1179                                 puts("unknown");
1180
1181                         dbus_error_free(&error);
1182                         continue;
1183                 }
1184
1185                 if (!dbus_message_get_args(reply, &error,
1186                                            DBUS_TYPE_OBJECT_PATH, &path,
1187                                            DBUS_TYPE_INVALID)) {
1188                         log_error("Failed to parse reply: %s", error.message);
1189                         r = -EIO;
1190                         goto finish;
1191                 }
1192
1193                 dbus_message_unref(m);
1194                 if (!(m = dbus_message_new_method_call(
1195                                       "org.freedesktop.systemd1",
1196                                       path,
1197                                       "org.freedesktop.DBus.Properties",
1198                                       "Get"))) {
1199                         log_error("Could not allocate message.");
1200                         r = -ENOMEM;
1201                         goto finish;
1202                 }
1203
1204                 if (!dbus_message_append_args(m,
1205                                               DBUS_TYPE_STRING, &interface,
1206                                               DBUS_TYPE_STRING, &property,
1207                                               DBUS_TYPE_INVALID)) {
1208                         log_error("Could not append arguments to message.");
1209                         r = -ENOMEM;
1210                         goto finish;
1211                 }
1212
1213                 dbus_message_unref(reply);
1214                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1215                         log_error("Failed to issue method call: %s", error.message);
1216                         r = -EIO;
1217                         goto finish;
1218                 }
1219
1220                 if (!dbus_message_iter_init(reply, &iter) ||
1221                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
1222                         log_error("Failed to parse reply.");
1223                         r = -EIO;
1224                         goto finish;
1225                 }
1226
1227                 dbus_message_iter_recurse(&iter, &sub);
1228
1229                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1230                         log_error("Failed to parse reply.");
1231                         r = -EIO;
1232                         goto finish;
1233                 }
1234
1235                 dbus_message_iter_get_basic(&sub, &state);
1236
1237                 if (!arg_quiet)
1238                         puts(state);
1239
1240                 if (streq(state, "active") || startswith(state, "reloading"))
1241                         r = 0;
1242
1243                 dbus_message_unref(m);
1244                 dbus_message_unref(reply);
1245                 m = reply = NULL;
1246         }
1247
1248 finish:
1249         if (m)
1250                 dbus_message_unref(m);
1251
1252         if (reply)
1253                 dbus_message_unref(reply);
1254
1255         dbus_error_free(&error);
1256
1257         return r;
1258 }
1259
1260 typedef struct ExecStatusInfo {
1261         char *path;
1262         char **argv;
1263
1264         bool ignore;
1265
1266         usec_t start_timestamp;
1267         usec_t exit_timestamp;
1268         pid_t pid;
1269         int code;
1270         int status;
1271
1272         LIST_FIELDS(struct ExecStatusInfo, exec);
1273 } ExecStatusInfo;
1274
1275 static void exec_status_info_free(ExecStatusInfo *i) {
1276         assert(i);
1277
1278         free(i->path);
1279         strv_free(i->argv);
1280         free(i);
1281 }
1282
1283 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
1284         uint64_t start_timestamp, exit_timestamp;
1285         DBusMessageIter sub2, sub3;
1286         const char*path;
1287         unsigned n;
1288         uint32_t pid;
1289         int32_t code, status;
1290         dbus_bool_t ignore;
1291
1292         assert(i);
1293         assert(i);
1294
1295         if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
1296                 return -EIO;
1297
1298         dbus_message_iter_recurse(sub, &sub2);
1299
1300         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
1301                 return -EIO;
1302
1303         if (!(i->path = strdup(path)))
1304                 return -ENOMEM;
1305
1306         if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
1307             dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
1308                 return -EIO;
1309
1310         n = 0;
1311         dbus_message_iter_recurse(&sub2, &sub3);
1312         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
1313                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
1314                 dbus_message_iter_next(&sub3);
1315                 n++;
1316         }
1317
1318
1319         if (!(i->argv = new0(char*, n+1)))
1320                 return -ENOMEM;
1321
1322         n = 0;
1323         dbus_message_iter_recurse(&sub2, &sub3);
1324         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
1325                 const char *s;
1326
1327                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
1328                 dbus_message_iter_get_basic(&sub3, &s);
1329                 dbus_message_iter_next(&sub3);
1330
1331                 if (!(i->argv[n++] = strdup(s)))
1332                         return -ENOMEM;
1333         }
1334
1335         if (!dbus_message_iter_next(&sub2) ||
1336             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
1337             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
1338             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
1339             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
1340             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
1341             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
1342                 return -EIO;
1343
1344         i->ignore = ignore;
1345         i->start_timestamp = (usec_t) start_timestamp;
1346         i->exit_timestamp = (usec_t) exit_timestamp;
1347         i->pid = (pid_t) pid;
1348         i->code = code;
1349         i->status = status;
1350
1351         return 0;
1352 }
1353
1354 typedef struct UnitStatusInfo {
1355         const char *id;
1356         const char *load_state;
1357         const char *active_state;
1358         const char *sub_state;
1359
1360         const char *description;
1361
1362         const char *fragment_path;
1363         const char *default_control_group;
1364
1365         bool need_daemon_reload;
1366
1367         /* Service */
1368         pid_t main_pid;
1369         pid_t control_pid;
1370         const char *status_text;
1371         bool running;
1372
1373         usec_t start_timestamp;
1374         usec_t exit_timestamp;
1375
1376         int exit_code, exit_status;
1377
1378         /* Socket */
1379         unsigned n_accepted;
1380         unsigned n_connections;
1381         bool accept;
1382
1383         /* Device */
1384         const char *sysfs_path;
1385
1386         /* Mount, Automount */
1387         const char *where;
1388
1389         /* Swap */
1390         const char *what;
1391
1392         LIST_HEAD(ExecStatusInfo, exec);
1393 } UnitStatusInfo;
1394
1395 static void print_status_info(UnitStatusInfo *i) {
1396         ExecStatusInfo *p;
1397
1398         assert(i);
1399
1400         /* This shows pretty information about a unit. See
1401          * print_property() for a low-level property printer */
1402
1403         printf("%s", strna(i->id));
1404
1405         if (i->description && !streq_ptr(i->id, i->description))
1406                 printf(" - %s", i->description);
1407
1408         printf("\n");
1409
1410         if (i->fragment_path)
1411                 printf("\t  Loaded: %s (%s)\n", strna(i->load_state), i->fragment_path);
1412         else if (streq_ptr(i->load_state, "failed"))
1413                 printf("\t  Loaded: " ANSI_HIGHLIGHT_ON "%s" ANSI_HIGHLIGHT_OFF "\n", strna(i->load_state));
1414         else
1415                 printf("\t  Loaded: %s\n", strna(i->load_state));
1416
1417         if (streq_ptr(i->active_state, "maintenance")) {
1418                         if (streq_ptr(i->active_state, i->sub_state))
1419                                 printf("\t  Active: " ANSI_HIGHLIGHT_ON "%s" ANSI_HIGHLIGHT_OFF "\n",
1420                                        strna(i->active_state));
1421                         else
1422                                 printf("\t  Active: " ANSI_HIGHLIGHT_ON "%s (%s)" ANSI_HIGHLIGHT_OFF "\n",
1423                                        strna(i->active_state),
1424                                        strna(i->sub_state));
1425         } else {
1426                 if (streq_ptr(i->active_state, i->sub_state))
1427                         printf("\t  Active: %s\n",
1428                                strna(i->active_state));
1429                 else
1430                         printf("\t  Active: %s (%s)\n",
1431                                strna(i->active_state),
1432                                strna(i->sub_state));
1433         }
1434
1435         if (i->sysfs_path)
1436                 printf("\t  Device: %s\n", i->sysfs_path);
1437         else if (i->where)
1438                 printf("\t   Where: %s\n", i->where);
1439         else if (i->what)
1440                 printf("\t    What: %s\n", i->what);
1441
1442         if (i->accept)
1443                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
1444
1445         LIST_FOREACH(exec, p, i->exec) {
1446                 char *t;
1447
1448                 /* Only show exited processes here */
1449                 if (p->code == 0)
1450                         continue;
1451
1452                 t = strv_join(p->argv, " ");
1453                 printf("\t  Exited: %u (%s, code=%s, ", p->pid, strna(t), sigchld_code_to_string(p->code));
1454                 free(t);
1455
1456                 if (p->code == CLD_EXITED)
1457                         printf("status=%i", p->status);
1458                 else
1459                         printf("signal=%s", signal_to_string(p->status));
1460                 printf(")\n");
1461
1462                 if (i->main_pid == p->pid &&
1463                     i->start_timestamp == p->start_timestamp &&
1464                     i->exit_timestamp == p->start_timestamp)
1465                         /* Let's not show this twice */
1466                         i->main_pid = 0;
1467
1468                 if (p->pid == i->control_pid)
1469                         i->control_pid = 0;
1470         }
1471
1472         if (i->main_pid > 0 || i->control_pid > 0) {
1473                 printf("\t");
1474
1475                 if (i->main_pid > 0) {
1476                         printf("    Main: %u", (unsigned) i->main_pid);
1477
1478                         if (i->running) {
1479                                 char *t = NULL;
1480                                 get_process_name(i->main_pid, &t);
1481                                 if (t) {
1482                                         printf(" (%s)", t);
1483                                         free(t);
1484                                 }
1485                         } else {
1486                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
1487
1488                                 if (i->exit_code == CLD_EXITED)
1489                                         printf("status=%i", i->exit_status);
1490                                 else
1491                                         printf("signal=%s", signal_to_string(i->exit_status));
1492                                 printf(")");
1493                         }
1494                 }
1495
1496                 if (i->main_pid > 0 && i->control_pid > 0)
1497                         printf(";");
1498
1499                 if (i->control_pid > 0) {
1500                         char *t = NULL;
1501
1502                         printf(" Control: %u", (unsigned) i->control_pid);
1503
1504                         get_process_name(i->control_pid, &t);
1505                         if (t) {
1506                                 printf(" (%s)", t);
1507                                 free(t);
1508                         }
1509                 }
1510
1511                 printf("\n");
1512         }
1513
1514         if (i->status_text)
1515                 printf("\t  Status: \"%s\"\n", i->status_text);
1516
1517         if (i->default_control_group) {
1518                 unsigned c;
1519
1520                 printf("\t  CGroup: %s\n", i->default_control_group);
1521
1522                 if ((c = columns()) > 18)
1523                         c -= 18;
1524                 else
1525                         c = 0;
1526
1527                 show_cgroup_by_path(i->default_control_group, "\t\t  ", c);
1528         }
1529
1530         if (i->need_daemon_reload)
1531                 printf("\n" ANSI_HIGHLIGHT_ON "Warning:" ANSI_HIGHLIGHT_OFF " Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
1532                        arg_session ? "--session" : "--system");
1533 }
1534
1535 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
1536
1537         switch (dbus_message_iter_get_arg_type(iter)) {
1538
1539         case DBUS_TYPE_STRING: {
1540                 const char *s;
1541
1542                 dbus_message_iter_get_basic(iter, &s);
1543
1544                 if (s[0]) {
1545                         if (streq(name, "Id"))
1546                                 i->id = s;
1547                         else if (streq(name, "LoadState"))
1548                                 i->load_state = s;
1549                         else if (streq(name, "ActiveState"))
1550                                 i->active_state = s;
1551                         else if (streq(name, "SubState"))
1552                                 i->sub_state = s;
1553                         else if (streq(name, "Description"))
1554                                 i->description = s;
1555                         else if (streq(name, "FragmentPath"))
1556                                 i->fragment_path = s;
1557                         else if (streq(name, "DefaultControlGroup"))
1558                                 i->default_control_group = s;
1559                         else if (streq(name, "StatusText"))
1560                                 i->status_text = s;
1561                         else if (streq(name, "SysFSPath"))
1562                                 i->sysfs_path = s;
1563                         else if (streq(name, "Where"))
1564                                 i->where = s;
1565                         else if (streq(name, "What"))
1566                                 i->what = s;
1567                 }
1568
1569                 break;
1570         }
1571
1572         case DBUS_TYPE_BOOLEAN: {
1573                 dbus_bool_t b;
1574
1575                 dbus_message_iter_get_basic(iter, &b);
1576
1577                 if (streq(name, "Accept"))
1578                         i->accept = b;
1579                 else if (streq(name, "NeedDaemonReload"))
1580                         i->need_daemon_reload = b;
1581
1582                 break;
1583         }
1584
1585         case DBUS_TYPE_UINT32: {
1586                 uint32_t u;
1587
1588                 dbus_message_iter_get_basic(iter, &u);
1589
1590                 if (streq(name, "MainPID")) {
1591                         if (u > 0) {
1592                                 i->main_pid = (pid_t) u;
1593                                 i->running = true;
1594                         }
1595                 } else if (streq(name, "ControlPID"))
1596                         i->control_pid = (pid_t) u;
1597                 else if (streq(name, "ExecMainPID")) {
1598                         if (u > 0)
1599                                 i->main_pid = (pid_t) u;
1600                 } else if (streq(name, "NAccepted"))
1601                         i->n_accepted = u;
1602                 else if (streq(name, "NConnections"))
1603                         i->n_connections = u;
1604
1605                 break;
1606         }
1607
1608         case DBUS_TYPE_INT32: {
1609                 int32_t j;
1610
1611                 dbus_message_iter_get_basic(iter, &j);
1612
1613                 if (streq(name, "ExecMainCode"))
1614                         i->exit_code = (int) j;
1615                 else if (streq(name, "ExecMainStatus"))
1616                         i->exit_status = (int) j;
1617
1618                 break;
1619         }
1620
1621         case DBUS_TYPE_UINT64: {
1622                 uint64_t u;
1623
1624                 dbus_message_iter_get_basic(iter, &u);
1625
1626                 if (streq(name, "ExecMainStartTimestamp"))
1627                         i->start_timestamp = (usec_t) u;
1628                 else if (streq(name, "ExecMainExitTimestamp"))
1629                         i->exit_timestamp = (usec_t) u;
1630
1631                 break;
1632         }
1633
1634         case DBUS_TYPE_ARRAY: {
1635
1636                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
1637                     startswith(name, "Exec")) {
1638                         DBusMessageIter sub;
1639
1640                         dbus_message_iter_recurse(iter, &sub);
1641                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1642                                 ExecStatusInfo *info;
1643                                 int r;
1644
1645                                 if (!(info = new0(ExecStatusInfo, 1)))
1646                                         return -ENOMEM;
1647
1648                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
1649                                         free(info);
1650                                         return r;
1651                                 }
1652
1653                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
1654
1655                                 dbus_message_iter_next(&sub);
1656                         }
1657                 }
1658
1659                 break;
1660         }
1661         }
1662
1663         return 0;
1664 }
1665
1666 static int print_property(const char *name, DBusMessageIter *iter) {
1667         assert(name);
1668         assert(iter);
1669
1670         /* This is a low-level property printer, see
1671          * print_status_info() for the nicer output */
1672
1673         if (arg_property && !streq(name, arg_property))
1674                 return 0;
1675
1676         switch (dbus_message_iter_get_arg_type(iter)) {
1677
1678         case DBUS_TYPE_STRING: {
1679                 const char *s;
1680                 dbus_message_iter_get_basic(iter, &s);
1681
1682                 if (arg_all || s[0])
1683                         printf("%s=%s\n", name, s);
1684
1685                 return 0;
1686         }
1687
1688         case DBUS_TYPE_BOOLEAN: {
1689                 dbus_bool_t b;
1690                 dbus_message_iter_get_basic(iter, &b);
1691                 printf("%s=%s\n", name, yes_no(b));
1692
1693                 return 0;
1694         }
1695
1696         case DBUS_TYPE_UINT64: {
1697                 uint64_t u;
1698                 dbus_message_iter_get_basic(iter, &u);
1699
1700                 /* Yes, heuristics! But we can change this check
1701                  * should it turn out to not be sufficient */
1702
1703                 if (strstr(name, "Timestamp")) {
1704                         char timestamp[FORMAT_TIMESTAMP_MAX], *t;
1705
1706                         if ((t = format_timestamp(timestamp, sizeof(timestamp), u)) || arg_all)
1707                                 printf("%s=%s\n", name, strempty(t));
1708                 } else if (strstr(name, "USec")) {
1709                         char timespan[FORMAT_TIMESPAN_MAX];
1710
1711                         printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
1712                 } else
1713                         printf("%s=%llu\n", name, (unsigned long long) u);
1714
1715                 return 0;
1716         }
1717
1718         case DBUS_TYPE_UINT32: {
1719                 uint32_t u;
1720                 dbus_message_iter_get_basic(iter, &u);
1721
1722                 if (strstr(name, "UMask") || strstr(name, "Mode"))
1723                         printf("%s=%04o\n", name, u);
1724                 else
1725                         printf("%s=%u\n", name, (unsigned) u);
1726
1727                 return 0;
1728         }
1729
1730         case DBUS_TYPE_INT32: {
1731                 int32_t i;
1732                 dbus_message_iter_get_basic(iter, &i);
1733
1734                 printf("%s=%i\n", name, (int) i);
1735                 return 0;
1736         }
1737
1738         case DBUS_TYPE_STRUCT: {
1739                 DBusMessageIter sub;
1740                 dbus_message_iter_recurse(iter, &sub);
1741
1742                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
1743                         uint32_t u;
1744
1745                         dbus_message_iter_get_basic(&sub, &u);
1746
1747                         if (u)
1748                                 printf("%s=%u\n", name, (unsigned) u);
1749                         else if (arg_all)
1750                                 printf("%s=\n", name);
1751
1752                         return 0;
1753                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
1754                         const char *s;
1755
1756                         dbus_message_iter_get_basic(&sub, &s);
1757
1758                         if (arg_all || s[0])
1759                                 printf("%s=%s\n", name, s);
1760
1761                         return 0;
1762                 }
1763
1764                 break;
1765         }
1766
1767         case DBUS_TYPE_ARRAY:
1768
1769                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
1770                         DBusMessageIter sub;
1771                         bool space = false;
1772
1773                         dbus_message_iter_recurse(iter, &sub);
1774                         if (arg_all ||
1775                             dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1776                                 printf("%s=", name);
1777
1778                                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1779                                         const char *s;
1780
1781                                         assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
1782                                         dbus_message_iter_get_basic(&sub, &s);
1783                                         printf("%s%s", space ? " " : "", s);
1784
1785                                         space = true;
1786                                         dbus_message_iter_next(&sub);
1787                                 }
1788
1789                                 puts("");
1790                         }
1791
1792                         return 0;
1793
1794                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
1795                         DBusMessageIter sub;
1796
1797                         dbus_message_iter_recurse(iter, &sub);
1798                         if (arg_all ||
1799                             dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1800                                 printf("%s=", name);
1801
1802                                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1803                                         uint8_t u;
1804
1805                                         assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
1806                                         dbus_message_iter_get_basic(&sub, &u);
1807                                         printf("%02x", u);
1808
1809                                         dbus_message_iter_next(&sub);
1810                                 }
1811
1812                                 puts("");
1813                         }
1814
1815                         return 0;
1816
1817                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
1818                         DBusMessageIter sub, sub2;
1819
1820                         dbus_message_iter_recurse(iter, &sub);
1821                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1822                                 const char *type, *path;
1823
1824                                 dbus_message_iter_recurse(&sub, &sub2);
1825
1826                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
1827                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
1828                                         printf("%s=%s\n", type, path);
1829
1830                                 dbus_message_iter_next(&sub);
1831                         }
1832
1833                         return 0;
1834
1835                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
1836                         DBusMessageIter sub, sub2;
1837
1838                         dbus_message_iter_recurse(iter, &sub);
1839                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1840                                 const char *base;
1841                                 uint64_t value, next_elapse;
1842
1843                                 dbus_message_iter_recurse(&sub, &sub2);
1844
1845                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
1846                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
1847                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
1848                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
1849
1850                                         printf("%s={ value=%s ; next_elapse=%s }\n",
1851                                                base,
1852                                                format_timespan(timespan1, sizeof(timespan1), value),
1853                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
1854                                 }
1855
1856                                 dbus_message_iter_next(&sub);
1857                         }
1858
1859                         return 0;
1860
1861                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
1862                         DBusMessageIter sub;
1863
1864                         dbus_message_iter_recurse(iter, &sub);
1865                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1866                                 ExecStatusInfo info;
1867
1868                                 zero(info);
1869                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
1870                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
1871                                         char *t;
1872
1873                                         t = strv_join(info.argv, " ");
1874
1875                                         printf("%s={ path=%s ; argv[]=%s ; ignore=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
1876                                                name,
1877                                                strna(info.path),
1878                                                strna(t),
1879                                                yes_no(info.ignore),
1880                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
1881                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
1882                                                (unsigned) info. pid,
1883                                                sigchld_code_to_string(info.code),
1884                                                info.status,
1885                                                info.code == CLD_EXITED ? "" : "/",
1886                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
1887
1888                                         free(t);
1889                                 }
1890
1891                                 free(info.path);
1892                                 strv_free(info.argv);
1893
1894                                 dbus_message_iter_next(&sub);
1895                         }
1896
1897                         return 0;
1898                 }
1899
1900                 break;
1901         }
1902
1903         if (arg_all)
1904                 printf("%s=[unprintable]\n", name);
1905
1906         return 0;
1907 }
1908
1909 static int show_one(DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
1910         DBusMessage *m = NULL, *reply = NULL;
1911         const char *interface = "";
1912         int r;
1913         DBusError error;
1914         DBusMessageIter iter, sub, sub2, sub3;
1915         UnitStatusInfo info;
1916         ExecStatusInfo *p;
1917
1918         assert(bus);
1919         assert(path);
1920         assert(new_line);
1921
1922         zero(info);
1923         dbus_error_init(&error);
1924
1925         if (!(m = dbus_message_new_method_call(
1926                               "org.freedesktop.systemd1",
1927                               path,
1928                               "org.freedesktop.DBus.Properties",
1929                               "GetAll"))) {
1930                 log_error("Could not allocate message.");
1931                 r = -ENOMEM;
1932                 goto finish;
1933         }
1934
1935         if (!dbus_message_append_args(m,
1936                                       DBUS_TYPE_STRING, &interface,
1937                                       DBUS_TYPE_INVALID)) {
1938                 log_error("Could not append arguments to message.");
1939                 r = -ENOMEM;
1940                 goto finish;
1941         }
1942
1943         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1944                 log_error("Failed to issue method call: %s", error.message);
1945                 r = -EIO;
1946                 goto finish;
1947         }
1948
1949         if (!dbus_message_iter_init(reply, &iter) ||
1950             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1951             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
1952                 log_error("Failed to parse reply.");
1953                 r = -EIO;
1954                 goto finish;
1955         }
1956
1957         dbus_message_iter_recurse(&iter, &sub);
1958
1959         if (*new_line)
1960                 printf("\n");
1961
1962         *new_line = true;
1963
1964         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1965                 const char *name;
1966
1967                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
1968                         log_error("Failed to parse reply.");
1969                         r = -EIO;
1970                         goto finish;
1971                 }
1972
1973                 dbus_message_iter_recurse(&sub, &sub2);
1974
1975                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
1976                         log_error("Failed to parse reply.");
1977                         r = -EIO;
1978                         goto finish;
1979                 }
1980
1981                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
1982                         log_error("Failed to parse reply.");
1983                         r = -EIO;
1984                         goto finish;
1985                 }
1986
1987                 dbus_message_iter_recurse(&sub2, &sub3);
1988
1989                 if (show_properties)
1990                         r = print_property(name, &sub3);
1991                 else
1992                         r = status_property(name, &sub3, &info);
1993
1994                 if (r < 0) {
1995                         log_error("Failed to parse reply.");
1996                         r = -EIO;
1997                         goto finish;
1998                 }
1999
2000                 dbus_message_iter_next(&sub);
2001         }
2002
2003         if (!show_properties)
2004                 print_status_info(&info);
2005
2006         while ((p = info.exec)) {
2007                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
2008                 exec_status_info_free(p);
2009         }
2010
2011         r = 0;
2012
2013 finish:
2014         if (m)
2015                 dbus_message_unref(m);
2016
2017         if (reply)
2018                 dbus_message_unref(reply);
2019
2020         dbus_error_free(&error);
2021
2022         return r;
2023 }
2024
2025 static int show(DBusConnection *bus, char **args, unsigned n) {
2026         DBusMessage *m = NULL, *reply = NULL;
2027         int r;
2028         DBusError error;
2029         unsigned i;
2030         bool show_properties, new_line = false;
2031
2032         assert(bus);
2033         assert(args);
2034
2035         dbus_error_init(&error);
2036
2037         show_properties = !streq(args[0], "status");
2038
2039         if (show_properties && n <= 1) {
2040                 /* If not argument is specified inspect the manager
2041                  * itself */
2042
2043                 r = show_one(bus, "/org/freedesktop/systemd1", show_properties, &new_line);
2044                 goto finish;
2045         }
2046
2047         for (i = 1; i < n; i++) {
2048                 const char *path = NULL;
2049                 uint32_t id;
2050
2051                 if (!show_properties || safe_atou32(args[i], &id) < 0) {
2052
2053                         if (!(m = dbus_message_new_method_call(
2054                                               "org.freedesktop.systemd1",
2055                                               "/org/freedesktop/systemd1",
2056                                               "org.freedesktop.systemd1.Manager",
2057                                               "LoadUnit"))) {
2058                                 log_error("Could not allocate message.");
2059                                 r = -ENOMEM;
2060                                 goto finish;
2061                         }
2062
2063                         if (!dbus_message_append_args(m,
2064                                                       DBUS_TYPE_STRING, &args[i],
2065                                                       DBUS_TYPE_INVALID)) {
2066                                 log_error("Could not append arguments to message.");
2067                                 r = -ENOMEM;
2068                                 goto finish;
2069                         }
2070
2071                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2072
2073                                 if (!dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
2074                                         log_error("Failed to issue method call: %s", error.message);
2075                                         r = -EIO;
2076                                         goto finish;
2077                                 }
2078
2079                                 dbus_error_free(&error);
2080
2081                                 dbus_message_unref(m);
2082                                 if (!(m = dbus_message_new_method_call(
2083                                                       "org.freedesktop.systemd1",
2084                                                       "/org/freedesktop/systemd1",
2085                                                       "org.freedesktop.systemd1.Manager",
2086                                                       "GetUnit"))) {
2087                                         log_error("Could not allocate message.");
2088                                         r = -ENOMEM;
2089                                         goto finish;
2090                                 }
2091
2092                                 if (!dbus_message_append_args(m,
2093                                                               DBUS_TYPE_STRING, &args[i],
2094                                                               DBUS_TYPE_INVALID)) {
2095                                         log_error("Could not append arguments to message.");
2096                                         r = -ENOMEM;
2097                                         goto finish;
2098                                 }
2099
2100                                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2101                                         log_error("Failed to issue method call: %s", error.message);
2102                                         r = -EIO;
2103                                         goto finish;
2104                                 }
2105                         }
2106
2107                 } else {
2108
2109                         if (!(m = dbus_message_new_method_call(
2110                                               "org.freedesktop.systemd1",
2111                                               "/org/freedesktop/systemd1",
2112                                               "org.freedesktop.systemd1.Manager",
2113                                               "GetJob"))) {
2114                                 log_error("Could not allocate message.");
2115                                 r = -ENOMEM;
2116                                 goto finish;
2117                         }
2118
2119                         if (!dbus_message_append_args(m,
2120                                                       DBUS_TYPE_UINT32, &id,
2121                                                       DBUS_TYPE_INVALID)) {
2122                                 log_error("Could not append arguments to message.");
2123                                 r = -ENOMEM;
2124                                 goto finish;
2125                         }
2126
2127                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2128                                 log_error("Failed to issue method call: %s", error.message);
2129                                 r = -EIO;
2130                                 goto finish;
2131                         }
2132                 }
2133
2134                 if (!dbus_message_get_args(reply, &error,
2135                                            DBUS_TYPE_OBJECT_PATH, &path,
2136                                            DBUS_TYPE_INVALID)) {
2137                         log_error("Failed to parse reply: %s", error.message);
2138                         r = -EIO;
2139                         goto finish;
2140                 }
2141
2142                 if ((r = show_one(bus, path, show_properties, &new_line)) < 0)
2143                         goto finish;
2144
2145                 dbus_message_unref(m);
2146                 dbus_message_unref(reply);
2147                 m = reply = NULL;
2148         }
2149
2150         r = 0;
2151
2152 finish:
2153         if (m)
2154                 dbus_message_unref(m);
2155
2156         if (reply)
2157                 dbus_message_unref(reply);
2158
2159         dbus_error_free(&error);
2160
2161         return r;
2162 }
2163
2164 static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage *message, void *data) {
2165         DBusError error;
2166         DBusMessage *m = NULL, *reply = NULL;
2167
2168         assert(connection);
2169         assert(message);
2170
2171         dbus_error_init(&error);
2172
2173         log_debug("Got D-Bus request: %s.%s() on %s",
2174                   dbus_message_get_interface(message),
2175                   dbus_message_get_member(message),
2176                   dbus_message_get_path(message));
2177
2178         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
2179                 log_error("Warning! D-Bus connection terminated.");
2180                 dbus_connection_close(connection);
2181
2182         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitNew") ||
2183                    dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitRemoved")) {
2184                 const char *id, *path;
2185
2186                 if (!dbus_message_get_args(message, &error,
2187                                            DBUS_TYPE_STRING, &id,
2188                                            DBUS_TYPE_OBJECT_PATH, &path,
2189                                            DBUS_TYPE_INVALID))
2190                         log_error("Failed to parse message: %s", error.message);
2191                 else if (streq(dbus_message_get_member(message), "UnitNew"))
2192                         printf("Unit %s added.\n", id);
2193                 else
2194                         printf("Unit %s removed.\n", id);
2195
2196         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobNew") ||
2197                    dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2198                 uint32_t id;
2199                 const char *path;
2200
2201                 if (!dbus_message_get_args(message, &error,
2202                                            DBUS_TYPE_UINT32, &id,
2203                                            DBUS_TYPE_OBJECT_PATH, &path,
2204                                            DBUS_TYPE_INVALID))
2205                         log_error("Failed to parse message: %s", error.message);
2206                 else if (streq(dbus_message_get_member(message), "JobNew"))
2207                         printf("Job %u added.\n", id);
2208                 else
2209                         printf("Job %u removed.\n", id);
2210
2211
2212         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Unit", "Changed") ||
2213                    dbus_message_is_signal(message, "org.freedesktop.systemd1.Job", "Changed")) {
2214
2215                 const char *path, *interface, *property = "Id";
2216                 DBusMessageIter iter, sub;
2217
2218                 path = dbus_message_get_path(message);
2219                 interface = dbus_message_get_interface(message);
2220
2221                 if (!(m = dbus_message_new_method_call(
2222                               "org.freedesktop.systemd1",
2223                               path,
2224                               "org.freedesktop.DBus.Properties",
2225                               "Get"))) {
2226                         log_error("Could not allocate message.");
2227                         goto oom;
2228                 }
2229
2230                 if (!dbus_message_append_args(m,
2231                                               DBUS_TYPE_STRING, &interface,
2232                                               DBUS_TYPE_STRING, &property,
2233                                               DBUS_TYPE_INVALID)) {
2234                         log_error("Could not append arguments to message.");
2235                         goto finish;
2236                 }
2237
2238                 if (!(reply = dbus_connection_send_with_reply_and_block(connection, m, -1, &error))) {
2239                         log_error("Failed to issue method call: %s", error.message);
2240                         goto finish;
2241                 }
2242
2243                 if (!dbus_message_iter_init(reply, &iter) ||
2244                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
2245                         log_error("Failed to parse reply.");
2246                         goto finish;
2247                 }
2248
2249                 dbus_message_iter_recurse(&iter, &sub);
2250
2251                 if (streq(interface, "org.freedesktop.systemd1.Unit")) {
2252                         const char *id;
2253
2254                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
2255                                 log_error("Failed to parse reply.");
2256                                 goto finish;
2257                         }
2258
2259                         dbus_message_iter_get_basic(&sub, &id);
2260                         printf("Unit %s changed.\n", id);
2261                 } else {
2262                         uint32_t id;
2263
2264                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32)  {
2265                                 log_error("Failed to parse reply.");
2266                                 goto finish;
2267                         }
2268
2269                         dbus_message_iter_get_basic(&sub, &id);
2270                         printf("Job %u changed.\n", id);
2271                 }
2272         }
2273
2274 finish:
2275         if (m)
2276                 dbus_message_unref(m);
2277
2278         if (reply)
2279                 dbus_message_unref(reply);
2280
2281         dbus_error_free(&error);
2282         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2283
2284 oom:
2285         if (m)
2286                 dbus_message_unref(m);
2287
2288         if (reply)
2289                 dbus_message_unref(reply);
2290
2291         dbus_error_free(&error);
2292         return DBUS_HANDLER_RESULT_NEED_MEMORY;
2293 }
2294
2295 static int monitor(DBusConnection *bus, char **args, unsigned n) {
2296         DBusMessage *m = NULL, *reply = NULL;
2297         DBusError error;
2298         int r;
2299
2300         dbus_error_init(&error);
2301
2302         if (!private_bus) {
2303                 dbus_bus_add_match(bus,
2304                                    "type='signal',"
2305                                    "sender='org.freedesktop.systemd1',"
2306                                    "interface='org.freedesktop.systemd1.Manager',"
2307                                    "path='/org/freedesktop/systemd1'",
2308                                    &error);
2309
2310                 if (dbus_error_is_set(&error)) {
2311                         log_error("Failed to add match: %s", error.message);
2312                         r = -EIO;
2313                         goto finish;
2314                 }
2315
2316                 dbus_bus_add_match(bus,
2317                                    "type='signal',"
2318                                    "sender='org.freedesktop.systemd1',"
2319                                    "interface='org.freedesktop.systemd1.Unit',"
2320                                    "member='Changed'",
2321                                    &error);
2322
2323                 if (dbus_error_is_set(&error)) {
2324                         log_error("Failed to add match: %s", error.message);
2325                         r = -EIO;
2326                         goto finish;
2327                 }
2328
2329                 dbus_bus_add_match(bus,
2330                                    "type='signal',"
2331                                    "sender='org.freedesktop.systemd1',"
2332                                    "interface='org.freedesktop.systemd1.Job',"
2333                                    "member='Changed'",
2334                                    &error);
2335
2336                 if (dbus_error_is_set(&error)) {
2337                         log_error("Failed to add match: %s", error.message);
2338                         r = -EIO;
2339                         goto finish;
2340                 }
2341         }
2342
2343         if (!dbus_connection_add_filter(bus, monitor_filter, NULL, NULL)) {
2344                 log_error("Failed to add filter.");
2345                 r = -ENOMEM;
2346                 goto finish;
2347         }
2348
2349         if (!(m = dbus_message_new_method_call(
2350                               "org.freedesktop.systemd1",
2351                               "/org/freedesktop/systemd1",
2352                               "org.freedesktop.systemd1.Manager",
2353                               "Subscribe"))) {
2354                 log_error("Could not allocate message.");
2355                 r = -ENOMEM;
2356                 goto finish;
2357         }
2358
2359         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2360                 log_error("Failed to issue method call: %s", error.message);
2361                 r = -EIO;
2362                 goto finish;
2363         }
2364
2365         while (dbus_connection_read_write_dispatch(bus, -1))
2366                 ;
2367
2368         r = 0;
2369
2370 finish:
2371
2372         /* This is slightly dirty, since we don't undo the filter or the matches. */
2373
2374         if (m)
2375                 dbus_message_unref(m);
2376
2377         if (reply)
2378                 dbus_message_unref(reply);
2379
2380         dbus_error_free(&error);
2381
2382         return r;
2383 }
2384
2385 static int dump(DBusConnection *bus, char **args, unsigned n) {
2386         DBusMessage *m = NULL, *reply = NULL;
2387         DBusError error;
2388         int r;
2389         const char *text;
2390
2391         dbus_error_init(&error);
2392
2393         if (!(m = dbus_message_new_method_call(
2394                               "org.freedesktop.systemd1",
2395                               "/org/freedesktop/systemd1",
2396                               "org.freedesktop.systemd1.Manager",
2397                               "Dump"))) {
2398                 log_error("Could not allocate message.");
2399                 return -ENOMEM;
2400         }
2401
2402         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2403                 log_error("Failed to issue method call: %s", error.message);
2404                 r = -EIO;
2405                 goto finish;
2406         }
2407
2408         if (!dbus_message_get_args(reply, &error,
2409                                    DBUS_TYPE_STRING, &text,
2410                                    DBUS_TYPE_INVALID)) {
2411                 log_error("Failed to parse reply: %s", error.message);
2412                 r = -EIO;
2413                 goto finish;
2414         }
2415
2416         fputs(text, stdout);
2417
2418         r = 0;
2419
2420 finish:
2421         if (m)
2422                 dbus_message_unref(m);
2423
2424         if (reply)
2425                 dbus_message_unref(reply);
2426
2427         dbus_error_free(&error);
2428
2429         return r;
2430 }
2431
2432 static int snapshot(DBusConnection *bus, char **args, unsigned n) {
2433         DBusMessage *m = NULL, *reply = NULL;
2434         DBusError error;
2435         int r;
2436         const char *name = "", *path, *id;
2437         dbus_bool_t cleanup = FALSE;
2438         DBusMessageIter iter, sub;
2439         const char
2440                 *interface = "org.freedesktop.systemd1.Unit",
2441                 *property = "Id";
2442
2443         dbus_error_init(&error);
2444
2445         if (!(m = dbus_message_new_method_call(
2446                               "org.freedesktop.systemd1",
2447                               "/org/freedesktop/systemd1",
2448                               "org.freedesktop.systemd1.Manager",
2449                               "CreateSnapshot"))) {
2450                 log_error("Could not allocate message.");
2451                 return -ENOMEM;
2452         }
2453
2454         if (n > 1)
2455                 name = args[1];
2456
2457         if (!dbus_message_append_args(m,
2458                                       DBUS_TYPE_STRING, &name,
2459                                       DBUS_TYPE_BOOLEAN, &cleanup,
2460                                       DBUS_TYPE_INVALID)) {
2461                 log_error("Could not append arguments to message.");
2462                 r = -ENOMEM;
2463                 goto finish;
2464         }
2465
2466         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2467                 log_error("Failed to issue method call: %s", error.message);
2468                 r = -EIO;
2469                 goto finish;
2470         }
2471
2472         if (!dbus_message_get_args(reply, &error,
2473                                    DBUS_TYPE_OBJECT_PATH, &path,
2474                                    DBUS_TYPE_INVALID)) {
2475                 log_error("Failed to parse reply: %s", error.message);
2476                 r = -EIO;
2477                 goto finish;
2478         }
2479
2480         dbus_message_unref(m);
2481         if (!(m = dbus_message_new_method_call(
2482                               "org.freedesktop.systemd1",
2483                               path,
2484                               "org.freedesktop.DBus.Properties",
2485                               "Get"))) {
2486                 log_error("Could not allocate message.");
2487                 return -ENOMEM;
2488         }
2489
2490         if (!dbus_message_append_args(m,
2491                                       DBUS_TYPE_STRING, &interface,
2492                                       DBUS_TYPE_STRING, &property,
2493                                       DBUS_TYPE_INVALID)) {
2494                 log_error("Could not append arguments to message.");
2495                 r = -ENOMEM;
2496                 goto finish;
2497         }
2498
2499         dbus_message_unref(reply);
2500         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2501                 log_error("Failed to issue method call: %s", error.message);
2502                 r = -EIO;
2503                 goto finish;
2504         }
2505
2506         if (!dbus_message_iter_init(reply, &iter) ||
2507             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
2508                 log_error("Failed to parse reply.");
2509                 r = -EIO;
2510                 goto finish;
2511         }
2512
2513         dbus_message_iter_recurse(&iter, &sub);
2514
2515         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
2516                 log_error("Failed to parse reply.");
2517                 r = -EIO;
2518                 goto finish;
2519         }
2520
2521         dbus_message_iter_get_basic(&sub, &id);
2522
2523         if (!arg_quiet)
2524                 puts(id);
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 delete_snapshot(DBusConnection *bus, char **args, unsigned n) {
2540         DBusMessage *m = NULL, *reply = NULL;
2541         int r;
2542         DBusError error;
2543         unsigned i;
2544
2545         assert(bus);
2546         assert(args);
2547
2548         dbus_error_init(&error);
2549
2550         for (i = 1; i < n; i++) {
2551                 const char *path = NULL;
2552
2553                 if (!(m = dbus_message_new_method_call(
2554                                       "org.freedesktop.systemd1",
2555                                       "/org/freedesktop/systemd1",
2556                                       "org.freedesktop.systemd1.Manager",
2557                                       "GetUnit"))) {
2558                         log_error("Could not allocate message.");
2559                         r = -ENOMEM;
2560                         goto finish;
2561                 }
2562
2563                 if (!dbus_message_append_args(m,
2564                                               DBUS_TYPE_STRING, &args[i],
2565                                               DBUS_TYPE_INVALID)) {
2566                         log_error("Could not append arguments to message.");
2567                         r = -ENOMEM;
2568                         goto finish;
2569                 }
2570
2571                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2572                         log_error("Failed to issue method call: %s", error.message);
2573                         r = -EIO;
2574                         goto finish;
2575                 }
2576
2577                 if (!dbus_message_get_args(reply, &error,
2578                                            DBUS_TYPE_OBJECT_PATH, &path,
2579                                            DBUS_TYPE_INVALID)) {
2580                         log_error("Failed to parse reply: %s", error.message);
2581                         r = -EIO;
2582                         goto finish;
2583                 }
2584
2585                 dbus_message_unref(m);
2586                 if (!(m = dbus_message_new_method_call(
2587                                       "org.freedesktop.systemd1",
2588                                       path,
2589                                       "org.freedesktop.systemd1.Snapshot",
2590                                       "Remove"))) {
2591                         log_error("Could not allocate message.");
2592                         r = -ENOMEM;
2593                         goto finish;
2594                 }
2595
2596                 dbus_message_unref(reply);
2597                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2598                         log_error("Failed to issue method call: %s", error.message);
2599                         r = -EIO;
2600                         goto finish;
2601                 }
2602
2603                 dbus_message_unref(m);
2604                 dbus_message_unref(reply);
2605                 m = reply = NULL;
2606         }
2607
2608         r = 0;
2609
2610 finish:
2611         if (m)
2612                 dbus_message_unref(m);
2613
2614         if (reply)
2615                 dbus_message_unref(reply);
2616
2617         dbus_error_free(&error);
2618
2619         return r;
2620 }
2621
2622 static int clear_jobs(DBusConnection *bus, char **args, unsigned n) {
2623         DBusMessage *m = NULL, *reply = NULL;
2624         DBusError error;
2625         int r;
2626         const char *method;
2627
2628         dbus_error_init(&error);
2629
2630         if (arg_action == ACTION_RELOAD)
2631                 method = "Reload";
2632         else if (arg_action == ACTION_REEXEC)
2633                 method = "Reexecute";
2634         else {
2635                 assert(arg_action == ACTION_SYSTEMCTL);
2636
2637                 method =
2638                         streq(args[0], "clear-jobs")    ? "ClearJobs" :
2639                         streq(args[0], "daemon-reload") ? "Reload" :
2640                         streq(args[0], "daemon-reexec") ? "Reexecute" :
2641                                                           "Exit";
2642         }
2643
2644         if (!(m = dbus_message_new_method_call(
2645                               "org.freedesktop.systemd1",
2646                               "/org/freedesktop/systemd1",
2647                               "org.freedesktop.systemd1.Manager",
2648                               method))) {
2649                 log_error("Could not allocate message.");
2650                 return -ENOMEM;
2651         }
2652
2653         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2654
2655                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
2656                         /* There's always a fallback possible for
2657                          * legacy actions. */
2658                         r = 0;
2659                         goto finish;
2660                 }
2661
2662                 log_error("Failed to issue method call: %s", error.message);
2663                 r = -EIO;
2664                 goto finish;
2665         }
2666
2667         r = 1;
2668
2669 finish:
2670         if (m)
2671                 dbus_message_unref(m);
2672
2673         if (reply)
2674                 dbus_message_unref(reply);
2675
2676         dbus_error_free(&error);
2677
2678         return r;
2679 }
2680
2681 static int show_enviroment(DBusConnection *bus, char **args, unsigned n) {
2682         DBusMessage *m = NULL, *reply = NULL;
2683         DBusError error;
2684         DBusMessageIter iter, sub, sub2;
2685         int r;
2686         const char
2687                 *interface = "org.freedesktop.systemd1.Manager",
2688                 *property = "Environment";
2689
2690         dbus_error_init(&error);
2691
2692         if (!(m = dbus_message_new_method_call(
2693                               "org.freedesktop.systemd1",
2694                               "/org/freedesktop/systemd1",
2695                               "org.freedesktop.DBus.Properties",
2696                               "Get"))) {
2697                 log_error("Could not allocate message.");
2698                 return -ENOMEM;
2699         }
2700
2701         if (!dbus_message_append_args(m,
2702                                       DBUS_TYPE_STRING, &interface,
2703                                       DBUS_TYPE_STRING, &property,
2704                                       DBUS_TYPE_INVALID)) {
2705                 log_error("Could not append arguments to message.");
2706                 r = -ENOMEM;
2707                 goto finish;
2708         }
2709
2710         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2711                 log_error("Failed to issue method call: %s", error.message);
2712                 r = -EIO;
2713                 goto finish;
2714         }
2715
2716         if (!dbus_message_iter_init(reply, &iter) ||
2717             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
2718                 log_error("Failed to parse reply.");
2719                 r = -EIO;
2720                 goto finish;
2721         }
2722
2723         dbus_message_iter_recurse(&iter, &sub);
2724
2725         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
2726             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
2727                 log_error("Failed to parse reply.");
2728                 r = -EIO;
2729                 goto finish;
2730         }
2731
2732         dbus_message_iter_recurse(&sub, &sub2);
2733
2734         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
2735                 const char *text;
2736
2737                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
2738                         log_error("Failed to parse reply.");
2739                         r = -EIO;
2740                         goto finish;
2741                 }
2742
2743                 dbus_message_iter_get_basic(&sub2, &text);
2744                 printf("%s\n", text);
2745
2746                 dbus_message_iter_next(&sub2);
2747         }
2748
2749         r = 0;
2750
2751 finish:
2752         if (m)
2753                 dbus_message_unref(m);
2754
2755         if (reply)
2756                 dbus_message_unref(reply);
2757
2758         dbus_error_free(&error);
2759
2760         return r;
2761 }
2762
2763 static int set_environment(DBusConnection *bus, char **args, unsigned n) {
2764         DBusMessage *m = NULL, *reply = NULL;
2765         DBusError error;
2766         int r;
2767         const char *method;
2768         DBusMessageIter iter, sub;
2769         unsigned i;
2770
2771         dbus_error_init(&error);
2772
2773         method = streq(args[0], "set-environment")
2774                 ? "SetEnvironment"
2775                 : "UnsetEnvironment";
2776
2777         if (!(m = dbus_message_new_method_call(
2778                               "org.freedesktop.systemd1",
2779                               "/org/freedesktop/systemd1",
2780                               "org.freedesktop.systemd1.Manager",
2781                               method))) {
2782
2783                 log_error("Could not allocate message.");
2784                 return -ENOMEM;
2785         }
2786
2787         dbus_message_iter_init_append(m, &iter);
2788
2789         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
2790                 log_error("Could not append arguments to message.");
2791                 r = -ENOMEM;
2792                 goto finish;
2793         }
2794
2795         for (i = 1; i < n; i++)
2796                 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &args[i])) {
2797                         log_error("Could not append arguments to message.");
2798                         r = -ENOMEM;
2799                         goto finish;
2800                 }
2801
2802         if (!dbus_message_iter_close_container(&iter, &sub)) {
2803                 log_error("Could not append arguments to message.");
2804                 r = -ENOMEM;
2805                 goto finish;
2806         }
2807
2808         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2809                 log_error("Failed to issue method call: %s", error.message);
2810                 r = -EIO;
2811                 goto finish;
2812         }
2813
2814         r = 0;
2815
2816 finish:
2817         if (m)
2818                 dbus_message_unref(m);
2819
2820         if (reply)
2821                 dbus_message_unref(reply);
2822
2823         dbus_error_free(&error);
2824
2825         return r;
2826 }
2827
2828 static int systemctl_help(void) {
2829
2830         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
2831                "Send control commands to the systemd manager.\n\n"
2832                "  -h --help          Show this help\n"
2833                "  -t --type=TYPE     List only units of a particular type\n"
2834                "  -p --property=NAME Show only properties by this name\n"
2835                "  -a --all           Show all units/properties, including dead/empty ones\n"
2836                "     --fail          When installing a new job, fail if conflicting jobs are\n"
2837                "                     pending\n"
2838                "     --system        Connect to system bus\n"
2839                "     --session       Connect to session bus\n"
2840                "     --order         When generating graph for dot, show only order\n"
2841                "     --require        When generating graph for dot, show only requirement\n"
2842                "  -q --quiet         Suppress output\n"
2843                "     --no-block      Do not wait until operation finished\n"
2844                "     --no-wall       Don't send wall message before halt/power-off/reboot\n\n"
2845                "Commands:\n"
2846                "  list-units                      List units\n"
2847                "  start [NAME...]                 Start one or more units\n"
2848                "  stop [NAME...]                  Stop one or more units\n"
2849                "  reload [NAME...]                Reload one or more units\n"
2850                "  restart [NAME...]               Start or restart one or more units\n"
2851                "  try-restart [NAME...]           Restart one or more units if active\n"
2852                "  reload-or-restart [NAME...]     Reload one or more units is possible,\n"
2853                "                                  otherwise start or restart\n"
2854                "  reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
2855                "                                  otherwise restart if active\n"
2856                "  isolate [NAME]                  Start one unit and stop all others\n"
2857                "  check [NAME...]                 Check whether units are active\n"
2858                "  status [NAME...]                Show status of one or more units\n"
2859                "  show [NAME...|JOB...]           Show properties of one or more\n"
2860                "                                  units/jobs/manager\n"
2861                "  load [NAME...]                  Load one or more units\n"
2862                "  list-jobs                       List jobs\n"
2863                "  cancel [JOB...]                 Cancel one or more jobs\n"
2864                "  clear-jobs                      Cancel all jobs\n"
2865                "  monitor                         Monitor unit/job changes\n"
2866                "  dump                            Dump server status\n"
2867                "  dot                             Dump dependency graph for dot(1)\n"
2868                "  snapshot [NAME]                 Create a snapshot\n"
2869                "  delete [NAME...]                Remove one or more snapshots\n"
2870                "  daemon-reload                   Reload systemd manager configuration\n"
2871                "  daemon-reexec                   Reexecute systemd manager\n"
2872                "  daemon-exit                     Ask the systemd manager to quit\n"
2873                "  show-environment                Dump environment\n"
2874                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
2875                "  unset-environment [NAME...]     Unset one or more environment variables\n"
2876                "  halt                            Shut down and halt the system\n"
2877                "  poweroff                        Shut down and power-off the system\n"
2878                "  reboot                          Shut down and reboot the system\n"
2879                "  rescue                          Enter system rescue mode\n"
2880                "  emergency                       Enter system emergency mode\n"
2881                "  default                         Enter system default mode\n",
2882                program_invocation_short_name);
2883
2884         return 0;
2885 }
2886
2887 static int halt_help(void) {
2888
2889         printf("%s [OPTIONS...]\n\n"
2890                "%s the system.\n\n"
2891                "     --help      Show this help\n"
2892                "     --halt      Halt the machine\n"
2893                "  -p --poweroff  Switch off the machine\n"
2894                "     --reboot    Reboot the machine\n"
2895                "  -f --force     Force immediate halt/power-off/reboot\n"
2896                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
2897                "  -d --no-wtmp   Don't write wtmp record\n"
2898                "  -n --no-sync   Don't sync before halt/power-off/reboot\n"
2899                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
2900                program_invocation_short_name,
2901                arg_action == ACTION_REBOOT   ? "Reboot" :
2902                arg_action == ACTION_POWEROFF ? "Power off" :
2903                                                "Halt");
2904
2905         return 0;
2906 }
2907
2908 static int shutdown_help(void) {
2909
2910         printf("%s [OPTIONS...] [now] [WALL...]\n\n"
2911                "Shut down the system.\n\n"
2912                "     --help      Show this help\n"
2913                "  -H --halt      Halt the machine\n"
2914                "  -P --poweroff  Power-off the machine\n"
2915                "  -r --reboot    Reboot the machine\n"
2916                "  -h             Equivalent to --poweroff, overriden by --halt\n"
2917                "  -k             Don't halt/power-off/reboot, just send warnings\n"
2918                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
2919                program_invocation_short_name);
2920
2921         return 0;
2922 }
2923
2924 static int telinit_help(void) {
2925
2926         printf("%s [OPTIONS...] {COMMAND}\n\n"
2927                "Send control commands to the init daemon.\n\n"
2928                "     --help      Show this help\n"
2929                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
2930                "Commands:\n"
2931                "  0              Power-off the machine\n"
2932                "  6              Reboot the machine\n"
2933                "  2, 3, 4, 5     Start runlevelX.target unit\n"
2934                "  1, s, S        Enter rescue mode\n"
2935                "  q, Q           Reload init daemon configuration\n"
2936                "  u, U           Reexecute init daemon\n",
2937                program_invocation_short_name);
2938
2939         return 0;
2940 }
2941
2942 static int runlevel_help(void) {
2943
2944         printf("%s [OPTIONS...]\n\n"
2945                "Prints the previous and current runlevel of the init system.\n\n"
2946                "     --help      Show this help\n",
2947                program_invocation_short_name);
2948
2949         return 0;
2950 }
2951
2952 static int systemctl_parse_argv(int argc, char *argv[]) {
2953
2954         enum {
2955                 ARG_FAIL = 0x100,
2956                 ARG_SESSION,
2957                 ARG_SYSTEM,
2958                 ARG_NO_BLOCK,
2959                 ARG_NO_WALL,
2960                 ARG_ORDER,
2961                 ARG_REQUIRE
2962         };
2963
2964         static const struct option options[] = {
2965                 { "help",      no_argument,       NULL, 'h'          },
2966                 { "type",      required_argument, NULL, 't'          },
2967                 { "property",  required_argument, NULL, 'p'          },
2968                 { "all",       no_argument,       NULL, 'a'          },
2969                 { "fail",      no_argument,       NULL, ARG_FAIL     },
2970                 { "session",   no_argument,       NULL, ARG_SESSION  },
2971                 { "system",    no_argument,       NULL, ARG_SYSTEM   },
2972                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK },
2973                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL  },
2974                 { "quiet",     no_argument,       NULL, 'q'          },
2975                 { "order",     no_argument,       NULL, ARG_ORDER    },
2976                 { "require",   no_argument,       NULL, ARG_REQUIRE  },
2977                 { NULL,        0,                 NULL, 0            }
2978         };
2979
2980         int c;
2981
2982         assert(argc >= 0);
2983         assert(argv);
2984
2985         while ((c = getopt_long(argc, argv, "ht:p:aq", options, NULL)) >= 0) {
2986
2987                 switch (c) {
2988
2989                 case 'h':
2990                         systemctl_help();
2991                         return 0;
2992
2993                 case 't':
2994                         arg_type = optarg;
2995                         break;
2996
2997                 case 'p':
2998                         arg_property = optarg;
2999
3000                         /* If the user asked for a particular
3001                          * property, show it to him, even if it is
3002                          * empty. */
3003                         arg_all = true;
3004                         break;
3005
3006                 case 'a':
3007                         arg_all = true;
3008                         break;
3009
3010                 case ARG_FAIL:
3011                         arg_fail = true;
3012                         break;
3013
3014                 case ARG_SESSION:
3015                         arg_session = true;
3016                         break;
3017
3018                 case ARG_SYSTEM:
3019                         arg_session = false;
3020                         break;
3021
3022                 case ARG_NO_BLOCK:
3023                         arg_no_block = true;
3024                         break;
3025
3026                 case ARG_NO_WALL:
3027                         arg_no_wall = true;
3028                         break;
3029
3030                 case ARG_ORDER:
3031                         arg_dot = DOT_ORDER;
3032                         break;
3033
3034                 case ARG_REQUIRE:
3035                         arg_dot = DOT_REQUIRE;
3036                         break;
3037
3038                 case 'q':
3039                         arg_quiet = true;
3040                         break;
3041
3042                 case '?':
3043                         return -EINVAL;
3044
3045                 default:
3046                         log_error("Unknown option code %c", c);
3047                         return -EINVAL;
3048                 }
3049         }
3050
3051         return 1;
3052 }
3053
3054 static int halt_parse_argv(int argc, char *argv[]) {
3055
3056         enum {
3057                 ARG_HELP = 0x100,
3058                 ARG_HALT,
3059                 ARG_REBOOT,
3060                 ARG_NO_WALL
3061         };
3062
3063         static const struct option options[] = {
3064                 { "help",      no_argument,       NULL, ARG_HELP    },
3065                 { "halt",      no_argument,       NULL, ARG_HALT    },
3066                 { "poweroff",  no_argument,       NULL, 'p'         },
3067                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
3068                 { "force",     no_argument,       NULL, 'f'         },
3069                 { "wtmp-only", no_argument,       NULL, 'w'         },
3070                 { "no-wtmp",   no_argument,       NULL, 'd'         },
3071                 { "no-sync",   no_argument,       NULL, 'n'         },
3072                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
3073                 { NULL,        0,                 NULL, 0           }
3074         };
3075
3076         int c, runlevel;
3077
3078         assert(argc >= 0);
3079         assert(argv);
3080
3081         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
3082                 if (runlevel == '0' || runlevel == '6')
3083                         arg_immediate = true;
3084
3085         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
3086                 switch (c) {
3087
3088                 case ARG_HELP:
3089                         halt_help();
3090                         return 0;
3091
3092                 case ARG_HALT:
3093                         arg_action = ACTION_HALT;
3094                         break;
3095
3096                 case 'p':
3097                         arg_action = ACTION_POWEROFF;
3098                         break;
3099
3100                 case ARG_REBOOT:
3101                         arg_action = ACTION_REBOOT;
3102                         break;
3103
3104                 case 'f':
3105                         arg_immediate = true;
3106                         break;
3107
3108                 case 'w':
3109                         arg_dry = true;
3110                         break;
3111
3112                 case 'd':
3113                         arg_no_wtmp = true;
3114                         break;
3115
3116                 case 'n':
3117                         arg_no_sync = true;
3118                         break;
3119
3120                 case ARG_NO_WALL:
3121                         arg_no_wall = true;
3122                         break;
3123
3124                 case 'i':
3125                 case 'h':
3126                         /* Compatibility nops */
3127                         break;
3128
3129                 case '?':
3130                         return -EINVAL;
3131
3132                 default:
3133                         log_error("Unknown option code %c", c);
3134                         return -EINVAL;
3135                 }
3136         }
3137
3138         if (optind < argc) {
3139                 log_error("Too many arguments.");
3140                 return -EINVAL;
3141         }
3142
3143         return 1;
3144 }
3145
3146 static int shutdown_parse_argv(int argc, char *argv[]) {
3147
3148         enum {
3149                 ARG_HELP = 0x100,
3150                 ARG_NO_WALL
3151         };
3152
3153         static const struct option options[] = {
3154                 { "help",      no_argument,       NULL, ARG_HELP    },
3155                 { "halt",      no_argument,       NULL, 'H'         },
3156                 { "poweroff",  no_argument,       NULL, 'P'         },
3157                 { "reboot",    no_argument,       NULL, 'r'         },
3158                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
3159                 { NULL,        0,                 NULL, 0           }
3160         };
3161
3162         int c;
3163
3164         assert(argc >= 0);
3165         assert(argv);
3166
3167         while ((c = getopt_long(argc, argv, "HPrhkt:a", options, NULL)) >= 0) {
3168                 switch (c) {
3169
3170                 case ARG_HELP:
3171                         shutdown_help();
3172                         return 0;
3173
3174                 case 'H':
3175                         arg_action = ACTION_HALT;
3176                         break;
3177
3178                 case 'P':
3179                         arg_action = ACTION_POWEROFF;
3180                         break;
3181
3182                 case 'r':
3183                         arg_action = ACTION_REBOOT;
3184                         break;
3185
3186                 case 'h':
3187                         if (arg_action != ACTION_HALT)
3188                                 arg_action = ACTION_POWEROFF;
3189                         break;
3190
3191                 case 'k':
3192                         arg_dry = true;
3193                         break;
3194
3195                 case ARG_NO_WALL:
3196                         arg_no_wall = true;
3197                         break;
3198
3199                 case 't':
3200                 case 'a':
3201                         /* Compatibility nops */
3202                         break;
3203
3204                 case '?':
3205                         return -EINVAL;
3206
3207                 default:
3208                         log_error("Unknown option code %c", c);
3209                         return -EINVAL;
3210                 }
3211         }
3212
3213         if (argc > optind && !streq(argv[optind], "now"))
3214                 log_warning("First argument '%s' isn't 'now'. Ignoring.", argv[optind]);
3215
3216         /* We ignore the time argument */
3217         if (argc > optind + 1)
3218                 arg_wall = argv + optind + 1;
3219
3220         optind = argc;
3221
3222         return 1;
3223 }
3224
3225 static int telinit_parse_argv(int argc, char *argv[]) {
3226
3227         enum {
3228                 ARG_HELP = 0x100,
3229                 ARG_NO_WALL
3230         };
3231
3232         static const struct option options[] = {
3233                 { "help",      no_argument,       NULL, ARG_HELP    },
3234                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
3235                 { NULL,        0,                 NULL, 0           }
3236         };
3237
3238         static const struct {
3239                 char from;
3240                 enum action to;
3241         } table[] = {
3242                 { '0', ACTION_POWEROFF },
3243                 { '6', ACTION_REBOOT },
3244                 { '1', ACTION_RESCUE },
3245                 { '2', ACTION_RUNLEVEL2 },
3246                 { '3', ACTION_RUNLEVEL3 },
3247                 { '4', ACTION_RUNLEVEL4 },
3248                 { '5', ACTION_RUNLEVEL5 },
3249                 { 's', ACTION_RESCUE },
3250                 { 'S', ACTION_RESCUE },
3251                 { 'q', ACTION_RELOAD },
3252                 { 'Q', ACTION_RELOAD },
3253                 { 'u', ACTION_REEXEC },
3254                 { 'U', ACTION_REEXEC }
3255         };
3256
3257         unsigned i;
3258         int c;
3259
3260         assert(argc >= 0);
3261         assert(argv);
3262
3263         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
3264                 switch (c) {
3265
3266                 case ARG_HELP:
3267                         telinit_help();
3268                         return 0;
3269
3270                 case ARG_NO_WALL:
3271                         arg_no_wall = true;
3272                         break;
3273
3274                 case '?':
3275                         return -EINVAL;
3276
3277                 default:
3278                         log_error("Unknown option code %c", c);
3279                         return -EINVAL;
3280                 }
3281         }
3282
3283         if (optind >= argc) {
3284                 telinit_help();
3285                 return -EINVAL;
3286         }
3287
3288         if (optind + 1 < argc) {
3289                 log_error("Too many arguments.");
3290                 return -EINVAL;
3291         }
3292
3293         if (strlen(argv[optind]) != 1) {
3294                 log_error("Expected single character argument.");
3295                 return -EINVAL;
3296         }
3297
3298         for (i = 0; i < ELEMENTSOF(table); i++)
3299                 if (table[i].from == argv[optind][0])
3300                         break;
3301
3302         if (i >= ELEMENTSOF(table)) {
3303                 log_error("Unknown command %s.", argv[optind]);
3304                 return -EINVAL;
3305         }
3306
3307         arg_action = table[i].to;
3308
3309         optind ++;
3310
3311         return 1;
3312 }
3313
3314 static int runlevel_parse_argv(int argc, char *argv[]) {
3315
3316         enum {
3317                 ARG_HELP = 0x100,
3318         };
3319
3320         static const struct option options[] = {
3321                 { "help",      no_argument,       NULL, ARG_HELP    },
3322                 { NULL,        0,                 NULL, 0           }
3323         };
3324
3325         int c;
3326
3327         assert(argc >= 0);
3328         assert(argv);
3329
3330         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
3331                 switch (c) {
3332
3333                 case ARG_HELP:
3334                         runlevel_help();
3335                         return 0;
3336
3337                 case '?':
3338                         return -EINVAL;
3339
3340                 default:
3341                         log_error("Unknown option code %c", c);
3342                         return -EINVAL;
3343                 }
3344         }
3345
3346         if (optind < argc) {
3347                 log_error("Too many arguments.");
3348                 return -EINVAL;
3349         }
3350
3351         return 1;
3352 }
3353
3354 static int parse_argv(int argc, char *argv[]) {
3355         assert(argc >= 0);
3356         assert(argv);
3357
3358         if (program_invocation_short_name) {
3359
3360                 if (strstr(program_invocation_short_name, "halt")) {
3361                         arg_action = ACTION_HALT;
3362                         return halt_parse_argv(argc, argv);
3363                 } else if (strstr(program_invocation_short_name, "poweroff")) {
3364                         arg_action = ACTION_POWEROFF;
3365                         return halt_parse_argv(argc, argv);
3366                 } else if (strstr(program_invocation_short_name, "reboot")) {
3367                         arg_action = ACTION_REBOOT;
3368                         return halt_parse_argv(argc, argv);
3369                 } else if (strstr(program_invocation_short_name, "shutdown")) {
3370                         arg_action = ACTION_POWEROFF;
3371                         return shutdown_parse_argv(argc, argv);
3372                 } else if (strstr(program_invocation_short_name, "init")) {
3373                         arg_action = ACTION_INVALID;
3374                         return telinit_parse_argv(argc, argv);
3375                 } else if (strstr(program_invocation_short_name, "runlevel")) {
3376                         arg_action = ACTION_RUNLEVEL;
3377                         return runlevel_parse_argv(argc, argv);
3378                 }
3379         }
3380
3381         arg_action = ACTION_SYSTEMCTL;
3382         return systemctl_parse_argv(argc, argv);
3383 }
3384
3385 static int action_to_runlevel(void) {
3386
3387         static const char table[_ACTION_MAX] = {
3388                 [ACTION_HALT] =      '0',
3389                 [ACTION_POWEROFF] =  '0',
3390                 [ACTION_REBOOT] =    '6',
3391                 [ACTION_RUNLEVEL2] = '2',
3392                 [ACTION_RUNLEVEL3] = '3',
3393                 [ACTION_RUNLEVEL4] = '4',
3394                 [ACTION_RUNLEVEL5] = '5',
3395                 [ACTION_RESCUE] =    '1'
3396         };
3397
3398         assert(arg_action < _ACTION_MAX);
3399
3400         return table[arg_action];
3401 }
3402
3403 static int talk_upstart(void) {
3404         DBusMessage *m = NULL, *reply = NULL;
3405         DBusError error;
3406         int previous, rl, r;
3407         char
3408                 env1_buf[] = "RUNLEVEL=X",
3409                 env2_buf[] = "PREVLEVEL=X";
3410         char *env1 = env1_buf, *env2 = env2_buf;
3411         const char *emit = "runlevel";
3412         dbus_bool_t b_false = FALSE;
3413         DBusMessageIter iter, sub;
3414         DBusConnection *bus;
3415
3416         dbus_error_init(&error);
3417
3418         if (!(rl = action_to_runlevel()))
3419                 return 0;
3420
3421         if (utmp_get_runlevel(&previous, NULL) < 0)
3422                 previous = 'N';
3423
3424         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
3425                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
3426                         r = 0;
3427                         goto finish;
3428                 }
3429
3430                 log_error("Failed to connect to Upstart bus: %s", error.message);
3431                 r = -EIO;
3432                 goto finish;
3433         }
3434
3435         if ((r = bus_check_peercred(bus)) < 0) {
3436                 log_error("Failed to verify owner of bus.");
3437                 goto finish;
3438         }
3439
3440         if (!(m = dbus_message_new_method_call(
3441                               "com.ubuntu.Upstart",
3442                               "/com/ubuntu/Upstart",
3443                               "com.ubuntu.Upstart0_6",
3444                               "EmitEvent"))) {
3445
3446                 log_error("Could not allocate message.");
3447                 r = -ENOMEM;
3448                 goto finish;
3449         }
3450
3451         dbus_message_iter_init_append(m, &iter);
3452
3453         env1_buf[sizeof(env1_buf)-2] = rl;
3454         env2_buf[sizeof(env2_buf)-2] = previous;
3455
3456         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
3457             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
3458             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
3459             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
3460             !dbus_message_iter_close_container(&iter, &sub) ||
3461             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
3462                 log_error("Could not append arguments to message.");
3463                 r = -ENOMEM;
3464                 goto finish;
3465         }
3466
3467         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3468
3469                 if (error_is_no_service(&error)) {
3470                         r = 0;
3471                         goto finish;
3472                 }
3473
3474                 log_error("Failed to issue method call: %s", error.message);
3475                 r = -EIO;
3476                 goto finish;
3477         }
3478
3479         r = 1;
3480
3481 finish:
3482         if (m)
3483                 dbus_message_unref(m);
3484
3485         if (reply)
3486                 dbus_message_unref(reply);
3487
3488         if (bus) {
3489                 dbus_connection_close(bus);
3490                 dbus_connection_unref(bus);
3491         }
3492
3493         dbus_error_free(&error);
3494
3495         return r;
3496 }
3497
3498 static int talk_initctl(void) {
3499         struct init_request request;
3500         int r, fd;
3501         char rl;
3502
3503         if (!(rl = action_to_runlevel()))
3504                 return 0;
3505
3506         zero(request);
3507         request.magic = INIT_MAGIC;
3508         request.sleeptime = 0;
3509         request.cmd = INIT_CMD_RUNLVL;
3510         request.runlevel = rl;
3511
3512         if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
3513
3514                 if (errno == ENOENT)
3515                         return 0;
3516
3517                 log_error("Failed to open "INIT_FIFO": %m");
3518                 return -errno;
3519         }
3520
3521         errno = 0;
3522         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
3523         close_nointr_nofail(fd);
3524
3525         if (r < 0) {
3526                 log_error("Failed to write to "INIT_FIFO": %m");
3527                 return errno ? -errno : -EIO;
3528         }
3529
3530         return 1;
3531 }
3532
3533 static int systemctl_main(DBusConnection *bus, int argc, char *argv[]) {
3534
3535         static const struct {
3536                 const char* verb;
3537                 const enum {
3538                         MORE,
3539                         LESS,
3540                         EQUAL
3541                 } argc_cmp;
3542                 const int argc;
3543                 int (* const dispatch)(DBusConnection *bus, char **args, unsigned n);
3544         } verbs[] = {
3545                 { "list-units",        LESS,  1, list_units      },
3546                 { "list-jobs",         EQUAL, 1, list_jobs       },
3547                 { "clear-jobs",        EQUAL, 1, clear_jobs      },
3548                 { "load",              MORE,  2, load_unit       },
3549                 { "cancel",            MORE,  2, cancel_job      },
3550                 { "start",             MORE,  2, start_unit      },
3551                 { "stop",              MORE,  2, start_unit      },
3552                 { "reload",            MORE,  2, start_unit      },
3553                 { "restart",           MORE,  2, start_unit      },
3554                 { "try-restart",       MORE,  2, start_unit      },
3555                 { "reload-or-restart", MORE,  2, start_unit      },
3556                 { "reload-or-try-restart", MORE, 2, start_unit   },
3557                 { "isolate",           EQUAL, 2, start_unit      },
3558                 { "check",             MORE,  2, check_unit      },
3559                 { "show",              MORE,  1, show            },
3560                 { "status",            MORE,  2, show            },
3561                 { "monitor",           EQUAL, 1, monitor         },
3562                 { "dump",              EQUAL, 1, dump            },
3563                 { "dot",               EQUAL, 1, dot             },
3564                 { "snapshot",          LESS,  2, snapshot        },
3565                 { "delete",            MORE,  2, delete_snapshot },
3566                 { "daemon-reload",     EQUAL, 1, clear_jobs      },
3567                 { "daemon-reexec",     EQUAL, 1, clear_jobs      },
3568                 { "daemon-exit",       EQUAL, 1, clear_jobs      },
3569                 { "show-environment",  EQUAL, 1, show_enviroment },
3570                 { "set-environment",   MORE,  2, set_environment },
3571                 { "unset-environment", MORE,  2, set_environment },
3572                 { "halt",              EQUAL, 1, start_special   },
3573                 { "poweroff",          EQUAL, 1, start_special   },
3574                 { "reboot",            EQUAL, 1, start_special   },
3575                 { "default",           EQUAL, 1, start_special   },
3576                 { "rescue",            EQUAL, 1, start_special   },
3577                 { "emergency",         EQUAL, 1, start_special   },
3578         };
3579
3580         int left;
3581         unsigned i;
3582
3583         assert(bus);
3584         assert(argc >= 0);
3585         assert(argv);
3586
3587         left = argc - optind;
3588
3589         if (left <= 0)
3590                 /* Special rule: no arguments means "list-units" */
3591                 i = 0;
3592         else {
3593                 if (streq(argv[optind], "help")) {
3594                         systemctl_help();
3595                         return 0;
3596                 }
3597
3598                 for (i = 0; i < ELEMENTSOF(verbs); i++)
3599                         if (streq(argv[optind], verbs[i].verb))
3600                                 break;
3601
3602                 if (i >= ELEMENTSOF(verbs)) {
3603                         log_error("Unknown operation %s", argv[optind]);
3604                         return -EINVAL;
3605                 }
3606         }
3607
3608         switch (verbs[i].argc_cmp) {
3609
3610         case EQUAL:
3611                 if (left != verbs[i].argc) {
3612                         log_error("Invalid number of arguments.");
3613                         return -EINVAL;
3614                 }
3615
3616                 break;
3617
3618         case MORE:
3619                 if (left < verbs[i].argc) {
3620                         log_error("Too few arguments.");
3621                         return -EINVAL;
3622                 }
3623
3624                 break;
3625
3626         case LESS:
3627                 if (left > verbs[i].argc) {
3628                         log_error("Too many arguments.");
3629                         return -EINVAL;
3630                 }
3631
3632                 break;
3633
3634         default:
3635                 assert_not_reached("Unknown comparison operator.");
3636         }
3637
3638         return verbs[i].dispatch(bus, argv + optind, left);
3639 }
3640
3641 static int reload_with_fallback(DBusConnection *bus) {
3642         int r;
3643
3644         if (bus) {
3645                 /* First, try systemd via D-Bus. */
3646                 if ((r = clear_jobs(bus, NULL, 0)) > 0)
3647                         return 0;
3648         }
3649
3650         /* Nothing else worked, so let's try signals */
3651         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
3652
3653         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
3654                 log_error("kill() failed: %m");
3655                 return -errno;
3656         }
3657
3658         return 0;
3659 }
3660
3661 static int start_with_fallback(DBusConnection *bus) {
3662         int r;
3663
3664
3665         if (bus) {
3666                 /* First, try systemd via D-Bus. */
3667                 if ((r = start_unit(bus, NULL, 0)) > 0)
3668                         goto done;
3669
3670                 /* Hmm, talking to systemd via D-Bus didn't work. Then
3671                  * let's try to talk to Upstart via D-Bus. */
3672                 if ((r = talk_upstart()) > 0)
3673                         goto done;
3674         }
3675
3676         /* Nothing else worked, so let's try
3677          * /dev/initctl */
3678         if ((r = talk_initctl()) != 0)
3679                 goto done;
3680
3681         log_error("Failed to talk to init daemon.");
3682         return -EIO;
3683
3684 done:
3685         warn_wall(arg_action);
3686         return 0;
3687 }
3688
3689 static int halt_main(DBusConnection *bus) {
3690         int r;
3691
3692         if (geteuid() != 0) {
3693                 log_error("Must to be root.");
3694                 return -EPERM;
3695         }
3696
3697         if (!arg_dry && !arg_immediate)
3698                 return start_with_fallback(bus);
3699
3700         if (!arg_no_wtmp)
3701                 if ((r = utmp_put_shutdown(0)) < 0)
3702                         log_warning("Failed to write utmp record: %s", strerror(-r));
3703
3704         if (!arg_no_sync)
3705                 sync();
3706
3707         if (arg_dry)
3708                 return 0;
3709
3710         /* Make sure C-A-D is handled by the kernel from this
3711          * point on... */
3712         reboot(RB_ENABLE_CAD);
3713
3714         switch (arg_action) {
3715
3716         case ACTION_HALT:
3717                 log_info("Halting");
3718                 reboot(RB_HALT_SYSTEM);
3719                 break;
3720
3721         case ACTION_POWEROFF:
3722                 log_info("Powering off");
3723                 reboot(RB_POWER_OFF);
3724                 break;
3725
3726         case ACTION_REBOOT:
3727                 log_info("Rebooting");
3728                 reboot(RB_AUTOBOOT);
3729                 break;
3730
3731         default:
3732                 assert_not_reached("Unknown halt action.");
3733         }
3734
3735         /* We should never reach this. */
3736         return -ENOSYS;
3737 }
3738
3739 static int runlevel_main(void) {
3740         int r, runlevel, previous;
3741
3742         if ((r = utmp_get_runlevel(&runlevel, &previous)) < 0) {
3743                 printf("unknown");
3744                 return r;
3745         }
3746
3747         printf("%c %c\n",
3748                previous <= 0 ? 'N' : previous,
3749                runlevel <= 0 ? 'N' : runlevel);
3750
3751         return 0;
3752 }
3753
3754 int main(int argc, char*argv[]) {
3755         int r, retval = 1;
3756         DBusConnection *bus = NULL;
3757         DBusError error;
3758
3759         dbus_error_init(&error);
3760
3761         log_parse_environment();
3762
3763         if ((r = parse_argv(argc, argv)) < 0)
3764                 goto finish;
3765         else if (r == 0) {
3766                 retval = 0;
3767                 goto finish;
3768         }
3769
3770         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
3771          * let's shortcut this */
3772         if (arg_action == ACTION_RUNLEVEL) {
3773                 retval = runlevel_main() < 0;
3774                 goto finish;
3775         }
3776
3777         bus_connect(arg_session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, &private_bus, &error);
3778
3779         switch (arg_action) {
3780
3781         case ACTION_SYSTEMCTL: {
3782
3783                 if (!bus) {
3784                         log_error("Failed to get D-Bus connection: %s", error.message);
3785                         goto finish;
3786                 }
3787
3788                 retval = systemctl_main(bus, argc, argv) < 0;
3789                 break;
3790         }
3791
3792         case ACTION_HALT:
3793         case ACTION_POWEROFF:
3794         case ACTION_REBOOT:
3795                 retval = halt_main(bus) < 0;
3796                 break;
3797
3798         case ACTION_RUNLEVEL2:
3799         case ACTION_RUNLEVEL3:
3800         case ACTION_RUNLEVEL4:
3801         case ACTION_RUNLEVEL5:
3802         case ACTION_RESCUE:
3803         case ACTION_EMERGENCY:
3804         case ACTION_DEFAULT:
3805                 retval = start_with_fallback(bus) < 0;
3806                 break;
3807
3808         case ACTION_RELOAD:
3809         case ACTION_REEXEC:
3810                 retval = reload_with_fallback(bus) < 0;
3811                 break;
3812
3813         case ACTION_INVALID:
3814         case ACTION_RUNLEVEL:
3815         default:
3816                 assert_not_reached("Unknown action");
3817         }
3818
3819 finish:
3820
3821         if (bus) {
3822                 dbus_connection_close(bus);
3823                 dbus_connection_unref(bus);
3824         }
3825
3826         dbus_error_free(&error);
3827
3828         dbus_shutdown();
3829
3830         return retval;
3831 }