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