diff options
-rw-r--r-- | hcid/dbus-service.c | 147 | ||||
-rw-r--r-- | hcid/dbus-service.h | 1 | ||||
-rw-r--r-- | hcid/main.c | 5 |
3 files changed, 91 insertions, 62 deletions
diff --git a/hcid/dbus-service.c b/hcid/dbus-service.c index e060938e..bb9bc336 100644 --- a/hcid/dbus-service.c +++ b/hcid/dbus-service.c @@ -37,6 +37,7 @@ #include "hcid.h" #include "dbus.h" +#include "notify.h" #include "dbus-common.h" #include "dbus-error.h" #include "dbus-manager.h" @@ -125,6 +126,9 @@ static void service_free(struct service *service) if (!service) return; + if (service->filename) + free(service->filename); + if (service->object_path) free(service->object_path); @@ -735,16 +739,18 @@ static const DBusObjectPathVTable services_vtable = { .unregister_function = NULL }; -int register_service(char *path, struct service *service) +static int register_service(struct service *service) { - char obj_path[PATH_MAX], *slash; + char obj_path[PATH_MAX], *suffix; DBusConnection *conn = get_dbus_connection(); DBusMessage *signal; - path[strlen(path) - strlen(SERVICE_SUFFIX)] = '\0'; - slash = strrchr(path, '/'); + snprintf(obj_path, sizeof(obj_path) - 1, "/org/bluez/service_%s", + service->filename); - snprintf(obj_path, sizeof(obj_path) - 1, "/org/bluez/service_%s", slash + 1); + /* Don't include the .service part in the path */ + suffix = strstr(obj_path, SERVICE_SUFFIX); + *suffix = '\0'; debug("Registering service object: exec=%s, name=%s (%s)", service->exec, service->name, obj_path); @@ -755,7 +761,7 @@ int register_service(char *path, struct service *service) service->object_path = strdup(obj_path); - services = g_slist_append(services, strdup(obj_path)); + services = g_slist_append(services, service); signal = dbus_message_new_signal(BASE_PATH, MANAGER_INTERFACE, "ServiceAdded"); @@ -771,51 +777,23 @@ int register_service(char *path, struct service *service) return 0; } -int unregister_service(const char *sender, const char *path) +static int unregister_service(struct service *service) { - struct service *service; + DBusMessage *signal; DBusConnection *conn = get_dbus_connection(); - GSList *l; - - debug("Unregistering service object: %s", path); - - if (dbus_connection_get_object_path_data(conn, path, (void *) &service)) { - /* No data assigned to this path or it is not the owner */ - if (!service || strcmp(sender, service->bus_name)) - return -EPERM; - - if (service->records) - unregister_service_records(service->records); - service_free(service); - } + debug("Unregistering service object: %s", service->object_path); - if (!dbus_connection_unregister_object_path(conn, path)) + if (!dbus_connection_unregister_object_path(conn, service->object_path)) return -ENOMEM; - name_listener_remove(conn, sender, (name_cb_t) service_exit, service); - - l = g_slist_find_custom(services, path, (GCompareFunc) strcmp); - if (l) { - void *p = l->data; - services = g_slist_remove(services, l->data); - free(p); - } - - return 0; -} - -static void release_service(struct service *service) -{ - DBusMessage *signal; - signal = dbus_message_new_signal(BASE_PATH, MANAGER_INTERFACE, "ServiceRemoved"); if (signal) { dbus_message_append_args(signal, DBUS_TYPE_STRING, &service->object_path, DBUS_TYPE_INVALID); - send_message_and_unref(get_dbus_connection(), signal); + send_message_and_unref(conn, signal); } if (service->records) @@ -850,33 +828,16 @@ static void release_service(struct service *service) if (service->shutdown_timer) g_timeout_remove(service->shutdown_timer); + services = g_slist_remove(services, service); + service_free(service); } void release_services(DBusConnection *conn) { - GSList *l = services; - struct service *service; - const char *path; - debug("release_services"); - while (l) { - path = l->data; - - l = l->next; - - if (dbus_connection_get_object_path_data(conn, path, (void *) &service)) { - if (!service) - continue; - - release_service(service); - } - - dbus_connection_unregister_object_path(conn, path); - } - - g_slist_foreach(services, (GFunc) free, NULL); + g_slist_foreach(services, (GFunc) unregister_service, NULL); g_slist_free(services); services = NULL; } @@ -909,15 +870,19 @@ void append_available_services(DBusMessageIter *array_iter) { GSList *l; - for (l = services; l != NULL; l = l->next) + for (l = services; l != NULL; l = l->next) { + struct service *service = l->data; + dbus_message_iter_append_basic(array_iter, - DBUS_TYPE_STRING, &l->data); + DBUS_TYPE_STRING, &service->object_path); + } } static struct service *create_service(const char *file) { GKeyFile *keyfile; struct service *service; + const char *slash; service = malloc(sizeof(struct service)); if (!service) { @@ -948,6 +913,14 @@ static struct service *create_service(const char *file) goto failed; } + slash = strrchr(file, '/'); + if (!slash) { + error("No slash in service file path!?"); + goto failed; + } + + service->filename = strdup(slash + 1); + service->descr = g_key_file_get_string(keyfile, SERVICE_GROUP, "Description", NULL); @@ -964,6 +937,54 @@ failed: return NULL; } +static gint service_filename_cmp(struct service *service, const char *filename) +{ + return strcmp(service->filename, filename); +} + +static void service_notify(int action, const char *name, void *user_data) +{ + GSList *l; + struct service *service; + size_t len; + char fullpath[PATH_MAX]; + + len = strlen(name); + if (len < (strlen(SERVICE_SUFFIX) + 1)) + return; + + if (strcmp(name + (len - strlen(SERVICE_SUFFIX)), SERVICE_SUFFIX)) + return; + + switch (action) { + case NOTIFY_CREATE: + debug("%s was created", name); + snprintf(fullpath, sizeof(fullpath) - 1, "%s/%s", CONFIGDIR, name); + service = create_service(fullpath); + if (!service) { + error("Unable to read %s", fullpath); + break; + } + + register_service(service); + + break; + case NOTIFY_DELETE: + debug("%s was deleted", name); + l = g_slist_find_custom(services, name, + (GCompareFunc) service_filename_cmp); + if (l) + unregister_service(l->data); + break; + case NOTIFY_MODIFY: + debug("%s was modified", name); + break; + default: + debug("Unknown notify action %d", action); + break; + } +} + int init_services(const char *path) { DIR *d; @@ -995,11 +1016,13 @@ int init_services(const char *path) continue; } - register_service(full_path, service); + register_service(service); } closedir(d); + notify_add(path, service_notify, NULL); + return 0; } diff --git a/hcid/dbus-service.h b/hcid/dbus-service.h index 94fd580a..f0f66721 100644 --- a/hcid/dbus-service.h +++ b/hcid/dbus-service.h @@ -27,6 +27,7 @@ #define START_REPLY_TIMEOUT 5000 struct service { + char *filename; char *object_path; DBusMessage *action; /* Either Start or Stop method call */ diff --git a/hcid/main.c b/hcid/main.c index c7461c03..5da2216b 100644 --- a/hcid/main.c +++ b/hcid/main.c @@ -43,6 +43,7 @@ #include <bluetooth/hci_lib.h> #include "glib-ectomy.h" +#include "notify.h" #include "hcid.h" #include "sdpd.h" @@ -757,6 +758,8 @@ int main(int argc, char *argv[]) if (sdp) start_sdp_server(0, SDP_SERVER_COMPAT); + notify_init(); + init_services(CONFIGDIR); /* Start event processor */ @@ -769,6 +772,8 @@ int main(int argc, char *argv[]) hcid_dbus_exit(); + notify_close(); + cleanup_sdp_session(); g_main_loop_unref(event_loop); |