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