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