blob: 4b69ac22a31c0dabf0c556251e19cd5d47b038fd [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"
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050017
18#include "mapper.h"
19
20#include <errno.h>
William A. Kennington III20cbbfb2018-06-15 10:10:13 -070021#include <stdbool.h>
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050022#include <stdio.h>
Brad Bishop2afe7182016-08-13 14:08:17 -040023#include <stdlib.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040024#include <string.h>
Brad Bishop3d468792016-09-20 15:39:38 -040025#include <sys/timerfd.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040026#include <systemd/sd-bus.h>
Brad Bishop3d468792016-09-20 15:39:38 -040027#include <systemd/sd-event.h>
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050028#include <unistd.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040029
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050030static const char* async_wait_introspection_match =
Ed Tanous167e2372018-05-07 11:59:10 -070031 "type='signal',"
32 "sender='xyz.openbmc_project.ObjectMapper',"
33 "interface='xyz.openbmc_project.ObjectMapper.Private',"
34 "member='IntrospectionComplete'";
Brad Bishop2afe7182016-08-13 14:08:17 -040035
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050036static const char* async_wait_interfaces_added_match =
Ed Tanous167e2372018-05-07 11:59:10 -070037 "type='signal',"
38 "interface='org.freedesktop.DBus.ObjectManager',"
39 "member='InterfacesAdded'";
Brad Bishop2afe7182016-08-13 14:08:17 -040040
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050041static const char* interfaces_removed_match =
Ed Tanous167e2372018-05-07 11:59:10 -070042 "type='signal',"
43 "interface='org.freedesktop.DBus.ObjectManager',"
44 "member='InterfacesRemoved'";
Adriana Kobylak78edbb62017-05-04 15:45:19 -050045
Brad Bishop3d468792016-09-20 15:39:38 -040046static const int mapper_busy_retries = 5;
47static const uint64_t mapper_busy_delay_interval_usec = 1000000;
48
Brad Bishop2afe7182016-08-13 14:08:17 -040049struct mapper_async_wait
50{
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050051 char** objs;
52 void (*callback)(int, void*);
53 void* userdata;
54 sd_event* loop;
55 sd_bus* conn;
56 sd_bus_slot* introspection_slot;
57 sd_bus_slot* intf_slot;
58 int* status;
Ed Tanous167e2372018-05-07 11:59:10 -070059 int count;
60 int finished;
61 int r;
Brad Bishop2afe7182016-08-13 14:08:17 -040062};
63
64struct async_wait_callback_data
65{
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050066 mapper_async_wait* wait;
67 const char* path;
68 sd_event_source* event_source;
Ed Tanous167e2372018-05-07 11:59:10 -070069 int retry;
Brad Bishop2afe7182016-08-13 14:08:17 -040070};
71
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -050072struct mapper_async_subtree
73{
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050074 char* namespace;
75 char* interface;
76 void (*callback)(int, void*);
77 void* userdata;
78 sd_event* loop;
79 sd_bus* conn;
80 sd_bus_slot* slot;
81 sd_event_source* event_source;
Ed Tanous167e2372018-05-07 11:59:10 -070082 int finished;
83 int op;
84 int retry;
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -050085};
86
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050087static int async_wait_match_introspection_complete(sd_bus_message*, void*,
88 sd_bus_error*);
89static int async_wait_check_done(mapper_async_wait*);
90static void async_wait_done(int r, mapper_async_wait*);
91static int async_wait_get_objects(mapper_async_wait*);
92static int async_wait_getobject_callback(sd_bus_message*, void*, sd_bus_error*);
Brad Bishop2afe7182016-08-13 14:08:17 -040093
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050094static int async_subtree_match_callback(sd_bus_message*, void*, sd_bus_error*);
95static void async_subtree_done(int r, mapper_async_subtree*);
96static int async_subtree_getpaths(mapper_async_subtree*);
97static int async_subtree_getpaths_callback(sd_bus_message*, void*,
98 sd_bus_error*);
Adriana Kobylak78edbb62017-05-04 15:45:19 -050099
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500100static int sarraylen(char* array[])
Brad Bishop2afe7182016-08-13 14:08:17 -0400101{
Ed Tanous167e2372018-05-07 11:59:10 -0700102 int count = 0;
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500103 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
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500114static void sarrayfree(char* array[])
Brad Bishop2afe7182016-08-13 14:08:17 -0400115{
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500116 char** p = array;
Ed Tanous167e2372018-05-07 11:59:10 -0700117 while (*p != NULL)
118 {
119 free(*p);
120 ++p;
121 }
122 free(array);
Brad Bishop2afe7182016-08-13 14:08:17 -0400123}
124
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500125static char** sarraydup(char* array[])
Brad Bishop2afe7182016-08-13 14:08:17 -0400126{
Ed Tanous167e2372018-05-07 11:59:10 -0700127 int count = sarraylen(array);
128 int i;
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500129 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
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500149static 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;
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500153 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
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500170static 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;
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500174 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
Patrick Williamse82b0582020-11-16 16:25:20 -0600181 if (sd_bus_message_is_method_error(
182 m, "xyz.openbmc_project.Common.Error.ResourceNotFound"))
Ed Tanous167e2372018-05-07 11:59:10 -0700183 goto exit;
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400184
Patrick Williamse82b0582020-11-16 16:25:20 -0600185 r = sd_bus_message_get_errno(m);
186
William A. Kennington III24829462018-06-15 10:10:25 -0700187 if ((r == EBUSY || r == ENOBUFS) && data->retry < mapper_busy_retries)
Ed Tanous167e2372018-05-07 11:59:10 -0700188 {
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700189 r = sd_event_now(wait->loop, CLOCK_MONOTONIC, &next_retry);
Ed Tanous167e2372018-05-07 11:59:10 -0700190 if (r < 0)
191 {
192 async_wait_done(r, wait);
193 goto exit;
194 }
Brad Bishop3d468792016-09-20 15:39:38 -0400195
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700196 next_retry += mapper_busy_delay_interval_usec * (1 << data->retry);
Ed Tanous167e2372018-05-07 11:59:10 -0700197 r = sd_event_add_time(wait->loop, &data->event_source, CLOCK_MONOTONIC,
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700198 next_retry, 0, async_wait_timeout_callback, data);
199 ++data->retry;
Ed Tanous167e2372018-05-07 11:59:10 -0700200 if (r < 0)
201 {
202 async_wait_done(r, wait);
203 goto exit;
204 }
Brad Bishop3d468792016-09-20 15:39:38 -0400205
Ed Tanous167e2372018-05-07 11:59:10 -0700206 return 0;
207 }
Brad Bishop3d468792016-09-20 15:39:38 -0400208
Ed Tanous167e2372018-05-07 11:59:10 -0700209 if (r)
210 {
211 async_wait_done(-r, wait);
212 goto exit;
213 }
Brad Bishop3d468792016-09-20 15:39:38 -0400214
Ed Tanous167e2372018-05-07 11:59:10 -0700215 for (i = 0; i < wait->count; ++i)
216 {
217 if (!strcmp(data->path, wait->objs[i]))
218 {
219 wait->status[i] = 1;
220 }
221 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400222
Ed Tanous167e2372018-05-07 11:59:10 -0700223 if (async_wait_check_done(wait))
224 async_wait_done(0, wait);
Brad Bishop2afe7182016-08-13 14:08:17 -0400225
Brad Bishop3d468792016-09-20 15:39:38 -0400226exit:
Ed Tanous167e2372018-05-07 11:59:10 -0700227 free(data);
228 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400229}
230
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500231static int async_wait_get_objects(mapper_async_wait* wait)
Brad Bishop2afe7182016-08-13 14:08:17 -0400232{
Ed Tanous167e2372018-05-07 11:59:10 -0700233 int i, r;
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500234 struct async_wait_callback_data* data = NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400235
Ed Tanous167e2372018-05-07 11:59:10 -0700236 for (i = 0; i < wait->count; ++i)
237 {
238 if (wait->status[i])
239 continue;
240 data = malloc(sizeof(*data));
241 data->wait = wait;
242 data->path = wait->objs[i];
243 data->retry = 0;
244 data->event_source = NULL;
245 r = sd_bus_call_method_async(wait->conn, NULL, MAPPER_BUSNAME,
246 MAPPER_PATH, MAPPER_INTERFACE, "GetObject",
247 async_wait_getobject_callback, data, "sas",
248 wait->objs[i], 0, NULL);
249 if (r < 0)
250 {
251 free(data);
252 fprintf(stderr, "Error invoking method: %s\n", strerror(-r));
253 return r;
254 }
255 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400256
Ed Tanous167e2372018-05-07 11:59:10 -0700257 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400258}
259
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500260static int async_wait_match_introspection_complete(sd_bus_message* m, void* w,
261 sd_bus_error* e)
Brad Bishop2afe7182016-08-13 14:08:17 -0400262{
Ed Tanous167e2372018-05-07 11:59:10 -0700263 int r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400264
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500265 mapper_async_wait* wait = w;
Ed Tanous167e2372018-05-07 11:59:10 -0700266 if (wait->finished)
267 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400268
Ed Tanous167e2372018-05-07 11:59:10 -0700269 r = async_wait_get_objects(wait);
270 if (r < 0)
271 async_wait_done(r, wait);
Brad Bishop2afe7182016-08-13 14:08:17 -0400272
Ed Tanous167e2372018-05-07 11:59:10 -0700273 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400274}
275
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500276static void async_wait_done(int r, mapper_async_wait* w)
Brad Bishop2afe7182016-08-13 14:08:17 -0400277{
Ed Tanous167e2372018-05-07 11:59:10 -0700278 if (w->finished)
279 return;
Brad Bishop2afe7182016-08-13 14:08:17 -0400280
Ed Tanous167e2372018-05-07 11:59:10 -0700281 w->finished = 1;
282 sd_bus_slot_unref(w->introspection_slot);
283 sd_bus_slot_unref(w->intf_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400284
Ed Tanous167e2372018-05-07 11:59:10 -0700285 if (w->callback)
286 w->callback(r, w->userdata);
Brad Bishop2afe7182016-08-13 14:08:17 -0400287}
288
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500289static int async_wait_check_done(mapper_async_wait* w)
Brad Bishop2afe7182016-08-13 14:08:17 -0400290{
Ed Tanous167e2372018-05-07 11:59:10 -0700291 int i;
Brad Bishop2afe7182016-08-13 14:08:17 -0400292
Ed Tanous167e2372018-05-07 11:59:10 -0700293 if (w->finished)
294 return 1;
Brad Bishop2afe7182016-08-13 14:08:17 -0400295
Ed Tanous167e2372018-05-07 11:59:10 -0700296 for (i = 0; i < w->count; ++i)
297 if (!w->status[i])
298 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400299
Ed Tanous167e2372018-05-07 11:59:10 -0700300 return 1;
Brad Bishop2afe7182016-08-13 14:08:17 -0400301}
302
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500303void mapper_wait_async_free(mapper_async_wait* w)
Brad Bishop2afe7182016-08-13 14:08:17 -0400304{
Ed Tanous167e2372018-05-07 11:59:10 -0700305 free(w->status);
306 sarrayfree(w->objs);
307 free(w);
Brad Bishop2afe7182016-08-13 14:08:17 -0400308}
309
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500310int mapper_wait_async(sd_bus* conn, sd_event* loop, char* objs[],
311 void (*callback)(int, void*), void* userdata,
312 mapper_async_wait** w)
Brad Bishop2afe7182016-08-13 14:08:17 -0400313{
Ed Tanous167e2372018-05-07 11:59:10 -0700314 int r;
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500315 mapper_async_wait* wait = NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400316
Ed Tanous167e2372018-05-07 11:59:10 -0700317 wait = malloc(sizeof(*wait));
318 if (!wait)
319 return -ENOMEM;
Brad Bishop2afe7182016-08-13 14:08:17 -0400320
Ed Tanous167e2372018-05-07 11:59:10 -0700321 memset(wait, 0, sizeof(*wait));
322 wait->conn = conn;
323 wait->loop = loop;
324 wait->callback = callback;
325 wait->userdata = userdata;
326 wait->count = sarraylen(objs);
327 if (!wait->count)
328 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400329
Ed Tanous167e2372018-05-07 11:59:10 -0700330 wait->objs = sarraydup(objs);
331 if (!wait->objs)
332 {
333 r = -ENOMEM;
334 goto free_wait;
335 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400336
Ed Tanous167e2372018-05-07 11:59:10 -0700337 wait->status = malloc(sizeof(*wait->status) * wait->count);
338 if (!wait->status)
339 {
340 r = -ENOMEM;
341 goto free_objs;
342 }
343 memset(wait->status, 0, sizeof(*wait->status) * wait->count);
Brad Bishop2afe7182016-08-13 14:08:17 -0400344
Ed Tanous167e2372018-05-07 11:59:10 -0700345 r = sd_bus_add_match(conn, &wait->introspection_slot,
346 async_wait_introspection_match,
347 async_wait_match_introspection_complete, wait);
348 if (r < 0)
349 {
350 fprintf(stderr, "Error adding match rule: %s\n", strerror(-r));
351 goto free_status;
352 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400353
Ed Tanous167e2372018-05-07 11:59:10 -0700354 r = sd_bus_add_match(conn, &wait->intf_slot,
355 async_wait_interfaces_added_match,
356 async_wait_match_introspection_complete, wait);
357 if (r < 0)
358 {
359 fprintf(stderr, "Error adding match rule: %s\n", strerror(-r));
360 goto unref_name_slot;
361 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400362
Ed Tanous167e2372018-05-07 11:59:10 -0700363 r = async_wait_get_objects(wait);
364 if (r < 0)
365 {
366 fprintf(stderr, "Error calling method: %s\n", strerror(-r));
367 goto unref_intf_slot;
368 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400369
Ed Tanous167e2372018-05-07 11:59:10 -0700370 *w = wait;
Brad Bishop2afe7182016-08-13 14:08:17 -0400371
Ed Tanous167e2372018-05-07 11:59:10 -0700372 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400373
374unref_intf_slot:
Ed Tanous167e2372018-05-07 11:59:10 -0700375 sd_bus_slot_unref(wait->intf_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400376unref_name_slot:
Ed Tanous167e2372018-05-07 11:59:10 -0700377 sd_bus_slot_unref(wait->introspection_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400378free_status:
Ed Tanous167e2372018-05-07 11:59:10 -0700379 free(wait->status);
Brad Bishop2afe7182016-08-13 14:08:17 -0400380free_objs:
Ed Tanous167e2372018-05-07 11:59:10 -0700381 sarrayfree(wait->objs);
Brad Bishop2afe7182016-08-13 14:08:17 -0400382free_wait:
Ed Tanous167e2372018-05-07 11:59:10 -0700383 free(wait);
Brad Bishop2afe7182016-08-13 14:08:17 -0400384
Ed Tanous167e2372018-05-07 11:59:10 -0700385 return r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400386}
387
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500388static int async_subtree_timeout_callback(sd_event_source* s, uint64_t usec,
389 void* userdata)
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500390{
Ed Tanous167e2372018-05-07 11:59:10 -0700391 int r;
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500392 struct mapper_async_subtree* subtree = userdata;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500393
Ed Tanous167e2372018-05-07 11:59:10 -0700394 sd_event_source_unref(subtree->event_source);
395 r = sd_bus_call_method_async(
396 subtree->conn, NULL, MAPPER_BUSNAME, MAPPER_PATH, MAPPER_INTERFACE,
397 "GetSubTreePaths", async_subtree_getpaths_callback, subtree, "sias",
398 subtree->namespace, 0, 1, subtree->interface);
399 if (r < 0)
400 async_subtree_done(r, subtree);
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500401
Ed Tanous167e2372018-05-07 11:59:10 -0700402 return 0;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500403}
404
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500405static int async_subtree_getpaths_callback(sd_bus_message* m, void* userdata,
406 sd_bus_error* e)
Adriana Kobylak025d7952017-05-08 13:30:45 -0500407{
Ed Tanous167e2372018-05-07 11:59:10 -0700408 int r;
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500409 struct mapper_async_subtree* subtree = userdata;
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700410 uint64_t next_retry;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500411
Ed Tanous167e2372018-05-07 11:59:10 -0700412 if (subtree->finished)
413 goto exit;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500414
Ed Tanous167e2372018-05-07 11:59:10 -0700415 r = sd_bus_message_get_errno(m);
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500416
Patrick Williamse82b0582020-11-16 16:25:20 -0600417 if (sd_bus_message_is_method_error(
418 m, "xyz.openbmc_project.Common.Error.ResourceNotFound"))
Ed Tanous167e2372018-05-07 11:59:10 -0700419 {
420 if (subtree->op == MAPPER_OP_REMOVE)
421 r = 0;
422 else
423 goto exit;
424 }
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500425
William A. Kennington III24829462018-06-15 10:10:25 -0700426 if ((r == EBUSY || r == ENOBUFS) && subtree->retry < mapper_busy_retries)
Ed Tanous167e2372018-05-07 11:59:10 -0700427 {
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700428 r = sd_event_now(subtree->loop, CLOCK_MONOTONIC, &next_retry);
Ed Tanous167e2372018-05-07 11:59:10 -0700429 if (r < 0)
430 {
431 async_subtree_done(r, subtree);
432 goto exit;
433 }
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500434
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700435 next_retry += mapper_busy_delay_interval_usec * (1 << subtree->retry);
Ed Tanous167e2372018-05-07 11:59:10 -0700436 r = sd_event_add_time(subtree->loop, &subtree->event_source,
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700437 CLOCK_MONOTONIC, next_retry, 0,
Ed Tanous167e2372018-05-07 11:59:10 -0700438 async_subtree_timeout_callback, subtree);
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700439 ++subtree->retry;
Ed Tanous167e2372018-05-07 11:59:10 -0700440 if (r < 0)
441 {
442 async_subtree_done(r, subtree);
443 goto exit;
444 }
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500445
Ed Tanous167e2372018-05-07 11:59:10 -0700446 return 0;
447 }
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500448
Ed Tanous167e2372018-05-07 11:59:10 -0700449 if (r)
450 {
451 async_subtree_done(-r, subtree);
452 goto exit;
453 }
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500454
Ed Tanous167e2372018-05-07 11:59:10 -0700455 if (subtree->op == MAPPER_OP_REMOVE)
456 {
William A. Kennington III20cbbfb2018-06-15 10:10:13 -0700457 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
458 if (r < 0)
459 {
460 async_subtree_done(r, subtree);
461 goto exit;
462 }
463
464 r = sd_bus_message_at_end(m, false);
465 if (r < 0)
466 {
467 async_subtree_done(r, subtree);
468 goto exit;
469 }
470
Ed Tanous167e2372018-05-07 11:59:10 -0700471 /* For remove, operation is complete when the interface is not present
William A. Kennington III20cbbfb2018-06-15 10:10:13 -0700472 * we know it is empty if the returned array is empty
Ed Tanous167e2372018-05-07 11:59:10 -0700473 */
William A. Kennington III20cbbfb2018-06-15 10:10:13 -0700474 if (r)
Ed Tanous167e2372018-05-07 11:59:10 -0700475 async_subtree_done(0, subtree);
476 }
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500477
478exit:
Ed Tanous167e2372018-05-07 11:59:10 -0700479 return 0;
Adriana Kobylak025d7952017-05-08 13:30:45 -0500480}
481
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500482static int async_subtree_getpaths(mapper_async_subtree* subtree)
Adriana Kobylak025d7952017-05-08 13:30:45 -0500483{
Ed Tanous167e2372018-05-07 11:59:10 -0700484 int r = 0;
Adriana Kobylak025d7952017-05-08 13:30:45 -0500485
Ed Tanous167e2372018-05-07 11:59:10 -0700486 subtree->retry = 0;
487 subtree->event_source = NULL;
488 r = sd_bus_call_method_async(
489 subtree->conn, NULL, MAPPER_BUSNAME, MAPPER_PATH, MAPPER_INTERFACE,
490 "GetSubTreePaths", async_subtree_getpaths_callback, subtree, "sias",
491 subtree->namespace, 0, 1, subtree->interface);
492 if (r < 0)
493 {
494 fprintf(stderr, "Error invoking method: %s\n", strerror(-r));
495 return r;
496 }
Adriana Kobylak025d7952017-05-08 13:30:45 -0500497
Ed Tanous167e2372018-05-07 11:59:10 -0700498 return 0;
Adriana Kobylak025d7952017-05-08 13:30:45 -0500499}
500
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500501static int async_subtree_match_callback(sd_bus_message* m, void* t,
502 sd_bus_error* e)
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500503{
Ed Tanous167e2372018-05-07 11:59:10 -0700504 int r;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500505
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500506 mapper_async_subtree* subtree = t;
Ed Tanous167e2372018-05-07 11:59:10 -0700507 if (subtree->finished)
508 return 0;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500509
Ed Tanous167e2372018-05-07 11:59:10 -0700510 r = async_subtree_getpaths(subtree);
511 if (r < 0)
512 async_subtree_done(r, subtree);
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500513
Ed Tanous167e2372018-05-07 11:59:10 -0700514 return 0;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500515}
516
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500517static void async_subtree_done(int r, mapper_async_subtree* t)
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500518{
Ed Tanous167e2372018-05-07 11:59:10 -0700519 if (t->finished)
520 return;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500521
Ed Tanous167e2372018-05-07 11:59:10 -0700522 t->finished = 1;
523 sd_bus_slot_unref(t->slot);
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500524
Ed Tanous167e2372018-05-07 11:59:10 -0700525 if (t->callback)
526 t->callback(r, t->userdata);
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500527}
528
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500529int mapper_subtree_async(sd_bus* conn, sd_event* loop, char* namespace,
530 char* interface, void (*callback)(int, void*),
531 void* userdata, mapper_async_subtree** t, int op)
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -0500532{
Ed Tanous167e2372018-05-07 11:59:10 -0700533 int r = 0;
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500534 mapper_async_subtree* subtree = NULL;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500535
Ed Tanous167e2372018-05-07 11:59:10 -0700536 subtree = malloc(sizeof(*subtree));
537 if (!subtree)
538 return -ENOMEM;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500539
Ed Tanous167e2372018-05-07 11:59:10 -0700540 memset(subtree, 0, sizeof(*subtree));
541 subtree->conn = conn;
542 subtree->loop = loop;
543 subtree->namespace = namespace;
544 subtree->interface = interface;
545 subtree->callback = callback;
546 subtree->userdata = userdata;
547 subtree->op = op;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500548
Ed Tanous167e2372018-05-07 11:59:10 -0700549 if (subtree->op == MAPPER_OP_REMOVE)
550 {
551 r = sd_bus_add_match(conn, &subtree->slot, interfaces_removed_match,
552 async_subtree_match_callback, subtree);
553 if (r < 0)
554 {
555 fprintf(stderr, "Error adding match rule: %s\n", strerror(-r));
556 goto unref_slot;
557 }
558 }
559 else
560 {
561 /* Operation not supported */
562 r = -EINVAL;
563 goto free_subtree;
564 }
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500565
Ed Tanous167e2372018-05-07 11:59:10 -0700566 r = async_subtree_getpaths(subtree);
567 if (r < 0)
568 {
569 fprintf(stderr, "Error calling method: %s\n", strerror(-r));
570 goto unref_slot;
571 }
Adriana Kobylak025d7952017-05-08 13:30:45 -0500572
Ed Tanous167e2372018-05-07 11:59:10 -0700573 *t = subtree;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500574
Ed Tanous167e2372018-05-07 11:59:10 -0700575 return 0;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500576
577unref_slot:
Ed Tanous167e2372018-05-07 11:59:10 -0700578 sd_bus_slot_unref(subtree->slot);
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500579free_subtree:
Ed Tanous167e2372018-05-07 11:59:10 -0700580 free(subtree);
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -0500581
Ed Tanous167e2372018-05-07 11:59:10 -0700582 return r;
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -0500583}
584
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500585int mapper_get_object(sd_bus* conn, const char* obj, sd_bus_message** reply)
Brad Bishop62ece2b2016-07-25 09:00:51 -0400586{
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500587 sd_bus_message* request = NULL;
Ed Tanous167e2372018-05-07 11:59:10 -0700588 int r, retry = 0;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400589
Ed Tanous167e2372018-05-07 11:59:10 -0700590 r = sd_bus_message_new_method_call(conn, &request, MAPPER_BUSNAME,
591 MAPPER_PATH, MAPPER_INTERFACE,
592 "GetObject");
593 if (r < 0)
594 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400595
Ed Tanous167e2372018-05-07 11:59:10 -0700596 r = sd_bus_message_append(request, "s", obj);
597 if (r < 0)
598 goto exit;
599 r = sd_bus_message_append(request, "as", 0, NULL);
600 if (r < 0)
601 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400602
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700603 while (true)
Ed Tanous167e2372018-05-07 11:59:10 -0700604 {
William A. Kennington III24829462018-06-15 10:10:25 -0700605 r = sd_bus_call(conn, request, 0, NULL, reply);
606 if (r == -EBUSY || r == -ENOBUFS)
Ed Tanous167e2372018-05-07 11:59:10 -0700607 {
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700608 if (retry >= mapper_busy_retries)
609 break;
Brad Bishop3d468792016-09-20 15:39:38 -0400610
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700611 usleep(mapper_busy_delay_interval_usec * (1 << retry));
612 ++retry;
Ed Tanous167e2372018-05-07 11:59:10 -0700613 continue;
614 }
615 break;
616 }
Brad Bishop3d468792016-09-20 15:39:38 -0400617
Ed Tanous167e2372018-05-07 11:59:10 -0700618 if (r < 0)
619 goto exit;
Brad Bishop3d468792016-09-20 15:39:38 -0400620
621exit:
Ed Tanous167e2372018-05-07 11:59:10 -0700622 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
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500627int mapper_get_service(sd_bus* conn, const char* obj, char** service)
Brad Bishop3d468792016-09-20 15:39:38 -0400628{
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500629 sd_bus_message* reply = NULL;
630 const char* tmp;
Ed Tanous167e2372018-05-07 11:59:10 -0700631 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}