]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl.c
systemctl: show StatusErrno value in "systemctl status"
[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
f459b602 7 Copyright 2013 Marc-Antoine Perennou
7e4249b9
LP
8
9 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
7e4249b9
LP
12 (at your option) any later version.
13
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 17 Lesser General Public License for more details.
7e4249b9 18
5430f7f2 19 You should have received a copy of the GNU Lesser General Public License
7e4249b9
LP
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21***/
22
e4b61340 23#include <sys/reboot.h>
37185ec8
WC
24#include <linux/reboot.h>
25#include <sys/syscall.h>
7e4249b9
LP
26#include <stdio.h>
27#include <getopt.h>
a9cdc94f 28#include <locale.h>
7e4249b9
LP
29#include <stdbool.h>
30#include <string.h>
31#include <errno.h>
32#include <sys/ioctl.h>
33#include <termios.h>
34#include <unistd.h>
eb22ac37 35#include <fcntl.h>
f1c5860b 36#include <sys/socket.h>
ee5762e3 37#include <sys/stat.h>
0e098b15 38#include <stddef.h>
501fc174 39#include <sys/prctl.h>
d8fba7c6 40#include <fnmatch.h>
81527be1 41
f459b602
MAP
42#include "sd-daemon.h"
43#include "sd-shutdown.h"
44#include "sd-login.h"
45#include "sd-bus.h"
7e4249b9
LP
46#include "log.h"
47#include "util.h"
48#include "macro.h"
49#include "set.h"
e4b61340 50#include "utmp-wtmp.h"
514f4ef5 51#include "special.h"
eb22ac37 52#include "initreq.h"
9eb977db 53#include "path-util.h"
e4a9373f 54#include "strv.h"
ab35fb1b 55#include "cgroup-show.h"
c6c18be3 56#include "cgroup-util.h"
582a507f 57#include "list.h"
ee5762e3
LP
58#include "path-lookup.h"
59#include "conf-parser.h"
d06dacd0 60#include "exit-status.h"
7d568925 61#include "build.h"
71fad675 62#include "unit-name.h"
1968a360 63#include "pager.h"
6bb92a16
LP
64#include "spawn-ask-password-agent.h"
65#include "spawn-polkit-agent.h"
729e3769 66#include "install.h"
86aa7ba4 67#include "logs-show.h"
67445f4e 68#include "socket-util.h"
a5c32cff 69#include "fileio.h"
ac3efa8a 70#include "env-util.h"
f459b602
MAP
71#include "bus-util.h"
72#include "bus-message.h"
73#include "bus-error.h"
718db961 74#include "bus-errors.h"
7e4249b9 75
20b3f379 76static char **arg_types = NULL;
9b9b3d36 77static char **arg_states = NULL;
20b3f379 78static char **arg_properties = NULL;
7e4249b9 79static bool arg_all = false;
afba4199
ZJS
80static enum dependency {
81 DEPENDENCY_FORWARD,
82 DEPENDENCY_REVERSE,
83 DEPENDENCY_AFTER,
84 DEPENDENCY_BEFORE,
071066a5 85 _DEPENDENCY_MAX
afba4199 86} arg_dependency = DEPENDENCY_FORWARD;
e67c3609 87static const char *arg_job_mode = "replace";
729e3769 88static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
ee5762e3 89static bool arg_no_block = false;
ebed32bf 90static bool arg_no_legend = false;
0736af98 91static bool arg_no_pager = false;
e4b61340 92static bool arg_no_wtmp = false;
514f4ef5 93static bool arg_no_wall = false;
ee5762e3 94static bool arg_no_reload = false;
991f2a39 95static bool arg_show_types = false;
b37844d3 96static bool arg_ignore_inhibitors = false;
e4b61340 97static bool arg_dry = false;
0183528f 98static bool arg_quiet = false;
ee5762e3 99static bool arg_full = false;
1238ee09 100static bool arg_recursive = false;
e606bb61 101static int arg_force = 0;
6bb92a16 102static bool arg_ask_password = true;
729e3769 103static bool arg_runtime = false;
d309c1c3 104static UnitFilePresetMode arg_preset_mode = UNIT_FILE_PRESET_FULL;
e4b61340 105static char **arg_wall = NULL;
8a0867d6 106static const char *arg_kill_who = NULL;
8a0867d6 107static int arg_signal = SIGTERM;
69fc152f 108static const char *arg_root = NULL;
f6144808 109static usec_t arg_when = 0;
4445a875 110static enum action {
f459b602 111 _ACTION_INVALID,
e4b61340
LP
112 ACTION_SYSTEMCTL,
113 ACTION_HALT,
114 ACTION_POWEROFF,
115 ACTION_REBOOT,
20b09ca7
LP
116 ACTION_KEXEC,
117 ACTION_EXIT,
6edd7d0a
LP
118 ACTION_SUSPEND,
119 ACTION_HIBERNATE,
6524990f 120 ACTION_HYBRID_SLEEP,
e4b61340
LP
121 ACTION_RUNLEVEL2,
122 ACTION_RUNLEVEL3,
123 ACTION_RUNLEVEL4,
124 ACTION_RUNLEVEL5,
125 ACTION_RESCUE,
514f4ef5
LP
126 ACTION_EMERGENCY,
127 ACTION_DEFAULT,
e4b61340
LP
128 ACTION_RELOAD,
129 ACTION_REEXEC,
130 ACTION_RUNLEVEL,
f6144808 131 ACTION_CANCEL_SHUTDOWN,
e4b61340
LP
132 _ACTION_MAX
133} arg_action = ACTION_SYSTEMCTL;
f459b602 134static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
7085053a 135static char *arg_host = NULL;
df50185b
LP
136static unsigned arg_lines = 10;
137static OutputMode arg_output = OUTPUT_SHORT;
5d0c05e5 138static bool arg_plain = false;
1238ee09 139
39602c39
TA
140static const struct {
141 const char *verb;
142 const char *method;
143} unit_actions[] = {
144 { "start", "StartUnit" },
145 { "stop", "StopUnit" },
146 { "condstop", "StopUnit" },
147 { "reload", "ReloadUnit" },
148 { "restart", "RestartUnit" },
149 { "try-restart", "TryRestartUnit" },
150 { "condrestart", "TryRestartUnit" },
151 { "reload-or-restart", "ReloadOrRestartUnit" },
152 { "reload-or-try-restart", "ReloadOrTryRestartUnit" },
153 { "condreload", "ReloadOrTryRestartUnit" },
154 { "force-reload", "ReloadOrTryRestartUnit" }
155};
e4b61340 156
1238ee09
LP
157static bool original_stdout_is_tty;
158
f459b602 159static int daemon_reload(sd_bus *bus, char **args);
477def80 160static int halt_now(enum action a);
dbc2c080
LP
161static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet);
162
d8fba7c6
ZJS
163static char** strv_skip_first(char **strv) {
164 if (strv_length(strv) > 0)
165 return strv + 1;
166 return NULL;
167}
168
3b0727f5 169static void pager_open_if_enabled(void) {
f8440af5 170
729e3769
LP
171 if (arg_no_pager)
172 return;
3b0727f5 173
1b12a7b5 174 pager_open(false);
729e3769 175}
c0f9c7da 176
6bb92a16 177static void ask_password_agent_open_if_enabled(void) {
501fc174 178
729e3769 179 /* Open the password agent as a child process if necessary */
501fc174
LP
180
181 if (!arg_ask_password)
182 return;
715554e7 183
729e3769 184 if (arg_scope != UNIT_FILE_SYSTEM)
501fc174
LP
185 return;
186
cbc9fbd1
LP
187 if (arg_transport != BUS_TRANSPORT_LOCAL)
188 return;
189
6bb92a16
LP
190 ask_password_agent_open();
191}
192
ba1261bc 193#ifdef HAVE_LOGIND
6bb92a16
LP
194static void polkit_agent_open_if_enabled(void) {
195
196 /* Open the polkit agent as a child process if necessary */
197
198 if (!arg_ask_password)
199 return;
200
201 if (arg_scope != UNIT_FILE_SYSTEM)
202 return;
203
f459b602
MAP
204 if (arg_transport != BUS_TRANSPORT_LOCAL)
205 return;
206
6bb92a16 207 polkit_agent_open();
501fc174 208}
ba1261bc 209#endif
501fc174 210
f459b602 211static int translate_bus_error_to_exit_status(int r, const sd_bus_error *error) {
22f4096c
LP
212 assert(error);
213
f459b602 214 if (!sd_bus_error_is_set(error))
22f4096c
LP
215 return r;
216
f459b602
MAP
217 if (sd_bus_error_has_name(error, SD_BUS_ERROR_ACCESS_DENIED) ||
218 sd_bus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) ||
219 sd_bus_error_has_name(error, BUS_ERROR_NO_ISOLATION) ||
220 sd_bus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
22f4096c
LP
221 return EXIT_NOPERMISSION;
222
f459b602 223 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
22f4096c
LP
224 return EXIT_NOTINSTALLED;
225
f459b602 226 if (sd_bus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) ||
718db961 227 sd_bus_error_has_name(error, SD_BUS_ERROR_NOT_SUPPORTED))
22f4096c
LP
228 return EXIT_NOTIMPLEMENTED;
229
f459b602 230 if (sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
22f4096c
LP
231 return EXIT_NOTCONFIGURED;
232
233 if (r != 0)
234 return r;
235
236 return EXIT_FAILURE;
237}
238
4c80c73c 239static void warn_wall(enum action a) {
ef2f1067 240 static const char *table[_ACTION_MAX] = {
dfcc5c33
MS
241 [ACTION_HALT] = "The system is going down for system halt NOW!",
242 [ACTION_REBOOT] = "The system is going down for reboot NOW!",
243 [ACTION_POWEROFF] = "The system is going down for power-off NOW!",
244 [ACTION_KEXEC] = "The system is going down for kexec reboot NOW!",
245 [ACTION_RESCUE] = "The system is going down to rescue mode NOW!",
246 [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!",
247 [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!"
ef2f1067
LP
248 };
249
514f4ef5
LP
250 if (arg_no_wall)
251 return;
252
e4a9373f 253 if (arg_wall) {
f84190d8 254 _cleanup_free_ char *p;
e4a9373f 255
7e59bfcb
LP
256 p = strv_join(arg_wall, " ");
257 if (!p) {
f84190d8 258 log_oom();
e4a9373f
LP
259 return;
260 }
261
262 if (*p) {
9003d9b0 263 utmp_wall(p, NULL, NULL);
e4a9373f
LP
264 return;
265 }
e4a9373f
LP
266 }
267
4c80c73c 268 if (!table[a])
ef2f1067
LP
269 return;
270
9003d9b0 271 utmp_wall(table[a], NULL, NULL);
ef2f1067
LP
272}
273
729e3769
LP
274static bool avoid_bus(void) {
275
276 if (running_in_chroot() > 0)
277 return true;
278
279 if (sd_booted() <= 0)
280 return true;
281
282 if (!isempty(arg_root))
283 return true;
284
285 if (arg_scope == UNIT_FILE_GLOBAL)
286 return true;
287
288 return false;
289}
290
36c32ba2 291static int compare_unit_info(const void *a, const void *b) {
f459b602 292 const UnitInfo *u = a, *v = b;
36c32ba2 293 const char *d1, *d2;
1238ee09
LP
294 int r;
295
296 /* First, order by machine */
297 if (!u->machine && v->machine)
298 return -1;
299 if (u->machine && !v->machine)
300 return 1;
301 if (u->machine && v->machine) {
302 r = strcasecmp(u->machine, v->machine);
303 if (r != 0)
304 return r;
305 }
36c32ba2 306
1238ee09 307 /* Second, order by unit type */
36c32ba2
LP
308 d1 = strrchr(u->id, '.');
309 d2 = strrchr(v->id, '.');
36c32ba2 310 if (d1 && d2) {
f84190d8
LP
311 r = strcasecmp(d1, d2);
312 if (r != 0)
36c32ba2
LP
313 return r;
314 }
315
1238ee09 316 /* Third, order by name */
a2a3a5b9 317 return strcasecmp(u->id, v->id);
36c32ba2
LP
318}
319
d8fba7c6 320static bool output_show_unit(const UnitInfo *u, char **patterns) {
33330222 321 const char *dot;
b036fc00 322
d8fba7c6
ZJS
323 if (!strv_isempty(patterns)) {
324 char **pattern;
325
326 STRV_FOREACH(pattern, patterns)
327 if (fnmatch(*pattern, u->id, FNM_NOESCAPE) == 0)
328 return true;
329 return false;
330 }
331
20b3f379
ZJS
332 return (!arg_types || ((dot = strrchr(u->id, '.')) &&
333 strv_find(arg_types, dot+1))) &&
c147dc42
ZJS
334 (arg_all || !(streq(u->active_state, "inactive")
335 || u->following[0]) || u->job_id > 0);
33330222
ZJS
336}
337
1238ee09 338static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
90c3f79d 339 unsigned circle_len = 0, id_len, max_id_len, load_len, active_len, sub_len, job_len, desc_len;
f459b602 340 const UnitInfo *u;
a1074881 341 unsigned n_shown = 0;
ccd41387 342 int job_count = 0;
33330222 343
f8294e41
JT
344 max_id_len = strlen("UNIT");
345 load_len = strlen("LOAD");
346 active_len = strlen("ACTIVE");
347 sub_len = strlen("SUB");
348 job_len = strlen("JOB");
4deb3b93 349 desc_len = 0;
b036fc00
LP
350
351 for (u = unit_infos; u < unit_infos + c; u++) {
1238ee09 352 max_id_len = MAX(max_id_len, strlen(u->id) + (u->machine ? strlen(u->machine)+1 : 0));
a1074881 353 load_len = MAX(load_len, strlen(u->load_state));
b036fc00
LP
354 active_len = MAX(active_len, strlen(u->active_state));
355 sub_len = MAX(sub_len, strlen(u->sub_state));
f459b602 356
ccd41387 357 if (u->job_id != 0) {
b036fc00 358 job_len = MAX(job_len, strlen(u->job_type));
ccd41387
ZJS
359 job_count++;
360 }
90c3f79d
LP
361
362 if (!arg_no_legend &&
363 (streq(u->active_state, "failed") ||
364 STR_IN_SET(u->load_state, "error", "not-found", "masked")))
365 circle_len = 2;
33330222
ZJS
366 }
367
184ecaf7 368 if (!arg_full && original_stdout_is_tty) {
4deb3b93 369 unsigned basic_len;
cbc9fbd1 370
9607d947 371 id_len = MIN(max_id_len, 25u);
90c3f79d 372 basic_len = circle_len + 5 + id_len + 5 + active_len + sub_len;
cbc9fbd1 373
ccd41387
ZJS
374 if (job_count)
375 basic_len += job_len + 1;
cbc9fbd1 376
4deb3b93
MS
377 if (basic_len < (unsigned) columns()) {
378 unsigned extra_len, incr;
379 extra_len = columns() - basic_len;
cbc9fbd1 380
4deb3b93
MS
381 /* Either UNIT already got 25, or is fully satisfied.
382 * Grant up to 25 to DESC now. */
9607d947 383 incr = MIN(extra_len, 25u);
4deb3b93
MS
384 desc_len += incr;
385 extra_len -= incr;
cbc9fbd1 386
4deb3b93
MS
387 /* split the remaining space between UNIT and DESC,
388 * but do not give UNIT more than it needs. */
389 if (extra_len > 0) {
390 incr = MIN(extra_len / 2, max_id_len - id_len);
391 id_len += incr;
392 desc_len += extra_len - incr;
393 }
394 }
395 } else
396 id_len = max_id_len;
397
b036fc00 398 for (u = unit_infos; u < unit_infos + c; u++) {
1238ee09 399 _cleanup_free_ char *e = NULL, *j = NULL;
90c3f79d
LP
400 const char *on_loaded = "", *off_loaded = "";
401 const char *on_active = "", *off_active = "";
402 const char *on_circle = "", *off_circle = "";
1238ee09 403 const char *id;
90c3f79d 404 bool circle = false;
b036fc00 405
ad94ad63 406 if (!n_shown && !arg_no_legend) {
90c3f79d
LP
407
408 if (circle_len > 0)
409 fputs(" ", stdout);
410
cbc9fbd1
LP
411 printf("%-*s %-*s %-*s %-*s ",
412 id_len, "UNIT",
413 load_len, "LOAD",
414 active_len, "ACTIVE",
415 sub_len, "SUB");
416
ccd41387
ZJS
417 if (job_count)
418 printf("%-*s ", job_len, "JOB");
cbc9fbd1 419
ad94ad63
ZJS
420 if (!arg_full && arg_no_pager)
421 printf("%.*s\n", desc_len, "DESCRIPTION");
422 else
423 printf("%s\n", "DESCRIPTION");
424 }
425
688c6725
LP
426 n_shown++;
427
90c3f79d
LP
428 if (STR_IN_SET(u->load_state, "error", "not-found", "masked")) {
429 on_loaded = ansi_highlight_red();
430 on_circle = ansi_highlight_yellow();
431 off_loaded = off_circle = ansi_highlight_off();
432 circle = true;
433 }
b036fc00
LP
434
435 if (streq(u->active_state, "failed")) {
90c3f79d
LP
436 on_circle = on_active = ansi_highlight_red();
437 off_circle = off_active = ansi_highlight_off();
438 circle = true;
439 }
eb68c413 440
1238ee09
LP
441 if (u->machine) {
442 j = strjoin(u->machine, ":", u->id, NULL);
443 if (!j)
444 return log_oom();
445
446 id = j;
447 } else
448 id = u->id;
449
450 if (arg_full) {
451 e = ellipsize(id, id_len, 33);
452 if (!e)
453 return log_oom();
454
455 id = e;
456 }
eb68c413 457
90c3f79d
LP
458 if (circle_len > 0)
459 printf("%s%s%s", on_circle, circle ? draw_special_char(DRAW_BLACK_CIRCLE) : " ", off_circle);
460
a1074881 461 printf("%s%-*s%s %s%-*s%s %s%-*s %-*s%s %-*s",
90c3f79d 462 on_active, id_len, id, off_active,
a1074881 463 on_loaded, load_len, u->load_state, off_loaded,
b036fc00
LP
464 on_active, active_len, u->active_state,
465 sub_len, u->sub_state, off_active,
ccd41387 466 job_count ? job_len + 1 : 0, u->job_id ? u->job_type : "");
cbc9fbd1 467
184ecaf7 468 if (desc_len > 0)
798e258d
MS
469 printf("%.*s\n", desc_len, u->description);
470 else
471 printf("%s\n", u->description);
eb68c413
ZJS
472 }
473
ebed32bf 474 if (!arg_no_legend) {
57f7ae4f
ZJS
475 const char *on, *off;
476
477 if (n_shown) {
90c3f79d
LP
478 puts("\n"
479 "LOAD = Reflects whether the unit definition was properly loaded.\n"
e3e0314b
ZJS
480 "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
481 "SUB = The low-level unit activation state, values depend on unit type.");
482 puts(job_count ? "JOB = Pending job for the unit.\n" : "");
0b5a519c
DS
483 on = ansi_highlight();
484 off = ansi_highlight_off();
57f7ae4f 485 } else {
0b5a519c
DS
486 on = ansi_highlight_red();
487 off = ansi_highlight_off();
57f7ae4f 488 }
eb68c413
ZJS
489
490 if (arg_all)
48c2826b 491 printf("%s%u loaded units listed.%s\n"
57f7ae4f
ZJS
492 "To show all installed unit files use 'systemctl list-unit-files'.\n",
493 on, n_shown, off);
eb68c413 494 else
48c2826b 495 printf("%s%u loaded units listed.%s Pass --all to see loaded but inactive units, too.\n"
57f7ae4f
ZJS
496 "To show all installed unit files use 'systemctl list-unit-files'.\n",
497 on, n_shown, off);
eb68c413 498 }
1238ee09
LP
499
500 return 0;
eb68c413
ZJS
501}
502
a00963a2 503static int get_unit_list(
f459b602 504 sd_bus *bus,
1238ee09
LP
505 const char *machine,
506 char **patterns,
507 UnitInfo **unit_infos,
508 int c,
509 sd_bus_message **_reply) {
a00963a2 510
cdc06ed7 511 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
f459b602
MAP
512 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
513 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
ca2d3784 514 size_t size = c;
1238ee09 515 int r;
f459b602 516 UnitInfo u;
7e4249b9 517
265a7a2a 518 assert(bus);
1238ee09 519 assert(unit_infos);
f459b602 520 assert(_reply);
1238ee09 521
cdc06ed7 522 r = sd_bus_message_new_method_call(
f22f08cd 523 bus,
cdc06ed7 524 &m,
f22f08cd
SP
525 "org.freedesktop.systemd1",
526 "/org/freedesktop/systemd1",
527 "org.freedesktop.systemd1.Manager",
cdc06ed7
DS
528 "ListUnitsFiltered");
529
530 if (r < 0)
531 return bus_log_create_error(r);
532
533 r = sd_bus_message_append_strv(m, arg_states);
534 if (r < 0)
535 return bus_log_create_error(r);
536
537 r = sd_bus_call(bus, m, 0, &error, &reply);
f459b602
MAP
538 if (r < 0) {
539 log_error("Failed to list units: %s", bus_error_message(&error, r));
f84190d8 540 return r;
7e4249b9
LP
541 }
542
f459b602
MAP
543 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
544 if (r < 0)
545 return bus_log_parse_error(r);
7e4249b9 546
f459b602 547 while ((r = bus_parse_unit_info(reply, &u)) > 0) {
1238ee09
LP
548 u.machine = machine;
549
8d5ba5a9
ZJS
550 if (!output_show_unit(&u, patterns))
551 continue;
7e4249b9 552
1238ee09 553 if (!GREEDY_REALLOC(*unit_infos, size, c+1))
f459b602 554 return log_oom();
36c32ba2 555
1238ee09 556 (*unit_infos)[c++] = u;
991f2a39 557 }
f459b602
MAP
558 if (r < 0)
559 return bus_log_parse_error(r);
991f2a39 560
f459b602
MAP
561 r = sd_bus_message_exit_container(reply);
562 if (r < 0)
563 return bus_log_parse_error(r);
564
565 *_reply = reply;
566 reply = NULL;
567
1238ee09
LP
568 return c;
569}
570
571static void message_set_freep(Set **set) {
572 sd_bus_message *m;
573
574 while ((m = set_steal_first(*set)))
575 sd_bus_message_unref(m);
576
577 set_free(*set);
578}
579
580static int get_unit_list_recursive(
581 sd_bus *bus,
582 char **patterns,
583 UnitInfo **_unit_infos,
584 Set **_replies,
585 char ***_machines) {
586
587 _cleanup_free_ UnitInfo *unit_infos = NULL;
588 _cleanup_(message_set_freep) Set *replies;
589 sd_bus_message *reply;
590 int c, r;
591
592 assert(bus);
593 assert(_replies);
594 assert(_unit_infos);
595 assert(_machines);
596
597 replies = set_new(NULL, NULL);
598 if (!replies)
599 return log_oom();
600
601 c = get_unit_list(bus, NULL, patterns, &unit_infos, 0, &reply);
602 if (c < 0)
603 return c;
604
605 r = set_put(replies, reply);
606 if (r < 0) {
607 sd_bus_message_unref(reply);
608 return r;
609 }
610
611 if (arg_recursive) {
612 _cleanup_strv_free_ char **machines = NULL;
613 char **i;
614
615 r = sd_get_machine_names(&machines);
616 if (r < 0)
617 return r;
618
619 STRV_FOREACH(i, machines) {
620 _cleanup_bus_unref_ sd_bus *container = NULL;
621 int k;
622
623 r = sd_bus_open_system_container(&container, *i);
624 if (r < 0) {
625 log_error("Failed to connect to container %s: %s", *i, strerror(-r));
626 continue;
627 }
628
629 k = get_unit_list(container, *i, patterns, &unit_infos, c, &reply);
630 if (k < 0)
631 return k;
632
633 c = k;
634
635 r = set_put(replies, reply);
636 if (r < 0) {
637 sd_bus_message_unref(reply);
638 return r;
639 }
640 }
641
642 *_machines = machines;
643 machines = NULL;
644 } else
645 *_machines = NULL;
646
f459b602
MAP
647 *_unit_infos = unit_infos;
648 unit_infos = NULL;
649
1238ee09
LP
650 *_replies = replies;
651 replies = NULL;
652
f459b602 653 return c;
991f2a39
ZJS
654}
655
f459b602 656static int list_units(sd_bus *bus, char **args) {
f459b602 657 _cleanup_free_ UnitInfo *unit_infos = NULL;
1238ee09
LP
658 _cleanup_(message_set_freep) Set *replies = NULL;
659 _cleanup_strv_free_ char **machines = NULL;
991f2a39
ZJS
660 int r;
661
662 pager_open_if_enabled();
663
1238ee09 664 r = get_unit_list_recursive(bus, strv_skip_first(args), &unit_infos, &replies, &machines);
991f2a39
ZJS
665 if (r < 0)
666 return r;
667
f459b602 668 qsort_safe(unit_infos, r, sizeof(UnitInfo), compare_unit_info);
1238ee09 669 return output_units_list(unit_infos, r);
991f2a39
ZJS
670}
671
a00963a2 672static int get_triggered_units(
f459b602
MAP
673 sd_bus *bus,
674 const char* path,
675 char*** ret) {
a00963a2 676
f459b602 677 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
991f2a39
ZJS
678 int r;
679
f459b602
MAP
680 r = sd_bus_get_property_strv(
681 bus,
682 "org.freedesktop.systemd1",
683 path,
684 "org.freedesktop.systemd1.Unit",
685 "Triggers",
686 &error,
687 ret);
991f2a39 688
f459b602
MAP
689 if (r < 0)
690 log_error("Failed to determine triggers: %s", bus_error_message(&error, r));
991f2a39
ZJS
691
692 return 0;
693}
694
f459b602
MAP
695static int get_listening(
696 sd_bus *bus,
697 const char* unit_path,
cbb76c29 698 char*** listening) {
f459b602 699
f459b602 700 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
cbb76c29 701 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
f459b602 702 const char *type, *path;
cbb76c29 703 int r, n = 0;
991f2a39 704
f459b602
MAP
705 r = sd_bus_get_property(
706 bus,
707 "org.freedesktop.systemd1",
708 unit_path,
709 "org.freedesktop.systemd1.Socket",
710 "Listen",
711 &error,
712 &reply,
713 "a(ss)");
714 if (r < 0) {
715 log_error("Failed to get list of listening sockets: %s", bus_error_message(&error, r));
991f2a39 716 return r;
991f2a39
ZJS
717 }
718
f459b602
MAP
719 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)");
720 if (r < 0)
721 return bus_log_parse_error(r);
991f2a39 722
f459b602 723 while ((r = sd_bus_message_read(reply, "(ss)", &type, &path)) > 0) {
36c32ba2 724
0d95178e 725 r = strv_extend(listening, type);
f459b602
MAP
726 if (r < 0)
727 return log_oom();
991f2a39 728
0d95178e 729 r = strv_extend(listening, path);
f459b602
MAP
730 if (r < 0)
731 return log_oom();
7e4249b9 732
cbb76c29 733 n++;
36c32ba2 734 }
f459b602
MAP
735 if (r < 0)
736 return bus_log_parse_error(r);
737
738 r = sd_bus_message_exit_container(reply);
739 if (r < 0)
740 return bus_log_parse_error(r);
36c32ba2 741
cbb76c29 742 return n;
991f2a39
ZJS
743}
744
745struct socket_info {
0cfc3525 746 const char *machine;
991f2a39
ZJS
747 const char* id;
748
749 char* type;
750 char* path;
751
752 /* Note: triggered is a list here, although it almost certainly
753 * will always be one unit. Nevertheless, dbus API allows for multiple
754 * values, so let's follow that.*/
755 char** triggered;
756
757 /* The strv above is shared. free is set only in the first one. */
758 bool own_triggered;
759};
760
cbb76c29 761static int socket_info_compare(const struct socket_info *a, const struct socket_info *b) {
cbc9fbd1
LP
762 int o;
763
cbb76c29
LP
764 assert(a);
765 assert(b);
766
0cfc3525
TA
767 if (!a->machine && b->machine)
768 return -1;
769 if (a->machine && !b->machine)
770 return 1;
771 if (a->machine && b->machine) {
772 o = strcasecmp(a->machine, b->machine);
773 if (o != 0)
774 return o;
775 }
776
cbc9fbd1 777 o = strcmp(a->path, b->path);
991f2a39
ZJS
778 if (o == 0)
779 o = strcmp(a->type, b->type);
cbc9fbd1 780
991f2a39
ZJS
781 return o;
782}
783
784static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
785 struct socket_info *s;
f8294e41
JT
786 unsigned pathlen = strlen("LISTEN"),
787 typelen = strlen("TYPE") * arg_show_types,
788 socklen = strlen("UNIT"),
789 servlen = strlen("ACTIVATES");
991f2a39
ZJS
790 const char *on, *off;
791
792 for (s = socket_infos; s < socket_infos + cs; s++) {
991f2a39 793 unsigned tmp = 0;
cbc9fbd1 794 char **a;
991f2a39
ZJS
795
796 socklen = MAX(socklen, strlen(s->id));
797 if (arg_show_types)
798 typelen = MAX(typelen, strlen(s->type));
0cfc3525 799 pathlen = MAX(pathlen, strlen(s->path) + (s->machine ? strlen(s->machine)+1 : 0));
991f2a39
ZJS
800
801 STRV_FOREACH(a, s->triggered)
802 tmp += strlen(*a) + 2*(a != s->triggered);
803 servlen = MAX(servlen, tmp);
804 }
805
806 if (cs) {
571bfc6c
MM
807 if (!arg_no_legend)
808 printf("%-*s %-*.*s%-*s %s\n",
809 pathlen, "LISTEN",
810 typelen + arg_show_types, typelen + arg_show_types, "TYPE ",
811 socklen, "UNIT",
812 "ACTIVATES");
991f2a39
ZJS
813
814 for (s = socket_infos; s < socket_infos + cs; s++) {
0cfc3525
TA
815 _cleanup_free_ char *j = NULL;
816 const char *path;
991f2a39
ZJS
817 char **a;
818
0cfc3525
TA
819 if (s->machine) {
820 j = strjoin(s->machine, ":", s->path, NULL);
821 if (!j)
822 return log_oom();
823 path = j;
824 } else
825 path = s->path;
826
991f2a39
ZJS
827 if (arg_show_types)
828 printf("%-*s %-*s %-*s",
0cfc3525 829 pathlen, path, typelen, s->type, socklen, s->id);
991f2a39
ZJS
830 else
831 printf("%-*s %-*s",
0cfc3525 832 pathlen, path, socklen, s->id);
991f2a39
ZJS
833 STRV_FOREACH(a, s->triggered)
834 printf("%s %s",
835 a == s->triggered ? "" : ",", *a);
836 printf("\n");
837 }
838
0b5a519c
DS
839 on = ansi_highlight();
840 off = ansi_highlight_off();
571bfc6c
MM
841 if (!arg_no_legend)
842 printf("\n");
991f2a39 843 } else {
0b5a519c
DS
844 on = ansi_highlight_red();
845 off = ansi_highlight_off();
991f2a39
ZJS
846 }
847
571bfc6c
MM
848 if (!arg_no_legend) {
849 printf("%s%u sockets listed.%s\n", on, cs, off);
850 if (!arg_all)
851 printf("Pass --all to see loaded but inactive sockets, too.\n");
852 }
265a7a2a
ZJS
853
854 return 0;
855}
856
f459b602 857static int list_sockets(sd_bus *bus, char **args) {
0cfc3525
TA
858 _cleanup_(message_set_freep) Set *replies = NULL;
859 _cleanup_strv_free_ char **machines = NULL;
f459b602 860 _cleanup_free_ UnitInfo *unit_infos = NULL;
8d5ba5a9 861 _cleanup_free_ struct socket_info *socket_infos = NULL;
f459b602 862 const UnitInfo *u;
991f2a39 863 struct socket_info *s;
cbb76c29 864 unsigned cs = 0;
991f2a39 865 size_t size = 0;
ad83b4c4 866 int r = 0, n;
265a7a2a
ZJS
867
868 pager_open_if_enabled();
869
0cfc3525 870 n = get_unit_list_recursive(bus, strv_skip_first(args), &unit_infos, &replies, &machines);
cbb76c29
LP
871 if (n < 0)
872 return n;
265a7a2a 873
cbb76c29 874 for (u = unit_infos; u < unit_infos + n; u++) {
0d95178e 875 _cleanup_strv_free_ char **listening = NULL, **triggered = NULL;
cbb76c29 876 int i, c;
991f2a39 877
cbc9fbd1 878 if (!endswith(u->id, ".socket"))
991f2a39
ZJS
879 continue;
880
881 r = get_triggered_units(bus, u->unit_path, &triggered);
882 if (r < 0)
883 goto cleanup;
884
cbb76c29
LP
885 c = get_listening(bus, u->unit_path, &listening);
886 if (c < 0) {
887 r = c;
991f2a39 888 goto cleanup;
cbb76c29 889 }
991f2a39
ZJS
890
891 if (!GREEDY_REALLOC(socket_infos, size, cs + c)) {
892 r = log_oom();
893 goto cleanup;
894 }
895
896 for (i = 0; i < c; i++)
897 socket_infos[cs + i] = (struct socket_info) {
0cfc3525 898 .machine = u->machine,
991f2a39 899 .id = u->id,
0d95178e
KS
900 .type = listening[i*2],
901 .path = listening[i*2 + 1],
991f2a39
ZJS
902 .triggered = triggered,
903 .own_triggered = i==0,
904 };
905
906 /* from this point on we will cleanup those socket_infos */
907 cs += c;
0d95178e
KS
908 free(listening);
909 listening = triggered = NULL; /* avoid cleanup */
991f2a39
ZJS
910 }
911
7ff7394d
ZJS
912 qsort_safe(socket_infos, cs, sizeof(struct socket_info),
913 (__compar_fn_t) socket_info_compare);
991f2a39
ZJS
914
915 output_sockets_list(socket_infos, cs);
916
917 cleanup:
918 assert(cs == 0 || socket_infos);
919 for (s = socket_infos; s < socket_infos + cs; s++) {
920 free(s->type);
921 free(s->path);
922 if (s->own_triggered)
923 strv_free(s->triggered);
924 }
4445a875 925
872c8faa 926 return r;
4445a875
LP
927}
928
cbb76c29
LP
929static int get_next_elapse(
930 sd_bus *bus,
931 const char *path,
932 dual_timestamp *next) {
933
934 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
cbb76c29
LP
935 dual_timestamp t;
936 int r;
937
938 assert(bus);
939 assert(path);
940 assert(next);
941
942 r = sd_bus_get_property_trivial(
943 bus,
944 "org.freedesktop.systemd1",
945 path,
946 "org.freedesktop.systemd1.Timer",
947 "NextElapseUSecMonotonic",
948 &error,
949 't',
950 &t.monotonic);
951 if (r < 0) {
952 log_error("Failed to get next elapsation time: %s", bus_error_message(&error, r));
953 return r;
954 }
955
956 r = sd_bus_get_property_trivial(
957 bus,
958 "org.freedesktop.systemd1",
959 path,
960 "org.freedesktop.systemd1.Timer",
961 "NextElapseUSecRealtime",
962 &error,
963 't',
964 &t.realtime);
965 if (r < 0) {
966 log_error("Failed to get next elapsation time: %s", bus_error_message(&error, r));
967 return r;
968 }
969
970 *next = t;
971 return 0;
972}
973
d784e2db
LP
974static int get_last_trigger(
975 sd_bus *bus,
976 const char *path,
977 usec_t *last) {
978
979 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
980 int r;
981
982 assert(bus);
983 assert(path);
984 assert(last);
985
986 r = sd_bus_get_property_trivial(
987 bus,
988 "org.freedesktop.systemd1",
989 path,
990 "org.freedesktop.systemd1.Timer",
dedabea4 991 "LastTriggerUSec",
d784e2db
LP
992 &error,
993 't',
994 last);
995 if (r < 0) {
996 log_error("Failed to get last trigger time: %s", bus_error_message(&error, r));
997 return r;
998 }
999
1000 return 0;
1001}
1002
cbb76c29 1003struct timer_info {
806a37e7 1004 const char* machine;
cbb76c29
LP
1005 const char* id;
1006 usec_t next_elapse;
d784e2db 1007 usec_t last_trigger;
cbb76c29
LP
1008 char** triggered;
1009};
1010
1011static int timer_info_compare(const struct timer_info *a, const struct timer_info *b) {
806a37e7
TA
1012 int o;
1013
cbb76c29
LP
1014 assert(a);
1015 assert(b);
1016
806a37e7
TA
1017 if (!a->machine && b->machine)
1018 return -1;
1019 if (a->machine && !b->machine)
1020 return 1;
1021 if (a->machine && b->machine) {
1022 o = strcasecmp(a->machine, b->machine);
1023 if (o != 0)
1024 return o;
1025 }
1026
cbb76c29
LP
1027 if (a->next_elapse < b->next_elapse)
1028 return -1;
1029 if (a->next_elapse > b->next_elapse)
1030 return 1;
1031
1032 return strcmp(a->id, b->id);
1033}
1034
1035static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
1036 struct timer_info *t;
1037 unsigned
f8294e41
JT
1038 nextlen = strlen("NEXT"),
1039 leftlen = strlen("LEFT"),
d784e2db
LP
1040 lastlen = strlen("LAST"),
1041 passedlen = strlen("PASSED"),
f8294e41
JT
1042 unitlen = strlen("UNIT"),
1043 activatelen = strlen("ACTIVATES");
cbb76c29
LP
1044
1045 const char *on, *off;
1046
1047 assert(timer_infos || n == 0);
1048
1049 for (t = timer_infos; t < timer_infos + n; t++) {
1050 unsigned ul = 0;
1051 char **a;
1052
1053 if (t->next_elapse > 0) {
1054 char tstamp[FORMAT_TIMESTAMP_MAX] = "", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = "";
1055
1056 format_timestamp(tstamp, sizeof(tstamp), t->next_elapse);
1057 nextlen = MAX(nextlen, strlen(tstamp) + 1);
1058
1059 format_timestamp_relative(trel, sizeof(trel), t->next_elapse);
1060 leftlen = MAX(leftlen, strlen(trel));
1061 }
1062
d784e2db
LP
1063 if (t->last_trigger > 0) {
1064 char tstamp[FORMAT_TIMESTAMP_MAX] = "", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = "";
1065
1066 format_timestamp(tstamp, sizeof(tstamp), t->last_trigger);
1067 lastlen = MAX(lastlen, strlen(tstamp) + 1);
1068
1069 format_timestamp_relative(trel, sizeof(trel), t->last_trigger);
1070 passedlen = MAX(passedlen, strlen(trel));
1071 }
1072
806a37e7 1073 unitlen = MAX(unitlen, strlen(t->id) + (t->machine ? strlen(t->machine)+1 : 0));
cbb76c29
LP
1074
1075 STRV_FOREACH(a, t->triggered)
1076 ul += strlen(*a) + 2*(a != t->triggered);
d784e2db 1077
cbb76c29
LP
1078 activatelen = MAX(activatelen, ul);
1079 }
1080
1081 if (n > 0) {
1082 if (!arg_no_legend)
d784e2db
LP
1083 printf("%-*s %-*s %-*s %-*s %-*s %s\n",
1084 nextlen, "NEXT",
1085 leftlen, "LEFT",
1086 lastlen, "LAST",
1087 passedlen, "PASSED",
1088 unitlen, "UNIT",
1089 "ACTIVATES");
cbb76c29
LP
1090
1091 for (t = timer_infos; t < timer_infos + n; t++) {
806a37e7
TA
1092 _cleanup_free_ char *j = NULL;
1093 const char *unit;
d784e2db
LP
1094 char tstamp1[FORMAT_TIMESTAMP_MAX] = "n/a", trel1[FORMAT_TIMESTAMP_RELATIVE_MAX] = "n/a";
1095 char tstamp2[FORMAT_TIMESTAMP_MAX] = "n/a", trel2[FORMAT_TIMESTAMP_RELATIVE_MAX] = "n/a";
cbb76c29
LP
1096 char **a;
1097
d784e2db
LP
1098 format_timestamp(tstamp1, sizeof(tstamp1), t->next_elapse);
1099 format_timestamp_relative(trel1, sizeof(trel1), t->next_elapse);
cbb76c29 1100
d784e2db
LP
1101 format_timestamp(tstamp2, sizeof(tstamp2), t->last_trigger);
1102 format_timestamp_relative(trel2, sizeof(trel2), t->last_trigger);
1103
806a37e7
TA
1104 if (t->machine) {
1105 j = strjoin(t->machine, ":", t->id, NULL);
1106 if (!j)
1107 return log_oom();
1108 unit = j;
1109 } else
1110 unit = t->id;
1111
d784e2db 1112 printf("%-*s %-*s %-*s %-*s %-*s",
806a37e7 1113 nextlen, tstamp1, leftlen, trel1, lastlen, tstamp2, passedlen, trel2, unitlen, unit);
cbb76c29
LP
1114
1115 STRV_FOREACH(a, t->triggered)
1116 printf("%s %s",
1117 a == t->triggered ? "" : ",", *a);
1118 printf("\n");
1119 }
1120
1121 on = ansi_highlight();
1122 off = ansi_highlight_off();
1123 if (!arg_no_legend)
1124 printf("\n");
1125 } else {
1126 on = ansi_highlight_red();
1127 off = ansi_highlight_off();
1128 }
1129
1130 if (!arg_no_legend) {
1131 printf("%s%u timers listed.%s\n", on, n, off);
1132 if (!arg_all)
1133 printf("Pass --all to see loaded but inactive timers, too.\n");
1134 }
1135
1136 return 0;
1137}
1138
f5080e73
DH
1139static usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next) {
1140 usec_t next_elapse;
1141
1142 assert(nw);
1143 assert(next);
1144
1145 if (next->monotonic != (usec_t) -1 && next->monotonic > 0) {
1146 usec_t converted;
1147
1148 if (next->monotonic > nw->monotonic)
1149 converted = nw->realtime + (next->monotonic - nw->monotonic);
1150 else
1151 converted = nw->realtime - (nw->monotonic - next->monotonic);
1152
1153 if (next->realtime != (usec_t) -1 && next->realtime > 0)
1154 next_elapse = MIN(converted, next->realtime);
1155 else
1156 next_elapse = converted;
1157
1158 } else
1159 next_elapse = next->realtime;
1160
1161 return next_elapse;
1162}
1163
cbb76c29 1164static int list_timers(sd_bus *bus, char **args) {
806a37e7
TA
1165 _cleanup_(message_set_freep) Set *replies = NULL;
1166 _cleanup_strv_free_ char **machines = NULL;
cbb76c29
LP
1167 _cleanup_free_ struct timer_info *timer_infos = NULL;
1168 _cleanup_free_ UnitInfo *unit_infos = NULL;
1169 struct timer_info *t;
1170 const UnitInfo *u;
1171 size_t size = 0;
1823b86e 1172 int n, c = 0;
cbb76c29 1173 dual_timestamp nw;
1823b86e 1174 int r = 0;
cbb76c29
LP
1175
1176 pager_open_if_enabled();
1177
806a37e7 1178 n = get_unit_list_recursive(bus, strv_skip_first(args), &unit_infos, &replies, &machines);
cbb76c29
LP
1179 if (n < 0)
1180 return n;
1181
1182 dual_timestamp_get(&nw);
1183
1184 for (u = unit_infos; u < unit_infos + n; u++) {
1185 _cleanup_strv_free_ char **triggered = NULL;
9e82ffa0 1186 dual_timestamp next = {};
d784e2db 1187 usec_t m, last = 0;
cbb76c29 1188
cbb76c29
LP
1189 if (!endswith(u->id, ".timer"))
1190 continue;
1191
1192 r = get_triggered_units(bus, u->unit_path, &triggered);
1193 if (r < 0)
1194 goto cleanup;
1195
1196 r = get_next_elapse(bus, u->unit_path, &next);
1197 if (r < 0)
1198 goto cleanup;
1199
d784e2db
LP
1200 get_last_trigger(bus, u->unit_path, &last);
1201
cbb76c29
LP
1202 if (!GREEDY_REALLOC(timer_infos, size, c+1)) {
1203 r = log_oom();
1204 goto cleanup;
1205 }
1206
f5080e73
DH
1207 m = calc_next_elapse(&nw, &next);
1208
cbb76c29 1209 timer_infos[c++] = (struct timer_info) {
806a37e7 1210 .machine = u->machine,
cbb76c29
LP
1211 .id = u->id,
1212 .next_elapse = m,
d784e2db 1213 .last_trigger = last,
cbb76c29
LP
1214 .triggered = triggered,
1215 };
1216
1217 triggered = NULL; /* avoid cleanup */
1218 }
1219
1220 qsort_safe(timer_infos, c, sizeof(struct timer_info),
1221 (__compar_fn_t) timer_info_compare);
1222
1223 output_timers_list(timer_infos, c);
1224
1225 cleanup:
1226 for (t = timer_infos; t < timer_infos + c; t++)
1227 strv_free(t->triggered);
1228
1229 return r;
1230}
1231
729e3769
LP
1232static int compare_unit_file_list(const void *a, const void *b) {
1233 const char *d1, *d2;
1234 const UnitFileList *u = a, *v = b;
1235
1236 d1 = strrchr(u->path, '.');
1237 d2 = strrchr(v->path, '.');
1238
1239 if (d1 && d2) {
1240 int r;
1241
1242 r = strcasecmp(d1, d2);
1243 if (r != 0)
1244 return r;
1245 }
1246
2b6bf07d 1247 return strcasecmp(basename(u->path), basename(v->path));
729e3769
LP
1248}
1249
d8fba7c6 1250static bool output_show_unit_file(const UnitFileList *u, char **patterns) {
729e3769
LP
1251 const char *dot;
1252
d8fba7c6
ZJS
1253 if (!strv_isempty(patterns)) {
1254 char **pattern;
1255
1256 STRV_FOREACH(pattern, patterns)
1257 if (fnmatch(*pattern, basename(u->path), FNM_NOESCAPE) == 0)
1258 return true;
1259 return false;
1260 }
1261
20b3f379 1262 return !arg_types || ((dot = strrchr(u->path, '.')) && strv_find(arg_types, dot+1));
729e3769
LP
1263}
1264
8d5ba5a9 1265static void output_unit_file_list(const UnitFileList *units, unsigned c) {
0d292f5e 1266 unsigned max_id_len, id_cols, state_cols;
729e3769
LP
1267 const UnitFileList *u;
1268
f8294e41
JT
1269 max_id_len = strlen("UNIT FILE");
1270 state_cols = strlen("STATE");
cbc9fbd1 1271
1c0a113f 1272 for (u = units; u < units + c; u++) {
2b6bf07d 1273 max_id_len = MAX(max_id_len, strlen(basename(u->path)));
1c0a113f
ZJS
1274 state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state)));
1275 }
1276
1277 if (!arg_full) {
1278 unsigned basic_cols;
cbc9fbd1 1279
9607d947 1280 id_cols = MIN(max_id_len, 25u);
1c0a113f
ZJS
1281 basic_cols = 1 + id_cols + state_cols;
1282 if (basic_cols < (unsigned) columns())
1283 id_cols += MIN(columns() - basic_cols, max_id_len - id_cols);
1284 } else
1285 id_cols = max_id_len;
1286
1287 if (!arg_no_legend)
cbc9fbd1
LP
1288 printf("%-*s %-*s\n",
1289 id_cols, "UNIT FILE",
1290 state_cols, "STATE");
729e3769
LP
1291
1292 for (u = units; u < units + c; u++) {
7fd1b19b 1293 _cleanup_free_ char *e = NULL;
729e3769
LP
1294 const char *on, *off;
1295 const char *id;
1296
729e3769
LP
1297 if (u->state == UNIT_FILE_MASKED ||
1298 u->state == UNIT_FILE_MASKED_RUNTIME ||
b5b46d59
LP
1299 u->state == UNIT_FILE_DISABLED ||
1300 u->state == UNIT_FILE_INVALID) {
0b5a519c
DS
1301 on = ansi_highlight_red();
1302 off = ansi_highlight_off();
729e3769 1303 } else if (u->state == UNIT_FILE_ENABLED) {
0b5a519c
DS
1304 on = ansi_highlight_green();
1305 off = ansi_highlight_off();
729e3769
LP
1306 } else
1307 on = off = "";
1308
2b6bf07d 1309 id = basename(u->path);
729e3769 1310
1c0a113f 1311 e = arg_full ? NULL : ellipsize(id, id_cols, 33);
729e3769 1312
1c0a113f
ZJS
1313 printf("%-*s %s%-*s%s\n",
1314 id_cols, e ? e : id,
1315 on, state_cols, unit_file_state_to_string(u->state), off);
729e3769
LP
1316 }
1317
1c0a113f 1318 if (!arg_no_legend)
0d292f5e 1319 printf("\n%u unit files listed.\n", c);
729e3769
LP
1320}
1321
f459b602
MAP
1322static int list_unit_files(sd_bus *bus, char **args) {
1323 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1324 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
f84190d8 1325 _cleanup_free_ UnitFileList *units = NULL;
8d5ba5a9
ZJS
1326 UnitFileList *unit;
1327 size_t size = 0;
f459b602
MAP
1328 unsigned c = 0;
1329 const char *state;
1330 char *path;
f84190d8 1331 int r;
729e3769 1332
729e3769
LP
1333 pager_open_if_enabled();
1334
1335 if (avoid_bus()) {
1336 Hashmap *h;
1337 UnitFileList *u;
1338 Iterator i;
f459b602 1339 unsigned n_units;
729e3769
LP
1340
1341 h = hashmap_new(string_hash_func, string_compare_func);
0d0f0c50
SL
1342 if (!h)
1343 return log_oom();
729e3769
LP
1344
1345 r = unit_file_get_list(arg_scope, arg_root, h);
1346 if (r < 0) {
8ea913b2 1347 unit_file_list_free(h);
729e3769
LP
1348 log_error("Failed to get unit file list: %s", strerror(-r));
1349 return r;
1350 }
1351
1352 n_units = hashmap_size(h);
1353 units = new(UnitFileList, n_units);
1354 if (!units) {
1355 unit_file_list_free(h);
0d0f0c50 1356 return log_oom();
729e3769
LP
1357 }
1358
1359 HASHMAP_FOREACH(u, h, i) {
8d5ba5a9
ZJS
1360 if (!output_show_unit_file(u, strv_skip_first(args)))
1361 continue;
1362
1363 units[c++] = *u;
729e3769
LP
1364 free(u);
1365 }
1366
8d5ba5a9 1367 assert(c <= n_units);
729e3769
LP
1368 hashmap_free(h);
1369 } else {
f459b602 1370 r = sd_bus_call_method(
f22f08cd 1371 bus,
729e3769
LP
1372 "org.freedesktop.systemd1",
1373 "/org/freedesktop/systemd1",
1374 "org.freedesktop.systemd1.Manager",
f22f08cd 1375 "ListUnitFiles",
f459b602 1376 &error,
f22f08cd 1377 &reply,
f459b602
MAP
1378 NULL);
1379 if (r < 0) {
1380 log_error("Failed to list unit files: %s", bus_error_message(&error, r));
f84190d8 1381 return r;
729e3769
LP
1382 }
1383
f459b602
MAP
1384 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)");
1385 if (r < 0)
1386 return bus_log_parse_error(r);
729e3769 1387
f459b602 1388 while ((r = sd_bus_message_read(reply, "(ss)", &path, &state)) > 0) {
729e3769 1389
f459b602
MAP
1390 if (!GREEDY_REALLOC(units, size, c + 1))
1391 return log_oom();
729e3769 1392
8d5ba5a9 1393 units[c] = (struct UnitFileList) {
f459b602
MAP
1394 path,
1395 unit_file_state_from_string(state)
1396 };
8d5ba5a9
ZJS
1397
1398 if (output_show_unit_file(&units[c], strv_skip_first(args)))
1399 c ++;
1400
729e3769 1401 }
f459b602
MAP
1402 if (r < 0)
1403 return bus_log_parse_error(r);
1404
1405 r = sd_bus_message_exit_container(reply);
1406 if (r < 0)
1407 return bus_log_parse_error(r);
729e3769
LP
1408 }
1409
1410 if (c > 0) {
1411 qsort(units, c, sizeof(UnitFileList), compare_unit_file_list);
8d5ba5a9 1412 output_unit_file_list(units, c);
729e3769
LP
1413 }
1414
8d5ba5a9
ZJS
1415 if (avoid_bus())
1416 for (unit = units; unit < units + c; unit++)
1417 free(unit->path);
1418
f84190d8 1419 return 0;
729e3769
LP
1420}
1421
55c0b89c 1422static int list_dependencies_print(const char *name, int level, unsigned int branches, bool last) {
55c0b89c 1423 _cleanup_free_ char *n = NULL;
9607d947 1424 size_t max_len = MAX(columns(),20u);
cbc9fbd1
LP
1425 size_t len = 0;
1426 int i;
55c0b89c 1427
5d0c05e5 1428 if (!arg_plain) {
cbc9fbd1 1429
5d0c05e5
LN
1430 for (i = level - 1; i >= 0; i--) {
1431 len += 2;
f168c273 1432 if (len > max_len - 3 && !arg_full) {
5d0c05e5
LN
1433 printf("%s...\n",max_len % 2 ? "" : " ");
1434 return 0;
1435 }
6b01f1d3 1436 printf("%s", draw_special_char(branches & (1 << i) ? DRAW_TREE_VERTICAL : DRAW_TREE_SPACE));
5d0c05e5 1437 }
55c0b89c 1438 len += 2;
cbc9fbd1 1439
f168c273 1440 if (len > max_len - 3 && !arg_full) {
55c0b89c
LN
1441 printf("%s...\n",max_len % 2 ? "" : " ");
1442 return 0;
1443 }
cbc9fbd1 1444
5d0c05e5 1445 printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
55c0b89c 1446 }
55c0b89c 1447
cbc9fbd1 1448 if (arg_full){
55c0b89c
LN
1449 printf("%s\n", name);
1450 return 0;
1451 }
1452
1453 n = ellipsize(name, max_len-len, 100);
f168c273 1454 if (!n)
55c0b89c
LN
1455 return log_oom();
1456
1457 printf("%s\n", n);
1458 return 0;
1459}
1460
f459b602
MAP
1461static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, char ***deps) {
1462
071066a5 1463 static const char *dependencies[_DEPENDENCY_MAX] = {
afba4199
ZJS
1464 [DEPENDENCY_FORWARD] = "Requires\0"
1465 "RequiresOverridable\0"
1466 "Requisite\0"
1467 "RequisiteOverridable\0"
1468 "Wants\0",
1469 [DEPENDENCY_REVERSE] = "RequiredBy\0"
1470 "RequiredByOverridable\0"
1471 "WantedBy\0"
1472 "PartOf\0",
1473 [DEPENDENCY_AFTER] = "After\0",
1474 [DEPENDENCY_BEFORE] = "Before\0",
1475 };
55c0b89c 1476
f459b602
MAP
1477 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1478 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1479 _cleanup_strv_free_ char **ret = NULL;
1480 _cleanup_free_ char *path = NULL;
1481 int r;
55c0b89c
LN
1482
1483 assert(bus);
1484 assert(name);
1485 assert(deps);
071066a5 1486 assert_cc(ELEMENTSOF(dependencies) == _DEPENDENCY_MAX);
55c0b89c
LN
1487
1488 path = unit_dbus_path_from_name(name);
f459b602
MAP
1489 if (!path)
1490 return log_oom();
55c0b89c 1491
f459b602
MAP
1492 r = sd_bus_call_method(
1493 bus,
1494 "org.freedesktop.systemd1",
1495 path,
1496 "org.freedesktop.DBus.Properties",
1497 "GetAll",
1498 &error,
1499 &reply,
1500 "s", "org.freedesktop.systemd1.Unit");
1501 if (r < 0) {
1502 log_error("Failed to get properties of %s: %s", name, bus_error_message(&error, r));
1503 return r;
55c0b89c
LN
1504 }
1505
f459b602
MAP
1506 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
1507 if (r < 0)
1508 return bus_log_parse_error(r);
55c0b89c 1509
f459b602 1510 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
55c0b89c
LN
1511 const char *prop;
1512
f459b602
MAP
1513 r = sd_bus_message_read(reply, "s", &prop);
1514 if (r < 0)
1515 return bus_log_parse_error(r);
55c0b89c 1516
f459b602
MAP
1517 if (!nulstr_contains(dependencies[arg_dependency], prop)) {
1518 r = sd_bus_message_skip(reply, "v");
1519 if (r < 0)
1520 return bus_log_parse_error(r);
1521 } else {
55c0b89c 1522
f459b602
MAP
1523 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, "as");
1524 if (r < 0)
1525 return bus_log_parse_error(r);
55c0b89c 1526
f459b602
MAP
1527 r = bus_message_read_strv_extend(reply, &ret);
1528 if (r < 0)
1529 return bus_log_parse_error(r);
55c0b89c 1530
f459b602
MAP
1531 r = sd_bus_message_exit_container(reply);
1532 if (r < 0)
1533 return bus_log_parse_error(r);
1534 }
55c0b89c 1535
f459b602
MAP
1536 r = sd_bus_message_exit_container(reply);
1537 if (r < 0)
1538 return bus_log_parse_error(r);
55c0b89c 1539
f459b602
MAP
1540 }
1541 if (r < 0)
1542 return bus_log_parse_error(r);
55c0b89c 1543
f459b602
MAP
1544 r = sd_bus_message_exit_container(reply);
1545 if (r < 0)
1546 return bus_log_parse_error(r);
540e7dbe 1547
f459b602
MAP
1548 *deps = ret;
1549 ret = NULL;
540e7dbe 1550
f459b602 1551 return 0;
55c0b89c
LN
1552}
1553
1554static int list_dependencies_compare(const void *_a, const void *_b) {
1555 const char **a = (const char**) _a, **b = (const char**) _b;
cbc9fbd1 1556
55c0b89c
LN
1557 if (unit_name_to_type(*a) == UNIT_TARGET && unit_name_to_type(*b) != UNIT_TARGET)
1558 return 1;
1559 if (unit_name_to_type(*a) != UNIT_TARGET && unit_name_to_type(*b) == UNIT_TARGET)
1560 return -1;
cbc9fbd1 1561
55c0b89c
LN
1562 return strcasecmp(*a, *b);
1563}
1564
f459b602
MAP
1565static int list_dependencies_one(
1566 sd_bus *bus,
1567 const char *name,
1568 int level,
1569 char ***units,
1570 unsigned int branches) {
1571
e3e45d4f 1572 _cleanup_strv_free_ char **deps = NULL;
55c0b89c 1573 char **c;
55c0b89c
LN
1574 int r = 0;
1575
cbc9fbd1
LP
1576 assert(bus);
1577 assert(name);
1578 assert(units);
1579
e3e45d4f
SP
1580 r = strv_extend(units, name);
1581 if (r < 0)
55c0b89c
LN
1582 return log_oom();
1583
1584 r = list_dependencies_get_dependencies(bus, name, &deps);
1585 if (r < 0)
cec7eda5 1586 return r;
55c0b89c 1587
7ff7394d 1588 qsort_safe(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
55c0b89c
LN
1589
1590 STRV_FOREACH(c, deps) {
dbc2c080
LP
1591 int state;
1592
e3e45d4f 1593 if (strv_contains(*units, *c)) {
5d0c05e5
LN
1594 if (!arg_plain) {
1595 r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
1596 if (r < 0)
1597 return r;
1598 }
55c0b89c
LN
1599 continue;
1600 }
1601
dbc2c080
LP
1602 state = check_one_unit(bus, *c, "activating\0active\0reloading\0", true);
1603 if (state > 0)
6b01f1d3 1604 printf("%s%s%s ", ansi_highlight_green(), draw_special_char(DRAW_BLACK_CIRCLE), ansi_highlight_off());
dbc2c080 1605 else
6b01f1d3 1606 printf("%s%s%s ", ansi_highlight_red(), draw_special_char(DRAW_BLACK_CIRCLE), ansi_highlight_off());
dbc2c080 1607
55c0b89c 1608 r = list_dependencies_print(*c, level, branches, c[1] == NULL);
cec7eda5
ZJS
1609 if (r < 0)
1610 return r;
55c0b89c
LN
1611
1612 if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) {
e3e45d4f 1613 r = list_dependencies_one(bus, *c, level + 1, units, (branches << 1) | (c[1] == NULL ? 0 : 1));
f168c273 1614 if (r < 0)
cec7eda5 1615 return r;
55c0b89c
LN
1616 }
1617 }
f459b602 1618
e3e45d4f
SP
1619 if (!arg_plain)
1620 strv_remove(*units, name);
f459b602 1621
cec7eda5 1622 return 0;
55c0b89c
LN
1623}
1624
f459b602 1625static int list_dependencies(sd_bus *bus, char **args) {
5d0c05e5 1626 _cleanup_strv_free_ char **units = NULL;
f459b602 1627 _cleanup_free_ char *unit = NULL;
e31165b2 1628 const char *u;
55c0b89c
LN
1629
1630 assert(bus);
55c0b89c 1631
e31165b2 1632 if (args[1]) {
f78e6385 1633 unit = unit_name_mangle(args[1], MANGLE_NOGLOB);
e31165b2
LP
1634 if (!unit)
1635 return log_oom();
1636 u = unit;
1637 } else
1638 u = SPECIAL_DEFAULT_TARGET;
55c0b89c
LN
1639
1640 pager_open_if_enabled();
e31165b2
LP
1641
1642 puts(u);
1643
5d0c05e5 1644 return list_dependencies_one(bus, u, 0, &units, 0);
55c0b89c
LN
1645}
1646
0d292f5e
LP
1647struct machine_info {
1648 bool is_host;
1649 char *name;
0d292f5e 1650 char *state;
8fcf784d
LP
1651 char *control_group;
1652 uint32_t n_failed_units;
1653 uint32_t n_jobs;
1654 usec_t timestamp;
1655};
1656
1657static const struct bus_properties_map machine_info_property_map[] = {
1658 { "SystemState", "s", NULL, offsetof(struct machine_info, state) },
1659 { "NJobs", "u", NULL, offsetof(struct machine_info, n_jobs) },
1660 { "NFailedUnits", "u", NULL, offsetof(struct machine_info, n_failed_units) },
1661 { "ControlGroup", "s", NULL, offsetof(struct machine_info, control_group) },
1662 { "UserspaceTimestamp", "t", NULL, offsetof(struct machine_info, timestamp) },
1663 {}
0d292f5e
LP
1664};
1665
1666static void free_machines_list(struct machine_info *machine_infos, int n) {
1667 int i;
1668
1669 if (!machine_infos)
1670 return;
1671
1672 for (i = 0; i < n; i++) {
1673 free(machine_infos[i].name);
1674 free(machine_infos[i].state);
8fcf784d 1675 free(machine_infos[i].control_group);
0d292f5e
LP
1676 }
1677
1678 free(machine_infos);
1679}
1680
1681static int compare_machine_info(const void *a, const void *b) {
1682 const struct machine_info *u = a, *v = b;
1683
1684 if (u->is_host != v->is_host)
50933da0 1685 return u->is_host > v->is_host ? -1 : 1;
0d292f5e
LP
1686
1687 return strcasecmp(u->name, v->name);
1688}
1689
1690static int get_machine_properties(sd_bus *bus, struct machine_info *mi) {
0d292f5e
LP
1691 _cleanup_bus_unref_ sd_bus *container = NULL;
1692 int r;
1693
1694 assert(mi);
1695
1696 if (!bus) {
1697 r = sd_bus_open_system_container(&container, mi->name);
1698 if (r < 0)
1699 return r;
1700
1701 bus = container;
1702 }
1703
8fcf784d 1704 r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, mi);
0d292f5e
LP
1705 if (r < 0)
1706 return r;
1707
1708 return 0;
1709}
1710
1711static bool output_show_machine(const char *name, char **patterns) {
1712 char **i;
1713
1714 assert(name);
1715
1716 if (strv_isempty(patterns))
1717 return true;
1718
1719 STRV_FOREACH(i, patterns)
1720 if (fnmatch(*i, name, FNM_NOESCAPE) == 0)
1721 return true;
1722
1723 return false;
1724}
1725
1726static int get_machine_list(
1727 sd_bus *bus,
1728 struct machine_info **_machine_infos,
1729 char **patterns) {
1730
1731 struct machine_info *machine_infos = NULL;
1732 _cleanup_strv_free_ char **m = NULL;
1733 _cleanup_free_ char *hn = NULL;
1734 size_t sz = 0;
1735 char **i;
1736 int c = 0;
1737
1738 hn = gethostname_malloc();
1739 if (!hn)
1740 return log_oom();
1741
1742 if (output_show_machine(hn, patterns)) {
1743 if (!GREEDY_REALLOC0(machine_infos, sz, c+1))
1744 return log_oom();
1745
1746 machine_infos[c].is_host = true;
1747 machine_infos[c].name = hn;
1748 hn = NULL;
1749
1750 get_machine_properties(bus, &machine_infos[c]);
1751 c++;
1752 }
1753
1754 sd_get_machine_names(&m);
1755 STRV_FOREACH(i, m) {
1756 _cleanup_free_ char *class = NULL;
1757
1758 if (!output_show_machine(*i, patterns))
1759 continue;
1760
1761 sd_machine_get_class(*i, &class);
1762 if (!streq_ptr(class, "container"))
1763 continue;
1764
1765 if (!GREEDY_REALLOC0(machine_infos, sz, c+1)) {
1766 free_machines_list(machine_infos, c);
1767 return log_oom();
1768 }
1769
1770 machine_infos[c].is_host = false;
1771 machine_infos[c].name = strdup(*i);
1772 if (!machine_infos[c].name) {
1773 free_machines_list(machine_infos, c);
1774 return log_oom();
1775 }
1776
1777 get_machine_properties(NULL, &machine_infos[c]);
1778 c++;
1779 }
1780
1781 *_machine_infos = machine_infos;
1782 return c;
1783}
1784
1785static void output_machines_list(struct machine_info *machine_infos, unsigned n) {
1786 struct machine_info *m;
1787 unsigned
90c3f79d 1788 circle_len = 0,
0d292f5e
LP
1789 namelen = sizeof("NAME") - 1,
1790 statelen = sizeof("STATE") - 1,
1791 failedlen = sizeof("FAILED") - 1,
1792 jobslen = sizeof("JOBS") - 1;
1793
1794 assert(machine_infos || n == 0);
1795
1796 for (m = machine_infos; m < machine_infos + n; m++) {
1797 namelen = MAX(namelen, strlen(m->name) + (m->is_host ? sizeof(" (host)") - 1 : 0));
1798 statelen = MAX(statelen, m->state ? strlen(m->state) : 0);
1799 failedlen = MAX(failedlen, DECIMAL_STR_WIDTH(m->n_failed_units));
1800 jobslen = MAX(jobslen, DECIMAL_STR_WIDTH(m->n_jobs));
90c3f79d
LP
1801
1802 if (!arg_no_legend && !streq_ptr(m->state, "running"))
1803 circle_len = 2;
0d292f5e
LP
1804 }
1805
90c3f79d
LP
1806 if (!arg_no_legend) {
1807 if (circle_len > 0)
1808 fputs(" ", stdout);
1809
0d292f5e
LP
1810 printf("%-*s %-*s %-*s %-*s\n",
1811 namelen, "NAME",
1812 statelen, "STATE",
1813 failedlen, "FAILED",
1814 jobslen, "JOBS");
90c3f79d 1815 }
0d292f5e
LP
1816
1817 for (m = machine_infos; m < machine_infos + n; m++) {
90c3f79d
LP
1818 const char *on_state = "", *off_state = "";
1819 const char *on_failed = "", *off_failed = "";
1820 bool circle = false;
0d292f5e
LP
1821
1822 if (streq_ptr(m->state, "degraded")) {
1823 on_state = ansi_highlight_red();
1824 off_state = ansi_highlight_off();
90c3f79d 1825 circle = true;
0d292f5e
LP
1826 } else if (!streq_ptr(m->state, "running")) {
1827 on_state = ansi_highlight_yellow();
1828 off_state = ansi_highlight_off();
90c3f79d
LP
1829 circle = true;
1830 }
0d292f5e
LP
1831
1832 if (m->n_failed_units > 0) {
1833 on_failed = ansi_highlight_red();
1834 off_failed = ansi_highlight_off();
1835 } else
1836 on_failed = off_failed = "";
1837
90c3f79d 1838 if (circle_len > 0)
6b01f1d3 1839 printf("%s%s%s ", on_state, circle ? draw_special_char(DRAW_BLACK_CIRCLE) : " ", off_state);
90c3f79d 1840
0d292f5e
LP
1841 if (m->is_host)
1842 printf("%-*s (host) %s%-*s%s %s%*u%s %*u\n",
1843 (int) (namelen - (sizeof(" (host)")-1)), strna(m->name),
1844 on_state, statelen, strna(m->state), off_state,
1845 on_failed, failedlen, m->n_failed_units, off_failed,
1846 jobslen, m->n_jobs);
1847 else
1848 printf("%-*s %s%-*s%s %s%*u%s %*u\n",
1849 namelen, strna(m->name),
1850 on_state, statelen, strna(m->state), off_state,
1851 on_failed, failedlen, m->n_failed_units, off_failed,
1852 jobslen, m->n_jobs);
1853 }
1854
1855 if (!arg_no_legend)
1856 printf("\n%u machines listed.\n", n);
1857}
1858
1859static int list_machines(sd_bus *bus, char **args) {
1860 struct machine_info *machine_infos = NULL;
1861 int r;
1862
1863 assert(bus);
1864
1865 if (geteuid() != 0) {
1866 log_error("Must be root.");
1867 return -EPERM;
1868 }
1869
1870 pager_open_if_enabled();
1871
1872 r = get_machine_list(bus, &machine_infos, strv_skip_first(args));
1873 if (r < 0)
1874 return r;
1875
1876 qsort_safe(machine_infos, r, sizeof(struct machine_info), compare_machine_info);
1877 output_machines_list(machine_infos, r);
1878 free_machines_list(machine_infos, r);
1879
1880 return 0;
1881}
1882
f459b602
MAP
1883static int get_default(sd_bus *bus, char **args) {
1884 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1885 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1886 _cleanup_free_ char *_path = NULL;
1887 const char *path;
99504dd4 1888 int r;
99504dd4
VP
1889
1890 if (!bus || avoid_bus()) {
f459b602 1891 r = unit_file_get_default(arg_scope, arg_root, &_path);
99504dd4 1892 if (r < 0) {
f459b602
MAP
1893 log_error("Failed to get default target: %s", strerror(-r));
1894 return r;
99504dd4 1895 }
f459b602 1896 path = _path;
99504dd4 1897
99504dd4 1898 } else {
f459b602
MAP
1899 r = sd_bus_call_method(
1900 bus,
1901 "org.freedesktop.systemd1",
1902 "/org/freedesktop/systemd1",
1903 "org.freedesktop.systemd1.Manager",
1904 "GetDefaultTarget",
1905 &error,
1906 &reply,
1907 NULL);
99504dd4 1908 if (r < 0) {
f459b602
MAP
1909 log_error("Failed to get default target: %s", bus_error_message(&error, -r));
1910 return r;
99504dd4
VP
1911 }
1912
f459b602
MAP
1913 r = sd_bus_message_read(reply, "s", &path);
1914 if (r < 0)
1915 return bus_log_parse_error(r);
99504dd4
VP
1916 }
1917
1918 if (path)
1919 printf("%s\n", path);
1920
f459b602 1921 return 0;
99504dd4
VP
1922}
1923
718db961
LP
1924static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_changes) {
1925 unsigned i;
1926
1927 assert(changes || n_changes == 0);
1928
1929 for (i = 0; i < n_changes; i++) {
1930 if (changes[i].type == UNIT_FILE_SYMLINK)
735a1a2e 1931 log_info("Created symlink from %s to %s.", changes[i].path, changes[i].source);
718db961 1932 else
749ebb2d 1933 log_info("Removed symlink %s.", changes[i].path);
718db961
LP
1934 }
1935}
1936
1937static int deserialize_and_dump_unit_file_changes(sd_bus_message *m) {
1938 const char *type, *path, *source;
1939 int r;
1940
1941 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
1942 if (r < 0)
1943 return bus_log_parse_error(r);
1944
1945 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
1946 if (!arg_quiet) {
1947 if (streq(type, "symlink"))
735a1a2e 1948 log_info("Created symlink from %s to %s.", path, source);
718db961 1949 else
749ebb2d 1950 log_info("Removed symlink %s.", path);
718db961
LP
1951 }
1952 }
1953 if (r < 0)
1954 return bus_log_parse_error(r);
1955
1956 r = sd_bus_message_exit_container(m);
1957 if (r < 0)
1958 return bus_log_parse_error(r);
1959
1960 return 0;
1961}
1962
1963static int set_default(sd_bus *bus, char **args) {
1964 _cleanup_free_ char *unit = NULL;
1965 UnitFileChange *changes = NULL;
1966 unsigned n_changes = 0;
1967 int r;
1968
f78e6385 1969 unit = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".target");
718db961
LP
1970 if (!unit)
1971 return log_oom();
1972
1973 if (!bus || avoid_bus()) {
a1484a21 1974 r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes);
718db961
LP
1975 if (r < 0) {
1976 log_error("Failed to set default target: %s", strerror(-r));
1977 return r;
1978 }
1979
1980 if (!arg_quiet)
1981 dump_unit_file_changes(changes, n_changes);
1982
1983 r = 0;
1984 } else {
1985 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1986 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1987
1988 r = sd_bus_call_method(
1989 bus,
1990 "org.freedesktop.systemd1",
1991 "/org/freedesktop/systemd1",
1992 "org.freedesktop.systemd1.Manager",
1993 "SetDefaultTarget",
1994 &error,
1995 &reply,
a1484a21 1996 "sb", unit, true);
718db961
LP
1997 if (r < 0) {
1998 log_error("Failed to set default target: %s", bus_error_message(&error, -r));
1999 return r;
2000 }
2001
2002 r = deserialize_and_dump_unit_file_changes(reply);
2003 if (r < 0)
2004 return r;
2005
93c941e3 2006 /* Try to reload if enabled */
718db961
LP
2007 if (!arg_no_reload)
2008 r = daemon_reload(bus, args);
2009 else
2010 r = 0;
2011 }
2012
2013 unit_file_changes_free(changes, n_changes);
2014
2015 return r;
2016}
2017
75add28a
ZJS
2018struct job_info {
2019 uint32_t id;
f459b602 2020 const char *name, *type, *state;
75add28a
ZJS
2021};
2022
d8fba7c6 2023static void output_jobs_list(const struct job_info* jobs, unsigned n, bool skipped) {
f459b602
MAP
2024 unsigned id_len, unit_len, type_len, state_len;
2025 const struct job_info *j;
75add28a
ZJS
2026 const char *on, *off;
2027 bool shorten = false;
2028
2029 assert(n == 0 || jobs);
2030
2031 if (n == 0) {
0b5a519c
DS
2032 on = ansi_highlight_green();
2033 off = ansi_highlight_off();
75add28a 2034
d8fba7c6 2035 printf("%sNo jobs %s.%s\n", on, skipped ? "listed" : "running", off);
75add28a
ZJS
2036 return;
2037 }
2038
2039 pager_open_if_enabled();
2040
f8294e41
JT
2041 id_len = strlen("JOB");
2042 unit_len = strlen("UNIT");
2043 type_len = strlen("TYPE");
2044 state_len = strlen("STATE");
6d6d40c9 2045
f459b602
MAP
2046 for (j = jobs; j < jobs + n; j++) {
2047 uint32_t id = j->id;
2048 assert(j->name && j->type && j->state);
75add28a 2049
f459b602
MAP
2050 id_len = MAX(id_len, DECIMAL_STR_WIDTH(id));
2051 unit_len = MAX(unit_len, strlen(j->name));
2052 type_len = MAX(type_len, strlen(j->type));
2053 state_len = MAX(state_len, strlen(j->state));
2054 }
75add28a 2055
f459b602
MAP
2056 if (!arg_full && id_len + 1 + unit_len + type_len + 1 + state_len > columns()) {
2057 unit_len = MAX(33u, columns() - id_len - type_len - state_len - 3);
2058 shorten = true;
2059 }
75add28a 2060
6ce774fd
MM
2061 if (!arg_no_legend)
2062 printf("%*s %-*s %-*s %-*s\n",
2063 id_len, "JOB",
2064 unit_len, "UNIT",
2065 type_len, "TYPE",
2066 state_len, "STATE");
75add28a 2067
f459b602
MAP
2068 for (j = jobs; j < jobs + n; j++) {
2069 _cleanup_free_ char *e = NULL;
75add28a 2070
f459b602
MAP
2071 if (streq(j->state, "running")) {
2072 on = ansi_highlight();
2073 off = ansi_highlight_off();
2074 } else
2075 on = off = "";
2076
2077 e = shorten ? ellipsize(j->name, unit_len, 33) : NULL;
2078 printf("%*u %s%-*s%s %-*s %s%-*s%s\n",
2079 id_len, j->id,
2080 on, unit_len, e ? e : j->name, off,
2081 type_len, j->type,
2082 on, state_len, j->state, off);
75add28a
ZJS
2083 }
2084
6ce774fd
MM
2085 if (!arg_no_legend) {
2086 on = ansi_highlight();
2087 off = ansi_highlight_off();
75add28a 2088
6ce774fd
MM
2089 printf("\n%s%u jobs listed%s.\n", on, n, off);
2090 }
75add28a
ZJS
2091}
2092
d8fba7c6 2093static bool output_show_job(struct job_info *job, char **patterns) {
0d292f5e 2094 char **pattern;
d8fba7c6 2095
0d292f5e 2096 assert(job);
d8fba7c6 2097
0d292f5e
LP
2098 if (strv_isempty(patterns))
2099 return true;
2100
2101 STRV_FOREACH(pattern, patterns)
2102 if (fnmatch(*pattern, job->name, FNM_NOESCAPE) == 0)
2103 return true;
2104 return false;
d8fba7c6
ZJS
2105}
2106
f459b602
MAP
2107static int list_jobs(sd_bus *bus, char **args) {
2108 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2109 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
2110 const char *name, *type, *state, *job_path, *unit_path;
2111 _cleanup_free_ struct job_info *jobs = NULL;
2112 size_t size = 0;
2113 unsigned c = 0;
2114 uint32_t id;
f84190d8 2115 int r;
d8fba7c6 2116 bool skipped = false;
ec14911e 2117
f459b602 2118 r = sd_bus_call_method(
f22f08cd
SP
2119 bus,
2120 "org.freedesktop.systemd1",
2121 "/org/freedesktop/systemd1",
2122 "org.freedesktop.systemd1.Manager",
2123 "ListJobs",
f459b602 2124 &error,
f22f08cd 2125 &reply,
f459b602
MAP
2126 NULL);
2127 if (r < 0) {
2128 log_error("Failed to list jobs: %s", bus_error_message(&error, r));
f84190d8 2129 return r;
7e4249b9
LP
2130 }
2131
f459b602
MAP
2132 r = sd_bus_message_enter_container(reply, 'a', "(usssoo)");
2133 if (r < 0)
2134 return bus_log_parse_error(r);
7e4249b9 2135
f459b602 2136 while ((r = sd_bus_message_read(reply, "(usssoo)", &id, &name, &type, &state, &job_path, &unit_path)) > 0) {
d8fba7c6
ZJS
2137 struct job_info job = { id, name, type, state };
2138
2139 if (!output_show_job(&job, strv_skip_first(args))) {
2140 skipped = true;
2141 continue;
2142 }
8fe914ec 2143
f459b602
MAP
2144 if (!GREEDY_REALLOC(jobs, size, c + 1))
2145 return log_oom();
7e4249b9 2146
d8fba7c6 2147 jobs[c++] = job;
7e4249b9 2148 }
f459b602
MAP
2149 if (r < 0)
2150 return bus_log_parse_error(r);
7e4249b9 2151
f459b602
MAP
2152 r = sd_bus_message_exit_container(reply);
2153 if (r < 0)
2154 return bus_log_parse_error(r);
f73e33d9 2155
d8fba7c6 2156 output_jobs_list(jobs, c, skipped);
c6581cc1 2157 return r;
7e4249b9
LP
2158}
2159
f459b602
MAP
2160static int cancel_job(sd_bus *bus, char **args) {
2161 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
729e3769 2162 char **name;
7e4249b9 2163
514f4ef5
LP
2164 assert(args);
2165
729e3769
LP
2166 if (strv_length(args) <= 1)
2167 return daemon_reload(bus, args);
ee5762e3 2168
729e3769 2169 STRV_FOREACH(name, args+1) {
5dd9014f
LP
2170 uint32_t id;
2171 int r;
7e4249b9 2172
5dd9014f 2173 r = safe_atou32(*name, &id);
f22f08cd 2174 if (r < 0) {
f459b602 2175 log_error("Failed to parse job id \"%s\": %s", *name, strerror(-r));
5dd9014f 2176 return r;
7e4249b9 2177 }
7e4249b9 2178
f459b602 2179 r = sd_bus_call_method(
f22f08cd
SP
2180 bus,
2181 "org.freedesktop.systemd1",
2182 "/org/freedesktop/systemd1",
2183 "org.freedesktop.systemd1.Manager",
5dd9014f 2184 "CancelJob",
f459b602 2185 &error,
f22f08cd 2186 NULL,
f459b602
MAP
2187 "u", id);
2188 if (r < 0) {
2189 log_error("Failed to cancel job %u: %s", (unsigned) id, bus_error_message(&error, r));
5dd9014f 2190 return r;
f459b602 2191 }
7e4249b9
LP
2192 }
2193
5dd9014f 2194 return 0;
7e4249b9
LP
2195}
2196
f459b602
MAP
2197static int need_daemon_reload(sd_bus *bus, const char *unit) {
2198 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
f459b602
MAP
2199 const char *path;
2200 int b, r;
94c01aeb 2201
f459b602
MAP
2202 /* We ignore all errors here, since this is used to show a
2203 * warning only */
45fb0699 2204
f459b602
MAP
2205 /* We don't use unit_dbus_path_from_name() directly since we
2206 * don't want to load the unit if it isn't loaded. */
f84190d8 2207
f459b602 2208 r = sd_bus_call_method(
f22f08cd
SP
2209 bus,
2210 "org.freedesktop.systemd1",
2211 "/org/freedesktop/systemd1",
2212 "org.freedesktop.systemd1.Manager",
2213 "GetUnit",
f459b602 2214 NULL,
f22f08cd 2215 &reply,
e3e0314b 2216 "s", unit);
f84190d8
LP
2217 if (r < 0)
2218 return r;
45fb0699 2219
f459b602
MAP
2220 r = sd_bus_message_read(reply, "o", &path);
2221 if (r < 0)
2222 return r;
f84190d8 2223
f459b602 2224 r = sd_bus_get_property_trivial(
f22f08cd 2225 bus,
b0193f1c
LP
2226 "org.freedesktop.systemd1",
2227 path,
f459b602
MAP
2228 "org.freedesktop.systemd1.Unit",
2229 "NeedDaemonReload",
2230 NULL,
2231 'b', &b);
f84190d8
LP
2232 if (r < 0)
2233 return r;
45fb0699 2234
45fb0699
LP
2235 return b;
2236}
2237
5e374895
LP
2238typedef struct WaitData {
2239 Set *set;
67f3c402
LP
2240
2241 char *name;
5d44db4a 2242 char *result;
5e374895
LP
2243} WaitData;
2244
ebcf1f97 2245static int wait_filter(sd_bus *bus, sd_bus_message *m, void *data, sd_bus_error *error) {
5e374895 2246 WaitData *d = data;
7e4249b9 2247
f459b602
MAP
2248 assert(bus);
2249 assert(m);
5e374895 2250 assert(d);
7e4249b9 2251
54165a39 2252 log_debug("Got D-Bus request: %s.%s() on %s",
f459b602
MAP
2253 sd_bus_message_get_interface(m),
2254 sd_bus_message_get_member(m),
2255 sd_bus_message_get_path(m));
7e4249b9 2256
f459b602 2257 if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
7e4249b9 2258 log_error("Warning! D-Bus connection terminated.");
f459b602
MAP
2259 sd_bus_close(bus);
2260 } else if (sd_bus_message_is_signal(m, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
7e4249b9 2261 uint32_t id;
6e869e18 2262 const char *path, *result, *unit;
f459b602
MAP
2263 char *ret;
2264 int r;
7e4249b9 2265
f459b602
MAP
2266 r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
2267 if (r >= 0) {
2268 ret = set_remove(d->set, (char*) path);
2269 if (!ret)
2270 return 0;
c1e784fe 2271
f459b602 2272 free(ret);
5d44db4a 2273
67f3c402 2274 if (!isempty(result))
5d44db4a
LP
2275 d->result = strdup(result);
2276
67f3c402
LP
2277 if (!isempty(unit))
2278 d->name = strdup(unit);
2279
f459b602 2280 return 0;
5d44db4a 2281 }
286ca485 2282#ifndef NOLEGACY
f459b602
MAP
2283 r = sd_bus_message_read(m, "uos", &id, &path, &result);
2284 if (r >= 0) {
2285 ret = set_remove(d->set, (char*) path);
2286 if (!ret)
2287 return 0;
2288
2289 free(ret);
5d44db4a 2290
06dab8e1
LP
2291 if (*result)
2292 d->result = strdup(result);
2293
f459b602 2294 return 0;
06dab8e1 2295 }
5d44db4a
LP
2296#endif
2297
ebcf1f97 2298 bus_log_parse_error(r);
7e4249b9
LP
2299 }
2300
f459b602 2301 return 0;
7e4249b9
LP
2302}
2303
f459b602
MAP
2304static int enable_wait_for_jobs(sd_bus *bus) {
2305 int r;
7e4249b9
LP
2306
2307 assert(bus);
7e4249b9 2308
f459b602
MAP
2309 r = sd_bus_add_match(
2310 bus,
19befb2d 2311 NULL,
f459b602
MAP
2312 "type='signal',"
2313 "sender='org.freedesktop.systemd1',"
2314 "interface='org.freedesktop.systemd1.Manager',"
2315 "member='JobRemoved',"
2316 "path='/org/freedesktop/systemd1'",
2317 NULL, NULL);
2318 if (r < 0) {
2319 log_error("Failed to add match");
a567261a 2320 return -EIO;
7e4249b9
LP
2321 }
2322
479ef5d3 2323 /* This is slightly dirty, since we don't undo the match registrations. */
a567261a 2324 return 0;
7e4249b9
LP
2325}
2326
4c49ab0e
TA
2327static int bus_process_wait(sd_bus *bus) {
2328 int r;
2329
2330 for (;;) {
2331 r = sd_bus_process(bus, NULL);
2332 if (r < 0)
2333 return r;
2334 if (r > 0)
2335 return 0;
2336 r = sd_bus_wait(bus, (uint64_t) -1);
2337 if (r < 0)
2338 return r;
2339 }
2340}
2341
2342static int check_wait_response(WaitData *d) {
2343 int r = 0;
2344
2345 assert(d->result);
2346
2347 if (!arg_quiet) {
2348 if (streq(d->result, "timeout"))
2349 log_error("Job for %s timed out.", strna(d->name));
2350 else if (streq(d->result, "canceled"))
2351 log_error("Job for %s canceled.", strna(d->name));
2352 else if (streq(d->result, "dependency"))
2353 log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d->name));
2354 else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
2355 log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d->name), strna(d->name));
2356 }
2357
2358 if (streq(d->result, "timeout"))
2359 r = -ETIME;
2360 else if (streq(d->result, "canceled"))
2361 r = -ECANCELED;
2362 else if (streq(d->result, "dependency"))
2363 r = -EIO;
2364 else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
2365 r = -EIO;
2366
2367 return r;
2368}
2369
f459b602 2370static int wait_for_jobs(sd_bus *bus, Set *s) {
19befb2d 2371 _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
b92bea5d 2372 WaitData d = { .set = s };
4c49ab0e 2373 int r = 0, q;
479ef5d3
LP
2374
2375 assert(bus);
2376 assert(s);
2377
19befb2d 2378 q = sd_bus_add_filter(bus, &slot, wait_filter, &d);
4c49ab0e 2379 if (q < 0)
67f3c402 2380 return log_oom();
479ef5d3 2381
67f3c402 2382 while (!set_isempty(s)) {
4c49ab0e 2383 q = bus_process_wait(bus);
e3e0314b
ZJS
2384 if (q < 0) {
2385 log_error("Failed to wait for response: %s", strerror(-r));
4c49ab0e 2386 return q;
e3e0314b 2387 }
4c49ab0e
TA
2388
2389 if (d.result) {
2390 q = check_wait_response(&d);
2391 /* Return the first error as it is most likely to be
2392 * meaningful. */
2393 if (q < 0 && r == 0)
2394 r = q;
e3e0314b
ZJS
2395 log_debug("Got result %s/%s for job %s",
2396 strna(d.result), strerror(-q), strna(d.name));
67f3c402 2397 }
479ef5d3 2398
4c49ab0e
TA
2399 free(d.name);
2400 d.name = NULL;
67f3c402
LP
2401
2402 free(d.result);
2403 d.result = NULL;
67f3c402 2404 }
479ef5d3 2405
4c49ab0e 2406 return r;
479ef5d3
LP
2407}
2408
f459b602
MAP
2409static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet) {
2410 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
2411 _cleanup_free_ char *n = NULL, *state = NULL;
2412 const char *path;
f22f08cd 2413 int r;
701cdcb9 2414
31be1221 2415 assert(name);
701cdcb9 2416
f78e6385 2417 n = unit_name_mangle(name, MANGLE_NOGLOB);
60f9ba0b
LP
2418 if (!n)
2419 return log_oom();
2420
f459b602
MAP
2421 /* We don't use unit_dbus_path_from_name() directly since we
2422 * don't want to load the unit if it isn't loaded. */
2423
2424 r = sd_bus_call_method(
f22f08cd
SP
2425 bus,
2426 "org.freedesktop.systemd1",
2427 "/org/freedesktop/systemd1",
2428 "org.freedesktop.systemd1.Manager",
2429 "GetUnit",
f459b602 2430 NULL,
f22f08cd 2431 &reply,
f459b602 2432 "s", n);
60f9ba0b 2433 if (r < 0) {
60f9ba0b 2434 if (!quiet)
f22f08cd 2435 puts("unknown");
60f9ba0b 2436 return 0;
f22f08cd 2437 }
e61a3135 2438
f459b602
MAP
2439 r = sd_bus_message_read(reply, "o", &path);
2440 if (r < 0)
2441 return bus_log_parse_error(r);
60f9ba0b 2442
f459b602 2443 r = sd_bus_get_property_string(
f22f08cd
SP
2444 bus,
2445 "org.freedesktop.systemd1",
2446 path,
f459b602
MAP
2447 "org.freedesktop.systemd1.Unit",
2448 "ActiveState",
f22f08cd 2449 NULL,
f459b602 2450 &state);
60f9ba0b
LP
2451 if (r < 0) {
2452 if (!quiet)
2453 puts("unknown");
2454 return 0;
2455 }
701cdcb9 2456
31be1221
MS
2457 if (!quiet)
2458 puts(state);
2459
f459b602 2460 return nulstr_contains(good_states, state);
701cdcb9
MS
2461}
2462
f459b602
MAP
2463static int check_triggering_units(
2464 sd_bus *bus,
2465 const char *name) {
2466
2467 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2468 _cleanup_free_ char *path = NULL, *n = NULL, *state = NULL;
2469 _cleanup_strv_free_ char **triggered_by = NULL;
e61a3135 2470 bool print_warning_label = true;
f459b602 2471 char **i;
f22f08cd 2472 int r;
701cdcb9 2473
f78e6385 2474 n = unit_name_mangle(name, MANGLE_NOGLOB);
f459b602
MAP
2475 if (!n)
2476 return log_oom();
d3b52baf 2477
f459b602
MAP
2478 path = unit_dbus_path_from_name(n);
2479 if (!path)
2480 return log_oom();
701cdcb9 2481
f459b602 2482 r = sd_bus_get_property_string(
d0a5cdb2
JJ
2483 bus,
2484 "org.freedesktop.systemd1",
f459b602
MAP
2485 path,
2486 "org.freedesktop.systemd1.Unit",
2487 "LoadState",
2488 &error,
2489 &state);
2490 if (r < 0) {
2491 log_error("Failed to get load state of %s: %s", n, bus_error_message(&error, r));
2492 return r;
d0a5cdb2
JJ
2493 }
2494
d0a5cdb2 2495 if (streq(state, "masked"))
f459b602 2496 return 0;
701cdcb9 2497
f459b602
MAP
2498 r = sd_bus_get_property_strv(
2499 bus,
2500 "org.freedesktop.systemd1",
2501 path,
2502 "org.freedesktop.systemd1.Unit",
2503 "TriggeredBy",
2504 &error,
2505 &triggered_by);
2506 if (r < 0) {
2507 log_error("Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r));
2508 return r;
2509 }
701cdcb9 2510
f459b602
MAP
2511 STRV_FOREACH(i, triggered_by) {
2512 r = check_one_unit(bus, *i, "active\0reloading\0", true);
2513 if (r < 0) {
2514 log_error("Failed to check unit: %s", strerror(-r));
2515 return r;
701cdcb9
MS
2516 }
2517
f459b602
MAP
2518 if (r == 0)
2519 continue;
60f9ba0b 2520
f459b602
MAP
2521 if (print_warning_label) {
2522 log_warning("Warning: Stopping %s, but it can still be activated by:", n);
2523 print_warning_label = false;
701cdcb9 2524 }
1c291cf3 2525
f459b602 2526 log_warning(" %s", *i);
701cdcb9 2527 }
f459b602
MAP
2528
2529 return 0;
701cdcb9
MS
2530}
2531
39602c39
TA
2532static const char *verb_to_method(const char *verb) {
2533 uint i;
2534
2535 for (i = 0; i < ELEMENTSOF(unit_actions); i++)
2536 if (streq_ptr(unit_actions[i].verb, verb))
2537 return unit_actions[i].method;
2538
2539 return "StartUnit";
2540}
2541
2542static const char *method_to_verb(const char *method) {
2543 uint i;
2544
2545 for (i = 0; i < ELEMENTSOF(unit_actions); i++)
2546 if (streq_ptr(unit_actions[i].method, method))
2547 return unit_actions[i].verb;
2548
2549 return "n/a";
2550}
2551
e4b61340 2552static int start_unit_one(
f459b602 2553 sd_bus *bus,
e4b61340
LP
2554 const char *method,
2555 const char *name,
2556 const char *mode,
f459b602 2557 sd_bus_error *error,
e4b61340 2558 Set *s) {
7e4249b9 2559
f459b602 2560 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
45fb0699 2561 const char *path;
7e4249b9 2562 int r;
7e4249b9 2563
e4b61340
LP
2564 assert(method);
2565 assert(name);
2566 assert(mode);
22f4096c 2567 assert(error);
7e4249b9 2568
e3e0314b 2569 log_debug("Calling manager for %s on %s, %s", method, name, mode);
f459b602 2570 r = sd_bus_call_method(
f22f08cd 2571 bus,
b0193f1c
LP
2572 "org.freedesktop.systemd1",
2573 "/org/freedesktop/systemd1",
2574 "org.freedesktop.systemd1.Manager",
f22f08cd 2575 method,
f22f08cd 2576 error,
f459b602 2577 &reply,
e3e0314b 2578 "ss", name, mode);
f459b602 2579 if (r < 0) {
39602c39
TA
2580 const char *verb;
2581
67f3c402 2582 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
e4b61340
LP
2583 /* There's always a fallback possible for
2584 * legacy actions. */
f459b602 2585 return -EADDRNOTAVAIL;
67f3c402 2586
39602c39
TA
2587 verb = method_to_verb(method);
2588
2589 log_error("Failed to %s %s: %s", verb, name, bus_error_message(error, r));
46eddbb5 2590 return r;
7e4249b9
LP
2591 }
2592
f459b602
MAP
2593 r = sd_bus_message_read(reply, "o", &path);
2594 if (r < 0)
2595 return bus_log_parse_error(r);
45fb0699 2596
e3e0314b 2597 if (need_daemon_reload(bus, name) > 0)
f459b602 2598 log_warning("Warning: Unit file of %s changed on disk, 'systemctl%s daemon-reload' recommended.",
e3e0314b 2599 name, arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
45fb0699 2600
67f3c402 2601 if (s) {
f84190d8
LP
2602 char *p;
2603
67f3c402 2604 p = strdup(path);
46eddbb5
ZJS
2605 if (!p)
2606 return log_oom();
7e4249b9 2607
e3e0314b 2608 log_debug("Adding %s to the set", p);
ef42202a 2609 r = set_consume(s, p);
cbc9fbd1
LP
2610 if (r < 0)
2611 return log_oom();
e4b61340 2612 }
7e4249b9 2613
46eddbb5 2614 return 0;
7e4249b9
LP
2615}
2616
e3e0314b
ZJS
2617static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) {
2618
e3e0314b
ZJS
2619 _cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
2620 char **name;
2621 int r = 0, i;
2622
2623 STRV_FOREACH(name, names) {
2624 char *t;
2625
2626 if (suffix)
f78e6385 2627 t = unit_name_mangle_with_suffix(*name, MANGLE_GLOB, suffix);
e3e0314b 2628 else
f78e6385 2629 t = unit_name_mangle(*name, MANGLE_GLOB);
e3e0314b
ZJS
2630 if (!t)
2631 return log_oom();
2632
2633 if (string_is_glob(t))
6e18964d 2634 r = strv_consume(&globs, t);
e3e0314b 2635 else
6e18964d
ZJS
2636 r = strv_consume(&mangled, t);
2637 if (r < 0)
e3e0314b 2638 return log_oom();
e3e0314b
ZJS
2639 }
2640
2641 /* Query the manager only if any of the names are a glob, since
2642 * this is fairly expensive */
2643 if (!strv_isempty(globs)) {
1238ee09 2644 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
e3e0314b
ZJS
2645 _cleanup_free_ UnitInfo *unit_infos = NULL;
2646
1238ee09 2647 r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
e3e0314b
ZJS
2648 if (r < 0)
2649 return r;
2650
2651 for (i = 0; i < r; i++)
2652 if (strv_extend(&mangled, unit_infos[i].id) < 0)
2653 return log_oom();
2654 }
2655
2656 *ret = mangled;
2657 mangled = NULL; /* do not free */
1238ee09 2658
e3e0314b
ZJS
2659 return 0;
2660}
2661
47a0eaa6
MS
2662static const struct {
2663 const char *target;
2664 const char *verb;
2665 const char *mode;
2666} action_table[_ACTION_MAX] = {
2667 [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" },
2668 [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
2669 [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" },
2670 [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" },
2671 [ACTION_RUNLEVEL2] = { SPECIAL_RUNLEVEL2_TARGET, NULL, "isolate" },
2672 [ACTION_RUNLEVEL3] = { SPECIAL_RUNLEVEL3_TARGET, NULL, "isolate" },
2673 [ACTION_RUNLEVEL4] = { SPECIAL_RUNLEVEL4_TARGET, NULL, "isolate" },
2674 [ACTION_RUNLEVEL5] = { SPECIAL_RUNLEVEL5_TARGET, NULL, "isolate" },
2675 [ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" },
2676 [ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" },
2677 [ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" },
2678 [ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" },
2679 [ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" },
2680 [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" },
2681 [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
2682};
2683
514f4ef5 2684static enum action verb_to_action(const char *verb) {
47a0eaa6
MS
2685 enum action i;
2686
f459b602
MAP
2687 for (i = _ACTION_INVALID; i < _ACTION_MAX; i++)
2688 if (streq_ptr(action_table[i].verb, verb))
47a0eaa6 2689 return i;
514f4ef5 2690
f459b602
MAP
2691 return _ACTION_INVALID;
2692}
e4b61340 2693
f459b602 2694static int start_unit(sd_bus *bus, char **args) {
7fd1b19b 2695 _cleanup_set_free_free_ Set *s = NULL;
e3e0314b
ZJS
2696 _cleanup_strv_free_ char **names = NULL;
2697 const char *method, *mode, *one_name;
729e3769 2698 char **name;
b6520546 2699 int r = 0;
e4b61340 2700
514f4ef5
LP
2701 assert(bus);
2702
6bb92a16 2703 ask_password_agent_open_if_enabled();
501fc174 2704
e4b61340 2705 if (arg_action == ACTION_SYSTEMCTL) {
47a0eaa6 2706 enum action action;
39602c39 2707 method = verb_to_method(args[0]);
47a0eaa6 2708 action = verb_to_action(args[0]);
e4b61340 2709
47a0eaa6
MS
2710 mode = streq(args[0], "isolate") ? "isolate" :
2711 action_table[action].mode ?: arg_job_mode;
e4b61340 2712
e3e0314b 2713 one_name = action_table[action].target;
e4b61340 2714 } else {
47a0eaa6
MS
2715 assert(arg_action < ELEMENTSOF(action_table));
2716 assert(action_table[arg_action].target);
e4b61340
LP
2717
2718 method = "StartUnit";
514f4ef5 2719
47a0eaa6 2720 mode = action_table[arg_action].mode;
e3e0314b 2721 one_name = action_table[arg_action].target;
514f4ef5
LP
2722 }
2723
e3e0314b
ZJS
2724 if (one_name)
2725 names = strv_new(one_name, NULL);
2726 else {
2727 r = expand_names(bus, args + 1, NULL, &names);
2728 if (r < 0)
2729 log_error("Failed to expand names: %s", strerror(-r));
2730 }
b6520546 2731
6e905d93 2732 if (!arg_no_block) {
f459b602
MAP
2733 r = enable_wait_for_jobs(bus);
2734 if (r < 0) {
2735 log_error("Could not watch jobs: %s", strerror(-r));
2736 return r;
514f4ef5
LP
2737 }
2738
67f3c402 2739 s = set_new(string_hash_func, string_compare_func);
cec7eda5
ZJS
2740 if (!s)
2741 return log_oom();
e4b61340
LP
2742 }
2743
b6520546 2744 STRV_FOREACH(name, names) {
e3e0314b 2745 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
b6520546 2746 int q;
f459b602 2747
b6520546 2748 q = start_unit_one(bus, method, *name, mode, &error, s);
e3e0314b 2749 if (r >= 0 && q < 0)
b6520546 2750 r = translate_bus_error_to_exit_status(q, &error);
e4b61340
LP
2751 }
2752
67f3c402 2753 if (!arg_no_block) {
f459b602
MAP
2754 int q;
2755
2756 q = wait_for_jobs(bus, s);
2757 if (q < 0)
2758 return q;
49111a70
ZJS
2759
2760 /* When stopping units, warn if they can still be triggered by
2761 * another active unit (socket, path, timer) */
b6520546
ZJS
2762 if (!arg_quiet && streq(method, "StopUnit"))
2763 STRV_FOREACH(name, names)
2764 check_triggering_units(bus, *name);
67f3c402 2765 }
514f4ef5 2766
f459b602 2767 return r;
e4b61340
LP
2768}
2769
7e59bfcb
LP
2770/* Ask systemd-logind, which might grant access to unprivileged users
2771 * through PolicyKit */
f459b602 2772static int reboot_with_logind(sd_bus *bus, enum action a) {
4c80c73c 2773#ifdef HAVE_LOGIND
f459b602 2774 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4c80c73c 2775 const char *method;
f459b602 2776 int r;
4c80c73c 2777
d255133d
LP
2778 if (!bus)
2779 return -EIO;
2780
6bb92a16
LP
2781 polkit_agent_open_if_enabled();
2782
4c80c73c
KS
2783 switch (a) {
2784
2785 case ACTION_REBOOT:
2786 method = "Reboot";
2787 break;
2788
2789 case ACTION_POWEROFF:
2790 method = "PowerOff";
2791 break;
2792
d889a206
LP
2793 case ACTION_SUSPEND:
2794 method = "Suspend";
2795 break;
2796
2797 case ACTION_HIBERNATE:
2798 method = "Hibernate";
2799 break;
2800
6524990f
LP
2801 case ACTION_HYBRID_SLEEP:
2802 method = "HybridSleep";
2803 break;
2804
4c80c73c
KS
2805 default:
2806 return -EINVAL;
2807 }
2808
f459b602 2809 r = sd_bus_call_method(
f22f08cd
SP
2810 bus,
2811 "org.freedesktop.login1",
2812 "/org/freedesktop/login1",
2813 "org.freedesktop.login1.Manager",
2814 method,
f459b602 2815 &error,
f22f08cd 2816 NULL,
f459b602
MAP
2817 "b", true);
2818 if (r < 0)
2819 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
2820
2821 return r;
4c80c73c
KS
2822#else
2823 return -ENOSYS;
2824#endif
2825}
2826
f459b602 2827static int check_inhibitors(sd_bus *bus, enum action a) {
b37844d3 2828#ifdef HAVE_LOGIND
f459b602 2829 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
59164be4 2830 _cleanup_strv_free_ char **sessions = NULL;
f459b602
MAP
2831 const char *what, *who, *why, *mode;
2832 uint32_t uid, pid;
2833 unsigned c = 0;
59164be4 2834 char **s;
f459b602 2835 int r;
b37844d3 2836
748ebafa
LP
2837 if (!bus)
2838 return 0;
2839
2840 if (arg_ignore_inhibitors || arg_force > 0)
2841 return 0;
2842
2843 if (arg_when > 0)
2844 return 0;
2845
2846 if (geteuid() == 0)
b37844d3
LP
2847 return 0;
2848
2849 if (!on_tty())
2850 return 0;
2851
f459b602 2852 r = sd_bus_call_method(
b37844d3
LP
2853 bus,
2854 "org.freedesktop.login1",
2855 "/org/freedesktop/login1",
2856 "org.freedesktop.login1.Manager",
2857 "ListInhibitors",
b37844d3 2858 NULL,
f459b602
MAP
2859 &reply,
2860 NULL);
b37844d3
LP
2861 if (r < 0)
2862 /* If logind is not around, then there are no inhibitors... */
2863 return 0;
2864
4aa2beac 2865 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
f459b602
MAP
2866 if (r < 0)
2867 return bus_log_parse_error(r);
b37844d3 2868
4aa2beac 2869 while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
59164be4 2870 _cleanup_free_ char *comm = NULL, *user = NULL;
f459b602 2871 _cleanup_strv_free_ char **sv = NULL;
b37844d3
LP
2872
2873 if (!streq(mode, "block"))
f459b602 2874 continue;
b37844d3
LP
2875
2876 sv = strv_split(what, ":");
2877 if (!sv)
2878 return log_oom();
2879
2880 if (!strv_contains(sv,
2881 a == ACTION_HALT ||
2882 a == ACTION_POWEROFF ||
2883 a == ACTION_REBOOT ||
2884 a == ACTION_KEXEC ? "shutdown" : "sleep"))
f459b602 2885 continue;
b37844d3
LP
2886
2887 get_process_comm(pid, &comm);
59164be4 2888 user = uid_to_name(uid);
f459b602 2889
de0671ee
ZJS
2890 log_warning("Operation inhibited by \"%s\" (PID "PID_FMT" \"%s\", user %s), reason is \"%s\".",
2891 who, pid, strna(comm), strna(user), why);
b37844d3 2892
f459b602 2893 c++;
b37844d3 2894 }
f459b602
MAP
2895 if (r < 0)
2896 return bus_log_parse_error(r);
b37844d3 2897
f459b602
MAP
2898 r = sd_bus_message_exit_container(reply);
2899 if (r < 0)
2900 return bus_log_parse_error(r);
b37844d3 2901
59164be4
LP
2902 /* Check for current sessions */
2903 sd_get_sessions(&sessions);
2904 STRV_FOREACH(s, sessions) {
59164be4
LP
2905 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
2906
2907 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
2908 continue;
2909
2910 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
2911 continue;
2912
2913 if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
2914 continue;
2915
2916 sd_session_get_tty(*s, &tty);
2917 sd_session_get_seat(*s, &seat);
2918 sd_session_get_service(*s, &service);
2919 user = uid_to_name(uid);
2920
2921 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
2922 c++;
2923 }
2924
b37844d3
LP
2925 if (c <= 0)
2926 return 0;
2927
59164be4 2928 log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
47a0eaa6 2929 action_table[a].verb);
b37844d3
LP
2930
2931 return -EPERM;
2932#else
2933 return 0;
2934#endif
2935}
2936
f459b602 2937static int start_special(sd_bus *bus, char **args) {
4c80c73c 2938 enum action a;
983d9c90
LP
2939 int r;
2940
514f4ef5
LP
2941 assert(args);
2942
4c80c73c
KS
2943 a = verb_to_action(args[0]);
2944
748ebafa
LP
2945 r = check_inhibitors(bus, a);
2946 if (r < 0)
2947 return r;
2948
c32b90de
LP
2949 if (arg_force >= 2 && geteuid() != 0) {
2950 log_error("Must be root.");
2951 return -EPERM;
2952 }
2953
7e59bfcb
LP
2954 if (arg_force >= 2 &&
2955 (a == ACTION_HALT ||
2956 a == ACTION_POWEROFF ||
2957 a == ACTION_REBOOT))
477def80 2958 return halt_now(a);
e606bb61 2959
7e59bfcb 2960 if (arg_force >= 1 &&
4c80c73c
KS
2961 (a == ACTION_HALT ||
2962 a == ACTION_POWEROFF ||
2963 a == ACTION_REBOOT ||
2964 a == ACTION_KEXEC ||
2965 a == ACTION_EXIT))
729e3769 2966 return daemon_reload(bus, args);
20b09ca7 2967
7e59bfcb
LP
2968 /* first try logind, to allow authentication with polkit */
2969 if (geteuid() != 0 &&
2970 (a == ACTION_POWEROFF ||
d889a206
LP
2971 a == ACTION_REBOOT ||
2972 a == ACTION_SUSPEND ||
6524990f
LP
2973 a == ACTION_HIBERNATE ||
2974 a == ACTION_HYBRID_SLEEP)) {
7e59bfcb
LP
2975 r = reboot_with_logind(bus, a);
2976 if (r >= 0)
2977 return r;
4c80c73c 2978 }
983d9c90 2979
4c80c73c 2980 r = start_unit(bus, args);
f6bb13ab 2981 if (r == EXIT_SUCCESS)
4c80c73c 2982 warn_wall(a);
514f4ef5 2983
983d9c90 2984 return r;
514f4ef5
LP
2985}
2986
e3e0314b 2987static int check_unit_generic(sd_bus *bus, int code, const char *good_states, char **args) {
e3e0314b 2988 _cleanup_strv_free_ char **names = NULL;
729e3769 2989 char **name;
5a1aece5 2990 int r;
0183528f
LP
2991
2992 assert(bus);
2993 assert(args);
2994
e3e0314b 2995 r = expand_names(bus, args, NULL, &names);
5a1aece5 2996 if (r < 0) {
e3e0314b 2997 log_error("Failed to expand names: %s", strerror(-r));
5a1aece5
DR
2998 return r;
2999 }
e3e0314b
ZJS
3000
3001 STRV_FOREACH(name, names) {
60f9ba0b
LP
3002 int state;
3003
e3e0314b 3004 state = check_one_unit(bus, *name, good_states, arg_quiet);
1a0fce45
TA
3005 if (state < 0)
3006 return state;
5a1aece5
DR
3007 if (state == 0)
3008 r = code;
1a0fce45
TA
3009 }
3010
3011 return r;
3012}
3013
e3e0314b
ZJS
3014static int check_unit_active(sd_bus *bus, char **args) {
3015 /* According to LSB: 3, "program is not running" */
3016 return check_unit_generic(bus, 3, "active\0reloading\0", args + 1);
3017}
0183528f 3018
e3e0314b
ZJS
3019static int check_unit_failed(sd_bus *bus, char **args) {
3020 return check_unit_generic(bus, 1, "failed\0", args + 1);
48220598
LP
3021}
3022
f459b602
MAP
3023static int kill_unit(sd_bus *bus, char **args) {
3024 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
e3e0314b 3025 _cleanup_strv_free_ char **names = NULL;
60f9ba0b 3026 char **name;
e3e0314b 3027 int r, q;
8a0867d6 3028
60f9ba0b 3029 assert(bus);
8a0867d6
LP
3030 assert(args);
3031
8a0867d6
LP
3032 if (!arg_kill_who)
3033 arg_kill_who = "all";
3034
e3e0314b
ZJS
3035 r = expand_names(bus, args + 1, NULL, &names);
3036 if (r < 0)
3037 log_error("Failed to expand names: %s", strerror(-r));
60f9ba0b 3038
e3e0314b
ZJS
3039 STRV_FOREACH(name, names) {
3040 q = sd_bus_call_method(
f22f08cd 3041 bus,
b0193f1c
LP
3042 "org.freedesktop.systemd1",
3043 "/org/freedesktop/systemd1",
3044 "org.freedesktop.systemd1.Manager",
f22f08cd 3045 "KillUnit",
f459b602 3046 &error,
f22f08cd 3047 NULL,
e3e0314b
ZJS
3048 "ssi", *names, arg_kill_who, arg_signal);
3049 if (q < 0) {
3050 log_error("Failed to kill unit %s: %s",
3051 *names, bus_error_message(&error, r));
3052 if (r == 0)
3053 r = q;
f459b602 3054 }
8a0867d6 3055 }
f459b602 3056
e3e0314b 3057 return r;
8a0867d6
LP
3058}
3059
582a507f 3060typedef struct ExecStatusInfo {
0129173a
LP
3061 char *name;
3062
582a507f
LP
3063 char *path;
3064 char **argv;
3065
b708e7ce
LP
3066 bool ignore;
3067
582a507f
LP
3068 usec_t start_timestamp;
3069 usec_t exit_timestamp;
3070 pid_t pid;
3071 int code;
3072 int status;
3073
3074 LIST_FIELDS(struct ExecStatusInfo, exec);
3075} ExecStatusInfo;
3076
3077static void exec_status_info_free(ExecStatusInfo *i) {
3078 assert(i);
3079
0129173a 3080 free(i->name);
582a507f
LP
3081 free(i->path);
3082 strv_free(i->argv);
3083 free(i);
3084}
3085
f459b602 3086static int exec_status_info_deserialize(sd_bus_message *m, ExecStatusInfo *i) {
b21a0ef8 3087 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
f459b602 3088 const char *path;
582a507f
LP
3089 uint32_t pid;
3090 int32_t code, status;
f459b602 3091 int ignore, r;
582a507f 3092
f459b602 3093 assert(m);
582a507f 3094 assert(i);
582a507f 3095
f459b602
MAP
3096 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, "sasbttttuii");
3097 if (r < 0)
3098 return bus_log_parse_error(r);
3099 else if (r == 0)
3100 return 0;
582a507f 3101
f459b602
MAP
3102 r = sd_bus_message_read(m, "s", &path);
3103 if (r < 0)
3104 return bus_log_parse_error(r);
582a507f 3105
f84190d8
LP
3106 i->path = strdup(path);
3107 if (!i->path)
f459b602 3108 return log_oom();
582a507f 3109
f459b602
MAP
3110 r = sd_bus_message_read_strv(m, &i->argv);
3111 if (r < 0)
3112 return bus_log_parse_error(r);
3113
3114 r = sd_bus_message_read(m,
3115 "bttttuii",
3116 &ignore,
3117 &start_timestamp, &start_timestamp_monotonic,
3118 &exit_timestamp, &exit_timestamp_monotonic,
3119 &pid,
3120 &code, &status);
3121 if (r < 0)
3122 return bus_log_parse_error(r);
582a507f 3123
b708e7ce 3124 i->ignore = ignore;
582a507f
LP
3125 i->start_timestamp = (usec_t) start_timestamp;
3126 i->exit_timestamp = (usec_t) exit_timestamp;
3127 i->pid = (pid_t) pid;
3128 i->code = code;
3129 i->status = status;
3130
f459b602
MAP
3131 r = sd_bus_message_exit_container(m);
3132 if (r < 0)
3133 return bus_log_parse_error(r);
3134
3135 return 1;
582a507f
LP
3136}
3137
61cbdc4b
LP
3138typedef struct UnitStatusInfo {
3139 const char *id;
3140 const char *load_state;
3141 const char *active_state;
3142 const char *sub_state;
a4375746 3143 const char *unit_file_state;
61cbdc4b
LP
3144
3145 const char *description;
4a9e2fff 3146 const char *following;
61cbdc4b 3147
49dbfa7b
LP
3148 char **documentation;
3149
1b64d026
LP
3150 const char *fragment_path;
3151 const char *source_path;
4ad49000 3152 const char *control_group;
61cbdc4b 3153
76d14b87
OS
3154 char **dropin_paths;
3155
9f39404c 3156 const char *load_error;
f42806df 3157 const char *result;
9f39404c 3158
584be568 3159 usec_t inactive_exit_timestamp;
df50185b 3160 usec_t inactive_exit_timestamp_monotonic;
584be568
LP
3161 usec_t active_enter_timestamp;
3162 usec_t active_exit_timestamp;
3163 usec_t inactive_enter_timestamp;
3164
45fb0699
LP
3165 bool need_daemon_reload;
3166
61cbdc4b
LP
3167 /* Service */
3168 pid_t main_pid;
3169 pid_t control_pid;
3170 const char *status_text;
175728c4 3171 const char *pid_file;
d06dacd0 3172 bool running:1;
b4af5a80 3173 int status_errno;
61cbdc4b
LP
3174
3175 usec_t start_timestamp;
3176 usec_t exit_timestamp;
3177
3178 int exit_code, exit_status;
3179
90bbc946
LP
3180 usec_t condition_timestamp;
3181 bool condition_result;
52990c2e
ZJS
3182 bool failed_condition_trigger;
3183 bool failed_condition_negate;
3184 const char *failed_condition;
3185 const char *failed_condition_param;
90bbc946 3186
61cbdc4b
LP
3187 /* Socket */
3188 unsigned n_accepted;
3189 unsigned n_connections;
b8131a87 3190 bool accept;
61cbdc4b 3191
13160134 3192 /* Pairs of type, path */
67419600
OS
3193 char **listen;
3194
61cbdc4b
LP
3195 /* Device */
3196 const char *sysfs_path;
3197
3198 /* Mount, Automount */
3199 const char *where;
3200
3201 /* Swap */
3202 const char *what;
582a507f
LP
3203
3204 LIST_HEAD(ExecStatusInfo, exec);
61cbdc4b
LP
3205} UnitStatusInfo;
3206
f459b602
MAP
3207static void print_status_info(
3208 UnitStatusInfo *i,
3209 bool *ellipsized) {
3210
582a507f 3211 ExecStatusInfo *p;
b0d14c69 3212 const char *active_on, *active_off, *on, *off, *ss;
584be568 3213 usec_t timestamp;
9185c8e6 3214 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
584be568 3215 char since2[FORMAT_TIMESTAMP_MAX], *s2;
1b64d026 3216 const char *path;
9bdbc2e2
LN
3217 int flags =
3218 arg_all * OUTPUT_SHOW_ALL |
3219 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
3220 on_tty() * OUTPUT_COLOR |
3221 !arg_quiet * OUTPUT_WARN_CUTOFF |
3222 arg_full * OUTPUT_FULL_WIDTH;
13160134 3223 char **t, **t2;
582a507f 3224
61cbdc4b
LP
3225 assert(i);
3226
3227 /* This shows pretty information about a unit. See
3228 * print_property() for a low-level property printer */
3229
b0d14c69
LP
3230 if (streq_ptr(i->active_state, "failed")) {
3231 active_on = ansi_highlight_red();
3232 active_off = ansi_highlight_off();
3233 } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
3234 active_on = ansi_highlight_green();
3235 active_off = ansi_highlight_off();
3236 } else
3237 active_on = active_off = "";
3238
6b01f1d3 3239 printf("%s%s%s %s", active_on, draw_special_char(DRAW_BLACK_CIRCLE), active_off, strna(i->id));
61cbdc4b
LP
3240
3241 if (i->description && !streq_ptr(i->id, i->description))
3242 printf(" - %s", i->description);
3243
3244 printf("\n");
3245
4a9e2fff 3246 if (i->following)
856323c9 3247 printf(" Follow: unit currently follows state of %s\n", i->following);
4a9e2fff 3248
f7b9e331 3249 if (streq_ptr(i->load_state, "error")) {
0b5a519c
DS
3250 on = ansi_highlight_red();
3251 off = ansi_highlight_off();
c31b4423
LP
3252 } else
3253 on = off = "";
3254
1b64d026
LP
3255 path = i->source_path ? i->source_path : i->fragment_path;
3256
9f39404c 3257 if (i->load_error)
856323c9
ZJS
3258 printf(" Loaded: %s%s%s (Reason: %s)\n",
3259 on, strna(i->load_state), off, i->load_error);
1b64d026 3260 else if (path && i->unit_file_state)
856323c9
ZJS
3261 printf(" Loaded: %s%s%s (%s; %s)\n",
3262 on, strna(i->load_state), off, path, i->unit_file_state);
1b64d026 3263 else if (path)
856323c9
ZJS
3264 printf(" Loaded: %s%s%s (%s)\n",
3265 on, strna(i->load_state), off, path);
61cbdc4b 3266 else
856323c9
ZJS
3267 printf(" Loaded: %s%s%s\n",
3268 on, strna(i->load_state), off);
61cbdc4b 3269
76d14b87 3270 if (!strv_isempty(i->dropin_paths)) {
f459b602 3271 _cleanup_free_ char *dir = NULL;
76d14b87 3272 bool last = false;
f459b602 3273 char ** dropin;
76d14b87
OS
3274
3275 STRV_FOREACH(dropin, i->dropin_paths) {
3276 if (! dir || last) {
856323c9 3277 printf(dir ? " " : " Drop-In: ");
76d14b87
OS
3278
3279 free(dir);
f459b602 3280 dir = NULL;
76d14b87
OS
3281
3282 if (path_get_parent(*dropin, &dir) < 0) {
3283 log_oom();
3284 return;
3285 }
3286
856323c9 3287 printf("%s\n %s", dir,
76d14b87
OS
3288 draw_special_char(DRAW_TREE_RIGHT));
3289 }
3290
3291 last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
3292
2b6bf07d 3293 printf("%s%s", basename(*dropin), last ? "\n" : ", ");
76d14b87 3294 }
76d14b87
OS
3295 }
3296
2ee68f72 3297 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2ee68f72 3298 if (ss)
856323c9 3299 printf(" Active: %s%s (%s)%s",
b0d14c69 3300 active_on, strna(i->active_state), ss, active_off);
2ee68f72 3301 else
856323c9 3302 printf(" Active: %s%s%s",
b0d14c69 3303 active_on, strna(i->active_state), active_off);
61cbdc4b 3304
f42806df
LP
3305 if (!isempty(i->result) && !streq(i->result, "success"))
3306 printf(" (Result: %s)", i->result);
3307
584be568
LP
3308 timestamp = (streq_ptr(i->active_state, "active") ||
3309 streq_ptr(i->active_state, "reloading")) ? i->active_enter_timestamp :
3310 (streq_ptr(i->active_state, "inactive") ||
fdf20a31 3311 streq_ptr(i->active_state, "failed")) ? i->inactive_enter_timestamp :
584be568
LP
3312 streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp :
3313 i->active_exit_timestamp;
3314
bbb8486e 3315 s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
584be568
LP
3316 s2 = format_timestamp(since2, sizeof(since2), timestamp);
3317
3318 if (s1)
538da63d 3319 printf(" since %s; %s\n", s2, s1);
584be568 3320 else if (s2)
538da63d 3321 printf(" since %s\n", s2);
584be568
LP
3322 else
3323 printf("\n");
3324
90bbc946 3325 if (!i->condition_result && i->condition_timestamp > 0) {
bbb8486e 3326 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
90bbc946
LP
3327 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
3328
52990c2e
ZJS
3329 printf(" start condition failed at %s%s%s\n",
3330 s2, s1 ? "; " : "", s1 ? s1 : "");
3331 if (i->failed_condition_trigger)
3332 printf(" none of the trigger conditions were met\n");
3333 else if (i->failed_condition)
3334 printf(" %s=%s%s was not met\n",
3335 i->failed_condition,
3336 i->failed_condition_negate ? "!" : "",
3337 i->failed_condition_param);
90bbc946
LP
3338 }
3339
61cbdc4b 3340 if (i->sysfs_path)
856323c9 3341 printf(" Device: %s\n", i->sysfs_path);
9feeba4b 3342 if (i->where)
856323c9 3343 printf(" Where: %s\n", i->where);
9feeba4b 3344 if (i->what)
856323c9 3345 printf(" What: %s\n", i->what);
49dbfa7b 3346
13160134 3347 STRV_FOREACH(t, i->documentation)
856323c9 3348 printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", *t);
49dbfa7b 3349
13160134 3350 STRV_FOREACH_PAIR(t, t2, i->listen)
856323c9 3351 printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
67419600 3352
b8131a87 3353 if (i->accept)
856323c9 3354 printf(" Accepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
61cbdc4b 3355
582a507f 3356 LIST_FOREACH(exec, p, i->exec) {
13160134 3357 _cleanup_free_ char *argv = NULL;
9a57c629 3358 bool good;
582a507f
LP
3359
3360 /* Only show exited processes here */
3361 if (p->code == 0)
3362 continue;
3363
13160134 3364 argv = strv_join(p->argv, " ");
856323c9 3365 printf(" Process: %u %s=%s ", p->pid, p->name, strna(argv));
582a507f 3366
96342de6 3367 good = is_clean_exit_lsb(p->code, p->status, NULL);
9a57c629 3368 if (!good) {
0b5a519c
DS
3369 on = ansi_highlight_red();
3370 off = ansi_highlight_off();
9a57c629
LP
3371 } else
3372 on = off = "";
3373
3374 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
3375
d06dacd0
LP
3376 if (p->code == CLD_EXITED) {
3377 const char *c;
3378
582a507f 3379 printf("status=%i", p->status);
d06dacd0 3380
1b64d026
LP
3381 c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
3382 if (c)
d06dacd0
LP
3383 printf("/%s", c);
3384
3385 } else
582a507f 3386 printf("signal=%s", signal_to_string(p->status));
9a57c629
LP
3387
3388 printf(")%s\n", off);
3389
582a507f
LP
3390 if (i->main_pid == p->pid &&
3391 i->start_timestamp == p->start_timestamp &&
3392 i->exit_timestamp == p->start_timestamp)
3393 /* Let's not show this twice */
3394 i->main_pid = 0;
3395
3396 if (p->pid == i->control_pid)
3397 i->control_pid = 0;
3398 }
3399
61cbdc4b 3400 if (i->main_pid > 0 || i->control_pid > 0) {
61cbdc4b 3401 if (i->main_pid > 0) {
856323c9 3402 printf(" Main PID: %u", (unsigned) i->main_pid);
61cbdc4b
LP
3403
3404 if (i->running) {
13160134
ZJS
3405 _cleanup_free_ char *comm = NULL;
3406 get_process_comm(i->main_pid, &comm);
3407 if (comm)
3408 printf(" (%s)", comm);
6d4fc029 3409 } else if (i->exit_code > 0) {
61cbdc4b
LP
3410 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
3411
d06dacd0
LP
3412 if (i->exit_code == CLD_EXITED) {
3413 const char *c;
3414
61cbdc4b 3415 printf("status=%i", i->exit_status);
d06dacd0 3416
1b64d026
LP
3417 c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
3418 if (c)
d06dacd0
LP
3419 printf("/%s", c);
3420
3421 } else
582a507f 3422 printf("signal=%s", signal_to_string(i->exit_status));
6d4fc029
LP
3423 printf(")");
3424 }
61cbdc4b 3425
13160134
ZJS
3426 if (i->control_pid > 0)
3427 printf(";");
3428 }
61cbdc4b
LP
3429
3430 if (i->control_pid > 0) {
13160134 3431 _cleanup_free_ char *c = NULL;
61cbdc4b 3432
856323c9 3433 printf(" %8s: %u", i->main_pid ? "" : " Control", (unsigned) i->control_pid);
61cbdc4b 3434
13160134
ZJS
3435 get_process_comm(i->control_pid, &c);
3436 if (c)
3437 printf(" (%s)", c);
61cbdc4b
LP
3438 }
3439
3440 printf("\n");
3441 }
3442
17bb7382 3443 if (i->status_text)
856323c9 3444 printf(" Status: \"%s\"\n", i->status_text);
b4af5a80
LP
3445 if (i->status_errno > 0)
3446 printf(" Error: %i (%s)\n", i->status_errno, strerror(i->status_errno));
17bb7382 3447
4ad49000 3448 if (i->control_group &&
8fcf784d
LP
3449 (i->main_pid > 0 || i->control_pid > 0 ||
3450 ((arg_transport != BUS_TRANSPORT_LOCAL && arg_transport != BUS_TRANSPORT_CONTAINER) || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group, false) == 0))) {
ab35fb1b
LP
3451 unsigned c;
3452
4ad49000 3453 printf(" CGroup: %s\n", i->control_group);
ab35fb1b 3454
7af5a806 3455 if (arg_transport == BUS_TRANSPORT_LOCAL || arg_transport == BUS_TRANSPORT_CONTAINER) {
b69d29ce
LP
3456 unsigned k = 0;
3457 pid_t extra[2];
8fcf784d 3458 static const char prefix[] = " ";
b69d29ce
LP
3459
3460 c = columns();
e8853816
ZJS
3461 if (c > sizeof(prefix) - 1)
3462 c -= sizeof(prefix) - 1;
a8f11321
LP
3463 else
3464 c = 0;
ab35fb1b 3465
b69d29ce
LP
3466 if (i->main_pid > 0)
3467 extra[k++] = i->main_pid;
3468
3469 if (i->control_pid > 0)
3470 extra[k++] = i->control_pid;
3471
8fcf784d 3472 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, false, extra, k, flags);
a8f11321 3473 }
c59760ee 3474 }
45fb0699 3475
f459b602 3476 if (i->id && arg_transport == BUS_TRANSPORT_LOCAL) {
886a64fe
ZJS
3477 show_journal_by_unit(stdout,
3478 i->id,
3479 arg_output,
3480 0,
3481 i->inactive_exit_timestamp_monotonic,
3482 arg_lines,
3483 getuid(),
ea6c2dd1 3484 flags | OUTPUT_BEGIN_NEWLINE,
94e0bd7d
ZJS
3485 arg_scope == UNIT_FILE_SYSTEM,
3486 ellipsized);
6f003b43 3487 }
86aa7ba4 3488
45fb0699 3489 if (i->need_daemon_reload)
1058cbf2 3490 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %sdaemon-reload' recommended.\n",
0b5a519c
DS
3491 ansi_highlight_red(),
3492 ansi_highlight_off(),
1058cbf2 3493 arg_scope == UNIT_FILE_SYSTEM ? "" : "--user ");
61cbdc4b
LP
3494}
3495
b43f208f 3496static void show_unit_help(UnitStatusInfo *i) {
256425cc
LP
3497 char **p;
3498
3499 assert(i);
3500
3501 if (!i->documentation) {
3502 log_info("Documentation for %s not known.", i->id);
3503 return;
3504 }
3505
3506 STRV_FOREACH(p, i->documentation) {
3507
3508 if (startswith(*p, "man:")) {
256425cc 3509 const char *args[4] = { "man", NULL, NULL, NULL };
cbc9fbd1
LP
3510 _cleanup_free_ char *page = NULL, *section = NULL;
3511 char *e = NULL;
256425cc 3512 pid_t pid;
cbc9fbd1 3513 size_t k;
256425cc
LP
3514
3515 k = strlen(*p);
3516
3517 if ((*p)[k-1] == ')')
3518 e = strrchr(*p, '(');
3519
3520 if (e) {
3521 page = strndup((*p) + 4, e - *p - 4);
256425cc 3522 section = strndup(e + 1, *p + k - e - 2);
cec7eda5 3523 if (!page || !section) {
0d0f0c50 3524 log_oom();
256425cc
LP
3525 return;
3526 }
3527
3528 args[1] = section;
3529 args[2] = page;
3530 } else
3531 args[1] = *p + 4;
3532
3533 pid = fork();
3534 if (pid < 0) {
3535 log_error("Failed to fork: %m");
256425cc
LP
3536 continue;
3537 }
3538
3539 if (pid == 0) {
3540 /* Child */
3541 execvp(args[0], (char**) args);
3542 log_error("Failed to execute man: %m");
3543 _exit(EXIT_FAILURE);
3544 }
3545
256425cc
LP
3546 wait_for_terminate(pid, NULL);
3547 } else
0315fe37 3548 log_info("Can't show: %s", *p);
256425cc
LP
3549 }
3550}
3551
f459b602
MAP
3552static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *i, const char *contents) {
3553 int r;
61cbdc4b 3554
a4c279f8 3555 assert(name);
f459b602 3556 assert(m);
a4c279f8
LP
3557 assert(i);
3558
f459b602 3559 switch (contents[0]) {
61cbdc4b 3560
f459b602 3561 case SD_BUS_TYPE_STRING: {
61cbdc4b
LP
3562 const char *s;
3563
f459b602
MAP
3564 r = sd_bus_message_read(m, "s", &s);
3565 if (r < 0)
3566 return bus_log_parse_error(r);
61cbdc4b 3567
a4c279f8 3568 if (!isempty(s)) {
61cbdc4b
LP
3569 if (streq(name, "Id"))
3570 i->id = s;
3571 else if (streq(name, "LoadState"))
3572 i->load_state = s;
3573 else if (streq(name, "ActiveState"))
3574 i->active_state = s;
3575 else if (streq(name, "SubState"))
3576 i->sub_state = s;
3577 else if (streq(name, "Description"))
3578 i->description = s;
3579 else if (streq(name, "FragmentPath"))
1b64d026
LP
3580 i->fragment_path = s;
3581 else if (streq(name, "SourcePath"))
3582 i->source_path = s;
286ca485 3583#ifndef NOLEGACY
a00963a2
LP
3584 else if (streq(name, "DefaultControlGroup")) {
3585 const char *e;
3586 e = startswith(s, SYSTEMD_CGROUP_CONTROLLER ":");
3587 if (e)
3588 i->control_group = e;
3589 }
4ad49000
LP
3590#endif
3591 else if (streq(name, "ControlGroup"))
3592 i->control_group = s;
61cbdc4b
LP
3593 else if (streq(name, "StatusText"))
3594 i->status_text = s;
175728c4
HH
3595 else if (streq(name, "PIDFile"))
3596 i->pid_file = s;
61cbdc4b
LP
3597 else if (streq(name, "SysFSPath"))
3598 i->sysfs_path = s;
3599 else if (streq(name, "Where"))
3600 i->where = s;
3601 else if (streq(name, "What"))
3602 i->what = s;
4a9e2fff
LP
3603 else if (streq(name, "Following"))
3604 i->following = s;
a4375746
LP
3605 else if (streq(name, "UnitFileState"))
3606 i->unit_file_state = s;
f42806df
LP
3607 else if (streq(name, "Result"))
3608 i->result = s;
61cbdc4b
LP
3609 }
3610
3611 break;
3612 }
3613
f459b602
MAP
3614 case SD_BUS_TYPE_BOOLEAN: {
3615 int b;
b8131a87 3616
f459b602
MAP
3617 r = sd_bus_message_read(m, "b", &b);
3618 if (r < 0)
3619 return bus_log_parse_error(r);
b8131a87
LP
3620
3621 if (streq(name, "Accept"))
3622 i->accept = b;
45fb0699
LP
3623 else if (streq(name, "NeedDaemonReload"))
3624 i->need_daemon_reload = b;
90bbc946
LP
3625 else if (streq(name, "ConditionResult"))
3626 i->condition_result = b;
b8131a87
LP
3627
3628 break;
3629 }
3630
f459b602 3631 case SD_BUS_TYPE_UINT32: {
61cbdc4b
LP
3632 uint32_t u;
3633
f459b602
MAP
3634 r = sd_bus_message_read(m, "u", &u);
3635 if (r < 0)
3636 return bus_log_parse_error(r);
61cbdc4b
LP
3637
3638 if (streq(name, "MainPID")) {
3639 if (u > 0) {
3640 i->main_pid = (pid_t) u;
3641 i->running = true;
3642 }
3643 } else if (streq(name, "ControlPID"))
3644 i->control_pid = (pid_t) u;
3645 else if (streq(name, "ExecMainPID")) {
3646 if (u > 0)
3647 i->main_pid = (pid_t) u;
3648 } else if (streq(name, "NAccepted"))
3649 i->n_accepted = u;
3650 else if (streq(name, "NConnections"))
3651 i->n_connections = u;
3652
3653 break;
3654 }
3655
f459b602 3656 case SD_BUS_TYPE_INT32: {
61cbdc4b
LP
3657 int32_t j;
3658
f459b602
MAP
3659 r = sd_bus_message_read(m, "i", &j);
3660 if (r < 0)
3661 return bus_log_parse_error(r);
61cbdc4b
LP
3662
3663 if (streq(name, "ExecMainCode"))
3664 i->exit_code = (int) j;
3665 else if (streq(name, "ExecMainStatus"))
3666 i->exit_status = (int) j;
b4af5a80
LP
3667 else if (streq(name, "StatusErrno"))
3668 i->status_errno = (int) j;
61cbdc4b
LP
3669
3670 break;
3671 }
3672
f459b602 3673 case SD_BUS_TYPE_UINT64: {
61cbdc4b
LP
3674 uint64_t u;
3675
f459b602
MAP
3676 r = sd_bus_message_read(m, "t", &u);
3677 if (r < 0)
3678 return bus_log_parse_error(r);
61cbdc4b
LP
3679
3680 if (streq(name, "ExecMainStartTimestamp"))
3681 i->start_timestamp = (usec_t) u;
3682 else if (streq(name, "ExecMainExitTimestamp"))
3683 i->exit_timestamp = (usec_t) u;
584be568
LP
3684 else if (streq(name, "ActiveEnterTimestamp"))
3685 i->active_enter_timestamp = (usec_t) u;
3686 else if (streq(name, "InactiveEnterTimestamp"))
3687 i->inactive_enter_timestamp = (usec_t) u;
3688 else if (streq(name, "InactiveExitTimestamp"))
3689 i->inactive_exit_timestamp = (usec_t) u;
df50185b
LP
3690 else if (streq(name, "InactiveExitTimestampMonotonic"))
3691 i->inactive_exit_timestamp_monotonic = (usec_t) u;
584be568
LP
3692 else if (streq(name, "ActiveExitTimestamp"))
3693 i->active_exit_timestamp = (usec_t) u;
90bbc946
LP
3694 else if (streq(name, "ConditionTimestamp"))
3695 i->condition_timestamp = (usec_t) u;
61cbdc4b
LP
3696
3697 break;
3698 }
582a507f 3699
f459b602 3700 case SD_BUS_TYPE_ARRAY:
582a507f 3701
f459b602
MAP
3702 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
3703 _cleanup_free_ ExecStatusInfo *info = NULL;
582a507f 3704
f459b602
MAP
3705 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
3706 if (r < 0)
3707 return bus_log_parse_error(r);
582a507f 3708
f459b602
MAP
3709 info = new0(ExecStatusInfo, 1);
3710 if (!info)
3711 return log_oom();
582a507f 3712
f459b602 3713 while ((r = exec_status_info_deserialize(m, info)) > 0) {
0129173a 3714
f459b602
MAP
3715 info->name = strdup(name);
3716 if (!info->name)
3717 log_oom();
582a507f 3718
71fda00f 3719 LIST_PREPEND(exec, i->exec, info);
582a507f 3720
f459b602
MAP
3721 info = new0(ExecStatusInfo, 1);
3722 if (!info)
3723 log_oom();
49dbfa7b 3724 }
67419600 3725
f459b602
MAP
3726 if (r < 0)
3727 return bus_log_parse_error(r);
67419600 3728
f459b602
MAP
3729 r = sd_bus_message_exit_container(m);
3730 if (r < 0)
3731 return bus_log_parse_error(r);
67419600 3732
f459b602 3733 return 0;
67419600 3734
f459b602
MAP
3735 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
3736 const char *type, *path;
13160134 3737
f459b602
MAP
3738 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
3739 if (r < 0)
3740 return bus_log_parse_error(r);
67419600 3741
f459b602 3742 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0) {
67419600 3743
f459b602
MAP
3744 r = strv_extend(&i->listen, type);
3745 if (r < 0)
3746 return r;
67419600 3747
f459b602
MAP
3748 r = strv_extend(&i->listen, path);
3749 if (r < 0)
3750 return r;
3751 }
76d14b87 3752 if (r < 0)
f459b602 3753 return bus_log_parse_error(r);
76d14b87 3754
f459b602
MAP
3755 r = sd_bus_message_exit_container(m);
3756 if (r < 0)
3757 return bus_log_parse_error(r);
49dbfa7b 3758
f459b602 3759 return 0;
49dbfa7b 3760
f459b602 3761 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "DropInPaths")) {
49dbfa7b 3762
f459b602
MAP
3763 r = sd_bus_message_read_strv(m, &i->dropin_paths);
3764 if (r < 0)
3765 return bus_log_parse_error(r);
49dbfa7b 3766
f459b602 3767 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "Documentation")) {
49dbfa7b 3768
f459b602
MAP
3769 r = sd_bus_message_read_strv(m, &i->documentation);
3770 if (r < 0)
3771 return bus_log_parse_error(r);
52990c2e 3772
f459b602
MAP
3773 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Conditions")) {
3774 const char *cond, *param;
3775 int trigger, negate;
3776 int32_t state;
52990c2e 3777
f459b602
MAP
3778 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
3779 if (r < 0)
3780 return bus_log_parse_error(r);
3781
3782 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
3783 log_debug("%s %d %d %s %d", cond, trigger, negate, param, state);
3784 if (state < 0 && (!trigger || !i->failed_condition)) {
3785 i->failed_condition = cond;
3786 i->failed_condition_trigger = trigger;
3787 i->failed_condition_negate = negate;
3788 i->failed_condition_param = param;
3789 }
582a507f 3790 }
f459b602
MAP
3791 if (r < 0)
3792 return bus_log_parse_error(r);
3793
3794 r = sd_bus_message_exit_container(m);
3795 if (r < 0)
3796 return bus_log_parse_error(r);
3797
3798 } else
3799 goto skip;
582a507f
LP
3800
3801 break;
9f39404c 3802
f459b602 3803 case SD_BUS_TYPE_STRUCT_BEGIN:
9f39404c
LP
3804
3805 if (streq(name, "LoadError")) {
9f39404c 3806 const char *n, *message;
9f39404c 3807
f459b602 3808 r = sd_bus_message_read(m, "(ss)", &n, &message);
9f39404c 3809 if (r < 0)
f459b602 3810 return bus_log_parse_error(r);
9f39404c
LP
3811
3812 if (!isempty(message))
3813 i->load_error = message;
f459b602
MAP
3814 } else
3815 goto skip;
9f39404c
LP
3816
3817 break;
f459b602
MAP
3818
3819 default:
3820 goto skip;
9f39404c 3821 }
f459b602
MAP
3822
3823 return 0;
3824
3825skip:
3826 r = sd_bus_message_skip(m, contents);
3827 if (r < 0)
3828 return bus_log_parse_error(r);
61cbdc4b
LP
3829
3830 return 0;
3831}
3832
f459b602
MAP
3833static int print_property(const char *name, sd_bus_message *m, const char *contents) {
3834 int r;
3835
48220598 3836 assert(name);
f459b602 3837 assert(m);
48220598 3838
61cbdc4b
LP
3839 /* This is a low-level property printer, see
3840 * print_status_info() for the nicer output */
3841
852c1b4d
ZJS
3842 if (arg_properties && !strv_find(arg_properties, name)) {
3843 /* skip what we didn't read */
3844 r = sd_bus_message_skip(m, contents);
3845 return r;
3846 }
48220598 3847
f459b602 3848 switch (contents[0]) {
48220598 3849
f459b602 3850 case SD_BUS_TYPE_STRUCT_BEGIN:
48220598 3851
f459b602 3852 if (contents[1] == SD_BUS_TYPE_UINT32 && streq(name, "Job")) {
48220598
LP
3853 uint32_t u;
3854
f459b602
MAP
3855 r = sd_bus_message_read(m, "(uo)", &u, NULL);
3856 if (r < 0)
3857 return bus_log_parse_error(r);
48220598 3858
f459b602 3859 if (u > 0)
48220598
LP
3860 printf("%s=%u\n", name, (unsigned) u);
3861 else if (arg_all)
3862 printf("%s=\n", name);
3863
3864 return 0;
f459b602
MAP
3865
3866 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "Unit")) {
48220598
LP
3867 const char *s;
3868
f459b602
MAP
3869 r = sd_bus_message_read(m, "(so)", &s, NULL);
3870 if (r < 0)
3871 return bus_log_parse_error(r);
48220598 3872
f459b602 3873 if (arg_all || !isempty(s))
48220598
LP
3874 printf("%s=%s\n", name, s);
3875
3876 return 0;
f459b602
MAP
3877
3878 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "LoadError")) {
9f39404c
LP
3879 const char *a = NULL, *b = NULL;
3880
f459b602
MAP
3881 r = sd_bus_message_read(m, "(ss)", &a, &b);
3882 if (r < 0)
3883 return bus_log_parse_error(r);
9f39404c
LP
3884
3885 if (arg_all || !isempty(a) || !isempty(b))
3886 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
f786e80d 3887
57183d11
LP
3888 return 0;
3889 } else if (streq_ptr(name, "SystemCallFilter")) {
3890 _cleanup_strv_free_ char **l = NULL;
3891 int whitelist;
3892
3893 r = sd_bus_message_enter_container(m, 'r', "bas");
3894 if (r < 0)
3895 return bus_log_parse_error(r);
3896
3897 r = sd_bus_message_read(m, "b", &whitelist);
3898 if (r < 0)
3899 return bus_log_parse_error(r);
3900
3901 r = sd_bus_message_read_strv(m, &l);
3902 if (r < 0)
3903 return bus_log_parse_error(r);
3904
3905 r = sd_bus_message_exit_container(m);
3906 if (r < 0)
3907 return bus_log_parse_error(r);
3908
3909 if (arg_all || whitelist || !strv_isempty(l)) {
3910 bool first = true;
3911 char **i;
3912
3913 fputs(name, stdout);
3914 fputc('=', stdout);
3915
3916 if (!whitelist)
3917 fputc('~', stdout);
3918
3919 STRV_FOREACH(i, l) {
3920 if (first)
3921 first = false;
3922 else
3923 fputc(' ', stdout);
3924
3925 fputs(*i, stdout);
3926 }
3927 fputc('\n', stdout);
3928 }
3929
f786e80d 3930 return 0;
48220598
LP
3931 }
3932
3933 break;
48220598 3934
f459b602 3935 case SD_BUS_TYPE_ARRAY:
48220598 3936
f459b602
MAP
3937 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "EnvironmentFiles")) {
3938 const char *path;
3939 int ignore;
8c7be95e 3940
f459b602
MAP
3941 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sb)");
3942 if (r < 0)
3943 return bus_log_parse_error(r);
8c7be95e 3944
f459b602
MAP
3945 while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
3946 printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
8c7be95e 3947
f459b602
MAP
3948 if (r < 0)
3949 return bus_log_parse_error(r);
8c7be95e 3950
f459b602
MAP
3951 r = sd_bus_message_exit_container(m);
3952 if (r < 0)
3953 return bus_log_parse_error(r);
8c7be95e
LP
3954
3955 return 0;
3956
f459b602
MAP
3957 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Paths")) {
3958 const char *type, *path;
67419600 3959
f459b602
MAP
3960 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
3961 if (r < 0)
3962 return bus_log_parse_error(r);
ebf57b80 3963
f459b602
MAP
3964 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
3965 printf("%s=%s\n", type, path);
3966 if (r < 0)
3967 return bus_log_parse_error(r);
ebf57b80 3968
f459b602
MAP
3969 r = sd_bus_message_exit_container(m);
3970 if (r < 0)
3971 return bus_log_parse_error(r);
ebf57b80 3972
707e5e52 3973 return 0;
582a507f 3974
f459b602
MAP
3975 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
3976 const char *type, *path;
67419600 3977
f459b602
MAP
3978 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
3979 if (r < 0)
3980 return bus_log_parse_error(r);
67419600 3981
f459b602
MAP
3982 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
3983 printf("Listen%s=%s\n", type, path);
3984 if (r < 0)
3985 return bus_log_parse_error(r);
67419600 3986
f459b602
MAP
3987 r = sd_bus_message_exit_container(m);
3988 if (r < 0)
3989 return bus_log_parse_error(r);
67419600
OS
3990
3991 return 0;
3992
f459b602
MAP
3993 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Timers")) {
3994 const char *base;
3995 uint64_t value, next_elapse;
707e5e52 3996
f459b602
MAP
3997 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(stt)");
3998 if (r < 0)
3999 return bus_log_parse_error(r);
552e4331 4000
f459b602
MAP
4001 while ((r = sd_bus_message_read(m, "(stt)", &base, &value, &next_elapse)) > 0) {
4002 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
fe68089d 4003
f459b602
MAP
4004 printf("%s={ value=%s ; next_elapse=%s }\n",
4005 base,
4006 format_timespan(timespan1, sizeof(timespan1), value, 0),
4007 format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
fe68089d 4008 }
f459b602
MAP
4009 if (r < 0)
4010 return bus_log_parse_error(r);
4011
4012 r = sd_bus_message_exit_container(m);
4013 if (r < 0)
4014 return bus_log_parse_error(r);
fe68089d
LP
4015
4016 return 0;
fe68089d 4017
f459b602
MAP
4018 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
4019 ExecStatusInfo info = {};
4020
4021 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
4022 if (r < 0)
4023 return bus_log_parse_error(r);
4024
4025 while ((r = exec_status_info_deserialize(m, &info)) > 0) {
4026 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
4027 _cleanup_free_ char *tt;
4028
4029 tt = strv_join(info.argv, " ");
4030
4031 printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
4032 name,
4033 strna(info.path),
4034 strna(tt),
4035 yes_no(info.ignore),
4036 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
4037 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
4038 (unsigned) info. pid,
4039 sigchld_code_to_string(info.code),
4040 info.status,
4041 info.code == CLD_EXITED ? "" : "/",
4042 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
fe68089d 4043
582a507f
LP
4044 free(info.path);
4045 strv_free(info.argv);
f459b602 4046 zero(info);
707e5e52
LP
4047 }
4048
f459b602
MAP
4049 r = sd_bus_message_exit_container(m);
4050 if (r < 0)
4051 return bus_log_parse_error(r);
4052
48220598 4053 return 0;
4ad49000 4054
f459b602
MAP
4055 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "DeviceAllow")) {
4056 const char *path, *rwm;
4ad49000 4057
f459b602
MAP
4058 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4059 if (r < 0)
4060 return bus_log_parse_error(r);
4ad49000 4061
f459b602
MAP
4062 while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0)
4063 printf("%s=%s %s\n", name, strna(path), strna(rwm));
4064 if (r < 0)
4065 return bus_log_parse_error(r);
4ad49000 4066
f459b602
MAP
4067 r = sd_bus_message_exit_container(m);
4068 if (r < 0)
4069 return bus_log_parse_error(r);
4ad49000 4070
4ad49000
LP
4071 return 0;
4072
f459b602
MAP
4073 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "BlockIODeviceWeight")) {
4074 const char *path;
4075 uint64_t weight;
b8ab2dc6 4076
f459b602
MAP
4077 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
4078 if (r < 0)
4079 return bus_log_parse_error(r);
b8ab2dc6 4080
f459b602
MAP
4081 while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0)
4082 printf("%s=%s %" PRIu64 "\n", name, strna(path), weight);
4083 if (r < 0)
4084 return bus_log_parse_error(r);
b8ab2dc6 4085
f459b602
MAP
4086 r = sd_bus_message_exit_container(m);
4087 if (r < 0)
4088 return bus_log_parse_error(r);
b8ab2dc6 4089
b8ab2dc6
G
4090 return 0;
4091
f459b602
MAP
4092 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) {
4093 const char *path;
4094 uint64_t bandwidth;
4ad49000 4095
f459b602
MAP
4096 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
4097 if (r < 0)
4098 return bus_log_parse_error(r);
4ad49000 4099
f459b602
MAP
4100 while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0)
4101 printf("%s=%s %" PRIu64 "\n", name, strna(path), bandwidth);
4102 if (r < 0)
4103 return bus_log_parse_error(r);
4ad49000 4104
f459b602
MAP
4105 r = sd_bus_message_exit_container(m);
4106 if (r < 0)
4107 return bus_log_parse_error(r);
4ad49000 4108
4ad49000 4109 return 0;
48220598
LP
4110 }
4111
4112 break;
4113 }
4114
f459b602
MAP
4115 r = bus_print_property(name, m, arg_all);
4116 if (r < 0)
4117 return bus_log_parse_error(r);
4118
4119 if (r == 0) {
4120 r = sd_bus_message_skip(m, contents);
4121 if (r < 0)
4122 return bus_log_parse_error(r);
a4c279f8 4123
f459b602
MAP
4124 if (arg_all)
4125 printf("%s=[unprintable]\n", name);
4126 }
48220598
LP
4127
4128 return 0;
4129}
4130
f459b602
MAP
4131static int show_one(
4132 const char *verb,
4133 sd_bus *bus,
4134 const char *path,
4135 bool show_properties,
4136 bool *new_line,
4137 bool *ellipsized) {
4138
4139 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4140 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
b92bea5d 4141 UnitStatusInfo info = {};
582a507f 4142 ExecStatusInfo *p;
f459b602 4143 int r;
48220598 4144
48220598 4145 assert(path);
61cbdc4b 4146 assert(new_line);
48220598 4147
e3e0314b
ZJS
4148 log_debug("Showing one %s", path);
4149
f459b602 4150 r = sd_bus_call_method(
f22f08cd
SP
4151 bus,
4152 "org.freedesktop.systemd1",
4153 path,
4154 "org.freedesktop.DBus.Properties",
4155 "GetAll",
f459b602 4156 &error,
f22f08cd 4157 &reply,
f459b602
MAP
4158 "s", "");
4159 if (r < 0) {
4160 log_error("Failed to get properties: %s", bus_error_message(&error, r));
f84190d8 4161 return r;
48220598
LP
4162 }
4163
f459b602
MAP
4164 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
4165 if (r < 0)
4166 return bus_log_parse_error(r);
48220598 4167
61cbdc4b
LP
4168 if (*new_line)
4169 printf("\n");
4170
4171 *new_line = true;
4172
f459b602
MAP
4173 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
4174 const char *name, *contents;
0183528f 4175
f459b602
MAP
4176 r = sd_bus_message_read(reply, "s", &name);
4177 if (r < 0)
4178 return bus_log_parse_error(r);
48220598 4179
f459b602
MAP
4180 r = sd_bus_message_peek_type(reply, NULL, &contents);
4181 if (r < 0)
4182 return bus_log_parse_error(r);
4183
4184 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
4185 if (r < 0)
4186 return bus_log_parse_error(r);
48220598 4187
61cbdc4b 4188 if (show_properties)
f459b602 4189 r = print_property(name, reply, contents);
61cbdc4b 4190 else
f459b602
MAP
4191 r = status_property(name, reply, &info, contents);
4192 if (r < 0)
4193 return r;
48220598 4194
f459b602
MAP
4195 r = sd_bus_message_exit_container(reply);
4196 if (r < 0)
4197 return bus_log_parse_error(r);
4198
4199 r = sd_bus_message_exit_container(reply);
4200 if (r < 0)
4201 return bus_log_parse_error(r);
48220598 4202 }
f459b602
MAP
4203 if (r < 0)
4204 return bus_log_parse_error(r);
4205
4206 r = sd_bus_message_exit_container(reply);
4207 if (r < 0)
4208 return bus_log_parse_error(r);
48220598 4209
f1e36d67
LP
4210 r = 0;
4211
256425cc 4212 if (!show_properties) {
b43f208f
KS
4213 if (streq(verb, "help"))
4214 show_unit_help(&info);
256425cc 4215 else
94e0bd7d 4216 print_status_info(&info, ellipsized);
256425cc 4217 }
f1e36d67 4218
49dbfa7b 4219 strv_free(info.documentation);
76d14b87 4220 strv_free(info.dropin_paths);
67419600 4221 strv_free(info.listen);
49dbfa7b 4222
22f4096c 4223 if (!streq_ptr(info.active_state, "active") &&
be8088a2 4224 !streq_ptr(info.active_state, "reloading") &&
3b05b8b3 4225 streq(verb, "status")) {
22f4096c 4226 /* According to LSB: "program not running" */
175728c4 4227 /* 0: program is running or service is OK
41a55c46
ZJS
4228 * 1: program is dead and /run PID file exists
4229 * 2: program is dead and /run/lock lock file exists
175728c4
HH
4230 * 3: program is not running
4231 * 4: program or service status is unknown
4232 */
3b05b8b3 4233 if (info.pid_file && access(info.pid_file, F_OK) == 0)
175728c4
HH
4234 r = 1;
4235 else
4236 r = 3;
e9c1ea9d 4237 }
61cbdc4b 4238
582a507f 4239 while ((p = info.exec)) {
71fda00f 4240 LIST_REMOVE(exec, info.exec, p);
582a507f
LP
4241 exec_status_info_free(p);
4242 }
4243
48220598
LP
4244 return r;
4245}
4246
f74294c1 4247static int get_unit_dbus_path_by_pid(
f459b602
MAP
4248 sd_bus *bus,
4249 uint32_t pid,
f74294c1 4250 char **unit) {
f459b602
MAP
4251
4252 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4253 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
373d32c9 4254 char *u;
a223b325
MS
4255 int r;
4256
f459b602 4257 r = sd_bus_call_method(
f22f08cd
SP
4258 bus,
4259 "org.freedesktop.systemd1",
4260 "/org/freedesktop/systemd1",
4261 "org.freedesktop.systemd1.Manager",
4262 "GetUnitByPID",
f459b602 4263 &error,
f22f08cd 4264 &reply,
f459b602
MAP
4265 "u", pid);
4266 if (r < 0) {
de0671ee 4267 log_error("Failed to get unit for PID "PID_FMT": %s", pid, bus_error_message(&error, r));
cec7eda5 4268 return r;
a223b325
MS
4269 }
4270
373d32c9 4271 r = sd_bus_message_read(reply, "o", &u);
f459b602
MAP
4272 if (r < 0)
4273 return bus_log_parse_error(r);
4274
373d32c9
LP
4275 u = strdup(u);
4276 if (!u)
4277 return log_oom();
4278
4279 *unit = u;
f74294c1 4280 return 0;
a223b325
MS
4281}
4282
f459b602
MAP
4283static int show_all(
4284 const char* verb,
4285 sd_bus *bus,
4286 bool show_properties,
4287 bool *new_line,
4288 bool *ellipsized) {
4289
f459b602
MAP
4290 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4291 _cleanup_free_ UnitInfo *unit_infos = NULL;
4292 const UnitInfo *u;
4293 unsigned c;
5bb75bc7 4294 int r, ret = 0;
265a7a2a 4295
1238ee09 4296 r = get_unit_list(bus, NULL, NULL, &unit_infos, 0, &reply);
265a7a2a
ZJS
4297 if (r < 0)
4298 return r;
4299
dbed408b
LP
4300 pager_open_if_enabled();
4301
f459b602
MAP
4302 c = (unsigned) r;
4303
4304 qsort_safe(unit_infos, c, sizeof(UnitInfo), compare_unit_info);
991f2a39 4305
265a7a2a 4306 for (u = unit_infos; u < unit_infos + c; u++) {
7fd1b19b 4307 _cleanup_free_ char *p = NULL;
265a7a2a 4308
265a7a2a
ZJS
4309 p = unit_dbus_path_from_name(u->id);
4310 if (!p)
4311 return log_oom();
4312
94e0bd7d 4313 r = show_one(verb, bus, p, show_properties, new_line, ellipsized);
3df538da 4314 if (r < 0)
265a7a2a 4315 return r;
5bb75bc7
ZJS
4316 else if (r > 0 && ret == 0)
4317 ret = r;
265a7a2a
ZJS
4318 }
4319
5bb75bc7 4320 return ret;
265a7a2a
ZJS
4321}
4322
8fcf784d
LP
4323static int show_system_status(sd_bus *bus) {
4324 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
4325 _cleanup_free_ char *hn = NULL;
4326 struct machine_info mi = {};
4327 const char *on, *off;
4328 int r;
4329
4330 hn = gethostname_malloc();
4331 if (!hn)
4332 return log_oom();
4333
4334 r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, &mi);
4335 if (r < 0) {
4336 log_error("Failed to read server status: %s", strerror(-r));
4337 return r;
4338 }
4339
8fcf784d
LP
4340 if (streq_ptr(mi.state, "degraded")) {
4341 on = ansi_highlight_red();
4342 off = ansi_highlight_off();
4343 } else if (!streq_ptr(mi.state, "running")) {
4344 on = ansi_highlight_yellow();
4345 off = ansi_highlight_off();
4346 } else
4347 on = off = "";
4348
6b01f1d3 4349 printf("%s%s%s %s\n", on, draw_special_char(DRAW_BLACK_CIRCLE), off, arg_host ? arg_host : hn);
b0d14c69 4350
8fcf784d
LP
4351 printf(" State: %s%s%s\n",
4352 on, strna(mi.state), off);
4353
4354 printf(" Jobs: %u queued\n", mi.n_jobs);
4355 printf(" Failed: %u units\n", mi.n_failed_units);
4356
4357 printf(" Since: %s; %s\n",
4358 format_timestamp(since2, sizeof(since2), mi.timestamp),
4359 format_timestamp_relative(since1, sizeof(since1), mi.timestamp));
4360
4361 printf(" CGroup: %s\n", mi.control_group ?: "/");
4362 if (arg_transport == BUS_TRANSPORT_LOCAL || arg_transport == BUS_TRANSPORT_CONTAINER) {
4363 int flags =
4364 arg_all * OUTPUT_SHOW_ALL |
4365 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
4366 on_tty() * OUTPUT_COLOR |
4367 !arg_quiet * OUTPUT_WARN_CUTOFF |
4368 arg_full * OUTPUT_FULL_WIDTH;
4369
4370 static const char prefix[] = " ";
4371 unsigned c;
4372
4373 c = columns();
4374 if (c > sizeof(prefix) - 1)
4375 c -= sizeof(prefix) - 1;
4376 else
4377 c = 0;
4378
4379 show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, false, flags);
4380 }
4381
4382 free(mi.state);
4383 free(mi.control_group);
4384
4385 return 0;
4386}
4387
f459b602 4388static int show(sd_bus *bus, char **args) {
265a7a2a 4389 bool show_properties, show_status, new_line = false;
94e0bd7d 4390 bool ellipsized = false;
e3e0314b 4391 int r, ret = 0;
48220598
LP
4392
4393 assert(bus);
4394 assert(args);
4395
256425cc 4396 show_properties = streq(args[0], "show");
265a7a2a 4397 show_status = streq(args[0], "status");
61cbdc4b 4398
ec14911e 4399 if (show_properties)
1968a360 4400 pager_open_if_enabled();
ec14911e 4401
f84190d8 4402 /* If no argument is specified inspect the manager itself */
48220598 4403
f84190d8 4404 if (show_properties && strv_length(args) <= 1)
94e0bd7d 4405 return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized);
48220598 4406
8fcf784d
LP
4407 if (show_status && strv_length(args) <= 1) {
4408
c3441de0 4409 pager_open_if_enabled();
8fcf784d
LP
4410 show_system_status(bus);
4411 new_line = true;
4412
4413 if (arg_all)
4414 ret = show_all(args[0], bus, false, &new_line, &ellipsized);
4415 } else {
e3e0314b
ZJS
4416 _cleanup_free_ char **patterns = NULL;
4417 char **name;
4418
4419 STRV_FOREACH(name, args + 1) {
f74294c1 4420 _cleanup_free_ char *unit = NULL;
94e0bd7d 4421 uint32_t id;
48220598 4422
94e0bd7d 4423 if (safe_atou32(*name, &id) < 0) {
e3e0314b 4424 if (strv_push(&patterns, *name) < 0)
94e0bd7d 4425 return log_oom();
48220598 4426
e3e0314b 4427 continue;
94e0bd7d 4428 } else if (show_properties) {
94e0bd7d 4429 /* Interpret as job id */
f74294c1 4430 if (asprintf(&unit, "/org/freedesktop/systemd1/job/%u", id) < 0)
94e0bd7d 4431 return log_oom();
48220598 4432
94e0bd7d
ZJS
4433 } else {
4434 /* Interpret as PID */
f74294c1 4435 r = get_unit_dbus_path_by_pid(bus, id, &unit);
373d32c9 4436 if (r < 0) {
94e0bd7d 4437 ret = r;
373d32c9
LP
4438 continue;
4439 }
94e0bd7d 4440 }
f74294c1 4441
5bb75bc7
ZJS
4442 r = show_one(args[0], bus, unit, show_properties,
4443 &new_line, &ellipsized);
4444 if (r < 0)
4445 return r;
4446 else if (r > 0 && ret == 0)
4447 ret = r;
48220598 4448 }
94e0bd7d 4449
e3e0314b
ZJS
4450 if (!strv_isempty(patterns)) {
4451 _cleanup_strv_free_ char **names = NULL;
4452
4453 r = expand_names(bus, patterns, NULL, &names);
4454 if (r < 0)
4455 log_error("Failed to expand names: %s", strerror(-r));
4456
4457 STRV_FOREACH(name, names) {
4458 _cleanup_free_ char *unit;
4459
4460 unit = unit_dbus_path_from_name(*name);
4461 if (!unit)
4462 return log_oom();
4463
5bb75bc7
ZJS
4464 r = show_one(args[0], bus, unit, show_properties,
4465 &new_line, &ellipsized);
4466 if (r < 0)
4467 return r;
4468 else if (r > 0 && ret == 0)
4469 ret = r;
e3e0314b
ZJS
4470 }
4471 }
4472 }
4473
94e0bd7d
ZJS
4474 if (ellipsized && !arg_quiet)
4475 printf("Hint: Some lines were ellipsized, use -l to show in full.\n");
48220598 4476
22f4096c 4477 return ret;
0183528f
LP
4478}
4479
15ef1144
LP
4480static int cat(sd_bus *bus, char **args) {
4481 _cleanup_free_ char *unit = NULL;
4482 _cleanup_strv_free_ char **names = NULL;
4483 char **name;
4484 bool first = true;
4485 int r = 0;
4486
4487 assert(bus);
4488 assert(args);
4489
4490 r = expand_names(bus, args + 1, NULL, &names);
4491 if (r < 0)
4492 log_error("Failed to expand names: %s", strerror(-r));
4493
4494 pager_open_if_enabled();
4495
4496 STRV_FOREACH(name, names) {
4497 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4498 _cleanup_strv_free_ char **dropin_paths = NULL;
4499 _cleanup_free_ char *fragment_path = NULL;
4500 char **path;
4501
4502 unit = unit_dbus_path_from_name(*name);
4503 if (!unit)
4504 return log_oom();
4505
4506 if (need_daemon_reload(bus, *name) > 0)
4507 log_warning("Unit file of %s changed on disk. Run 'systemctl%s daemon-reload'.",
4508 *name, arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
4509
4510 r = sd_bus_get_property_string(
4511 bus,
4512 "org.freedesktop.systemd1",
4513 unit,
4514 "org.freedesktop.systemd1.Unit",
4515 "FragmentPath",
4516 &error,
4517 &fragment_path);
4518 if (r < 0) {
4519 log_warning("Failed to get FragmentPath: %s", bus_error_message(&error, r));
4520 continue;
4521 }
4522
4523 r = sd_bus_get_property_strv(
4524 bus,
4525 "org.freedesktop.systemd1",
4526 unit,
4527 "org.freedesktop.systemd1.Unit",
4528 "DropInPaths",
4529 &error,
4530 &dropin_paths);
4531 if (r < 0) {
4532 log_warning("Failed to get DropInPaths: %s", bus_error_message(&error, r));
4533 continue;
4534 }
4535
4536 if (first)
4537 first = false;
4538 else
4539 puts("");
4540
4541 if (!isempty(fragment_path)) {
4542 printf("%s# %s%s\n",
4543 ansi_highlight_blue(),
4544 fragment_path,
4545 ansi_highlight_off());
4546 fflush(stdout);
4547
4548 r = sendfile_full(STDOUT_FILENO, fragment_path);
4549 if (r < 0) {
4550 log_warning("Failed to cat %s: %s", fragment_path, strerror(-r));
4551 continue;
4552 }
4553 }
4554
4555 STRV_FOREACH(path, dropin_paths) {
4556 printf("%s%s# %s%s\n",
4557 isempty(fragment_path) && path == dropin_paths ? "" : "\n",
4558 ansi_highlight_blue(),
4559 *path,
4560 ansi_highlight_off());
4561 fflush(stdout);
4562
4563 r = sendfile_full(STDOUT_FILENO, *path);
4564 if (r < 0) {
4565 log_warning("Failed to cat %s: %s", *path, strerror(-r));
4566 continue;
4567 }
4568 }
4569 }
4570
4571 return r < 0 ? r : 0;
4572}
4573
f459b602
MAP
4574static int set_property(sd_bus *bus, char **args) {
4575 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
4576 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
68372da6 4577 _cleanup_free_ char *n = NULL;
8e2af478
LP
4578 char **i;
4579 int r;
4580
f459b602
MAP
4581 r = sd_bus_message_new_method_call(
4582 bus,
151b9b96 4583 &m,
8e2af478
LP
4584 "org.freedesktop.systemd1",
4585 "/org/freedesktop/systemd1",
4586 "org.freedesktop.systemd1.Manager",
151b9b96 4587 "SetUnitProperties");
f459b602
MAP
4588 if (r < 0)
4589 return bus_log_create_error(r);
8e2af478 4590
f78e6385 4591 n = unit_name_mangle(args[1], MANGLE_NOGLOB);
68372da6
LP
4592 if (!n)
4593 return log_oom();
4594
f459b602
MAP
4595 r = sd_bus_message_append(m, "sb", n, arg_runtime);
4596 if (r < 0)
4597 return bus_log_create_error(r);
8e2af478 4598
f459b602
MAP
4599 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, "(sv)");
4600 if (r < 0)
4601 return bus_log_create_error(r);
8e2af478 4602
f459b602
MAP
4603 STRV_FOREACH(i, args + 2) {
4604 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
4605 if (r < 0)
4606 return bus_log_create_error(r);
8e2af478 4607
df31a6c0 4608 r = bus_append_unit_property_assignment(m, *i);
8e2af478
LP
4609 if (r < 0)
4610 return r;
4611
f459b602
MAP
4612 r = sd_bus_message_close_container(m);
4613 if (r < 0)
4614 return bus_log_create_error(r);
8e2af478
LP
4615 }
4616
f459b602
MAP
4617 r = sd_bus_message_close_container(m);
4618 if (r < 0)
4619 return bus_log_create_error(r);
8e2af478 4620
c49b30a2 4621 r = sd_bus_call(bus, m, 0, &error, NULL);
f459b602
MAP
4622 if (r < 0) {
4623 log_error("Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
4624 return r;
8e2af478
LP
4625 }
4626
4627 return 0;
4628}
4629
f459b602
MAP
4630static int snapshot(sd_bus *bus, char **args) {
4631 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4632 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4633 _cleanup_free_ char *n = NULL, *id = NULL;
4634 const char *path;
7e4249b9 4635 int r;
7e4249b9 4636
1dcf6065 4637 if (strv_length(args) > 1)
f78e6385 4638 n = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".snapshot");
1dcf6065
LP
4639 else
4640 n = strdup("");
4641 if (!n)
4642 return log_oom();
7e4249b9 4643
f459b602 4644 r = sd_bus_call_method(
f22f08cd
SP
4645 bus,
4646 "org.freedesktop.systemd1",
4647 "/org/freedesktop/systemd1",
4648 "org.freedesktop.systemd1.Manager",
4649 "CreateSnapshot",
f459b602 4650 &error,
f22f08cd 4651 &reply,
f459b602
MAP
4652 "sb", n, false);
4653 if (r < 0) {
4654 log_error("Failed to create snapshot: %s", bus_error_message(&error, r));
1dcf6065 4655 return r;
7e4249b9
LP
4656 }
4657
f459b602
MAP
4658 r = sd_bus_message_read(reply, "o", &path);
4659 if (r < 0)
4660 return bus_log_parse_error(r);
5dd9014f 4661
f459b602 4662 r = sd_bus_get_property_string(
f22f08cd
SP
4663 bus,
4664 "org.freedesktop.systemd1",
4665 path,
f459b602
MAP
4666 "org.freedesktop.systemd1.Unit",
4667 "Id",
4668 &error,
4669 &id);
4670 if (r < 0) {
4671 log_error("Failed to get ID of snapshot: %s", bus_error_message(&error, r));
1dcf6065 4672 return r;
7e4249b9
LP
4673 }
4674
0183528f
LP
4675 if (!arg_quiet)
4676 puts(id);
7e4249b9 4677
1dcf6065 4678 return 0;
7e4249b9
LP
4679}
4680
f459b602
MAP
4681static int delete_snapshot(sd_bus *bus, char **args) {
4682 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
e3e0314b 4683 _cleanup_strv_free_ char **names = NULL;
729e3769 4684 char **name;
e3e0314b 4685 int r, q;
6759e7a7 4686
6759e7a7
LP
4687 assert(args);
4688
e3e0314b
ZJS
4689 r = expand_names(bus, args + 1, ".snapshot", &names);
4690 if (r < 0)
4691 log_error("Failed to expand names: %s", strerror(-r));
1dcf6065 4692
e3e0314b
ZJS
4693 STRV_FOREACH(name, names) {
4694 q = sd_bus_call_method(
f22f08cd 4695 bus,
b0193f1c
LP
4696 "org.freedesktop.systemd1",
4697 "/org/freedesktop/systemd1",
4698 "org.freedesktop.systemd1.Manager",
5dd9014f 4699 "RemoveSnapshot",
f459b602 4700 &error,
f22f08cd 4701 NULL,
e3e0314b
ZJS
4702 "s", *name);
4703 if (q < 0) {
4704 log_error("Failed to remove snapshot %s: %s",
4705 *name, bus_error_message(&error, r));
4706 if (r == 0)
4707 r = q;
f459b602 4708 }
6759e7a7
LP
4709 }
4710
e3e0314b 4711 return r;
6759e7a7
LP
4712}
4713
f459b602
MAP
4714static int daemon_reload(sd_bus *bus, char **args) {
4715 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
7e4249b9 4716 const char *method;
f459b602 4717 int r;
7e4249b9 4718
e4b61340
LP
4719 if (arg_action == ACTION_RELOAD)
4720 method = "Reload";
4721 else if (arg_action == ACTION_REEXEC)
4722 method = "Reexecute";
4723 else {
4724 assert(arg_action == ACTION_SYSTEMCTL);
4725
4726 method =
20b09ca7
LP
4727 streq(args[0], "clear-jobs") ||
4728 streq(args[0], "cancel") ? "ClearJobs" :
4729 streq(args[0], "daemon-reexec") ? "Reexecute" :
4730 streq(args[0], "reset-failed") ? "ResetFailed" :
4731 streq(args[0], "halt") ? "Halt" :
4732 streq(args[0], "poweroff") ? "PowerOff" :
4733 streq(args[0], "reboot") ? "Reboot" :
4734 streq(args[0], "kexec") ? "KExec" :
4735 streq(args[0], "exit") ? "Exit" :
4736 /* "daemon-reload" */ "Reload";
e4b61340 4737 }
7e4249b9 4738
f459b602 4739 r = sd_bus_call_method(
f22f08cd
SP
4740 bus,
4741 "org.freedesktop.systemd1",
4742 "/org/freedesktop/systemd1",
4743 "org.freedesktop.systemd1.Manager",
4744 method,
c516c8d1 4745 &error,
f459b602
MAP
4746 NULL,
4747 NULL);
f22f08cd
SP
4748
4749 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
4750 /* There's always a fallback possible for
4751 * legacy actions. */
4752 r = -EADDRNOTAVAIL;
d0ede8f1
LP
4753 else if ((r == -ETIMEDOUT || r == -ECONNRESET) && streq(method, "Reexecute"))
4754 /* On reexecution, we expect a disconnect, not a
4755 * reply */
f22f08cd 4756 r = 0;
1dcf6065 4757 else if (r < 0)
f459b602 4758 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
7e4249b9 4759
0a9776c2 4760 return r < 0 ? r : 0;
7e4249b9
LP
4761}
4762
f459b602
MAP
4763static int reset_failed(sd_bus *bus, char **args) {
4764 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
e3e0314b 4765 _cleanup_strv_free_ char **names = NULL;
f84190d8 4766 char **name;
e3e0314b 4767 int r, q;
5632e374 4768
729e3769
LP
4769 if (strv_length(args) <= 1)
4770 return daemon_reload(bus, args);
5632e374 4771
e3e0314b
ZJS
4772 r = expand_names(bus, args + 1, NULL, &names);
4773 if (r < 0)
4774 log_error("Failed to expand names: %s", strerror(-r));
f84190d8 4775
e3e0314b
ZJS
4776 STRV_FOREACH(name, names) {
4777 q = sd_bus_call_method(
f22f08cd 4778 bus,
b0193f1c
LP
4779 "org.freedesktop.systemd1",
4780 "/org/freedesktop/systemd1",
4781 "org.freedesktop.systemd1.Manager",
f22f08cd 4782 "ResetFailedUnit",
f459b602 4783 &error,
f22f08cd 4784 NULL,
e3e0314b
ZJS
4785 "s", *name);
4786 if (q < 0) {
4787 log_error("Failed to reset failed state of unit %s: %s",
4788 *name, bus_error_message(&error, r));
4789 if (r == 0)
4790 r = q;
f459b602 4791 }
5632e374
LP
4792 }
4793
e3e0314b 4794 return r;
5632e374
LP
4795}
4796
f459b602
MAP
4797static int show_environment(sd_bus *bus, char **args) {
4798 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4799 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4800 const char *text;
7e4249b9 4801 int r;
7e4249b9 4802
1968a360 4803 pager_open_if_enabled();
ec14911e 4804
f459b602 4805 r = sd_bus_get_property(
f22f08cd
SP
4806 bus,
4807 "org.freedesktop.systemd1",
4808 "/org/freedesktop/systemd1",
f459b602
MAP
4809 "org.freedesktop.systemd1.Manager",
4810 "Environment",
4811 &error,
f22f08cd 4812 &reply,
f459b602
MAP
4813 "as");
4814 if (r < 0) {
4815 log_error("Failed to get environment: %s", bus_error_message(&error, r));
f84190d8 4816 return r;
7e4249b9
LP
4817 }
4818
f459b602
MAP
4819 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
4820 if (r < 0)
4821 return bus_log_parse_error(r);
7e4249b9 4822
f459b602 4823 while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0)
f84190d8 4824 puts(text);
f459b602
MAP
4825 if (r < 0)
4826 return bus_log_parse_error(r);
7e4249b9 4827
f459b602
MAP
4828 r = sd_bus_message_exit_container(reply);
4829 if (r < 0)
4830 return bus_log_parse_error(r);
7e4249b9 4831
f84190d8 4832 return 0;
7e4249b9
LP
4833}
4834
f459b602
MAP
4835static int switch_root(sd_bus *bus, char **args) {
4836 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
f39d4a08
HH
4837 _cleanup_free_ char *cmdline_init = NULL;
4838 const char *root, *init;
f459b602
MAP
4839 unsigned l;
4840 int r;
957eb8ca
LP
4841
4842 l = strv_length(args);
4843 if (l < 2 || l > 3) {
4844 log_error("Wrong number of arguments.");
4845 return -EINVAL;
4846 }
4847
4848 root = args[1];
13068da8
TG
4849
4850 if (l >= 3)
f39d4a08 4851 init = args[2];
13068da8 4852 else {
f39d4a08
HH
4853 r = parse_env_file("/proc/cmdline", WHITESPACE,
4854 "init", &cmdline_init,
4855 NULL);
4856 if (r < 0)
4857 log_debug("Failed to parse /proc/cmdline: %s", strerror(-r));
13068da8 4858
f39d4a08 4859 init = cmdline_init;
13068da8 4860 }
f459b602 4861
f39d4a08
HH
4862 if (isempty(init))
4863 init = NULL;
4864
4865 if (init) {
4866 const char *root_systemd_path = NULL, *root_init_path = NULL;
4867
4868 root_systemd_path = strappenda(root, "/" SYSTEMD_BINARY_PATH);
4869 root_init_path = strappenda3(root, "/", init);
4870
4871 /* If the passed init is actually the same as the
4872 * systemd binary, then let's suppress it. */
4873 if (files_same(root_init_path, root_systemd_path) > 0)
4874 init = NULL;
4875 }
13068da8 4876
f39d4a08 4877 log_debug("Switching root - root: %s; init: %s", root, strna(init));
957eb8ca 4878
f459b602 4879 r = sd_bus_call_method(
f22f08cd 4880 bus,
957eb8ca
LP
4881 "org.freedesktop.systemd1",
4882 "/org/freedesktop/systemd1",
4883 "org.freedesktop.systemd1.Manager",
f22f08cd 4884 "SwitchRoot",
f459b602 4885 &error,
f22f08cd 4886 NULL,
f459b602
MAP
4887 "ss", root, init);
4888 if (r < 0) {
4889 log_error("Failed to switch root: %s", bus_error_message(&error, r));
4890 return r;
4891 }
4892
4893 return 0;
957eb8ca
LP
4894}
4895
f459b602
MAP
4896static int set_environment(sd_bus *bus, char **args) {
4897 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4898 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
7e4249b9 4899 const char *method;
31e767f7
LP
4900 int r;
4901
4902 assert(bus);
60f9ba0b 4903 assert(args);
7e4249b9 4904
7e4249b9
LP
4905 method = streq(args[0], "set-environment")
4906 ? "SetEnvironment"
4907 : "UnsetEnvironment";
4908
f459b602
MAP
4909 r = sd_bus_message_new_method_call(
4910 bus,
151b9b96 4911 &m,
31e767f7
LP
4912 "org.freedesktop.systemd1",
4913 "/org/freedesktop/systemd1",
4914 "org.freedesktop.systemd1.Manager",
151b9b96 4915 method);
f459b602
MAP
4916 if (r < 0)
4917 return bus_log_create_error(r);
7e4249b9 4918
f459b602 4919 r = sd_bus_message_append_strv(m, args + 1);
31e767f7 4920 if (r < 0)
f459b602 4921 return bus_log_create_error(r);
7e4249b9 4922
c49b30a2 4923 r = sd_bus_call(bus, m, 0, &error, NULL);
f459b602
MAP
4924 if (r < 0) {
4925 log_error("Failed to set environment: %s", bus_error_message(&error, r));
4926 return r;
7e4249b9
LP
4927 }
4928
f84190d8 4929 return 0;
7e4249b9
LP
4930}
4931
ac3efa8a
LP
4932static int import_environment(sd_bus *bus, char **args) {
4933 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4934 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
4935 int r;
4936
4937 assert(bus);
4938 assert(args);
4939
4940 r = sd_bus_message_new_method_call(
4941 bus,
151b9b96 4942 &m,
ac3efa8a
LP
4943 "org.freedesktop.systemd1",
4944 "/org/freedesktop/systemd1",
4945 "org.freedesktop.systemd1.Manager",
151b9b96 4946 "SetEnvironment");
ac3efa8a
LP
4947 if (r < 0)
4948 return bus_log_create_error(r);
4949
4950 if (strv_isempty(args + 1))
4951 r = sd_bus_message_append_strv(m, environ);
4952 else {
4953 char **a, **b;
4954
4955 r = sd_bus_message_open_container(m, 'a', "s");
4956 if (r < 0)
4957 return bus_log_create_error(r);
4958
4959 STRV_FOREACH(a, args + 1) {
4960
4961 if (!env_name_is_valid(*a)) {
4962 log_error("Not a valid environment variable name: %s", *a);
4963 return -EINVAL;
4964 }
4965
4966 STRV_FOREACH(b, environ) {
4967 const char *eq;
4968
4969 eq = startswith(*b, *a);
4970 if (eq && *eq == '=') {
4971
4972 r = sd_bus_message_append(m, "s", *b);
4973 if (r < 0)
4974 return bus_log_create_error(r);
4975
4976 break;
4977 }
4978 }
4979 }
4980
4981 r = sd_bus_message_close_container(m);
4982 }
4983 if (r < 0)
4984 return bus_log_create_error(r);
4985
4986 r = sd_bus_call(bus, m, 0, &error, NULL);
4987 if (r < 0) {
4988 log_error("Failed to import environment: %s", bus_error_message(&error, r));
4989 return r;
4990 }
4991
4992 return 0;
4993}
4994
cbb13b2a 4995static int enable_sysv_units(const char *verb, char **args) {
729e3769 4996 int r = 0;
ee5762e3 4997
77e68fa2 4998#if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
729e3769 4999 unsigned f = 1, t = 1;
fb15be83 5000 _cleanup_lookup_paths_free_ LookupPaths paths = {};
ee5762e3 5001
729e3769
LP
5002 if (arg_scope != UNIT_FILE_SYSTEM)
5003 return 0;
ee5762e3 5004
729e3769
LP
5005 if (!streq(verb, "enable") &&
5006 !streq(verb, "disable") &&
5007 !streq(verb, "is-enabled"))
5008 return 0;
ee5762e3 5009
729e3769
LP
5010 /* Processes all SysV units, and reshuffles the array so that
5011 * afterwards only the native units remain */
ee5762e3 5012
12ed81d9 5013 r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, arg_root, NULL, NULL, NULL);
729e3769
LP
5014 if (r < 0)
5015 return r;
ee5762e3 5016
729e3769 5017 r = 0;
cbb13b2a 5018 for (f = 0; args[f]; f++) {
729e3769 5019 const char *name;
05cae7f3 5020 _cleanup_free_ char *p = NULL, *q = NULL, *l = NULL;
729e3769
LP
5021 bool found_native = false, found_sysv;
5022 unsigned c = 1;
5023 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
05cae7f3 5024 char **k;
729e3769
LP
5025 int j;
5026 pid_t pid;
5027 siginfo_t status;
ee5762e3 5028
729e3769 5029 name = args[f];
ee5762e3 5030
729e3769
LP
5031 if (!endswith(name, ".service"))
5032 continue;
ee5762e3 5033
729e3769
LP
5034 if (path_is_absolute(name))
5035 continue;
ee5762e3 5036
729e3769 5037 STRV_FOREACH(k, paths.unit_path) {
05cae7f3
ZJS
5038 _cleanup_free_ char *path = NULL;
5039
729e3769 5040 if (!isempty(arg_root))
4723e4b2 5041 asprintf(&path, "%s/%s/%s", arg_root, *k, name);
729e3769 5042 else
4723e4b2 5043 asprintf(&path, "%s/%s", *k, name);
ee5762e3 5044
4723e4b2 5045 if (!path) {
0d0f0c50 5046 r = log_oom();
729e3769
LP
5047 goto finish;
5048 }
ee5762e3 5049
4723e4b2 5050 found_native = access(path, F_OK) >= 0;
729e3769
LP
5051 if (found_native)
5052 break;
5053 }
ee5762e3 5054
729e3769
LP
5055 if (found_native)
5056 continue;
ee5762e3 5057
729e3769
LP
5058 if (!isempty(arg_root))
5059 asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
5060 else
5061 asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
5062 if (!p) {
0d0f0c50 5063 r = log_oom();
729e3769
LP
5064 goto finish;
5065 }
ee5762e3 5066
05cae7f3 5067 p[strlen(p) - strlen(".service")] = 0;
729e3769 5068 found_sysv = access(p, F_OK) >= 0;
4b6756a8 5069 if (!found_sysv)
729e3769 5070 continue;
71fad675 5071
729e3769
LP
5072 /* Mark this entry, so that we don't try enabling it as native unit */
5073 args[f] = (char*) "";
ee5762e3 5074
729e3769 5075 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
ee5762e3 5076
729e3769
LP
5077 if (!isempty(arg_root))
5078 argv[c++] = q = strappend("--root=", arg_root);
ee5762e3 5079
2b6bf07d 5080 argv[c++] = basename(p);
729e3769
LP
5081 argv[c++] =
5082 streq(verb, "enable") ? "on" :
5083 streq(verb, "disable") ? "off" : "--level=5";
5084 argv[c] = NULL;
ee5762e3 5085
729e3769
LP
5086 l = strv_join((char**)argv, " ");
5087 if (!l) {
0d0f0c50 5088 r = log_oom();
729e3769
LP
5089 goto finish;
5090 }
ee5762e3 5091
729e3769 5092 log_info("Executing %s", l);
ee5762e3 5093
729e3769
LP
5094 pid = fork();
5095 if (pid < 0) {
5096 log_error("Failed to fork: %m");
729e3769
LP
5097 r = -errno;
5098 goto finish;
5099 } else if (pid == 0) {
5100 /* Child */
ee5762e3 5101
729e3769
LP
5102 execv(argv[0], (char**) argv);
5103 _exit(EXIT_FAILURE);
5104 }
ee5762e3 5105
729e3769
LP
5106 j = wait_for_terminate(pid, &status);
5107 if (j < 0) {
5108 log_error("Failed to wait for child: %s", strerror(-r));
5109 r = j;
5110 goto finish;
5111 }
ee5762e3 5112
729e3769
LP
5113 if (status.si_code == CLD_EXITED) {
5114 if (streq(verb, "is-enabled")) {
5115 if (status.si_status == 0) {
5116 if (!arg_quiet)
5117 puts("enabled");
5118 r = 1;
5119 } else {
5120 if (!arg_quiet)
5121 puts("disabled");
5122 }
ee5762e3 5123
729e3769
LP
5124 } else if (status.si_status != 0) {
5125 r = -EINVAL;
5126 goto finish;
5127 }
5128 } else {
5129 r = -EPROTO;
5130 goto finish;
5131 }
ee5762e3
LP
5132 }
5133
729e3769 5134finish:
729e3769 5135 /* Drop all SysV units */
cbb13b2a 5136 for (f = 0, t = 0; args[f]; f++) {
ee5762e3 5137
729e3769 5138 if (isempty(args[f]))
ee5762e3
LP
5139 continue;
5140
729e3769
LP
5141 args[t++] = args[f];
5142 }
ee5762e3 5143
729e3769 5144 args[t] = NULL;
ee5762e3 5145
729e3769
LP
5146#endif
5147 return r;
5148}
ee5762e3 5149
37370d0c 5150static int mangle_names(char **original_names, char ***mangled_names) {
a33fdebb 5151 char **i, **l, **name;
37370d0c 5152
a33fdebb
LP
5153 l = new(char*, strv_length(original_names) + 1);
5154 if (!l)
37370d0c
VP
5155 return log_oom();
5156
a33fdebb 5157 i = l;
37370d0c 5158 STRV_FOREACH(name, original_names) {
44386fc1
LN
5159
5160 /* When enabling units qualified path names are OK,
5161 * too, hence allow them explicitly. */
5162
5163 if (is_path(*name))
5164 *i = strdup(*name);
5165 else
f78e6385 5166 *i = unit_name_mangle(*name, MANGLE_NOGLOB);
44386fc1 5167
a33fdebb
LP
5168 if (!*i) {
5169 strv_free(l);
37370d0c 5170 return log_oom();
a33fdebb
LP
5171 }
5172
5173 i++;
37370d0c 5174 }
a33fdebb
LP
5175
5176 *i = NULL;
5177 *mangled_names = l;
37370d0c
VP
5178
5179 return 0;
5180}
5181
f459b602 5182static int enable_unit(sd_bus *bus, char **args) {
e3e0314b 5183 _cleanup_strv_free_ char **names = NULL;
729e3769
LP
5184 const char *verb = args[0];
5185 UnitFileChange *changes = NULL;
718db961 5186 unsigned n_changes = 0;
729e3769 5187 int carries_install_info = -1;
729e3769 5188 int r;
ee5762e3 5189
ab5919fa
MS
5190 if (!args[1])
5191 return 0;
5192
e3e0314b 5193 r = mangle_names(args+1, &names);
3a05c0f9 5194 if (r < 0)
cbb13b2a
VP
5195 return r;
5196
e3e0314b 5197 r = enable_sysv_units(verb, names);
cbb13b2a
VP
5198 if (r < 0)
5199 return r;
3a05c0f9 5200
67d66210
LP
5201 /* If the operation was fully executed by the SysV compat,
5202 * let's finish early */
5203 if (strv_isempty(names))
5204 return 0;
5205
729e3769
LP
5206 if (!bus || avoid_bus()) {
5207 if (streq(verb, "enable")) {
e3e0314b 5208 r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769
LP
5209 carries_install_info = r;
5210 } else if (streq(verb, "disable"))
e3e0314b 5211 r = unit_file_disable(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
729e3769 5212 else if (streq(verb, "reenable")) {
e3e0314b 5213 r = unit_file_reenable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769
LP
5214 carries_install_info = r;
5215 } else if (streq(verb, "link"))
e3e0314b 5216 r = unit_file_link(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769 5217 else if (streq(verb, "preset")) {
d309c1c3 5218 r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_preset_mode, arg_force, &changes, &n_changes);
729e3769
LP
5219 carries_install_info = r;
5220 } else if (streq(verb, "mask"))
e3e0314b 5221 r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769 5222 else if (streq(verb, "unmask"))
e3e0314b 5223 r = unit_file_unmask(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
729e3769
LP
5224 else
5225 assert_not_reached("Unknown verb");
ee5762e3 5226
729e3769
LP
5227 if (r < 0) {
5228 log_error("Operation failed: %s", strerror(-r));
5229 goto finish;
ee5762e3
LP
5230 }
5231
718db961
LP
5232 if (!arg_quiet)
5233 dump_unit_file_changes(changes, n_changes);
ee5762e3 5234
df77cdf0 5235 r = 0;
729e3769 5236 } else {
718db961
LP
5237 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
5238 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
f459b602 5239 int expect_carries_install_info = false;
d309c1c3 5240 bool send_force = true, send_preset_mode = false;
718db961 5241 const char *method;
729e3769
LP
5242
5243 if (streq(verb, "enable")) {
5244 method = "EnableUnitFiles";
5245 expect_carries_install_info = true;
5246 } else if (streq(verb, "disable")) {
5247 method = "DisableUnitFiles";
5248 send_force = false;
5249 } else if (streq(verb, "reenable")) {
5250 method = "ReenableUnitFiles";
5251 expect_carries_install_info = true;
5252 } else if (streq(verb, "link"))
5253 method = "LinkUnitFiles";
5254 else if (streq(verb, "preset")) {
d309c1c3
LP
5255
5256 if (arg_preset_mode != UNIT_FILE_PRESET_FULL) {
5257 method = "PresetUnitFilesWithMode";
5258 send_preset_mode = true;
5259 } else
5260 method = "PresetUnitFiles";
5261
729e3769
LP
5262 expect_carries_install_info = true;
5263 } else if (streq(verb, "mask"))
5264 method = "MaskUnitFiles";
5265 else if (streq(verb, "unmask")) {
5266 method = "UnmaskUnitFiles";
5267 send_force = false;
5268 } else
5269 assert_not_reached("Unknown verb");
5270
f459b602
MAP
5271 r = sd_bus_message_new_method_call(
5272 bus,
151b9b96 5273 &m,
729e3769
LP
5274 "org.freedesktop.systemd1",
5275 "/org/freedesktop/systemd1",
5276 "org.freedesktop.systemd1.Manager",
151b9b96 5277 method);
f459b602
MAP
5278 if (r < 0)
5279 return bus_log_create_error(r);
ee5762e3 5280
e3e0314b 5281 r = sd_bus_message_append_strv(m, names);
f459b602
MAP
5282 if (r < 0)
5283 return bus_log_create_error(r);
ee5762e3 5284
d309c1c3
LP
5285 if (send_preset_mode) {
5286 r = sd_bus_message_append(m, "s", unit_file_preset_mode_to_string(arg_preset_mode));
5287 if (r < 0)
5288 return bus_log_create_error(r);
5289 }
5290
f459b602
MAP
5291 r = sd_bus_message_append(m, "b", arg_runtime);
5292 if (r < 0)
5293 return bus_log_create_error(r);
ee5762e3 5294
729e3769 5295 if (send_force) {
f459b602
MAP
5296 r = sd_bus_message_append(m, "b", arg_force);
5297 if (r < 0)
5298 return bus_log_create_error(r);
ee5762e3
LP
5299 }
5300
c49b30a2 5301 r = sd_bus_call(bus, m, 0, &error, &reply);
f459b602
MAP
5302 if (r < 0) {
5303 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
5304 return r;
729e3769 5305 }
be394c48 5306
729e3769 5307 if (expect_carries_install_info) {
f459b602
MAP
5308 r = sd_bus_message_read(reply, "b", &carries_install_info);
5309 if (r < 0)
5310 return bus_log_parse_error(r);
ee5762e3
LP
5311 }
5312
cc3f2093 5313 r = deserialize_and_dump_unit_file_changes(reply);
f459b602 5314 if (r < 0)
718db961 5315 return r;
b77398f7 5316
93c941e3 5317 /* Try to reload if enabled */
d6cb60c7 5318 if (!arg_no_reload)
729e3769 5319 r = daemon_reload(bus, args);
f459b602
MAP
5320 else
5321 r = 0;
b647f10d 5322 }
3d3961f2 5323
729e3769 5324 if (carries_install_info == 0)
416389f7
LP
5325 log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
5326 "using systemctl.\n"
5327 "Possible reasons for having this kind of units are:\n"
5328 "1) A unit may be statically enabled by being symlinked from another unit's\n"
5329 " .wants/ or .requires/ directory.\n"
5330 "2) A unit's purpose may be to act as a helper for some other unit which has\n"
5331 " a requirement dependency on it.\n"
5332 "3) A unit may be started when needed via activation (socket, path, timer,\n"
5333 " D-Bus, udev, scripted systemctl call, ...).\n");
ee5762e3 5334
729e3769 5335finish:
729e3769 5336 unit_file_changes_free(changes, n_changes);
ee5762e3 5337
729e3769 5338 return r;
ee5762e3
LP
5339}
5340
d309c1c3
LP
5341static int preset_all(sd_bus *bus, char **args) {
5342 UnitFileChange *changes = NULL;
5343 unsigned n_changes = 0;
5344 int r;
5345
5346 if (!bus || avoid_bus()) {
5347
5348 r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes);
5349 if (r < 0) {
5350 log_error("Operation failed: %s", strerror(-r));
5351 goto finish;
5352 }
5353
5354 if (!arg_quiet)
5355 dump_unit_file_changes(changes, n_changes);
5356
5357 r = 0;
5358
5359 } else {
5360 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
5361 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
5362
5363 r = sd_bus_call_method(
5364 bus,
5365 "org.freedesktop.systemd1",
5366 "/org/freedesktop/systemd1",
5367 "org.freedesktop.systemd1.Manager",
5368 "PresetAllUnitFiles",
5369 &error,
5370 &reply,
5371 "sbb",
5372 unit_file_preset_mode_to_string(arg_preset_mode),
5373 arg_runtime,
5374 arg_force);
5375 if (r < 0) {
5376 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
5377 return r;
5378 }
5379
5380 r = deserialize_and_dump_unit_file_changes(reply);
5381 if (r < 0)
5382 return r;
5383
5384 if (!arg_no_reload)
5385 r = daemon_reload(bus, args);
5386 else
5387 r = 0;
5388 }
5389
5390finish:
5391 unit_file_changes_free(changes, n_changes);
5392
5393 return r;
5394}
5395
f459b602
MAP
5396static int unit_is_enabled(sd_bus *bus, char **args) {
5397
5398 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
e3e0314b 5399 _cleanup_strv_free_ char **names = NULL;
729e3769
LP
5400 bool enabled;
5401 char **name;
f459b602 5402 int r;
ee5762e3 5403
e3e0314b 5404 r = mangle_names(args+1, &names);
cbb13b2a
VP
5405 if (r < 0)
5406 return r;
5407
e3e0314b 5408 r = enable_sysv_units(args[0], names);
729e3769
LP
5409 if (r < 0)
5410 return r;
ee5762e3 5411
729e3769 5412 enabled = r > 0;
ee5762e3 5413
729e3769 5414 if (!bus || avoid_bus()) {
ee5762e3 5415
e3e0314b 5416 STRV_FOREACH(name, names) {
729e3769 5417 UnitFileState state;
ee5762e3 5418
cbb13b2a 5419 state = unit_file_get_state(arg_scope, arg_root, *name);
cbc9fbd1
LP
5420 if (state < 0) {
5421 log_error("Failed to get unit file state for %s: %s", *name, strerror(-state));
cec7eda5 5422 return state;
cbc9fbd1 5423 }
ee5762e3 5424
729e3769
LP
5425 if (state == UNIT_FILE_ENABLED ||
5426 state == UNIT_FILE_ENABLED_RUNTIME ||
5427 state == UNIT_FILE_STATIC)
5428 enabled = true;
5429
5430 if (!arg_quiet)
5431 puts(unit_file_state_to_string(state));
71fad675 5432 }
ee5762e3 5433
729e3769 5434 } else {
e3e0314b 5435 STRV_FOREACH(name, names) {
f459b602 5436 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
729e3769 5437 const char *s;
63a723f3 5438
f459b602 5439 r = sd_bus_call_method(
f22f08cd 5440 bus,
729e3769
LP
5441 "org.freedesktop.systemd1",
5442 "/org/freedesktop/systemd1",
5443 "org.freedesktop.systemd1.Manager",
f22f08cd 5444 "GetUnitFileState",
f459b602 5445 &error,
f22f08cd 5446 &reply,
04504f93 5447 "s", *name);
f459b602
MAP
5448 if (r < 0) {
5449 log_error("Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
cec7eda5 5450 return r;
ee5762e3
LP
5451 }
5452
f459b602
MAP
5453 r = sd_bus_message_read(reply, "s", &s);
5454 if (r < 0)
5455 return bus_log_parse_error(r);
ee5762e3 5456
729e3769
LP
5457 if (streq(s, "enabled") ||
5458 streq(s, "enabled-runtime") ||
5459 streq(s, "static"))
5460 enabled = true;
5461
5462 if (!arg_quiet)
5463 puts(s);
560d8f23 5464 }
ee5762e3
LP
5465 }
5466
f459b602 5467 return !enabled;
ee5762e3
LP
5468}
5469
99813a19
LP
5470static int is_system_running(sd_bus *bus, char **args) {
5471 _cleanup_free_ char *state = NULL;
5472 int r;
5473
5474 r = sd_bus_get_property_string(
5475 bus,
5476 "org.freedesktop.systemd1",
5477 "/org/freedesktop/systemd1",
5478 "org.freedesktop.systemd1.Manager",
5479 "SystemState",
5480 NULL,
5481 &state);
5482 if (r < 0) {
5483 if (!arg_quiet)
5484 puts("unknown");
5485 return 0;
5486 }
5487
5488 if (!arg_quiet)
5489 puts(state);
5490
5491 return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE;
5492}
5493
e4b61340 5494static int systemctl_help(void) {
7e4249b9 5495
729e3769
LP
5496 pager_open_if_enabled();
5497
2e33c433 5498 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
729e3769 5499 "Query or send control commands to the systemd manager.\n\n"
8a0867d6
LP
5500 " -h --help Show this help\n"
5501 " --version Show package version\n"
f459b602
MAP
5502 " --system Connect to system manager\n"
5503 " --user Connect to user service manager\n"
5504 " -H --host=[USER@]HOST\n"
5505 " Operate on remote host\n"
5506 " -M --machine=CONTAINER\n"
5507 " Operate on local container\n"
8a0867d6 5508 " -t --type=TYPE List only units of a particular type\n"
a521ae4a 5509 " --state=STATE List only units with particular LOAD or SUB or ACTIVE state\n"
8a0867d6 5510 " -p --property=NAME Show only properties by this name\n"
a5e4972c
LP
5511 " -a --all Show all loaded units/properties, including dead/empty\n"
5512 " ones. To list all units installed on the system, use\n"
5513 " the 'list-unit-files' command instead.\n"
98a6e132 5514 " -l --full Don't ellipsize unit names on output\n"
1238ee09 5515 " -r --recursive Show unit list of host and local containers\n"
4dc5b821
LP
5516 " --reverse Show reverse dependencies with 'list-dependencies'\n"
5517 " --job-mode=MODE Specify how to deal with already queued jobs, when\n"
5518 " queueing a new job\n"
a521ae4a 5519 " --show-types When showing sockets, explicitly show their type\n"
b37844d3
LP
5520 " -i --ignore-inhibitors\n"
5521 " When shutting down or sleeping, ignore inhibitors\n"
a8f11321
LP
5522 " --kill-who=WHO Who to send signal to\n"
5523 " -s --signal=SIGNAL Which signal to send\n"
8a0867d6
LP
5524 " -q --quiet Suppress output\n"
5525 " --no-block Do not wait until operation finished\n"
8a0867d6 5526 " --no-wall Don't send wall message before halt/power-off/reboot\n"
8a0867d6
LP
5527 " --no-reload When enabling/disabling unit files, don't reload daemon\n"
5528 " configuration\n"
ebed32bf 5529 " --no-legend Do not print a legend (column headers and hints)\n"
69fc152f 5530 " --no-pager Do not pipe output into a pager\n"
501fc174
LP
5531 " --no-ask-password\n"
5532 " Do not ask for system passwords\n"
a8f11321 5533 " --global Enable/disable unit files globally\n"
a521ae4a 5534 " --runtime Enable unit files only temporarily until next reboot\n"
8a0867d6
LP
5535 " -f --force When enabling unit files, override existing symlinks\n"
5536 " When shutting down, execute action immediately\n"
d309c1c3
LP
5537 " --preset-mode= Specifies whether fully apply presets, or only enable,\n"
5538 " or only disable\n"
729e3769 5539 " --root=PATH Enable unit files in the specified root directory\n"
76fdc966 5540 " -n --lines=INTEGER Number of journal entries to show\n"
d3f2bdbf 5541 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
815ebc54
DH
5542 " verbose, export, json, json-pretty, json-sse, cat)\n"
5543 " --plain Print unit dependencies as a list instead of a tree\n\n"
34c4b47b 5544 "Unit Commands:\n"
d8fba7c6
ZJS
5545 " list-units [PATTERN...] List loaded units\n"
5546 " list-sockets [PATTERN...] List loaded sockets ordered by address\n"
5547 " list-timers [PATTERN...] List loaded timers ordered by next elapse\n"
4f8f66cb
ZJS
5548 " start NAME... Start (activate) one or more units\n"
5549 " stop NAME... Stop (deactivate) one or more units\n"
5550 " reload NAME... Reload one or more units\n"
5551 " restart NAME... Start or restart one or more units\n"
5552 " try-restart NAME... Restart one or more units if active\n"
5553 " reload-or-restart NAME... Reload one or more units if possible,\n"
6f28c033 5554 " otherwise start or restart\n"
4f8f66cb 5555 " reload-or-try-restart NAME... Reload one or more units if possible,\n"
6f28c033 5556 " otherwise restart if active\n"
4f8f66cb
ZJS
5557 " isolate NAME Start one unit and stop all others\n"
5558 " kill NAME... Send signal to processes of a unit\n"
b3ae710c
ZJS
5559 " is-active PATTERN... Check whether units are active\n"
5560 " is-failed PATTERN... Check whether units are failed\n"
5561 " status [PATTERN...|PID...] Show runtime status of one or more units\n"
5562 " show [PATTERN...|JOB...] Show properties of one or more\n"
ee5762e3 5563 " units/jobs or the manager\n"
b3ae710c 5564 " cat PATTERN... Show files and drop-ins of one or more units\n"
4f8f66cb 5565 " set-property NAME ASSIGNMENT... Sets one or more properties of a unit\n"
b3ae710c
ZJS
5566 " help PATTERN...|PID... Show manual for one or more units\n"
5567 " reset-failed [PATTERN...] Reset failed state for all, one, or more\n"
fdf20a31 5568 " units\n"
55c0b89c 5569 " list-dependencies [NAME] Recursively show units which are required\n"
afba4199
ZJS
5570 " or wanted by this unit or by which this\n"
5571 " unit is required or wanted\n\n"
34c4b47b 5572 "Unit File Commands:\n"
d8fba7c6 5573 " list-unit-files [PATTERN...] List installed unit files\n"
4f8f66cb
ZJS
5574 " enable NAME... Enable one or more unit files\n"
5575 " disable NAME... Disable one or more unit files\n"
5576 " reenable NAME... Reenable one or more unit files\n"
5577 " preset NAME... Enable/disable one or more unit files\n"
729e3769 5578 " based on preset configuration\n"
d309c1c3
LP
5579 " preset-all Enable/disable all unit files based on\n"
5580 " preset configuration\n"
4f8f66cb
ZJS
5581 " is-enabled NAME... Check whether unit files are enabled\n\n"
5582 " mask NAME... Mask one or more units\n"
5583 " unmask NAME... Unmask one or more units\n"
5584 " link PATH... Link one or more units files into\n"
729e3769 5585 " the search path\n"
99504dd4 5586 " get-default Get the name of the default target\n"
f535088e 5587 " set-default NAME Set the default target\n\n"
0d292f5e
LP
5588 "Machine Commands:\n"
5589 " list-machines [PATTERN...] List local containers and host\n\n"
34c4b47b 5590 "Job Commands:\n"
d8fba7c6 5591 " list-jobs [PATTERN...] List jobs\n"
34c4b47b 5592 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
34c4b47b 5593 "Snapshot Commands:\n"
7e4249b9 5594 " snapshot [NAME] Create a snapshot\n"
4f8f66cb 5595 " delete NAME... Remove one or more snapshots\n\n"
34c4b47b 5596 "Environment Commands:\n"
7e4249b9 5597 " show-environment Dump environment\n"
4f8f66cb 5598 " set-environment NAME=VALUE... Set one or more environment variables\n"
ac3efa8a
LP
5599 " unset-environment NAME... Unset one or more environment variables\n"
5600 " import-environment NAME... Import all, one or more environment variables\n\n"
34c4b47b
LP
5601 "Manager Lifecycle Commands:\n"
5602 " daemon-reload Reload systemd manager configuration\n"
5603 " daemon-reexec Reexecute systemd manager\n\n"
5604 "System Commands:\n"
99813a19 5605 " is-system-running Check whether system is fully running\n"
20b09ca7
LP
5606 " default Enter system default mode\n"
5607 " rescue Enter system rescue mode\n"
5608 " emergency Enter system emergency mode\n"
514f4ef5 5609 " halt Shut down and halt the system\n"
2e33c433 5610 " poweroff Shut down and power-off the system\n"
37185ec8 5611 " reboot [ARG] Shut down and reboot the system\n"
20b09ca7 5612 " kexec Shut down and reboot the system with kexec\n"
6edd7d0a 5613 " exit Request user instance exit\n"
4f8f66cb 5614 " switch-root ROOT [INIT] Change to a different root file system\n"
6edd7d0a 5615 " suspend Suspend the system\n"
6524990f
LP
5616 " hibernate Hibernate the system\n"
5617 " hybrid-sleep Hibernate and suspend the system\n",
5b6319dc 5618 program_invocation_short_name);
7e4249b9
LP
5619
5620 return 0;
5621}
5622
e4b61340
LP
5623static int halt_help(void) {
5624
37185ec8 5625 printf("%s [OPTIONS...]%s\n\n"
e4b61340
LP
5626 "%s the system.\n\n"
5627 " --help Show this help\n"
5628 " --halt Halt the machine\n"
5629 " -p --poweroff Switch off the machine\n"
5630 " --reboot Reboot the machine\n"
2e33c433
LP
5631 " -f --force Force immediate halt/power-off/reboot\n"
5632 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
e4b61340 5633 " -d --no-wtmp Don't write wtmp record\n"
2e33c433 5634 " --no-wall Don't send wall message before halt/power-off/reboot\n",
e4b61340 5635 program_invocation_short_name,
37185ec8 5636 arg_action == ACTION_REBOOT ? " [ARG]" : "",
e4b61340
LP
5637 arg_action == ACTION_REBOOT ? "Reboot" :
5638 arg_action == ACTION_POWEROFF ? "Power off" :
5639 "Halt");
5640
5641 return 0;
5642}
5643
5644static int shutdown_help(void) {
5645
08e4b1c5 5646 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
e4b61340
LP
5647 "Shut down the system.\n\n"
5648 " --help Show this help\n"
5649 " -H --halt Halt the machine\n"
5650 " -P --poweroff Power-off the machine\n"
5651 " -r --reboot Reboot the machine\n"
386da858 5652 " -h Equivalent to --poweroff, overridden by --halt\n"
2e33c433 5653 " -k Don't halt/power-off/reboot, just send warnings\n"
f6144808 5654 " --no-wall Don't send wall message before halt/power-off/reboot\n"
f6144808 5655 " -c Cancel a pending shutdown\n",
e4b61340
LP
5656 program_invocation_short_name);
5657
5658 return 0;
5659}
5660
5661static int telinit_help(void) {
5662
2e33c433 5663 printf("%s [OPTIONS...] {COMMAND}\n\n"
514f4ef5
LP
5664 "Send control commands to the init daemon.\n\n"
5665 " --help Show this help\n"
2e33c433 5666 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
e4b61340
LP
5667 "Commands:\n"
5668 " 0 Power-off the machine\n"
5669 " 6 Reboot the machine\n"
514f4ef5
LP
5670 " 2, 3, 4, 5 Start runlevelX.target unit\n"
5671 " 1, s, S Enter rescue mode\n"
5672 " q, Q Reload init daemon configuration\n"
5673 " u, U Reexecute init daemon\n",
e4b61340
LP
5674 program_invocation_short_name);
5675
5676 return 0;
5677}
5678
5679static int runlevel_help(void) {
5680
2e33c433 5681 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
5682 "Prints the previous and current runlevel of the init system.\n\n"
5683 " --help Show this help\n",
5684 program_invocation_short_name);
5685
5686 return 0;
5687}
5688
45c0c61d
ZJS
5689static int help_types(void) {
5690 int i;
830f01f0 5691 const char *t;
45c0c61d
ZJS
5692
5693 puts("Available unit types:");
f168c273 5694 for (i = 0; i < _UNIT_TYPE_MAX; i++) {
830f01f0
LP
5695 t = unit_type_to_string(i);
5696 if (t)
5697 puts(t);
5698 }
45c0c61d 5699
45c0c61d
ZJS
5700 return 0;
5701}
5702
e4b61340 5703static int systemctl_parse_argv(int argc, char *argv[]) {
7e4249b9
LP
5704
5705 enum {
90d473a1 5706 ARG_FAIL = 0x100,
afba4199
ZJS
5707 ARG_REVERSE,
5708 ARG_AFTER,
5709 ARG_BEFORE,
991f2a39 5710 ARG_SHOW_TYPES,
23ade460 5711 ARG_IRREVERSIBLE,
e67c3609 5712 ARG_IGNORE_DEPENDENCIES,
35df8f27 5713 ARG_VERSION,
af2d49f7 5714 ARG_USER,
7e4249b9 5715 ARG_SYSTEM,
ee5762e3 5716 ARG_GLOBAL,
6e905d93 5717 ARG_NO_BLOCK,
ebed32bf 5718 ARG_NO_LEGEND,
611efaac 5719 ARG_NO_PAGER,
4445a875 5720 ARG_NO_WALL,
be394c48 5721 ARG_ROOT,
ee5762e3 5722 ARG_NO_RELOAD,
501fc174 5723 ARG_KILL_WHO,
30732560 5724 ARG_NO_ASK_PASSWORD,
729e3769 5725 ARG_FAILED,
df50185b 5726 ARG_RUNTIME,
5d0c05e5 5727 ARG_FORCE,
9b9b3d36 5728 ARG_PLAIN,
4dc5b821 5729 ARG_STATE,
d309c1c3
LP
5730 ARG_JOB_MODE,
5731 ARG_PRESET_MODE,
7e4249b9
LP
5732 };
5733
5734 static const struct option options[] = {
9ea9d4cf
LP
5735 { "help", no_argument, NULL, 'h' },
5736 { "version", no_argument, NULL, ARG_VERSION },
5737 { "type", required_argument, NULL, 't' },
5738 { "property", required_argument, NULL, 'p' },
5739 { "all", no_argument, NULL, 'a' },
5740 { "reverse", no_argument, NULL, ARG_REVERSE },
5741 { "after", no_argument, NULL, ARG_AFTER },
5742 { "before", no_argument, NULL, ARG_BEFORE },
5743 { "show-types", no_argument, NULL, ARG_SHOW_TYPES },
5744 { "failed", no_argument, NULL, ARG_FAILED }, /* compatibility only */
5745 { "full", no_argument, NULL, 'l' },
4dc5b821
LP
5746 { "job-mode", required_argument, NULL, ARG_JOB_MODE },
5747 { "fail", no_argument, NULL, ARG_FAIL }, /* compatibility only */
5748 { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, /* compatibility only */
5749 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */
9ea9d4cf
LP
5750 { "ignore-inhibitors", no_argument, NULL, 'i' },
5751 { "user", no_argument, NULL, ARG_USER },
5752 { "system", no_argument, NULL, ARG_SYSTEM },
5753 { "global", no_argument, NULL, ARG_GLOBAL },
5754 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
5755 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
5756 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
5757 { "no-wall", no_argument, NULL, ARG_NO_WALL },
5758 { "quiet", no_argument, NULL, 'q' },
5759 { "root", required_argument, NULL, ARG_ROOT },
5760 { "force", no_argument, NULL, ARG_FORCE },
5761 { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
5762 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
5763 { "signal", required_argument, NULL, 's' },
5764 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
5765 { "host", required_argument, NULL, 'H' },
f459b602 5766 { "machine", required_argument, NULL, 'M' },
9ea9d4cf
LP
5767 { "runtime", no_argument, NULL, ARG_RUNTIME },
5768 { "lines", required_argument, NULL, 'n' },
5769 { "output", required_argument, NULL, 'o' },
5770 { "plain", no_argument, NULL, ARG_PLAIN },
5771 { "state", required_argument, NULL, ARG_STATE },
1238ee09 5772 { "recursive", no_argument, NULL, 'r' },
d309c1c3 5773 { "preset-mode", required_argument, NULL, ARG_PRESET_MODE },
eb9da376 5774 {}
7e4249b9
LP
5775 };
5776
5777 int c;
5778
e4b61340 5779 assert(argc >= 0);
7e4249b9
LP
5780 assert(argv);
5781
1238ee09 5782 while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir", options, NULL)) >= 0) {
7e4249b9
LP
5783
5784 switch (c) {
5785
5786 case 'h':
eb9da376 5787 return systemctl_help();
35df8f27
LP
5788
5789 case ARG_VERSION:
5790 puts(PACKAGE_STRING);
7d568925 5791 puts(SYSTEMD_FEATURES);
35df8f27 5792 return 0;
7e4249b9 5793
20b3f379
ZJS
5794 case 't': {
5795 char *word, *state;
5796 size_t size;
45c0c61d 5797
20b3f379 5798 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
7fd1b19b 5799 _cleanup_free_ char *type;
20b3f379
ZJS
5800
5801 type = strndup(word, size);
5802 if (!type)
5803 return -ENOMEM;
5804
5805 if (streq(type, "help")) {
5806 help_types();
5807 return 0;
5808 }
5809
5810 if (unit_type_from_string(type) >= 0) {
5811 if (strv_push(&arg_types, type))
5812 return log_oom();
5813 type = NULL;
5814 continue;
5815 }
5816
9b9b3d36
MW
5817 /* It's much nicer to use --state= for
5818 * load states, but let's support this
5819 * in --types= too for compatibility
5820 * with old versions */
20b3f379 5821 if (unit_load_state_from_string(optarg) >= 0) {
9b9b3d36 5822 if (strv_push(&arg_states, type) < 0)
20b3f379
ZJS
5823 return log_oom();
5824 type = NULL;
5825 continue;
5826 }
5827
ab06eef8 5828 log_error("Unknown unit type or load state '%s'.", type);
20b3f379
ZJS
5829 log_info("Use -t help to see a list of allowed values.");
5830 return -EINVAL;
c147dc42 5831 }
20b3f379
ZJS
5832
5833 break;
5834 }
5835
ea4a240d 5836 case 'p': {
033a842c
ZJS
5837 /* Make sure that if the empty property list
5838 was specified, we won't show any properties. */
20b3f379 5839 if (isempty(optarg) && !arg_properties) {
cbc9fbd1 5840 arg_properties = new0(char*, 1);
20b3f379
ZJS
5841 if (!arg_properties)
5842 return log_oom();
5843 } else {
5844 char *word, *state;
5845 size_t size;
033a842c 5846
20b3f379
ZJS
5847 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
5848 char *prop;
033a842c 5849
20b3f379
ZJS
5850 prop = strndup(word, size);
5851 if (!prop)
5852 return log_oom();
ea4a240d 5853
6e18964d 5854 if (strv_consume(&arg_properties, prop) < 0)
20b3f379 5855 return log_oom();
20b3f379 5856 }
033a842c 5857 }
48220598
LP
5858
5859 /* If the user asked for a particular
5860 * property, show it to him, even if it is
5861 * empty. */
5862 arg_all = true;
033a842c 5863
48220598 5864 break;
ea4a240d 5865 }
48220598 5866
7e4249b9
LP
5867 case 'a':
5868 arg_all = true;
5869 break;
5870
afba4199
ZJS
5871 case ARG_REVERSE:
5872 arg_dependency = DEPENDENCY_REVERSE;
5873 break;
5874
5875 case ARG_AFTER:
5876 arg_dependency = DEPENDENCY_AFTER;
5877 break;
5878
5879 case ARG_BEFORE:
5880 arg_dependency = DEPENDENCY_BEFORE;
5881 break;
5882
991f2a39
ZJS
5883 case ARG_SHOW_TYPES:
5884 arg_show_types = true;
5885 break;
5886
4dc5b821
LP
5887 case ARG_JOB_MODE:
5888 arg_job_mode = optarg;
5889 break;
5890
90d473a1 5891 case ARG_FAIL:
e67c3609
LP
5892 arg_job_mode = "fail";
5893 break;
5894
23ade460
MS
5895 case ARG_IRREVERSIBLE:
5896 arg_job_mode = "replace-irreversibly";
5897 break;
5898
e67c3609
LP
5899 case ARG_IGNORE_DEPENDENCIES:
5900 arg_job_mode = "ignore-dependencies";
7e4249b9
LP
5901 break;
5902
af2d49f7 5903 case ARG_USER:
729e3769 5904 arg_scope = UNIT_FILE_USER;
7e4249b9
LP
5905 break;
5906
5907 case ARG_SYSTEM:
729e3769
LP
5908 arg_scope = UNIT_FILE_SYSTEM;
5909 break;
5910
5911 case ARG_GLOBAL:
5912 arg_scope = UNIT_FILE_GLOBAL;
7e4249b9
LP
5913 break;
5914
6e905d93
LP
5915 case ARG_NO_BLOCK:
5916 arg_no_block = true;
7e4249b9
LP
5917 break;
5918
ebed32bf
MS
5919 case ARG_NO_LEGEND:
5920 arg_no_legend = true;
5921 break;
5922
611efaac
LP
5923 case ARG_NO_PAGER:
5924 arg_no_pager = true;
5925 break;
0736af98 5926
514f4ef5
LP
5927 case ARG_NO_WALL:
5928 arg_no_wall = true;
5929 break;
5930
be394c48
FC
5931 case ARG_ROOT:
5932 arg_root = optarg;
5933 break;
5934
98a6e132 5935 case 'l':
8fe914ec
LP
5936 arg_full = true;
5937 break;
5938
30732560 5939 case ARG_FAILED:
9b9b3d36
MW
5940 if (strv_extend(&arg_states, "failed") < 0)
5941 return log_oom();
5942
30732560
LP
5943 break;
5944
0183528f
LP
5945 case 'q':
5946 arg_quiet = true;
5947 break;
5948
568b679f
LP
5949 case ARG_FORCE:
5950 arg_force ++;
5951 break;
5952
b4f27ccc 5953 case 'f':
e606bb61 5954 arg_force ++;
ee5762e3
LP
5955 break;
5956
5957 case ARG_NO_RELOAD:
5958 arg_no_reload = true;
5959 break;
5960
8a0867d6
LP
5961 case ARG_KILL_WHO:
5962 arg_kill_who = optarg;
5963 break;
5964
8a0867d6
LP
5965 case 's':
5966 if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
5967 log_error("Failed to parse signal string %s.", optarg);
5968 return -EINVAL;
5969 }
5970 break;
5971
501fc174
LP
5972 case ARG_NO_ASK_PASSWORD:
5973 arg_ask_password = false;
5974 break;
5975
f459b602
MAP
5976 case 'H':
5977 arg_transport = BUS_TRANSPORT_REMOTE;
5978 arg_host = optarg;
a8f11321
LP
5979 break;
5980
f459b602
MAP
5981 case 'M':
5982 arg_transport = BUS_TRANSPORT_CONTAINER;
5983 arg_host = optarg;
a8f11321
LP
5984 break;
5985
729e3769
LP
5986 case ARG_RUNTIME:
5987 arg_runtime = true;
5988 break;
5989
df50185b
LP
5990 case 'n':
5991 if (safe_atou(optarg, &arg_lines) < 0) {
5992 log_error("Failed to parse lines '%s'", optarg);
5993 return -EINVAL;
5994 }
5995 break;
5996
df50185b
LP
5997 case 'o':
5998 arg_output = output_mode_from_string(optarg);
5999 if (arg_output < 0) {
6000 log_error("Unknown output '%s'.", optarg);
6001 return -EINVAL;
6002 }
6003 break;
6004
b37844d3
LP
6005 case 'i':
6006 arg_ignore_inhibitors = true;
6007 break;
6008
5d0c05e5
LN
6009 case ARG_PLAIN:
6010 arg_plain = true;
6011 break;
6012
9b9b3d36
MW
6013 case ARG_STATE: {
6014 char *word, *state;
6015 size_t size;
6016
6017 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
6018 char *s;
6019
6020 s = strndup(word, size);
6021 if (!s)
6022 return log_oom();
6023
6e18964d 6024 if (strv_consume(&arg_states, s) < 0)
9b9b3d36 6025 return log_oom();
9b9b3d36
MW
6026 }
6027 break;
6028 }
6029
1238ee09
LP
6030 case 'r':
6031 if (geteuid() != 0) {
f1721625 6032 log_error("--recursive requires root privileges.");
1238ee09
LP
6033 return -EPERM;
6034 }
6035
6036 arg_recursive = true;
6037 break;
6038
d309c1c3
LP
6039 case ARG_PRESET_MODE:
6040
6041 arg_preset_mode = unit_file_preset_mode_from_string(optarg);
6042 if (arg_preset_mode < 0) {
6043 log_error("Failed to parse preset mode: %s.", optarg);
6044 return -EINVAL;
6045 }
6046
6047 break;
6048
7e4249b9
LP
6049 case '?':
6050 return -EINVAL;
6051
6052 default:
eb9da376 6053 assert_not_reached("Unhandled option");
7e4249b9
LP
6054 }
6055 }
6056
f459b602 6057 if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM) {
a8f11321
LP
6058 log_error("Cannot access user instance remotely.");
6059 return -EINVAL;
6060 }
6061
7e4249b9
LP
6062 return 1;
6063}
6064
e4b61340
LP
6065static int halt_parse_argv(int argc, char *argv[]) {
6066
6067 enum {
6068 ARG_HELP = 0x100,
6069 ARG_HALT,
514f4ef5
LP
6070 ARG_REBOOT,
6071 ARG_NO_WALL
e4b61340
LP
6072 };
6073
6074 static const struct option options[] = {
6075 { "help", no_argument, NULL, ARG_HELP },
6076 { "halt", no_argument, NULL, ARG_HALT },
6077 { "poweroff", no_argument, NULL, 'p' },
6078 { "reboot", no_argument, NULL, ARG_REBOOT },
6079 { "force", no_argument, NULL, 'f' },
6080 { "wtmp-only", no_argument, NULL, 'w' },
6081 { "no-wtmp", no_argument, NULL, 'd' },
514f4ef5 6082 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 6083 {}
e4b61340
LP
6084 };
6085
37185ec8 6086 int c, r, runlevel;
e4b61340
LP
6087
6088 assert(argc >= 0);
6089 assert(argv);
6090
6091 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
6092 if (runlevel == '0' || runlevel == '6')
65491fd8 6093 arg_force = 2;
e4b61340
LP
6094
6095 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
6096 switch (c) {
6097
6098 case ARG_HELP:
eb9da376 6099 return halt_help();
e4b61340
LP
6100
6101 case ARG_HALT:
6102 arg_action = ACTION_HALT;
6103 break;
6104
6105 case 'p':
a042efad
MS
6106 if (arg_action != ACTION_REBOOT)
6107 arg_action = ACTION_POWEROFF;
e4b61340
LP
6108 break;
6109
6110 case ARG_REBOOT:
6111 arg_action = ACTION_REBOOT;
6112 break;
6113
6114 case 'f':
65491fd8 6115 arg_force = 2;
e4b61340
LP
6116 break;
6117
6118 case 'w':
6119 arg_dry = true;
6120 break;
6121
6122 case 'd':
6123 arg_no_wtmp = true;
6124 break;
6125
514f4ef5
LP
6126 case ARG_NO_WALL:
6127 arg_no_wall = true;
6128 break;
6129
e4b61340
LP
6130 case 'i':
6131 case 'h':
57371e58 6132 case 'n':
e4b61340
LP
6133 /* Compatibility nops */
6134 break;
6135
6136 case '?':
6137 return -EINVAL;
6138
6139 default:
eb9da376 6140 assert_not_reached("Unhandled option");
e4b61340
LP
6141 }
6142 }
6143
c5220a94
MO
6144 if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
6145 r = update_reboot_param_file(argc == optind + 1 ? argv[optind] : NULL);
6146 if (r < 0)
37185ec8 6147 return r;
37185ec8 6148 } else if (optind < argc) {
e4b61340
LP
6149 log_error("Too many arguments.");
6150 return -EINVAL;
6151 }
6152
6153 return 1;
6154}
6155
f6144808
LP
6156static int parse_time_spec(const char *t, usec_t *_u) {
6157 assert(t);
6158 assert(_u);
6159
6160 if (streq(t, "now"))
6161 *_u = 0;
1a639877 6162 else if (!strchr(t, ':')) {
f6144808
LP
6163 uint64_t u;
6164
1a639877 6165 if (safe_atou64(t, &u) < 0)
f6144808
LP
6166 return -EINVAL;
6167
6168 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
6169 } else {
6170 char *e = NULL;
6171 long hour, minute;
b92bea5d 6172 struct tm tm = {};
f6144808
LP
6173 time_t s;
6174 usec_t n;
6175
6176 errno = 0;
6177 hour = strtol(t, &e, 10);
8333c77e 6178 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
f6144808
LP
6179 return -EINVAL;
6180
6181 minute = strtol(e+1, &e, 10);
8333c77e 6182 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
f6144808
LP
6183 return -EINVAL;
6184
6185 n = now(CLOCK_REALTIME);
08e4b1c5
LP
6186 s = (time_t) (n / USEC_PER_SEC);
6187
f6144808
LP
6188 assert_se(localtime_r(&s, &tm));
6189
6190 tm.tm_hour = (int) hour;
6191 tm.tm_min = (int) minute;
08e4b1c5 6192 tm.tm_sec = 0;
f6144808
LP
6193
6194 assert_se(s = mktime(&tm));
6195
6196 *_u = (usec_t) s * USEC_PER_SEC;
6197
6198 while (*_u <= n)
6199 *_u += USEC_PER_DAY;
6200 }
6201
6202 return 0;
6203}
6204
e4b61340
LP
6205static int shutdown_parse_argv(int argc, char *argv[]) {
6206
6207 enum {
6208 ARG_HELP = 0x100,
514f4ef5 6209 ARG_NO_WALL
e4b61340
LP
6210 };
6211
6212 static const struct option options[] = {
6213 { "help", no_argument, NULL, ARG_HELP },
6214 { "halt", no_argument, NULL, 'H' },
6215 { "poweroff", no_argument, NULL, 'P' },
6216 { "reboot", no_argument, NULL, 'r' },
04ebb595 6217 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
514f4ef5 6218 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 6219 {}
e4b61340
LP
6220 };
6221
f6144808 6222 int c, r;
e4b61340
LP
6223
6224 assert(argc >= 0);
6225 assert(argv);
6226
f6144808 6227 while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
e4b61340
LP
6228 switch (c) {
6229
6230 case ARG_HELP:
eb9da376 6231 return shutdown_help();
e4b61340
LP
6232
6233 case 'H':
6234 arg_action = ACTION_HALT;
6235 break;
6236
6237 case 'P':
6238 arg_action = ACTION_POWEROFF;
6239 break;
6240
6241 case 'r':
5622dde3
KS
6242 if (kexec_loaded())
6243 arg_action = ACTION_KEXEC;
6244 else
6245 arg_action = ACTION_REBOOT;
e4b61340
LP
6246 break;
6247
04ebb595
LP
6248 case 'K':
6249 arg_action = ACTION_KEXEC;
6250 break;
6251
e4b61340
LP
6252 case 'h':
6253 if (arg_action != ACTION_HALT)
6254 arg_action = ACTION_POWEROFF;
6255 break;
6256
6257 case 'k':
6258 arg_dry = true;
6259 break;
6260
514f4ef5
LP
6261 case ARG_NO_WALL:
6262 arg_no_wall = true;
6263 break;
6264
e4b61340
LP
6265 case 't':
6266 case 'a':
6267 /* Compatibility nops */
6268 break;
6269
f6144808
LP
6270 case 'c':
6271 arg_action = ACTION_CANCEL_SHUTDOWN;
6272 break;
6273
e4b61340
LP
6274 case '?':
6275 return -EINVAL;
6276
6277 default:
eb9da376 6278 assert_not_reached("Unhandled option");
e4b61340
LP
6279 }
6280 }
6281
dfcc5c33 6282 if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
7e59bfcb
LP
6283 r = parse_time_spec(argv[optind], &arg_when);
6284 if (r < 0) {
f6144808
LP
6285 log_error("Failed to parse time specification: %s", argv[optind]);
6286 return r;
6287 }
6b5ad000 6288 } else
08e4b1c5 6289 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
442b9094 6290
dfcc5c33
MS
6291 if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
6292 /* No time argument for shutdown cancel */
6293 arg_wall = argv + optind;
6294 else if (argc > optind + 1)
6295 /* We skip the time argument */
e4b61340
LP
6296 arg_wall = argv + optind + 1;
6297
6298 optind = argc;
6299
6300 return 1;
e4b61340
LP
6301}
6302
6303static int telinit_parse_argv(int argc, char *argv[]) {
6304
6305 enum {
6306 ARG_HELP = 0x100,
514f4ef5 6307 ARG_NO_WALL
e4b61340
LP
6308 };
6309
6310 static const struct option options[] = {
6311 { "help", no_argument, NULL, ARG_HELP },
514f4ef5 6312 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 6313 {}
e4b61340
LP
6314 };
6315
6316 static const struct {
6317 char from;
6318 enum action to;
6319 } table[] = {
6320 { '0', ACTION_POWEROFF },
6321 { '6', ACTION_REBOOT },
ef2f1067 6322 { '1', ACTION_RESCUE },
e4b61340
LP
6323 { '2', ACTION_RUNLEVEL2 },
6324 { '3', ACTION_RUNLEVEL3 },
6325 { '4', ACTION_RUNLEVEL4 },
6326 { '5', ACTION_RUNLEVEL5 },
6327 { 's', ACTION_RESCUE },
6328 { 'S', ACTION_RESCUE },
6329 { 'q', ACTION_RELOAD },
6330 { 'Q', ACTION_RELOAD },
6331 { 'u', ACTION_REEXEC },
6332 { 'U', ACTION_REEXEC }
6333 };
6334
6335 unsigned i;
6336 int c;
6337
6338 assert(argc >= 0);
6339 assert(argv);
6340
6341 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
6342 switch (c) {
6343
6344 case ARG_HELP:
eb9da376 6345 return telinit_help();
e4b61340 6346
514f4ef5
LP
6347 case ARG_NO_WALL:
6348 arg_no_wall = true;
6349 break;
6350
e4b61340
LP
6351 case '?':
6352 return -EINVAL;
6353
6354 default:
eb9da376 6355 assert_not_reached("Unhandled option");
e4b61340
LP
6356 }
6357 }
6358
6359 if (optind >= argc) {
2f02ce40 6360 telinit_help();
e4b61340
LP
6361 return -EINVAL;
6362 }
6363
6364 if (optind + 1 < argc) {
6365 log_error("Too many arguments.");
6366 return -EINVAL;
6367 }
6368
6369 if (strlen(argv[optind]) != 1) {
6370 log_error("Expected single character argument.");
6371 return -EINVAL;
6372 }
6373
6374 for (i = 0; i < ELEMENTSOF(table); i++)
6375 if (table[i].from == argv[optind][0])
6376 break;
6377
6378 if (i >= ELEMENTSOF(table)) {
b0193f1c 6379 log_error("Unknown command '%s'.", argv[optind]);
e4b61340
LP
6380 return -EINVAL;
6381 }
6382
6383 arg_action = table[i].to;
6384
6385 optind ++;
6386
6387 return 1;
6388}
6389
6390static int runlevel_parse_argv(int argc, char *argv[]) {
6391
6392 enum {
6393 ARG_HELP = 0x100,
6394 };
6395
6396 static const struct option options[] = {
6397 { "help", no_argument, NULL, ARG_HELP },
eb9da376 6398 {}
e4b61340
LP
6399 };
6400
6401 int c;
6402
6403 assert(argc >= 0);
6404 assert(argv);
6405
6406 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
6407 switch (c) {
6408
6409 case ARG_HELP:
eb9da376 6410 return runlevel_help();
e4b61340
LP
6411
6412 case '?':
6413 return -EINVAL;
6414
6415 default:
eb9da376 6416 assert_not_reached("Unhandled option");
e4b61340
LP
6417 }
6418 }
6419
6420 if (optind < argc) {
6421 log_error("Too many arguments.");
6422 return -EINVAL;
6423 }
6424
6425 return 1;
6426}
6427
6428static int parse_argv(int argc, char *argv[]) {
6429 assert(argc >= 0);
6430 assert(argv);
6431
6432 if (program_invocation_short_name) {
6433
6434 if (strstr(program_invocation_short_name, "halt")) {
6435 arg_action = ACTION_HALT;
6436 return halt_parse_argv(argc, argv);
6437 } else if (strstr(program_invocation_short_name, "poweroff")) {
6438 arg_action = ACTION_POWEROFF;
6439 return halt_parse_argv(argc, argv);
6440 } else if (strstr(program_invocation_short_name, "reboot")) {
5622dde3
KS
6441 if (kexec_loaded())
6442 arg_action = ACTION_KEXEC;
6443 else
6444 arg_action = ACTION_REBOOT;
e4b61340
LP
6445 return halt_parse_argv(argc, argv);
6446 } else if (strstr(program_invocation_short_name, "shutdown")) {
6447 arg_action = ACTION_POWEROFF;
6448 return shutdown_parse_argv(argc, argv);
6449 } else if (strstr(program_invocation_short_name, "init")) {
d5ca5f11
LP
6450
6451 if (sd_booted() > 0) {
f459b602 6452 arg_action = _ACTION_INVALID;
d5ca5f11
LP
6453 return telinit_parse_argv(argc, argv);
6454 } else {
6455 /* Hmm, so some other init system is
6456 * running, we need to forward this
6457 * request to it. For now we simply
6458 * guess that it is Upstart. */
6459
4ad61fd1 6460 execv(TELINIT, argv);
d5ca5f11
LP
6461
6462 log_error("Couldn't find an alternative telinit implementation to spawn.");
6463 return -EIO;
6464 }
6465
e4b61340
LP
6466 } else if (strstr(program_invocation_short_name, "runlevel")) {
6467 arg_action = ACTION_RUNLEVEL;
6468 return runlevel_parse_argv(argc, argv);
6469 }
6470 }
6471
6472 arg_action = ACTION_SYSTEMCTL;
6473 return systemctl_parse_argv(argc, argv);
6474}
6475
44a6b1b6 6476_pure_ static int action_to_runlevel(void) {
eb22ac37
LP
6477
6478 static const char table[_ACTION_MAX] = {
6479 [ACTION_HALT] = '0',
6480 [ACTION_POWEROFF] = '0',
6481 [ACTION_REBOOT] = '6',
6482 [ACTION_RUNLEVEL2] = '2',
6483 [ACTION_RUNLEVEL3] = '3',
6484 [ACTION_RUNLEVEL4] = '4',
6485 [ACTION_RUNLEVEL5] = '5',
6486 [ACTION_RESCUE] = '1'
6487 };
6488
d55ae9e6
LP
6489 assert(arg_action < _ACTION_MAX);
6490
6491 return table[arg_action];
6492}
6493
d55ae9e6 6494static int talk_initctl(void) {
cbc9fbd1
LP
6495
6496 struct init_request request = {
6497 .magic = INIT_MAGIC,
6498 .sleeptime = 0,
6499 .cmd = INIT_CMD_RUNLVL
6500 };
6501
7fd1b19b 6502 _cleanup_close_ int fd = -1;
d55ae9e6 6503 char rl;
cbc9fbd1 6504 int r;
eb22ac37 6505
427b47c4
ZJS
6506 rl = action_to_runlevel();
6507 if (!rl)
eb22ac37
LP
6508 return 0;
6509
d55ae9e6
LP
6510 request.runlevel = rl;
6511
427b47c4
ZJS
6512 fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
6513 if (fd < 0) {
d55ae9e6
LP
6514 if (errno == ENOENT)
6515 return 0;
eb22ac37 6516
d55ae9e6 6517 log_error("Failed to open "INIT_FIFO": %m");
eb22ac37 6518 return -errno;
d55ae9e6 6519 }
eb22ac37 6520
d55ae9e6 6521 errno = 0;
eb22ac37 6522 r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
427b47c4 6523 if (r) {
d55ae9e6 6524 log_error("Failed to write to "INIT_FIFO": %m");
bcb161b0 6525 return errno > 0 ? -errno : -EIO;
d55ae9e6 6526 }
eb22ac37
LP
6527
6528 return 1;
e4b61340
LP
6529}
6530
41dd15e4 6531static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
7e4249b9 6532
7e4249b9
LP
6533 static const struct {
6534 const char* verb;
6535 const enum {
6536 MORE,
6537 LESS,
6538 EQUAL
6539 } argc_cmp;
6540 const int argc;
f459b602 6541 int (* const dispatch)(sd_bus *bus, char **args);
d08e75ed
ZJS
6542 const enum {
6543 NOBUS = 1,
6544 FORCE,
6545 } bus;
7e4249b9 6546 } verbs[] = {
d8fba7c6 6547 { "list-units", MORE, 0, list_units },
d08e75ed 6548 { "list-unit-files", MORE, 1, list_unit_files, NOBUS },
d8fba7c6
ZJS
6549 { "list-sockets", MORE, 1, list_sockets },
6550 { "list-timers", MORE, 1, list_timers },
6551 { "list-jobs", MORE, 1, list_jobs },
0d292f5e 6552 { "list-machines", MORE, 1, list_machines },
ee5762e3 6553 { "clear-jobs", EQUAL, 1, daemon_reload },
ee5762e3
LP
6554 { "cancel", MORE, 2, cancel_job },
6555 { "start", MORE, 2, start_unit },
6556 { "stop", MORE, 2, start_unit },
a76f7be2 6557 { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
6558 { "reload", MORE, 2, start_unit },
6559 { "restart", MORE, 2, start_unit },
6560 { "try-restart", MORE, 2, start_unit },
6561 { "reload-or-restart", MORE, 2, start_unit },
6562 { "reload-or-try-restart", MORE, 2, start_unit },
6563 { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */
64e5f1b7 6564 { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
6565 { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
6566 { "isolate", EQUAL, 2, start_unit },
8a0867d6 6567 { "kill", MORE, 2, kill_unit },
1a0fce45
TA
6568 { "is-active", MORE, 2, check_unit_active },
6569 { "check", MORE, 2, check_unit_active },
6570 { "is-failed", MORE, 2, check_unit_failed },
ee5762e3 6571 { "show", MORE, 1, show },
e93c33d4 6572 { "cat", MORE, 2, cat },
265a7a2a 6573 { "status", MORE, 1, show },
b43f208f 6574 { "help", MORE, 2, show },
ee5762e3
LP
6575 { "snapshot", LESS, 2, snapshot },
6576 { "delete", MORE, 2, delete_snapshot },
6577 { "daemon-reload", EQUAL, 1, daemon_reload },
6578 { "daemon-reexec", EQUAL, 1, daemon_reload },
f459b602 6579 { "show-environment", EQUAL, 1, show_environment },
ee5762e3
LP
6580 { "set-environment", MORE, 2, set_environment },
6581 { "unset-environment", MORE, 2, set_environment },
ac3efa8a 6582 { "import-environment", MORE, 1, import_environment},
d08e75ed
ZJS
6583 { "halt", EQUAL, 1, start_special, FORCE },
6584 { "poweroff", EQUAL, 1, start_special, FORCE },
6585 { "reboot", EQUAL, 1, start_special, FORCE },
20b09ca7 6586 { "kexec", EQUAL, 1, start_special },
6edd7d0a
LP
6587 { "suspend", EQUAL, 1, start_special },
6588 { "hibernate", EQUAL, 1, start_special },
6524990f 6589 { "hybrid-sleep", EQUAL, 1, start_special },
ee5762e3
LP
6590 { "default", EQUAL, 1, start_special },
6591 { "rescue", EQUAL, 1, start_special },
6592 { "emergency", EQUAL, 1, start_special },
20b09ca7 6593 { "exit", EQUAL, 1, start_special },
fdf20a31 6594 { "reset-failed", MORE, 1, reset_failed },
d08e75ed
ZJS
6595 { "enable", MORE, 2, enable_unit, NOBUS },
6596 { "disable", MORE, 2, enable_unit, NOBUS },
6597 { "is-enabled", MORE, 2, unit_is_enabled, NOBUS },
6598 { "reenable", MORE, 2, enable_unit, NOBUS },
6599 { "preset", MORE, 2, enable_unit, NOBUS },
d309c1c3 6600 { "preset-all", EQUAL, 1, preset_all, NOBUS },
d08e75ed
ZJS
6601 { "mask", MORE, 2, enable_unit, NOBUS },
6602 { "unmask", MORE, 2, enable_unit, NOBUS },
6603 { "link", MORE, 2, enable_unit, NOBUS },
957eb8ca 6604 { "switch-root", MORE, 2, switch_root },
e31165b2 6605 { "list-dependencies", LESS, 2, list_dependencies },
d08e75ed
ZJS
6606 { "set-default", EQUAL, 2, set_default, NOBUS },
6607 { "get-default", EQUAL, 1, get_default, NOBUS },
8e2af478 6608 { "set-property", MORE, 3, set_property },
99813a19 6609 { "is-system-running", EQUAL, 1, is_system_running },
d08e75ed
ZJS
6610 {}
6611 }, *verb = verbs;
7e4249b9 6612
e4b61340 6613 int left;
7e4249b9 6614
e4b61340
LP
6615 assert(argc >= 0);
6616 assert(argv);
7e4249b9
LP
6617
6618 left = argc - optind;
6619
d08e75ed
ZJS
6620 /* Special rule: no arguments (left == 0) means "list-units" */
6621 if (left > 0) {
b43f208f
KS
6622 if (streq(argv[optind], "help") && !argv[optind+1]) {
6623 log_error("This command expects one or more "
6624 "unit names. Did you mean --help?");
6625 return -EINVAL;
0183528f
LP
6626 }
6627
d08e75ed
ZJS
6628 for (; verb->verb; verb++)
6629 if (streq(argv[optind], verb->verb))
6630 goto found;
7e4249b9 6631
d08e75ed
ZJS
6632 log_error("Unknown operation '%s'.", argv[optind]);
6633 return -EINVAL;
7e4249b9 6634 }
d08e75ed 6635found:
7e4249b9 6636
d08e75ed 6637 switch (verb->argc_cmp) {
7e4249b9
LP
6638
6639 case EQUAL:
d08e75ed 6640 if (left != verb->argc) {
7e4249b9 6641 log_error("Invalid number of arguments.");
e4b61340 6642 return -EINVAL;
7e4249b9
LP
6643 }
6644
6645 break;
6646
6647 case MORE:
d08e75ed 6648 if (left < verb->argc) {
7e4249b9 6649 log_error("Too few arguments.");
e4b61340 6650 return -EINVAL;
7e4249b9
LP
6651 }
6652
6653 break;
6654
6655 case LESS:
d08e75ed 6656 if (left > verb->argc) {
7e4249b9 6657 log_error("Too many arguments.");
e4b61340 6658 return -EINVAL;
7e4249b9
LP
6659 }
6660
6661 break;
6662
6663 default:
6664 assert_not_reached("Unknown comparison operator.");
6665 }
6666
ee5762e3
LP
6667 /* Require a bus connection for all operations but
6668 * enable/disable */
d08e75ed
ZJS
6669 if (verb->bus == NOBUS) {
6670 if (!bus && !avoid_bus()) {
6671 log_error("Failed to get D-Bus connection: %s", strerror(-bus_error));
6672 return -EIO;
6673 }
82e23ddd 6674
d08e75ed 6675 } else {
82e23ddd
LP
6676 if (running_in_chroot() > 0) {
6677 log_info("Running in chroot, ignoring request.");
6678 return 0;
6679 }
6680
d08e75ed
ZJS
6681 if ((verb->bus != FORCE || arg_force <= 0) && !bus) {
6682 log_error("Failed to get D-Bus connection: %s", strerror(-bus_error));
82e23ddd
LP
6683 return -EIO;
6684 }
ee5762e3
LP
6685 }
6686
d08e75ed 6687 return verb->dispatch(bus, argv + optind);
e4b61340
LP
6688}
6689
52c00215 6690static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
cbc9fbd1 6691
b92bea5d
ZJS
6692 struct sd_shutdown_command c = {
6693 .usec = t,
6694 .mode = mode,
6695 .dry_run = dry_run,
6696 .warn_wall = warn,
6697 };
cbc9fbd1 6698
b92bea5d
ZJS
6699 union sockaddr_union sockaddr = {
6700 .un.sun_family = AF_UNIX,
6701 .un.sun_path = "/run/systemd/shutdownd",
6702 };
cbc9fbd1
LP
6703
6704 struct iovec iovec[2] = {{
6705 .iov_base = (char*) &c,
b92bea5d 6706 .iov_len = offsetof(struct sd_shutdown_command, wall_message),
cbc9fbd1
LP
6707 }};
6708
b92bea5d
ZJS
6709 struct msghdr msghdr = {
6710 .msg_name = &sockaddr,
6711 .msg_namelen = offsetof(struct sockaddr_un, sun_path)
f8294e41 6712 + strlen("/run/systemd/shutdownd"),
b92bea5d
ZJS
6713 .msg_iov = iovec,
6714 .msg_iovlen = 1,
6715 };
04ebb595 6716
cbc9fbd1
LP
6717 _cleanup_close_ int fd;
6718
04ebb595
LP
6719 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
6720 if (fd < 0)
6721 return -errno;
f6144808 6722
b92bea5d 6723 if (!isempty(message)) {
04ebb595
LP
6724 iovec[1].iov_base = (char*) message;
6725 iovec[1].iov_len = strlen(message);
b92bea5d 6726 msghdr.msg_iovlen++;
04ebb595 6727 }
f6144808 6728
cec7eda5 6729 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
f6144808 6730 return -errno;
f6144808 6731
f6144808
LP
6732 return 0;
6733}
6734
f459b602 6735static int reload_with_fallback(sd_bus *bus) {
e4b61340
LP
6736
6737 if (bus) {
6738 /* First, try systemd via D-Bus. */
d76702a7 6739 if (daemon_reload(bus, NULL) >= 0)
e4b61340
LP
6740 return 0;
6741 }
6742
6743 /* Nothing else worked, so let's try signals */
6744 assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
6745
6746 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
6747 log_error("kill() failed: %m");
6748 return -errno;
6749 }
6750
6751 return 0;
6752}
6753
f459b602 6754static int start_with_fallback(sd_bus *bus) {
e4b61340
LP
6755
6756 if (bus) {
6757 /* First, try systemd via D-Bus. */
729e3769 6758 if (start_unit(bus, NULL) >= 0)
983d9c90 6759 goto done;
e4b61340
LP
6760 }
6761
6762 /* Nothing else worked, so let's try
6763 * /dev/initctl */
fbc43921 6764 if (talk_initctl() > 0)
983d9c90 6765 goto done;
d55ae9e6
LP
6766
6767 log_error("Failed to talk to init daemon.");
6768 return -EIO;
983d9c90
LP
6769
6770done:
6771 warn_wall(arg_action);
6772 return 0;
e4b61340
LP
6773}
6774
477def80 6775static int halt_now(enum action a) {
e606bb61 6776
477def80 6777/* Make sure C-A-D is handled by the kernel from this
e606bb61
LP
6778 * point on... */
6779 reboot(RB_ENABLE_CAD);
6780
4c80c73c 6781 switch (a) {
e606bb61
LP
6782
6783 case ACTION_HALT:
6784 log_info("Halting.");
6785 reboot(RB_HALT_SYSTEM);
477def80 6786 return -errno;
e606bb61
LP
6787
6788 case ACTION_POWEROFF:
6789 log_info("Powering off.");
6790 reboot(RB_POWER_OFF);
477def80 6791 return -errno;
e606bb61 6792
477def80
LP
6793 case ACTION_REBOOT: {
6794 _cleanup_free_ char *param = NULL;
cbc9fbd1 6795
477def80
LP
6796 if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
6797 log_info("Rebooting with argument '%s'.", param);
37185ec8
WC
6798 syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
6799 LINUX_REBOOT_CMD_RESTART2, param);
37185ec8 6800 }
e606bb61 6801
477def80
LP
6802 log_info("Rebooting.");
6803 reboot(RB_AUTOBOOT);
6804 return -errno;
e606bb61
LP
6805 }
6806
477def80
LP
6807 default:
6808 assert_not_reached("Unknown action.");
6809 }
e606bb61
LP
6810}
6811
f459b602 6812static int halt_main(sd_bus *bus) {
e4b61340
LP
6813 int r;
6814
748ebafa
LP
6815 r = check_inhibitors(bus, arg_action);
6816 if (r < 0)
6817 return r;
b37844d3 6818
bc8c2f5c 6819 if (geteuid() != 0) {
7e59bfcb
LP
6820 /* Try logind if we are a normal user and no special
6821 * mode applies. Maybe PolicyKit allows us to shutdown
6822 * the machine. */
6823
6824 if (arg_when <= 0 &&
6825 !arg_dry &&
b37844d3 6826 arg_force <= 0 &&
7e59bfcb
LP
6827 (arg_action == ACTION_POWEROFF ||
6828 arg_action == ACTION_REBOOT)) {
4c80c73c
KS
6829 r = reboot_with_logind(bus, arg_action);
6830 if (r >= 0)
6831 return r;
6832 }
6833
cc8a7a61 6834 log_error("Must be root.");
bc8c2f5c
LP
6835 return -EPERM;
6836 }
6837
f6144808 6838 if (arg_when > 0) {
7fd1b19b 6839 _cleanup_free_ char *m;
9be9828c
LP
6840
6841 m = strv_join(arg_wall, " ");
cbc9fbd1
LP
6842 if (!m)
6843 return log_oom();
6844
9be9828c
LP
6845 r = send_shutdownd(arg_when,
6846 arg_action == ACTION_HALT ? 'H' :
6847 arg_action == ACTION_POWEROFF ? 'P' :
04ebb595 6848 arg_action == ACTION_KEXEC ? 'K' :
9be9828c 6849 'r',
52c00215 6850 arg_dry,
9be9828c
LP
6851 !arg_no_wall,
6852 m);
9be9828c
LP
6853
6854 if (r < 0)
f6144808 6855 log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
08e4b1c5 6856 else {
7e59bfcb
LP
6857 char date[FORMAT_TIMESTAMP_MAX];
6858
08e4b1c5
LP
6859 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
6860 format_timestamp(date, sizeof(date), arg_when));
f6144808 6861 return 0;
08e4b1c5 6862 }
f6144808
LP
6863 }
6864
65491fd8 6865 if (!arg_dry && !arg_force)
e4b61340
LP
6866 return start_with_fallback(bus);
6867
d90e1a30
LP
6868 if (!arg_no_wtmp) {
6869 if (sd_booted() > 0)
6870 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
7e59bfcb
LP
6871 else {
6872 r = utmp_put_shutdown();
6873 if (r < 0)
6874 log_warning("Failed to write utmp record: %s", strerror(-r));
6875 }
d90e1a30 6876 }
e4b61340 6877
e4b61340
LP
6878 if (arg_dry)
6879 return 0;
6880
477def80
LP
6881 r = halt_now(arg_action);
6882 log_error("Failed to reboot: %s", strerror(-r));
6883
6884 return r;
e4b61340
LP
6885}
6886
6887static int runlevel_main(void) {
6888 int r, runlevel, previous;
6889
729e3769
LP
6890 r = utmp_get_runlevel(&runlevel, &previous);
6891 if (r < 0) {
6892 puts("unknown");
e4b61340
LP
6893 return r;
6894 }
6895
6896 printf("%c %c\n",
6897 previous <= 0 ? 'N' : previous,
6898 runlevel <= 0 ? 'N' : runlevel);
6899
6900 return 0;
6901}
6902
6903int main(int argc, char*argv[]) {
f459b602
MAP
6904 _cleanup_bus_unref_ sd_bus *bus = NULL;
6905 int r;
e4b61340 6906
a9cdc94f 6907 setlocale(LC_ALL, "");
e4b61340 6908 log_parse_environment();
2396fb04 6909 log_open();
e4b61340 6910
184ecaf7
DR
6911 /* Explicitly not on_tty() to avoid setting cached value.
6912 * This becomes relevant for piping output which might be
6913 * ellipsized. */
6914 original_stdout_is_tty = isatty(STDOUT_FILENO);
6915
04ebb595 6916 r = parse_argv(argc, argv);
f459b602 6917 if (r <= 0)
e4b61340 6918 goto finish;
7e4249b9 6919
e4b61340
LP
6920 /* /sbin/runlevel doesn't need to communicate via D-Bus, so
6921 * let's shortcut this */
6922 if (arg_action == ACTION_RUNLEVEL) {
22f4096c 6923 r = runlevel_main();
e4b61340
LP
6924 goto finish;
6925 }
6926
82e23ddd
LP
6927 if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
6928 log_info("Running in chroot, ignoring request.");
f459b602 6929 r = 0;
82e23ddd
LP
6930 goto finish;
6931 }
6932
41dd15e4
LP
6933 if (!avoid_bus())
6934 r = bus_open_transport_systemd(arg_transport, arg_host, arg_scope != UNIT_FILE_SYSTEM, &bus);
6935
6936 /* systemctl_main() will print an error message for the bus
6937 * connection, but only if it needs to */
e4b61340
LP
6938
6939 switch (arg_action) {
6940
22f4096c 6941 case ACTION_SYSTEMCTL:
f459b602 6942 r = systemctl_main(bus, argc, argv, r);
e4b61340 6943 break;
e4b61340
LP
6944
6945 case ACTION_HALT:
6946 case ACTION_POWEROFF:
6947 case ACTION_REBOOT:
5622dde3 6948 case ACTION_KEXEC:
22f4096c 6949 r = halt_main(bus);
e4b61340
LP
6950 break;
6951
e4b61340
LP
6952 case ACTION_RUNLEVEL2:
6953 case ACTION_RUNLEVEL3:
6954 case ACTION_RUNLEVEL4:
6955 case ACTION_RUNLEVEL5:
6956 case ACTION_RESCUE:
514f4ef5 6957 case ACTION_EMERGENCY:
eb22ac37 6958 case ACTION_DEFAULT:
22f4096c 6959 r = start_with_fallback(bus);
e4b61340 6960 break;
7e4249b9 6961
e4b61340
LP
6962 case ACTION_RELOAD:
6963 case ACTION_REEXEC:
22f4096c 6964 r = reload_with_fallback(bus);
e4b61340
LP
6965 break;
6966
dfcc5c33 6967 case ACTION_CANCEL_SHUTDOWN: {
f459b602 6968 _cleanup_free_ char *m = NULL;
dfcc5c33
MS
6969
6970 if (arg_wall) {
6971 m = strv_join(arg_wall, " ");
6972 if (!m) {
f459b602 6973 r = log_oom();
dfcc5c33
MS
6974 goto finish;
6975 }
6976 }
f459b602 6977
dfcc5c33
MS
6978 r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
6979 if (r < 0)
6980 log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
f6144808 6981 break;
dfcc5c33 6982 }
f6144808 6983
eb22ac37 6984 case ACTION_RUNLEVEL:
f459b602 6985 case _ACTION_INVALID:
e4b61340
LP
6986 default:
6987 assert_not_reached("Unknown action");
6988 }
7e4249b9
LP
6989
6990finish:
f459b602
MAP
6991 pager_close();
6992 ask_password_agent_close();
6993 polkit_agent_close();
7e4249b9 6994
20b3f379 6995 strv_free(arg_types);
9b9b3d36 6996 strv_free(arg_states);
20b3f379 6997 strv_free(arg_properties);
ea4a240d 6998
f459b602 6999 return r < 0 ? EXIT_FAILURE : r;
7e4249b9 7000}