blob: 3646cc17f1d14085e5fa6c729a644937d796e648 [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 Bishop2afe7182016-08-13 14:08:17 -040016#include <stdlib.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040017#include <string.h>
Brad Bishop2afe7182016-08-13 14:08:17 -040018#include <stdio.h>
19#include <errno.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040020#include <systemd/sd-bus.h>
21#include "mapper.h"
22
Brad Bishop2afe7182016-08-13 14:08:17 -040023static 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
30static const char *async_wait_interfaces_added_match =
31 "type='signal',"
32 "interface='org.freedesktop.DBus.ObjectManager',"
33 "member='InterfacesAdded'";
34
35struct 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
49struct async_wait_callback_data
50{
51 mapper_async_wait *wait;
52 const char *path;
53};
54
55static int async_wait_match_name_owner_changed(sd_bus_message *, void *,
56 sd_bus_error *);
57static int async_wait_match_interfaces_added(sd_bus_message *, void *,
58 sd_bus_error *);
59static int async_wait_check_done(mapper_async_wait *);
60static void async_wait_done(int r, mapper_async_wait *);
61static int async_wait_get_objects(mapper_async_wait *);
62
63static 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
76static void sarrayfree(char *array[])
77{
78 char **p = array;
79 while(*p != NULL) {
80 free(*p);
81 ++p;
82 }
83 free(array);
84}
85
86static 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
104error:
105 sarrayfree(ret);
106 return NULL;
107}
108
109static 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
136static 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
169static 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
185static 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
207finished:
208 if(r < 0 || async_wait_check_done(wait))
209 async_wait_done(r < 0 ? r : 0, wait);
210
211 return 0;
212}
213
214static 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
227static 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
241void mapper_wait_async_free(mapper_async_wait *w)
242{
243 free(w->status);
244 sarrayfree(w->objs);
245 free(w);
246}
247
248int 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
315unref_intf_slot:
316 sd_bus_slot_unref(wait->intf_slot);
317unref_name_slot:
318 sd_bus_slot_unref(wait->name_owner_slot);
319free_status:
320 free(wait->status);
321free_objs:
322 sarrayfree(wait->objs);
323free_wait:
324 free(wait);
325
326 return r;
327}
328
Brad Bishop62ece2b2016-07-25 09:00:51 -0400329int 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
368exit:
369 sd_bus_error_free(&error);
370 sd_bus_message_unref(request);
371 sd_bus_message_unref(reply);
372
373 return r;
374}