blob: 962b4e041b43a8f8487305baab0a6787362834e9 [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
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;
Brad Bishop829181d2017-02-24 09:49:14 -050048 sd_bus_slot *introspection_slot;
Brad Bishop2afe7182016-08-13 14:08:17 -040049 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
Brad Bishop829181d2017-02-24 09:49:14 -050064static int async_wait_match_introspection_complete(sd_bus_message *, void *,
Brad Bishop2afe7182016-08-13 14:08:17 -040065 sd_bus_error *);
66static int async_wait_check_done(mapper_async_wait *);
67static void async_wait_done(int r, mapper_async_wait *);
68static int async_wait_get_objects(mapper_async_wait *);
Brad Bishop3d468792016-09-20 15:39:38 -040069static int async_wait_getobject_callback(sd_bus_message *,
70 void *, sd_bus_error *);
Brad Bishop2afe7182016-08-13 14:08:17 -040071
72static int sarraylen(char *array[])
73{
74 int count = 0;
75 char **p = array;
76
77 while(*p != NULL) {
78 ++count;
79 ++p;
80 }
81
82 return count;
83}
84
85static void sarrayfree(char *array[])
86{
87 char **p = array;
88 while(*p != NULL) {
89 free(*p);
90 ++p;
91 }
92 free(array);
93}
94
95static char **sarraydup(char *array[])
96{
97 int count = sarraylen(array);
98 int i;
99 char **ret = NULL;
100
101 ret = malloc(sizeof(*ret) * count);
102 if(!ret)
103 return NULL;
104
105 for(i=0; i<count; ++i) {
106 ret[i] = strdup(array[i]);
107 if(!ret[i])
108 goto error;
109 }
110
111 return ret;
112
113error:
114 sarrayfree(ret);
115 return NULL;
116}
117
Brad Bishop3d468792016-09-20 15:39:38 -0400118static int async_wait_timeout_callback(sd_event_source *s,
119 uint64_t usec, void *userdata)
120{
121 int r;
122 struct async_wait_callback_data *data = userdata;
123 mapper_async_wait *wait = data->wait;
124
125 sd_event_source_unref(data->event_source);
126 r = sd_bus_call_method_async(
127 wait->conn,
128 NULL,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400129 MAPPER_BUSNAME,
130 MAPPER_PATH,
131 MAPPER_INTERFACE,
Brad Bishop3d468792016-09-20 15:39:38 -0400132 "GetObject",
133 async_wait_getobject_callback,
134 data,
Brad Bishope1c7cf92016-11-02 10:20:35 -0400135 "sas",
136 data->path,
137 0,
138 NULL);
Brad Bishop3d468792016-09-20 15:39:38 -0400139 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);
Adriana Kobylakc7a7c452017-05-04 12:35:31 -0500160 if(r == ENOENT)
161 goto exit;
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400162
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,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400223 MAPPER_BUSNAME,
224 MAPPER_PATH,
225 MAPPER_INTERFACE,
Brad Bishop2afe7182016-08-13 14:08:17 -0400226 "GetObject",
227 async_wait_getobject_callback,
228 data,
Brad Bishope1c7cf92016-11-02 10:20:35 -0400229 "sas",
230 wait->objs[i],
231 0,
232 NULL);
Brad Bishop2afe7182016-08-13 14:08:17 -0400233 if(r < 0) {
234 free(data);
235 fprintf(stderr, "Error invoking method: %s\n",
236 strerror(-r));
237 return r;
238 }
239 }
240
241 return 0;
242}
243
Brad Bishop829181d2017-02-24 09:49:14 -0500244static int async_wait_match_introspection_complete(sd_bus_message *m, void *w,
Brad Bishop2afe7182016-08-13 14:08:17 -0400245 sd_bus_error *e)
246{
Brad Bishopa6797f82016-08-30 13:02:46 -0400247 int r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400248
249 mapper_async_wait *wait = w;
250 if(wait->finished)
251 return 0;
252
253 r = async_wait_get_objects(wait);
254 if(r < 0)
255 async_wait_done(r, wait);
256
257 return 0;
258}
259
Brad Bishop2afe7182016-08-13 14:08:17 -0400260static void async_wait_done(int r, mapper_async_wait *w)
261{
262 if(w->finished)
263 return;
264
265 w->finished = 1;
Brad Bishop829181d2017-02-24 09:49:14 -0500266 sd_bus_slot_unref(w->introspection_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400267 sd_bus_slot_unref(w->intf_slot);
268
269 if(w->callback)
270 w->callback(r, w->userdata);
271}
272
273static int async_wait_check_done(mapper_async_wait *w)
274{
275 int i;
276
277 if(w->finished)
278 return 1;
279
280 for(i=0; i<w->count; ++i)
281 if(!w->status[i])
282 return 0;
283
284 return 1;
285}
286
287void mapper_wait_async_free(mapper_async_wait *w)
288{
289 free(w->status);
290 sarrayfree(w->objs);
291 free(w);
292}
293
294int mapper_wait_async(sd_bus *conn,
Brad Bishop3d468792016-09-20 15:39:38 -0400295 sd_event *loop,
Brad Bishop2afe7182016-08-13 14:08:17 -0400296 char *objs[],
297 void (*callback)(int, void *),
298 void *userdata,
Adriana Kobylakc7a7c452017-05-04 12:35:31 -0500299 mapper_async_wait **w)
Brad Bishop2afe7182016-08-13 14:08:17 -0400300{
301 int r;
302 mapper_async_wait *wait = NULL;
303
304 wait = malloc(sizeof(*wait));
305 if(!wait)
306 return -ENOMEM;
307
308 memset(wait, 0, sizeof(*wait));
309 wait->conn = conn;
Brad Bishop3d468792016-09-20 15:39:38 -0400310 wait->loop = loop;
Brad Bishop2afe7182016-08-13 14:08:17 -0400311 wait->callback = callback;
312 wait->userdata = userdata;
313 wait->count = sarraylen(objs);
314 if(!wait->count)
315 return 0;
316
317 wait->objs = sarraydup(objs);
318 if(!wait->objs) {
319 r = -ENOMEM;
320 goto free_wait;
321 }
322
323 wait->status = malloc(sizeof(*wait->status) * wait->count);
324 if(!wait->status) {
325 r = -ENOMEM;
326 goto free_objs;
327 }
328 memset(wait->status, 0, sizeof(*wait->status) * wait->count);
329
Adriana Kobylakc7a7c452017-05-04 12:35:31 -0500330 r = sd_bus_add_match(conn,
331 &wait->introspection_slot,
332 async_wait_introspection_match,
333 async_wait_match_introspection_complete,
334 wait);
335 if(r < 0) {
336 fprintf(stderr, "Error adding match rule: %s\n",
337 strerror(-r));
338 goto free_status;
339 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400340
Adriana Kobylakc7a7c452017-05-04 12:35:31 -0500341 r = sd_bus_add_match(conn,
342 &wait->intf_slot,
343 async_wait_interfaces_added_match,
344 async_wait_match_introspection_complete,
345 wait);
346 if(r < 0) {
347 fprintf(stderr, "Error adding match rule: %s\n",
348 strerror(-r));
349 goto unref_name_slot;
Brad Bishop2afe7182016-08-13 14:08:17 -0400350 }
351
352 r = async_wait_get_objects(wait);
353 if(r < 0) {
354 fprintf(stderr, "Error calling method: %s\n",
355 strerror(-r));
356 goto unref_intf_slot;
357 }
358
359 *w = wait;
360
361 return 0;
362
363unref_intf_slot:
364 sd_bus_slot_unref(wait->intf_slot);
365unref_name_slot:
Brad Bishop829181d2017-02-24 09:49:14 -0500366 sd_bus_slot_unref(wait->introspection_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400367free_status:
368 free(wait->status);
369free_objs:
370 sarrayfree(wait->objs);
371free_wait:
372 free(wait);
373
374 return r;
375}
376
Brad Bishop3d468792016-09-20 15:39:38 -0400377int mapper_get_object(sd_bus *conn, const char *obj, sd_bus_message **reply)
Brad Bishop62ece2b2016-07-25 09:00:51 -0400378{
379 sd_bus_error error = SD_BUS_ERROR_NULL;
Brad Bishop3d468792016-09-20 15:39:38 -0400380 sd_bus_message *request = NULL;
381 int r, retry = 0;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400382
383 r = sd_bus_message_new_method_call(
384 conn,
385 &request,
Brad Bishop36eb1e52016-11-01 15:18:36 -0400386 MAPPER_BUSNAME,
387 MAPPER_PATH,
388 MAPPER_INTERFACE,
Brad Bishop62ece2b2016-07-25 09:00:51 -0400389 "GetObject");
390 if (r < 0)
391 goto exit;
392
393 r = sd_bus_message_append(request, "s", obj);
394 if (r < 0)
395 goto exit;
Brad Bishope1c7cf92016-11-02 10:20:35 -0400396 r = sd_bus_message_append(request, "as", 0, NULL);
397 if (r < 0)
398 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400399
Brad Bishop3d468792016-09-20 15:39:38 -0400400 while(retry < mapper_busy_retries) {
401 sd_bus_error_free(&error);
402 r = sd_bus_call(conn, request, 0, &error, reply);
403 if (r < 0 && sd_bus_error_get_errno(&error) == EBUSY) {
404 ++retry;
405
406 if(retry != mapper_busy_retries)
407 usleep(mapper_busy_delay_interval_usec);
408 continue;
409 }
410 break;
411 }
412
413 if (r < 0)
414 goto exit;
415
416exit:
417 sd_bus_error_free(&error);
418 sd_bus_message_unref(request);
419
420 return r;
421}
422
423int mapper_get_service(sd_bus *conn, const char *obj, char **service)
424{
425 sd_bus_message *reply = NULL;
426 const char *tmp;
427 int r;
428
429 r = mapper_get_object(conn, obj, &reply);
Brad Bishop62ece2b2016-07-25 09:00:51 -0400430 if (r < 0)
431 goto exit;
432
433 r = sd_bus_message_enter_container(reply, 0, NULL);
434 if (r < 0)
435 goto exit;
436
437 r = sd_bus_message_enter_container(reply, 0, NULL);
438 if (r < 0)
439 goto exit;
440
441 r = sd_bus_message_read(reply, "s", &tmp);
442 if (r < 0)
443 goto exit;
444
445 *service = strdup(tmp);
446
447exit:
Brad Bishop62ece2b2016-07-25 09:00:51 -0400448 sd_bus_message_unref(reply);
449
450 return r;
451}