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