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