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