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