+/*
+ * Copyright (C) 2011 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
#include "ubusd.h"
#include "ubusd_obj.h"
static void ubus_unref_object_type(struct ubus_object_type *type)
{
- struct ubus_method *m;
+ struct ubus_method *m, *tmp;
if (--type->refcount > 0)
return;
- while (!list_empty(&type->methods)) {
- m = list_first_entry(&type->methods, struct ubus_method, list);
+ list_for_each_entry_safe(m, tmp, &type->methods, list) {
list_del(&m->list);
free(m);
}
if (!m)
return false;
- list_add(&m->list, &type->methods);
+ list_add_tail(&m->list, &type->methods);
memcpy(m->data, attr, bloblen);
m->name = blobmsg_name(m->data);
{
struct ubus_object_type *type;
struct blob_attr *pos;
- int rem;
+ size_t rem;
type = calloc(1, sizeof(*type));
+ if (!type)
+ return NULL;
+
type->refcount = 1;
if (!ubus_alloc_id(&obj_types, &type->id, 0))
obj->type = type;
INIT_LIST_HEAD(&obj->list);
INIT_LIST_HEAD(&obj->events);
+ INIT_LIST_HEAD(&obj->subscribers);
+ INIT_LIST_HEAD(&obj->target_list);
if (type)
type->refcount++;
else if (attr[UBUS_ATTR_SIGNATURE])
type = ubus_create_obj_type(attr[UBUS_ATTR_SIGNATURE]);
- if (!!type ^ !!attr[UBUS_ATTR_OBJPATH])
- return NULL;
-
obj = ubusd_create_object_internal(type, 0);
if (type)
ubus_unref_object_type(type);
return NULL;
if (attr[UBUS_ATTR_OBJPATH]) {
+ if (ubusd_acl_check(cl, blob_data(attr[UBUS_ATTR_OBJPATH]), NULL, UBUS_ACL_PUBLISH))
+ goto free;
+
obj->path.key = strdup(blob_data(attr[UBUS_ATTR_OBJPATH]));
if (!obj->path.key)
goto free;
if (avl_insert(&path, &obj->path) != 0) {
- free(obj->path.key);
+ free((void *) obj->path.key);
obj->path.key = NULL;
goto free;
}
return NULL;
}
+void ubus_subscribe(struct ubus_object *obj, struct ubus_object *target)
+{
+ struct ubus_subscription *s;
+ bool first = list_empty(&target->subscribers);
+
+ s = calloc(1, sizeof(*s));
+ if (!s)
+ return;
+
+ s->subscriber = obj;
+ s->target = target;
+ list_add(&s->list, &target->subscribers);
+ list_add(&s->target_list, &obj->target_list);
+
+ if (first)
+ ubus_notify_subscription(target);
+}
+
+void ubus_unsubscribe(struct ubus_subscription *s)
+{
+ struct ubus_object *obj = s->target;
+
+ list_del(&s->list);
+ list_del(&s->target_list);
+ free(s);
+
+ if (list_empty(&obj->subscribers))
+ ubus_notify_subscription(obj);
+}
+
void ubusd_free_object(struct ubus_object *obj)
{
+ struct ubus_subscription *s, *tmp;
+
+ list_for_each_entry_safe(s, tmp, &obj->target_list, target_list) {
+ ubus_unsubscribe(s);
+ }
+ list_for_each_entry_safe(s, tmp, &obj->subscribers, list) {
+ ubus_notify_unsubscribe(s);
+ }
+
ubusd_event_cleanup_object(obj);
if (obj->path.key) {
ubusd_send_obj_event(obj, false);
avl_delete(&path, &obj->path);
- free(obj->path.key);
+ free((void *) obj->path.key);
}
if (!list_empty(&obj->list))
list_del(&obj->list);
free(obj);
}
-static void __init ubusd_obj_init(void)
+static void __constructor ubusd_obj_init(void)
{
ubus_init_id_tree(&objects);
ubus_init_id_tree(&obj_types);
ubus_init_string_tree(&path, false);
ubusd_event_init();
+ ubusd_acl_init();
+ ubusd_monitor_init();
}