chiark / gitweb /
login: track login class (i.e. one of "user", "greeter", "lock-screen") for each...
[elogind.git] / src / systemctl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/reboot.h>
23 #include <stdio.h>
24 #include <getopt.h>
25 #include <stdbool.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <sys/ioctl.h>
29 #include <termios.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <sys/socket.h>
33 #include <sys/stat.h>
34 #include <stddef.h>
35 #include <sys/prctl.h>
36 #include <dbus/dbus.h>
37
38 #include <systemd/sd-daemon.h>
39
40 #include "log.h"
41 #include "util.h"
42 #include "macro.h"
43 #include "set.h"
44 #include "utmp-wtmp.h"
45 #include "special.h"
46 #include "initreq.h"
47 #include "strv.h"
48 #include "dbus-common.h"
49 #include "cgroup-show.h"
50 #include "cgroup-util.h"
51 #include "list.h"
52 #include "path-lookup.h"
53 #include "conf-parser.h"
54 #include "shutdownd.h"
55 #include "exit-status.h"
56 #include "bus-errors.h"
57 #include "build.h"
58 #include "unit-name.h"
59 #include "pager.h"
60 #include "spawn-agent.h"
61 #include "install.h"
62 #include "logs-show.h"
63
64 static const char *arg_type = NULL;
65 static char **arg_property = NULL;
66 static bool arg_all = false;
67 static const char *arg_job_mode = "replace";
68 static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
69 static bool arg_immediate = false;
70 static bool arg_no_block = false;
71 static bool arg_no_legend = false;
72 static bool arg_no_pager = false;
73 static bool arg_no_wtmp = false;
74 static bool arg_no_sync = false;
75 static bool arg_no_wall = false;
76 static bool arg_no_reload = false;
77 static bool arg_dry = false;
78 static bool arg_quiet = false;
79 static bool arg_full = false;
80 static bool arg_force = false;
81 static bool arg_ask_password = false;
82 static bool arg_failed = false;
83 static bool arg_runtime = false;
84 static char **arg_wall = NULL;
85 static const char *arg_kill_who = NULL;
86 static const char *arg_kill_mode = NULL;
87 static int arg_signal = SIGTERM;
88 static const char *arg_root = NULL;
89 static usec_t arg_when = 0;
90 static enum action {
91         ACTION_INVALID,
92         ACTION_SYSTEMCTL,
93         ACTION_HALT,
94         ACTION_POWEROFF,
95         ACTION_REBOOT,
96         ACTION_KEXEC,
97         ACTION_EXIT,
98         ACTION_RUNLEVEL2,
99         ACTION_RUNLEVEL3,
100         ACTION_RUNLEVEL4,
101         ACTION_RUNLEVEL5,
102         ACTION_RESCUE,
103         ACTION_EMERGENCY,
104         ACTION_DEFAULT,
105         ACTION_RELOAD,
106         ACTION_REEXEC,
107         ACTION_RUNLEVEL,
108         ACTION_CANCEL_SHUTDOWN,
109         _ACTION_MAX
110 } arg_action = ACTION_SYSTEMCTL;
111 static enum dot {
112         DOT_ALL,
113         DOT_ORDER,
114         DOT_REQUIRE
115 } arg_dot = DOT_ALL;
116 static enum transport {
117         TRANSPORT_NORMAL,
118         TRANSPORT_SSH,
119         TRANSPORT_POLKIT
120 } arg_transport = TRANSPORT_NORMAL;
121 static const char *arg_host = NULL;
122 static bool arg_follow = false;
123 static unsigned arg_lines = 10;
124 static OutputMode arg_output = OUTPUT_SHORT;
125
126 static bool private_bus = false;
127
128 static int daemon_reload(DBusConnection *bus, char **args);
129
130 static bool on_tty(void) {
131         static int t = -1;
132
133         /* Note that this is invoked relatively early, before we start
134          * the pager. That means the value we return reflects whether
135          * we originally were started on a tty, not if we currently
136          * are. But this is intended, since we want colour and so on
137          * when run in our own pager. */
138
139         if (_unlikely_(t < 0))
140                 t = isatty(STDOUT_FILENO) > 0;
141
142         return t;
143 }
144
145 static void pager_open_if_enabled(void) {
146
147         /* Cache result before we open the pager */
148         on_tty();
149
150         if (arg_no_pager)
151                 return;
152
153         pager_open();
154 }
155
156 static void agent_open_if_enabled(void) {
157
158         /* Open the password agent as a child process if necessary */
159
160         if (!arg_ask_password)
161                 return;
162
163         if (arg_scope != UNIT_FILE_SYSTEM)
164                 return;
165
166         agent_open();
167 }
168
169 static const char *ansi_highlight_red(bool b) {
170
171         if (!on_tty())
172                 return "";
173
174         return b ? ANSI_HIGHLIGHT_RED_ON : ANSI_HIGHLIGHT_OFF;
175 }
176
177 static const char *ansi_highlight_green(bool b) {
178
179         if (!on_tty())
180                 return "";
181
182         return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF;
183 }
184
185 static bool error_is_no_service(const DBusError *error) {
186         assert(error);
187
188         if (!dbus_error_is_set(error))
189                 return false;
190
191         if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER))
192                 return true;
193
194         if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN))
195                 return true;
196
197         return startswith(error->name, "org.freedesktop.DBus.Error.Spawn.");
198 }
199
200 static int translate_bus_error_to_exit_status(int r, const DBusError *error) {
201         assert(error);
202
203         if (!dbus_error_is_set(error))
204                 return r;
205
206         if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED) ||
207             dbus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) ||
208             dbus_error_has_name(error, BUS_ERROR_NO_ISOLATION) ||
209             dbus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
210                 return EXIT_NOPERMISSION;
211
212         if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
213                 return EXIT_NOTINSTALLED;
214
215         if (dbus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) ||
216             dbus_error_has_name(error, BUS_ERROR_NOT_SUPPORTED))
217                 return EXIT_NOTIMPLEMENTED;
218
219         if (dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
220                 return EXIT_NOTCONFIGURED;
221
222         if (r != 0)
223                 return r;
224
225         return EXIT_FAILURE;
226 }
227
228 static void warn_wall(enum action action) {
229         static const char *table[_ACTION_MAX] = {
230                 [ACTION_HALT]      = "The system is going down for system halt NOW!",
231                 [ACTION_REBOOT]    = "The system is going down for reboot NOW!",
232                 [ACTION_POWEROFF]  = "The system is going down for power-off NOW!",
233                 [ACTION_KEXEC]     = "The system is going down for kexec reboot NOW!",
234                 [ACTION_RESCUE]    = "The system is going down to rescue mode NOW!",
235                 [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!"
236         };
237
238         if (arg_no_wall)
239                 return;
240
241         if (arg_wall) {
242                 char *p;
243
244                 if (!(p = strv_join(arg_wall, " "))) {
245                         log_error("Failed to join strings.");
246                         return;
247                 }
248
249                 if (*p) {
250                         utmp_wall(p, NULL);
251                         free(p);
252                         return;
253                 }
254
255                 free(p);
256         }
257
258         if (!table[action])
259                 return;
260
261         utmp_wall(table[action], NULL);
262 }
263
264 static bool avoid_bus(void) {
265
266         if (running_in_chroot() > 0)
267                 return true;
268
269         if (sd_booted() <= 0)
270                 return true;
271
272         if (!isempty(arg_root))
273                 return true;
274
275         if (arg_scope == UNIT_FILE_GLOBAL)
276                 return true;
277
278         return false;
279 }
280
281 struct unit_info {
282         const char *id;
283         const char *description;
284         const char *load_state;
285         const char *active_state;
286         const char *sub_state;
287         const char *following;
288         const char *unit_path;
289         uint32_t job_id;
290         const char *job_type;
291         const char *job_path;
292 };
293
294 static int compare_unit_info(const void *a, const void *b) {
295         const char *d1, *d2;
296         const struct unit_info *u = a, *v = b;
297
298         d1 = strrchr(u->id, '.');
299         d2 = strrchr(v->id, '.');
300
301         if (d1 && d2) {
302                 int r;
303
304                 if ((r = strcasecmp(d1, d2)) != 0)
305                         return r;
306         }
307
308         return strcasecmp(u->id, v->id);
309 }
310
311 static bool output_show_unit(const struct unit_info *u) {
312         const char *dot;
313
314         if (arg_failed)
315                 return streq(u->active_state, "failed");
316
317         return (!arg_type || ((dot = strrchr(u->id, '.')) &&
318                               streq(dot+1, arg_type))) &&
319                 (arg_all || !(streq(u->active_state, "inactive") || u->following[0]) || u->job_id > 0);
320 }
321
322 static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
323         unsigned id_len, max_id_len, active_len, sub_len, job_len, desc_len, n_shown = 0;
324         const struct unit_info *u;
325
326         max_id_len = sizeof("UNIT")-1;
327         active_len = sizeof("ACTIVE")-1;
328         sub_len = sizeof("SUB")-1;
329         job_len = sizeof("JOB")-1;
330         desc_len = 0;
331
332         for (u = unit_infos; u < unit_infos + c; u++) {
333                 if (!output_show_unit(u))
334                         continue;
335
336                 max_id_len = MAX(max_id_len, strlen(u->id));
337                 active_len = MAX(active_len, strlen(u->active_state));
338                 sub_len = MAX(sub_len, strlen(u->sub_state));
339                 if (u->job_id != 0)
340                         job_len = MAX(job_len, strlen(u->job_type));
341         }
342
343         if (!arg_full) {
344                 unsigned basic_len;
345                 id_len = MIN(max_id_len, 25);
346                 basic_len = 5 + id_len + 6 + active_len + sub_len + job_len;
347                 if (basic_len < (unsigned) columns()) {
348                         unsigned extra_len, incr;
349                         extra_len = columns() - basic_len;
350                         /* Either UNIT already got 25, or is fully satisfied.
351                          * Grant up to 25 to DESC now. */
352                         incr = MIN(extra_len, 25);
353                         desc_len += incr;
354                         extra_len -= incr;
355                         /* split the remaining space between UNIT and DESC,
356                          * but do not give UNIT more than it needs. */
357                         if (extra_len > 0) {
358                                 incr = MIN(extra_len / 2, max_id_len - id_len);
359                                 id_len += incr;
360                                 desc_len += extra_len - incr;
361                         }
362                 }
363         } else
364                 id_len = max_id_len;
365
366         if (!arg_no_legend) {
367                 printf("%-*s %-6s %-*s %-*s %-*s ", id_len, "UNIT", "LOAD",
368                        active_len, "ACTIVE", sub_len, "SUB", job_len, "JOB");
369                 if (!arg_full && arg_no_pager)
370                         printf("%.*s\n", desc_len, "DESCRIPTION");
371                 else
372                         printf("%s\n", "DESCRIPTION");
373         }
374
375         for (u = unit_infos; u < unit_infos + c; u++) {
376                 char *e;
377                 const char *on_loaded, *off_loaded;
378                 const char *on_active, *off_active;
379
380                 if (!output_show_unit(u))
381                         continue;
382
383                 n_shown++;
384
385                 if (streq(u->load_state, "error")) {
386                         on_loaded = ansi_highlight_red(true);
387                         off_loaded = ansi_highlight_red(false);
388                 } else
389                         on_loaded = off_loaded = "";
390
391                 if (streq(u->active_state, "failed")) {
392                         on_active = ansi_highlight_red(true);
393                         off_active = ansi_highlight_red(false);
394                 } else
395                         on_active = off_active = "";
396
397                 e = arg_full ? NULL : ellipsize(u->id, id_len, 33);
398
399                 printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s ",
400                        id_len, e ? e : u->id,
401                        on_loaded, u->load_state, off_loaded,
402                        on_active, active_len, u->active_state,
403                        sub_len, u->sub_state, off_active,
404                        job_len, u->job_id ? u->job_type : "");
405                 if (!arg_full && arg_no_pager)
406                         printf("%.*s\n", desc_len, u->description);
407                 else
408                         printf("%s\n", u->description);
409
410                 free(e);
411         }
412
413         if (!arg_no_legend) {
414                 printf("\nLOAD   = Reflects whether the unit definition was properly loaded.\n"
415                        "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
416                        "SUB    = The low-level unit activation state, values depend on unit type.\n"
417                        "JOB    = Pending job for the unit.\n");
418
419                 if (arg_all)
420                         printf("\n%u units listed.\n", n_shown);
421                 else
422                         printf("\n%u units listed. Pass --all to see inactive units, too.\n", n_shown);
423         }
424 }
425
426 static int list_units(DBusConnection *bus, char **args) {
427         DBusMessage *m = NULL, *reply = NULL;
428         DBusError error;
429         int r;
430         DBusMessageIter iter, sub, sub2;
431         unsigned c = 0, n_units = 0;
432         struct unit_info *unit_infos = NULL;
433
434         dbus_error_init(&error);
435
436         assert(bus);
437
438         pager_open_if_enabled();
439
440         if (!(m = dbus_message_new_method_call(
441                               "org.freedesktop.systemd1",
442                               "/org/freedesktop/systemd1",
443                               "org.freedesktop.systemd1.Manager",
444                               "ListUnits"))) {
445                 log_error("Could not allocate message.");
446                 return -ENOMEM;
447         }
448
449         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
450                 log_error("Failed to issue method call: %s", bus_error_message(&error));
451                 r = -EIO;
452                 goto finish;
453         }
454
455         if (!dbus_message_iter_init(reply, &iter) ||
456             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
457             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
458                 log_error("Failed to parse reply.");
459                 r = -EIO;
460                 goto finish;
461         }
462
463         dbus_message_iter_recurse(&iter, &sub);
464
465         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
466                 struct unit_info *u;
467
468                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
469                         log_error("Failed to parse reply.");
470                         r = -EIO;
471                         goto finish;
472                 }
473
474                 if (c >= n_units) {
475                         struct unit_info *w;
476
477                         n_units = MAX(2*c, 16);
478                         w = realloc(unit_infos, sizeof(struct unit_info) * n_units);
479
480                         if (!w) {
481                                 log_error("Failed to allocate unit array.");
482                                 r = -ENOMEM;
483                                 goto finish;
484                         }
485
486                         unit_infos = w;
487                 }
488
489                 u = unit_infos+c;
490
491                 dbus_message_iter_recurse(&sub, &sub2);
492
493                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->id, true) < 0 ||
494                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->description, true) < 0 ||
495                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->load_state, true) < 0 ||
496                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->active_state, true) < 0 ||
497                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->sub_state, true) < 0 ||
498                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->following, true) < 0 ||
499                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->unit_path, true) < 0 ||
500                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &u->job_id, true) < 0 ||
501                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->job_type, true) < 0 ||
502                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->job_path, false) < 0) {
503                         log_error("Failed to parse reply.");
504                         r = -EIO;
505                         goto finish;
506                 }
507
508                 dbus_message_iter_next(&sub);
509                 c++;
510         }
511
512         if (c > 0) {
513                 qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
514                 output_units_list(unit_infos, c);
515         }
516
517         r = 0;
518
519 finish:
520         if (m)
521                 dbus_message_unref(m);
522
523         if (reply)
524                 dbus_message_unref(reply);
525
526         free(unit_infos);
527
528         dbus_error_free(&error);
529
530         return r;
531 }
532
533 static int compare_unit_file_list(const void *a, const void *b) {
534         const char *d1, *d2;
535         const UnitFileList *u = a, *v = b;
536
537         d1 = strrchr(u->path, '.');
538         d2 = strrchr(v->path, '.');
539
540         if (d1 && d2) {
541                 int r;
542
543                 r = strcasecmp(d1, d2);
544                 if (r != 0)
545                         return r;
546         }
547
548         return strcasecmp(file_name_from_path(u->path), file_name_from_path(v->path));
549 }
550
551 static bool output_show_unit_file(const UnitFileList *u) {
552         const char *dot;
553
554         return !arg_type || ((dot = strrchr(u->path, '.')) && streq(dot+1, arg_type));
555 }
556
557 static void output_unit_file_list(const UnitFileList *units, unsigned c) {
558         unsigned max_id_len, id_cols, state_cols, n_shown = 0;
559         const UnitFileList *u;
560
561         max_id_len = sizeof("UNIT FILE")-1;
562         state_cols = sizeof("STATE")-1;
563         for (u = units; u < units + c; u++) {
564                 if (!output_show_unit_file(u))
565                         continue;
566
567                 max_id_len = MAX(max_id_len, strlen(file_name_from_path(u->path)));
568                 state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state)));
569         }
570
571         if (!arg_full) {
572                 unsigned basic_cols;
573                 id_cols = MIN(max_id_len, 25);
574                 basic_cols = 1 + id_cols + state_cols;
575                 if (basic_cols < (unsigned) columns())
576                         id_cols += MIN(columns() - basic_cols, max_id_len - id_cols);
577         } else
578                 id_cols = max_id_len;
579
580         if (!arg_no_legend)
581                 printf("%-*s %-*s\n", id_cols, "UNIT FILE", state_cols, "STATE");
582
583         for (u = units; u < units + c; u++) {
584                 char *e;
585                 const char *on, *off;
586                 const char *id;
587
588                 if (!output_show_unit_file(u))
589                         continue;
590
591                 n_shown++;
592
593                 if (u->state == UNIT_FILE_MASKED ||
594                     u->state == UNIT_FILE_MASKED_RUNTIME ||
595                     u->state == UNIT_FILE_DISABLED) {
596                         on  = ansi_highlight_red(true);
597                         off = ansi_highlight_red(false);
598                 } else if (u->state == UNIT_FILE_ENABLED) {
599                         on  = ansi_highlight_green(true);
600                         off = ansi_highlight_green(false);
601                 } else
602                         on = off = "";
603
604                 id = file_name_from_path(u->path);
605
606                 e = arg_full ? NULL : ellipsize(id, id_cols, 33);
607
608                 printf("%-*s %s%-*s%s\n",
609                        id_cols, e ? e : id,
610                        on, state_cols, unit_file_state_to_string(u->state), off);
611
612                 free(e);
613         }
614
615         if (!arg_no_legend)
616                 printf("\n%u unit files listed.\n", n_shown);
617 }
618
619 static int list_unit_files(DBusConnection *bus, char **args) {
620         DBusMessage *m = NULL, *reply = NULL;
621         DBusError error;
622         int r;
623         DBusMessageIter iter, sub, sub2;
624         unsigned c = 0, n_units = 0;
625         UnitFileList *units = NULL;
626
627         dbus_error_init(&error);
628
629         pager_open_if_enabled();
630
631         if (avoid_bus()) {
632                 Hashmap *h;
633                 UnitFileList *u;
634                 Iterator i;
635
636                 h = hashmap_new(string_hash_func, string_compare_func);
637                 if (!h) {
638                         log_error("Out of memory");
639                         return -ENOMEM;
640                 }
641
642                 r = unit_file_get_list(arg_scope, arg_root, h);
643                 if (r < 0) {
644                         unit_file_list_free(h);
645                         log_error("Failed to get unit file list: %s", strerror(-r));
646                         return r;
647                 }
648
649                 n_units = hashmap_size(h);
650                 units = new(UnitFileList, n_units);
651                 if (!units) {
652                         unit_file_list_free(h);
653                         log_error("Out of memory");
654                         return -ENOMEM;
655                 }
656
657                 HASHMAP_FOREACH(u, h, i) {
658                         memcpy(units + c++, u, sizeof(UnitFileList));
659                         free(u);
660                 }
661
662                 hashmap_free(h);
663         } else {
664                 assert(bus);
665
666                 m = dbus_message_new_method_call(
667                                 "org.freedesktop.systemd1",
668                                 "/org/freedesktop/systemd1",
669                                 "org.freedesktop.systemd1.Manager",
670                                 "ListUnitFiles");
671                 if (!m) {
672                         log_error("Could not allocate message.");
673                         return -ENOMEM;
674                 }
675
676                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
677                 if (!reply) {
678                         log_error("Failed to issue method call: %s", bus_error_message(&error));
679                         r = -EIO;
680                         goto finish;
681                 }
682
683                 if (!dbus_message_iter_init(reply, &iter) ||
684                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
685                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
686                         log_error("Failed to parse reply.");
687                         r = -EIO;
688                         goto finish;
689                 }
690
691                 dbus_message_iter_recurse(&iter, &sub);
692
693                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
694                         UnitFileList *u;
695                         const char *state;
696
697                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
698                                 log_error("Failed to parse reply.");
699                                 r = -EIO;
700                                 goto finish;
701                         }
702
703                         if (c >= n_units) {
704                                 UnitFileList *w;
705
706                                 n_units = MAX(2*c, 16);
707                                 w = realloc(units, sizeof(struct UnitFileList) * n_units);
708
709                                 if (!w) {
710                                         log_error("Failed to allocate unit array.");
711                                         r = -ENOMEM;
712                                         goto finish;
713                                 }
714
715                                 units = w;
716                         }
717
718                         u = units+c;
719
720                         dbus_message_iter_recurse(&sub, &sub2);
721
722                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->path, true) < 0 ||
723                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, false) < 0) {
724                                 log_error("Failed to parse reply.");
725                                 r = -EIO;
726                                 goto finish;
727                         }
728
729                         u->state = unit_file_state_from_string(state);
730
731                         dbus_message_iter_next(&sub);
732                         c++;
733                 }
734         }
735
736         if (c > 0) {
737                 qsort(units, c, sizeof(UnitFileList), compare_unit_file_list);
738                 output_unit_file_list(units, c);
739         }
740
741         r = 0;
742
743 finish:
744         if (m)
745                 dbus_message_unref(m);
746
747         if (reply)
748                 dbus_message_unref(reply);
749
750         free(units);
751
752         dbus_error_free(&error);
753
754         return r;
755 }
756
757 static int dot_one_property(const char *name, const char *prop, DBusMessageIter *iter) {
758         static const char * const colors[] = {
759                 "Requires",              "[color=\"black\"]",
760                 "RequiresOverridable",   "[color=\"black\"]",
761                 "Requisite",             "[color=\"darkblue\"]",
762                 "RequisiteOverridable",  "[color=\"darkblue\"]",
763                 "Wants",                 "[color=\"darkgrey\"]",
764                 "Conflicts",             "[color=\"red\"]",
765                 "ConflictedBy",          "[color=\"red\"]",
766                 "After",                 "[color=\"green\"]"
767         };
768
769         const char *c = NULL;
770         unsigned i;
771
772         assert(name);
773         assert(prop);
774         assert(iter);
775
776         for (i = 0; i < ELEMENTSOF(colors); i += 2)
777                 if (streq(colors[i], prop)) {
778                         c = colors[i+1];
779                         break;
780                 }
781
782         if (!c)
783                 return 0;
784
785         if (arg_dot != DOT_ALL)
786                 if ((arg_dot == DOT_ORDER) != streq(prop, "After"))
787                         return 0;
788
789         switch (dbus_message_iter_get_arg_type(iter)) {
790
791         case DBUS_TYPE_ARRAY:
792
793                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
794                         DBusMessageIter sub;
795
796                         dbus_message_iter_recurse(iter, &sub);
797
798                         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
799                                 const char *s;
800
801                                 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING);
802                                 dbus_message_iter_get_basic(&sub, &s);
803                                 printf("\t\"%s\"->\"%s\" %s;\n", name, s, c);
804
805                                 dbus_message_iter_next(&sub);
806                         }
807
808                         return 0;
809                 }
810         }
811
812         return 0;
813 }
814
815 static int dot_one(DBusConnection *bus, const char *name, const char *path) {
816         DBusMessage *m = NULL, *reply = NULL;
817         const char *interface = "org.freedesktop.systemd1.Unit";
818         int r;
819         DBusError error;
820         DBusMessageIter iter, sub, sub2, sub3;
821
822         assert(bus);
823         assert(path);
824
825         dbus_error_init(&error);
826
827         if (!(m = dbus_message_new_method_call(
828                               "org.freedesktop.systemd1",
829                               path,
830                               "org.freedesktop.DBus.Properties",
831                               "GetAll"))) {
832                 log_error("Could not allocate message.");
833                 r = -ENOMEM;
834                 goto finish;
835         }
836
837         if (!dbus_message_append_args(m,
838                                       DBUS_TYPE_STRING, &interface,
839                                       DBUS_TYPE_INVALID)) {
840                 log_error("Could not append arguments to message.");
841                 r = -ENOMEM;
842                 goto finish;
843         }
844
845         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
846                 log_error("Failed to issue method call: %s", bus_error_message(&error));
847                 r = -EIO;
848                 goto finish;
849         }
850
851         if (!dbus_message_iter_init(reply, &iter) ||
852             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
853             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
854                 log_error("Failed to parse reply.");
855                 r = -EIO;
856                 goto finish;
857         }
858
859         dbus_message_iter_recurse(&iter, &sub);
860
861         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
862                 const char *prop;
863
864                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
865                         log_error("Failed to parse reply.");
866                         r = -EIO;
867                         goto finish;
868                 }
869
870                 dbus_message_iter_recurse(&sub, &sub2);
871
872                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) {
873                         log_error("Failed to parse reply.");
874                         r = -EIO;
875                         goto finish;
876                 }
877
878                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
879                         log_error("Failed to parse reply.");
880                         r = -EIO;
881                         goto finish;
882                 }
883
884                 dbus_message_iter_recurse(&sub2, &sub3);
885
886                 if (dot_one_property(name, prop, &sub3)) {
887                         log_error("Failed to parse reply.");
888                         r = -EIO;
889                         goto finish;
890                 }
891
892                 dbus_message_iter_next(&sub);
893         }
894
895         r = 0;
896
897 finish:
898         if (m)
899                 dbus_message_unref(m);
900
901         if (reply)
902                 dbus_message_unref(reply);
903
904         dbus_error_free(&error);
905
906         return r;
907 }
908
909 static int dot(DBusConnection *bus, char **args) {
910         DBusMessage *m = NULL, *reply = NULL;
911         DBusError error;
912         int r;
913         DBusMessageIter iter, sub, sub2;
914
915         dbus_error_init(&error);
916
917         assert(bus);
918
919         if (!(m = dbus_message_new_method_call(
920                               "org.freedesktop.systemd1",
921                               "/org/freedesktop/systemd1",
922                               "org.freedesktop.systemd1.Manager",
923                               "ListUnits"))) {
924                 log_error("Could not allocate message.");
925                 return -ENOMEM;
926         }
927
928         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
929                 log_error("Failed to issue method call: %s", bus_error_message(&error));
930                 r = -EIO;
931                 goto finish;
932         }
933
934         if (!dbus_message_iter_init(reply, &iter) ||
935             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
936             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
937                 log_error("Failed to parse reply.");
938                 r = -EIO;
939                 goto finish;
940         }
941
942         printf("digraph systemd {\n");
943
944         dbus_message_iter_recurse(&iter, &sub);
945         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
946                 const char *id, *description, *load_state, *active_state, *sub_state, *following, *unit_path;
947
948                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
949                         log_error("Failed to parse reply.");
950                         r = -EIO;
951                         goto finish;
952                 }
953
954                 dbus_message_iter_recurse(&sub, &sub2);
955
956                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
957                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 ||
958                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
959                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
960                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
961                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &following, true) < 0 ||
962                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0) {
963                         log_error("Failed to parse reply.");
964                         r = -EIO;
965                         goto finish;
966                 }
967
968                 if ((r = dot_one(bus, id, unit_path)) < 0)
969                         goto finish;
970
971                 /* printf("\t\"%s\";\n", id); */
972                 dbus_message_iter_next(&sub);
973         }
974
975         printf("}\n");
976
977         log_info("   Color legend: black     = Requires\n"
978                  "                 dark blue = Requisite\n"
979                  "                 dark grey = Wants\n"
980                  "                 red       = Conflicts\n"
981                  "                 green     = After\n");
982
983         if (on_tty())
984                 log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
985                            "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n");
986
987         r = 0;
988
989 finish:
990         if (m)
991                 dbus_message_unref(m);
992
993         if (reply)
994                 dbus_message_unref(reply);
995
996         dbus_error_free(&error);
997
998         return r;
999 }
1000
1001 static int list_jobs(DBusConnection *bus, char **args) {
1002         DBusMessage *m = NULL, *reply = NULL;
1003         DBusError error;
1004         int r;
1005         DBusMessageIter iter, sub, sub2;
1006         unsigned k = 0;
1007
1008         dbus_error_init(&error);
1009
1010         assert(bus);
1011
1012         pager_open_if_enabled();
1013
1014         if (!(m = dbus_message_new_method_call(
1015                               "org.freedesktop.systemd1",
1016                               "/org/freedesktop/systemd1",
1017                               "org.freedesktop.systemd1.Manager",
1018                               "ListJobs"))) {
1019                 log_error("Could not allocate message.");
1020                 return -ENOMEM;
1021         }
1022
1023         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1024                 log_error("Failed to issue method call: %s", bus_error_message(&error));
1025                 r = -EIO;
1026                 goto finish;
1027         }
1028
1029         if (!dbus_message_iter_init(reply, &iter) ||
1030             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1031             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
1032                 log_error("Failed to parse reply.");
1033                 r = -EIO;
1034                 goto finish;
1035         }
1036
1037         dbus_message_iter_recurse(&iter, &sub);
1038
1039         if (on_tty())
1040                 printf("%4s %-25s %-15s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
1041
1042         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1043                 const char *name, *type, *state, *job_path, *unit_path;
1044                 uint32_t id;
1045                 char *e;
1046
1047                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
1048                         log_error("Failed to parse reply.");
1049                         r = -EIO;
1050                         goto finish;
1051                 }
1052
1053                 dbus_message_iter_recurse(&sub, &sub2);
1054
1055                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
1056                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
1057                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
1058                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
1059                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
1060                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
1061                         log_error("Failed to parse reply.");
1062                         r = -EIO;
1063                         goto finish;
1064                 }
1065
1066                 e = arg_full ? NULL : ellipsize(name, 25, 33);
1067                 printf("%4u %-25s %-15s %-7s\n", id, e ? e : name, type, state);
1068                 free(e);
1069
1070                 k++;
1071
1072                 dbus_message_iter_next(&sub);
1073         }
1074
1075         if (on_tty())
1076                 printf("\n%u jobs listed.\n", k);
1077
1078         r = 0;
1079
1080 finish:
1081         if (m)
1082                 dbus_message_unref(m);
1083
1084         if (reply)
1085                 dbus_message_unref(reply);
1086
1087         dbus_error_free(&error);
1088
1089         return r;
1090 }
1091
1092 static int load_unit(DBusConnection *bus, char **args) {
1093         DBusMessage *m = NULL;
1094         DBusError error;
1095         int r;
1096         char **name;
1097
1098         dbus_error_init(&error);
1099
1100         assert(bus);
1101         assert(args);
1102
1103         STRV_FOREACH(name, args+1) {
1104                 DBusMessage *reply;
1105
1106                 if (!(m = dbus_message_new_method_call(
1107                                       "org.freedesktop.systemd1",
1108                                       "/org/freedesktop/systemd1",
1109                                       "org.freedesktop.systemd1.Manager",
1110                                       "LoadUnit"))) {
1111                         log_error("Could not allocate message.");
1112                         r = -ENOMEM;
1113                         goto finish;
1114                 }
1115
1116                 if (!dbus_message_append_args(m,
1117                                               DBUS_TYPE_STRING, name,
1118                                               DBUS_TYPE_INVALID)) {
1119                         log_error("Could not append arguments to message.");
1120                         r = -ENOMEM;
1121                         goto finish;
1122                 }
1123
1124                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1125                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1126                         r = -EIO;
1127                         goto finish;
1128                 }
1129
1130                 dbus_message_unref(m);
1131                 dbus_message_unref(reply);
1132
1133                 m = reply = NULL;
1134         }
1135
1136         r = 0;
1137
1138 finish:
1139         if (m)
1140                 dbus_message_unref(m);
1141
1142         dbus_error_free(&error);
1143
1144         return r;
1145 }
1146
1147 static int cancel_job(DBusConnection *bus, char **args) {
1148         DBusMessage *m = NULL, *reply = NULL;
1149         DBusError error;
1150         int r;
1151         char **name;
1152
1153         dbus_error_init(&error);
1154
1155         assert(bus);
1156         assert(args);
1157
1158         if (strv_length(args) <= 1)
1159                 return daemon_reload(bus, args);
1160
1161         STRV_FOREACH(name, args+1) {
1162                 unsigned id;
1163                 const char *path;
1164
1165                 if (!(m = dbus_message_new_method_call(
1166                                       "org.freedesktop.systemd1",
1167                                       "/org/freedesktop/systemd1",
1168                                       "org.freedesktop.systemd1.Manager",
1169                                       "GetJob"))) {
1170                         log_error("Could not allocate message.");
1171                         r = -ENOMEM;
1172                         goto finish;
1173                 }
1174
1175                 if ((r = safe_atou(*name, &id)) < 0) {
1176                         log_error("Failed to parse job id: %s", strerror(-r));
1177                         goto finish;
1178                 }
1179
1180                 assert_cc(sizeof(uint32_t) == sizeof(id));
1181                 if (!dbus_message_append_args(m,
1182                                               DBUS_TYPE_UINT32, &id,
1183                                               DBUS_TYPE_INVALID)) {
1184                         log_error("Could not append arguments to message.");
1185                         r = -ENOMEM;
1186                         goto finish;
1187                 }
1188
1189                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1190                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1191                         r = -EIO;
1192                         goto finish;
1193                 }
1194
1195                 if (!dbus_message_get_args(reply, &error,
1196                                            DBUS_TYPE_OBJECT_PATH, &path,
1197                                            DBUS_TYPE_INVALID)) {
1198                         log_error("Failed to parse reply: %s", bus_error_message(&error));
1199                         r = -EIO;
1200                         goto finish;
1201                 }
1202
1203                 dbus_message_unref(m);
1204                 if (!(m = dbus_message_new_method_call(
1205                                       "org.freedesktop.systemd1",
1206                                       path,
1207                                       "org.freedesktop.systemd1.Job",
1208                                       "Cancel"))) {
1209                         log_error("Could not allocate message.");
1210                         r = -ENOMEM;
1211                         goto finish;
1212                 }
1213
1214                 dbus_message_unref(reply);
1215                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1216                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1217                         r = -EIO;
1218                         goto finish;
1219                 }
1220
1221                 dbus_message_unref(m);
1222                 dbus_message_unref(reply);
1223                 m = reply = NULL;
1224         }
1225
1226         r = 0;
1227
1228 finish:
1229         if (m)
1230                 dbus_message_unref(m);
1231
1232         if (reply)
1233                 dbus_message_unref(reply);
1234
1235         dbus_error_free(&error);
1236
1237         return r;
1238 }
1239
1240 static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
1241         DBusMessage *m = NULL, *reply = NULL;
1242         dbus_bool_t b = FALSE;
1243         DBusMessageIter iter, sub;
1244         const char
1245                 *interface = "org.freedesktop.systemd1.Unit",
1246                 *property = "NeedDaemonReload",
1247                 *path;
1248
1249         /* We ignore all errors here, since this is used to show a warning only */
1250
1251         if (!(m = dbus_message_new_method_call(
1252                               "org.freedesktop.systemd1",
1253                               "/org/freedesktop/systemd1",
1254                               "org.freedesktop.systemd1.Manager",
1255                               "GetUnit")))
1256                 goto finish;
1257
1258         if (!dbus_message_append_args(m,
1259                                       DBUS_TYPE_STRING, &unit,
1260                                       DBUS_TYPE_INVALID))
1261                 goto finish;
1262
1263         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL)))
1264                 goto finish;
1265
1266         if (!dbus_message_get_args(reply, NULL,
1267                                    DBUS_TYPE_OBJECT_PATH, &path,
1268                                    DBUS_TYPE_INVALID))
1269                 goto finish;
1270
1271         dbus_message_unref(m);
1272         if (!(m = dbus_message_new_method_call(
1273                               "org.freedesktop.systemd1",
1274                               path,
1275                               "org.freedesktop.DBus.Properties",
1276                               "Get")))
1277                 goto finish;
1278
1279         if (!dbus_message_append_args(m,
1280                                       DBUS_TYPE_STRING, &interface,
1281                                       DBUS_TYPE_STRING, &property,
1282                                       DBUS_TYPE_INVALID)) {
1283                 goto finish;
1284         }
1285
1286         dbus_message_unref(reply);
1287         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, NULL)))
1288                 goto finish;
1289
1290         if (!dbus_message_iter_init(reply, &iter) ||
1291             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
1292                 goto finish;
1293
1294         dbus_message_iter_recurse(&iter, &sub);
1295
1296         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
1297                 goto finish;
1298
1299         dbus_message_iter_get_basic(&sub, &b);
1300
1301 finish:
1302         if (m)
1303                 dbus_message_unref(m);
1304
1305         if (reply)
1306                 dbus_message_unref(reply);
1307
1308         return b;
1309 }
1310
1311 typedef struct WaitData {
1312         Set *set;
1313         char *result;
1314 } WaitData;
1315
1316 static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
1317         DBusError error;
1318         WaitData *d = data;
1319
1320         assert(connection);
1321         assert(message);
1322         assert(d);
1323
1324         dbus_error_init(&error);
1325
1326         log_debug("Got D-Bus request: %s.%s() on %s",
1327                   dbus_message_get_interface(message),
1328                   dbus_message_get_member(message),
1329                   dbus_message_get_path(message));
1330
1331         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1332                 log_error("Warning! D-Bus connection terminated.");
1333                 dbus_connection_close(connection);
1334
1335         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1336                 uint32_t id;
1337                 const char *path, *result;
1338                 dbus_bool_t success = true;
1339
1340                 if (dbus_message_get_args(message, &error,
1341                                           DBUS_TYPE_UINT32, &id,
1342                                           DBUS_TYPE_OBJECT_PATH, &path,
1343                                           DBUS_TYPE_STRING, &result,
1344                                           DBUS_TYPE_INVALID)) {
1345                         char *p;
1346
1347                         if ((p = set_remove(d->set, (char*) path)))
1348                                 free(p);
1349
1350                         if (*result)
1351                                 d->result = strdup(result);
1352
1353                         goto finish;
1354                 }
1355 #ifndef LEGACY
1356                 dbus_error_free(&error);
1357
1358                 if (dbus_message_get_args(message, &error,
1359                                           DBUS_TYPE_UINT32, &id,
1360                                           DBUS_TYPE_OBJECT_PATH, &path,
1361                                           DBUS_TYPE_BOOLEAN, &success,
1362                                           DBUS_TYPE_INVALID)) {
1363                         char *p;
1364
1365                         /* Compatibility with older systemd versions <
1366                          * 19 during upgrades. This should be dropped
1367                          * one day */
1368
1369                         if ((p = set_remove(d->set, (char*) path)))
1370                                 free(p);
1371
1372                         if (!success)
1373                                 d->result = strdup("failed");
1374
1375                         goto finish;
1376                 }
1377 #endif
1378
1379                 log_error("Failed to parse message: %s", bus_error_message(&error));
1380         }
1381
1382 finish:
1383         dbus_error_free(&error);
1384         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1385 }
1386
1387 static int enable_wait_for_jobs(DBusConnection *bus) {
1388         DBusError error;
1389
1390         assert(bus);
1391
1392         if (private_bus)
1393                 return 0;
1394
1395         dbus_error_init(&error);
1396         dbus_bus_add_match(bus,
1397                            "type='signal',"
1398                            "sender='org.freedesktop.systemd1',"
1399                            "interface='org.freedesktop.systemd1.Manager',"
1400                            "member='JobRemoved',"
1401                            "path='/org/freedesktop/systemd1'",
1402                            &error);
1403
1404         if (dbus_error_is_set(&error)) {
1405                 log_error("Failed to add match: %s", bus_error_message(&error));
1406                 dbus_error_free(&error);
1407                 return -EIO;
1408         }
1409
1410         /* This is slightly dirty, since we don't undo the match registrations. */
1411         return 0;
1412 }
1413
1414 static int wait_for_jobs(DBusConnection *bus, Set *s) {
1415         int r;
1416         WaitData d;
1417
1418         assert(bus);
1419         assert(s);
1420
1421         zero(d);
1422         d.set = s;
1423
1424         if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) {
1425                 log_error("Failed to add filter.");
1426                 r = -ENOMEM;
1427                 goto finish;
1428         }
1429
1430         while (!set_isempty(s) &&
1431                dbus_connection_read_write_dispatch(bus, -1))
1432                 ;
1433
1434         if (!arg_quiet && d.result) {
1435                 if (streq(d.result, "timeout"))
1436                         log_error("Job timed out.");
1437                 else if (streq(d.result, "canceled"))
1438                         log_error("Job canceled.");
1439                 else if (streq(d.result, "dependency"))
1440                         log_error("A dependency job failed. See system journal for details.");
1441                 else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
1442                         log_error("Job failed. See system journal and 'systemctl status' for details.");
1443         }
1444
1445         if (streq_ptr(d.result, "timeout"))
1446                 r = -ETIME;
1447         else if (streq_ptr(d.result, "canceled"))
1448                 r = -ECANCELED;
1449         else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
1450                 r = -EIO;
1451         else
1452                 r = 0;
1453
1454         free(d.result);
1455
1456 finish:
1457         /* This is slightly dirty, since we don't undo the filter registration. */
1458
1459         return r;
1460 }
1461
1462 static int start_unit_one(
1463                 DBusConnection *bus,
1464                 const char *method,
1465                 const char *name,
1466                 const char *mode,
1467                 DBusError *error,
1468                 Set *s) {
1469
1470         DBusMessage *m = NULL, *reply = NULL;
1471         const char *path;
1472         int r;
1473
1474         assert(bus);
1475         assert(method);
1476         assert(name);
1477         assert(mode);
1478         assert(error);
1479         assert(arg_no_block || s);
1480
1481         if (!(m = dbus_message_new_method_call(
1482                               "org.freedesktop.systemd1",
1483                               "/org/freedesktop/systemd1",
1484                               "org.freedesktop.systemd1.Manager",
1485                               method))) {
1486                 log_error("Could not allocate message.");
1487                 r = -ENOMEM;
1488                 goto finish;
1489         }
1490
1491         if (!dbus_message_append_args(m,
1492                                       DBUS_TYPE_STRING, &name,
1493                                       DBUS_TYPE_STRING, &mode,
1494                                       DBUS_TYPE_INVALID)) {
1495                 log_error("Could not append arguments to message.");
1496                 r = -ENOMEM;
1497                 goto finish;
1498         }
1499
1500         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error))) {
1501
1502                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(error)) {
1503                         /* There's always a fallback possible for
1504                          * legacy actions. */
1505                         r = -EADDRNOTAVAIL;
1506                         goto finish;
1507                 }
1508
1509                 log_error("Failed to issue method call: %s", bus_error_message(error));
1510                 r = -EIO;
1511                 goto finish;
1512         }
1513
1514         if (!dbus_message_get_args(reply, error,
1515                                    DBUS_TYPE_OBJECT_PATH, &path,
1516                                    DBUS_TYPE_INVALID)) {
1517                 log_error("Failed to parse reply: %s", bus_error_message(error));
1518                 r = -EIO;
1519                 goto finish;
1520         }
1521
1522         if (need_daemon_reload(bus, name))
1523                 log_warning("Warning: Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.",
1524                             arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
1525
1526         if (!arg_no_block) {
1527                 char *p;
1528
1529                 if (!(p = strdup(path))) {
1530                         log_error("Failed to duplicate path.");
1531                         r = -ENOMEM;
1532                         goto finish;
1533                 }
1534
1535                 if ((r = set_put(s, p)) < 0) {
1536                         free(p);
1537                         log_error("Failed to add path to set.");
1538                         goto finish;
1539                 }
1540         }
1541
1542         r = 0;
1543
1544 finish:
1545         if (m)
1546                 dbus_message_unref(m);
1547
1548         if (reply)
1549                 dbus_message_unref(reply);
1550
1551         return r;
1552 }
1553
1554 static enum action verb_to_action(const char *verb) {
1555         if (streq(verb, "halt"))
1556                 return ACTION_HALT;
1557         else if (streq(verb, "poweroff"))
1558                 return ACTION_POWEROFF;
1559         else if (streq(verb, "reboot"))
1560                 return ACTION_REBOOT;
1561         else if (streq(verb, "kexec"))
1562                 return ACTION_KEXEC;
1563         else if (streq(verb, "rescue"))
1564                 return ACTION_RESCUE;
1565         else if (streq(verb, "emergency"))
1566                 return ACTION_EMERGENCY;
1567         else if (streq(verb, "default"))
1568                 return ACTION_DEFAULT;
1569         else if (streq(verb, "exit"))
1570                 return ACTION_EXIT;
1571         else
1572                 return ACTION_INVALID;
1573 }
1574
1575 static int start_unit(DBusConnection *bus, char **args) {
1576
1577         static const char * const table[_ACTION_MAX] = {
1578                 [ACTION_HALT] = SPECIAL_HALT_TARGET,
1579                 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
1580                 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
1581                 [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET,
1582                 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
1583                 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
1584                 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
1585                 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
1586                 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
1587                 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
1588                 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
1589                 [ACTION_EXIT] = SPECIAL_EXIT_TARGET
1590         };
1591
1592         int r, ret = 0;
1593         const char *method, *mode, *one_name;
1594         Set *s = NULL;
1595         DBusError error;
1596         char **name;
1597
1598         dbus_error_init(&error);
1599
1600         assert(bus);
1601
1602         agent_open_if_enabled();
1603
1604         if (arg_action == ACTION_SYSTEMCTL) {
1605                 method =
1606                         streq(args[0], "stop") ||
1607                         streq(args[0], "condstop")              ? "StopUnit" :
1608                         streq(args[0], "reload")                ? "ReloadUnit" :
1609                         streq(args[0], "restart")               ? "RestartUnit" :
1610
1611                         streq(args[0], "try-restart")           ||
1612                         streq(args[0], "condrestart")           ? "TryRestartUnit" :
1613
1614                         streq(args[0], "reload-or-restart")     ? "ReloadOrRestartUnit" :
1615
1616                         streq(args[0], "reload-or-try-restart") ||
1617                         streq(args[0], "condreload") ||
1618
1619                         streq(args[0], "force-reload")          ? "ReloadOrTryRestartUnit" :
1620                                                                   "StartUnit";
1621
1622                 mode =
1623                         (streq(args[0], "isolate") ||
1624                          streq(args[0], "rescue")  ||
1625                          streq(args[0], "emergency")) ? "isolate" : arg_job_mode;
1626
1627                 one_name = table[verb_to_action(args[0])];
1628
1629         } else {
1630                 assert(arg_action < ELEMENTSOF(table));
1631                 assert(table[arg_action]);
1632
1633                 method = "StartUnit";
1634
1635                 mode = (arg_action == ACTION_EMERGENCY ||
1636                         arg_action == ACTION_RESCUE ||
1637                         arg_action == ACTION_RUNLEVEL2 ||
1638                         arg_action == ACTION_RUNLEVEL3 ||
1639                         arg_action == ACTION_RUNLEVEL4 ||
1640                         arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace";
1641
1642                 one_name = table[arg_action];
1643         }
1644
1645         if (!arg_no_block) {
1646                 if ((ret = enable_wait_for_jobs(bus)) < 0) {
1647                         log_error("Could not watch jobs: %s", strerror(-ret));
1648                         goto finish;
1649                 }
1650
1651                 if (!(s = set_new(string_hash_func, string_compare_func))) {
1652                         log_error("Failed to allocate set.");
1653                         ret = -ENOMEM;
1654                         goto finish;
1655                 }
1656         }
1657
1658         if (one_name) {
1659                 if ((ret = start_unit_one(bus, method, one_name, mode, &error, s)) <= 0)
1660                         goto finish;
1661         } else {
1662                 STRV_FOREACH(name, args+1)
1663                         if ((r = start_unit_one(bus, method, *name, mode, &error, s)) != 0) {
1664                                 ret = translate_bus_error_to_exit_status(r, &error);
1665                                 dbus_error_free(&error);
1666                         }
1667         }
1668
1669         if (!arg_no_block)
1670                 if ((r = wait_for_jobs(bus, s)) < 0) {
1671                         ret = r;
1672                         goto finish;
1673                 }
1674
1675 finish:
1676         if (s)
1677                 set_free_free(s);
1678
1679         dbus_error_free(&error);
1680
1681         return ret;
1682 }
1683
1684 static int start_special(DBusConnection *bus, char **args) {
1685         int r;
1686
1687         assert(bus);
1688         assert(args);
1689
1690         if (arg_force &&
1691             (streq(args[0], "halt") ||
1692              streq(args[0], "poweroff") ||
1693              streq(args[0], "reboot") ||
1694              streq(args[0], "kexec") ||
1695              streq(args[0], "exit")))
1696                 return daemon_reload(bus, args);
1697
1698         r = start_unit(bus, args);
1699
1700         if (r >= 0)
1701                 warn_wall(verb_to_action(args[0]));
1702
1703         return r;
1704 }
1705
1706 static int check_unit(DBusConnection *bus, char **args) {
1707         DBusMessage *m = NULL, *reply = NULL;
1708         const char
1709                 *interface = "org.freedesktop.systemd1.Unit",
1710                 *property = "ActiveState";
1711         int r = 3; /* According to LSB: "program is not running" */
1712         DBusError error;
1713         char **name;
1714
1715         assert(bus);
1716         assert(args);
1717
1718         dbus_error_init(&error);
1719
1720         STRV_FOREACH(name, args+1) {
1721                 const char *path = NULL;
1722                 const char *state;
1723                 DBusMessageIter iter, sub;
1724
1725                 if (!(m = dbus_message_new_method_call(
1726                                       "org.freedesktop.systemd1",
1727                                       "/org/freedesktop/systemd1",
1728                                       "org.freedesktop.systemd1.Manager",
1729                                       "GetUnit"))) {
1730                         log_error("Could not allocate message.");
1731                         r = -ENOMEM;
1732                         goto finish;
1733                 }
1734
1735                 if (!dbus_message_append_args(m,
1736                                               DBUS_TYPE_STRING, name,
1737                                               DBUS_TYPE_INVALID)) {
1738                         log_error("Could not append arguments to message.");
1739                         r = -ENOMEM;
1740                         goto finish;
1741                 }
1742
1743                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1744
1745                         /* Hmm, cannot figure out anything about this unit... */
1746                         if (!arg_quiet)
1747                                 puts("unknown");
1748
1749                         dbus_error_free(&error);
1750                         dbus_message_unref(m);
1751                         m = NULL;
1752                         continue;
1753                 }
1754
1755                 if (!dbus_message_get_args(reply, &error,
1756                                            DBUS_TYPE_OBJECT_PATH, &path,
1757                                            DBUS_TYPE_INVALID)) {
1758                         log_error("Failed to parse reply: %s", bus_error_message(&error));
1759                         r = -EIO;
1760                         goto finish;
1761                 }
1762
1763                 dbus_message_unref(m);
1764                 if (!(m = dbus_message_new_method_call(
1765                                       "org.freedesktop.systemd1",
1766                                       path,
1767                                       "org.freedesktop.DBus.Properties",
1768                                       "Get"))) {
1769                         log_error("Could not allocate message.");
1770                         r = -ENOMEM;
1771                         goto finish;
1772                 }
1773
1774                 if (!dbus_message_append_args(m,
1775                                               DBUS_TYPE_STRING, &interface,
1776                                               DBUS_TYPE_STRING, &property,
1777                                               DBUS_TYPE_INVALID)) {
1778                         log_error("Could not append arguments to message.");
1779                         r = -ENOMEM;
1780                         goto finish;
1781                 }
1782
1783                 dbus_message_unref(reply);
1784                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1785                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1786                         r = -EIO;
1787                         goto finish;
1788                 }
1789
1790                 if (!dbus_message_iter_init(reply, &iter) ||
1791                     dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
1792                         log_error("Failed to parse reply.");
1793                         r = -EIO;
1794                         goto finish;
1795                 }
1796
1797                 dbus_message_iter_recurse(&iter, &sub);
1798
1799                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
1800                         log_error("Failed to parse reply.");
1801                         r = -EIO;
1802                         goto finish;
1803                 }
1804
1805                 dbus_message_iter_get_basic(&sub, &state);
1806
1807                 if (!arg_quiet)
1808                         puts(state);
1809
1810                 if (streq(state, "active") || streq(state, "reloading"))
1811                         r = 0;
1812
1813                 dbus_message_unref(m);
1814                 dbus_message_unref(reply);
1815                 m = reply = NULL;
1816         }
1817
1818 finish:
1819         if (m)
1820                 dbus_message_unref(m);
1821
1822         if (reply)
1823                 dbus_message_unref(reply);
1824
1825         dbus_error_free(&error);
1826
1827         return r;
1828 }
1829
1830 static int kill_unit(DBusConnection *bus, char **args) {
1831         DBusMessage *m = NULL;
1832         int r = 0;
1833         DBusError error;
1834         char **name;
1835
1836         assert(bus);
1837         assert(args);
1838
1839         dbus_error_init(&error);
1840
1841         if (!arg_kill_who)
1842                 arg_kill_who = "all";
1843
1844         if (!arg_kill_mode)
1845                 arg_kill_mode = streq(arg_kill_who, "all") ? "control-group" : "process";
1846
1847         STRV_FOREACH(name, args+1) {
1848                 DBusMessage *reply;
1849
1850                 if (!(m = dbus_message_new_method_call(
1851                                       "org.freedesktop.systemd1",
1852                                       "/org/freedesktop/systemd1",
1853                                       "org.freedesktop.systemd1.Manager",
1854                                       "KillUnit"))) {
1855                         log_error("Could not allocate message.");
1856                         r = -ENOMEM;
1857                         goto finish;
1858                 }
1859
1860                 if (!dbus_message_append_args(m,
1861                                               DBUS_TYPE_STRING, name,
1862                                               DBUS_TYPE_STRING, &arg_kill_who,
1863                                               DBUS_TYPE_STRING, &arg_kill_mode,
1864                                               DBUS_TYPE_INT32, &arg_signal,
1865                                               DBUS_TYPE_INVALID)) {
1866                         log_error("Could not append arguments to message.");
1867                         r = -ENOMEM;
1868                         goto finish;
1869                 }
1870
1871                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1872                         log_error("Failed to issue method call: %s", bus_error_message(&error));
1873                         dbus_error_free(&error);
1874                         r = -EIO;
1875                 }
1876
1877                 dbus_message_unref(m);
1878
1879                 if (reply)
1880                         dbus_message_unref(reply);
1881                 m = reply = NULL;
1882         }
1883
1884 finish:
1885         if (m)
1886                 dbus_message_unref(m);
1887
1888         dbus_error_free(&error);
1889
1890         return r;
1891 }
1892
1893 typedef struct ExecStatusInfo {
1894         char *name;
1895
1896         char *path;
1897         char **argv;
1898
1899         bool ignore;
1900
1901         usec_t start_timestamp;
1902         usec_t exit_timestamp;
1903         pid_t pid;
1904         int code;
1905         int status;
1906
1907         LIST_FIELDS(struct ExecStatusInfo, exec);
1908 } ExecStatusInfo;
1909
1910 static void exec_status_info_free(ExecStatusInfo *i) {
1911         assert(i);
1912
1913         free(i->name);
1914         free(i->path);
1915         strv_free(i->argv);
1916         free(i);
1917 }
1918
1919 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
1920         uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
1921         DBusMessageIter sub2, sub3;
1922         const char*path;
1923         unsigned n;
1924         uint32_t pid;
1925         int32_t code, status;
1926         dbus_bool_t ignore;
1927
1928         assert(i);
1929         assert(i);
1930
1931         if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
1932                 return -EIO;
1933
1934         dbus_message_iter_recurse(sub, &sub2);
1935
1936         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
1937                 return -EIO;
1938
1939         if (!(i->path = strdup(path)))
1940                 return -ENOMEM;
1941
1942         if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
1943             dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
1944                 return -EIO;
1945
1946         n = 0;
1947         dbus_message_iter_recurse(&sub2, &sub3);
1948         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
1949                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
1950                 dbus_message_iter_next(&sub3);
1951                 n++;
1952         }
1953
1954
1955         if (!(i->argv = new0(char*, n+1)))
1956                 return -ENOMEM;
1957
1958         n = 0;
1959         dbus_message_iter_recurse(&sub2, &sub3);
1960         while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
1961                 const char *s;
1962
1963                 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
1964                 dbus_message_iter_get_basic(&sub3, &s);
1965                 dbus_message_iter_next(&sub3);
1966
1967                 if (!(i->argv[n++] = strdup(s)))
1968                         return -ENOMEM;
1969         }
1970
1971         if (!dbus_message_iter_next(&sub2) ||
1972             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
1973             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
1974             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
1975             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
1976             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
1977             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
1978             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
1979             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
1980                 return -EIO;
1981
1982         i->ignore = ignore;
1983         i->start_timestamp = (usec_t) start_timestamp;
1984         i->exit_timestamp = (usec_t) exit_timestamp;
1985         i->pid = (pid_t) pid;
1986         i->code = code;
1987         i->status = status;
1988
1989         return 0;
1990 }
1991
1992 typedef struct UnitStatusInfo {
1993         const char *id;
1994         const char *load_state;
1995         const char *active_state;
1996         const char *sub_state;
1997         const char *unit_file_state;
1998
1999         const char *description;
2000         const char *following;
2001
2002         const char *path;
2003         const char *default_control_group;
2004
2005         const char *load_error;
2006         const char *result;
2007
2008         usec_t inactive_exit_timestamp;
2009         usec_t inactive_exit_timestamp_monotonic;
2010         usec_t active_enter_timestamp;
2011         usec_t active_exit_timestamp;
2012         usec_t inactive_enter_timestamp;
2013
2014         bool need_daemon_reload;
2015
2016         /* Service */
2017         pid_t main_pid;
2018         pid_t control_pid;
2019         const char *status_text;
2020         bool running:1;
2021 #ifdef HAVE_SYSV_COMPAT
2022         bool is_sysv:1;
2023 #endif
2024
2025         usec_t start_timestamp;
2026         usec_t exit_timestamp;
2027
2028         int exit_code, exit_status;
2029
2030         usec_t condition_timestamp;
2031         bool condition_result;
2032
2033         /* Socket */
2034         unsigned n_accepted;
2035         unsigned n_connections;
2036         bool accept;
2037
2038         /* Device */
2039         const char *sysfs_path;
2040
2041         /* Mount, Automount */
2042         const char *where;
2043
2044         /* Swap */
2045         const char *what;
2046
2047         LIST_HEAD(ExecStatusInfo, exec);
2048 } UnitStatusInfo;
2049
2050 static void print_status_info(UnitStatusInfo *i) {
2051         ExecStatusInfo *p;
2052         const char *on, *off, *ss;
2053         usec_t timestamp;
2054         char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
2055         char since2[FORMAT_TIMESTAMP_MAX], *s2;
2056
2057         assert(i);
2058
2059         /* This shows pretty information about a unit. See
2060          * print_property() for a low-level property printer */
2061
2062         printf("%s", strna(i->id));
2063
2064         if (i->description && !streq_ptr(i->id, i->description))
2065                 printf(" - %s", i->description);
2066
2067         printf("\n");
2068
2069         if (i->following)
2070                 printf("\t  Follow: unit currently follows state of %s\n", i->following);
2071
2072         if (streq_ptr(i->load_state, "error")) {
2073                 on = ansi_highlight_red(true);
2074                 off = ansi_highlight_red(false);
2075         } else
2076                 on = off = "";
2077
2078         if (i->load_error)
2079                 printf("\t  Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error);
2080         else if (i->path && i->unit_file_state)
2081                 printf("\t  Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, i->path, i->unit_file_state);
2082         else if (i->path)
2083                 printf("\t  Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, i->path);
2084         else
2085                 printf("\t  Loaded: %s%s%s\n", on, strna(i->load_state), off);
2086
2087         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2088
2089         if (streq_ptr(i->active_state, "failed")) {
2090                 on = ansi_highlight_red(true);
2091                 off = ansi_highlight_red(false);
2092         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2093                 on = ansi_highlight_green(true);
2094                 off = ansi_highlight_green(false);
2095         } else
2096                 on = off = "";
2097
2098         if (ss)
2099                 printf("\t  Active: %s%s (%s)%s",
2100                        on,
2101                        strna(i->active_state),
2102                        ss,
2103                        off);
2104         else
2105                 printf("\t  Active: %s%s%s",
2106                        on,
2107                        strna(i->active_state),
2108                        off);
2109
2110         if (!isempty(i->result) && !streq(i->result, "success"))
2111                 printf(" (Result: %s)", i->result);
2112
2113         timestamp = (streq_ptr(i->active_state, "active")      ||
2114                      streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
2115                     (streq_ptr(i->active_state, "inactive")    ||
2116                      streq_ptr(i->active_state, "failed"))      ? i->inactive_enter_timestamp :
2117                     streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
2118                                                                   i->active_exit_timestamp;
2119
2120         s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp);
2121         s2 = format_timestamp(since2, sizeof(since2), timestamp);
2122
2123         if (s1)
2124                 printf(" since %s; %s\n", s2, s1);
2125         else if (s2)
2126                 printf(" since %s\n", s2);
2127         else
2128                 printf("\n");
2129
2130         if (!i->condition_result && i->condition_timestamp > 0) {
2131                 s1 = format_timestamp_pretty(since1, sizeof(since1), i->condition_timestamp);
2132                 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2133
2134                 if (s1)
2135                         printf("\t          start condition failed at %s; %s\n", s2, s1);
2136                 else if (s2)
2137                         printf("\t          start condition failed at %s\n", s2);
2138         }
2139
2140         if (i->sysfs_path)
2141                 printf("\t  Device: %s\n", i->sysfs_path);
2142         if (i->where)
2143                 printf("\t   Where: %s\n", i->where);
2144         if (i->what)
2145                 printf("\t    What: %s\n", i->what);
2146
2147         if (i->accept)
2148                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
2149
2150         LIST_FOREACH(exec, p, i->exec) {
2151                 char *t;
2152                 bool good;
2153
2154                 /* Only show exited processes here */
2155                 if (p->code == 0)
2156                         continue;
2157
2158                 t = strv_join(p->argv, " ");
2159                 printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
2160                 free(t);
2161
2162 #ifdef HAVE_SYSV_COMPAT
2163                 if (i->is_sysv)
2164                         good = is_clean_exit_lsb(p->code, p->status);
2165                 else
2166 #endif
2167                         good = is_clean_exit(p->code, p->status);
2168
2169                 if (!good) {
2170                         on = ansi_highlight_red(true);
2171                         off = ansi_highlight_red(false);
2172                 } else
2173                         on = off = "";
2174
2175                 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2176
2177                 if (p->code == CLD_EXITED) {
2178                         const char *c;
2179
2180                         printf("status=%i", p->status);
2181
2182 #ifdef HAVE_SYSV_COMPAT
2183                         if ((c = exit_status_to_string(p->status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
2184 #else
2185                         if ((c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD)))
2186 #endif
2187                                 printf("/%s", c);
2188
2189                 } else
2190                         printf("signal=%s", signal_to_string(p->status));
2191
2192                 printf(")%s\n", off);
2193
2194                 if (i->main_pid == p->pid &&
2195                     i->start_timestamp == p->start_timestamp &&
2196                     i->exit_timestamp == p->start_timestamp)
2197                         /* Let's not show this twice */
2198                         i->main_pid = 0;
2199
2200                 if (p->pid == i->control_pid)
2201                         i->control_pid = 0;
2202         }
2203
2204         if (i->main_pid > 0 || i->control_pid > 0) {
2205                 printf("\t");
2206
2207                 if (i->main_pid > 0) {
2208                         printf("Main PID: %u", (unsigned) i->main_pid);
2209
2210                         if (i->running) {
2211                                 char *t = NULL;
2212                                 get_process_comm(i->main_pid, &t);
2213                                 if (t) {
2214                                         printf(" (%s)", t);
2215                                         free(t);
2216                                 }
2217                         } else if (i->exit_code > 0) {
2218                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2219
2220                                 if (i->exit_code == CLD_EXITED) {
2221                                         const char *c;
2222
2223                                         printf("status=%i", i->exit_status);
2224
2225 #ifdef HAVE_SYSV_COMPAT
2226                                         if ((c = exit_status_to_string(i->exit_status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
2227 #else
2228                                         if ((c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD)))
2229 #endif
2230                                                 printf("/%s", c);
2231
2232                                 } else
2233                                         printf("signal=%s", signal_to_string(i->exit_status));
2234                                 printf(")");
2235                         }
2236                 }
2237
2238                 if (i->main_pid > 0 && i->control_pid > 0)
2239                         printf(";");
2240
2241                 if (i->control_pid > 0) {
2242                         char *t = NULL;
2243
2244                         printf(" Control: %u", (unsigned) i->control_pid);
2245
2246                         get_process_comm(i->control_pid, &t);
2247                         if (t) {
2248                                 printf(" (%s)", t);
2249                                 free(t);
2250                         }
2251                 }
2252
2253                 printf("\n");
2254         }
2255
2256         if (i->status_text)
2257                 printf("\t  Status: \"%s\"\n", i->status_text);
2258
2259         if (i->default_control_group) {
2260                 unsigned c;
2261
2262                 printf("\t  CGroup: %s\n", i->default_control_group);
2263
2264                 if (arg_transport != TRANSPORT_SSH) {
2265                         if ((c = columns()) > 18)
2266                                 c -= 18;
2267                         else
2268                                 c = 0;
2269
2270                         show_cgroup_by_path(i->default_control_group, "\t\t  ", c, false);
2271                 }
2272         }
2273
2274         if (i->id && arg_transport != TRANSPORT_SSH) {
2275                 printf("\n");
2276                 show_journal_by_unit(i->id, arg_output, NULL, 0, i->inactive_exit_timestamp_monotonic, arg_lines, arg_all, arg_follow);
2277         }
2278
2279         if (i->need_daemon_reload)
2280                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2281                        ansi_highlight_red(true),
2282                        ansi_highlight_red(false),
2283                        arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2284 }
2285
2286 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2287
2288         assert(name);
2289         assert(iter);
2290         assert(i);
2291
2292         switch (dbus_message_iter_get_arg_type(iter)) {
2293
2294         case DBUS_TYPE_STRING: {
2295                 const char *s;
2296
2297                 dbus_message_iter_get_basic(iter, &s);
2298
2299                 if (!isempty(s)) {
2300                         if (streq(name, "Id"))
2301                                 i->id = s;
2302                         else if (streq(name, "LoadState"))
2303                                 i->load_state = s;
2304                         else if (streq(name, "ActiveState"))
2305                                 i->active_state = s;
2306                         else if (streq(name, "SubState"))
2307                                 i->sub_state = s;
2308                         else if (streq(name, "Description"))
2309                                 i->description = s;
2310                         else if (streq(name, "FragmentPath"))
2311                                 i->path = s;
2312 #ifdef HAVE_SYSV_COMPAT
2313                         else if (streq(name, "SysVPath")) {
2314                                 i->is_sysv = true;
2315                                 i->path = s;
2316                         }
2317 #endif
2318                         else if (streq(name, "DefaultControlGroup"))
2319                                 i->default_control_group = s;
2320                         else if (streq(name, "StatusText"))
2321                                 i->status_text = s;
2322                         else if (streq(name, "SysFSPath"))
2323                                 i->sysfs_path = s;
2324                         else if (streq(name, "Where"))
2325                                 i->where = s;
2326                         else if (streq(name, "What"))
2327                                 i->what = s;
2328                         else if (streq(name, "Following"))
2329                                 i->following = s;
2330                         else if (streq(name, "UnitFileState"))
2331                                 i->unit_file_state = s;
2332                         else if (streq(name, "Result"))
2333                                 i->result = s;
2334                 }
2335
2336                 break;
2337         }
2338
2339         case DBUS_TYPE_BOOLEAN: {
2340                 dbus_bool_t b;
2341
2342                 dbus_message_iter_get_basic(iter, &b);
2343
2344                 if (streq(name, "Accept"))
2345                         i->accept = b;
2346                 else if (streq(name, "NeedDaemonReload"))
2347                         i->need_daemon_reload = b;
2348                 else if (streq(name, "ConditionResult"))
2349                         i->condition_result = b;
2350
2351                 break;
2352         }
2353
2354         case DBUS_TYPE_UINT32: {
2355                 uint32_t u;
2356
2357                 dbus_message_iter_get_basic(iter, &u);
2358
2359                 if (streq(name, "MainPID")) {
2360                         if (u > 0) {
2361                                 i->main_pid = (pid_t) u;
2362                                 i->running = true;
2363                         }
2364                 } else if (streq(name, "ControlPID"))
2365                         i->control_pid = (pid_t) u;
2366                 else if (streq(name, "ExecMainPID")) {
2367                         if (u > 0)
2368                                 i->main_pid = (pid_t) u;
2369                 } else if (streq(name, "NAccepted"))
2370                         i->n_accepted = u;
2371                 else if (streq(name, "NConnections"))
2372                         i->n_connections = u;
2373
2374                 break;
2375         }
2376
2377         case DBUS_TYPE_INT32: {
2378                 int32_t j;
2379
2380                 dbus_message_iter_get_basic(iter, &j);
2381
2382                 if (streq(name, "ExecMainCode"))
2383                         i->exit_code = (int) j;
2384                 else if (streq(name, "ExecMainStatus"))
2385                         i->exit_status = (int) j;
2386
2387                 break;
2388         }
2389
2390         case DBUS_TYPE_UINT64: {
2391                 uint64_t u;
2392
2393                 dbus_message_iter_get_basic(iter, &u);
2394
2395                 if (streq(name, "ExecMainStartTimestamp"))
2396                         i->start_timestamp = (usec_t) u;
2397                 else if (streq(name, "ExecMainExitTimestamp"))
2398                         i->exit_timestamp = (usec_t) u;
2399                 else if (streq(name, "ActiveEnterTimestamp"))
2400                         i->active_enter_timestamp = (usec_t) u;
2401                 else if (streq(name, "InactiveEnterTimestamp"))
2402                         i->inactive_enter_timestamp = (usec_t) u;
2403                 else if (streq(name, "InactiveExitTimestamp"))
2404                         i->inactive_exit_timestamp = (usec_t) u;
2405                 else if (streq(name, "InactiveExitTimestampMonotonic"))
2406                         i->inactive_exit_timestamp_monotonic = (usec_t) u;
2407                 else if (streq(name, "ActiveExitTimestamp"))
2408                         i->active_exit_timestamp = (usec_t) u;
2409                 else if (streq(name, "ConditionTimestamp"))
2410                         i->condition_timestamp = (usec_t) u;
2411
2412                 break;
2413         }
2414
2415         case DBUS_TYPE_ARRAY: {
2416
2417                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2418                     startswith(name, "Exec")) {
2419                         DBusMessageIter sub;
2420
2421                         dbus_message_iter_recurse(iter, &sub);
2422                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2423                                 ExecStatusInfo *info;
2424                                 int r;
2425
2426                                 if (!(info = new0(ExecStatusInfo, 1)))
2427                                         return -ENOMEM;
2428
2429                                 if (!(info->name = strdup(name))) {
2430                                         free(info);
2431                                         return -ENOMEM;
2432                                 }
2433
2434                                 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2435                                         free(info);
2436                                         return r;
2437                                 }
2438
2439                                 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2440
2441                                 dbus_message_iter_next(&sub);
2442                         }
2443                 }
2444
2445                 break;
2446         }
2447
2448         case DBUS_TYPE_STRUCT: {
2449
2450                 if (streq(name, "LoadError")) {
2451                         DBusMessageIter sub;
2452                         const char *n, *message;
2453                         int r;
2454
2455                         dbus_message_iter_recurse(iter, &sub);
2456
2457                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2458                         if (r < 0)
2459                                 return r;
2460
2461                         r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2462                         if (r < 0)
2463                                 return r;
2464
2465                         if (!isempty(message))
2466                                 i->load_error = message;
2467                 }
2468
2469                 break;
2470         }
2471         }
2472
2473         return 0;
2474 }
2475
2476 static int print_property(const char *name, DBusMessageIter *iter) {
2477         assert(name);
2478         assert(iter);
2479
2480         /* This is a low-level property printer, see
2481          * print_status_info() for the nicer output */
2482
2483         if (arg_property && !strv_find(arg_property, name))
2484                 return 0;
2485
2486         switch (dbus_message_iter_get_arg_type(iter)) {
2487
2488         case DBUS_TYPE_STRUCT: {
2489                 DBusMessageIter sub;
2490                 dbus_message_iter_recurse(iter, &sub);
2491
2492                 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2493                         uint32_t u;
2494
2495                         dbus_message_iter_get_basic(&sub, &u);
2496
2497                         if (u)
2498                                 printf("%s=%u\n", name, (unsigned) u);
2499                         else if (arg_all)
2500                                 printf("%s=\n", name);
2501
2502                         return 0;
2503                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2504                         const char *s;
2505
2506                         dbus_message_iter_get_basic(&sub, &s);
2507
2508                         if (arg_all || s[0])
2509                                 printf("%s=%s\n", name, s);
2510
2511                         return 0;
2512                 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2513                         const char *a = NULL, *b = NULL;
2514
2515                         if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2516                                 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2517
2518                         if (arg_all || !isempty(a) || !isempty(b))
2519                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2520
2521                         return 0;
2522                 }
2523
2524                 break;
2525         }
2526
2527         case DBUS_TYPE_ARRAY:
2528
2529                 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2530                         DBusMessageIter sub, sub2;
2531
2532                         dbus_message_iter_recurse(iter, &sub);
2533                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2534                                 const char *path;
2535                                 dbus_bool_t ignore;
2536
2537                                 dbus_message_iter_recurse(&sub, &sub2);
2538
2539                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2540                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2541                                         printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2542
2543                                 dbus_message_iter_next(&sub);
2544                         }
2545
2546                         return 0;
2547
2548                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2549                         DBusMessageIter sub, sub2;
2550
2551                         dbus_message_iter_recurse(iter, &sub);
2552                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2553                                 const char *type, *path;
2554
2555                                 dbus_message_iter_recurse(&sub, &sub2);
2556
2557                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2558                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2559                                         printf("%s=%s\n", type, path);
2560
2561                                 dbus_message_iter_next(&sub);
2562                         }
2563
2564                         return 0;
2565
2566                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2567                         DBusMessageIter sub, sub2;
2568
2569                         dbus_message_iter_recurse(iter, &sub);
2570                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2571                                 const char *base;
2572                                 uint64_t value, next_elapse;
2573
2574                                 dbus_message_iter_recurse(&sub, &sub2);
2575
2576                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2577                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2578                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2579                                         char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2580
2581                                         printf("%s={ value=%s ; next_elapse=%s }\n",
2582                                                base,
2583                                                format_timespan(timespan1, sizeof(timespan1), value),
2584                                                format_timespan(timespan2, sizeof(timespan2), next_elapse));
2585                                 }
2586
2587                                 dbus_message_iter_next(&sub);
2588                         }
2589
2590                         return 0;
2591
2592                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2593                         DBusMessageIter sub, sub2;
2594
2595                         dbus_message_iter_recurse(iter, &sub);
2596                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2597                                 const char *controller, *attr, *value;
2598
2599                                 dbus_message_iter_recurse(&sub, &sub2);
2600
2601                                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
2602                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
2603                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
2604
2605                                         printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2606                                                controller,
2607                                                attr,
2608                                                value);
2609                                 }
2610
2611                                 dbus_message_iter_next(&sub);
2612                         }
2613
2614                         return 0;
2615
2616                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
2617                         DBusMessageIter sub;
2618
2619                         dbus_message_iter_recurse(iter, &sub);
2620                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2621                                 ExecStatusInfo info;
2622
2623                                 zero(info);
2624                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
2625                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
2626                                         char *t;
2627
2628                                         t = strv_join(info.argv, " ");
2629
2630                                         printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
2631                                                name,
2632                                                strna(info.path),
2633                                                strna(t),
2634                                                yes_no(info.ignore),
2635                                                strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
2636                                                strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
2637                                                (unsigned) info. pid,
2638                                                sigchld_code_to_string(info.code),
2639                                                info.status,
2640                                                info.code == CLD_EXITED ? "" : "/",
2641                                                strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
2642
2643                                         free(t);
2644                                 }
2645
2646                                 free(info.path);
2647                                 strv_free(info.argv);
2648
2649                                 dbus_message_iter_next(&sub);
2650                         }
2651
2652                         return 0;
2653                 }
2654
2655                 break;
2656         }
2657
2658         if (generic_print_property(name, iter, arg_all) > 0)
2659                 return 0;
2660
2661         if (arg_all)
2662                 printf("%s=[unprintable]\n", name);
2663
2664         return 0;
2665 }
2666
2667 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
2668         DBusMessage *m = NULL, *reply = NULL;
2669         const char *interface = "";
2670         int r;
2671         DBusError error;
2672         DBusMessageIter iter, sub, sub2, sub3;
2673         UnitStatusInfo info;
2674         ExecStatusInfo *p;
2675
2676         assert(bus);
2677         assert(path);
2678         assert(new_line);
2679
2680         zero(info);
2681         dbus_error_init(&error);
2682
2683         if (!(m = dbus_message_new_method_call(
2684                               "org.freedesktop.systemd1",
2685                               path,
2686                               "org.freedesktop.DBus.Properties",
2687                               "GetAll"))) {
2688                 log_error("Could not allocate message.");
2689                 r = -ENOMEM;
2690                 goto finish;
2691         }
2692
2693         if (!dbus_message_append_args(m,
2694                                       DBUS_TYPE_STRING, &interface,
2695                                       DBUS_TYPE_INVALID)) {
2696                 log_error("Could not append arguments to message.");
2697                 r = -ENOMEM;
2698                 goto finish;
2699         }
2700
2701         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2702                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2703                 r = -EIO;
2704                 goto finish;
2705         }
2706
2707         if (!dbus_message_iter_init(reply, &iter) ||
2708             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
2709             dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
2710                 log_error("Failed to parse reply.");
2711                 r = -EIO;
2712                 goto finish;
2713         }
2714
2715         dbus_message_iter_recurse(&iter, &sub);
2716
2717         if (*new_line)
2718                 printf("\n");
2719
2720         *new_line = true;
2721
2722         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2723                 const char *name;
2724
2725                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
2726                         log_error("Failed to parse reply.");
2727                         r = -EIO;
2728                         goto finish;
2729                 }
2730
2731                 dbus_message_iter_recurse(&sub, &sub2);
2732
2733                 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
2734                         log_error("Failed to parse reply.");
2735                         r = -EIO;
2736                         goto finish;
2737                 }
2738
2739                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
2740                         log_error("Failed to parse reply.");
2741                         r = -EIO;
2742                         goto finish;
2743                 }
2744
2745                 dbus_message_iter_recurse(&sub2, &sub3);
2746
2747                 if (show_properties)
2748                         r = print_property(name, &sub3);
2749                 else
2750                         r = status_property(name, &sub3, &info);
2751
2752                 if (r < 0) {
2753                         log_error("Failed to parse reply.");
2754                         r = -EIO;
2755                         goto finish;
2756                 }
2757
2758                 dbus_message_iter_next(&sub);
2759         }
2760
2761         r = 0;
2762
2763         if (!show_properties)
2764                 print_status_info(&info);
2765
2766         if (!streq_ptr(info.active_state, "active") &&
2767             !streq_ptr(info.active_state, "reloading") &&
2768             streq(verb, "status"))
2769                 /* According to LSB: "program not running" */
2770                 r = 3;
2771
2772         while ((p = info.exec)) {
2773                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
2774                 exec_status_info_free(p);
2775         }
2776
2777 finish:
2778         if (m)
2779                 dbus_message_unref(m);
2780
2781         if (reply)
2782                 dbus_message_unref(reply);
2783
2784         dbus_error_free(&error);
2785
2786         return r;
2787 }
2788
2789 static int show(DBusConnection *bus, char **args) {
2790         DBusMessage *m = NULL, *reply = NULL;
2791         int r, ret = 0;
2792         DBusError error;
2793         bool show_properties, new_line = false;
2794         char **name;
2795
2796         assert(bus);
2797         assert(args);
2798
2799         dbus_error_init(&error);
2800
2801         show_properties = !streq(args[0], "status");
2802
2803         if (show_properties)
2804                 pager_open_if_enabled();
2805
2806         if (show_properties && strv_length(args) <= 1) {
2807                 /* If not argument is specified inspect the manager
2808                  * itself */
2809
2810                 ret = show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
2811                 goto finish;
2812         }
2813
2814         STRV_FOREACH(name, args+1) {
2815                 const char *path = NULL;
2816                 uint32_t id;
2817
2818                 if (safe_atou32(*name, &id) < 0) {
2819
2820                         /* Interpret as unit name */
2821
2822                         if (!(m = dbus_message_new_method_call(
2823                                               "org.freedesktop.systemd1",
2824                                               "/org/freedesktop/systemd1",
2825                                               "org.freedesktop.systemd1.Manager",
2826                                               "LoadUnit"))) {
2827                                 log_error("Could not allocate message.");
2828                                 ret = -ENOMEM;
2829                                 goto finish;
2830                         }
2831
2832                         if (!dbus_message_append_args(m,
2833                                                       DBUS_TYPE_STRING, name,
2834                                                       DBUS_TYPE_INVALID)) {
2835                                 log_error("Could not append arguments to message.");
2836                                 ret = -ENOMEM;
2837                                 goto finish;
2838                         }
2839
2840                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2841
2842                                 if (!dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
2843                                         log_error("Failed to issue method call: %s", bus_error_message(&error));
2844                                         ret = -EIO;
2845                                         goto finish;
2846                                 }
2847
2848                                 dbus_error_free(&error);
2849
2850                                 dbus_message_unref(m);
2851                                 if (!(m = dbus_message_new_method_call(
2852                                                       "org.freedesktop.systemd1",
2853                                                       "/org/freedesktop/systemd1",
2854                                                       "org.freedesktop.systemd1.Manager",
2855                                                       "GetUnit"))) {
2856                                         log_error("Could not allocate message.");
2857                                         ret = -ENOMEM;
2858                                         goto finish;
2859                                 }
2860
2861                                 if (!dbus_message_append_args(m,
2862                                                               DBUS_TYPE_STRING, name,
2863                                                               DBUS_TYPE_INVALID)) {
2864                                         log_error("Could not append arguments to message.");
2865                                         ret = -ENOMEM;
2866                                         goto finish;
2867                                 }
2868
2869                                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2870                                         log_error("Failed to issue method call: %s", bus_error_message(&error));
2871
2872                                         if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT))
2873                                                 ret = 4; /* According to LSB: "program or service status is unknown" */
2874                                         else
2875                                                 ret = -EIO;
2876                                         goto finish;
2877                                 }
2878                         }
2879
2880                 } else if (show_properties) {
2881
2882                         /* Interpret as job id */
2883
2884                         if (!(m = dbus_message_new_method_call(
2885                                               "org.freedesktop.systemd1",
2886                                               "/org/freedesktop/systemd1",
2887                                               "org.freedesktop.systemd1.Manager",
2888                                               "GetJob"))) {
2889                                 log_error("Could not allocate message.");
2890                                 ret = -ENOMEM;
2891                                 goto finish;
2892                         }
2893
2894                         if (!dbus_message_append_args(m,
2895                                                       DBUS_TYPE_UINT32, &id,
2896                                                       DBUS_TYPE_INVALID)) {
2897                                 log_error("Could not append arguments to message.");
2898                                 ret = -ENOMEM;
2899                                 goto finish;
2900                         }
2901
2902                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2903                                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2904                                 ret = -EIO;
2905                                 goto finish;
2906                         }
2907                 } else {
2908
2909                         /* Interpret as PID */
2910
2911                         if (!(m = dbus_message_new_method_call(
2912                                               "org.freedesktop.systemd1",
2913                                               "/org/freedesktop/systemd1",
2914                                               "org.freedesktop.systemd1.Manager",
2915                                               "GetUnitByPID"))) {
2916                                 log_error("Could not allocate message.");
2917                                 ret = -ENOMEM;
2918                                 goto finish;
2919                         }
2920
2921                         if (!dbus_message_append_args(m,
2922                                                       DBUS_TYPE_UINT32, &id,
2923                                                       DBUS_TYPE_INVALID)) {
2924                                 log_error("Could not append arguments to message.");
2925                                 ret = -ENOMEM;
2926                                 goto finish;
2927                         }
2928
2929                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2930                                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2931                                 ret = -EIO;
2932                                 goto finish;
2933                         }
2934                 }
2935
2936                 if (!dbus_message_get_args(reply, &error,
2937                                            DBUS_TYPE_OBJECT_PATH, &path,
2938                                            DBUS_TYPE_INVALID)) {
2939                         log_error("Failed to parse reply: %s", bus_error_message(&error));
2940                         ret = -EIO;
2941                         goto finish;
2942                 }
2943
2944                 if ((r = show_one(args[0], bus, path, show_properties, &new_line)) != 0)
2945                         ret = r;
2946
2947                 dbus_message_unref(m);
2948                 dbus_message_unref(reply);
2949                 m = reply = NULL;
2950         }
2951
2952 finish:
2953         if (m)
2954                 dbus_message_unref(m);
2955
2956         if (reply)
2957                 dbus_message_unref(reply);
2958
2959         dbus_error_free(&error);
2960
2961         return ret;
2962 }
2963
2964 static int dump(DBusConnection *bus, char **args) {
2965         DBusMessage *m = NULL, *reply = NULL;
2966         DBusError error;
2967         int r;
2968         const char *text;
2969
2970         dbus_error_init(&error);
2971
2972         pager_open_if_enabled();
2973
2974         if (!(m = dbus_message_new_method_call(
2975                               "org.freedesktop.systemd1",
2976                               "/org/freedesktop/systemd1",
2977                               "org.freedesktop.systemd1.Manager",
2978                               "Dump"))) {
2979                 log_error("Could not allocate message.");
2980                 return -ENOMEM;
2981         }
2982
2983         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2984                 log_error("Failed to issue method call: %s", bus_error_message(&error));
2985                 r = -EIO;
2986                 goto finish;
2987         }
2988
2989         if (!dbus_message_get_args(reply, &error,
2990                                    DBUS_TYPE_STRING, &text,
2991                                    DBUS_TYPE_INVALID)) {
2992                 log_error("Failed to parse reply: %s", bus_error_message(&error));
2993                 r = -EIO;
2994                 goto finish;
2995         }
2996
2997         fputs(text, stdout);
2998
2999         r = 0;
3000
3001 finish:
3002         if (m)
3003                 dbus_message_unref(m);
3004
3005         if (reply)
3006                 dbus_message_unref(reply);
3007
3008         dbus_error_free(&error);
3009
3010         return r;
3011 }
3012
3013 static int snapshot(DBusConnection *bus, char **args) {
3014         DBusMessage *m = NULL, *reply = NULL;
3015         DBusError error;
3016         int r;
3017         const char *name = "", *path, *id;
3018         dbus_bool_t cleanup = FALSE;
3019         DBusMessageIter iter, sub;
3020         const char
3021                 *interface = "org.freedesktop.systemd1.Unit",
3022                 *property = "Id";
3023
3024         dbus_error_init(&error);
3025
3026         if (!(m = dbus_message_new_method_call(
3027                               "org.freedesktop.systemd1",
3028                               "/org/freedesktop/systemd1",
3029                               "org.freedesktop.systemd1.Manager",
3030                               "CreateSnapshot"))) {
3031                 log_error("Could not allocate message.");
3032                 return -ENOMEM;
3033         }
3034
3035         if (strv_length(args) > 1)
3036                 name = args[1];
3037
3038         if (!dbus_message_append_args(m,
3039                                       DBUS_TYPE_STRING, &name,
3040                                       DBUS_TYPE_BOOLEAN, &cleanup,
3041                                       DBUS_TYPE_INVALID)) {
3042                 log_error("Could not append arguments to message.");
3043                 r = -ENOMEM;
3044                 goto finish;
3045         }
3046
3047         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3048                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3049                 r = -EIO;
3050                 goto finish;
3051         }
3052
3053         if (!dbus_message_get_args(reply, &error,
3054                                    DBUS_TYPE_OBJECT_PATH, &path,
3055                                    DBUS_TYPE_INVALID)) {
3056                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3057                 r = -EIO;
3058                 goto finish;
3059         }
3060
3061         dbus_message_unref(m);
3062         if (!(m = dbus_message_new_method_call(
3063                               "org.freedesktop.systemd1",
3064                               path,
3065                               "org.freedesktop.DBus.Properties",
3066                               "Get"))) {
3067                 log_error("Could not allocate message.");
3068                 return -ENOMEM;
3069         }
3070
3071         if (!dbus_message_append_args(m,
3072                                       DBUS_TYPE_STRING, &interface,
3073                                       DBUS_TYPE_STRING, &property,
3074                                       DBUS_TYPE_INVALID)) {
3075                 log_error("Could not append arguments to message.");
3076                 r = -ENOMEM;
3077                 goto finish;
3078         }
3079
3080         dbus_message_unref(reply);
3081         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3082                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3083                 r = -EIO;
3084                 goto finish;
3085         }
3086
3087         if (!dbus_message_iter_init(reply, &iter) ||
3088             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3089                 log_error("Failed to parse reply.");
3090                 r = -EIO;
3091                 goto finish;
3092         }
3093
3094         dbus_message_iter_recurse(&iter, &sub);
3095
3096         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
3097                 log_error("Failed to parse reply.");
3098                 r = -EIO;
3099                 goto finish;
3100         }
3101
3102         dbus_message_iter_get_basic(&sub, &id);
3103
3104         if (!arg_quiet)
3105                 puts(id);
3106         r = 0;
3107
3108 finish:
3109         if (m)
3110                 dbus_message_unref(m);
3111
3112         if (reply)
3113                 dbus_message_unref(reply);
3114
3115         dbus_error_free(&error);
3116
3117         return r;
3118 }
3119
3120 static int delete_snapshot(DBusConnection *bus, char **args) {
3121         DBusMessage *m = NULL, *reply = NULL;
3122         int r;
3123         DBusError error;
3124         char **name;
3125
3126         assert(bus);
3127         assert(args);
3128
3129         dbus_error_init(&error);
3130
3131         STRV_FOREACH(name, args+1) {
3132                 const char *path = NULL;
3133
3134                 if (!(m = dbus_message_new_method_call(
3135                                       "org.freedesktop.systemd1",
3136                                       "/org/freedesktop/systemd1",
3137                                       "org.freedesktop.systemd1.Manager",
3138                                       "GetUnit"))) {
3139                         log_error("Could not allocate message.");
3140                         r = -ENOMEM;
3141                         goto finish;
3142                 }
3143
3144                 if (!dbus_message_append_args(m,
3145                                               DBUS_TYPE_STRING, name,
3146                                               DBUS_TYPE_INVALID)) {
3147                         log_error("Could not append arguments to message.");
3148                         r = -ENOMEM;
3149                         goto finish;
3150                 }
3151
3152                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3153                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3154                         r = -EIO;
3155                         goto finish;
3156                 }
3157
3158                 if (!dbus_message_get_args(reply, &error,
3159                                            DBUS_TYPE_OBJECT_PATH, &path,
3160                                            DBUS_TYPE_INVALID)) {
3161                         log_error("Failed to parse reply: %s", bus_error_message(&error));
3162                         r = -EIO;
3163                         goto finish;
3164                 }
3165
3166                 dbus_message_unref(m);
3167                 if (!(m = dbus_message_new_method_call(
3168                                       "org.freedesktop.systemd1",
3169                                       path,
3170                                       "org.freedesktop.systemd1.Snapshot",
3171                                       "Remove"))) {
3172                         log_error("Could not allocate message.");
3173                         r = -ENOMEM;
3174                         goto finish;
3175                 }
3176
3177                 dbus_message_unref(reply);
3178                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3179                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3180                         r = -EIO;
3181                         goto finish;
3182                 }
3183
3184                 dbus_message_unref(m);
3185                 dbus_message_unref(reply);
3186                 m = reply = NULL;
3187         }
3188
3189         r = 0;
3190
3191 finish:
3192         if (m)
3193                 dbus_message_unref(m);
3194
3195         if (reply)
3196                 dbus_message_unref(reply);
3197
3198         dbus_error_free(&error);
3199
3200         return r;
3201 }
3202
3203 static int daemon_reload(DBusConnection *bus, char **args) {
3204         DBusMessage *m = NULL, *reply = NULL;
3205         DBusError error;
3206         int r;
3207         const char *method;
3208
3209         dbus_error_init(&error);
3210
3211         if (arg_action == ACTION_RELOAD)
3212                 method = "Reload";
3213         else if (arg_action == ACTION_REEXEC)
3214                 method = "Reexecute";
3215         else {
3216                 assert(arg_action == ACTION_SYSTEMCTL);
3217
3218                 method =
3219                         streq(args[0], "clear-jobs")    ||
3220                         streq(args[0], "cancel")        ? "ClearJobs" :
3221                         streq(args[0], "daemon-reexec") ? "Reexecute" :
3222                         streq(args[0], "reset-failed")  ? "ResetFailed" :
3223                         streq(args[0], "halt")          ? "Halt" :
3224                         streq(args[0], "poweroff")      ? "PowerOff" :
3225                         streq(args[0], "reboot")        ? "Reboot" :
3226                         streq(args[0], "kexec")         ? "KExec" :
3227                         streq(args[0], "exit")          ? "Exit" :
3228                                     /* "daemon-reload" */ "Reload";
3229         }
3230
3231         if (!(m = dbus_message_new_method_call(
3232                               "org.freedesktop.systemd1",
3233                               "/org/freedesktop/systemd1",
3234                               "org.freedesktop.systemd1.Manager",
3235                               method))) {
3236                 log_error("Could not allocate message.");
3237                 return -ENOMEM;
3238         }
3239
3240         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3241
3242                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
3243                         /* There's always a fallback possible for
3244                          * legacy actions. */
3245                         r = -EADDRNOTAVAIL;
3246                         goto finish;
3247                 }
3248
3249                 if (streq(method, "Reexecute") && dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY)) {
3250                         /* On reexecution, we expect a disconnect, not
3251                          * a reply */
3252                         r = 0;
3253                         goto finish;
3254                 }
3255
3256                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3257                 r = -EIO;
3258                 goto finish;
3259         }
3260
3261         r = 0;
3262
3263 finish:
3264         if (m)
3265                 dbus_message_unref(m);
3266
3267         if (reply)
3268                 dbus_message_unref(reply);
3269
3270         dbus_error_free(&error);
3271
3272         return r;
3273 }
3274
3275 static int reset_failed(DBusConnection *bus, char **args) {
3276         DBusMessage *m = NULL;
3277         int r;
3278         DBusError error;
3279         char **name;
3280
3281         assert(bus);
3282         dbus_error_init(&error);
3283
3284         if (strv_length(args) <= 1)
3285                 return daemon_reload(bus, args);
3286
3287         STRV_FOREACH(name, args+1) {
3288                 DBusMessage *reply;
3289
3290                 if (!(m = dbus_message_new_method_call(
3291                                       "org.freedesktop.systemd1",
3292                                       "/org/freedesktop/systemd1",
3293                                       "org.freedesktop.systemd1.Manager",
3294                                       "ResetFailedUnit"))) {
3295                         log_error("Could not allocate message.");
3296                         r = -ENOMEM;
3297                         goto finish;
3298                 }
3299
3300                 if (!dbus_message_append_args(m,
3301                                               DBUS_TYPE_STRING, name,
3302                                               DBUS_TYPE_INVALID)) {
3303                         log_error("Could not append arguments to message.");
3304                         r = -ENOMEM;
3305                         goto finish;
3306                 }
3307
3308                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3309                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3310                         r = -EIO;
3311                         goto finish;
3312                 }
3313
3314                 dbus_message_unref(m);
3315                 dbus_message_unref(reply);
3316                 m = reply = NULL;
3317         }
3318
3319         r = 0;
3320
3321 finish:
3322         if (m)
3323                 dbus_message_unref(m);
3324
3325         dbus_error_free(&error);
3326
3327         return r;
3328 }
3329
3330 static int show_enviroment(DBusConnection *bus, char **args) {
3331         DBusMessage *m = NULL, *reply = NULL;
3332         DBusError error;
3333         DBusMessageIter iter, sub, sub2;
3334         int r;
3335         const char
3336                 *interface = "org.freedesktop.systemd1.Manager",
3337                 *property = "Environment";
3338
3339         dbus_error_init(&error);
3340
3341         pager_open_if_enabled();
3342
3343         if (!(m = dbus_message_new_method_call(
3344                               "org.freedesktop.systemd1",
3345                               "/org/freedesktop/systemd1",
3346                               "org.freedesktop.DBus.Properties",
3347                               "Get"))) {
3348                 log_error("Could not allocate message.");
3349                 return -ENOMEM;
3350         }
3351
3352         if (!dbus_message_append_args(m,
3353                                       DBUS_TYPE_STRING, &interface,
3354                                       DBUS_TYPE_STRING, &property,
3355                                       DBUS_TYPE_INVALID)) {
3356                 log_error("Could not append arguments to message.");
3357                 r = -ENOMEM;
3358                 goto finish;
3359         }
3360
3361         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3362                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3363                 r = -EIO;
3364                 goto finish;
3365         }
3366
3367         if (!dbus_message_iter_init(reply, &iter) ||
3368             dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
3369                 log_error("Failed to parse reply.");
3370                 r = -EIO;
3371                 goto finish;
3372         }
3373
3374         dbus_message_iter_recurse(&iter, &sub);
3375
3376         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
3377             dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
3378                 log_error("Failed to parse reply.");
3379                 r = -EIO;
3380                 goto finish;
3381         }
3382
3383         dbus_message_iter_recurse(&sub, &sub2);
3384
3385         while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
3386                 const char *text;
3387
3388                 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
3389                         log_error("Failed to parse reply.");
3390                         r = -EIO;
3391                         goto finish;
3392                 }
3393
3394                 dbus_message_iter_get_basic(&sub2, &text);
3395                 printf("%s\n", text);
3396
3397                 dbus_message_iter_next(&sub2);
3398         }
3399
3400         r = 0;
3401
3402 finish:
3403         if (m)
3404                 dbus_message_unref(m);
3405
3406         if (reply)
3407                 dbus_message_unref(reply);
3408
3409         dbus_error_free(&error);
3410
3411         return r;
3412 }
3413
3414 static int set_environment(DBusConnection *bus, char **args) {
3415         DBusMessage *m = NULL, *reply = NULL;
3416         DBusError error;
3417         int r;
3418         const char *method;
3419         DBusMessageIter iter, sub;
3420         char **name;
3421
3422         dbus_error_init(&error);
3423
3424         method = streq(args[0], "set-environment")
3425                 ? "SetEnvironment"
3426                 : "UnsetEnvironment";
3427
3428         if (!(m = dbus_message_new_method_call(
3429                               "org.freedesktop.systemd1",
3430                               "/org/freedesktop/systemd1",
3431                               "org.freedesktop.systemd1.Manager",
3432                               method))) {
3433
3434                 log_error("Could not allocate message.");
3435                 return -ENOMEM;
3436         }
3437
3438         dbus_message_iter_init_append(m, &iter);
3439
3440         if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
3441                 log_error("Could not append arguments to message.");
3442                 r = -ENOMEM;
3443                 goto finish;
3444         }
3445
3446         STRV_FOREACH(name, args+1)
3447                 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, name)) {
3448                         log_error("Could not append arguments to message.");
3449                         r = -ENOMEM;
3450                         goto finish;
3451                 }
3452
3453         if (!dbus_message_iter_close_container(&iter, &sub)) {
3454                 log_error("Could not append arguments to message.");
3455                 r = -ENOMEM;
3456                 goto finish;
3457         }
3458
3459         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3460                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3461                 r = -EIO;
3462                 goto finish;
3463         }
3464
3465         r = 0;
3466
3467 finish:
3468         if (m)
3469                 dbus_message_unref(m);
3470
3471         if (reply)
3472                 dbus_message_unref(reply);
3473
3474         dbus_error_free(&error);
3475
3476         return r;
3477 }
3478
3479 static int enable_sysv_units(char **args) {
3480         int r = 0;
3481
3482 #if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_MEEGO) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA))
3483         const char *verb = args[0];
3484         unsigned f = 1, t = 1;
3485         LookupPaths paths;
3486
3487         if (arg_scope != UNIT_FILE_SYSTEM)
3488                 return 0;
3489
3490         if (!streq(verb, "enable") &&
3491             !streq(verb, "disable") &&
3492             !streq(verb, "is-enabled"))
3493                 return 0;
3494
3495         /* Processes all SysV units, and reshuffles the array so that
3496          * afterwards only the native units remain */
3497
3498         zero(paths);
3499         r = lookup_paths_init(&paths, MANAGER_SYSTEM, false);
3500         if (r < 0)
3501                 return r;
3502
3503         r = 0;
3504
3505         for (f = 1; args[f]; f++) {
3506                 const char *name;
3507                 char *p;
3508                 bool found_native = false, found_sysv;
3509                 unsigned c = 1;
3510                 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
3511                 char **k, *l, *q = NULL;
3512                 int j;
3513                 pid_t pid;
3514                 siginfo_t status;
3515
3516                 name = args[f];
3517
3518                 if (!endswith(name, ".service"))
3519                         continue;
3520
3521                 if (path_is_absolute(name))
3522                         continue;
3523
3524                 STRV_FOREACH(k, paths.unit_path) {
3525                         p = NULL;
3526
3527                         if (!isempty(arg_root))
3528                                 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
3529                         else
3530                                 asprintf(&p, "%s/%s", *k, name);
3531
3532                         if (!p) {
3533                                 log_error("No memory");
3534                                 r = -ENOMEM;
3535                                 goto finish;
3536                         }
3537
3538                         found_native = access(p, F_OK) >= 0;
3539                         free(p);
3540
3541                         if (found_native)
3542                                 break;
3543                 }
3544
3545                 if (found_native)
3546                         continue;
3547
3548                 p = NULL;
3549                 if (!isempty(arg_root))
3550                         asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
3551                 else
3552                         asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
3553                 if (!p) {
3554                         log_error("No memory");
3555                         r = -ENOMEM;
3556                         goto finish;
3557                 }
3558
3559                 p[strlen(p) - sizeof(".service") + 1] = 0;
3560                 found_sysv = access(p, F_OK) >= 0;
3561
3562                 if (!found_sysv) {
3563                         free(p);
3564                         continue;
3565                 }
3566
3567                 /* Mark this entry, so that we don't try enabling it as native unit */
3568                 args[f] = (char*) "";
3569
3570                 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
3571
3572                 if (!isempty(arg_root))
3573                         argv[c++] = q = strappend("--root=", arg_root);
3574
3575                 argv[c++] = file_name_from_path(p);
3576                 argv[c++] =
3577                         streq(verb, "enable") ? "on" :
3578                         streq(verb, "disable") ? "off" : "--level=5";
3579                 argv[c] = NULL;
3580
3581                 l = strv_join((char**)argv, " ");
3582                 if (!l) {
3583                         log_error("No memory.");
3584                         free(q);
3585                         free(p);
3586                         r = -ENOMEM;
3587                         goto finish;
3588                 }
3589
3590                 log_info("Executing %s", l);
3591                 free(l);
3592
3593                 pid = fork();
3594                 if (pid < 0) {
3595                         log_error("Failed to fork: %m");
3596                         free(p);
3597                         free(q);
3598                         r = -errno;
3599                         goto finish;
3600                 } else if (pid == 0) {
3601                         /* Child */
3602
3603                         execv(argv[0], (char**) argv);
3604                         _exit(EXIT_FAILURE);
3605                 }
3606
3607                 free(p);
3608                 free(q);
3609
3610                 j = wait_for_terminate(pid, &status);
3611                 if (j < 0) {
3612                         log_error("Failed to wait for child: %s", strerror(-r));
3613                         r = j;
3614                         goto finish;
3615                 }
3616
3617                 if (status.si_code == CLD_EXITED) {
3618                         if (streq(verb, "is-enabled")) {
3619                                 if (status.si_status == 0) {
3620                                         if (!arg_quiet)
3621                                                 puts("enabled");
3622                                         r = 1;
3623                                 } else {
3624                                         if (!arg_quiet)
3625                                                 puts("disabled");
3626                                 }
3627
3628                         } else if (status.si_status != 0) {
3629                                 r = -EINVAL;
3630                                 goto finish;
3631                         }
3632                 } else {
3633                         r = -EPROTO;
3634                         goto finish;
3635                 }
3636         }
3637
3638 finish:
3639         lookup_paths_free(&paths);
3640
3641         /* Drop all SysV units */
3642         for (f = 1, t = 1; args[f]; f++) {
3643
3644                 if (isempty(args[f]))
3645                         continue;
3646
3647                 args[t++] = args[f];
3648         }
3649
3650         args[t] = NULL;
3651
3652 #endif
3653         return r;
3654 }
3655
3656 static int enable_unit(DBusConnection *bus, char **args) {
3657         const char *verb = args[0];
3658         UnitFileChange *changes = NULL;
3659         unsigned n_changes = 0, i;
3660         int carries_install_info = -1;
3661         DBusMessage *m = NULL, *reply = NULL;
3662         int r;
3663         DBusError error;
3664
3665         r = enable_sysv_units(args);
3666         if (r < 0)
3667                 return r;
3668
3669         if (!args[1])
3670                 return 0;
3671
3672         dbus_error_init(&error);
3673
3674         if (!bus || avoid_bus()) {
3675                 if (streq(verb, "enable")) {
3676                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3677                         carries_install_info = r;
3678                 } else if (streq(verb, "disable"))
3679                         r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3680                 else if (streq(verb, "reenable")) {
3681                         r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3682                         carries_install_info = r;
3683                 } else if (streq(verb, "link"))
3684                         r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3685                 else if (streq(verb, "preset")) {
3686                         r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3687                         carries_install_info = r;
3688                 } else if (streq(verb, "mask"))
3689                         r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3690                 else if (streq(verb, "unmask"))
3691                         r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3692                 else
3693                         assert_not_reached("Unknown verb");
3694
3695                 if (r < 0) {
3696                         log_error("Operation failed: %s", strerror(-r));
3697                         goto finish;
3698                 }
3699
3700                 if (!arg_quiet) {
3701                         for (i = 0; i < n_changes; i++) {
3702                                 if (changes[i].type == UNIT_FILE_SYMLINK)
3703                                         log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
3704                                 else
3705                                         log_info("rm '%s'", changes[i].path);
3706                         }
3707                 }
3708
3709         } else {
3710                 const char *method;
3711                 bool send_force = true, expect_carries_install_info = false;
3712                 dbus_bool_t a, b;
3713                 DBusMessageIter iter, sub, sub2;
3714
3715                 if (streq(verb, "enable")) {
3716                         method = "EnableUnitFiles";
3717                         expect_carries_install_info = true;
3718                 } else if (streq(verb, "disable")) {
3719                         method = "DisableUnitFiles";
3720                         send_force = false;
3721                 } else if (streq(verb, "reenable")) {
3722                         method = "ReenableUnitFiles";
3723                         expect_carries_install_info = true;
3724                 } else if (streq(verb, "link"))
3725                         method = "LinkUnitFiles";
3726                 else if (streq(verb, "preset")) {
3727                         method = "PresetUnitFiles";
3728                         expect_carries_install_info = true;
3729                 } else if (streq(verb, "mask"))
3730                         method = "MaskUnitFiles";
3731                 else if (streq(verb, "unmask")) {
3732                         method = "UnmaskUnitFiles";
3733                         send_force = false;
3734                 } else
3735                         assert_not_reached("Unknown verb");
3736
3737                 m = dbus_message_new_method_call(
3738                                 "org.freedesktop.systemd1",
3739                                 "/org/freedesktop/systemd1",
3740                                 "org.freedesktop.systemd1.Manager",
3741                                 method);
3742                 if (!m) {
3743                         log_error("Out of memory");
3744                         r = -ENOMEM;
3745                         goto finish;
3746                 }
3747
3748                 dbus_message_iter_init_append(m, &iter);
3749
3750                 r = bus_append_strv_iter(&iter, args+1);
3751                 if (r < 0) {
3752                         log_error("Failed to append unit files.");
3753                         goto finish;
3754                 }
3755
3756                 a = arg_runtime;
3757                 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
3758                         log_error("Failed to append runtime boolean.");
3759                         r = -ENOMEM;
3760                         goto finish;
3761                 }
3762
3763                 if (send_force) {
3764                         b = arg_force;
3765
3766                         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
3767                                 log_error("Failed to append force boolean.");
3768                                 r = -ENOMEM;
3769                                 goto finish;
3770                         }
3771                 }
3772
3773                 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3774                 if (!reply) {
3775                         log_error("Failed to issue method call: %s", bus_error_message(&error));
3776                         r = -EIO;
3777                         goto finish;
3778                 }
3779
3780                 if (!dbus_message_iter_init(reply, &iter)) {
3781                         log_error("Failed to initialize iterator.");
3782                         goto finish;
3783                 }
3784
3785                 if (expect_carries_install_info) {
3786                         r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
3787                         if (r < 0) {
3788                                 log_error("Failed to parse reply.");
3789                                 goto finish;
3790                         }
3791
3792                         carries_install_info = b;
3793                 }
3794
3795                 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3796                     dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
3797                         log_error("Failed to parse reply.");
3798                         r = -EIO;
3799                         goto finish;
3800                 }
3801
3802                 dbus_message_iter_recurse(&iter, &sub);
3803                 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3804                         const char *type, *path, *source;
3805
3806                         if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
3807                                 log_error("Failed to parse reply.");
3808                                 r = -EIO;
3809                                 goto finish;
3810                         }
3811
3812                         dbus_message_iter_recurse(&sub, &sub2);
3813
3814                         if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
3815                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
3816                             bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
3817                                 log_error("Failed to parse reply.");
3818                                 r = -EIO;
3819                                 goto finish;
3820                         }
3821
3822                         if (!arg_quiet) {
3823                                 if (streq(type, "symlink"))
3824                                         log_info("ln -s '%s' '%s'", source, path);
3825                                 else
3826                                         log_info("rm '%s'", path);
3827                         }
3828
3829                         dbus_message_iter_next(&sub);
3830                 }
3831
3832                 /* Try to reload if enabeld */
3833                 if (!arg_no_reload)
3834                         r = daemon_reload(bus, args);
3835         }
3836
3837         if (carries_install_info == 0)
3838                 log_warning("Warning: unit files do not carry install information. No operation executed.");
3839
3840 finish:
3841         if (m)
3842                 dbus_message_unref(m);
3843
3844         if (reply)
3845                 dbus_message_unref(reply);
3846
3847         unit_file_changes_free(changes, n_changes);
3848
3849         dbus_error_free(&error);
3850         return r;
3851 }
3852
3853 static int unit_is_enabled(DBusConnection *bus, char **args) {
3854         DBusError error;
3855         int r;
3856         DBusMessage *m = NULL, *reply = NULL;
3857         bool enabled;
3858         char **name;
3859
3860         dbus_error_init(&error);
3861
3862         r = enable_sysv_units(args);
3863         if (r < 0)
3864                 return r;
3865
3866         enabled = r > 0;
3867
3868         if (!bus || avoid_bus()) {
3869
3870                 STRV_FOREACH(name, args+1) {
3871                         UnitFileState state;
3872
3873                         state = unit_file_get_state(arg_scope, arg_root, *name);
3874                         if (state < 0) {
3875                                 r = state;
3876                                 goto finish;
3877                         }
3878
3879                         if (state == UNIT_FILE_ENABLED ||
3880                             state == UNIT_FILE_ENABLED_RUNTIME ||
3881                             state == UNIT_FILE_STATIC)
3882                                 enabled = true;
3883
3884                         if (!arg_quiet)
3885                                 puts(unit_file_state_to_string(state));
3886                 }
3887
3888         } else {
3889                 STRV_FOREACH(name, args+1) {
3890                         const char *s;
3891
3892                         m = dbus_message_new_method_call(
3893                                         "org.freedesktop.systemd1",
3894                                         "/org/freedesktop/systemd1",
3895                                         "org.freedesktop.systemd1.Manager",
3896                                         "GetUnitFileState");
3897                         if (!m) {
3898                                 log_error("Out of memory");
3899                                 r = -ENOMEM;
3900                                 goto finish;
3901                         }
3902
3903                         if (!dbus_message_append_args(m,
3904                                                       DBUS_TYPE_STRING, name,
3905                                                       DBUS_TYPE_INVALID)) {
3906                                 log_error("Could not append arguments to message.");
3907                                 r = -ENOMEM;
3908                                 goto finish;
3909                         }
3910
3911                         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3912                         if (!reply) {
3913                                 log_error("Failed to issue method call: %s", bus_error_message(&error));
3914                                 r = -EIO;
3915                                 goto finish;
3916                         }
3917
3918                         if (!dbus_message_get_args(reply, &error,
3919                                                    DBUS_TYPE_STRING, &s,
3920                                                    DBUS_TYPE_INVALID)) {
3921                                 log_error("Failed to parse reply: %s", bus_error_message(&error));
3922                                 r = -EIO;
3923                                 goto finish;
3924                         }
3925
3926                         dbus_message_unref(m);
3927                         dbus_message_unref(reply);
3928                         m = reply = NULL;
3929
3930                         if (streq(s, "enabled") ||
3931                             streq(s, "enabled-runtime") ||
3932                             streq(s, "static"))
3933                                 enabled = true;
3934
3935                         if (!arg_quiet)
3936                                 puts(s);
3937                 }
3938         }
3939
3940         r = enabled ? 0 : 1;
3941
3942 finish:
3943         if (m)
3944                 dbus_message_unref(m);
3945
3946         if (reply)
3947                 dbus_message_unref(reply);
3948
3949         dbus_error_free(&error);
3950         return r;
3951 }
3952
3953 static int systemctl_help(void) {
3954
3955         pager_open_if_enabled();
3956
3957         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
3958                "Query or send control commands to the systemd manager.\n\n"
3959                "  -h --help           Show this help\n"
3960                "     --version        Show package version\n"
3961                "  -t --type=TYPE      List only units of a particular type\n"
3962                "  -p --property=NAME  Show only properties by this name\n"
3963                "  -a --all            Show all units/properties, including dead/empty ones\n"
3964                "     --failed         Show only failed units\n"
3965                "     --full           Don't ellipsize unit names on output\n"
3966                "     --fail           When queueing a new job, fail if conflicting jobs are\n"
3967                "                      pending\n"
3968                "     --ignore-dependencies\n"
3969                "                      When queueing a new job, ignore all its dependencies\n"
3970                "     --kill-who=WHO   Who to send signal to\n"
3971                "  -s --signal=SIGNAL  Which signal to send\n"
3972                "  -H --host=[USER@]HOST\n"
3973                "                      Show information for remote host\n"
3974                "  -P --privileged     Acquire privileges before execution\n"
3975                "  -q --quiet          Suppress output\n"
3976                "     --no-block       Do not wait until operation finished\n"
3977                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
3978                "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
3979                "                      configuration\n"
3980                "     --no-legend      Do not print a legend (column headers and hints)\n"
3981                "     --no-pager       Do not pipe output into a pager\n"
3982                "     --no-ask-password\n"
3983                "                      Do not ask for system passwords\n"
3984                "     --order          When generating graph for dot, show only order\n"
3985                "     --require        When generating graph for dot, show only requirement\n"
3986                "     --system         Connect to system manager\n"
3987                "     --user           Connect to user service manager\n"
3988                "     --global         Enable/disable unit files globally\n"
3989                "  -f --force          When enabling unit files, override existing symlinks\n"
3990                "                      When shutting down, execute action immediately\n"
3991                "     --root=PATH      Enable unit files in the specified root directory\n"
3992                "     --runtime        Enable unit files only temporarily until next reboot\n"
3993                "  -n --lines=INTEGER  Journal entries to show\n"
3994                "     --follow         Follow journal\n"
3995                "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
3996                "                      verbose, export, json, cat)\n\n"
3997                "Unit Commands:\n"
3998                "  list-units                      List loaded units\n"
3999                "  start [NAME...]                 Start (activate) one or more units\n"
4000                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
4001                "  reload [NAME...]                Reload one or more units\n"
4002                "  restart [NAME...]               Start or restart one or more units\n"
4003                "  try-restart [NAME...]           Restart one or more units if active\n"
4004                "  reload-or-restart [NAME...]     Reload one or more units is possible,\n"
4005                "                                  otherwise start or restart\n"
4006                "  reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
4007                "                                  otherwise restart if active\n"
4008                "  isolate [NAME]                  Start one unit and stop all others\n"
4009                "  kill [NAME...]                  Send signal to processes of a unit\n"
4010                "  is-active [NAME...]             Check whether units are active\n"
4011                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
4012                "  show [NAME...|JOB...]           Show properties of one or more\n"
4013                "                                  units/jobs or the manager\n"
4014                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
4015                "                                  units\n"
4016                "  load [NAME...]                  Load one or more units\n\n"
4017                "Unit File Commands:\n"
4018                "  list-unit-files                 List installed unit files\n"
4019                "  enable [NAME...]                Enable one or more unit files\n"
4020                "  disable [NAME...]               Disable one or more unit files\n"
4021                "  reenable [NAME...]              Reenable one or more unit files\n"
4022                "  preset [NAME...]                Enable/disable one or more unit files\n"
4023                "                                  based on preset configuration\n"
4024                "  mask [NAME...]                  Mask one or more units\n"
4025                "  unmask [NAME...]                Unmask one or more units\n"
4026                "  link [PATH...]                  Link one or more units files into\n"
4027                "                                  the search path\n"
4028                "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
4029                "Job Commands:\n"
4030                "  list-jobs                       List jobs\n"
4031                "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
4032                "Status Commands:\n"
4033                "  dump                            Dump server status\n"
4034                "  dot                             Dump dependency graph for dot(1)\n\n"
4035                "Snapshot Commands:\n"
4036                "  snapshot [NAME]                 Create a snapshot\n"
4037                "  delete [NAME...]                Remove one or more snapshots\n\n"
4038                "Environment Commands:\n"
4039                "  show-environment                Dump environment\n"
4040                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
4041                "  unset-environment [NAME...]     Unset one or more environment variables\n\n"
4042                "Manager Lifecycle Commands:\n"
4043                "  daemon-reload                   Reload systemd manager configuration\n"
4044                "  daemon-reexec                   Reexecute systemd manager\n\n"
4045                "System Commands:\n"
4046                "  default                         Enter system default mode\n"
4047                "  rescue                          Enter system rescue mode\n"
4048                "  emergency                       Enter system emergency mode\n"
4049                "  halt                            Shut down and halt the system\n"
4050                "  poweroff                        Shut down and power-off the system\n"
4051                "  reboot                          Shut down and reboot the system\n"
4052                "  kexec                           Shut down and reboot the system with kexec\n"
4053                "  exit                            Ask for user instance termination\n",
4054                program_invocation_short_name);
4055
4056         return 0;
4057 }
4058
4059 static int halt_help(void) {
4060
4061         printf("%s [OPTIONS...]\n\n"
4062                "%s the system.\n\n"
4063                "     --help      Show this help\n"
4064                "     --halt      Halt the machine\n"
4065                "  -p --poweroff  Switch off the machine\n"
4066                "     --reboot    Reboot the machine\n"
4067                "  -f --force     Force immediate halt/power-off/reboot\n"
4068                "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
4069                "  -d --no-wtmp   Don't write wtmp record\n"
4070                "  -n --no-sync   Don't sync before halt/power-off/reboot\n"
4071                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
4072                program_invocation_short_name,
4073                arg_action == ACTION_REBOOT   ? "Reboot" :
4074                arg_action == ACTION_POWEROFF ? "Power off" :
4075                                                "Halt");
4076
4077         return 0;
4078 }
4079
4080 static int shutdown_help(void) {
4081
4082         printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
4083                "Shut down the system.\n\n"
4084                "     --help      Show this help\n"
4085                "  -H --halt      Halt the machine\n"
4086                "  -P --poweroff  Power-off the machine\n"
4087                "  -r --reboot    Reboot the machine\n"
4088                "  -h             Equivalent to --poweroff, overriden by --halt\n"
4089                "  -k             Don't halt/power-off/reboot, just send warnings\n"
4090                "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
4091                "  -c             Cancel a pending shutdown\n",
4092                program_invocation_short_name);
4093
4094         return 0;
4095 }
4096
4097 static int telinit_help(void) {
4098
4099         printf("%s [OPTIONS...] {COMMAND}\n\n"
4100                "Send control commands to the init daemon.\n\n"
4101                "     --help      Show this help\n"
4102                "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
4103                "Commands:\n"
4104                "  0              Power-off the machine\n"
4105                "  6              Reboot the machine\n"
4106                "  2, 3, 4, 5     Start runlevelX.target unit\n"
4107                "  1, s, S        Enter rescue mode\n"
4108                "  q, Q           Reload init daemon configuration\n"
4109                "  u, U           Reexecute init daemon\n",
4110                program_invocation_short_name);
4111
4112         return 0;
4113 }
4114
4115 static int runlevel_help(void) {
4116
4117         printf("%s [OPTIONS...]\n\n"
4118                "Prints the previous and current runlevel of the init system.\n\n"
4119                "     --help      Show this help\n",
4120                program_invocation_short_name);
4121
4122         return 0;
4123 }
4124
4125 static int systemctl_parse_argv(int argc, char *argv[]) {
4126
4127         enum {
4128                 ARG_FAIL = 0x100,
4129                 ARG_IGNORE_DEPENDENCIES,
4130                 ARG_VERSION,
4131                 ARG_USER,
4132                 ARG_SYSTEM,
4133                 ARG_GLOBAL,
4134                 ARG_NO_BLOCK,
4135                 ARG_NO_LEGEND,
4136                 ARG_NO_PAGER,
4137                 ARG_NO_WALL,
4138                 ARG_ORDER,
4139                 ARG_REQUIRE,
4140                 ARG_ROOT,
4141                 ARG_FULL,
4142                 ARG_NO_RELOAD,
4143                 ARG_KILL_MODE,
4144                 ARG_KILL_WHO,
4145                 ARG_NO_ASK_PASSWORD,
4146                 ARG_FAILED,
4147                 ARG_RUNTIME,
4148                 ARG_FOLLOW
4149         };
4150
4151         static const struct option options[] = {
4152                 { "help",      no_argument,       NULL, 'h'           },
4153                 { "version",   no_argument,       NULL, ARG_VERSION   },
4154                 { "type",      required_argument, NULL, 't'           },
4155                 { "property",  required_argument, NULL, 'p'           },
4156                 { "all",       no_argument,       NULL, 'a'           },
4157                 { "failed",    no_argument,       NULL, ARG_FAILED    },
4158                 { "full",      no_argument,       NULL, ARG_FULL      },
4159                 { "fail",      no_argument,       NULL, ARG_FAIL      },
4160                 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
4161                 { "user",      no_argument,       NULL, ARG_USER      },
4162                 { "system",    no_argument,       NULL, ARG_SYSTEM    },
4163                 { "global",    no_argument,       NULL, ARG_GLOBAL    },
4164                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
4165                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
4166                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
4167                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
4168                 { "quiet",     no_argument,       NULL, 'q'           },
4169                 { "order",     no_argument,       NULL, ARG_ORDER     },
4170                 { "require",   no_argument,       NULL, ARG_REQUIRE   },
4171                 { "root",      required_argument, NULL, ARG_ROOT      },
4172                 { "force",     no_argument,       NULL, 'f'           },
4173                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
4174                 { "kill-mode", required_argument, NULL, ARG_KILL_MODE }, /* undocumented on purpose */
4175                 { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
4176                 { "signal",    required_argument, NULL, 's'           },
4177                 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
4178                 { "host",      required_argument, NULL, 'H'           },
4179                 { "privileged",no_argument,       NULL, 'P'           },
4180                 { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
4181                 { "lines",     required_argument, NULL, 'n'           },
4182                 { "follow",    no_argument,       NULL, ARG_FOLLOW    },
4183                 { "output",    required_argument, NULL, 'o'           },
4184                 { NULL,        0,                 NULL, 0             }
4185         };
4186
4187         int c;
4188
4189         assert(argc >= 0);
4190         assert(argv);
4191
4192         /* Only when running as systemctl we ask for passwords */
4193         arg_ask_password = true;
4194
4195         while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:", options, NULL)) >= 0) {
4196
4197                 switch (c) {
4198
4199                 case 'h':
4200                         systemctl_help();
4201                         return 0;
4202
4203                 case ARG_VERSION:
4204                         puts(PACKAGE_STRING);
4205                         puts(DISTRIBUTION);
4206                         puts(SYSTEMD_FEATURES);
4207                         return 0;
4208
4209                 case 't':
4210                         arg_type = optarg;
4211                         break;
4212
4213                 case 'p': {
4214                         char **l;
4215
4216                         if (!(l = strv_append(arg_property, optarg)))
4217                                 return -ENOMEM;
4218
4219                         strv_free(arg_property);
4220                         arg_property = l;
4221
4222                         /* If the user asked for a particular
4223                          * property, show it to him, even if it is
4224                          * empty. */
4225                         arg_all = true;
4226                         break;
4227                 }
4228
4229                 case 'a':
4230                         arg_all = true;
4231                         break;
4232
4233                 case ARG_FAIL:
4234                         arg_job_mode = "fail";
4235                         break;
4236
4237                 case ARG_IGNORE_DEPENDENCIES:
4238                         arg_job_mode = "ignore-dependencies";
4239                         break;
4240
4241                 case ARG_USER:
4242                         arg_scope = UNIT_FILE_USER;
4243                         break;
4244
4245                 case ARG_SYSTEM:
4246                         arg_scope = UNIT_FILE_SYSTEM;
4247                         break;
4248
4249                 case ARG_GLOBAL:
4250                         arg_scope = UNIT_FILE_GLOBAL;
4251                         break;
4252
4253                 case ARG_NO_BLOCK:
4254                         arg_no_block = true;
4255                         break;
4256
4257                 case ARG_NO_LEGEND:
4258                         arg_no_legend = true;
4259                         break;
4260
4261                 case ARG_NO_PAGER:
4262                         arg_no_pager = true;
4263                         break;
4264
4265                 case ARG_NO_WALL:
4266                         arg_no_wall = true;
4267                         break;
4268
4269                 case ARG_ORDER:
4270                         arg_dot = DOT_ORDER;
4271                         break;
4272
4273                 case ARG_REQUIRE:
4274                         arg_dot = DOT_REQUIRE;
4275                         break;
4276
4277                 case ARG_ROOT:
4278                         arg_root = optarg;
4279                         break;
4280
4281                 case ARG_FULL:
4282                         arg_full = true;
4283                         break;
4284
4285                 case ARG_FAILED:
4286                         arg_failed = true;
4287                         break;
4288
4289                 case 'q':
4290                         arg_quiet = true;
4291                         break;
4292
4293                 case 'f':
4294                         arg_force = true;
4295                         break;
4296
4297                 case ARG_NO_RELOAD:
4298                         arg_no_reload = true;
4299                         break;
4300
4301                 case ARG_KILL_WHO:
4302                         arg_kill_who = optarg;
4303                         break;
4304
4305                 case ARG_KILL_MODE:
4306                         arg_kill_mode = optarg;
4307                         break;
4308
4309                 case 's':
4310                         if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
4311                                 log_error("Failed to parse signal string %s.", optarg);
4312                                 return -EINVAL;
4313                         }
4314                         break;
4315
4316                 case ARG_NO_ASK_PASSWORD:
4317                         arg_ask_password = false;
4318                         break;
4319
4320                 case 'P':
4321                         arg_transport = TRANSPORT_POLKIT;
4322                         break;
4323
4324                 case 'H':
4325                         arg_transport = TRANSPORT_SSH;
4326                         arg_host = optarg;
4327                         break;
4328
4329                 case ARG_RUNTIME:
4330                         arg_runtime = true;
4331                         break;
4332
4333                 case 'n':
4334                         if (safe_atou(optarg, &arg_lines) < 0) {
4335                                 log_error("Failed to parse lines '%s'", optarg);
4336                                 return -EINVAL;
4337                         }
4338                         break;
4339
4340                 case ARG_FOLLOW:
4341                         arg_follow = true;
4342                         break;
4343
4344                 case 'o':
4345                         arg_output = output_mode_from_string(optarg);
4346                         if (arg_output < 0) {
4347                                 log_error("Unknown output '%s'.", optarg);
4348                                 return -EINVAL;
4349                         }
4350                         break;
4351
4352                 case '?':
4353                         return -EINVAL;
4354
4355                 default:
4356                         log_error("Unknown option code %c", c);
4357                         return -EINVAL;
4358                 }
4359         }
4360
4361         if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
4362                 log_error("Cannot access user instance remotely.");
4363                 return -EINVAL;
4364         }
4365
4366         return 1;
4367 }
4368
4369 static int halt_parse_argv(int argc, char *argv[]) {
4370
4371         enum {
4372                 ARG_HELP = 0x100,
4373                 ARG_HALT,
4374                 ARG_REBOOT,
4375                 ARG_NO_WALL
4376         };
4377
4378         static const struct option options[] = {
4379                 { "help",      no_argument,       NULL, ARG_HELP    },
4380                 { "halt",      no_argument,       NULL, ARG_HALT    },
4381                 { "poweroff",  no_argument,       NULL, 'p'         },
4382                 { "reboot",    no_argument,       NULL, ARG_REBOOT  },
4383                 { "force",     no_argument,       NULL, 'f'         },
4384                 { "wtmp-only", no_argument,       NULL, 'w'         },
4385                 { "no-wtmp",   no_argument,       NULL, 'd'         },
4386                 { "no-sync",   no_argument,       NULL, 'n'         },
4387                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4388                 { NULL,        0,                 NULL, 0           }
4389         };
4390
4391         int c, runlevel;
4392
4393         assert(argc >= 0);
4394         assert(argv);
4395
4396         if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4397                 if (runlevel == '0' || runlevel == '6')
4398                         arg_immediate = true;
4399
4400         while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
4401                 switch (c) {
4402
4403                 case ARG_HELP:
4404                         halt_help();
4405                         return 0;
4406
4407                 case ARG_HALT:
4408                         arg_action = ACTION_HALT;
4409                         break;
4410
4411                 case 'p':
4412                         if (arg_action != ACTION_REBOOT)
4413                                 arg_action = ACTION_POWEROFF;
4414                         break;
4415
4416                 case ARG_REBOOT:
4417                         arg_action = ACTION_REBOOT;
4418                         break;
4419
4420                 case 'f':
4421                         arg_immediate = true;
4422                         break;
4423
4424                 case 'w':
4425                         arg_dry = true;
4426                         break;
4427
4428                 case 'd':
4429                         arg_no_wtmp = true;
4430                         break;
4431
4432                 case 'n':
4433                         arg_no_sync = true;
4434                         break;
4435
4436                 case ARG_NO_WALL:
4437                         arg_no_wall = true;
4438                         break;
4439
4440                 case 'i':
4441                 case 'h':
4442                         /* Compatibility nops */
4443                         break;
4444
4445                 case '?':
4446                         return -EINVAL;
4447
4448                 default:
4449                         log_error("Unknown option code %c", c);
4450                         return -EINVAL;
4451                 }
4452         }
4453
4454         if (optind < argc) {
4455                 log_error("Too many arguments.");
4456                 return -EINVAL;
4457         }
4458
4459         return 1;
4460 }
4461
4462 static int parse_time_spec(const char *t, usec_t *_u) {
4463         assert(t);
4464         assert(_u);
4465
4466         if (streq(t, "now"))
4467                 *_u = 0;
4468         else if (!strchr(t, ':')) {
4469                 uint64_t u;
4470
4471                 if (safe_atou64(t, &u) < 0)
4472                         return -EINVAL;
4473
4474                 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
4475         } else {
4476                 char *e = NULL;
4477                 long hour, minute;
4478                 struct tm tm;
4479                 time_t s;
4480                 usec_t n;
4481
4482                 errno = 0;
4483                 hour = strtol(t, &e, 10);
4484                 if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
4485                         return -EINVAL;
4486
4487                 minute = strtol(e+1, &e, 10);
4488                 if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
4489                         return -EINVAL;
4490
4491                 n = now(CLOCK_REALTIME);
4492                 s = (time_t) (n / USEC_PER_SEC);
4493
4494                 zero(tm);
4495                 assert_se(localtime_r(&s, &tm));
4496
4497                 tm.tm_hour = (int) hour;
4498                 tm.tm_min = (int) minute;
4499                 tm.tm_sec = 0;
4500
4501                 assert_se(s = mktime(&tm));
4502
4503                 *_u = (usec_t) s * USEC_PER_SEC;
4504
4505                 while (*_u <= n)
4506                         *_u += USEC_PER_DAY;
4507         }
4508
4509         return 0;
4510 }
4511
4512 static int shutdown_parse_argv(int argc, char *argv[]) {
4513
4514         enum {
4515                 ARG_HELP = 0x100,
4516                 ARG_NO_WALL
4517         };
4518
4519         static const struct option options[] = {
4520                 { "help",      no_argument,       NULL, ARG_HELP    },
4521                 { "halt",      no_argument,       NULL, 'H'         },
4522                 { "poweroff",  no_argument,       NULL, 'P'         },
4523                 { "reboot",    no_argument,       NULL, 'r'         },
4524                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4525                 { NULL,        0,                 NULL, 0           }
4526         };
4527
4528         int c, r;
4529
4530         assert(argc >= 0);
4531         assert(argv);
4532
4533         while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
4534                 switch (c) {
4535
4536                 case ARG_HELP:
4537                         shutdown_help();
4538                         return 0;
4539
4540                 case 'H':
4541                         arg_action = ACTION_HALT;
4542                         break;
4543
4544                 case 'P':
4545                         arg_action = ACTION_POWEROFF;
4546                         break;
4547
4548                 case 'r':
4549                         if (kexec_loaded())
4550                                 arg_action = ACTION_KEXEC;
4551                         else
4552                                 arg_action = ACTION_REBOOT;
4553                         break;
4554
4555                 case 'h':
4556                         if (arg_action != ACTION_HALT)
4557                                 arg_action = ACTION_POWEROFF;
4558                         break;
4559
4560                 case 'k':
4561                         arg_dry = true;
4562                         break;
4563
4564                 case ARG_NO_WALL:
4565                         arg_no_wall = true;
4566                         break;
4567
4568                 case 't':
4569                 case 'a':
4570                         /* Compatibility nops */
4571                         break;
4572
4573                 case 'c':
4574                         arg_action = ACTION_CANCEL_SHUTDOWN;
4575                         break;
4576
4577                 case '?':
4578                         return -EINVAL;
4579
4580                 default:
4581                         log_error("Unknown option code %c", c);
4582                         return -EINVAL;
4583                 }
4584         }
4585
4586         if (argc > optind) {
4587                 if ((r = parse_time_spec(argv[optind], &arg_when)) < 0) {
4588                         log_error("Failed to parse time specification: %s", argv[optind]);
4589                         return r;
4590                 }
4591         } else
4592                 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
4593
4594         /* We skip the time argument */
4595         if (argc > optind + 1)
4596                 arg_wall = argv + optind + 1;
4597
4598         optind = argc;
4599
4600         return 1;
4601 }
4602
4603 static int telinit_parse_argv(int argc, char *argv[]) {
4604
4605         enum {
4606                 ARG_HELP = 0x100,
4607                 ARG_NO_WALL
4608         };
4609
4610         static const struct option options[] = {
4611                 { "help",      no_argument,       NULL, ARG_HELP    },
4612                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
4613                 { NULL,        0,                 NULL, 0           }
4614         };
4615
4616         static const struct {
4617                 char from;
4618                 enum action to;
4619         } table[] = {
4620                 { '0', ACTION_POWEROFF },
4621                 { '6', ACTION_REBOOT },
4622                 { '1', ACTION_RESCUE },
4623                 { '2', ACTION_RUNLEVEL2 },
4624                 { '3', ACTION_RUNLEVEL3 },
4625                 { '4', ACTION_RUNLEVEL4 },
4626                 { '5', ACTION_RUNLEVEL5 },
4627                 { 's', ACTION_RESCUE },
4628                 { 'S', ACTION_RESCUE },
4629                 { 'q', ACTION_RELOAD },
4630                 { 'Q', ACTION_RELOAD },
4631                 { 'u', ACTION_REEXEC },
4632                 { 'U', ACTION_REEXEC }
4633         };
4634
4635         unsigned i;
4636         int c;
4637
4638         assert(argc >= 0);
4639         assert(argv);
4640
4641         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4642                 switch (c) {
4643
4644                 case ARG_HELP:
4645                         telinit_help();
4646                         return 0;
4647
4648                 case ARG_NO_WALL:
4649                         arg_no_wall = true;
4650                         break;
4651
4652                 case '?':
4653                         return -EINVAL;
4654
4655                 default:
4656                         log_error("Unknown option code %c", c);
4657                         return -EINVAL;
4658                 }
4659         }
4660
4661         if (optind >= argc) {
4662                 telinit_help();
4663                 return -EINVAL;
4664         }
4665
4666         if (optind + 1 < argc) {
4667                 log_error("Too many arguments.");
4668                 return -EINVAL;
4669         }
4670
4671         if (strlen(argv[optind]) != 1) {
4672                 log_error("Expected single character argument.");
4673                 return -EINVAL;
4674         }
4675
4676         for (i = 0; i < ELEMENTSOF(table); i++)
4677                 if (table[i].from == argv[optind][0])
4678                         break;
4679
4680         if (i >= ELEMENTSOF(table)) {
4681                 log_error("Unknown command %s.", argv[optind]);
4682                 return -EINVAL;
4683         }
4684
4685         arg_action = table[i].to;
4686
4687         optind ++;
4688
4689         return 1;
4690 }
4691
4692 static int runlevel_parse_argv(int argc, char *argv[]) {
4693
4694         enum {
4695                 ARG_HELP = 0x100,
4696         };
4697
4698         static const struct option options[] = {
4699                 { "help",      no_argument,       NULL, ARG_HELP    },
4700                 { NULL,        0,                 NULL, 0           }
4701         };
4702
4703         int c;
4704
4705         assert(argc >= 0);
4706         assert(argv);
4707
4708         while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4709                 switch (c) {
4710
4711                 case ARG_HELP:
4712                         runlevel_help();
4713                         return 0;
4714
4715                 case '?':
4716                         return -EINVAL;
4717
4718                 default:
4719                         log_error("Unknown option code %c", c);
4720                         return -EINVAL;
4721                 }
4722         }
4723
4724         if (optind < argc) {
4725                 log_error("Too many arguments.");
4726                 return -EINVAL;
4727         }
4728
4729         return 1;
4730 }
4731
4732 static int parse_argv(int argc, char *argv[]) {
4733         assert(argc >= 0);
4734         assert(argv);
4735
4736         if (program_invocation_short_name) {
4737
4738                 if (strstr(program_invocation_short_name, "halt")) {
4739                         arg_action = ACTION_HALT;
4740                         return halt_parse_argv(argc, argv);
4741                 } else if (strstr(program_invocation_short_name, "poweroff")) {
4742                         arg_action = ACTION_POWEROFF;
4743                         return halt_parse_argv(argc, argv);
4744                 } else if (strstr(program_invocation_short_name, "reboot")) {
4745                         if (kexec_loaded())
4746                                 arg_action = ACTION_KEXEC;
4747                         else
4748                                 arg_action = ACTION_REBOOT;
4749                         return halt_parse_argv(argc, argv);
4750                 } else if (strstr(program_invocation_short_name, "shutdown")) {
4751                         arg_action = ACTION_POWEROFF;
4752                         return shutdown_parse_argv(argc, argv);
4753                 } else if (strstr(program_invocation_short_name, "init")) {
4754
4755                         if (sd_booted() > 0) {
4756                                 arg_action = ACTION_INVALID;
4757                                 return telinit_parse_argv(argc, argv);
4758                         } else {
4759                                 /* Hmm, so some other init system is
4760                                  * running, we need to forward this
4761                                  * request to it. For now we simply
4762                                  * guess that it is Upstart. */
4763
4764                                 execv("/lib/upstart/telinit", argv);
4765
4766                                 log_error("Couldn't find an alternative telinit implementation to spawn.");
4767                                 return -EIO;
4768                         }
4769
4770                 } else if (strstr(program_invocation_short_name, "runlevel")) {
4771                         arg_action = ACTION_RUNLEVEL;
4772                         return runlevel_parse_argv(argc, argv);
4773                 }
4774         }
4775
4776         arg_action = ACTION_SYSTEMCTL;
4777         return systemctl_parse_argv(argc, argv);
4778 }
4779
4780 static int action_to_runlevel(void) {
4781
4782         static const char table[_ACTION_MAX] = {
4783                 [ACTION_HALT] =      '0',
4784                 [ACTION_POWEROFF] =  '0',
4785                 [ACTION_REBOOT] =    '6',
4786                 [ACTION_RUNLEVEL2] = '2',
4787                 [ACTION_RUNLEVEL3] = '3',
4788                 [ACTION_RUNLEVEL4] = '4',
4789                 [ACTION_RUNLEVEL5] = '5',
4790                 [ACTION_RESCUE] =    '1'
4791         };
4792
4793         assert(arg_action < _ACTION_MAX);
4794
4795         return table[arg_action];
4796 }
4797
4798 static int talk_upstart(void) {
4799         DBusMessage *m = NULL, *reply = NULL;
4800         DBusError error;
4801         int previous, rl, r;
4802         char
4803                 env1_buf[] = "RUNLEVEL=X",
4804                 env2_buf[] = "PREVLEVEL=X";
4805         char *env1 = env1_buf, *env2 = env2_buf;
4806         const char *emit = "runlevel";
4807         dbus_bool_t b_false = FALSE;
4808         DBusMessageIter iter, sub;
4809         DBusConnection *bus;
4810
4811         dbus_error_init(&error);
4812
4813         if (!(rl = action_to_runlevel()))
4814                 return 0;
4815
4816         if (utmp_get_runlevel(&previous, NULL) < 0)
4817                 previous = 'N';
4818
4819         if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
4820                 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
4821                         r = 0;
4822                         goto finish;
4823                 }
4824
4825                 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
4826                 r = -EIO;
4827                 goto finish;
4828         }
4829
4830         if ((r = bus_check_peercred(bus)) < 0) {
4831                 log_error("Failed to verify owner of bus.");
4832                 goto finish;
4833         }
4834
4835         if (!(m = dbus_message_new_method_call(
4836                               "com.ubuntu.Upstart",
4837                               "/com/ubuntu/Upstart",
4838                               "com.ubuntu.Upstart0_6",
4839                               "EmitEvent"))) {
4840
4841                 log_error("Could not allocate message.");
4842                 r = -ENOMEM;
4843                 goto finish;
4844         }
4845
4846         dbus_message_iter_init_append(m, &iter);
4847
4848         env1_buf[sizeof(env1_buf)-2] = rl;
4849         env2_buf[sizeof(env2_buf)-2] = previous;
4850
4851         if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
4852             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
4853             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
4854             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
4855             !dbus_message_iter_close_container(&iter, &sub) ||
4856             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
4857                 log_error("Could not append arguments to message.");
4858                 r = -ENOMEM;
4859                 goto finish;
4860         }
4861
4862         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4863
4864                 if (error_is_no_service(&error)) {
4865                         r = -EADDRNOTAVAIL;
4866                         goto finish;
4867                 }
4868
4869                 log_error("Failed to issue method call: %s", bus_error_message(&error));
4870                 r = -EIO;
4871                 goto finish;
4872         }
4873
4874         r = 1;
4875
4876 finish:
4877         if (m)
4878                 dbus_message_unref(m);
4879
4880         if (reply)
4881                 dbus_message_unref(reply);
4882
4883         if (bus) {
4884                 dbus_connection_flush(bus);
4885                 dbus_connection_close(bus);
4886                 dbus_connection_unref(bus);
4887         }
4888
4889         dbus_error_free(&error);
4890
4891         return r;
4892 }
4893
4894 static int talk_initctl(void) {
4895         struct init_request request;
4896         int r, fd;
4897         char rl;
4898
4899         if (!(rl = action_to_runlevel()))
4900                 return 0;
4901
4902         zero(request);
4903         request.magic = INIT_MAGIC;
4904         request.sleeptime = 0;
4905         request.cmd = INIT_CMD_RUNLVL;
4906         request.runlevel = rl;
4907
4908         if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
4909
4910                 if (errno == ENOENT)
4911                         return 0;
4912
4913                 log_error("Failed to open "INIT_FIFO": %m");
4914                 return -errno;
4915         }
4916
4917         errno = 0;
4918         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
4919         close_nointr_nofail(fd);
4920
4921         if (r < 0) {
4922                 log_error("Failed to write to "INIT_FIFO": %m");
4923                 return errno ? -errno : -EIO;
4924         }
4925
4926         return 1;
4927 }
4928
4929 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
4930
4931         static const struct {
4932                 const char* verb;
4933                 const enum {
4934                         MORE,
4935                         LESS,
4936                         EQUAL
4937                 } argc_cmp;
4938                 const int argc;
4939                 int (* const dispatch)(DBusConnection *bus, char **args);
4940         } verbs[] = {
4941                 { "list-units",            LESS,  1, list_units        },
4942                 { "list-unit-files",       EQUAL, 1, list_unit_files   },
4943                 { "list-jobs",             EQUAL, 1, list_jobs         },
4944                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
4945                 { "load",                  MORE,  2, load_unit         },
4946                 { "cancel",                MORE,  2, cancel_job        },
4947                 { "start",                 MORE,  2, start_unit        },
4948                 { "stop",                  MORE,  2, start_unit        },
4949                 { "condstop",              MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
4950                 { "reload",                MORE,  2, start_unit        },
4951                 { "restart",               MORE,  2, start_unit        },
4952                 { "try-restart",           MORE,  2, start_unit        },
4953                 { "reload-or-restart",     MORE,  2, start_unit        },
4954                 { "reload-or-try-restart", MORE,  2, start_unit        },
4955                 { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
4956                 { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
4957                 { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
4958                 { "isolate",               EQUAL, 2, start_unit        },
4959                 { "kill",                  MORE,  2, kill_unit         },
4960                 { "is-active",             MORE,  2, check_unit        },
4961                 { "check",                 MORE,  2, check_unit        },
4962                 { "show",                  MORE,  1, show              },
4963                 { "status",                MORE,  2, show              },
4964                 { "dump",                  EQUAL, 1, dump              },
4965                 { "dot",                   EQUAL, 1, dot               },
4966                 { "snapshot",              LESS,  2, snapshot          },
4967                 { "delete",                MORE,  2, delete_snapshot   },
4968                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
4969                 { "daemon-reexec",         EQUAL, 1, daemon_reload     },
4970                 { "show-environment",      EQUAL, 1, show_enviroment   },
4971                 { "set-environment",       MORE,  2, set_environment   },
4972                 { "unset-environment",     MORE,  2, set_environment   },
4973                 { "halt",                  EQUAL, 1, start_special     },
4974                 { "poweroff",              EQUAL, 1, start_special     },
4975                 { "reboot",                EQUAL, 1, start_special     },
4976                 { "kexec",                 EQUAL, 1, start_special     },
4977                 { "default",               EQUAL, 1, start_special     },
4978                 { "rescue",                EQUAL, 1, start_special     },
4979                 { "emergency",             EQUAL, 1, start_special     },
4980                 { "exit",                  EQUAL, 1, start_special     },
4981                 { "reset-failed",          MORE,  1, reset_failed      },
4982                 { "enable",                MORE,  2, enable_unit       },
4983                 { "disable",               MORE,  2, enable_unit       },
4984                 { "is-enabled",            MORE,  2, unit_is_enabled   },
4985                 { "reenable",              MORE,  2, enable_unit       },
4986                 { "preset",                MORE,  2, enable_unit       },
4987                 { "mask",                  MORE,  2, enable_unit       },
4988                 { "unmask",                MORE,  2, enable_unit       },
4989                 { "link",                  MORE,  2, enable_unit       }
4990         };
4991
4992         int left;
4993         unsigned i;
4994
4995         assert(argc >= 0);
4996         assert(argv);
4997         assert(error);
4998
4999         left = argc - optind;
5000
5001         if (left <= 0)
5002                 /* Special rule: no arguments means "list-units" */
5003                 i = 0;
5004         else {
5005                 if (streq(argv[optind], "help")) {
5006                         systemctl_help();
5007                         return 0;
5008                 }
5009
5010                 for (i = 0; i < ELEMENTSOF(verbs); i++)
5011                         if (streq(argv[optind], verbs[i].verb))
5012                                 break;
5013
5014                 if (i >= ELEMENTSOF(verbs)) {
5015                         log_error("Unknown operation %s", argv[optind]);
5016                         return -EINVAL;
5017                 }
5018         }
5019
5020         switch (verbs[i].argc_cmp) {
5021
5022         case EQUAL:
5023                 if (left != verbs[i].argc) {
5024                         log_error("Invalid number of arguments.");
5025                         return -EINVAL;
5026                 }
5027
5028                 break;
5029
5030         case MORE:
5031                 if (left < verbs[i].argc) {
5032                         log_error("Too few arguments.");
5033                         return -EINVAL;
5034                 }
5035
5036                 break;
5037
5038         case LESS:
5039                 if (left > verbs[i].argc) {
5040                         log_error("Too many arguments.");
5041                         return -EINVAL;
5042                 }
5043
5044                 break;
5045
5046         default:
5047                 assert_not_reached("Unknown comparison operator.");
5048         }
5049
5050         /* Require a bus connection for all operations but
5051          * enable/disable */
5052         if (!streq(verbs[i].verb, "enable") &&
5053             !streq(verbs[i].verb, "disable") &&
5054             !streq(verbs[i].verb, "is-enabled") &&
5055             !streq(verbs[i].verb, "list-unit-files") &&
5056             !streq(verbs[i].verb, "reenable") &&
5057             !streq(verbs[i].verb, "preset") &&
5058             !streq(verbs[i].verb, "mask") &&
5059             !streq(verbs[i].verb, "unmask") &&
5060             !streq(verbs[i].verb, "link")) {
5061
5062                 if (running_in_chroot() > 0) {
5063                         log_info("Running in chroot, ignoring request.");
5064                         return 0;
5065                 }
5066
5067                 if (!bus) {
5068                         log_error("Failed to get D-Bus connection: %s",
5069                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5070                         return -EIO;
5071                 }
5072
5073         } else {
5074
5075                 if (!bus && !avoid_bus()) {
5076                         log_error("Failed to get D-Bus connection: %s",
5077                                   dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5078                         return -EIO;
5079                 }
5080         }
5081
5082         return verbs[i].dispatch(bus, argv + optind);
5083 }
5084
5085 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
5086         int fd = -1;
5087         struct msghdr msghdr;
5088         struct iovec iovec;
5089         union sockaddr_union sockaddr;
5090         struct shutdownd_command c;
5091
5092         zero(c);
5093         c.elapse = t;
5094         c.mode = mode;
5095         c.dry_run = dry_run;
5096         c.warn_wall = warn;
5097
5098         if (message)
5099                 strncpy(c.wall_message, message, sizeof(c.wall_message));
5100
5101         if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0)
5102                 return -errno;
5103
5104         zero(sockaddr);
5105         sockaddr.sa.sa_family = AF_UNIX;
5106         sockaddr.un.sun_path[0] = 0;
5107         strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
5108
5109         zero(iovec);
5110         iovec.iov_base = (char*) &c;
5111         iovec.iov_len = sizeof(c);
5112
5113         zero(msghdr);
5114         msghdr.msg_name = &sockaddr;
5115         msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
5116
5117         msghdr.msg_iov = &iovec;
5118         msghdr.msg_iovlen = 1;
5119
5120         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
5121                 close_nointr_nofail(fd);
5122                 return -errno;
5123         }
5124
5125         close_nointr_nofail(fd);
5126         return 0;
5127 }
5128
5129 static int reload_with_fallback(DBusConnection *bus) {
5130
5131         if (bus) {
5132                 /* First, try systemd via D-Bus. */
5133                 if (daemon_reload(bus, NULL) >= 0)
5134                         return 0;
5135         }
5136
5137         /* Nothing else worked, so let's try signals */
5138         assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5139
5140         if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5141                 log_error("kill() failed: %m");
5142                 return -errno;
5143         }
5144
5145         return 0;
5146 }
5147
5148 static int start_with_fallback(DBusConnection *bus) {
5149
5150         if (bus) {
5151                 /* First, try systemd via D-Bus. */
5152                 if (start_unit(bus, NULL) >= 0)
5153                         goto done;
5154         }
5155
5156         /* Hmm, talking to systemd via D-Bus didn't work. Then
5157          * let's try to talk to Upstart via D-Bus. */
5158         if (talk_upstart() > 0)
5159                 goto done;
5160
5161         /* Nothing else worked, so let's try
5162          * /dev/initctl */
5163         if (talk_initctl() > 0)
5164                 goto done;
5165
5166         log_error("Failed to talk to init daemon.");
5167         return -EIO;
5168
5169 done:
5170         warn_wall(arg_action);
5171         return 0;
5172 }
5173
5174 static int halt_main(DBusConnection *bus) {
5175         int r;
5176
5177         if (geteuid() != 0) {
5178                 log_error("Must be root.");
5179                 return -EPERM;
5180         }
5181
5182         if (arg_when > 0) {
5183                 char *m;
5184                 char date[FORMAT_TIMESTAMP_MAX];
5185
5186                 m = strv_join(arg_wall, " ");
5187                 r = send_shutdownd(arg_when,
5188                                    arg_action == ACTION_HALT     ? 'H' :
5189                                    arg_action == ACTION_POWEROFF ? 'P' :
5190                                                                    'r',
5191                                    arg_dry,
5192                                    !arg_no_wall,
5193                                    m);
5194                 free(m);
5195
5196                 if (r < 0)
5197                         log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
5198                 else {
5199                         log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5200                                  format_timestamp(date, sizeof(date), arg_when));
5201                         return 0;
5202                 }
5203         }
5204
5205         if (!arg_dry && !arg_immediate)
5206                 return start_with_fallback(bus);
5207
5208         if (!arg_no_wtmp) {
5209                 if (sd_booted() > 0)
5210                         log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
5211                 else if ((r = utmp_put_shutdown()) < 0)
5212                         log_warning("Failed to write utmp record: %s", strerror(-r));
5213         }
5214
5215         if (!arg_no_sync)
5216                 sync();
5217
5218         if (arg_dry)
5219                 return 0;
5220
5221         /* Make sure C-A-D is handled by the kernel from this
5222          * point on... */
5223         reboot(RB_ENABLE_CAD);
5224
5225         switch (arg_action) {
5226
5227         case ACTION_HALT:
5228                 log_info("Halting.");
5229                 reboot(RB_HALT_SYSTEM);
5230                 break;
5231
5232         case ACTION_POWEROFF:
5233                 log_info("Powering off.");
5234                 reboot(RB_POWER_OFF);
5235                 break;
5236
5237         case ACTION_REBOOT:
5238                 log_info("Rebooting.");
5239                 reboot(RB_AUTOBOOT);
5240                 break;
5241
5242         default:
5243                 assert_not_reached("Unknown halt action.");
5244         }
5245
5246         /* We should never reach this. */
5247         return -ENOSYS;
5248 }
5249
5250 static int runlevel_main(void) {
5251         int r, runlevel, previous;
5252
5253         r = utmp_get_runlevel(&runlevel, &previous);
5254         if (r < 0) {
5255                 puts("unknown");
5256                 return r;
5257         }
5258
5259         printf("%c %c\n",
5260                previous <= 0 ? 'N' : previous,
5261                runlevel <= 0 ? 'N' : runlevel);
5262
5263         return 0;
5264 }
5265
5266 int main(int argc, char*argv[]) {
5267         int r, retval = EXIT_FAILURE;
5268         DBusConnection *bus = NULL;
5269         DBusError error;
5270
5271         dbus_error_init(&error);
5272
5273         log_parse_environment();
5274         log_open();
5275
5276         if ((r = parse_argv(argc, argv)) < 0)
5277                 goto finish;
5278         else if (r == 0) {
5279                 retval = EXIT_SUCCESS;
5280                 goto finish;
5281         }
5282
5283         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5284          * let's shortcut this */
5285         if (arg_action == ACTION_RUNLEVEL) {
5286                 r = runlevel_main();
5287                 retval = r < 0 ? EXIT_FAILURE : r;
5288                 goto finish;
5289         }
5290
5291         if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
5292                 log_info("Running in chroot, ignoring request.");
5293                 retval = 0;
5294                 goto finish;
5295         }
5296
5297         if (!avoid_bus()) {
5298                 if (arg_transport == TRANSPORT_NORMAL)
5299                         bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
5300                 else if (arg_transport == TRANSPORT_POLKIT) {
5301                         bus_connect_system_polkit(&bus, &error);
5302                         private_bus = false;
5303                 } else if (arg_transport == TRANSPORT_SSH) {
5304                         bus_connect_system_ssh(NULL, arg_host, &bus, &error);
5305                         private_bus = false;
5306                 } else
5307                         assert_not_reached("Uh, invalid transport...");
5308         }
5309
5310         switch (arg_action) {
5311
5312         case ACTION_SYSTEMCTL:
5313                 r = systemctl_main(bus, argc, argv, &error);
5314                 break;
5315
5316         case ACTION_HALT:
5317         case ACTION_POWEROFF:
5318         case ACTION_REBOOT:
5319         case ACTION_KEXEC:
5320                 r = halt_main(bus);
5321                 break;
5322
5323         case ACTION_RUNLEVEL2:
5324         case ACTION_RUNLEVEL3:
5325         case ACTION_RUNLEVEL4:
5326         case ACTION_RUNLEVEL5:
5327         case ACTION_RESCUE:
5328         case ACTION_EMERGENCY:
5329         case ACTION_DEFAULT:
5330                 r = start_with_fallback(bus);
5331                 break;
5332
5333         case ACTION_RELOAD:
5334         case ACTION_REEXEC:
5335                 r = reload_with_fallback(bus);
5336                 break;
5337
5338         case ACTION_CANCEL_SHUTDOWN:
5339                 r = send_shutdownd(0, 0, false, false, NULL);
5340                 break;
5341
5342         case ACTION_INVALID:
5343         case ACTION_RUNLEVEL:
5344         default:
5345                 assert_not_reached("Unknown action");
5346         }
5347
5348         retval = r < 0 ? EXIT_FAILURE : r;
5349
5350 finish:
5351         if (bus) {
5352                 dbus_connection_flush(bus);
5353                 dbus_connection_close(bus);
5354                 dbus_connection_unref(bus);
5355         }
5356
5357         dbus_error_free(&error);
5358
5359         dbus_shutdown();
5360
5361         strv_free(arg_property);
5362
5363         pager_close();
5364         agent_close();
5365
5366         return retval;
5367 }