blob: 6e93e17bf8c22e4de792e3d84d435e3e8dfdfe33 [file] [log] [blame]
Brad Bishop62ece2b2016-07-25 09:00:51 -04001/**
2 * Copyright © 2016 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Brad Bishop2afe7182016-08-13 14:08:17 -040016#include <stdlib.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040017#include <string.h>
Brad Bishop2afe7182016-08-13 14:08:17 -040018#include <stdio.h>
19#include <errno.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040020#include <systemd/sd-bus.h>
21#include "mapper.h"
22
Brad Bishop2afe7182016-08-13 14:08:17 -040023static const char *async_wait_name_owner_match =
24 "type='signal',"
25 "sender='org.freedesktop.DBus',"
26 "interface='org.freedesktop.DBus',"
27 "member='NameOwnerChanged',"
28 "path='/org/freedesktop/DBus'";
29
30static const char *async_wait_interfaces_added_match =
31 "type='signal',"
32 "interface='org.freedesktop.DBus.ObjectManager',"
33 "member='InterfacesAdded'";
34
35struct mapper_async_wait
36{
37 char **objs;
38 void (*callback)(int, void *);
39 void *userdata;
40 sd_bus *conn;
41 sd_bus_slot *name_owner_slot;
42 sd_bus_slot *intf_slot;
43 int *status;
44 int count;
45 int finished;
46 int r;
47};
48
49struct async_wait_callback_data
50{
51 mapper_async_wait *wait;
52 const char *path;
53};
54
55static int async_wait_match_name_owner_changed(sd_bus_message *, void *,
56 sd_bus_error *);
57static int async_wait_match_interfaces_added(sd_bus_message *, void *,
58 sd_bus_error *);
59static int async_wait_check_done(mapper_async_wait *);
60static void async_wait_done(int r, mapper_async_wait *);
61static int async_wait_get_objects(mapper_async_wait *);
62
63static int sarraylen(char *array[])
64{
65 int count = 0;
66 char **p = array;
67
68 while(*p != NULL) {
69 ++count;
70 ++p;
71 }
72
73 return count;
74}
75
76static void sarrayfree(char *array[])
77{
78 char **p = array;
79 while(*p != NULL) {
80 free(*p);
81 ++p;
82 }
83 free(array);
84}
85
86static char **sarraydup(char *array[])
87{
88 int count = sarraylen(array);
89 int i;
90 char **ret = NULL;
91
92 ret = malloc(sizeof(*ret) * count);
93 if(!ret)
94 return NULL;
95
96 for(i=0; i<count; ++i) {
97 ret[i] = strdup(array[i]);
98 if(!ret[i])
99 goto error;
100 }
101
102 return ret;
103
104error:
105 sarrayfree(ret);
106 return NULL;
107}
108
109static int async_wait_getobject_callback(sd_bus_message *m,
110 void *userdata,
111 sd_bus_error *e)
112{
Brad Bishopa6797f82016-08-30 13:02:46 -0400113 int i;
Brad Bishop2afe7182016-08-13 14:08:17 -0400114 struct async_wait_callback_data *data = userdata;
115 mapper_async_wait *wait = data->wait;
116
117 if(wait->finished)
118 return 0;
119 if(sd_bus_message_get_errno(m))
120 return 0;
121
122 for(i=0; i<wait->count; ++i) {
123 if(!strcmp(data->path, wait->objs[i])) {
124 wait->status[i] = 1;
125 }
126 }
127
128 free(data);
129 if(async_wait_check_done(wait))
130 async_wait_done(0, wait);
131
132 return 0;
133}
134
135static int async_wait_get_objects(mapper_async_wait *wait)
136{
137 int i, r;
138 struct async_wait_callback_data *data = NULL;
139
140 for(i=0; i<wait->count; ++i) {
141 if(wait->status[i])
142 continue;
143 data = malloc(sizeof(*data));
144 data->wait = wait;
145 data->path = wait->objs[i];
146 r = sd_bus_call_method_async(
147 wait->conn,
148 NULL,
149 "org.openbmc.ObjectMapper",
150 "/org/openbmc/ObjectMapper",
151 "org.openbmc.ObjectMapper",
152 "GetObject",
153 async_wait_getobject_callback,
154 data,
155 "s",
156 wait->objs[i]);
157 if(r < 0) {
158 free(data);
159 fprintf(stderr, "Error invoking method: %s\n",
160 strerror(-r));
161 return r;
162 }
163 }
164
165 return 0;
166}
167
168static int async_wait_match_name_owner_changed(sd_bus_message *m, void *w,
169 sd_bus_error *e)
170{
Brad Bishopa6797f82016-08-30 13:02:46 -0400171 int r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400172
173 mapper_async_wait *wait = w;
174 if(wait->finished)
175 return 0;
176
177 r = async_wait_get_objects(wait);
178 if(r < 0)
179 async_wait_done(r, wait);
180
181 return 0;
182}
183
184static int async_wait_match_interfaces_added(sd_bus_message *m, void *w,
185 sd_bus_error *e)
186{
187 int i, r;
188 mapper_async_wait *wait = w;
189 const char *path;
190
191 if(wait->finished)
192 return 0;
193
194 r = sd_bus_message_read(m, "o", &path);
195 if (r < 0) {
196 fprintf(stderr, "Error reading message: %s\n",
197 strerror(-r));
198 goto finished;
199 }
200
201 for(i=0; i<wait->count; ++i) {
202 if(!strcmp(path, wait->objs[i]))
203 wait->status[i] = 1;
204 }
205
206finished:
207 if(r < 0 || async_wait_check_done(wait))
208 async_wait_done(r < 0 ? r : 0, wait);
209
210 return 0;
211}
212
213static void async_wait_done(int r, mapper_async_wait *w)
214{
215 if(w->finished)
216 return;
217
218 w->finished = 1;
219 sd_bus_slot_unref(w->name_owner_slot);
220 sd_bus_slot_unref(w->intf_slot);
221
222 if(w->callback)
223 w->callback(r, w->userdata);
224}
225
226static int async_wait_check_done(mapper_async_wait *w)
227{
228 int i;
229
230 if(w->finished)
231 return 1;
232
233 for(i=0; i<w->count; ++i)
234 if(!w->status[i])
235 return 0;
236
237 return 1;
238}
239
240void mapper_wait_async_free(mapper_async_wait *w)
241{
242 free(w->status);
243 sarrayfree(w->objs);
244 free(w);
245}
246
247int mapper_wait_async(sd_bus *conn,
248 char *objs[],
249 void (*callback)(int, void *),
250 void *userdata,
251 mapper_async_wait **w)
252{
253 int r;
254 mapper_async_wait *wait = NULL;
255
256 wait = malloc(sizeof(*wait));
257 if(!wait)
258 return -ENOMEM;
259
260 memset(wait, 0, sizeof(*wait));
261 wait->conn = conn;
262 wait->callback = callback;
263 wait->userdata = userdata;
264 wait->count = sarraylen(objs);
265 if(!wait->count)
266 return 0;
267
268 wait->objs = sarraydup(objs);
269 if(!wait->objs) {
270 r = -ENOMEM;
271 goto free_wait;
272 }
273
274 wait->status = malloc(sizeof(*wait->status) * wait->count);
275 if(!wait->status) {
276 r = -ENOMEM;
277 goto free_objs;
278 }
279 memset(wait->status, 0, sizeof(*wait->status) * wait->count);
280
281 r = sd_bus_add_match(conn,
282 &wait->name_owner_slot,
283 async_wait_name_owner_match,
284 async_wait_match_name_owner_changed,
285 wait);
286 if(r < 0) {
287 fprintf(stderr, "Error adding match rule: %s\n",
288 strerror(-r));
289 goto free_status;
290 }
291
292 r = sd_bus_add_match(conn,
293 &wait->intf_slot,
294 async_wait_interfaces_added_match,
295 async_wait_match_interfaces_added,
296 wait);
297 if(r < 0) {
298 fprintf(stderr, "Error adding match rule: %s\n",
299 strerror(-r));
300 goto unref_name_slot;
301 }
302
303 r = async_wait_get_objects(wait);
304 if(r < 0) {
305 fprintf(stderr, "Error calling method: %s\n",
306 strerror(-r));
307 goto unref_intf_slot;
308 }
309
310 *w = wait;
311
312 return 0;
313
314unref_intf_slot:
315 sd_bus_slot_unref(wait->intf_slot);
316unref_name_slot:
317 sd_bus_slot_unref(wait->name_owner_slot);
318free_status:
319 free(wait->status);
320free_objs:
321 sarrayfree(wait->objs);
322free_wait:
323 free(wait);
324
325 return r;
326}
327
Brad Bishop62ece2b2016-07-25 09:00:51 -0400328int mapper_get_service(sd_bus *conn, const char *obj, char **service)
329{
330 sd_bus_error error = SD_BUS_ERROR_NULL;
331 sd_bus_message *request = NULL, *reply = NULL;
332 const char *tmp;
333 int r;
334
335 r = sd_bus_message_new_method_call(
336 conn,
337 &request,
338 "org.openbmc.ObjectMapper",
339 "/org/openbmc/ObjectMapper",
340 "org.openbmc.ObjectMapper",
341 "GetObject");
342 if (r < 0)
343 goto exit;
344
345 r = sd_bus_message_append(request, "s", obj);
346 if (r < 0)
347 goto exit;
348
349 r = sd_bus_call(conn, request, 0, &error, &reply);
350 if (r < 0)
351 goto exit;
352
353 r = sd_bus_message_enter_container(reply, 0, NULL);
354 if (r < 0)
355 goto exit;
356
357 r = sd_bus_message_enter_container(reply, 0, NULL);
358 if (r < 0)
359 goto exit;
360
361 r = sd_bus_message_read(reply, "s", &tmp);
362 if (r < 0)
363 goto exit;
364
365 *service = strdup(tmp);
366
367exit:
368 sd_bus_error_free(&error);
369 sd_bus_message_unref(request);
370 sd_bus_message_unref(reply);
371
372 return r;
373}