]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-bus/bus-convenience.c
7c9824258be5e2bf503464beaddc4379e44427f5
[thirdparty/systemd.git] / src / libsystemd-bus / bus-convenience.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 "bus-internal.h"
23 #include "bus-message.h"
24 #include "bus-signature.h"
25 #include "bus-util.h"
26 #include "bus-type.h"
27
28 int sd_bus_emit_signal(
29 sd_bus *bus,
30 const char *path,
31 const char *interface,
32 const char *member,
33 const char *types, ...) {
34
35 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
36 int r;
37
38 assert_return(bus, -EINVAL);
39 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
40 assert_return(!bus_pid_changed(bus), -ECHILD);
41
42 r = sd_bus_message_new_signal(bus, path, interface, member, &m);
43 if (r < 0)
44 return r;
45
46 if (!isempty(types)) {
47 va_list ap;
48
49 va_start(ap, types);
50 r = bus_message_append_ap(m, types, ap);
51 va_end(ap);
52 if (r < 0)
53 return r;
54 }
55
56 return sd_bus_send(bus, m, NULL);
57 }
58
59 int sd_bus_call_method(
60 sd_bus *bus,
61 const char *destination,
62 const char *path,
63 const char *interface,
64 const char *member,
65 sd_bus_error *error,
66 sd_bus_message **reply,
67 const char *types, ...) {
68
69 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
70 int r;
71
72 assert_return(bus, -EINVAL);
73 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
74 assert_return(!bus_pid_changed(bus), -ECHILD);
75
76 r = sd_bus_message_new_method_call(bus, destination, path, interface, member, &m);
77 if (r < 0)
78 return r;
79
80 if (!isempty(types)) {
81 va_list ap;
82
83 va_start(ap, types);
84 r = bus_message_append_ap(m, types, ap);
85 va_end(ap);
86 if (r < 0)
87 return r;
88 }
89
90 return sd_bus_send_with_reply_and_block(bus, m, 0, error, reply);
91 }
92
93 int sd_bus_reply_method_return(
94 sd_bus *bus,
95 sd_bus_message *call,
96 const char *types, ...) {
97
98 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
99 int r;
100
101 assert_return(bus, -EINVAL);
102 assert_return(call, -EINVAL);
103 assert_return(call->sealed, -EPERM);
104 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
105 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
106 assert_return(!bus_pid_changed(bus), -ECHILD);
107
108 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
109 return 0;
110
111 r = sd_bus_message_new_method_return(bus, call, &m);
112 if (r < 0)
113 return r;
114
115 if (!isempty(types)) {
116 va_list ap;
117
118 va_start(ap, types);
119 r = bus_message_append_ap(m, types, ap);
120 va_end(ap);
121 if (r < 0)
122 return r;
123 }
124
125 return sd_bus_send(bus, m, NULL);
126 }
127
128 int sd_bus_reply_method_error(
129 sd_bus *bus,
130 sd_bus_message *call,
131 const sd_bus_error *e) {
132
133 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
134 int r;
135
136 assert_return(bus, -EINVAL);
137 assert_return(call, -EINVAL);
138 assert_return(call->sealed, -EPERM);
139 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
140 assert_return(sd_bus_error_is_set(e), -EINVAL);
141 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
142 assert_return(!bus_pid_changed(bus), -ECHILD);
143
144 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
145 return 0;
146
147 r = sd_bus_message_new_method_error(bus, call, e, &m);
148 if (r < 0)
149 return r;
150
151 return sd_bus_send(bus, m, NULL);
152 }
153
154 int sd_bus_reply_method_errorf(
155 sd_bus *bus,
156 sd_bus_message *call,
157 const char *name,
158 const char *format,
159 ...) {
160
161 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
162 va_list ap;
163 int r;
164
165 assert_return(bus, -EINVAL);
166 assert_return(call, -EINVAL);
167 assert_return(call->sealed, -EPERM);
168 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
169 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
170 assert_return(!bus_pid_changed(bus), -ECHILD);
171
172 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
173 return 0;
174
175 va_start(ap, format);
176 r = bus_error_setfv(&error, name, format, ap);
177 va_end(ap);
178
179 if (r < 0)
180 return r;
181
182 return sd_bus_reply_method_error(bus, call, &error);
183 }
184
185 int sd_bus_reply_method_errno(
186 sd_bus *bus,
187 sd_bus_message *call,
188 int error,
189 const sd_bus_error *p) {
190
191 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
192
193 assert_return(bus, -EINVAL);
194 assert_return(call, -EINVAL);
195 assert_return(call->sealed, -EPERM);
196 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
197 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
198 assert_return(!bus_pid_changed(bus), -ECHILD);
199
200 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
201 return 0;
202
203 if (sd_bus_error_is_set(p))
204 return sd_bus_reply_method_error(bus, call, p);
205
206 sd_bus_error_set_errno(&berror, error);
207
208 return sd_bus_reply_method_error(bus, call, &berror);
209 }
210
211 int sd_bus_reply_method_errnof(
212 sd_bus *bus,
213 sd_bus_message *call,
214 int error,
215 const char *format,
216 ...) {
217
218 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
219 va_list ap;
220
221 assert_return(bus, -EINVAL);
222 assert_return(call, -EINVAL);
223 assert_return(call->sealed, -EPERM);
224 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
225 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
226 assert_return(!bus_pid_changed(bus), -ECHILD);
227
228 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
229 return 0;
230
231 va_start(ap, format);
232 bus_error_set_errnofv(&berror, error, format, ap);
233 va_end(ap);
234
235 return sd_bus_reply_method_error(bus, call, &berror);
236 }
237
238 int sd_bus_get_property(
239 sd_bus *bus,
240 const char *destination,
241 const char *path,
242 const char *interface,
243 const char *member,
244 sd_bus_error *error,
245 sd_bus_message **reply,
246 const char *type) {
247
248 sd_bus_message *rep = NULL;
249 int r;
250
251 assert_return(bus, -EINVAL);
252 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
253 assert_return(member_name_is_valid(member), -EINVAL);
254 assert_return(reply, -EINVAL);
255 assert_return(signature_is_single(type, false), -EINVAL);
256 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
257 assert_return(!bus_pid_changed(bus), -ECHILD);
258
259 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
260 if (r < 0)
261 return r;
262
263 r = sd_bus_message_enter_container(rep, 'v', type);
264 if (r < 0) {
265 sd_bus_message_unref(rep);
266 return r;
267 }
268
269 *reply = rep;
270 return 0;
271 }
272
273 int sd_bus_get_property_trivial(
274 sd_bus *bus,
275 const char *destination,
276 const char *path,
277 const char *interface,
278 const char *member,
279 sd_bus_error *error,
280 char type, void *ptr) {
281
282 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
283 int r;
284
285 assert_return(bus, -EINVAL);
286 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
287 assert_return(member_name_is_valid(member), -EINVAL);
288 assert_return(bus_type_is_trivial(type), -EINVAL);
289 assert_return(ptr, -EINVAL);
290 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
291 assert_return(!bus_pid_changed(bus), -ECHILD);
292
293 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
294 if (r < 0)
295 return r;
296
297 r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
298 if (r < 0)
299 return r;
300
301 r = sd_bus_message_read_basic(reply, type, ptr);
302 if (r < 0)
303 return r;
304
305 return 0;
306 }
307
308 int sd_bus_set_property(
309 sd_bus *bus,
310 const char *destination,
311 const char *path,
312 const char *interface,
313 const char *member,
314 sd_bus_error *error,
315 const char *type, ...) {
316
317 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
318 va_list ap;
319 int r;
320
321 assert_return(bus, -EINVAL);
322 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
323 assert_return(member_name_is_valid(member), -EINVAL);
324 assert_return(signature_is_single(type, false), -EINVAL);
325 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
326 assert_return(!bus_pid_changed(bus), -ECHILD);
327
328 r = sd_bus_message_new_method_call(bus, destination, path, "org.freedesktop.DBus.Properties", "Set", &m);
329 if (r < 0)
330 return r;
331
332 r = sd_bus_message_append(m, "ss", strempty(interface), member);
333 if (r < 0)
334 return r;
335
336 r = sd_bus_message_open_container(m, 'v', type);
337 if (r < 0)
338 return r;
339
340 va_start(ap, type);
341 r = bus_message_append_ap(m, type, ap);
342 va_end(ap);
343 if (r < 0)
344 return r;
345
346 r = sd_bus_message_close_container(m);
347 if (r < 0)
348 return r;
349
350 return sd_bus_send_with_reply_and_block(bus, m, 0, error, NULL);
351 }