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