chiark / gitweb /
systemctl: don't use the systemd bus to talk to upstart
[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 #include <sys/stat.h>
34
35 #include <dbus/dbus.h>
36
37 #include "log.h"
38 #include "util.h"
39 #include "macro.h"
40 #include "set.h"
41 #include "utmp-wtmp.h"
42 #include "special.h"
43 #include "initreq.h"
44 #include "strv.h"
45 #include "dbus-common.h"
46 #include "cgroup-show.h"
47 #include "cgroup-util.h"
48 #include "list.h"
49 #include "path-lookup.h"
50 #include "conf-parser.h"
51 #include "sd-daemon.h"
52
53 static const char *arg_type = NULL;
54 static char **arg_property = NULL;
55 static bool arg_all = false;
56 static bool arg_fail = false;
57 static bool arg_session = false;
58 static bool arg_global = false;
59 static bool arg_immediate = false;
60 static bool arg_no_block = false;
61 static bool arg_no_wtmp = false;
62 static bool arg_no_sync = false;
63 static bool arg_no_wall = false;
64 static bool arg_no_reload = false;
65 static bool arg_dry = false;
66 static bool arg_quiet = false;
67 static bool arg_full = false;
68 static bool arg_force = false;
69 static bool arg_defaults = false;
70 static char **arg_wall = NULL;
71 static enum action {
72         ACTION_INVALID,
73         ACTION_SYSTEMCTL,
74         ACTION_HALT,
75         ACTION_POWEROFF,
76         ACTION_REBOOT,
77         ACTION_RUNLEVEL2,
78         ACTION_RUNLEVEL3,
79         ACTION_RUNLEVEL4,
80         ACTION_RUNLEVEL5,
81         ACTION_RESCUE,
82         ACTION_EMERGENCY,
83         ACTION_DEFAULT,
84         ACTION_RELOAD,
85         ACTION_REEXEC,
86         ACTION_RUNLEVEL,
87         _ACTION_MAX
88 } arg_action = ACTION_SYSTEMCTL;
89 static enum dot {
90         DOT_ALL,
91         DOT_ORDER,
92         DOT_REQUIRE
93 } arg_dot = DOT_ALL;
94
95 static bool private_bus = false;
96
97 static int daemon_reload(DBusConnection *bus, char **args, unsigned n);
98
99 static const char *ansi_highlight(bool b) {
100         static int t = -1;
101
102         if (_unlikely_(t < 0))
103                 t = isatty(STDOUT_FILENO) > 0;
104
105         if (!t)
106                 return "";
107
108         return b ? ANSI_HIGHLIGHT_ON : ANSI_HIGHLIGHT_OFF;
109 }
110
111 static bool error_is_no_service(DBusError *error) {
112
113         assert(error);
114
115         if (!dbus_error_is_set(error))
116                 return false;
117
118         if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER))
119                 return true;
120
121         if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN))
122                 return true;
123
124         return startswith(error->name, "org.freedesktop.DBus.Error.Spawn.");
125 }
126
127 static int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
128
129         assert(iter);
130         assert(data);
131
132         if (dbus_message_iter_get_arg_type(iter) != type)
133                 return -EIO;
134
135         dbus_message_iter_get_basic(iter, data);
136
137         if (!dbus_message_iter_next(iter) != !next)
138                 return -EIO;
139
140         return 0;
141 }
142
143 static void warn_wall(enum action action) {
144         static const char *table[_ACTION_MAX] = {
145                 [ACTION_HALT]      = "The system is going down for system halt NOW!",
146                 [ACTION_REBOOT]    = "The system is going down for reboot NOW!",
147                 [ACTION_POWEROFF]  = "The system is going down for power-off NOW!",
148                 [ACTION_RESCUE]    = "The system is going down to rescue mode NOW!",
149                 [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!"
150         };
151
152         if (arg_no_wall)
153                 return;
154
155         if (arg_wall) {
156                 char *p;
157
158                 if (!(p = strv_join(arg_wall, " "))) {
159                         log_error("Failed to join strings.");
160                         return;
161                 }
162
163                 if (*p) {
164                         utmp_wall(p);
165                         free(p);
166                         return;
167                 }
168
169                 free(p);
170         }
171
172         if (!table[action])
173                 return;
174
175         utmp_wall(table[action]);
176 }
177
178 static int list_units(DBusConnection *bus, char **args, unsigned n) {
179         DBusMessage *m = NULL, *reply = NULL;
180         DBusError error;
181         int r;
182         DBusMessageIter iter, sub, sub2;
183         unsigned k = 0;
184
185         dbus_error_init(&error);
186
187         assert(bus);
188
189         if (!(m = dbus_message_new_method_call(
190                               "org.freedesktop.systemd1",
191                               "/org/freedesktop/systemd1",
192                               "org.freedesktop.systemd1.Manager",
193                               "ListUnits"))) {
194                 log_error("Could not allocate message.");
195                 return -ENOMEM;
196         }
197
198         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
199                 log_error("Failed to issue method call: %s", error.message);
200                 r = -EIO;
201                 goto finish;
202         }
203
204         if (!dbus_message_iter_init(reply, &iter) ||
205             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
206             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
207                 log_error("Failed to parse reply.");
208                 r = -EIO;
209                 goto finish;
210         }
211
212         dbus_message_iter_recurse(&iter, &sub);
213
214         if (isatty(STDOUT_FILENO))
215                 printf("%-45s %-6s %-12s %-12s %-15s %s\n", "UNIT", "LOAD", "ACTIVE", "SUB", "JOB", "DESCRIPTION");
216
217         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
218                 const char *id, *description, *load_state, *active_state, *sub_state, *following, *unit_path, *job_type, *job_path, *dot;
219                 uint32_t job_id;
220
221                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
222                         log_error("Failed to parse reply.");
223                         r = -EIO;
224                         goto finish;
225                 }
226
227                 dbus_message_iter_recurse(&sub, &sub2);
228
229                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
230                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 ||
231                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
232                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
233                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
234                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &following, true) < 0 ||
235                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0 ||
236                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &job_id, true) < 0 ||
237                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &job_type, true) < 0 ||
238                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, false) < 0) {
239                         log_error("Failed to parse reply.");
240                         r = -EIO;
241                         goto finish;
242                 }
243
244                 if ((!arg_type || ((dot = strrchr(id, '.')) &&
245                                    streq(dot+1, arg_type))) &&
246                     (arg_all || !(streq(active_state, "inactive") || following[0]) || job_id > 0)) {
247                         char *e;
248                         int a = 0, b = 0;
249
250                         if (streq(active_state, "maintenance"))
251                                 fputs(ansi_highlight(true), stdout);
252
253                         e = arg_full ? NULL : ellipsize(id, 45, 33);
254                         printf("%-45s %-6s %-12s %-12s%n", e ? e : id, load_state, active_state, sub_state, &a);
255                         free(e);
256
257                         if (job_id != 0)
258                                 printf(" => %-12s%n", job_type, &b);
259                         else
260                                 b = 1 + 15;
261
262                         if (a + b + 2 < columns()) {
263                                 if (job_id == 0)
264                                         printf("                ");
265
266                                 printf(" %.*s", columns() - a - b - 2, description);
267                         }
268
269                         if (streq(active_state, "maintenance"))
270                                 fputs(ansi_highlight(false), stdout);
271
272                         fputs("\n", stdout);
273                         k++;
274                 }
275
276                 dbus_message_iter_next(&sub);
277         }
278
279         if (isatty(STDOUT_FILENO)) {
280
281                 printf("\nLOAD   = Load State, reflects whether the unit configuration was properly loaded.\n"
282                        "ACTIVE = Active State, the high-level unit activation state, i.e. generalization of the substate.\n"
283                        "SUB    = Substate, the low-level unit activation state, possible values depend on unit type.\n"
284                        "JOB    = Job, shows pending jobs for the unit.\n");
285
286                 if (arg_all)
287                         printf("\n%u units listed.\n", k);
288                 else
289                         printf("\n%u units listed. Pass --all to see inactive units, too.\n", k);
290         }
291
292         r = 0;
293
294 finish:
295         if (m)
296                 dbus_message_unref(m);
297
298         if (reply)
299                 dbus_message_unref(reply);
300
301         dbus_error_free(&error);
302
303         return r;
304 }
305
306 static int dot_one_property(const char *name, const char *prop, DBusMessageIter *iter) {
307         static const char * const colors[] = {
308                 "Requires",              "[color=\"black\"]",
309                 "RequiresOverridable",   "[color=\"black\"]",
310                 "Requisite",             "[color=\"darkblue\"]",
311                 "RequisiteOverridable",  "[color=\"darkblue\"]",
312                 "Wants",                 "[color=\"darkgrey\"]",
313                 "Conflicts",             "[color=\"red\"]",
314                 "After",                 "[color=\"green\"]"
315         };
316
317         const char *c = NULL;
318         unsigned i;
319
320         assert(name);
321         assert(prop);
322         assert(iter);
323
324         for (i = 0; i < ELEMENTSOF(colors); i += 2)
325                 if (streq(colors[i], prop)) {
326                         c = colors[i+1];
327                         break;
328                 }
329
330         if (!c)
331                 return 0;
332
333         if (arg_dot != DOT_ALL)
334                 if ((arg_dot == DOT_ORDER) != streq(prop, "After"))
335                         return 0;
336
337         switch (dbus_message_iter_get_arg_type(iter)) {
338
339         case DBUS_TYPE_ARRAY:
340
341                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
342                         DBusMessageIter sub;
343
344                         dbus_message_iter_recurse(iter, &sub);
345
346                         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
347                                 const char *s;
348
349                                 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
350                                 dbus_message_iter_get_basic(&sub, &s);
351                                 printf("\t\"%s\"->\"%s\" %s;\n", name, s, c);
352
353                                 dbus_message_iter_next(&sub);
354                         }
355
356                         return 0;
357                 }
358         }
359
360         return 0;
361 }
362
363 static int dot_one(DBusConnection *bus, const char *name, const char *path) {
364         DBusMessage *m = NULL, *reply = NULL;
365         const char *interface = "org.freedesktop.systemd1.Unit";
366         int r;
367         DBusError error;
368         DBusMessageIter iter, sub, sub2, sub3;
369
370         assert(bus);
371         assert(path);
372
373         dbus_error_init(&error);
374
375         if (!(m = dbus_message_new_method_call(
376                               "org.freedesktop.systemd1",
377                               path,
378                               "org.freedesktop.DBus.Properties",
379                               "GetAll"))) {
380                 log_error("Could not allocate message.");
381                 r = -ENOMEM;
382                 goto finish;
383         }
384
385         if (!dbus_message_append_args(m,
386                                       DBUS_TYPE_STRING, &interface,
387                                       DBUS_TYPE_INVALID)) {
388                 log_error("Could not append arguments to message.");
389                 r = -ENOMEM;
390                 goto finish;
391         }
392
393         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
394                 log_error("Failed to issue method call: %s", error.message);
395                 r = -EIO;
396                 goto finish;
397         }
398
399         if (!dbus_message_iter_init(reply, &iter) ||
400             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
401             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
402                 log_error("Failed to parse reply.");
403                 r = -EIO;
404                 goto finish;
405         }
406
407         dbus_message_iter_recurse(&iter, &sub);
408
409         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
410                 const char *prop;
411
412                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
413                         log_error("Failed to parse reply.");
414                         r = -EIO;
415                         goto finish;
416                 }
417
418                 dbus_message_iter_recurse(&sub, &sub2);
419
420                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) {
421                         log_error("Failed to parse reply.");
422                         r = -EIO;
423                         goto finish;
424                 }
425
426                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
427                         log_error("Failed to parse reply.");
428                         r = -EIO;
429                         goto finish;
430                 }
431
432                 dbus_message_iter_recurse(&sub2, &sub3);
433
434                 if (dot_one_property(name, prop, &sub3)) {
435                         log_error("Failed to parse reply.");
436                         r = -EIO;
437                         goto finish;
438                 }
439
440                 dbus_message_iter_next(&sub);
441         }
442
443 finish:
444         if (m)
445                 dbus_message_unref(m);
446
447         if (reply)
448                 dbus_message_unref(reply);
449
450         dbus_error_free(&error);
451
452         return r;
453 }
454
455 static int dot(DBusConnection *bus, char **args, unsigned n) {
456         DBusMessage *m = NULL, *reply = NULL;
457         DBusError error;
458         int r;
459         DBusMessageIter iter, sub, sub2;
460
461         dbus_error_init(&error);
462
463         assert(bus);
464
465         if (!(m = dbus_message_new_method_call(
466                               "org.freedesktop.systemd1",
467                               "/org/freedesktop/systemd1",
468                               "org.freedesktop.systemd1.Manager",
469                               "ListUnits"))) {
470                 log_error("Could not allocate message.");
471                 return -ENOMEM;
472         }
473
474         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
475                 log_error("Failed to issue method call: %s", error.message);
476                 r = -EIO;
477                 goto finish;
478         }
479
480         if (!dbus_message_iter_init(reply, &iter) ||
481             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
482             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
483                 log_error("Failed to parse reply.");
484                 r = -EIO;
485                 goto finish;
486         }
487
488         printf("digraph systemd {\n");
489
490         dbus_message_iter_recurse(&iter, &sub);
491         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
492                 const char *id, *description, *load_state, *active_state, *sub_state, *unit_path;
493
494                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
495                         log_error("Failed to parse reply.");
496                         r = -EIO;
497                         goto finish;
498                 }
499
500                 dbus_message_iter_recurse(&sub, &sub2);
501
502                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
503                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 ||
504                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
505                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
506                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
507                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0) {
508                         log_error("Failed to parse reply.");
509                         r = -EIO;
510                         goto finish;
511                 }
512
513                 if ((r = dot_one(bus, id, unit_path)) < 0)
514                         goto finish;
515
516                 /* printf("\t\"%s\";\n", id); */
517                 dbus_message_iter_next(&sub);
518         }
519
520         printf("}\n");
521
522         log_info("   Color legend: black     = Requires\n"
523                  "                 dark blue = Requisite\n"
524                  "                 dark grey = Wants\n"
525                  "                 red       = Conflicts\n"
526                  "                 green     = After\n");
527
528         if (isatty(fileno(stdout)))
529                 log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
530                            "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n");
531
532         r = 0;
533
534 finish:
535         if (m)
536                 dbus_message_unref(m);
537
538         if (reply)
539                 dbus_message_unref(reply);
540
541         dbus_error_free(&error);
542
543         return r;
544 }
545
546 static int list_jobs(DBusConnection *bus, char **args, unsigned n) {
547         DBusMessage *m = NULL, *reply = NULL;
548         DBusError error;
549         int r;
550         DBusMessageIter iter, sub, sub2;
551         unsigned k = 0;
552
553         dbus_error_init(&error);
554
555         assert(bus);
556
557         if (!(m = dbus_message_new_method_call(
558                               "org.freedesktop.systemd1",
559                               "/org/freedesktop/systemd1",
560                               "org.freedesktop.systemd1.Manager",
561                               "ListJobs"))) {
562                 log_error("Could not allocate message.");
563                 return -ENOMEM;
564         }
565
566         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
567                 log_error("Failed to issue method call: %s", error.message);
568                 r = -EIO;
569                 goto finish;
570         }
571
572         if (!dbus_message_iter_init(reply, &iter) ||
573             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
574             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
575                 log_error("Failed to parse reply.");
576                 r = -EIO;
577                 goto finish;
578         }
579
580         dbus_message_iter_recurse(&iter, &sub);
581
582         printf("%4s %-45s %-17s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
583
584         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
585                 const char *name, *type, *state, *job_path, *unit_path;
586                 uint32_t id;
587                 char *e;
588
589                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
590                         log_error("Failed to parse reply.");
591                         r = -EIO;
592                         goto finish;
593                 }
594
595                 dbus_message_iter_recurse(&sub, &sub2);
596
597                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
598                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
599                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
600                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
601                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
602                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
603                         log_error("Failed to parse reply.");
604                         r = -EIO;
605                         goto finish;
606                 }
607
608                 e = arg_full ? NULL : ellipsize(name, 45, 33);
609                 printf("%4u %-45s %-17s %-7s\n", id, e ? e : name, type, state);
610                 free(e);
611
612                 k++;
613
614                 dbus_message_iter_next(&sub);
615         }
616
617         printf("\n%u jobs listed.\n", k);
618         r = 0;
619
620 finish:
621         if (m)
622                 dbus_message_unref(m);
623
624         if (reply)
625                 dbus_message_unref(reply);
626
627         dbus_error_free(&error);
628
629         return r;
630 }
631
632 static int load_unit(DBusConnection *bus, char **args, unsigned n) {
633         DBusMessage *m = NULL, *reply = NULL;
634         DBusError error;
635         int r;
636         unsigned i;
637
638         dbus_error_init(&error);
639
640         assert(bus);
641         assert(args);
642
643         for (i = 1; i < n; i++) {
644
645                 if (!(m = dbus_message_new_method_call(
646                                       "org.freedesktop.systemd1",
647                                       "/org/freedesktop/systemd1",
648                                       "org.freedesktop.systemd1.Manager",
649                                       "LoadUnit"))) {
650                         log_error("Could not allocate message.");
651                         r = -ENOMEM;
652                         goto finish;
653                 }
654
655                 if (!dbus_message_append_args(m,
656                                               DBUS_TYPE_STRING, &args[i],
657                                               DBUS_TYPE_INVALID)) {
658                         log_error("Could not append arguments to message.");
659                         r = -ENOMEM;
660                         goto finish;
661                 }
662
663                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
664                         log_error("Failed to issue method call: %s", error.message);
665                         r = -EIO;
666                         goto finish;
667                 }
668
669                 dbus_message_unref(m);
670                 dbus_message_unref(reply);
671
672                 m = reply = NULL;
673         }
674
675         r = 0;
676
677 finish:
678         if (m)
679                 dbus_message_unref(m);
680
681         if (reply)
682                 dbus_message_unref(reply);
683
684         dbus_error_free(&error);
685
686         return r;
687 }
688
689 static int cancel_job(DBusConnection *bus, char **args, unsigned n) {
690         DBusMessage *m = NULL, *reply = NULL;
691         DBusError error;
692         int r;
693         unsigned i;
694
695         dbus_error_init(&error);
696
697         assert(bus);
698         assert(args);
699
700         if (n <= 1)
701                 return daemon_reload(bus, args, n);
702
703         for (i = 1; i < n; i++) {
704                 unsigned id;
705                 const char *path;
706
707                 if (!(m = dbus_message_new_method_call(
708                                       "org.freedesktop.systemd1",
709                                       "/org/freedesktop/systemd1",
710                                       "org.freedesktop.systemd1.Manager",
711                                       "GetJob"))) {
712                         log_error("Could not allocate message.");
713                         r = -ENOMEM;
714                         goto finish;
715                 }
716
717                 if ((r = safe_atou(args[i], &id)) < 0) {
718                         log_error("Failed to parse job id: %s", strerror(-r));
719                         goto finish;
720                 }
721
722                 assert_cc(sizeof(uint32_t) == sizeof(id));
723                 if (!dbus_message_append_args(m,
724                                               DBUS_TYPE_UINT32, &id,
725                                               DBUS_TYPE_INVALID)) {
726                         log_error("Could not append arguments to message.");
727                         r = -ENOMEM;
728                         goto finish;
729                 }
730
731                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
732                         log_error("Failed to issue method call: %s", error.message);
733                         r = -EIO;
734                         goto finish;
735                 }
736
737                 if (!dbus_message_get_args(reply, &error,
738                                            DBUS_TYPE_OBJECT_PATH, &path,
739                                            DBUS_TYPE_INVALID)) {
740                         log_error("Failed to parse reply: %s", error.message);
741                         r = -EIO;
742                         goto finish;
743                 }
744
745                 dbus_message_unref(m);
746                 if (!(m = dbus_message_new_method_call(
747                                       "org.freedesktop.systemd1",
748                                       path,
749                                       "org.freedesktop.systemd1.Job",
750                                       "Cancel"))) {
751                         log_error("Could not allocate message.");
752                         r = -ENOMEM;
753                         goto finish;
754                 }
755
756                 dbus_message_unref(reply);
757                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
758                         log_error("Failed to issue method call: %s", error.message);
759                         r = -EIO;
760                         goto finish;
761                 }
762
763                 dbus_message_unref(m);
764                 dbus_message_unref(reply);
765                 m = reply = NULL;
766         }
767
768         r = 0;
769
770 finish:
771         if (m)
772                 dbus_message_unref(m);
773
774         if (reply)
775                 dbus_message_unref(reply);
776
777         dbus_error_free(&error);
778
779         return r;
780 }
781
782 static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
783         DBusMessage *m, *reply;
784         dbus_bool_t b = FALSE;
785         DBusMessageIter iter, sub;
786         const char
787                 *interface = "org.freedesktop.systemd1.Unit",
788                 *property = "NeedDaemonReload",
789                 *path;
790
791         /* We ignore all errors here, since this is used to show a warning only */
792
793         if (!(m = dbus_message_new_method_call(
794                               "org.freedesktop.systemd1",
795                               "/org/freedesktop/systemd1",
796                               "org.freedesktop.systemd1.Manager",
797                               "GetUnit")))
798                 goto finish;
799
800         if (!dbus_message_append_args(m,
801                                       DBUS_TYPE_STRING, &unit,
802                                       DBUS_TYPE_INVALID))
803                 goto finish;
804
805         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL)))
806                 goto finish;
807
808         if (!dbus_message_get_args(reply, NULL,
809                                    DBUS_TYPE_OBJECT_PATH, &path,
810                                    DBUS_TYPE_INVALID))
811                 goto finish;
812
813         dbus_message_unref(m);
814         if (!(m = dbus_message_new_method_call(
815                               "org.freedesktop.systemd1",
816                               path,
817                               "org.freedesktop.DBus.Properties",
818                               "Get")))
819                 goto finish;
820
821         if (!dbus_message_append_args(m,
822                                       DBUS_TYPE_STRING, &interface,
823                                       DBUS_TYPE_STRING, &property,
824                                       DBUS_TYPE_INVALID)) {
825                 goto finish;
826         }
827
828         dbus_message_unref(reply);
829         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL)))
830                 goto finish;
831
832         if (!dbus_message_iter_init(reply, &iter) ||
833             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
834                 goto finish;
835
836         dbus_message_iter_recurse(&iter, &sub);
837
838         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
839                 goto finish;
840
841         dbus_message_iter_get_basic(&sub, &b);
842
843 finish:
844         if (m)
845                 dbus_message_unref(m);
846
847         if (reply)
848                 dbus_message_unref(reply);
849
850         return b;
851 }
852
853 typedef struct WaitData {
854         Set *set;
855         bool failed;
856 } WaitData;
857
858 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
859         DBusError error;
860         WaitData *d = data;
861
862         assert(connection);
863         assert(message);
864         assert(d);
865
866         dbus_error_init(&error);
867
868         log_debug("Got D-Bus request: %s.%s() on %s",
869                   dbus_message_get_interface(message),
870                   dbus_message_get_member(message),
871                   dbus_message_get_path(message));
872
873         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
874                 log_error("Warning! D-Bus connection terminated.");
875                 dbus_connection_close(connection);
876
877         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
878                 uint32_t id;
879                 const char *path;
880                 dbus_bool_t success = true;
881
882                 if (!dbus_message_get_args(message, &error,
883                                            DBUS_TYPE_UINT32, &id,
884                                            DBUS_TYPE_OBJECT_PATH, &path,
885                                            DBUS_TYPE_BOOLEAN, &success,
886                                            DBUS_TYPE_INVALID))
887                         log_error("Failed to parse message: %s", error.message);
888                 else {
889                         char *p;
890
891                         if ((p = set_remove(d->set, (char*) path)))
892                                 free(p);
893
894                         if (!success)
895                                 d->failed = true;
896                 }
897         }
898
899         dbus_error_free(&error);
900         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
901 }
902
903 static int enable_wait_for_jobs(DBusConnection *bus) {
904         DBusError error;
905
906         assert(bus);
907
908         if (private_bus)
909                 return 0;
910
911         dbus_error_init(&error);
912         dbus_bus_add_match(bus,
913                            "type='signal',"
914                            "sender='org.freedesktop.systemd1',"
915                            "interface='org.freedesktop.systemd1.Manager',"
916                            "member='JobRemoved',"
917                            "path='/org/freedesktop/systemd1'",
918                            &error);
919
920         if (dbus_error_is_set(&error)) {
921                 log_error("Failed to add match: %s", error.message);
922                 dbus_error_free(&error);
923                 return -EIO;
924         }
925
926         /* This is slightly dirty, since we don't undo the match registrations. */
927         return 0;
928 }
929
930 static int wait_for_jobs(DBusConnection *bus, Set *s) {
931         int r;
932         WaitData d;
933
934         assert(bus);
935         assert(s);
936
937         zero(d);
938         d.set = s;
939         d.failed = false;
940
941         if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) {
942                 log_error("Failed to add filter.");
943                 r = -ENOMEM;
944                 goto finish;
945         }
946
947         while (!set_isempty(s) &&
948                dbus_connection_read_write_dispatch(bus, -1))
949                 ;
950
951         if (!arg_quiet && d.failed)
952                 log_error("Job failed, see logs for details.");
953
954         r = d.failed ? -EIO : 0;
955
956 finish:
957         /* This is slightly dirty, since we don't undo the filter registration. */
958
959         return r;
960 }
961
962 static int start_unit_one(
963                 DBusConnection *bus,
964                 const char *method,
965                 const char *name,
966                 const char *mode,
967                 Set *s) {
968
969         DBusMessage *m = NULL, *reply = NULL;
970         DBusError error;
971         const char *path;
972         int r;
973
974         assert(bus);
975         assert(method);
976         assert(name);
977         assert(mode);
978         assert(arg_no_block || s);
979
980         dbus_error_init(&error);
981
982         if (!(m = dbus_message_new_method_call(
983                               "org.freedesktop.systemd1",
984                               "/org/freedesktop/systemd1",
985                               "org.freedesktop.systemd1.Manager",
986                               method))) {
987                 log_error("Could not allocate message.");
988                 r = -ENOMEM;
989                 goto finish;
990         }
991
992         if (!dbus_message_append_args(m,
993                                       DBUS_TYPE_STRING, &name,
994                                       DBUS_TYPE_STRING, &mode,
995                                       DBUS_TYPE_INVALID)) {
996                 log_error("Could not append arguments to message.");
997                 r = -ENOMEM;
998                 goto finish;
999         }
1000
1001         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1002
1003                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
1004                         /* There's always a fallback possible for
1005                          * legacy actions. */
1006                         r = 0;
1007                         goto finish;
1008                 }
1009
1010                 log_error("Failed to issue method call: %s", error.message);
1011                 r = -EIO;
1012                 goto finish;
1013         }
1014
1015         if (!dbus_message_get_args(reply, &error,
1016                                    DBUS_TYPE_OBJECT_PATH, &path,
1017                                    DBUS_TYPE_INVALID)) {
1018                 log_error("Failed to parse reply: %s", error.message);
1019                 r = -EIO;
1020                 goto finish;
1021         }
1022
1023         if (need_daemon_reload(bus, name))
1024                 log_warning("Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.",
1025                             arg_session ? "--session" : "--system");
1026
1027         if (!arg_no_block) {
1028                 char *p;
1029
1030                 if (!(p = strdup(path))) {
1031                         log_error("Failed to duplicate path.");
1032                         r = -ENOMEM;
1033                         goto finish;
1034                 }
1035
1036                 if ((r = set_put(s, p)) < 0) {
1037                         free(p);
1038                         log_error("Failed to add path to set.");
1039                         goto finish;
1040                 }
1041         }
1042
1043         r = 1;
1044
1045 finish:
1046         if (m)
1047                 dbus_message_unref(m);
1048
1049         if (reply)
1050                 dbus_message_unref(reply);
1051
1052         dbus_error_free(&error);
1053
1054         return r;
1055 }
1056
1057 static enum action verb_to_action(const char *verb) {
1058         if (streq(verb, "halt"))
1059                 return ACTION_HALT;
1060         else if (streq(verb, "poweroff"))
1061                 return ACTION_POWEROFF;
1062         else if (streq(verb, "reboot"))
1063                 return ACTION_REBOOT;
1064         else if (streq(verb, "rescue"))
1065                 return ACTION_RESCUE;
1066         else if (streq(verb, "emergency"))
1067                 return ACTION_EMERGENCY;
1068         else if (streq(verb, "default"))
1069                 return ACTION_DEFAULT;
1070         else
1071                 return ACTION_INVALID;
1072 }
1073
1074 static int start_unit(DBusConnection *bus, char **args, unsigned n) {
1075
1076         static const char * const table[_ACTION_MAX] = {
1077                 [ACTION_HALT] = SPECIAL_HALT_TARGET,
1078                 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
1079                 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
1080                 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
1081                 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
1082                 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
1083                 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
1084                 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
1085                 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
1086                 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET
1087         };
1088
1089         int r;
1090         unsigned i;
1091         const char *method, *mode, *one_name;
1092         Set *s = NULL;
1093
1094         assert(bus);
1095
1096         if (arg_action == ACTION_SYSTEMCTL) {
1097                 method =
1098                         streq(args[0], "stop")                  ? "StopUnit" :
1099                         streq(args[0], "reload")                ? "ReloadUnit" :
1100                         streq(args[0], "restart")               ? "RestartUnit" :
1101                         streq(args[0], "try-restart")           ? "TryRestartUnit" :
1102                         streq(args[0], "reload-or-restart")     ? "ReloadOrRestartUnit" :
1103                         streq(args[0], "reload-or-try-restart") ||
1104                         streq(args[0], "force-reload")          ||
1105                         streq(args[0], "condrestart")           ? "ReloadOrTryRestartUnit" :
1106                                                                   "StartUnit";
1107
1108                 mode =
1109                         (streq(args[0], "isolate") ||
1110                          streq(args[0], "rescue")  ||
1111                          streq(args[0], "emergency")) ? "isolate" :
1112                                              arg_fail ? "fail" :
1113                                                         "replace";
1114
1115                 one_name = table[verb_to_action(args[0])];
1116
1117         } else {
1118                 assert(arg_action < ELEMENTSOF(table));
1119                 assert(table[arg_action]);
1120
1121                 method = "StartUnit";
1122
1123                 mode = (arg_action == ACTION_EMERGENCY ||
1124                         arg_action == ACTION_RESCUE) ? "isolate" : "replace";
1125
1126                 one_name = table[arg_action];
1127         }
1128
1129         if (!arg_no_block) {
1130                 if ((r = enable_wait_for_jobs(bus)) < 0) {
1131                         log_error("Could not watch jobs: %s", strerror(-r));
1132                         goto finish;
1133                 }
1134
1135                 if (!(s = set_new(string_hash_func, string_compare_func))) {
1136                         log_error("Failed to allocate set.");
1137                         r = -ENOMEM;
1138                         goto finish;
1139                 }
1140         }
1141
1142         r = 0;
1143
1144         if (one_name) {
1145                 if ((r = start_unit_one(bus, method, one_name, mode, s)) <= 0)
1146                         goto finish;
1147         } else {
1148                 for (i = 1; i < n; i++)
1149                         if ((r = start_unit_one(bus, method, args[i], mode, s)) < 0)
1150                                 goto finish;
1151         }
1152
1153         if (!arg_no_block)
1154                 r = wait_for_jobs(bus, s);
1155
1156 finish:
1157         if (s)
1158                 set_free_free(s);
1159
1160         return r;
1161 }
1162
1163 static int start_special(DBusConnection *bus, char **args, unsigned n) {
1164         int r;
1165
1166         assert(bus);
1167         assert(args);
1168
1169         r = start_unit(bus, args, n);
1170
1171         if (r >= 0)
1172                 warn_wall(verb_to_action(args[0]));
1173
1174         return r;
1175 }
1176
1177 static int check_unit(DBusConnection *bus, char **args, unsigned n) {
1178         DBusMessage *m = NULL, *reply = NULL;
1179         const char
1180                 *interface = "org.freedesktop.systemd1.Unit",
1181                 *property = "ActiveState";
1182         int r = -EADDRNOTAVAIL;
1183         DBusError error;
1184         unsigned i;
1185
1186         assert(bus);
1187         assert(args);
1188
1189         dbus_error_init(&error);
1190
1191         for (i = 1; i < n; i++) {
1192                 const char *path = NULL;
1193                 const char *state;
1194                 DBusMessageIter iter, sub;
1195
1196                 if (!(m = dbus_message_new_method_call(
1197                                       "org.freedesktop.systemd1",
1198                                       "/org/freedesktop/systemd1",
1199                                       "org.freedesktop.systemd1.Manager",
1200                                       "GetUnit"))) {
1201                         log_error("Could not allocate message.");
1202                         r = -ENOMEM;
1203                         goto finish;
1204                 }
1205
1206                 if (!dbus_message_append_args(m,
1207                                               DBUS_TYPE_STRING, &args[i],
1208                                               DBUS_TYPE_INVALID)) {
1209                         log_error("Could not append arguments to message.");
1210                         r = -ENOMEM;
1211                         goto finish;
1212                 }
1213
1214                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1215
1216                         /* Hmm, cannot figure out anything about this unit... */
1217                         if (!arg_quiet)
1218                                 puts("unknown");
1219
1220                         dbus_error_free(&error);
1221                         continue;
1222                 }
1223
1224                 if (!dbus_message_get_args(reply, &error,
1225                                            DBUS_TYPE_OBJECT_PATH, &path,
1226                                            DBUS_TYPE_INVALID)) {
1227                         log_error("Failed to parse reply: %s", error.message);
1228                         r = -EIO;
1229                         goto finish;
1230                 }
1231
1232                 dbus_message_unref(m);
1233                 if (!(m = dbus_message_new_method_call(
1234                                       "org.freedesktop.systemd1",
1235                                       path,
1236                                       "org.freedesktop.DBus.Properties",
1237                                       "Get"))) {
1238                         log_error("Could not allocate message.");
1239                         r = -ENOMEM;
1240                         goto finish;
1241                 }
1242
1243                 if (!dbus_message_append_args(m,
1244                                               DBUS_TYPE_STRING, &interface,
1245                                               DBUS_TYPE_STRING, &property,
1246                                               DBUS_TYPE_INVALID)) {
1247                         log_error("Could not append arguments to message.");
1248                         r = -ENOMEM;
1249                         goto finish;
1250                 }
1251
1252                 dbus_message_unref(reply);
1253                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1254                         log_error("Failed to issue method call: %s", error.message);
1255                         r = -EIO;
1256                         goto finish;
1257                 }
1258
1259                 if (!dbus_message_iter_init(reply, &iter) ||
1260                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
1261                         log_error("Failed to parse reply.");
1262                         r = -EIO;
1263                         goto finish;
1264                 }
1265
1266                 dbus_message_iter_recurse(&iter, &sub);
1267
1268                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1269                         log_error("Failed to parse reply.");
1270                         r = -EIO;
1271                         goto finish;
1272                 }
1273
1274                 dbus_message_iter_get_basic(&sub, &state);
1275
1276                 if (!arg_quiet)
1277                         puts(state);
1278
1279                 if (streq(state, "active") || startswith(state, "reloading"))
1280                         r = 0;
1281
1282                 dbus_message_unref(m);
1283                 dbus_message_unref(reply);
1284                 m = reply = NULL;
1285         }
1286
1287 finish:
1288         if (m)
1289                 dbus_message_unref(m);
1290
1291         if (reply)
1292                 dbus_message_unref(reply);
1293
1294         dbus_error_free(&error);
1295
1296         return r;
1297 }
1298
1299 typedef struct ExecStatusInfo {
1300         char *path;
1301         char **argv;
1302
1303         bool ignore;
1304
1305         usec_t start_timestamp;
1306         usec_t exit_timestamp;
1307         pid_t pid;
1308         int code;
1309         int status;
1310
1311         LIST_FIELDS(struct ExecStatusInfo, exec);
1312 } ExecStatusInfo;
1313
1314 static void exec_status_info_free(ExecStatusInfo *i) {
1315         assert(i);
1316
1317         free(i->path);
1318         strv_free(i->argv);
1319         free(i);
1320 }
1321
1322 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
1323         uint64_t start_timestamp, exit_timestamp;
1324         DBusMessageIter sub2, sub3;
1325         const char*path;
1326         unsigned n;
1327         uint32_t pid;
1328         int32_t code, status;
1329         dbus_bool_t ignore;
1330
1331         assert(i);
1332         assert(i);
1333
1334         if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
1335                 return -EIO;
1336
1337         dbus_message_iter_recurse(sub, &sub2);
1338
1339         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
1340                 return -EIO;
1341
1342         if (!(i->path = strdup(path)))
1343                 return -ENOMEM;
1344
1345         if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
1346             dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
1347                 return -EIO;
1348
1349         n = 0;
1350         dbus_message_iter_recurse(&sub2, &sub3);
1351         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
1352                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
1353                 dbus_message_iter_next(&sub3);
1354                 n++;
1355         }
1356
1357
1358         if (!(i->argv = new0(char*, n+1)))
1359                 return -ENOMEM;
1360
1361         n = 0;
1362         dbus_message_iter_recurse(&sub2, &sub3);
1363         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
1364                 const char *s;
1365
1366                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
1367                 dbus_message_iter_get_basic(&sub3, &s);
1368                 dbus_message_iter_next(&sub3);
1369
1370                 if (!(i->argv[n++] = strdup(s)))
1371                         return -ENOMEM;
1372         }
1373
1374         if (!dbus_message_iter_next(&sub2) ||
1375             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
1376             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
1377             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
1378             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
1379             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
1380             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
1381                 return -EIO;
1382
1383         i->ignore = ignore;
1384         i->start_timestamp = (usec_t) start_timestamp;
1385         i->exit_timestamp = (usec_t) exit_timestamp;
1386         i->pid = (pid_t) pid;
1387         i->code = code;
1388         i->status = status;
1389
1390         return 0;
1391 }
1392
1393 typedef struct UnitStatusInfo {
1394         const char *id;
1395         const char *load_state;
1396         const char *active_state;
1397         const char *sub_state;
1398
1399         const char *description;
1400
1401         const char *fragment_path;
1402         const char *default_control_group;
1403
1404         bool need_daemon_reload;
1405
1406         /* Service */
1407         pid_t main_pid;
1408         pid_t control_pid;
1409         const char *status_text;
1410         bool running;
1411
1412         usec_t start_timestamp;
1413         usec_t exit_timestamp;
1414
1415         int exit_code, exit_status;
1416
1417         /* Socket */
1418         unsigned n_accepted;
1419         unsigned n_connections;
1420         bool accept;
1421
1422         /* Device */
1423         const char *sysfs_path;
1424
1425         /* Mount, Automount */
1426         const char *where;
1427
1428         /* Swap */
1429         const char *what;
1430
1431         LIST_HEAD(ExecStatusInfo, exec);
1432 } UnitStatusInfo;
1433
1434 static void print_status_info(UnitStatusInfo *i) {
1435         ExecStatusInfo *p;
1436
1437         assert(i);
1438
1439         /* This shows pretty information about a unit. See
1440          * print_property() for a low-level property printer */
1441
1442         printf("%s", strna(i->id));
1443
1444         if (i->description && !streq_ptr(i->id, i->description))
1445                 printf(" - %s", i->description);
1446
1447         printf("\n");
1448
1449         if (i->fragment_path)
1450                 printf("\t  Loaded: %s (%s)\n", strna(i->load_state), i->fragment_path);
1451         else if (streq_ptr(i->load_state, "failed"))
1452                 printf("\t  Loaded: %s%s%s\n",
1453                        ansi_highlight(true),
1454                        strna(i->load_state),
1455                        ansi_highlight(false));
1456         else
1457                 printf("\t  Loaded: %s\n", strna(i->load_state));
1458
1459         if (streq_ptr(i->active_state, "maintenance")) {
1460                         if (streq_ptr(i->active_state, i->sub_state))
1461                                 printf("\t  Active: %s%s%s\n",
1462                                        ansi_highlight(true),
1463                                        strna(i->active_state),
1464                                        ansi_highlight(false));
1465                         else
1466                                 printf("\t  Active: %s%s (%s)%s\n",
1467                                        ansi_highlight(true),
1468                                        strna(i->active_state),
1469                                        strna(i->sub_state),
1470                                        ansi_highlight(false));
1471         } else {
1472                 if (streq_ptr(i->active_state, i->sub_state))
1473                         printf("\t  Active: %s\n",
1474                                strna(i->active_state));
1475                 else
1476                         printf("\t  Active: %s (%s)\n",
1477                                strna(i->active_state),
1478                                strna(i->sub_state));
1479         }
1480
1481         if (i->sysfs_path)
1482                 printf("\t  Device: %s\n", i->sysfs_path);
1483         else if (i->where)
1484                 printf("\t   Where: %s\n", i->where);
1485         else if (i->what)
1486                 printf("\t    What: %s\n", i->what);
1487
1488         if (i->accept)
1489                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
1490
1491         LIST_FOREACH(exec, p, i->exec) {
1492                 char *t;
1493
1494                 /* Only show exited processes here */
1495                 if (p->code == 0)
1496                         continue;
1497
1498                 t = strv_join(p->argv, " ");
1499                 printf("\t  Exited: %u (%s, code=%s, ", p->pid, strna(t), sigchld_code_to_string(p->code));
1500                 free(t);
1501
1502                 if (p->code == CLD_EXITED)
1503                         printf("status=%i", p->status);
1504                 else
1505                         printf("signal=%s", signal_to_string(p->status));
1506                 printf(")\n");
1507
1508                 if (i->main_pid == p->pid &&
1509                     i->start_timestamp == p->start_timestamp &&
1510                     i->exit_timestamp == p->start_timestamp)
1511                         /* Let's not show this twice */
1512                         i->main_pid = 0;
1513
1514                 if (p->pid == i->control_pid)
1515                         i->control_pid = 0;
1516         }
1517
1518         if (i->main_pid > 0 || i->control_pid > 0) {
1519                 printf("\t");
1520
1521                 if (i->main_pid > 0) {
1522                         printf("    Main: %u", (unsigned) i->main_pid);
1523
1524                         if (i->running) {
1525                                 char *t = NULL;
1526                                 get_process_name(i->main_pid, &t);
1527                                 if (t) {
1528                                         printf(" (%s)", t);
1529                                         free(t);
1530                                 }
1531                         } else {
1532                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
1533
1534                                 if (i->exit_code == CLD_EXITED)
1535                                         printf("status=%i", i->exit_status);
1536                                 else
1537                                         printf("signal=%s", signal_to_string(i->exit_status));
1538                                 printf(")");                        }
1539                 }
1540
1541                 if (i->main_pid > 0 && i->control_pid > 0)
1542                         printf(";");
1543
1544                 if (i->control_pid > 0) {
1545                         char *t = NULL;
1546
1547                         printf(" Control: %u", (unsigned) i->control_pid);
1548
1549                         get_process_name(i->control_pid, &t);
1550                         if (t) {
1551                                 printf(" (%s)", t);
1552                                 free(t);
1553                         }
1554                 }
1555
1556                 printf("\n");
1557         }
1558
1559         if (i->status_text)
1560                 printf("\t  Status: \"%s\"\n", i->status_text);
1561
1562         if (i->default_control_group) {
1563                 unsigned c;
1564
1565                 printf("\t  CGroup: %s\n", i->default_control_group);
1566
1567                 if ((c = columns()) > 18)
1568                         c -= 18;
1569                 else
1570                         c = 0;
1571
1572                 show_cgroup_by_path(i->default_control_group, "\t\t  ", c);
1573         }
1574
1575         if (i->need_daemon_reload)
1576                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
1577                        ansi_highlight(true),
1578                        ansi_highlight(false),
1579                        arg_session ? "--session" : "--system");
1580 }
1581
1582 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
1583
1584         switch (dbus_message_iter_get_arg_type(iter)) {
1585
1586         case DBUS_TYPE_STRING: {
1587                 const char *s;
1588
1589                 dbus_message_iter_get_basic(iter, &s);
1590
1591                 if (s[0]) {
1592                         if (streq(name, "Id"))
1593                                 i->id = s;
1594                         else if (streq(name, "LoadState"))
1595                                 i->load_state = s;
1596                         else if (streq(name, "ActiveState"))
1597                                 i->active_state = s;
1598                         else if (streq(name, "SubState"))
1599                                 i->sub_state = s;
1600                         else if (streq(name, "Description"))
1601                                 i->description = s;
1602                         else if (streq(name, "FragmentPath"))
1603                                 i->fragment_path = s;
1604                         else if (streq(name, "DefaultControlGroup"))
1605                                 i->default_control_group = s;
1606                         else if (streq(name, "StatusText"))
1607                                 i->status_text = s;
1608                         else if (streq(name, "SysFSPath"))
1609                                 i->sysfs_path = s;
1610                         else if (streq(name, "Where"))
1611                                 i->where = s;
1612                         else if (streq(name, "What"))
1613                                 i->what = s;
1614                 }
1615
1616                 break;
1617         }
1618
1619         case DBUS_TYPE_BOOLEAN: {
1620                 dbus_bool_t b;
1621
1622                 dbus_message_iter_get_basic(iter, &b);
1623
1624                 if (streq(name, "Accept"))
1625                         i->accept = b;
1626                 else if (streq(name, "NeedDaemonReload"))
1627                         i->need_daemon_reload = b;
1628
1629                 break;
1630         }
1631
1632         case DBUS_TYPE_UINT32: {
1633                 uint32_t u;
1634
1635                 dbus_message_iter_get_basic(iter, &u);
1636
1637                 if (streq(name, "MainPID")) {
1638                         if (u > 0) {
1639                                 i->main_pid = (pid_t) u;
1640                                 i->running = true;
1641                         }
1642                 } else if (streq(name, "ControlPID"))
1643                         i->control_pid = (pid_t) u;
1644                 else if (streq(name, "ExecMainPID")) {
1645                         if (u > 0)
1646                                 i->main_pid = (pid_t) u;
1647                 } else if (streq(name, "NAccepted"))
1648                         i->n_accepted = u;
1649                 else if (streq(name, "NConnections"))
1650                         i->n_connections = u;
1651
1652                 break;
1653         }
1654
1655         case DBUS_TYPE_INT32: {
1656                 int32_t j;
1657
1658                 dbus_message_iter_get_basic(iter, &j);
1659
1660                 if (streq(name, "ExecMainCode"))
1661                         i->exit_code = (int) j;
1662                 else if (streq(name, "ExecMainStatus"))
1663                         i->exit_status = (int) j;
1664
1665                 break;
1666         }
1667
1668         case DBUS_TYPE_UINT64: {
1669                 uint64_t u;
1670
1671                 dbus_message_iter_get_basic(iter, &u);
1672
1673                 if (streq(name, "ExecMainStartTimestamp"))
1674                         i->start_timestamp = (usec_t) u;
1675                 else if (streq(name, "ExecMainExitTimestamp"))
1676                         i->exit_timestamp = (usec_t) u;
1677
1678                 break;
1679         }
1680
1681         case DBUS_TYPE_ARRAY: {
1682
1683                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
1684                     startswith(name, "Exec")) {
1685                         DBusMessageIter sub;
1686
1687                         dbus_message_iter_recurse(iter, &sub);
1688                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1689                                 ExecStatusInfo *info;
1690                                 int r;
1691
1692                                 if (!(info = new0(ExecStatusInfo, 1)))
1693                                         return -ENOMEM;
1694
1695                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
1696                                         free(info);
1697                                         return r;
1698                                 }
1699
1700                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
1701
1702                                 dbus_message_iter_next(&sub);
1703                         }
1704                 }
1705
1706                 break;
1707         }
1708         }
1709
1710         return 0;
1711 }
1712
1713 static int print_property(const char *name, DBusMessageIter *iter) {
1714         assert(name);
1715         assert(iter);
1716
1717         /* This is a low-level property printer, see
1718          * print_status_info() for the nicer output */
1719
1720         if (arg_property && !strv_find(arg_property, name))
1721                 return 0;
1722
1723         switch (dbus_message_iter_get_arg_type(iter)) {
1724
1725         case DBUS_TYPE_STRING: {
1726                 const char *s;
1727                 dbus_message_iter_get_basic(iter, &s);
1728
1729                 if (arg_all || s[0])
1730                         printf("%s=%s\n", name, s);
1731
1732                 return 0;
1733         }
1734
1735         case DBUS_TYPE_BOOLEAN: {
1736                 dbus_bool_t b;
1737                 dbus_message_iter_get_basic(iter, &b);
1738                 printf("%s=%s\n", name, yes_no(b));
1739
1740                 return 0;
1741         }
1742
1743         case DBUS_TYPE_UINT64: {
1744                 uint64_t u;
1745                 dbus_message_iter_get_basic(iter, &u);
1746
1747                 /* Yes, heuristics! But we can change this check
1748                  * should it turn out to not be sufficient */
1749
1750                 if (strstr(name, "Timestamp")) {
1751                         char timestamp[FORMAT_TIMESTAMP_MAX], *t;
1752
1753                         if ((t = format_timestamp(timestamp, sizeof(timestamp), u)) || arg_all)
1754                                 printf("%s=%s\n", name, strempty(t));
1755                 } else if (strstr(name, "USec")) {
1756                         char timespan[FORMAT_TIMESPAN_MAX];
1757
1758                         printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
1759                 } else
1760                         printf("%s=%llu\n", name, (unsigned long long) u);
1761
1762                 return 0;
1763         }
1764
1765         case DBUS_TYPE_UINT32: {
1766                 uint32_t u;
1767                 dbus_message_iter_get_basic(iter, &u);
1768
1769                 if (strstr(name, "UMask") || strstr(name, "Mode"))
1770                         printf("%s=%04o\n", name, u);
1771                 else
1772                         printf("%s=%u\n", name, (unsigned) u);
1773
1774                 return 0;
1775         }
1776
1777         case DBUS_TYPE_INT32: {
1778                 int32_t i;
1779                 dbus_message_iter_get_basic(iter, &i);
1780
1781                 printf("%s=%i\n", name, (int) i);
1782                 return 0;
1783         }
1784
1785         case DBUS_TYPE_STRUCT: {
1786                 DBusMessageIter sub;
1787                 dbus_message_iter_recurse(iter, &sub);
1788
1789                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
1790                         uint32_t u;
1791
1792                         dbus_message_iter_get_basic(&sub, &u);
1793
1794                         if (u)
1795                                 printf("%s=%u\n", name, (unsigned) u);
1796                         else if (arg_all)
1797                                 printf("%s=\n", name);
1798
1799                         return 0;
1800                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
1801                         const char *s;
1802
1803                         dbus_message_iter_get_basic(&sub, &s);
1804
1805                         if (arg_all || s[0])
1806                                 printf("%s=%s\n", name, s);
1807
1808                         return 0;
1809                 }
1810
1811                 break;
1812         }
1813
1814         case DBUS_TYPE_ARRAY:
1815
1816                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
1817                         DBusMessageIter sub;
1818                         bool space = false;
1819
1820                         dbus_message_iter_recurse(iter, &sub);
1821                         if (arg_all ||
1822                             dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1823                                 printf("%s=", name);
1824
1825                                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1826                                         const char *s;
1827
1828                                         assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
1829                                         dbus_message_iter_get_basic(&sub, &s);
1830                                         printf("%s%s", space ? " " : "", s);
1831
1832                                         space = true;
1833                                         dbus_message_iter_next(&sub);
1834                                 }
1835
1836                                 puts("");
1837                         }
1838
1839                         return 0;
1840
1841                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
1842                         DBusMessageIter sub;
1843
1844                         dbus_message_iter_recurse(iter, &sub);
1845                         if (arg_all ||
1846                             dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1847                                 printf("%s=", name);
1848
1849                                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1850                                         uint8_t u;
1851
1852                                         assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
1853                                         dbus_message_iter_get_basic(&sub, &u);
1854                                         printf("%02x", u);
1855
1856                                         dbus_message_iter_next(&sub);
1857                                 }
1858
1859                                 puts("");
1860                         }
1861
1862                         return 0;
1863
1864                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
1865                         DBusMessageIter sub, sub2;
1866
1867                         dbus_message_iter_recurse(iter, &sub);
1868                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1869                                 const char *type, *path;
1870
1871                                 dbus_message_iter_recurse(&sub, &sub2);
1872
1873                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
1874                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
1875                                         printf("%s=%s\n", type, path);
1876
1877                                 dbus_message_iter_next(&sub);
1878                         }
1879
1880                         return 0;
1881
1882                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
1883                         DBusMessageIter sub, sub2;
1884
1885                         dbus_message_iter_recurse(iter, &sub);
1886                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1887                                 const char *base;
1888                                 uint64_t value, next_elapse;
1889
1890                                 dbus_message_iter_recurse(&sub, &sub2);
1891
1892                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
1893                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
1894                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
1895                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
1896
1897                                         printf("%s={ value=%s ; next_elapse=%s }\n",
1898                                                base,
1899                                                format_timespan(timespan1, sizeof(timespan1), value),
1900                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
1901                                 }
1902
1903                                 dbus_message_iter_next(&sub);
1904                         }
1905
1906                         return 0;
1907
1908                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
1909                         DBusMessageIter sub;
1910
1911                         dbus_message_iter_recurse(iter, &sub);
1912                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1913                                 ExecStatusInfo info;
1914
1915                                 zero(info);
1916                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
1917                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
1918                                         char *t;
1919
1920                                         t = strv_join(info.argv, " ");
1921
1922                                         printf("%s={ path=%s ; argv[]=%s ; ignore=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
1923                                                name,
1924                                                strna(info.path),
1925                                                strna(t),
1926                                                yes_no(info.ignore),
1927                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
1928                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
1929                                                (unsigned) info. pid,
1930                                                sigchld_code_to_string(info.code),
1931                                                info.status,
1932                                                info.code == CLD_EXITED ? "" : "/",
1933                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
1934
1935                                         free(t);
1936                                 }
1937
1938                                 free(info.path);
1939                                 strv_free(info.argv);
1940
1941                                 dbus_message_iter_next(&sub);
1942                         }
1943
1944                         return 0;
1945                 }
1946
1947                 break;
1948         }
1949
1950         if (arg_all)
1951                 printf("%s=[unprintable]\n", name);
1952
1953         return 0;
1954 }
1955
1956 static int show_one(DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
1957         DBusMessage *m = NULL, *reply = NULL;
1958         const char *interface = "";
1959         int r;
1960         DBusError error;
1961         DBusMessageIter iter, sub, sub2, sub3;
1962         UnitStatusInfo info;
1963         ExecStatusInfo *p;
1964
1965         assert(bus);
1966         assert(path);
1967         assert(new_line);
1968
1969         zero(info);
1970         dbus_error_init(&error);
1971
1972         if (!(m = dbus_message_new_method_call(
1973                               "org.freedesktop.systemd1",
1974                               path,
1975                               "org.freedesktop.DBus.Properties",
1976                               "GetAll"))) {
1977                 log_error("Could not allocate message.");
1978                 r = -ENOMEM;
1979                 goto finish;
1980         }
1981
1982         if (!dbus_message_append_args(m,
1983                                       DBUS_TYPE_STRING, &interface,
1984                                       DBUS_TYPE_INVALID)) {
1985                 log_error("Could not append arguments to message.");
1986                 r = -ENOMEM;
1987                 goto finish;
1988         }
1989
1990         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1991                 log_error("Failed to issue method call: %s", error.message);
1992                 r = -EIO;
1993                 goto finish;
1994         }
1995
1996         if (!dbus_message_iter_init(reply, &iter) ||
1997             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1998             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
1999                 log_error("Failed to parse reply.");
2000                 r = -EIO;
2001                 goto finish;
2002         }
2003
2004         dbus_message_iter_recurse(&iter, &sub);
2005
2006         if (*new_line)
2007                 printf("\n");
2008
2009         *new_line = true;
2010
2011         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2012                 const char *name;
2013
2014                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
2015                         log_error("Failed to parse reply.");
2016                         r = -EIO;
2017                         goto finish;
2018                 }
2019
2020                 dbus_message_iter_recurse(&sub, &sub2);
2021
2022                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
2023                         log_error("Failed to parse reply.");
2024                         r = -EIO;
2025                         goto finish;
2026                 }
2027
2028                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
2029                         log_error("Failed to parse reply.");
2030                         r = -EIO;
2031                         goto finish;
2032                 }
2033
2034                 dbus_message_iter_recurse(&sub2, &sub3);
2035
2036                 if (show_properties)
2037                         r = print_property(name, &sub3);
2038                 else
2039                         r = status_property(name, &sub3, &info);
2040
2041                 if (r < 0) {
2042                         log_error("Failed to parse reply.");
2043                         r = -EIO;
2044                         goto finish;
2045                 }
2046
2047                 dbus_message_iter_next(&sub);
2048         }
2049
2050         if (!show_properties)
2051                 print_status_info(&info);
2052
2053         while ((p = info.exec)) {
2054                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
2055                 exec_status_info_free(p);
2056         }
2057
2058         r = 0;
2059
2060 finish:
2061         if (m)
2062                 dbus_message_unref(m);
2063
2064         if (reply)
2065                 dbus_message_unref(reply);
2066
2067         dbus_error_free(&error);
2068
2069         return r;
2070 }
2071
2072 static int show(DBusConnection *bus, char **args, unsigned n) {
2073         DBusMessage *m = NULL, *reply = NULL;
2074         int r;
2075         DBusError error;
2076         unsigned i;
2077         bool show_properties, new_line = false;
2078
2079         assert(bus);
2080         assert(args);
2081
2082         dbus_error_init(&error);
2083
2084         show_properties = !streq(args[0], "status");
2085
2086         if (show_properties && n <= 1) {
2087                 /* If not argument is specified inspect the manager
2088                  * itself */
2089
2090                 r = show_one(bus, "/org/freedesktop/systemd1", show_properties, &new_line);
2091                 goto finish;
2092         }
2093
2094         for (i = 1; i < n; i++) {
2095                 const char *path = NULL;
2096                 uint32_t id;
2097
2098                 if (!show_properties || safe_atou32(args[i], &id) < 0) {
2099
2100                         if (!(m = dbus_message_new_method_call(
2101                                               "org.freedesktop.systemd1",
2102                                               "/org/freedesktop/systemd1",
2103                                               "org.freedesktop.systemd1.Manager",
2104                                               "LoadUnit"))) {
2105                                 log_error("Could not allocate message.");
2106                                 r = -ENOMEM;
2107                                 goto finish;
2108                         }
2109
2110                         if (!dbus_message_append_args(m,
2111                                                       DBUS_TYPE_STRING, &args[i],
2112                                                       DBUS_TYPE_INVALID)) {
2113                                 log_error("Could not append arguments to message.");
2114                                 r = -ENOMEM;
2115                                 goto finish;
2116                         }
2117
2118                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2119
2120                                 if (!dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
2121                                         log_error("Failed to issue method call: %s", error.message);
2122                                         r = -EIO;
2123                                         goto finish;
2124                                 }
2125
2126                                 dbus_error_free(&error);
2127
2128                                 dbus_message_unref(m);
2129                                 if (!(m = dbus_message_new_method_call(
2130                                                       "org.freedesktop.systemd1",
2131                                                       "/org/freedesktop/systemd1",
2132                                                       "org.freedesktop.systemd1.Manager",
2133                                                       "GetUnit"))) {
2134                                         log_error("Could not allocate message.");
2135                                         r = -ENOMEM;
2136                                         goto finish;
2137                                 }
2138
2139                                 if (!dbus_message_append_args(m,
2140                                                               DBUS_TYPE_STRING, &args[i],
2141                                                               DBUS_TYPE_INVALID)) {
2142                                         log_error("Could not append arguments to message.");
2143                                         r = -ENOMEM;
2144                                         goto finish;
2145                                 }
2146
2147                                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2148                                         log_error("Failed to issue method call: %s", error.message);
2149                                         r = -EIO;
2150                                         goto finish;
2151                                 }
2152                         }
2153
2154                 } else {
2155
2156                         if (!(m = dbus_message_new_method_call(
2157                                               "org.freedesktop.systemd1",
2158                                               "/org/freedesktop/systemd1",
2159                                               "org.freedesktop.systemd1.Manager",
2160                                               "GetJob"))) {
2161                                 log_error("Could not allocate message.");
2162                                 r = -ENOMEM;
2163                                 goto finish;
2164                         }
2165
2166                         if (!dbus_message_append_args(m,
2167                                                       DBUS_TYPE_UINT32, &id,
2168                                                       DBUS_TYPE_INVALID)) {
2169                                 log_error("Could not append arguments to message.");
2170                                 r = -ENOMEM;
2171                                 goto finish;
2172                         }
2173
2174                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2175                                 log_error("Failed to issue method call: %s", error.message);
2176                                 r = -EIO;
2177                                 goto finish;
2178                         }
2179                 }
2180
2181                 if (!dbus_message_get_args(reply, &error,
2182                                            DBUS_TYPE_OBJECT_PATH, &path,
2183                                            DBUS_TYPE_INVALID)) {
2184                         log_error("Failed to parse reply: %s", error.message);
2185                         r = -EIO;
2186                         goto finish;
2187                 }
2188
2189                 if ((r = show_one(bus, path, show_properties, &new_line)) < 0)
2190                         goto finish;
2191
2192                 dbus_message_unref(m);
2193                 dbus_message_unref(reply);
2194                 m = reply = NULL;
2195         }
2196
2197         r = 0;
2198
2199 finish:
2200         if (m)
2201                 dbus_message_unref(m);
2202
2203         if (reply)
2204                 dbus_message_unref(reply);
2205
2206         dbus_error_free(&error);
2207
2208         return r;
2209 }
2210
2211 static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage *message, void *data) {
2212         DBusError error;
2213         DBusMessage *m = NULL, *reply = NULL;
2214
2215         assert(connection);
2216         assert(message);
2217
2218         dbus_error_init(&error);
2219
2220         log_debug("Got D-Bus request: %s.%s() on %s",
2221                   dbus_message_get_interface(message),
2222                   dbus_message_get_member(message),
2223                   dbus_message_get_path(message));
2224
2225         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
2226                 log_error("Warning! D-Bus connection terminated.");
2227                 dbus_connection_close(connection);
2228
2229         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitNew") ||
2230                    dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitRemoved")) {
2231                 const char *id, *path;
2232
2233                 if (!dbus_message_get_args(message, &error,
2234                                            DBUS_TYPE_STRING, &id,
2235                                            DBUS_TYPE_OBJECT_PATH, &path,
2236                                            DBUS_TYPE_INVALID))
2237                         log_error("Failed to parse message: %s", error.message);
2238                 else if (streq(dbus_message_get_member(message), "UnitNew"))
2239                         printf("Unit %s added.\n", id);
2240                 else
2241                         printf("Unit %s removed.\n", id);
2242
2243         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobNew") ||
2244                    dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
2245                 uint32_t id;
2246                 const char *path;
2247
2248                 if (!dbus_message_get_args(message, &error,
2249                                            DBUS_TYPE_UINT32, &id,
2250                                            DBUS_TYPE_OBJECT_PATH, &path,
2251                                            DBUS_TYPE_INVALID))
2252                         log_error("Failed to parse message: %s", error.message);
2253                 else if (streq(dbus_message_get_member(message), "JobNew"))
2254                         printf("Job %u added.\n", id);
2255                 else
2256                         printf("Job %u removed.\n", id);
2257
2258
2259         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Unit", "Changed") ||
2260                    dbus_message_is_signal(message, "org.freedesktop.systemd1.Job", "Changed")) {
2261
2262                 const char *path, *interface, *property = "Id";
2263                 DBusMessageIter iter, sub;
2264
2265                 path = dbus_message_get_path(message);
2266                 interface = dbus_message_get_interface(message);
2267
2268                 if (!(m = dbus_message_new_method_call(
2269                               "org.freedesktop.systemd1",
2270                               path,
2271                               "org.freedesktop.DBus.Properties",
2272                               "Get"))) {
2273                         log_error("Could not allocate message.");
2274                         goto oom;
2275                 }
2276
2277                 if (!dbus_message_append_args(m,
2278                                               DBUS_TYPE_STRING, &interface,
2279                                               DBUS_TYPE_STRING, &property,
2280                                               DBUS_TYPE_INVALID)) {
2281                         log_error("Could not append arguments to message.");
2282                         goto finish;
2283                 }
2284
2285                 if (!(reply = dbus_connection_send_with_reply_and_block(connection, m, -1, &error))) {
2286                         log_error("Failed to issue method call: %s", error.message);
2287                         goto finish;
2288                 }
2289
2290                 if (!dbus_message_iter_init(reply, &iter) ||
2291                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
2292                         log_error("Failed to parse reply.");
2293                         goto finish;
2294                 }
2295
2296                 dbus_message_iter_recurse(&iter, &sub);
2297
2298                 if (streq(interface, "org.freedesktop.systemd1.Unit")) {
2299                         const char *id;
2300
2301                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
2302                                 log_error("Failed to parse reply.");
2303                                 goto finish;
2304                         }
2305
2306                         dbus_message_iter_get_basic(&sub, &id);
2307                         printf("Unit %s changed.\n", id);
2308                 } else {
2309                         uint32_t id;
2310
2311                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32)  {
2312                                 log_error("Failed to parse reply.");
2313                                 goto finish;
2314                         }
2315
2316                         dbus_message_iter_get_basic(&sub, &id);
2317                         printf("Job %u changed.\n", id);
2318                 }
2319         }
2320
2321 finish:
2322         if (m)
2323                 dbus_message_unref(m);
2324
2325         if (reply)
2326                 dbus_message_unref(reply);
2327
2328         dbus_error_free(&error);
2329         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
2330
2331 oom:
2332         if (m)
2333                 dbus_message_unref(m);
2334
2335         if (reply)
2336                 dbus_message_unref(reply);
2337
2338         dbus_error_free(&error);
2339         return DBUS_HANDLER_RESULT_NEED_MEMORY;
2340 }
2341
2342 static int monitor(DBusConnection *bus, char **args, unsigned n) {
2343         DBusMessage *m = NULL, *reply = NULL;
2344         DBusError error;
2345         int r;
2346
2347         dbus_error_init(&error);
2348
2349         if (!private_bus) {
2350                 dbus_bus_add_match(bus,
2351                                    "type='signal',"
2352                                    "sender='org.freedesktop.systemd1',"
2353                                    "interface='org.freedesktop.systemd1.Manager',"
2354                                    "path='/org/freedesktop/systemd1'",
2355                                    &error);
2356
2357                 if (dbus_error_is_set(&error)) {
2358                         log_error("Failed to add match: %s", error.message);
2359                         r = -EIO;
2360                         goto finish;
2361                 }
2362
2363                 dbus_bus_add_match(bus,
2364                                    "type='signal',"
2365                                    "sender='org.freedesktop.systemd1',"
2366                                    "interface='org.freedesktop.systemd1.Unit',"
2367                                    "member='Changed'",
2368                                    &error);
2369
2370                 if (dbus_error_is_set(&error)) {
2371                         log_error("Failed to add match: %s", error.message);
2372                         r = -EIO;
2373                         goto finish;
2374                 }
2375
2376                 dbus_bus_add_match(bus,
2377                                    "type='signal',"
2378                                    "sender='org.freedesktop.systemd1',"
2379                                    "interface='org.freedesktop.systemd1.Job',"
2380                                    "member='Changed'",
2381                                    &error);
2382
2383                 if (dbus_error_is_set(&error)) {
2384                         log_error("Failed to add match: %s", error.message);
2385                         r = -EIO;
2386                         goto finish;
2387                 }
2388         }
2389
2390         if (!dbus_connection_add_filter(bus, monitor_filter, NULL, NULL)) {
2391                 log_error("Failed to add filter.");
2392                 r = -ENOMEM;
2393                 goto finish;
2394         }
2395
2396         if (!(m = dbus_message_new_method_call(
2397                               "org.freedesktop.systemd1",
2398                               "/org/freedesktop/systemd1",
2399                               "org.freedesktop.systemd1.Manager",
2400                               "Subscribe"))) {
2401                 log_error("Could not allocate message.");
2402                 r = -ENOMEM;
2403                 goto finish;
2404         }
2405
2406         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2407                 log_error("Failed to issue method call: %s", error.message);
2408                 r = -EIO;
2409                 goto finish;
2410         }
2411
2412         while (dbus_connection_read_write_dispatch(bus, -1))
2413                 ;
2414
2415         r = 0;
2416
2417 finish:
2418
2419         /* This is slightly dirty, since we don't undo the filter or the matches. */
2420
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 dump(DBusConnection *bus, char **args, unsigned n) {
2433         DBusMessage *m = NULL, *reply = NULL;
2434         DBusError error;
2435         int r;
2436         const char *text;
2437
2438         dbus_error_init(&error);
2439
2440         if (!(m = dbus_message_new_method_call(
2441                               "org.freedesktop.systemd1",
2442                               "/org/freedesktop/systemd1",
2443                               "org.freedesktop.systemd1.Manager",
2444                               "Dump"))) {
2445                 log_error("Could not allocate message.");
2446                 return -ENOMEM;
2447         }
2448
2449         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2450                 log_error("Failed to issue method call: %s", error.message);
2451                 r = -EIO;
2452                 goto finish;
2453         }
2454
2455         if (!dbus_message_get_args(reply, &error,
2456                                    DBUS_TYPE_STRING, &text,
2457                                    DBUS_TYPE_INVALID)) {
2458                 log_error("Failed to parse reply: %s", error.message);
2459                 r = -EIO;
2460                 goto finish;
2461         }
2462
2463         fputs(text, stdout);
2464
2465         r = 0;
2466
2467 finish:
2468         if (m)
2469                 dbus_message_unref(m);
2470
2471         if (reply)
2472                 dbus_message_unref(reply);
2473
2474         dbus_error_free(&error);
2475
2476         return r;
2477 }
2478
2479 static int snapshot(DBusConnection *bus, char **args, unsigned n) {
2480         DBusMessage *m = NULL, *reply = NULL;
2481         DBusError error;
2482         int r;
2483         const char *name = "", *path, *id;
2484         dbus_bool_t cleanup = FALSE;
2485         DBusMessageIter iter, sub;
2486         const char
2487                 *interface = "org.freedesktop.systemd1.Unit",
2488                 *property = "Id";
2489
2490         dbus_error_init(&error);
2491
2492         if (!(m = dbus_message_new_method_call(
2493                               "org.freedesktop.systemd1",
2494                               "/org/freedesktop/systemd1",
2495                               "org.freedesktop.systemd1.Manager",
2496                               "CreateSnapshot"))) {
2497                 log_error("Could not allocate message.");
2498                 return -ENOMEM;
2499         }
2500
2501         if (n > 1)
2502                 name = args[1];
2503
2504         if (!dbus_message_append_args(m,
2505                                       DBUS_TYPE_STRING, &name,
2506                                       DBUS_TYPE_BOOLEAN, &cleanup,
2507                                       DBUS_TYPE_INVALID)) {
2508                 log_error("Could not append arguments to message.");
2509                 r = -ENOMEM;
2510                 goto finish;
2511         }
2512
2513         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2514                 log_error("Failed to issue method call: %s", error.message);
2515                 r = -EIO;
2516                 goto finish;
2517         }
2518
2519         if (!dbus_message_get_args(reply, &error,
2520                                    DBUS_TYPE_OBJECT_PATH, &path,
2521                                    DBUS_TYPE_INVALID)) {
2522                 log_error("Failed to parse reply: %s", error.message);
2523                 r = -EIO;
2524                 goto finish;
2525         }
2526
2527         dbus_message_unref(m);
2528         if (!(m = dbus_message_new_method_call(
2529                               "org.freedesktop.systemd1",
2530                               path,
2531                               "org.freedesktop.DBus.Properties",
2532                               "Get"))) {
2533                 log_error("Could not allocate message.");
2534                 return -ENOMEM;
2535         }
2536
2537         if (!dbus_message_append_args(m,
2538                                       DBUS_TYPE_STRING, &interface,
2539                                       DBUS_TYPE_STRING, &property,
2540                                       DBUS_TYPE_INVALID)) {
2541                 log_error("Could not append arguments to message.");
2542                 r = -ENOMEM;
2543                 goto finish;
2544         }
2545
2546         dbus_message_unref(reply);
2547         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2548                 log_error("Failed to issue method call: %s", error.message);
2549                 r = -EIO;
2550                 goto finish;
2551         }
2552
2553         if (!dbus_message_iter_init(reply, &iter) ||
2554             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
2555                 log_error("Failed to parse reply.");
2556                 r = -EIO;
2557                 goto finish;
2558         }
2559
2560         dbus_message_iter_recurse(&iter, &sub);
2561
2562         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
2563                 log_error("Failed to parse reply.");
2564                 r = -EIO;
2565                 goto finish;
2566         }
2567
2568         dbus_message_iter_get_basic(&sub, &id);
2569
2570         if (!arg_quiet)
2571                 puts(id);
2572         r = 0;
2573
2574 finish:
2575         if (m)
2576                 dbus_message_unref(m);
2577
2578         if (reply)
2579                 dbus_message_unref(reply);
2580
2581         dbus_error_free(&error);
2582
2583         return r;
2584 }
2585
2586 static int delete_snapshot(DBusConnection *bus, char **args, unsigned n) {
2587         DBusMessage *m = NULL, *reply = NULL;
2588         int r;
2589         DBusError error;
2590         unsigned i;
2591
2592         assert(bus);
2593         assert(args);
2594
2595         dbus_error_init(&error);
2596
2597         for (i = 1; i < n; i++) {
2598                 const char *path = NULL;
2599
2600                 if (!(m = dbus_message_new_method_call(
2601                                       "org.freedesktop.systemd1",
2602                                       "/org/freedesktop/systemd1",
2603                                       "org.freedesktop.systemd1.Manager",
2604                                       "GetUnit"))) {
2605                         log_error("Could not allocate message.");
2606                         r = -ENOMEM;
2607                         goto finish;
2608                 }
2609
2610                 if (!dbus_message_append_args(m,
2611                                               DBUS_TYPE_STRING, &args[i],
2612                                               DBUS_TYPE_INVALID)) {
2613                         log_error("Could not append arguments to message.");
2614                         r = -ENOMEM;
2615                         goto finish;
2616                 }
2617
2618                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2619                         log_error("Failed to issue method call: %s", error.message);
2620                         r = -EIO;
2621                         goto finish;
2622                 }
2623
2624                 if (!dbus_message_get_args(reply, &error,
2625                                            DBUS_TYPE_OBJECT_PATH, &path,
2626                                            DBUS_TYPE_INVALID)) {
2627                         log_error("Failed to parse reply: %s", error.message);
2628                         r = -EIO;
2629                         goto finish;
2630                 }
2631
2632                 dbus_message_unref(m);
2633                 if (!(m = dbus_message_new_method_call(
2634                                       "org.freedesktop.systemd1",
2635                                       path,
2636                                       "org.freedesktop.systemd1.Snapshot",
2637                                       "Remove"))) {
2638                         log_error("Could not allocate message.");
2639                         r = -ENOMEM;
2640                         goto finish;
2641                 }
2642
2643                 dbus_message_unref(reply);
2644                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2645                         log_error("Failed to issue method call: %s", error.message);
2646                         r = -EIO;
2647                         goto finish;
2648                 }
2649
2650                 dbus_message_unref(m);
2651                 dbus_message_unref(reply);
2652                 m = reply = NULL;
2653         }
2654
2655         r = 0;
2656
2657 finish:
2658         if (m)
2659                 dbus_message_unref(m);
2660
2661         if (reply)
2662                 dbus_message_unref(reply);
2663
2664         dbus_error_free(&error);
2665
2666         return r;
2667 }
2668
2669 static int daemon_reload(DBusConnection *bus, char **args, unsigned n) {
2670         DBusMessage *m = NULL, *reply = NULL;
2671         DBusError error;
2672         int r;
2673         const char *method;
2674
2675         dbus_error_init(&error);
2676
2677         if (arg_action == ACTION_RELOAD)
2678                 method = "Reload";
2679         else if (arg_action == ACTION_REEXEC)
2680                 method = "Reexecute";
2681         else {
2682                 assert(arg_action == ACTION_SYSTEMCTL);
2683
2684                 method =
2685                         streq(args[0], "clear-jobs")        ||
2686                         streq(args[0], "cancel")            ? "ClearJobs" :
2687                         streq(args[0], "daemon-reexec")     ? "Reexecute" :
2688                         streq(args[0], "reset-maintenance") ? "ResetMaintenance" :
2689                         streq(args[0], "daemon-exit")       ? "Exit" :
2690                                                               "Reload";
2691         }
2692
2693         if (!(m = dbus_message_new_method_call(
2694                               "org.freedesktop.systemd1",
2695                               "/org/freedesktop/systemd1",
2696                               "org.freedesktop.systemd1.Manager",
2697                               method))) {
2698                 log_error("Could not allocate message.");
2699                 return -ENOMEM;
2700         }
2701
2702         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2703
2704                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
2705                         /* There's always a fallback possible for
2706                          * legacy actions. */
2707                         r = 0;
2708                         goto finish;
2709                 }
2710
2711                 log_error("Failed to issue method call: %s", error.message);
2712                 r = -EIO;
2713                 goto finish;
2714         }
2715
2716         r = 1;
2717
2718 finish:
2719         if (m)
2720                 dbus_message_unref(m);
2721
2722         if (reply)
2723                 dbus_message_unref(reply);
2724
2725         dbus_error_free(&error);
2726
2727         return r;
2728 }
2729
2730 static int reset_maintenance(DBusConnection *bus, char **args, unsigned n) {
2731         DBusMessage *m = NULL, *reply = NULL;
2732         unsigned i;
2733         int r;
2734         DBusError error;
2735
2736         assert(bus);
2737         dbus_error_init(&error);
2738
2739         if (n <= 1)
2740                 return daemon_reload(bus, args, n);
2741
2742         for (i = 1; i < n; i++) {
2743
2744                 if (!(m = dbus_message_new_method_call(
2745                                       "org.freedesktop.systemd1",
2746                                       "/org/freedesktop/systemd1",
2747                                       "org.freedesktop.systemd1.Manager",
2748                                       "ResetMaintenanceUnit"))) {
2749                         log_error("Could not allocate message.");
2750                         r = -ENOMEM;
2751                         goto finish;
2752                 }
2753
2754                 if (!dbus_message_append_args(m,
2755                                               DBUS_TYPE_STRING, args + i,
2756                                               DBUS_TYPE_INVALID)) {
2757                         log_error("Could not append arguments to message.");
2758                         r = -ENOMEM;
2759                         goto finish;
2760                 }
2761
2762                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2763                         log_error("Failed to issue method call: %s", error.message);
2764                         r = -EIO;
2765                         goto finish;
2766                 }
2767
2768                 dbus_message_unref(m);
2769                 dbus_message_unref(reply);
2770                 m = reply = NULL;
2771         }
2772
2773         r = 0;
2774
2775 finish:
2776         if (m)
2777                 dbus_message_unref(m);
2778
2779         if (reply)
2780                 dbus_message_unref(reply);
2781
2782         dbus_error_free(&error);
2783
2784         return r;
2785 }
2786
2787 static int show_enviroment(DBusConnection *bus, char **args, unsigned n) {
2788         DBusMessage *m = NULL, *reply = NULL;
2789         DBusError error;
2790         DBusMessageIter iter, sub, sub2;
2791         int r;
2792         const char
2793                 *interface = "org.freedesktop.systemd1.Manager",
2794                 *property = "Environment";
2795
2796         dbus_error_init(&error);
2797
2798         if (!(m = dbus_message_new_method_call(
2799                               "org.freedesktop.systemd1",
2800                               "/org/freedesktop/systemd1",
2801                               "org.freedesktop.DBus.Properties",
2802                               "Get"))) {
2803                 log_error("Could not allocate message.");
2804                 return -ENOMEM;
2805         }
2806
2807         if (!dbus_message_append_args(m,
2808                                       DBUS_TYPE_STRING, &interface,
2809                                       DBUS_TYPE_STRING, &property,
2810                                       DBUS_TYPE_INVALID)) {
2811                 log_error("Could not append arguments to message.");
2812                 r = -ENOMEM;
2813                 goto finish;
2814         }
2815
2816         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2817                 log_error("Failed to issue method call: %s", error.message);
2818                 r = -EIO;
2819                 goto finish;
2820         }
2821
2822         if (!dbus_message_iter_init(reply, &iter) ||
2823             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
2824                 log_error("Failed to parse reply.");
2825                 r = -EIO;
2826                 goto finish;
2827         }
2828
2829         dbus_message_iter_recurse(&iter, &sub);
2830
2831         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
2832             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
2833                 log_error("Failed to parse reply.");
2834                 r = -EIO;
2835                 goto finish;
2836         }
2837
2838         dbus_message_iter_recurse(&sub, &sub2);
2839
2840         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
2841                 const char *text;
2842
2843                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
2844                         log_error("Failed to parse reply.");
2845                         r = -EIO;
2846                         goto finish;
2847                 }
2848
2849                 dbus_message_iter_get_basic(&sub2, &text);
2850                 printf("%s\n", text);
2851
2852                 dbus_message_iter_next(&sub2);
2853         }
2854
2855         r = 0;
2856
2857 finish:
2858         if (m)
2859                 dbus_message_unref(m);
2860
2861         if (reply)
2862                 dbus_message_unref(reply);
2863
2864         dbus_error_free(&error);
2865
2866         return r;
2867 }
2868
2869 static int set_environment(DBusConnection *bus, char **args, unsigned n) {
2870         DBusMessage *m = NULL, *reply = NULL;
2871         DBusError error;
2872         int r;
2873         const char *method;
2874         DBusMessageIter iter, sub;
2875         unsigned i;
2876
2877         dbus_error_init(&error);
2878
2879         method = streq(args[0], "set-environment")
2880                 ? "SetEnvironment"
2881                 : "UnsetEnvironment";
2882
2883         if (!(m = dbus_message_new_method_call(
2884                               "org.freedesktop.systemd1",
2885                               "/org/freedesktop/systemd1",
2886                               "org.freedesktop.systemd1.Manager",
2887                               method))) {
2888
2889                 log_error("Could not allocate message.");
2890                 return -ENOMEM;
2891         }
2892
2893         dbus_message_iter_init_append(m, &iter);
2894
2895         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
2896                 log_error("Could not append arguments to message.");
2897                 r = -ENOMEM;
2898                 goto finish;
2899         }
2900
2901         for (i = 1; i < n; i++)
2902                 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &args[i])) {
2903                         log_error("Could not append arguments to message.");
2904                         r = -ENOMEM;
2905                         goto finish;
2906                 }
2907
2908         if (!dbus_message_iter_close_container(&iter, &sub)) {
2909                 log_error("Could not append arguments to message.");
2910                 r = -ENOMEM;
2911                 goto finish;
2912         }
2913
2914         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2915                 log_error("Failed to issue method call: %s", error.message);
2916                 r = -EIO;
2917                 goto finish;
2918         }
2919
2920         r = 0;
2921
2922 finish:
2923         if (m)
2924                 dbus_message_unref(m);
2925
2926         if (reply)
2927                 dbus_message_unref(reply);
2928
2929         dbus_error_free(&error);
2930
2931         return r;
2932 }
2933
2934 typedef struct {
2935         char *name;
2936         char *path;
2937
2938         char **aliases;
2939         char **wanted_by;
2940 } InstallInfo;
2941
2942 static Hashmap *will_install = NULL, *have_installed = NULL;
2943 static Set *remove_symlinks_to = NULL;
2944
2945 static void install_info_free(InstallInfo *i) {
2946         assert(i);
2947
2948         free(i->name);
2949         free(i->path);
2950         strv_free(i->aliases);
2951         strv_free(i->wanted_by);
2952         free(i);
2953 }
2954
2955 static void install_info_hashmap_free(Hashmap *m) {
2956         InstallInfo *i;
2957
2958         while ((i = hashmap_steal_first(m)))
2959                 install_info_free(i);
2960
2961         hashmap_free(m);
2962 }
2963
2964 static bool unit_name_valid(const char *name) {
2965
2966         /* This is a minimal version of unit_name_valid() from
2967          * unit-name.c */
2968
2969         if (!*name)
2970                 return false;
2971
2972         if (ignore_file(name))
2973                 return false;
2974
2975         return true;
2976 }
2977
2978 static int install_info_add(const char *name) {
2979         InstallInfo *i;
2980         int r;
2981
2982         assert(will_install);
2983
2984         if (!unit_name_valid(name))
2985                 return -EINVAL;
2986
2987         if (hashmap_get(have_installed, name) ||
2988             hashmap_get(will_install, name))
2989                 return 0;
2990
2991         if (!(i = new0(InstallInfo, 1))) {
2992                 r = -ENOMEM;
2993                 goto fail;
2994         }
2995
2996         if (!(i->name = strdup(name))) {
2997                 r = -ENOMEM;
2998                 goto fail;
2999         }
3000
3001         if ((r = hashmap_put(will_install, i->name, i)) < 0)
3002                 goto fail;
3003
3004         return 0;
3005
3006 fail:
3007         if (i)
3008                 install_info_free(i);
3009
3010         return r;
3011 }
3012
3013 static int config_parse_also(
3014                 const char *filename,
3015                 unsigned line,
3016                 const char *section,
3017                 const char *lvalue,
3018                 const char *rvalue,
3019                 void *data,
3020                 void *userdata) {
3021
3022         char *w;
3023         size_t l;
3024         char *state;
3025
3026         assert(filename);
3027         assert(lvalue);
3028         assert(rvalue);
3029
3030         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
3031                 char *n;
3032                 int r;
3033
3034                 if (!(n = strndup(w, l)))
3035                         return -ENOMEM;
3036
3037                 r = install_info_add(n);
3038                 free(n);
3039
3040                 if (r < 0)
3041                         return r;
3042         }
3043
3044         return 0;
3045 }
3046
3047 static int mark_symlink_for_removal(const char *p) {
3048         char *n;
3049         int r;
3050
3051         assert(p);
3052         assert(path_is_absolute(p));
3053
3054         if (!remove_symlinks_to)
3055                 return 0;
3056
3057         if (!(n = strdup(p)))
3058                 return -ENOMEM;
3059
3060         path_kill_slashes(n);
3061
3062         if ((r = set_put(remove_symlinks_to, n)) < 0) {
3063                 free(n);
3064                 return r == -EEXIST ? 0 : r;
3065         }
3066
3067         return 0;
3068 }
3069
3070 static int remove_marked_symlinks_fd(int fd, const char *config_path, const char *root, bool *deleted) {
3071         int r = 0;
3072         DIR *d;
3073         struct dirent *de;
3074
3075         assert(fd >= 0);
3076         assert(root);
3077         assert(deleted);
3078
3079         if (!(d = fdopendir(fd))) {
3080                 close_nointr_nofail(fd);
3081                 return -errno;
3082         }
3083
3084         rewinddir(d);
3085
3086         while ((de = readdir(d))) {
3087                 bool is_dir = false, is_link = false;
3088
3089                 if (ignore_file(de->d_name))
3090                         continue;
3091
3092                 if (de->d_type == DT_LNK)
3093                         is_link = true;
3094                 else if (de->d_type == DT_DIR)
3095                         is_dir = true;
3096                 else if (de->d_type == DT_UNKNOWN) {
3097                         struct stat st;
3098
3099                         if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
3100                                 log_error("Failed to stat %s/%s: %m", root, de->d_name);
3101
3102                                 if (r == 0)
3103                                         r = -errno;
3104                                 continue;
3105                         }
3106
3107                         is_link = S_ISLNK(st.st_mode);
3108                         is_dir = S_ISDIR(st.st_mode);
3109                 } else
3110                         continue;
3111
3112                 if (is_dir) {
3113                         int nfd, q;
3114                         char *p;
3115
3116                         if ((nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW)) < 0) {
3117                                 log_error("Failed to open %s/%s: %m", root, de->d_name);
3118
3119                                 if (r == 0)
3120                                         r = -errno;
3121                                 continue;
3122                         }
3123
3124                         if (asprintf(&p, "%s/%s", root, de->d_name) < 0) {
3125                                 log_error("Failed to allocate directory string.");
3126                                 close_nointr_nofail(nfd);
3127                                 r = -ENOMEM;
3128                                 break;
3129                         }
3130
3131                         /* This will close nfd, regardless whether it succeeds or not */
3132                         q = remove_marked_symlinks_fd(nfd, config_path, p, deleted);
3133                         free(p);
3134
3135                         if (r == 0)
3136                                 q = r;
3137
3138                 } else if (is_link) {
3139                         char *p, *dest, *c;
3140                         int q;
3141
3142                         if (asprintf(&p, "%s/%s", root, de->d_name) < 0) {
3143                                 log_error("Failed to allocate symlink string.");
3144                                 r = -ENOMEM;
3145                                 break;
3146                         }
3147
3148                         if ((q = readlink_and_make_absolute(p, &dest)) < 0) {
3149                                 log_error("Cannot read symlink %s: %s", p, strerror(-q));
3150                                 free(p);
3151
3152                                 if (r == 0)
3153                                         r = q;
3154                                 continue;
3155                         }
3156
3157                         if ((c = canonicalize_file_name(dest))) {
3158                                 /* This might fail if the destination
3159                                  * is already removed */
3160
3161                                 free(dest);
3162                                 dest = c;
3163                         }
3164
3165                         path_kill_slashes(dest);
3166                         if (set_get(remove_symlinks_to, dest)) {
3167
3168                                 if (!arg_quiet)
3169                                         log_info("rm '%s'", p);
3170
3171                                 if (unlink(p) < 0) {
3172                                         log_error("Cannot unlink symlink %s: %m", p);
3173
3174                                         if (r == 0)
3175                                                 r = -errno;
3176                                 } else {
3177                                         rmdir_parents(p, config_path);
3178                                         path_kill_slashes(p);
3179
3180                                         if (!set_get(remove_symlinks_to, p)) {
3181
3182                                                 if ((r = mark_symlink_for_removal(p)) < 0) {
3183                                                         if (r == 0)
3184                                                                 r = q;
3185                                                 } else
3186                                                         *deleted = true;
3187                                         }
3188                                 }
3189                         }
3190
3191                         free(p);
3192                         free(dest);
3193                 }
3194         }
3195
3196         closedir(d);
3197
3198         return r;
3199 }
3200
3201 static int remove_marked_symlinks(const char *config_path) {
3202         int fd, r = 0;
3203         bool deleted;
3204
3205         assert(config_path);
3206
3207         if (set_size(remove_symlinks_to) <= 0)
3208                 return 0;
3209
3210         if ((fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW)) < 0)
3211                 return -errno;
3212
3213         do {
3214                 int q, cfd;
3215                 deleted = false;
3216
3217                 if ((cfd = dup(fd)) < 0) {
3218                         r = -errno;
3219                         break;
3220                 }
3221
3222                 /* This takes possession of cfd and closes it */
3223                 if ((q = remove_marked_symlinks_fd(cfd, config_path, config_path, &deleted)) < 0) {
3224                         if (r == 0)
3225                                 r = q;
3226                 }
3227         } while (deleted);
3228
3229         close_nointr_nofail(fd);
3230
3231         return r;
3232 }
3233
3234 static int create_symlink(const char *verb, const char *old_path, const char *new_path) {
3235         int r;
3236
3237         assert(old_path);
3238         assert(new_path);
3239         assert(verb);
3240
3241         if (streq(verb, "enable")) {
3242                 char *dest;
3243
3244                 mkdir_parents(new_path, 0755);
3245
3246                 if (symlink(old_path, new_path) >= 0) {
3247
3248                         if (!arg_quiet)
3249                                 log_info("ln -s '%s' '%s'", old_path, new_path);
3250
3251                         return 0;
3252                 }
3253
3254                 if (errno != EEXIST) {
3255                         log_error("Cannot link %s to %s: %m", old_path, new_path);
3256                         return -errno;
3257                 }
3258
3259                 if ((r = readlink_and_make_absolute(new_path, &dest)) < 0) {
3260
3261                         if (errno == EINVAL) {
3262                                 log_error("Cannot link %s to %s, file exists already and is not a symlink.", old_path, new_path);
3263                                 return -EEXIST;
3264                         }
3265
3266                         log_error("readlink() failed: %s", strerror(-r));
3267                         return r;
3268                 }
3269
3270                 if (streq(dest, old_path)) {
3271                         free(dest);
3272                         return 0;
3273                 }
3274
3275                 if (!arg_force) {
3276                         log_error("Cannot link %s to %s, symlink exists already and points to %s.", old_path, new_path, dest);
3277                         free(dest);
3278                         return -EEXIST;
3279                 }
3280
3281                 free(dest);
3282                 unlink(new_path);
3283
3284                 if (!arg_quiet)
3285                         log_info("ln -s '%s' '%s'", old_path, new_path);
3286
3287                 if (symlink(old_path, new_path) >= 0)
3288                         return 0;
3289
3290                 log_error("Cannot link %s to %s: %m", old_path, new_path);
3291                 return -errno;
3292
3293         } else if (streq(verb, "disable")) {
3294                 char *dest;
3295
3296                 if ((r = mark_symlink_for_removal(old_path)) < 0)
3297                         return r;
3298
3299                 if ((r = readlink_and_make_absolute(new_path, &dest)) < 0) {
3300                         if (errno == ENOENT)
3301                                 return 0;
3302
3303                         if (errno == EINVAL) {
3304                                 log_warning("File %s not a symlink, ignoring.", old_path);
3305                                 return 0;
3306                         }
3307
3308                         log_error("readlink() failed: %s", strerror(-r));
3309                         return r;
3310                 }
3311
3312                 if (!streq(dest, old_path)) {
3313                         log_warning("File %s not a symlink to %s but points to %s, ignoring.", new_path, old_path, dest);
3314                         free(dest);
3315                         return 0;
3316                 }
3317
3318                 free(dest);
3319
3320                 if ((r = mark_symlink_for_removal(new_path)) < 0)
3321                         return r;
3322
3323                 if (!arg_quiet)
3324                         log_info("rm '%s'", new_path);
3325
3326                 if (unlink(new_path) >= 0)
3327                         return 0;
3328
3329                 log_error("Cannot unlink %s: %m", new_path);
3330                 return -errno;
3331
3332         } else if (streq(verb, "is-enabled")) {
3333                 char *dest;
3334
3335                 if ((r = readlink_and_make_absolute(new_path, &dest)) < 0) {
3336
3337                         if (errno == ENOENT || errno == EINVAL)
3338                                 return 0;
3339
3340                         log_error("readlink() failed: %s", strerror(-r));
3341                         return r;
3342                 }
3343
3344                 if (streq(dest, old_path)) {
3345                         free(dest);
3346                         return 1;
3347                 }
3348
3349                 return 0;
3350         }
3351
3352         assert_not_reached("Unknown action.");
3353 }
3354
3355 static int install_info_symlink_alias(const char *verb, InstallInfo *i, const char *config_path) {
3356         char **s;
3357         char *alias_path = NULL;
3358         int r;
3359
3360         assert(verb);
3361         assert(i);
3362         assert(config_path);
3363
3364         STRV_FOREACH(s, i->aliases) {
3365
3366                 if (!unit_name_valid(*s)) {
3367                         log_error("Invalid name %s.", *s);
3368                         r = -EINVAL;
3369                         goto finish;
3370                 }
3371
3372                 free(alias_path);
3373                 if (!(alias_path = path_make_absolute(*s, config_path))) {
3374                         log_error("Out of memory");
3375                         r = -ENOMEM;
3376                         goto finish;
3377                 }
3378
3379                 if ((r = create_symlink(verb, i->path, alias_path)) != 0)
3380                         goto finish;
3381
3382                 if (streq(verb, "disable"))
3383                         rmdir_parents(alias_path, config_path);
3384         }
3385
3386         r = 0;
3387
3388 finish:
3389         free(alias_path);
3390
3391         return r;
3392 }
3393
3394 static int install_info_symlink_wants(const char *verb, InstallInfo *i, const char *config_path) {
3395         char **s;
3396         char *alias_path = NULL;
3397         int r;
3398
3399         assert(verb);
3400         assert(i);
3401         assert(config_path);
3402
3403         STRV_FOREACH(s, i->wanted_by) {
3404                 if (!unit_name_valid(*s)) {
3405                         log_error("Invalid name %s.", *s);
3406                         r = -EINVAL;
3407                         goto finish;
3408                 }
3409
3410                 free(alias_path);
3411                 alias_path = NULL;
3412
3413                 if (asprintf(&alias_path, "%s/%s.wants/%s", config_path, *s, i->name) < 0) {
3414                         log_error("Out of memory");
3415                         r = -ENOMEM;
3416                         goto finish;
3417                 }
3418
3419                 if ((r = create_symlink(verb, i->path, alias_path)) != 0)
3420                         goto finish;
3421
3422                 if (streq(verb, "disable"))
3423                         rmdir_parents(alias_path, config_path);
3424         }
3425
3426         r = 0;
3427
3428 finish:
3429         free(alias_path);
3430
3431         return r;
3432 }
3433
3434 static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo *i, const char *config_path) {
3435
3436         const ConfigItem items[] = {
3437                 { "Alias",    config_parse_strv, &i->aliases,   "Install" },
3438                 { "WantedBy", config_parse_strv, &i->wanted_by, "Install" },
3439                 { "Also",     config_parse_also, NULL,          "Install" },
3440
3441                 { NULL, NULL, NULL, NULL }
3442         };
3443
3444         char **p;
3445         char *filename = NULL;
3446         FILE *f = NULL;
3447         int r;
3448
3449         assert(paths);
3450         assert(i);
3451
3452         STRV_FOREACH(p, paths->unit_path) {
3453                 int fd;
3454
3455                 if (!(filename = path_make_absolute(i->name, *p))) {
3456                         log_error("Out of memory");
3457                         return -ENOMEM;
3458                 }
3459
3460                 /* Ensure that we don't follow symlinks */
3461                 if ((fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NOCTTY)) >= 0)
3462                         if ((f = fdopen(fd, "re")))
3463                                 break;
3464
3465                 if (errno == ELOOP) {
3466                         log_error("Refusing to operate on symlinks, please pass unit names or absolute paths to unit files.");
3467                         free(filename);
3468                         return -errno;
3469                 }
3470
3471                 if (errno != ENOENT) {
3472                         log_error("Failed to open %s: %m", filename);
3473                         free(filename);
3474                         return -errno;
3475                 }
3476
3477                 free(filename);
3478                 filename = NULL;
3479         }
3480
3481         if (!f) {
3482                 log_error("Couldn't find %s.", i->name);
3483                 return -ENOENT;
3484         }
3485
3486         i->path = filename;
3487
3488         if ((r = config_parse(filename, f, NULL, items, true, i)) < 0) {
3489                 fclose(f);
3490                 return r;
3491         }
3492
3493         fclose(f);
3494
3495         if ((r = install_info_symlink_alias(verb, i, config_path)) != 0)
3496                 return r;
3497
3498         if ((r = install_info_symlink_wants(verb, i, config_path)) != 0)
3499                 return r;
3500
3501         if ((r = mark_symlink_for_removal(filename)) < 0)
3502                 return r;
3503
3504         if ((r = remove_marked_symlinks(config_path)) < 0)
3505                 return r;
3506
3507         return 0;
3508 }
3509
3510 static char *get_config_path(void) {
3511
3512         if (arg_session && arg_global)
3513                 return strdup(SESSION_CONFIG_UNIT_PATH);
3514
3515         if (arg_session) {
3516                 char *p;
3517
3518                 if (session_config_home(&p) < 0)
3519                         return NULL;
3520
3521                 return p;
3522         }
3523
3524         return strdup(SYSTEM_CONFIG_UNIT_PATH);
3525 }
3526
3527 static int enable_unit(DBusConnection *bus, char **args, unsigned n) {
3528         DBusError error;
3529         int r;
3530         LookupPaths paths;
3531         char *config_path = NULL;
3532         unsigned j;
3533         InstallInfo *i;
3534         const char *verb = args[0];
3535
3536         dbus_error_init(&error);
3537
3538         zero(paths);
3539         if ((r = lookup_paths_init(&paths, arg_session ? MANAGER_SESSION : MANAGER_SYSTEM)) < 0) {
3540                 log_error("Failed to determine lookup paths: %s", strerror(-r));
3541                 goto finish;
3542         }
3543
3544         if (!(config_path = get_config_path())) {
3545                 log_error("Failed to determine config path");
3546                 r = -ENOMEM;
3547                 goto finish;
3548         }
3549
3550         will_install = hashmap_new(string_hash_func, string_compare_func);
3551         have_installed = hashmap_new(string_hash_func, string_compare_func);
3552
3553         if (!will_install || !have_installed) {
3554                 log_error("Failed to allocate unit sets.");
3555                 r = -ENOMEM;
3556                 goto finish;
3557         }
3558
3559         if (!arg_defaults && streq(verb, "disable"))
3560                 if (!(remove_symlinks_to = set_new(string_hash_func, string_compare_func))) {
3561                         log_error("Failed to allocate symlink sets.");
3562                         r = -ENOMEM;
3563                         goto finish;
3564                 }
3565
3566         for (j = 1; j < n; j++)
3567                 if ((r = install_info_add(args[j])) < 0)
3568                         goto finish;
3569
3570         while ((i = hashmap_first(will_install))) {
3571                 int q;
3572
3573                 assert_se(hashmap_move_one(have_installed, will_install, i->name) == 0);
3574
3575                 if ((q = install_info_apply(verb, &paths, i, config_path)) != 0) {
3576
3577                         if (q < 0) {
3578                                 if (r == 0)
3579                                         r = q;
3580                                 goto finish;
3581                         }
3582
3583                         /* In test mode and found something */
3584                         r = 1;
3585                         break;
3586                 }
3587         }
3588
3589         if (streq(verb, "is-enabled"))
3590                 r = r > 0 ? 0 : -ENOENT;
3591         else if (bus &&
3592                  /* Don't try to reload anything if the user asked us to not do this */
3593                  !arg_no_reload &&
3594                  /* Don't try to reload anything when updating a unit globally */
3595                  !arg_global &&
3596                  /* Don't try to reload anything if we are called for system changes but the system wasn't booted with systemd */
3597                  (arg_session || sd_booted() > 0) &&
3598                  /* Don't try to reload anything if we are running in a chroot environment */
3599                  (arg_session || running_in_chroot() <= 0) ) {
3600                 int q;
3601
3602                 if ((q = daemon_reload(bus, args, n)) < 0)
3603                         r = q;
3604         }
3605
3606 finish:
3607         install_info_hashmap_free(will_install);
3608         install_info_hashmap_free(have_installed);
3609
3610         set_free_free(remove_symlinks_to);
3611
3612         lookup_paths_free(&paths);
3613
3614         free(config_path);
3615
3616         return r;
3617 }
3618
3619 static int systemctl_help(void) {
3620
3621         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
3622                "Send control commands to or query the systemd manager.\n\n"
3623                "  -h --help          Show this help\n"
3624                "  -t --type=TYPE     List only units of a particular type\n"
3625                "  -p --property=NAME Show only properties by this name\n"
3626                "  -a --all           Show all units/properties, including dead/empty ones\n"
3627                "     --full          Don't ellipsize unit names on output\n"
3628                "     --fail          When queueing a new job, fail if conflicting jobs are\n"
3629                "                     pending\n"
3630                "  -q --quiet         Suppress output\n"
3631                "     --no-block      Do not wait until operation finished\n"
3632                "     --system        Connect to system bus\n"
3633                "     --session       Connect to session bus\n"
3634                "     --order         When generating graph for dot, show only order\n"
3635                "     --require       When generating graph for dot, show only requirement\n"
3636                "     --no-wall       Don't send wall message before halt/power-off/reboot\n"
3637                "     --global        Enable/disable unit files globally\n"
3638                "     --no-reload     When enabling/disabling unit files, don't reload daemon\n"
3639                "                     configuration\n"
3640                "     --force         When enabling unit files, override existing symlinks\n"
3641                "     --defaults      When disabling unit files, remove default symlinks only\n\n"
3642                "Commands:\n"
3643                "  list-units                      List units\n"
3644                "  start [NAME...]                 Start (activate) one or more units\n"
3645                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
3646                "  reload [NAME...]                Reload one or more units\n"
3647                "  restart [NAME...]               Start or restart one or more units\n"
3648                "  try-restart [NAME...]           Restart one or more units if active\n"
3649                "  reload-or-restart [NAME...]     Reload one or more units is possible,\n"
3650                "                                  otherwise start or restart\n"
3651                "  reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
3652                "                                  otherwise restart if active\n"
3653                "  isolate [NAME]                  Start one unit and stop all others\n"
3654                "  is-active [NAME...]             Check whether units are active\n"
3655                "  status [NAME...]                Show runtime status of one or more units\n"
3656                "  show [NAME...|JOB...]           Show properties of one or more\n"
3657                "                                  units/jobs or the manager\n"
3658                "  reset-maintenance [NAME...]     Reset maintenance state for all, one,\n"
3659                "                                  or more units\n"
3660                "  enable [NAME...]                Enable one or more unit files\n"
3661                "  disable [NAME...]               Disable one or more unit files\n"
3662                "  is-enabled [NAME...]            Check whether unit files are enabled\n"
3663                "  load [NAME...]                  Load one or more units\n"
3664                "  list-jobs                       List jobs\n"
3665                "  cancel [JOB...]                 Cancel all, one, or more jobs\n"
3666                "  monitor                         Monitor unit/job changes\n"
3667                "  dump                            Dump server status\n"
3668                "  dot                             Dump dependency graph for dot(1)\n"
3669                "  snapshot [NAME]                 Create a snapshot\n"
3670                "  delete [NAME...]                Remove one or more snapshots\n"
3671                "  daemon-reload                   Reload systemd manager configuration\n"
3672                "  daemon-reexec                   Reexecute systemd manager\n"
3673                "  daemon-exit                     Ask the systemd manager to quit\n"
3674                "  show-environment                Dump environment\n"
3675                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
3676                "  unset-environment [NAME...]     Unset one or more environment variables\n"
3677                "  halt                            Shut down and halt the system\n"
3678                "  poweroff                        Shut down and power-off the system\n"
3679                "  reboot                          Shut down and reboot the system\n"
3680                "  rescue                          Enter system rescue mode\n"
3681                "  emergency                       Enter system emergency mode\n"
3682                "  default                         Enter system default mode\n",
3683                program_invocation_short_name);
3684
3685         return 0;
3686 }
3687
3688 static int halt_help(void) {
3689
3690         printf("%s [OPTIONS...]\n\n"
3691                "%s the system.\n\n"
3692                "     --help      Show this help\n"
3693                "     --halt      Halt the machine\n"
3694                "  -p --poweroff  Switch off the machine\n"
3695                "     --reboot    Reboot the machine\n"
3696                "  -f --force     Force immediate halt/power-off/reboot\n"
3697                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
3698                "  -d --no-wtmp   Don't write wtmp record\n"
3699                "  -n --no-sync   Don't sync before halt/power-off/reboot\n"
3700                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
3701                program_invocation_short_name,
3702                arg_action == ACTION_REBOOT   ? "Reboot" :
3703                arg_action == ACTION_POWEROFF ? "Power off" :
3704                                                "Halt");
3705
3706         return 0;
3707 }
3708
3709 static int shutdown_help(void) {
3710
3711         printf("%s [OPTIONS...] [now] [WALL...]\n\n"
3712                "Shut down the system.\n\n"
3713                "     --help      Show this help\n"
3714                "  -H --halt      Halt the machine\n"
3715                "  -P --poweroff  Power-off the machine\n"
3716                "  -r --reboot    Reboot the machine\n"
3717                "  -h             Equivalent to --poweroff, overriden by --halt\n"
3718                "  -k             Don't halt/power-off/reboot, just send warnings\n"
3719                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
3720                program_invocation_short_name);
3721
3722         return 0;
3723 }
3724
3725 static int telinit_help(void) {
3726
3727         printf("%s [OPTIONS...] {COMMAND}\n\n"
3728                "Send control commands to the init daemon.\n\n"
3729                "     --help      Show this help\n"
3730                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
3731                "Commands:\n"
3732                "  0              Power-off the machine\n"
3733                "  6              Reboot the machine\n"
3734                "  2, 3, 4, 5     Start runlevelX.target unit\n"
3735                "  1, s, S        Enter rescue mode\n"
3736                "  q, Q           Reload init daemon configuration\n"
3737                "  u, U           Reexecute init daemon\n",
3738                program_invocation_short_name);
3739
3740         return 0;
3741 }
3742
3743 static int runlevel_help(void) {
3744
3745         printf("%s [OPTIONS...]\n\n"
3746                "Prints the previous and current runlevel of the init system.\n\n"
3747                "     --help      Show this help\n",
3748                program_invocation_short_name);
3749
3750         return 0;
3751 }
3752
3753 static int systemctl_parse_argv(int argc, char *argv[]) {
3754
3755         enum {
3756                 ARG_FAIL = 0x100,
3757                 ARG_SESSION,
3758                 ARG_SYSTEM,
3759                 ARG_GLOBAL,
3760                 ARG_NO_BLOCK,
3761                 ARG_NO_WALL,
3762                 ARG_ORDER,
3763                 ARG_REQUIRE,
3764                 ARG_FULL,
3765                 ARG_FORCE,
3766                 ARG_NO_RELOAD,
3767                 ARG_DEFAULTS
3768         };
3769
3770         static const struct option options[] = {
3771                 { "help",      no_argument,       NULL, 'h'           },
3772                 { "type",      required_argument, NULL, 't'           },
3773                 { "property",  required_argument, NULL, 'p'           },
3774                 { "all",       no_argument,       NULL, 'a'           },
3775                 { "full",      no_argument,       NULL, ARG_FULL      },
3776                 { "fail",      no_argument,       NULL, ARG_FAIL      },
3777                 { "session",   no_argument,       NULL, ARG_SESSION   },
3778                 { "system",    no_argument,       NULL, ARG_SYSTEM    },
3779                 { "global",    no_argument,       NULL, ARG_GLOBAL    },
3780                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
3781                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
3782                 { "quiet",     no_argument,       NULL, 'q'           },
3783                 { "order",     no_argument,       NULL, ARG_ORDER     },
3784                 { "require",   no_argument,       NULL, ARG_REQUIRE   },
3785                 { "force",     no_argument,       NULL, ARG_FORCE     },
3786                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
3787                 { "defaults",   no_argument,      NULL, ARG_DEFAULTS  },
3788                 { NULL,        0,                 NULL, 0             }
3789         };
3790
3791         int c;
3792
3793         assert(argc >= 0);
3794         assert(argv);
3795
3796         while ((c = getopt_long(argc, argv, "ht:p:aq", options, NULL)) >= 0) {
3797
3798                 switch (c) {
3799
3800                 case 'h':
3801                         systemctl_help();
3802                         return 0;
3803
3804                 case 't':
3805                         arg_type = optarg;
3806                         break;
3807
3808                 case 'p': {
3809                         char **l;
3810
3811                         if (!(l = strv_append(arg_property, optarg)))
3812                                 return -ENOMEM;
3813
3814                         strv_free(arg_property);
3815                         arg_property = l;
3816
3817                         /* If the user asked for a particular
3818                          * property, show it to him, even if it is
3819                          * empty. */
3820                         arg_all = true;
3821                         break;
3822                 }
3823
3824                 case 'a':
3825                         arg_all = true;
3826                         break;
3827
3828                 case ARG_FAIL:
3829                         arg_fail = true;
3830                         break;
3831
3832                 case ARG_SESSION:
3833                         arg_session = true;
3834                         break;
3835
3836                 case ARG_SYSTEM:
3837                         arg_session = false;
3838                         break;
3839
3840                 case ARG_NO_BLOCK:
3841                         arg_no_block = true;
3842                         break;
3843
3844                 case ARG_NO_WALL:
3845                         arg_no_wall = true;
3846                         break;
3847
3848                 case ARG_ORDER:
3849                         arg_dot = DOT_ORDER;
3850                         break;
3851
3852                 case ARG_REQUIRE:
3853                         arg_dot = DOT_REQUIRE;
3854                         break;
3855
3856                 case ARG_FULL:
3857                         arg_full = true;
3858                         break;
3859
3860                 case 'q':
3861                         arg_quiet = true;
3862                         break;
3863
3864                 case ARG_FORCE:
3865                         arg_force = true;
3866                         break;
3867
3868                 case ARG_NO_RELOAD:
3869                         arg_no_reload = true;
3870                         break;
3871
3872                 case ARG_GLOBAL:
3873                         arg_global = true;
3874                         arg_session = true;
3875                         break;
3876
3877                 case ARG_DEFAULTS:
3878                         arg_defaults = true;
3879                         break;
3880
3881                 case '?':
3882                         return -EINVAL;
3883
3884                 default:
3885                         log_error("Unknown option code %c", c);
3886                         return -EINVAL;
3887                 }
3888         }
3889
3890         return 1;
3891 }
3892
3893 static int halt_parse_argv(int argc, char *argv[]) {
3894
3895         enum {
3896                 ARG_HELP = 0x100,
3897                 ARG_HALT,
3898                 ARG_REBOOT,
3899                 ARG_NO_WALL
3900         };
3901
3902         static const struct option options[] = {
3903                 { "help",      no_argument,       NULL, ARG_HELP    },
3904                 { "halt",      no_argument,       NULL, ARG_HALT    },
3905                 { "poweroff",  no_argument,       NULL, 'p'         },
3906                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
3907                 { "force",     no_argument,       NULL, 'f'         },
3908                 { "wtmp-only", no_argument,       NULL, 'w'         },
3909                 { "no-wtmp",   no_argument,       NULL, 'd'         },
3910                 { "no-sync",   no_argument,       NULL, 'n'         },
3911                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
3912                 { NULL,        0,                 NULL, 0           }
3913         };
3914
3915         int c, runlevel;
3916
3917         assert(argc >= 0);
3918         assert(argv);
3919
3920         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
3921                 if (runlevel == '0' || runlevel == '6')
3922                         arg_immediate = true;
3923
3924         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
3925                 switch (c) {
3926
3927                 case ARG_HELP:
3928                         halt_help();
3929                         return 0;
3930
3931                 case ARG_HALT:
3932                         arg_action = ACTION_HALT;
3933                         break;
3934
3935                 case 'p':
3936                         arg_action = ACTION_POWEROFF;
3937                         break;
3938
3939                 case ARG_REBOOT:
3940                         arg_action = ACTION_REBOOT;
3941                         break;
3942
3943                 case 'f':
3944                         arg_immediate = true;
3945                         break;
3946
3947                 case 'w':
3948                         arg_dry = true;
3949                         break;
3950
3951                 case 'd':
3952                         arg_no_wtmp = true;
3953                         break;
3954
3955                 case 'n':
3956                         arg_no_sync = true;
3957                         break;
3958
3959                 case ARG_NO_WALL:
3960                         arg_no_wall = true;
3961                         break;
3962
3963                 case 'i':
3964                 case 'h':
3965                         /* Compatibility nops */
3966                         break;
3967
3968                 case '?':
3969                         return -EINVAL;
3970
3971                 default:
3972                         log_error("Unknown option code %c", c);
3973                         return -EINVAL;
3974                 }
3975         }
3976
3977         if (optind < argc) {
3978                 log_error("Too many arguments.");
3979                 return -EINVAL;
3980         }
3981
3982         return 1;
3983 }
3984
3985 static int shutdown_parse_argv(int argc, char *argv[]) {
3986
3987         enum {
3988                 ARG_HELP = 0x100,
3989                 ARG_NO_WALL
3990         };
3991
3992         static const struct option options[] = {
3993                 { "help",      no_argument,       NULL, ARG_HELP    },
3994                 { "halt",      no_argument,       NULL, 'H'         },
3995                 { "poweroff",  no_argument,       NULL, 'P'         },
3996                 { "reboot",    no_argument,       NULL, 'r'         },
3997                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
3998                 { NULL,        0,                 NULL, 0           }
3999         };
4000
4001         int c;
4002
4003         assert(argc >= 0);
4004         assert(argv);
4005
4006         while ((c = getopt_long(argc, argv, "HPrhkt:a", options, NULL)) >= 0) {
4007                 switch (c) {
4008
4009                 case ARG_HELP:
4010                         shutdown_help();
4011                         return 0;
4012
4013                 case 'H':
4014                         arg_action = ACTION_HALT;
4015                         break;
4016
4017                 case 'P':
4018                         arg_action = ACTION_POWEROFF;
4019                         break;
4020
4021                 case 'r':
4022                         arg_action = ACTION_REBOOT;
4023                         break;
4024
4025                 case 'h':
4026                         if (arg_action != ACTION_HALT)
4027                                 arg_action = ACTION_POWEROFF;
4028                         break;
4029
4030                 case 'k':
4031                         arg_dry = true;
4032                         break;
4033
4034                 case ARG_NO_WALL:
4035                         arg_no_wall = true;
4036                         break;
4037
4038                 case 't':
4039                 case 'a':
4040                         /* Compatibility nops */
4041                         break;
4042
4043                 case '?':
4044                         return -EINVAL;
4045
4046                 default:
4047                         log_error("Unknown option code %c", c);
4048                         return -EINVAL;
4049                 }
4050         }
4051
4052         if (argc > optind && !streq(argv[optind], "now"))
4053                 log_warning("First argument '%s' isn't 'now'. Ignoring.", argv[optind]);
4054
4055         /* We ignore the time argument */
4056         if (argc > optind + 1)
4057                 arg_wall = argv + optind + 1;
4058
4059         optind = argc;
4060
4061         return 1;
4062 }
4063
4064 static int telinit_parse_argv(int argc, char *argv[]) {
4065
4066         enum {
4067                 ARG_HELP = 0x100,
4068                 ARG_NO_WALL
4069         };
4070
4071         static const struct option options[] = {
4072                 { "help",      no_argument,       NULL, ARG_HELP    },
4073                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4074                 { NULL,        0,                 NULL, 0           }
4075         };
4076
4077         static const struct {
4078                 char from;
4079                 enum action to;
4080         } table[] = {
4081                 { '0', ACTION_POWEROFF },
4082                 { '6', ACTION_REBOOT },
4083                 { '1', ACTION_RESCUE },
4084                 { '2', ACTION_RUNLEVEL2 },
4085                 { '3', ACTION_RUNLEVEL3 },
4086                 { '4', ACTION_RUNLEVEL4 },
4087                 { '5', ACTION_RUNLEVEL5 },
4088                 { 's', ACTION_RESCUE },
4089                 { 'S', ACTION_RESCUE },
4090                 { 'q', ACTION_RELOAD },
4091                 { 'Q', ACTION_RELOAD },
4092                 { 'u', ACTION_REEXEC },
4093                 { 'U', ACTION_REEXEC }
4094         };
4095
4096         unsigned i;
4097         int c;
4098
4099         assert(argc >= 0);
4100         assert(argv);
4101
4102         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4103                 switch (c) {
4104
4105                 case ARG_HELP:
4106                         telinit_help();
4107                         return 0;
4108
4109                 case ARG_NO_WALL:
4110                         arg_no_wall = true;
4111                         break;
4112
4113                 case '?':
4114                         return -EINVAL;
4115
4116                 default:
4117                         log_error("Unknown option code %c", c);
4118                         return -EINVAL;
4119                 }
4120         }
4121
4122         if (optind >= argc) {
4123                 telinit_help();
4124                 return -EINVAL;
4125         }
4126
4127         if (optind + 1 < argc) {
4128                 log_error("Too many arguments.");
4129                 return -EINVAL;
4130         }
4131
4132         if (strlen(argv[optind]) != 1) {
4133                 log_error("Expected single character argument.");
4134                 return -EINVAL;
4135         }
4136
4137         for (i = 0; i < ELEMENTSOF(table); i++)
4138                 if (table[i].from == argv[optind][0])
4139                         break;
4140
4141         if (i >= ELEMENTSOF(table)) {
4142                 log_error("Unknown command %s.", argv[optind]);
4143                 return -EINVAL;
4144         }
4145
4146         arg_action = table[i].to;
4147
4148         optind ++;
4149
4150         return 1;
4151 }
4152
4153 static int runlevel_parse_argv(int argc, char *argv[]) {
4154
4155         enum {
4156                 ARG_HELP = 0x100,
4157         };
4158
4159         static const struct option options[] = {
4160                 { "help",      no_argument,       NULL, ARG_HELP    },
4161                 { NULL,        0,                 NULL, 0           }
4162         };
4163
4164         int c;
4165
4166         assert(argc >= 0);
4167         assert(argv);
4168
4169         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4170                 switch (c) {
4171
4172                 case ARG_HELP:
4173                         runlevel_help();
4174                         return 0;
4175
4176                 case '?':
4177                         return -EINVAL;
4178
4179                 default:
4180                         log_error("Unknown option code %c", c);
4181                         return -EINVAL;
4182                 }
4183         }
4184
4185         if (optind < argc) {
4186                 log_error("Too many arguments.");
4187                 return -EINVAL;
4188         }
4189
4190         return 1;
4191 }
4192
4193 static int parse_argv(int argc, char *argv[]) {
4194         assert(argc >= 0);
4195         assert(argv);
4196
4197         if (program_invocation_short_name) {
4198
4199                 if (strstr(program_invocation_short_name, "halt")) {
4200                         arg_action = ACTION_HALT;
4201                         return halt_parse_argv(argc, argv);
4202                 } else if (strstr(program_invocation_short_name, "poweroff")) {
4203                         arg_action = ACTION_POWEROFF;
4204                         return halt_parse_argv(argc, argv);
4205                 } else if (strstr(program_invocation_short_name, "reboot")) {
4206                         arg_action = ACTION_REBOOT;
4207                         return halt_parse_argv(argc, argv);
4208                 } else if (strstr(program_invocation_short_name, "shutdown")) {
4209                         arg_action = ACTION_POWEROFF;
4210                         return shutdown_parse_argv(argc, argv);
4211                 } else if (strstr(program_invocation_short_name, "init")) {
4212                         arg_action = ACTION_INVALID;
4213                         return telinit_parse_argv(argc, argv);
4214                 } else if (strstr(program_invocation_short_name, "runlevel")) {
4215                         arg_action = ACTION_RUNLEVEL;
4216                         return runlevel_parse_argv(argc, argv);
4217                 }
4218         }
4219
4220         arg_action = ACTION_SYSTEMCTL;
4221         return systemctl_parse_argv(argc, argv);
4222 }
4223
4224 static int action_to_runlevel(void) {
4225
4226         static const char table[_ACTION_MAX] = {
4227                 [ACTION_HALT] =      '0',
4228                 [ACTION_POWEROFF] =  '0',
4229                 [ACTION_REBOOT] =    '6',
4230                 [ACTION_RUNLEVEL2] = '2',
4231                 [ACTION_RUNLEVEL3] = '3',
4232                 [ACTION_RUNLEVEL4] = '4',
4233                 [ACTION_RUNLEVEL5] = '5',
4234                 [ACTION_RESCUE] =    '1'
4235         };
4236
4237         assert(arg_action < _ACTION_MAX);
4238
4239         return table[arg_action];
4240 }
4241
4242 static int talk_upstart(void) {
4243         DBusMessage *m = NULL, *reply = NULL;
4244         DBusError error;
4245         int previous, rl, r;
4246         char
4247                 env1_buf[] = "RUNLEVEL=X",
4248                 env2_buf[] = "PREVLEVEL=X";
4249         char *env1 = env1_buf, *env2 = env2_buf;
4250         const char *emit = "runlevel";
4251         dbus_bool_t b_false = FALSE;
4252         DBusMessageIter iter, sub;
4253         DBusConnection *bus;
4254
4255         dbus_error_init(&error);
4256
4257         if (!(rl = action_to_runlevel()))
4258                 return 0;
4259
4260         if (utmp_get_runlevel(&previous, NULL) < 0)
4261                 previous = 'N';
4262
4263         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
4264                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
4265                         r = 0;
4266                         goto finish;
4267                 }
4268
4269                 log_error("Failed to connect to Upstart bus: %s", error.message);
4270                 r = -EIO;
4271                 goto finish;
4272         }
4273
4274         if ((r = bus_check_peercred(bus)) < 0) {
4275                 log_error("Failed to verify owner of bus.");
4276                 goto finish;
4277         }
4278
4279         if (!(m = dbus_message_new_method_call(
4280                               "com.ubuntu.Upstart",
4281                               "/com/ubuntu/Upstart",
4282                               "com.ubuntu.Upstart0_6",
4283                               "EmitEvent"))) {
4284
4285                 log_error("Could not allocate message.");
4286                 r = -ENOMEM;
4287                 goto finish;
4288         }
4289
4290         dbus_message_iter_init_append(m, &iter);
4291
4292         env1_buf[sizeof(env1_buf)-2] = rl;
4293         env2_buf[sizeof(env2_buf)-2] = previous;
4294
4295         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
4296             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
4297             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
4298             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
4299             !dbus_message_iter_close_container(&iter, &sub) ||
4300             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
4301                 log_error("Could not append arguments to message.");
4302                 r = -ENOMEM;
4303                 goto finish;
4304         }
4305
4306         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4307
4308                 if (error_is_no_service(&error)) {
4309                         r = 0;
4310                         goto finish;
4311                 }
4312
4313                 log_error("Failed to issue method call: %s", error.message);
4314                 r = -EIO;
4315                 goto finish;
4316         }
4317
4318         r = 1;
4319
4320 finish:
4321         if (m)
4322                 dbus_message_unref(m);
4323
4324         if (reply)
4325                 dbus_message_unref(reply);
4326
4327         if (bus) {
4328                 dbus_connection_close(bus);
4329                 dbus_connection_unref(bus);
4330         }
4331
4332         dbus_error_free(&error);
4333
4334         return r;
4335 }
4336
4337 static int talk_initctl(void) {
4338         struct init_request request;
4339         int r, fd;
4340         char rl;
4341
4342         if (!(rl = action_to_runlevel()))
4343                 return 0;
4344
4345         zero(request);
4346         request.magic = INIT_MAGIC;
4347         request.sleeptime = 0;
4348         request.cmd = INIT_CMD_RUNLVL;
4349         request.runlevel = rl;
4350
4351         if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
4352
4353                 if (errno == ENOENT)
4354                         return 0;
4355
4356                 log_error("Failed to open "INIT_FIFO": %m");
4357                 return -errno;
4358         }
4359
4360         errno = 0;
4361         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
4362         close_nointr_nofail(fd);
4363
4364         if (r < 0) {
4365                 log_error("Failed to write to "INIT_FIFO": %m");
4366                 return errno ? -errno : -EIO;
4367         }
4368
4369         return 1;
4370 }
4371
4372 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
4373
4374         static const struct {
4375                 const char* verb;
4376                 const enum {
4377                         MORE,
4378                         LESS,
4379                         EQUAL
4380                 } argc_cmp;
4381                 const int argc;
4382                 int (* const dispatch)(DBusConnection *bus, char **args, unsigned n);
4383         } verbs[] = {
4384                 { "list-units",            LESS,  1, list_units        },
4385                 { "list-jobs",             EQUAL, 1, list_jobs         },
4386                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
4387                 { "load",                  MORE,  2, load_unit         },
4388                 { "cancel",                MORE,  2, cancel_job        },
4389                 { "start",                 MORE,  2, start_unit        },
4390                 { "stop",                  MORE,  2, start_unit        },
4391                 { "reload",                MORE,  2, start_unit        },
4392                 { "restart",               MORE,  2, start_unit        },
4393                 { "try-restart",           MORE,  2, start_unit        },
4394                 { "reload-or-restart",     MORE,  2, start_unit        },
4395                 { "reload-or-try-restart", MORE,  2, start_unit        },
4396                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
4397                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
4398                 { "isolate",               EQUAL, 2, start_unit        },
4399                 { "is-active",             MORE,  2, check_unit        },
4400                 { "check",                 MORE,  2, check_unit        },
4401                 { "show",                  MORE,  1, show              },
4402                 { "status",                MORE,  2, show              },
4403                 { "monitor",               EQUAL, 1, monitor           },
4404                 { "dump",                  EQUAL, 1, dump              },
4405                 { "dot",                   EQUAL, 1, dot               },
4406                 { "snapshot",              LESS,  2, snapshot          },
4407                 { "delete",                MORE,  2, delete_snapshot   },
4408                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
4409                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
4410                 { "daemon-exit",           EQUAL, 1, daemon_reload     },
4411                 { "show-environment",      EQUAL, 1, show_enviroment   },
4412                 { "set-environment",       MORE,  2, set_environment   },
4413                 { "unset-environment",     MORE,  2, set_environment   },
4414                 { "halt",                  EQUAL, 1, start_special     },
4415                 { "poweroff",              EQUAL, 1, start_special     },
4416                 { "reboot",                EQUAL, 1, start_special     },
4417                 { "default",               EQUAL, 1, start_special     },
4418                 { "rescue",                EQUAL, 1, start_special     },
4419                 { "emergency",             EQUAL, 1, start_special     },
4420                 { "reset-maintenance",     MORE,  1, reset_maintenance },
4421                 { "enable",                MORE,  2, enable_unit       },
4422                 { "disable",               MORE,  2, enable_unit       },
4423                 { "is-enabled",            MORE,  2, enable_unit       }
4424         };
4425
4426         int left;
4427         unsigned i;
4428
4429         assert(argc >= 0);
4430         assert(argv);
4431         assert(error);
4432
4433         left = argc - optind;
4434
4435         if (left <= 0)
4436                 /* Special rule: no arguments means "list-units" */
4437                 i = 0;
4438         else {
4439                 if (streq(argv[optind], "help")) {
4440                         systemctl_help();
4441                         return 0;
4442                 }
4443
4444                 for (i = 0; i < ELEMENTSOF(verbs); i++)
4445                         if (streq(argv[optind], verbs[i].verb))
4446                                 break;
4447
4448                 if (i >= ELEMENTSOF(verbs)) {
4449                         log_error("Unknown operation %s", argv[optind]);
4450                         return -EINVAL;
4451                 }
4452         }
4453
4454         switch (verbs[i].argc_cmp) {
4455
4456         case EQUAL:
4457                 if (left != verbs[i].argc) {
4458                         log_error("Invalid number of arguments.");
4459                         return -EINVAL;
4460                 }
4461
4462                 break;
4463
4464         case MORE:
4465                 if (left < verbs[i].argc) {
4466                         log_error("Too few arguments.");
4467                         return -EINVAL;
4468                 }
4469
4470                 break;
4471
4472         case LESS:
4473                 if (left > verbs[i].argc) {
4474                         log_error("Too many arguments.");
4475                         return -EINVAL;
4476                 }
4477
4478                 break;
4479
4480         default:
4481                 assert_not_reached("Unknown comparison operator.");
4482         }
4483
4484         /* Require a bus connection for all operations but
4485          * enable/disable */
4486         if (!streq(verbs[i].verb, "enable") &&
4487             !streq(verbs[i].verb, "disable") &&
4488             !bus) {
4489                 log_error("Failed to get D-Bus connection: %s", error->message);
4490                 return -EIO;
4491         }
4492
4493         return verbs[i].dispatch(bus, argv + optind, left);
4494 }
4495
4496 static int reload_with_fallback(DBusConnection *bus) {
4497         int r;
4498
4499         if (bus) {
4500                 /* First, try systemd via D-Bus. */
4501                 if ((r = daemon_reload(bus, NULL, 0)) > 0)
4502                         return 0;
4503         }
4504
4505         /* Nothing else worked, so let's try signals */
4506         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
4507
4508         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
4509                 log_error("kill() failed: %m");
4510                 return -errno;
4511         }
4512
4513         return 0;
4514 }
4515
4516 static int start_with_fallback(DBusConnection *bus) {
4517         int r;
4518
4519         if (bus) {
4520                 /* First, try systemd via D-Bus. */
4521                 if ((r = start_unit(bus, NULL, 0)) > 0)
4522                         goto done;
4523         }
4524
4525         /* Hmm, talking to systemd via D-Bus didn't work. Then
4526          * let's try to talk to Upstart via D-Bus. */
4527         if ((r = talk_upstart()) > 0)
4528                 goto done;
4529
4530         /* Nothing else worked, so let's try
4531          * /dev/initctl */
4532         if ((r = talk_initctl()) != 0)
4533                 goto done;
4534
4535         log_error("Failed to talk to init daemon.");
4536         return -EIO;
4537
4538 done:
4539         warn_wall(arg_action);
4540         return 0;
4541 }
4542
4543 static int halt_main(DBusConnection *bus) {
4544         int r;
4545
4546         if (geteuid() != 0) {
4547                 log_error("Must to be root.");
4548                 return -EPERM;
4549         }
4550
4551         if (!arg_dry && !arg_immediate)
4552                 return start_with_fallback(bus);
4553
4554         if (!arg_no_wtmp)
4555                 if ((r = utmp_put_shutdown(0)) < 0)
4556                         log_warning("Failed to write utmp record: %s", strerror(-r));
4557
4558         if (!arg_no_sync)
4559                 sync();
4560
4561         if (arg_dry)
4562                 return 0;
4563
4564         /* Make sure C-A-D is handled by the kernel from this
4565          * point on... */
4566         reboot(RB_ENABLE_CAD);
4567
4568         switch (arg_action) {
4569
4570         case ACTION_HALT:
4571                 log_info("Halting");
4572                 reboot(RB_HALT_SYSTEM);
4573                 break;
4574
4575         case ACTION_POWEROFF:
4576                 log_info("Powering off");
4577                 reboot(RB_POWER_OFF);
4578                 break;
4579
4580         case ACTION_REBOOT:
4581                 log_info("Rebooting");
4582                 reboot(RB_AUTOBOOT);
4583                 break;
4584
4585         default:
4586                 assert_not_reached("Unknown halt action.");
4587         }
4588
4589         /* We should never reach this. */
4590         return -ENOSYS;
4591 }
4592
4593 static int runlevel_main(void) {
4594         int r, runlevel, previous;
4595
4596         if ((r = utmp_get_runlevel(&runlevel, &previous)) < 0) {
4597                 printf("unknown");
4598                 return r;
4599         }
4600
4601         printf("%c %c\n",
4602                previous <= 0 ? 'N' : previous,
4603                runlevel <= 0 ? 'N' : runlevel);
4604
4605         return 0;
4606 }
4607
4608 int main(int argc, char*argv[]) {
4609         int r, retval = 1;
4610         DBusConnection *bus = NULL;
4611         DBusError error;
4612
4613         dbus_error_init(&error);
4614
4615         log_parse_environment();
4616
4617         if ((r = parse_argv(argc, argv)) < 0)
4618                 goto finish;
4619         else if (r == 0) {
4620                 retval = 0;
4621                 goto finish;
4622         }
4623
4624         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
4625          * let's shortcut this */
4626         if (arg_action == ACTION_RUNLEVEL) {
4627                 retval = runlevel_main() < 0;
4628                 goto finish;
4629         }
4630
4631         bus_connect(arg_session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, &private_bus, &error);
4632
4633         switch (arg_action) {
4634
4635         case ACTION_SYSTEMCTL: {
4636                 retval = systemctl_main(bus, argc, argv, &error) < 0;
4637                 break;
4638         }
4639
4640         case ACTION_HALT:
4641         case ACTION_POWEROFF:
4642         case ACTION_REBOOT:
4643                 retval = halt_main(bus) < 0;
4644                 break;
4645
4646         case ACTION_RUNLEVEL2:
4647         case ACTION_RUNLEVEL3:
4648         case ACTION_RUNLEVEL4:
4649         case ACTION_RUNLEVEL5:
4650         case ACTION_RESCUE:
4651         case ACTION_EMERGENCY:
4652         case ACTION_DEFAULT:
4653                 retval = start_with_fallback(bus) < 0;
4654                 break;
4655
4656         case ACTION_RELOAD:
4657         case ACTION_REEXEC:
4658                 retval = reload_with_fallback(bus) < 0;
4659                 break;
4660
4661         case ACTION_INVALID:
4662         case ACTION_RUNLEVEL:
4663         default:
4664                 assert_not_reached("Unknown action");
4665         }
4666
4667 finish:
4668
4669         if (bus) {
4670                 dbus_connection_close(bus);
4671                 dbus_connection_unref(bus);
4672         }
4673
4674         dbus_error_free(&error);
4675
4676         dbus_shutdown();
4677
4678         strv_free(arg_property);
4679
4680         return retval;
4681 }