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