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