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