chiark / gitweb /
644687471311186e351e06d1f84412829a9c83a2
[elogind.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 _public_ 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 _public_ 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_call(bus, m, 0, error, reply);
91 }
92
93 _public_ int sd_bus_reply_method_return(
94                 sd_bus_message *call,
95                 const char *types, ...) {
96
97         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
98         int r;
99
100         assert_return(call, -EINVAL);
101         assert_return(call->sealed, -EPERM);
102         assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
103         assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
104         assert_return(!bus_pid_changed(call->bus), -ECHILD);
105
106         if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
107                 return 0;
108
109         r = sd_bus_message_new_method_return(call, &m);
110         if (r < 0)
111                 return r;
112
113         if (!isempty(types)) {
114                 va_list ap;
115
116                 va_start(ap, types);
117                 r = bus_message_append_ap(m, types, ap);
118                 va_end(ap);
119                 if (r < 0)
120                         return r;
121         }
122
123         return sd_bus_send(call->bus, m, NULL);
124 }
125
126 _public_ int sd_bus_reply_method_error(
127                 sd_bus_message *call,
128                 const sd_bus_error *e) {
129
130         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
131         int r;
132
133         assert_return(call, -EINVAL);
134         assert_return(call->sealed, -EPERM);
135         assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
136         assert_return(sd_bus_error_is_set(e), -EINVAL);
137         assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
138         assert_return(!bus_pid_changed(call->bus), -ECHILD);
139
140         if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
141                 return 0;
142
143         r = sd_bus_message_new_method_error(call, e, &m);
144         if (r < 0)
145                 return r;
146
147         return sd_bus_send(call->bus, m, NULL);
148 }
149
150 _public_ int sd_bus_reply_method_errorf(
151                 sd_bus_message *call,
152                 const char *name,
153                 const char *format,
154                 ...) {
155
156         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
157         va_list ap;
158         int r;
159
160         assert_return(call, -EINVAL);
161         assert_return(call->sealed, -EPERM);
162         assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
163         assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
164         assert_return(!bus_pid_changed(call->bus), -ECHILD);
165
166         if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
167                 return 0;
168
169         va_start(ap, format);
170         r = bus_error_setfv(&error, name, format, ap);
171         va_end(ap);
172
173         if (r < 0)
174                 return r;
175
176         return sd_bus_reply_method_error(call, &error);
177 }
178
179 _public_ int sd_bus_reply_method_errno(
180                 sd_bus_message *call,
181                 int error,
182                 const sd_bus_error *p) {
183
184         _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
185
186         assert_return(call, -EINVAL);
187         assert_return(call->sealed, -EPERM);
188         assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
189         assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
190         assert_return(!bus_pid_changed(call->bus), -ECHILD);
191
192         if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
193                 return 0;
194
195         if (sd_bus_error_is_set(p))
196                 return sd_bus_reply_method_error(call, p);
197
198         sd_bus_error_set_errno(&berror, error);
199
200         return sd_bus_reply_method_error(call, &berror);
201 }
202
203 _public_ int sd_bus_reply_method_errnof(
204                 sd_bus_message *call,
205                 int error,
206                 const char *format,
207                 ...) {
208
209         _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
210         va_list ap;
211
212         assert_return(call, -EINVAL);
213         assert_return(call->sealed, -EPERM);
214         assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
215         assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
216         assert_return(!bus_pid_changed(call->bus), -ECHILD);
217
218         if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
219                 return 0;
220
221         va_start(ap, format);
222         bus_error_set_errnofv(&berror, error, format, ap);
223         va_end(ap);
224
225         return sd_bus_reply_method_error(call, &berror);
226 }
227
228 _public_ int sd_bus_get_property(
229                 sd_bus *bus,
230                 const char *destination,
231                 const char *path,
232                 const char *interface,
233                 const char *member,
234                 sd_bus_error *error,
235                 sd_bus_message **reply,
236                 const char *type) {
237
238         sd_bus_message *rep = NULL;
239         int r;
240
241         assert_return(bus, -EINVAL);
242         assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
243         assert_return(member_name_is_valid(member), -EINVAL);
244         assert_return(reply, -EINVAL);
245         assert_return(signature_is_single(type, false), -EINVAL);
246         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
247         assert_return(!bus_pid_changed(bus), -ECHILD);
248
249         r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
250         if (r < 0)
251                 return r;
252
253         r = sd_bus_message_enter_container(rep, 'v', type);
254         if (r < 0) {
255                 sd_bus_message_unref(rep);
256                 return r;
257         }
258
259         *reply = rep;
260         return 0;
261 }
262
263 _public_ int sd_bus_get_property_trivial(
264                 sd_bus *bus,
265                 const char *destination,
266                 const char *path,
267                 const char *interface,
268                 const char *member,
269                 sd_bus_error *error,
270                 char type, void *ptr) {
271
272         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
273         int r;
274
275         assert_return(bus, -EINVAL);
276         assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
277         assert_return(member_name_is_valid(member), -EINVAL);
278         assert_return(bus_type_is_trivial(type), -EINVAL);
279         assert_return(ptr, -EINVAL);
280         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
281         assert_return(!bus_pid_changed(bus), -ECHILD);
282
283         r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
284         if (r < 0)
285                 return r;
286
287         r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
288         if (r < 0)
289                 return r;
290
291         r = sd_bus_message_read_basic(reply, type, ptr);
292         if (r < 0)
293                 return r;
294
295         return 0;
296 }
297
298 _public_ int sd_bus_get_property_string(
299                 sd_bus *bus,
300                 const char *destination,
301                 const char *path,
302                 const char *interface,
303                 const char *member,
304                 sd_bus_error *error,
305                 char **ret) {
306
307         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
308         const char *s;
309         char *n;
310         int r;
311
312         assert_return(bus, -EINVAL);
313         assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
314         assert_return(member_name_is_valid(member), -EINVAL);
315         assert_return(ret, -EINVAL);
316         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
317         assert_return(!bus_pid_changed(bus), -ECHILD);
318
319         r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
320         if (r < 0)
321                 return r;
322
323         r = sd_bus_message_enter_container(reply, 'v', "s");
324         if (r < 0)
325                 return r;
326
327         r = sd_bus_message_read_basic(reply, 's', &s);
328         if (r < 0)
329                 return r;
330
331         n = strdup(s);
332         if (!n)
333                 return -ENOMEM;
334
335         *ret = n;
336         return 0;
337 }
338
339 _public_ int sd_bus_get_property_strv(
340                 sd_bus *bus,
341                 const char *destination,
342                 const char *path,
343                 const char *interface,
344                 const char *member,
345                 sd_bus_error *error,
346                 char ***ret) {
347
348         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
349         int r;
350
351         assert_return(bus, -EINVAL);
352         assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
353         assert_return(member_name_is_valid(member), -EINVAL);
354         assert_return(ret, -EINVAL);
355         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
356         assert_return(!bus_pid_changed(bus), -ECHILD);
357
358         r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
359         if (r < 0)
360                 return r;
361
362         r = sd_bus_message_enter_container(reply, 'v', NULL);
363         if (r < 0)
364                 return r;
365
366         r = sd_bus_message_read_strv(reply, ret);
367         if (r < 0)
368                 return r;
369
370         return 0;
371 }
372
373 _public_ int sd_bus_set_property(
374                 sd_bus *bus,
375                 const char *destination,
376                 const char *path,
377                 const char *interface,
378                 const char *member,
379                 sd_bus_error *error,
380                 const char *type, ...) {
381
382         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
383         va_list ap;
384         int r;
385
386         assert_return(bus, -EINVAL);
387         assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
388         assert_return(member_name_is_valid(member), -EINVAL);
389         assert_return(signature_is_single(type, false), -EINVAL);
390         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
391         assert_return(!bus_pid_changed(bus), -ECHILD);
392
393         r = sd_bus_message_new_method_call(bus, destination, path, "org.freedesktop.DBus.Properties", "Set", &m);
394         if (r < 0)
395                 return r;
396
397         r = sd_bus_message_append(m, "ss", strempty(interface), member);
398         if (r < 0)
399                 return r;
400
401         r = sd_bus_message_open_container(m, 'v', type);
402         if (r < 0)
403                 return r;
404
405         va_start(ap, type);
406         r = bus_message_append_ap(m, type, ap);
407         va_end(ap);
408         if (r < 0)
409                 return r;
410
411         r = sd_bus_message_close_container(m);
412         if (r < 0)
413                 return r;
414
415         return sd_bus_call(bus, m, 0, error, NULL);
416 }