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