]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/dbus-scope.c
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
[thirdparty/systemd.git] / src / core / dbus-scope.c
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 "alloc-util.h"
23 #include "bus-common-errors.h"
24 #include "bus-internal.h"
25 #include "bus-util.h"
26 #include "dbus-cgroup.h"
27 #include "dbus-kill.h"
28 #include "dbus-scope.h"
29 #include "dbus-unit.h"
30 #include "dbus.h"
31 #include "scope.h"
32 #include "selinux-access.h"
33 #include "unit.h"
34
35 static int bus_scope_abandon(sd_bus_message *message, void *userdata, sd_bus_error *error) {
36 Scope *s = userdata;
37 int r;
38
39 assert(message);
40 assert(s);
41
42 r = mac_selinux_unit_access_check(UNIT(s), message, "stop", error);
43 if (r < 0)
44 return r;
45
46 r = bus_verify_manage_units_async(UNIT(s)->manager, message, error);
47 if (r < 0)
48 return r;
49 if (r == 0)
50 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
51
52 r = scope_abandon(s);
53 if (r == -ESTALE)
54 return sd_bus_error_setf(error, BUS_ERROR_SCOPE_NOT_RUNNING, "Scope %s is not running, cannot abandon.", UNIT(s)->id);
55 if (r < 0)
56 return r;
57
58 return sd_bus_reply_method_return(message, NULL);
59 }
60
61 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, scope_result, ScopeResult);
62
63 const sd_bus_vtable bus_scope_vtable[] = {
64 SD_BUS_VTABLE_START(0),
65 SD_BUS_PROPERTY("Controller", "s", NULL, offsetof(Scope, controller), SD_BUS_VTABLE_PROPERTY_CONST),
66 SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Scope, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
67 SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Scope, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
68 SD_BUS_SIGNAL("RequestStop", NULL, 0),
69 SD_BUS_METHOD("Abandon", NULL, NULL, bus_scope_abandon, SD_BUS_VTABLE_UNPRIVILEGED),
70 SD_BUS_VTABLE_END
71 };
72
73 static int bus_scope_set_transient_property(
74 Scope *s,
75 const char *name,
76 sd_bus_message *message,
77 UnitSetPropertiesMode mode,
78 sd_bus_error *error) {
79
80 int r;
81
82 assert(s);
83 assert(name);
84 assert(message);
85
86 if (streq(name, "PIDs")) {
87 unsigned n = 0;
88 uint32_t pid;
89
90 r = sd_bus_message_enter_container(message, 'a', "u");
91 if (r < 0)
92 return r;
93
94 while ((r = sd_bus_message_read(message, "u", &pid)) > 0) {
95
96 if (pid <= 1)
97 return -EINVAL;
98
99 if (mode != UNIT_CHECK) {
100 r = unit_watch_pid(UNIT(s), pid);
101 if (r < 0 && r != -EEXIST)
102 return r;
103 }
104
105 n++;
106 }
107 if (r < 0)
108 return r;
109
110 r = sd_bus_message_exit_container(message);
111 if (r < 0)
112 return r;
113
114 if (n <= 0)
115 return -EINVAL;
116
117 return 1;
118
119 } else if (streq(name, "Controller")) {
120 const char *controller;
121 char *c;
122
123 r = sd_bus_message_read(message, "s", &controller);
124 if (r < 0)
125 return r;
126
127 if (!isempty(controller) && !service_name_is_valid(controller))
128 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Controller '%s' is not a valid bus name.", controller);
129
130 if (mode != UNIT_CHECK) {
131 if (isempty(controller))
132 c = NULL;
133 else {
134 c = strdup(controller);
135 if (!c)
136 return -ENOMEM;
137 }
138
139 free(s->controller);
140 s->controller = c;
141 }
142
143 return 1;
144
145 } else if (streq(name, "TimeoutStopUSec")) {
146
147 if (mode != UNIT_CHECK) {
148 r = sd_bus_message_read(message, "t", &s->timeout_stop_usec);
149 if (r < 0)
150 return r;
151
152 unit_write_drop_in_format(UNIT(s), mode, name, "[Scope]\nTimeoutStopSec="USEC_FMT"us\n", s->timeout_stop_usec);
153 } else {
154 r = sd_bus_message_skip(message, "t");
155 if (r < 0)
156 return r;
157 }
158
159 return 1;
160 }
161
162 return 0;
163 }
164
165 int bus_scope_set_property(
166 Unit *u,
167 const char *name,
168 sd_bus_message *message,
169 UnitSetPropertiesMode mode,
170 sd_bus_error *error) {
171
172 Scope *s = SCOPE(u);
173 int r;
174
175 assert(s);
176 assert(name);
177 assert(message);
178
179 r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
180 if (r != 0)
181 return r;
182
183 if (u->load_state == UNIT_STUB) {
184 /* While we are created we still accept PIDs */
185
186 r = bus_scope_set_transient_property(s, name, message, mode, error);
187 if (r != 0)
188 return r;
189
190 r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, mode, error);
191 if (r != 0)
192 return r;
193 }
194
195 return 0;
196 }
197
198 int bus_scope_commit_properties(Unit *u) {
199 assert(u);
200
201 unit_update_cgroup_members_masks(u);
202 unit_realize_cgroup(u);
203
204 return 0;
205 }
206
207 int bus_scope_send_request_stop(Scope *s) {
208 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
209 _cleanup_free_ char *p = NULL;
210 int r;
211
212 assert(s);
213
214 if (!s->controller)
215 return 0;
216
217 p = unit_dbus_path(UNIT(s));
218 if (!p)
219 return -ENOMEM;
220
221 r = sd_bus_message_new_signal(
222 UNIT(s)->manager->api_bus,
223 &m,
224 p,
225 "org.freedesktop.systemd1.Scope",
226 "RequestStop");
227 if (r < 0)
228 return r;
229
230 return sd_bus_send_to(UNIT(s)->manager->api_bus, m, /* s->controller */ NULL, NULL);
231 }