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