blob: ff96dc8a677da5e8b2eec264ce7bcb207d525d12 [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"
William A. Kennington III20cbbfb2018-06-15 10:10:13 -070017#include <stdbool.h>
Brad Bishop2afe7182016-08-13 14:08:17 -040018#include <stdlib.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040019#include <string.h>
Brad Bishop2afe7182016-08-13 14:08:17 -040020#include <stdio.h>
21#include <errno.h>
Brad Bishop3d468792016-09-20 15:39:38 -040022#include <unistd.h>
23#include <sys/timerfd.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040024#include <systemd/sd-bus.h>
Brad Bishop3d468792016-09-20 15:39:38 -040025#include <systemd/sd-event.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040026#include "mapper.h"
27
Brad Bishop829181d2017-02-24 09:49:14 -050028static const char *async_wait_introspection_match =
Ed Tanous167e2372018-05-07 11:59:10 -070029 "type='signal',"
30 "sender='xyz.openbmc_project.ObjectMapper',"
31 "interface='xyz.openbmc_project.ObjectMapper.Private',"
32 "member='IntrospectionComplete'";
Brad Bishop2afe7182016-08-13 14:08:17 -040033
34static const char *async_wait_interfaces_added_match =
Ed Tanous167e2372018-05-07 11:59:10 -070035 "type='signal',"
36 "interface='org.freedesktop.DBus.ObjectManager',"
37 "member='InterfacesAdded'";
Brad Bishop2afe7182016-08-13 14:08:17 -040038
Adriana Kobylak78edbb62017-05-04 15:45:19 -050039static const char *interfaces_removed_match =
Ed Tanous167e2372018-05-07 11:59:10 -070040 "type='signal',"
41 "interface='org.freedesktop.DBus.ObjectManager',"
42 "member='InterfacesRemoved'";
Adriana Kobylak78edbb62017-05-04 15:45:19 -050043
Brad Bishop3d468792016-09-20 15:39:38 -040044static const int mapper_busy_retries = 5;
45static const uint64_t mapper_busy_delay_interval_usec = 1000000;
46
Brad Bishop2afe7182016-08-13 14:08:17 -040047struct mapper_async_wait
48{
Ed Tanous167e2372018-05-07 11:59:10 -070049 char **objs;
50 void (*callback)(int, void *);
51 void *userdata;
52 sd_event *loop;
53 sd_bus *conn;
54 sd_bus_slot *introspection_slot;
55 sd_bus_slot *intf_slot;
56 int *status;
57 int count;
58 int finished;
59 int r;
Brad Bishop2afe7182016-08-13 14:08:17 -040060};
61
62struct async_wait_callback_data
63{
Ed Tanous167e2372018-05-07 11:59:10 -070064 mapper_async_wait *wait;
65 const char *path;
66 sd_event_source *event_source;
67 int retry;
Brad Bishop2afe7182016-08-13 14:08:17 -040068};
69
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -050070struct mapper_async_subtree
71{
Ed Tanous167e2372018-05-07 11:59:10 -070072 char *namespace;
73 char *interface;
74 void (*callback)(int, void *);
75 void *userdata;
76 sd_event *loop;
77 sd_bus *conn;
78 sd_bus_slot *slot;
79 sd_event_source *event_source;
80 int finished;
81 int op;
82 int retry;
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -050083};
84
Brad Bishop829181d2017-02-24 09:49:14 -050085static int async_wait_match_introspection_complete(sd_bus_message *, void *,
Ed Tanous167e2372018-05-07 11:59:10 -070086 sd_bus_error *);
Brad Bishop2afe7182016-08-13 14:08:17 -040087static int async_wait_check_done(mapper_async_wait *);
88static void async_wait_done(int r, mapper_async_wait *);
89static int async_wait_get_objects(mapper_async_wait *);
Ed Tanous167e2372018-05-07 11:59:10 -070090static int async_wait_getobject_callback(sd_bus_message *, void *,
91 sd_bus_error *);
Brad Bishop2afe7182016-08-13 14:08:17 -040092
Adriana Kobylak78edbb62017-05-04 15:45:19 -050093static int async_subtree_match_callback(sd_bus_message *, void *,
Ed Tanous167e2372018-05-07 11:59:10 -070094 sd_bus_error *);
Adriana Kobylakb2f26812017-05-08 13:58:02 -050095static void async_subtree_done(int r, mapper_async_subtree *);
Adriana Kobylak025d7952017-05-08 13:30:45 -050096static int async_subtree_getpaths(mapper_async_subtree *);
Ed Tanous167e2372018-05-07 11:59:10 -070097static int async_subtree_getpaths_callback(sd_bus_message *, void *,
98 sd_bus_error *);
Adriana Kobylak78edbb62017-05-04 15:45:19 -050099
Brad Bishop2afe7182016-08-13 14:08:17 -0400100static int sarraylen(char *array[])
101{
Ed Tanous167e2372018-05-07 11:59:10 -0700102 int count = 0;
103 char **p = array;
Brad Bishop2afe7182016-08-13 14:08:17 -0400104
Ed Tanous167e2372018-05-07 11:59:10 -0700105 while (*p != NULL)
106 {
107 ++count;
108 ++p;
109 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400110
Ed Tanous167e2372018-05-07 11:59:10 -0700111 return count;
Brad Bishop2afe7182016-08-13 14:08:17 -0400112}
113
114static void sarrayfree(char *array[])
115{
Ed Tanous167e2372018-05-07 11:59:10 -0700116 char **p = array;
117 while (*p != NULL)
118 {
119 free(*p);
120 ++p;
121 }
122 free(array);
Brad Bishop2afe7182016-08-13 14:08:17 -0400123}
124
125static char **sarraydup(char *array[])
126{
Ed Tanous167e2372018-05-07 11:59:10 -0700127 int count = sarraylen(array);
128 int i;
129 char **ret = NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400130
Ed Tanous167e2372018-05-07 11:59:10 -0700131 ret = malloc(sizeof(*ret) * count);
132 if (!ret)
133 return NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400134
Ed Tanous167e2372018-05-07 11:59:10 -0700135 for (i = 0; i < count; ++i)
136 {
137 ret[i] = strdup(array[i]);
138 if (!ret[i])
139 goto error;
140 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400141
Ed Tanous167e2372018-05-07 11:59:10 -0700142 return ret;
Brad Bishop2afe7182016-08-13 14:08:17 -0400143
144error:
Ed Tanous167e2372018-05-07 11:59:10 -0700145 sarrayfree(ret);
146 return NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400147}
148
Ed Tanous167e2372018-05-07 11:59:10 -0700149static int async_wait_timeout_callback(sd_event_source *s, uint64_t usec,
150 void *userdata)
Brad Bishop3d468792016-09-20 15:39:38 -0400151{
Ed Tanous167e2372018-05-07 11:59:10 -0700152 int r;
153 struct async_wait_callback_data *data = userdata;
154 mapper_async_wait *wait = data->wait;
Brad Bishop3d468792016-09-20 15:39:38 -0400155
Ed Tanous167e2372018-05-07 11:59:10 -0700156 sd_event_source_unref(data->event_source);
157 r = sd_bus_call_method_async(wait->conn, NULL, MAPPER_BUSNAME, MAPPER_PATH,
158 MAPPER_INTERFACE, "GetObject",
159 async_wait_getobject_callback, data, "sas",
160 data->path, 0, NULL);
161 if (r < 0)
162 {
163 async_wait_done(r, wait);
164 free(data);
165 }
Brad Bishop3d468792016-09-20 15:39:38 -0400166
Ed Tanous167e2372018-05-07 11:59:10 -0700167 return 0;
Brad Bishop3d468792016-09-20 15:39:38 -0400168}
169
Ed Tanous167e2372018-05-07 11:59:10 -0700170static int async_wait_getobject_callback(sd_bus_message *m, void *userdata,
171 sd_bus_error *e)
Brad Bishop2afe7182016-08-13 14:08:17 -0400172{
Ed Tanous167e2372018-05-07 11:59:10 -0700173 int i, r;
174 struct async_wait_callback_data *data = userdata;
175 mapper_async_wait *wait = data->wait;
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700176 uint64_t next_retry;
Brad Bishop2afe7182016-08-13 14:08:17 -0400177
Ed Tanous167e2372018-05-07 11:59:10 -0700178 if (wait->finished)
179 goto exit;
Brad Bishop3d468792016-09-20 15:39:38 -0400180
Ed Tanous167e2372018-05-07 11:59:10 -0700181 r = sd_bus_message_get_errno(m);
182 if (r == ENOENT)
183 goto exit;
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400184
Ed Tanous167e2372018-05-07 11:59:10 -0700185 if (r == EBUSY && data->retry < mapper_busy_retries)
186 {
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700187 r = sd_event_now(wait->loop, CLOCK_MONOTONIC, &next_retry);
Ed Tanous167e2372018-05-07 11:59:10 -0700188 if (r < 0)
189 {
190 async_wait_done(r, wait);
191 goto exit;
192 }
Brad Bishop3d468792016-09-20 15:39:38 -0400193
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700194 next_retry += mapper_busy_delay_interval_usec * (1 << data->retry);
Ed Tanous167e2372018-05-07 11:59:10 -0700195 r = sd_event_add_time(wait->loop, &data->event_source, CLOCK_MONOTONIC,
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700196 next_retry, 0, async_wait_timeout_callback, data);
197 ++data->retry;
Ed Tanous167e2372018-05-07 11:59:10 -0700198 if (r < 0)
199 {
200 async_wait_done(r, wait);
201 goto exit;
202 }
Brad Bishop3d468792016-09-20 15:39:38 -0400203
Ed Tanous167e2372018-05-07 11:59:10 -0700204 return 0;
205 }
Brad Bishop3d468792016-09-20 15:39:38 -0400206
Ed Tanous167e2372018-05-07 11:59:10 -0700207 if (r)
208 {
209 async_wait_done(-r, wait);
210 goto exit;
211 }
Brad Bishop3d468792016-09-20 15:39:38 -0400212
Ed Tanous167e2372018-05-07 11:59:10 -0700213 for (i = 0; i < wait->count; ++i)
214 {
215 if (!strcmp(data->path, wait->objs[i]))
216 {
217 wait->status[i] = 1;
218 }
219 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400220
Ed Tanous167e2372018-05-07 11:59:10 -0700221 if (async_wait_check_done(wait))
222 async_wait_done(0, wait);
Brad Bishop2afe7182016-08-13 14:08:17 -0400223
Brad Bishop3d468792016-09-20 15:39:38 -0400224exit:
Ed Tanous167e2372018-05-07 11:59:10 -0700225 free(data);
226 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400227}
228
229static int async_wait_get_objects(mapper_async_wait *wait)
230{
Ed Tanous167e2372018-05-07 11:59:10 -0700231 int i, r;
232 struct async_wait_callback_data *data = NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400233
Ed Tanous167e2372018-05-07 11:59:10 -0700234 for (i = 0; i < wait->count; ++i)
235 {
236 if (wait->status[i])
237 continue;
238 data = malloc(sizeof(*data));
239 data->wait = wait;
240 data->path = wait->objs[i];
241 data->retry = 0;
242 data->event_source = NULL;
243 r = sd_bus_call_method_async(wait->conn, NULL, MAPPER_BUSNAME,
244 MAPPER_PATH, MAPPER_INTERFACE, "GetObject",
245 async_wait_getobject_callback, data, "sas",
246 wait->objs[i], 0, NULL);
247 if (r < 0)
248 {
249 free(data);
250 fprintf(stderr, "Error invoking method: %s\n", strerror(-r));
251 return r;
252 }
253 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400254
Ed Tanous167e2372018-05-07 11:59:10 -0700255 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400256}
257
Brad Bishop829181d2017-02-24 09:49:14 -0500258static int async_wait_match_introspection_complete(sd_bus_message *m, void *w,
Ed Tanous167e2372018-05-07 11:59:10 -0700259 sd_bus_error *e)
Brad Bishop2afe7182016-08-13 14:08:17 -0400260{
Ed Tanous167e2372018-05-07 11:59:10 -0700261 int r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400262
Ed Tanous167e2372018-05-07 11:59:10 -0700263 mapper_async_wait *wait = w;
264 if (wait->finished)
265 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400266
Ed Tanous167e2372018-05-07 11:59:10 -0700267 r = async_wait_get_objects(wait);
268 if (r < 0)
269 async_wait_done(r, wait);
Brad Bishop2afe7182016-08-13 14:08:17 -0400270
Ed Tanous167e2372018-05-07 11:59:10 -0700271 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400272}
273
Brad Bishop2afe7182016-08-13 14:08:17 -0400274static void async_wait_done(int r, mapper_async_wait *w)
275{
Ed Tanous167e2372018-05-07 11:59:10 -0700276 if (w->finished)
277 return;
Brad Bishop2afe7182016-08-13 14:08:17 -0400278
Ed Tanous167e2372018-05-07 11:59:10 -0700279 w->finished = 1;
280 sd_bus_slot_unref(w->introspection_slot);
281 sd_bus_slot_unref(w->intf_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400282
Ed Tanous167e2372018-05-07 11:59:10 -0700283 if (w->callback)
284 w->callback(r, w->userdata);
Brad Bishop2afe7182016-08-13 14:08:17 -0400285}
286
287static int async_wait_check_done(mapper_async_wait *w)
288{
Ed Tanous167e2372018-05-07 11:59:10 -0700289 int i;
Brad Bishop2afe7182016-08-13 14:08:17 -0400290
Ed Tanous167e2372018-05-07 11:59:10 -0700291 if (w->finished)
292 return 1;
Brad Bishop2afe7182016-08-13 14:08:17 -0400293
Ed Tanous167e2372018-05-07 11:59:10 -0700294 for (i = 0; i < w->count; ++i)
295 if (!w->status[i])
296 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400297
Ed Tanous167e2372018-05-07 11:59:10 -0700298 return 1;
Brad Bishop2afe7182016-08-13 14:08:17 -0400299}
300
301void mapper_wait_async_free(mapper_async_wait *w)
302{
Ed Tanous167e2372018-05-07 11:59:10 -0700303 free(w->status);
304 sarrayfree(w->objs);
305 free(w);
Brad Bishop2afe7182016-08-13 14:08:17 -0400306}
307
Ed Tanous167e2372018-05-07 11:59:10 -0700308int mapper_wait_async(sd_bus *conn, sd_event *loop, char *objs[],
309 void (*callback)(int, void *), void *userdata,
310 mapper_async_wait **w)
Brad Bishop2afe7182016-08-13 14:08:17 -0400311{
Ed Tanous167e2372018-05-07 11:59:10 -0700312 int r;
313 mapper_async_wait *wait = NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400314
Ed Tanous167e2372018-05-07 11:59:10 -0700315 wait = malloc(sizeof(*wait));
316 if (!wait)
317 return -ENOMEM;
Brad Bishop2afe7182016-08-13 14:08:17 -0400318
Ed Tanous167e2372018-05-07 11:59:10 -0700319 memset(wait, 0, sizeof(*wait));
320 wait->conn = conn;
321 wait->loop = loop;
322 wait->callback = callback;
323 wait->userdata = userdata;
324 wait->count = sarraylen(objs);
325 if (!wait->count)
326 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400327
Ed Tanous167e2372018-05-07 11:59:10 -0700328 wait->objs = sarraydup(objs);
329 if (!wait->objs)
330 {
331 r = -ENOMEM;
332 goto free_wait;
333 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400334
Ed Tanous167e2372018-05-07 11:59:10 -0700335 wait->status = malloc(sizeof(*wait->status) * wait->count);
336 if (!wait->status)
337 {
338 r = -ENOMEM;
339 goto free_objs;
340 }
341 memset(wait->status, 0, sizeof(*wait->status) * wait->count);
Brad Bishop2afe7182016-08-13 14:08:17 -0400342
Ed Tanous167e2372018-05-07 11:59:10 -0700343 r = sd_bus_add_match(conn, &wait->introspection_slot,
344 async_wait_introspection_match,
345 async_wait_match_introspection_complete, wait);
346 if (r < 0)
347 {
348 fprintf(stderr, "Error adding match rule: %s\n", strerror(-r));
349 goto free_status;
350 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400351
Ed Tanous167e2372018-05-07 11:59:10 -0700352 r = sd_bus_add_match(conn, &wait->intf_slot,
353 async_wait_interfaces_added_match,
354 async_wait_match_introspection_complete, wait);
355 if (r < 0)
356 {
357 fprintf(stderr, "Error adding match rule: %s\n", strerror(-r));
358 goto unref_name_slot;
359 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400360
Ed Tanous167e2372018-05-07 11:59:10 -0700361 r = async_wait_get_objects(wait);
362 if (r < 0)
363 {
364 fprintf(stderr, "Error calling method: %s\n", strerror(-r));
365 goto unref_intf_slot;
366 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400367
Ed Tanous167e2372018-05-07 11:59:10 -0700368 *w = wait;
Brad Bishop2afe7182016-08-13 14:08:17 -0400369
Ed Tanous167e2372018-05-07 11:59:10 -0700370 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400371
372unref_intf_slot:
Ed Tanous167e2372018-05-07 11:59:10 -0700373 sd_bus_slot_unref(wait->intf_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400374unref_name_slot:
Ed Tanous167e2372018-05-07 11:59:10 -0700375 sd_bus_slot_unref(wait->introspection_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400376free_status:
Ed Tanous167e2372018-05-07 11:59:10 -0700377 free(wait->status);
Brad Bishop2afe7182016-08-13 14:08:17 -0400378free_objs:
Ed Tanous167e2372018-05-07 11:59:10 -0700379 sarrayfree(wait->objs);
Brad Bishop2afe7182016-08-13 14:08:17 -0400380free_wait:
Ed Tanous167e2372018-05-07 11:59:10 -0700381 free(wait);
Brad Bishop2afe7182016-08-13 14:08:17 -0400382
Ed Tanous167e2372018-05-07 11:59:10 -0700383 return r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400384}
385
Ed Tanous167e2372018-05-07 11:59:10 -0700386static int async_subtree_timeout_callback(sd_event_source *s, uint64_t usec,
387 void *userdata)
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500388{
Ed Tanous167e2372018-05-07 11:59:10 -0700389 int r;
390 struct mapper_async_subtree *subtree = userdata;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500391
Ed Tanous167e2372018-05-07 11:59:10 -0700392 sd_event_source_unref(subtree->event_source);
393 r = sd_bus_call_method_async(
394 subtree->conn, NULL, MAPPER_BUSNAME, MAPPER_PATH, MAPPER_INTERFACE,
395 "GetSubTreePaths", async_subtree_getpaths_callback, subtree, "sias",
396 subtree->namespace, 0, 1, subtree->interface);
397 if (r < 0)
398 async_subtree_done(r, subtree);
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500399
Ed Tanous167e2372018-05-07 11:59:10 -0700400 return 0;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500401}
402
Ed Tanous167e2372018-05-07 11:59:10 -0700403static int async_subtree_getpaths_callback(sd_bus_message *m, void *userdata,
404 sd_bus_error *e)
Adriana Kobylak025d7952017-05-08 13:30:45 -0500405{
Ed Tanous167e2372018-05-07 11:59:10 -0700406 int r;
Ed Tanous167e2372018-05-07 11:59:10 -0700407 struct mapper_async_subtree *subtree = userdata;
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700408 uint64_t next_retry;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500409
Ed Tanous167e2372018-05-07 11:59:10 -0700410 if (subtree->finished)
411 goto exit;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500412
Ed Tanous167e2372018-05-07 11:59:10 -0700413 r = sd_bus_message_get_errno(m);
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500414
Ed Tanous167e2372018-05-07 11:59:10 -0700415 if (r == ENOENT)
416 {
417 if (subtree->op == MAPPER_OP_REMOVE)
418 r = 0;
419 else
420 goto exit;
421 }
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500422
Ed Tanous167e2372018-05-07 11:59:10 -0700423 if (r == EBUSY && subtree->retry < mapper_busy_retries)
424 {
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700425 r = sd_event_now(subtree->loop, CLOCK_MONOTONIC, &next_retry);
Ed Tanous167e2372018-05-07 11:59:10 -0700426 if (r < 0)
427 {
428 async_subtree_done(r, subtree);
429 goto exit;
430 }
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500431
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700432 next_retry += mapper_busy_delay_interval_usec * (1 << subtree->retry);
Ed Tanous167e2372018-05-07 11:59:10 -0700433 r = sd_event_add_time(subtree->loop, &subtree->event_source,
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700434 CLOCK_MONOTONIC, next_retry, 0,
Ed Tanous167e2372018-05-07 11:59:10 -0700435 async_subtree_timeout_callback, subtree);
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700436 ++subtree->retry;
Ed Tanous167e2372018-05-07 11:59:10 -0700437 if (r < 0)
438 {
439 async_subtree_done(r, subtree);
440 goto exit;
441 }
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500442
Ed Tanous167e2372018-05-07 11:59:10 -0700443 return 0;
444 }
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500445
Ed Tanous167e2372018-05-07 11:59:10 -0700446 if (r)
447 {
448 async_subtree_done(-r, subtree);
449 goto exit;
450 }
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500451
Ed Tanous167e2372018-05-07 11:59:10 -0700452 if (subtree->op == MAPPER_OP_REMOVE)
453 {
William A. Kennington III20cbbfb2018-06-15 10:10:13 -0700454 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
455 if (r < 0)
456 {
457 async_subtree_done(r, subtree);
458 goto exit;
459 }
460
461 r = sd_bus_message_at_end(m, false);
462 if (r < 0)
463 {
464 async_subtree_done(r, subtree);
465 goto exit;
466 }
467
Ed Tanous167e2372018-05-07 11:59:10 -0700468 /* For remove, operation is complete when the interface is not present
William A. Kennington III20cbbfb2018-06-15 10:10:13 -0700469 * we know it is empty if the returned array is empty
Ed Tanous167e2372018-05-07 11:59:10 -0700470 */
William A. Kennington III20cbbfb2018-06-15 10:10:13 -0700471 if (r)
Ed Tanous167e2372018-05-07 11:59:10 -0700472 async_subtree_done(0, subtree);
473 }
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500474
475exit:
Ed Tanous167e2372018-05-07 11:59:10 -0700476 return 0;
Adriana Kobylak025d7952017-05-08 13:30:45 -0500477}
478
479static int async_subtree_getpaths(mapper_async_subtree *subtree)
480{
Ed Tanous167e2372018-05-07 11:59:10 -0700481 int r = 0;
Adriana Kobylak025d7952017-05-08 13:30:45 -0500482
Ed Tanous167e2372018-05-07 11:59:10 -0700483 subtree->retry = 0;
484 subtree->event_source = NULL;
485 r = sd_bus_call_method_async(
486 subtree->conn, NULL, MAPPER_BUSNAME, MAPPER_PATH, MAPPER_INTERFACE,
487 "GetSubTreePaths", async_subtree_getpaths_callback, subtree, "sias",
488 subtree->namespace, 0, 1, subtree->interface);
489 if (r < 0)
490 {
491 fprintf(stderr, "Error invoking method: %s\n", strerror(-r));
492 return r;
493 }
Adriana Kobylak025d7952017-05-08 13:30:45 -0500494
Ed Tanous167e2372018-05-07 11:59:10 -0700495 return 0;
Adriana Kobylak025d7952017-05-08 13:30:45 -0500496}
497
Ed Tanous167e2372018-05-07 11:59:10 -0700498static int async_subtree_match_callback(sd_bus_message *m, void *t,
499 sd_bus_error *e)
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500500{
Ed Tanous167e2372018-05-07 11:59:10 -0700501 int r;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500502
Ed Tanous167e2372018-05-07 11:59:10 -0700503 mapper_async_subtree *subtree = t;
504 if (subtree->finished)
505 return 0;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500506
Ed Tanous167e2372018-05-07 11:59:10 -0700507 r = async_subtree_getpaths(subtree);
508 if (r < 0)
509 async_subtree_done(r, subtree);
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500510
Ed Tanous167e2372018-05-07 11:59:10 -0700511 return 0;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500512}
513
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500514static void async_subtree_done(int r, mapper_async_subtree *t)
515{
Ed Tanous167e2372018-05-07 11:59:10 -0700516 if (t->finished)
517 return;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500518
Ed Tanous167e2372018-05-07 11:59:10 -0700519 t->finished = 1;
520 sd_bus_slot_unref(t->slot);
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500521
Ed Tanous167e2372018-05-07 11:59:10 -0700522 if (t->callback)
523 t->callback(r, t->userdata);
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500524}
525
Ed Tanous167e2372018-05-07 11:59:10 -0700526int mapper_subtree_async(sd_bus *conn, sd_event *loop, char *namespace,
527 char *interface, void (*callback)(int, void *),
528 void *userdata, mapper_async_subtree **t, int op)
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -0500529{
Ed Tanous167e2372018-05-07 11:59:10 -0700530 int r = 0;
531 mapper_async_subtree *subtree = NULL;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500532
Ed Tanous167e2372018-05-07 11:59:10 -0700533 subtree = malloc(sizeof(*subtree));
534 if (!subtree)
535 return -ENOMEM;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500536
Ed Tanous167e2372018-05-07 11:59:10 -0700537 memset(subtree, 0, sizeof(*subtree));
538 subtree->conn = conn;
539 subtree->loop = loop;
540 subtree->namespace = namespace;
541 subtree->interface = interface;
542 subtree->callback = callback;
543 subtree->userdata = userdata;
544 subtree->op = op;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500545
Ed Tanous167e2372018-05-07 11:59:10 -0700546 if (subtree->op == MAPPER_OP_REMOVE)
547 {
548 r = sd_bus_add_match(conn, &subtree->slot, interfaces_removed_match,
549 async_subtree_match_callback, subtree);
550 if (r < 0)
551 {
552 fprintf(stderr, "Error adding match rule: %s\n", strerror(-r));
553 goto unref_slot;
554 }
555 }
556 else
557 {
558 /* Operation not supported */
559 r = -EINVAL;
560 goto free_subtree;
561 }
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500562
Ed Tanous167e2372018-05-07 11:59:10 -0700563 r = async_subtree_getpaths(subtree);
564 if (r < 0)
565 {
566 fprintf(stderr, "Error calling method: %s\n", strerror(-r));
567 goto unref_slot;
568 }
Adriana Kobylak025d7952017-05-08 13:30:45 -0500569
Ed Tanous167e2372018-05-07 11:59:10 -0700570 *t = subtree;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500571
Ed Tanous167e2372018-05-07 11:59:10 -0700572 return 0;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500573
574unref_slot:
Ed Tanous167e2372018-05-07 11:59:10 -0700575 sd_bus_slot_unref(subtree->slot);
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500576free_subtree:
Ed Tanous167e2372018-05-07 11:59:10 -0700577 free(subtree);
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -0500578
Ed Tanous167e2372018-05-07 11:59:10 -0700579 return r;
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -0500580}
581
Brad Bishop3d468792016-09-20 15:39:38 -0400582int mapper_get_object(sd_bus *conn, const char *obj, sd_bus_message **reply)
Brad Bishop62ece2b2016-07-25 09:00:51 -0400583{
Ed Tanous167e2372018-05-07 11:59:10 -0700584 sd_bus_error error = SD_BUS_ERROR_NULL;
585 sd_bus_message *request = NULL;
586 int r, retry = 0;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400587
Ed Tanous167e2372018-05-07 11:59:10 -0700588 r = sd_bus_message_new_method_call(conn, &request, MAPPER_BUSNAME,
589 MAPPER_PATH, MAPPER_INTERFACE,
590 "GetObject");
591 if (r < 0)
592 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400593
Ed Tanous167e2372018-05-07 11:59:10 -0700594 r = sd_bus_message_append(request, "s", obj);
595 if (r < 0)
596 goto exit;
597 r = sd_bus_message_append(request, "as", 0, NULL);
598 if (r < 0)
599 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400600
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700601 while (true)
Ed Tanous167e2372018-05-07 11:59:10 -0700602 {
603 sd_bus_error_free(&error);
604 r = sd_bus_call(conn, request, 0, &error, reply);
605 if (r < 0 && sd_bus_error_get_errno(&error) == EBUSY)
606 {
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700607 if (retry >= mapper_busy_retries)
608 break;
Brad Bishop3d468792016-09-20 15:39:38 -0400609
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700610 usleep(mapper_busy_delay_interval_usec * (1 << retry));
611 ++retry;
Ed Tanous167e2372018-05-07 11:59:10 -0700612 continue;
613 }
614 break;
615 }
Brad Bishop3d468792016-09-20 15:39:38 -0400616
Ed Tanous167e2372018-05-07 11:59:10 -0700617 if (r < 0)
618 goto exit;
Brad Bishop3d468792016-09-20 15:39:38 -0400619
620exit:
Ed Tanous167e2372018-05-07 11:59:10 -0700621 sd_bus_error_free(&error);
622 sd_bus_message_unref(request);
Brad Bishop3d468792016-09-20 15:39:38 -0400623
Ed Tanous167e2372018-05-07 11:59:10 -0700624 return r;
Brad Bishop3d468792016-09-20 15:39:38 -0400625}
626
627int mapper_get_service(sd_bus *conn, const char *obj, char **service)
628{
Ed Tanous167e2372018-05-07 11:59:10 -0700629 sd_bus_message *reply = NULL;
630 const char *tmp;
631 int r;
Brad Bishop3d468792016-09-20 15:39:38 -0400632
Ed Tanous167e2372018-05-07 11:59:10 -0700633 r = mapper_get_object(conn, obj, &reply);
634 if (r < 0)
635 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400636
Ed Tanous167e2372018-05-07 11:59:10 -0700637 r = sd_bus_message_enter_container(reply, 0, NULL);
638 if (r < 0)
639 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400640
Ed Tanous167e2372018-05-07 11:59:10 -0700641 r = sd_bus_message_enter_container(reply, 0, NULL);
642 if (r < 0)
643 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400644
Ed Tanous167e2372018-05-07 11:59:10 -0700645 r = sd_bus_message_read(reply, "s", &tmp);
646 if (r < 0)
647 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400648
Ed Tanous167e2372018-05-07 11:59:10 -0700649 *service = strdup(tmp);
Brad Bishop62ece2b2016-07-25 09:00:51 -0400650
651exit:
Ed Tanous167e2372018-05-07 11:59:10 -0700652 sd_bus_message_unref(reply);
Brad Bishop62ece2b2016-07-25 09:00:51 -0400653
Ed Tanous167e2372018-05-07 11:59:10 -0700654 return r;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400655}