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