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