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