1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include "bus-error.h"
4 #include "bus-locator.h"
5 #include "bus-wait-for-units.h"
6 #include "systemctl-clean-or-freeze.h"
7 #include "systemctl-util.h"
8 #include "systemctl.h"
9 
verb_clean_or_freeze(int argc,char * argv[],void * userdata)10 int verb_clean_or_freeze(int argc, char *argv[], void *userdata) {
11         _cleanup_(bus_wait_for_units_freep) BusWaitForUnits *w = NULL;
12         _cleanup_strv_free_ char **names = NULL;
13         int r, ret = EXIT_SUCCESS;
14         const char *method;
15         sd_bus *bus;
16 
17         r = acquire_bus(BUS_FULL, &bus);
18         if (r < 0)
19                 return r;
20 
21         polkit_agent_open_maybe();
22 
23         if (!arg_clean_what) {
24                 arg_clean_what = strv_new("cache", "runtime");
25                 if (!arg_clean_what)
26                         return log_oom();
27         }
28 
29         r = expand_unit_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
30         if (r < 0)
31                 return log_error_errno(r, "Failed to expand names: %m");
32 
33         if (!arg_no_block) {
34                 r = bus_wait_for_units_new(bus, &w);
35                 if (r < 0)
36                         return log_error_errno(r, "Failed to allocate unit waiter: %m");
37         }
38 
39         if (streq(argv[0], "clean"))
40                 method = "CleanUnit";
41         else if (streq(argv[0], "freeze"))
42                 method = "FreezeUnit";
43         else if (streq(argv[0], "thaw"))
44                 method = "ThawUnit";
45         else
46                 assert_not_reached();
47 
48         STRV_FOREACH(name, names) {
49                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
50                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
51 
52                 if (w) {
53                         /* If we shall wait for the cleaning to complete, let's add a ref on the unit first */
54                         r = bus_call_method(bus, bus_systemd_mgr, "RefUnit", &error, NULL, "s", *name);
55                         if (r < 0) {
56                                 log_error_errno(r, "Failed to add reference to unit %s: %s", *name, bus_error_message(&error, r));
57                                 if (ret == EXIT_SUCCESS)
58                                         ret = r;
59                                 continue;
60                         }
61                 }
62 
63                 r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, method);
64                 if (r < 0)
65                         return bus_log_create_error(r);
66 
67                 r = sd_bus_message_append(m, "s", *name);
68                 if (r < 0)
69                         return bus_log_create_error(r);
70 
71                 if (streq(method, "CleanUnit")) {
72                         r = sd_bus_message_append_strv(m, arg_clean_what);
73                         if (r < 0)
74                                 return bus_log_create_error(r);
75                 }
76 
77                 r = sd_bus_call(bus, m, 0, &error, NULL);
78                 if (r < 0) {
79                         log_error_errno(r, "Failed to %s unit %s: %s", argv[0], *name, bus_error_message(&error, r));
80                         if (ret == EXIT_SUCCESS) {
81                                 ret = r;
82                                 continue;
83                         }
84                 }
85 
86                 if (w) {
87                         r = bus_wait_for_units_add_unit(w, *name, BUS_WAIT_REFFED|BUS_WAIT_FOR_MAINTENANCE_END, NULL, NULL);
88                         if (r < 0)
89                                 return log_error_errno(r, "Failed to watch unit %s: %m", *name);
90                 }
91         }
92 
93         r = bus_wait_for_units_run(w);
94         if (r < 0)
95                 return log_error_errno(r, "Failed to wait for units: %m");
96         if (r == BUS_WAIT_FAILURE)
97                 ret = EXIT_FAILURE;
98 
99         return ret;
100 }
101