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