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