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