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