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