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