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