Line data Source code
1 : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2 :
3 : /***
4 : This file is part of systemd.
5 :
6 : Copyright 2013 Lennart Poettering
7 :
8 : systemd is free software; you can redistribute it and/or modify it
9 : under the terms of the GNU Lesser General Public License as published by
10 : the Free Software Foundation; either version 2.1 of the License, or
11 : (at your option) any later version.
12 :
13 : systemd is distributed in the hope that it will be useful, but
14 : WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : Lesser General Public License for more details.
17 :
18 : You should have received a copy of the GNU Lesser General Public License
19 : along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 : ***/
21 :
22 : #include "selinux-access.h"
23 : #include "unit.h"
24 : #include "scope.h"
25 : #include "dbus.h"
26 : #include "bus-util.h"
27 : #include "bus-internal.h"
28 : #include "bus-common-errors.h"
29 : #include "dbus-unit.h"
30 : #include "dbus-cgroup.h"
31 : #include "dbus-kill.h"
32 : #include "dbus-scope.h"
33 :
34 0 : static int bus_scope_abandon(sd_bus_message *message, void *userdata, sd_bus_error *error) {
35 0 : Scope *s = userdata;
36 : int r;
37 :
38 0 : assert(message);
39 0 : assert(s);
40 :
41 0 : r = mac_selinux_unit_access_check(UNIT(s), message, "stop", error);
42 0 : if (r < 0)
43 0 : return r;
44 :
45 0 : r = bus_verify_manage_units_async(UNIT(s)->manager, message, error);
46 0 : if (r < 0)
47 0 : return r;
48 0 : if (r == 0)
49 0 : return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
50 :
51 0 : r = scope_abandon(s);
52 0 : if (r == -ESTALE)
53 0 : return sd_bus_error_setf(error, BUS_ERROR_SCOPE_NOT_RUNNING, "Scope %s is not running, cannot abandon.", UNIT(s)->id);
54 0 : if (r < 0)
55 0 : return r;
56 :
57 0 : return sd_bus_reply_method_return(message, NULL);
58 : }
59 :
60 0 : static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, scope_result, ScopeResult);
61 :
62 : const sd_bus_vtable bus_scope_vtable[] = {
63 : SD_BUS_VTABLE_START(0),
64 : SD_BUS_PROPERTY("Controller", "s", NULL, offsetof(Scope, controller), SD_BUS_VTABLE_PROPERTY_CONST),
65 : SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Scope, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
66 : SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Scope, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
67 : SD_BUS_SIGNAL("RequestStop", NULL, 0),
68 : SD_BUS_METHOD("Abandon", NULL, NULL, bus_scope_abandon, SD_BUS_VTABLE_UNPRIVILEGED),
69 : SD_BUS_VTABLE_END
70 : };
71 :
72 0 : static int bus_scope_set_transient_property(
73 : Scope *s,
74 : const char *name,
75 : sd_bus_message *message,
76 : UnitSetPropertiesMode mode,
77 : sd_bus_error *error) {
78 :
79 : int r;
80 :
81 0 : assert(s);
82 0 : assert(name);
83 0 : assert(message);
84 :
85 0 : if (streq(name, "PIDs")) {
86 0 : unsigned n = 0;
87 : uint32_t pid;
88 :
89 0 : r = sd_bus_message_enter_container(message, 'a', "u");
90 0 : if (r < 0)
91 0 : return r;
92 :
93 0 : while ((r = sd_bus_message_read(message, "u", &pid)) > 0) {
94 :
95 0 : if (pid <= 1)
96 0 : return -EINVAL;
97 :
98 0 : if (mode != UNIT_CHECK) {
99 0 : r = unit_watch_pid(UNIT(s), pid);
100 0 : if (r < 0 && r != -EEXIST)
101 0 : return r;
102 : }
103 :
104 0 : n++;
105 : }
106 0 : if (r < 0)
107 0 : return r;
108 :
109 0 : r = sd_bus_message_exit_container(message);
110 0 : if (r < 0)
111 0 : return r;
112 :
113 0 : if (n <= 0)
114 0 : return -EINVAL;
115 :
116 0 : return 1;
117 :
118 0 : } else if (streq(name, "Controller")) {
119 : const char *controller;
120 : char *c;
121 :
122 0 : r = sd_bus_message_read(message, "s", &controller);
123 0 : if (r < 0)
124 0 : return r;
125 :
126 0 : if (!isempty(controller) && !service_name_is_valid(controller))
127 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Controller '%s' is not a valid bus name.", controller);
128 :
129 0 : if (mode != UNIT_CHECK) {
130 0 : if (isempty(controller))
131 0 : c = NULL;
132 : else {
133 0 : c = strdup(controller);
134 0 : if (!c)
135 0 : return -ENOMEM;
136 : }
137 :
138 0 : free(s->controller);
139 0 : s->controller = c;
140 : }
141 :
142 0 : return 1;
143 :
144 0 : } else if (streq(name, "TimeoutStopUSec")) {
145 :
146 0 : if (mode != UNIT_CHECK) {
147 0 : r = sd_bus_message_read(message, "t", &s->timeout_stop_usec);
148 0 : if (r < 0)
149 0 : return r;
150 :
151 0 : unit_write_drop_in_format(UNIT(s), mode, name, "[Scope]\nTimeoutStopSec="USEC_FMT"us\n", s->timeout_stop_usec);
152 : } else {
153 0 : r = sd_bus_message_skip(message, "t");
154 0 : if (r < 0)
155 0 : return r;
156 : }
157 :
158 0 : return 1;
159 : }
160 :
161 0 : return 0;
162 : }
163 :
164 0 : int bus_scope_set_property(
165 : Unit *u,
166 : const char *name,
167 : sd_bus_message *message,
168 : UnitSetPropertiesMode mode,
169 : sd_bus_error *error) {
170 :
171 0 : Scope *s = SCOPE(u);
172 : int r;
173 :
174 0 : assert(s);
175 0 : assert(name);
176 0 : assert(message);
177 :
178 0 : r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
179 0 : if (r != 0)
180 0 : return r;
181 :
182 0 : if (u->load_state == UNIT_STUB) {
183 : /* While we are created we still accept PIDs */
184 :
185 0 : r = bus_scope_set_transient_property(s, name, message, mode, error);
186 0 : if (r != 0)
187 0 : return r;
188 :
189 0 : r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, mode, error);
190 0 : if (r != 0)
191 0 : return r;
192 : }
193 :
194 0 : return 0;
195 : }
196 :
197 0 : int bus_scope_commit_properties(Unit *u) {
198 0 : assert(u);
199 :
200 0 : unit_update_cgroup_members_masks(u);
201 0 : unit_realize_cgroup(u);
202 :
203 0 : return 0;
204 : }
205 :
206 0 : int bus_scope_send_request_stop(Scope *s) {
207 0 : _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
208 0 : _cleanup_free_ char *p = NULL;
209 : int r;
210 :
211 0 : assert(s);
212 :
213 0 : if (!s->controller)
214 0 : return 0;
215 :
216 0 : p = unit_dbus_path(UNIT(s));
217 0 : if (!p)
218 0 : return -ENOMEM;
219 :
220 0 : r = sd_bus_message_new_signal(
221 0 : UNIT(s)->manager->api_bus,
222 : &m,
223 : p,
224 : "org.freedesktop.systemd1.Scope",
225 : "RequestStop");
226 0 : if (r < 0)
227 0 : return r;
228 :
229 0 : return sd_bus_send_to(UNIT(s)->manager->api_bus, m, /* s->controller */ NULL, NULL);
230 : }
|