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