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