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