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