]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl-util.c
license: LGPL-2.1+ -> LGPL-2.1-or-later
[thirdparty/systemd.git] / src / systemctl / systemctl-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
daf71ef6
LP
2
3#include <sys/reboot.h>
4#include <unistd.h>
5
6#include "sd-bus.h"
7#include "sd-daemon.h"
8
9#include "bus-common-errors.h"
10#include "bus-locator.h"
11#include "bus-map-properties.h"
12#include "bus-unit-util.h"
13#include "dropin.h"
14#include "env-util.h"
15#include "exit-status.h"
16#include "fs-util.h"
17#include "glob-util.h"
18#include "macro.h"
19#include "path-util.h"
20#include "reboot-util.h"
21#include "set.h"
22#include "spawn-ask-password-agent.h"
23#include "spawn-polkit-agent.h"
24#include "stat-util.h"
25#include "systemctl-util.h"
26#include "systemctl.h"
27#include "terminal-util.h"
28#include "verbs.h"
29
30static sd_bus *buses[_BUS_FOCUS_MAX] = {};
31
32int acquire_bus(BusFocus focus, sd_bus **ret) {
33 int r;
34
35 assert(focus < _BUS_FOCUS_MAX);
36 assert(ret);
37
38 /* We only go directly to the manager, if we are using a local transport */
39 if (arg_transport != BUS_TRANSPORT_LOCAL)
40 focus = BUS_FULL;
41
42 if (getenv_bool("SYSTEMCTL_FORCE_BUS") > 0)
43 focus = BUS_FULL;
44
45 if (!buses[focus]) {
46 bool user;
47
48 user = arg_scope != UNIT_FILE_SYSTEM;
49
50 if (focus == BUS_MANAGER)
51 r = bus_connect_transport_systemd(arg_transport, arg_host, user, &buses[focus]);
52 else
53 r = bus_connect_transport(arg_transport, arg_host, user, &buses[focus]);
54 if (r < 0)
ab4a88eb 55 return bus_log_connect_error(r);
daf71ef6
LP
56
57 (void) sd_bus_set_allow_interactive_authorization(buses[focus], arg_ask_password);
58 }
59
60 *ret = buses[focus];
61 return 0;
62}
63
64void release_busses(void) {
65 BusFocus w;
66
67 for (w = 0; w < _BUS_FOCUS_MAX; w++)
68 buses[w] = sd_bus_flush_close_unref(buses[w]);
69}
70
71void ask_password_agent_open_maybe(void) {
72 /* Open the password agent as a child process if necessary */
73
74 if (arg_dry_run)
75 return;
76
77 if (arg_scope != UNIT_FILE_SYSTEM)
78 return;
79
80 ask_password_agent_open_if_enabled(arg_transport, arg_ask_password);
81}
82
83void polkit_agent_open_maybe(void) {
84 /* Open the polkit agent as a child process if necessary */
85
86 if (arg_scope != UNIT_FILE_SYSTEM)
87 return;
88
89 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
90}
91
92int translate_bus_error_to_exit_status(int r, const sd_bus_error *error) {
93 assert(error);
94
95 if (!sd_bus_error_is_set(error))
96 return r;
97
98 if (sd_bus_error_has_names(error, SD_BUS_ERROR_ACCESS_DENIED,
99 BUS_ERROR_ONLY_BY_DEPENDENCY,
100 BUS_ERROR_NO_ISOLATION,
101 BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
102 return EXIT_NOPERMISSION;
103
104 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
105 return EXIT_NOTINSTALLED;
106
107 if (sd_bus_error_has_names(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE,
108 SD_BUS_ERROR_NOT_SUPPORTED))
109 return EXIT_NOTIMPLEMENTED;
110
111 if (sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
112 return EXIT_NOTCONFIGURED;
113
114 if (r != 0)
115 return r;
116
117 return EXIT_FAILURE;
118}
119
120int get_state_one_unit(sd_bus *bus, const char *unit, UnitActiveState *ret_active_state) {
121 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
122 _cleanup_free_ char *buf = NULL, *dbus_path = NULL;
123 UnitActiveState state;
124 int r;
125
126 assert(unit);
127 assert(ret_active_state);
128
129 dbus_path = unit_dbus_path_from_name(unit);
130 if (!dbus_path)
131 return log_oom();
132
133 r = sd_bus_get_property_string(
134 bus,
135 "org.freedesktop.systemd1",
136 dbus_path,
137 "org.freedesktop.systemd1.Unit",
138 "ActiveState",
139 &error,
140 &buf);
141 if (r < 0)
142 return log_error_errno(r, "Failed to retrieve unit state: %s", bus_error_message(&error, r));
143
144 state = unit_active_state_from_string(buf);
145 if (state < 0)
146 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid unit state '%s' for: %s", buf, unit);
147
148 *ret_active_state = state;
149 return 0;
150}
151
152int get_unit_list(
153 sd_bus *bus,
154 const char *machine,
155 char **patterns,
156 UnitInfo **unit_infos,
157 int c,
158 sd_bus_message **ret_reply) {
159
160 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
161 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
162 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
163 size_t size = c;
164 int r;
165 bool fallback = false;
166
167 assert(bus);
168 assert(unit_infos);
169 assert(ret_reply);
170
171 r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitsByPatterns");
172 if (r < 0)
173 return bus_log_create_error(r);
174
175 r = sd_bus_message_append_strv(m, arg_states);
176 if (r < 0)
177 return bus_log_create_error(r);
178
179 r = sd_bus_message_append_strv(m, patterns);
180 if (r < 0)
181 return bus_log_create_error(r);
182
183 r = sd_bus_call(bus, m, 0, &error, &reply);
184 if (r < 0 && (sd_bus_error_has_names(&error, SD_BUS_ERROR_UNKNOWN_METHOD,
185 SD_BUS_ERROR_ACCESS_DENIED))) {
186 /* Fallback to legacy ListUnitsFiltered method */
187 fallback = true;
188 log_debug_errno(r, "Failed to list units: %s Falling back to ListUnitsFiltered method.", bus_error_message(&error, r));
189 m = sd_bus_message_unref(m);
190 sd_bus_error_free(&error);
191
192 r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitsFiltered");
193 if (r < 0)
194 return bus_log_create_error(r);
195
196 r = sd_bus_message_append_strv(m, arg_states);
197 if (r < 0)
198 return bus_log_create_error(r);
199
200 r = sd_bus_call(bus, m, 0, &error, &reply);
201 }
202 if (r < 0)
203 return log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
204
205 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
206 if (r < 0)
207 return bus_log_parse_error(r);
208
209 for (;;) {
210 UnitInfo u;
211
212 r = bus_parse_unit_info(reply, &u);
213 if (r < 0)
214 return bus_log_parse_error(r);
215 if (r == 0)
216 break;
217
218 u.machine = machine;
219
220 if (!output_show_unit(&u, fallback ? patterns : NULL))
221 continue;
222
223 if (!GREEDY_REALLOC(*unit_infos, size, c+1))
224 return log_oom();
225
226 (*unit_infos)[c++] = u;
227 }
228
229 r = sd_bus_message_exit_container(reply);
230 if (r < 0)
231 return bus_log_parse_error(r);
232
233 *ret_reply = TAKE_PTR(reply);
234 return c;
235}
236
237int expand_unit_names(sd_bus *bus, char **names, const char* suffix, char ***ret, bool *ret_expanded) {
238 _cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
239 char **name;
240 int r, i;
241
242 assert(bus);
243 assert(ret);
244
245 STRV_FOREACH(name, names) {
246 UnitNameMangle options = UNIT_NAME_MANGLE_GLOB | (arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN);
247 char *t;
248
249 r = unit_name_mangle_with_suffix(*name, NULL, options, suffix ?: ".service", &t);
250 if (r < 0)
251 return log_error_errno(r, "Failed to mangle name: %m");
252
253 if (string_is_glob(t))
254 r = strv_consume(&globs, t);
255 else
256 r = strv_consume(&mangled, t);
257 if (r < 0)
258 return log_oom();
259 }
260
261 /* Query the manager only if any of the names are a glob, since this is fairly expensive */
262 bool expanded = !strv_isempty(globs);
263 if (expanded) {
264 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
265 _cleanup_free_ UnitInfo *unit_infos = NULL;
266 size_t allocated, n;
267
268 r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
269 if (r < 0)
270 return r;
271
272 n = strv_length(mangled);
273 allocated = n + 1;
274
275 for (i = 0; i < r; i++) {
276 if (!GREEDY_REALLOC(mangled, allocated, n+2))
277 return log_oom();
278
279 mangled[n] = strdup(unit_infos[i].id);
280 if (!mangled[n])
281 return log_oom();
282
283 mangled[++n] = NULL;
284 }
285 }
286
287 if (ret_expanded)
288 *ret_expanded = expanded;
289
290 *ret = TAKE_PTR(mangled);
291 return 0;
292}
293
294int check_triggering_units(sd_bus *bus, const char *unit) {
295 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
296 _cleanup_free_ char *n = NULL, *dbus_path = NULL, *load_state = NULL;
297 _cleanup_strv_free_ char **triggered_by = NULL;
298 bool print_warning_label = true;
299 UnitActiveState active_state;
300 char **i;
301 int r;
302
303 r = unit_name_mangle(unit, 0, &n);
304 if (r < 0)
305 return log_error_errno(r, "Failed to mangle unit name: %m");
306
307 r = unit_load_state(bus, n, &load_state);
308 if (r < 0)
309 return r;
310
311 if (streq(load_state, "masked"))
312 return 0;
313
314 dbus_path = unit_dbus_path_from_name(n);
315 if (!dbus_path)
316 return log_oom();
317
318 r = sd_bus_get_property_strv(
319 bus,
320 "org.freedesktop.systemd1",
321 dbus_path,
322 "org.freedesktop.systemd1.Unit",
323 "TriggeredBy",
324 &error,
325 &triggered_by);
326 if (r < 0)
327 return log_error_errno(r, "Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r));
328
329 STRV_FOREACH(i, triggered_by) {
330 r = get_state_one_unit(bus, *i, &active_state);
331 if (r < 0)
332 return r;
333
334 if (!IN_SET(active_state, UNIT_ACTIVE, UNIT_RELOADING))
335 continue;
336
337 if (print_warning_label) {
338 log_warning("Warning: Stopping %s, but it can still be activated by:", n);
339 print_warning_label = false;
340 }
341
342 log_warning(" %s", *i);
343 }
344
345 return 0;
346}
347
348int need_daemon_reload(sd_bus *bus, const char *unit) {
349 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
350 const char *path;
351 int b, r;
352
353 /* We ignore all errors here, since this is used to show a
354 * warning only */
355
356 /* We don't use unit_dbus_path_from_name() directly since we
357 * don't want to load the unit if it isn't loaded. */
358
359 r = bus_call_method(bus, bus_systemd_mgr, "GetUnit", NULL, &reply, "s", unit);
360 if (r < 0)
361 return r;
362
363 r = sd_bus_message_read(reply, "o", &path);
364 if (r < 0)
365 return r;
366
367 r = sd_bus_get_property_trivial(
368 bus,
369 "org.freedesktop.systemd1",
370 path,
371 "org.freedesktop.systemd1.Unit",
372 "NeedDaemonReload",
373 NULL,
374 'b', &b);
375 if (r < 0)
376 return r;
377
378 return b;
379}
380
381void warn_unit_file_changed(const char *unit) {
382 assert(unit);
383
384 log_warning("%sWarning:%s The unit file, source configuration file or drop-ins of %s changed on disk. Run 'systemctl%s daemon-reload' to reload units.",
385 ansi_highlight_red(),
386 ansi_normal(),
387 unit,
388 arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
389}
390
391int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **ret_unit_path) {
392 char **p;
393
394 assert(lp);
395 assert(unit_name);
396
397 STRV_FOREACH(p, lp->search_path) {
398 _cleanup_free_ char *path = NULL, *lpath = NULL;
399 int r;
400
401 path = path_join(*p, unit_name);
402 if (!path)
403 return log_oom();
404
405 r = chase_symlinks(path, arg_root, 0, &lpath, NULL);
406 if (r == -ENOENT)
407 continue;
408 if (r == -ENOMEM)
409 return log_oom();
410 if (r < 0)
411 return log_error_errno(r, "Failed to access path \"%s\": %m", path);
412
413 if (ret_unit_path)
414 *ret_unit_path = TAKE_PTR(lpath);
415
416 return 1;
417 }
418
419 if (ret_unit_path)
420 *ret_unit_path = NULL;
421
422 return 0;
423}
424
425int unit_find_paths(
426 sd_bus *bus,
427 const char *unit_name,
428 LookupPaths *lp,
429 bool force_client_side,
430 Hashmap **cached_name_map,
431 Hashmap **cached_id_map,
432 char **ret_fragment_path,
433 char ***ret_dropin_paths) {
434
435 _cleanup_strv_free_ char **dropins = NULL;
436 _cleanup_free_ char *path = NULL;
437 int r;
438
439 /**
440 * Finds where the unit is defined on disk. Returns 0 if the unit is not found. Returns 1 if it is
441 * found, and sets:
442 * - the path to the unit in *ret_frament_path, if it exists on disk,
443 * - and a strv of existing drop-ins in *ret_dropin_paths, if the arg is not NULL and any dropins
444 * were found.
445 *
446 * Returns -ERFKILL if the unit is masked, and -EKEYREJECTED if the unit file could not be loaded for
447 * some reason (the latter only applies if we are going through the service manager).
448 */
449
450 assert(unit_name);
451 assert(ret_fragment_path);
452 assert(lp);
453
454 /* Go via the bus to acquire the path, unless we are explicitly told not to, or when the unit name is a template */
455 if (!force_client_side &&
456 !install_client_side() &&
457 !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
458 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
459 _cleanup_free_ char *load_state = NULL, *dbus_path = NULL;
460
461 dbus_path = unit_dbus_path_from_name(unit_name);
462 if (!dbus_path)
463 return log_oom();
464
465 r = sd_bus_get_property_string(
466 bus,
467 "org.freedesktop.systemd1",
468 dbus_path,
469 "org.freedesktop.systemd1.Unit",
470 "LoadState",
471 &error,
472 &load_state);
473 if (r < 0)
474 return log_error_errno(r, "Failed to get LoadState: %s", bus_error_message(&error, r));
475
476 if (streq(load_state, "masked"))
477 return -ERFKILL;
478 if (streq(load_state, "not-found")) {
479 r = 0;
480 goto not_found;
481 }
482 if (!STR_IN_SET(load_state, "loaded", "bad-setting"))
483 return -EKEYREJECTED;
484
485 r = sd_bus_get_property_string(
486 bus,
487 "org.freedesktop.systemd1",
488 dbus_path,
489 "org.freedesktop.systemd1.Unit",
490 "FragmentPath",
491 &error,
492 &path);
493 if (r < 0)
494 return log_error_errno(r, "Failed to get FragmentPath: %s", bus_error_message(&error, r));
495
496 if (ret_dropin_paths) {
497 r = sd_bus_get_property_strv(
498 bus,
499 "org.freedesktop.systemd1",
500 dbus_path,
501 "org.freedesktop.systemd1.Unit",
502 "DropInPaths",
503 &error,
504 &dropins);
505 if (r < 0)
506 return log_error_errno(r, "Failed to get DropInPaths: %s", bus_error_message(&error, r));
507 }
508 } else {
509 const char *_path;
510 _cleanup_set_free_free_ Set *names = NULL;
511
512 if (!*cached_name_map) {
513 r = unit_file_build_name_map(lp, NULL, cached_id_map, cached_name_map, NULL);
514 if (r < 0)
515 return r;
516 }
517
518 r = unit_file_find_fragment(*cached_id_map, *cached_name_map, unit_name, &_path, &names);
519 if (r < 0)
520 return r;
521
522 if (_path) {
523 path = strdup(_path);
524 if (!path)
525 return log_oom();
526 }
527
528 if (ret_dropin_paths) {
529 r = unit_file_find_dropin_paths(arg_root, lp->search_path, NULL,
530 ".d", ".conf",
531 NULL, names, &dropins);
532 if (r < 0)
533 return r;
534 }
535 }
536
537 if (isempty(path)) {
538 *ret_fragment_path = NULL;
539 r = 0;
540 } else {
541 *ret_fragment_path = TAKE_PTR(path);
542 r = 1;
543 }
544
545 if (ret_dropin_paths) {
546 if (!strv_isempty(dropins)) {
547 *ret_dropin_paths = TAKE_PTR(dropins);
548 r = 1;
549 } else
550 *ret_dropin_paths = NULL;
551 }
552
553 not_found:
554 if (r == 0 && !arg_force)
555 log_error("No files found for %s.", unit_name);
556
557 return r;
558}
559
560static int unit_find_template_path(
561 const char *unit_name,
562 LookupPaths *lp,
563 char **ret_fragment_path,
564 char **ret_template) {
565
566 _cleanup_free_ char *t = NULL, *f = NULL;
567 int r;
568
569 /* Returns 1 if a fragment was found, 0 if not found, negative on error. */
570
571 r = unit_file_find_path(lp, unit_name, &f);
572 if (r < 0)
573 return r;
574 if (r > 0) {
575 if (ret_fragment_path)
576 *ret_fragment_path = TAKE_PTR(f);
577 if (ret_template)
578 *ret_template = NULL;
579 return r; /* found a real unit */
580 }
581
582 r = unit_name_template(unit_name, &t);
583 if (r == -EINVAL) {
584 if (ret_fragment_path)
585 *ret_fragment_path = NULL;
586 if (ret_template)
587 *ret_template = NULL;
588
589 return 0; /* not a template, does not exist */
590 }
591 if (r < 0)
592 return log_error_errno(r, "Failed to determine template name: %m");
593
594 r = unit_file_find_path(lp, t, ret_fragment_path);
595 if (r < 0)
596 return r;
597
598 if (ret_template)
599 *ret_template = r > 0 ? TAKE_PTR(t) : NULL;
600
601 return r;
602}
603
604int unit_is_masked(sd_bus *bus, LookupPaths *lp, const char *name) {
605 _cleanup_free_ char *load_state = NULL;
606 int r;
607
608 if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
609 _cleanup_free_ char *path = NULL;
610
611 /* A template cannot be loaded, but it can be still masked, so
612 * we need to use a different method. */
613
614 r = unit_file_find_path(lp, name, &path);
615 if (r < 0)
616 return r;
617 if (r == 0)
618 return false;
619 return null_or_empty_path(path);
620 }
621
622 r = unit_load_state(bus, name, &load_state);
623 if (r < 0)
624 return r;
625
626 return streq(load_state, "masked");
627}
628
629int unit_exists(LookupPaths *lp, const char *unit) {
630 typedef struct UnitStateInfo {
631 const char *load_state;
632 const char *active_state;
633 } UnitStateInfo;
634
635 static const struct bus_properties_map property_map[] = {
636 { "LoadState", "s", NULL, offsetof(UnitStateInfo, load_state) },
637 { "ActiveState", "s", NULL, offsetof(UnitStateInfo, active_state) },
638 {},
639 };
640
641 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
642 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
643 _cleanup_free_ char *path = NULL;
644 UnitStateInfo info = {};
645 sd_bus *bus;
646 int r;
647
648 if (unit_name_is_valid(unit, UNIT_NAME_TEMPLATE))
649 return unit_find_template_path(unit, lp, NULL, NULL);
650
651 path = unit_dbus_path_from_name(unit);
652 if (!path)
653 return log_oom();
654
655 r = acquire_bus(BUS_MANAGER, &bus);
656 if (r < 0)
657 return r;
658
659 r = bus_map_all_properties(bus, "org.freedesktop.systemd1", path, property_map, 0, &error, &m, &info);
660 if (r < 0)
661 return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
662
663 return !streq_ptr(info.load_state, "not-found") || !streq_ptr(info.active_state, "inactive");
664}
665
666
667int append_unit_dependencies(sd_bus *bus, char **names, char ***ret) {
668 _cleanup_strv_free_ char **with_deps = NULL;
669 char **name;
670
671 assert(bus);
672 assert(ret);
673
674 STRV_FOREACH(name, names) {
675 _cleanup_strv_free_ char **deps = NULL;
676
677 if (strv_extend(&with_deps, *name) < 0)
678 return log_oom();
679
680 (void) unit_get_dependencies(bus, *name, &deps);
681
682 if (strv_extend_strv(&with_deps, deps, true) < 0)
683 return log_oom();
684 }
685
686 *ret = TAKE_PTR(with_deps);
687
688 return 0;
689}
690
691int maybe_extend_with_unit_dependencies(sd_bus *bus, char ***list) {
692 _cleanup_strv_free_ char **list_with_deps = NULL;
693 int r;
694
695 assert(bus);
696 assert(list);
697
698 if (!arg_with_dependencies)
699 return 0;
700
701 r = append_unit_dependencies(bus, *list, &list_with_deps);
702 if (r < 0)
703 return log_error_errno(r, "Failed to append unit dependencies: %m");
704
705 strv_free(*list);
706 *list = TAKE_PTR(list_with_deps);
707 return 0;
708}
709
710int unit_get_dependencies(sd_bus *bus, const char *name, char ***ret) {
711 _cleanup_strv_free_ char **deps = NULL;
712
713 static const struct bus_properties_map map[_DEPENDENCY_MAX][6] = {
714 [DEPENDENCY_FORWARD] = {
715 { "Requires", "as", NULL, 0 },
716 { "Requisite", "as", NULL, 0 },
717 { "Wants", "as", NULL, 0 },
718 { "ConsistsOf", "as", NULL, 0 },
719 { "BindsTo", "as", NULL, 0 },
720 {}
721 },
722 [DEPENDENCY_REVERSE] = {
723 { "RequiredBy", "as", NULL, 0 },
724 { "RequisiteOf", "as", NULL, 0 },
725 { "WantedBy", "as", NULL, 0 },
726 { "PartOf", "as", NULL, 0 },
727 { "BoundBy", "as", NULL, 0 },
728 {}
729 },
730 [DEPENDENCY_AFTER] = {
731 { "After", "as", NULL, 0 },
732 {}
733 },
734 [DEPENDENCY_BEFORE] = {
735 { "Before", "as", NULL, 0 },
736 {}
737 },
738 };
739
740 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
741 _cleanup_free_ char *dbus_path = NULL;
742 int r;
743
744 assert(bus);
745 assert(name);
746 assert(ret);
747
748 dbus_path = unit_dbus_path_from_name(name);
749 if (!dbus_path)
750 return log_oom();
751
752 r = bus_map_all_properties(bus,
753 "org.freedesktop.systemd1",
754 dbus_path,
755 map[arg_dependency],
756 BUS_MAP_STRDUP,
757 &error,
758 NULL,
759 &deps);
760 if (r < 0)
761 return log_error_errno(r, "Failed to get properties of %s: %s", name, bus_error_message(&error, r));
762
763 strv_uniq(deps); /* Sometimes a unit might have multiple deps on the other unit,
764 * but we still want to show it just once. */
765 *ret = TAKE_PTR(deps);
766
767 return 0;
768}
769
770const char* unit_type_suffix(const char *unit) {
771 const char *dot;
772
773 dot = strrchr(unit, '.');
774 if (!dot)
775 return "";
776
777 return dot + 1;
778}
779
780bool output_show_unit(const UnitInfo *u, char **patterns) {
781 assert(u);
782
783 if (!strv_fnmatch_or_empty(patterns, u->id, FNM_NOESCAPE))
784 return false;
785
786 if (arg_types && !strv_find(arg_types, unit_type_suffix(u->id)))
787 return false;
788
789 if (arg_all)
790 return true;
791
792 /* Note that '--all' is not purely a state filter, but also a filter that hides units that "follow"
793 * other units (which is used for device units that appear under different names). */
794 if (!isempty(u->following))
795 return false;
796
797 if (!strv_isempty(arg_states))
798 return true;
799
800 /* By default show all units except the ones in inactive state and with no pending job */
801 if (u->job_id > 0)
802 return true;
803
804 if (streq(u->active_state, "inactive"))
805 return false;
806
807 return true;
808}
809
810bool install_client_side(void) {
811 /* Decides when to execute enable/disable/... operations client-side rather than server-side. */
812
813 if (running_in_chroot_or_offline())
814 return true;
815
816 if (sd_booted() <= 0)
817 return true;
818
819 if (!isempty(arg_root))
820 return true;
821
822 if (arg_scope == UNIT_FILE_GLOBAL)
823 return true;
824
825 /* Unsupported environment variable, mostly for debugging purposes */
826 if (getenv_bool("SYSTEMCTL_INSTALL_CLIENT_SIDE") > 0)
827 return true;
828
829 return false;
830}
831
832int output_table(Table *table) {
833 int r;
834
835 assert(table);
836
837 if (OUTPUT_MODE_IS_JSON(arg_output))
838 r = table_print_json(table, NULL, output_mode_to_json_format_flags(arg_output) | JSON_FORMAT_COLOR_AUTO);
839 else
840 r = table_print(table, NULL);
841 if (r < 0)
842 return table_log_print_error(r);
843
844 return 0;
845}
846
847bool show_preset_for_state(UnitFileState state) {
848 /* Don't show preset state in those unit file states, it'll only confuse users. */
849 return !IN_SET(state,
850 UNIT_FILE_ALIAS,
851 UNIT_FILE_STATIC,
852 UNIT_FILE_GENERATED,
853 UNIT_FILE_TRANSIENT);
854}
855
856UnitFileFlags unit_file_flags_from_args(void) {
857 return (arg_runtime ? UNIT_FILE_RUNTIME : 0) |
858 (arg_force ? UNIT_FILE_FORCE : 0);
859}
860
861int mangle_names(const char *operation, char **original_names, char ***ret_mangled_names) {
862 _cleanup_strv_free_ char **l = NULL;
863 char **i, **name;
864 int r;
865
866 assert(ret_mangled_names);
867
868 l = i = new(char*, strv_length(original_names) + 1);
869 if (!l)
870 return log_oom();
871
872 STRV_FOREACH(name, original_names) {
873
874 /* When enabling units qualified path names are OK, too, hence allow them explicitly. */
875
876 if (is_path(*name)) {
877 *i = strdup(*name);
878 if (!*i)
879 return log_oom();
880 } else {
881 r = unit_name_mangle_with_suffix(*name, operation,
882 arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
883 ".service", i);
884 if (r < 0) {
885 *i = NULL;
886 return log_error_errno(r, "Failed to mangle unit name: %m");
887 }
888 }
889
890 i++;
891 }
892
893 *i = NULL;
894 *ret_mangled_names = TAKE_PTR(l);
895
896 return 0;
897}
898
899int halt_now(enum action a) {
900 /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need
901 * to be synced explicitly in advance. */
902 if (!arg_no_sync && !arg_dry_run)
903 (void) sync();
904
905 /* Make sure C-A-D is handled by the kernel from this point on... */
906 if (!arg_dry_run)
907 (void) reboot(RB_ENABLE_CAD);
908
909 switch (a) {
910
911 case ACTION_HALT:
912 if (!arg_quiet)
913 log_info("Halting.");
914 if (arg_dry_run)
915 return 0;
916 (void) reboot(RB_HALT_SYSTEM);
917 return -errno;
918
919 case ACTION_POWEROFF:
920 if (!arg_quiet)
921 log_info("Powering off.");
922 if (arg_dry_run)
923 return 0;
924 (void) reboot(RB_POWER_OFF);
925 return -errno;
926
927 case ACTION_KEXEC:
928 case ACTION_REBOOT:
929 return reboot_with_parameter(REBOOT_FALLBACK |
930 (arg_quiet ? 0 : REBOOT_LOG) |
931 (arg_dry_run ? REBOOT_DRY_RUN : 0));
932
933 default:
934 assert_not_reached("Unknown action.");
935 }
936}