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