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