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