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