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 <stdlib.h> 17 #include <string.h> 18 #include <stdio.h> 19 #include <errno.h> 20 #include <systemd/sd-bus.h> 21 #include "mapper.h" 22 23 static const char *async_wait_name_owner_match = 24 "type='signal'," 25 "sender='org.freedesktop.DBus'," 26 "interface='org.freedesktop.DBus'," 27 "member='NameOwnerChanged'," 28 "path='/org/freedesktop/DBus'"; 29 30 static const char *async_wait_interfaces_added_match = 31 "type='signal'," 32 "interface='org.freedesktop.DBus.ObjectManager'," 33 "member='InterfacesAdded'"; 34 35 struct mapper_async_wait 36 { 37 char **objs; 38 void (*callback)(int, void *); 39 void *userdata; 40 sd_bus *conn; 41 sd_bus_slot *name_owner_slot; 42 sd_bus_slot *intf_slot; 43 int *status; 44 int count; 45 int finished; 46 int r; 47 }; 48 49 struct async_wait_callback_data 50 { 51 mapper_async_wait *wait; 52 const char *path; 53 }; 54 55 static int async_wait_match_name_owner_changed(sd_bus_message *, void *, 56 sd_bus_error *); 57 static int async_wait_match_interfaces_added(sd_bus_message *, void *, 58 sd_bus_error *); 59 static int async_wait_check_done(mapper_async_wait *); 60 static void async_wait_done(int r, mapper_async_wait *); 61 static int async_wait_get_objects(mapper_async_wait *); 62 63 static int sarraylen(char *array[]) 64 { 65 int count = 0; 66 char **p = array; 67 68 while(*p != NULL) { 69 ++count; 70 ++p; 71 } 72 73 return count; 74 } 75 76 static void sarrayfree(char *array[]) 77 { 78 char **p = array; 79 while(*p != NULL) { 80 free(*p); 81 ++p; 82 } 83 free(array); 84 } 85 86 static char **sarraydup(char *array[]) 87 { 88 int count = sarraylen(array); 89 int i; 90 char **ret = NULL; 91 92 ret = malloc(sizeof(*ret) * count); 93 if(!ret) 94 return NULL; 95 96 for(i=0; i<count; ++i) { 97 ret[i] = strdup(array[i]); 98 if(!ret[i]) 99 goto error; 100 } 101 102 return ret; 103 104 error: 105 sarrayfree(ret); 106 return NULL; 107 } 108 109 static int async_wait_getobject_callback(sd_bus_message *m, 110 void *userdata, 111 sd_bus_error *e) 112 { 113 int i, r; 114 const char *msg; 115 struct async_wait_callback_data *data = userdata; 116 mapper_async_wait *wait = data->wait; 117 118 if(wait->finished) 119 return 0; 120 if(sd_bus_message_get_errno(m)) 121 return 0; 122 123 for(i=0; i<wait->count; ++i) { 124 if(!strcmp(data->path, wait->objs[i])) { 125 wait->status[i] = 1; 126 } 127 } 128 129 free(data); 130 if(async_wait_check_done(wait)) 131 async_wait_done(0, wait); 132 133 return 0; 134 } 135 136 static int async_wait_get_objects(mapper_async_wait *wait) 137 { 138 int i, r; 139 struct async_wait_callback_data *data = NULL; 140 141 for(i=0; i<wait->count; ++i) { 142 if(wait->status[i]) 143 continue; 144 data = malloc(sizeof(*data)); 145 data->wait = wait; 146 data->path = wait->objs[i]; 147 r = sd_bus_call_method_async( 148 wait->conn, 149 NULL, 150 "org.openbmc.ObjectMapper", 151 "/org/openbmc/ObjectMapper", 152 "org.openbmc.ObjectMapper", 153 "GetObject", 154 async_wait_getobject_callback, 155 data, 156 "s", 157 wait->objs[i]); 158 if(r < 0) { 159 free(data); 160 fprintf(stderr, "Error invoking method: %s\n", 161 strerror(-r)); 162 return r; 163 } 164 } 165 166 return 0; 167 } 168 169 static int async_wait_match_name_owner_changed(sd_bus_message *m, void *w, 170 sd_bus_error *e) 171 { 172 int i, r; 173 174 mapper_async_wait *wait = w; 175 if(wait->finished) 176 return 0; 177 178 r = async_wait_get_objects(wait); 179 if(r < 0) 180 async_wait_done(r, wait); 181 182 return 0; 183 } 184 185 static int async_wait_match_interfaces_added(sd_bus_message *m, void *w, 186 sd_bus_error *e) 187 { 188 int i, r; 189 mapper_async_wait *wait = w; 190 const char *path; 191 192 if(wait->finished) 193 return 0; 194 195 r = sd_bus_message_read(m, "o", &path); 196 if (r < 0) { 197 fprintf(stderr, "Error reading message: %s\n", 198 strerror(-r)); 199 goto finished; 200 } 201 202 for(i=0; i<wait->count; ++i) { 203 if(!strcmp(path, wait->objs[i])) 204 wait->status[i] = 1; 205 } 206 207 finished: 208 if(r < 0 || async_wait_check_done(wait)) 209 async_wait_done(r < 0 ? r : 0, wait); 210 211 return 0; 212 } 213 214 static void async_wait_done(int r, mapper_async_wait *w) 215 { 216 if(w->finished) 217 return; 218 219 w->finished = 1; 220 sd_bus_slot_unref(w->name_owner_slot); 221 sd_bus_slot_unref(w->intf_slot); 222 223 if(w->callback) 224 w->callback(r, w->userdata); 225 } 226 227 static int async_wait_check_done(mapper_async_wait *w) 228 { 229 int i; 230 231 if(w->finished) 232 return 1; 233 234 for(i=0; i<w->count; ++i) 235 if(!w->status[i]) 236 return 0; 237 238 return 1; 239 } 240 241 void mapper_wait_async_free(mapper_async_wait *w) 242 { 243 free(w->status); 244 sarrayfree(w->objs); 245 free(w); 246 } 247 248 int mapper_wait_async(sd_bus *conn, 249 char *objs[], 250 void (*callback)(int, void *), 251 void *userdata, 252 mapper_async_wait **w) 253 { 254 int r; 255 mapper_async_wait *wait = NULL; 256 257 wait = malloc(sizeof(*wait)); 258 if(!wait) 259 return -ENOMEM; 260 261 memset(wait, 0, sizeof(*wait)); 262 wait->conn = conn; 263 wait->callback = callback; 264 wait->userdata = userdata; 265 wait->count = sarraylen(objs); 266 if(!wait->count) 267 return 0; 268 269 wait->objs = sarraydup(objs); 270 if(!wait->objs) { 271 r = -ENOMEM; 272 goto free_wait; 273 } 274 275 wait->status = malloc(sizeof(*wait->status) * wait->count); 276 if(!wait->status) { 277 r = -ENOMEM; 278 goto free_objs; 279 } 280 memset(wait->status, 0, sizeof(*wait->status) * wait->count); 281 282 r = sd_bus_add_match(conn, 283 &wait->name_owner_slot, 284 async_wait_name_owner_match, 285 async_wait_match_name_owner_changed, 286 wait); 287 if(r < 0) { 288 fprintf(stderr, "Error adding match rule: %s\n", 289 strerror(-r)); 290 goto free_status; 291 } 292 293 r = sd_bus_add_match(conn, 294 &wait->intf_slot, 295 async_wait_interfaces_added_match, 296 async_wait_match_interfaces_added, 297 wait); 298 if(r < 0) { 299 fprintf(stderr, "Error adding match rule: %s\n", 300 strerror(-r)); 301 goto unref_name_slot; 302 } 303 304 r = async_wait_get_objects(wait); 305 if(r < 0) { 306 fprintf(stderr, "Error calling method: %s\n", 307 strerror(-r)); 308 goto unref_intf_slot; 309 } 310 311 *w = wait; 312 313 return 0; 314 315 unref_intf_slot: 316 sd_bus_slot_unref(wait->intf_slot); 317 unref_name_slot: 318 sd_bus_slot_unref(wait->name_owner_slot); 319 free_status: 320 free(wait->status); 321 free_objs: 322 sarrayfree(wait->objs); 323 free_wait: 324 free(wait); 325 326 return r; 327 } 328 329 int mapper_get_service(sd_bus *conn, const char *obj, char **service) 330 { 331 sd_bus_error error = SD_BUS_ERROR_NULL; 332 sd_bus_message *request = NULL, *reply = NULL; 333 const char *tmp; 334 int r; 335 336 r = sd_bus_message_new_method_call( 337 conn, 338 &request, 339 "org.openbmc.ObjectMapper", 340 "/org/openbmc/ObjectMapper", 341 "org.openbmc.ObjectMapper", 342 "GetObject"); 343 if (r < 0) 344 goto exit; 345 346 r = sd_bus_message_append(request, "s", obj); 347 if (r < 0) 348 goto exit; 349 350 r = sd_bus_call(conn, request, 0, &error, &reply); 351 if (r < 0) 352 goto exit; 353 354 r = sd_bus_message_enter_container(reply, 0, NULL); 355 if (r < 0) 356 goto exit; 357 358 r = sd_bus_message_enter_container(reply, 0, NULL); 359 if (r < 0) 360 goto exit; 361 362 r = sd_bus_message_read(reply, "s", &tmp); 363 if (r < 0) 364 goto exit; 365 366 *service = strdup(tmp); 367 368 exit: 369 sd_bus_error_free(&error); 370 sd_bus_message_unref(request); 371 sd_bus_message_unref(reply); 372 373 return r; 374 } 375