]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl.c
util: be a bit safer in path_is_safe()
[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;
55c0b89c
LN
1639
1640 assert(bus);
55c0b89c 1641
e31165b2 1642 if (args[1]) {
f78e6385 1643 unit = unit_name_mangle(args[1], MANGLE_NOGLOB);
e31165b2
LP
1644 if (!unit)
1645 return log_oom();
1646 u = unit;
1647 } else
1648 u = SPECIAL_DEFAULT_TARGET;
55c0b89c
LN
1649
1650 pager_open_if_enabled();
e31165b2
LP
1651
1652 puts(u);
1653
5d0c05e5 1654 return list_dependencies_one(bus, u, 0, &units, 0);
55c0b89c
LN
1655}
1656
0d292f5e
LP
1657struct machine_info {
1658 bool is_host;
1659 char *name;
0d292f5e 1660 char *state;
8fcf784d
LP
1661 char *control_group;
1662 uint32_t n_failed_units;
1663 uint32_t n_jobs;
1664 usec_t timestamp;
1665};
1666
1667static const struct bus_properties_map machine_info_property_map[] = {
1668 { "SystemState", "s", NULL, offsetof(struct machine_info, state) },
1669 { "NJobs", "u", NULL, offsetof(struct machine_info, n_jobs) },
1670 { "NFailedUnits", "u", NULL, offsetof(struct machine_info, n_failed_units) },
1671 { "ControlGroup", "s", NULL, offsetof(struct machine_info, control_group) },
1672 { "UserspaceTimestamp", "t", NULL, offsetof(struct machine_info, timestamp) },
1673 {}
0d292f5e
LP
1674};
1675
1676static void free_machines_list(struct machine_info *machine_infos, int n) {
1677 int i;
1678
1679 if (!machine_infos)
1680 return;
1681
1682 for (i = 0; i < n; i++) {
1683 free(machine_infos[i].name);
1684 free(machine_infos[i].state);
8fcf784d 1685 free(machine_infos[i].control_group);
0d292f5e
LP
1686 }
1687
1688 free(machine_infos);
1689}
1690
1691static int compare_machine_info(const void *a, const void *b) {
1692 const struct machine_info *u = a, *v = b;
1693
1694 if (u->is_host != v->is_host)
50933da0 1695 return u->is_host > v->is_host ? -1 : 1;
0d292f5e
LP
1696
1697 return strcasecmp(u->name, v->name);
1698}
1699
1700static int get_machine_properties(sd_bus *bus, struct machine_info *mi) {
24996861 1701 _cleanup_bus_close_unref_ sd_bus *container = NULL;
0d292f5e
LP
1702 int r;
1703
1704 assert(mi);
1705
1706 if (!bus) {
de33fc62 1707 r = sd_bus_open_system_machine(&container, mi->name);
0d292f5e
LP
1708 if (r < 0)
1709 return r;
1710
1711 bus = container;
1712 }
1713
8fcf784d 1714 r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, mi);
0d292f5e
LP
1715 if (r < 0)
1716 return r;
1717
1718 return 0;
1719}
1720
1721static bool output_show_machine(const char *name, char **patterns) {
2404701e 1722 return strv_fnmatch_or_empty(patterns, name, FNM_NOESCAPE);
0d292f5e
LP
1723}
1724
1725static int get_machine_list(
1726 sd_bus *bus,
1727 struct machine_info **_machine_infos,
1728 char **patterns) {
1729
1730 struct machine_info *machine_infos = NULL;
1731 _cleanup_strv_free_ char **m = NULL;
1732 _cleanup_free_ char *hn = NULL;
1733 size_t sz = 0;
1734 char **i;
1735 int c = 0;
1736
1737 hn = gethostname_malloc();
1738 if (!hn)
1739 return log_oom();
1740
1741 if (output_show_machine(hn, patterns)) {
1742 if (!GREEDY_REALLOC0(machine_infos, sz, c+1))
1743 return log_oom();
1744
1745 machine_infos[c].is_host = true;
1746 machine_infos[c].name = hn;
1747 hn = NULL;
1748
1749 get_machine_properties(bus, &machine_infos[c]);
1750 c++;
1751 }
1752
1753 sd_get_machine_names(&m);
1754 STRV_FOREACH(i, m) {
1755 _cleanup_free_ char *class = NULL;
1756
1757 if (!output_show_machine(*i, patterns))
1758 continue;
1759
1760 sd_machine_get_class(*i, &class);
1761 if (!streq_ptr(class, "container"))
1762 continue;
1763
1764 if (!GREEDY_REALLOC0(machine_infos, sz, c+1)) {
1765 free_machines_list(machine_infos, c);
1766 return log_oom();
1767 }
1768
1769 machine_infos[c].is_host = false;
1770 machine_infos[c].name = strdup(*i);
1771 if (!machine_infos[c].name) {
1772 free_machines_list(machine_infos, c);
1773 return log_oom();
1774 }
1775
1776 get_machine_properties(NULL, &machine_infos[c]);
1777 c++;
1778 }
1779
1780 *_machine_infos = machine_infos;
1781 return c;
1782}
1783
1784static void output_machines_list(struct machine_info *machine_infos, unsigned n) {
1785 struct machine_info *m;
1786 unsigned
90c3f79d 1787 circle_len = 0,
0d292f5e
LP
1788 namelen = sizeof("NAME") - 1,
1789 statelen = sizeof("STATE") - 1,
1790 failedlen = sizeof("FAILED") - 1,
1791 jobslen = sizeof("JOBS") - 1;
1792
1793 assert(machine_infos || n == 0);
1794
1795 for (m = machine_infos; m < machine_infos + n; m++) {
1796 namelen = MAX(namelen, strlen(m->name) + (m->is_host ? sizeof(" (host)") - 1 : 0));
1797 statelen = MAX(statelen, m->state ? strlen(m->state) : 0);
1798 failedlen = MAX(failedlen, DECIMAL_STR_WIDTH(m->n_failed_units));
1799 jobslen = MAX(jobslen, DECIMAL_STR_WIDTH(m->n_jobs));
90c3f79d 1800
250ba664 1801 if (!arg_plain && !streq_ptr(m->state, "running"))
90c3f79d 1802 circle_len = 2;
0d292f5e
LP
1803 }
1804
90c3f79d
LP
1805 if (!arg_no_legend) {
1806 if (circle_len > 0)
1807 fputs(" ", stdout);
1808
0d292f5e
LP
1809 printf("%-*s %-*s %-*s %-*s\n",
1810 namelen, "NAME",
1811 statelen, "STATE",
1812 failedlen, "FAILED",
1813 jobslen, "JOBS");
90c3f79d 1814 }
0d292f5e
LP
1815
1816 for (m = machine_infos; m < machine_infos + n; m++) {
90c3f79d
LP
1817 const char *on_state = "", *off_state = "";
1818 const char *on_failed = "", *off_failed = "";
1819 bool circle = false;
0d292f5e
LP
1820
1821 if (streq_ptr(m->state, "degraded")) {
1822 on_state = ansi_highlight_red();
1823 off_state = ansi_highlight_off();
90c3f79d 1824 circle = true;
0d292f5e
LP
1825 } else if (!streq_ptr(m->state, "running")) {
1826 on_state = ansi_highlight_yellow();
1827 off_state = ansi_highlight_off();
90c3f79d
LP
1828 circle = true;
1829 }
0d292f5e
LP
1830
1831 if (m->n_failed_units > 0) {
1832 on_failed = ansi_highlight_red();
1833 off_failed = ansi_highlight_off();
1834 } else
1835 on_failed = off_failed = "";
1836
90c3f79d 1837 if (circle_len > 0)
6b01f1d3 1838 printf("%s%s%s ", on_state, circle ? draw_special_char(DRAW_BLACK_CIRCLE) : " ", off_state);
90c3f79d 1839
0d292f5e
LP
1840 if (m->is_host)
1841 printf("%-*s (host) %s%-*s%s %s%*u%s %*u\n",
1842 (int) (namelen - (sizeof(" (host)")-1)), strna(m->name),
1843 on_state, statelen, strna(m->state), off_state,
1844 on_failed, failedlen, m->n_failed_units, off_failed,
1845 jobslen, m->n_jobs);
1846 else
1847 printf("%-*s %s%-*s%s %s%*u%s %*u\n",
1848 namelen, strna(m->name),
1849 on_state, statelen, strna(m->state), off_state,
1850 on_failed, failedlen, m->n_failed_units, off_failed,
1851 jobslen, m->n_jobs);
1852 }
1853
1854 if (!arg_no_legend)
1855 printf("\n%u machines listed.\n", n);
1856}
1857
1858static int list_machines(sd_bus *bus, char **args) {
1859 struct machine_info *machine_infos = NULL;
1860 int r;
1861
1862 assert(bus);
1863
1864 if (geteuid() != 0) {
1865 log_error("Must be root.");
1866 return -EPERM;
1867 }
1868
1869 pager_open_if_enabled();
1870
1871 r = get_machine_list(bus, &machine_infos, strv_skip_first(args));
1872 if (r < 0)
1873 return r;
1874
1875 qsort_safe(machine_infos, r, sizeof(struct machine_info), compare_machine_info);
1876 output_machines_list(machine_infos, r);
1877 free_machines_list(machine_infos, r);
1878
1879 return 0;
1880}
1881
f459b602
MAP
1882static int get_default(sd_bus *bus, char **args) {
1883 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
f459b602
MAP
1884 _cleanup_free_ char *_path = NULL;
1885 const char *path;
99504dd4 1886 int r;
99504dd4
VP
1887
1888 if (!bus || avoid_bus()) {
f459b602 1889 r = unit_file_get_default(arg_scope, arg_root, &_path);
f647962d
MS
1890 if (r < 0)
1891 return log_error_errno(r, "Failed to get default target: %m");
f459b602 1892 path = _path;
99504dd4 1893
99504dd4 1894 } else {
6e646d22
LP
1895 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1896
f459b602
MAP
1897 r = sd_bus_call_method(
1898 bus,
1899 "org.freedesktop.systemd1",
1900 "/org/freedesktop/systemd1",
1901 "org.freedesktop.systemd1.Manager",
1902 "GetDefaultTarget",
1903 &error,
1904 &reply,
1905 NULL);
99504dd4 1906 if (r < 0) {
f459b602
MAP
1907 log_error("Failed to get default target: %s", bus_error_message(&error, -r));
1908 return r;
99504dd4
VP
1909 }
1910
f459b602
MAP
1911 r = sd_bus_message_read(reply, "s", &path);
1912 if (r < 0)
1913 return bus_log_parse_error(r);
99504dd4
VP
1914 }
1915
1916 if (path)
1917 printf("%s\n", path);
1918
f459b602 1919 return 0;
99504dd4
VP
1920}
1921
718db961
LP
1922static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_changes) {
1923 unsigned i;
1924
1925 assert(changes || n_changes == 0);
1926
1927 for (i = 0; i < n_changes; i++) {
1928 if (changes[i].type == UNIT_FILE_SYMLINK)
735a1a2e 1929 log_info("Created symlink from %s to %s.", changes[i].path, changes[i].source);
718db961 1930 else
749ebb2d 1931 log_info("Removed symlink %s.", changes[i].path);
718db961
LP
1932 }
1933}
1934
718db961
LP
1935static int set_default(sd_bus *bus, char **args) {
1936 _cleanup_free_ char *unit = NULL;
1937 UnitFileChange *changes = NULL;
1938 unsigned n_changes = 0;
1939 int r;
1940
f78e6385 1941 unit = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".target");
718db961
LP
1942 if (!unit)
1943 return log_oom();
1944
1945 if (!bus || avoid_bus()) {
a1484a21 1946 r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes);
f647962d
MS
1947 if (r < 0)
1948 return log_error_errno(r, "Failed to set default target: %m");
718db961
LP
1949
1950 if (!arg_quiet)
1951 dump_unit_file_changes(changes, n_changes);
1952
1953 r = 0;
1954 } else {
718db961 1955 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
6e646d22 1956 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
718db961 1957
6e646d22
LP
1958 polkit_agent_open_if_enabled();
1959
1960 r = sd_bus_call_method(
718db961
LP
1961 bus,
1962 "org.freedesktop.systemd1",
1963 "/org/freedesktop/systemd1",
1964 "org.freedesktop.systemd1.Manager",
6e646d22
LP
1965 "SetDefaultTarget",
1966 &error,
1967 &reply,
1968 "sb", unit, 1);
718db961
LP
1969 if (r < 0) {
1970 log_error("Failed to set default target: %s", bus_error_message(&error, -r));
1971 return r;
1972 }
1973
d8f52ed2 1974 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
718db961
LP
1975 if (r < 0)
1976 return r;
1977
93c941e3 1978 /* Try to reload if enabled */
718db961
LP
1979 if (!arg_no_reload)
1980 r = daemon_reload(bus, args);
1981 else
1982 r = 0;
1983 }
1984
1985 unit_file_changes_free(changes, n_changes);
1986
1987 return r;
1988}
1989
75add28a
ZJS
1990struct job_info {
1991 uint32_t id;
f459b602 1992 const char *name, *type, *state;
75add28a
ZJS
1993};
1994
d8fba7c6 1995static void output_jobs_list(const struct job_info* jobs, unsigned n, bool skipped) {
f459b602
MAP
1996 unsigned id_len, unit_len, type_len, state_len;
1997 const struct job_info *j;
75add28a
ZJS
1998 const char *on, *off;
1999 bool shorten = false;
2000
2001 assert(n == 0 || jobs);
2002
2003 if (n == 0) {
250ba664
ZJS
2004 if (!arg_no_legend) {
2005 on = ansi_highlight_green();
2006 off = ansi_highlight_off();
75add28a 2007
250ba664
ZJS
2008 printf("%sNo jobs %s.%s\n", on, skipped ? "listed" : "running", off);
2009 }
75add28a
ZJS
2010 return;
2011 }
2012
2013 pager_open_if_enabled();
2014
f8294e41
JT
2015 id_len = strlen("JOB");
2016 unit_len = strlen("UNIT");
2017 type_len = strlen("TYPE");
2018 state_len = strlen("STATE");
6d6d40c9 2019
f459b602
MAP
2020 for (j = jobs; j < jobs + n; j++) {
2021 uint32_t id = j->id;
2022 assert(j->name && j->type && j->state);
75add28a 2023
f459b602
MAP
2024 id_len = MAX(id_len, DECIMAL_STR_WIDTH(id));
2025 unit_len = MAX(unit_len, strlen(j->name));
2026 type_len = MAX(type_len, strlen(j->type));
2027 state_len = MAX(state_len, strlen(j->state));
2028 }
75add28a 2029
f459b602
MAP
2030 if (!arg_full && id_len + 1 + unit_len + type_len + 1 + state_len > columns()) {
2031 unit_len = MAX(33u, columns() - id_len - type_len - state_len - 3);
2032 shorten = true;
2033 }
75add28a 2034
6ce774fd
MM
2035 if (!arg_no_legend)
2036 printf("%*s %-*s %-*s %-*s\n",
2037 id_len, "JOB",
2038 unit_len, "UNIT",
2039 type_len, "TYPE",
2040 state_len, "STATE");
75add28a 2041
f459b602
MAP
2042 for (j = jobs; j < jobs + n; j++) {
2043 _cleanup_free_ char *e = NULL;
75add28a 2044
f459b602
MAP
2045 if (streq(j->state, "running")) {
2046 on = ansi_highlight();
2047 off = ansi_highlight_off();
2048 } else
2049 on = off = "";
2050
2051 e = shorten ? ellipsize(j->name, unit_len, 33) : NULL;
2052 printf("%*u %s%-*s%s %-*s %s%-*s%s\n",
2053 id_len, j->id,
2054 on, unit_len, e ? e : j->name, off,
2055 type_len, j->type,
2056 on, state_len, j->state, off);
75add28a
ZJS
2057 }
2058
6ce774fd
MM
2059 if (!arg_no_legend) {
2060 on = ansi_highlight();
2061 off = ansi_highlight_off();
75add28a 2062
6ce774fd
MM
2063 printf("\n%s%u jobs listed%s.\n", on, n, off);
2064 }
75add28a
ZJS
2065}
2066
d8fba7c6 2067static bool output_show_job(struct job_info *job, char **patterns) {
2404701e 2068 return strv_fnmatch_or_empty(patterns, job->name, FNM_NOESCAPE);
d8fba7c6
ZJS
2069}
2070
f459b602
MAP
2071static int list_jobs(sd_bus *bus, char **args) {
2072 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2073 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
2074 const char *name, *type, *state, *job_path, *unit_path;
2075 _cleanup_free_ struct job_info *jobs = NULL;
2076 size_t size = 0;
2077 unsigned c = 0;
2078 uint32_t id;
f84190d8 2079 int r;
d8fba7c6 2080 bool skipped = false;
ec14911e 2081
f459b602 2082 r = sd_bus_call_method(
f22f08cd
SP
2083 bus,
2084 "org.freedesktop.systemd1",
2085 "/org/freedesktop/systemd1",
2086 "org.freedesktop.systemd1.Manager",
2087 "ListJobs",
f459b602 2088 &error,
f22f08cd 2089 &reply,
f459b602
MAP
2090 NULL);
2091 if (r < 0) {
2092 log_error("Failed to list jobs: %s", bus_error_message(&error, r));
f84190d8 2093 return r;
7e4249b9
LP
2094 }
2095
f459b602
MAP
2096 r = sd_bus_message_enter_container(reply, 'a', "(usssoo)");
2097 if (r < 0)
2098 return bus_log_parse_error(r);
7e4249b9 2099
f459b602 2100 while ((r = sd_bus_message_read(reply, "(usssoo)", &id, &name, &type, &state, &job_path, &unit_path)) > 0) {
d8fba7c6
ZJS
2101 struct job_info job = { id, name, type, state };
2102
2103 if (!output_show_job(&job, strv_skip_first(args))) {
2104 skipped = true;
2105 continue;
2106 }
8fe914ec 2107
f459b602
MAP
2108 if (!GREEDY_REALLOC(jobs, size, c + 1))
2109 return log_oom();
7e4249b9 2110
d8fba7c6 2111 jobs[c++] = job;
7e4249b9 2112 }
f459b602
MAP
2113 if (r < 0)
2114 return bus_log_parse_error(r);
7e4249b9 2115
f459b602
MAP
2116 r = sd_bus_message_exit_container(reply);
2117 if (r < 0)
2118 return bus_log_parse_error(r);
f73e33d9 2119
d8fba7c6 2120 output_jobs_list(jobs, c, skipped);
c6581cc1 2121 return r;
7e4249b9
LP
2122}
2123
f459b602 2124static int cancel_job(sd_bus *bus, char **args) {
729e3769 2125 char **name;
342641fb 2126 int r = 0;
7e4249b9 2127
514f4ef5
LP
2128 assert(args);
2129
729e3769
LP
2130 if (strv_length(args) <= 1)
2131 return daemon_reload(bus, args);
ee5762e3 2132
6e646d22
LP
2133 polkit_agent_open_if_enabled();
2134
729e3769 2135 STRV_FOREACH(name, args+1) {
6e646d22 2136 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
5dd9014f 2137 uint32_t id;
342641fb 2138 int q;
7e4249b9 2139
342641fb 2140 q = safe_atou32(*name, &id);
f647962d
MS
2141 if (q < 0)
2142 return log_error_errno(q, "Failed to parse job id \"%s\": %m", *name);
7e4249b9 2143
6e646d22 2144 q = sd_bus_call_method(
f22f08cd
SP
2145 bus,
2146 "org.freedesktop.systemd1",
2147 "/org/freedesktop/systemd1",
2148 "org.freedesktop.systemd1.Manager",
6e646d22
LP
2149 "CancelJob",
2150 &error,
2151 NULL,
2152 "u", id);
342641fb
LP
2153 if (q < 0) {
2154 log_error("Failed to cancel job %"PRIu32": %s", id, bus_error_message(&error, q));
2155 if (r == 0)
2156 r = q;
f459b602 2157 }
7e4249b9
LP
2158 }
2159
342641fb 2160 return r;
7e4249b9
LP
2161}
2162
f459b602
MAP
2163static int need_daemon_reload(sd_bus *bus, const char *unit) {
2164 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
f459b602
MAP
2165 const char *path;
2166 int b, r;
94c01aeb 2167
f459b602
MAP
2168 /* We ignore all errors here, since this is used to show a
2169 * warning only */
45fb0699 2170
f459b602
MAP
2171 /* We don't use unit_dbus_path_from_name() directly since we
2172 * don't want to load the unit if it isn't loaded. */
f84190d8 2173
f459b602 2174 r = sd_bus_call_method(
f22f08cd
SP
2175 bus,
2176 "org.freedesktop.systemd1",
2177 "/org/freedesktop/systemd1",
2178 "org.freedesktop.systemd1.Manager",
2179 "GetUnit",
f459b602 2180 NULL,
f22f08cd 2181 &reply,
e3e0314b 2182 "s", unit);
f84190d8
LP
2183 if (r < 0)
2184 return r;
45fb0699 2185
f459b602
MAP
2186 r = sd_bus_message_read(reply, "o", &path);
2187 if (r < 0)
2188 return r;
f84190d8 2189
f459b602 2190 r = sd_bus_get_property_trivial(
f22f08cd 2191 bus,
b0193f1c
LP
2192 "org.freedesktop.systemd1",
2193 path,
f459b602
MAP
2194 "org.freedesktop.systemd1.Unit",
2195 "NeedDaemonReload",
2196 NULL,
2197 'b', &b);
f84190d8
LP
2198 if (r < 0)
2199 return r;
45fb0699 2200
45fb0699
LP
2201 return b;
2202}
2203
3f36991e
ZJS
2204static void warn_unit_file_changed(const char *name) {
2205 log_warning("%sWarning:%s %s changed on disk. Run 'systemctl%s daemon-reload' to reload units.",
2206 ansi_highlight_red(),
2207 ansi_highlight_off(),
2208 name,
2209 arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
2210}
2211
33f6c497
ZJS
2212static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **unit_path) {
2213 char **p;
2214
2215 assert(lp);
2216 assert(unit_name);
2217 assert(unit_path);
2218
2219 STRV_FOREACH(p, lp->unit_path) {
ad2a0358 2220 _cleanup_free_ char *path;
33f6c497
ZJS
2221
2222 path = path_join(arg_root, *p, unit_name);
2223 if (!path)
2224 return log_oom();
2225
2226 if (access(path, F_OK) == 0) {
2227 *unit_path = path;
ad2a0358 2228 path = NULL;
33f6c497
ZJS
2229 return 1;
2230 }
33f6c497
ZJS
2231 }
2232
2233 return 0;
2234}
2235
6e646d22
LP
2236static int unit_find_paths(
2237 sd_bus *bus,
2238 const char *unit_name,
2239 bool avoid_bus_cache,
2240 LookupPaths *lp,
2241 char **fragment_path,
2242 char ***dropin_paths) {
dab2bce8
IS
2243
2244 _cleanup_free_ char *path = NULL;
2245 _cleanup_strv_free_ char **dropins = NULL;
33f6c497
ZJS
2246 int r;
2247
ad2a0358
ZJS
2248 /**
2249 * Finds where the unit is defined on disk. Returns 0 if the unit
2250 * is not found. Returns 1 if it is found, and sets
2251 * - the path to the unit in *path, if it exists on disk,
2252 * - and a strv of existing drop-ins in *dropins,
2253 * if the arg is not NULL and any dropins were found.
2254 */
2255
33f6c497 2256 assert(unit_name);
ad2a0358 2257 assert(fragment_path);
33f6c497
ZJS
2258 assert(lp);
2259
2260 if (!avoid_bus_cache && !unit_name_is_template(unit_name)) {
2261 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
b5e6a600 2262 _cleanup_bus_message_unref_ sd_bus_message *unit_load_error = NULL;
33f6c497 2263 _cleanup_free_ char *unit = NULL;
b5e6a600 2264 char *unit_load_error_name, *unit_load_error_message;
33f6c497
ZJS
2265
2266 unit = unit_dbus_path_from_name(unit_name);
2267 if (!unit)
2268 return log_oom();
2269
ad2a0358 2270 if (need_daemon_reload(bus, unit_name) > 0)
33f6c497 2271 warn_unit_file_changed(unit_name);
33f6c497 2272
b5e6a600
IS
2273 r = sd_bus_get_property(
2274 bus,
2275 "org.freedesktop.systemd1",
2276 unit,
2277 "org.freedesktop.systemd1.Unit",
2278 "LoadError",
2279 &error,
2280 &unit_load_error,
2281 "(ss)");
2282 if (r < 0)
2283 return log_error_errno(r, "Failed to get LoadError: %s", bus_error_message(&error, r));
2284
2285 r = sd_bus_message_read(
2286 unit_load_error,
2287 "(ss)",
2288 &unit_load_error_name,
2289 &unit_load_error_message);
2290 if (r < 0)
2291 return bus_log_parse_error(r);
2292
2293 if (!isempty(unit_load_error_name)) {
2294 log_error("Unit %s is not loaded: %s", unit_name, unit_load_error_message);
2295 return 0;
2296 }
2297
33f6c497
ZJS
2298 r = sd_bus_get_property_string(
2299 bus,
2300 "org.freedesktop.systemd1",
2301 unit,
2302 "org.freedesktop.systemd1.Unit",
2303 "FragmentPath",
2304 &error,
ad2a0358
ZJS
2305 &path);
2306 if (r < 0)
2307 return log_error_errno(r, "Failed to get FragmentPath: %s", bus_error_message(&error, r));
2308
dab2bce8
IS
2309 if (dropin_paths) {
2310 r = sd_bus_get_property_strv(
2311 bus,
2312 "org.freedesktop.systemd1",
2313 unit,
2314 "org.freedesktop.systemd1.Unit",
2315 "DropInPaths",
2316 &error,
2317 &dropins);
2318 if (r < 0)
2319 return log_error_errno(r, "Failed to get DropInPaths: %s", bus_error_message(&error, r));
33f6c497 2320 }
ad2a0358
ZJS
2321 } else {
2322 _cleanup_set_free_ Set *names;
33f6c497 2323
ad2a0358
ZJS
2324 names = set_new(NULL);
2325 if (!names)
2326 return -ENOMEM;
33f6c497 2327
ad2a0358
ZJS
2328 r = set_put(names, unit_name);
2329 if (r < 0)
2330 return r;
2331
dab2bce8 2332 r = unit_file_find_path(lp, unit_name, &path);
ad2a0358
ZJS
2333 if (r < 0)
2334 return r;
2335
2336 if (r == 0) {
2337 _cleanup_free_ char *template;
2338
2339 template = unit_name_template(unit_name);
2340 if (!template)
2341 return log_oom();
2342
2343 if (!streq(template, unit_name)) {
dab2bce8 2344 r = unit_file_find_path(lp, template, &path);
ad2a0358
ZJS
2345 if (r < 0)
2346 return r;
2347 }
2348 }
2349
dab2bce8
IS
2350 if (dropin_paths) {
2351 r = unit_file_find_dropin_paths(lp->unit_path, NULL, names, &dropins);
2352 if (r < 0)
2353 return r;
2354 }
2355 }
2356
2357 r = 0;
2358
2359 if (!isempty(path)) {
2360 *fragment_path = path;
2361 path = NULL;
2362 r = 1;
2363 }
2364
2365 if (dropin_paths && !strv_isempty(dropins)) {
2366 *dropin_paths = dropins;
2367 dropins = NULL;
2368 r = 1;
33f6c497
ZJS
2369 }
2370
b5e6a600
IS
2371 if (r == 0)
2372 log_error("No files found for %s.", unit_name);
2373
ad2a0358 2374 return r;
33f6c497
ZJS
2375}
2376
f459b602
MAP
2377static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet) {
2378 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
2379 _cleanup_free_ char *n = NULL, *state = NULL;
2380 const char *path;
f22f08cd 2381 int r;
701cdcb9 2382
31be1221 2383 assert(name);
701cdcb9 2384
f78e6385 2385 n = unit_name_mangle(name, MANGLE_NOGLOB);
60f9ba0b
LP
2386 if (!n)
2387 return log_oom();
2388
f459b602
MAP
2389 /* We don't use unit_dbus_path_from_name() directly since we
2390 * don't want to load the unit if it isn't loaded. */
2391
2392 r = sd_bus_call_method(
f22f08cd
SP
2393 bus,
2394 "org.freedesktop.systemd1",
2395 "/org/freedesktop/systemd1",
2396 "org.freedesktop.systemd1.Manager",
2397 "GetUnit",
f459b602 2398 NULL,
f22f08cd 2399 &reply,
f459b602 2400 "s", n);
60f9ba0b 2401 if (r < 0) {
60f9ba0b 2402 if (!quiet)
f22f08cd 2403 puts("unknown");
60f9ba0b 2404 return 0;
f22f08cd 2405 }
e61a3135 2406
f459b602
MAP
2407 r = sd_bus_message_read(reply, "o", &path);
2408 if (r < 0)
2409 return bus_log_parse_error(r);
60f9ba0b 2410
f459b602 2411 r = sd_bus_get_property_string(
f22f08cd
SP
2412 bus,
2413 "org.freedesktop.systemd1",
2414 path,
f459b602
MAP
2415 "org.freedesktop.systemd1.Unit",
2416 "ActiveState",
f22f08cd 2417 NULL,
f459b602 2418 &state);
60f9ba0b
LP
2419 if (r < 0) {
2420 if (!quiet)
2421 puts("unknown");
2422 return 0;
2423 }
701cdcb9 2424
31be1221
MS
2425 if (!quiet)
2426 puts(state);
2427
f459b602 2428 return nulstr_contains(good_states, state);
701cdcb9
MS
2429}
2430
f459b602
MAP
2431static int check_triggering_units(
2432 sd_bus *bus,
2433 const char *name) {
2434
2435 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2436 _cleanup_free_ char *path = NULL, *n = NULL, *state = NULL;
2437 _cleanup_strv_free_ char **triggered_by = NULL;
e61a3135 2438 bool print_warning_label = true;
f459b602 2439 char **i;
f22f08cd 2440 int r;
701cdcb9 2441
f78e6385 2442 n = unit_name_mangle(name, MANGLE_NOGLOB);
f459b602
MAP
2443 if (!n)
2444 return log_oom();
d3b52baf 2445
f459b602
MAP
2446 path = unit_dbus_path_from_name(n);
2447 if (!path)
2448 return log_oom();
701cdcb9 2449
f459b602 2450 r = sd_bus_get_property_string(
d0a5cdb2
JJ
2451 bus,
2452 "org.freedesktop.systemd1",
f459b602
MAP
2453 path,
2454 "org.freedesktop.systemd1.Unit",
2455 "LoadState",
2456 &error,
2457 &state);
2458 if (r < 0) {
2459 log_error("Failed to get load state of %s: %s", n, bus_error_message(&error, r));
2460 return r;
d0a5cdb2
JJ
2461 }
2462
d0a5cdb2 2463 if (streq(state, "masked"))
f459b602 2464 return 0;
701cdcb9 2465
f459b602
MAP
2466 r = sd_bus_get_property_strv(
2467 bus,
2468 "org.freedesktop.systemd1",
2469 path,
2470 "org.freedesktop.systemd1.Unit",
2471 "TriggeredBy",
2472 &error,
2473 &triggered_by);
2474 if (r < 0) {
2475 log_error("Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r));
2476 return r;
2477 }
701cdcb9 2478
f459b602
MAP
2479 STRV_FOREACH(i, triggered_by) {
2480 r = check_one_unit(bus, *i, "active\0reloading\0", true);
f647962d
MS
2481 if (r < 0)
2482 return log_error_errno(r, "Failed to check unit: %m");
701cdcb9 2483
f459b602
MAP
2484 if (r == 0)
2485 continue;
60f9ba0b 2486
f459b602
MAP
2487 if (print_warning_label) {
2488 log_warning("Warning: Stopping %s, but it can still be activated by:", n);
2489 print_warning_label = false;
701cdcb9 2490 }
1c291cf3 2491
f459b602 2492 log_warning(" %s", *i);
701cdcb9 2493 }
f459b602
MAP
2494
2495 return 0;
701cdcb9
MS
2496}
2497
2fc9a280
LP
2498static const struct {
2499 const char *verb;
2500 const char *method;
2501} unit_actions[] = {
2502 { "start", "StartUnit" },
2503 { "stop", "StopUnit" },
2504 { "condstop", "StopUnit" },
2505 { "reload", "ReloadUnit" },
2506 { "restart", "RestartUnit" },
2507 { "try-restart", "TryRestartUnit" },
2508 { "condrestart", "TryRestartUnit" },
2509 { "reload-or-restart", "ReloadOrRestartUnit" },
2510 { "reload-or-try-restart", "ReloadOrTryRestartUnit" },
2511 { "condreload", "ReloadOrTryRestartUnit" },
2512 { "force-reload", "ReloadOrTryRestartUnit" }
2513};
2514
39602c39
TA
2515static const char *verb_to_method(const char *verb) {
2516 uint i;
2517
2518 for (i = 0; i < ELEMENTSOF(unit_actions); i++)
2519 if (streq_ptr(unit_actions[i].verb, verb))
2520 return unit_actions[i].method;
2521
2522 return "StartUnit";
2523}
2524
2525static const char *method_to_verb(const char *method) {
2526 uint i;
2527
2528 for (i = 0; i < ELEMENTSOF(unit_actions); i++)
2529 if (streq_ptr(unit_actions[i].method, method))
2530 return unit_actions[i].verb;
2531
2532 return "n/a";
2533}
2534
e4b61340 2535static int start_unit_one(
f459b602 2536 sd_bus *bus,
e4b61340
LP
2537 const char *method,
2538 const char *name,
2539 const char *mode,
f459b602 2540 sd_bus_error *error,
ebd011d9 2541 BusWaitForJobs *w) {
7e4249b9 2542
6e646d22 2543 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
45fb0699 2544 const char *path;
7e4249b9 2545 int r;
7e4249b9 2546
e4b61340
LP
2547 assert(method);
2548 assert(name);
2549 assert(mode);
22f4096c 2550 assert(error);
7e4249b9 2551
e3e0314b 2552 log_debug("Calling manager for %s on %s, %s", method, name, mode);
342641fb 2553
6e646d22 2554 r = sd_bus_call_method(
f22f08cd 2555 bus,
b0193f1c
LP
2556 "org.freedesktop.systemd1",
2557 "/org/freedesktop/systemd1",
2558 "org.freedesktop.systemd1.Manager",
6e646d22
LP
2559 method,
2560 error,
2561 &reply,
2562 "ss", name, mode);
f459b602 2563 if (r < 0) {
39602c39
TA
2564 const char *verb;
2565
67f3c402 2566 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
e4b61340
LP
2567 /* There's always a fallback possible for
2568 * legacy actions. */
f459b602 2569 return -EADDRNOTAVAIL;
67f3c402 2570
39602c39
TA
2571 verb = method_to_verb(method);
2572
2573 log_error("Failed to %s %s: %s", verb, name, bus_error_message(error, r));
46eddbb5 2574 return r;
7e4249b9
LP
2575 }
2576
f459b602
MAP
2577 r = sd_bus_message_read(reply, "o", &path);
2578 if (r < 0)
2579 return bus_log_parse_error(r);
45fb0699 2580
e3e0314b 2581 if (need_daemon_reload(bus, name) > 0)
3f36991e 2582 warn_unit_file_changed(name);
45fb0699 2583
ebd011d9
LP
2584 if (w) {
2585 log_debug("Adding %s to the set", path);
2586 r = bus_wait_for_jobs_add(w, path);
cbc9fbd1
LP
2587 if (r < 0)
2588 return log_oom();
e4b61340 2589 }
7e4249b9 2590
46eddbb5 2591 return 0;
7e4249b9
LP
2592}
2593
e3e0314b
ZJS
2594static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) {
2595
e3e0314b
ZJS
2596 _cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
2597 char **name;
2598 int r = 0, i;
2599
2600 STRV_FOREACH(name, names) {
2601 char *t;
2602
e80733be
ZJS
2603 if (suffix)
2604 t = unit_name_mangle_with_suffix(*name, MANGLE_GLOB, suffix);
2605 else
2606 t = unit_name_mangle(*name, MANGLE_GLOB);
e3e0314b
ZJS
2607 if (!t)
2608 return log_oom();
2609
2610 if (string_is_glob(t))
6e18964d 2611 r = strv_consume(&globs, t);
e3e0314b 2612 else
6e18964d
ZJS
2613 r = strv_consume(&mangled, t);
2614 if (r < 0)
e3e0314b 2615 return log_oom();
e3e0314b
ZJS
2616 }
2617
2618 /* Query the manager only if any of the names are a glob, since
2619 * this is fairly expensive */
2620 if (!strv_isempty(globs)) {
1238ee09 2621 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
e3e0314b
ZJS
2622 _cleanup_free_ UnitInfo *unit_infos = NULL;
2623
ad2a0358 2624 if (!bus)
15411c0c 2625 return log_error_errno(EOPNOTSUPP, "Unit name globbing without bus is not implemented.");
ad2a0358 2626
1238ee09 2627 r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
e3e0314b
ZJS
2628 if (r < 0)
2629 return r;
2630
2631 for (i = 0; i < r; i++)
2632 if (strv_extend(&mangled, unit_infos[i].id) < 0)
2633 return log_oom();
2634 }
2635
2636 *ret = mangled;
2637 mangled = NULL; /* do not free */
1238ee09 2638
e3e0314b
ZJS
2639 return 0;
2640}
2641
47a0eaa6
MS
2642static const struct {
2643 const char *target;
2644 const char *verb;
2645 const char *mode;
2646} action_table[_ACTION_MAX] = {
2647 [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" },
2648 [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
2649 [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" },
2650 [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" },
d5d8429a
LP
2651 [ACTION_RUNLEVEL2] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
2652 [ACTION_RUNLEVEL3] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
2653 [ACTION_RUNLEVEL4] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
2654 [ACTION_RUNLEVEL5] = { SPECIAL_GRAPHICAL_TARGET, NULL, "isolate" },
47a0eaa6
MS
2655 [ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" },
2656 [ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" },
2657 [ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" },
2658 [ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" },
2659 [ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" },
2660 [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" },
2661 [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
2662};
2663
514f4ef5 2664static enum action verb_to_action(const char *verb) {
47a0eaa6
MS
2665 enum action i;
2666
f459b602
MAP
2667 for (i = _ACTION_INVALID; i < _ACTION_MAX; i++)
2668 if (streq_ptr(action_table[i].verb, verb))
47a0eaa6 2669 return i;
514f4ef5 2670
f459b602
MAP
2671 return _ACTION_INVALID;
2672}
e4b61340 2673
f459b602 2674static int start_unit(sd_bus *bus, char **args) {
ebd011d9 2675 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
08073121 2676 const char *method, *mode, *one_name, *suffix = NULL;
ebd011d9 2677 _cleanup_strv_free_ char **names = NULL;
729e3769 2678 char **name;
b6520546 2679 int r = 0;
e4b61340 2680
514f4ef5
LP
2681 assert(bus);
2682
6bb92a16 2683 ask_password_agent_open_if_enabled();
079dac08 2684 polkit_agent_open_if_enabled();
501fc174 2685
e4b61340 2686 if (arg_action == ACTION_SYSTEMCTL) {
47a0eaa6 2687 enum action action;
39602c39 2688 method = verb_to_method(args[0]);
47a0eaa6 2689 action = verb_to_action(args[0]);
e4b61340 2690
08073121
LP
2691 if (streq(args[0], "isolate")) {
2692 mode = "isolate";
2693 suffix = ".target";
2694 } else
2695 mode = action_table[action].mode ?: arg_job_mode;
e4b61340 2696
e3e0314b 2697 one_name = action_table[action].target;
e4b61340 2698 } else {
47a0eaa6
MS
2699 assert(arg_action < ELEMENTSOF(action_table));
2700 assert(action_table[arg_action].target);
e4b61340
LP
2701
2702 method = "StartUnit";
514f4ef5 2703
47a0eaa6 2704 mode = action_table[arg_action].mode;
e3e0314b 2705 one_name = action_table[arg_action].target;
514f4ef5
LP
2706 }
2707
e3e0314b
ZJS
2708 if (one_name)
2709 names = strv_new(one_name, NULL);
2710 else {
08073121 2711 r = expand_names(bus, args + 1, suffix, &names);
e3e0314b 2712 if (r < 0)
da927ba9 2713 log_error_errno(r, "Failed to expand names: %m");
e3e0314b 2714 }
b6520546 2715
6e905d93 2716 if (!arg_no_block) {
ebd011d9 2717 r = bus_wait_for_jobs_new(bus, &w);
f647962d
MS
2718 if (r < 0)
2719 return log_error_errno(r, "Could not watch jobs: %m");
e4b61340
LP
2720 }
2721
b6520546 2722 STRV_FOREACH(name, names) {
e3e0314b 2723 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
b6520546 2724 int q;
f459b602 2725
ebd011d9 2726 q = start_unit_one(bus, method, *name, mode, &error, w);
e3e0314b 2727 if (r >= 0 && q < 0)
b6520546 2728 r = translate_bus_error_to_exit_status(q, &error);
e4b61340
LP
2729 }
2730
67f3c402 2731 if (!arg_no_block) {
f459b602
MAP
2732 int q;
2733
ebd011d9 2734 q = bus_wait_for_jobs(w, arg_quiet);
f459b602
MAP
2735 if (q < 0)
2736 return q;
49111a70
ZJS
2737
2738 /* When stopping units, warn if they can still be triggered by
2739 * another active unit (socket, path, timer) */
b6520546
ZJS
2740 if (!arg_quiet && streq(method, "StopUnit"))
2741 STRV_FOREACH(name, names)
2742 check_triggering_units(bus, *name);
67f3c402 2743 }
514f4ef5 2744
f459b602 2745 return r;
e4b61340
LP
2746}
2747
7e59bfcb
LP
2748/* Ask systemd-logind, which might grant access to unprivileged users
2749 * through PolicyKit */
f459b602 2750static int reboot_with_logind(sd_bus *bus, enum action a) {
4c80c73c 2751#ifdef HAVE_LOGIND
f459b602 2752 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4c80c73c 2753 const char *method;
f459b602 2754 int r;
4c80c73c 2755
d255133d
LP
2756 if (!bus)
2757 return -EIO;
2758
6bb92a16
LP
2759 polkit_agent_open_if_enabled();
2760
4c80c73c
KS
2761 switch (a) {
2762
2763 case ACTION_REBOOT:
2764 method = "Reboot";
2765 break;
2766
2767 case ACTION_POWEROFF:
2768 method = "PowerOff";
2769 break;
2770
d889a206
LP
2771 case ACTION_SUSPEND:
2772 method = "Suspend";
2773 break;
2774
2775 case ACTION_HIBERNATE:
2776 method = "Hibernate";
2777 break;
2778
6524990f
LP
2779 case ACTION_HYBRID_SLEEP:
2780 method = "HybridSleep";
2781 break;
2782
4c80c73c
KS
2783 default:
2784 return -EINVAL;
2785 }
2786
f459b602 2787 r = sd_bus_call_method(
f22f08cd
SP
2788 bus,
2789 "org.freedesktop.login1",
2790 "/org/freedesktop/login1",
2791 "org.freedesktop.login1.Manager",
2792 method,
f459b602 2793 &error,
f22f08cd 2794 NULL,
342641fb 2795 "b", arg_ask_password);
f459b602
MAP
2796 if (r < 0)
2797 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
2798
2799 return r;
4c80c73c
KS
2800#else
2801 return -ENOSYS;
2802#endif
2803}
2804
f459b602 2805static int check_inhibitors(sd_bus *bus, enum action a) {
b37844d3 2806#ifdef HAVE_LOGIND
f459b602 2807 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
59164be4 2808 _cleanup_strv_free_ char **sessions = NULL;
f459b602
MAP
2809 const char *what, *who, *why, *mode;
2810 uint32_t uid, pid;
2811 unsigned c = 0;
59164be4 2812 char **s;
f459b602 2813 int r;
b37844d3 2814
748ebafa
LP
2815 if (!bus)
2816 return 0;
2817
2818 if (arg_ignore_inhibitors || arg_force > 0)
2819 return 0;
2820
2821 if (arg_when > 0)
2822 return 0;
2823
2824 if (geteuid() == 0)
b37844d3
LP
2825 return 0;
2826
2827 if (!on_tty())
2828 return 0;
2829
f459b602 2830 r = sd_bus_call_method(
b37844d3
LP
2831 bus,
2832 "org.freedesktop.login1",
2833 "/org/freedesktop/login1",
2834 "org.freedesktop.login1.Manager",
2835 "ListInhibitors",
b37844d3 2836 NULL,
f459b602
MAP
2837 &reply,
2838 NULL);
b37844d3
LP
2839 if (r < 0)
2840 /* If logind is not around, then there are no inhibitors... */
2841 return 0;
2842
4aa2beac 2843 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
f459b602
MAP
2844 if (r < 0)
2845 return bus_log_parse_error(r);
b37844d3 2846
4aa2beac 2847 while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
59164be4 2848 _cleanup_free_ char *comm = NULL, *user = NULL;
f459b602 2849 _cleanup_strv_free_ char **sv = NULL;
b37844d3
LP
2850
2851 if (!streq(mode, "block"))
f459b602 2852 continue;
b37844d3
LP
2853
2854 sv = strv_split(what, ":");
2855 if (!sv)
2856 return log_oom();
2857
d028e018
ZJS
2858 if ((pid_t) pid < 0)
2859 return log_error_errno(ERANGE, "Bad PID %"PRIu32": %m", pid);
2860
b37844d3
LP
2861 if (!strv_contains(sv,
2862 a == ACTION_HALT ||
2863 a == ACTION_POWEROFF ||
2864 a == ACTION_REBOOT ||
2865 a == ACTION_KEXEC ? "shutdown" : "sleep"))
f459b602 2866 continue;
b37844d3
LP
2867
2868 get_process_comm(pid, &comm);
59164be4 2869 user = uid_to_name(uid);
f459b602 2870
de0671ee 2871 log_warning("Operation inhibited by \"%s\" (PID "PID_FMT" \"%s\", user %s), reason is \"%s\".",
d028e018 2872 who, (pid_t) pid, strna(comm), strna(user), why);
b37844d3 2873
f459b602 2874 c++;
b37844d3 2875 }
f459b602
MAP
2876 if (r < 0)
2877 return bus_log_parse_error(r);
b37844d3 2878
f459b602
MAP
2879 r = sd_bus_message_exit_container(reply);
2880 if (r < 0)
2881 return bus_log_parse_error(r);
b37844d3 2882
59164be4
LP
2883 /* Check for current sessions */
2884 sd_get_sessions(&sessions);
2885 STRV_FOREACH(s, sessions) {
59164be4
LP
2886 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
2887
2888 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
2889 continue;
2890
2891 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
2892 continue;
2893
2894 if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
2895 continue;
2896
2897 sd_session_get_tty(*s, &tty);
2898 sd_session_get_seat(*s, &seat);
2899 sd_session_get_service(*s, &service);
2900 user = uid_to_name(uid);
2901
2902 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
2903 c++;
2904 }
2905
b37844d3
LP
2906 if (c <= 0)
2907 return 0;
2908
59164be4 2909 log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
47a0eaa6 2910 action_table[a].verb);
b37844d3
LP
2911
2912 return -EPERM;
2913#else
2914 return 0;
2915#endif
2916}
2917
a4921cf4
JJ
2918static int prepare_firmware_setup(sd_bus *bus) {
2919#ifdef HAVE_LOGIND
2920 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2921#endif
2922 int r;
2923
2924 if (!arg_firmware_setup)
2925 return 0;
2926
2927 if (arg_transport == BUS_TRANSPORT_LOCAL) {
2928
2929 r = efi_set_reboot_to_firmware(true);
2930 if (r < 0)
2931 log_debug_errno(r, "Cannot indicate to EFI to boot into setup mode, will retry via logind: %m");
2932 else
2933 return r;
2934 }
2935
2936#ifdef HAVE_LOGIND
2937 r = sd_bus_call_method(
2938 bus,
2939 "org.freedesktop.login1",
2940 "/org/freedesktop/login1",
2941 "org.freedesktop.login1.Manager",
2942 "SetRebootToFirmwareSetup",
2943 &error,
2944 NULL,
2945 "b", true);
2946 if (r < 0) {
2947 log_error("Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
2948 return r;
2949 }
2950
2951 return 0;
2952#else
2953 log_error("Cannot remotely indicate to EFI to boot into setup mode.");
2954 return -EINVAL;
2955#endif
2956}
2957
f459b602 2958static int start_special(sd_bus *bus, char **args) {
4c80c73c 2959 enum action a;
983d9c90
LP
2960 int r;
2961
514f4ef5
LP
2962 assert(args);
2963
4c80c73c
KS
2964 a = verb_to_action(args[0]);
2965
748ebafa
LP
2966 r = check_inhibitors(bus, a);
2967 if (r < 0)
2968 return r;
2969
c32b90de
LP
2970 if (arg_force >= 2 && geteuid() != 0) {
2971 log_error("Must be root.");
2972 return -EPERM;
2973 }
2974
a4921cf4
JJ
2975 r = prepare_firmware_setup(bus);
2976 if (r < 0)
2977 return r;
5bdf2243 2978
c31c4324 2979 if (a == ACTION_REBOOT && args[1]) {
b986229e
SW
2980 r = update_reboot_param_file(args[1]);
2981 if (r < 0)
2982 return r;
2983 }
2984
7e59bfcb
LP
2985 if (arg_force >= 2 &&
2986 (a == ACTION_HALT ||
2987 a == ACTION_POWEROFF ||
2988 a == ACTION_REBOOT))
477def80 2989 return halt_now(a);
e606bb61 2990
7e59bfcb 2991 if (arg_force >= 1 &&
4c80c73c
KS
2992 (a == ACTION_HALT ||
2993 a == ACTION_POWEROFF ||
2994 a == ACTION_REBOOT ||
2995 a == ACTION_KEXEC ||
2996 a == ACTION_EXIT))
729e3769 2997 return daemon_reload(bus, args);
20b09ca7 2998
7e59bfcb
LP
2999 /* first try logind, to allow authentication with polkit */
3000 if (geteuid() != 0 &&
3001 (a == ACTION_POWEROFF ||
d889a206
LP
3002 a == ACTION_REBOOT ||
3003 a == ACTION_SUSPEND ||
6524990f
LP
3004 a == ACTION_HIBERNATE ||
3005 a == ACTION_HYBRID_SLEEP)) {
7e59bfcb 3006 r = reboot_with_logind(bus, a);
15411c0c 3007 if (r >= 0 || IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
7e59bfcb 3008 return r;
4c80c73c 3009 }
983d9c90 3010
4c80c73c 3011 r = start_unit(bus, args);
f6bb13ab 3012 if (r == EXIT_SUCCESS)
4c80c73c 3013 warn_wall(a);
514f4ef5 3014
983d9c90 3015 return r;
514f4ef5
LP
3016}
3017
e3e0314b 3018static int check_unit_generic(sd_bus *bus, int code, const char *good_states, char **args) {
e3e0314b 3019 _cleanup_strv_free_ char **names = NULL;
729e3769 3020 char **name;
5a1aece5 3021 int r;
0183528f
LP
3022
3023 assert(bus);
3024 assert(args);
3025
e3e0314b 3026 r = expand_names(bus, args, NULL, &names);
f647962d
MS
3027 if (r < 0)
3028 return log_error_errno(r, "Failed to expand names: %m");
e3e0314b
ZJS
3029
3030 STRV_FOREACH(name, names) {
60f9ba0b
LP
3031 int state;
3032
e3e0314b 3033 state = check_one_unit(bus, *name, good_states, arg_quiet);
1a0fce45
TA
3034 if (state < 0)
3035 return state;
5a1aece5
DR
3036 if (state == 0)
3037 r = code;
1a0fce45
TA
3038 }
3039
3040 return r;
3041}
3042
e3e0314b
ZJS
3043static int check_unit_active(sd_bus *bus, char **args) {
3044 /* According to LSB: 3, "program is not running" */
3045 return check_unit_generic(bus, 3, "active\0reloading\0", args + 1);
3046}
0183528f 3047
e3e0314b
ZJS
3048static int check_unit_failed(sd_bus *bus, char **args) {
3049 return check_unit_generic(bus, 1, "failed\0", args + 1);
48220598
LP
3050}
3051
f459b602 3052static int kill_unit(sd_bus *bus, char **args) {
e3e0314b 3053 _cleanup_strv_free_ char **names = NULL;
60f9ba0b 3054 char **name;
e3e0314b 3055 int r, q;
8a0867d6 3056
60f9ba0b 3057 assert(bus);
8a0867d6
LP
3058 assert(args);
3059
079dac08
LP
3060 polkit_agent_open_if_enabled();
3061
8a0867d6
LP
3062 if (!arg_kill_who)
3063 arg_kill_who = "all";
3064
e3e0314b
ZJS
3065 r = expand_names(bus, args + 1, NULL, &names);
3066 if (r < 0)
da927ba9 3067 log_error_errno(r, "Failed to expand names: %m");
60f9ba0b 3068
e3e0314b 3069 STRV_FOREACH(name, names) {
6e646d22 3070 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
342641fb 3071
6e646d22 3072 q = sd_bus_call_method(
f22f08cd 3073 bus,
b0193f1c
LP
3074 "org.freedesktop.systemd1",
3075 "/org/freedesktop/systemd1",
3076 "org.freedesktop.systemd1.Manager",
6e646d22
LP
3077 "KillUnit",
3078 &error,
3079 NULL,
3080 "ssi", *names, arg_kill_who, arg_signal);
e3e0314b 3081 if (q < 0) {
342641fb 3082 log_error("Failed to kill unit %s: %s", *names, bus_error_message(&error, q));
e3e0314b
ZJS
3083 if (r == 0)
3084 r = q;
f459b602 3085 }
8a0867d6 3086 }
f459b602 3087
e3e0314b 3088 return r;
8a0867d6
LP
3089}
3090
582a507f 3091typedef struct ExecStatusInfo {
0129173a
LP
3092 char *name;
3093
582a507f
LP
3094 char *path;
3095 char **argv;
3096
b708e7ce
LP
3097 bool ignore;
3098
582a507f
LP
3099 usec_t start_timestamp;
3100 usec_t exit_timestamp;
3101 pid_t pid;
3102 int code;
3103 int status;
3104
3105 LIST_FIELDS(struct ExecStatusInfo, exec);
3106} ExecStatusInfo;
3107
3108static void exec_status_info_free(ExecStatusInfo *i) {
3109 assert(i);
3110
0129173a 3111 free(i->name);
582a507f
LP
3112 free(i->path);
3113 strv_free(i->argv);
3114 free(i);
3115}
3116
f459b602 3117static int exec_status_info_deserialize(sd_bus_message *m, ExecStatusInfo *i) {
b21a0ef8 3118 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
f459b602 3119 const char *path;
582a507f
LP
3120 uint32_t pid;
3121 int32_t code, status;
f459b602 3122 int ignore, r;
582a507f 3123
f459b602 3124 assert(m);
582a507f 3125 assert(i);
582a507f 3126
f459b602
MAP
3127 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, "sasbttttuii");
3128 if (r < 0)
3129 return bus_log_parse_error(r);
3130 else if (r == 0)
3131 return 0;
582a507f 3132
f459b602
MAP
3133 r = sd_bus_message_read(m, "s", &path);
3134 if (r < 0)
3135 return bus_log_parse_error(r);
582a507f 3136
f84190d8
LP
3137 i->path = strdup(path);
3138 if (!i->path)
f459b602 3139 return log_oom();
582a507f 3140
f459b602
MAP
3141 r = sd_bus_message_read_strv(m, &i->argv);
3142 if (r < 0)
3143 return bus_log_parse_error(r);
3144
3145 r = sd_bus_message_read(m,
3146 "bttttuii",
3147 &ignore,
3148 &start_timestamp, &start_timestamp_monotonic,
3149 &exit_timestamp, &exit_timestamp_monotonic,
3150 &pid,
3151 &code, &status);
3152 if (r < 0)
3153 return bus_log_parse_error(r);
582a507f 3154
b708e7ce 3155 i->ignore = ignore;
582a507f
LP
3156 i->start_timestamp = (usec_t) start_timestamp;
3157 i->exit_timestamp = (usec_t) exit_timestamp;
3158 i->pid = (pid_t) pid;
3159 i->code = code;
3160 i->status = status;
3161
f459b602
MAP
3162 r = sd_bus_message_exit_container(m);
3163 if (r < 0)
3164 return bus_log_parse_error(r);
3165
3166 return 1;
582a507f
LP
3167}
3168
61cbdc4b
LP
3169typedef struct UnitStatusInfo {
3170 const char *id;
3171 const char *load_state;
3172 const char *active_state;
3173 const char *sub_state;
a4375746 3174 const char *unit_file_state;
d2dc52db 3175 const char *unit_file_preset;
61cbdc4b
LP
3176
3177 const char *description;
4a9e2fff 3178 const char *following;
61cbdc4b 3179
49dbfa7b
LP
3180 char **documentation;
3181
1b64d026
LP
3182 const char *fragment_path;
3183 const char *source_path;
4ad49000 3184 const char *control_group;
61cbdc4b 3185
76d14b87
OS
3186 char **dropin_paths;
3187
9f39404c 3188 const char *load_error;
f42806df 3189 const char *result;
9f39404c 3190
584be568 3191 usec_t inactive_exit_timestamp;
df50185b 3192 usec_t inactive_exit_timestamp_monotonic;
584be568
LP
3193 usec_t active_enter_timestamp;
3194 usec_t active_exit_timestamp;
3195 usec_t inactive_enter_timestamp;
3196
45fb0699
LP
3197 bool need_daemon_reload;
3198
61cbdc4b
LP
3199 /* Service */
3200 pid_t main_pid;
3201 pid_t control_pid;
3202 const char *status_text;
175728c4 3203 const char *pid_file;
d06dacd0 3204 bool running:1;
b4af5a80 3205 int status_errno;
61cbdc4b
LP
3206
3207 usec_t start_timestamp;
3208 usec_t exit_timestamp;
3209
3210 int exit_code, exit_status;
3211
90bbc946
LP
3212 usec_t condition_timestamp;
3213 bool condition_result;
52990c2e
ZJS
3214 bool failed_condition_trigger;
3215 bool failed_condition_negate;
3216 const char *failed_condition;
59fccdc5
LP
3217 const char *failed_condition_parameter;
3218
3219 usec_t assert_timestamp;
3220 bool assert_result;
3221 bool failed_assert_trigger;
3222 bool failed_assert_negate;
3223 const char *failed_assert;
3224 const char *failed_assert_parameter;
90bbc946 3225
61cbdc4b
LP
3226 /* Socket */
3227 unsigned n_accepted;
3228 unsigned n_connections;
b8131a87 3229 bool accept;
61cbdc4b 3230
13160134 3231 /* Pairs of type, path */
67419600
OS
3232 char **listen;
3233
61cbdc4b
LP
3234 /* Device */
3235 const char *sysfs_path;
3236
3237 /* Mount, Automount */
3238 const char *where;
3239
3240 /* Swap */
3241 const char *what;
582a507f 3242
934277fe
LP
3243 /* CGroup */
3244 uint64_t memory_current;
3245 uint64_t memory_limit;
5ad096b3 3246 uint64_t cpu_usage_nsec;
934277fe 3247
582a507f 3248 LIST_HEAD(ExecStatusInfo, exec);
61cbdc4b
LP
3249} UnitStatusInfo;
3250
f459b602
MAP
3251static void print_status_info(
3252 UnitStatusInfo *i,
3253 bool *ellipsized) {
3254
582a507f 3255 ExecStatusInfo *p;
b0d14c69 3256 const char *active_on, *active_off, *on, *off, *ss;
584be568 3257 usec_t timestamp;
9185c8e6 3258 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
584be568 3259 char since2[FORMAT_TIMESTAMP_MAX], *s2;
1b64d026 3260 const char *path;
13160134 3261 char **t, **t2;
582a507f 3262
61cbdc4b
LP
3263 assert(i);
3264
3265 /* This shows pretty information about a unit. See
3266 * print_property() for a low-level property printer */
3267
b0d14c69
LP
3268 if (streq_ptr(i->active_state, "failed")) {
3269 active_on = ansi_highlight_red();
3270 active_off = ansi_highlight_off();
3271 } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
3272 active_on = ansi_highlight_green();
3273 active_off = ansi_highlight_off();
3274 } else
3275 active_on = active_off = "";
3276
6b01f1d3 3277 printf("%s%s%s %s", active_on, draw_special_char(DRAW_BLACK_CIRCLE), active_off, strna(i->id));
61cbdc4b
LP
3278
3279 if (i->description && !streq_ptr(i->id, i->description))
3280 printf(" - %s", i->description);
3281
3282 printf("\n");
3283
4a9e2fff 3284 if (i->following)
856323c9 3285 printf(" Follow: unit currently follows state of %s\n", i->following);
4a9e2fff 3286
f7b9e331 3287 if (streq_ptr(i->load_state, "error")) {
0b5a519c
DS
3288 on = ansi_highlight_red();
3289 off = ansi_highlight_off();
c31b4423
LP
3290 } else
3291 on = off = "";
3292
1b64d026
LP
3293 path = i->source_path ? i->source_path : i->fragment_path;
3294
9f39404c 3295 if (i->load_error)
856323c9
ZJS
3296 printf(" Loaded: %s%s%s (Reason: %s)\n",
3297 on, strna(i->load_state), off, i->load_error);
d2dc52db
LP
3298 else if (path && !isempty(i->unit_file_state) && !isempty(i->unit_file_preset))
3299 printf(" Loaded: %s%s%s (%s; %s; vendor preset: %s)\n",
3300 on, strna(i->load_state), off, path, i->unit_file_state, i->unit_file_preset);
3301 else if (path && !isempty(i->unit_file_state))
856323c9
ZJS
3302 printf(" Loaded: %s%s%s (%s; %s)\n",
3303 on, strna(i->load_state), off, path, i->unit_file_state);
1b64d026 3304 else if (path)
856323c9
ZJS
3305 printf(" Loaded: %s%s%s (%s)\n",
3306 on, strna(i->load_state), off, path);
61cbdc4b 3307 else
856323c9
ZJS
3308 printf(" Loaded: %s%s%s\n",
3309 on, strna(i->load_state), off);
61cbdc4b 3310
76d14b87 3311 if (!strv_isempty(i->dropin_paths)) {
f459b602 3312 _cleanup_free_ char *dir = NULL;
76d14b87 3313 bool last = false;
f459b602 3314 char ** dropin;
76d14b87
OS
3315
3316 STRV_FOREACH(dropin, i->dropin_paths) {
3317 if (! dir || last) {
856323c9 3318 printf(dir ? " " : " Drop-In: ");
76d14b87
OS
3319
3320 free(dir);
f459b602 3321 dir = NULL;
76d14b87
OS
3322
3323 if (path_get_parent(*dropin, &dir) < 0) {
3324 log_oom();
3325 return;
3326 }
3327
856323c9 3328 printf("%s\n %s", dir,
76d14b87
OS
3329 draw_special_char(DRAW_TREE_RIGHT));
3330 }
3331
3332 last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
3333
2b6bf07d 3334 printf("%s%s", basename(*dropin), last ? "\n" : ", ");
76d14b87 3335 }
76d14b87
OS
3336 }
3337
2ee68f72 3338 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2ee68f72 3339 if (ss)
856323c9 3340 printf(" Active: %s%s (%s)%s",
b0d14c69 3341 active_on, strna(i->active_state), ss, active_off);
2ee68f72 3342 else
856323c9 3343 printf(" Active: %s%s%s",
b0d14c69 3344 active_on, strna(i->active_state), active_off);
61cbdc4b 3345
f42806df
LP
3346 if (!isempty(i->result) && !streq(i->result, "success"))
3347 printf(" (Result: %s)", i->result);
3348
584be568
LP
3349 timestamp = (streq_ptr(i->active_state, "active") ||
3350 streq_ptr(i->active_state, "reloading")) ? i->active_enter_timestamp :
3351 (streq_ptr(i->active_state, "inactive") ||
fdf20a31 3352 streq_ptr(i->active_state, "failed")) ? i->inactive_enter_timestamp :
584be568
LP
3353 streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp :
3354 i->active_exit_timestamp;
3355
bbb8486e 3356 s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
584be568
LP
3357 s2 = format_timestamp(since2, sizeof(since2), timestamp);
3358
3359 if (s1)
538da63d 3360 printf(" since %s; %s\n", s2, s1);
584be568 3361 else if (s2)
538da63d 3362 printf(" since %s\n", s2);
584be568
LP
3363 else
3364 printf("\n");
3365
90bbc946 3366 if (!i->condition_result && i->condition_timestamp > 0) {
bbb8486e 3367 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
90bbc946
LP
3368 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
3369
59fccdc5
LP
3370 printf("Condition: start %scondition failed%s at %s%s%s\n",
3371 ansi_highlight_yellow(), ansi_highlight_off(),
52990c2e
ZJS
3372 s2, s1 ? "; " : "", s1 ? s1 : "");
3373 if (i->failed_condition_trigger)
3374 printf(" none of the trigger conditions were met\n");
3375 else if (i->failed_condition)
3376 printf(" %s=%s%s was not met\n",
3377 i->failed_condition,
3378 i->failed_condition_negate ? "!" : "",
59fccdc5
LP
3379 i->failed_condition_parameter);
3380 }
3381
3382 if (!i->assert_result && i->assert_timestamp > 0) {
3383 s1 = format_timestamp_relative(since1, sizeof(since1), i->assert_timestamp);
3384 s2 = format_timestamp(since2, sizeof(since2), i->assert_timestamp);
3385
3386 printf(" Assert: start %sassertion failed%s at %s%s%s\n",
3387 ansi_highlight_red(), ansi_highlight_off(),
3388 s2, s1 ? "; " : "", s1 ? s1 : "");
3389 if (i->failed_assert_trigger)
3390 printf(" none of the trigger assertions were met\n");
3391 else if (i->failed_assert)
3392 printf(" %s=%s%s was not met\n",
3393 i->failed_assert,
3394 i->failed_assert_negate ? "!" : "",
3395 i->failed_assert_parameter);
90bbc946
LP
3396 }
3397
61cbdc4b 3398 if (i->sysfs_path)
856323c9 3399 printf(" Device: %s\n", i->sysfs_path);
9feeba4b 3400 if (i->where)
856323c9 3401 printf(" Where: %s\n", i->where);
9feeba4b 3402 if (i->what)
856323c9 3403 printf(" What: %s\n", i->what);
49dbfa7b 3404
13160134 3405 STRV_FOREACH(t, i->documentation)
856323c9 3406 printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", *t);
49dbfa7b 3407
13160134 3408 STRV_FOREACH_PAIR(t, t2, i->listen)
856323c9 3409 printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
67419600 3410
b8131a87 3411 if (i->accept)
856323c9 3412 printf(" Accepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
61cbdc4b 3413
582a507f 3414 LIST_FOREACH(exec, p, i->exec) {
13160134 3415 _cleanup_free_ char *argv = NULL;
9a57c629 3416 bool good;
582a507f
LP
3417
3418 /* Only show exited processes here */
3419 if (p->code == 0)
3420 continue;
3421
13160134 3422 argv = strv_join(p->argv, " ");
1fa2f38f 3423 printf(" Process: "PID_FMT" %s=%s ", p->pid, p->name, strna(argv));
582a507f 3424
96342de6 3425 good = is_clean_exit_lsb(p->code, p->status, NULL);
9a57c629 3426 if (!good) {
0b5a519c
DS
3427 on = ansi_highlight_red();
3428 off = ansi_highlight_off();
9a57c629
LP
3429 } else
3430 on = off = "";
3431
3432 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
3433
d06dacd0
LP
3434 if (p->code == CLD_EXITED) {
3435 const char *c;
3436
582a507f 3437 printf("status=%i", p->status);
d06dacd0 3438
1b64d026
LP
3439 c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
3440 if (c)
d06dacd0
LP
3441 printf("/%s", c);
3442
3443 } else
582a507f 3444 printf("signal=%s", signal_to_string(p->status));
9a57c629
LP
3445
3446 printf(")%s\n", off);
3447
582a507f
LP
3448 if (i->main_pid == p->pid &&
3449 i->start_timestamp == p->start_timestamp &&
3450 i->exit_timestamp == p->start_timestamp)
3451 /* Let's not show this twice */
3452 i->main_pid = 0;
3453
3454 if (p->pid == i->control_pid)
3455 i->control_pid = 0;
3456 }
3457
61cbdc4b 3458 if (i->main_pid > 0 || i->control_pid > 0) {
61cbdc4b 3459 if (i->main_pid > 0) {
8c06592f 3460 printf(" Main PID: "PID_FMT, i->main_pid);
61cbdc4b
LP
3461
3462 if (i->running) {
13160134
ZJS
3463 _cleanup_free_ char *comm = NULL;
3464 get_process_comm(i->main_pid, &comm);
3465 if (comm)
3466 printf(" (%s)", comm);
6d4fc029 3467 } else if (i->exit_code > 0) {
61cbdc4b
LP
3468 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
3469
d06dacd0
LP
3470 if (i->exit_code == CLD_EXITED) {
3471 const char *c;
3472
61cbdc4b 3473 printf("status=%i", i->exit_status);
d06dacd0 3474
1b64d026
LP
3475 c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
3476 if (c)
d06dacd0
LP
3477 printf("/%s", c);
3478
3479 } else
582a507f 3480 printf("signal=%s", signal_to_string(i->exit_status));
6d4fc029
LP
3481 printf(")");
3482 }
61cbdc4b 3483
13160134
ZJS
3484 if (i->control_pid > 0)
3485 printf(";");
3486 }
61cbdc4b
LP
3487
3488 if (i->control_pid > 0) {
13160134 3489 _cleanup_free_ char *c = NULL;
61cbdc4b 3490
8c06592f 3491 printf(" %8s: "PID_FMT, i->main_pid ? "" : " Control", i->control_pid);
61cbdc4b 3492
13160134
ZJS
3493 get_process_comm(i->control_pid, &c);
3494 if (c)
3495 printf(" (%s)", c);
61cbdc4b
LP
3496 }
3497
3498 printf("\n");
3499 }
3500
17bb7382 3501 if (i->status_text)
856323c9 3502 printf(" Status: \"%s\"\n", i->status_text);
b4af5a80
LP
3503 if (i->status_errno > 0)
3504 printf(" Error: %i (%s)\n", i->status_errno, strerror(i->status_errno));
17bb7382 3505
934277fe
LP
3506 if (i->memory_current != (uint64_t) -1) {
3507 char buf[FORMAT_BYTES_MAX];
3508
3509 printf(" Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current));
3510
3511 if (i->memory_limit != (uint64_t) -1)
3512 printf(" (limit: %s)\n", format_bytes(buf, sizeof(buf), i->memory_limit));
3513 else
3514 printf("\n");
3515 }
3516
5ad096b3
LP
3517 if (i->cpu_usage_nsec != (uint64_t) -1) {
3518 char buf[FORMAT_TIMESPAN_MAX];
3519 printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
3520 }
3521
4ad49000 3522 if (i->control_group &&
8fcf784d 3523 (i->main_pid > 0 || i->control_pid > 0 ||
de33fc62 3524 ((arg_transport != BUS_TRANSPORT_LOCAL && arg_transport != BUS_TRANSPORT_MACHINE) || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group, false) == 0))) {
ab35fb1b
LP
3525 unsigned c;
3526
4ad49000 3527 printf(" CGroup: %s\n", i->control_group);
ab35fb1b 3528
de33fc62 3529 if (arg_transport == BUS_TRANSPORT_LOCAL || arg_transport == BUS_TRANSPORT_MACHINE) {
b69d29ce
LP
3530 unsigned k = 0;
3531 pid_t extra[2];
8fcf784d 3532 static const char prefix[] = " ";
b69d29ce
LP
3533
3534 c = columns();
e8853816
ZJS
3535 if (c > sizeof(prefix) - 1)
3536 c -= sizeof(prefix) - 1;
a8f11321
LP
3537 else
3538 c = 0;
ab35fb1b 3539
b69d29ce
LP
3540 if (i->main_pid > 0)
3541 extra[k++] = i->main_pid;
3542
3543 if (i->control_pid > 0)
3544 extra[k++] = i->control_pid;
3545
3c756001 3546 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, false, extra, k, get_output_flags());
a8f11321 3547 }
c59760ee 3548 }
45fb0699 3549
f459b602 3550 if (i->id && arg_transport == BUS_TRANSPORT_LOCAL) {
3c756001
LP
3551 show_journal_by_unit(
3552 stdout,
3553 i->id,
3554 arg_output,
3555 0,
3556 i->inactive_exit_timestamp_monotonic,
3557 arg_lines,
3558 getuid(),
3559 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
3560 SD_JOURNAL_LOCAL_ONLY,
3561 arg_scope == UNIT_FILE_SYSTEM,
3562 ellipsized);
6f003b43 3563 }
86aa7ba4 3564
45fb0699 3565 if (i->need_daemon_reload)
3f36991e 3566 warn_unit_file_changed(i->id);
61cbdc4b
LP
3567}
3568
b43f208f 3569static void show_unit_help(UnitStatusInfo *i) {
256425cc
LP
3570 char **p;
3571
3572 assert(i);
3573
3574 if (!i->documentation) {
3575 log_info("Documentation for %s not known.", i->id);
3576 return;
3577 }
3578
78002a67
ZJS
3579 STRV_FOREACH(p, i->documentation)
3580 if (startswith(*p, "man:"))
3581 show_man_page(*p + 4, false);
3582 else
0315fe37 3583 log_info("Can't show: %s", *p);
256425cc
LP
3584}
3585
f459b602
MAP
3586static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *i, const char *contents) {
3587 int r;
61cbdc4b 3588
a4c279f8 3589 assert(name);
f459b602 3590 assert(m);
a4c279f8
LP
3591 assert(i);
3592
f459b602 3593 switch (contents[0]) {
61cbdc4b 3594
f459b602 3595 case SD_BUS_TYPE_STRING: {
61cbdc4b
LP
3596 const char *s;
3597
f459b602
MAP
3598 r = sd_bus_message_read(m, "s", &s);
3599 if (r < 0)
3600 return bus_log_parse_error(r);
61cbdc4b 3601
a4c279f8 3602 if (!isempty(s)) {
61cbdc4b
LP
3603 if (streq(name, "Id"))
3604 i->id = s;
3605 else if (streq(name, "LoadState"))
3606 i->load_state = s;
3607 else if (streq(name, "ActiveState"))
3608 i->active_state = s;
3609 else if (streq(name, "SubState"))
3610 i->sub_state = s;
3611 else if (streq(name, "Description"))
3612 i->description = s;
3613 else if (streq(name, "FragmentPath"))
1b64d026
LP
3614 i->fragment_path = s;
3615 else if (streq(name, "SourcePath"))
3616 i->source_path = s;
286ca485 3617#ifndef NOLEGACY
a00963a2
LP
3618 else if (streq(name, "DefaultControlGroup")) {
3619 const char *e;
3620 e = startswith(s, SYSTEMD_CGROUP_CONTROLLER ":");
3621 if (e)
3622 i->control_group = e;
3623 }
4ad49000
LP
3624#endif
3625 else if (streq(name, "ControlGroup"))
3626 i->control_group = s;
61cbdc4b
LP
3627 else if (streq(name, "StatusText"))
3628 i->status_text = s;
175728c4
HH
3629 else if (streq(name, "PIDFile"))
3630 i->pid_file = s;
61cbdc4b
LP
3631 else if (streq(name, "SysFSPath"))
3632 i->sysfs_path = s;
3633 else if (streq(name, "Where"))
3634 i->where = s;
3635 else if (streq(name, "What"))
3636 i->what = s;
4a9e2fff
LP
3637 else if (streq(name, "Following"))
3638 i->following = s;
a4375746
LP
3639 else if (streq(name, "UnitFileState"))
3640 i->unit_file_state = s;
d2dc52db
LP
3641 else if (streq(name, "UnitFilePreset"))
3642 i->unit_file_preset = s;
f42806df
LP
3643 else if (streq(name, "Result"))
3644 i->result = s;
61cbdc4b
LP
3645 }
3646
3647 break;
3648 }
3649
f459b602
MAP
3650 case SD_BUS_TYPE_BOOLEAN: {
3651 int b;
b8131a87 3652
f459b602
MAP
3653 r = sd_bus_message_read(m, "b", &b);
3654 if (r < 0)
3655 return bus_log_parse_error(r);
b8131a87
LP
3656
3657 if (streq(name, "Accept"))
3658 i->accept = b;
45fb0699
LP
3659 else if (streq(name, "NeedDaemonReload"))
3660 i->need_daemon_reload = b;
90bbc946
LP
3661 else if (streq(name, "ConditionResult"))
3662 i->condition_result = b;
59fccdc5
LP
3663 else if (streq(name, "AssertResult"))
3664 i->assert_result = b;
b8131a87
LP
3665
3666 break;
3667 }
3668
f459b602 3669 case SD_BUS_TYPE_UINT32: {
61cbdc4b
LP
3670 uint32_t u;
3671
f459b602
MAP
3672 r = sd_bus_message_read(m, "u", &u);
3673 if (r < 0)
3674 return bus_log_parse_error(r);
61cbdc4b
LP
3675
3676 if (streq(name, "MainPID")) {
3677 if (u > 0) {
3678 i->main_pid = (pid_t) u;
3679 i->running = true;
3680 }
3681 } else if (streq(name, "ControlPID"))
3682 i->control_pid = (pid_t) u;
3683 else if (streq(name, "ExecMainPID")) {
3684 if (u > 0)
3685 i->main_pid = (pid_t) u;
3686 } else if (streq(name, "NAccepted"))
3687 i->n_accepted = u;
3688 else if (streq(name, "NConnections"))
3689 i->n_connections = u;
3690
3691 break;
3692 }
3693
f459b602 3694 case SD_BUS_TYPE_INT32: {
61cbdc4b
LP
3695 int32_t j;
3696
f459b602
MAP
3697 r = sd_bus_message_read(m, "i", &j);
3698 if (r < 0)
3699 return bus_log_parse_error(r);
61cbdc4b
LP
3700
3701 if (streq(name, "ExecMainCode"))
3702 i->exit_code = (int) j;
3703 else if (streq(name, "ExecMainStatus"))
3704 i->exit_status = (int) j;
b4af5a80
LP
3705 else if (streq(name, "StatusErrno"))
3706 i->status_errno = (int) j;
61cbdc4b
LP
3707
3708 break;
3709 }
3710
f459b602 3711 case SD_BUS_TYPE_UINT64: {
61cbdc4b
LP
3712 uint64_t u;
3713
f459b602
MAP
3714 r = sd_bus_message_read(m, "t", &u);
3715 if (r < 0)
3716 return bus_log_parse_error(r);
61cbdc4b
LP
3717
3718 if (streq(name, "ExecMainStartTimestamp"))
3719 i->start_timestamp = (usec_t) u;
3720 else if (streq(name, "ExecMainExitTimestamp"))
3721 i->exit_timestamp = (usec_t) u;
584be568
LP
3722 else if (streq(name, "ActiveEnterTimestamp"))
3723 i->active_enter_timestamp = (usec_t) u;
3724 else if (streq(name, "InactiveEnterTimestamp"))
3725 i->inactive_enter_timestamp = (usec_t) u;
3726 else if (streq(name, "InactiveExitTimestamp"))
3727 i->inactive_exit_timestamp = (usec_t) u;
df50185b
LP
3728 else if (streq(name, "InactiveExitTimestampMonotonic"))
3729 i->inactive_exit_timestamp_monotonic = (usec_t) u;
584be568
LP
3730 else if (streq(name, "ActiveExitTimestamp"))
3731 i->active_exit_timestamp = (usec_t) u;
90bbc946
LP
3732 else if (streq(name, "ConditionTimestamp"))
3733 i->condition_timestamp = (usec_t) u;
59fccdc5
LP
3734 else if (streq(name, "AssertTimestamp"))
3735 i->assert_timestamp = (usec_t) u;
934277fe
LP
3736 else if (streq(name, "MemoryCurrent"))
3737 i->memory_current = u;
3738 else if (streq(name, "MemoryLimit"))
3739 i->memory_limit = u;
5ad096b3
LP
3740 else if (streq(name, "CPUUsageNSec"))
3741 i->cpu_usage_nsec = u;
61cbdc4b
LP
3742
3743 break;
3744 }
582a507f 3745
f459b602 3746 case SD_BUS_TYPE_ARRAY:
582a507f 3747
f459b602
MAP
3748 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
3749 _cleanup_free_ ExecStatusInfo *info = NULL;
582a507f 3750
f459b602
MAP
3751 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
3752 if (r < 0)
3753 return bus_log_parse_error(r);
582a507f 3754
f459b602
MAP
3755 info = new0(ExecStatusInfo, 1);
3756 if (!info)
3757 return log_oom();
582a507f 3758
f459b602 3759 while ((r = exec_status_info_deserialize(m, info)) > 0) {
0129173a 3760
f459b602
MAP
3761 info->name = strdup(name);
3762 if (!info->name)
3763 log_oom();
582a507f 3764
71fda00f 3765 LIST_PREPEND(exec, i->exec, info);
582a507f 3766
f459b602
MAP
3767 info = new0(ExecStatusInfo, 1);
3768 if (!info)
3769 log_oom();
49dbfa7b 3770 }
67419600 3771
f459b602
MAP
3772 if (r < 0)
3773 return bus_log_parse_error(r);
67419600 3774
f459b602
MAP
3775 r = sd_bus_message_exit_container(m);
3776 if (r < 0)
3777 return bus_log_parse_error(r);
67419600 3778
f459b602 3779 return 0;
67419600 3780
f459b602
MAP
3781 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
3782 const char *type, *path;
13160134 3783
f459b602
MAP
3784 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
3785 if (r < 0)
3786 return bus_log_parse_error(r);
67419600 3787
f459b602 3788 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0) {
67419600 3789
f459b602
MAP
3790 r = strv_extend(&i->listen, type);
3791 if (r < 0)
3792 return r;
67419600 3793
f459b602
MAP
3794 r = strv_extend(&i->listen, path);
3795 if (r < 0)
3796 return r;
3797 }
76d14b87 3798 if (r < 0)
f459b602 3799 return bus_log_parse_error(r);
76d14b87 3800
f459b602
MAP
3801 r = sd_bus_message_exit_container(m);
3802 if (r < 0)
3803 return bus_log_parse_error(r);
49dbfa7b 3804
f459b602 3805 return 0;
49dbfa7b 3806
f459b602 3807 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "DropInPaths")) {
49dbfa7b 3808
f459b602
MAP
3809 r = sd_bus_message_read_strv(m, &i->dropin_paths);
3810 if (r < 0)
3811 return bus_log_parse_error(r);
49dbfa7b 3812
f459b602 3813 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "Documentation")) {
49dbfa7b 3814
f459b602
MAP
3815 r = sd_bus_message_read_strv(m, &i->documentation);
3816 if (r < 0)
3817 return bus_log_parse_error(r);
52990c2e 3818
f459b602
MAP
3819 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Conditions")) {
3820 const char *cond, *param;
3821 int trigger, negate;
3822 int32_t state;
52990c2e 3823
f459b602
MAP
3824 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
3825 if (r < 0)
3826 return bus_log_parse_error(r);
3827
3828 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
3829 log_debug("%s %d %d %s %d", cond, trigger, negate, param, state);
3830 if (state < 0 && (!trigger || !i->failed_condition)) {
3831 i->failed_condition = cond;
3832 i->failed_condition_trigger = trigger;
3833 i->failed_condition_negate = negate;
59fccdc5
LP
3834 i->failed_condition_parameter = param;
3835 }
3836 }
3837 if (r < 0)
3838 return bus_log_parse_error(r);
3839
3840 r = sd_bus_message_exit_container(m);
3841 if (r < 0)
3842 return bus_log_parse_error(r);
3843
3844 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Asserts")) {
3845 const char *cond, *param;
3846 int trigger, negate;
3847 int32_t state;
3848
3849 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
3850 if (r < 0)
3851 return bus_log_parse_error(r);
3852
3853 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
3854 log_debug("%s %d %d %s %d", cond, trigger, negate, param, state);
3855 if (state < 0 && (!trigger || !i->failed_assert)) {
3856 i->failed_assert = cond;
3857 i->failed_assert_trigger = trigger;
3858 i->failed_assert_negate = negate;
3859 i->failed_assert_parameter = param;
f459b602 3860 }
582a507f 3861 }
f459b602
MAP
3862 if (r < 0)
3863 return bus_log_parse_error(r);
3864
3865 r = sd_bus_message_exit_container(m);
3866 if (r < 0)
3867 return bus_log_parse_error(r);
3868
3869 } else
3870 goto skip;
582a507f
LP
3871
3872 break;
9f39404c 3873
f459b602 3874 case SD_BUS_TYPE_STRUCT_BEGIN:
9f39404c
LP
3875
3876 if (streq(name, "LoadError")) {
9f39404c 3877 const char *n, *message;
9f39404c 3878
f459b602 3879 r = sd_bus_message_read(m, "(ss)", &n, &message);
9f39404c 3880 if (r < 0)
f459b602 3881 return bus_log_parse_error(r);
9f39404c
LP
3882
3883 if (!isempty(message))
3884 i->load_error = message;
f459b602
MAP
3885 } else
3886 goto skip;
9f39404c
LP
3887
3888 break;
f459b602
MAP
3889
3890 default:
3891 goto skip;
9f39404c 3892 }
f459b602
MAP
3893
3894 return 0;
3895
3896skip:
3897 r = sd_bus_message_skip(m, contents);
3898 if (r < 0)
3899 return bus_log_parse_error(r);
61cbdc4b
LP
3900
3901 return 0;
3902}
3903
f459b602
MAP
3904static int print_property(const char *name, sd_bus_message *m, const char *contents) {
3905 int r;
3906
48220598 3907 assert(name);
f459b602 3908 assert(m);
48220598 3909
61cbdc4b
LP
3910 /* This is a low-level property printer, see
3911 * print_status_info() for the nicer output */
3912
852c1b4d
ZJS
3913 if (arg_properties && !strv_find(arg_properties, name)) {
3914 /* skip what we didn't read */
3915 r = sd_bus_message_skip(m, contents);
3916 return r;
3917 }
48220598 3918
f459b602 3919 switch (contents[0]) {
48220598 3920
f459b602 3921 case SD_BUS_TYPE_STRUCT_BEGIN:
48220598 3922
f459b602 3923 if (contents[1] == SD_BUS_TYPE_UINT32 && streq(name, "Job")) {
48220598
LP
3924 uint32_t u;
3925
f459b602
MAP
3926 r = sd_bus_message_read(m, "(uo)", &u, NULL);
3927 if (r < 0)
3928 return bus_log_parse_error(r);
48220598 3929
f459b602 3930 if (u > 0)
8c06592f 3931 printf("%s=%"PRIu32"\n", name, u);
48220598
LP
3932 else if (arg_all)
3933 printf("%s=\n", name);
3934
3935 return 0;
f459b602
MAP
3936
3937 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "Unit")) {
48220598
LP
3938 const char *s;
3939
f459b602
MAP
3940 r = sd_bus_message_read(m, "(so)", &s, NULL);
3941 if (r < 0)
3942 return bus_log_parse_error(r);
48220598 3943
f459b602 3944 if (arg_all || !isempty(s))
48220598
LP
3945 printf("%s=%s\n", name, s);
3946
3947 return 0;
f459b602
MAP
3948
3949 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "LoadError")) {
9f39404c
LP
3950 const char *a = NULL, *b = NULL;
3951
f459b602
MAP
3952 r = sd_bus_message_read(m, "(ss)", &a, &b);
3953 if (r < 0)
3954 return bus_log_parse_error(r);
9f39404c
LP
3955
3956 if (arg_all || !isempty(a) || !isempty(b))
3957 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
f786e80d 3958
57183d11
LP
3959 return 0;
3960 } else if (streq_ptr(name, "SystemCallFilter")) {
3961 _cleanup_strv_free_ char **l = NULL;
3962 int whitelist;
3963
3964 r = sd_bus_message_enter_container(m, 'r', "bas");
3965 if (r < 0)
3966 return bus_log_parse_error(r);
3967
3968 r = sd_bus_message_read(m, "b", &whitelist);
3969 if (r < 0)
3970 return bus_log_parse_error(r);
3971
3972 r = sd_bus_message_read_strv(m, &l);
3973 if (r < 0)
3974 return bus_log_parse_error(r);
3975
3976 r = sd_bus_message_exit_container(m);
3977 if (r < 0)
3978 return bus_log_parse_error(r);
3979
3980 if (arg_all || whitelist || !strv_isempty(l)) {
3981 bool first = true;
3982 char **i;
3983
3984 fputs(name, stdout);
3985 fputc('=', stdout);
3986
3987 if (!whitelist)
3988 fputc('~', stdout);
3989
3990 STRV_FOREACH(i, l) {
3991 if (first)
3992 first = false;
3993 else
3994 fputc(' ', stdout);
3995
3996 fputs(*i, stdout);
3997 }
3998 fputc('\n', stdout);
3999 }
4000
f786e80d 4001 return 0;
48220598
LP
4002 }
4003
4004 break;
48220598 4005
f459b602 4006 case SD_BUS_TYPE_ARRAY:
48220598 4007
f459b602
MAP
4008 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "EnvironmentFiles")) {
4009 const char *path;
4010 int ignore;
8c7be95e 4011
f459b602
MAP
4012 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sb)");
4013 if (r < 0)
4014 return bus_log_parse_error(r);
8c7be95e 4015
f459b602
MAP
4016 while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
4017 printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
8c7be95e 4018
f459b602
MAP
4019 if (r < 0)
4020 return bus_log_parse_error(r);
8c7be95e 4021
f459b602
MAP
4022 r = sd_bus_message_exit_container(m);
4023 if (r < 0)
4024 return bus_log_parse_error(r);
8c7be95e
LP
4025
4026 return 0;
4027
f459b602
MAP
4028 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Paths")) {
4029 const char *type, *path;
67419600 4030
f459b602
MAP
4031 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4032 if (r < 0)
4033 return bus_log_parse_error(r);
ebf57b80 4034
f459b602
MAP
4035 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
4036 printf("%s=%s\n", type, path);
4037 if (r < 0)
4038 return bus_log_parse_error(r);
ebf57b80 4039
f459b602
MAP
4040 r = sd_bus_message_exit_container(m);
4041 if (r < 0)
4042 return bus_log_parse_error(r);
ebf57b80 4043
707e5e52 4044 return 0;
582a507f 4045
f459b602
MAP
4046 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
4047 const char *type, *path;
67419600 4048
f459b602
MAP
4049 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4050 if (r < 0)
4051 return bus_log_parse_error(r);
67419600 4052
f459b602
MAP
4053 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
4054 printf("Listen%s=%s\n", type, path);
4055 if (r < 0)
4056 return bus_log_parse_error(r);
67419600 4057
f459b602
MAP
4058 r = sd_bus_message_exit_container(m);
4059 if (r < 0)
4060 return bus_log_parse_error(r);
67419600
OS
4061
4062 return 0;
4063
f459b602
MAP
4064 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Timers")) {
4065 const char *base;
4066 uint64_t value, next_elapse;
707e5e52 4067
f459b602
MAP
4068 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(stt)");
4069 if (r < 0)
4070 return bus_log_parse_error(r);
552e4331 4071
f459b602
MAP
4072 while ((r = sd_bus_message_read(m, "(stt)", &base, &value, &next_elapse)) > 0) {
4073 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
fe68089d 4074
f459b602
MAP
4075 printf("%s={ value=%s ; next_elapse=%s }\n",
4076 base,
4077 format_timespan(timespan1, sizeof(timespan1), value, 0),
4078 format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
fe68089d 4079 }
f459b602
MAP
4080 if (r < 0)
4081 return bus_log_parse_error(r);
4082
4083 r = sd_bus_message_exit_container(m);
4084 if (r < 0)
4085 return bus_log_parse_error(r);
fe68089d
LP
4086
4087 return 0;
fe68089d 4088
f459b602
MAP
4089 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
4090 ExecStatusInfo info = {};
4091
4092 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
4093 if (r < 0)
4094 return bus_log_parse_error(r);
4095
4096 while ((r = exec_status_info_deserialize(m, &info)) > 0) {
4097 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
4098 _cleanup_free_ char *tt;
4099
4100 tt = strv_join(info.argv, " ");
4101
8c06592f 4102 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
4103 name,
4104 strna(info.path),
4105 strna(tt),
4106 yes_no(info.ignore),
4107 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
4108 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
8c06592f 4109 info.pid,
f459b602
MAP
4110 sigchld_code_to_string(info.code),
4111 info.status,
4112 info.code == CLD_EXITED ? "" : "/",
4113 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
fe68089d 4114
582a507f
LP
4115 free(info.path);
4116 strv_free(info.argv);
f459b602 4117 zero(info);
707e5e52
LP
4118 }
4119
f459b602
MAP
4120 r = sd_bus_message_exit_container(m);
4121 if (r < 0)
4122 return bus_log_parse_error(r);
4123
48220598 4124 return 0;
4ad49000 4125
f459b602
MAP
4126 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "DeviceAllow")) {
4127 const char *path, *rwm;
4ad49000 4128
f459b602
MAP
4129 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4130 if (r < 0)
4131 return bus_log_parse_error(r);
4ad49000 4132
f459b602
MAP
4133 while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0)
4134 printf("%s=%s %s\n", name, strna(path), strna(rwm));
4135 if (r < 0)
4136 return bus_log_parse_error(r);
4ad49000 4137
f459b602
MAP
4138 r = sd_bus_message_exit_container(m);
4139 if (r < 0)
4140 return bus_log_parse_error(r);
4ad49000 4141
4ad49000
LP
4142 return 0;
4143
f459b602
MAP
4144 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "BlockIODeviceWeight")) {
4145 const char *path;
4146 uint64_t weight;
b8ab2dc6 4147
f459b602
MAP
4148 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
4149 if (r < 0)
4150 return bus_log_parse_error(r);
b8ab2dc6 4151
f459b602
MAP
4152 while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0)
4153 printf("%s=%s %" PRIu64 "\n", name, strna(path), weight);
4154 if (r < 0)
4155 return bus_log_parse_error(r);
b8ab2dc6 4156
f459b602
MAP
4157 r = sd_bus_message_exit_container(m);
4158 if (r < 0)
4159 return bus_log_parse_error(r);
b8ab2dc6 4160
b8ab2dc6
G
4161 return 0;
4162
f459b602
MAP
4163 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) {
4164 const char *path;
4165 uint64_t bandwidth;
4ad49000 4166
f459b602
MAP
4167 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
4168 if (r < 0)
4169 return bus_log_parse_error(r);
4ad49000 4170
f459b602
MAP
4171 while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0)
4172 printf("%s=%s %" PRIu64 "\n", name, strna(path), bandwidth);
4173 if (r < 0)
4174 return bus_log_parse_error(r);
4ad49000 4175
f459b602
MAP
4176 r = sd_bus_message_exit_container(m);
4177 if (r < 0)
4178 return bus_log_parse_error(r);
4ad49000 4179
4ad49000 4180 return 0;
48220598
LP
4181 }
4182
4183 break;
4184 }
4185
f459b602
MAP
4186 r = bus_print_property(name, m, arg_all);
4187 if (r < 0)
4188 return bus_log_parse_error(r);
4189
4190 if (r == 0) {
4191 r = sd_bus_message_skip(m, contents);
4192 if (r < 0)
4193 return bus_log_parse_error(r);
a4c279f8 4194
f459b602
MAP
4195 if (arg_all)
4196 printf("%s=[unprintable]\n", name);
4197 }
48220598
LP
4198
4199 return 0;
4200}
4201
f459b602
MAP
4202static int show_one(
4203 const char *verb,
4204 sd_bus *bus,
4205 const char *path,
4206 bool show_properties,
4207 bool *new_line,
4208 bool *ellipsized) {
4209
4210 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4211 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
934277fe
LP
4212 UnitStatusInfo info = {
4213 .memory_current = (uint64_t) -1,
4214 .memory_limit = (uint64_t) -1,
5ad096b3 4215 .cpu_usage_nsec = (uint64_t) -1,
934277fe 4216 };
582a507f 4217 ExecStatusInfo *p;
f459b602 4218 int r;
48220598 4219
48220598 4220 assert(path);
61cbdc4b 4221 assert(new_line);
48220598 4222
e3e0314b
ZJS
4223 log_debug("Showing one %s", path);
4224
f459b602 4225 r = sd_bus_call_method(
f22f08cd
SP
4226 bus,
4227 "org.freedesktop.systemd1",
4228 path,
4229 "org.freedesktop.DBus.Properties",
4230 "GetAll",
f459b602 4231 &error,
f22f08cd 4232 &reply,
f459b602
MAP
4233 "s", "");
4234 if (r < 0) {
4235 log_error("Failed to get properties: %s", bus_error_message(&error, r));
f84190d8 4236 return r;
48220598
LP
4237 }
4238
f459b602
MAP
4239 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
4240 if (r < 0)
4241 return bus_log_parse_error(r);
48220598 4242
61cbdc4b
LP
4243 if (*new_line)
4244 printf("\n");
4245
4246 *new_line = true;
4247
f459b602
MAP
4248 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
4249 const char *name, *contents;
0183528f 4250
f459b602
MAP
4251 r = sd_bus_message_read(reply, "s", &name);
4252 if (r < 0)
4253 return bus_log_parse_error(r);
48220598 4254
f459b602
MAP
4255 r = sd_bus_message_peek_type(reply, NULL, &contents);
4256 if (r < 0)
4257 return bus_log_parse_error(r);
4258
4259 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
4260 if (r < 0)
4261 return bus_log_parse_error(r);
48220598 4262
61cbdc4b 4263 if (show_properties)
f459b602 4264 r = print_property(name, reply, contents);
61cbdc4b 4265 else
f459b602
MAP
4266 r = status_property(name, reply, &info, contents);
4267 if (r < 0)
4268 return r;
48220598 4269
f459b602
MAP
4270 r = sd_bus_message_exit_container(reply);
4271 if (r < 0)
4272 return bus_log_parse_error(r);
4273
4274 r = sd_bus_message_exit_container(reply);
4275 if (r < 0)
4276 return bus_log_parse_error(r);
48220598 4277 }
f459b602
MAP
4278 if (r < 0)
4279 return bus_log_parse_error(r);
4280
4281 r = sd_bus_message_exit_container(reply);
4282 if (r < 0)
4283 return bus_log_parse_error(r);
48220598 4284
f1e36d67
LP
4285 r = 0;
4286
256425cc 4287 if (!show_properties) {
b43f208f
KS
4288 if (streq(verb, "help"))
4289 show_unit_help(&info);
256425cc 4290 else
94e0bd7d 4291 print_status_info(&info, ellipsized);
256425cc 4292 }
f1e36d67 4293
49dbfa7b 4294 strv_free(info.documentation);
76d14b87 4295 strv_free(info.dropin_paths);
67419600 4296 strv_free(info.listen);
49dbfa7b 4297
22f4096c 4298 if (!streq_ptr(info.active_state, "active") &&
be8088a2 4299 !streq_ptr(info.active_state, "reloading") &&
3b05b8b3 4300 streq(verb, "status")) {
22f4096c 4301 /* According to LSB: "program not running" */
175728c4 4302 /* 0: program is running or service is OK
41a55c46
ZJS
4303 * 1: program is dead and /run PID file exists
4304 * 2: program is dead and /run/lock lock file exists
175728c4
HH
4305 * 3: program is not running
4306 * 4: program or service status is unknown
4307 */
3b05b8b3 4308 if (info.pid_file && access(info.pid_file, F_OK) == 0)
175728c4
HH
4309 r = 1;
4310 else
4311 r = 3;
e9c1ea9d 4312 }
61cbdc4b 4313
582a507f 4314 while ((p = info.exec)) {
71fda00f 4315 LIST_REMOVE(exec, info.exec, p);
582a507f
LP
4316 exec_status_info_free(p);
4317 }
4318
48220598
LP
4319 return r;
4320}
4321
f74294c1 4322static int get_unit_dbus_path_by_pid(
f459b602
MAP
4323 sd_bus *bus,
4324 uint32_t pid,
f74294c1 4325 char **unit) {
f459b602
MAP
4326
4327 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4328 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
373d32c9 4329 char *u;
a223b325
MS
4330 int r;
4331
f459b602 4332 r = sd_bus_call_method(
f22f08cd
SP
4333 bus,
4334 "org.freedesktop.systemd1",
4335 "/org/freedesktop/systemd1",
4336 "org.freedesktop.systemd1.Manager",
4337 "GetUnitByPID",
f459b602 4338 &error,
f22f08cd 4339 &reply,
f459b602
MAP
4340 "u", pid);
4341 if (r < 0) {
1fa2f38f 4342 log_error("Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
cec7eda5 4343 return r;
a223b325
MS
4344 }
4345
373d32c9 4346 r = sd_bus_message_read(reply, "o", &u);
f459b602
MAP
4347 if (r < 0)
4348 return bus_log_parse_error(r);
4349
373d32c9
LP
4350 u = strdup(u);
4351 if (!u)
4352 return log_oom();
4353
4354 *unit = u;
f74294c1 4355 return 0;
a223b325
MS
4356}
4357
f459b602
MAP
4358static int show_all(
4359 const char* verb,
4360 sd_bus *bus,
4361 bool show_properties,
4362 bool *new_line,
4363 bool *ellipsized) {
4364
f459b602
MAP
4365 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4366 _cleanup_free_ UnitInfo *unit_infos = NULL;
4367 const UnitInfo *u;
4368 unsigned c;
5bb75bc7 4369 int r, ret = 0;
265a7a2a 4370
1238ee09 4371 r = get_unit_list(bus, NULL, NULL, &unit_infos, 0, &reply);
265a7a2a
ZJS
4372 if (r < 0)
4373 return r;
4374
dbed408b
LP
4375 pager_open_if_enabled();
4376
f459b602
MAP
4377 c = (unsigned) r;
4378
4379 qsort_safe(unit_infos, c, sizeof(UnitInfo), compare_unit_info);
991f2a39 4380
265a7a2a 4381 for (u = unit_infos; u < unit_infos + c; u++) {
7fd1b19b 4382 _cleanup_free_ char *p = NULL;
265a7a2a 4383
265a7a2a
ZJS
4384 p = unit_dbus_path_from_name(u->id);
4385 if (!p)
4386 return log_oom();
4387
94e0bd7d 4388 r = show_one(verb, bus, p, show_properties, new_line, ellipsized);
3df538da 4389 if (r < 0)
265a7a2a 4390 return r;
5bb75bc7
ZJS
4391 else if (r > 0 && ret == 0)
4392 ret = r;
265a7a2a
ZJS
4393 }
4394
5bb75bc7 4395 return ret;
265a7a2a
ZJS
4396}
4397
8fcf784d
LP
4398static int show_system_status(sd_bus *bus) {
4399 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
4400 _cleanup_free_ char *hn = NULL;
4401 struct machine_info mi = {};
4402 const char *on, *off;
4403 int r;
4404
4405 hn = gethostname_malloc();
4406 if (!hn)
4407 return log_oom();
4408
4409 r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, &mi);
f647962d
MS
4410 if (r < 0)
4411 return log_error_errno(r, "Failed to read server status: %m");
8fcf784d 4412
8fcf784d
LP
4413 if (streq_ptr(mi.state, "degraded")) {
4414 on = ansi_highlight_red();
4415 off = ansi_highlight_off();
4416 } else if (!streq_ptr(mi.state, "running")) {
4417 on = ansi_highlight_yellow();
4418 off = ansi_highlight_off();
4419 } else
4420 on = off = "";
4421
6b01f1d3 4422 printf("%s%s%s %s\n", on, draw_special_char(DRAW_BLACK_CIRCLE), off, arg_host ? arg_host : hn);
b0d14c69 4423
8fcf784d
LP
4424 printf(" State: %s%s%s\n",
4425 on, strna(mi.state), off);
4426
4427 printf(" Jobs: %u queued\n", mi.n_jobs);
4428 printf(" Failed: %u units\n", mi.n_failed_units);
4429
4430 printf(" Since: %s; %s\n",
4431 format_timestamp(since2, sizeof(since2), mi.timestamp),
4432 format_timestamp_relative(since1, sizeof(since1), mi.timestamp));
4433
4434 printf(" CGroup: %s\n", mi.control_group ?: "/");
de33fc62 4435 if (arg_transport == BUS_TRANSPORT_LOCAL || arg_transport == BUS_TRANSPORT_MACHINE) {
8fcf784d
LP
4436 static const char prefix[] = " ";
4437 unsigned c;
4438
4439 c = columns();
4440 if (c > sizeof(prefix) - 1)
4441 c -= sizeof(prefix) - 1;
4442 else
4443 c = 0;
4444
3c756001 4445 show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, false, get_output_flags());
8fcf784d
LP
4446 }
4447
4448 free(mi.state);
4449 free(mi.control_group);
4450
4451 return 0;
4452}
4453
f459b602 4454static int show(sd_bus *bus, char **args) {
265a7a2a 4455 bool show_properties, show_status, new_line = false;
94e0bd7d 4456 bool ellipsized = false;
e3e0314b 4457 int r, ret = 0;
48220598
LP
4458
4459 assert(bus);
4460 assert(args);
4461
256425cc 4462 show_properties = streq(args[0], "show");
265a7a2a 4463 show_status = streq(args[0], "status");
61cbdc4b 4464
ec14911e 4465 if (show_properties)
1968a360 4466 pager_open_if_enabled();
ec14911e 4467
40acc203
ZJS
4468 if (show_status)
4469 /* Increase max number of open files to 16K if we can, we
4470 * might needs this when browsing journal files, which might
4471 * be split up into many files. */
4472 setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
4473
f84190d8 4474 /* If no argument is specified inspect the manager itself */
48220598 4475
f84190d8 4476 if (show_properties && strv_length(args) <= 1)
94e0bd7d 4477 return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized);
48220598 4478
8fcf784d
LP
4479 if (show_status && strv_length(args) <= 1) {
4480
c3441de0 4481 pager_open_if_enabled();
8fcf784d
LP
4482 show_system_status(bus);
4483 new_line = true;
4484
4485 if (arg_all)
4486 ret = show_all(args[0], bus, false, &new_line, &ellipsized);
4487 } else {
e3e0314b
ZJS
4488 _cleanup_free_ char **patterns = NULL;
4489 char **name;
4490
4491 STRV_FOREACH(name, args + 1) {
f74294c1 4492 _cleanup_free_ char *unit = NULL;
94e0bd7d 4493 uint32_t id;
48220598 4494
94e0bd7d 4495 if (safe_atou32(*name, &id) < 0) {
e3e0314b 4496 if (strv_push(&patterns, *name) < 0)
94e0bd7d 4497 return log_oom();
48220598 4498
e3e0314b 4499 continue;
94e0bd7d 4500 } else if (show_properties) {
94e0bd7d 4501 /* Interpret as job id */
f74294c1 4502 if (asprintf(&unit, "/org/freedesktop/systemd1/job/%u", id) < 0)
94e0bd7d 4503 return log_oom();
48220598 4504
94e0bd7d
ZJS
4505 } else {
4506 /* Interpret as PID */
f74294c1 4507 r = get_unit_dbus_path_by_pid(bus, id, &unit);
373d32c9 4508 if (r < 0) {
94e0bd7d 4509 ret = r;
373d32c9
LP
4510 continue;
4511 }
94e0bd7d 4512 }
f74294c1 4513
5bb75bc7
ZJS
4514 r = show_one(args[0], bus, unit, show_properties,
4515 &new_line, &ellipsized);
4516 if (r < 0)
4517 return r;
4518 else if (r > 0 && ret == 0)
4519 ret = r;
48220598 4520 }
94e0bd7d 4521
e3e0314b
ZJS
4522 if (!strv_isempty(patterns)) {
4523 _cleanup_strv_free_ char **names = NULL;
4524
4525 r = expand_names(bus, patterns, NULL, &names);
4526 if (r < 0)
da927ba9 4527 log_error_errno(r, "Failed to expand names: %m");
e3e0314b
ZJS
4528
4529 STRV_FOREACH(name, names) {
4530 _cleanup_free_ char *unit;
4531
4532 unit = unit_dbus_path_from_name(*name);
4533 if (!unit)
4534 return log_oom();
4535
5bb75bc7
ZJS
4536 r = show_one(args[0], bus, unit, show_properties,
4537 &new_line, &ellipsized);
4538 if (r < 0)
4539 return r;
4540 else if (r > 0 && ret == 0)
4541 ret = r;
e3e0314b
ZJS
4542 }
4543 }
4544 }
4545
94e0bd7d
ZJS
4546 if (ellipsized && !arg_quiet)
4547 printf("Hint: Some lines were ellipsized, use -l to show in full.\n");
48220598 4548
22f4096c 4549 return ret;
0183528f
LP
4550}
4551
8df18507
ZJS
4552static int init_home_and_lookup_paths(char **user_home, char **user_runtime, LookupPaths *lp) {
4553 int r;
4554
4555 assert(user_home);
4556 assert(user_runtime);
4557 assert(lp);
4558
4559 if (arg_scope == UNIT_FILE_USER) {
4560 r = user_config_home(user_home);
4561 if (r < 0)
4562 return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m");
4563 else if (r == 0)
4564 return log_error_errno(ENOTDIR, "Cannot find units: $XDG_CONFIG_HOME and $HOME are not set.");
4565
4566 r = user_runtime_dir(user_runtime);
4567 if (r < 0)
4568 return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m");
4569 else if (r == 0)
4570 return log_error_errno(ENOTDIR, "Cannot find units: $XDG_RUNTIME_DIR is not set.");
4571 }
4572
60d27f19 4573 r = lookup_paths_init_from_scope(lp, arg_scope, arg_root);
8df18507 4574 if (r < 0)
029009d4 4575 return log_error_errno(r, "Failed to query unit lookup paths: %m");
8df18507
ZJS
4576
4577 return 0;
4578}
4579
8527b07b
ZJS
4580static int cat_file(const char *filename, bool newline) {
4581 _cleanup_close_ int fd;
4582
4583 fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOCTTY);
4584 if (fd < 0)
4585 return -errno;
4586
4587 printf("%s%s# %s%s\n",
4588 newline ? "\n" : "",
4589 ansi_highlight_blue(),
4590 filename,
4591 ansi_highlight_off());
4592 fflush(stdout);
4593
4594 return copy_bytes(fd, STDOUT_FILENO, (off_t) -1, false);
4595}
4596
15ef1144 4597static int cat(sd_bus *bus, char **args) {
ad2a0358
ZJS
4598 _cleanup_free_ char *user_home = NULL;
4599 _cleanup_free_ char *user_runtime = NULL;
4600 _cleanup_lookup_paths_free_ LookupPaths lp = {};
15ef1144
LP
4601 _cleanup_strv_free_ char **names = NULL;
4602 char **name;
ad2a0358 4603 bool first = true, avoid_bus_cache;
25586912 4604 int r;
15ef1144 4605
15ef1144
LP
4606 assert(args);
4607
3e7eed84
IS
4608 if (arg_transport != BUS_TRANSPORT_LOCAL) {
4609 log_error("Cannot remotely cat units");
3e495a66
ZJS
4610 return -EINVAL;
4611 }
4612
ad2a0358
ZJS
4613 r = init_home_and_lookup_paths(&user_home, &user_runtime, &lp);
4614 if (r < 0)
4615 return r;
4616
15ef1144
LP
4617 r = expand_names(bus, args + 1, NULL, &names);
4618 if (r < 0)
3e7eed84 4619 return log_error_errno(r, "Failed to expand names: %m");
15ef1144 4620
ad2a0358
ZJS
4621 avoid_bus_cache = !bus || avoid_bus();
4622
15ef1144
LP
4623 pager_open_if_enabled();
4624
4625 STRV_FOREACH(name, names) {
ad2a0358 4626 _cleanup_free_ char *fragment_path = NULL;
15ef1144 4627 _cleanup_strv_free_ char **dropin_paths = NULL;
15ef1144
LP
4628 char **path;
4629
ad2a0358
ZJS
4630 r = unit_find_paths(bus, *name, avoid_bus_cache, &lp, &fragment_path, &dropin_paths);
4631 if (r < 0)
4632 return r;
b5e6a600
IS
4633 else if (r == 0)
4634 return -ENOENT;
15ef1144
LP
4635
4636 if (first)
4637 first = false;
4638 else
4639 puts("");
4640
ad2a0358 4641 if (fragment_path) {
8527b07b
ZJS
4642 r = cat_file(fragment_path, false);
4643 if (r < 0)
4644 return log_warning_errno(r, "Failed to cat %s: %m", fragment_path);
15ef1144
LP
4645 }
4646
4647 STRV_FOREACH(path, dropin_paths) {
8527b07b
ZJS
4648 r = cat_file(*path, path == dropin_paths);
4649 if (r < 0)
4650 return log_warning_errno(r, "Failed to cat %s: %m", *path);
15ef1144
LP
4651 }
4652 }
4653
25586912 4654 return 0;
15ef1144
LP
4655}
4656
f459b602
MAP
4657static int set_property(sd_bus *bus, char **args) {
4658 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
4659 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
68372da6 4660 _cleanup_free_ char *n = NULL;
8e2af478
LP
4661 char **i;
4662 int r;
4663
079dac08
LP
4664 polkit_agent_open_if_enabled();
4665
f459b602
MAP
4666 r = sd_bus_message_new_method_call(
4667 bus,
151b9b96 4668 &m,
8e2af478
LP
4669 "org.freedesktop.systemd1",
4670 "/org/freedesktop/systemd1",
4671 "org.freedesktop.systemd1.Manager",
151b9b96 4672 "SetUnitProperties");
f459b602
MAP
4673 if (r < 0)
4674 return bus_log_create_error(r);
8e2af478 4675
f78e6385 4676 n = unit_name_mangle(args[1], MANGLE_NOGLOB);
68372da6
LP
4677 if (!n)
4678 return log_oom();
4679
f459b602
MAP
4680 r = sd_bus_message_append(m, "sb", n, arg_runtime);
4681 if (r < 0)
4682 return bus_log_create_error(r);
8e2af478 4683
f459b602
MAP
4684 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, "(sv)");
4685 if (r < 0)
4686 return bus_log_create_error(r);
8e2af478 4687
f459b602
MAP
4688 STRV_FOREACH(i, args + 2) {
4689 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
4690 if (r < 0)
4691 return bus_log_create_error(r);
8e2af478 4692
df31a6c0 4693 r = bus_append_unit_property_assignment(m, *i);
8e2af478
LP
4694 if (r < 0)
4695 return r;
4696
f459b602
MAP
4697 r = sd_bus_message_close_container(m);
4698 if (r < 0)
4699 return bus_log_create_error(r);
8e2af478
LP
4700 }
4701
f459b602
MAP
4702 r = sd_bus_message_close_container(m);
4703 if (r < 0)
4704 return bus_log_create_error(r);
8e2af478 4705
c49b30a2 4706 r = sd_bus_call(bus, m, 0, &error, NULL);
f459b602
MAP
4707 if (r < 0) {
4708 log_error("Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
4709 return r;
8e2af478
LP
4710 }
4711
4712 return 0;
4713}
4714
f459b602
MAP
4715static int snapshot(sd_bus *bus, char **args) {
4716 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
6e646d22 4717 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
f459b602
MAP
4718 _cleanup_free_ char *n = NULL, *id = NULL;
4719 const char *path;
7e4249b9 4720 int r;
7e4249b9 4721
079dac08
LP
4722 polkit_agent_open_if_enabled();
4723
1dcf6065 4724 if (strv_length(args) > 1)
f78e6385 4725 n = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".snapshot");
1dcf6065
LP
4726 else
4727 n = strdup("");
4728 if (!n)
4729 return log_oom();
7e4249b9 4730
6e646d22 4731 r = sd_bus_call_method(
f22f08cd
SP
4732 bus,
4733 "org.freedesktop.systemd1",
4734 "/org/freedesktop/systemd1",
4735 "org.freedesktop.systemd1.Manager",
6e646d22
LP
4736 "CreateSnapshot",
4737 &error,
4738 &reply,
4739 "sb", n, false);
f459b602
MAP
4740 if (r < 0) {
4741 log_error("Failed to create snapshot: %s", bus_error_message(&error, r));
1dcf6065 4742 return r;
7e4249b9
LP
4743 }
4744
f459b602
MAP
4745 r = sd_bus_message_read(reply, "o", &path);
4746 if (r < 0)
4747 return bus_log_parse_error(r);
5dd9014f 4748
f459b602 4749 r = sd_bus_get_property_string(
f22f08cd
SP
4750 bus,
4751 "org.freedesktop.systemd1",
4752 path,
f459b602
MAP
4753 "org.freedesktop.systemd1.Unit",
4754 "Id",
4755 &error,
4756 &id);
4757 if (r < 0) {
4758 log_error("Failed to get ID of snapshot: %s", bus_error_message(&error, r));
1dcf6065 4759 return r;
7e4249b9
LP
4760 }
4761
0183528f
LP
4762 if (!arg_quiet)
4763 puts(id);
7e4249b9 4764
1dcf6065 4765 return 0;
7e4249b9
LP
4766}
4767
f459b602 4768static int delete_snapshot(sd_bus *bus, char **args) {
e3e0314b 4769 _cleanup_strv_free_ char **names = NULL;
729e3769 4770 char **name;
342641fb 4771 int r;
6759e7a7 4772
6759e7a7
LP
4773 assert(args);
4774
079dac08
LP
4775 polkit_agent_open_if_enabled();
4776
e3e0314b
ZJS
4777 r = expand_names(bus, args + 1, ".snapshot", &names);
4778 if (r < 0)
da927ba9 4779 log_error_errno(r, "Failed to expand names: %m");
1dcf6065 4780
e3e0314b 4781 STRV_FOREACH(name, names) {
6e646d22 4782 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
342641fb
LP
4783 int q;
4784
6e646d22 4785 q = sd_bus_call_method(
f22f08cd 4786 bus,
b0193f1c
LP
4787 "org.freedesktop.systemd1",
4788 "/org/freedesktop/systemd1",
4789 "org.freedesktop.systemd1.Manager",
6e646d22
LP
4790 "RemoveSnapshot",
4791 &error,
4792 NULL,
4793 "s", *name);
e3e0314b 4794 if (q < 0) {
342641fb 4795 log_error("Failed to remove snapshot %s: %s", *name, bus_error_message(&error, q));
e3e0314b
ZJS
4796 if (r == 0)
4797 r = q;
f459b602 4798 }
6759e7a7
LP
4799 }
4800
e3e0314b 4801 return r;
6759e7a7
LP
4802}
4803
f459b602
MAP
4804static int daemon_reload(sd_bus *bus, char **args) {
4805 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
7e4249b9 4806 const char *method;
f459b602 4807 int r;
7e4249b9 4808
079dac08
LP
4809 polkit_agent_open_if_enabled();
4810
e4b61340
LP
4811 if (arg_action == ACTION_RELOAD)
4812 method = "Reload";
4813 else if (arg_action == ACTION_REEXEC)
4814 method = "Reexecute";
4815 else {
4816 assert(arg_action == ACTION_SYSTEMCTL);
4817
4818 method =
20b09ca7
LP
4819 streq(args[0], "clear-jobs") ||
4820 streq(args[0], "cancel") ? "ClearJobs" :
4821 streq(args[0], "daemon-reexec") ? "Reexecute" :
4822 streq(args[0], "reset-failed") ? "ResetFailed" :
4823 streq(args[0], "halt") ? "Halt" :
4824 streq(args[0], "poweroff") ? "PowerOff" :
4825 streq(args[0], "reboot") ? "Reboot" :
4826 streq(args[0], "kexec") ? "KExec" :
4827 streq(args[0], "exit") ? "Exit" :
4828 /* "daemon-reload" */ "Reload";
e4b61340 4829 }
7e4249b9 4830
6e646d22 4831 r = sd_bus_call_method(
f22f08cd
SP
4832 bus,
4833 "org.freedesktop.systemd1",
4834 "/org/freedesktop/systemd1",
4835 "org.freedesktop.systemd1.Manager",
6e646d22
LP
4836 method,
4837 &error,
4838 NULL,
4839 NULL);
f22f08cd
SP
4840 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
4841 /* There's always a fallback possible for
4842 * legacy actions. */
4843 r = -EADDRNOTAVAIL;
d0ede8f1
LP
4844 else if ((r == -ETIMEDOUT || r == -ECONNRESET) && streq(method, "Reexecute"))
4845 /* On reexecution, we expect a disconnect, not a
4846 * reply */
f22f08cd 4847 r = 0;
1dcf6065 4848 else if (r < 0)
f459b602 4849 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
7e4249b9 4850
0a9776c2 4851 return r < 0 ? r : 0;
7e4249b9
LP
4852}
4853
f459b602 4854static int reset_failed(sd_bus *bus, char **args) {
e3e0314b 4855 _cleanup_strv_free_ char **names = NULL;
f84190d8 4856 char **name;
e3e0314b 4857 int r, q;
5632e374 4858
729e3769
LP
4859 if (strv_length(args) <= 1)
4860 return daemon_reload(bus, args);
5632e374 4861
079dac08
LP
4862 polkit_agent_open_if_enabled();
4863
e3e0314b
ZJS
4864 r = expand_names(bus, args + 1, NULL, &names);
4865 if (r < 0)
da927ba9 4866 log_error_errno(r, "Failed to expand names: %m");
f84190d8 4867
e3e0314b 4868 STRV_FOREACH(name, names) {
6e646d22 4869 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
342641fb 4870
6e646d22 4871 q = sd_bus_call_method(
f22f08cd 4872 bus,
b0193f1c
LP
4873 "org.freedesktop.systemd1",
4874 "/org/freedesktop/systemd1",
4875 "org.freedesktop.systemd1.Manager",
6e646d22
LP
4876 "ResetFailedUnit",
4877 &error,
4878 NULL,
4879 "s", *name);
e3e0314b 4880 if (q < 0) {
342641fb 4881 log_error("Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
e3e0314b
ZJS
4882 if (r == 0)
4883 r = q;
f459b602 4884 }
5632e374
LP
4885 }
4886
e3e0314b 4887 return r;
5632e374
LP
4888}
4889
f459b602
MAP
4890static int show_environment(sd_bus *bus, char **args) {
4891 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4892 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4893 const char *text;
7e4249b9 4894 int r;
7e4249b9 4895
1968a360 4896 pager_open_if_enabled();
ec14911e 4897
f459b602 4898 r = sd_bus_get_property(
f22f08cd
SP
4899 bus,
4900 "org.freedesktop.systemd1",
4901 "/org/freedesktop/systemd1",
f459b602
MAP
4902 "org.freedesktop.systemd1.Manager",
4903 "Environment",
4904 &error,
f22f08cd 4905 &reply,
f459b602
MAP
4906 "as");
4907 if (r < 0) {
4908 log_error("Failed to get environment: %s", bus_error_message(&error, r));
f84190d8 4909 return r;
7e4249b9
LP
4910 }
4911
f459b602
MAP
4912 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
4913 if (r < 0)
4914 return bus_log_parse_error(r);
7e4249b9 4915
f459b602 4916 while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0)
f84190d8 4917 puts(text);
f459b602
MAP
4918 if (r < 0)
4919 return bus_log_parse_error(r);
7e4249b9 4920
f459b602
MAP
4921 r = sd_bus_message_exit_container(reply);
4922 if (r < 0)
4923 return bus_log_parse_error(r);
7e4249b9 4924
f84190d8 4925 return 0;
7e4249b9
LP
4926}
4927
f459b602
MAP
4928static int switch_root(sd_bus *bus, char **args) {
4929 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
f39d4a08
HH
4930 _cleanup_free_ char *cmdline_init = NULL;
4931 const char *root, *init;
f459b602
MAP
4932 unsigned l;
4933 int r;
957eb8ca
LP
4934
4935 l = strv_length(args);
4936 if (l < 2 || l > 3) {
4937 log_error("Wrong number of arguments.");
4938 return -EINVAL;
4939 }
4940
4941 root = args[1];
13068da8
TG
4942
4943 if (l >= 3)
f39d4a08 4944 init = args[2];
13068da8 4945 else {
f39d4a08
HH
4946 r = parse_env_file("/proc/cmdline", WHITESPACE,
4947 "init", &cmdline_init,
4948 NULL);
4949 if (r < 0)
da927ba9 4950 log_debug_errno(r, "Failed to parse /proc/cmdline: %m");
13068da8 4951
f39d4a08 4952 init = cmdline_init;
13068da8 4953 }
f459b602 4954
f39d4a08
HH
4955 if (isempty(init))
4956 init = NULL;
4957
4958 if (init) {
4959 const char *root_systemd_path = NULL, *root_init_path = NULL;
4960
63c372cb
LP
4961 root_systemd_path = strjoina(root, "/" SYSTEMD_BINARY_PATH);
4962 root_init_path = strjoina(root, "/", init);
f39d4a08
HH
4963
4964 /* If the passed init is actually the same as the
4965 * systemd binary, then let's suppress it. */
4966 if (files_same(root_init_path, root_systemd_path) > 0)
4967 init = NULL;
4968 }
13068da8 4969
f39d4a08 4970 log_debug("Switching root - root: %s; init: %s", root, strna(init));
957eb8ca 4971
f459b602 4972 r = sd_bus_call_method(
f22f08cd 4973 bus,
957eb8ca
LP
4974 "org.freedesktop.systemd1",
4975 "/org/freedesktop/systemd1",
4976 "org.freedesktop.systemd1.Manager",
f22f08cd 4977 "SwitchRoot",
f459b602 4978 &error,
f22f08cd 4979 NULL,
f459b602
MAP
4980 "ss", root, init);
4981 if (r < 0) {
4982 log_error("Failed to switch root: %s", bus_error_message(&error, r));
4983 return r;
4984 }
4985
4986 return 0;
957eb8ca
LP
4987}
4988
f459b602
MAP
4989static int set_environment(sd_bus *bus, char **args) {
4990 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4991 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
7e4249b9 4992 const char *method;
31e767f7
LP
4993 int r;
4994
4995 assert(bus);
60f9ba0b 4996 assert(args);
7e4249b9 4997
6e646d22
LP
4998 polkit_agent_open_if_enabled();
4999
7e4249b9
LP
5000 method = streq(args[0], "set-environment")
5001 ? "SetEnvironment"
5002 : "UnsetEnvironment";
5003
f459b602
MAP
5004 r = sd_bus_message_new_method_call(
5005 bus,
151b9b96 5006 &m,
31e767f7
LP
5007 "org.freedesktop.systemd1",
5008 "/org/freedesktop/systemd1",
5009 "org.freedesktop.systemd1.Manager",
151b9b96 5010 method);
f459b602
MAP
5011 if (r < 0)
5012 return bus_log_create_error(r);
7e4249b9 5013
f459b602 5014 r = sd_bus_message_append_strv(m, args + 1);
31e767f7 5015 if (r < 0)
f459b602 5016 return bus_log_create_error(r);
7e4249b9 5017
c49b30a2 5018 r = sd_bus_call(bus, m, 0, &error, NULL);
f459b602
MAP
5019 if (r < 0) {
5020 log_error("Failed to set environment: %s", bus_error_message(&error, r));
5021 return r;
7e4249b9
LP
5022 }
5023
f84190d8 5024 return 0;
7e4249b9
LP
5025}
5026
ac3efa8a
LP
5027static int import_environment(sd_bus *bus, char **args) {
5028 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
5029 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
5030 int r;
5031
5032 assert(bus);
5033 assert(args);
5034
6e646d22
LP
5035 polkit_agent_open_if_enabled();
5036
ac3efa8a
LP
5037 r = sd_bus_message_new_method_call(
5038 bus,
151b9b96 5039 &m,
ac3efa8a
LP
5040 "org.freedesktop.systemd1",
5041 "/org/freedesktop/systemd1",
5042 "org.freedesktop.systemd1.Manager",
151b9b96 5043 "SetEnvironment");
ac3efa8a
LP
5044 if (r < 0)
5045 return bus_log_create_error(r);
5046
5047 if (strv_isempty(args + 1))
5048 r = sd_bus_message_append_strv(m, environ);
5049 else {
5050 char **a, **b;
5051
5052 r = sd_bus_message_open_container(m, 'a', "s");
5053 if (r < 0)
5054 return bus_log_create_error(r);
5055
5056 STRV_FOREACH(a, args + 1) {
5057
5058 if (!env_name_is_valid(*a)) {
5059 log_error("Not a valid environment variable name: %s", *a);
5060 return -EINVAL;
5061 }
5062
5063 STRV_FOREACH(b, environ) {
5064 const char *eq;
5065
5066 eq = startswith(*b, *a);
5067 if (eq && *eq == '=') {
5068
5069 r = sd_bus_message_append(m, "s", *b);
5070 if (r < 0)
5071 return bus_log_create_error(r);
5072
5073 break;
5074 }
5075 }
5076 }
5077
5078 r = sd_bus_message_close_container(m);
5079 }
5080 if (r < 0)
5081 return bus_log_create_error(r);
5082
5083 r = sd_bus_call(bus, m, 0, &error, NULL);
5084 if (r < 0) {
5085 log_error("Failed to import environment: %s", bus_error_message(&error, r));
5086 return r;
5087 }
5088
5089 return 0;
5090}
5091
cbb13b2a 5092static int enable_sysv_units(const char *verb, char **args) {
729e3769 5093 int r = 0;
ee5762e3 5094
77e68fa2 5095#if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
a644abed 5096 unsigned f = 0;
fb15be83 5097 _cleanup_lookup_paths_free_ LookupPaths paths = {};
ee5762e3 5098
729e3769
LP
5099 if (arg_scope != UNIT_FILE_SYSTEM)
5100 return 0;
ee5762e3 5101
729e3769
LP
5102 if (!streq(verb, "enable") &&
5103 !streq(verb, "disable") &&
5104 !streq(verb, "is-enabled"))
5105 return 0;
ee5762e3 5106
729e3769
LP
5107 /* Processes all SysV units, and reshuffles the array so that
5108 * afterwards only the native units remain */
ee5762e3 5109
12ed81d9 5110 r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, arg_root, NULL, NULL, NULL);
729e3769
LP
5111 if (r < 0)
5112 return r;
ee5762e3 5113
729e3769 5114 r = 0;
a644abed 5115 while (args[f]) {
729e3769 5116 const char *name;
05cae7f3 5117 _cleanup_free_ char *p = NULL, *q = NULL, *l = NULL;
729e3769
LP
5118 bool found_native = false, found_sysv;
5119 unsigned c = 1;
5120 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
05cae7f3 5121 char **k;
729e3769
LP
5122 int j;
5123 pid_t pid;
5124 siginfo_t status;
ee5762e3 5125
a644abed 5126 name = args[f++];
ee5762e3 5127
729e3769
LP
5128 if (!endswith(name, ".service"))
5129 continue;
ee5762e3 5130
729e3769
LP
5131 if (path_is_absolute(name))
5132 continue;
ee5762e3 5133
729e3769 5134 STRV_FOREACH(k, paths.unit_path) {
05cae7f3
ZJS
5135 _cleanup_free_ char *path = NULL;
5136
0c6ea3a4
ZJS
5137 path = path_join(arg_root, *k, name);
5138 if (!path)
60731f32 5139 return log_oom();
ee5762e3 5140
4723e4b2 5141 found_native = access(path, F_OK) >= 0;
729e3769
LP
5142 if (found_native)
5143 break;
5144 }
ee5762e3 5145
729e3769
LP
5146 if (found_native)
5147 continue;
ee5762e3 5148
0c6ea3a4
ZJS
5149 p = path_join(arg_root, SYSTEM_SYSVINIT_PATH, name);
5150 if (!p)
60731f32 5151 return log_oom();
ee5762e3 5152
05cae7f3 5153 p[strlen(p) - strlen(".service")] = 0;
729e3769 5154 found_sysv = access(p, F_OK) >= 0;
4b6756a8 5155 if (!found_sysv)
729e3769 5156 continue;
71fad675 5157
729e3769 5158 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
ee5762e3 5159
729e3769
LP
5160 if (!isempty(arg_root))
5161 argv[c++] = q = strappend("--root=", arg_root);
ee5762e3 5162
2b6bf07d 5163 argv[c++] = basename(p);
729e3769
LP
5164 argv[c++] =
5165 streq(verb, "enable") ? "on" :
5166 streq(verb, "disable") ? "off" : "--level=5";
5167 argv[c] = NULL;
ee5762e3 5168
729e3769 5169 l = strv_join((char**)argv, " ");
60731f32
ZJS
5170 if (!l)
5171 return log_oom();
ee5762e3 5172
729e3769 5173 log_info("Executing %s", l);
ee5762e3 5174
729e3769 5175 pid = fork();
4a62c710
MS
5176 if (pid < 0)
5177 return log_error_errno(errno, "Failed to fork: %m");
5178 else if (pid == 0) {
729e3769 5179 /* Child */
ee5762e3 5180
729e3769
LP
5181 execv(argv[0], (char**) argv);
5182 _exit(EXIT_FAILURE);
5183 }
ee5762e3 5184
729e3769
LP
5185 j = wait_for_terminate(pid, &status);
5186 if (j < 0) {
da927ba9 5187 log_error_errno(r, "Failed to wait for child: %m");
60731f32 5188 return j;
729e3769 5189 }
ee5762e3 5190
729e3769
LP
5191 if (status.si_code == CLD_EXITED) {
5192 if (streq(verb, "is-enabled")) {
5193 if (status.si_status == 0) {
5194 if (!arg_quiet)
5195 puts("enabled");
5196 r = 1;
5197 } else {
5198 if (!arg_quiet)
5199 puts("disabled");
5200 }
ee5762e3 5201
60731f32
ZJS
5202 } else if (status.si_status != 0)
5203 return -EINVAL;
5204 } else
5205 return -EPROTO;
ee5762e3 5206
a644abed 5207 /* Remove this entry, so that we don't try enabling it as native unit */
aba84331
LP
5208 assert(f > 0);
5209 f--;
5210 assert(args[f] == name);
5211 strv_remove(args, name);
729e3769 5212 }
ee5762e3 5213
729e3769
LP
5214#endif
5215 return r;
5216}
ee5762e3 5217
37370d0c 5218static int mangle_names(char **original_names, char ***mangled_names) {
a33fdebb 5219 char **i, **l, **name;
37370d0c 5220
a33fdebb
LP
5221 l = new(char*, strv_length(original_names) + 1);
5222 if (!l)
37370d0c
VP
5223 return log_oom();
5224
a33fdebb 5225 i = l;
37370d0c 5226 STRV_FOREACH(name, original_names) {
44386fc1
LN
5227
5228 /* When enabling units qualified path names are OK,
5229 * too, hence allow them explicitly. */
5230
5231 if (is_path(*name))
5232 *i = strdup(*name);
5233 else
f78e6385 5234 *i = unit_name_mangle(*name, MANGLE_NOGLOB);
44386fc1 5235
a33fdebb
LP
5236 if (!*i) {
5237 strv_free(l);
37370d0c 5238 return log_oom();
a33fdebb
LP
5239 }
5240
5241 i++;
37370d0c 5242 }
a33fdebb
LP
5243
5244 *i = NULL;
5245 *mangled_names = l;
37370d0c
VP
5246
5247 return 0;
5248}
5249
f459b602 5250static int enable_unit(sd_bus *bus, char **args) {
e3e0314b 5251 _cleanup_strv_free_ char **names = NULL;
729e3769
LP
5252 const char *verb = args[0];
5253 UnitFileChange *changes = NULL;
718db961 5254 unsigned n_changes = 0;
729e3769 5255 int carries_install_info = -1;
729e3769 5256 int r;
ee5762e3 5257
ab5919fa
MS
5258 if (!args[1])
5259 return 0;
5260
e3e0314b 5261 r = mangle_names(args+1, &names);
3a05c0f9 5262 if (r < 0)
cbb13b2a
VP
5263 return r;
5264
e3e0314b 5265 r = enable_sysv_units(verb, names);
cbb13b2a
VP
5266 if (r < 0)
5267 return r;
3a05c0f9 5268
67d66210
LP
5269 /* If the operation was fully executed by the SysV compat,
5270 * let's finish early */
5271 if (strv_isempty(names))
5272 return 0;
5273
729e3769
LP
5274 if (!bus || avoid_bus()) {
5275 if (streq(verb, "enable")) {
e3e0314b 5276 r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769
LP
5277 carries_install_info = r;
5278 } else if (streq(verb, "disable"))
e3e0314b 5279 r = unit_file_disable(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
729e3769 5280 else if (streq(verb, "reenable")) {
e3e0314b 5281 r = unit_file_reenable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769
LP
5282 carries_install_info = r;
5283 } else if (streq(verb, "link"))
e3e0314b 5284 r = unit_file_link(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769 5285 else if (streq(verb, "preset")) {
d309c1c3 5286 r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_preset_mode, arg_force, &changes, &n_changes);
729e3769
LP
5287 carries_install_info = r;
5288 } else if (streq(verb, "mask"))
e3e0314b 5289 r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769 5290 else if (streq(verb, "unmask"))
e3e0314b 5291 r = unit_file_unmask(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
729e3769
LP
5292 else
5293 assert_not_reached("Unknown verb");
ee5762e3 5294
729e3769 5295 if (r < 0) {
da927ba9 5296 log_error_errno(r, "Operation failed: %m");
729e3769 5297 goto finish;
ee5762e3
LP
5298 }
5299
718db961
LP
5300 if (!arg_quiet)
5301 dump_unit_file_changes(changes, n_changes);
ee5762e3 5302
df77cdf0 5303 r = 0;
729e3769 5304 } else {
718db961
LP
5305 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
5306 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
f459b602 5307 int expect_carries_install_info = false;
d309c1c3 5308 bool send_force = true, send_preset_mode = false;
718db961 5309 const char *method;
729e3769 5310
079dac08
LP
5311 polkit_agent_open_if_enabled();
5312
729e3769
LP
5313 if (streq(verb, "enable")) {
5314 method = "EnableUnitFiles";
5315 expect_carries_install_info = true;
5316 } else if (streq(verb, "disable")) {
5317 method = "DisableUnitFiles";
5318 send_force = false;
5319 } else if (streq(verb, "reenable")) {
5320 method = "ReenableUnitFiles";
5321 expect_carries_install_info = true;
5322 } else if (streq(verb, "link"))
5323 method = "LinkUnitFiles";
5324 else if (streq(verb, "preset")) {
d309c1c3
LP
5325
5326 if (arg_preset_mode != UNIT_FILE_PRESET_FULL) {
5327 method = "PresetUnitFilesWithMode";
5328 send_preset_mode = true;
5329 } else
5330 method = "PresetUnitFiles";
5331
729e3769
LP
5332 expect_carries_install_info = true;
5333 } else if (streq(verb, "mask"))
5334 method = "MaskUnitFiles";
5335 else if (streq(verb, "unmask")) {
5336 method = "UnmaskUnitFiles";
5337 send_force = false;
5338 } else
5339 assert_not_reached("Unknown verb");
5340
f459b602
MAP
5341 r = sd_bus_message_new_method_call(
5342 bus,
151b9b96 5343 &m,
729e3769
LP
5344 "org.freedesktop.systemd1",
5345 "/org/freedesktop/systemd1",
5346 "org.freedesktop.systemd1.Manager",
151b9b96 5347 method);
f459b602
MAP
5348 if (r < 0)
5349 return bus_log_create_error(r);
ee5762e3 5350
e3e0314b 5351 r = sd_bus_message_append_strv(m, names);
f459b602
MAP
5352 if (r < 0)
5353 return bus_log_create_error(r);
ee5762e3 5354
d309c1c3
LP
5355 if (send_preset_mode) {
5356 r = sd_bus_message_append(m, "s", unit_file_preset_mode_to_string(arg_preset_mode));
5357 if (r < 0)
5358 return bus_log_create_error(r);
5359 }
5360
f459b602
MAP
5361 r = sd_bus_message_append(m, "b", arg_runtime);
5362 if (r < 0)
5363 return bus_log_create_error(r);
ee5762e3 5364
729e3769 5365 if (send_force) {
f459b602
MAP
5366 r = sd_bus_message_append(m, "b", arg_force);
5367 if (r < 0)
5368 return bus_log_create_error(r);
ee5762e3
LP
5369 }
5370
c49b30a2 5371 r = sd_bus_call(bus, m, 0, &error, &reply);
f459b602
MAP
5372 if (r < 0) {
5373 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
5374 return r;
729e3769 5375 }
be394c48 5376
729e3769 5377 if (expect_carries_install_info) {
f459b602
MAP
5378 r = sd_bus_message_read(reply, "b", &carries_install_info);
5379 if (r < 0)
5380 return bus_log_parse_error(r);
ee5762e3
LP
5381 }
5382
d8f52ed2 5383 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
f459b602 5384 if (r < 0)
718db961 5385 return r;
b77398f7 5386
93c941e3 5387 /* Try to reload if enabled */
d6cb60c7 5388 if (!arg_no_reload)
729e3769 5389 r = daemon_reload(bus, args);
f459b602
MAP
5390 else
5391 r = 0;
b647f10d 5392 }
3d3961f2 5393
729e3769 5394 if (carries_install_info == 0)
416389f7
LP
5395 log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
5396 "using systemctl.\n"
5397 "Possible reasons for having this kind of units are:\n"
5398 "1) A unit may be statically enabled by being symlinked from another unit's\n"
5399 " .wants/ or .requires/ directory.\n"
5400 "2) A unit's purpose may be to act as a helper for some other unit which has\n"
5401 " a requirement dependency on it.\n"
5402 "3) A unit may be started when needed via activation (socket, path, timer,\n"
5403 " D-Bus, udev, scripted systemctl call, ...).\n");
ee5762e3 5404
729e3769 5405finish:
729e3769 5406 unit_file_changes_free(changes, n_changes);
ee5762e3 5407
729e3769 5408 return r;
ee5762e3
LP
5409}
5410
e94937df
LN
5411static int add_dependency(sd_bus *bus, char **args) {
5412 _cleanup_strv_free_ char **names = NULL;
5413 _cleanup_free_ char *target = NULL;
5414 const char *verb = args[0];
5415 UnitDependency dep;
5416 int r = 0;
5417
5418 if (!args[1])
5419 return 0;
5420
5421 target = unit_name_mangle_with_suffix(args[1], MANGLE_NOGLOB, ".target");
5422 if (!target)
5423 return log_oom();
5424
5425 r = mangle_names(args+2, &names);
5426 if (r < 0)
5427 return r;
5428
5429 if (streq(verb, "add-wants"))
5430 dep = UNIT_WANTS;
5431 else if (streq(verb, "add-requires"))
5432 dep = UNIT_REQUIRES;
5433 else
5434 assert_not_reached("Unknown verb");
5435
5436 if (!bus || avoid_bus()) {
5437 UnitFileChange *changes = NULL;
5438 unsigned n_changes = 0;
5439
5440 r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes);
5441
f647962d
MS
5442 if (r < 0)
5443 return log_error_errno(r, "Can't add dependency: %m");
e94937df
LN
5444
5445 if (!arg_quiet)
5446 dump_unit_file_changes(changes, n_changes);
5447
5448 unit_file_changes_free(changes, n_changes);
5449
5450 } else {
5451 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
5452 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
5453
079dac08
LP
5454 polkit_agent_open_if_enabled();
5455
e94937df
LN
5456 r = sd_bus_message_new_method_call(
5457 bus,
5458 &m,
5459 "org.freedesktop.systemd1",
5460 "/org/freedesktop/systemd1",
5461 "org.freedesktop.systemd1.Manager",
5462 "AddDependencyUnitFiles");
5463 if (r < 0)
5464 return bus_log_create_error(r);
5465
342641fb 5466 r = sd_bus_message_append_strv(m, names);
e94937df
LN
5467 if (r < 0)
5468 return bus_log_create_error(r);
5469
342641fb 5470 r = sd_bus_message_append(m, "ssbb", target, unit_dependency_to_string(dep), arg_runtime, arg_force);
e94937df
LN
5471 if (r < 0)
5472 return bus_log_create_error(r);
5473
5474 r = sd_bus_call(bus, m, 0, &error, &reply);
5475 if (r < 0) {
5476 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
5477 return r;
5478 }
5479
d8f52ed2 5480 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
e94937df
LN
5481 if (r < 0)
5482 return r;
5483
5484 if (!arg_no_reload)
5485 r = daemon_reload(bus, args);
5486 else
5487 r = 0;
5488 }
5489
5490 return r;
5491}
5492
d309c1c3
LP
5493static int preset_all(sd_bus *bus, char **args) {
5494 UnitFileChange *changes = NULL;
5495 unsigned n_changes = 0;
5496 int r;
5497
5498 if (!bus || avoid_bus()) {
5499
5500 r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes);
5501 if (r < 0) {
da927ba9 5502 log_error_errno(r, "Operation failed: %m");
d309c1c3
LP
5503 goto finish;
5504 }
5505
5506 if (!arg_quiet)
5507 dump_unit_file_changes(changes, n_changes);
5508
5509 r = 0;
5510
5511 } else {
d309c1c3 5512 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
6e646d22 5513 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
d309c1c3 5514
079dac08
LP
5515 polkit_agent_open_if_enabled();
5516
6e646d22 5517 r = sd_bus_call_method(
d309c1c3
LP
5518 bus,
5519 "org.freedesktop.systemd1",
5520 "/org/freedesktop/systemd1",
5521 "org.freedesktop.systemd1.Manager",
6e646d22
LP
5522 "PresetAllUnitFiles",
5523 &error,
5524 &reply,
d309c1c3
LP
5525 "sbb",
5526 unit_file_preset_mode_to_string(arg_preset_mode),
5527 arg_runtime,
5528 arg_force);
5529 if (r < 0) {
5530 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
5531 return r;
5532 }
5533
d8f52ed2 5534 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
d309c1c3
LP
5535 if (r < 0)
5536 return r;
5537
5538 if (!arg_no_reload)
5539 r = daemon_reload(bus, args);
5540 else
5541 r = 0;
5542 }
5543
5544finish:
5545 unit_file_changes_free(changes, n_changes);
5546
5547 return r;
5548}
5549
f459b602
MAP
5550static int unit_is_enabled(sd_bus *bus, char **args) {
5551
5552 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
e3e0314b 5553 _cleanup_strv_free_ char **names = NULL;
729e3769
LP
5554 bool enabled;
5555 char **name;
f459b602 5556 int r;
ee5762e3 5557
e3e0314b 5558 r = mangle_names(args+1, &names);
cbb13b2a
VP
5559 if (r < 0)
5560 return r;
5561
e3e0314b 5562 r = enable_sysv_units(args[0], names);
729e3769
LP
5563 if (r < 0)
5564 return r;
ee5762e3 5565
729e3769 5566 enabled = r > 0;
ee5762e3 5567
729e3769 5568 if (!bus || avoid_bus()) {
ee5762e3 5569
e3e0314b 5570 STRV_FOREACH(name, names) {
729e3769 5571 UnitFileState state;
ee5762e3 5572
cbb13b2a 5573 state = unit_file_get_state(arg_scope, arg_root, *name);
f647962d
MS
5574 if (state < 0)
5575 return log_error_errno(state, "Failed to get unit file state for %s: %m", *name);
ee5762e3 5576
729e3769
LP
5577 if (state == UNIT_FILE_ENABLED ||
5578 state == UNIT_FILE_ENABLED_RUNTIME ||
aedd4012
JS
5579 state == UNIT_FILE_STATIC ||
5580 state == UNIT_FILE_INDIRECT)
729e3769
LP
5581 enabled = true;
5582
5583 if (!arg_quiet)
5584 puts(unit_file_state_to_string(state));
71fad675 5585 }
ee5762e3 5586
729e3769 5587 } else {
e3e0314b 5588 STRV_FOREACH(name, names) {
f459b602 5589 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
729e3769 5590 const char *s;
63a723f3 5591
f459b602 5592 r = sd_bus_call_method(
f22f08cd 5593 bus,
729e3769
LP
5594 "org.freedesktop.systemd1",
5595 "/org/freedesktop/systemd1",
5596 "org.freedesktop.systemd1.Manager",
f22f08cd 5597 "GetUnitFileState",
f459b602 5598 &error,
f22f08cd 5599 &reply,
04504f93 5600 "s", *name);
f459b602
MAP
5601 if (r < 0) {
5602 log_error("Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
cec7eda5 5603 return r;
ee5762e3
LP
5604 }
5605
f459b602
MAP
5606 r = sd_bus_message_read(reply, "s", &s);
5607 if (r < 0)
5608 return bus_log_parse_error(r);
ee5762e3 5609
aedd4012 5610 if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect"))
729e3769
LP
5611 enabled = true;
5612
5613 if (!arg_quiet)
5614 puts(s);
560d8f23 5615 }
ee5762e3
LP
5616 }
5617
f459b602 5618 return !enabled;
ee5762e3
LP
5619}
5620
99813a19
LP
5621static int is_system_running(sd_bus *bus, char **args) {
5622 _cleanup_free_ char *state = NULL;
5623 int r;
5624
5625 r = sd_bus_get_property_string(
5626 bus,
5627 "org.freedesktop.systemd1",
5628 "/org/freedesktop/systemd1",
5629 "org.freedesktop.systemd1.Manager",
5630 "SystemState",
5631 NULL,
5632 &state);
5633 if (r < 0) {
5634 if (!arg_quiet)
5635 puts("unknown");
5636 return 0;
5637 }
5638
5639 if (!arg_quiet)
5640 puts(state);
5641
5642 return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE;
5643}
5644
7d4fb3b1 5645static int create_edit_temp_file(const char *new_path, const char *original_path, char **ret_tmp_fn) {
7d4fb3b1 5646 char *t;
ae6c3cc0 5647 int r;
7d4fb3b1
RC
5648
5649 assert(new_path);
5650 assert(original_path);
5651 assert(ret_tmp_fn);
5652
ae6c3cc0
LP
5653 r = tempfn_random(new_path, &t);
5654 if (r < 0)
029009d4 5655 return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", new_path);
7d4fb3b1
RC
5656
5657 r = mkdir_parents(new_path, 0755);
652212b0 5658 if (r < 0) {
029009d4 5659 log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
652212b0
TA
5660 free(t);
5661 return r;
5662 }
7d4fb3b1 5663
f2068bcc 5664 r = copy_file(original_path, t, 0, 0644, 0);
7d4fb3b1
RC
5665 if (r == -ENOENT) {
5666 r = touch(t);
5667 if (r < 0) {
029009d4 5668 log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
7d4fb3b1
RC
5669 free(t);
5670 return r;
5671 }
5672 } else if (r < 0) {
029009d4 5673 log_error_errno(r, "Failed to copy \"%s\" to \"%s\": %m", original_path, t);
7d4fb3b1
RC
5674 free(t);
5675 return r;
5676 }
5677
5678 *ret_tmp_fn = t;
5679
5680 return 0;
5681}
5682
bc854dc7
ZJS
5683static int get_file_to_edit(const char *name, const char *user_home, const char *user_runtime, char **ret_path) {
5684 _cleanup_free_ char *path = NULL, *path2 = NULL, *run = NULL;
7d4fb3b1
RC
5685
5686 switch (arg_scope) {
5687 case UNIT_FILE_SYSTEM:
bc854dc7
ZJS
5688 path = path_join(arg_root, SYSTEM_CONFIG_UNIT_PATH, name);
5689 if (arg_runtime)
5690 run = path_join(arg_root, "/run/systemd/system/", name);
7d4fb3b1
RC
5691 break;
5692 case UNIT_FILE_GLOBAL:
bc854dc7
ZJS
5693 path = path_join(arg_root, USER_CONFIG_UNIT_PATH, name);
5694 if (arg_runtime)
5695 run = path_join(arg_root, "/run/systemd/user/", name);
7d4fb3b1
RC
5696 break;
5697 case UNIT_FILE_USER:
5698 assert(user_home);
5699 assert(user_runtime);
5700
bc854dc7
ZJS
5701 path = path_join(arg_root, user_home, name);
5702 if (arg_runtime) {
5703 path2 = path_join(arg_root, USER_CONFIG_UNIT_PATH, name);
5704 if (!path2)
5705 return log_oom();
5706 run = path_join(arg_root, user_runtime, name);
5707 }
7d4fb3b1
RC
5708 break;
5709 default:
5710 assert_not_reached("Invalid scope");
5711 }
bc854dc7 5712 if (!path || (arg_runtime && !run))
7d4fb3b1
RC
5713 return log_oom();
5714
bc854dc7
ZJS
5715 if (arg_runtime) {
5716 if (access(path, F_OK) >= 0)
5717 return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overriden by \"%s\" anyway.",
5718 run, path);
5719 if (path2 && access(path2, F_OK) >= 0)
5720 return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overriden by \"%s\" anyway.",
5721 run, path2);
5722 *ret_path = run;
5723 run = NULL;
5724 } else {
5725 *ret_path = path;
5726 path = NULL;
5727 }
7d4fb3b1
RC
5728
5729 return 0;
5730}
5731
bc854dc7
ZJS
5732static 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) {
5733 char *tmp_new_path, *ending;
7d4fb3b1
RC
5734 char *tmp_tmp_path;
5735 int r;
5736
5737 assert(unit_name);
5738 assert(ret_new_path);
5739 assert(ret_tmp_path);
5740
63c372cb 5741 ending = strjoina(unit_name, ".d/override.conf");
bc854dc7 5742 r = get_file_to_edit(ending, user_home, user_runtime, &tmp_new_path);
7d4fb3b1
RC
5743 if (r < 0)
5744 return r;
5745
5746 r = create_edit_temp_file(tmp_new_path, tmp_new_path, &tmp_tmp_path);
5747 if (r < 0) {
5748 free(tmp_new_path);
5749 return r;
5750 }
5751
5752 *ret_new_path = tmp_new_path;
5753 *ret_tmp_path = tmp_tmp_path;
5754
5755 return 0;
5756}
5757
1cfa9a4c
LP
5758static int unit_file_create_copy(
5759 const char *unit_name,
5760 const char *fragment_path,
5761 const char *user_home,
5762 const char *user_runtime,
5763 char **ret_new_path,
5764 char **ret_tmp_path) {
5765
7d4fb3b1
RC
5766 char *tmp_new_path;
5767 char *tmp_tmp_path;
5768 int r;
5769
5770 assert(fragment_path);
5771 assert(unit_name);
5772 assert(ret_new_path);
5773 assert(ret_tmp_path);
5774
bc854dc7 5775 r = get_file_to_edit(unit_name, user_home, user_runtime, &tmp_new_path);
7d4fb3b1
RC
5776 if (r < 0)
5777 return r;
5778
5779 if (!path_equal(fragment_path, tmp_new_path) && access(tmp_new_path, F_OK) == 0) {
5780 char response;
5781
029009d4 5782 r = ask_char(&response, "yn", "\"%s\" already exists. Overwrite with \"%s\"? [(y)es, (n)o] ", tmp_new_path, fragment_path);
7d4fb3b1
RC
5783 if (r < 0) {
5784 free(tmp_new_path);
5785 return r;
5786 }
5787 if (response != 'y') {
5788 log_warning("%s ignored", unit_name);
5789 free(tmp_new_path);
5790 return -1;
5791 }
5792 }
5793
5794 r = create_edit_temp_file(tmp_new_path, fragment_path, &tmp_tmp_path);
5795 if (r < 0) {
029009d4 5796 log_error_errno(r, "Failed to create temporary file for \"%s\": %m", tmp_new_path);
7d4fb3b1
RC
5797 free(tmp_new_path);
5798 return r;
5799 }
5800
5801 *ret_new_path = tmp_new_path;
5802 *ret_tmp_path = tmp_tmp_path;
5803
5804 return 0;
5805}
5806
5807static int run_editor(char **paths) {
5808 pid_t pid;
5809 int r;
5810
5811 assert(paths);
5812
5813 pid = fork();
5814 if (pid < 0) {
5815 log_error_errno(errno, "Failed to fork: %m");
5816 return -errno;
5817 }
5818
5819 if (pid == 0) {
5820 const char **args;
7d4fb3b1 5821 char *editor;
1cfa9a4c 5822 char **tmp_path, **original_path, *p;
7d4fb3b1
RC
5823 unsigned i = 1;
5824 size_t argc;
5825
5826 argc = strv_length(paths)/2 + 1;
5827 args = newa(const char*, argc + 1);
5828
5829 args[0] = NULL;
5830 STRV_FOREACH_PAIR(original_path, tmp_path, paths) {
5831 args[i] = *tmp_path;
5832 i++;
5833 }
5834 args[argc] = NULL;
5835
5836 /* SYSTEMD_EDITOR takes precedence over EDITOR which takes precedence over VISUAL
5837 * If neither SYSTEMD_EDITOR nor EDITOR nor VISUAL are present,
5838 * we try to execute well known editors
5839 */
5840 editor = getenv("SYSTEMD_EDITOR");
5841 if (!editor)
5842 editor = getenv("EDITOR");
5843 if (!editor)
5844 editor = getenv("VISUAL");
5845
5846 if (!isempty(editor)) {
5847 args[0] = editor;
5848 execvp(editor, (char* const*) args);
5849 }
5850
1cfa9a4c
LP
5851 FOREACH_STRING(p, "nano", "vim", "vi") {
5852 args[0] = p;
5853 execvp(p, (char* const*) args);
7d4fb3b1
RC
5854 /* We do not fail if the editor doesn't exist
5855 * because we want to try each one of them before
5856 * failing.
5857 */
5858 if (errno != ENOENT) {
5859 log_error("Failed to execute %s: %m", editor);
5860 _exit(EXIT_FAILURE);
5861 }
5862 }
5863
1cfa9a4c 5864 log_error("Cannot edit unit(s), no editor available. Please set either $SYSTEMD_EDITOR, $EDITOR or $VISUAL.");
7d4fb3b1
RC
5865 _exit(EXIT_FAILURE);
5866 }
5867
5868 r = wait_for_terminate_and_warn("editor", pid, true);
5869 if (r < 0)
5870 return log_error_errno(r, "Failed to wait for child: %m");
5871
5872 return r;
5873}
5874
5875static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
5876 _cleanup_free_ char *user_home = NULL;
5877 _cleanup_free_ char *user_runtime = NULL;
e9e310f8
RC
5878 _cleanup_lookup_paths_free_ LookupPaths lp = {};
5879 bool avoid_bus_cache;
7d4fb3b1
RC
5880 char **name;
5881 int r;
5882
5883 assert(names);
5884 assert(paths);
5885
8df18507 5886 r = init_home_and_lookup_paths(&user_home, &user_runtime, &lp);
5b013a2f 5887 if (r < 0)
8df18507 5888 return r;
7d4fb3b1 5889
e9e310f8 5890 avoid_bus_cache = !bus || avoid_bus();
7d4fb3b1 5891
e9e310f8
RC
5892 STRV_FOREACH(name, names) {
5893 _cleanup_free_ char *path = NULL;
e9e310f8 5894 char *new_path, *tmp_path;
7d4fb3b1 5895
ad2a0358 5896 r = unit_find_paths(bus, *name, avoid_bus_cache, &lp, &path, NULL);
e9e310f8
RC
5897 if (r < 0)
5898 return r;
b5e6a600
IS
5899 else if (r == 0)
5900 return -ENOENT;
5901 else if (!path) {
ad2a0358 5902 // FIXME: support units with path==NULL (no FragmentPath)
b5e6a600
IS
5903 log_error("No fragment exists for %s.", *name);
5904 return -ENOENT;
5905 }
7d4fb3b1 5906
e9e310f8 5907 if (arg_full)
ad2a0358 5908 r = unit_file_create_copy(*name, path, user_home, user_runtime, &new_path, &tmp_path);
e9e310f8 5909 else
bc854dc7 5910 r = unit_file_create_dropin(*name, user_home, user_runtime, &new_path, &tmp_path);
e9e310f8 5911 if (r < 0)
ad2a0358 5912 return r;
7d4fb3b1 5913
e9e310f8
RC
5914 r = strv_push_pair(paths, new_path, tmp_path);
5915 if (r < 0)
5916 return log_oom();
7d4fb3b1
RC
5917 }
5918
5919 return 0;
5920}
5921
5922static int edit(sd_bus *bus, char **args) {
5923 _cleanup_strv_free_ char **names = NULL;
5924 _cleanup_strv_free_ char **paths = NULL;
5925 char **original, **tmp;
5926 int r;
5927
5928 assert(args);
5929
5930 if (!on_tty()) {
029009d4 5931 log_error("Cannot edit units if not on a tty");
7d4fb3b1
RC
5932 return -EINVAL;
5933 }
5934
5935 if (arg_transport != BUS_TRANSPORT_LOCAL) {
5936 log_error("Cannot remotely edit units");
5937 return -EINVAL;
5938 }
5939
5940 r = expand_names(bus, args + 1, NULL, &names);
5941 if (r < 0)
5942 return log_error_errno(r, "Failed to expand names: %m");
5943
7d4fb3b1
RC
5944 r = find_paths_to_edit(bus, names, &paths);
5945 if (r < 0)
5946 return r;
5947
b5e6a600 5948 if (strv_isempty(paths))
7d4fb3b1 5949 return -ENOENT;
7d4fb3b1
RC
5950
5951 r = run_editor(paths);
5952 if (r < 0)
5953 goto end;
5954
5955 STRV_FOREACH_PAIR(original, tmp, paths) {
5956 /* If the temporary file is empty we ignore it.
5957 * It's useful if the user wants to cancel its modification
5958 */
5959 if (null_or_empty_path(*tmp)) {
029009d4 5960 log_warning("Editing \"%s\" canceled: temporary file is empty", *original);
7d4fb3b1
RC
5961 continue;
5962 }
5963 r = rename(*tmp, *original);
5964 if (r < 0) {
029009d4 5965 r = log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", *tmp, *original);
7d4fb3b1
RC
5966 goto end;
5967 }
5968 }
5969
5970 if (!arg_no_reload && bus && !avoid_bus())
5971 r = daemon_reload(bus, args);
5972
5973end:
5974 STRV_FOREACH_PAIR(original, tmp, paths)
5975 unlink_noerrno(*tmp);
5976
5977 return r;
5978}
5979
601185b4 5980static void systemctl_help(void) {
7e4249b9 5981
729e3769
LP
5982 pager_open_if_enabled();
5983
2e33c433 5984 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
729e3769 5985 "Query or send control commands to the systemd manager.\n\n"
8a0867d6
LP
5986 " -h --help Show this help\n"
5987 " --version Show package version\n"
f459b602
MAP
5988 " --system Connect to system manager\n"
5989 " --user Connect to user service manager\n"
5990 " -H --host=[USER@]HOST\n"
5991 " Operate on remote host\n"
5992 " -M --machine=CONTAINER\n"
5993 " Operate on local container\n"
3fb90db2
ZJS
5994 " -t --type=TYPE List units of a particular type\n"
5995 " --state=STATE List units with particular LOAD or SUB or ACTIVE state\n"
8a0867d6 5996 " -p --property=NAME Show only properties by this name\n"
a5e4972c
LP
5997 " -a --all Show all loaded units/properties, including dead/empty\n"
5998 " ones. To list all units installed on the system, use\n"
5999 " the 'list-unit-files' command instead.\n"
98a6e132 6000 " -l --full Don't ellipsize unit names on output\n"
1238ee09 6001 " -r --recursive Show unit list of host and local containers\n"
4dc5b821
LP
6002 " --reverse Show reverse dependencies with 'list-dependencies'\n"
6003 " --job-mode=MODE Specify how to deal with already queued jobs, when\n"
6004 " queueing a new job\n"
a521ae4a 6005 " --show-types When showing sockets, explicitly show their type\n"
b37844d3
LP
6006 " -i --ignore-inhibitors\n"
6007 " When shutting down or sleeping, ignore inhibitors\n"
a8f11321
LP
6008 " --kill-who=WHO Who to send signal to\n"
6009 " -s --signal=SIGNAL Which signal to send\n"
8a0867d6
LP
6010 " -q --quiet Suppress output\n"
6011 " --no-block Do not wait until operation finished\n"
8a0867d6 6012 " --no-wall Don't send wall message before halt/power-off/reboot\n"
3fb90db2 6013 " --no-reload Don't reload daemon after en-/dis-abling unit files\n"
ebed32bf 6014 " --no-legend Do not print a legend (column headers and hints)\n"
69fc152f 6015 " --no-pager Do not pipe output into a pager\n"
501fc174
LP
6016 " --no-ask-password\n"
6017 " Do not ask for system passwords\n"
a8f11321 6018 " --global Enable/disable unit files globally\n"
a521ae4a 6019 " --runtime Enable unit files only temporarily until next reboot\n"
8a0867d6
LP
6020 " -f --force When enabling unit files, override existing symlinks\n"
6021 " When shutting down, execute action immediately\n"
3fb90db2 6022 " --preset-mode= Apply only enable, only disable, or all presets\n"
729e3769 6023 " --root=PATH Enable unit files in the specified root directory\n"
76fdc966 6024 " -n --lines=INTEGER Number of journal entries to show\n"
86d81e50
RC
6025 " -o --output=STRING Change journal output mode (short, short-iso,\n"
6026 " short-precise, short-monotonic, verbose,\n"
6027 " export, json, json-pretty, json-sse, cat)\n"
5bdf2243 6028 " --firmware-setup Tell the firmware to show the setup menu on next boot\n"
815ebc54 6029 " --plain Print unit dependencies as a list instead of a tree\n\n"
34c4b47b 6030 "Unit Commands:\n"
d8fba7c6
ZJS
6031 " list-units [PATTERN...] List loaded units\n"
6032 " list-sockets [PATTERN...] List loaded sockets ordered by address\n"
6033 " list-timers [PATTERN...] List loaded timers ordered by next elapse\n"
4f8f66cb
ZJS
6034 " start NAME... Start (activate) one or more units\n"
6035 " stop NAME... Stop (deactivate) one or more units\n"
6036 " reload NAME... Reload one or more units\n"
6037 " restart NAME... Start or restart one or more units\n"
6038 " try-restart NAME... Restart one or more units if active\n"
6039 " reload-or-restart NAME... Reload one or more units if possible,\n"
6f28c033 6040 " otherwise start or restart\n"
4f8f66cb 6041 " reload-or-try-restart NAME... Reload one or more units if possible,\n"
6f28c033 6042 " otherwise restart if active\n"
4f8f66cb
ZJS
6043 " isolate NAME Start one unit and stop all others\n"
6044 " kill NAME... Send signal to processes of a unit\n"
b3ae710c
ZJS
6045 " is-active PATTERN... Check whether units are active\n"
6046 " is-failed PATTERN... Check whether units are failed\n"
6047 " status [PATTERN...|PID...] Show runtime status of one or more units\n"
6048 " show [PATTERN...|JOB...] Show properties of one or more\n"
ee5762e3 6049 " units/jobs or the manager\n"
b3ae710c 6050 " cat PATTERN... Show files and drop-ins of one or more units\n"
4f8f66cb 6051 " set-property NAME ASSIGNMENT... Sets one or more properties of a unit\n"
b3ae710c
ZJS
6052 " help PATTERN...|PID... Show manual for one or more units\n"
6053 " reset-failed [PATTERN...] Reset failed state for all, one, or more\n"
fdf20a31 6054 " units\n"
55c0b89c 6055 " list-dependencies [NAME] Recursively show units which are required\n"
afba4199
ZJS
6056 " or wanted by this unit or by which this\n"
6057 " unit is required or wanted\n\n"
34c4b47b 6058 "Unit File Commands:\n"
d8fba7c6 6059 " list-unit-files [PATTERN...] List installed unit files\n"
4f8f66cb
ZJS
6060 " enable NAME... Enable one or more unit files\n"
6061 " disable NAME... Disable one or more unit files\n"
6062 " reenable NAME... Reenable one or more unit files\n"
6063 " preset NAME... Enable/disable one or more unit files\n"
729e3769 6064 " based on preset configuration\n"
d309c1c3
LP
6065 " preset-all Enable/disable all unit files based on\n"
6066 " preset configuration\n"
b619ec8f 6067 " is-enabled NAME... Check whether unit files are enabled\n"
4f8f66cb
ZJS
6068 " mask NAME... Mask one or more units\n"
6069 " unmask NAME... Unmask one or more units\n"
6070 " link PATH... Link one or more units files into\n"
729e3769 6071 " the search path\n"
e94937df
LN
6072 " add-wants TARGET NAME... Add 'Wants' dependency for the target\n"
6073 " on specified one or more units\n"
6074 " add-requires TARGET NAME... Add 'Requires' dependency for the target\n"
6075 " on specified one or more units\n"
7d4fb3b1 6076 " edit NAME... Edit one or more unit files\n"
b619ec8f
LP
6077 " get-default Get the name of the default target\n"
6078 " set-default NAME Set the default target\n\n"
0d292f5e
LP
6079 "Machine Commands:\n"
6080 " list-machines [PATTERN...] List local containers and host\n\n"
34c4b47b 6081 "Job Commands:\n"
d8fba7c6 6082 " list-jobs [PATTERN...] List jobs\n"
34c4b47b 6083 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
34c4b47b 6084 "Snapshot Commands:\n"
7e4249b9 6085 " snapshot [NAME] Create a snapshot\n"
4f8f66cb 6086 " delete NAME... Remove one or more snapshots\n\n"
34c4b47b 6087 "Environment Commands:\n"
7e4249b9 6088 " show-environment Dump environment\n"
4f8f66cb 6089 " set-environment NAME=VALUE... Set one or more environment variables\n"
ac3efa8a 6090 " unset-environment NAME... Unset one or more environment variables\n"
3fb90db2 6091 " import-environment [NAME...] Import all or some environment variables\n\n"
34c4b47b
LP
6092 "Manager Lifecycle Commands:\n"
6093 " daemon-reload Reload systemd manager configuration\n"
6094 " daemon-reexec Reexecute systemd manager\n\n"
6095 "System Commands:\n"
99813a19 6096 " is-system-running Check whether system is fully running\n"
20b09ca7
LP
6097 " default Enter system default mode\n"
6098 " rescue Enter system rescue mode\n"
6099 " emergency Enter system emergency mode\n"
514f4ef5 6100 " halt Shut down and halt the system\n"
2e33c433 6101 " poweroff Shut down and power-off the system\n"
37185ec8 6102 " reboot [ARG] Shut down and reboot the system\n"
20b09ca7 6103 " kexec Shut down and reboot the system with kexec\n"
6edd7d0a 6104 " exit Request user instance exit\n"
4f8f66cb 6105 " switch-root ROOT [INIT] Change to a different root file system\n"
6edd7d0a 6106 " suspend Suspend the system\n"
6524990f
LP
6107 " hibernate Hibernate the system\n"
6108 " hybrid-sleep Hibernate and suspend the system\n",
5b6319dc 6109 program_invocation_short_name);
7e4249b9
LP
6110}
6111
601185b4 6112static void halt_help(void) {
37185ec8 6113 printf("%s [OPTIONS...]%s\n\n"
e4b61340
LP
6114 "%s the system.\n\n"
6115 " --help Show this help\n"
6116 " --halt Halt the machine\n"
6117 " -p --poweroff Switch off the machine\n"
6118 " --reboot Reboot the machine\n"
2e33c433
LP
6119 " -f --force Force immediate halt/power-off/reboot\n"
6120 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
e4b61340 6121 " -d --no-wtmp Don't write wtmp record\n"
2e33c433 6122 " --no-wall Don't send wall message before halt/power-off/reboot\n",
e4b61340 6123 program_invocation_short_name,
37185ec8 6124 arg_action == ACTION_REBOOT ? " [ARG]" : "",
e4b61340
LP
6125 arg_action == ACTION_REBOOT ? "Reboot" :
6126 arg_action == ACTION_POWEROFF ? "Power off" :
6127 "Halt");
e4b61340
LP
6128}
6129
601185b4 6130static void shutdown_help(void) {
08e4b1c5 6131 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
e4b61340
LP
6132 "Shut down the system.\n\n"
6133 " --help Show this help\n"
6134 " -H --halt Halt the machine\n"
6135 " -P --poweroff Power-off the machine\n"
6136 " -r --reboot Reboot the machine\n"
386da858 6137 " -h Equivalent to --poweroff, overridden by --halt\n"
2e33c433 6138 " -k Don't halt/power-off/reboot, just send warnings\n"
f6144808 6139 " --no-wall Don't send wall message before halt/power-off/reboot\n"
f6144808 6140 " -c Cancel a pending shutdown\n",
e4b61340 6141 program_invocation_short_name);
e4b61340
LP
6142}
6143
601185b4 6144static void telinit_help(void) {
2e33c433 6145 printf("%s [OPTIONS...] {COMMAND}\n\n"
514f4ef5
LP
6146 "Send control commands to the init daemon.\n\n"
6147 " --help Show this help\n"
2e33c433 6148 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
e4b61340
LP
6149 "Commands:\n"
6150 " 0 Power-off the machine\n"
6151 " 6 Reboot the machine\n"
514f4ef5
LP
6152 " 2, 3, 4, 5 Start runlevelX.target unit\n"
6153 " 1, s, S Enter rescue mode\n"
6154 " q, Q Reload init daemon configuration\n"
6155 " u, U Reexecute init daemon\n",
e4b61340 6156 program_invocation_short_name);
e4b61340
LP
6157}
6158
601185b4 6159static void runlevel_help(void) {
2e33c433 6160 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
6161 "Prints the previous and current runlevel of the init system.\n\n"
6162 " --help Show this help\n",
6163 program_invocation_short_name);
e4b61340
LP
6164}
6165
b93312f5 6166static void help_types(void) {
45c0c61d 6167 int i;
830f01f0 6168 const char *t;
45c0c61d 6169
b93312f5
ZJS
6170 if (!arg_no_legend)
6171 puts("Available unit types:");
f168c273 6172 for (i = 0; i < _UNIT_TYPE_MAX; i++) {
830f01f0
LP
6173 t = unit_type_to_string(i);
6174 if (t)
6175 puts(t);
6176 }
45c0c61d
ZJS
6177}
6178
e4b61340 6179static int systemctl_parse_argv(int argc, char *argv[]) {
7e4249b9
LP
6180
6181 enum {
90d473a1 6182 ARG_FAIL = 0x100,
afba4199
ZJS
6183 ARG_REVERSE,
6184 ARG_AFTER,
6185 ARG_BEFORE,
991f2a39 6186 ARG_SHOW_TYPES,
23ade460 6187 ARG_IRREVERSIBLE,
e67c3609 6188 ARG_IGNORE_DEPENDENCIES,
35df8f27 6189 ARG_VERSION,
af2d49f7 6190 ARG_USER,
7e4249b9 6191 ARG_SYSTEM,
ee5762e3 6192 ARG_GLOBAL,
6e905d93 6193 ARG_NO_BLOCK,
ebed32bf 6194 ARG_NO_LEGEND,
611efaac 6195 ARG_NO_PAGER,
4445a875 6196 ARG_NO_WALL,
be394c48 6197 ARG_ROOT,
ee5762e3 6198 ARG_NO_RELOAD,
501fc174 6199 ARG_KILL_WHO,
30732560 6200 ARG_NO_ASK_PASSWORD,
729e3769 6201 ARG_FAILED,
df50185b 6202 ARG_RUNTIME,
5d0c05e5 6203 ARG_FORCE,
9b9b3d36 6204 ARG_PLAIN,
4dc5b821 6205 ARG_STATE,
d309c1c3
LP
6206 ARG_JOB_MODE,
6207 ARG_PRESET_MODE,
5bdf2243 6208 ARG_FIRMWARE_SETUP,
7e4249b9
LP
6209 };
6210
6211 static const struct option options[] = {
9ea9d4cf
LP
6212 { "help", no_argument, NULL, 'h' },
6213 { "version", no_argument, NULL, ARG_VERSION },
6214 { "type", required_argument, NULL, 't' },
6215 { "property", required_argument, NULL, 'p' },
6216 { "all", no_argument, NULL, 'a' },
6217 { "reverse", no_argument, NULL, ARG_REVERSE },
6218 { "after", no_argument, NULL, ARG_AFTER },
6219 { "before", no_argument, NULL, ARG_BEFORE },
6220 { "show-types", no_argument, NULL, ARG_SHOW_TYPES },
6221 { "failed", no_argument, NULL, ARG_FAILED }, /* compatibility only */
6222 { "full", no_argument, NULL, 'l' },
4dc5b821
LP
6223 { "job-mode", required_argument, NULL, ARG_JOB_MODE },
6224 { "fail", no_argument, NULL, ARG_FAIL }, /* compatibility only */
6225 { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, /* compatibility only */
6226 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */
9ea9d4cf
LP
6227 { "ignore-inhibitors", no_argument, NULL, 'i' },
6228 { "user", no_argument, NULL, ARG_USER },
6229 { "system", no_argument, NULL, ARG_SYSTEM },
6230 { "global", no_argument, NULL, ARG_GLOBAL },
6231 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
6232 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
6233 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
6234 { "no-wall", no_argument, NULL, ARG_NO_WALL },
6235 { "quiet", no_argument, NULL, 'q' },
6236 { "root", required_argument, NULL, ARG_ROOT },
6237 { "force", no_argument, NULL, ARG_FORCE },
6238 { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
6239 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
6240 { "signal", required_argument, NULL, 's' },
6241 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
6242 { "host", required_argument, NULL, 'H' },
f459b602 6243 { "machine", required_argument, NULL, 'M' },
9ea9d4cf
LP
6244 { "runtime", no_argument, NULL, ARG_RUNTIME },
6245 { "lines", required_argument, NULL, 'n' },
6246 { "output", required_argument, NULL, 'o' },
6247 { "plain", no_argument, NULL, ARG_PLAIN },
6248 { "state", required_argument, NULL, ARG_STATE },
1238ee09 6249 { "recursive", no_argument, NULL, 'r' },
d309c1c3 6250 { "preset-mode", required_argument, NULL, ARG_PRESET_MODE },
5bdf2243 6251 { "firmware-setup", no_argument, NULL, ARG_FIRMWARE_SETUP },
eb9da376 6252 {}
7e4249b9
LP
6253 };
6254
6255 int c;
6256
e4b61340 6257 assert(argc >= 0);
7e4249b9
LP
6258 assert(argv);
6259
601185b4 6260 while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir", options, NULL)) >= 0)
7e4249b9
LP
6261
6262 switch (c) {
6263
6264 case 'h':
601185b4
ZJS
6265 systemctl_help();
6266 return 0;
35df8f27
LP
6267
6268 case ARG_VERSION:
6269 puts(PACKAGE_STRING);
7d568925 6270 puts(SYSTEMD_FEATURES);
35df8f27 6271 return 0;
7e4249b9 6272
20b3f379 6273 case 't': {
a2a5291b 6274 const char *word, *state;
20b3f379 6275 size_t size;
45c0c61d 6276
20b3f379 6277 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
7fd1b19b 6278 _cleanup_free_ char *type;
20b3f379
ZJS
6279
6280 type = strndup(word, size);
6281 if (!type)
6282 return -ENOMEM;
6283
6284 if (streq(type, "help")) {
6285 help_types();
6286 return 0;
6287 }
6288
6289 if (unit_type_from_string(type) >= 0) {
6290 if (strv_push(&arg_types, type))
6291 return log_oom();
6292 type = NULL;
6293 continue;
6294 }
6295
9b9b3d36
MW
6296 /* It's much nicer to use --state= for
6297 * load states, but let's support this
6298 * in --types= too for compatibility
6299 * with old versions */
20b3f379 6300 if (unit_load_state_from_string(optarg) >= 0) {
9b9b3d36 6301 if (strv_push(&arg_states, type) < 0)
20b3f379
ZJS
6302 return log_oom();
6303 type = NULL;
6304 continue;
6305 }
6306
ab06eef8 6307 log_error("Unknown unit type or load state '%s'.", type);
20b3f379
ZJS
6308 log_info("Use -t help to see a list of allowed values.");
6309 return -EINVAL;
c147dc42 6310 }
20b3f379
ZJS
6311
6312 break;
6313 }
6314
ea4a240d 6315 case 'p': {
033a842c
ZJS
6316 /* Make sure that if the empty property list
6317 was specified, we won't show any properties. */
20b3f379 6318 if (isempty(optarg) && !arg_properties) {
cbc9fbd1 6319 arg_properties = new0(char*, 1);
20b3f379
ZJS
6320 if (!arg_properties)
6321 return log_oom();
6322 } else {
a2a5291b 6323 const char *word, *state;
20b3f379 6324 size_t size;
033a842c 6325
20b3f379
ZJS
6326 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
6327 char *prop;
033a842c 6328
20b3f379
ZJS
6329 prop = strndup(word, size);
6330 if (!prop)
6331 return log_oom();
ea4a240d 6332
6e18964d 6333 if (strv_consume(&arg_properties, prop) < 0)
20b3f379 6334 return log_oom();
20b3f379 6335 }
033a842c 6336 }
48220598
LP
6337
6338 /* If the user asked for a particular
6339 * property, show it to him, even if it is
6340 * empty. */
6341 arg_all = true;
033a842c 6342
48220598 6343 break;
ea4a240d 6344 }
48220598 6345
7e4249b9
LP
6346 case 'a':
6347 arg_all = true;
6348 break;
6349
afba4199
ZJS
6350 case ARG_REVERSE:
6351 arg_dependency = DEPENDENCY_REVERSE;
6352 break;
6353
6354 case ARG_AFTER:
6355 arg_dependency = DEPENDENCY_AFTER;
6356 break;
6357
6358 case ARG_BEFORE:
6359 arg_dependency = DEPENDENCY_BEFORE;
6360 break;
6361
991f2a39
ZJS
6362 case ARG_SHOW_TYPES:
6363 arg_show_types = true;
6364 break;
6365
4dc5b821
LP
6366 case ARG_JOB_MODE:
6367 arg_job_mode = optarg;
6368 break;
6369
90d473a1 6370 case ARG_FAIL:
e67c3609
LP
6371 arg_job_mode = "fail";
6372 break;
6373
23ade460
MS
6374 case ARG_IRREVERSIBLE:
6375 arg_job_mode = "replace-irreversibly";
6376 break;
6377
e67c3609
LP
6378 case ARG_IGNORE_DEPENDENCIES:
6379 arg_job_mode = "ignore-dependencies";
7e4249b9
LP
6380 break;
6381
af2d49f7 6382 case ARG_USER:
729e3769 6383 arg_scope = UNIT_FILE_USER;
7e4249b9
LP
6384 break;
6385
6386 case ARG_SYSTEM:
729e3769
LP
6387 arg_scope = UNIT_FILE_SYSTEM;
6388 break;
6389
6390 case ARG_GLOBAL:
6391 arg_scope = UNIT_FILE_GLOBAL;
7e4249b9
LP
6392 break;
6393
6e905d93
LP
6394 case ARG_NO_BLOCK:
6395 arg_no_block = true;
7e4249b9
LP
6396 break;
6397
ebed32bf
MS
6398 case ARG_NO_LEGEND:
6399 arg_no_legend = true;
6400 break;
6401
611efaac
LP
6402 case ARG_NO_PAGER:
6403 arg_no_pager = true;
6404 break;
0736af98 6405
514f4ef5
LP
6406 case ARG_NO_WALL:
6407 arg_no_wall = true;
6408 break;
6409
be394c48
FC
6410 case ARG_ROOT:
6411 arg_root = optarg;
6412 break;
6413
98a6e132 6414 case 'l':
8fe914ec
LP
6415 arg_full = true;
6416 break;
6417
30732560 6418 case ARG_FAILED:
9b9b3d36
MW
6419 if (strv_extend(&arg_states, "failed") < 0)
6420 return log_oom();
6421
30732560
LP
6422 break;
6423
0183528f
LP
6424 case 'q':
6425 arg_quiet = true;
6426 break;
6427
568b679f
LP
6428 case ARG_FORCE:
6429 arg_force ++;
6430 break;
6431
b4f27ccc 6432 case 'f':
e606bb61 6433 arg_force ++;
ee5762e3
LP
6434 break;
6435
6436 case ARG_NO_RELOAD:
6437 arg_no_reload = true;
6438 break;
6439
8a0867d6
LP
6440 case ARG_KILL_WHO:
6441 arg_kill_who = optarg;
6442 break;
6443
8a0867d6
LP
6444 case 's':
6445 if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
6446 log_error("Failed to parse signal string %s.", optarg);
6447 return -EINVAL;
6448 }
6449 break;
6450
501fc174
LP
6451 case ARG_NO_ASK_PASSWORD:
6452 arg_ask_password = false;
6453 break;
6454
f459b602
MAP
6455 case 'H':
6456 arg_transport = BUS_TRANSPORT_REMOTE;
6457 arg_host = optarg;
a8f11321
LP
6458 break;
6459
f459b602 6460 case 'M':
de33fc62 6461 arg_transport = BUS_TRANSPORT_MACHINE;
f459b602 6462 arg_host = optarg;
a8f11321
LP
6463 break;
6464
729e3769
LP
6465 case ARG_RUNTIME:
6466 arg_runtime = true;
6467 break;
6468
df50185b
LP
6469 case 'n':
6470 if (safe_atou(optarg, &arg_lines) < 0) {
6471 log_error("Failed to parse lines '%s'", optarg);
6472 return -EINVAL;
6473 }
6474 break;
6475
df50185b
LP
6476 case 'o':
6477 arg_output = output_mode_from_string(optarg);
6478 if (arg_output < 0) {
6479 log_error("Unknown output '%s'.", optarg);
6480 return -EINVAL;
6481 }
6482 break;
6483
b37844d3
LP
6484 case 'i':
6485 arg_ignore_inhibitors = true;
6486 break;
6487
5d0c05e5
LN
6488 case ARG_PLAIN:
6489 arg_plain = true;
6490 break;
6491
5bdf2243
JJ
6492 case ARG_FIRMWARE_SETUP:
6493 arg_firmware_setup = true;
6494 break;
6495
9b9b3d36 6496 case ARG_STATE: {
a2a5291b 6497 const char *word, *state;
9b9b3d36
MW
6498 size_t size;
6499
6500 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
6501 char *s;
6502
6503 s = strndup(word, size);
6504 if (!s)
6505 return log_oom();
6506
6e18964d 6507 if (strv_consume(&arg_states, s) < 0)
9b9b3d36 6508 return log_oom();
9b9b3d36
MW
6509 }
6510 break;
6511 }
6512
1238ee09
LP
6513 case 'r':
6514 if (geteuid() != 0) {
f1721625 6515 log_error("--recursive requires root privileges.");
1238ee09
LP
6516 return -EPERM;
6517 }
6518
6519 arg_recursive = true;
6520 break;
6521
d309c1c3
LP
6522 case ARG_PRESET_MODE:
6523
6524 arg_preset_mode = unit_file_preset_mode_from_string(optarg);
6525 if (arg_preset_mode < 0) {
6526 log_error("Failed to parse preset mode: %s.", optarg);
6527 return -EINVAL;
6528 }
6529
6530 break;
6531
7e4249b9
LP
6532 case '?':
6533 return -EINVAL;
6534
6535 default:
eb9da376 6536 assert_not_reached("Unhandled option");
7e4249b9 6537 }
7e4249b9 6538
f459b602 6539 if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM) {
a8f11321
LP
6540 log_error("Cannot access user instance remotely.");
6541 return -EINVAL;
6542 }
6543
7e4249b9
LP
6544 return 1;
6545}
6546
e4b61340
LP
6547static int halt_parse_argv(int argc, char *argv[]) {
6548
6549 enum {
6550 ARG_HELP = 0x100,
6551 ARG_HALT,
514f4ef5
LP
6552 ARG_REBOOT,
6553 ARG_NO_WALL
e4b61340
LP
6554 };
6555
6556 static const struct option options[] = {
6557 { "help", no_argument, NULL, ARG_HELP },
6558 { "halt", no_argument, NULL, ARG_HALT },
6559 { "poweroff", no_argument, NULL, 'p' },
6560 { "reboot", no_argument, NULL, ARG_REBOOT },
6561 { "force", no_argument, NULL, 'f' },
6562 { "wtmp-only", no_argument, NULL, 'w' },
6563 { "no-wtmp", no_argument, NULL, 'd' },
514f4ef5 6564 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 6565 {}
e4b61340
LP
6566 };
6567
37185ec8 6568 int c, r, runlevel;
e4b61340
LP
6569
6570 assert(argc >= 0);
6571 assert(argv);
6572
6573 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
6574 if (runlevel == '0' || runlevel == '6')
65491fd8 6575 arg_force = 2;
e4b61340 6576
601185b4 6577 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0)
e4b61340
LP
6578 switch (c) {
6579
6580 case ARG_HELP:
601185b4
ZJS
6581 halt_help();
6582 return 0;
e4b61340
LP
6583
6584 case ARG_HALT:
6585 arg_action = ACTION_HALT;
6586 break;
6587
6588 case 'p':
a042efad
MS
6589 if (arg_action != ACTION_REBOOT)
6590 arg_action = ACTION_POWEROFF;
e4b61340
LP
6591 break;
6592
6593 case ARG_REBOOT:
6594 arg_action = ACTION_REBOOT;
6595 break;
6596
6597 case 'f':
65491fd8 6598 arg_force = 2;
e4b61340
LP
6599 break;
6600
6601 case 'w':
6602 arg_dry = true;
6603 break;
6604
6605 case 'd':
6606 arg_no_wtmp = true;
6607 break;
6608
514f4ef5
LP
6609 case ARG_NO_WALL:
6610 arg_no_wall = true;
6611 break;
6612
e4b61340
LP
6613 case 'i':
6614 case 'h':
57371e58 6615 case 'n':
e4b61340
LP
6616 /* Compatibility nops */
6617 break;
6618
6619 case '?':
6620 return -EINVAL;
6621
6622 default:
eb9da376 6623 assert_not_reached("Unhandled option");
e4b61340 6624 }
e4b61340 6625
c5220a94
MO
6626 if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
6627 r = update_reboot_param_file(argc == optind + 1 ? argv[optind] : NULL);
6628 if (r < 0)
37185ec8 6629 return r;
37185ec8 6630 } else if (optind < argc) {
e4b61340
LP
6631 log_error("Too many arguments.");
6632 return -EINVAL;
6633 }
6634
6635 return 1;
6636}
6637
f6144808
LP
6638static int parse_time_spec(const char *t, usec_t *_u) {
6639 assert(t);
6640 assert(_u);
6641
6642 if (streq(t, "now"))
6643 *_u = 0;
1a639877 6644 else if (!strchr(t, ':')) {
f6144808
LP
6645 uint64_t u;
6646
1a639877 6647 if (safe_atou64(t, &u) < 0)
f6144808
LP
6648 return -EINVAL;
6649
6650 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
6651 } else {
6652 char *e = NULL;
6653 long hour, minute;
b92bea5d 6654 struct tm tm = {};
f6144808
LP
6655 time_t s;
6656 usec_t n;
6657
6658 errno = 0;
6659 hour = strtol(t, &e, 10);
8333c77e 6660 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
f6144808
LP
6661 return -EINVAL;
6662
6663 minute = strtol(e+1, &e, 10);
8333c77e 6664 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
f6144808
LP
6665 return -EINVAL;
6666
6667 n = now(CLOCK_REALTIME);
08e4b1c5
LP
6668 s = (time_t) (n / USEC_PER_SEC);
6669
f6144808
LP
6670 assert_se(localtime_r(&s, &tm));
6671
6672 tm.tm_hour = (int) hour;
6673 tm.tm_min = (int) minute;
08e4b1c5 6674 tm.tm_sec = 0;
f6144808
LP
6675
6676 assert_se(s = mktime(&tm));
6677
6678 *_u = (usec_t) s * USEC_PER_SEC;
6679
6680 while (*_u <= n)
6681 *_u += USEC_PER_DAY;
6682 }
6683
6684 return 0;
6685}
6686
e4b61340
LP
6687static int shutdown_parse_argv(int argc, char *argv[]) {
6688
6689 enum {
6690 ARG_HELP = 0x100,
514f4ef5 6691 ARG_NO_WALL
e4b61340
LP
6692 };
6693
6694 static const struct option options[] = {
6695 { "help", no_argument, NULL, ARG_HELP },
6696 { "halt", no_argument, NULL, 'H' },
6697 { "poweroff", no_argument, NULL, 'P' },
6698 { "reboot", no_argument, NULL, 'r' },
04ebb595 6699 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
514f4ef5 6700 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 6701 {}
e4b61340
LP
6702 };
6703
f6144808 6704 int c, r;
e4b61340
LP
6705
6706 assert(argc >= 0);
6707 assert(argv);
6708
75836b9d 6709 while ((c = getopt_long(argc, argv, "HPrhkKt:afFc", options, NULL)) >= 0)
e4b61340
LP
6710 switch (c) {
6711
6712 case ARG_HELP:
601185b4
ZJS
6713 shutdown_help();
6714 return 0;
e4b61340
LP
6715
6716 case 'H':
6717 arg_action = ACTION_HALT;
6718 break;
6719
6720 case 'P':
6721 arg_action = ACTION_POWEROFF;
6722 break;
6723
6724 case 'r':
5622dde3
KS
6725 if (kexec_loaded())
6726 arg_action = ACTION_KEXEC;
6727 else
6728 arg_action = ACTION_REBOOT;
e4b61340
LP
6729 break;
6730
04ebb595
LP
6731 case 'K':
6732 arg_action = ACTION_KEXEC;
6733 break;
6734
e4b61340
LP
6735 case 'h':
6736 if (arg_action != ACTION_HALT)
6737 arg_action = ACTION_POWEROFF;
6738 break;
6739
6740 case 'k':
6741 arg_dry = true;
6742 break;
6743
514f4ef5
LP
6744 case ARG_NO_WALL:
6745 arg_no_wall = true;
6746 break;
6747
e4b61340
LP
6748 case 't':
6749 case 'a':
75836b9d
JS
6750 case 'f':
6751 case 'F':
e4b61340
LP
6752 /* Compatibility nops */
6753 break;
6754
f6144808
LP
6755 case 'c':
6756 arg_action = ACTION_CANCEL_SHUTDOWN;
6757 break;
6758
e4b61340
LP
6759 case '?':
6760 return -EINVAL;
6761
6762 default:
eb9da376 6763 assert_not_reached("Unhandled option");
e4b61340 6764 }
e4b61340 6765
dfcc5c33 6766 if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
7e59bfcb
LP
6767 r = parse_time_spec(argv[optind], &arg_when);
6768 if (r < 0) {
f6144808
LP
6769 log_error("Failed to parse time specification: %s", argv[optind]);
6770 return r;
6771 }
6b5ad000 6772 } else
08e4b1c5 6773 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
442b9094 6774
dfcc5c33
MS
6775 if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
6776 /* No time argument for shutdown cancel */
6777 arg_wall = argv + optind;
6778 else if (argc > optind + 1)
6779 /* We skip the time argument */
e4b61340
LP
6780 arg_wall = argv + optind + 1;
6781
6782 optind = argc;
6783
6784 return 1;
e4b61340
LP
6785}
6786
6787static int telinit_parse_argv(int argc, char *argv[]) {
6788
6789 enum {
6790 ARG_HELP = 0x100,
514f4ef5 6791 ARG_NO_WALL
e4b61340
LP
6792 };
6793
6794 static const struct option options[] = {
6795 { "help", no_argument, NULL, ARG_HELP },
514f4ef5 6796 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 6797 {}
e4b61340
LP
6798 };
6799
6800 static const struct {
6801 char from;
6802 enum action to;
6803 } table[] = {
6804 { '0', ACTION_POWEROFF },
6805 { '6', ACTION_REBOOT },
ef2f1067 6806 { '1', ACTION_RESCUE },
e4b61340
LP
6807 { '2', ACTION_RUNLEVEL2 },
6808 { '3', ACTION_RUNLEVEL3 },
6809 { '4', ACTION_RUNLEVEL4 },
6810 { '5', ACTION_RUNLEVEL5 },
6811 { 's', ACTION_RESCUE },
6812 { 'S', ACTION_RESCUE },
6813 { 'q', ACTION_RELOAD },
6814 { 'Q', ACTION_RELOAD },
6815 { 'u', ACTION_REEXEC },
6816 { 'U', ACTION_REEXEC }
6817 };
6818
6819 unsigned i;
6820 int c;
6821
6822 assert(argc >= 0);
6823 assert(argv);
6824
601185b4 6825 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
6826 switch (c) {
6827
6828 case ARG_HELP:
601185b4
ZJS
6829 telinit_help();
6830 return 0;
e4b61340 6831
514f4ef5
LP
6832 case ARG_NO_WALL:
6833 arg_no_wall = true;
6834 break;
6835
e4b61340
LP
6836 case '?':
6837 return -EINVAL;
6838
6839 default:
eb9da376 6840 assert_not_reached("Unhandled option");
e4b61340 6841 }
e4b61340
LP
6842
6843 if (optind >= argc) {
601185b4
ZJS
6844 log_error("%s: required argument missing.",
6845 program_invocation_short_name);
e4b61340
LP
6846 return -EINVAL;
6847 }
6848
6849 if (optind + 1 < argc) {
6850 log_error("Too many arguments.");
6851 return -EINVAL;
6852 }
6853
6854 if (strlen(argv[optind]) != 1) {
6855 log_error("Expected single character argument.");
6856 return -EINVAL;
6857 }
6858
6859 for (i = 0; i < ELEMENTSOF(table); i++)
6860 if (table[i].from == argv[optind][0])
6861 break;
6862
6863 if (i >= ELEMENTSOF(table)) {
b0193f1c 6864 log_error("Unknown command '%s'.", argv[optind]);
e4b61340
LP
6865 return -EINVAL;
6866 }
6867
6868 arg_action = table[i].to;
6869
6870 optind ++;
6871
6872 return 1;
6873}
6874
6875static int runlevel_parse_argv(int argc, char *argv[]) {
6876
6877 enum {
6878 ARG_HELP = 0x100,
6879 };
6880
6881 static const struct option options[] = {
6882 { "help", no_argument, NULL, ARG_HELP },
eb9da376 6883 {}
e4b61340
LP
6884 };
6885
6886 int c;
6887
6888 assert(argc >= 0);
6889 assert(argv);
6890
601185b4 6891 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
6892 switch (c) {
6893
6894 case ARG_HELP:
601185b4
ZJS
6895 runlevel_help();
6896 return 0;
e4b61340
LP
6897
6898 case '?':
6899 return -EINVAL;
6900
6901 default:
eb9da376 6902 assert_not_reached("Unhandled option");
e4b61340 6903 }
e4b61340
LP
6904
6905 if (optind < argc) {
6906 log_error("Too many arguments.");
6907 return -EINVAL;
6908 }
6909
6910 return 1;
6911}
6912
6913static int parse_argv(int argc, char *argv[]) {
6914 assert(argc >= 0);
6915 assert(argv);
6916
6917 if (program_invocation_short_name) {
6918
6919 if (strstr(program_invocation_short_name, "halt")) {
6920 arg_action = ACTION_HALT;
6921 return halt_parse_argv(argc, argv);
6922 } else if (strstr(program_invocation_short_name, "poweroff")) {
6923 arg_action = ACTION_POWEROFF;
6924 return halt_parse_argv(argc, argv);
6925 } else if (strstr(program_invocation_short_name, "reboot")) {
5622dde3
KS
6926 if (kexec_loaded())
6927 arg_action = ACTION_KEXEC;
6928 else
6929 arg_action = ACTION_REBOOT;
e4b61340
LP
6930 return halt_parse_argv(argc, argv);
6931 } else if (strstr(program_invocation_short_name, "shutdown")) {
6932 arg_action = ACTION_POWEROFF;
6933 return shutdown_parse_argv(argc, argv);
6934 } else if (strstr(program_invocation_short_name, "init")) {
d5ca5f11
LP
6935
6936 if (sd_booted() > 0) {
f459b602 6937 arg_action = _ACTION_INVALID;
d5ca5f11
LP
6938 return telinit_parse_argv(argc, argv);
6939 } else {
6940 /* Hmm, so some other init system is
6941 * running, we need to forward this
6942 * request to it. For now we simply
6943 * guess that it is Upstart. */
6944
4ad61fd1 6945 execv(TELINIT, argv);
d5ca5f11
LP
6946
6947 log_error("Couldn't find an alternative telinit implementation to spawn.");
6948 return -EIO;
6949 }
6950
e4b61340
LP
6951 } else if (strstr(program_invocation_short_name, "runlevel")) {
6952 arg_action = ACTION_RUNLEVEL;
6953 return runlevel_parse_argv(argc, argv);
6954 }
6955 }
6956
6957 arg_action = ACTION_SYSTEMCTL;
6958 return systemctl_parse_argv(argc, argv);
6959}
6960
44a6b1b6 6961_pure_ static int action_to_runlevel(void) {
eb22ac37
LP
6962
6963 static const char table[_ACTION_MAX] = {
6964 [ACTION_HALT] = '0',
6965 [ACTION_POWEROFF] = '0',
6966 [ACTION_REBOOT] = '6',
6967 [ACTION_RUNLEVEL2] = '2',
6968 [ACTION_RUNLEVEL3] = '3',
6969 [ACTION_RUNLEVEL4] = '4',
6970 [ACTION_RUNLEVEL5] = '5',
6971 [ACTION_RESCUE] = '1'
6972 };
6973
d55ae9e6
LP
6974 assert(arg_action < _ACTION_MAX);
6975
6976 return table[arg_action];
6977}
6978
d55ae9e6 6979static int talk_initctl(void) {
cbc9fbd1
LP
6980
6981 struct init_request request = {
6982 .magic = INIT_MAGIC,
6983 .sleeptime = 0,
6984 .cmd = INIT_CMD_RUNLVL
6985 };
6986
7fd1b19b 6987 _cleanup_close_ int fd = -1;
d55ae9e6 6988 char rl;
cbc9fbd1 6989 int r;
eb22ac37 6990
427b47c4
ZJS
6991 rl = action_to_runlevel();
6992 if (!rl)
eb22ac37
LP
6993 return 0;
6994
d55ae9e6
LP
6995 request.runlevel = rl;
6996
427b47c4
ZJS
6997 fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
6998 if (fd < 0) {
d55ae9e6
LP
6999 if (errno == ENOENT)
7000 return 0;
eb22ac37 7001
56f64d95 7002 log_error_errno(errno, "Failed to open "INIT_FIFO": %m");
eb22ac37 7003 return -errno;
d55ae9e6 7004 }
eb22ac37 7005
553acb7b
ZJS
7006 r = loop_write(fd, &request, sizeof(request), false);
7007 if (r < 0)
7008 return log_error_errno(r, "Failed to write to "INIT_FIFO": %m");
eb22ac37
LP
7009
7010 return 1;
e4b61340
LP
7011}
7012
41dd15e4 7013static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
7e4249b9 7014
7e4249b9
LP
7015 static const struct {
7016 const char* verb;
7017 const enum {
7018 MORE,
7019 LESS,
7020 EQUAL
7021 } argc_cmp;
7022 const int argc;
f459b602 7023 int (* const dispatch)(sd_bus *bus, char **args);
d08e75ed
ZJS
7024 const enum {
7025 NOBUS = 1,
7026 FORCE,
7027 } bus;
7e4249b9 7028 } verbs[] = {
d8fba7c6 7029 { "list-units", MORE, 0, list_units },
d08e75ed 7030 { "list-unit-files", MORE, 1, list_unit_files, NOBUS },
d8fba7c6
ZJS
7031 { "list-sockets", MORE, 1, list_sockets },
7032 { "list-timers", MORE, 1, list_timers },
7033 { "list-jobs", MORE, 1, list_jobs },
0d292f5e 7034 { "list-machines", MORE, 1, list_machines },
ee5762e3 7035 { "clear-jobs", EQUAL, 1, daemon_reload },
ee5762e3
LP
7036 { "cancel", MORE, 2, cancel_job },
7037 { "start", MORE, 2, start_unit },
7038 { "stop", MORE, 2, start_unit },
a76f7be2 7039 { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
7040 { "reload", MORE, 2, start_unit },
7041 { "restart", MORE, 2, start_unit },
7042 { "try-restart", MORE, 2, start_unit },
7043 { "reload-or-restart", MORE, 2, start_unit },
7044 { "reload-or-try-restart", MORE, 2, start_unit },
7045 { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */
64e5f1b7 7046 { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
7047 { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
7048 { "isolate", EQUAL, 2, start_unit },
8a0867d6 7049 { "kill", MORE, 2, kill_unit },
1a0fce45
TA
7050 { "is-active", MORE, 2, check_unit_active },
7051 { "check", MORE, 2, check_unit_active },
7052 { "is-failed", MORE, 2, check_unit_failed },
ee5762e3 7053 { "show", MORE, 1, show },
ad2a0358 7054 { "cat", MORE, 2, cat, NOBUS },
265a7a2a 7055 { "status", MORE, 1, show },
b43f208f 7056 { "help", MORE, 2, show },
ee5762e3
LP
7057 { "snapshot", LESS, 2, snapshot },
7058 { "delete", MORE, 2, delete_snapshot },
7059 { "daemon-reload", EQUAL, 1, daemon_reload },
7060 { "daemon-reexec", EQUAL, 1, daemon_reload },
f459b602 7061 { "show-environment", EQUAL, 1, show_environment },
ee5762e3
LP
7062 { "set-environment", MORE, 2, set_environment },
7063 { "unset-environment", MORE, 2, set_environment },
ac3efa8a 7064 { "import-environment", MORE, 1, import_environment},
d08e75ed
ZJS
7065 { "halt", EQUAL, 1, start_special, FORCE },
7066 { "poweroff", EQUAL, 1, start_special, FORCE },
b986229e 7067 { "reboot", MORE, 1, start_special, FORCE },
20b09ca7 7068 { "kexec", EQUAL, 1, start_special },
6edd7d0a
LP
7069 { "suspend", EQUAL, 1, start_special },
7070 { "hibernate", EQUAL, 1, start_special },
6524990f 7071 { "hybrid-sleep", EQUAL, 1, start_special },
ee5762e3
LP
7072 { "default", EQUAL, 1, start_special },
7073 { "rescue", EQUAL, 1, start_special },
7074 { "emergency", EQUAL, 1, start_special },
20b09ca7 7075 { "exit", EQUAL, 1, start_special },
fdf20a31 7076 { "reset-failed", MORE, 1, reset_failed },
d08e75ed
ZJS
7077 { "enable", MORE, 2, enable_unit, NOBUS },
7078 { "disable", MORE, 2, enable_unit, NOBUS },
7079 { "is-enabled", MORE, 2, unit_is_enabled, NOBUS },
7080 { "reenable", MORE, 2, enable_unit, NOBUS },
7081 { "preset", MORE, 2, enable_unit, NOBUS },
d309c1c3 7082 { "preset-all", EQUAL, 1, preset_all, NOBUS },
d08e75ed
ZJS
7083 { "mask", MORE, 2, enable_unit, NOBUS },
7084 { "unmask", MORE, 2, enable_unit, NOBUS },
7085 { "link", MORE, 2, enable_unit, NOBUS },
957eb8ca 7086 { "switch-root", MORE, 2, switch_root },
e31165b2 7087 { "list-dependencies", LESS, 2, list_dependencies },
d08e75ed
ZJS
7088 { "set-default", EQUAL, 2, set_default, NOBUS },
7089 { "get-default", EQUAL, 1, get_default, NOBUS },
8e2af478 7090 { "set-property", MORE, 3, set_property },
99813a19 7091 { "is-system-running", EQUAL, 1, is_system_running },
7d4fb3b1
RC
7092 { "add-wants", MORE, 3, add_dependency, NOBUS },
7093 { "add-requires", MORE, 3, add_dependency, NOBUS },
7094 { "edit", MORE, 2, edit, NOBUS },
d08e75ed
ZJS
7095 {}
7096 }, *verb = verbs;
7e4249b9 7097
e4b61340 7098 int left;
7e4249b9 7099
e4b61340
LP
7100 assert(argc >= 0);
7101 assert(argv);
7e4249b9
LP
7102
7103 left = argc - optind;
7104
d08e75ed
ZJS
7105 /* Special rule: no arguments (left == 0) means "list-units" */
7106 if (left > 0) {
b43f208f
KS
7107 if (streq(argv[optind], "help") && !argv[optind+1]) {
7108 log_error("This command expects one or more "
7109 "unit names. Did you mean --help?");
7110 return -EINVAL;
0183528f
LP
7111 }
7112
d08e75ed
ZJS
7113 for (; verb->verb; verb++)
7114 if (streq(argv[optind], verb->verb))
7115 goto found;
7e4249b9 7116
d08e75ed
ZJS
7117 log_error("Unknown operation '%s'.", argv[optind]);
7118 return -EINVAL;
7e4249b9 7119 }
d08e75ed 7120found:
7e4249b9 7121
d08e75ed 7122 switch (verb->argc_cmp) {
7e4249b9
LP
7123
7124 case EQUAL:
d08e75ed 7125 if (left != verb->argc) {
7e4249b9 7126 log_error("Invalid number of arguments.");
e4b61340 7127 return -EINVAL;
7e4249b9
LP
7128 }
7129
7130 break;
7131
7132 case MORE:
d08e75ed 7133 if (left < verb->argc) {
7e4249b9 7134 log_error("Too few arguments.");
e4b61340 7135 return -EINVAL;
7e4249b9
LP
7136 }
7137
7138 break;
7139
7140 case LESS:
d08e75ed 7141 if (left > verb->argc) {
7e4249b9 7142 log_error("Too many arguments.");
e4b61340 7143 return -EINVAL;
7e4249b9
LP
7144 }
7145
7146 break;
7147
7148 default:
7149 assert_not_reached("Unknown comparison operator.");
7150 }
7151
ee5762e3
LP
7152 /* Require a bus connection for all operations but
7153 * enable/disable */
d08e75ed
ZJS
7154 if (verb->bus == NOBUS) {
7155 if (!bus && !avoid_bus()) {
da927ba9 7156 log_error_errno(bus_error, "Failed to get D-Bus connection: %m");
d08e75ed
ZJS
7157 return -EIO;
7158 }
82e23ddd 7159
d08e75ed 7160 } else {
82e23ddd
LP
7161 if (running_in_chroot() > 0) {
7162 log_info("Running in chroot, ignoring request.");
7163 return 0;
7164 }
7165
d08e75ed 7166 if ((verb->bus != FORCE || arg_force <= 0) && !bus) {
da927ba9 7167 log_error_errno(bus_error, "Failed to get D-Bus connection: %m");
82e23ddd
LP
7168 return -EIO;
7169 }
ee5762e3
LP
7170 }
7171
d08e75ed 7172 return verb->dispatch(bus, argv + optind);
e4b61340
LP
7173}
7174
f459b602 7175static int reload_with_fallback(sd_bus *bus) {
e4b61340
LP
7176
7177 if (bus) {
7178 /* First, try systemd via D-Bus. */
d76702a7 7179 if (daemon_reload(bus, NULL) >= 0)
e4b61340
LP
7180 return 0;
7181 }
7182
7183 /* Nothing else worked, so let's try signals */
7184 assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
7185
4a62c710
MS
7186 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0)
7187 return log_error_errno(errno, "kill() failed: %m");
e4b61340
LP
7188
7189 return 0;
7190}
7191
f459b602 7192static int start_with_fallback(sd_bus *bus) {
e4b61340
LP
7193
7194 if (bus) {
7195 /* First, try systemd via D-Bus. */
729e3769 7196 if (start_unit(bus, NULL) >= 0)
983d9c90 7197 goto done;
e4b61340
LP
7198 }
7199
7200 /* Nothing else worked, so let's try
7201 * /dev/initctl */
fbc43921 7202 if (talk_initctl() > 0)
983d9c90 7203 goto done;
d55ae9e6
LP
7204
7205 log_error("Failed to talk to init daemon.");
7206 return -EIO;
983d9c90
LP
7207
7208done:
7209 warn_wall(arg_action);
7210 return 0;
e4b61340
LP
7211}
7212
477def80 7213static int halt_now(enum action a) {
e606bb61 7214
4a3ad399
LP
7215 /* The kernel will automaticall flush ATA disks and suchlike
7216 * on reboot(), but the file systems need to be synce'd
7217 * explicitly in advance. */
7218 sync();
7219
7220 /* Make sure C-A-D is handled by the kernel from this point
7221 * on... */
e606bb61
LP
7222 reboot(RB_ENABLE_CAD);
7223
4c80c73c 7224 switch (a) {
e606bb61
LP
7225
7226 case ACTION_HALT:
7227 log_info("Halting.");
7228 reboot(RB_HALT_SYSTEM);
477def80 7229 return -errno;
e606bb61
LP
7230
7231 case ACTION_POWEROFF:
7232 log_info("Powering off.");
7233 reboot(RB_POWER_OFF);
477def80 7234 return -errno;
e606bb61 7235
477def80
LP
7236 case ACTION_REBOOT: {
7237 _cleanup_free_ char *param = NULL;
cbc9fbd1 7238
477def80
LP
7239 if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
7240 log_info("Rebooting with argument '%s'.", param);
37185ec8
WC
7241 syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
7242 LINUX_REBOOT_CMD_RESTART2, param);
37185ec8 7243 }
e606bb61 7244
477def80
LP
7245 log_info("Rebooting.");
7246 reboot(RB_AUTOBOOT);
7247 return -errno;
e606bb61
LP
7248 }
7249
477def80
LP
7250 default:
7251 assert_not_reached("Unknown action.");
7252 }
e606bb61
LP
7253}
7254
f459b602 7255static int halt_main(sd_bus *bus) {
e4b61340
LP
7256 int r;
7257
748ebafa
LP
7258 r = check_inhibitors(bus, arg_action);
7259 if (r < 0)
7260 return r;
b37844d3 7261
bc8c2f5c 7262 if (geteuid() != 0) {
7e59bfcb
LP
7263 /* Try logind if we are a normal user and no special
7264 * mode applies. Maybe PolicyKit allows us to shutdown
7265 * the machine. */
7266
7267 if (arg_when <= 0 &&
7268 !arg_dry &&
b37844d3 7269 arg_force <= 0 &&
7e59bfcb
LP
7270 (arg_action == ACTION_POWEROFF ||
7271 arg_action == ACTION_REBOOT)) {
4c80c73c
KS
7272 r = reboot_with_logind(bus, arg_action);
7273 if (r >= 0)
7274 return r;
7275 }
7276
cc8a7a61 7277 log_error("Must be root.");
bc8c2f5c
LP
7278 return -EPERM;
7279 }
7280
f6144808 7281 if (arg_when > 0) {
f0efea23
DM
7282 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
7283 _cleanup_bus_close_unref_ sd_bus *b = NULL;
7fd1b19b 7284 _cleanup_free_ char *m;
9be9828c 7285
f0efea23
DM
7286 if (avoid_bus()) {
7287 log_error("Unable to perform operation without bus connection.");
7288 return -ENOSYS;
7289 }
7290
7291 r = sd_bus_open_system(&b);
7292 if (r < 0)
d3a2a053 7293 return log_error_errno(r, "Unable to open system bus: %m");
f0efea23 7294
9be9828c 7295 m = strv_join(arg_wall, " ");
cbc9fbd1
LP
7296 if (!m)
7297 return log_oom();
7298
f0efea23
DM
7299 r = sd_bus_set_property(
7300 b,
7301 "org.freedesktop.login1",
7302 "/org/freedesktop/login1",
7303 "org.freedesktop.login1.Manager",
7304 "WallMessage",
7305 &error,
7306 "s", m);
7307 if (r < 0) {
7308 log_warning_errno(r, "Failed to set WallMessage property in logind: %s",
7309 bus_error_message(&error, r));
7310 sd_bus_error_free(&error);
7311 }
7312
7313 r = sd_bus_set_property(
7314 b,
7315 "org.freedesktop.login1",
7316 "/org/freedesktop/login1",
7317 "org.freedesktop.login1.Manager",
7318 "EnableWallMessages",
7319 &error,
7320 "b", !arg_no_wall);
7321 if (r < 0) {
7322 log_warning_errno(r, "Failed to set EnableWallMessages property in logind: %s",
7323 bus_error_message(&error, r));
7324 sd_bus_error_free(&error);
7325 }
9be9828c 7326
f0efea23
DM
7327 r = sd_bus_call_method(
7328 b,
7329 "org.freedesktop.login1",
7330 "/org/freedesktop/login1",
7331 "org.freedesktop.login1.Manager",
7332 "ScheduleShutdown",
7333 &error,
7334 NULL,
7335 "st",
7336 arg_action == ACTION_HALT ? "halt" :
7337 arg_action == ACTION_POWEROFF ? "poweroff" :
7338 arg_action == ACTION_KEXEC ? "kexec" :
7339 "reboot",
7340 arg_when);
9be9828c 7341 if (r < 0)
f0efea23
DM
7342 log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s",
7343 bus_error_message(&error, r));
08e4b1c5 7344 else {
7e59bfcb
LP
7345 char date[FORMAT_TIMESTAMP_MAX];
7346
08e4b1c5
LP
7347 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
7348 format_timestamp(date, sizeof(date), arg_when));
f6144808 7349 return 0;
08e4b1c5 7350 }
f6144808
LP
7351 }
7352
65491fd8 7353 if (!arg_dry && !arg_force)
e4b61340
LP
7354 return start_with_fallback(bus);
7355
d90e1a30
LP
7356 if (!arg_no_wtmp) {
7357 if (sd_booted() > 0)
7358 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
7e59bfcb
LP
7359 else {
7360 r = utmp_put_shutdown();
7361 if (r < 0)
da927ba9 7362 log_warning_errno(r, "Failed to write utmp record: %m");
7e59bfcb 7363 }
d90e1a30 7364 }
e4b61340 7365
e4b61340
LP
7366 if (arg_dry)
7367 return 0;
7368
477def80 7369 r = halt_now(arg_action);
da927ba9 7370 log_error_errno(r, "Failed to reboot: %m");
477def80
LP
7371
7372 return r;
e4b61340
LP
7373}
7374
7375static int runlevel_main(void) {
7376 int r, runlevel, previous;
7377
729e3769
LP
7378 r = utmp_get_runlevel(&runlevel, &previous);
7379 if (r < 0) {
7380 puts("unknown");
e4b61340
LP
7381 return r;
7382 }
7383
7384 printf("%c %c\n",
7385 previous <= 0 ? 'N' : previous,
7386 runlevel <= 0 ? 'N' : runlevel);
7387
7388 return 0;
7389}
7390
7391int main(int argc, char*argv[]) {
24996861 7392 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
f459b602 7393 int r;
e4b61340 7394
a9cdc94f 7395 setlocale(LC_ALL, "");
e4b61340 7396 log_parse_environment();
2396fb04 7397 log_open();
e4b61340 7398
184ecaf7
DR
7399 /* Explicitly not on_tty() to avoid setting cached value.
7400 * This becomes relevant for piping output which might be
7401 * ellipsized. */
7402 original_stdout_is_tty = isatty(STDOUT_FILENO);
7403
04ebb595 7404 r = parse_argv(argc, argv);
f459b602 7405 if (r <= 0)
e4b61340 7406 goto finish;
7e4249b9 7407
e4b61340
LP
7408 /* /sbin/runlevel doesn't need to communicate via D-Bus, so
7409 * let's shortcut this */
7410 if (arg_action == ACTION_RUNLEVEL) {
22f4096c 7411 r = runlevel_main();
e4b61340
LP
7412 goto finish;
7413 }
7414
82e23ddd
LP
7415 if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
7416 log_info("Running in chroot, ignoring request.");
f459b602 7417 r = 0;
82e23ddd
LP
7418 goto finish;
7419 }
7420
41dd15e4
LP
7421 if (!avoid_bus())
7422 r = bus_open_transport_systemd(arg_transport, arg_host, arg_scope != UNIT_FILE_SYSTEM, &bus);
7423
6e646d22
LP
7424 if (bus)
7425 sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
7426
41dd15e4
LP
7427 /* systemctl_main() will print an error message for the bus
7428 * connection, but only if it needs to */
e4b61340
LP
7429
7430 switch (arg_action) {
7431
22f4096c 7432 case ACTION_SYSTEMCTL:
f459b602 7433 r = systemctl_main(bus, argc, argv, r);
e4b61340 7434 break;
e4b61340
LP
7435
7436 case ACTION_HALT:
7437 case ACTION_POWEROFF:
7438 case ACTION_REBOOT:
5622dde3 7439 case ACTION_KEXEC:
22f4096c 7440 r = halt_main(bus);
e4b61340
LP
7441 break;
7442
e4b61340
LP
7443 case ACTION_RUNLEVEL2:
7444 case ACTION_RUNLEVEL3:
7445 case ACTION_RUNLEVEL4:
7446 case ACTION_RUNLEVEL5:
7447 case ACTION_RESCUE:
514f4ef5 7448 case ACTION_EMERGENCY:
eb22ac37 7449 case ACTION_DEFAULT:
22f4096c 7450 r = start_with_fallback(bus);
e4b61340 7451 break;
7e4249b9 7452
e4b61340
LP
7453 case ACTION_RELOAD:
7454 case ACTION_REEXEC:
22f4096c 7455 r = reload_with_fallback(bus);
e4b61340
LP
7456 break;
7457
dfcc5c33 7458 case ACTION_CANCEL_SHUTDOWN: {
f0efea23
DM
7459 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
7460 _cleanup_bus_close_unref_ sd_bus *b = NULL;
f459b602 7461 _cleanup_free_ char *m = NULL;
dfcc5c33 7462
f0efea23
DM
7463 if (avoid_bus()) {
7464 log_error("Unable to perform operation without bus connection.");
7465 return -ENOSYS;
7466 }
7467
7468 r = sd_bus_open_system(&b);
7469 if (r < 0)
d3a2a053 7470 return log_error_errno(r, "Unable to open system bus: %m");
f0efea23 7471
dfcc5c33
MS
7472 if (arg_wall) {
7473 m = strv_join(arg_wall, " ");
7474 if (!m) {
f459b602 7475 r = log_oom();
dfcc5c33
MS
7476 goto finish;
7477 }
7478 }
f459b602 7479
f0efea23
DM
7480 r = sd_bus_set_property(
7481 b,
7482 "org.freedesktop.login1",
7483 "/org/freedesktop/login1",
7484 "org.freedesktop.login1.Manager",
7485 "WallMessage",
7486 &error,
7487 "s", arg_wall);
7488 if (r < 0) {
7489 log_warning_errno(r, "Failed to set WallMessage property in logind: %s",
7490 bus_error_message(&error, r));
7491 sd_bus_error_free(&error);
7492 }
7493
7494 r = sd_bus_set_property(
7495 b,
7496 "org.freedesktop.login1",
7497 "/org/freedesktop/login1",
7498 "org.freedesktop.login1.Manager",
7499 "EnableWallMessages",
7500 &error,
7501 "b", !arg_no_wall);
7502 if (r < 0) {
7503 log_warning_errno(r, "Failed to set EnableWallMessages property in logind: %s",
7504 bus_error_message(&error, r));
7505 sd_bus_error_free(&error);
7506 }
7507
7508 r = sd_bus_call_method(
7509 b,
7510 "org.freedesktop.login1",
7511 "/org/freedesktop/login1",
7512 "org.freedesktop.login1.Manager",
7513 "CancelScheduledShutdown",
7514 &error,
7515 NULL, NULL);
dfcc5c33 7516 if (r < 0)
f0efea23
DM
7517 log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s",
7518 bus_error_message(&error, r));
f6144808 7519 break;
dfcc5c33 7520 }
f6144808 7521
eb22ac37 7522 case ACTION_RUNLEVEL:
f459b602 7523 case _ACTION_INVALID:
e4b61340
LP
7524 default:
7525 assert_not_reached("Unknown action");
7526 }
7e4249b9
LP
7527
7528finish:
f459b602
MAP
7529 pager_close();
7530 ask_password_agent_close();
7531 polkit_agent_close();
7e4249b9 7532
20b3f379 7533 strv_free(arg_types);
9b9b3d36 7534 strv_free(arg_states);
20b3f379 7535 strv_free(arg_properties);
ea4a240d 7536
f459b602 7537 return r < 0 ? EXIT_FAILURE : r;
7e4249b9 7538}