]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl-util.c
basic/include: replace _Static_assert() with static_assert()
[thirdparty/systemd.git] / src / systemctl / systemctl-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
daf71ef6 2
6553db60 3#include <fnmatch.h>
daf71ef6
LP
4#include <sys/reboot.h>
5#include <unistd.h>
6
7#include "sd-bus.h"
8#include "sd-daemon.h"
9
a8c3ed5f 10#include "ask-password-agent.h"
daf71ef6
LP
11#include "bus-common-errors.h"
12#include "bus-locator.h"
13#include "bus-map-properties.h"
14#include "bus-unit-util.h"
1e35e81b 15#include "bus-util.h"
f461a28d 16#include "chase.h"
daf71ef6
LP
17#include "dropin.h"
18#include "env-util.h"
19#include "exit-status.h"
0bbd8e18
DDM
20#include "format-table.h"
21#include "format-util.h"
daf71ef6 22#include "glob-util.h"
0bbd8e18
DDM
23#include "install.h"
24#include "output-mode.h"
25#include "path-lookup.h"
daf71ef6 26#include "path-util.h"
716a4cdb 27#include "pidref.h"
1b919ca4 28#include "polkit-agent.h"
716a4cdb 29#include "process-util.h"
daf71ef6 30#include "reboot-util.h"
0bbd8e18 31#include "runtime-scope.h"
daf71ef6 32#include "set.h"
0bbd8e18
DDM
33#include "string-util.h"
34#include "strv.h"
daf71ef6 35#include "systemctl.h"
1cf40697 36#include "systemctl-util.h"
0bbd8e18
DDM
37#include "unit-file.h"
38#include "unit-name.h"
daf71ef6
LP
39#include "verbs.h"
40
41static sd_bus *buses[_BUS_FOCUS_MAX] = {};
42
c577fe65 43int acquire_bus_full(BusFocus focus, bool graceful, sd_bus **ret) {
daf71ef6
LP
44 int r;
45
46 assert(focus < _BUS_FOCUS_MAX);
47 assert(ret);
48
d77d42ed
YW
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
daf71ef6 52 /* We only go directly to the manager, if we are using a local transport */
56cb74c3 53 if (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_CAPSULE))
daf71ef6
LP
54 focus = BUS_FULL;
55
56 if (getenv_bool("SYSTEMCTL_FORCE_BUS") > 0)
57 focus = BUS_FULL;
58
59 if (!buses[focus]) {
daf71ef6 60 if (focus == BUS_MANAGER)
4870133b 61 r = bus_connect_transport_systemd(arg_transport, arg_host, arg_runtime_scope, &buses[focus]);
daf71ef6 62 else
4870133b 63 r = bus_connect_transport(arg_transport, arg_host, arg_runtime_scope, &buses[focus]);
daf71ef6 64 if (r < 0)
c577fe65
YW
65 return bus_log_connect_full(graceful && focus == BUS_FULL && r == -ECONNREFUSED ? LOG_DEBUG : LOG_ERR,
66 r, arg_transport, arg_runtime_scope);
daf71ef6
LP
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
75void release_busses(void) {
848cdaa6
MY
76 FOREACH_ARRAY(w, buses, _BUS_FOCUS_MAX)
77 *w = sd_bus_flush_close_unref(*w);
daf71ef6
LP
78}
79
80void 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
4870133b 86 if (arg_runtime_scope != RUNTIME_SCOPE_SYSTEM)
daf71ef6
LP
87 return;
88
89 ask_password_agent_open_if_enabled(arg_transport, arg_ask_password);
90}
91
92void polkit_agent_open_maybe(void) {
93 /* Open the polkit agent as a child process if necessary */
94
4870133b 95 if (arg_runtime_scope != RUNTIME_SCOPE_SYSTEM)
daf71ef6
LP
96 return;
97
f3cf6167 98 (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
daf71ef6
LP
99}
100
101int 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
129int 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
37299769 135 assert(bus);
daf71ef6
LP
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)
7211c853 156 return log_error_errno(state, "Invalid unit state '%s' for: %s", buf, unit);
daf71ef6
LP
157
158 *ret_active_state = state;
159 return 0;
160}
161
37299769
MY
162int 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
daf71ef6
LP
190int 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;
daf71ef6
LP
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
319a4f4b 260 if (!GREEDY_REALLOC(*unit_infos, c+1))
daf71ef6
LP
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
f27d595d
MY
274int expand_unit_names(
275 sd_bus *bus,
276 char * const *names,
277 const char *suffix,
278 char ***ret,
279 bool *ret_expanded) {
280
daf71ef6 281 _cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
deaf4b86 282 int r;
daf71ef6
LP
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;
daf71ef6
LP
308
309 r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
310 if (r < 0)
311 return r;
312
f27d595d
MY
313 FOREACH_ARRAY(info, unit_infos, r)
314 if (strv_extend(&mangled, info->id) < 0)
daf71ef6 315 return log_oom();
daf71ef6
LP
316 }
317
f27d595d 318 *ret = TAKE_PTR(mangled);
daf71ef6
LP
319 if (ret_expanded)
320 *ret_expanded = expanded;
321
daf71ef6
LP
322 return 0;
323}
324
002db03f 325int get_active_triggering_units(sd_bus *bus, const char *unit, bool ignore_masked, char ***ret) {
daf71ef6 326 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
002db03f
MY
327 _cleanup_strv_free_ char **triggered_by = NULL, **active = NULL;
328 _cleanup_free_ char *name = NULL, *dbus_path = NULL;
daf71ef6
LP
329 int r;
330
002db03f
MY
331 assert(bus);
332 assert(unit);
333 assert(ret);
daf71ef6 334
002db03f 335 r = unit_name_mangle(unit, 0, &name);
daf71ef6
LP
336 if (r < 0)
337 return r;
338
09d6038d
MY
339 if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE))
340 goto skip;
341
002db03f
MY
342 if (ignore_masked) {
343 r = unit_is_masked(bus, name);
344 if (r < 0)
345 return r;
09d6038d
MY
346 if (r > 0)
347 goto skip;
002db03f 348 }
daf71ef6 349
002db03f 350 dbus_path = unit_dbus_path_from_name(name);
daf71ef6 351 if (!dbus_path)
002db03f 352 return -ENOMEM;
daf71ef6
LP
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)
002db03f
MY
363 return log_debug_errno(r, "Failed to get TriggeredBy property of unit '%s': %s",
364 name, bus_error_message(&error, r));
daf71ef6
LP
365
366 STRV_FOREACH(i, triggered_by) {
c4da8e90
ZJS
367 UnitActiveState active_state;
368
daf71ef6
LP
369 r = get_state_one_unit(bus, *i, &active_state);
370 if (r < 0)
371 return r;
372
5162829e 373 if (!IN_SET(active_state, UNIT_ACTIVE, UNIT_RELOADING, UNIT_REFRESHING))
daf71ef6
LP
374 continue;
375
002db03f
MY
376 r = strv_extend(&active, *i);
377 if (r < 0)
378 return r;
daf71ef6
LP
379 }
380
002db03f 381 *ret = TAKE_PTR(active);
daf71ef6 382 return 0;
09d6038d
MY
383
384skip:
385 *ret = NULL;
386 return 0;
daf71ef6
LP
387}
388
002db03f
MY
389void 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) {
701bd9d0
MY
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);
002db03f
MY
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
daf71ef6
LP
417int 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
450void warn_unit_file_changed(const char *unit) {
451 assert(unit);
452
37257662
MY
453 if (arg_no_warn)
454 return;
455
55721877 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.",
daf71ef6 457 unit,
4870133b 458 arg_runtime_scope == RUNTIME_SCOPE_SYSTEM ? "" : " --user");
daf71ef6
LP
459}
460
461int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **ret_unit_path) {
daf71ef6
LP
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
f461a28d 473 r = chase(path, arg_root, 0, &lpath, NULL);
daf71ef6
LP
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
493int unit_find_paths(
494 sd_bus *bus,
495 const char *unit_name,
496 LookupPaths *lp,
497 bool force_client_side,
daf71ef6 498 Hashmap **cached_id_map,
08ba85c7 499 Hashmap **cached_name_map,
daf71ef6
LP
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:
1842c1b2 510 *
daf71ef6 511 * - the path to the unit in *ret_frament_path, if it exists on disk,
1842c1b2 512 *
daf71ef6
LP
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
1842c1b2
LP
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.
daf71ef6
LP
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"))
1842c1b2 548 return -ERFKILL; /* special case: no logging */
daf71ef6
LP
549 if (streq(load_state, "not-found")) {
550 r = 0;
d5427dd2 551 goto finish;
daf71ef6
LP
552 }
553 if (!STR_IN_SET(load_state, "loaded", "bad-setting"))
1842c1b2 554 return -EKEYREJECTED; /* special case: no logging */
daf71ef6
LP
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 {
daf71ef6
LP
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
5793a39d
YW
586 const char *_path;
587 _cleanup_set_free_ Set *names = NULL;
daf71ef6
LP
588 r = unit_file_find_fragment(*cached_id_map, *cached_name_map, unit_name, &_path, &names);
589 if (r < 0)
b420e6f0 590 return log_error_errno(r, "Failed to find fragment for '%s': %m", unit_name);
daf71ef6
LP
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
d5427dd2 607 finish:
daf71ef6
LP
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
daf71ef6
LP
624 if (r == 0 && !arg_force)
625 log_error("No files found for %s.", unit_name);
626
627 return r;
628}
629
630static 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
6ea32f61 674int unit_is_masked(sd_bus *bus, const char *unit) {
daf71ef6
LP
675 _cleanup_free_ char *load_state = NULL;
676 int r;
677
6ea32f61
MY
678 assert(bus);
679 assert(unit);
daf71ef6 680
6ea32f61
MY
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;
daf71ef6 685
6ea32f61 686 r = bus_call_method(bus, bus_systemd_mgr, "GetUnitFileState", &error, &reply, "s", unit);
daf71ef6 687 if (r < 0)
6ea32f61
MY
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");
daf71ef6
LP
696 }
697
6ea32f61 698 r = unit_load_state(bus, unit, &load_state);
daf71ef6
LP
699 if (r < 0)
700 return r;
701
702 return streq(load_state, "masked");
703}
704
705int 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
daf71ef6
LP
742int append_unit_dependencies(sd_bus *bus, char **names, char ***ret) {
743 _cleanup_strv_free_ char **with_deps = NULL;
daf71ef6
LP
744
745 assert(bus);
746 assert(ret);
747
748 STRV_FOREACH(name, names) {
a2c8652a 749 char **deps;
daf71ef6
LP
750
751 if (strv_extend(&with_deps, *name) < 0)
752 return log_oom();
753
754 (void) unit_get_dependencies(bus, *name, &deps);
755
a2c8652a 756 if (strv_extend_strv_consume(&with_deps, deps, /* filter_duplicates = */ true) < 0)
daf71ef6
LP
757 return log_oom();
758 }
759
760 *ret = TAKE_PTR(with_deps);
761
762 return 0;
763}
764
765int 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
d9219935 779 return strv_free_and_replace(*list, list_with_deps);
daf71ef6
LP
780}
781
782int unit_get_dependencies(sd_bus *bus, const char *name, char ***ret) {
783 _cleanup_strv_free_ char **deps = NULL;
784
cbc2593e 785 static const struct bus_properties_map map[_DEPENDENCY_MAX][7] = {
daf71ef6
LP
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 },
cbc2593e 792 { "Upholds", "as", NULL, 0 },
daf71ef6
LP
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 },
cbc2593e 801 { "UpheldBy", "as", NULL, 0 },
daf71ef6
LP
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
844const 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
854bool 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
d29cc4d6 860 if (arg_types && !strv_contains(arg_types, unit_type_suffix(u->id)))
daf71ef6
LP
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
884bool 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
4870133b 896 if (arg_runtime_scope == RUNTIME_SCOPE_GLOBAL)
daf71ef6
LP
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
906int output_table(Table *table) {
907 int r;
908
909 assert(table);
910
911 if (OUTPUT_MODE_IS_JSON(arg_output))
309a747f 912 r = table_print_json(table, NULL, output_mode_to_json_format_flags(arg_output) | SD_JSON_FORMAT_COLOR_AUTO);
daf71ef6
LP
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
921bool 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
930UnitFileFlags unit_file_flags_from_args(void) {
931 return (arg_runtime ? UNIT_FILE_RUNTIME : 0) |
932 (arg_force ? UNIT_FILE_FORCE : 0);
933}
934
f27d595d 935int mangle_names(const char *operation, char * const *original_names, char ***ret) {
daf71ef6 936 _cleanup_strv_free_ char **l = NULL;
daf71ef6
LP
937 int r;
938
f27d595d
MY
939 assert(operation);
940 assert(ret);
daf71ef6
LP
941
942 STRV_FOREACH(name, original_names) {
f27d595d 943 char *mangled;
daf71ef6 944
23484e12 945 if (is_path(*name))
f27d595d
MY
946 /* When enabling units qualified path names are OK, too, hence allow them explicitly. */
947 r = path_make_absolute_cwd(*name, &mangled);
23484e12 948 else
daf71ef6
LP
949 r = unit_name_mangle_with_suffix(*name, operation,
950 arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
f27d595d
MY
951 ".service", &mangled);
952 if (r < 0)
23484e12 953 return log_error_errno(r, "Failed to mangle unit name or path '%s': %m", *name);
daf71ef6 954
f27d595d
MY
955 if (strv_consume(&l, mangled) < 0)
956 return log_oom();
daf71ef6
LP
957 }
958
f27d595d 959 *ret = TAKE_PTR(l);
daf71ef6
LP
960
961 return 0;
962}
963
964int 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)
b7106af4 968 sync();
daf71ef6
LP
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:
04499a70 999 assert_not_reached();
daf71ef6
LP
1000 }
1001}
716a4cdb
MY
1002
1003int 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
1051static 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
1102int 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}