blob: b1aec6b4bc52c2707468d720a057199844e2f934 [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 Bishop3d468792016-09-20 15:39:38 -040020#include <unistd.h>
21#include <sys/timerfd.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040022#include <systemd/sd-bus.h>
Brad Bishop3d468792016-09-20 15:39:38 -040023#include <systemd/sd-event.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040024#include "mapper.h"
25
Brad Bishop2afe7182016-08-13 14:08:17 -040026static const char *async_wait_name_owner_match =
27 "type='signal',"
28 "sender='org.freedesktop.DBus',"
29 "interface='org.freedesktop.DBus',"
30 "member='NameOwnerChanged',"
31 "path='/org/freedesktop/DBus'";
32
33static const char *async_wait_interfaces_added_match =
34 "type='signal',"
35 "interface='org.freedesktop.DBus.ObjectManager',"
36 "member='InterfacesAdded'";
37
Brad Bishop3d468792016-09-20 15:39:38 -040038static const int mapper_busy_retries = 5;
39static const uint64_t mapper_busy_delay_interval_usec = 1000000;
40
Brad Bishop2afe7182016-08-13 14:08:17 -040041struct mapper_async_wait
42{
43 char **objs;
44 void (*callback)(int, void *);
45 void *userdata;
Brad Bishop3d468792016-09-20 15:39:38 -040046 sd_event *loop;
Brad Bishop2afe7182016-08-13 14:08:17 -040047 sd_bus *conn;
48 sd_bus_slot *name_owner_slot;
49 sd_bus_slot *intf_slot;
50 int *status;
51 int count;
52 int finished;
53 int r;
54};
55
56struct async_wait_callback_data
57{
58 mapper_async_wait *wait;
59 const char *path;
Brad Bishop3d468792016-09-20 15:39:38 -040060 sd_event_source *event_source;
61 int retry;
Brad Bishop2afe7182016-08-13 14:08:17 -040062};
63
64static int async_wait_match_name_owner_changed(sd_bus_message *, void *,
65 sd_bus_error *);
66static int async_wait_match_interfaces_added(sd_bus_message *, void *,
67 sd_bus_error *);
68static int async_wait_check_done(mapper_async_wait *);
69static void async_wait_done(int r, mapper_async_wait *);
70static int async_wait_get_objects(mapper_async_wait *);
Brad Bishop3d468792016-09-20 15:39:38 -040071static int async_wait_getobject_callback(sd_bus_message *,
72 void *, sd_bus_error *);
Brad Bishop2afe7182016-08-13 14:08:17 -040073
74static int sarraylen(char *array[])
75{
76 int count = 0;
77 char **p = array;
78
79 while(*p != NULL) {
80 ++count;
81 ++p;
82 }
83
84 return count;
85}
86
87static void sarrayfree(char *array[])
88{
89 char **p = array;
90 while(*p != NULL) {
91 free(*p);
92 ++p;
93 }
94 free(array);
95}
96
97static char **sarraydup(char *array[])
98{
99 int count = sarraylen(array);
100 int i;
101 char **ret = NULL;
102
103 ret = malloc(sizeof(*ret) * count);
104 if(!ret)
105 return NULL;
106
107 for(i=0; i<count; ++i) {
108 ret[i] = strdup(array[i]);
109 if(!ret[i])
110 goto error;
111 }
112
113 return ret;
114
115error:
116 sarrayfree(ret);
117 return NULL;
118}
119
Brad Bishop3d468792016-09-20 15:39:38 -0400120static int async_wait_timeout_callback(sd_event_source *s,
121 uint64_t usec, void *userdata)
122{
123 int r;
124 struct async_wait_callback_data *data = userdata;
125 mapper_async_wait *wait = data->wait;
126
127 sd_event_source_unref(data->event_source);
128 r = sd_bus_call_method_async(
129 wait->conn,
130 NULL,
131 "org.openbmc.ObjectMapper",
132 "/org/openbmc/ObjectMapper",
133 "org.openbmc.ObjectMapper",
134 "GetObject",
135 async_wait_getobject_callback,
136 data,
137 "s",
138 data->path);
139 if(r < 0) {
140 async_wait_done(r, wait);
141 free(data);
142 }
143
144 return 0;
145}
146
Brad Bishop2afe7182016-08-13 14:08:17 -0400147static int async_wait_getobject_callback(sd_bus_message *m,
148 void *userdata,
149 sd_bus_error *e)
150{
Brad Bishop3d468792016-09-20 15:39:38 -0400151 int i, r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400152 struct async_wait_callback_data *data = userdata;
153 mapper_async_wait *wait = data->wait;
Brad Bishop3d468792016-09-20 15:39:38 -0400154 uint64_t now;
Brad Bishop2afe7182016-08-13 14:08:17 -0400155
156 if(wait->finished)
Brad Bishop3d468792016-09-20 15:39:38 -0400157 goto exit;
158
159 r = sd_bus_message_get_errno(m);
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400160 if(r == ENOENT)
161 goto exit;
162
Brad Bishop3d468792016-09-20 15:39:38 -0400163 if(r == EBUSY && data->retry < mapper_busy_retries) {
164 r = sd_event_now(wait->loop,
165 CLOCK_MONOTONIC,
166 &now);
167 if(r < 0) {
168 async_wait_done(r, wait);
169 goto exit;
170 }
171
172 ++data->retry;
173 r = sd_event_add_time(wait->loop,
174 &data->event_source,
175 CLOCK_MONOTONIC,
176 now + mapper_busy_delay_interval_usec,
177 0,
178 async_wait_timeout_callback,
179 data);
180 if(r < 0) {
181 async_wait_done(r, wait);
182 goto exit;
183 }
184
Brad Bishop2afe7182016-08-13 14:08:17 -0400185 return 0;
Brad Bishop3d468792016-09-20 15:39:38 -0400186 }
187
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400188 if(r) {
Brad Bishop3d468792016-09-20 15:39:38 -0400189 async_wait_done(-r, wait);
190 goto exit;
191 }
192
Brad Bishop2afe7182016-08-13 14:08:17 -0400193 for(i=0; i<wait->count; ++i) {
194 if(!strcmp(data->path, wait->objs[i])) {
195 wait->status[i] = 1;
196 }
197 }
198
Brad Bishop2afe7182016-08-13 14:08:17 -0400199 if(async_wait_check_done(wait))
200 async_wait_done(0, wait);
201
Brad Bishop3d468792016-09-20 15:39:38 -0400202exit:
203 free(data);
Brad Bishop2afe7182016-08-13 14:08:17 -0400204 return 0;
205}
206
207static int async_wait_get_objects(mapper_async_wait *wait)
208{
209 int i, r;
210 struct async_wait_callback_data *data = NULL;
211
212 for(i=0; i<wait->count; ++i) {
213 if(wait->status[i])
214 continue;
215 data = malloc(sizeof(*data));
216 data->wait = wait;
217 data->path = wait->objs[i];
Brad Bishop3d468792016-09-20 15:39:38 -0400218 data->retry = 0;
219 data->event_source = NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400220 r = sd_bus_call_method_async(
221 wait->conn,
222 NULL,
223 "org.openbmc.ObjectMapper",
224 "/org/openbmc/ObjectMapper",
225 "org.openbmc.ObjectMapper",
226 "GetObject",
227 async_wait_getobject_callback,
228 data,
229 "s",
230 wait->objs[i]);
231 if(r < 0) {
232 free(data);
233 fprintf(stderr, "Error invoking method: %s\n",
234 strerror(-r));
235 return r;
236 }
237 }
238
239 return 0;
240}
241
242static int async_wait_match_name_owner_changed(sd_bus_message *m, void *w,
243 sd_bus_error *e)
244{
Brad Bishopa6797f82016-08-30 13:02:46 -0400245 int r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400246
247 mapper_async_wait *wait = w;
248 if(wait->finished)
249 return 0;
250
251 r = async_wait_get_objects(wait);
252 if(r < 0)
253 async_wait_done(r, wait);
254
255 return 0;
256}
257
258static int async_wait_match_interfaces_added(sd_bus_message *m, void *w,
259 sd_bus_error *e)
260{
261 int i, r;
262 mapper_async_wait *wait = w;
263 const char *path;
264
265 if(wait->finished)
266 return 0;
267
268 r = sd_bus_message_read(m, "o", &path);
269 if (r < 0) {
270 fprintf(stderr, "Error reading message: %s\n",
271 strerror(-r));
272 goto finished;
273 }
274
275 for(i=0; i<wait->count; ++i) {
276 if(!strcmp(path, wait->objs[i]))
277 wait->status[i] = 1;
278 }
279
280finished:
281 if(r < 0 || async_wait_check_done(wait))
282 async_wait_done(r < 0 ? r : 0, wait);
283
284 return 0;
285}
286
287static void async_wait_done(int r, mapper_async_wait *w)
288{
289 if(w->finished)
290 return;
291
292 w->finished = 1;
293 sd_bus_slot_unref(w->name_owner_slot);
294 sd_bus_slot_unref(w->intf_slot);
295
296 if(w->callback)
297 w->callback(r, w->userdata);
298}
299
300static int async_wait_check_done(mapper_async_wait *w)
301{
302 int i;
303
304 if(w->finished)
305 return 1;
306
307 for(i=0; i<w->count; ++i)
308 if(!w->status[i])
309 return 0;
310
311 return 1;
312}
313
314void mapper_wait_async_free(mapper_async_wait *w)
315{
316 free(w->status);
317 sarrayfree(w->objs);
318 free(w);
319}
320
321int mapper_wait_async(sd_bus *conn,
Brad Bishop3d468792016-09-20 15:39:38 -0400322 sd_event *loop,
Brad Bishop2afe7182016-08-13 14:08:17 -0400323 char *objs[],
324 void (*callback)(int, void *),
325 void *userdata,
326 mapper_async_wait **w)
327{
328 int r;
329 mapper_async_wait *wait = NULL;
330
331 wait = malloc(sizeof(*wait));
332 if(!wait)
333 return -ENOMEM;
334
335 memset(wait, 0, sizeof(*wait));
336 wait->conn = conn;
Brad Bishop3d468792016-09-20 15:39:38 -0400337 wait->loop = loop;
Brad Bishop2afe7182016-08-13 14:08:17 -0400338 wait->callback = callback;
339 wait->userdata = userdata;
340 wait->count = sarraylen(objs);
341 if(!wait->count)
342 return 0;
343
344 wait->objs = sarraydup(objs);
345 if(!wait->objs) {
346 r = -ENOMEM;
347 goto free_wait;
348 }
349
350 wait->status = malloc(sizeof(*wait->status) * wait->count);
351 if(!wait->status) {
352 r = -ENOMEM;
353 goto free_objs;
354 }
355 memset(wait->status, 0, sizeof(*wait->status) * wait->count);
356
357 r = sd_bus_add_match(conn,
358 &wait->name_owner_slot,
359 async_wait_name_owner_match,
360 async_wait_match_name_owner_changed,
361 wait);
362 if(r < 0) {
363 fprintf(stderr, "Error adding match rule: %s\n",
364 strerror(-r));
365 goto free_status;
366 }
367
368 r = sd_bus_add_match(conn,
369 &wait->intf_slot,
370 async_wait_interfaces_added_match,
371 async_wait_match_interfaces_added,
372 wait);
373 if(r < 0) {
374 fprintf(stderr, "Error adding match rule: %s\n",
375 strerror(-r));
376 goto unref_name_slot;
377 }
378
379 r = async_wait_get_objects(wait);
380 if(r < 0) {
381 fprintf(stderr, "Error calling method: %s\n",
382 strerror(-r));
383 goto unref_intf_slot;
384 }
385
386 *w = wait;
387
388 return 0;
389
390unref_intf_slot:
391 sd_bus_slot_unref(wait->intf_slot);
392unref_name_slot:
393 sd_bus_slot_unref(wait->name_owner_slot);
394free_status:
395 free(wait->status);
396free_objs:
397 sarrayfree(wait->objs);
398free_wait:
399 free(wait);
400
401 return r;
402}
403
Brad Bishop3d468792016-09-20 15:39:38 -0400404int mapper_get_object(sd_bus *conn, const char *obj, sd_bus_message **reply)
Brad Bishop62ece2b2016-07-25 09:00:51 -0400405{
406 sd_bus_error error = SD_BUS_ERROR_NULL;
Brad Bishop3d468792016-09-20 15:39:38 -0400407 sd_bus_message *request = NULL;
408 int r, retry = 0;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400409
410 r = sd_bus_message_new_method_call(
411 conn,
412 &request,
413 "org.openbmc.ObjectMapper",
414 "/org/openbmc/ObjectMapper",
415 "org.openbmc.ObjectMapper",
416 "GetObject");
417 if (r < 0)
418 goto exit;
419
420 r = sd_bus_message_append(request, "s", obj);
421 if (r < 0)
422 goto exit;
423
Brad Bishop3d468792016-09-20 15:39:38 -0400424 while(retry < mapper_busy_retries) {
425 sd_bus_error_free(&error);
426 r = sd_bus_call(conn, request, 0, &error, reply);
427 if (r < 0 && sd_bus_error_get_errno(&error) == EBUSY) {
428 ++retry;
429
430 if(retry != mapper_busy_retries)
431 usleep(mapper_busy_delay_interval_usec);
432 continue;
433 }
434 break;
435 }
436
437 if (r < 0)
438 goto exit;
439
440exit:
441 sd_bus_error_free(&error);
442 sd_bus_message_unref(request);
443
444 return r;
445}
446
447int mapper_get_service(sd_bus *conn, const char *obj, char **service)
448{
449 sd_bus_message *reply = NULL;
450 const char *tmp;
451 int r;
452
453 r = mapper_get_object(conn, obj, &reply);
Brad Bishop62ece2b2016-07-25 09:00:51 -0400454 if (r < 0)
455 goto exit;
456
457 r = sd_bus_message_enter_container(reply, 0, NULL);
458 if (r < 0)
459 goto exit;
460
461 r = sd_bus_message_enter_container(reply, 0, NULL);
462 if (r < 0)
463 goto exit;
464
465 r = sd_bus_message_read(reply, "s", &tmp);
466 if (r < 0)
467 goto exit;
468
469 *service = strdup(tmp);
470
471exit:
Brad Bishop62ece2b2016-07-25 09:00:51 -0400472 sd_bus_message_unref(reply);
473
474 return r;
475}