chiark / gitweb /
core: Rename Job.subscribed field to Job.clients
[elogind.git] / src / libsystemd / sd-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_pid_changed(bus), -ECHILD);
40
41         if (!BUS_IS_OPEN(bus->state))
42                 return -ENOTCONN;
43
44         r = sd_bus_message_new_signal(bus, &m, path, interface, member);
45         if (r < 0)
46                 return r;
47
48         if (!isempty(types)) {
49                 va_list ap;
50
51                 va_start(ap, types);
52                 r = bus_message_append_ap(m, types, ap);
53                 va_end(ap);
54                 if (r < 0)
55                         return r;
56         }
57
58         return sd_bus_send(bus, m, NULL);
59 }
60
61 _public_ int sd_bus_call_method(
62                 sd_bus *bus,
63                 const char *destination,
64                 const char *path,
65                 const char *interface,
66                 const char *member,
67                 sd_bus_error *error,
68                 sd_bus_message **reply,
69                 const char *types, ...) {
70
71         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
72         int r;
73
74         assert_return(bus, -EINVAL);
75         assert_return(!bus_pid_changed(bus), -ECHILD);
76
77         if (!BUS_IS_OPEN(bus->state))
78                 return -ENOTCONN;
79
80         r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
81         if (r < 0)
82                 return r;
83
84         if (!isempty(types)) {
85                 va_list ap;
86
87                 va_start(ap, types);
88                 r = bus_message_append_ap(m, types, ap);
89                 va_end(ap);
90                 if (r < 0)
91                         return r;
92         }
93
94         return sd_bus_call(bus, m, 0, error, reply);
95 }
96
97 _public_ int sd_bus_reply_method_return(
98                 sd_bus_message *call,
99                 const char *types, ...) {
100
101         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
102         int r;
103
104         assert_return(call, -EINVAL);
105         assert_return(call->sealed, -EPERM);
106         assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
107         assert_return(call->bus, -EINVAL);
108         assert_return(!bus_pid_changed(call->bus), -ECHILD);
109
110         if (!BUS_IS_OPEN(call->bus->state))
111                 return -ENOTCONN;
112
113         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
114                 return 0;
115
116         r = sd_bus_message_new_method_return(call, &m);
117         if (r < 0)
118                 return r;
119
120         if (!isempty(types)) {
121                 va_list ap;
122
123                 va_start(ap, types);
124                 r = bus_message_append_ap(m, types, ap);
125                 va_end(ap);
126                 if (r < 0)
127                         return r;
128         }
129
130         return sd_bus_send(call->bus, m, NULL);
131 }
132
133 _public_ int sd_bus_reply_method_error(
134                 sd_bus_message *call,
135                 const sd_bus_error *e) {
136
137         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
138         int r;
139
140         assert_return(call, -EINVAL);
141         assert_return(call->sealed, -EPERM);
142         assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
143         assert_return(sd_bus_error_is_set(e), -EINVAL);
144         assert_return(call->bus, -EINVAL);
145         assert_return(!bus_pid_changed(call->bus), -ECHILD);
146
147         if (!BUS_IS_OPEN(call->bus->state))
148                 return -ENOTCONN;
149
150         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
151                 return 0;
152
153         r = sd_bus_message_new_method_error(call, &m, e);
154         if (r < 0)
155                 return r;
156
157         return sd_bus_send(call->bus, m, NULL);
158 }
159
160 _public_ int sd_bus_reply_method_errorf(
161                 sd_bus_message *call,
162                 const char *name,
163                 const char *format,
164                 ...) {
165
166         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
167         va_list ap;
168
169         assert_return(call, -EINVAL);
170         assert_return(call->sealed, -EPERM);
171         assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
172         assert_return(call->bus, -EINVAL);
173         assert_return(!bus_pid_changed(call->bus), -ECHILD);
174
175         if (!BUS_IS_OPEN(call->bus->state))
176                 return -ENOTCONN;
177
178         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
179                 return 0;
180
181         va_start(ap, format);
182         bus_error_setfv(&error, name, format, ap);
183         va_end(ap);
184
185         return sd_bus_reply_method_error(call, &error);
186 }
187
188 _public_ int sd_bus_reply_method_errno(
189                 sd_bus_message *call,
190                 int error,
191                 const sd_bus_error *p) {
192
193         _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
194
195         assert_return(call, -EINVAL);
196         assert_return(call->sealed, -EPERM);
197         assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
198         assert_return(call->bus, -EINVAL);
199         assert_return(!bus_pid_changed(call->bus), -ECHILD);
200
201         if (!BUS_IS_OPEN(call->bus->state))
202                 return -ENOTCONN;
203
204         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
205                 return 0;
206
207         if (sd_bus_error_is_set(p))
208                 return sd_bus_reply_method_error(call, p);
209
210         sd_bus_error_set_errno(&berror, error);
211
212         return sd_bus_reply_method_error(call, &berror);
213 }
214
215 _public_ int sd_bus_reply_method_errnof(
216                 sd_bus_message *call,
217                 int error,
218                 const char *format,
219                 ...) {
220
221         _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
222         va_list ap;
223
224         assert_return(call, -EINVAL);
225         assert_return(call->sealed, -EPERM);
226         assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
227         assert_return(call->bus, -EINVAL);
228         assert_return(!bus_pid_changed(call->bus), -ECHILD);
229
230         if (!BUS_IS_OPEN(call->bus->state))
231                 return -ENOTCONN;
232
233         if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
234                 return 0;
235
236         va_start(ap, format);
237         bus_error_set_errnofv(&berror, error, format, ap);
238         va_end(ap);
239
240         return sd_bus_reply_method_error(call, &berror);
241 }
242
243 _public_ int sd_bus_get_property(
244                 sd_bus *bus,
245                 const char *destination,
246                 const char *path,
247                 const char *interface,
248                 const char *member,
249                 sd_bus_error *error,
250                 sd_bus_message **reply,
251                 const char *type) {
252
253         sd_bus_message *rep = NULL;
254         int r;
255
256         assert_return(bus, -EINVAL);
257         assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
258         assert_return(member_name_is_valid(member), -EINVAL);
259         assert_return(reply, -EINVAL);
260         assert_return(signature_is_single(type, false), -EINVAL);
261         assert_return(!bus_pid_changed(bus), -ECHILD);
262
263         if (!BUS_IS_OPEN(bus->state))
264                 return -ENOTCONN;
265
266         r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
267         if (r < 0)
268                 return r;
269
270         r = sd_bus_message_enter_container(rep, 'v', type);
271         if (r < 0) {
272                 sd_bus_message_unref(rep);
273                 return r;
274         }
275
276         *reply = rep;
277         return 0;
278 }
279
280 _public_ int sd_bus_get_property_trivial(
281                 sd_bus *bus,
282                 const char *destination,
283                 const char *path,
284                 const char *interface,
285                 const char *member,
286                 sd_bus_error *error,
287                 char type, void *ptr) {
288
289         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
290         int r;
291
292         assert_return(bus, -EINVAL);
293         assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
294         assert_return(member_name_is_valid(member), -EINVAL);
295         assert_return(bus_type_is_trivial(type), -EINVAL);
296         assert_return(ptr, -EINVAL);
297         assert_return(!bus_pid_changed(bus), -ECHILD);
298
299         if (!BUS_IS_OPEN(bus->state))
300                 return -ENOTCONN;
301
302         r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
303         if (r < 0)
304                 return r;
305
306         r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
307         if (r < 0)
308                 return r;
309
310         r = sd_bus_message_read_basic(reply, type, ptr);
311         if (r < 0)
312                 return r;
313
314         return 0;
315 }
316
317 _public_ int sd_bus_get_property_string(
318                 sd_bus *bus,
319                 const char *destination,
320                 const char *path,
321                 const char *interface,
322                 const char *member,
323                 sd_bus_error *error,
324                 char **ret) {
325
326         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
327         const char *s;
328         char *n;
329         int r;
330
331         assert_return(bus, -EINVAL);
332         assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
333         assert_return(member_name_is_valid(member), -EINVAL);
334         assert_return(ret, -EINVAL);
335         assert_return(!bus_pid_changed(bus), -ECHILD);
336
337         if (!BUS_IS_OPEN(bus->state))
338                 return -ENOTCONN;
339
340         r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
341         if (r < 0)
342                 return r;
343
344         r = sd_bus_message_enter_container(reply, 'v', "s");
345         if (r < 0)
346                 return r;
347
348         r = sd_bus_message_read_basic(reply, 's', &s);
349         if (r < 0)
350                 return r;
351
352         n = strdup(s);
353         if (!n)
354                 return -ENOMEM;
355
356         *ret = n;
357         return 0;
358 }
359
360 _public_ int sd_bus_get_property_strv(
361                 sd_bus *bus,
362                 const char *destination,
363                 const char *path,
364                 const char *interface,
365                 const char *member,
366                 sd_bus_error *error,
367                 char ***ret) {
368
369         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
370         int r;
371
372         assert_return(bus, -EINVAL);
373         assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
374         assert_return(member_name_is_valid(member), -EINVAL);
375         assert_return(ret, -EINVAL);
376         assert_return(!bus_pid_changed(bus), -ECHILD);
377
378         if (!BUS_IS_OPEN(bus->state))
379                 return -ENOTCONN;
380
381         r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
382         if (r < 0)
383                 return r;
384
385         r = sd_bus_message_enter_container(reply, 'v', NULL);
386         if (r < 0)
387                 return r;
388
389         r = sd_bus_message_read_strv(reply, ret);
390         if (r < 0)
391                 return r;
392
393         return 0;
394 }
395
396 _public_ int sd_bus_set_property(
397                 sd_bus *bus,
398                 const char *destination,
399                 const char *path,
400                 const char *interface,
401                 const char *member,
402                 sd_bus_error *error,
403                 const char *type, ...) {
404
405         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
406         va_list ap;
407         int r;
408
409         assert_return(bus, -EINVAL);
410         assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
411         assert_return(member_name_is_valid(member), -EINVAL);
412         assert_return(signature_is_single(type, false), -EINVAL);
413         assert_return(!bus_pid_changed(bus), -ECHILD);
414
415         if (!BUS_IS_OPEN(bus->state))
416                 return -ENOTCONN;
417
418         r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set");
419         if (r < 0)
420                 return r;
421
422         r = sd_bus_message_append(m, "ss", strempty(interface), member);
423         if (r < 0)
424                 return r;
425
426         r = sd_bus_message_open_container(m, 'v', type);
427         if (r < 0)
428                 return r;
429
430         va_start(ap, type);
431         r = bus_message_append_ap(m, type, ap);
432         va_end(ap);
433         if (r < 0)
434                 return r;
435
436         r = sd_bus_message_close_container(m);
437         if (r < 0)
438                 return r;
439
440         return sd_bus_call(bus, m, 0, error, NULL);
441 }
442
443 _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
444         sd_bus_creds *c;
445
446         assert_return(call, -EINVAL);
447         assert_return(call->sealed, -EPERM);
448         assert_return(call->bus, -EINVAL);
449         assert_return(!bus_pid_changed(call->bus), -ECHILD);
450
451         if (!BUS_IS_OPEN(call->bus->state))
452                 return -ENOTCONN;
453
454         c = sd_bus_message_get_creds(call);
455
456         /* All data we need? */
457         if (c && (mask & ~c->mask) == 0) {
458                 *creds = sd_bus_creds_ref(c);
459                 return 0;
460         }
461
462         /* No data passed? Or not enough data passed to retrieve the missing bits? */
463         if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
464                 /* We couldn't read anything from the call, let's try
465                  * to get it from the sender or peer */
466
467                 if (call->sender)
468                         return sd_bus_get_owner(call->bus, call->sender, mask, creds);
469                 else
470                         return sd_bus_get_peer_creds(call->bus, mask, creds);
471         }
472
473         return bus_creds_extend_by_pid(c, mask, creds);
474 }