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