chiark / gitweb /
d32a688d8415d6045c5297203c592e0e8bf986d8
[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 typedef struct UnitStatusInfo {
963         const char *id;
964         const char *load_state;
965         const char *active_state;
966         const char *sub_state;
967
968         const char *description;
969
970         const char *fragment_path;
971         const char *default_control_group;
972
973         /* Service */
974         pid_t main_pid;
975         pid_t control_pid;
976         const char *status_text;
977         bool running;
978
979         usec_t start_timestamp;
980         usec_t exit_timestamp;
981
982         int exit_code, exit_status;
983
984         /* Socket */
985         unsigned n_accepted;
986         unsigned n_connections;
987
988         /* Device */
989         const char *sysfs_path;
990
991         /* Mount, Automount */
992         const char *where;
993
994         /* Swap */
995         const char *what;
996 } UnitStatusInfo;
997
998 static void print_status_info(UnitStatusInfo *i) {
999         assert(i);
1000
1001         /* This shows pretty information about a unit. See
1002          * print_property() for a low-level property printer */
1003
1004         printf("%s", strna(i->id));
1005
1006         if (i->description && !streq_ptr(i->id, i->description))
1007                 printf(" - %s", i->description);
1008
1009         printf("\n");
1010
1011         if (i->fragment_path)
1012                 printf("\t  Loaded: %s (%s)\n", strna(i->load_state), i->fragment_path);
1013         else if (streq_ptr(i->load_state, "failed"))
1014                 printf("\t  Loaded: " ANSI_HIGHLIGHT_ON "%s" ANSI_HIGHLIGHT_OFF "\n", strna(i->load_state));
1015         else
1016                 printf("\t  Loaded: %s\n", strna(i->load_state));
1017
1018         if (streq_ptr(i->active_state, "maintenance"))
1019                 printf("\t  Active: " ANSI_HIGHLIGHT_ON "%s (%s)" ANSI_HIGHLIGHT_OFF "\n",
1020                        strna(i->active_state),
1021                        strna(i->sub_state));
1022         else
1023                 printf("\t  Active: %s (%s)\n",
1024                        strna(i->active_state),
1025                        strna(i->sub_state));
1026
1027         if (i->sysfs_path)
1028                 printf("\t  Device: %s\n", i->sysfs_path);
1029         else if (i->where)
1030                 printf("\t   Where: %s\n", i->where);
1031         else if (i->what)
1032                 printf("\t    What: %s\n", i->what);
1033
1034         if (i->status_text)
1035                 printf("\t  Status: \"%s\"\n", i->status_text);
1036
1037         if (i->id && endswith(i->id, ".socket"))
1038                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
1039
1040         if (i->main_pid > 0 || i->control_pid > 0) {
1041                 printf("\t");
1042
1043                 if (i->main_pid > 0) {
1044                         printf(" Process: %u", (unsigned) i->main_pid);
1045
1046                         if (i->running) {
1047                                 char *t = NULL;
1048                                 get_process_name(i->main_pid, &t);
1049                                 if (t) {
1050                                         printf(" (%s)", t);
1051                                         free(t);
1052                                 }
1053                         } else {
1054                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
1055
1056                                 if (i->exit_code == CLD_EXITED)
1057                                         printf("status=%i", i->exit_status);
1058                                 else
1059                                         printf("signal=%s", strsignal(i->exit_status));
1060                                 printf(")");
1061                         }
1062                 }
1063
1064                 if (i->main_pid > 0 && i->control_pid > 0)
1065                         printf(";");
1066
1067                 if (i->control_pid > 0) {
1068                         char *t = NULL;
1069
1070                         printf(" Control: %u", (unsigned) i->control_pid);
1071
1072                         get_process_name(i->control_pid, &t);
1073                         if (t) {
1074                                 printf(" (%s)", t);
1075                                 free(t);
1076                         }
1077                 }
1078
1079                 printf("\n");
1080         }
1081
1082         if (i->default_control_group)
1083                 printf("\t  CGroup: %s\n", i->default_control_group);
1084 }
1085
1086 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
1087
1088         switch (dbus_message_iter_get_arg_type(iter)) {
1089
1090         case DBUS_TYPE_STRING: {
1091                 const char *s;
1092
1093                 dbus_message_iter_get_basic(iter, &s);
1094
1095                 if (s[0]) {
1096                         if (streq(name, "Id"))
1097                                 i->id = s;
1098                         else if (streq(name, "LoadState"))
1099                                 i->load_state = s;
1100                         else if (streq(name, "ActiveState"))
1101                                 i->active_state = s;
1102                         else if (streq(name, "SubState"))
1103                                 i->sub_state = s;
1104                         else if (streq(name, "Description"))
1105                                 i->description = s;
1106                         else if (streq(name, "FragmentPath"))
1107                                 i->fragment_path = s;
1108                         else if (streq(name, "DefaultControlGroup"))
1109                                 i->default_control_group = s;
1110                         else if (streq(name, "StatusText"))
1111                                 i->status_text = s;
1112                         else if (streq(name, "SysFSPath"))
1113                                 i->sysfs_path = s;
1114                         else if (streq(name, "Where"))
1115                                 i->where = s;
1116                         else if (streq(name, "What"))
1117                                 i->what = s;
1118                 }
1119
1120                 break;
1121         }
1122
1123         case DBUS_TYPE_UINT32: {
1124                 uint32_t u;
1125
1126                 dbus_message_iter_get_basic(iter, &u);
1127
1128                 if (streq(name, "MainPID")) {
1129                         if (u > 0) {
1130                                 i->main_pid = (pid_t) u;
1131                                 i->running = true;
1132                         }
1133                 } else if (streq(name, "ControlPID"))
1134                         i->control_pid = (pid_t) u;
1135                 else if (streq(name, "ExecMainPID")) {
1136                         if (u > 0)
1137                                 i->main_pid = (pid_t) u;
1138                 } else if (streq(name, "NAccepted"))
1139                         i->n_accepted = u;
1140                 else if (streq(name, "NConnections"))
1141                         i->n_connections = u;
1142
1143                 break;
1144         }
1145
1146         case DBUS_TYPE_INT32: {
1147                 int32_t j;
1148
1149                 dbus_message_iter_get_basic(iter, &j);
1150
1151                 if (streq(name, "ExecMainCode"))
1152                         i->exit_code = (int) j;
1153                 else if (streq(name, "ExecMainStatus"))
1154                         i->exit_status = (int) j;
1155
1156                 break;
1157         }
1158
1159         case DBUS_TYPE_UINT64: {
1160                 uint64_t u;
1161
1162                 dbus_message_iter_get_basic(iter, &u);
1163
1164                 if (streq(name, "ExecMainStartTimestamp"))
1165                         i->start_timestamp = (usec_t) u;
1166                 else if (streq(name, "ExecMainExitTimestamp"))
1167                         i->exit_timestamp = (usec_t) u;
1168
1169                 break;
1170         }
1171         }
1172
1173         return 0;
1174 }
1175
1176 static int print_property(const char *name, DBusMessageIter *iter) {
1177         assert(name);
1178         assert(iter);
1179
1180         /* This is a low-level property printer, see
1181          * print_status_info() for the nicer output */
1182
1183         if (arg_property && !streq(name, arg_property))
1184                 return 0;
1185
1186         switch (dbus_message_iter_get_arg_type(iter)) {
1187
1188         case DBUS_TYPE_STRING: {
1189                 const char *s;
1190                 dbus_message_iter_get_basic(iter, &s);
1191
1192                 if (arg_all || s[0])
1193                         printf("%s=%s\n", name, s);
1194
1195                 return 0;
1196         }
1197
1198         case DBUS_TYPE_BOOLEAN: {
1199                 dbus_bool_t b;
1200                 dbus_message_iter_get_basic(iter, &b);
1201                 printf("%s=%s\n", name, yes_no(b));
1202
1203                 return 0;
1204         }
1205
1206         case DBUS_TYPE_UINT64: {
1207                 uint64_t u;
1208                 dbus_message_iter_get_basic(iter, &u);
1209
1210                 /* Yes, heuristics! But we can change this check
1211                  * should it turn out to not be sufficient */
1212
1213                 if (strstr(name, "Timestamp")) {
1214                         char timestamp[FORMAT_TIMESTAMP_MAX], *t;
1215
1216                         if ((t = format_timestamp(timestamp, sizeof(timestamp), u)) || arg_all)
1217                                 printf("%s=%s\n", name, strempty(t));
1218                 } else if (strstr(name, "USec")) {
1219                         char timespan[FORMAT_TIMESPAN_MAX];
1220
1221                         printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u));
1222                 } else
1223                         printf("%s=%llu\n", name, (unsigned long long) u);
1224
1225                 return 0;
1226         }
1227
1228         case DBUS_TYPE_UINT32: {
1229                 uint32_t u;
1230                 dbus_message_iter_get_basic(iter, &u);
1231
1232                 if (strstr(name, "UMask") || strstr(name, "Mode"))
1233                         printf("%s=%04o\n", name, u);
1234                 else
1235                         printf("%s=%u\n", name, (unsigned) u);
1236
1237                 return 0;
1238         }
1239
1240         case DBUS_TYPE_INT32: {
1241                 int32_t i;
1242                 dbus_message_iter_get_basic(iter, &i);
1243
1244                 printf("%s=%i\n", name, (int) i);
1245                 return 0;
1246         }
1247
1248         case DBUS_TYPE_STRUCT: {
1249                 DBusMessageIter sub;
1250                 dbus_message_iter_recurse(iter, &sub);
1251
1252                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
1253                         uint32_t u;
1254
1255                         dbus_message_iter_get_basic(&sub, &u);
1256
1257                         if (u)
1258                                 printf("%s=%u\n", name, (unsigned) u);
1259                         else if (arg_all)
1260                                 printf("%s=\n", name);
1261
1262                         return 0;
1263                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
1264                         const char *s;
1265
1266                         dbus_message_iter_get_basic(&sub, &s);
1267
1268                         if (arg_all || s[0])
1269                                 printf("%s=%s\n", name, s);
1270
1271                         return 0;
1272                 }
1273
1274                 break;
1275         }
1276
1277         case DBUS_TYPE_ARRAY:
1278
1279                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
1280                         DBusMessageIter sub;
1281                         bool space = false;
1282
1283                         dbus_message_iter_recurse(iter, &sub);
1284
1285                         if (arg_all ||
1286                             dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1287                                 printf("%s=", name);
1288
1289                                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1290                                         const char *s;
1291
1292                                         assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
1293                                         dbus_message_iter_get_basic(&sub, &s);
1294                                         printf("%s%s", space ? " " : "", s);
1295
1296                                         space = true;
1297                                         dbus_message_iter_next(&sub);
1298                                 }
1299
1300                                 puts("");
1301                         }
1302
1303                         return 0;
1304                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
1305                         DBusMessageIter sub;
1306
1307                         dbus_message_iter_recurse(iter, &sub);
1308
1309                         if (arg_all ||
1310                             dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1311                                 printf("%s=", name);
1312
1313                                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1314                                         uint8_t u;
1315
1316                                         assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE);
1317                                         dbus_message_iter_get_basic(&sub, &u);
1318                                         printf("%02x", u);
1319
1320                                         dbus_message_iter_next(&sub);
1321                                 }
1322
1323                                 puts("");
1324                         }
1325
1326                         return 0;
1327                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
1328                         DBusMessageIter sub, sub2;
1329
1330                         dbus_message_iter_recurse(iter, &sub);
1331
1332                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1333                                 const char *type, *path;
1334
1335                                 dbus_message_iter_recurse(&sub, &sub2);
1336
1337                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
1338                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
1339                                         printf("%s=%s\n", type, path);
1340
1341                                 dbus_message_iter_next(&sub);
1342                         }
1343
1344                         return 0;
1345                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
1346                         DBusMessageIter sub, sub2;
1347
1348                         dbus_message_iter_recurse(iter, &sub);
1349
1350                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1351                                 const char *base;
1352                                 uint64_t value, next_elapse;
1353
1354                                 dbus_message_iter_recurse(&sub, &sub2);
1355
1356                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
1357                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
1358                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
1359                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
1360
1361                                         printf("%s={ value=%s ; next_elapse=%s }\n",
1362                                                base,
1363                                                format_timespan(timespan1, sizeof(timespan1), value),
1364                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
1365                                 }
1366
1367                                 dbus_message_iter_next(&sub);
1368                         }
1369
1370                         return 0;
1371                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
1372
1373                         DBusMessageIter sub, sub2, sub3;
1374
1375                         dbus_message_iter_recurse(iter, &sub);
1376
1377                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
1378                                 const char *path;
1379                                 uint64_t start_time, exit_time;
1380                                 uint32_t pid;
1381                                 int32_t code, status;
1382
1383                                 dbus_message_iter_recurse(&sub, &sub2);
1384
1385                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
1386                                         continue;
1387
1388                                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
1389                                     dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
1390                                         continue;
1391
1392                                 printf("%s={ path=%s ; argv[]=", name, path);
1393
1394                                 dbus_message_iter_recurse(&sub2, &sub3);
1395
1396                                 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
1397                                         const char *s;
1398
1399                                         assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
1400                                         dbus_message_iter_get_basic(&sub3, &s);
1401                                         printf("%s ", s);
1402                                         dbus_message_iter_next(&sub3);
1403                                 }
1404
1405                                 if (dbus_message_iter_next(&sub2) &&
1406                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_time, true) >= 0 &&
1407                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_time, true) >= 0 &&
1408                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) >= 0 &&
1409                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) >= 0 &&
1410                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) >= 0) {
1411
1412                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
1413
1414                                         printf("; start=%s ; stop=%s ; pid=%u ; code=%s ; status=%i/%s",
1415                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), start_time)),
1416                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), exit_time)),
1417                                                (unsigned) pid,
1418                                                sigchld_code_to_string(code),
1419                                                status,
1420                                                strempty(code == CLD_EXITED ? NULL : strsignal(status)));
1421                                 }
1422
1423                                 printf(" }\n");
1424
1425                                 dbus_message_iter_next(&sub);
1426                         }
1427
1428                         return 0;
1429                 }
1430
1431                 break;
1432         }
1433
1434         if (arg_all)
1435                 printf("%s=[unprintable]\n", name);
1436
1437         return 0;
1438 }
1439
1440 static int show_one(DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
1441         DBusMessage *m = NULL, *reply = NULL;
1442         const char *interface = "";
1443         int r;
1444         DBusError error;
1445         DBusMessageIter iter, sub, sub2, sub3;
1446         UnitStatusInfo info;
1447
1448         assert(bus);
1449         assert(path);
1450         assert(new_line);
1451
1452         zero(info);
1453         dbus_error_init(&error);
1454
1455         if (!(m = dbus_message_new_method_call(
1456                               "org.freedesktop.systemd1",
1457                               path,
1458                               "org.freedesktop.DBus.Properties",
1459                               "GetAll"))) {
1460                 log_error("Could not allocate message.");
1461                 r = -ENOMEM;
1462                 goto finish;
1463         }
1464
1465         if (!dbus_message_append_args(m,
1466                                       DBUS_TYPE_STRING, &interface,
1467                                       DBUS_TYPE_INVALID)) {
1468                 log_error("Could not append arguments to message.");
1469                 r = -ENOMEM;
1470                 goto finish;
1471         }
1472
1473         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1474                 log_error("Failed to issue method call: %s", error.message);
1475                 r = -EIO;
1476                 goto finish;
1477         }
1478
1479         if (!dbus_message_iter_init(reply, &iter) ||
1480             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1481             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
1482                 log_error("Failed to parse reply.");
1483                 r = -EIO;
1484                 goto finish;
1485         }
1486
1487         dbus_message_iter_recurse(&iter, &sub);
1488
1489         if (*new_line)
1490                 printf("\n");
1491
1492         *new_line = true;
1493
1494         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1495                 const char *name;
1496
1497                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
1498                         log_error("Failed to parse reply.");
1499                         r = -EIO;
1500                         goto finish;
1501                 }
1502
1503                 dbus_message_iter_recurse(&sub, &sub2);
1504
1505                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
1506                         log_error("Failed to parse reply.");
1507                         r = -EIO;
1508                         goto finish;
1509                 }
1510
1511                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
1512                         log_error("Failed to parse reply.");
1513                         r = -EIO;
1514                         goto finish;
1515                 }
1516
1517                 dbus_message_iter_recurse(&sub2, &sub3);
1518
1519                 if (show_properties)
1520                         r = print_property(name, &sub3);
1521                 else
1522                         r = status_property(name, &sub3, &info);
1523
1524                 if (r < 0) {
1525                         log_error("Failed to parse reply.");
1526                         r = -EIO;
1527                         goto finish;
1528                 }
1529
1530                 dbus_message_iter_next(&sub);
1531         }
1532
1533         if (!show_properties)
1534                 print_status_info(&info);
1535
1536         r = 0;
1537
1538 finish:
1539         if (m)
1540                 dbus_message_unref(m);
1541
1542         if (reply)
1543                 dbus_message_unref(reply);
1544
1545         dbus_error_free(&error);
1546
1547         return r;
1548 }
1549
1550 static int show(DBusConnection *bus, char **args, unsigned n) {
1551         DBusMessage *m = NULL, *reply = NULL;
1552         int r;
1553         DBusError error;
1554         unsigned i;
1555         bool show_properties, new_line = false;
1556
1557         assert(bus);
1558         assert(args);
1559
1560         dbus_error_init(&error);
1561
1562         show_properties = !streq(args[0], "status");
1563
1564         if (show_properties && n <= 1) {
1565                 /* If not argument is specified inspect the manager
1566                  * itself */
1567
1568                 r = show_one(bus, "/org/freedesktop/systemd1", show_properties, &new_line);
1569                 goto finish;
1570         }
1571
1572         for (i = 1; i < n; i++) {
1573                 const char *path = NULL;
1574                 uint32_t id;
1575
1576                 if (!show_properties || safe_atou32(args[i], &id) < 0) {
1577
1578                         if (!(m = dbus_message_new_method_call(
1579                                               "org.freedesktop.systemd1",
1580                                               "/org/freedesktop/systemd1",
1581                                               "org.freedesktop.systemd1.Manager",
1582                                               "LoadUnit"))) {
1583                                 log_error("Could not allocate message.");
1584                                 r = -ENOMEM;
1585                                 goto finish;
1586                         }
1587
1588                         if (!dbus_message_append_args(m,
1589                                                       DBUS_TYPE_STRING, &args[i],
1590                                                       DBUS_TYPE_INVALID)) {
1591                                 log_error("Could not append arguments to message.");
1592                                 r = -ENOMEM;
1593                                 goto finish;
1594                         }
1595
1596                 } else {
1597
1598                         if (!(m = dbus_message_new_method_call(
1599                                               "org.freedesktop.systemd1",
1600                                               "/org/freedesktop/systemd1",
1601                                               "org.freedesktop.systemd1.Manager",
1602                                               "GetJob"))) {
1603                                 log_error("Could not allocate message.");
1604                                 r = -ENOMEM;
1605                                 goto finish;
1606                         }
1607
1608                         if (!dbus_message_append_args(m,
1609                                                       DBUS_TYPE_UINT32, &id,
1610                                                       DBUS_TYPE_INVALID)) {
1611                                 log_error("Could not append arguments to message.");
1612                                 r = -ENOMEM;
1613                                 goto finish;
1614                         }
1615                 }
1616
1617                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1618                         log_error("Failed to issue method call: %s", error.message);
1619                         r = -EIO;
1620                         goto finish;
1621                 }
1622
1623                 if (!dbus_message_get_args(reply, &error,
1624                                            DBUS_TYPE_OBJECT_PATH, &path,
1625                                            DBUS_TYPE_INVALID)) {
1626                         log_error("Failed to parse reply: %s", error.message);
1627                         r = -EIO;
1628                         goto finish;
1629                 }
1630
1631                 if ((r = show_one(bus, path, show_properties, &new_line)) < 0)
1632                         goto finish;
1633
1634                 dbus_message_unref(m);
1635                 dbus_message_unref(reply);
1636                 m = reply = NULL;
1637         }
1638
1639         r = 0;
1640
1641 finish:
1642         if (m)
1643                 dbus_message_unref(m);
1644
1645         if (reply)
1646                 dbus_message_unref(reply);
1647
1648         dbus_error_free(&error);
1649
1650         return r;
1651 }
1652
1653 static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage *message, void *data) {
1654         DBusError error;
1655         DBusMessage *m = NULL, *reply = NULL;
1656
1657         assert(connection);
1658         assert(message);
1659
1660         dbus_error_init(&error);
1661
1662         /* log_debug("Got D-Bus request: %s.%s() on %s", */
1663         /*           dbus_message_get_interface(message), */
1664         /*           dbus_message_get_member(message), */
1665         /*           dbus_message_get_path(message)); */
1666
1667         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1668                 log_error("Warning! D-Bus connection terminated.");
1669                 dbus_connection_close(connection);
1670
1671         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitNew") ||
1672                    dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "UnitRemoved")) {
1673                 const char *id, *path;
1674
1675                 if (!dbus_message_get_args(message, &error,
1676                                            DBUS_TYPE_STRING, &id,
1677                                            DBUS_TYPE_OBJECT_PATH, &path,
1678                                            DBUS_TYPE_INVALID))
1679                         log_error("Failed to parse message: %s", error.message);
1680                 else if (streq(dbus_message_get_member(message), "UnitNew"))
1681                         printf("Unit %s added.\n", id);
1682                 else
1683                         printf("Unit %s removed.\n", id);
1684
1685         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobNew") ||
1686                    dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1687                 uint32_t id;
1688                 const char *path;
1689
1690                 if (!dbus_message_get_args(message, &error,
1691                                            DBUS_TYPE_UINT32, &id,
1692                                            DBUS_TYPE_OBJECT_PATH, &path,
1693                                            DBUS_TYPE_INVALID))
1694                         log_error("Failed to parse message: %s", error.message);
1695                 else if (streq(dbus_message_get_member(message), "JobNew"))
1696                         printf("Job %u added.\n", id);
1697                 else
1698                         printf("Job %u removed.\n", id);
1699
1700
1701         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Unit", "Changed") ||
1702                    dbus_message_is_signal(message, "org.freedesktop.systemd1.Job", "Changed")) {
1703
1704                 const char *path, *interface, *property = "Id";
1705                 DBusMessageIter iter, sub;
1706
1707                 path = dbus_message_get_path(message);
1708                 interface = dbus_message_get_interface(message);
1709
1710                 if (!(m = dbus_message_new_method_call(
1711                               "org.freedesktop.systemd1",
1712                               path,
1713                               "org.freedesktop.DBus.Properties",
1714                               "Get"))) {
1715                         log_error("Could not allocate message.");
1716                         goto oom;
1717                 }
1718
1719                 if (!dbus_message_append_args(m,
1720                                               DBUS_TYPE_STRING, &interface,
1721                                               DBUS_TYPE_STRING, &property,
1722                                               DBUS_TYPE_INVALID)) {
1723                         log_error("Could not append arguments to message.");
1724                         goto finish;
1725                 }
1726
1727                 if (!(reply = dbus_connection_send_with_reply_and_block(connection, m, -1, &error))) {
1728                         log_error("Failed to issue method call: %s", error.message);
1729                         goto finish;
1730                 }
1731
1732                 if (!dbus_message_iter_init(reply, &iter) ||
1733                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
1734                         log_error("Failed to parse reply.");
1735                         goto finish;
1736                 }
1737
1738                 dbus_message_iter_recurse(&iter, &sub);
1739
1740                 if (streq(interface, "org.freedesktop.systemd1.Unit")) {
1741                         const char *id;
1742
1743                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1744                                 log_error("Failed to parse reply.");
1745                                 goto finish;
1746                         }
1747
1748                         dbus_message_iter_get_basic(&sub, &id);
1749                         printf("Unit %s changed.\n", id);
1750                 } else {
1751                         uint32_t id;
1752
1753                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32)  {
1754                                 log_error("Failed to parse reply.");
1755                                 goto finish;
1756                         }
1757
1758                         dbus_message_iter_get_basic(&sub, &id);
1759                         printf("Job %u changed.\n", id);
1760                 }
1761         }
1762
1763 finish:
1764         if (m)
1765                 dbus_message_unref(m);
1766
1767         if (reply)
1768                 dbus_message_unref(reply);
1769
1770         dbus_error_free(&error);
1771         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1772
1773 oom:
1774         if (m)
1775                 dbus_message_unref(m);
1776
1777         if (reply)
1778                 dbus_message_unref(reply);
1779
1780         dbus_error_free(&error);
1781         return DBUS_HANDLER_RESULT_NEED_MEMORY;
1782 }
1783
1784 static int monitor(DBusConnection *bus, char **args, unsigned n) {
1785         DBusMessage *m = NULL, *reply = NULL;
1786         DBusError error;
1787         int r;
1788
1789         dbus_error_init(&error);
1790
1791         dbus_bus_add_match(bus,
1792                            "type='signal',"
1793                            "sender='org.freedesktop.systemd1',"
1794                            "interface='org.freedesktop.systemd1.Manager',"
1795                            "path='/org/freedesktop/systemd1'",
1796                            &error);
1797
1798         if (dbus_error_is_set(&error)) {
1799                 log_error("Failed to add match: %s", error.message);
1800                 r = -EIO;
1801                 goto finish;
1802         }
1803
1804         dbus_bus_add_match(bus,
1805                            "type='signal',"
1806                            "sender='org.freedesktop.systemd1',"
1807                            "interface='org.freedesktop.systemd1.Unit',"
1808                            "member='Changed'",
1809                            &error);
1810
1811         if (dbus_error_is_set(&error)) {
1812                 log_error("Failed to add match: %s", error.message);
1813                 r = -EIO;
1814                 goto finish;
1815         }
1816
1817         dbus_bus_add_match(bus,
1818                            "type='signal',"
1819                            "sender='org.freedesktop.systemd1',"
1820                            "interface='org.freedesktop.systemd1.Job',"
1821                            "member='Changed'",
1822                            &error);
1823
1824         if (dbus_error_is_set(&error)) {
1825                 log_error("Failed to add match: %s", error.message);
1826                 r = -EIO;
1827                 goto finish;
1828         }
1829
1830         if (!dbus_connection_add_filter(bus, monitor_filter, NULL, NULL)) {
1831                 log_error("Failed to add filter.");
1832                 r = -ENOMEM;
1833                 goto finish;
1834         }
1835
1836         if (!(m = dbus_message_new_method_call(
1837                               "org.freedesktop.systemd1",
1838                               "/org/freedesktop/systemd1",
1839                               "org.freedesktop.systemd1.Manager",
1840                               "Subscribe"))) {
1841                 log_error("Could not allocate message.");
1842                 r = -ENOMEM;
1843                 goto finish;
1844         }
1845
1846         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1847                 log_error("Failed to issue method call: %s", error.message);
1848                 r = -EIO;
1849                 goto finish;
1850         }
1851
1852         while (dbus_connection_read_write_dispatch(bus, -1))
1853                 ;
1854
1855         r = 0;
1856
1857 finish:
1858
1859         /* This is slightly dirty, since we don't undo the filter or the matches. */
1860
1861         if (m)
1862                 dbus_message_unref(m);
1863
1864         if (reply)
1865                 dbus_message_unref(reply);
1866
1867         dbus_error_free(&error);
1868
1869         return r;
1870 }
1871
1872 static int dump(DBusConnection *bus, char **args, unsigned n) {
1873         DBusMessage *m = NULL, *reply = NULL;
1874         DBusError error;
1875         int r;
1876         const char *text;
1877
1878         dbus_error_init(&error);
1879
1880         if (!(m = dbus_message_new_method_call(
1881                               "org.freedesktop.systemd1",
1882                               "/org/freedesktop/systemd1",
1883                               "org.freedesktop.systemd1.Manager",
1884                               "Dump"))) {
1885                 log_error("Could not allocate message.");
1886                 return -ENOMEM;
1887         }
1888
1889         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1890                 log_error("Failed to issue method call: %s", error.message);
1891                 r = -EIO;
1892                 goto finish;
1893         }
1894
1895         if (!dbus_message_get_args(reply, &error,
1896                                    DBUS_TYPE_STRING, &text,
1897                                    DBUS_TYPE_INVALID)) {
1898                 log_error("Failed to parse reply: %s", error.message);
1899                 r = -EIO;
1900                 goto finish;
1901         }
1902
1903         fputs(text, stdout);
1904
1905         r = 0;
1906
1907 finish:
1908         if (m)
1909                 dbus_message_unref(m);
1910
1911         if (reply)
1912                 dbus_message_unref(reply);
1913
1914         dbus_error_free(&error);
1915
1916         return r;
1917 }
1918
1919 static int snapshot(DBusConnection *bus, char **args, unsigned n) {
1920         DBusMessage *m = NULL, *reply = NULL;
1921         DBusError error;
1922         int r;
1923         const char *name = "", *path, *id;
1924         dbus_bool_t cleanup = FALSE;
1925         DBusMessageIter iter, sub;
1926         const char
1927                 *interface = "org.freedesktop.systemd1.Unit",
1928                 *property = "Id";
1929
1930         dbus_error_init(&error);
1931
1932         if (!(m = dbus_message_new_method_call(
1933                               "org.freedesktop.systemd1",
1934                               "/org/freedesktop/systemd1",
1935                               "org.freedesktop.systemd1.Manager",
1936                               "CreateSnapshot"))) {
1937                 log_error("Could not allocate message.");
1938                 return -ENOMEM;
1939         }
1940
1941         if (n > 1)
1942                 name = args[1];
1943
1944         if (!dbus_message_append_args(m,
1945                                       DBUS_TYPE_STRING, &name,
1946                                       DBUS_TYPE_BOOLEAN, &cleanup,
1947                                       DBUS_TYPE_INVALID)) {
1948                 log_error("Could not append arguments to message.");
1949                 r = -ENOMEM;
1950                 goto finish;
1951         }
1952
1953         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1954                 log_error("Failed to issue method call: %s", error.message);
1955                 r = -EIO;
1956                 goto finish;
1957         }
1958
1959         if (!dbus_message_get_args(reply, &error,
1960                                    DBUS_TYPE_OBJECT_PATH, &path,
1961                                    DBUS_TYPE_INVALID)) {
1962                 log_error("Failed to parse reply: %s", error.message);
1963                 r = -EIO;
1964                 goto finish;
1965         }
1966
1967         dbus_message_unref(m);
1968         if (!(m = dbus_message_new_method_call(
1969                               "org.freedesktop.systemd1",
1970                               path,
1971                               "org.freedesktop.DBus.Properties",
1972                               "Get"))) {
1973                 log_error("Could not allocate message.");
1974                 return -ENOMEM;
1975         }
1976
1977         if (!dbus_message_append_args(m,
1978                                       DBUS_TYPE_STRING, &interface,
1979                                       DBUS_TYPE_STRING, &property,
1980                                       DBUS_TYPE_INVALID)) {
1981                 log_error("Could not append arguments to message.");
1982                 r = -ENOMEM;
1983                 goto finish;
1984         }
1985
1986         dbus_message_unref(reply);
1987         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1988                 log_error("Failed to issue method call: %s", error.message);
1989                 r = -EIO;
1990                 goto finish;
1991         }
1992
1993         if (!dbus_message_iter_init(reply, &iter) ||
1994             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
1995                 log_error("Failed to parse reply.");
1996                 r = -EIO;
1997                 goto finish;
1998         }
1999
2000         dbus_message_iter_recurse(&iter, &sub);
2001
2002         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
2003                 log_error("Failed to parse reply.");
2004                 r = -EIO;
2005                 goto finish;
2006         }
2007
2008         dbus_message_iter_get_basic(&sub, &id);
2009
2010         if (!arg_quiet)
2011                 puts(id);
2012         r = 0;
2013
2014 finish:
2015         if (m)
2016                 dbus_message_unref(m);
2017
2018         if (reply)
2019                 dbus_message_unref(reply);
2020
2021         dbus_error_free(&error);
2022
2023         return r;
2024 }
2025
2026 static int delete_snapshot(DBusConnection *bus, char **args, unsigned n) {
2027         DBusMessage *m = NULL, *reply = NULL;
2028         int r;
2029         DBusError error;
2030         unsigned i;
2031
2032         assert(bus);
2033         assert(args);
2034
2035         dbus_error_init(&error);
2036
2037         for (i = 1; i < n; i++) {
2038                 const char *path = NULL;
2039
2040                 if (!(m = dbus_message_new_method_call(
2041                                       "org.freedesktop.systemd1",
2042                                       "/org/freedesktop/systemd1",
2043                                       "org.freedesktop.systemd1.Manager",
2044                                       "GetUnit"))) {
2045                         log_error("Could not allocate message.");
2046                         r = -ENOMEM;
2047                         goto finish;
2048                 }
2049
2050                 if (!dbus_message_append_args(m,
2051                                               DBUS_TYPE_STRING, &args[i],
2052                                               DBUS_TYPE_INVALID)) {
2053                         log_error("Could not append arguments to message.");
2054                         r = -ENOMEM;
2055                         goto finish;
2056                 }
2057
2058                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2059                         log_error("Failed to issue method call: %s", error.message);
2060                         r = -EIO;
2061                         goto finish;
2062                 }
2063
2064                 if (!dbus_message_get_args(reply, &error,
2065                                            DBUS_TYPE_OBJECT_PATH, &path,
2066                                            DBUS_TYPE_INVALID)) {
2067                         log_error("Failed to parse reply: %s", error.message);
2068                         r = -EIO;
2069                         goto finish;
2070                 }
2071
2072                 dbus_message_unref(m);
2073                 if (!(m = dbus_message_new_method_call(
2074                                       "org.freedesktop.systemd1",
2075                                       path,
2076                                       "org.freedesktop.systemd1.Snapshot",
2077                                       "Remove"))) {
2078                         log_error("Could not allocate message.");
2079                         r = -ENOMEM;
2080                         goto finish;
2081                 }
2082
2083                 dbus_message_unref(reply);
2084                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2085                         log_error("Failed to issue method call: %s", error.message);
2086                         r = -EIO;
2087                         goto finish;
2088                 }
2089
2090                 dbus_message_unref(m);
2091                 dbus_message_unref(reply);
2092                 m = reply = NULL;
2093         }
2094
2095         r = 0;
2096
2097 finish:
2098         if (m)
2099                 dbus_message_unref(m);
2100
2101         if (reply)
2102                 dbus_message_unref(reply);
2103
2104         dbus_error_free(&error);
2105
2106         return r;
2107 }
2108
2109 static int clear_jobs(DBusConnection *bus, char **args, unsigned n) {
2110         DBusMessage *m = NULL, *reply = NULL;
2111         DBusError error;
2112         int r;
2113         const char *method;
2114
2115         dbus_error_init(&error);
2116
2117         if (arg_action == ACTION_RELOAD)
2118                 method = "Reload";
2119         else if (arg_action == ACTION_REEXEC)
2120                 method = "Reexecute";
2121         else {
2122                 assert(arg_action == ACTION_SYSTEMCTL);
2123
2124                 method =
2125                         streq(args[0], "clear-jobs")    ? "ClearJobs" :
2126                         streq(args[0], "daemon-reload") ? "Reload" :
2127                         streq(args[0], "daemon-reexec") ? "Reexecute" :
2128                                                           "Exit";
2129         }
2130
2131         if (!(m = dbus_message_new_method_call(
2132                               "org.freedesktop.systemd1",
2133                               "/org/freedesktop/systemd1",
2134                               "org.freedesktop.systemd1.Manager",
2135                               method))) {
2136                 log_error("Could not allocate message.");
2137                 return -ENOMEM;
2138         }
2139
2140         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2141
2142                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
2143                         /* There's always a fallback possible for
2144                          * legacy actions. */
2145                         r = 0;
2146                         goto finish;
2147                 }
2148
2149                 log_error("Failed to issue method call: %s", error.message);
2150                 r = -EIO;
2151                 goto finish;
2152         }
2153
2154         r = 1;
2155
2156 finish:
2157         if (m)
2158                 dbus_message_unref(m);
2159
2160         if (reply)
2161                 dbus_message_unref(reply);
2162
2163         dbus_error_free(&error);
2164
2165         return r;
2166 }
2167
2168 static int show_enviroment(DBusConnection *bus, char **args, unsigned n) {
2169         DBusMessage *m = NULL, *reply = NULL;
2170         DBusError error;
2171         DBusMessageIter iter, sub, sub2;
2172         int r;
2173         const char
2174                 *interface = "org.freedesktop.systemd1.Manager",
2175                 *property = "Environment";
2176
2177         dbus_error_init(&error);
2178
2179         if (!(m = dbus_message_new_method_call(
2180                               "org.freedesktop.systemd1",
2181                               "/org/freedesktop/systemd1",
2182                               "org.freedesktop.DBus.Properties",
2183                               "Get"))) {
2184                 log_error("Could not allocate message.");
2185                 return -ENOMEM;
2186         }
2187
2188         if (!dbus_message_append_args(m,
2189                                       DBUS_TYPE_STRING, &interface,
2190                                       DBUS_TYPE_STRING, &property,
2191                                       DBUS_TYPE_INVALID)) {
2192                 log_error("Could not append arguments to message.");
2193                 r = -ENOMEM;
2194                 goto finish;
2195         }
2196
2197         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2198                 log_error("Failed to issue method call: %s", error.message);
2199                 r = -EIO;
2200                 goto finish;
2201         }
2202
2203         if (!dbus_message_iter_init(reply, &iter) ||
2204             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
2205                 log_error("Failed to parse reply.");
2206                 r = -EIO;
2207                 goto finish;
2208         }
2209
2210         dbus_message_iter_recurse(&iter, &sub);
2211
2212         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
2213             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
2214                 log_error("Failed to parse reply.");
2215                 r = -EIO;
2216                 goto finish;
2217         }
2218
2219         dbus_message_iter_recurse(&sub, &sub2);
2220
2221         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
2222                 const char *text;
2223
2224                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
2225                         log_error("Failed to parse reply.");
2226                         r = -EIO;
2227                         goto finish;
2228                 }
2229
2230                 dbus_message_iter_get_basic(&sub2, &text);
2231                 printf("%s\n", text);
2232
2233                 dbus_message_iter_next(&sub2);
2234         }
2235
2236         r = 0;
2237
2238 finish:
2239         if (m)
2240                 dbus_message_unref(m);
2241
2242         if (reply)
2243                 dbus_message_unref(reply);
2244
2245         dbus_error_free(&error);
2246
2247         return r;
2248 }
2249
2250 static int set_environment(DBusConnection *bus, char **args, unsigned n) {
2251         DBusMessage *m = NULL, *reply = NULL;
2252         DBusError error;
2253         int r;
2254         const char *method;
2255         DBusMessageIter iter, sub;
2256         unsigned i;
2257
2258         dbus_error_init(&error);
2259
2260         method = streq(args[0], "set-environment")
2261                 ? "SetEnvironment"
2262                 : "UnsetEnvironment";
2263
2264         if (!(m = dbus_message_new_method_call(
2265                               "org.freedesktop.systemd1",
2266                               "/org/freedesktop/systemd1",
2267                               "org.freedesktop.systemd1.Manager",
2268                               method))) {
2269
2270                 log_error("Could not allocate message.");
2271                 return -ENOMEM;
2272         }
2273
2274         dbus_message_iter_init_append(m, &iter);
2275
2276         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
2277                 log_error("Could not append arguments to message.");
2278                 r = -ENOMEM;
2279                 goto finish;
2280         }
2281
2282         for (i = 1; i < n; i++)
2283                 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &args[i])) {
2284                         log_error("Could not append arguments to message.");
2285                         r = -ENOMEM;
2286                         goto finish;
2287                 }
2288
2289         if (!dbus_message_iter_close_container(&iter, &sub)) {
2290                 log_error("Could not append arguments to message.");
2291                 r = -ENOMEM;
2292                 goto finish;
2293         }
2294
2295         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2296                 log_error("Failed to issue method call: %s", error.message);
2297                 r = -EIO;
2298                 goto finish;
2299         }
2300
2301         r = 0;
2302
2303 finish:
2304         if (m)
2305                 dbus_message_unref(m);
2306
2307         if (reply)
2308                 dbus_message_unref(reply);
2309
2310         dbus_error_free(&error);
2311
2312         return r;
2313 }
2314
2315 static int systemctl_help(void) {
2316
2317         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
2318                "Send control commands to the systemd manager.\n\n"
2319                "  -h --help          Show this help\n"
2320                "  -t --type=TYPE     List only units of a particular type\n"
2321                "  -p --property=NAME Show only properties by this name\n"
2322                "  -a --all           Show all units/properties, including dead/empty ones\n"
2323                "     --replace       When installing a new job, replace existing conflicting ones\n"
2324                "     --system        Connect to system bus\n"
2325                "     --session       Connect to session bus\n"
2326                "  -q --quiet         Suppress output\n"
2327                "     --no-block      Do not wait until operation finished\n"
2328                "     --no-wall       Don't send wall message before halt/power-off/reboot\n\n"
2329                "Commands:\n"
2330                "  list-units                      List units\n"
2331                "  start [NAME...]                 Start one or more units\n"
2332                "  stop [NAME...]                  Stop one or more units\n"
2333                "  restart [NAME...]               Restart one or more units\n"
2334                "  reload [NAME...]                Reload one or more units\n"
2335                "  isolate [NAME]                  Start one unit and stop all others\n"
2336                "  check [NAME...]                 Check whether any of the passed units are active\n"
2337                "  status [NAME...]                Show status of one or more units\n"
2338                "  show [NAME...|JOB...]           Show properties of one or more units/jobs/manager\n"
2339                "  load [NAME...]                  Load one or more units\n"
2340                "  list-jobs                       List jobs\n"
2341                "  cancel [JOB...]                 Cancel one or more jobs\n"
2342                "  clear-jobs                      Cancel all jobs\n"
2343                "  monitor                         Monitor unit/job changes\n"
2344                "  dump                            Dump server status\n"
2345                "  snapshot [NAME]                 Create a snapshot\n"
2346                "  delete [NAME...]                Remove one or more snapshots\n"
2347                "  daemon-reload                   Reload systemd manager configuration\n"
2348                "  daemon-reexec                   Reexecute systemd manager\n"
2349                "  daemon-exit                     Ask the systemd manager to quit\n"
2350                "  show-environment                Dump environment\n"
2351                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
2352                "  unset-environment [NAME...]     Unset one or more environment variables\n"
2353                "  halt                            Shut down and halt the system\n"
2354                "  poweroff                        Shut down and power-off the system\n"
2355                "  reboot                          Shut down and reboot the system\n"
2356                "  default                         Enter default mode\n"
2357                "  rescue                          Enter rescue mode\n"
2358                "  emergency                       Enter emergency mode\n",
2359                program_invocation_short_name);
2360
2361         return 0;
2362 }
2363
2364 static int halt_help(void) {
2365
2366         printf("%s [OPTIONS...]\n\n"
2367                "%s the system.\n\n"
2368                "     --help      Show this help\n"
2369                "     --halt      Halt the machine\n"
2370                "  -p --poweroff  Switch off the machine\n"
2371                "     --reboot    Reboot the machine\n"
2372                "  -f --force     Force immediate halt/power-off/reboot\n"
2373                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
2374                "  -d --no-wtmp   Don't write wtmp record\n"
2375                "  -n --no-sync   Don't sync before halt/power-off/reboot\n"
2376                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
2377                program_invocation_short_name,
2378                arg_action == ACTION_REBOOT   ? "Reboot" :
2379                arg_action == ACTION_POWEROFF ? "Power off" :
2380                                                "Halt");
2381
2382         return 0;
2383 }
2384
2385 static int shutdown_help(void) {
2386
2387         printf("%s [OPTIONS...] [now] [WALL...]\n\n"
2388                "Shut down the system.\n\n"
2389                "     --help      Show this help\n"
2390                "  -H --halt      Halt the machine\n"
2391                "  -P --poweroff  Power-off the machine\n"
2392                "  -r --reboot    Reboot the machine\n"
2393                "  -h             Equivalent to --poweroff, overriden by --halt\n"
2394                "  -k             Don't halt/power-off/reboot, just send warnings\n"
2395                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
2396                program_invocation_short_name);
2397
2398         return 0;
2399 }
2400
2401 static int telinit_help(void) {
2402
2403         printf("%s [OPTIONS...] {COMMAND}\n\n"
2404                "Send control commands to the init daemon.\n\n"
2405                "     --help      Show this help\n"
2406                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
2407                "Commands:\n"
2408                "  0              Power-off the machine\n"
2409                "  6              Reboot the machine\n"
2410                "  2, 3, 4, 5     Start runlevelX.target unit\n"
2411                "  1, s, S        Enter rescue mode\n"
2412                "  q, Q           Reload init daemon configuration\n"
2413                "  u, U           Reexecute init daemon\n",
2414                program_invocation_short_name);
2415
2416         return 0;
2417 }
2418
2419 static int runlevel_help(void) {
2420
2421         printf("%s [OPTIONS...]\n\n"
2422                "Prints the previous and current runlevel of the init system.\n\n"
2423                "     --help      Show this help\n",
2424                program_invocation_short_name);
2425
2426         return 0;
2427 }
2428
2429 static int systemctl_parse_argv(int argc, char *argv[]) {
2430
2431         enum {
2432                 ARG_REPLACE = 0x100,
2433                 ARG_SESSION,
2434                 ARG_SYSTEM,
2435                 ARG_NO_BLOCK,
2436                 ARG_NO_WALL
2437         };
2438
2439         static const struct option options[] = {
2440                 { "help",      no_argument,       NULL, 'h'          },
2441                 { "type",      required_argument, NULL, 't'          },
2442                 { "property",  required_argument, NULL, 'p'          },
2443                 { "all",       no_argument,       NULL, 'a'          },
2444                 { "replace",   no_argument,       NULL, ARG_REPLACE  },
2445                 { "session",   no_argument,       NULL, ARG_SESSION  },
2446                 { "system",    no_argument,       NULL, ARG_SYSTEM   },
2447                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK },
2448                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL  },
2449                 { "quiet",     no_argument,       NULL, 'q'          },
2450                 { NULL,        0,                 NULL, 0            }
2451         };
2452
2453         int c;
2454
2455         assert(argc >= 0);
2456         assert(argv);
2457
2458         while ((c = getopt_long(argc, argv, "ht:p:aq", options, NULL)) >= 0) {
2459
2460                 switch (c) {
2461
2462                 case 'h':
2463                         systemctl_help();
2464                         return 0;
2465
2466                 case 't':
2467                         arg_type = optarg;
2468                         break;
2469
2470                 case 'p':
2471                         arg_property = optarg;
2472
2473                         /* If the user asked for a particular
2474                          * property, show it to him, even if it is
2475                          * empty. */
2476                         arg_all = true;
2477                         break;
2478
2479                 case 'a':
2480                         arg_all = true;
2481                         break;
2482
2483                 case ARG_REPLACE:
2484                         arg_replace = true;
2485                         break;
2486
2487                 case ARG_SESSION:
2488                         arg_session = true;
2489                         break;
2490
2491                 case ARG_SYSTEM:
2492                         arg_session = false;
2493                         break;
2494
2495                 case ARG_NO_BLOCK:
2496                         arg_no_block = true;
2497                         break;
2498
2499                 case ARG_NO_WALL:
2500                         arg_no_wall = true;
2501                         break;
2502
2503                 case 'q':
2504                         arg_quiet = true;
2505                         break;
2506
2507                 case '?':
2508                         return -EINVAL;
2509
2510                 default:
2511                         log_error("Unknown option code %c", c);
2512                         return -EINVAL;
2513                 }
2514         }
2515
2516         return 1;
2517 }
2518
2519 static int halt_parse_argv(int argc, char *argv[]) {
2520
2521         enum {
2522                 ARG_HELP = 0x100,
2523                 ARG_HALT,
2524                 ARG_REBOOT,
2525                 ARG_NO_WALL
2526         };
2527
2528         static const struct option options[] = {
2529                 { "help",      no_argument,       NULL, ARG_HELP    },
2530                 { "halt",      no_argument,       NULL, ARG_HALT    },
2531                 { "poweroff",  no_argument,       NULL, 'p'         },
2532                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
2533                 { "force",     no_argument,       NULL, 'f'         },
2534                 { "wtmp-only", no_argument,       NULL, 'w'         },
2535                 { "no-wtmp",   no_argument,       NULL, 'd'         },
2536                 { "no-sync",   no_argument,       NULL, 'n'         },
2537                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
2538                 { NULL,        0,                 NULL, 0           }
2539         };
2540
2541         int c, runlevel;
2542
2543         assert(argc >= 0);
2544         assert(argv);
2545
2546         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
2547                 if (runlevel == '0' || runlevel == '6')
2548                         arg_immediate = true;
2549
2550         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
2551                 switch (c) {
2552
2553                 case ARG_HELP:
2554                         halt_help();
2555                         return 0;
2556
2557                 case ARG_HALT:
2558                         arg_action = ACTION_HALT;
2559                         break;
2560
2561                 case 'p':
2562                         arg_action = ACTION_POWEROFF;
2563                         break;
2564
2565                 case ARG_REBOOT:
2566                         arg_action = ACTION_REBOOT;
2567                         break;
2568
2569                 case 'f':
2570                         arg_immediate = true;
2571                         break;
2572
2573                 case 'w':
2574                         arg_dry = true;
2575                         break;
2576
2577                 case 'd':
2578                         arg_no_wtmp = true;
2579                         break;
2580
2581                 case 'n':
2582                         arg_no_sync = true;
2583                         break;
2584
2585                 case ARG_NO_WALL:
2586                         arg_no_wall = true;
2587                         break;
2588
2589                 case 'i':
2590                 case 'h':
2591                         /* Compatibility nops */
2592                         break;
2593
2594                 case '?':
2595                         return -EINVAL;
2596
2597                 default:
2598                         log_error("Unknown option code %c", c);
2599                         return -EINVAL;
2600                 }
2601         }
2602
2603         if (optind < argc) {
2604                 log_error("Too many arguments.");
2605                 return -EINVAL;
2606         }
2607
2608         return 1;
2609 }
2610
2611 static int shutdown_parse_argv(int argc, char *argv[]) {
2612
2613         enum {
2614                 ARG_HELP = 0x100,
2615                 ARG_NO_WALL
2616         };
2617
2618         static const struct option options[] = {
2619                 { "help",      no_argument,       NULL, ARG_HELP    },
2620                 { "halt",      no_argument,       NULL, 'H'         },
2621                 { "poweroff",  no_argument,       NULL, 'P'         },
2622                 { "reboot",    no_argument,       NULL, 'r'         },
2623                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
2624                 { NULL,        0,                 NULL, 0           }
2625         };
2626
2627         int c;
2628
2629         assert(argc >= 0);
2630         assert(argv);
2631
2632         while ((c = getopt_long(argc, argv, "HPrhkt:a", options, NULL)) >= 0) {
2633                 switch (c) {
2634
2635                 case ARG_HELP:
2636                         shutdown_help();
2637                         return 0;
2638
2639                 case 'H':
2640                         arg_action = ACTION_HALT;
2641                         break;
2642
2643                 case 'P':
2644                         arg_action = ACTION_POWEROFF;
2645                         break;
2646
2647                 case 'r':
2648                         arg_action = ACTION_REBOOT;
2649                         break;
2650
2651                 case 'h':
2652                         if (arg_action != ACTION_HALT)
2653                                 arg_action = ACTION_POWEROFF;
2654                         break;
2655
2656                 case 'k':
2657                         arg_dry = true;
2658                         break;
2659
2660                 case ARG_NO_WALL:
2661                         arg_no_wall = true;
2662                         break;
2663
2664                 case 't':
2665                 case 'a':
2666                         /* Compatibility nops */
2667                         break;
2668
2669                 case '?':
2670                         return -EINVAL;
2671
2672                 default:
2673                         log_error("Unknown option code %c", c);
2674                         return -EINVAL;
2675                 }
2676         }
2677
2678         if (argc > optind && !streq(argv[optind], "now"))
2679                 log_warning("First argument '%s' isn't 'now'. Ignoring.", argv[optind]);
2680
2681         /* We ignore the time argument */
2682         if (argc > optind + 1)
2683                 arg_wall = argv + optind + 1;
2684
2685         optind = argc;
2686
2687         return 1;
2688 }
2689
2690 static int telinit_parse_argv(int argc, char *argv[]) {
2691
2692         enum {
2693                 ARG_HELP = 0x100,
2694                 ARG_NO_WALL
2695         };
2696
2697         static const struct option options[] = {
2698                 { "help",      no_argument,       NULL, ARG_HELP    },
2699                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
2700                 { NULL,        0,                 NULL, 0           }
2701         };
2702
2703         static const struct {
2704                 char from;
2705                 enum action to;
2706         } table[] = {
2707                 { '0', ACTION_POWEROFF },
2708                 { '6', ACTION_REBOOT },
2709                 { '1', ACTION_RESCUE },
2710                 { '2', ACTION_RUNLEVEL2 },
2711                 { '3', ACTION_RUNLEVEL3 },
2712                 { '4', ACTION_RUNLEVEL4 },
2713                 { '5', ACTION_RUNLEVEL5 },
2714                 { 's', ACTION_RESCUE },
2715                 { 'S', ACTION_RESCUE },
2716                 { 'q', ACTION_RELOAD },
2717                 { 'Q', ACTION_RELOAD },
2718                 { 'u', ACTION_REEXEC },
2719                 { 'U', ACTION_REEXEC }
2720         };
2721
2722         unsigned i;
2723         int c;
2724
2725         assert(argc >= 0);
2726         assert(argv);
2727
2728         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
2729                 switch (c) {
2730
2731                 case ARG_HELP:
2732                         telinit_help();
2733                         return 0;
2734
2735                 case ARG_NO_WALL:
2736                         arg_no_wall = true;
2737                         break;
2738
2739                 case '?':
2740                         return -EINVAL;
2741
2742                 default:
2743                         log_error("Unknown option code %c", c);
2744                         return -EINVAL;
2745                 }
2746         }
2747
2748         if (optind >= argc) {
2749                 telinit_help();
2750                 return -EINVAL;
2751         }
2752
2753         if (optind + 1 < argc) {
2754                 log_error("Too many arguments.");
2755                 return -EINVAL;
2756         }
2757
2758         if (strlen(argv[optind]) != 1) {
2759                 log_error("Expected single character argument.");
2760                 return -EINVAL;
2761         }
2762
2763         for (i = 0; i < ELEMENTSOF(table); i++)
2764                 if (table[i].from == argv[optind][0])
2765                         break;
2766
2767         if (i >= ELEMENTSOF(table)) {
2768                 log_error("Unknown command %s.", argv[optind]);
2769                 return -EINVAL;
2770         }
2771
2772         arg_action = table[i].to;
2773
2774         optind ++;
2775
2776         return 1;
2777 }
2778
2779 static int runlevel_parse_argv(int argc, char *argv[]) {
2780
2781         enum {
2782                 ARG_HELP = 0x100,
2783         };
2784
2785         static const struct option options[] = {
2786                 { "help",      no_argument,       NULL, ARG_HELP    },
2787                 { NULL,        0,                 NULL, 0           }
2788         };
2789
2790         int c;
2791
2792         assert(argc >= 0);
2793         assert(argv);
2794
2795         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
2796                 switch (c) {
2797
2798                 case ARG_HELP:
2799                         runlevel_help();
2800                         return 0;
2801
2802                 case '?':
2803                         return -EINVAL;
2804
2805                 default:
2806                         log_error("Unknown option code %c", c);
2807                         return -EINVAL;
2808                 }
2809         }
2810
2811         if (optind < argc) {
2812                 log_error("Too many arguments.");
2813                 return -EINVAL;
2814         }
2815
2816         return 1;
2817 }
2818
2819 static int parse_argv(int argc, char *argv[]) {
2820         assert(argc >= 0);
2821         assert(argv);
2822
2823         if (program_invocation_short_name) {
2824
2825                 if (strstr(program_invocation_short_name, "halt")) {
2826                         arg_action = ACTION_HALT;
2827                         return halt_parse_argv(argc, argv);
2828                 } else if (strstr(program_invocation_short_name, "poweroff")) {
2829                         arg_action = ACTION_POWEROFF;
2830                         return halt_parse_argv(argc, argv);
2831                 } else if (strstr(program_invocation_short_name, "reboot")) {
2832                         arg_action = ACTION_REBOOT;
2833                         return halt_parse_argv(argc, argv);
2834                 } else if (strstr(program_invocation_short_name, "shutdown")) {
2835                         arg_action = ACTION_POWEROFF;
2836                         return shutdown_parse_argv(argc, argv);
2837                 } else if (strstr(program_invocation_short_name, "init")) {
2838                         arg_action = ACTION_INVALID;
2839                         return telinit_parse_argv(argc, argv);
2840                 } else if (strstr(program_invocation_short_name, "runlevel")) {
2841                         arg_action = ACTION_RUNLEVEL;
2842                         return runlevel_parse_argv(argc, argv);
2843                 }
2844         }
2845
2846         arg_action = ACTION_SYSTEMCTL;
2847         return systemctl_parse_argv(argc, argv);
2848 }
2849
2850 static int action_to_runlevel(void) {
2851
2852         static const char table[_ACTION_MAX] = {
2853                 [ACTION_HALT] =      '0',
2854                 [ACTION_POWEROFF] =  '0',
2855                 [ACTION_REBOOT] =    '6',
2856                 [ACTION_RUNLEVEL2] = '2',
2857                 [ACTION_RUNLEVEL3] = '3',
2858                 [ACTION_RUNLEVEL4] = '4',
2859                 [ACTION_RUNLEVEL5] = '5',
2860                 [ACTION_RESCUE] =    '1'
2861         };
2862
2863         assert(arg_action < _ACTION_MAX);
2864
2865         return table[arg_action];
2866 }
2867
2868 static int talk_upstart(void) {
2869         DBusMessage *m = NULL, *reply = NULL;
2870         DBusError error;
2871         int previous, rl, r;
2872         char
2873                 env1_buf[] = "RUNLEVEL=X",
2874                 env2_buf[] = "PREVLEVEL=X";
2875         char *env1 = env1_buf, *env2 = env2_buf;
2876         const char *emit = "runlevel";
2877         dbus_bool_t b_false = FALSE;
2878         DBusMessageIter iter, sub;
2879         DBusConnection *bus;
2880
2881         dbus_error_init(&error);
2882
2883         if (!(rl = action_to_runlevel()))
2884                 return 0;
2885
2886         if (utmp_get_runlevel(&previous, NULL) < 0)
2887                 previous = 'N';
2888
2889         if (!(bus = dbus_connection_open("unix:abstract=/com/ubuntu/upstart", &error))) {
2890                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
2891                         r = 0;
2892                         goto finish;
2893                 }
2894
2895                 log_error("Failed to connect to Upstart bus: %s", error.message);
2896                 r = -EIO;
2897                 goto finish;
2898         }
2899
2900         if ((r = bus_check_peercred(bus)) < 0) {
2901                 log_error("Failed to verify owner of bus.");
2902                 goto finish;
2903         }
2904
2905         if (!(m = dbus_message_new_method_call(
2906                               "com.ubuntu.Upstart",
2907                               "/com/ubuntu/Upstart",
2908                               "com.ubuntu.Upstart0_6",
2909                               "EmitEvent"))) {
2910
2911                 log_error("Could not allocate message.");
2912                 r = -ENOMEM;
2913                 goto finish;
2914         }
2915
2916         dbus_message_iter_init_append(m, &iter);
2917
2918         env1_buf[sizeof(env1_buf)-2] = rl;
2919         env2_buf[sizeof(env2_buf)-2] = previous;
2920
2921         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
2922             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
2923             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
2924             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
2925             !dbus_message_iter_close_container(&iter, &sub) ||
2926             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
2927                 log_error("Could not append arguments to message.");
2928                 r = -ENOMEM;
2929                 goto finish;
2930         }
2931
2932         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2933
2934                 if (error_is_no_service(&error)) {
2935                         r = 0;
2936                         goto finish;
2937                 }
2938
2939                 log_error("Failed to issue method call: %s", error.message);
2940                 r = -EIO;
2941                 goto finish;
2942         }
2943
2944         r = 1;
2945
2946 finish:
2947         if (m)
2948                 dbus_message_unref(m);
2949
2950         if (reply)
2951                 dbus_message_unref(reply);
2952
2953         if (bus)
2954                 dbus_connection_unref(bus);
2955
2956         dbus_error_free(&error);
2957
2958         return r;
2959 }
2960
2961 static int talk_initctl(void) {
2962         struct init_request request;
2963         int r, fd;
2964         char rl;
2965
2966         if (!(rl = action_to_runlevel()))
2967                 return 0;
2968
2969         zero(request);
2970         request.magic = INIT_MAGIC;
2971         request.sleeptime = 0;
2972         request.cmd = INIT_CMD_RUNLVL;
2973         request.runlevel = rl;
2974
2975         if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
2976
2977                 if (errno == ENOENT)
2978                         return 0;
2979
2980                 log_error("Failed to open "INIT_FIFO": %m");
2981                 return -errno;
2982         }
2983
2984         errno = 0;
2985         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
2986         close_nointr_nofail(fd);
2987
2988         if (r < 0) {
2989                 log_error("Failed to write to "INIT_FIFO": %m");
2990                 return errno ? -errno : -EIO;
2991         }
2992
2993         return 1;
2994 }
2995
2996 static int systemctl_main(DBusConnection *bus, int argc, char *argv[]) {
2997
2998         static const struct {
2999                 const char* verb;
3000                 const enum {
3001                         MORE,
3002                         LESS,
3003                         EQUAL
3004                 } argc_cmp;
3005                 const int argc;
3006                 int (* const dispatch)(DBusConnection *bus, char **args, unsigned n);
3007         } verbs[] = {
3008                 { "list-units",        LESS,  1, list_units      },
3009                 { "list-jobs",         EQUAL, 1, list_jobs       },
3010                 { "clear-jobs",        EQUAL, 1, clear_jobs      },
3011                 { "load",              MORE,  2, load_unit       },
3012                 { "cancel",            MORE,  2, cancel_job      },
3013                 { "start",             MORE,  2, start_unit      },
3014                 { "stop",              MORE,  2, start_unit      },
3015                 { "reload",            MORE,  2, start_unit      },
3016                 { "restart",           MORE,  2, start_unit      },
3017                 { "isolate",           EQUAL, 2, start_unit      },
3018                 { "check",             MORE,  2, check_unit      },
3019                 { "show",              MORE,  1, show            },
3020                 { "status",            MORE,  2, show            },
3021                 { "monitor",           EQUAL, 1, monitor         },
3022                 { "dump",              EQUAL, 1, dump            },
3023                 { "snapshot",          LESS,  2, snapshot        },
3024                 { "delete",            MORE,  2, delete_snapshot },
3025                 { "daemon-reload",     EQUAL, 1, clear_jobs      },
3026                 { "daemon-reexec",     EQUAL, 1, clear_jobs      },
3027                 { "daemon-exit",       EQUAL, 1, clear_jobs      },
3028                 { "show-environment",  EQUAL, 1, show_enviroment },
3029                 { "set-environment",   MORE,  2, set_environment },
3030                 { "unset-environment", MORE,  2, set_environment },
3031                 { "halt",              EQUAL, 1, start_special   },
3032                 { "poweroff",          EQUAL, 1, start_special   },
3033                 { "reboot",            EQUAL, 1, start_special   },
3034                 { "default",           EQUAL, 1, start_special   },
3035                 { "rescue",            EQUAL, 1, start_special   },
3036                 { "emergency",         EQUAL, 1, start_special   },
3037         };
3038
3039         int left;
3040         unsigned i;
3041
3042         assert(bus);
3043         assert(argc >= 0);
3044         assert(argv);
3045
3046         left = argc - optind;
3047
3048         if (left <= 0)
3049                 /* Special rule: no arguments means "list-units" */
3050                 i = 0;
3051         else {
3052                 if (streq(argv[optind], "help")) {
3053                         systemctl_help();
3054                         return 0;
3055                 }
3056
3057                 for (i = 0; i < ELEMENTSOF(verbs); i++)
3058                         if (streq(argv[optind], verbs[i].verb))
3059                                 break;
3060
3061                 if (i >= ELEMENTSOF(verbs)) {
3062                         log_error("Unknown operation %s", argv[optind]);
3063                         return -EINVAL;
3064                 }
3065         }
3066
3067         switch (verbs[i].argc_cmp) {
3068
3069         case EQUAL:
3070                 if (left != verbs[i].argc) {
3071                         log_error("Invalid number of arguments.");
3072                         return -EINVAL;
3073                 }
3074
3075                 break;
3076
3077         case MORE:
3078                 if (left < verbs[i].argc) {
3079                         log_error("Too few arguments.");
3080                         return -EINVAL;
3081                 }
3082
3083                 break;
3084
3085         case LESS:
3086                 if (left > verbs[i].argc) {
3087                         log_error("Too many arguments.");
3088                         return -EINVAL;
3089                 }
3090
3091                 break;
3092
3093         default:
3094                 assert_not_reached("Unknown comparison operator.");
3095         }
3096
3097         return verbs[i].dispatch(bus, argv + optind, left);
3098 }
3099
3100 static int reload_with_fallback(DBusConnection *bus) {
3101         int r;
3102
3103         if (bus) {
3104                 /* First, try systemd via D-Bus. */
3105                 if ((r = clear_jobs(bus, NULL, 0)) > 0)
3106                         return 0;
3107         }
3108
3109         /* Nothing else worked, so let's try signals */
3110         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
3111
3112         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
3113                 log_error("kill() failed: %m");
3114                 return -errno;
3115         }
3116
3117         return 0;
3118 }
3119
3120 static int start_with_fallback(DBusConnection *bus) {
3121         int r;
3122
3123         warn_wall(arg_action);
3124
3125         if (bus) {
3126                 /* First, try systemd via D-Bus. */
3127                 if ((r = start_unit(bus, NULL, 0)) > 0)
3128                         return 0;
3129
3130                 /* Hmm, talking to systemd via D-Bus didn't work. Then
3131                  * let's try to talk to Upstart via D-Bus. */
3132                 if ((r = talk_upstart()) > 0)
3133                         return 0;
3134         }
3135
3136         /* Nothing else worked, so let's try
3137          * /dev/initctl */
3138         if ((r = talk_initctl()) != 0)
3139                 return 0;
3140
3141         log_error("Failed to talk to init daemon.");
3142         return -EIO;
3143 }
3144
3145 static int halt_main(DBusConnection *bus) {
3146         int r;
3147
3148         if (!arg_immediate)
3149                 return start_with_fallback(bus);
3150
3151         if (!arg_no_wtmp)
3152                 if ((r = utmp_put_shutdown(0)) < 0)
3153                         log_warning("Failed to write utmp record: %s", strerror(-r));
3154
3155         if (!arg_no_sync)
3156                 sync();
3157
3158         if (arg_dry)
3159                 return 0;
3160
3161         /* Make sure C-A-D is handled by the kernel from this
3162          * point on... */
3163         reboot(RB_ENABLE_CAD);
3164
3165         switch (arg_action) {
3166
3167         case ACTION_HALT:
3168                 log_info("Halting");
3169                 reboot(RB_HALT_SYSTEM);
3170                 break;
3171
3172         case ACTION_POWEROFF:
3173                 log_info("Powering off");
3174                 reboot(RB_POWER_OFF);
3175                 break;
3176
3177         case ACTION_REBOOT:
3178                 log_info("Rebooting");
3179                 reboot(RB_AUTOBOOT);
3180                 break;
3181
3182         default:
3183                 assert_not_reached("Unknown halt action.");
3184         }
3185
3186         /* We should never reach this. */
3187         return -ENOSYS;
3188 }
3189
3190 static int runlevel_main(void) {
3191         int r, runlevel, previous;
3192
3193         if ((r = utmp_get_runlevel(&runlevel, &previous)) < 0) {
3194                 printf("unknown");
3195                 return r;
3196         }
3197
3198         printf("%c %c\n",
3199                previous <= 0 ? 'N' : previous,
3200                runlevel <= 0 ? 'N' : runlevel);
3201
3202         return 0;
3203 }
3204
3205 int main(int argc, char*argv[]) {
3206         int r, retval = 1;
3207         DBusConnection *bus = NULL;
3208         DBusError error;
3209
3210         dbus_error_init(&error);
3211
3212         log_parse_environment();
3213
3214         if ((r = parse_argv(argc, argv)) < 0)
3215                 goto finish;
3216         else if (r == 0) {
3217                 retval = 0;
3218                 goto finish;
3219         }
3220
3221         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
3222          * let's shortcut this */
3223         if (arg_action == ACTION_RUNLEVEL) {
3224                 retval = runlevel_main() < 0;
3225                 goto finish;
3226         }
3227
3228         /* If we are root, then let's not go via the bus */
3229         if (geteuid() == 0 && !arg_session) {
3230                 bus = dbus_connection_open("unix:abstract=/org/freedesktop/systemd1/private", &error);
3231
3232                 if (bus && bus_check_peercred(bus) < 0) {
3233                         log_error("Failed to verify owner of bus.");
3234                         goto finish;
3235                 }
3236         } else
3237                 bus = dbus_bus_get(arg_session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &error);
3238
3239         if (bus)
3240                 dbus_connection_set_exit_on_disconnect(bus, FALSE);
3241
3242         switch (arg_action) {
3243
3244         case ACTION_SYSTEMCTL: {
3245
3246                 if (!bus) {
3247                         log_error("Failed to get D-Bus connection: %s", error.message);
3248                         goto finish;
3249                 }
3250
3251                 retval = systemctl_main(bus, argc, argv) < 0;
3252                 break;
3253         }
3254
3255         case ACTION_HALT:
3256         case ACTION_POWEROFF:
3257         case ACTION_REBOOT:
3258                 retval = halt_main(bus) < 0;
3259                 break;
3260
3261         case ACTION_RUNLEVEL2:
3262         case ACTION_RUNLEVEL3:
3263         case ACTION_RUNLEVEL4:
3264         case ACTION_RUNLEVEL5:
3265         case ACTION_RESCUE:
3266         case ACTION_EMERGENCY:
3267         case ACTION_DEFAULT:
3268                 retval = start_with_fallback(bus) < 0;
3269                 break;
3270
3271         case ACTION_RELOAD:
3272         case ACTION_REEXEC:
3273                 retval = reload_with_fallback(bus) < 0;
3274                 break;
3275
3276         case ACTION_INVALID:
3277         case ACTION_RUNLEVEL:
3278         default:
3279                 assert_not_reached("Unknown action");
3280         }
3281
3282 finish:
3283
3284         if (bus)
3285                 dbus_connection_unref(bus);
3286
3287         dbus_error_free(&error);
3288
3289         dbus_shutdown();
3290
3291         return retval;
3292 }