blob: 56fa5b8c5f1b8974ebdc54608c5257f416c86d0c [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;
78 int op;
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -050079};
80
Brad Bishop829181d2017-02-24 09:49:14 -050081static int async_wait_match_introspection_complete(sd_bus_message *, void *,
Brad Bishop2afe7182016-08-13 14:08:17 -040082 sd_bus_error *);
83static int async_wait_check_done(mapper_async_wait *);
84static void async_wait_done(int r, mapper_async_wait *);
85static int async_wait_get_objects(mapper_async_wait *);
Brad Bishop3d468792016-09-20 15:39:38 -040086static int async_wait_getobject_callback(sd_bus_message *,
87 void *, sd_bus_error *);
Brad Bishop2afe7182016-08-13 14:08:17 -040088
Adriana Kobylak78edbb62017-05-04 15:45:19 -050089static int async_subtree_match_callback(sd_bus_message *, void *,
90 sd_bus_error *);
91
Brad Bishop2afe7182016-08-13 14:08:17 -040092static int sarraylen(char *array[])
93{
94 int count = 0;
95 char **p = array;
96
97 while(*p != NULL) {
98 ++count;
99 ++p;
100 }
101
102 return count;
103}
104
105static void sarrayfree(char *array[])
106{
107 char **p = array;
108 while(*p != NULL) {
109 free(*p);
110 ++p;
111 }
112 free(array);
113}
114
115static char **sarraydup(char *array[])
116{
117 int count = sarraylen(array);
118 int i;
119 char **ret = NULL;
120
121 ret = malloc(sizeof(*ret) * count);
122 if(!ret)
123 return NULL;
124
125 for(i=0; i<count; ++i) {
126 ret[i] = strdup(array[i]);
127 if(!ret[i])
128 goto error;
129 }
130
131 return ret;
132
133error:
134 sarrayfree(ret);
135 return NULL;
136}
137
Brad Bishop3d468792016-09-20 15:39:38 -0400138static int async_wait_timeout_callback(sd_event_source *s,
139 uint64_t usec, void *userdata)
140{
141 int r;
142 struct async_wait_callback_data *data = userdata;
143 mapper_async_wait *wait = data->wait;
144
145 sd_event_source_unref(data->event_source);
146 r = sd_bus_call_method_async(
147 wait->conn,
148 NULL,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400149 MAPPER_BUSNAME,
150 MAPPER_PATH,
151 MAPPER_INTERFACE,
Brad Bishop3d468792016-09-20 15:39:38 -0400152 "GetObject",
153 async_wait_getobject_callback,
154 data,
Brad Bishope1c7cf92016-11-02 10:20:35 -0400155 "sas",
156 data->path,
157 0,
158 NULL);
Brad Bishop3d468792016-09-20 15:39:38 -0400159 if(r < 0) {
160 async_wait_done(r, wait);
161 free(data);
162 }
163
164 return 0;
165}
166
Brad Bishop2afe7182016-08-13 14:08:17 -0400167static int async_wait_getobject_callback(sd_bus_message *m,
168 void *userdata,
169 sd_bus_error *e)
170{
Brad Bishop3d468792016-09-20 15:39:38 -0400171 int i, r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400172 struct async_wait_callback_data *data = userdata;
173 mapper_async_wait *wait = data->wait;
Brad Bishop3d468792016-09-20 15:39:38 -0400174 uint64_t now;
Brad Bishop2afe7182016-08-13 14:08:17 -0400175
176 if(wait->finished)
Brad Bishop3d468792016-09-20 15:39:38 -0400177 goto exit;
178
179 r = sd_bus_message_get_errno(m);
Adriana Kobylakc7a7c452017-05-04 12:35:31 -0500180 if(r == ENOENT)
181 goto exit;
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400182
Brad Bishop3d468792016-09-20 15:39:38 -0400183 if(r == EBUSY && data->retry < mapper_busy_retries) {
184 r = sd_event_now(wait->loop,
185 CLOCK_MONOTONIC,
186 &now);
187 if(r < 0) {
188 async_wait_done(r, wait);
189 goto exit;
190 }
191
192 ++data->retry;
193 r = sd_event_add_time(wait->loop,
194 &data->event_source,
195 CLOCK_MONOTONIC,
196 now + mapper_busy_delay_interval_usec,
197 0,
198 async_wait_timeout_callback,
199 data);
200 if(r < 0) {
201 async_wait_done(r, wait);
202 goto exit;
203 }
204
Brad Bishop2afe7182016-08-13 14:08:17 -0400205 return 0;
Brad Bishop3d468792016-09-20 15:39:38 -0400206 }
207
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400208 if(r) {
Brad Bishop3d468792016-09-20 15:39:38 -0400209 async_wait_done(-r, wait);
210 goto exit;
211 }
212
Brad Bishop2afe7182016-08-13 14:08:17 -0400213 for(i=0; i<wait->count; ++i) {
214 if(!strcmp(data->path, wait->objs[i])) {
215 wait->status[i] = 1;
216 }
217 }
218
Brad Bishop2afe7182016-08-13 14:08:17 -0400219 if(async_wait_check_done(wait))
220 async_wait_done(0, wait);
221
Brad Bishop3d468792016-09-20 15:39:38 -0400222exit:
223 free(data);
Brad Bishop2afe7182016-08-13 14:08:17 -0400224 return 0;
225}
226
227static int async_wait_get_objects(mapper_async_wait *wait)
228{
229 int i, r;
230 struct async_wait_callback_data *data = NULL;
231
232 for(i=0; i<wait->count; ++i) {
233 if(wait->status[i])
234 continue;
235 data = malloc(sizeof(*data));
236 data->wait = wait;
237 data->path = wait->objs[i];
Brad Bishop3d468792016-09-20 15:39:38 -0400238 data->retry = 0;
239 data->event_source = NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400240 r = sd_bus_call_method_async(
241 wait->conn,
242 NULL,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400243 MAPPER_BUSNAME,
244 MAPPER_PATH,
245 MAPPER_INTERFACE,
Brad Bishop2afe7182016-08-13 14:08:17 -0400246 "GetObject",
247 async_wait_getobject_callback,
248 data,
Brad Bishope1c7cf92016-11-02 10:20:35 -0400249 "sas",
250 wait->objs[i],
251 0,
252 NULL);
Brad Bishop2afe7182016-08-13 14:08:17 -0400253 if(r < 0) {
254 free(data);
255 fprintf(stderr, "Error invoking method: %s\n",
256 strerror(-r));
257 return r;
258 }
259 }
260
261 return 0;
262}
263
Brad Bishop829181d2017-02-24 09:49:14 -0500264static int async_wait_match_introspection_complete(sd_bus_message *m, void *w,
Brad Bishop2afe7182016-08-13 14:08:17 -0400265 sd_bus_error *e)
266{
Brad Bishopa6797f82016-08-30 13:02:46 -0400267 int r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400268
269 mapper_async_wait *wait = w;
270 if(wait->finished)
271 return 0;
272
273 r = async_wait_get_objects(wait);
274 if(r < 0)
275 async_wait_done(r, wait);
276
277 return 0;
278}
279
Brad Bishop2afe7182016-08-13 14:08:17 -0400280static void async_wait_done(int r, mapper_async_wait *w)
281{
282 if(w->finished)
283 return;
284
285 w->finished = 1;
Brad Bishop829181d2017-02-24 09:49:14 -0500286 sd_bus_slot_unref(w->introspection_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400287 sd_bus_slot_unref(w->intf_slot);
288
289 if(w->callback)
290 w->callback(r, w->userdata);
291}
292
293static int async_wait_check_done(mapper_async_wait *w)
294{
295 int i;
296
297 if(w->finished)
298 return 1;
299
300 for(i=0; i<w->count; ++i)
301 if(!w->status[i])
302 return 0;
303
304 return 1;
305}
306
307void mapper_wait_async_free(mapper_async_wait *w)
308{
309 free(w->status);
310 sarrayfree(w->objs);
311 free(w);
312}
313
314int mapper_wait_async(sd_bus *conn,
Brad Bishop3d468792016-09-20 15:39:38 -0400315 sd_event *loop,
Brad Bishop2afe7182016-08-13 14:08:17 -0400316 char *objs[],
317 void (*callback)(int, void *),
318 void *userdata,
Adriana Kobylakc7a7c452017-05-04 12:35:31 -0500319 mapper_async_wait **w)
Brad Bishop2afe7182016-08-13 14:08:17 -0400320{
321 int r;
322 mapper_async_wait *wait = NULL;
323
324 wait = malloc(sizeof(*wait));
325 if(!wait)
326 return -ENOMEM;
327
328 memset(wait, 0, sizeof(*wait));
329 wait->conn = conn;
Brad Bishop3d468792016-09-20 15:39:38 -0400330 wait->loop = loop;
Brad Bishop2afe7182016-08-13 14:08:17 -0400331 wait->callback = callback;
332 wait->userdata = userdata;
333 wait->count = sarraylen(objs);
334 if(!wait->count)
335 return 0;
336
337 wait->objs = sarraydup(objs);
338 if(!wait->objs) {
339 r = -ENOMEM;
340 goto free_wait;
341 }
342
343 wait->status = malloc(sizeof(*wait->status) * wait->count);
344 if(!wait->status) {
345 r = -ENOMEM;
346 goto free_objs;
347 }
348 memset(wait->status, 0, sizeof(*wait->status) * wait->count);
349
Adriana Kobylakc7a7c452017-05-04 12:35:31 -0500350 r = sd_bus_add_match(conn,
351 &wait->introspection_slot,
352 async_wait_introspection_match,
353 async_wait_match_introspection_complete,
354 wait);
355 if(r < 0) {
356 fprintf(stderr, "Error adding match rule: %s\n",
357 strerror(-r));
358 goto free_status;
359 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400360
Adriana Kobylakc7a7c452017-05-04 12:35:31 -0500361 r = sd_bus_add_match(conn,
362 &wait->intf_slot,
363 async_wait_interfaces_added_match,
364 async_wait_match_introspection_complete,
365 wait);
366 if(r < 0) {
367 fprintf(stderr, "Error adding match rule: %s\n",
368 strerror(-r));
369 goto unref_name_slot;
Brad Bishop2afe7182016-08-13 14:08:17 -0400370 }
371
372 r = async_wait_get_objects(wait);
373 if(r < 0) {
374 fprintf(stderr, "Error calling method: %s\n",
375 strerror(-r));
376 goto unref_intf_slot;
377 }
378
379 *w = wait;
380
381 return 0;
382
383unref_intf_slot:
384 sd_bus_slot_unref(wait->intf_slot);
385unref_name_slot:
Brad Bishop829181d2017-02-24 09:49:14 -0500386 sd_bus_slot_unref(wait->introspection_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400387free_status:
388 free(wait->status);
389free_objs:
390 sarrayfree(wait->objs);
391free_wait:
392 free(wait);
393
394 return r;
395}
396
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500397static int async_subtree_match_callback(sd_bus_message *m,
398 void *t,
399 sd_bus_error *e)
400{
401 return 0;
402}
403
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -0500404int mapper_subtree_async(sd_bus *conn,
405 sd_event *loop,
406 char *namespace,
407 char *interface,
408 void (*callback)(int, void *),
409 void *userdata,
410 mapper_async_subtree **t,
411 int op)
412{
413 int r = 0;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500414 mapper_async_subtree *subtree = NULL;
415
416 subtree = malloc(sizeof(*subtree));
417 if(!subtree)
418 return -ENOMEM;
419
420 memset(subtree, 0, sizeof(*subtree));
421 subtree->conn = conn;
422 subtree->loop = loop;
423 subtree->namespace = namespace;
424 subtree->interface = interface;
425 subtree->callback = callback;
426 subtree->userdata = userdata;
427 subtree->op = op;
428
429 if (subtree->op == MAPPER_OP_REMOVE) {
430 r = sd_bus_add_match(
431 conn,
432 &subtree->slot,
433 interfaces_removed_match,
434 async_subtree_match_callback,
435 subtree);
436 if(r < 0) {
437 fprintf(stderr, "Error adding match rule: %s\n",
438 strerror(-r));
439 goto unref_slot;
440 }
441 } else {
442 /* Operation not supported */
443 r = -EINVAL;
444 goto free_subtree;
445 }
446
447 *t = subtree;
448
449 return 0;
450
451unref_slot:
452 sd_bus_slot_unref(subtree->slot);
453free_subtree:
454 free(subtree);
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -0500455
456 return r;
457}
458
Brad Bishop3d468792016-09-20 15:39:38 -0400459int mapper_get_object(sd_bus *conn, const char *obj, sd_bus_message **reply)
Brad Bishop62ece2b2016-07-25 09:00:51 -0400460{
461 sd_bus_error error = SD_BUS_ERROR_NULL;
Brad Bishop3d468792016-09-20 15:39:38 -0400462 sd_bus_message *request = NULL;
463 int r, retry = 0;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400464
465 r = sd_bus_message_new_method_call(
466 conn,
467 &request,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400468 MAPPER_BUSNAME,
469 MAPPER_PATH,
470 MAPPER_INTERFACE,
Brad Bishop62ece2b2016-07-25 09:00:51 -0400471 "GetObject");
472 if (r < 0)
473 goto exit;
474
475 r = sd_bus_message_append(request, "s", obj);
476 if (r < 0)
477 goto exit;
Brad Bishope1c7cf92016-11-02 10:20:35 -0400478 r = sd_bus_message_append(request, "as", 0, NULL);
479 if (r < 0)
480 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400481
Brad Bishop3d468792016-09-20 15:39:38 -0400482 while(retry < mapper_busy_retries) {
483 sd_bus_error_free(&error);
484 r = sd_bus_call(conn, request, 0, &error, reply);
485 if (r < 0 && sd_bus_error_get_errno(&error) == EBUSY) {
486 ++retry;
487
488 if(retry != mapper_busy_retries)
489 usleep(mapper_busy_delay_interval_usec);
490 continue;
491 }
492 break;
493 }
494
495 if (r < 0)
496 goto exit;
497
498exit:
499 sd_bus_error_free(&error);
500 sd_bus_message_unref(request);
501
502 return r;
503}
504
505int mapper_get_service(sd_bus *conn, const char *obj, char **service)
506{
507 sd_bus_message *reply = NULL;
508 const char *tmp;
509 int r;
510
511 r = mapper_get_object(conn, obj, &reply);
Brad Bishop62ece2b2016-07-25 09:00:51 -0400512 if (r < 0)
513 goto exit;
514
515 r = sd_bus_message_enter_container(reply, 0, NULL);
516 if (r < 0)
517 goto exit;
518
519 r = sd_bus_message_enter_container(reply, 0, NULL);
520 if (r < 0)
521 goto exit;
522
523 r = sd_bus_message_read(reply, "s", &tmp);
524 if (r < 0)
525 goto exit;
526
527 *service = strdup(tmp);
528
529exit:
Brad Bishop62ece2b2016-07-25 09:00:51 -0400530 sd_bus_message_unref(reply);
531
532 return r;
533}