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