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