162ece2b4SBrad Bishop /**
262ece2b4SBrad Bishop  * Copyright © 2016 IBM Corporation
362ece2b4SBrad Bishop  *
462ece2b4SBrad Bishop  * Licensed under the Apache License, Version 2.0 (the "License");
562ece2b4SBrad Bishop  * you may not use this file except in compliance with the License.
662ece2b4SBrad Bishop  * You may obtain a copy of the License at
762ece2b4SBrad Bishop  *
862ece2b4SBrad Bishop  *     http://www.apache.org/licenses/LICENSE-2.0
962ece2b4SBrad Bishop  *
1062ece2b4SBrad Bishop  * Unless required by applicable law or agreed to in writing, software
1162ece2b4SBrad Bishop  * distributed under the License is distributed on an "AS IS" BASIS,
1262ece2b4SBrad Bishop  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1362ece2b4SBrad Bishop  * See the License for the specific language governing permissions and
1462ece2b4SBrad Bishop  * limitations under the License.
1562ece2b4SBrad Bishop  */
16cc6ee9cbSMatt Spinler #include "mapper.h"
17cc6ee9cbSMatt Spinler 
18cc6ee9cbSMatt Spinler #include <errno.h>
1920cbbfb0SWilliam A. Kennington III #include <stdbool.h>
20a959f127SBrad Bishop #include <stddef.h>
21cc6ee9cbSMatt Spinler #include <stdio.h>
222afe718fSBrad Bishop #include <stdlib.h>
2362ece2b4SBrad Bishop #include <string.h>
243d46879cSBrad Bishop #include <sys/timerfd.h>
2562ece2b4SBrad Bishop #include <systemd/sd-bus.h>
263d46879cSBrad Bishop #include <systemd/sd-event.h>
27cc6ee9cbSMatt Spinler #include <unistd.h>
2862ece2b4SBrad Bishop 
29a669a50aSBrad Bishop #include "internal.h"
30a669a50aSBrad Bishop 
3175057c87SBrad Bishop #define _public_ __attribute__((__visibility__("default")))
322d41d6abSBrad Bishop #define _unused_ __attribute__((unused))
3375057c87SBrad Bishop 
34829181d8SBrad Bishop static const char* async_wait_introspection_match =
352afe718fSBrad Bishop     "type='signal',"
36829181d8SBrad Bishop     "sender='xyz.openbmc_project.ObjectMapper',"
37829181d8SBrad Bishop     "interface='xyz.openbmc_project.ObjectMapper.Private',"
38829181d8SBrad Bishop     "member='IntrospectionComplete'";
392afe718fSBrad Bishop 
402afe718fSBrad Bishop static const char* async_wait_interfaces_added_match =
412afe718fSBrad Bishop     "type='signal',"
422afe718fSBrad Bishop     "interface='org.freedesktop.DBus.ObjectManager',"
432afe718fSBrad Bishop     "member='InterfacesAdded'";
442afe718fSBrad Bishop 
4578edbb6fSAdriana Kobylak static const char* interfaces_removed_match =
4678edbb6fSAdriana Kobylak     "type='signal',"
4778edbb6fSAdriana Kobylak     "interface='org.freedesktop.DBus.ObjectManager',"
4878edbb6fSAdriana Kobylak     "member='InterfacesRemoved'";
4978edbb6fSAdriana Kobylak 
503d46879cSBrad Bishop static const int mapper_busy_retries = 5;
513d46879cSBrad Bishop static const uint64_t mapper_busy_delay_interval_usec = 1000000;
523d46879cSBrad Bishop 
532afe718fSBrad Bishop struct mapper_async_wait
542afe718fSBrad Bishop {
552afe718fSBrad Bishop     char** objs;
562afe718fSBrad Bishop     void (*callback)(int, void*);
572afe718fSBrad Bishop     void* userdata;
583d46879cSBrad Bishop     sd_event* loop;
592afe718fSBrad Bishop     sd_bus* conn;
60829181d8SBrad Bishop     sd_bus_slot* introspection_slot;
612afe718fSBrad Bishop     sd_bus_slot* intf_slot;
622afe718fSBrad Bishop     int* status;
63a959f127SBrad Bishop     size_t count;
642afe718fSBrad Bishop     int finished;
652afe718fSBrad Bishop     int r;
662afe718fSBrad Bishop };
672afe718fSBrad Bishop 
682afe718fSBrad Bishop struct async_wait_callback_data
692afe718fSBrad Bishop {
702afe718fSBrad Bishop     mapper_async_wait* wait;
712afe718fSBrad Bishop     const char* path;
723d46879cSBrad Bishop     sd_event_source* event_source;
733d46879cSBrad Bishop     int retry;
742afe718fSBrad Bishop };
752afe718fSBrad Bishop 
762a8bfc96SAdriana Kobylak struct mapper_async_subtree
772a8bfc96SAdriana Kobylak {
7878edbb6fSAdriana Kobylak     char* namespace;
7978edbb6fSAdriana Kobylak     char* interface;
8078edbb6fSAdriana Kobylak     void (*callback)(int, void*);
8178edbb6fSAdriana Kobylak     void* userdata;
8278edbb6fSAdriana Kobylak     sd_event* loop;
8378edbb6fSAdriana Kobylak     sd_bus* conn;
8478edbb6fSAdriana Kobylak     sd_bus_slot* slot;
85025d7959SAdriana Kobylak     sd_event_source* event_source;
86b2f2681fSAdriana Kobylak     int finished;
8778edbb6fSAdriana Kobylak     int op;
88025d7959SAdriana Kobylak     int retry;
892a8bfc96SAdriana Kobylak };
902a8bfc96SAdriana Kobylak 
91829181d8SBrad Bishop static int async_wait_match_introspection_complete(sd_bus_message*, void*,
922afe718fSBrad Bishop                                                    sd_bus_error*);
932afe718fSBrad Bishop static int async_wait_check_done(mapper_async_wait*);
942afe718fSBrad Bishop static void async_wait_done(int r, mapper_async_wait*);
952afe718fSBrad Bishop static int async_wait_get_objects(mapper_async_wait*);
96cc6ee9cbSMatt Spinler static int async_wait_getobject_callback(sd_bus_message*, void*, sd_bus_error*);
972afe718fSBrad Bishop 
98cc6ee9cbSMatt Spinler static int async_subtree_match_callback(sd_bus_message*, void*, sd_bus_error*);
99b2f2681fSAdriana Kobylak static void async_subtree_done(int r, mapper_async_subtree*);
100025d7959SAdriana Kobylak static int async_subtree_getpaths(mapper_async_subtree*);
101167e2379SEd Tanous static int async_subtree_getpaths_callback(sd_bus_message*, void*,
102167e2379SEd Tanous                                            sd_bus_error*);
10378edbb6fSAdriana Kobylak 
sarraylen(char * array[])104a959f127SBrad Bishop size_t sarraylen(char* array[])
1052afe718fSBrad Bishop {
106a959f127SBrad Bishop     size_t count = 0;
1072afe718fSBrad Bishop     char** p = array;
1082afe718fSBrad Bishop 
109167e2379SEd Tanous     while (*p != NULL)
110167e2379SEd Tanous     {
1112afe718fSBrad Bishop         ++count;
1122afe718fSBrad Bishop         ++p;
1132afe718fSBrad Bishop     }
1142afe718fSBrad Bishop 
1152afe718fSBrad Bishop     return count;
1162afe718fSBrad Bishop }
1172afe718fSBrad Bishop 
sarrayfree(char * array[])118a669a50aSBrad Bishop void sarrayfree(char* array[])
1192afe718fSBrad Bishop {
1202afe718fSBrad Bishop     char** p = array;
121167e2379SEd Tanous     while (*p != NULL)
122167e2379SEd Tanous     {
1232afe718fSBrad Bishop         free(*p);
1242afe718fSBrad Bishop         ++p;
1252afe718fSBrad Bishop     }
1262afe718fSBrad Bishop     free(array);
1272afe718fSBrad Bishop }
1282afe718fSBrad Bishop 
sarraydup(char * array[])129a669a50aSBrad Bishop char** sarraydup(char* array[])
1302afe718fSBrad Bishop {
131a959f127SBrad Bishop     size_t count = sarraylen(array);
132a959f127SBrad Bishop     size_t i;
1332afe718fSBrad Bishop     char** ret = NULL;
1342afe718fSBrad Bishop 
135a669a50aSBrad Bishop     ret = calloc(count + 1, sizeof(*ret));
1362afe718fSBrad Bishop     if (!ret)
1372afe718fSBrad Bishop         return NULL;
1382afe718fSBrad Bishop 
139167e2379SEd Tanous     for (i = 0; i < count; ++i)
140167e2379SEd Tanous     {
1412afe718fSBrad Bishop         ret[i] = strdup(array[i]);
1422afe718fSBrad Bishop         if (!ret[i])
1432afe718fSBrad Bishop             goto error;
1442afe718fSBrad Bishop     }
1452afe718fSBrad Bishop 
1462afe718fSBrad Bishop     return ret;
1472afe718fSBrad Bishop 
1482afe718fSBrad Bishop error:
1492afe718fSBrad Bishop     sarrayfree(ret);
1502afe718fSBrad Bishop     return NULL;
1512afe718fSBrad Bishop }
1522afe718fSBrad Bishop 
async_wait_timeout_callback(_unused_ sd_event_source * s,_unused_ uint64_t usec,void * userdata)1532d41d6abSBrad Bishop static int async_wait_timeout_callback(_unused_ sd_event_source* s,
1542d41d6abSBrad Bishop                                        _unused_ uint64_t usec, void* userdata)
1553d46879cSBrad Bishop {
1563d46879cSBrad Bishop     int r;
1573d46879cSBrad Bishop     struct async_wait_callback_data* data = userdata;
1583d46879cSBrad Bishop     mapper_async_wait* wait = data->wait;
1593d46879cSBrad Bishop 
1603d46879cSBrad Bishop     sd_event_source_unref(data->event_source);
161*a02cd54cSBrad Bishop     r = sd_bus_call_method_async(
162*a02cd54cSBrad Bishop         wait->conn, NULL, "xyz.openbmc_project.ObjectMapper",
163*a02cd54cSBrad Bishop         "/xyz/openbmc_project/object_mapper",
164*a02cd54cSBrad Bishop         "xyz.openbmc_project.ObjectMapper", "GetObject",
165*a02cd54cSBrad Bishop         async_wait_getobject_callback, data, "sas", data->path, 0, NULL);
166167e2379SEd Tanous     if (r < 0)
167167e2379SEd Tanous     {
1683d46879cSBrad Bishop         async_wait_done(r, wait);
1693d46879cSBrad Bishop         free(data);
1703d46879cSBrad Bishop     }
1713d46879cSBrad Bishop 
1723d46879cSBrad Bishop     return 0;
1733d46879cSBrad Bishop }
1743d46879cSBrad Bishop 
async_wait_getobject_callback(sd_bus_message * m,void * userdata,_unused_ sd_bus_error * e)175167e2379SEd Tanous static int async_wait_getobject_callback(sd_bus_message* m, void* userdata,
1762d41d6abSBrad Bishop                                          _unused_ sd_bus_error* e)
1772afe718fSBrad Bishop {
178a959f127SBrad Bishop     size_t i;
179a959f127SBrad Bishop     int r;
1802afe718fSBrad Bishop     struct async_wait_callback_data* data = userdata;
1812afe718fSBrad Bishop     mapper_async_wait* wait = data->wait;
1825e21ac01SWilliam A. Kennington III     uint64_t next_retry;
1832afe718fSBrad Bishop 
1842afe718fSBrad Bishop     if (wait->finished)
1853d46879cSBrad Bishop         goto exit;
1863d46879cSBrad Bishop 
187e82b0584SPatrick Williams     if (sd_bus_message_is_method_error(
188e82b0584SPatrick Williams             m, "xyz.openbmc_project.Common.Error.ResourceNotFound"))
1898ccdaed0SBrad Bishop         goto exit;
1908ccdaed0SBrad Bishop 
191e82b0584SPatrick Williams     r = sd_bus_message_get_errno(m);
192e82b0584SPatrick Williams 
1932482946eSWilliam A. Kennington III     if ((r == EBUSY || r == ENOBUFS) && data->retry < mapper_busy_retries)
194167e2379SEd Tanous     {
1955e21ac01SWilliam A. Kennington III         r = sd_event_now(wait->loop, CLOCK_MONOTONIC, &next_retry);
196167e2379SEd Tanous         if (r < 0)
197167e2379SEd Tanous         {
1983d46879cSBrad Bishop             async_wait_done(r, wait);
1993d46879cSBrad Bishop             goto exit;
2003d46879cSBrad Bishop         }
2013d46879cSBrad Bishop 
2025e21ac01SWilliam A. Kennington III         next_retry += mapper_busy_delay_interval_usec * (1 << data->retry);
203167e2379SEd Tanous         r = sd_event_add_time(wait->loop, &data->event_source, CLOCK_MONOTONIC,
2045e21ac01SWilliam A. Kennington III                               next_retry, 0, async_wait_timeout_callback, data);
2055e21ac01SWilliam A. Kennington III         ++data->retry;
206167e2379SEd Tanous         if (r < 0)
207167e2379SEd Tanous         {
2083d46879cSBrad Bishop             async_wait_done(r, wait);
2093d46879cSBrad Bishop             goto exit;
2103d46879cSBrad Bishop         }
2113d46879cSBrad Bishop 
2122afe718fSBrad Bishop         return 0;
2133d46879cSBrad Bishop     }
2143d46879cSBrad Bishop 
215167e2379SEd Tanous     if (r)
216167e2379SEd Tanous     {
2173d46879cSBrad Bishop         async_wait_done(-r, wait);
2183d46879cSBrad Bishop         goto exit;
2193d46879cSBrad Bishop     }
2203d46879cSBrad Bishop 
221167e2379SEd Tanous     for (i = 0; i < wait->count; ++i)
222167e2379SEd Tanous     {
223167e2379SEd Tanous         if (!strcmp(data->path, wait->objs[i]))
224167e2379SEd Tanous         {
2252afe718fSBrad Bishop             wait->status[i] = 1;
2262afe718fSBrad Bishop         }
2272afe718fSBrad Bishop     }
2282afe718fSBrad Bishop 
2292afe718fSBrad Bishop     if (async_wait_check_done(wait))
2302afe718fSBrad Bishop         async_wait_done(0, wait);
2312afe718fSBrad Bishop 
2323d46879cSBrad Bishop exit:
2333d46879cSBrad Bishop     free(data);
2342afe718fSBrad Bishop     return 0;
2352afe718fSBrad Bishop }
2362afe718fSBrad Bishop 
async_wait_get_objects(mapper_async_wait * wait)2372afe718fSBrad Bishop static int async_wait_get_objects(mapper_async_wait* wait)
2382afe718fSBrad Bishop {
239a959f127SBrad Bishop     size_t i;
240a959f127SBrad Bishop     int r;
2412afe718fSBrad Bishop     struct async_wait_callback_data* data = NULL;
2422afe718fSBrad Bishop 
243167e2379SEd Tanous     for (i = 0; i < wait->count; ++i)
244167e2379SEd Tanous     {
2452afe718fSBrad Bishop         if (wait->status[i])
2462afe718fSBrad Bishop             continue;
2472afe718fSBrad Bishop         data = malloc(sizeof(*data));
2482afe718fSBrad Bishop         data->wait = wait;
2492afe718fSBrad Bishop         data->path = wait->objs[i];
2503d46879cSBrad Bishop         data->retry = 0;
2513d46879cSBrad Bishop         data->event_source = NULL;
252*a02cd54cSBrad Bishop         r = sd_bus_call_method_async(
253*a02cd54cSBrad Bishop             wait->conn, NULL, "xyz.openbmc_project.ObjectMapper",
254*a02cd54cSBrad Bishop             "/xyz/openbmc_project/object_mapper",
255*a02cd54cSBrad Bishop             "xyz.openbmc_project.ObjectMapper", "GetObject",
256*a02cd54cSBrad Bishop             async_wait_getobject_callback, data, "sas", wait->objs[i], 0, NULL);
257167e2379SEd Tanous         if (r < 0)
258167e2379SEd Tanous         {
2592afe718fSBrad Bishop             free(data);
260167e2379SEd Tanous             fprintf(stderr, "Error invoking method: %s\n", strerror(-r));
2612afe718fSBrad Bishop             return r;
2622afe718fSBrad Bishop         }
2632afe718fSBrad Bishop     }
2642afe718fSBrad Bishop 
2652afe718fSBrad Bishop     return 0;
2662afe718fSBrad Bishop }
2672afe718fSBrad Bishop 
async_wait_match_introspection_complete(_unused_ sd_bus_message * m,void * w,_unused_ sd_bus_error * e)2682d41d6abSBrad Bishop static int async_wait_match_introspection_complete(_unused_ sd_bus_message* m,
2692d41d6abSBrad Bishop                                                    void* w,
2702d41d6abSBrad Bishop                                                    _unused_ sd_bus_error* e)
2712afe718fSBrad Bishop {
272a6797f83SBrad Bishop     int r;
2732afe718fSBrad Bishop 
2742afe718fSBrad Bishop     mapper_async_wait* wait = w;
2752afe718fSBrad Bishop     if (wait->finished)
2762afe718fSBrad Bishop         return 0;
2772afe718fSBrad Bishop 
2782afe718fSBrad Bishop     r = async_wait_get_objects(wait);
2792afe718fSBrad Bishop     if (r < 0)
2802afe718fSBrad Bishop         async_wait_done(r, wait);
2812afe718fSBrad Bishop 
2822afe718fSBrad Bishop     return 0;
2832afe718fSBrad Bishop }
2842afe718fSBrad Bishop 
async_wait_done(int r,mapper_async_wait * w)2852afe718fSBrad Bishop static void async_wait_done(int r, mapper_async_wait* w)
2862afe718fSBrad Bishop {
2872afe718fSBrad Bishop     if (w->finished)
2882afe718fSBrad Bishop         return;
2892afe718fSBrad Bishop 
2902afe718fSBrad Bishop     w->finished = 1;
291829181d8SBrad Bishop     sd_bus_slot_unref(w->introspection_slot);
2922afe718fSBrad Bishop     sd_bus_slot_unref(w->intf_slot);
2932afe718fSBrad Bishop 
2942afe718fSBrad Bishop     if (w->callback)
2952afe718fSBrad Bishop         w->callback(r, w->userdata);
2962afe718fSBrad Bishop }
2972afe718fSBrad Bishop 
async_wait_check_done(mapper_async_wait * w)2982afe718fSBrad Bishop static int async_wait_check_done(mapper_async_wait* w)
2992afe718fSBrad Bishop {
300a959f127SBrad Bishop     size_t i;
3012afe718fSBrad Bishop 
3022afe718fSBrad Bishop     if (w->finished)
3032afe718fSBrad Bishop         return 1;
3042afe718fSBrad Bishop 
3052afe718fSBrad Bishop     for (i = 0; i < w->count; ++i)
3062afe718fSBrad Bishop         if (!w->status[i])
3072afe718fSBrad Bishop             return 0;
3082afe718fSBrad Bishop 
3092afe718fSBrad Bishop     return 1;
3102afe718fSBrad Bishop }
3112afe718fSBrad Bishop 
mapper_wait_async_free(mapper_async_wait * w)31275057c87SBrad Bishop _public_ void mapper_wait_async_free(mapper_async_wait* w)
3132afe718fSBrad Bishop {
3142afe718fSBrad Bishop     free(w->status);
3152afe718fSBrad Bishop     sarrayfree(w->objs);
3162afe718fSBrad Bishop     free(w);
3172afe718fSBrad Bishop }
3182afe718fSBrad Bishop 
mapper_wait_async(sd_bus * conn,sd_event * loop,char * objs[],void (* callback)(int,void *),void * userdata,mapper_async_wait ** w)31975057c87SBrad Bishop _public_ int mapper_wait_async(sd_bus* conn, sd_event* loop, char* objs[],
320167e2379SEd Tanous                                void (*callback)(int, void*), void* userdata,
321c7a7c45fSAdriana Kobylak                                mapper_async_wait** w)
3222afe718fSBrad Bishop {
3232afe718fSBrad Bishop     int r;
3242afe718fSBrad Bishop     mapper_async_wait* wait = NULL;
3252afe718fSBrad Bishop 
3262afe718fSBrad Bishop     wait = malloc(sizeof(*wait));
3272afe718fSBrad Bishop     if (!wait)
3282afe718fSBrad Bishop         return -ENOMEM;
3292afe718fSBrad Bishop 
3302afe718fSBrad Bishop     memset(wait, 0, sizeof(*wait));
3312afe718fSBrad Bishop     wait->conn = conn;
3323d46879cSBrad Bishop     wait->loop = loop;
3332afe718fSBrad Bishop     wait->callback = callback;
3342afe718fSBrad Bishop     wait->userdata = userdata;
3352afe718fSBrad Bishop     wait->count = sarraylen(objs);
3362afe718fSBrad Bishop     if (!wait->count)
3372ac32337SBrad Bishop     {
3382ac32337SBrad Bishop         r = 0;
3392ac32337SBrad Bishop         goto free_wait;
3402ac32337SBrad Bishop     }
3412afe718fSBrad Bishop 
3422afe718fSBrad Bishop     wait->objs = sarraydup(objs);
343167e2379SEd Tanous     if (!wait->objs)
344167e2379SEd Tanous     {
3452afe718fSBrad Bishop         r = -ENOMEM;
3462afe718fSBrad Bishop         goto free_wait;
3472afe718fSBrad Bishop     }
3482afe718fSBrad Bishop 
3492afe718fSBrad Bishop     wait->status = malloc(sizeof(*wait->status) * wait->count);
350167e2379SEd Tanous     if (!wait->status)
351167e2379SEd Tanous     {
3522afe718fSBrad Bishop         r = -ENOMEM;
3532afe718fSBrad Bishop         goto free_objs;
3542afe718fSBrad Bishop     }
3552afe718fSBrad Bishop     memset(wait->status, 0, sizeof(*wait->status) * wait->count);
3562afe718fSBrad Bishop 
357167e2379SEd Tanous     r = sd_bus_add_match(conn, &wait->introspection_slot,
358829181d8SBrad Bishop                          async_wait_introspection_match,
359167e2379SEd Tanous                          async_wait_match_introspection_complete, wait);
360167e2379SEd Tanous     if (r < 0)
361167e2379SEd Tanous     {
362167e2379SEd Tanous         fprintf(stderr, "Error adding match rule: %s\n", strerror(-r));
3632afe718fSBrad Bishop         goto free_status;
3642afe718fSBrad Bishop     }
3652afe718fSBrad Bishop 
366167e2379SEd Tanous     r = sd_bus_add_match(conn, &wait->intf_slot,
3672afe718fSBrad Bishop                          async_wait_interfaces_added_match,
368167e2379SEd Tanous                          async_wait_match_introspection_complete, wait);
369167e2379SEd Tanous     if (r < 0)
370167e2379SEd Tanous     {
371167e2379SEd Tanous         fprintf(stderr, "Error adding match rule: %s\n", strerror(-r));
3722afe718fSBrad Bishop         goto unref_name_slot;
3732afe718fSBrad Bishop     }
3742afe718fSBrad Bishop 
3752afe718fSBrad Bishop     r = async_wait_get_objects(wait);
376167e2379SEd Tanous     if (r < 0)
377167e2379SEd Tanous     {
378167e2379SEd Tanous         fprintf(stderr, "Error calling method: %s\n", strerror(-r));
3792afe718fSBrad Bishop         goto unref_intf_slot;
3802afe718fSBrad Bishop     }
3812afe718fSBrad Bishop 
3822afe718fSBrad Bishop     *w = wait;
3832afe718fSBrad Bishop 
3842afe718fSBrad Bishop     return 0;
3852afe718fSBrad Bishop 
3862afe718fSBrad Bishop unref_intf_slot:
3872afe718fSBrad Bishop     sd_bus_slot_unref(wait->intf_slot);
3882afe718fSBrad Bishop unref_name_slot:
389829181d8SBrad Bishop     sd_bus_slot_unref(wait->introspection_slot);
3902afe718fSBrad Bishop free_status:
3912afe718fSBrad Bishop     free(wait->status);
3922afe718fSBrad Bishop free_objs:
3932afe718fSBrad Bishop     sarrayfree(wait->objs);
3942afe718fSBrad Bishop free_wait:
3952afe718fSBrad Bishop     free(wait);
3962afe718fSBrad Bishop 
3972afe718fSBrad Bishop     return r;
3982afe718fSBrad Bishop }
3992afe718fSBrad Bishop 
async_subtree_timeout_callback(_unused_ sd_event_source * s,_unused_ uint64_t usec,void * userdata)4002d41d6abSBrad Bishop static int async_subtree_timeout_callback(_unused_ sd_event_source* s,
4012d41d6abSBrad Bishop                                           _unused_ uint64_t usec,
402167e2379SEd Tanous                                           void* userdata)
403b2f2681fSAdriana Kobylak {
404b2f2681fSAdriana Kobylak     int r;
405b2f2681fSAdriana Kobylak     struct mapper_async_subtree* subtree = userdata;
406b2f2681fSAdriana Kobylak 
407b2f2681fSAdriana Kobylak     sd_event_source_unref(subtree->event_source);
408b2f2681fSAdriana Kobylak     r = sd_bus_call_method_async(
409*a02cd54cSBrad Bishop         subtree->conn, NULL, "xyz.openbmc_project.ObjectMapper",
410*a02cd54cSBrad Bishop         "/xyz/openbmc_project/object_mapper",
411*a02cd54cSBrad Bishop         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
412*a02cd54cSBrad Bishop         async_subtree_getpaths_callback, subtree, "sias", subtree->namespace, 0,
413*a02cd54cSBrad Bishop         1, subtree->interface);
414b2f2681fSAdriana Kobylak     if (r < 0)
415b2f2681fSAdriana Kobylak         async_subtree_done(r, subtree);
416b2f2681fSAdriana Kobylak 
417b2f2681fSAdriana Kobylak     return 0;
418b2f2681fSAdriana Kobylak }
419b2f2681fSAdriana Kobylak 
async_subtree_getpaths_callback(sd_bus_message * m,void * userdata,_unused_ sd_bus_error * e)420167e2379SEd Tanous static int async_subtree_getpaths_callback(sd_bus_message* m, void* userdata,
4212d41d6abSBrad Bishop                                            _unused_ sd_bus_error* e)
422025d7959SAdriana Kobylak {
423b2f2681fSAdriana Kobylak     int r;
424b2f2681fSAdriana Kobylak     struct mapper_async_subtree* subtree = userdata;
4255e21ac01SWilliam A. Kennington III     uint64_t next_retry;
426b2f2681fSAdriana Kobylak 
427b2f2681fSAdriana Kobylak     if (subtree->finished)
428b2f2681fSAdriana Kobylak         goto exit;
429b2f2681fSAdriana Kobylak 
430b2f2681fSAdriana Kobylak     r = sd_bus_message_get_errno(m);
431b2f2681fSAdriana Kobylak 
432e82b0584SPatrick Williams     if (sd_bus_message_is_method_error(
433e82b0584SPatrick Williams             m, "xyz.openbmc_project.Common.Error.ResourceNotFound"))
434167e2379SEd Tanous     {
435b2f2681fSAdriana Kobylak         if (subtree->op == MAPPER_OP_REMOVE)
436b2f2681fSAdriana Kobylak             r = 0;
437b2f2681fSAdriana Kobylak         else
438b2f2681fSAdriana Kobylak             goto exit;
439b2f2681fSAdriana Kobylak     }
440b2f2681fSAdriana Kobylak 
4412482946eSWilliam A. Kennington III     if ((r == EBUSY || r == ENOBUFS) && subtree->retry < mapper_busy_retries)
442167e2379SEd Tanous     {
4435e21ac01SWilliam A. Kennington III         r = sd_event_now(subtree->loop, CLOCK_MONOTONIC, &next_retry);
444167e2379SEd Tanous         if (r < 0)
445167e2379SEd Tanous         {
446b2f2681fSAdriana Kobylak             async_subtree_done(r, subtree);
447b2f2681fSAdriana Kobylak             goto exit;
448b2f2681fSAdriana Kobylak         }
449b2f2681fSAdriana Kobylak 
4505e21ac01SWilliam A. Kennington III         next_retry += mapper_busy_delay_interval_usec * (1 << subtree->retry);
451167e2379SEd Tanous         r = sd_event_add_time(subtree->loop, &subtree->event_source,
4525e21ac01SWilliam A. Kennington III                               CLOCK_MONOTONIC, next_retry, 0,
453167e2379SEd Tanous                               async_subtree_timeout_callback, subtree);
4545e21ac01SWilliam A. Kennington III         ++subtree->retry;
455167e2379SEd Tanous         if (r < 0)
456167e2379SEd Tanous         {
457b2f2681fSAdriana Kobylak             async_subtree_done(r, subtree);
458b2f2681fSAdriana Kobylak             goto exit;
459b2f2681fSAdriana Kobylak         }
460b2f2681fSAdriana Kobylak 
461b2f2681fSAdriana Kobylak         return 0;
462b2f2681fSAdriana Kobylak     }
463b2f2681fSAdriana Kobylak 
464167e2379SEd Tanous     if (r)
465167e2379SEd Tanous     {
466b2f2681fSAdriana Kobylak         async_subtree_done(-r, subtree);
467b2f2681fSAdriana Kobylak         goto exit;
468b2f2681fSAdriana Kobylak     }
469b2f2681fSAdriana Kobylak 
470167e2379SEd Tanous     if (subtree->op == MAPPER_OP_REMOVE)
471167e2379SEd Tanous     {
47220cbbfb0SWilliam A. Kennington III         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "s");
47320cbbfb0SWilliam A. Kennington III         if (r < 0)
47420cbbfb0SWilliam A. Kennington III         {
47520cbbfb0SWilliam A. Kennington III             async_subtree_done(r, subtree);
47620cbbfb0SWilliam A. Kennington III             goto exit;
47720cbbfb0SWilliam A. Kennington III         }
47820cbbfb0SWilliam A. Kennington III 
47920cbbfb0SWilliam A. Kennington III         r = sd_bus_message_at_end(m, false);
48020cbbfb0SWilliam A. Kennington III         if (r < 0)
48120cbbfb0SWilliam A. Kennington III         {
48220cbbfb0SWilliam A. Kennington III             async_subtree_done(r, subtree);
48320cbbfb0SWilliam A. Kennington III             goto exit;
48420cbbfb0SWilliam A. Kennington III         }
48520cbbfb0SWilliam A. Kennington III 
486167e2379SEd Tanous         /* For remove, operation is complete when the interface is not present
48720cbbfb0SWilliam A. Kennington III          * we know it is empty if the returned array is empty
488167e2379SEd Tanous          */
48920cbbfb0SWilliam A. Kennington III         if (r)
490b2f2681fSAdriana Kobylak             async_subtree_done(0, subtree);
491b2f2681fSAdriana Kobylak     }
492b2f2681fSAdriana Kobylak 
493b2f2681fSAdriana Kobylak exit:
494025d7959SAdriana Kobylak     return 0;
495025d7959SAdriana Kobylak }
496025d7959SAdriana Kobylak 
async_subtree_getpaths(mapper_async_subtree * subtree)497025d7959SAdriana Kobylak static int async_subtree_getpaths(mapper_async_subtree* subtree)
498025d7959SAdriana Kobylak {
499025d7959SAdriana Kobylak     int r = 0;
500025d7959SAdriana Kobylak 
501025d7959SAdriana Kobylak     subtree->retry = 0;
502025d7959SAdriana Kobylak     subtree->event_source = NULL;
503025d7959SAdriana Kobylak     r = sd_bus_call_method_async(
504*a02cd54cSBrad Bishop         subtree->conn, NULL, "xyz.openbmc_project.ObjectMapper",
505*a02cd54cSBrad Bishop         "/xyz/openbmc_project/object_mapper",
506*a02cd54cSBrad Bishop         "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
507*a02cd54cSBrad Bishop         async_subtree_getpaths_callback, subtree, "sias", subtree->namespace, 0,
508*a02cd54cSBrad Bishop         1, subtree->interface);
509167e2379SEd Tanous     if (r < 0)
510167e2379SEd Tanous     {
511025d7959SAdriana Kobylak         fprintf(stderr, "Error invoking method: %s\n", strerror(-r));
512025d7959SAdriana Kobylak         return r;
513025d7959SAdriana Kobylak     }
514025d7959SAdriana Kobylak 
515025d7959SAdriana Kobylak     return 0;
516025d7959SAdriana Kobylak }
517025d7959SAdriana Kobylak 
async_subtree_match_callback(_unused_ sd_bus_message * m,void * t,_unused_ sd_bus_error * e)5182d41d6abSBrad Bishop static int async_subtree_match_callback(_unused_ sd_bus_message* m, void* t,
5192d41d6abSBrad Bishop                                         _unused_ sd_bus_error* e)
52078edbb6fSAdriana Kobylak {
521b2f2681fSAdriana Kobylak     int r;
522b2f2681fSAdriana Kobylak 
523b2f2681fSAdriana Kobylak     mapper_async_subtree* subtree = t;
524b2f2681fSAdriana Kobylak     if (subtree->finished)
52578edbb6fSAdriana Kobylak         return 0;
526b2f2681fSAdriana Kobylak 
527b2f2681fSAdriana Kobylak     r = async_subtree_getpaths(subtree);
528b2f2681fSAdriana Kobylak     if (r < 0)
529b2f2681fSAdriana Kobylak         async_subtree_done(r, subtree);
530b2f2681fSAdriana Kobylak 
531b2f2681fSAdriana Kobylak     return 0;
532b2f2681fSAdriana Kobylak }
533b2f2681fSAdriana Kobylak 
async_subtree_done(int r,mapper_async_subtree * t)534b2f2681fSAdriana Kobylak static void async_subtree_done(int r, mapper_async_subtree* t)
535b2f2681fSAdriana Kobylak {
536b2f2681fSAdriana Kobylak     if (t->finished)
537b2f2681fSAdriana Kobylak         return;
538b2f2681fSAdriana Kobylak 
539b2f2681fSAdriana Kobylak     t->finished = 1;
540b2f2681fSAdriana Kobylak     sd_bus_slot_unref(t->slot);
541b2f2681fSAdriana Kobylak 
542b2f2681fSAdriana Kobylak     if (t->callback)
543b2f2681fSAdriana Kobylak         t->callback(r, t->userdata);
54478edbb6fSAdriana Kobylak }
54578edbb6fSAdriana Kobylak 
mapper_subtree_async(sd_bus * conn,sd_event * loop,char * namespace,char * interface,void (* callback)(int,void *),void * userdata,mapper_async_subtree ** t,int op)54675057c87SBrad Bishop _public_ int mapper_subtree_async(sd_bus* conn, sd_event* loop, char* namespace,
547167e2379SEd Tanous                                   char* interface, void (*callback)(int, void*),
54875057c87SBrad Bishop                                   void* userdata, mapper_async_subtree** t,
54975057c87SBrad Bishop                                   int op)
5502a8bfc96SAdriana Kobylak {
5512a8bfc96SAdriana Kobylak     int r = 0;
55278edbb6fSAdriana Kobylak     mapper_async_subtree* subtree = NULL;
55378edbb6fSAdriana Kobylak 
55478edbb6fSAdriana Kobylak     subtree = malloc(sizeof(*subtree));
55578edbb6fSAdriana Kobylak     if (!subtree)
55678edbb6fSAdriana Kobylak         return -ENOMEM;
55778edbb6fSAdriana Kobylak 
55878edbb6fSAdriana Kobylak     memset(subtree, 0, sizeof(*subtree));
55978edbb6fSAdriana Kobylak     subtree->conn = conn;
56078edbb6fSAdriana Kobylak     subtree->loop = loop;
56178edbb6fSAdriana Kobylak     subtree->namespace = namespace;
56278edbb6fSAdriana Kobylak     subtree->interface = interface;
56378edbb6fSAdriana Kobylak     subtree->callback = callback;
56478edbb6fSAdriana Kobylak     subtree->userdata = userdata;
56578edbb6fSAdriana Kobylak     subtree->op = op;
56678edbb6fSAdriana Kobylak 
567167e2379SEd Tanous     if (subtree->op == MAPPER_OP_REMOVE)
568167e2379SEd Tanous     {
569167e2379SEd Tanous         r = sd_bus_add_match(conn, &subtree->slot, interfaces_removed_match,
570167e2379SEd Tanous                              async_subtree_match_callback, subtree);
571167e2379SEd Tanous         if (r < 0)
572167e2379SEd Tanous         {
573167e2379SEd Tanous             fprintf(stderr, "Error adding match rule: %s\n", strerror(-r));
57478edbb6fSAdriana Kobylak             goto unref_slot;
57578edbb6fSAdriana Kobylak         }
576167e2379SEd Tanous     }
577167e2379SEd Tanous     else
578167e2379SEd Tanous     {
57978edbb6fSAdriana Kobylak         /* Operation not supported */
58078edbb6fSAdriana Kobylak         r = -EINVAL;
58178edbb6fSAdriana Kobylak         goto free_subtree;
58278edbb6fSAdriana Kobylak     }
58378edbb6fSAdriana Kobylak 
584025d7959SAdriana Kobylak     r = async_subtree_getpaths(subtree);
585167e2379SEd Tanous     if (r < 0)
586167e2379SEd Tanous     {
587167e2379SEd Tanous         fprintf(stderr, "Error calling method: %s\n", strerror(-r));
588025d7959SAdriana Kobylak         goto unref_slot;
589025d7959SAdriana Kobylak     }
590025d7959SAdriana Kobylak 
59178edbb6fSAdriana Kobylak     *t = subtree;
59278edbb6fSAdriana Kobylak 
59378edbb6fSAdriana Kobylak     return 0;
59478edbb6fSAdriana Kobylak 
59578edbb6fSAdriana Kobylak unref_slot:
59678edbb6fSAdriana Kobylak     sd_bus_slot_unref(subtree->slot);
59778edbb6fSAdriana Kobylak free_subtree:
59878edbb6fSAdriana Kobylak     free(subtree);
5992a8bfc96SAdriana Kobylak 
6002a8bfc96SAdriana Kobylak     return r;
6012a8bfc96SAdriana Kobylak }
6022a8bfc96SAdriana Kobylak 
mapper_get_object(sd_bus * conn,const char * obj,sd_bus_message ** reply)60375057c87SBrad Bishop _public_ int mapper_get_object(sd_bus* conn, const char* obj,
60475057c87SBrad Bishop                                sd_bus_message** reply)
60562ece2b4SBrad Bishop {
6063d46879cSBrad Bishop     sd_bus_message* request = NULL;
6073d46879cSBrad Bishop     int r, retry = 0;
60862ece2b4SBrad Bishop 
609*a02cd54cSBrad Bishop     r = sd_bus_message_new_method_call(
610*a02cd54cSBrad Bishop         conn, &request, "xyz.openbmc_project.ObjectMapper",
611*a02cd54cSBrad Bishop         "/xyz/openbmc_project/object_mapper",
612*a02cd54cSBrad Bishop         "xyz.openbmc_project.ObjectMapper", "GetObject");
61362ece2b4SBrad Bishop     if (r < 0)
61462ece2b4SBrad Bishop         goto exit;
61562ece2b4SBrad Bishop 
61662ece2b4SBrad Bishop     r = sd_bus_message_append(request, "s", obj);
61762ece2b4SBrad Bishop     if (r < 0)
61862ece2b4SBrad Bishop         goto exit;
619e1c7cf9eSBrad Bishop     r = sd_bus_message_append(request, "as", 0, NULL);
620e1c7cf9eSBrad Bishop     if (r < 0)
621e1c7cf9eSBrad Bishop         goto exit;
62262ece2b4SBrad Bishop 
6235e21ac01SWilliam A. Kennington III     while (true)
624167e2379SEd Tanous     {
6252482946eSWilliam A. Kennington III         r = sd_bus_call(conn, request, 0, NULL, reply);
6262482946eSWilliam A. Kennington III         if (r == -EBUSY || r == -ENOBUFS)
627167e2379SEd Tanous         {
6285e21ac01SWilliam A. Kennington III             if (retry >= mapper_busy_retries)
6295e21ac01SWilliam A. Kennington III                 break;
6303d46879cSBrad Bishop 
6315e21ac01SWilliam A. Kennington III             usleep(mapper_busy_delay_interval_usec * (1 << retry));
6325e21ac01SWilliam A. Kennington III             ++retry;
6333d46879cSBrad Bishop             continue;
6343d46879cSBrad Bishop         }
6353d46879cSBrad Bishop         break;
6363d46879cSBrad Bishop     }
6373d46879cSBrad Bishop 
6383d46879cSBrad Bishop     if (r < 0)
6393d46879cSBrad Bishop         goto exit;
6403d46879cSBrad Bishop 
6413d46879cSBrad Bishop exit:
6423d46879cSBrad Bishop     sd_bus_message_unref(request);
6433d46879cSBrad Bishop 
6443d46879cSBrad Bishop     return r;
6453d46879cSBrad Bishop }
6463d46879cSBrad Bishop 
mapper_get_service(sd_bus * conn,const char * obj,char ** service)64775057c87SBrad Bishop _public_ int mapper_get_service(sd_bus* conn, const char* obj, char** service)
6483d46879cSBrad Bishop {
6493d46879cSBrad Bishop     sd_bus_message* reply = NULL;
6503d46879cSBrad Bishop     const char* tmp;
6513d46879cSBrad Bishop     int r;
6523d46879cSBrad Bishop 
6533d46879cSBrad Bishop     r = mapper_get_object(conn, obj, &reply);
65462ece2b4SBrad Bishop     if (r < 0)
65562ece2b4SBrad Bishop         goto exit;
65662ece2b4SBrad Bishop 
65762ece2b4SBrad Bishop     r = sd_bus_message_enter_container(reply, 0, NULL);
65862ece2b4SBrad Bishop     if (r < 0)
65962ece2b4SBrad Bishop         goto exit;
66062ece2b4SBrad Bishop 
66162ece2b4SBrad Bishop     r = sd_bus_message_enter_container(reply, 0, NULL);
66262ece2b4SBrad Bishop     if (r < 0)
66362ece2b4SBrad Bishop         goto exit;
66462ece2b4SBrad Bishop 
66562ece2b4SBrad Bishop     r = sd_bus_message_read(reply, "s", &tmp);
66662ece2b4SBrad Bishop     if (r < 0)
66762ece2b4SBrad Bishop         goto exit;
66862ece2b4SBrad Bishop 
66962ece2b4SBrad Bishop     *service = strdup(tmp);
67062ece2b4SBrad Bishop 
67162ece2b4SBrad Bishop exit:
67262ece2b4SBrad Bishop     sd_bus_message_unref(reply);
67362ece2b4SBrad Bishop 
67462ece2b4SBrad Bishop     return r;
67562ece2b4SBrad Bishop }
676