mapper-cli: rewrite with sdbus
There are too many instances of the wait/call applications
spawned during BMC startup. Re-write using sdbus.
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
Change-Id: Ia6fb3b74cb70f93cfd5cc57c1a8b7a9aa2d944c4
diff --git a/libmapper/mapper.c b/libmapper/mapper.c
index 62dd2e6..3646cc1 100644
--- a/libmapper/mapper.c
+++ b/libmapper/mapper.c
@@ -13,10 +13,319 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <stdlib.h>
#include <string.h>
+#include <stdio.h>
+#include <errno.h>
#include <systemd/sd-bus.h>
#include "mapper.h"
+static const char *async_wait_name_owner_match =
+ "type='signal',"
+ "sender='org.freedesktop.DBus',"
+ "interface='org.freedesktop.DBus',"
+ "member='NameOwnerChanged',"
+ "path='/org/freedesktop/DBus'";
+
+static const char *async_wait_interfaces_added_match =
+ "type='signal',"
+ "interface='org.freedesktop.DBus.ObjectManager',"
+ "member='InterfacesAdded'";
+
+struct mapper_async_wait
+{
+ char **objs;
+ void (*callback)(int, void *);
+ void *userdata;
+ sd_bus *conn;
+ sd_bus_slot *name_owner_slot;
+ sd_bus_slot *intf_slot;
+ int *status;
+ int count;
+ int finished;
+ int r;
+};
+
+struct async_wait_callback_data
+{
+ mapper_async_wait *wait;
+ const char *path;
+};
+
+static int async_wait_match_name_owner_changed(sd_bus_message *, void *,
+ sd_bus_error *);
+static int async_wait_match_interfaces_added(sd_bus_message *, void *,
+ sd_bus_error *);
+static int async_wait_check_done(mapper_async_wait *);
+static void async_wait_done(int r, mapper_async_wait *);
+static int async_wait_get_objects(mapper_async_wait *);
+
+static int sarraylen(char *array[])
+{
+ int count = 0;
+ char **p = array;
+
+ while(*p != NULL) {
+ ++count;
+ ++p;
+ }
+
+ return count;
+}
+
+static void sarrayfree(char *array[])
+{
+ char **p = array;
+ while(*p != NULL) {
+ free(*p);
+ ++p;
+ }
+ free(array);
+}
+
+static char **sarraydup(char *array[])
+{
+ int count = sarraylen(array);
+ int i;
+ char **ret = NULL;
+
+ ret = malloc(sizeof(*ret) * count);
+ if(!ret)
+ return NULL;
+
+ for(i=0; i<count; ++i) {
+ ret[i] = strdup(array[i]);
+ if(!ret[i])
+ goto error;
+ }
+
+ return ret;
+
+error:
+ sarrayfree(ret);
+ return NULL;
+}
+
+static int async_wait_getobject_callback(sd_bus_message *m,
+ void *userdata,
+ sd_bus_error *e)
+{
+ int i, r;
+ const char *msg;
+ struct async_wait_callback_data *data = userdata;
+ mapper_async_wait *wait = data->wait;
+
+ if(wait->finished)
+ return 0;
+ if(sd_bus_message_get_errno(m))
+ return 0;
+
+ for(i=0; i<wait->count; ++i) {
+ if(!strcmp(data->path, wait->objs[i])) {
+ wait->status[i] = 1;
+ }
+ }
+
+ free(data);
+ if(async_wait_check_done(wait))
+ async_wait_done(0, wait);
+
+ return 0;
+}
+
+static int async_wait_get_objects(mapper_async_wait *wait)
+{
+ int i, r;
+ struct async_wait_callback_data *data = NULL;
+
+ for(i=0; i<wait->count; ++i) {
+ if(wait->status[i])
+ continue;
+ data = malloc(sizeof(*data));
+ data->wait = wait;
+ data->path = wait->objs[i];
+ r = sd_bus_call_method_async(
+ wait->conn,
+ NULL,
+ "org.openbmc.ObjectMapper",
+ "/org/openbmc/ObjectMapper",
+ "org.openbmc.ObjectMapper",
+ "GetObject",
+ async_wait_getobject_callback,
+ data,
+ "s",
+ wait->objs[i]);
+ if(r < 0) {
+ free(data);
+ fprintf(stderr, "Error invoking method: %s\n",
+ strerror(-r));
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+static int async_wait_match_name_owner_changed(sd_bus_message *m, void *w,
+ sd_bus_error *e)
+{
+ int i, r;
+
+ mapper_async_wait *wait = w;
+ if(wait->finished)
+ return 0;
+
+ r = async_wait_get_objects(wait);
+ if(r < 0)
+ async_wait_done(r, wait);
+
+ return 0;
+}
+
+static int async_wait_match_interfaces_added(sd_bus_message *m, void *w,
+ sd_bus_error *e)
+{
+ int i, r;
+ mapper_async_wait *wait = w;
+ const char *path;
+
+ if(wait->finished)
+ return 0;
+
+ r = sd_bus_message_read(m, "o", &path);
+ if (r < 0) {
+ fprintf(stderr, "Error reading message: %s\n",
+ strerror(-r));
+ goto finished;
+ }
+
+ for(i=0; i<wait->count; ++i) {
+ if(!strcmp(path, wait->objs[i]))
+ wait->status[i] = 1;
+ }
+
+finished:
+ if(r < 0 || async_wait_check_done(wait))
+ async_wait_done(r < 0 ? r : 0, wait);
+
+ return 0;
+}
+
+static void async_wait_done(int r, mapper_async_wait *w)
+{
+ if(w->finished)
+ return;
+
+ w->finished = 1;
+ sd_bus_slot_unref(w->name_owner_slot);
+ sd_bus_slot_unref(w->intf_slot);
+
+ if(w->callback)
+ w->callback(r, w->userdata);
+}
+
+static int async_wait_check_done(mapper_async_wait *w)
+{
+ int i;
+
+ if(w->finished)
+ return 1;
+
+ for(i=0; i<w->count; ++i)
+ if(!w->status[i])
+ return 0;
+
+ return 1;
+}
+
+void mapper_wait_async_free(mapper_async_wait *w)
+{
+ free(w->status);
+ sarrayfree(w->objs);
+ free(w);
+}
+
+int mapper_wait_async(sd_bus *conn,
+ char *objs[],
+ void (*callback)(int, void *),
+ void *userdata,
+ mapper_async_wait **w)
+{
+ int r;
+ mapper_async_wait *wait = NULL;
+
+ wait = malloc(sizeof(*wait));
+ if(!wait)
+ return -ENOMEM;
+
+ memset(wait, 0, sizeof(*wait));
+ wait->conn = conn;
+ wait->callback = callback;
+ wait->userdata = userdata;
+ wait->count = sarraylen(objs);
+ if(!wait->count)
+ return 0;
+
+ wait->objs = sarraydup(objs);
+ if(!wait->objs) {
+ r = -ENOMEM;
+ goto free_wait;
+ }
+
+ wait->status = malloc(sizeof(*wait->status) * wait->count);
+ if(!wait->status) {
+ r = -ENOMEM;
+ goto free_objs;
+ }
+ memset(wait->status, 0, sizeof(*wait->status) * wait->count);
+
+ r = sd_bus_add_match(conn,
+ &wait->name_owner_slot,
+ async_wait_name_owner_match,
+ async_wait_match_name_owner_changed,
+ wait);
+ if(r < 0) {
+ fprintf(stderr, "Error adding match rule: %s\n",
+ strerror(-r));
+ goto free_status;
+ }
+
+ r = sd_bus_add_match(conn,
+ &wait->intf_slot,
+ async_wait_interfaces_added_match,
+ async_wait_match_interfaces_added,
+ wait);
+ if(r < 0) {
+ fprintf(stderr, "Error adding match rule: %s\n",
+ strerror(-r));
+ goto unref_name_slot;
+ }
+
+ r = async_wait_get_objects(wait);
+ if(r < 0) {
+ fprintf(stderr, "Error calling method: %s\n",
+ strerror(-r));
+ goto unref_intf_slot;
+ }
+
+ *w = wait;
+
+ return 0;
+
+unref_intf_slot:
+ sd_bus_slot_unref(wait->intf_slot);
+unref_name_slot:
+ sd_bus_slot_unref(wait->name_owner_slot);
+free_status:
+ free(wait->status);
+free_objs:
+ sarrayfree(wait->objs);
+free_wait:
+ free(wait);
+
+ return r;
+}
+
int mapper_get_service(sd_bus *conn, const char *obj, char **service)
{
sd_bus_error error = SD_BUS_ERROR_NULL;