1 /** 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 */ 16 #include "config.h" 17 #include <stdlib.h> 18 #include <string.h> 19 #include <stdio.h> 20 #include <errno.h> 21 #include <unistd.h> 22 #include <sys/timerfd.h> 23 #include <systemd/sd-bus.h> 24 #include <systemd/sd-event.h> 25 #include "mapper.h" 26 27 static const char *async_wait_introspection_match = 28 "type='signal'," 29 "sender='xyz.openbmc_project.ObjectMapper'," 30 "interface='xyz.openbmc_project.ObjectMapper.Private'," 31 "member='IntrospectionComplete'"; 32 33 static const char *async_wait_interfaces_added_match = 34 "type='signal'," 35 "interface='org.freedesktop.DBus.ObjectManager'," 36 "member='InterfacesAdded'"; 37 38 static const char *interfaces_removed_match = 39 "type='signal'," 40 "interface='org.freedesktop.DBus.ObjectManager'," 41 "member='InterfacesRemoved'"; 42 43 static const int mapper_busy_retries = 5; 44 static const uint64_t mapper_busy_delay_interval_usec = 1000000; 45 46 struct mapper_async_wait 47 { 48 char **objs; 49 void (*callback)(int, void *); 50 void *userdata; 51 sd_event *loop; 52 sd_bus *conn; 53 sd_bus_slot *introspection_slot; 54 sd_bus_slot *intf_slot; 55 int *status; 56 int count; 57 int finished; 58 int r; 59 }; 60 61 struct async_wait_callback_data 62 { 63 mapper_async_wait *wait; 64 const char *path; 65 sd_event_source *event_source; 66 int retry; 67 }; 68 69 struct mapper_async_subtree 70 { 71 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; 79 }; 80 81 static int async_wait_match_introspection_complete(sd_bus_message *, void *, 82 sd_bus_error *); 83 static int async_wait_check_done(mapper_async_wait *); 84 static void async_wait_done(int r, mapper_async_wait *); 85 static int async_wait_get_objects(mapper_async_wait *); 86 static int async_wait_getobject_callback(sd_bus_message *, 87 void *, sd_bus_error *); 88 89 static int async_subtree_match_callback(sd_bus_message *, void *, 90 sd_bus_error *); 91 92 static 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 105 static void sarrayfree(char *array[]) 106 { 107 char **p = array; 108 while(*p != NULL) { 109 free(*p); 110 ++p; 111 } 112 free(array); 113 } 114 115 static 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 133 error: 134 sarrayfree(ret); 135 return NULL; 136 } 137 138 static 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, 149 MAPPER_BUSNAME, 150 MAPPER_PATH, 151 MAPPER_INTERFACE, 152 "GetObject", 153 async_wait_getobject_callback, 154 data, 155 "sas", 156 data->path, 157 0, 158 NULL); 159 if(r < 0) { 160 async_wait_done(r, wait); 161 free(data); 162 } 163 164 return 0; 165 } 166 167 static int async_wait_getobject_callback(sd_bus_message *m, 168 void *userdata, 169 sd_bus_error *e) 170 { 171 int i, r; 172 struct async_wait_callback_data *data = userdata; 173 mapper_async_wait *wait = data->wait; 174 uint64_t now; 175 176 if(wait->finished) 177 goto exit; 178 179 r = sd_bus_message_get_errno(m); 180 if(r == ENOENT) 181 goto exit; 182 183 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 205 return 0; 206 } 207 208 if(r) { 209 async_wait_done(-r, wait); 210 goto exit; 211 } 212 213 for(i=0; i<wait->count; ++i) { 214 if(!strcmp(data->path, wait->objs[i])) { 215 wait->status[i] = 1; 216 } 217 } 218 219 if(async_wait_check_done(wait)) 220 async_wait_done(0, wait); 221 222 exit: 223 free(data); 224 return 0; 225 } 226 227 static 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]; 238 data->retry = 0; 239 data->event_source = NULL; 240 r = sd_bus_call_method_async( 241 wait->conn, 242 NULL, 243 MAPPER_BUSNAME, 244 MAPPER_PATH, 245 MAPPER_INTERFACE, 246 "GetObject", 247 async_wait_getobject_callback, 248 data, 249 "sas", 250 wait->objs[i], 251 0, 252 NULL); 253 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 264 static int async_wait_match_introspection_complete(sd_bus_message *m, void *w, 265 sd_bus_error *e) 266 { 267 int r; 268 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 280 static void async_wait_done(int r, mapper_async_wait *w) 281 { 282 if(w->finished) 283 return; 284 285 w->finished = 1; 286 sd_bus_slot_unref(w->introspection_slot); 287 sd_bus_slot_unref(w->intf_slot); 288 289 if(w->callback) 290 w->callback(r, w->userdata); 291 } 292 293 static 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 307 void mapper_wait_async_free(mapper_async_wait *w) 308 { 309 free(w->status); 310 sarrayfree(w->objs); 311 free(w); 312 } 313 314 int mapper_wait_async(sd_bus *conn, 315 sd_event *loop, 316 char *objs[], 317 void (*callback)(int, void *), 318 void *userdata, 319 mapper_async_wait **w) 320 { 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; 330 wait->loop = loop; 331 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 350 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 } 360 361 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; 370 } 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 383 unref_intf_slot: 384 sd_bus_slot_unref(wait->intf_slot); 385 unref_name_slot: 386 sd_bus_slot_unref(wait->introspection_slot); 387 free_status: 388 free(wait->status); 389 free_objs: 390 sarrayfree(wait->objs); 391 free_wait: 392 free(wait); 393 394 return r; 395 } 396 397 static int async_subtree_match_callback(sd_bus_message *m, 398 void *t, 399 sd_bus_error *e) 400 { 401 return 0; 402 } 403 404 int 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; 414 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 451 unref_slot: 452 sd_bus_slot_unref(subtree->slot); 453 free_subtree: 454 free(subtree); 455 456 return r; 457 } 458 459 int mapper_get_object(sd_bus *conn, const char *obj, sd_bus_message **reply) 460 { 461 sd_bus_error error = SD_BUS_ERROR_NULL; 462 sd_bus_message *request = NULL; 463 int r, retry = 0; 464 465 r = sd_bus_message_new_method_call( 466 conn, 467 &request, 468 MAPPER_BUSNAME, 469 MAPPER_PATH, 470 MAPPER_INTERFACE, 471 "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; 478 r = sd_bus_message_append(request, "as", 0, NULL); 479 if (r < 0) 480 goto exit; 481 482 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 498 exit: 499 sd_bus_error_free(&error); 500 sd_bus_message_unref(request); 501 502 return r; 503 } 504 505 int 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); 512 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 529 exit: 530 sd_bus_message_unref(reply); 531 532 return r; 533 } 534