]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/systemctl/systemctl.c
core: move ManagerRunningAs to shared
[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 *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 *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 free(n);
1457 if (!unit_path) {
1458 log_error("Could not allocate dbus path.");
1459 goto finish;
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 goto finish;
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 goto finish;
1480
1481 }
1482
1483 dbus_message_iter_recurse(&iter, &sub);
1484 dbus_message_iter_recurse(&sub, &iter);
1485 sub = iter;
1486
1487 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1488
1489 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1490 log_error("Failed to parse reply.");
1491 goto finish;
1492 }
1493
1494 dbus_message_iter_get_basic(&sub, &service_trigger);
1495
1496 r = check_one_unit(bus, service_trigger, true);
1497 if (r < 0)
1498 goto finish;
1499 if (r == 0) {
1500 if (print_warning_label) {
1501 log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name);
1502 print_warning_label = false;
1503 }
1504 log_warning(" %s", service_trigger);
1505 }
1506
1507 dbus_message_iter_next(&sub);
1508 }
1509 finish:
1510 if (reply)
1511 dbus_message_unref(reply);
1512
1513 free(unit_path);
1514 }
1515
1516 static int start_unit_one(
1517 DBusConnection *bus,
1518 const char *method,
1519 const char *name,
1520 const char *mode,
1521 DBusError *error,
1522 Set *s) {
1523
1524 DBusMessage *reply = NULL;
1525 const char *path;
1526 int r;
1527 _cleanup_free_ char *n, *p = NULL;
1528
1529 assert(method);
1530 assert(name);
1531 assert(mode);
1532 assert(error);
1533
1534 n = unit_name_mangle(name);
1535 if (!n)
1536 return log_oom();
1537
1538 r = bus_method_call_with_reply(
1539 bus,
1540 "org.freedesktop.systemd1",
1541 "/org/freedesktop/systemd1",
1542 "org.freedesktop.systemd1.Manager",
1543 method,
1544 &reply,
1545 error,
1546 DBUS_TYPE_STRING, &n,
1547 DBUS_TYPE_STRING, &mode,
1548 DBUS_TYPE_INVALID);
1549 if (r) {
1550 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
1551 /* There's always a fallback possible for
1552 * legacy actions. */
1553 r = -EADDRNOTAVAIL;
1554 else
1555 log_error("Failed to issue method call: %s", bus_error_message(error));
1556
1557 goto finish;
1558 }
1559
1560 if (!dbus_message_get_args(reply, error,
1561 DBUS_TYPE_OBJECT_PATH, &path,
1562 DBUS_TYPE_INVALID)) {
1563 log_error("Failed to parse reply: %s", bus_error_message(error));
1564 r = -EIO;
1565 goto finish;
1566 }
1567
1568 if (need_daemon_reload(bus, n))
1569 log_warning("Warning: Unit file of %s changed on disk, 'systemctl %s daemon-reload' recommended.",
1570 n, arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
1571
1572 if (s) {
1573 p = strdup(path);
1574 if (!p) {
1575 r = log_oom();
1576 goto finish;
1577 }
1578
1579 r = set_put(s, p);
1580 if (r < 0) {
1581 log_error("Failed to add path to set.");
1582 goto finish;
1583 }
1584
1585 p = NULL;
1586 }
1587
1588 /* When stopping a unit warn if it can still be triggered by
1589 * another active unit (socket, path, timer) */
1590 if (!arg_quiet && streq(method, "StopUnit"))
1591 check_triggering_units(bus, name);
1592
1593 r = 0;
1594
1595 finish:
1596 if (reply)
1597 dbus_message_unref(reply);
1598
1599 return r;
1600 }
1601
1602 static enum action verb_to_action(const char *verb) {
1603 if (streq(verb, "halt"))
1604 return ACTION_HALT;
1605 else if (streq(verb, "poweroff"))
1606 return ACTION_POWEROFF;
1607 else if (streq(verb, "reboot"))
1608 return ACTION_REBOOT;
1609 else if (streq(verb, "kexec"))
1610 return ACTION_KEXEC;
1611 else if (streq(verb, "rescue"))
1612 return ACTION_RESCUE;
1613 else if (streq(verb, "emergency"))
1614 return ACTION_EMERGENCY;
1615 else if (streq(verb, "default"))
1616 return ACTION_DEFAULT;
1617 else if (streq(verb, "exit"))
1618 return ACTION_EXIT;
1619 else if (streq(verb, "suspend"))
1620 return ACTION_SUSPEND;
1621 else if (streq(verb, "hibernate"))
1622 return ACTION_HIBERNATE;
1623 else
1624 return ACTION_INVALID;
1625 }
1626
1627 static int start_unit(DBusConnection *bus, char **args) {
1628
1629 static const char * const table[_ACTION_MAX] = {
1630 [ACTION_HALT] = SPECIAL_HALT_TARGET,
1631 [ACTION_POWEROFF] = SPECIAL_POWEROFF_TARGET,
1632 [ACTION_REBOOT] = SPECIAL_REBOOT_TARGET,
1633 [ACTION_KEXEC] = SPECIAL_KEXEC_TARGET,
1634 [ACTION_RUNLEVEL2] = SPECIAL_RUNLEVEL2_TARGET,
1635 [ACTION_RUNLEVEL3] = SPECIAL_RUNLEVEL3_TARGET,
1636 [ACTION_RUNLEVEL4] = SPECIAL_RUNLEVEL4_TARGET,
1637 [ACTION_RUNLEVEL5] = SPECIAL_RUNLEVEL5_TARGET,
1638 [ACTION_RESCUE] = SPECIAL_RESCUE_TARGET,
1639 [ACTION_EMERGENCY] = SPECIAL_EMERGENCY_TARGET,
1640 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
1641 [ACTION_EXIT] = SPECIAL_EXIT_TARGET,
1642 [ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET,
1643 [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET
1644 };
1645
1646 int r, ret = 0;
1647 const char *method, *mode, *one_name;
1648 Set *s = NULL;
1649 DBusError error;
1650 char **name;
1651
1652 dbus_error_init(&error);
1653
1654 assert(bus);
1655
1656 ask_password_agent_open_if_enabled();
1657
1658 if (arg_action == ACTION_SYSTEMCTL) {
1659 method =
1660 streq(args[0], "stop") ||
1661 streq(args[0], "condstop") ? "StopUnit" :
1662 streq(args[0], "reload") ? "ReloadUnit" :
1663 streq(args[0], "restart") ? "RestartUnit" :
1664
1665 streq(args[0], "try-restart") ||
1666 streq(args[0], "condrestart") ? "TryRestartUnit" :
1667
1668 streq(args[0], "reload-or-restart") ? "ReloadOrRestartUnit" :
1669
1670 streq(args[0], "reload-or-try-restart") ||
1671 streq(args[0], "condreload") ||
1672
1673 streq(args[0], "force-reload") ? "ReloadOrTryRestartUnit" :
1674 "StartUnit";
1675
1676 mode =
1677 (streq(args[0], "isolate") ||
1678 streq(args[0], "rescue") ||
1679 streq(args[0], "emergency")) ? "isolate" : arg_job_mode;
1680
1681 one_name = table[verb_to_action(args[0])];
1682
1683 } else {
1684 assert(arg_action < ELEMENTSOF(table));
1685 assert(table[arg_action]);
1686
1687 method = "StartUnit";
1688
1689 mode = (arg_action == ACTION_EMERGENCY ||
1690 arg_action == ACTION_RESCUE ||
1691 arg_action == ACTION_RUNLEVEL2 ||
1692 arg_action == ACTION_RUNLEVEL3 ||
1693 arg_action == ACTION_RUNLEVEL4 ||
1694 arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace";
1695
1696 one_name = table[arg_action];
1697 }
1698
1699 if (!arg_no_block) {
1700 ret = enable_wait_for_jobs(bus);
1701 if (ret < 0) {
1702 log_error("Could not watch jobs: %s", strerror(-ret));
1703 goto finish;
1704 }
1705
1706 s = set_new(string_hash_func, string_compare_func);
1707 if (!s) {
1708 ret = log_oom();
1709 goto finish;
1710 }
1711 }
1712
1713 if (one_name) {
1714 ret = start_unit_one(bus, method, one_name, mode, &error, s);
1715 if (ret < 0)
1716 ret = translate_bus_error_to_exit_status(ret, &error);
1717 } else {
1718 STRV_FOREACH(name, args+1) {
1719 r = start_unit_one(bus, method, *name, mode, &error, s);
1720 if (r < 0) {
1721 ret = translate_bus_error_to_exit_status(r, &error);
1722 dbus_error_free(&error);
1723 }
1724 }
1725 }
1726
1727 if (!arg_no_block) {
1728 r = wait_for_jobs(bus, s);
1729 if (r < 0) {
1730 ret = r;
1731 goto finish;
1732 }
1733 }
1734
1735 finish:
1736 set_free_free(s);
1737 dbus_error_free(&error);
1738
1739 return ret;
1740 }
1741
1742 /* Ask systemd-logind, which might grant access to unprivileged users
1743 * through PolicyKit */
1744 static int reboot_with_logind(DBusConnection *bus, enum action a) {
1745 #ifdef HAVE_LOGIND
1746 const char *method;
1747 dbus_bool_t interactive = true;
1748
1749 polkit_agent_open_if_enabled();
1750
1751 switch (a) {
1752
1753 case ACTION_REBOOT:
1754 method = "Reboot";
1755 break;
1756
1757 case ACTION_POWEROFF:
1758 method = "PowerOff";
1759 break;
1760
1761 case ACTION_SUSPEND:
1762 method = "Suspend";
1763 break;
1764
1765 case ACTION_HIBERNATE:
1766 method = "Hibernate";
1767 break;
1768
1769 default:
1770 return -EINVAL;
1771 }
1772
1773 return bus_method_call_with_reply (
1774 bus,
1775 "org.freedesktop.login1",
1776 "/org/freedesktop/login1",
1777 "org.freedesktop.login1.Manager",
1778 method,
1779 NULL,
1780 NULL,
1781 DBUS_TYPE_BOOLEAN, &interactive,
1782 DBUS_TYPE_INVALID);
1783 #else
1784 return -ENOSYS;
1785 #endif
1786 }
1787
1788 static int start_special(DBusConnection *bus, char **args) {
1789 enum action a;
1790 int r;
1791
1792 assert(args);
1793
1794 a = verb_to_action(args[0]);
1795
1796 if (arg_force >= 2 && geteuid() != 0) {
1797 log_error("Must be root.");
1798 return -EPERM;
1799 }
1800
1801 if (arg_force >= 2 &&
1802 (a == ACTION_HALT ||
1803 a == ACTION_POWEROFF ||
1804 a == ACTION_REBOOT))
1805 halt_now(a);
1806
1807 if (arg_force >= 1 &&
1808 (a == ACTION_HALT ||
1809 a == ACTION_POWEROFF ||
1810 a == ACTION_REBOOT ||
1811 a == ACTION_KEXEC ||
1812 a == ACTION_EXIT))
1813 return daemon_reload(bus, args);
1814
1815 /* first try logind, to allow authentication with polkit */
1816 if (geteuid() != 0 &&
1817 (a == ACTION_POWEROFF ||
1818 a == ACTION_REBOOT ||
1819 a == ACTION_SUSPEND ||
1820 a == ACTION_HIBERNATE)) {
1821 r = reboot_with_logind(bus, a);
1822 if (r >= 0)
1823 return r;
1824 }
1825
1826 r = start_unit(bus, args);
1827 if (r >= 0)
1828 warn_wall(a);
1829
1830 return r;
1831 }
1832
1833 static int check_unit(DBusConnection *bus, char **args) {
1834 char **name;
1835 int r = 3; /* According to LSB: "program is not running" */
1836
1837 assert(bus);
1838 assert(args);
1839
1840 STRV_FOREACH(name, args+1) {
1841 int state = check_one_unit(bus, *name, arg_quiet);
1842 if (state < 0)
1843 return state;
1844 if (state == 0)
1845 r = 0;
1846 }
1847
1848 return r;
1849 }
1850
1851 static int kill_unit(DBusConnection *bus, char **args) {
1852 int r = 0;
1853 char **name, *n;
1854
1855 assert(args);
1856
1857 if (!arg_kill_who)
1858 arg_kill_who = "all";
1859
1860 STRV_FOREACH(name, args+1) {
1861 n = unit_name_mangle(*name);
1862 r = bus_method_call_with_reply (
1863 bus,
1864 "org.freedesktop.systemd1",
1865 "/org/freedesktop/systemd1",
1866 "org.freedesktop.systemd1.Manager",
1867 "KillUnit",
1868 NULL,
1869 NULL,
1870 DBUS_TYPE_STRING, n ? &n : name,
1871 DBUS_TYPE_STRING, &arg_kill_who,
1872 DBUS_TYPE_INT32, &arg_signal,
1873 DBUS_TYPE_INVALID);
1874 free(n);
1875 if (r)
1876 return r;
1877 }
1878 return 0;
1879 }
1880
1881 typedef struct ExecStatusInfo {
1882 char *name;
1883
1884 char *path;
1885 char **argv;
1886
1887 bool ignore;
1888
1889 usec_t start_timestamp;
1890 usec_t exit_timestamp;
1891 pid_t pid;
1892 int code;
1893 int status;
1894
1895 LIST_FIELDS(struct ExecStatusInfo, exec);
1896 } ExecStatusInfo;
1897
1898 static void exec_status_info_free(ExecStatusInfo *i) {
1899 assert(i);
1900
1901 free(i->name);
1902 free(i->path);
1903 strv_free(i->argv);
1904 free(i);
1905 }
1906
1907 static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
1908 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
1909 DBusMessageIter sub2, sub3;
1910 const char*path;
1911 unsigned n;
1912 uint32_t pid;
1913 int32_t code, status;
1914 dbus_bool_t ignore;
1915
1916 assert(i);
1917 assert(i);
1918
1919 if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
1920 return -EIO;
1921
1922 dbus_message_iter_recurse(sub, &sub2);
1923
1924 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
1925 return -EIO;
1926
1927 if (!(i->path = strdup(path)))
1928 return -ENOMEM;
1929
1930 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
1931 dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
1932 return -EIO;
1933
1934 n = 0;
1935 dbus_message_iter_recurse(&sub2, &sub3);
1936 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
1937 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
1938 dbus_message_iter_next(&sub3);
1939 n++;
1940 }
1941
1942
1943 if (!(i->argv = new0(char*, n+1)))
1944 return -ENOMEM;
1945
1946 n = 0;
1947 dbus_message_iter_recurse(&sub2, &sub3);
1948 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
1949 const char *s;
1950
1951 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
1952 dbus_message_iter_get_basic(&sub3, &s);
1953 dbus_message_iter_next(&sub3);
1954
1955 if (!(i->argv[n++] = strdup(s)))
1956 return -ENOMEM;
1957 }
1958
1959 if (!dbus_message_iter_next(&sub2) ||
1960 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
1961 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
1962 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
1963 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
1964 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
1965 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
1966 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
1967 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
1968 return -EIO;
1969
1970 i->ignore = ignore;
1971 i->start_timestamp = (usec_t) start_timestamp;
1972 i->exit_timestamp = (usec_t) exit_timestamp;
1973 i->pid = (pid_t) pid;
1974 i->code = code;
1975 i->status = status;
1976
1977 return 0;
1978 }
1979
1980 typedef struct UnitStatusInfo {
1981 const char *id;
1982 const char *load_state;
1983 const char *active_state;
1984 const char *sub_state;
1985 const char *unit_file_state;
1986
1987 const char *description;
1988 const char *following;
1989
1990 char **documentation;
1991
1992 const char *fragment_path;
1993 const char *source_path;
1994 const char *default_control_group;
1995
1996 const char *load_error;
1997 const char *result;
1998
1999 usec_t inactive_exit_timestamp;
2000 usec_t inactive_exit_timestamp_monotonic;
2001 usec_t active_enter_timestamp;
2002 usec_t active_exit_timestamp;
2003 usec_t inactive_enter_timestamp;
2004
2005 bool need_daemon_reload;
2006
2007 /* Service */
2008 pid_t main_pid;
2009 pid_t control_pid;
2010 const char *status_text;
2011 bool running:1;
2012
2013 usec_t start_timestamp;
2014 usec_t exit_timestamp;
2015
2016 int exit_code, exit_status;
2017
2018 usec_t condition_timestamp;
2019 bool condition_result;
2020
2021 /* Socket */
2022 unsigned n_accepted;
2023 unsigned n_connections;
2024 bool accept;
2025
2026 /* Device */
2027 const char *sysfs_path;
2028
2029 /* Mount, Automount */
2030 const char *where;
2031
2032 /* Swap */
2033 const char *what;
2034
2035 LIST_HEAD(ExecStatusInfo, exec);
2036 } UnitStatusInfo;
2037
2038 static void print_status_info(UnitStatusInfo *i) {
2039 ExecStatusInfo *p;
2040 const char *on, *off, *ss;
2041 usec_t timestamp;
2042 char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
2043 char since2[FORMAT_TIMESTAMP_MAX], *s2;
2044 const char *path;
2045
2046 assert(i);
2047
2048 /* This shows pretty information about a unit. See
2049 * print_property() for a low-level property printer */
2050
2051 printf("%s", strna(i->id));
2052
2053 if (i->description && !streq_ptr(i->id, i->description))
2054 printf(" - %s", i->description);
2055
2056 printf("\n");
2057
2058 if (i->following)
2059 printf("\t Follow: unit currently follows state of %s\n", i->following);
2060
2061 if (streq_ptr(i->load_state, "error")) {
2062 on = ansi_highlight_red(true);
2063 off = ansi_highlight_red(false);
2064 } else
2065 on = off = "";
2066
2067 path = i->source_path ? i->source_path : i->fragment_path;
2068
2069 if (i->load_error)
2070 printf("\t Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error);
2071 else if (path && i->unit_file_state)
2072 printf("\t Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, path, i->unit_file_state);
2073 else if (path)
2074 printf("\t Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, path);
2075 else
2076 printf("\t Loaded: %s%s%s\n", on, strna(i->load_state), off);
2077
2078 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2079
2080 if (streq_ptr(i->active_state, "failed")) {
2081 on = ansi_highlight_red(true);
2082 off = ansi_highlight_red(false);
2083 } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2084 on = ansi_highlight_green(true);
2085 off = ansi_highlight_green(false);
2086 } else
2087 on = off = "";
2088
2089 if (ss)
2090 printf("\t Active: %s%s (%s)%s",
2091 on,
2092 strna(i->active_state),
2093 ss,
2094 off);
2095 else
2096 printf("\t Active: %s%s%s",
2097 on,
2098 strna(i->active_state),
2099 off);
2100
2101 if (!isempty(i->result) && !streq(i->result, "success"))
2102 printf(" (Result: %s)", i->result);
2103
2104 timestamp = (streq_ptr(i->active_state, "active") ||
2105 streq_ptr(i->active_state, "reloading")) ? i->active_enter_timestamp :
2106 (streq_ptr(i->active_state, "inactive") ||
2107 streq_ptr(i->active_state, "failed")) ? i->inactive_enter_timestamp :
2108 streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp :
2109 i->active_exit_timestamp;
2110
2111 s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp);
2112 s2 = format_timestamp(since2, sizeof(since2), timestamp);
2113
2114 if (s1)
2115 printf(" since %s; %s\n", s2, s1);
2116 else if (s2)
2117 printf(" since %s\n", s2);
2118 else
2119 printf("\n");
2120
2121 if (!i->condition_result && i->condition_timestamp > 0) {
2122 s1 = format_timestamp_pretty(since1, sizeof(since1), i->condition_timestamp);
2123 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2124
2125 if (s1)
2126 printf("\t start condition failed at %s; %s\n", s2, s1);
2127 else if (s2)
2128 printf("\t start condition failed at %s\n", s2);
2129 }
2130
2131 if (i->sysfs_path)
2132 printf("\t Device: %s\n", i->sysfs_path);
2133 if (i->where)
2134 printf("\t Where: %s\n", i->where);
2135 if (i->what)
2136 printf("\t What: %s\n", i->what);
2137
2138 if (!strv_isempty(i->documentation)) {
2139 char **t;
2140 bool first = true;
2141
2142 STRV_FOREACH(t, i->documentation) {
2143 if (first) {
2144 printf("\t Docs: %s\n", *t);
2145 first = false;
2146 } else
2147 printf("\t %s\n", *t);
2148 }
2149 }
2150
2151 if (i->accept)
2152 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
2153
2154 LIST_FOREACH(exec, p, i->exec) {
2155 char *t;
2156 bool good;
2157
2158 /* Only show exited processes here */
2159 if (p->code == 0)
2160 continue;
2161
2162 t = strv_join(p->argv, " ");
2163 printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
2164 free(t);
2165
2166 good = is_clean_exit_lsb(p->code, p->status, NULL);
2167 if (!good) {
2168 on = ansi_highlight_red(true);
2169 off = ansi_highlight_red(false);
2170 } else
2171 on = off = "";
2172
2173 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2174
2175 if (p->code == CLD_EXITED) {
2176 const char *c;
2177
2178 printf("status=%i", p->status);
2179
2180 c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2181 if (c)
2182 printf("/%s", c);
2183
2184 } else
2185 printf("signal=%s", signal_to_string(p->status));
2186
2187 printf(")%s\n", off);
2188
2189 if (i->main_pid == p->pid &&
2190 i->start_timestamp == p->start_timestamp &&
2191 i->exit_timestamp == p->start_timestamp)
2192 /* Let's not show this twice */
2193 i->main_pid = 0;
2194
2195 if (p->pid == i->control_pid)
2196 i->control_pid = 0;
2197 }
2198
2199 if (i->main_pid > 0 || i->control_pid > 0) {
2200 printf("\t");
2201
2202 if (i->main_pid > 0) {
2203 printf("Main PID: %u", (unsigned) i->main_pid);
2204
2205 if (i->running) {
2206 char *t = NULL;
2207 get_process_comm(i->main_pid, &t);
2208 if (t) {
2209 printf(" (%s)", t);
2210 free(t);
2211 }
2212 } else if (i->exit_code > 0) {
2213 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2214
2215 if (i->exit_code == CLD_EXITED) {
2216 const char *c;
2217
2218 printf("status=%i", i->exit_status);
2219
2220 c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2221 if (c)
2222 printf("/%s", c);
2223
2224 } else
2225 printf("signal=%s", signal_to_string(i->exit_status));
2226 printf(")");
2227 }
2228 }
2229
2230 if (i->main_pid > 0 && i->control_pid > 0)
2231 printf(";");
2232
2233 if (i->control_pid > 0) {
2234 char *t = NULL;
2235
2236 printf(" Control: %u", (unsigned) i->control_pid);
2237
2238 get_process_comm(i->control_pid, &t);
2239 if (t) {
2240 printf(" (%s)", t);
2241 free(t);
2242 }
2243 }
2244
2245 printf("\n");
2246 }
2247
2248 if (i->status_text)
2249 printf("\t Status: \"%s\"\n", i->status_text);
2250
2251 if (i->default_control_group) {
2252 unsigned c;
2253
2254 printf("\t CGroup: %s\n", i->default_control_group);
2255
2256 if (arg_transport != TRANSPORT_SSH) {
2257 unsigned k = 0;
2258 pid_t extra[2];
2259
2260 c = columns();
2261 if (c > 18)
2262 c -= 18;
2263 else
2264 c = 0;
2265
2266 if (i->main_pid > 0)
2267 extra[k++] = i->main_pid;
2268
2269 if (i->control_pid > 0)
2270 extra[k++] = i->control_pid;
2271
2272 show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t ", c, false, arg_all, extra, k);
2273 }
2274 }
2275
2276 if (i->id && arg_transport != TRANSPORT_SSH) {
2277 int flags =
2278 arg_all * OUTPUT_SHOW_ALL |
2279 arg_follow * OUTPUT_FOLLOW |
2280 !arg_quiet * OUTPUT_WARN_CUTOFF |
2281 on_tty() * OUTPUT_COLOR;
2282
2283 printf("\n");
2284 show_journal_by_unit(i->id, arg_output, 0,
2285 i->inactive_exit_timestamp_monotonic,
2286 arg_lines, flags);
2287 }
2288
2289 if (i->need_daemon_reload)
2290 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
2291 ansi_highlight_red(true),
2292 ansi_highlight_red(false),
2293 arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
2294 }
2295
2296 static void show_unit_help(UnitStatusInfo *i) {
2297 char **p;
2298
2299 assert(i);
2300
2301 if (!i->documentation) {
2302 log_info("Documentation for %s not known.", i->id);
2303 return;
2304 }
2305
2306 STRV_FOREACH(p, i->documentation) {
2307
2308 if (startswith(*p, "man:")) {
2309 size_t k;
2310 char *e = NULL;
2311 char *page = NULL, *section = NULL;
2312 const char *args[4] = { "man", NULL, NULL, NULL };
2313 pid_t pid;
2314
2315 k = strlen(*p);
2316
2317 if ((*p)[k-1] == ')')
2318 e = strrchr(*p, '(');
2319
2320 if (e) {
2321 page = strndup((*p) + 4, e - *p - 4);
2322 if (!page) {
2323 log_oom();
2324 return;
2325 }
2326
2327 section = strndup(e + 1, *p + k - e - 2);
2328 if (!section) {
2329 free(page);
2330 log_oom();
2331 return;
2332 }
2333
2334 args[1] = section;
2335 args[2] = page;
2336 } else
2337 args[1] = *p + 4;
2338
2339 pid = fork();
2340 if (pid < 0) {
2341 log_error("Failed to fork: %m");
2342 free(page);
2343 free(section);
2344 continue;
2345 }
2346
2347 if (pid == 0) {
2348 /* Child */
2349 execvp(args[0], (char**) args);
2350 log_error("Failed to execute man: %m");
2351 _exit(EXIT_FAILURE);
2352 }
2353
2354 free(page);
2355 free(section);
2356
2357 wait_for_terminate(pid, NULL);
2358 } else
2359 log_info("Can't show: %s", *p);
2360 }
2361 }
2362
2363 static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2364
2365 assert(name);
2366 assert(iter);
2367 assert(i);
2368
2369 switch (dbus_message_iter_get_arg_type(iter)) {
2370
2371 case DBUS_TYPE_STRING: {
2372 const char *s;
2373
2374 dbus_message_iter_get_basic(iter, &s);
2375
2376 if (!isempty(s)) {
2377 if (streq(name, "Id"))
2378 i->id = s;
2379 else if (streq(name, "LoadState"))
2380 i->load_state = s;
2381 else if (streq(name, "ActiveState"))
2382 i->active_state = s;
2383 else if (streq(name, "SubState"))
2384 i->sub_state = s;
2385 else if (streq(name, "Description"))
2386 i->description = s;
2387 else if (streq(name, "FragmentPath"))
2388 i->fragment_path = s;
2389 else if (streq(name, "SourcePath"))
2390 i->source_path = s;
2391 else if (streq(name, "DefaultControlGroup"))
2392 i->default_control_group = s;
2393 else if (streq(name, "StatusText"))
2394 i->status_text = s;
2395 else if (streq(name, "SysFSPath"))
2396 i->sysfs_path = s;
2397 else if (streq(name, "Where"))
2398 i->where = s;
2399 else if (streq(name, "What"))
2400 i->what = s;
2401 else if (streq(name, "Following"))
2402 i->following = s;
2403 else if (streq(name, "UnitFileState"))
2404 i->unit_file_state = s;
2405 else if (streq(name, "Result"))
2406 i->result = s;
2407 }
2408
2409 break;
2410 }
2411
2412 case DBUS_TYPE_BOOLEAN: {
2413 dbus_bool_t b;
2414
2415 dbus_message_iter_get_basic(iter, &b);
2416
2417 if (streq(name, "Accept"))
2418 i->accept = b;
2419 else if (streq(name, "NeedDaemonReload"))
2420 i->need_daemon_reload = b;
2421 else if (streq(name, "ConditionResult"))
2422 i->condition_result = b;
2423
2424 break;
2425 }
2426
2427 case DBUS_TYPE_UINT32: {
2428 uint32_t u;
2429
2430 dbus_message_iter_get_basic(iter, &u);
2431
2432 if (streq(name, "MainPID")) {
2433 if (u > 0) {
2434 i->main_pid = (pid_t) u;
2435 i->running = true;
2436 }
2437 } else if (streq(name, "ControlPID"))
2438 i->control_pid = (pid_t) u;
2439 else if (streq(name, "ExecMainPID")) {
2440 if (u > 0)
2441 i->main_pid = (pid_t) u;
2442 } else if (streq(name, "NAccepted"))
2443 i->n_accepted = u;
2444 else if (streq(name, "NConnections"))
2445 i->n_connections = u;
2446
2447 break;
2448 }
2449
2450 case DBUS_TYPE_INT32: {
2451 int32_t j;
2452
2453 dbus_message_iter_get_basic(iter, &j);
2454
2455 if (streq(name, "ExecMainCode"))
2456 i->exit_code = (int) j;
2457 else if (streq(name, "ExecMainStatus"))
2458 i->exit_status = (int) j;
2459
2460 break;
2461 }
2462
2463 case DBUS_TYPE_UINT64: {
2464 uint64_t u;
2465
2466 dbus_message_iter_get_basic(iter, &u);
2467
2468 if (streq(name, "ExecMainStartTimestamp"))
2469 i->start_timestamp = (usec_t) u;
2470 else if (streq(name, "ExecMainExitTimestamp"))
2471 i->exit_timestamp = (usec_t) u;
2472 else if (streq(name, "ActiveEnterTimestamp"))
2473 i->active_enter_timestamp = (usec_t) u;
2474 else if (streq(name, "InactiveEnterTimestamp"))
2475 i->inactive_enter_timestamp = (usec_t) u;
2476 else if (streq(name, "InactiveExitTimestamp"))
2477 i->inactive_exit_timestamp = (usec_t) u;
2478 else if (streq(name, "InactiveExitTimestampMonotonic"))
2479 i->inactive_exit_timestamp_monotonic = (usec_t) u;
2480 else if (streq(name, "ActiveExitTimestamp"))
2481 i->active_exit_timestamp = (usec_t) u;
2482 else if (streq(name, "ConditionTimestamp"))
2483 i->condition_timestamp = (usec_t) u;
2484
2485 break;
2486 }
2487
2488 case DBUS_TYPE_ARRAY: {
2489
2490 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2491 startswith(name, "Exec")) {
2492 DBusMessageIter sub;
2493
2494 dbus_message_iter_recurse(iter, &sub);
2495 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2496 ExecStatusInfo *info;
2497 int r;
2498
2499 if (!(info = new0(ExecStatusInfo, 1)))
2500 return -ENOMEM;
2501
2502 if (!(info->name = strdup(name))) {
2503 free(info);
2504 return -ENOMEM;
2505 }
2506
2507 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2508 free(info);
2509 return r;
2510 }
2511
2512 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2513
2514 dbus_message_iter_next(&sub);
2515 }
2516 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
2517 streq(name, "Documentation")) {
2518
2519 DBusMessageIter sub;
2520
2521 dbus_message_iter_recurse(iter, &sub);
2522 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
2523 const char *s;
2524 char **l;
2525
2526 dbus_message_iter_get_basic(&sub, &s);
2527
2528 l = strv_append(i->documentation, s);
2529 if (!l)
2530 return -ENOMEM;
2531
2532 strv_free(i->documentation);
2533 i->documentation = l;
2534
2535 dbus_message_iter_next(&sub);
2536 }
2537 }
2538
2539 break;
2540 }
2541
2542 case DBUS_TYPE_STRUCT: {
2543
2544 if (streq(name, "LoadError")) {
2545 DBusMessageIter sub;
2546 const char *n, *message;
2547 int r;
2548
2549 dbus_message_iter_recurse(iter, &sub);
2550
2551 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2552 if (r < 0)
2553 return r;
2554
2555 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2556 if (r < 0)
2557 return r;
2558
2559 if (!isempty(message))
2560 i->load_error = message;
2561 }
2562
2563 break;
2564 }
2565 }
2566
2567 return 0;
2568 }
2569
2570 static int print_property(const char *name, DBusMessageIter *iter) {
2571 assert(name);
2572 assert(iter);
2573
2574 /* This is a low-level property printer, see
2575 * print_status_info() for the nicer output */
2576
2577 if (arg_property && !strv_find(arg_property, name))
2578 return 0;
2579
2580 switch (dbus_message_iter_get_arg_type(iter)) {
2581
2582 case DBUS_TYPE_STRUCT: {
2583 DBusMessageIter sub;
2584 dbus_message_iter_recurse(iter, &sub);
2585
2586 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
2587 uint32_t u;
2588
2589 dbus_message_iter_get_basic(&sub, &u);
2590
2591 if (u)
2592 printf("%s=%u\n", name, (unsigned) u);
2593 else if (arg_all)
2594 printf("%s=\n", name);
2595
2596 return 0;
2597 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
2598 const char *s;
2599
2600 dbus_message_iter_get_basic(&sub, &s);
2601
2602 if (arg_all || s[0])
2603 printf("%s=%s\n", name, s);
2604
2605 return 0;
2606 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2607 const char *a = NULL, *b = NULL;
2608
2609 if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
2610 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2611
2612 if (arg_all || !isempty(a) || !isempty(b))
2613 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
2614
2615 return 0;
2616 }
2617
2618 break;
2619 }
2620
2621 case DBUS_TYPE_ARRAY:
2622
2623 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
2624 DBusMessageIter sub, sub2;
2625
2626 dbus_message_iter_recurse(iter, &sub);
2627 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2628 const char *path;
2629 dbus_bool_t ignore;
2630
2631 dbus_message_iter_recurse(&sub, &sub2);
2632
2633 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2634 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
2635 printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
2636
2637 dbus_message_iter_next(&sub);
2638 }
2639
2640 return 0;
2641
2642 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2643 DBusMessageIter sub, sub2;
2644
2645 dbus_message_iter_recurse(iter, &sub);
2646 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2647 const char *type, *path;
2648
2649 dbus_message_iter_recurse(&sub, &sub2);
2650
2651 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2652 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2653 printf("%s=%s\n", type, path);
2654
2655 dbus_message_iter_next(&sub);
2656 }
2657
2658 return 0;
2659
2660 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2661 DBusMessageIter sub, sub2;
2662
2663 dbus_message_iter_recurse(iter, &sub);
2664 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2665 const char *base;
2666 uint64_t value, next_elapse;
2667
2668 dbus_message_iter_recurse(&sub, &sub2);
2669
2670 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2671 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
2672 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2673 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2674
2675 printf("%s={ value=%s ; next_elapse=%s }\n",
2676 base,
2677 format_timespan(timespan1, sizeof(timespan1), value),
2678 format_timespan(timespan2, sizeof(timespan2), next_elapse));
2679 }
2680
2681 dbus_message_iter_next(&sub);
2682 }
2683
2684 return 0;
2685
2686 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2687 DBusMessageIter sub, sub2;
2688
2689 dbus_message_iter_recurse(iter, &sub);
2690 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2691 const char *controller, *attr, *value;
2692
2693 dbus_message_iter_recurse(&sub, &sub2);
2694
2695 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
2696 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
2697 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
2698
2699 printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2700 controller,
2701 attr,
2702 value);
2703 }
2704
2705 dbus_message_iter_next(&sub);
2706 }
2707
2708 return 0;
2709
2710 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
2711 DBusMessageIter sub;
2712
2713 dbus_message_iter_recurse(iter, &sub);
2714 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2715 ExecStatusInfo info;
2716
2717 zero(info);
2718 if (exec_status_info_deserialize(&sub, &info) >= 0) {
2719 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
2720 char *t;
2721
2722 t = strv_join(info.argv, " ");
2723
2724 printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
2725 name,
2726 strna(info.path),
2727 strna(t),
2728 yes_no(info.ignore),
2729 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
2730 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
2731 (unsigned) info. pid,
2732 sigchld_code_to_string(info.code),
2733 info.status,
2734 info.code == CLD_EXITED ? "" : "/",
2735 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
2736
2737 free(t);
2738 }
2739
2740 free(info.path);
2741 strv_free(info.argv);
2742
2743 dbus_message_iter_next(&sub);
2744 }
2745
2746 return 0;
2747 }
2748
2749 break;
2750 }
2751
2752 if (generic_print_property(name, iter, arg_all) > 0)
2753 return 0;
2754
2755 if (arg_all)
2756 printf("%s=[unprintable]\n", name);
2757
2758 return 0;
2759 }
2760
2761 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
2762 DBusMessage *reply = NULL;
2763 const char *interface = "";
2764 int r;
2765 DBusMessageIter iter, sub, sub2, sub3;
2766 UnitStatusInfo info;
2767 ExecStatusInfo *p;
2768
2769 assert(path);
2770 assert(new_line);
2771
2772 zero(info);
2773
2774 r = bus_method_call_with_reply (
2775 bus,
2776 "org.freedesktop.systemd1",
2777 path,
2778 "org.freedesktop.DBus.Properties",
2779 "GetAll",
2780 &reply,
2781 NULL,
2782 DBUS_TYPE_STRING, &interface,
2783 DBUS_TYPE_INVALID);
2784 if (r)
2785 goto finish;
2786
2787 if (!dbus_message_iter_init(reply, &iter) ||
2788 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
2789 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
2790 log_error("Failed to parse reply.");
2791 r = -EIO;
2792 goto finish;
2793 }
2794
2795 dbus_message_iter_recurse(&iter, &sub);
2796
2797 if (*new_line)
2798 printf("\n");
2799
2800 *new_line = true;
2801
2802 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2803 const char *name;
2804
2805 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
2806 log_error("Failed to parse reply.");
2807 r = -EIO;
2808 goto finish;
2809 }
2810
2811 dbus_message_iter_recurse(&sub, &sub2);
2812
2813 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
2814 log_error("Failed to parse reply.");
2815 r = -EIO;
2816 goto finish;
2817 }
2818
2819 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
2820 log_error("Failed to parse reply.");
2821 r = -EIO;
2822 goto finish;
2823 }
2824
2825 dbus_message_iter_recurse(&sub2, &sub3);
2826
2827 if (show_properties)
2828 r = print_property(name, &sub3);
2829 else
2830 r = status_property(name, &sub3, &info);
2831
2832 if (r < 0) {
2833 log_error("Failed to parse reply.");
2834 r = -EIO;
2835 goto finish;
2836 }
2837
2838 dbus_message_iter_next(&sub);
2839 }
2840
2841 r = 0;
2842
2843 if (!show_properties) {
2844 if (streq(verb, "help"))
2845 show_unit_help(&info);
2846 else
2847 print_status_info(&info);
2848 }
2849
2850 strv_free(info.documentation);
2851
2852 if (!streq_ptr(info.active_state, "active") &&
2853 !streq_ptr(info.active_state, "reloading") &&
2854 streq(verb, "status"))
2855 /* According to LSB: "program not running" */
2856 r = 3;
2857
2858 while ((p = info.exec)) {
2859 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
2860 exec_status_info_free(p);
2861 }
2862
2863 finish:
2864 if (reply)
2865 dbus_message_unref(reply);
2866
2867 return r;
2868 }
2869
2870 static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
2871 DBusMessage *reply = NULL;
2872 const char *path = NULL;
2873 DBusError error;
2874 int r;
2875
2876 dbus_error_init(&error);
2877
2878 r = bus_method_call_with_reply (
2879 bus,
2880 "org.freedesktop.systemd1",
2881 "/org/freedesktop/systemd1",
2882 "org.freedesktop.systemd1.Manager",
2883 "GetUnitByPID",
2884 &reply,
2885 NULL,
2886 DBUS_TYPE_UINT32, &pid,
2887 DBUS_TYPE_INVALID);
2888 if (r)
2889 goto finish;
2890
2891 if (!dbus_message_get_args(reply, &error,
2892 DBUS_TYPE_OBJECT_PATH, &path,
2893 DBUS_TYPE_INVALID)) {
2894 log_error("Failed to parse reply: %s", bus_error_message(&error));
2895 r = -EIO;
2896 goto finish;
2897 }
2898
2899 r = show_one(verb, bus, path, false, new_line);
2900
2901 finish:
2902 if (reply)
2903 dbus_message_unref(reply);
2904
2905 dbus_error_free(&error);
2906
2907 return r;
2908 }
2909
2910 static int show(DBusConnection *bus, char **args) {
2911 int r, ret = 0;
2912 bool show_properties, new_line = false;
2913 char **name;
2914
2915 assert(bus);
2916 assert(args);
2917
2918 show_properties = streq(args[0], "show");
2919
2920 if (show_properties)
2921 pager_open_if_enabled();
2922
2923 if (show_properties && strv_length(args) <= 1) {
2924 /* If not argument is specified inspect the manager
2925 * itself */
2926
2927 return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
2928 }
2929
2930 STRV_FOREACH(name, args+1) {
2931 uint32_t id;
2932
2933 if (safe_atou32(*name, &id) < 0) {
2934 char *p, *n;
2935 /* Interpret as unit name */
2936
2937 n = unit_name_mangle(*name);
2938 p = unit_dbus_path_from_name(n ? n : *name);
2939 free(n);
2940 if (!p)
2941 return log_oom();
2942
2943 r = show_one(args[0], bus, p, show_properties, &new_line);
2944 free(p);
2945
2946 if (r != 0)
2947 ret = r;
2948
2949 } else if (show_properties) {
2950
2951 /* Interpret as job id */
2952
2953 char *p;
2954 if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
2955 return log_oom();
2956
2957 r = show_one(args[0], bus, p, show_properties, &new_line);
2958 free(p);
2959
2960 if (r != 0)
2961 ret = r;
2962
2963 } else {
2964
2965 /* Interpret as PID */
2966
2967 r = show_one_by_pid(args[0], bus, id, &new_line);
2968 if (r != 0)
2969 ret = r;
2970 }
2971 }
2972
2973 return ret;
2974 }
2975
2976 static int dump(DBusConnection *bus, char **args) {
2977 DBusMessage *reply = NULL;
2978 DBusError error;
2979 int r;
2980 const char *text;
2981
2982 dbus_error_init(&error);
2983
2984 pager_open_if_enabled();
2985
2986 r = bus_method_call_with_reply (
2987 bus,
2988 "org.freedesktop.systemd1",
2989 "/org/freedesktop/systemd1",
2990 "org.freedesktop.systemd1.Manager",
2991 "Dump",
2992 &reply,
2993 NULL,
2994 DBUS_TYPE_INVALID);
2995 if (r)
2996 goto finish;
2997
2998 if (!dbus_message_get_args(reply, &error,
2999 DBUS_TYPE_STRING, &text,
3000 DBUS_TYPE_INVALID)) {
3001 log_error("Failed to parse reply: %s", bus_error_message(&error));
3002 r = -EIO;
3003 goto finish;
3004 }
3005
3006 fputs(text, stdout);
3007
3008 finish:
3009 if (reply)
3010 dbus_message_unref(reply);
3011
3012 dbus_error_free(&error);
3013
3014 return r;
3015 }
3016
3017 static int snapshot(DBusConnection *bus, char **args) {
3018 DBusMessage *reply = NULL;
3019 DBusError error;
3020 int r;
3021 dbus_bool_t cleanup = FALSE;
3022 DBusMessageIter iter, sub;
3023 const char
3024 *name = "", *path, *id,
3025 *interface = "org.freedesktop.systemd1.Unit",
3026 *property = "Id";
3027 char *n;
3028
3029 dbus_error_init(&error);
3030
3031 if (strv_length(args) > 1)
3032 name = args[1];
3033
3034 n = unit_name_mangle(name);
3035 r = bus_method_call_with_reply (
3036 bus,
3037 "org.freedesktop.systemd1",
3038 "/org/freedesktop/systemd1",
3039 "org.freedesktop.systemd1.Manager",
3040 "CreateSnapshot",
3041 &reply,
3042 NULL,
3043 DBUS_TYPE_STRING, n ? (const char**) &n : &name,
3044 DBUS_TYPE_BOOLEAN, &cleanup,
3045 DBUS_TYPE_INVALID);
3046 free(n);
3047 if (r)
3048 goto finish;
3049
3050 if (!dbus_message_get_args(reply, &error,
3051 DBUS_TYPE_OBJECT_PATH, &path,
3052 DBUS_TYPE_INVALID)) {
3053 log_error("Failed to parse reply: %s", bus_error_message(&error));
3054 r = -EIO;
3055 goto finish;
3056 }
3057
3058 dbus_message_unref(reply);
3059 r = bus_method_call_with_reply (
3060 bus,
3061 "org.freedesktop.systemd1",
3062 path,
3063 "org.freedesktop.DBus.Properties",
3064 "Get",
3065 &reply,
3066 NULL,
3067 DBUS_TYPE_STRING, &interface,
3068 DBUS_TYPE_STRING, &property,
3069 DBUS_TYPE_INVALID);
3070 if (r)
3071 goto finish;
3072
3073 if (!dbus_message_iter_init(reply, &iter) ||
3074 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
3075 log_error("Failed to parse reply.");
3076 r = -EIO;
3077 goto finish;
3078 }
3079
3080 dbus_message_iter_recurse(&iter, &sub);
3081
3082 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
3083 log_error("Failed to parse reply.");
3084 r = -EIO;
3085 goto finish;
3086 }
3087
3088 dbus_message_iter_get_basic(&sub, &id);
3089
3090 if (!arg_quiet)
3091 puts(id);
3092
3093 finish:
3094 if (reply)
3095 dbus_message_unref(reply);
3096
3097 dbus_error_free(&error);
3098
3099 return r;
3100 }
3101
3102 static int delete_snapshot(DBusConnection *bus, char **args) {
3103 DBusMessage *reply = NULL;
3104 int r = 0;
3105 DBusError error;
3106 char **name;
3107
3108 assert(args);
3109
3110 dbus_error_init(&error);
3111
3112 STRV_FOREACH(name, args+1) {
3113 const char *path = NULL;
3114 char *n;
3115
3116 n = unit_name_mangle(*name);
3117 r = bus_method_call_with_reply (
3118 bus,
3119 "org.freedesktop.systemd1",
3120 "/org/freedesktop/systemd1",
3121 "org.freedesktop.systemd1.Manager",
3122 "GetUnit",
3123 &reply,
3124 NULL,
3125 DBUS_TYPE_STRING, n ? &n : name,
3126 DBUS_TYPE_INVALID);
3127 free(n);
3128 if (r)
3129 goto finish;
3130
3131 if (!dbus_message_get_args(reply, &error,
3132 DBUS_TYPE_OBJECT_PATH, &path,
3133 DBUS_TYPE_INVALID)) {
3134 log_error("Failed to parse reply: %s", bus_error_message(&error));
3135 r = -EIO;
3136 dbus_message_unref(reply);
3137 dbus_error_free(&error);
3138 goto finish;
3139 }
3140 dbus_message_unref(reply);
3141
3142 r = bus_method_call_with_reply (
3143 bus,
3144 "org.freedesktop.systemd1",
3145 path,
3146 "org.freedesktop.systemd1.Snapshot",
3147 "Remove",
3148 NULL,
3149 NULL,
3150 DBUS_TYPE_INVALID);
3151 if (r)
3152 goto finish;
3153 }
3154
3155 finish:
3156 return r;
3157 }
3158
3159 static int daemon_reload(DBusConnection *bus, char **args) {
3160 int r;
3161 const char *method;
3162 DBusError error;
3163
3164 if (arg_action == ACTION_RELOAD)
3165 method = "Reload";
3166 else if (arg_action == ACTION_REEXEC)
3167 method = "Reexecute";
3168 else {
3169 assert(arg_action == ACTION_SYSTEMCTL);
3170
3171 method =
3172 streq(args[0], "clear-jobs") ||
3173 streq(args[0], "cancel") ? "ClearJobs" :
3174 streq(args[0], "daemon-reexec") ? "Reexecute" :
3175 streq(args[0], "reset-failed") ? "ResetFailed" :
3176 streq(args[0], "halt") ? "Halt" :
3177 streq(args[0], "poweroff") ? "PowerOff" :
3178 streq(args[0], "reboot") ? "Reboot" :
3179 streq(args[0], "kexec") ? "KExec" :
3180 streq(args[0], "exit") ? "Exit" :
3181 /* "daemon-reload" */ "Reload";
3182 }
3183
3184 r = bus_method_call_with_reply (
3185 bus,
3186 "org.freedesktop.systemd1",
3187 "/org/freedesktop/systemd1",
3188 "org.freedesktop.systemd1.Manager",
3189 method,
3190 NULL,
3191 &error,
3192 DBUS_TYPE_INVALID);
3193
3194 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
3195 /* There's always a fallback possible for
3196 * legacy actions. */
3197 r = -EADDRNOTAVAIL;
3198 else if (r == -ETIMEDOUT && streq(method, "Reexecute"))
3199 /* On reexecution, we expect a disconnect, not
3200 * a reply */
3201 r = 0;
3202 else if (r)
3203 log_error("Failed to issue method call: %s", bus_error_message(&error));
3204 dbus_error_free(&error);
3205
3206 return r;
3207 }
3208
3209 static int reset_failed(DBusConnection *bus, char **args) {
3210 int r = 0;
3211 char **name, *n;
3212
3213 if (strv_length(args) <= 1)
3214 return daemon_reload(bus, args);
3215
3216 STRV_FOREACH(name, args+1) {
3217 n = unit_name_mangle(*name);
3218 r = bus_method_call_with_reply (
3219 bus,
3220 "org.freedesktop.systemd1",
3221 "/org/freedesktop/systemd1",
3222 "org.freedesktop.systemd1.Manager",
3223 "ResetFailedUnit",
3224 NULL,
3225 NULL,
3226 DBUS_TYPE_STRING, n ? &n : name,
3227 DBUS_TYPE_INVALID);
3228 free(n);
3229 if (r)
3230 goto finish;
3231 }
3232
3233 finish:
3234 return r;
3235 }
3236
3237 static int show_enviroment(DBusConnection *bus, char **args) {
3238 DBusMessage *reply = NULL;
3239 DBusMessageIter iter, sub, sub2;
3240 int r;
3241 const char
3242 *interface = "org.freedesktop.systemd1.Manager",
3243 *property = "Environment";
3244
3245 pager_open_if_enabled();
3246
3247 r = bus_method_call_with_reply (
3248 bus,
3249 "org.freedesktop.systemd1",
3250 "/org/freedesktop/systemd1",
3251 "org.freedesktop.DBus.Properties",
3252 "Get",
3253 &reply,
3254 NULL,
3255 DBUS_TYPE_STRING, &interface,
3256 DBUS_TYPE_STRING, &property,
3257 DBUS_TYPE_INVALID);
3258 if (r)
3259 goto finish;
3260
3261 if (!dbus_message_iter_init(reply, &iter) ||
3262 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
3263 log_error("Failed to parse reply.");
3264 r = -EIO;
3265 goto finish;
3266 }
3267
3268 dbus_message_iter_recurse(&iter, &sub);
3269
3270 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
3271 dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING) {
3272 log_error("Failed to parse reply.");
3273 r = -EIO;
3274 goto finish;
3275 }
3276
3277 dbus_message_iter_recurse(&sub, &sub2);
3278
3279 while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
3280 const char *text;
3281
3282 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
3283 log_error("Failed to parse reply.");
3284 r = -EIO;
3285 goto finish;
3286 }
3287
3288 dbus_message_iter_get_basic(&sub2, &text);
3289 printf("%s\n", text);
3290
3291 dbus_message_iter_next(&sub2);
3292 }
3293
3294 r = 0;
3295
3296 finish:
3297 if (reply)
3298 dbus_message_unref(reply);
3299
3300 return r;
3301 }
3302
3303 static int switch_root(DBusConnection *bus, char **args) {
3304 unsigned l;
3305 const char *root, *init;
3306
3307 l = strv_length(args);
3308 if (l < 2 || l > 3) {
3309 log_error("Wrong number of arguments.");
3310 return -EINVAL;
3311 }
3312
3313 root = args[1];
3314 init = l >= 3 ? args[2] : "";
3315
3316 return bus_method_call_with_reply (
3317 bus,
3318 "org.freedesktop.systemd1",
3319 "/org/freedesktop/systemd1",
3320 "org.freedesktop.systemd1.Manager",
3321 "SwitchRoot",
3322 NULL,
3323 NULL,
3324 DBUS_TYPE_STRING, &root,
3325 DBUS_TYPE_STRING, &init,
3326 DBUS_TYPE_INVALID);
3327 }
3328
3329 static int set_environment(DBusConnection *bus, char **args) {
3330 DBusMessage *m = NULL, *reply = NULL;
3331 DBusError error;
3332 int r;
3333 const char *method;
3334 DBusMessageIter iter, sub;
3335 char **name;
3336
3337 dbus_error_init(&error);
3338
3339 method = streq(args[0], "set-environment")
3340 ? "SetEnvironment"
3341 : "UnsetEnvironment";
3342
3343 if (!(m = dbus_message_new_method_call(
3344 "org.freedesktop.systemd1",
3345 "/org/freedesktop/systemd1",
3346 "org.freedesktop.systemd1.Manager",
3347 method))) {
3348
3349 log_error("Could not allocate message.");
3350 return -ENOMEM;
3351 }
3352
3353 dbus_message_iter_init_append(m, &iter);
3354
3355 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
3356 log_error("Could not append arguments to message.");
3357 r = -ENOMEM;
3358 goto finish;
3359 }
3360
3361 STRV_FOREACH(name, args+1)
3362 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, name)) {
3363 log_error("Could not append arguments to message.");
3364 r = -ENOMEM;
3365 goto finish;
3366 }
3367
3368 if (!dbus_message_iter_close_container(&iter, &sub)) {
3369 log_error("Could not append arguments to message.");
3370 r = -ENOMEM;
3371 goto finish;
3372 }
3373
3374 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3375 log_error("Failed to issue method call: %s", bus_error_message(&error));
3376 r = -EIO;
3377 goto finish;
3378 }
3379
3380 r = 0;
3381
3382 finish:
3383 if (m)
3384 dbus_message_unref(m);
3385
3386 if (reply)
3387 dbus_message_unref(reply);
3388
3389 dbus_error_free(&error);
3390
3391 return r;
3392 }
3393
3394 static int enable_sysv_units(char **args) {
3395 int r = 0;
3396
3397 #if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA))
3398 const char *verb = args[0];
3399 unsigned f = 1, t = 1;
3400 LookupPaths paths;
3401
3402 if (arg_scope != UNIT_FILE_SYSTEM)
3403 return 0;
3404
3405 if (!streq(verb, "enable") &&
3406 !streq(verb, "disable") &&
3407 !streq(verb, "is-enabled"))
3408 return 0;
3409
3410 /* Processes all SysV units, and reshuffles the array so that
3411 * afterwards only the native units remain */
3412
3413 zero(paths);
3414 r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL);
3415 if (r < 0)
3416 return r;
3417
3418 r = 0;
3419 for (f = 1; args[f]; f++) {
3420 const char *name;
3421 char *p;
3422 bool found_native = false, found_sysv;
3423 unsigned c = 1;
3424 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
3425 char **k, *l, *q = NULL;
3426 int j;
3427 pid_t pid;
3428 siginfo_t status;
3429
3430 name = args[f];
3431
3432 if (!endswith(name, ".service"))
3433 continue;
3434
3435 if (path_is_absolute(name))
3436 continue;
3437
3438 STRV_FOREACH(k, paths.unit_path) {
3439 p = NULL;
3440
3441 if (!isempty(arg_root))
3442 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
3443 else
3444 asprintf(&p, "%s/%s", *k, name);
3445
3446 if (!p) {
3447 r = log_oom();
3448 goto finish;
3449 }
3450
3451 found_native = access(p, F_OK) >= 0;
3452 free(p);
3453
3454 if (found_native)
3455 break;
3456 }
3457
3458 if (found_native)
3459 continue;
3460
3461 p = NULL;
3462 if (!isempty(arg_root))
3463 asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
3464 else
3465 asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
3466 if (!p) {
3467 r = log_oom();
3468 goto finish;
3469 }
3470
3471 p[strlen(p) - sizeof(".service") + 1] = 0;
3472 found_sysv = access(p, F_OK) >= 0;
3473
3474 if (!found_sysv) {
3475 free(p);
3476 continue;
3477 }
3478
3479 /* Mark this entry, so that we don't try enabling it as native unit */
3480 args[f] = (char*) "";
3481
3482 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
3483
3484 if (!isempty(arg_root))
3485 argv[c++] = q = strappend("--root=", arg_root);
3486
3487 argv[c++] = path_get_file_name(p);
3488 argv[c++] =
3489 streq(verb, "enable") ? "on" :
3490 streq(verb, "disable") ? "off" : "--level=5";
3491 argv[c] = NULL;
3492
3493 l = strv_join((char**)argv, " ");
3494 if (!l) {
3495 free(q);
3496 free(p);
3497 r = log_oom();
3498 goto finish;
3499 }
3500
3501 log_info("Executing %s", l);
3502 free(l);
3503
3504 pid = fork();
3505 if (pid < 0) {
3506 log_error("Failed to fork: %m");
3507 free(p);
3508 free(q);
3509 r = -errno;
3510 goto finish;
3511 } else if (pid == 0) {
3512 /* Child */
3513
3514 execv(argv[0], (char**) argv);
3515 _exit(EXIT_FAILURE);
3516 }
3517
3518 free(p);
3519 free(q);
3520
3521 j = wait_for_terminate(pid, &status);
3522 if (j < 0) {
3523 log_error("Failed to wait for child: %s", strerror(-r));
3524 r = j;
3525 goto finish;
3526 }
3527
3528 if (status.si_code == CLD_EXITED) {
3529 if (streq(verb, "is-enabled")) {
3530 if (status.si_status == 0) {
3531 if (!arg_quiet)
3532 puts("enabled");
3533 r = 1;
3534 } else {
3535 if (!arg_quiet)
3536 puts("disabled");
3537 }
3538
3539 } else if (status.si_status != 0) {
3540 r = -EINVAL;
3541 goto finish;
3542 }
3543 } else {
3544 r = -EPROTO;
3545 goto finish;
3546 }
3547 }
3548
3549 finish:
3550 lookup_paths_free(&paths);
3551
3552 /* Drop all SysV units */
3553 for (f = 1, t = 1; args[f]; f++) {
3554
3555 if (isempty(args[f]))
3556 continue;
3557
3558 args[t++] = args[f];
3559 }
3560
3561 args[t] = NULL;
3562
3563 #endif
3564 return r;
3565 }
3566
3567 static int mangle_names(char **original_names, char ***mangled_names) {
3568 char **i, **l, **name;
3569
3570 l = new(char*, strv_length(original_names) + 1);
3571 if (!l)
3572 return log_oom();
3573
3574 i = l;
3575 STRV_FOREACH(name, original_names) {
3576 *i = unit_name_mangle(*name);
3577 if (!*i) {
3578 strv_free(l);
3579 return log_oom();
3580 }
3581
3582 i++;
3583 }
3584
3585 *i = NULL;
3586 *mangled_names = l;
3587
3588 return 0;
3589 }
3590
3591 static int enable_unit(DBusConnection *bus, char **args) {
3592 const char *verb = args[0];
3593 UnitFileChange *changes = NULL;
3594 unsigned n_changes = 0, i;
3595 int carries_install_info = -1;
3596 DBusMessage *m = NULL, *reply = NULL;
3597 int r;
3598 DBusError error;
3599 char **mangled_names = NULL;
3600
3601 r = enable_sysv_units(args);
3602 if (r < 0)
3603 return r;
3604
3605 if (!args[1])
3606 return 0;
3607
3608 dbus_error_init(&error);
3609
3610 if (!bus || avoid_bus()) {
3611 if (streq(verb, "enable")) {
3612 r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3613 carries_install_info = r;
3614 } else if (streq(verb, "disable"))
3615 r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3616 else if (streq(verb, "reenable")) {
3617 r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3618 carries_install_info = r;
3619 } else if (streq(verb, "link"))
3620 r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3621 else if (streq(verb, "preset")) {
3622 r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3623 carries_install_info = r;
3624 } else if (streq(verb, "mask"))
3625 r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3626 else if (streq(verb, "unmask"))
3627 r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3628 else
3629 assert_not_reached("Unknown verb");
3630
3631 if (r < 0) {
3632 log_error("Operation failed: %s", strerror(-r));
3633 goto finish;
3634 }
3635
3636 if (!arg_quiet) {
3637 for (i = 0; i < n_changes; i++) {
3638 if (changes[i].type == UNIT_FILE_SYMLINK)
3639 log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
3640 else
3641 log_info("rm '%s'", changes[i].path);
3642 }
3643 }
3644
3645 } else {
3646 const char *method;
3647 bool send_force = true, expect_carries_install_info = false;
3648 dbus_bool_t a, b;
3649 DBusMessageIter iter, sub, sub2;
3650
3651 if (streq(verb, "enable")) {
3652 method = "EnableUnitFiles";
3653 expect_carries_install_info = true;
3654 } else if (streq(verb, "disable")) {
3655 method = "DisableUnitFiles";
3656 send_force = false;
3657 } else if (streq(verb, "reenable")) {
3658 method = "ReenableUnitFiles";
3659 expect_carries_install_info = true;
3660 } else if (streq(verb, "link"))
3661 method = "LinkUnitFiles";
3662 else if (streq(verb, "preset")) {
3663 method = "PresetUnitFiles";
3664 expect_carries_install_info = true;
3665 } else if (streq(verb, "mask"))
3666 method = "MaskUnitFiles";
3667 else if (streq(verb, "unmask")) {
3668 method = "UnmaskUnitFiles";
3669 send_force = false;
3670 } else
3671 assert_not_reached("Unknown verb");
3672
3673 m = dbus_message_new_method_call(
3674 "org.freedesktop.systemd1",
3675 "/org/freedesktop/systemd1",
3676 "org.freedesktop.systemd1.Manager",
3677 method);
3678 if (!m) {
3679 r = log_oom();
3680 goto finish;
3681 }
3682
3683 dbus_message_iter_init_append(m, &iter);
3684
3685 r = mangle_names(args+1, &mangled_names);
3686 if(r < 0)
3687 goto finish;
3688
3689 r = bus_append_strv_iter(&iter, mangled_names);
3690 if (r < 0) {
3691 log_error("Failed to append unit files.");
3692 goto finish;
3693 }
3694
3695 a = arg_runtime;
3696 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
3697 log_error("Failed to append runtime boolean.");
3698 r = -ENOMEM;
3699 goto finish;
3700 }
3701
3702 if (send_force) {
3703 b = arg_force;
3704
3705 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
3706 log_error("Failed to append force boolean.");
3707 r = -ENOMEM;
3708 goto finish;
3709 }
3710 }
3711
3712 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3713 if (!reply) {
3714 log_error("Failed to issue method call: %s", bus_error_message(&error));
3715 r = -EIO;
3716 goto finish;
3717 }
3718
3719 if (!dbus_message_iter_init(reply, &iter)) {
3720 log_error("Failed to initialize iterator.");
3721 goto finish;
3722 }
3723
3724 if (expect_carries_install_info) {
3725 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
3726 if (r < 0) {
3727 log_error("Failed to parse reply.");
3728 goto finish;
3729 }
3730
3731 carries_install_info = b;
3732 }
3733
3734 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3735 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
3736 log_error("Failed to parse reply.");
3737 r = -EIO;
3738 goto finish;
3739 }
3740
3741 dbus_message_iter_recurse(&iter, &sub);
3742 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3743 const char *type, *path, *source;
3744
3745 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
3746 log_error("Failed to parse reply.");
3747 r = -EIO;
3748 goto finish;
3749 }
3750
3751 dbus_message_iter_recurse(&sub, &sub2);
3752
3753 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
3754 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
3755 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
3756 log_error("Failed to parse reply.");
3757 r = -EIO;
3758 goto finish;
3759 }
3760
3761 if (!arg_quiet) {
3762 if (streq(type, "symlink"))
3763 log_info("ln -s '%s' '%s'", source, path);
3764 else
3765 log_info("rm '%s'", path);
3766 }
3767
3768 dbus_message_iter_next(&sub);
3769 }
3770
3771 /* Try to reload if enabeld */
3772 if (!arg_no_reload)
3773 r = daemon_reload(bus, args);
3774 }
3775
3776 if (carries_install_info == 0)
3777 log_warning("The unit files have no [Install] section. They are not meant to be enabled using systemctl.");
3778
3779 finish:
3780 if (m)
3781 dbus_message_unref(m);
3782
3783 if (reply)
3784 dbus_message_unref(reply);
3785
3786 unit_file_changes_free(changes, n_changes);
3787
3788 dbus_error_free(&error);
3789
3790 strv_free(mangled_names);
3791
3792 return r;
3793 }
3794
3795 static int unit_is_enabled(DBusConnection *bus, char **args) {
3796 DBusError error;
3797 int r;
3798 DBusMessage *reply = NULL;
3799 bool enabled;
3800 char **name;
3801
3802 dbus_error_init(&error);
3803
3804 r = enable_sysv_units(args);
3805 if (r < 0)
3806 return r;
3807
3808 enabled = r > 0;
3809
3810 if (!bus || avoid_bus()) {
3811
3812 STRV_FOREACH(name, args+1) {
3813 UnitFileState state;
3814
3815 state = unit_file_get_state(arg_scope, arg_root, *name);
3816 if (state < 0) {
3817 r = state;
3818 goto finish;
3819 }
3820
3821 if (state == UNIT_FILE_ENABLED ||
3822 state == UNIT_FILE_ENABLED_RUNTIME ||
3823 state == UNIT_FILE_STATIC)
3824 enabled = true;
3825
3826 if (!arg_quiet)
3827 puts(unit_file_state_to_string(state));
3828 }
3829
3830 } else {
3831 STRV_FOREACH(name, args+1) {
3832 const char *s;
3833
3834 r = bus_method_call_with_reply (
3835 bus,
3836 "org.freedesktop.systemd1",
3837 "/org/freedesktop/systemd1",
3838 "org.freedesktop.systemd1.Manager",
3839 "GetUnitFileState",
3840 &reply,
3841 NULL,
3842 DBUS_TYPE_STRING, name,
3843 DBUS_TYPE_INVALID);
3844 if (r)
3845 goto finish;
3846
3847 if (!dbus_message_get_args(reply, &error,
3848 DBUS_TYPE_STRING, &s,
3849 DBUS_TYPE_INVALID)) {
3850 log_error("Failed to parse reply: %s", bus_error_message(&error));
3851 r = -EIO;
3852 goto finish;
3853 }
3854
3855 dbus_message_unref(reply);
3856 reply = NULL;
3857
3858 if (streq(s, "enabled") ||
3859 streq(s, "enabled-runtime") ||
3860 streq(s, "static"))
3861 enabled = true;
3862
3863 if (!arg_quiet)
3864 puts(s);
3865 }
3866 }
3867
3868 r = enabled ? 0 : 1;
3869
3870 finish:
3871 if (reply)
3872 dbus_message_unref(reply);
3873
3874 dbus_error_free(&error);
3875 return r;
3876 }
3877
3878 static int systemctl_help(void) {
3879
3880 pager_open_if_enabled();
3881
3882 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
3883 "Query or send control commands to the systemd manager.\n\n"
3884 " -h --help Show this help\n"
3885 " --version Show package version\n"
3886 " -t --type=TYPE List only units of a particular type\n"
3887 " -p --property=NAME Show only properties by this name\n"
3888 " -a --all Show all units/properties, including dead/empty ones\n"
3889 " --failed Show only failed units\n"
3890 " --full Don't ellipsize unit names on output\n"
3891 " --fail When queueing a new job, fail if conflicting jobs are\n"
3892 " pending\n"
3893 " --ignore-dependencies\n"
3894 " When queueing a new job, ignore all its dependencies\n"
3895 " --kill-who=WHO Who to send signal to\n"
3896 " -s --signal=SIGNAL Which signal to send\n"
3897 " -H --host=[USER@]HOST\n"
3898 " Show information for remote host\n"
3899 " -P --privileged Acquire privileges before execution\n"
3900 " -q --quiet Suppress output\n"
3901 " --no-block Do not wait until operation finished\n"
3902 " --no-wall Don't send wall message before halt/power-off/reboot\n"
3903 " --no-reload When enabling/disabling unit files, don't reload daemon\n"
3904 " configuration\n"
3905 " --no-legend Do not print a legend (column headers and hints)\n"
3906 " --no-pager Do not pipe output into a pager\n"
3907 " --no-ask-password\n"
3908 " Do not ask for system passwords\n"
3909 " --order When generating graph for dot, show only order\n"
3910 " --require When generating graph for dot, show only requirement\n"
3911 " --system Connect to system manager\n"
3912 " --user Connect to user service manager\n"
3913 " --global Enable/disable unit files globally\n"
3914 " -f --force When enabling unit files, override existing symlinks\n"
3915 " When shutting down, execute action immediately\n"
3916 " --root=PATH Enable unit files in the specified root directory\n"
3917 " --runtime Enable unit files only temporarily until next reboot\n"
3918 " -n --lines=INTEGER Journal entries to show\n"
3919 " --follow Follow journal\n"
3920 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
3921 " verbose, export, json, json-pretty, cat)\n\n"
3922 "Unit Commands:\n"
3923 " list-units List loaded units\n"
3924 " start [NAME...] Start (activate) one or more units\n"
3925 " stop [NAME...] Stop (deactivate) one or more units\n"
3926 " reload [NAME...] Reload one or more units\n"
3927 " restart [NAME...] Start or restart one or more units\n"
3928 " try-restart [NAME...] Restart one or more units if active\n"
3929 " reload-or-restart [NAME...] Reload one or more units is possible,\n"
3930 " otherwise start or restart\n"
3931 " reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
3932 " otherwise restart if active\n"
3933 " isolate [NAME] Start one unit and stop all others\n"
3934 " kill [NAME...] Send signal to processes of a unit\n"
3935 " is-active [NAME...] Check whether units are active\n"
3936 " status [NAME...|PID...] Show runtime status of one or more units\n"
3937 " show [NAME...|JOB...] Show properties of one or more\n"
3938 " units/jobs or the manager\n"
3939 " help [NAME...|PID...] Show manual for one or more units\n"
3940 " reset-failed [NAME...] Reset failed state for all, one, or more\n"
3941 " units\n"
3942 " load [NAME...] Load one or more units\n\n"
3943 "Unit File Commands:\n"
3944 " list-unit-files List installed unit files\n"
3945 " enable [NAME...] Enable one or more unit files\n"
3946 " disable [NAME...] Disable one or more unit files\n"
3947 " reenable [NAME...] Reenable one or more unit files\n"
3948 " preset [NAME...] Enable/disable one or more unit files\n"
3949 " based on preset configuration\n"
3950 " mask [NAME...] Mask one or more units\n"
3951 " unmask [NAME...] Unmask one or more units\n"
3952 " link [PATH...] Link one or more units files into\n"
3953 " the search path\n"
3954 " is-enabled [NAME...] Check whether unit files are enabled\n\n"
3955 "Job Commands:\n"
3956 " list-jobs List jobs\n"
3957 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
3958 "Status Commands:\n"
3959 " dump Dump server status\n"
3960 " dot Dump dependency graph for dot(1)\n\n"
3961 "Snapshot Commands:\n"
3962 " snapshot [NAME] Create a snapshot\n"
3963 " delete [NAME...] Remove one or more snapshots\n\n"
3964 "Environment Commands:\n"
3965 " show-environment Dump environment\n"
3966 " set-environment [NAME=VALUE...] Set one or more environment variables\n"
3967 " unset-environment [NAME...] Unset one or more environment variables\n\n"
3968 "Manager Lifecycle Commands:\n"
3969 " daemon-reload Reload systemd manager configuration\n"
3970 " daemon-reexec Reexecute systemd manager\n\n"
3971 "System Commands:\n"
3972 " default Enter system default mode\n"
3973 " rescue Enter system rescue mode\n"
3974 " emergency Enter system emergency mode\n"
3975 " halt Shut down and halt the system\n"
3976 " poweroff Shut down and power-off the system\n"
3977 " reboot Shut down and reboot the system\n"
3978 " kexec Shut down and reboot the system with kexec\n"
3979 " exit Request user instance exit\n"
3980 " switch-root [ROOT] [INIT] Change to a different root file system\n"
3981 " suspend Suspend the system\n"
3982 " hibernate Hibernate the system\n",
3983 program_invocation_short_name);
3984
3985 return 0;
3986 }
3987
3988 static int halt_help(void) {
3989
3990 printf("%s [OPTIONS...]\n\n"
3991 "%s the system.\n\n"
3992 " --help Show this help\n"
3993 " --halt Halt the machine\n"
3994 " -p --poweroff Switch off the machine\n"
3995 " --reboot Reboot the machine\n"
3996 " -f --force Force immediate halt/power-off/reboot\n"
3997 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
3998 " -d --no-wtmp Don't write wtmp record\n"
3999 " --no-wall Don't send wall message before halt/power-off/reboot\n",
4000 program_invocation_short_name,
4001 arg_action == ACTION_REBOOT ? "Reboot" :
4002 arg_action == ACTION_POWEROFF ? "Power off" :
4003 "Halt");
4004
4005 return 0;
4006 }
4007
4008 static int shutdown_help(void) {
4009
4010 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
4011 "Shut down the system.\n\n"
4012 " --help Show this help\n"
4013 " -H --halt Halt the machine\n"
4014 " -P --poweroff Power-off the machine\n"
4015 " -r --reboot Reboot the machine\n"
4016 " -h Equivalent to --poweroff, overridden by --halt\n"
4017 " -k Don't halt/power-off/reboot, just send warnings\n"
4018 " --no-wall Don't send wall message before halt/power-off/reboot\n"
4019 " -c Cancel a pending shutdown\n",
4020 program_invocation_short_name);
4021
4022 return 0;
4023 }
4024
4025 static int telinit_help(void) {
4026
4027 printf("%s [OPTIONS...] {COMMAND}\n\n"
4028 "Send control commands to the init daemon.\n\n"
4029 " --help Show this help\n"
4030 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
4031 "Commands:\n"
4032 " 0 Power-off the machine\n"
4033 " 6 Reboot the machine\n"
4034 " 2, 3, 4, 5 Start runlevelX.target unit\n"
4035 " 1, s, S Enter rescue mode\n"
4036 " q, Q Reload init daemon configuration\n"
4037 " u, U Reexecute init daemon\n",
4038 program_invocation_short_name);
4039
4040 return 0;
4041 }
4042
4043 static int runlevel_help(void) {
4044
4045 printf("%s [OPTIONS...]\n\n"
4046 "Prints the previous and current runlevel of the init system.\n\n"
4047 " --help Show this help\n",
4048 program_invocation_short_name);
4049
4050 return 0;
4051 }
4052
4053 static int systemctl_parse_argv(int argc, char *argv[]) {
4054
4055 enum {
4056 ARG_FAIL = 0x100,
4057 ARG_IGNORE_DEPENDENCIES,
4058 ARG_VERSION,
4059 ARG_USER,
4060 ARG_SYSTEM,
4061 ARG_GLOBAL,
4062 ARG_NO_BLOCK,
4063 ARG_NO_LEGEND,
4064 ARG_NO_PAGER,
4065 ARG_NO_WALL,
4066 ARG_ORDER,
4067 ARG_REQUIRE,
4068 ARG_ROOT,
4069 ARG_FULL,
4070 ARG_NO_RELOAD,
4071 ARG_KILL_WHO,
4072 ARG_NO_ASK_PASSWORD,
4073 ARG_FAILED,
4074 ARG_RUNTIME,
4075 ARG_FOLLOW,
4076 ARG_FORCE
4077 };
4078
4079 static const struct option options[] = {
4080 { "help", no_argument, NULL, 'h' },
4081 { "version", no_argument, NULL, ARG_VERSION },
4082 { "type", required_argument, NULL, 't' },
4083 { "property", required_argument, NULL, 'p' },
4084 { "all", no_argument, NULL, 'a' },
4085 { "failed", no_argument, NULL, ARG_FAILED },
4086 { "full", no_argument, NULL, ARG_FULL },
4087 { "fail", no_argument, NULL, ARG_FAIL },
4088 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
4089 { "user", no_argument, NULL, ARG_USER },
4090 { "system", no_argument, NULL, ARG_SYSTEM },
4091 { "global", no_argument, NULL, ARG_GLOBAL },
4092 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
4093 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
4094 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
4095 { "no-wall", no_argument, NULL, ARG_NO_WALL },
4096 { "quiet", no_argument, NULL, 'q' },
4097 { "order", no_argument, NULL, ARG_ORDER },
4098 { "require", no_argument, NULL, ARG_REQUIRE },
4099 { "root", required_argument, NULL, ARG_ROOT },
4100 { "force", no_argument, NULL, ARG_FORCE },
4101 { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
4102 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
4103 { "signal", required_argument, NULL, 's' },
4104 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
4105 { "host", required_argument, NULL, 'H' },
4106 { "privileged",no_argument, NULL, 'P' },
4107 { "runtime", no_argument, NULL, ARG_RUNTIME },
4108 { "lines", required_argument, NULL, 'n' },
4109 { "follow", no_argument, NULL, ARG_FOLLOW },
4110 { "output", required_argument, NULL, 'o' },
4111 { NULL, 0, NULL, 0 }
4112 };
4113
4114 int c;
4115
4116 assert(argc >= 0);
4117 assert(argv);
4118
4119 while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:", options, NULL)) >= 0) {
4120
4121 switch (c) {
4122
4123 case 'h':
4124 systemctl_help();
4125 return 0;
4126
4127 case ARG_VERSION:
4128 puts(PACKAGE_STRING);
4129 puts(DISTRIBUTION);
4130 puts(SYSTEMD_FEATURES);
4131 return 0;
4132
4133 case 't':
4134 if (unit_type_from_string(optarg) >= 0) {
4135 arg_type = optarg;
4136 break;
4137 }
4138 if (unit_load_state_from_string(optarg) >= 0) {
4139 arg_load_state = optarg;
4140 break;
4141 }
4142 log_error("Unkown unit type or load state '%s'.",
4143 optarg);
4144 return -EINVAL;
4145 case 'p': {
4146 char **l;
4147
4148 if (!(l = strv_append(arg_property, optarg)))
4149 return -ENOMEM;
4150
4151 strv_free(arg_property);
4152 arg_property = l;
4153
4154 /* If the user asked for a particular
4155 * property, show it to him, even if it is
4156 * empty. */
4157 arg_all = true;
4158 break;
4159 }
4160
4161 case 'a':
4162 arg_all = true;
4163 break;
4164
4165 case ARG_FAIL:
4166 arg_job_mode = "fail";
4167 break;
4168
4169 case ARG_IGNORE_DEPENDENCIES:
4170 arg_job_mode = "ignore-dependencies";
4171 break;
4172
4173 case ARG_USER:
4174 arg_scope = UNIT_FILE_USER;
4175 break;
4176
4177 case ARG_SYSTEM:
4178 arg_scope = UNIT_FILE_SYSTEM;
4179 break;
4180
4181 case ARG_GLOBAL:
4182 arg_scope = UNIT_FILE_GLOBAL;
4183 break;
4184
4185 case ARG_NO_BLOCK:
4186 arg_no_block = true;
4187 break;
4188
4189 case ARG_NO_LEGEND:
4190 arg_no_legend = true;
4191 break;
4192
4193 case ARG_NO_PAGER:
4194 arg_no_pager = true;
4195 break;
4196
4197 case ARG_NO_WALL:
4198 arg_no_wall = true;
4199 break;
4200
4201 case ARG_ORDER:
4202 arg_dot = DOT_ORDER;
4203 break;
4204
4205 case ARG_REQUIRE:
4206 arg_dot = DOT_REQUIRE;
4207 break;
4208
4209 case ARG_ROOT:
4210 arg_root = optarg;
4211 break;
4212
4213 case ARG_FULL:
4214 arg_full = true;
4215 break;
4216
4217 case ARG_FAILED:
4218 arg_failed = true;
4219 break;
4220
4221 case 'q':
4222 arg_quiet = true;
4223 break;
4224
4225 case ARG_FORCE:
4226 arg_force ++;
4227 break;
4228
4229 case ARG_FOLLOW:
4230 arg_follow = true;
4231 break;
4232
4233 case 'f':
4234 /* -f is short for both --follow and --force! */
4235 arg_force ++;
4236 arg_follow = true;
4237 break;
4238
4239 case ARG_NO_RELOAD:
4240 arg_no_reload = true;
4241 break;
4242
4243 case ARG_KILL_WHO:
4244 arg_kill_who = optarg;
4245 break;
4246
4247 case 's':
4248 if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
4249 log_error("Failed to parse signal string %s.", optarg);
4250 return -EINVAL;
4251 }
4252 break;
4253
4254 case ARG_NO_ASK_PASSWORD:
4255 arg_ask_password = false;
4256 break;
4257
4258 case 'P':
4259 arg_transport = TRANSPORT_POLKIT;
4260 break;
4261
4262 case 'H':
4263 arg_transport = TRANSPORT_SSH;
4264 arg_host = optarg;
4265 break;
4266
4267 case ARG_RUNTIME:
4268 arg_runtime = true;
4269 break;
4270
4271 case 'n':
4272 if (safe_atou(optarg, &arg_lines) < 0) {
4273 log_error("Failed to parse lines '%s'", optarg);
4274 return -EINVAL;
4275 }
4276 break;
4277
4278 case 'o':
4279 arg_output = output_mode_from_string(optarg);
4280 if (arg_output < 0) {
4281 log_error("Unknown output '%s'.", optarg);
4282 return -EINVAL;
4283 }
4284 break;
4285
4286 case '?':
4287 return -EINVAL;
4288
4289 default:
4290 log_error("Unknown option code '%c'.", c);
4291 return -EINVAL;
4292 }
4293 }
4294
4295 if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
4296 log_error("Cannot access user instance remotely.");
4297 return -EINVAL;
4298 }
4299
4300 return 1;
4301 }
4302
4303 static int halt_parse_argv(int argc, char *argv[]) {
4304
4305 enum {
4306 ARG_HELP = 0x100,
4307 ARG_HALT,
4308 ARG_REBOOT,
4309 ARG_NO_WALL
4310 };
4311
4312 static const struct option options[] = {
4313 { "help", no_argument, NULL, ARG_HELP },
4314 { "halt", no_argument, NULL, ARG_HALT },
4315 { "poweroff", no_argument, NULL, 'p' },
4316 { "reboot", no_argument, NULL, ARG_REBOOT },
4317 { "force", no_argument, NULL, 'f' },
4318 { "wtmp-only", no_argument, NULL, 'w' },
4319 { "no-wtmp", no_argument, NULL, 'd' },
4320 { "no-wall", no_argument, NULL, ARG_NO_WALL },
4321 { NULL, 0, NULL, 0 }
4322 };
4323
4324 int c, runlevel;
4325
4326 assert(argc >= 0);
4327 assert(argv);
4328
4329 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4330 if (runlevel == '0' || runlevel == '6')
4331 arg_force = 2;
4332
4333 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
4334 switch (c) {
4335
4336 case ARG_HELP:
4337 halt_help();
4338 return 0;
4339
4340 case ARG_HALT:
4341 arg_action = ACTION_HALT;
4342 break;
4343
4344 case 'p':
4345 if (arg_action != ACTION_REBOOT)
4346 arg_action = ACTION_POWEROFF;
4347 break;
4348
4349 case ARG_REBOOT:
4350 arg_action = ACTION_REBOOT;
4351 break;
4352
4353 case 'f':
4354 arg_force = 2;
4355 break;
4356
4357 case 'w':
4358 arg_dry = true;
4359 break;
4360
4361 case 'd':
4362 arg_no_wtmp = true;
4363 break;
4364
4365 case ARG_NO_WALL:
4366 arg_no_wall = true;
4367 break;
4368
4369 case 'i':
4370 case 'h':
4371 case 'n':
4372 /* Compatibility nops */
4373 break;
4374
4375 case '?':
4376 return -EINVAL;
4377
4378 default:
4379 log_error("Unknown option code '%c'.", c);
4380 return -EINVAL;
4381 }
4382 }
4383
4384 if (optind < argc) {
4385 log_error("Too many arguments.");
4386 return -EINVAL;
4387 }
4388
4389 return 1;
4390 }
4391
4392 static int parse_time_spec(const char *t, usec_t *_u) {
4393 assert(t);
4394 assert(_u);
4395
4396 if (streq(t, "now"))
4397 *_u = 0;
4398 else if (!strchr(t, ':')) {
4399 uint64_t u;
4400
4401 if (safe_atou64(t, &u) < 0)
4402 return -EINVAL;
4403
4404 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
4405 } else {
4406 char *e = NULL;
4407 long hour, minute;
4408 struct tm tm;
4409 time_t s;
4410 usec_t n;
4411
4412 errno = 0;
4413 hour = strtol(t, &e, 10);
4414 if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
4415 return -EINVAL;
4416
4417 minute = strtol(e+1, &e, 10);
4418 if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
4419 return -EINVAL;
4420
4421 n = now(CLOCK_REALTIME);
4422 s = (time_t) (n / USEC_PER_SEC);
4423
4424 zero(tm);
4425 assert_se(localtime_r(&s, &tm));
4426
4427 tm.tm_hour = (int) hour;
4428 tm.tm_min = (int) minute;
4429 tm.tm_sec = 0;
4430
4431 assert_se(s = mktime(&tm));
4432
4433 *_u = (usec_t) s * USEC_PER_SEC;
4434
4435 while (*_u <= n)
4436 *_u += USEC_PER_DAY;
4437 }
4438
4439 return 0;
4440 }
4441
4442 static int shutdown_parse_argv(int argc, char *argv[]) {
4443
4444 enum {
4445 ARG_HELP = 0x100,
4446 ARG_NO_WALL
4447 };
4448
4449 static const struct option options[] = {
4450 { "help", no_argument, NULL, ARG_HELP },
4451 { "halt", no_argument, NULL, 'H' },
4452 { "poweroff", no_argument, NULL, 'P' },
4453 { "reboot", no_argument, NULL, 'r' },
4454 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
4455 { "no-wall", no_argument, NULL, ARG_NO_WALL },
4456 { NULL, 0, NULL, 0 }
4457 };
4458
4459 int c, r;
4460
4461 assert(argc >= 0);
4462 assert(argv);
4463
4464 while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
4465 switch (c) {
4466
4467 case ARG_HELP:
4468 shutdown_help();
4469 return 0;
4470
4471 case 'H':
4472 arg_action = ACTION_HALT;
4473 break;
4474
4475 case 'P':
4476 arg_action = ACTION_POWEROFF;
4477 break;
4478
4479 case 'r':
4480 if (kexec_loaded())
4481 arg_action = ACTION_KEXEC;
4482 else
4483 arg_action = ACTION_REBOOT;
4484 break;
4485
4486 case 'K':
4487 arg_action = ACTION_KEXEC;
4488 break;
4489
4490 case 'h':
4491 if (arg_action != ACTION_HALT)
4492 arg_action = ACTION_POWEROFF;
4493 break;
4494
4495 case 'k':
4496 arg_dry = true;
4497 break;
4498
4499 case ARG_NO_WALL:
4500 arg_no_wall = true;
4501 break;
4502
4503 case 't':
4504 case 'a':
4505 /* Compatibility nops */
4506 break;
4507
4508 case 'c':
4509 arg_action = ACTION_CANCEL_SHUTDOWN;
4510 break;
4511
4512 case '?':
4513 return -EINVAL;
4514
4515 default:
4516 log_error("Unknown option code '%c'.", c);
4517 return -EINVAL;
4518 }
4519 }
4520
4521 if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
4522 r = parse_time_spec(argv[optind], &arg_when);
4523 if (r < 0) {
4524 log_error("Failed to parse time specification: %s", argv[optind]);
4525 return r;
4526 }
4527 } else
4528 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
4529
4530 if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
4531 /* No time argument for shutdown cancel */
4532 arg_wall = argv + optind;
4533 else if (argc > optind + 1)
4534 /* We skip the time argument */
4535 arg_wall = argv + optind + 1;
4536
4537 optind = argc;
4538
4539 return 1;
4540 }
4541
4542 static int telinit_parse_argv(int argc, char *argv[]) {
4543
4544 enum {
4545 ARG_HELP = 0x100,
4546 ARG_NO_WALL
4547 };
4548
4549 static const struct option options[] = {
4550 { "help", no_argument, NULL, ARG_HELP },
4551 { "no-wall", no_argument, NULL, ARG_NO_WALL },
4552 { NULL, 0, NULL, 0 }
4553 };
4554
4555 static const struct {
4556 char from;
4557 enum action to;
4558 } table[] = {
4559 { '0', ACTION_POWEROFF },
4560 { '6', ACTION_REBOOT },
4561 { '1', ACTION_RESCUE },
4562 { '2', ACTION_RUNLEVEL2 },
4563 { '3', ACTION_RUNLEVEL3 },
4564 { '4', ACTION_RUNLEVEL4 },
4565 { '5', ACTION_RUNLEVEL5 },
4566 { 's', ACTION_RESCUE },
4567 { 'S', ACTION_RESCUE },
4568 { 'q', ACTION_RELOAD },
4569 { 'Q', ACTION_RELOAD },
4570 { 'u', ACTION_REEXEC },
4571 { 'U', ACTION_REEXEC }
4572 };
4573
4574 unsigned i;
4575 int c;
4576
4577 assert(argc >= 0);
4578 assert(argv);
4579
4580 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4581 switch (c) {
4582
4583 case ARG_HELP:
4584 telinit_help();
4585 return 0;
4586
4587 case ARG_NO_WALL:
4588 arg_no_wall = true;
4589 break;
4590
4591 case '?':
4592 return -EINVAL;
4593
4594 default:
4595 log_error("Unknown option code '%c'.", c);
4596 return -EINVAL;
4597 }
4598 }
4599
4600 if (optind >= argc) {
4601 telinit_help();
4602 return -EINVAL;
4603 }
4604
4605 if (optind + 1 < argc) {
4606 log_error("Too many arguments.");
4607 return -EINVAL;
4608 }
4609
4610 if (strlen(argv[optind]) != 1) {
4611 log_error("Expected single character argument.");
4612 return -EINVAL;
4613 }
4614
4615 for (i = 0; i < ELEMENTSOF(table); i++)
4616 if (table[i].from == argv[optind][0])
4617 break;
4618
4619 if (i >= ELEMENTSOF(table)) {
4620 log_error("Unknown command '%s'.", argv[optind]);
4621 return -EINVAL;
4622 }
4623
4624 arg_action = table[i].to;
4625
4626 optind ++;
4627
4628 return 1;
4629 }
4630
4631 static int runlevel_parse_argv(int argc, char *argv[]) {
4632
4633 enum {
4634 ARG_HELP = 0x100,
4635 };
4636
4637 static const struct option options[] = {
4638 { "help", no_argument, NULL, ARG_HELP },
4639 { NULL, 0, NULL, 0 }
4640 };
4641
4642 int c;
4643
4644 assert(argc >= 0);
4645 assert(argv);
4646
4647 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4648 switch (c) {
4649
4650 case ARG_HELP:
4651 runlevel_help();
4652 return 0;
4653
4654 case '?':
4655 return -EINVAL;
4656
4657 default:
4658 log_error("Unknown option code '%c'.", c);
4659 return -EINVAL;
4660 }
4661 }
4662
4663 if (optind < argc) {
4664 log_error("Too many arguments.");
4665 return -EINVAL;
4666 }
4667
4668 return 1;
4669 }
4670
4671 static int parse_argv(int argc, char *argv[]) {
4672 assert(argc >= 0);
4673 assert(argv);
4674
4675 if (program_invocation_short_name) {
4676
4677 if (strstr(program_invocation_short_name, "halt")) {
4678 arg_action = ACTION_HALT;
4679 return halt_parse_argv(argc, argv);
4680 } else if (strstr(program_invocation_short_name, "poweroff")) {
4681 arg_action = ACTION_POWEROFF;
4682 return halt_parse_argv(argc, argv);
4683 } else if (strstr(program_invocation_short_name, "reboot")) {
4684 if (kexec_loaded())
4685 arg_action = ACTION_KEXEC;
4686 else
4687 arg_action = ACTION_REBOOT;
4688 return halt_parse_argv(argc, argv);
4689 } else if (strstr(program_invocation_short_name, "shutdown")) {
4690 arg_action = ACTION_POWEROFF;
4691 return shutdown_parse_argv(argc, argv);
4692 } else if (strstr(program_invocation_short_name, "init")) {
4693
4694 if (sd_booted() > 0) {
4695 arg_action = ACTION_INVALID;
4696 return telinit_parse_argv(argc, argv);
4697 } else {
4698 /* Hmm, so some other init system is
4699 * running, we need to forward this
4700 * request to it. For now we simply
4701 * guess that it is Upstart. */
4702
4703 execv("/lib/upstart/telinit", argv);
4704
4705 log_error("Couldn't find an alternative telinit implementation to spawn.");
4706 return -EIO;
4707 }
4708
4709 } else if (strstr(program_invocation_short_name, "runlevel")) {
4710 arg_action = ACTION_RUNLEVEL;
4711 return runlevel_parse_argv(argc, argv);
4712 }
4713 }
4714
4715 arg_action = ACTION_SYSTEMCTL;
4716 return systemctl_parse_argv(argc, argv);
4717 }
4718
4719 static int action_to_runlevel(void) {
4720
4721 static const char table[_ACTION_MAX] = {
4722 [ACTION_HALT] = '0',
4723 [ACTION_POWEROFF] = '0',
4724 [ACTION_REBOOT] = '6',
4725 [ACTION_RUNLEVEL2] = '2',
4726 [ACTION_RUNLEVEL3] = '3',
4727 [ACTION_RUNLEVEL4] = '4',
4728 [ACTION_RUNLEVEL5] = '5',
4729 [ACTION_RESCUE] = '1'
4730 };
4731
4732 assert(arg_action < _ACTION_MAX);
4733
4734 return table[arg_action];
4735 }
4736
4737 static int talk_upstart(void) {
4738 DBusMessage *m = NULL, *reply = NULL;
4739 DBusError error;
4740 int previous, rl, r;
4741 char
4742 env1_buf[] = "RUNLEVEL=X",
4743 env2_buf[] = "PREVLEVEL=X";
4744 char *env1 = env1_buf, *env2 = env2_buf;
4745 const char *emit = "runlevel";
4746 dbus_bool_t b_false = FALSE;
4747 DBusMessageIter iter, sub;
4748 DBusConnection *bus;
4749
4750 dbus_error_init(&error);
4751
4752 if (!(rl = action_to_runlevel()))
4753 return 0;
4754
4755 if (utmp_get_runlevel(&previous, NULL) < 0)
4756 previous = 'N';
4757
4758 if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
4759 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
4760 r = 0;
4761 goto finish;
4762 }
4763
4764 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
4765 r = -EIO;
4766 goto finish;
4767 }
4768
4769 if ((r = bus_check_peercred(bus)) < 0) {
4770 log_error("Failed to verify owner of bus.");
4771 goto finish;
4772 }
4773
4774 if (!(m = dbus_message_new_method_call(
4775 "com.ubuntu.Upstart",
4776 "/com/ubuntu/Upstart",
4777 "com.ubuntu.Upstart0_6",
4778 "EmitEvent"))) {
4779
4780 log_error("Could not allocate message.");
4781 r = -ENOMEM;
4782 goto finish;
4783 }
4784
4785 dbus_message_iter_init_append(m, &iter);
4786
4787 env1_buf[sizeof(env1_buf)-2] = rl;
4788 env2_buf[sizeof(env2_buf)-2] = previous;
4789
4790 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
4791 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
4792 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
4793 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
4794 !dbus_message_iter_close_container(&iter, &sub) ||
4795 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
4796 log_error("Could not append arguments to message.");
4797 r = -ENOMEM;
4798 goto finish;
4799 }
4800
4801 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4802
4803 if (bus_error_is_no_service(&error)) {
4804 r = -EADDRNOTAVAIL;
4805 goto finish;
4806 }
4807
4808 log_error("Failed to issue method call: %s", bus_error_message(&error));
4809 r = -EIO;
4810 goto finish;
4811 }
4812
4813 r = 1;
4814
4815 finish:
4816 if (m)
4817 dbus_message_unref(m);
4818
4819 if (reply)
4820 dbus_message_unref(reply);
4821
4822 if (bus) {
4823 dbus_connection_flush(bus);
4824 dbus_connection_close(bus);
4825 dbus_connection_unref(bus);
4826 }
4827
4828 dbus_error_free(&error);
4829
4830 return r;
4831 }
4832
4833 static int talk_initctl(void) {
4834 struct init_request request;
4835 int r, fd;
4836 char rl;
4837
4838 if (!(rl = action_to_runlevel()))
4839 return 0;
4840
4841 zero(request);
4842 request.magic = INIT_MAGIC;
4843 request.sleeptime = 0;
4844 request.cmd = INIT_CMD_RUNLVL;
4845 request.runlevel = rl;
4846
4847 if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
4848
4849 if (errno == ENOENT)
4850 return 0;
4851
4852 log_error("Failed to open "INIT_FIFO": %m");
4853 return -errno;
4854 }
4855
4856 errno = 0;
4857 r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
4858 close_nointr_nofail(fd);
4859
4860 if (r < 0) {
4861 log_error("Failed to write to "INIT_FIFO": %m");
4862 return errno ? -errno : -EIO;
4863 }
4864
4865 return 1;
4866 }
4867
4868 static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
4869
4870 static const struct {
4871 const char* verb;
4872 const enum {
4873 MORE,
4874 LESS,
4875 EQUAL
4876 } argc_cmp;
4877 const int argc;
4878 int (* const dispatch)(DBusConnection *bus, char **args);
4879 } verbs[] = {
4880 { "list-units", LESS, 1, list_units },
4881 { "list-unit-files", EQUAL, 1, list_unit_files },
4882 { "list-jobs", EQUAL, 1, list_jobs },
4883 { "clear-jobs", EQUAL, 1, daemon_reload },
4884 { "load", MORE, 2, load_unit },
4885 { "cancel", MORE, 2, cancel_job },
4886 { "start", MORE, 2, start_unit },
4887 { "stop", MORE, 2, start_unit },
4888 { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
4889 { "reload", MORE, 2, start_unit },
4890 { "restart", MORE, 2, start_unit },
4891 { "try-restart", MORE, 2, start_unit },
4892 { "reload-or-restart", MORE, 2, start_unit },
4893 { "reload-or-try-restart", MORE, 2, start_unit },
4894 { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */
4895 { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
4896 { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
4897 { "isolate", EQUAL, 2, start_unit },
4898 { "kill", MORE, 2, kill_unit },
4899 { "is-active", MORE, 2, check_unit },
4900 { "check", MORE, 2, check_unit },
4901 { "show", MORE, 1, show },
4902 { "status", MORE, 2, show },
4903 { "help", MORE, 2, show },
4904 { "dump", EQUAL, 1, dump },
4905 { "dot", EQUAL, 1, dot },
4906 { "snapshot", LESS, 2, snapshot },
4907 { "delete", MORE, 2, delete_snapshot },
4908 { "daemon-reload", EQUAL, 1, daemon_reload },
4909 { "daemon-reexec", EQUAL, 1, daemon_reload },
4910 { "show-environment", EQUAL, 1, show_enviroment },
4911 { "set-environment", MORE, 2, set_environment },
4912 { "unset-environment", MORE, 2, set_environment },
4913 { "halt", EQUAL, 1, start_special },
4914 { "poweroff", EQUAL, 1, start_special },
4915 { "reboot", EQUAL, 1, start_special },
4916 { "kexec", EQUAL, 1, start_special },
4917 { "suspend", EQUAL, 1, start_special },
4918 { "hibernate", EQUAL, 1, start_special },
4919 { "default", EQUAL, 1, start_special },
4920 { "rescue", EQUAL, 1, start_special },
4921 { "emergency", EQUAL, 1, start_special },
4922 { "exit", EQUAL, 1, start_special },
4923 { "reset-failed", MORE, 1, reset_failed },
4924 { "enable", MORE, 2, enable_unit },
4925 { "disable", MORE, 2, enable_unit },
4926 { "is-enabled", MORE, 2, unit_is_enabled },
4927 { "reenable", MORE, 2, enable_unit },
4928 { "preset", MORE, 2, enable_unit },
4929 { "mask", MORE, 2, enable_unit },
4930 { "unmask", MORE, 2, enable_unit },
4931 { "link", MORE, 2, enable_unit },
4932 { "switch-root", MORE, 2, switch_root },
4933 };
4934
4935 int left;
4936 unsigned i;
4937
4938 assert(argc >= 0);
4939 assert(argv);
4940 assert(error);
4941
4942 left = argc - optind;
4943
4944 if (left <= 0)
4945 /* Special rule: no arguments means "list-units" */
4946 i = 0;
4947 else {
4948 if (streq(argv[optind], "help") && !argv[optind+1]) {
4949 log_error("This command expects one or more "
4950 "unit names. Did you mean --help?");
4951 return -EINVAL;
4952 }
4953
4954 for (i = 0; i < ELEMENTSOF(verbs); i++)
4955 if (streq(argv[optind], verbs[i].verb))
4956 break;
4957
4958 if (i >= ELEMENTSOF(verbs)) {
4959 log_error("Unknown operation '%s'.", argv[optind]);
4960 return -EINVAL;
4961 }
4962 }
4963
4964 switch (verbs[i].argc_cmp) {
4965
4966 case EQUAL:
4967 if (left != verbs[i].argc) {
4968 log_error("Invalid number of arguments.");
4969 return -EINVAL;
4970 }
4971
4972 break;
4973
4974 case MORE:
4975 if (left < verbs[i].argc) {
4976 log_error("Too few arguments.");
4977 return -EINVAL;
4978 }
4979
4980 break;
4981
4982 case LESS:
4983 if (left > verbs[i].argc) {
4984 log_error("Too many arguments.");
4985 return -EINVAL;
4986 }
4987
4988 break;
4989
4990 default:
4991 assert_not_reached("Unknown comparison operator.");
4992 }
4993
4994 /* Require a bus connection for all operations but
4995 * enable/disable */
4996 if (!streq(verbs[i].verb, "enable") &&
4997 !streq(verbs[i].verb, "disable") &&
4998 !streq(verbs[i].verb, "is-enabled") &&
4999 !streq(verbs[i].verb, "list-unit-files") &&
5000 !streq(verbs[i].verb, "reenable") &&
5001 !streq(verbs[i].verb, "preset") &&
5002 !streq(verbs[i].verb, "mask") &&
5003 !streq(verbs[i].verb, "unmask") &&
5004 !streq(verbs[i].verb, "link")) {
5005
5006 if (running_in_chroot() > 0) {
5007 log_info("Running in chroot, ignoring request.");
5008 return 0;
5009 }
5010
5011 if (((!streq(verbs[i].verb, "reboot") &&
5012 !streq(verbs[i].verb, "halt") &&
5013 !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
5014 log_error("Failed to get D-Bus connection: %s",
5015 dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5016 return -EIO;
5017 }
5018
5019 } else {
5020
5021 if (!bus && !avoid_bus()) {
5022 log_error("Failed to get D-Bus connection: %s",
5023 dbus_error_is_set(error) ? error->message : "No connection to service manager.");
5024 return -EIO;
5025 }
5026 }
5027
5028 return verbs[i].dispatch(bus, argv + optind);
5029 }
5030
5031 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
5032 int fd;
5033 struct msghdr msghdr;
5034 struct iovec iovec[2];
5035 union sockaddr_union sockaddr;
5036 struct sd_shutdown_command c;
5037
5038 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5039 if (fd < 0)
5040 return -errno;
5041
5042 zero(c);
5043 c.usec = t;
5044 c.mode = mode;
5045 c.dry_run = dry_run;
5046 c.warn_wall = warn;
5047
5048 zero(sockaddr);
5049 sockaddr.sa.sa_family = AF_UNIX;
5050 strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
5051
5052 zero(msghdr);
5053 msghdr.msg_name = &sockaddr;
5054 msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
5055
5056 zero(iovec);
5057 iovec[0].iov_base = (char*) &c;
5058 iovec[0].iov_len = offsetof(struct sd_shutdown_command, wall_message);
5059
5060 if (isempty(message))
5061 msghdr.msg_iovlen = 1;
5062 else {
5063 iovec[1].iov_base = (char*) message;
5064 iovec[1].iov_len = strlen(message);
5065 msghdr.msg_iovlen = 2;
5066 }
5067 msghdr.msg_iov = iovec;
5068
5069 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
5070 close_nointr_nofail(fd);
5071 return -errno;
5072 }
5073
5074 close_nointr_nofail(fd);
5075 return 0;
5076 }
5077
5078 static int reload_with_fallback(DBusConnection *bus) {
5079
5080 if (bus) {
5081 /* First, try systemd via D-Bus. */
5082 if (daemon_reload(bus, NULL) >= 0)
5083 return 0;
5084 }
5085
5086 /* Nothing else worked, so let's try signals */
5087 assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5088
5089 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5090 log_error("kill() failed: %m");
5091 return -errno;
5092 }
5093
5094 return 0;
5095 }
5096
5097 static int start_with_fallback(DBusConnection *bus) {
5098
5099 if (bus) {
5100 /* First, try systemd via D-Bus. */
5101 if (start_unit(bus, NULL) >= 0)
5102 goto done;
5103 }
5104
5105 /* Hmm, talking to systemd via D-Bus didn't work. Then
5106 * let's try to talk to Upstart via D-Bus. */
5107 if (talk_upstart() > 0)
5108 goto done;
5109
5110 /* Nothing else worked, so let's try
5111 * /dev/initctl */
5112 if (talk_initctl() > 0)
5113 goto done;
5114
5115 log_error("Failed to talk to init daemon.");
5116 return -EIO;
5117
5118 done:
5119 warn_wall(arg_action);
5120 return 0;
5121 }
5122
5123 static _noreturn_ void halt_now(enum action a) {
5124
5125 /* Make sure C-A-D is handled by the kernel from this
5126 * point on... */
5127 reboot(RB_ENABLE_CAD);
5128
5129 switch (a) {
5130
5131 case ACTION_HALT:
5132 log_info("Halting.");
5133 reboot(RB_HALT_SYSTEM);
5134 break;
5135
5136 case ACTION_POWEROFF:
5137 log_info("Powering off.");
5138 reboot(RB_POWER_OFF);
5139 break;
5140
5141 case ACTION_REBOOT:
5142 log_info("Rebooting.");
5143 reboot(RB_AUTOBOOT);
5144 break;
5145
5146 default:
5147 assert_not_reached("Unknown halt action.");
5148 }
5149
5150 assert_not_reached("Uh? This shouldn't happen.");
5151 }
5152
5153 static int halt_main(DBusConnection *bus) {
5154 int r;
5155
5156 if (geteuid() != 0) {
5157 /* Try logind if we are a normal user and no special
5158 * mode applies. Maybe PolicyKit allows us to shutdown
5159 * the machine. */
5160
5161 if (arg_when <= 0 &&
5162 !arg_dry &&
5163 !arg_force &&
5164 (arg_action == ACTION_POWEROFF ||
5165 arg_action == ACTION_REBOOT)) {
5166 r = reboot_with_logind(bus, arg_action);
5167 if (r >= 0)
5168 return r;
5169 }
5170
5171 log_error("Must be root.");
5172 return -EPERM;
5173 }
5174
5175 if (arg_when > 0) {
5176 char *m;
5177
5178 m = strv_join(arg_wall, " ");
5179 r = send_shutdownd(arg_when,
5180 arg_action == ACTION_HALT ? 'H' :
5181 arg_action == ACTION_POWEROFF ? 'P' :
5182 arg_action == ACTION_KEXEC ? 'K' :
5183 'r',
5184 arg_dry,
5185 !arg_no_wall,
5186 m);
5187 free(m);
5188
5189 if (r < 0)
5190 log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
5191 else {
5192 char date[FORMAT_TIMESTAMP_MAX];
5193
5194 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5195 format_timestamp(date, sizeof(date), arg_when));
5196 return 0;
5197 }
5198 }
5199
5200 if (!arg_dry && !arg_force)
5201 return start_with_fallback(bus);
5202
5203 if (!arg_no_wtmp) {
5204 if (sd_booted() > 0)
5205 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
5206 else {
5207 r = utmp_put_shutdown();
5208 if (r < 0)
5209 log_warning("Failed to write utmp record: %s", strerror(-r));
5210 }
5211 }
5212
5213 if (arg_dry)
5214 return 0;
5215
5216 halt_now(arg_action);
5217 /* We should never reach this. */
5218 return -ENOSYS;
5219 }
5220
5221 static int runlevel_main(void) {
5222 int r, runlevel, previous;
5223
5224 r = utmp_get_runlevel(&runlevel, &previous);
5225 if (r < 0) {
5226 puts("unknown");
5227 return r;
5228 }
5229
5230 printf("%c %c\n",
5231 previous <= 0 ? 'N' : previous,
5232 runlevel <= 0 ? 'N' : runlevel);
5233
5234 return 0;
5235 }
5236
5237 int main(int argc, char*argv[]) {
5238 int r, retval = EXIT_FAILURE;
5239 DBusConnection *bus = NULL;
5240 DBusError error;
5241
5242 dbus_error_init(&error);
5243
5244 log_parse_environment();
5245 log_open();
5246
5247 r = parse_argv(argc, argv);
5248 if (r < 0)
5249 goto finish;
5250 else if (r == 0) {
5251 retval = EXIT_SUCCESS;
5252 goto finish;
5253 }
5254
5255 /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5256 * let's shortcut this */
5257 if (arg_action == ACTION_RUNLEVEL) {
5258 r = runlevel_main();
5259 retval = r < 0 ? EXIT_FAILURE : r;
5260 goto finish;
5261 }
5262
5263 if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
5264 log_info("Running in chroot, ignoring request.");
5265 retval = 0;
5266 goto finish;
5267 }
5268
5269 if (!avoid_bus()) {
5270 if (arg_transport == TRANSPORT_NORMAL)
5271 bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
5272 else if (arg_transport == TRANSPORT_POLKIT) {
5273 bus_connect_system_polkit(&bus, &error);
5274 private_bus = false;
5275 } else if (arg_transport == TRANSPORT_SSH) {
5276 bus_connect_system_ssh(NULL, arg_host, &bus, &error);
5277 private_bus = false;
5278 } else
5279 assert_not_reached("Uh, invalid transport...");
5280 }
5281
5282 switch (arg_action) {
5283
5284 case ACTION_SYSTEMCTL:
5285 r = systemctl_main(bus, argc, argv, &error);
5286 break;
5287
5288 case ACTION_HALT:
5289 case ACTION_POWEROFF:
5290 case ACTION_REBOOT:
5291 case ACTION_KEXEC:
5292 r = halt_main(bus);
5293 break;
5294
5295 case ACTION_RUNLEVEL2:
5296 case ACTION_RUNLEVEL3:
5297 case ACTION_RUNLEVEL4:
5298 case ACTION_RUNLEVEL5:
5299 case ACTION_RESCUE:
5300 case ACTION_EMERGENCY:
5301 case ACTION_DEFAULT:
5302 r = start_with_fallback(bus);
5303 break;
5304
5305 case ACTION_RELOAD:
5306 case ACTION_REEXEC:
5307 r = reload_with_fallback(bus);
5308 break;
5309
5310 case ACTION_CANCEL_SHUTDOWN: {
5311 char *m = NULL;
5312
5313 if (arg_wall) {
5314 m = strv_join(arg_wall, " ");
5315 if (!m) {
5316 retval = EXIT_FAILURE;
5317 goto finish;
5318 }
5319 }
5320 r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
5321 if (r < 0)
5322 log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
5323 free(m);
5324 break;
5325 }
5326
5327 case ACTION_INVALID:
5328 case ACTION_RUNLEVEL:
5329 default:
5330 assert_not_reached("Unknown action");
5331 }
5332
5333 retval = r < 0 ? EXIT_FAILURE : r;
5334
5335 finish:
5336 if (bus) {
5337 dbus_connection_flush(bus);
5338 dbus_connection_close(bus);
5339 dbus_connection_unref(bus);
5340 }
5341
5342 dbus_error_free(&error);
5343
5344 dbus_shutdown();
5345
5346 strv_free(arg_property);
5347
5348 pager_close();
5349 ask_password_agent_close();
5350 polkit_agent_close();
5351
5352 return retval;
5353 }