blob: 4a387905c452d690fbe7b67a35da0eeb54b7b83c [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 */
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050016#include "mapper.h"
17
18#include <errno.h>
William A. Kennington III20cbbfb2018-06-15 10:10:13 -070019#include <stdbool.h>
Brad Bishopa959f122021-08-03 11:21:01 -040020#include <stddef.h>
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050021#include <stdio.h>
Brad Bishop2afe7182016-08-13 14:08:17 -040022#include <stdlib.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040023#include <string.h>
Brad Bishop3d468792016-09-20 15:39:38 -040024#include <sys/timerfd.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040025#include <systemd/sd-bus.h>
Brad Bishop3d468792016-09-20 15:39:38 -040026#include <systemd/sd-event.h>
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050027#include <unistd.h>
Brad Bishop62ece2b2016-07-25 09:00:51 -040028
Brad Bishopa669a502021-08-03 16:01:43 -040029#include "internal.h"
30
Brad Bishop75057c82021-08-03 15:22:02 -040031#define _public_ __attribute__((__visibility__("default")))
Brad Bishop2d41d6a2021-08-03 08:14:45 -040032#define _unused_ __attribute__((unused))
Brad Bishop75057c82021-08-03 15:22:02 -040033
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050034static const char* async_wait_introspection_match =
Ed Tanous167e2372018-05-07 11:59:10 -070035 "type='signal',"
36 "sender='xyz.openbmc_project.ObjectMapper',"
37 "interface='xyz.openbmc_project.ObjectMapper.Private',"
38 "member='IntrospectionComplete'";
Brad Bishop2afe7182016-08-13 14:08:17 -040039
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050040static const char* async_wait_interfaces_added_match =
Ed Tanous167e2372018-05-07 11:59:10 -070041 "type='signal',"
42 "interface='org.freedesktop.DBus.ObjectManager',"
43 "member='InterfacesAdded'";
Brad Bishop2afe7182016-08-13 14:08:17 -040044
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050045static const char* interfaces_removed_match =
Ed Tanous167e2372018-05-07 11:59:10 -070046 "type='signal',"
47 "interface='org.freedesktop.DBus.ObjectManager',"
48 "member='InterfacesRemoved'";
Adriana Kobylak78edbb62017-05-04 15:45:19 -050049
Brad Bishop3d468792016-09-20 15:39:38 -040050static const int mapper_busy_retries = 5;
51static const uint64_t mapper_busy_delay_interval_usec = 1000000;
52
Brad Bishop2afe7182016-08-13 14:08:17 -040053struct mapper_async_wait
54{
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050055 char** objs;
56 void (*callback)(int, void*);
57 void* userdata;
58 sd_event* loop;
59 sd_bus* conn;
60 sd_bus_slot* introspection_slot;
61 sd_bus_slot* intf_slot;
62 int* status;
Brad Bishopa959f122021-08-03 11:21:01 -040063 size_t count;
Ed Tanous167e2372018-05-07 11:59:10 -070064 int finished;
65 int r;
Brad Bishop2afe7182016-08-13 14:08:17 -040066};
67
68struct async_wait_callback_data
69{
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050070 mapper_async_wait* wait;
71 const char* path;
72 sd_event_source* event_source;
Ed Tanous167e2372018-05-07 11:59:10 -070073 int retry;
Brad Bishop2afe7182016-08-13 14:08:17 -040074};
75
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -050076struct mapper_async_subtree
77{
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050078 char* namespace;
79 char* interface;
80 void (*callback)(int, void*);
81 void* userdata;
82 sd_event* loop;
83 sd_bus* conn;
84 sd_bus_slot* slot;
85 sd_event_source* event_source;
Ed Tanous167e2372018-05-07 11:59:10 -070086 int finished;
87 int op;
88 int retry;
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -050089};
90
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050091static int async_wait_match_introspection_complete(sd_bus_message*, void*,
92 sd_bus_error*);
93static int async_wait_check_done(mapper_async_wait*);
94static void async_wait_done(int r, mapper_async_wait*);
95static int async_wait_get_objects(mapper_async_wait*);
96static int async_wait_getobject_callback(sd_bus_message*, void*, sd_bus_error*);
Brad Bishop2afe7182016-08-13 14:08:17 -040097
Matt Spinlercc6ee9c2018-09-19 13:23:13 -050098static int async_subtree_match_callback(sd_bus_message*, void*, sd_bus_error*);
99static void async_subtree_done(int r, mapper_async_subtree*);
100static int async_subtree_getpaths(mapper_async_subtree*);
101static int async_subtree_getpaths_callback(sd_bus_message*, void*,
102 sd_bus_error*);
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500103
Brad Bishopa959f122021-08-03 11:21:01 -0400104size_t sarraylen(char* array[])
Brad Bishop2afe7182016-08-13 14:08:17 -0400105{
Brad Bishopa959f122021-08-03 11:21:01 -0400106 size_t count = 0;
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500107 char** p = array;
Brad Bishop2afe7182016-08-13 14:08:17 -0400108
Ed Tanous167e2372018-05-07 11:59:10 -0700109 while (*p != NULL)
110 {
111 ++count;
112 ++p;
113 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400114
Ed Tanous167e2372018-05-07 11:59:10 -0700115 return count;
Brad Bishop2afe7182016-08-13 14:08:17 -0400116}
117
Brad Bishopa669a502021-08-03 16:01:43 -0400118void sarrayfree(char* array[])
Brad Bishop2afe7182016-08-13 14:08:17 -0400119{
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500120 char** p = array;
Ed Tanous167e2372018-05-07 11:59:10 -0700121 while (*p != NULL)
122 {
123 free(*p);
124 ++p;
125 }
126 free(array);
Brad Bishop2afe7182016-08-13 14:08:17 -0400127}
128
Brad Bishopa669a502021-08-03 16:01:43 -0400129char** sarraydup(char* array[])
Brad Bishop2afe7182016-08-13 14:08:17 -0400130{
Brad Bishopa959f122021-08-03 11:21:01 -0400131 size_t count = sarraylen(array);
132 size_t i;
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500133 char** ret = NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400134
Brad Bishopa669a502021-08-03 16:01:43 -0400135 ret = calloc(count + 1, sizeof(*ret));
Ed Tanous167e2372018-05-07 11:59:10 -0700136 if (!ret)
137 return NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400138
Ed Tanous167e2372018-05-07 11:59:10 -0700139 for (i = 0; i < count; ++i)
140 {
141 ret[i] = strdup(array[i]);
142 if (!ret[i])
143 goto error;
144 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400145
Ed Tanous167e2372018-05-07 11:59:10 -0700146 return ret;
Brad Bishop2afe7182016-08-13 14:08:17 -0400147
148error:
Ed Tanous167e2372018-05-07 11:59:10 -0700149 sarrayfree(ret);
150 return NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400151}
152
Brad Bishop2d41d6a2021-08-03 08:14:45 -0400153static int async_wait_timeout_callback(_unused_ sd_event_source* s,
154 _unused_ uint64_t usec, void* userdata)
Brad Bishop3d468792016-09-20 15:39:38 -0400155{
Ed Tanous167e2372018-05-07 11:59:10 -0700156 int r;
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500157 struct async_wait_callback_data* data = userdata;
158 mapper_async_wait* wait = data->wait;
Brad Bishop3d468792016-09-20 15:39:38 -0400159
Ed Tanous167e2372018-05-07 11:59:10 -0700160 sd_event_source_unref(data->event_source);
Brad Bishopa02cd542021-10-12 19:12:42 -0400161 r = sd_bus_call_method_async(
162 wait->conn, NULL, "xyz.openbmc_project.ObjectMapper",
163 "/xyz/openbmc_project/object_mapper",
164 "xyz.openbmc_project.ObjectMapper", "GetObject",
165 async_wait_getobject_callback, data, "sas", data->path, 0, NULL);
Ed Tanous167e2372018-05-07 11:59:10 -0700166 if (r < 0)
167 {
168 async_wait_done(r, wait);
169 free(data);
170 }
Brad Bishop3d468792016-09-20 15:39:38 -0400171
Ed Tanous167e2372018-05-07 11:59:10 -0700172 return 0;
Brad Bishop3d468792016-09-20 15:39:38 -0400173}
174
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500175static int async_wait_getobject_callback(sd_bus_message* m, void* userdata,
Brad Bishop2d41d6a2021-08-03 08:14:45 -0400176 _unused_ sd_bus_error* e)
Brad Bishop2afe7182016-08-13 14:08:17 -0400177{
Brad Bishopa959f122021-08-03 11:21:01 -0400178 size_t i;
179 int r;
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500180 struct async_wait_callback_data* data = userdata;
181 mapper_async_wait* wait = data->wait;
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700182 uint64_t next_retry;
Brad Bishop2afe7182016-08-13 14:08:17 -0400183
Ed Tanous167e2372018-05-07 11:59:10 -0700184 if (wait->finished)
185 goto exit;
Brad Bishop3d468792016-09-20 15:39:38 -0400186
Patrick Williamse82b0582020-11-16 16:25:20 -0600187 if (sd_bus_message_is_method_error(
188 m, "xyz.openbmc_project.Common.Error.ResourceNotFound"))
Ed Tanous167e2372018-05-07 11:59:10 -0700189 goto exit;
Brad Bishop8ccdaed2016-09-20 15:54:32 -0400190
Patrick Williamse82b0582020-11-16 16:25:20 -0600191 r = sd_bus_message_get_errno(m);
192
William A. Kennington III24829462018-06-15 10:10:25 -0700193 if ((r == EBUSY || r == ENOBUFS) && data->retry < mapper_busy_retries)
Ed Tanous167e2372018-05-07 11:59:10 -0700194 {
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700195 r = sd_event_now(wait->loop, CLOCK_MONOTONIC, &next_retry);
Ed Tanous167e2372018-05-07 11:59:10 -0700196 if (r < 0)
197 {
198 async_wait_done(r, wait);
199 goto exit;
200 }
Brad Bishop3d468792016-09-20 15:39:38 -0400201
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700202 next_retry += mapper_busy_delay_interval_usec * (1 << data->retry);
Ed Tanous167e2372018-05-07 11:59:10 -0700203 r = sd_event_add_time(wait->loop, &data->event_source, CLOCK_MONOTONIC,
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700204 next_retry, 0, async_wait_timeout_callback, data);
205 ++data->retry;
Ed Tanous167e2372018-05-07 11:59:10 -0700206 if (r < 0)
207 {
208 async_wait_done(r, wait);
209 goto exit;
210 }
Brad Bishop3d468792016-09-20 15:39:38 -0400211
Ed Tanous167e2372018-05-07 11:59:10 -0700212 return 0;
213 }
Brad Bishop3d468792016-09-20 15:39:38 -0400214
Ed Tanous167e2372018-05-07 11:59:10 -0700215 if (r)
216 {
217 async_wait_done(-r, wait);
218 goto exit;
219 }
Brad Bishop3d468792016-09-20 15:39:38 -0400220
Ed Tanous167e2372018-05-07 11:59:10 -0700221 for (i = 0; i < wait->count; ++i)
222 {
223 if (!strcmp(data->path, wait->objs[i]))
224 {
225 wait->status[i] = 1;
226 }
227 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400228
Ed Tanous167e2372018-05-07 11:59:10 -0700229 if (async_wait_check_done(wait))
230 async_wait_done(0, wait);
Brad Bishop2afe7182016-08-13 14:08:17 -0400231
Brad Bishop3d468792016-09-20 15:39:38 -0400232exit:
Ed Tanous167e2372018-05-07 11:59:10 -0700233 free(data);
234 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400235}
236
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500237static int async_wait_get_objects(mapper_async_wait* wait)
Brad Bishop2afe7182016-08-13 14:08:17 -0400238{
Brad Bishopa959f122021-08-03 11:21:01 -0400239 size_t i;
240 int r;
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500241 struct async_wait_callback_data* data = NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400242
Ed Tanous167e2372018-05-07 11:59:10 -0700243 for (i = 0; i < wait->count; ++i)
244 {
245 if (wait->status[i])
246 continue;
247 data = malloc(sizeof(*data));
248 data->wait = wait;
249 data->path = wait->objs[i];
250 data->retry = 0;
251 data->event_source = NULL;
Brad Bishopa02cd542021-10-12 19:12:42 -0400252 r = sd_bus_call_method_async(
253 wait->conn, NULL, "xyz.openbmc_project.ObjectMapper",
254 "/xyz/openbmc_project/object_mapper",
255 "xyz.openbmc_project.ObjectMapper", "GetObject",
256 async_wait_getobject_callback, data, "sas", wait->objs[i], 0, NULL);
Ed Tanous167e2372018-05-07 11:59:10 -0700257 if (r < 0)
258 {
259 free(data);
260 fprintf(stderr, "Error invoking method: %s\n", strerror(-r));
261 return r;
262 }
263 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400264
Ed Tanous167e2372018-05-07 11:59:10 -0700265 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400266}
267
Brad Bishop2d41d6a2021-08-03 08:14:45 -0400268static int async_wait_match_introspection_complete(_unused_ sd_bus_message* m,
269 void* w,
270 _unused_ sd_bus_error* e)
Brad Bishop2afe7182016-08-13 14:08:17 -0400271{
Ed Tanous167e2372018-05-07 11:59:10 -0700272 int r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400273
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500274 mapper_async_wait* wait = w;
Ed Tanous167e2372018-05-07 11:59:10 -0700275 if (wait->finished)
276 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400277
Ed Tanous167e2372018-05-07 11:59:10 -0700278 r = async_wait_get_objects(wait);
279 if (r < 0)
280 async_wait_done(r, wait);
Brad Bishop2afe7182016-08-13 14:08:17 -0400281
Ed Tanous167e2372018-05-07 11:59:10 -0700282 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400283}
284
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500285static void async_wait_done(int r, mapper_async_wait* w)
Brad Bishop2afe7182016-08-13 14:08:17 -0400286{
Ed Tanous167e2372018-05-07 11:59:10 -0700287 if (w->finished)
288 return;
Brad Bishop2afe7182016-08-13 14:08:17 -0400289
Ed Tanous167e2372018-05-07 11:59:10 -0700290 w->finished = 1;
291 sd_bus_slot_unref(w->introspection_slot);
292 sd_bus_slot_unref(w->intf_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400293
Ed Tanous167e2372018-05-07 11:59:10 -0700294 if (w->callback)
295 w->callback(r, w->userdata);
Brad Bishop2afe7182016-08-13 14:08:17 -0400296}
297
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500298static int async_wait_check_done(mapper_async_wait* w)
Brad Bishop2afe7182016-08-13 14:08:17 -0400299{
Brad Bishopa959f122021-08-03 11:21:01 -0400300 size_t i;
Brad Bishop2afe7182016-08-13 14:08:17 -0400301
Ed Tanous167e2372018-05-07 11:59:10 -0700302 if (w->finished)
303 return 1;
Brad Bishop2afe7182016-08-13 14:08:17 -0400304
Ed Tanous167e2372018-05-07 11:59:10 -0700305 for (i = 0; i < w->count; ++i)
306 if (!w->status[i])
307 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400308
Ed Tanous167e2372018-05-07 11:59:10 -0700309 return 1;
Brad Bishop2afe7182016-08-13 14:08:17 -0400310}
311
Brad Bishop75057c82021-08-03 15:22:02 -0400312_public_ void mapper_wait_async_free(mapper_async_wait* w)
Brad Bishop2afe7182016-08-13 14:08:17 -0400313{
Ed Tanous167e2372018-05-07 11:59:10 -0700314 free(w->status);
315 sarrayfree(w->objs);
316 free(w);
Brad Bishop2afe7182016-08-13 14:08:17 -0400317}
318
Brad Bishop75057c82021-08-03 15:22:02 -0400319_public_ int mapper_wait_async(sd_bus* conn, sd_event* loop, char* objs[],
320 void (*callback)(int, void*), void* userdata,
321 mapper_async_wait** w)
Brad Bishop2afe7182016-08-13 14:08:17 -0400322{
Ed Tanous167e2372018-05-07 11:59:10 -0700323 int r;
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500324 mapper_async_wait* wait = NULL;
Brad Bishop2afe7182016-08-13 14:08:17 -0400325
Ed Tanous167e2372018-05-07 11:59:10 -0700326 wait = malloc(sizeof(*wait));
327 if (!wait)
328 return -ENOMEM;
Brad Bishop2afe7182016-08-13 14:08:17 -0400329
Ed Tanous167e2372018-05-07 11:59:10 -0700330 memset(wait, 0, sizeof(*wait));
331 wait->conn = conn;
332 wait->loop = loop;
333 wait->callback = callback;
334 wait->userdata = userdata;
335 wait->count = sarraylen(objs);
336 if (!wait->count)
Brad Bishop2ac32332021-08-03 14:06:52 -0400337 {
338 r = 0;
339 goto free_wait;
340 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400341
Ed Tanous167e2372018-05-07 11:59:10 -0700342 wait->objs = sarraydup(objs);
343 if (!wait->objs)
344 {
345 r = -ENOMEM;
346 goto free_wait;
347 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400348
Ed Tanous167e2372018-05-07 11:59:10 -0700349 wait->status = malloc(sizeof(*wait->status) * wait->count);
350 if (!wait->status)
351 {
352 r = -ENOMEM;
353 goto free_objs;
354 }
355 memset(wait->status, 0, sizeof(*wait->status) * wait->count);
Brad Bishop2afe7182016-08-13 14:08:17 -0400356
Ed Tanous167e2372018-05-07 11:59:10 -0700357 r = sd_bus_add_match(conn, &wait->introspection_slot,
358 async_wait_introspection_match,
359 async_wait_match_introspection_complete, wait);
360 if (r < 0)
361 {
362 fprintf(stderr, "Error adding match rule: %s\n", strerror(-r));
363 goto free_status;
364 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400365
Ed Tanous167e2372018-05-07 11:59:10 -0700366 r = sd_bus_add_match(conn, &wait->intf_slot,
367 async_wait_interfaces_added_match,
368 async_wait_match_introspection_complete, wait);
369 if (r < 0)
370 {
371 fprintf(stderr, "Error adding match rule: %s\n", strerror(-r));
372 goto unref_name_slot;
373 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400374
Ed Tanous167e2372018-05-07 11:59:10 -0700375 r = async_wait_get_objects(wait);
376 if (r < 0)
377 {
378 fprintf(stderr, "Error calling method: %s\n", strerror(-r));
379 goto unref_intf_slot;
380 }
Brad Bishop2afe7182016-08-13 14:08:17 -0400381
Ed Tanous167e2372018-05-07 11:59:10 -0700382 *w = wait;
Brad Bishop2afe7182016-08-13 14:08:17 -0400383
Ed Tanous167e2372018-05-07 11:59:10 -0700384 return 0;
Brad Bishop2afe7182016-08-13 14:08:17 -0400385
386unref_intf_slot:
Ed Tanous167e2372018-05-07 11:59:10 -0700387 sd_bus_slot_unref(wait->intf_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400388unref_name_slot:
Ed Tanous167e2372018-05-07 11:59:10 -0700389 sd_bus_slot_unref(wait->introspection_slot);
Brad Bishop2afe7182016-08-13 14:08:17 -0400390free_status:
Ed Tanous167e2372018-05-07 11:59:10 -0700391 free(wait->status);
Brad Bishop2afe7182016-08-13 14:08:17 -0400392free_objs:
Ed Tanous167e2372018-05-07 11:59:10 -0700393 sarrayfree(wait->objs);
Brad Bishop2afe7182016-08-13 14:08:17 -0400394free_wait:
Ed Tanous167e2372018-05-07 11:59:10 -0700395 free(wait);
Brad Bishop2afe7182016-08-13 14:08:17 -0400396
Ed Tanous167e2372018-05-07 11:59:10 -0700397 return r;
Brad Bishop2afe7182016-08-13 14:08:17 -0400398}
399
Brad Bishop2d41d6a2021-08-03 08:14:45 -0400400static int async_subtree_timeout_callback(_unused_ sd_event_source* s,
401 _unused_ uint64_t usec,
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500402 void* userdata)
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500403{
Ed Tanous167e2372018-05-07 11:59:10 -0700404 int r;
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500405 struct mapper_async_subtree* subtree = userdata;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500406
Ed Tanous167e2372018-05-07 11:59:10 -0700407 sd_event_source_unref(subtree->event_source);
408 r = sd_bus_call_method_async(
Brad Bishopa02cd542021-10-12 19:12:42 -0400409 subtree->conn, NULL, "xyz.openbmc_project.ObjectMapper",
410 "/xyz/openbmc_project/object_mapper",
411 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
412 async_subtree_getpaths_callback, subtree, "sias", subtree->namespace, 0,
413 1, subtree->interface);
Ed Tanous167e2372018-05-07 11:59:10 -0700414 if (r < 0)
415 async_subtree_done(r, subtree);
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500416
Ed Tanous167e2372018-05-07 11:59:10 -0700417 return 0;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500418}
419
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500420static int async_subtree_getpaths_callback(sd_bus_message* m, void* userdata,
Brad Bishop2d41d6a2021-08-03 08:14:45 -0400421 _unused_ sd_bus_error* e)
Adriana Kobylak025d7952017-05-08 13:30:45 -0500422{
Ed Tanous167e2372018-05-07 11:59:10 -0700423 int r;
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500424 struct mapper_async_subtree* subtree = userdata;
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700425 uint64_t next_retry;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500426
Ed Tanous167e2372018-05-07 11:59:10 -0700427 if (subtree->finished)
428 goto exit;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500429
Ed Tanous167e2372018-05-07 11:59:10 -0700430 r = sd_bus_message_get_errno(m);
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500431
Patrick Williamse82b0582020-11-16 16:25:20 -0600432 if (sd_bus_message_is_method_error(
433 m, "xyz.openbmc_project.Common.Error.ResourceNotFound"))
Ed Tanous167e2372018-05-07 11:59:10 -0700434 {
435 if (subtree->op == MAPPER_OP_REMOVE)
436 r = 0;
437 else
438 goto exit;
439 }
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500440
William A. Kennington III24829462018-06-15 10:10:25 -0700441 if ((r == EBUSY || r == ENOBUFS) && subtree->retry < mapper_busy_retries)
Ed Tanous167e2372018-05-07 11:59:10 -0700442 {
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700443 r = sd_event_now(subtree->loop, CLOCK_MONOTONIC, &next_retry);
Ed Tanous167e2372018-05-07 11:59:10 -0700444 if (r < 0)
445 {
446 async_subtree_done(r, subtree);
447 goto exit;
448 }
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500449
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700450 next_retry += mapper_busy_delay_interval_usec * (1 << subtree->retry);
Ed Tanous167e2372018-05-07 11:59:10 -0700451 r = sd_event_add_time(subtree->loop, &subtree->event_source,
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700452 CLOCK_MONOTONIC, next_retry, 0,
Ed Tanous167e2372018-05-07 11:59:10 -0700453 async_subtree_timeout_callback, subtree);
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700454 ++subtree->retry;
Ed Tanous167e2372018-05-07 11:59:10 -0700455 if (r < 0)
456 {
457 async_subtree_done(r, subtree);
458 goto exit;
459 }
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500460
Ed Tanous167e2372018-05-07 11:59:10 -0700461 return 0;
462 }
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500463
Ed Tanous167e2372018-05-07 11:59:10 -0700464 if (r)
465 {
466 async_subtree_done(-r, subtree);
467 goto exit;
468 }
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500469
Ed Tanous167e2372018-05-07 11:59:10 -0700470 if (subtree->op == MAPPER_OP_REMOVE)
471 {
William A. Kennington III20cbbfb2018-06-15 10:10:13 -0700472 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
473 if (r < 0)
474 {
475 async_subtree_done(r, subtree);
476 goto exit;
477 }
478
479 r = sd_bus_message_at_end(m, false);
480 if (r < 0)
481 {
482 async_subtree_done(r, subtree);
483 goto exit;
484 }
485
Ed Tanous167e2372018-05-07 11:59:10 -0700486 /* For remove, operation is complete when the interface is not present
William A. Kennington III20cbbfb2018-06-15 10:10:13 -0700487 * we know it is empty if the returned array is empty
Ed Tanous167e2372018-05-07 11:59:10 -0700488 */
William A. Kennington III20cbbfb2018-06-15 10:10:13 -0700489 if (r)
Ed Tanous167e2372018-05-07 11:59:10 -0700490 async_subtree_done(0, subtree);
491 }
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500492
493exit:
Ed Tanous167e2372018-05-07 11:59:10 -0700494 return 0;
Adriana Kobylak025d7952017-05-08 13:30:45 -0500495}
496
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500497static int async_subtree_getpaths(mapper_async_subtree* subtree)
Adriana Kobylak025d7952017-05-08 13:30:45 -0500498{
Ed Tanous167e2372018-05-07 11:59:10 -0700499 int r = 0;
Adriana Kobylak025d7952017-05-08 13:30:45 -0500500
Ed Tanous167e2372018-05-07 11:59:10 -0700501 subtree->retry = 0;
502 subtree->event_source = NULL;
503 r = sd_bus_call_method_async(
Brad Bishopa02cd542021-10-12 19:12:42 -0400504 subtree->conn, NULL, "xyz.openbmc_project.ObjectMapper",
505 "/xyz/openbmc_project/object_mapper",
506 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
507 async_subtree_getpaths_callback, subtree, "sias", subtree->namespace, 0,
508 1, subtree->interface);
Ed Tanous167e2372018-05-07 11:59:10 -0700509 if (r < 0)
510 {
511 fprintf(stderr, "Error invoking method: %s\n", strerror(-r));
512 return r;
513 }
Adriana Kobylak025d7952017-05-08 13:30:45 -0500514
Ed Tanous167e2372018-05-07 11:59:10 -0700515 return 0;
Adriana Kobylak025d7952017-05-08 13:30:45 -0500516}
517
Brad Bishop2d41d6a2021-08-03 08:14:45 -0400518static int async_subtree_match_callback(_unused_ sd_bus_message* m, void* t,
519 _unused_ sd_bus_error* e)
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500520{
Ed Tanous167e2372018-05-07 11:59:10 -0700521 int r;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500522
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500523 mapper_async_subtree* subtree = t;
Ed Tanous167e2372018-05-07 11:59:10 -0700524 if (subtree->finished)
525 return 0;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500526
Ed Tanous167e2372018-05-07 11:59:10 -0700527 r = async_subtree_getpaths(subtree);
528 if (r < 0)
529 async_subtree_done(r, subtree);
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500530
Ed Tanous167e2372018-05-07 11:59:10 -0700531 return 0;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500532}
533
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500534static void async_subtree_done(int r, mapper_async_subtree* t)
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500535{
Ed Tanous167e2372018-05-07 11:59:10 -0700536 if (t->finished)
537 return;
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500538
Ed Tanous167e2372018-05-07 11:59:10 -0700539 t->finished = 1;
540 sd_bus_slot_unref(t->slot);
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500541
Ed Tanous167e2372018-05-07 11:59:10 -0700542 if (t->callback)
543 t->callback(r, t->userdata);
Adriana Kobylakb2f26812017-05-08 13:58:02 -0500544}
545
Brad Bishop75057c82021-08-03 15:22:02 -0400546_public_ int mapper_subtree_async(sd_bus* conn, sd_event* loop, char* namespace,
547 char* interface, void (*callback)(int, void*),
548 void* userdata, mapper_async_subtree** t,
549 int op)
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -0500550{
Ed Tanous167e2372018-05-07 11:59:10 -0700551 int r = 0;
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500552 mapper_async_subtree* subtree = NULL;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500553
Ed Tanous167e2372018-05-07 11:59:10 -0700554 subtree = malloc(sizeof(*subtree));
555 if (!subtree)
556 return -ENOMEM;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500557
Ed Tanous167e2372018-05-07 11:59:10 -0700558 memset(subtree, 0, sizeof(*subtree));
559 subtree->conn = conn;
560 subtree->loop = loop;
561 subtree->namespace = namespace;
562 subtree->interface = interface;
563 subtree->callback = callback;
564 subtree->userdata = userdata;
565 subtree->op = op;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500566
Ed Tanous167e2372018-05-07 11:59:10 -0700567 if (subtree->op == MAPPER_OP_REMOVE)
568 {
569 r = sd_bus_add_match(conn, &subtree->slot, interfaces_removed_match,
570 async_subtree_match_callback, subtree);
571 if (r < 0)
572 {
573 fprintf(stderr, "Error adding match rule: %s\n", strerror(-r));
574 goto unref_slot;
575 }
576 }
577 else
578 {
579 /* Operation not supported */
580 r = -EINVAL;
581 goto free_subtree;
582 }
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500583
Ed Tanous167e2372018-05-07 11:59:10 -0700584 r = async_subtree_getpaths(subtree);
585 if (r < 0)
586 {
587 fprintf(stderr, "Error calling method: %s\n", strerror(-r));
588 goto unref_slot;
589 }
Adriana Kobylak025d7952017-05-08 13:30:45 -0500590
Ed Tanous167e2372018-05-07 11:59:10 -0700591 *t = subtree;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500592
Ed Tanous167e2372018-05-07 11:59:10 -0700593 return 0;
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500594
595unref_slot:
Ed Tanous167e2372018-05-07 11:59:10 -0700596 sd_bus_slot_unref(subtree->slot);
Adriana Kobylak78edbb62017-05-04 15:45:19 -0500597free_subtree:
Ed Tanous167e2372018-05-07 11:59:10 -0700598 free(subtree);
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -0500599
Ed Tanous167e2372018-05-07 11:59:10 -0700600 return r;
Adriana Kobylak2a8bfc92017-05-11 09:16:02 -0500601}
602
Brad Bishop75057c82021-08-03 15:22:02 -0400603_public_ int mapper_get_object(sd_bus* conn, const char* obj,
604 sd_bus_message** reply)
Brad Bishop62ece2b2016-07-25 09:00:51 -0400605{
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500606 sd_bus_message* request = NULL;
Ed Tanous167e2372018-05-07 11:59:10 -0700607 int r, retry = 0;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400608
Brad Bishopa02cd542021-10-12 19:12:42 -0400609 r = sd_bus_message_new_method_call(
610 conn, &request, "xyz.openbmc_project.ObjectMapper",
611 "/xyz/openbmc_project/object_mapper",
612 "xyz.openbmc_project.ObjectMapper", "GetObject");
Ed Tanous167e2372018-05-07 11:59:10 -0700613 if (r < 0)
614 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400615
Ed Tanous167e2372018-05-07 11:59:10 -0700616 r = sd_bus_message_append(request, "s", obj);
617 if (r < 0)
618 goto exit;
619 r = sd_bus_message_append(request, "as", 0, NULL);
620 if (r < 0)
621 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400622
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700623 while (true)
Ed Tanous167e2372018-05-07 11:59:10 -0700624 {
William A. Kennington III24829462018-06-15 10:10:25 -0700625 r = sd_bus_call(conn, request, 0, NULL, reply);
626 if (r == -EBUSY || r == -ENOBUFS)
Ed Tanous167e2372018-05-07 11:59:10 -0700627 {
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700628 if (retry >= mapper_busy_retries)
629 break;
Brad Bishop3d468792016-09-20 15:39:38 -0400630
William A. Kennington III5e21ac02018-06-15 10:10:20 -0700631 usleep(mapper_busy_delay_interval_usec * (1 << retry));
632 ++retry;
Ed Tanous167e2372018-05-07 11:59:10 -0700633 continue;
634 }
635 break;
636 }
Brad Bishop3d468792016-09-20 15:39:38 -0400637
Ed Tanous167e2372018-05-07 11:59:10 -0700638 if (r < 0)
639 goto exit;
Brad Bishop3d468792016-09-20 15:39:38 -0400640
641exit:
Ed Tanous167e2372018-05-07 11:59:10 -0700642 sd_bus_message_unref(request);
Brad Bishop3d468792016-09-20 15:39:38 -0400643
Ed Tanous167e2372018-05-07 11:59:10 -0700644 return r;
Brad Bishop3d468792016-09-20 15:39:38 -0400645}
646
Brad Bishop75057c82021-08-03 15:22:02 -0400647_public_ int mapper_get_service(sd_bus* conn, const char* obj, char** service)
Brad Bishop3d468792016-09-20 15:39:38 -0400648{
Matt Spinlercc6ee9c2018-09-19 13:23:13 -0500649 sd_bus_message* reply = NULL;
650 const char* tmp;
Ed Tanous167e2372018-05-07 11:59:10 -0700651 int r;
Brad Bishop3d468792016-09-20 15:39:38 -0400652
Ed Tanous167e2372018-05-07 11:59:10 -0700653 r = mapper_get_object(conn, obj, &reply);
654 if (r < 0)
655 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400656
Ed Tanous167e2372018-05-07 11:59:10 -0700657 r = sd_bus_message_enter_container(reply, 0, NULL);
658 if (r < 0)
659 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400660
Ed Tanous167e2372018-05-07 11:59:10 -0700661 r = sd_bus_message_enter_container(reply, 0, NULL);
662 if (r < 0)
663 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400664
Ed Tanous167e2372018-05-07 11:59:10 -0700665 r = sd_bus_message_read(reply, "s", &tmp);
666 if (r < 0)
667 goto exit;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400668
Ed Tanous167e2372018-05-07 11:59:10 -0700669 *service = strdup(tmp);
Brad Bishop62ece2b2016-07-25 09:00:51 -0400670
671exit:
Ed Tanous167e2372018-05-07 11:59:10 -0700672 sd_bus_message_unref(reply);
Brad Bishop62ece2b2016-07-25 09:00:51 -0400673
Ed Tanous167e2372018-05-07 11:59:10 -0700674 return r;
Brad Bishop62ece2b2016-07-25 09:00:51 -0400675}