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