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