diff options
| author | Brad Bishop <bradleyb@fuzziesquirrel.com> | 2016-08-13 14:08:17 -0400 |
|---|---|---|
| committer | Brad Bishop <bradleyb@fuzziesquirrel.com> | 2016-08-16 17:25:10 -0400 |
| commit | 2afe718f96f1a6d947de4ea0e7d06853400a72a7 (patch) | |
| tree | 939b57a43623da47d1fdf4673b7235736df6540f | |
| parent | 22ff24a6e668d00557ef6465f96d664fe33226f3 (diff) | |
| download | phosphor-objmgr-2afe718f96f1a6d947de4ea0e7d06853400a72a7.tar.gz phosphor-objmgr-2afe718f96f1a6d947de4ea0e7d06853400a72a7.zip | |
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
| -rw-r--r-- | libmapper/Makefile | 13 | ||||
| -rw-r--r-- | libmapper/app.c | 159 | ||||
| -rw-r--r-- | libmapper/mapper.c | 309 | ||||
| -rw-r--r-- | libmapper/mapper.h | 5 | ||||
| -rw-r--r-- | mapper | 23 | ||||
| -rw-r--r-- | obmc/mapper/cli.py | 125 | ||||
| -rw-r--r-- | setup.py | 2 |
7 files changed, 484 insertions, 152 deletions
diff --git a/libmapper/Makefile b/libmapper/Makefile index 806390c..2f71515 100644 --- a/libmapper/Makefile +++ b/libmapper/Makefile @@ -1,16 +1,18 @@ libdir=/usr/lib +sbindir=/usr/sbin includedir=/usr/include PACKAGE_DEPS=libsystemd SONAME=libmapper.so VERSION=1 LIBMAPPER=$(SONAME).$(VERSION) +BIN=mapper INCLUDES=mapper.h LDLIBS+=$(shell pkg-config --libs $(PACKAGE_DEPS)) ALL_CFLAGS+=$(shell pkg-config --cflags $(PACKAGE_DEPS)) -fPIC -Werror $(CFLAGS) -all: $(SONAME) +all: $(SONAME) $(BIN) %.o: %.c $(CC) -c $(ALL_CFLAGS) -o $@ $< @@ -22,12 +24,17 @@ $(LIBMAPPER): lib%.so.$(VERSION): %.o $(CC) -shared $(CFLAGS) $(LDFLAGS) -Wl,-soname,$(SONAME) \ -o $@ $^ $(LDLIBS) -install: $(SONAME) $(LIBMAPPER) +$(BIN): app.o $(LIBMAPPER) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +install: $(SONAME) $(LIBMAPPER) $(BIN) @mkdir -p $(DESTDIR)$(includedir) install $(INCLUDES) $(DESTDIR)$(includedir) @mkdir -p $(DESTDIR)$(libdir) install $(LIBMAPPER) $(DESTDIR)$(libdir) ln -sf $(LIBMAPPER) $(DESTDIR)$(libdir)/$(SONAME) + @mkdir -p $(DESTDIR)$(sbindir) + install $(BIN) $(DESTDIR)$(sbindir) clean: - rm -f *.o $(LIBMAPPER) $(SONAME) + rm -f *.o $(LIBMAPPER) $(SONAME) $(BIN) diff --git a/libmapper/app.c b/libmapper/app.c new file mode 100644 index 0000000..e2b94eb --- /dev/null +++ b/libmapper/app.c @@ -0,0 +1,159 @@ +/** + * Copyright © 2016 IBM Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <stdlib.h> +#include <stdio.h> +#include <systemd/sd-bus.h> +#include <systemd/sd-event.h> +#include "mapper.h" + +static int call_main(int argc, char *argv[]) +{ + int r; + sd_bus *conn = NULL; + char *service = NULL; + sd_bus_message *m = NULL, *reply = NULL; + sd_bus_error error = SD_BUS_ERROR_NULL; + + if(argc < 5) { + fprintf(stderr, "Usage: %s call OBJECTPATH INTERFACE " + "METHOD [SIGNATURE [ARGUMENT...]\n", argv[0]); + r = -1; + goto finish; + } + + r = sd_bus_default_system(&conn); + if(r < 0) { + fprintf(stderr, "Error connecting to system bus: %s\n", + strerror(-r)); + goto finish; + } + + r = mapper_get_service(conn, argv[2], &service); + if(r < 0) { + fprintf(stderr, "Error finding service: %s\n", + strerror(-r)); + goto finish; + } + + r = sd_bus_message_new_method_call( + conn, &m, service, argv[2], argv[3], argv[4]); + if(r < 0) { + fprintf(stderr, "Error populating message: %s\n", + strerror(-r)); + goto finish; + } + + if(argc > 5) { + char **p; + p = argv + 6; + r = sd_bus_message_append_cmdline(m, argv[5], &p); + if(r < 0) { + fprintf(stderr, "Error appending method arguments: %s\n", + strerror(-r)); + goto finish; + } + } + + r = sd_bus_call(conn, m, 0, &error, &reply); + if(r < 0) { + fprintf(stderr, "Error invoking method: %s\n", + strerror(-r)); + goto finish; + } + +finish: + exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS); +} + +static void quit(int r, void *loop) +{ + sd_event_exit((sd_event *)loop, r); +} + +static int wait_main(int argc, char *argv[]) +{ + int r; + sd_bus *conn = NULL; + sd_event *loop = NULL; + mapper_async_wait *wait = NULL; + + if(argc < 3) { + fprintf(stderr, "Usage: %s wait OBJECTPATH...\n", argv[0]); + exit(EXIT_FAILURE); + } + + r = sd_bus_default_system(&conn); + if(r < 0) { + fprintf(stderr, "Error connecting to system bus: %s\n", + strerror(-r)); + goto finish; + } + + r = sd_event_default(&loop); + if (r < 0) { + fprintf(stderr, "Error obtaining event loop: %s\n", + strerror(-r)); + + goto finish; + } + + r = sd_bus_attach_event(conn, loop, SD_EVENT_PRIORITY_NORMAL); + if (r < 0) { + fprintf(stderr, "Failed to attach system " + "bus to event loop: %s\n", + strerror(-r)); + goto finish; + } + + r = mapper_wait_async(conn, argv+2, quit, loop, &wait); + if(r < 0) { + fprintf(stderr, "Error configuring waitlist: %s\n", + strerror(-r)); + goto finish; + } + + r = sd_event_loop(loop); + if(r < 0) { + fprintf(stderr, "Error starting event loop: %s\n", + strerror(-r)); + goto finish; + } + +finish: + exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS); +} + +int main(int argc, char *argv[]) +{ + static const char *usage = + "Usage: %s {COMMAND} ...\n" + "\nCOMMANDS:\n" + " call invoke the specified method\n" + " wait wait for the specified objects to appear on the DBus\n"; + + if(argc < 2) { + fprintf(stderr, usage, argv[0]); + exit(EXIT_FAILURE); + } + + if(!strcmp(argv[1], "call")) + call_main(argc, argv); + if(!strcmp(argv[1], "wait")) + wait_main(argc, argv); + + fprintf(stderr, usage, argv[0]); + exit(EXIT_FAILURE); +} 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; diff --git a/libmapper/mapper.h b/libmapper/mapper.h index 58f1844..b49b302 100644 --- a/libmapper/mapper.h +++ b/libmapper/mapper.h @@ -3,6 +3,11 @@ #ifdef __cplusplus extern "C" { #endif +typedef struct mapper_async_wait mapper_async_wait; +void mapper_wait_async_free(mapper_async_wait *); + +int mapper_wait_async(sd_bus *, char *[], + void (*)(int, void *), void *, mapper_async_wait **); int mapper_get_service(sd_bus *conn, const char *obj, char **service); #ifdef __cplusplus } @@ -1,23 +0,0 @@ -#!/usr/bin/env python - -# Contributors Listed Below - COPYRIGHT 2016 -# [+] International Business Machines Corp. -# -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. See the License for the specific language governing -# permissions and limitations under the License. - -import sys -import obmc.mapper.cli - -if __name__ == '__main__': - sys.exit(obmc.mapper.cli.mapper_main()) diff --git a/obmc/mapper/cli.py b/obmc/mapper/cli.py deleted file mode 100644 index 7f96316..0000000 --- a/obmc/mapper/cli.py +++ /dev/null @@ -1,125 +0,0 @@ -# Contributors Listed Below - COPYRIGHT 2016 -# [+] International Business Machines Corp. -# -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. See the License for the specific language governing -# permissions and limitations under the License. - -import sys -import dbus -import dbus.mainloop.glib -import gobject -import obmc.dbuslib.enums -import obmc.mapper -import obmc.mapper.utils -import optparse - - -def add_systemd_path_option(parser): - parser.add_option( - '-s', '--systemd', action='store_true', default=False, - help='interpret-dash-delimited-path-arguments-as-paths') - - -def systemd_to_dbus(item): - if not item.startswith('/'): - item = '/%s' % item.replace('-', '/') - return item - - -class CallApp(object): - usage = 'OBJECTPATH INTERFACE METHOD ARGUMENTS...' - description = 'Invoke a DBus method on the named DBus object.' - - def setup(self, parser, command): - add_systemd_path_option(parser) - - def main(self, parser): - args = parser.largs - try: - path, interface, method, parameters = \ - args[0], args[1], args[2], args[3:] - except IndexError: - parser.error('Not enough arguments') - - bus = dbus.SystemBus() - mapper = obmc.mapper.Mapper(bus) - if parser.values.systemd: - path = systemd_to_dbus(path) - - try: - service_info = mapper.get_object(path) - except dbus.exceptions.DBusException, e: - if e.get_dbus_name() != obmc.mapper.MAPPER_NOT_FOUND: - raise - parser.error('\'%s\' was not found' % path) - - obj = bus.get_object(list(service_info)[0], path, introspect=False) - iface = dbus.Interface(obj, interface) - func = getattr(iface, method) - try: - return func(*parameters) - except dbus.exceptions.DBusException, e: - if e.get_dbus_name() != obmc.dbuslib.enums.DBUS_UNKNOWN_METHOD: - raise - parser.error( - '\'%s.%s\' is not a valid method for \'%s\'' - % (interface, method, path)) - - -class WaitApp(object): - usage = 'OBJECTPATH...' - description = 'Wait for one or more DBus ' \ - 'object(s) to appear on the system bus.' - - def setup(self, parser, command): - add_systemd_path_option(parser) - - def main(self, parser): - if not parser.largs: - parser.error('Specify one or more object paths') - - dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) - loop = gobject.MainLoop() - bus = dbus.SystemBus() - if parser.values.systemd: - waitlist = [systemd_to_dbus(x) for x in parser.largs] - else: - waitlist = parser.largs - - waiter = obmc.mapper.utils.Wait(bus, waitlist, callback=loop.quit) - loop.run() - - -def mapper_main(): - all_commands = [] - usage = '''%prog [options] SUBCOMMAND\n\nSUBCOMMANDS:\n''' - for k, v in sys.modules[__name__].__dict__.iteritems(): - if k.endswith('App'): - all_commands.append(k.replace('App', '').lower()) - usage += ' %s - %s\n' % (all_commands[-1], v.description) - - parser = optparse.OptionParser(usage=usage) - commands = list(set(sys.argv[1:]).intersection(all_commands)) - if len(commands) != 1: - parser.error('Specify a single sub-command') - - classname = '%sApp' % commands[0].capitalize() - cls = getattr(sys.modules[__name__], classname) - usage = getattr(cls, 'usage') - - parser.set_usage('%%prog %s [options] %s' % (commands[0], usage)) - inst = cls() - inst.setup(parser, commands[0]) - opts, args = parser.parse_args() - parser.largs = parser.largs[1:] - return inst.main(parser) @@ -2,5 +2,5 @@ from distutils.core import setup setup(name='phosphor-mapper', version='1.0', packages=['obmc.mapper'], - scripts=['phosphor-mapper', 'mapper'] + scripts=['phosphor-mapper'] ) |

