blob: 4f2d022b13f566c75c4c67f609d78561adf9f6fa [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 Kobylak9f4c3c72017-03-28 09:02:20 -050038static const char *async_wait_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{
Adriana Kobylake4d6c792017-04-04 12:47:38 -050048 char *intf;
Brad Bishop2afe7182016-08-13 14:08:17 -040049 char **objs;
50 void (*callback)(int, void *);
51 void *userdata;
Brad Bishop3d468792016-09-20 15:39:38 -040052 sd_event *loop;
Brad Bishop2afe7182016-08-13 14:08:17 -040053 sd_bus *conn;
Brad Bishop829181d2017-02-24 09:49:14 -050054 sd_bus_slot *introspection_slot;
Brad Bishop2afe7182016-08-13 14:08:17 -040055 sd_bus_slot *intf_slot;
56 int *status;
57 int count;
58 int finished;
59 int r;
Adriana Kobylak9f4c3c72017-03-28 09:02:20 -050060 bool added;
Brad Bishop2afe7182016-08-13 14:08:17 -040061};
62
63struct async_wait_callback_data
64{
65 mapper_async_wait *wait;
66 const char *path;
Brad Bishop3d468792016-09-20 15:39:38 -040067 sd_event_source *event_source;
68 int retry;
Brad Bishop2afe7182016-08-13 14:08:17 -040069};
70
Brad Bishop829181d2017-02-24 09:49:14 -050071static int async_wait_match_introspection_complete(sd_bus_message *, void *,
Brad Bishop2afe7182016-08-13 14:08:17 -040072 sd_bus_error *);
73static int async_wait_check_done(mapper_async_wait *);
74static void async_wait_done(int r, mapper_async_wait *);
75static int async_wait_get_objects(mapper_async_wait *);
Brad Bishop3d468792016-09-20 15:39:38 -040076static int async_wait_getobject_callback(sd_bus_message *,
77 void *, sd_bus_error *);
Brad Bishop2afe7182016-08-13 14:08:17 -040078
79static int sarraylen(char *array[])
80{
81 int count = 0;
82 char **p = array;
83
84 while(*p != NULL) {
85 ++count;
86 ++p;
87 }
88
89 return count;
90}
91
92static void sarrayfree(char *array[])
93{
94 char **p = array;
95 while(*p != NULL) {
96 free(*p);
97 ++p;
98 }
99 free(array);
100}
101
102static char **sarraydup(char *array[])
103{
104 int count = sarraylen(array);
105 int i;
106 char **ret = NULL;
107
108 ret = malloc(sizeof(*ret) * count);
109 if(!ret)
110 return NULL;
111
112 for(i=0; i<count; ++i) {
113 ret[i] = strdup(array[i]);
114 if(!ret[i])
115 goto error;
116 }
117
118 return ret;
119
120error:
121 sarrayfree(ret);
122 return NULL;
123}
124
Brad Bishop3d468792016-09-20 15:39:38 -0400125static int async_wait_timeout_callback(sd_event_source *s,
126 uint64_t usec, void *userdata)
127{
128 int r;
129 struct async_wait_callback_data *data = userdata;
130 mapper_async_wait *wait = data->wait;
131
132 sd_event_source_unref(data->event_source);
133 r = sd_bus_call_method_async(
134 wait->conn,
135 NULL,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400136 MAPPER_BUSNAME,
137 MAPPER_PATH,
138 MAPPER_INTERFACE,
Brad Bishop3d468792016-09-20 15:39:38 -0400139 "GetObject",
140 async_wait_getobject_callback,
141 data,
Brad Bishope1c7cf92016-11-02 10:20:35 -0400142 "sas",
143 data->path,
144 0,
145 NULL);
Brad Bishop3d468792016-09-20 15:39:38 -0400146 if(r < 0) {
147 async_wait_done(r, wait);
148 free(data);
149 }
150
151 return 0;
152}
153
Adriana Kobylake4d6c792017-04-04 12:47:38 -0500154static int get_interface(sd_bus_message *m,
155 mapper_async_wait *wait, char* interface)
156{
157 int r = 0;
158 char* tmp_intf = NULL;
159
160 for(int i = 0; i<wait->count; ++i) {
161 sd_bus_error error = SD_BUS_ERROR_NULL;
162 r = sd_bus_call_method(
163 wait->conn,
164 MAPPER_BUSNAME,
165 MAPPER_PATH,
166 MAPPER_INTERFACE,
167 "GetSubTreePaths",
168 &error,
169 &m,
170 "sias",
171 wait->objs[i],
172 0, 1,
173 wait->intf);
174 if (r < 0) {
175 fprintf(stderr, "Error invoking method: %s\n",
176 strerror(-r));
177 return r;
178 }
179
180 r = sd_bus_message_read(m, "as", 1, &tmp_intf);
181 if (r < 0) {
182 // Ignore the errno when the intf does not exist (ENXIO)
183 if (r == -ENXIO) {
184 r = 0;
185 continue;
186 }
187 } else
188 break;
189 }
190
191 if (tmp_intf)
192 strcpy(interface, tmp_intf);
193
194 return r;
195}
196
Brad Bishop2afe7182016-08-13 14:08:17 -0400197static int async_wait_getobject_callback(sd_bus_message *m,
198 void *userdata,
199 sd_bus_error *e)
200{
Brad Bishop3d468792016-09-20 15:39:38 -0400201 int i, r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400202 struct async_wait_callback_data *data = userdata;
203 mapper_async_wait *wait = data->wait;
Brad Bishop3d468792016-09-20 15:39:38 -0400204 uint64_t now;
Brad Bishop2afe7182016-08-13 14:08:17 -0400205
206 if(wait->finished)
Brad Bishop3d468792016-09-20 15:39:38 -0400207 goto exit;
208
209 r = sd_bus_message_get_errno(m);
Adriana Kobylake4d6c792017-04-04 12:47:38 -0500210
211 if (!r && !wait->added) {
212 // Dbus object exists, need to check if it has the requested interface
213 char intf[256];
214 intf[0] = '\0';
215 r = get_interface(m, wait, intf);
216 if ((r < 0) || (strlen(intf) != 0))
217 goto exit;
218 else
219 r = 0;
220 }
221
Adriana Kobylak9f4c3c72017-03-28 09:02:20 -0500222 if(r == ENOENT) {
223 if (wait->added)
224 goto exit;
225 else
226 r = 0;
227 }
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400228
Brad Bishop3d468792016-09-20 15:39:38 -0400229 if(r == EBUSY && data->retry < mapper_busy_retries) {
230 r = sd_event_now(wait->loop,
231 CLOCK_MONOTONIC,
232 &now);
233 if(r < 0) {
234 async_wait_done(r, wait);
235 goto exit;
236 }
237
238 ++data->retry;
239 r = sd_event_add_time(wait->loop,
240 &data->event_source,
241 CLOCK_MONOTONIC,
242 now + mapper_busy_delay_interval_usec,
243 0,
244 async_wait_timeout_callback,
245 data);
246 if(r < 0) {
247 async_wait_done(r, wait);
248 goto exit;
249 }
250
Brad Bishop2afe7182016-08-13 14:08:17 -0400251 return 0;
Brad Bishop3d468792016-09-20 15:39:38 -0400252 }
253
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400254 if(r) {
Brad Bishop3d468792016-09-20 15:39:38 -0400255 async_wait_done(-r, wait);
256 goto exit;
257 }
258
Brad Bishop2afe7182016-08-13 14:08:17 -0400259 for(i=0; i<wait->count; ++i) {
260 if(!strcmp(data->path, wait->objs[i])) {
261 wait->status[i] = 1;
262 }
263 }
264
Brad Bishop2afe7182016-08-13 14:08:17 -0400265 if(async_wait_check_done(wait))
266 async_wait_done(0, wait);
267
Brad Bishop3d468792016-09-20 15:39:38 -0400268exit:
269 free(data);
Brad Bishop2afe7182016-08-13 14:08:17 -0400270 return 0;
271}
272
273static int async_wait_get_objects(mapper_async_wait *wait)
274{
275 int i, r;
276 struct async_wait_callback_data *data = NULL;
277
278 for(i=0; i<wait->count; ++i) {
279 if(wait->status[i])
280 continue;
281 data = malloc(sizeof(*data));
282 data->wait = wait;
283 data->path = wait->objs[i];
Brad Bishop3d468792016-09-20 15:39:38 -0400284 data->retry = 0;
285 data->event_source = NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400286 r = sd_bus_call_method_async(
287 wait->conn,
288 NULL,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400289 MAPPER_BUSNAME,
290 MAPPER_PATH,
291 MAPPER_INTERFACE,
Brad Bishop2afe7182016-08-13 14:08:17 -0400292 "GetObject",
293 async_wait_getobject_callback,
294 data,
Brad Bishope1c7cf92016-11-02 10:20:35 -0400295 "sas",
296 wait->objs[i],
297 0,
298 NULL);
Brad Bishop2afe7182016-08-13 14:08:17 -0400299 if(r < 0) {
300 free(data);
301 fprintf(stderr, "Error invoking method: %s\n",
302 strerror(-r));
303 return r;
304 }
305 }
306
307 return 0;
308}
309
Brad Bishop829181d2017-02-24 09:49:14 -0500310static int async_wait_match_introspection_complete(sd_bus_message *m, void *w,
Brad Bishop2afe7182016-08-13 14:08:17 -0400311 sd_bus_error *e)
312{
Brad Bishopa6797f82016-08-30 13:02:46 -0400313 int r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400314
315 mapper_async_wait *wait = w;
316 if(wait->finished)
317 return 0;
318
319 r = async_wait_get_objects(wait);
320 if(r < 0)
321 async_wait_done(r, wait);
322
323 return 0;
324}
325
Brad Bishop2afe7182016-08-13 14:08:17 -0400326static void async_wait_done(int r, mapper_async_wait *w)
327{
328 if(w->finished)
329 return;
330
331 w->finished = 1;
Brad Bishop829181d2017-02-24 09:49:14 -0500332 sd_bus_slot_unref(w->introspection_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400333 sd_bus_slot_unref(w->intf_slot);
334
335 if(w->callback)
336 w->callback(r, w->userdata);
337}
338
339static int async_wait_check_done(mapper_async_wait *w)
340{
341 int i;
342
343 if(w->finished)
344 return 1;
345
346 for(i=0; i<w->count; ++i)
347 if(!w->status[i])
348 return 0;
349
350 return 1;
351}
352
353void mapper_wait_async_free(mapper_async_wait *w)
354{
355 free(w->status);
356 sarrayfree(w->objs);
357 free(w);
358}
359
360int mapper_wait_async(sd_bus *conn,
Brad Bishop3d468792016-09-20 15:39:38 -0400361 sd_event *loop,
Adriana Kobylake4d6c792017-04-04 12:47:38 -0500362 const char *intf,
Brad Bishop2afe7182016-08-13 14:08:17 -0400363 char *objs[],
364 void (*callback)(int, void *),
365 void *userdata,
Adriana Kobylak9f4c3c72017-03-28 09:02:20 -0500366 mapper_async_wait **w,
367 bool added)
Brad Bishop2afe7182016-08-13 14:08:17 -0400368{
369 int r;
370 mapper_async_wait *wait = NULL;
371
372 wait = malloc(sizeof(*wait));
373 if(!wait)
374 return -ENOMEM;
375
376 memset(wait, 0, sizeof(*wait));
377 wait->conn = conn;
Brad Bishop3d468792016-09-20 15:39:38 -0400378 wait->loop = loop;
Brad Bishop2afe7182016-08-13 14:08:17 -0400379 wait->callback = callback;
380 wait->userdata = userdata;
381 wait->count = sarraylen(objs);
382 if(!wait->count)
383 return 0;
Adriana Kobylak9f4c3c72017-03-28 09:02:20 -0500384 wait->added = added;
Adriana Kobylake4d6c792017-04-04 12:47:38 -0500385 if (intf != NULL)
386 wait->intf = strdup(intf);
387 else
388 wait->intf = NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400389
390 wait->objs = sarraydup(objs);
391 if(!wait->objs) {
392 r = -ENOMEM;
393 goto free_wait;
394 }
395
396 wait->status = malloc(sizeof(*wait->status) * wait->count);
397 if(!wait->status) {
398 r = -ENOMEM;
399 goto free_objs;
400 }
401 memset(wait->status, 0, sizeof(*wait->status) * wait->count);
402
Adriana Kobylak9f4c3c72017-03-28 09:02:20 -0500403 if (wait->added) {
404 r = sd_bus_add_match(conn,
405 &wait->introspection_slot,
406 async_wait_introspection_match,
407 async_wait_match_introspection_complete,
408 wait);
409 if(r < 0) {
410 fprintf(stderr, "Error adding match rule: %s\n",
411 strerror(-r));
412 goto free_status;
413 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400414
Adriana Kobylak9f4c3c72017-03-28 09:02:20 -0500415 r = sd_bus_add_match(conn,
416 &wait->intf_slot,
417 async_wait_interfaces_added_match,
418 async_wait_match_introspection_complete,
419 wait);
420 if(r < 0) {
421 fprintf(stderr, "Error adding match rule: %s\n",
422 strerror(-r));
423 goto unref_name_slot;
424 }
425 } else {
426 r = sd_bus_add_match(conn,
427 &wait->intf_slot,
428 async_wait_interfaces_removed_match,
429 async_wait_match_introspection_complete,
430 wait);
431 if(r < 0) {
432 fprintf(stderr, "Error adding match rule: %s\n",
433 strerror(-r));
434 goto unref_name_slot;
435 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400436 }
437
438 r = async_wait_get_objects(wait);
439 if(r < 0) {
440 fprintf(stderr, "Error calling method: %s\n",
441 strerror(-r));
442 goto unref_intf_slot;
443 }
444
445 *w = wait;
446
447 return 0;
448
449unref_intf_slot:
450 sd_bus_slot_unref(wait->intf_slot);
451unref_name_slot:
Brad Bishop829181d2017-02-24 09:49:14 -0500452 sd_bus_slot_unref(wait->introspection_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400453free_status:
454 free(wait->status);
455free_objs:
456 sarrayfree(wait->objs);
457free_wait:
458 free(wait);
459
460 return r;
461}
462
Brad Bishop3d468792016-09-20 15:39:38 -0400463int mapper_get_object(sd_bus *conn, const char *obj, sd_bus_message **reply)
Brad Bishop62ece2b2016-07-25 09:00:51 -0400464{
465 sd_bus_error error = SD_BUS_ERROR_NULL;
Brad Bishop3d468792016-09-20 15:39:38 -0400466 sd_bus_message *request = NULL;
467 int r, retry = 0;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400468
469 r = sd_bus_message_new_method_call(
470 conn,
471 &request,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400472 MAPPER_BUSNAME,
473 MAPPER_PATH,
474 MAPPER_INTERFACE,
Brad Bishop62ece2b2016-07-25 09:00:51 -0400475 "GetObject");
476 if (r < 0)
477 goto exit;
478
479 r = sd_bus_message_append(request, "s", obj);
480 if (r < 0)
481 goto exit;
Brad Bishope1c7cf92016-11-02 10:20:35 -0400482 r = sd_bus_message_append(request, "as", 0, NULL);
483 if (r < 0)
484 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400485
Brad Bishop3d468792016-09-20 15:39:38 -0400486 while(retry < mapper_busy_retries) {
487 sd_bus_error_free(&error);
488 r = sd_bus_call(conn, request, 0, &error, reply);
489 if (r < 0 && sd_bus_error_get_errno(&error) == EBUSY) {
490 ++retry;
491
492 if(retry != mapper_busy_retries)
493 usleep(mapper_busy_delay_interval_usec);
494 continue;
495 }
496 break;
497 }
498
499 if (r < 0)
500 goto exit;
501
502exit:
503 sd_bus_error_free(&error);
504 sd_bus_message_unref(request);
505
506 return r;
507}
508
509int mapper_get_service(sd_bus *conn, const char *obj, char **service)
510{
511 sd_bus_message *reply = NULL;
512 const char *tmp;
513 int r;
514
515 r = mapper_get_object(conn, obj, &reply);
Brad Bishop62ece2b2016-07-25 09:00:51 -0400516 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_enter_container(reply, 0, NULL);
524 if (r < 0)
525 goto exit;
526
527 r = sd_bus_message_read(reply, "s", &tmp);
528 if (r < 0)
529 goto exit;
530
531 *service = strdup(tmp);
532
533exit:
Brad Bishop62ece2b2016-07-25 09:00:51 -0400534 sd_bus_message_unref(reply);
535
536 return r;
537}