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