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