chiark / gitweb /
bus: properly handle if new objects are installed in the node tree while we are dispa...
[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
26 int sd_bus_emit_signal(
27                 sd_bus *bus,
28                 const char *path,
29                 const char *interface,
30                 const char *member,
31                 const char *types, ...) {
32
33         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
34         int r;
35
36         assert_return(bus, -EINVAL);
37         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
38         assert_return(!bus_pid_changed(bus), -ECHILD);
39
40         r = sd_bus_message_new_signal(bus, path, interface, member, &m);
41         if (r < 0)
42                 return r;
43
44         if (!isempty(types)) {
45                 va_list ap;
46
47                 va_start(ap, types);
48                 r = bus_message_append_ap(m, types, ap);
49                 va_end(ap);
50                 if (r < 0)
51                         return r;
52         }
53
54         return sd_bus_send(bus, m, NULL);
55 }
56
57 int sd_bus_call_method(
58                 sd_bus *bus,
59                 const char *destination,
60                 const char *path,
61                 const char *interface,
62                 const char *member,
63                 sd_bus_error *error,
64                 sd_bus_message **reply,
65                 const char *types, ...) {
66
67         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
68         int r;
69
70         assert_return(bus, -EINVAL);
71         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
72         assert_return(!bus_pid_changed(bus), -ECHILD);
73
74         r = sd_bus_message_new_method_call(bus, destination, path, interface, member, &m);
75         if (r < 0)
76                 return r;
77
78         if (!isempty(types)) {
79                 va_list ap;
80
81                 va_start(ap, types);
82                 r = bus_message_append_ap(m, types, ap);
83                 va_end(ap);
84                 if (r < 0)
85                         return r;
86         }
87
88         return sd_bus_send_with_reply_and_block(bus, m, 0, error, reply);
89 }
90
91 int sd_bus_reply_method_return(
92                 sd_bus *bus,
93                 sd_bus_message *call,
94                 const char *types, ...) {
95
96         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
97         int r;
98
99         assert_return(bus, -EINVAL);
100         assert_return(call, -EINVAL);
101         assert_return(call->sealed, -EPERM);
102         assert_return(call->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL, -EINVAL);
103         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
104         assert_return(!bus_pid_changed(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(bus, 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(bus, m, NULL);
124 }
125
126 int sd_bus_reply_method_error(
127                 sd_bus *bus,
128                 sd_bus_message *call,
129                 const sd_bus_error *e) {
130
131         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
132         int r;
133
134         assert_return(bus, -EINVAL);
135         assert_return(call, -EINVAL);
136         assert_return(call->sealed, -EPERM);
137         assert_return(call->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL, -EINVAL);
138         assert_return(sd_bus_error_is_set(e), -EINVAL);
139         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
140         assert_return(!bus_pid_changed(bus), -ECHILD);
141
142         if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
143                 return 0;
144
145         r = sd_bus_message_new_method_error(bus, call, e, &m);
146         if (r < 0)
147                 return r;
148
149         return sd_bus_send(bus, m, NULL);
150 }
151
152 int sd_bus_reply_method_errorf(
153                 sd_bus *bus,
154                 sd_bus_message *call,
155                 const char *name,
156                 const char *format,
157                 ...) {
158
159         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
160         va_list ap;
161         int r;
162
163         assert_return(bus, -EINVAL);
164         assert_return(call, -EINVAL);
165         assert_return(call->sealed, -EPERM);
166         assert_return(call->header->type == SD_BUS_MESSAGE_TYPE_METHOD_CALL, -EINVAL);
167         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
168         assert_return(!bus_pid_changed(bus), -ECHILD);
169
170         if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
171                 return 0;
172
173         error.name = strdup(name);
174         if (!error.name)
175                 return -ENOMEM;
176
177         error.need_free = true;
178
179         if (format) {
180                 va_start(ap, format);
181                 r = vasprintf((char**) &error.message, format, ap);
182                 va_end(ap);
183
184                 if (r < 0)
185                         return -ENOMEM;
186         }
187
188         return sd_bus_reply_method_error(bus, call, &error);
189 }
190
191 int sd_bus_get_property(
192                 sd_bus *bus,
193                 const char *destination,
194                 const char *path,
195                 const char *interface,
196                 const char *member,
197                 sd_bus_error *error,
198                 sd_bus_message **reply,
199                 const char *type) {
200
201         sd_bus_message *rep = NULL;
202         int r;
203
204         assert_return(bus, -EINVAL);
205         assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
206         assert_return(member_name_is_valid(member), -EINVAL);
207         assert_return(reply, -EINVAL);
208         assert_return(signature_is_single(type, false), -EINVAL);
209         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
210         assert_return(!bus_pid_changed(bus), -ECHILD);
211
212         r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
213         if (r < 0)
214                 return r;
215
216         r = sd_bus_message_enter_container(rep, 'v', type);
217         if (r < 0) {
218                 sd_bus_message_unref(rep);
219                 return r;
220         }
221
222         *reply = rep;
223         return 0;
224 }
225
226 int sd_bus_set_property(
227                 sd_bus *bus,
228                 const char *destination,
229                 const char *path,
230                 const char *interface,
231                 const char *member,
232                 sd_bus_error *error,
233                 const char *type, ...) {
234
235         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
236         va_list ap;
237         int r;
238
239         assert_return(bus, -EINVAL);
240         assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
241         assert_return(member_name_is_valid(member), -EINVAL);
242         assert_return(signature_is_single(type, false), -EINVAL);
243         assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
244         assert_return(!bus_pid_changed(bus), -ECHILD);
245
246         r = sd_bus_message_new_method_call(bus, destination, path, "org.freedesktop.DBus.Properties", "Set", &m);
247         if (r < 0)
248                 return r;
249
250         r = sd_bus_message_append(m, "ss", strempty(interface), member);
251         if (r < 0)
252                 return r;
253
254         r = sd_bus_message_open_container(m, 'v', type);
255         if (r < 0)
256                 return r;
257
258         va_start(ap, type);
259         r = bus_message_append_ap(m, type, ap);
260         va_end(ap);
261         if (r < 0)
262                 return r;
263
264         r = sd_bus_message_close_container(m);
265         if (r < 0)
266                 return r;
267
268         return sd_bus_send_with_reply_and_block(bus, m, 0, error, NULL);
269 }