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