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