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