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