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