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