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