blob: 8865bc7e98ab7f0e61b32faf2179ab5ee4d97be4 [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 Bishop36eb1e52016-11-01 15:18:36 -040016#include "config.h"
Brad Bishop2afe7182016-08-13 14:08:17 -040017#include <stdlib.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040018#include <string.h>
Brad Bishop2afe7182016-08-13 14:08:17 -040019#include <stdio.h>
20#include <errno.h>
Brad Bishop3d468792016-09-20 15:39:38 -040021#include <unistd.h>
22#include <sys/timerfd.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040023#include <systemd/sd-bus.h>
Brad Bishop3d468792016-09-20 15:39:38 -040024#include <systemd/sd-event.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040025#include "mapper.h"
26
Brad Bishop829181d2017-02-24 09:49:14 -050027static const char *async_wait_introspection_match =
Brad Bishop2afe7182016-08-13 14:08:17 -040028 "type='signal',"
Brad Bishop829181d2017-02-24 09:49:14 -050029 "sender='xyz.openbmc_project.ObjectMapper',"
30 "interface='xyz.openbmc_project.ObjectMapper.Private',"
31 "member='IntrospectionComplete'";
Brad Bishop2afe7182016-08-13 14:08:17 -040032
33static const char *async_wait_interfaces_added_match =
34 "type='signal',"
35 "interface='org.freedesktop.DBus.ObjectManager',"
36 "member='InterfacesAdded'";
37
Adriana Kobylak78edbb62017-05-04 15:45:19 -050038static const char *interfaces_removed_match =
39 "type='signal',"
40 "interface='org.freedesktop.DBus.ObjectManager',"
41 "member='InterfacesRemoved'";
42
Brad Bishop3d468792016-09-20 15:39:38 -040043static const int mapper_busy_retries = 5;
44static const uint64_t mapper_busy_delay_interval_usec = 1000000;
45
Brad Bishop2afe7182016-08-13 14:08:17 -040046struct mapper_async_wait
47{
48 char **objs;
49 void (*callback)(int, void *);
50 void *userdata;
Brad Bishop3d468792016-09-20 15:39:38 -040051 sd_event *loop;
Brad Bishop2afe7182016-08-13 14:08:17 -040052 sd_bus *conn;
Brad Bishop829181d2017-02-24 09:49:14 -050053 sd_bus_slot *introspection_slot;
Brad Bishop2afe7182016-08-13 14:08:17 -040054 sd_bus_slot *intf_slot;
55 int *status;
56 int count;
57 int finished;
58 int r;
59};
60
61struct async_wait_callback_data
62{
63 mapper_async_wait *wait;
64 const char *path;
Brad Bishop3d468792016-09-20 15:39:38 -040065 sd_event_source *event_source;
66 int retry;
Brad Bishop2afe7182016-08-13 14:08:17 -040067};
68
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -050069struct mapper_async_subtree
70{
Adriana Kobylak78edbb62017-05-04 15:45:19 -050071 char *namespace;
72 char *interface;
73 void (*callback)(int, void *);
74 void *userdata;
75 sd_event *loop;
76 sd_bus *conn;
77 sd_bus_slot *slot;
Adriana Kobylak025d7952017-05-08 13:30:45 -050078 sd_event_source *event_source;
Adriana Kobylak78edbb62017-05-04 15:45:19 -050079 int op;
Adriana Kobylak025d7952017-05-08 13:30:45 -050080 int retry;
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -050081};
82
Brad Bishop829181d2017-02-24 09:49:14 -050083static int async_wait_match_introspection_complete(sd_bus_message *, void *,
Brad Bishop2afe7182016-08-13 14:08:17 -040084 sd_bus_error *);
85static int async_wait_check_done(mapper_async_wait *);
86static void async_wait_done(int r, mapper_async_wait *);
87static int async_wait_get_objects(mapper_async_wait *);
Brad Bishop3d468792016-09-20 15:39:38 -040088static int async_wait_getobject_callback(sd_bus_message *,
89 void *, sd_bus_error *);
Brad Bishop2afe7182016-08-13 14:08:17 -040090
Adriana Kobylak78edbb62017-05-04 15:45:19 -050091static int async_subtree_match_callback(sd_bus_message *, void *,
92 sd_bus_error *);
Adriana Kobylak025d7952017-05-08 13:30:45 -050093static int async_subtree_getpaths(mapper_async_subtree *);
94static int async_subtree_getpaths_callback(sd_bus_message *,
95 void *, sd_bus_error *);
Adriana Kobylak78edbb62017-05-04 15:45:19 -050096
Brad Bishop2afe7182016-08-13 14:08:17 -040097static int sarraylen(char *array[])
98{
99 int count = 0;
100 char **p = array;
101
102 while(*p != NULL) {
103 ++count;
104 ++p;
105 }
106
107 return count;
108}
109
110static void sarrayfree(char *array[])
111{
112 char **p = array;
113 while(*p != NULL) {
114 free(*p);
115 ++p;
116 }
117 free(array);
118}
119
120static char **sarraydup(char *array[])
121{
122 int count = sarraylen(array);
123 int i;
124 char **ret = NULL;
125
126 ret = malloc(sizeof(*ret) * count);
127 if(!ret)
128 return NULL;
129
130 for(i=0; i<count; ++i) {
131 ret[i] = strdup(array[i]);
132 if(!ret[i])
133 goto error;
134 }
135
136 return ret;
137
138error:
139 sarrayfree(ret);
140 return NULL;
141}
142
Brad Bishop3d468792016-09-20 15:39:38 -0400143static int async_wait_timeout_callback(sd_event_source *s,
144 uint64_t usec, void *userdata)
145{
146 int r;
147 struct async_wait_callback_data *data = userdata;
148 mapper_async_wait *wait = data->wait;
149
150 sd_event_source_unref(data->event_source);
151 r = sd_bus_call_method_async(
152 wait->conn,
153 NULL,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400154 MAPPER_BUSNAME,
155 MAPPER_PATH,
156 MAPPER_INTERFACE,
Brad Bishop3d468792016-09-20 15:39:38 -0400157 "GetObject",
158 async_wait_getobject_callback,
159 data,
Brad Bishope1c7cf92016-11-02 10:20:35 -0400160 "sas",
161 data->path,
162 0,
163 NULL);
Brad Bishop3d468792016-09-20 15:39:38 -0400164 if(r < 0) {
165 async_wait_done(r, wait);
166 free(data);
167 }
168
169 return 0;
170}
171
Brad Bishop2afe7182016-08-13 14:08:17 -0400172static int async_wait_getobject_callback(sd_bus_message *m,
173 void *userdata,
174 sd_bus_error *e)
175{
Brad Bishop3d468792016-09-20 15:39:38 -0400176 int i, r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400177 struct async_wait_callback_data *data = userdata;
178 mapper_async_wait *wait = data->wait;
Brad Bishop3d468792016-09-20 15:39:38 -0400179 uint64_t now;
Brad Bishop2afe7182016-08-13 14:08:17 -0400180
181 if(wait->finished)
Brad Bishop3d468792016-09-20 15:39:38 -0400182 goto exit;
183
184 r = sd_bus_message_get_errno(m);
Adriana Kobylakc7a7c452017-05-04 12:35:31 -0500185 if(r == ENOENT)
186 goto exit;
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400187
Brad Bishop3d468792016-09-20 15:39:38 -0400188 if(r == EBUSY && data->retry < mapper_busy_retries) {
189 r = sd_event_now(wait->loop,
190 CLOCK_MONOTONIC,
191 &now);
192 if(r < 0) {
193 async_wait_done(r, wait);
194 goto exit;
195 }
196
197 ++data->retry;
198 r = sd_event_add_time(wait->loop,
199 &data->event_source,
200 CLOCK_MONOTONIC,
201 now + mapper_busy_delay_interval_usec,
202 0,
203 async_wait_timeout_callback,
204 data);
205 if(r < 0) {
206 async_wait_done(r, wait);
207 goto exit;
208 }
209
Brad Bishop2afe7182016-08-13 14:08:17 -0400210 return 0;
Brad Bishop3d468792016-09-20 15:39:38 -0400211 }
212
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400213 if(r) {
Brad Bishop3d468792016-09-20 15:39:38 -0400214 async_wait_done(-r, wait);
215 goto exit;
216 }
217
Brad Bishop2afe7182016-08-13 14:08:17 -0400218 for(i=0; i<wait->count; ++i) {
219 if(!strcmp(data->path, wait->objs[i])) {
220 wait->status[i] = 1;
221 }
222 }
223
Brad Bishop2afe7182016-08-13 14:08:17 -0400224 if(async_wait_check_done(wait))
225 async_wait_done(0, wait);
226
Brad Bishop3d468792016-09-20 15:39:38 -0400227exit:
228 free(data);
Brad Bishop2afe7182016-08-13 14:08:17 -0400229 return 0;
230}
231
232static int async_wait_get_objects(mapper_async_wait *wait)
233{
234 int i, r;
235 struct async_wait_callback_data *data = NULL;
236
237 for(i=0; i<wait->count; ++i) {
238 if(wait->status[i])
239 continue;
240 data = malloc(sizeof(*data));
241 data->wait = wait;
242 data->path = wait->objs[i];
Brad Bishop3d468792016-09-20 15:39:38 -0400243 data->retry = 0;
244 data->event_source = NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400245 r = sd_bus_call_method_async(
246 wait->conn,
247 NULL,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400248 MAPPER_BUSNAME,
249 MAPPER_PATH,
250 MAPPER_INTERFACE,
Brad Bishop2afe7182016-08-13 14:08:17 -0400251 "GetObject",
252 async_wait_getobject_callback,
253 data,
Brad Bishope1c7cf92016-11-02 10:20:35 -0400254 "sas",
255 wait->objs[i],
256 0,
257 NULL);
Brad Bishop2afe7182016-08-13 14:08:17 -0400258 if(r < 0) {
259 free(data);
260 fprintf(stderr, "Error invoking method: %s\n",
261 strerror(-r));
262 return r;
263 }
264 }
265
266 return 0;
267}
268
Brad Bishop829181d2017-02-24 09:49:14 -0500269static int async_wait_match_introspection_complete(sd_bus_message *m, void *w,
Brad Bishop2afe7182016-08-13 14:08:17 -0400270 sd_bus_error *e)
271{
Brad Bishopa6797f82016-08-30 13:02:46 -0400272 int r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400273
274 mapper_async_wait *wait = w;
275 if(wait->finished)
276 return 0;
277
278 r = async_wait_get_objects(wait);
279 if(r < 0)
280 async_wait_done(r, wait);
281
282 return 0;
283}
284
Brad Bishop2afe7182016-08-13 14:08:17 -0400285static void async_wait_done(int r, mapper_async_wait *w)
286{
287 if(w->finished)
288 return;
289
290 w->finished = 1;
Brad Bishop829181d2017-02-24 09:49:14 -0500291 sd_bus_slot_unref(w->introspection_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400292 sd_bus_slot_unref(w->intf_slot);
293
294 if(w->callback)
295 w->callback(r, w->userdata);
296}
297
298static int async_wait_check_done(mapper_async_wait *w)
299{
300 int i;
301
302 if(w->finished)
303 return 1;
304
305 for(i=0; i<w->count; ++i)
306 if(!w->status[i])
307 return 0;
308
309 return 1;
310}
311
312void mapper_wait_async_free(mapper_async_wait *w)
313{
314 free(w->status);
315 sarrayfree(w->objs);
316 free(w);
317}
318
319int mapper_wait_async(sd_bus *conn,
Brad Bishop3d468792016-09-20 15:39:38 -0400320 sd_event *loop,
Brad Bishop2afe7182016-08-13 14:08:17 -0400321 char *objs[],
322 void (*callback)(int, void *),
323 void *userdata,
Adriana Kobylakc7a7c452017-05-04 12:35:31 -0500324 mapper_async_wait **w)
Brad Bishop2afe7182016-08-13 14:08:17 -0400325{
326 int r;
327 mapper_async_wait *wait = NULL;
328
329 wait = malloc(sizeof(*wait));
330 if(!wait)
331 return -ENOMEM;
332
333 memset(wait, 0, sizeof(*wait));
334 wait->conn = conn;
Brad Bishop3d468792016-09-20 15:39:38 -0400335 wait->loop = loop;
Brad Bishop2afe7182016-08-13 14:08:17 -0400336 wait->callback = callback;
337 wait->userdata = userdata;
338 wait->count = sarraylen(objs);
339 if(!wait->count)
340 return 0;
341
342 wait->objs = sarraydup(objs);
343 if(!wait->objs) {
344 r = -ENOMEM;
345 goto free_wait;
346 }
347
348 wait->status = malloc(sizeof(*wait->status) * wait->count);
349 if(!wait->status) {
350 r = -ENOMEM;
351 goto free_objs;
352 }
353 memset(wait->status, 0, sizeof(*wait->status) * wait->count);
354
Adriana Kobylakc7a7c452017-05-04 12:35:31 -0500355 r = sd_bus_add_match(conn,
356 &wait->introspection_slot,
357 async_wait_introspection_match,
358 async_wait_match_introspection_complete,
359 wait);
360 if(r < 0) {
361 fprintf(stderr, "Error adding match rule: %s\n",
362 strerror(-r));
363 goto free_status;
364 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400365
Adriana Kobylakc7a7c452017-05-04 12:35:31 -0500366 r = sd_bus_add_match(conn,
367 &wait->intf_slot,
368 async_wait_interfaces_added_match,
369 async_wait_match_introspection_complete,
370 wait);
371 if(r < 0) {
372 fprintf(stderr, "Error adding match rule: %s\n",
373 strerror(-r));
374 goto unref_name_slot;
Brad Bishop2afe7182016-08-13 14:08:17 -0400375 }
376
377 r = async_wait_get_objects(wait);
378 if(r < 0) {
379 fprintf(stderr, "Error calling method: %s\n",
380 strerror(-r));
381 goto unref_intf_slot;
382 }
383
384 *w = wait;
385
386 return 0;
387
388unref_intf_slot:
389 sd_bus_slot_unref(wait->intf_slot);
390unref_name_slot:
Brad Bishop829181d2017-02-24 09:49:14 -0500391 sd_bus_slot_unref(wait->introspection_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400392free_status:
393 free(wait->status);
394free_objs:
395 sarrayfree(wait->objs);
396free_wait:
397 free(wait);
398
399 return r;
400}
401
Adriana Kobylak025d7952017-05-08 13:30:45 -0500402static int async_subtree_getpaths_callback(sd_bus_message *m,
403 void *userdata,
404 sd_bus_error *e)
405{
406 return 0;
407}
408
409static int async_subtree_getpaths(mapper_async_subtree *subtree)
410{
411 int r = 0;
412
413 subtree->retry = 0;
414 subtree->event_source = NULL;
415 r = sd_bus_call_method_async(
416 subtree->conn,
417 NULL,
418 MAPPER_BUSNAME,
419 MAPPER_PATH,
420 MAPPER_INTERFACE,
421 "GetSubTreePaths",
422 async_subtree_getpaths_callback,
423 subtree,
424 "sias",
425 subtree->namespace,
426 0, 1,
427 subtree->interface);
428 if (r < 0) {
429 fprintf(stderr, "Error invoking method: %s\n", strerror(-r));
430 return r;
431 }
432
433 return 0;
434}
435
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500436static int async_subtree_match_callback(sd_bus_message *m,
437 void *t,
438 sd_bus_error *e)
439{
440 return 0;
441}
442
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -0500443int mapper_subtree_async(sd_bus *conn,
444 sd_event *loop,
445 char *namespace,
446 char *interface,
447 void (*callback)(int, void *),
448 void *userdata,
449 mapper_async_subtree **t,
450 int op)
451{
452 int r = 0;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500453 mapper_async_subtree *subtree = NULL;
454
455 subtree = malloc(sizeof(*subtree));
456 if(!subtree)
457 return -ENOMEM;
458
459 memset(subtree, 0, sizeof(*subtree));
460 subtree->conn = conn;
461 subtree->loop = loop;
462 subtree->namespace = namespace;
463 subtree->interface = interface;
464 subtree->callback = callback;
465 subtree->userdata = userdata;
466 subtree->op = op;
467
468 if (subtree->op == MAPPER_OP_REMOVE) {
469 r = sd_bus_add_match(
470 conn,
471 &subtree->slot,
472 interfaces_removed_match,
473 async_subtree_match_callback,
474 subtree);
475 if(r < 0) {
476 fprintf(stderr, "Error adding match rule: %s\n",
477 strerror(-r));
478 goto unref_slot;
479 }
480 } else {
481 /* Operation not supported */
482 r = -EINVAL;
483 goto free_subtree;
484 }
485
Adriana Kobylak025d7952017-05-08 13:30:45 -0500486 r = async_subtree_getpaths(subtree);
487 if(r < 0) {
488 fprintf(stderr, "Error calling method: %s\n",
489 strerror(-r));
490 goto unref_slot;
491 }
492
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500493 *t = subtree;
494
495 return 0;
496
497unref_slot:
498 sd_bus_slot_unref(subtree->slot);
499free_subtree:
500 free(subtree);
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -0500501
502 return r;
503}
504
Brad Bishop3d468792016-09-20 15:39:38 -0400505int mapper_get_object(sd_bus *conn, const char *obj, sd_bus_message **reply)
Brad Bishop62ece2b2016-07-25 09:00:51 -0400506{
507 sd_bus_error error = SD_BUS_ERROR_NULL;
Brad Bishop3d468792016-09-20 15:39:38 -0400508 sd_bus_message *request = NULL;
509 int r, retry = 0;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400510
511 r = sd_bus_message_new_method_call(
512 conn,
513 &request,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400514 MAPPER_BUSNAME,
515 MAPPER_PATH,
516 MAPPER_INTERFACE,
Brad Bishop62ece2b2016-07-25 09:00:51 -0400517 "GetObject");
518 if (r < 0)
519 goto exit;
520
521 r = sd_bus_message_append(request, "s", obj);
522 if (r < 0)
523 goto exit;
Brad Bishope1c7cf92016-11-02 10:20:35 -0400524 r = sd_bus_message_append(request, "as", 0, NULL);
525 if (r < 0)
526 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400527
Brad Bishop3d468792016-09-20 15:39:38 -0400528 while(retry < mapper_busy_retries) {
529 sd_bus_error_free(&error);
530 r = sd_bus_call(conn, request, 0, &error, reply);
531 if (r < 0 && sd_bus_error_get_errno(&error) == EBUSY) {
532 ++retry;
533
534 if(retry != mapper_busy_retries)
535 usleep(mapper_busy_delay_interval_usec);
536 continue;
537 }
538 break;
539 }
540
541 if (r < 0)
542 goto exit;
543
544exit:
545 sd_bus_error_free(&error);
546 sd_bus_message_unref(request);
547
548 return r;
549}
550
551int mapper_get_service(sd_bus *conn, const char *obj, char **service)
552{
553 sd_bus_message *reply = NULL;
554 const char *tmp;
555 int r;
556
557 r = mapper_get_object(conn, obj, &reply);
Brad Bishop62ece2b2016-07-25 09:00:51 -0400558 if (r < 0)
559 goto exit;
560
561 r = sd_bus_message_enter_container(reply, 0, NULL);
562 if (r < 0)
563 goto exit;
564
565 r = sd_bus_message_enter_container(reply, 0, NULL);
566 if (r < 0)
567 goto exit;
568
569 r = sd_bus_message_read(reply, "s", &tmp);
570 if (r < 0)
571 goto exit;
572
573 *service = strdup(tmp);
574
575exit:
Brad Bishop62ece2b2016-07-25 09:00:51 -0400576 sd_bus_message_unref(reply);
577
578 return r;
579}