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