ca82d0b53d7b7d2d5f3a33e2f78610b261248720
[project/udebug.git] / ubus.c
1 #include <fnmatch.h>
2 #include <libubus.h>
3 #include "server.h"
4
5 struct ubus_auto_conn conn;
6 struct blob_buf b;
7 static struct ubus_object udebug_object;
8 static struct blob_attr *service_config;
9
10 enum {
11 LIST_ATTR_PROCNAME,
12 LIST_ATTR_RINGNAME,
13 LIST_ATTR_PID,
14 LIST_ATTR_UID,
15 __LIST_ATTR_MAX,
16 };
17
18 static const struct blobmsg_policy list_policy[__LIST_ATTR_MAX] = {
19 [LIST_ATTR_PROCNAME] = { "proc_name", BLOBMSG_TYPE_ARRAY },
20 [LIST_ATTR_RINGNAME] = { "ring_name", BLOBMSG_TYPE_ARRAY },
21 [LIST_ATTR_PID] = { "pid", BLOBMSG_TYPE_ARRAY },
22 [LIST_ATTR_UID] = { "uid", BLOBMSG_TYPE_ARRAY },
23 };
24
25 static bool
26 string_array_match(const char *val, struct blob_attr *match)
27 {
28 struct blob_attr *cur;
29 int rem;
30
31 if (!match || !blobmsg_len(match))
32 return true;
33
34 if (blobmsg_check_array(match, BLOBMSG_TYPE_STRING) < 0)
35 return false;
36
37 blobmsg_for_each_attr(cur, match, rem) {
38 if (fnmatch(blobmsg_get_string(cur), val, 0) == 0)
39 return true;
40 }
41
42 return false;
43 }
44
45 static bool
46 int_array_match(unsigned int val, struct blob_attr *match)
47 {
48 struct blob_attr *cur;
49 int rem;
50
51 if (!match || !blobmsg_len(match))
52 return true;
53
54 if (blobmsg_check_array(match, BLOBMSG_TYPE_INT32) < 0)
55 return false;
56
57 blobmsg_for_each_attr(cur, match, rem) {
58 if (val == blobmsg_get_u32(cur))
59 return true;
60 }
61
62 return false;
63 }
64
65 static bool
66 udebug_list_match(struct client_ring *r, struct blob_attr **tb)
67 {
68 return string_array_match(r->cl->proc_name, tb[LIST_ATTR_PROCNAME]) &&
69 string_array_match(r->name, tb[LIST_ATTR_RINGNAME]) &&
70 int_array_match(r->cl->pid, tb[LIST_ATTR_PID]) &&
71 int_array_match(r->cl->uid, tb[LIST_ATTR_UID]);
72 }
73
74 static void
75 udebug_list_add_ring_data(struct client_ring *r)
76 {
77 blobmsg_add_u32(&b, "id", ring_id(r));
78 blobmsg_add_string(&b, "proc_name", r->cl->proc_name);
79 blobmsg_add_string(&b, "ring_name", r->name);
80 blobmsg_add_u32(&b, "pid", r->cl->pid);
81 blobmsg_add_u32(&b, "uid", r->cl->uid);
82 if (r->flags)
83 blobmsg_add_blob(&b, r->flags);
84 }
85
86 void udebug_ubus_ring_notify(struct client_ring *r, bool add)
87 {
88 blob_buf_init(&b, 0);
89 udebug_list_add_ring_data(r);
90 ubus_notify(&conn.ctx, &udebug_object, add ? "add" : "remove", b.head, -1);
91 }
92
93 static void
94 udebug_list_add_ring(struct client_ring *r)
95 {
96 void *c;
97
98 c = blobmsg_open_table(&b, NULL);
99 udebug_list_add_ring_data(r);
100 blobmsg_close_table(&b, c);
101 }
102
103 static int
104 udebug_list(struct ubus_context *ctx, struct ubus_object *obj,
105 struct ubus_request_data *req, const char *method,
106 struct blob_attr *msg)
107 {
108 struct blob_attr *tb[__LIST_ATTR_MAX];
109 struct client_ring *r;
110 void *c;
111
112 blobmsg_parse_attr(list_policy, __LIST_ATTR_MAX, tb, msg);
113
114 blob_buf_init(&b, 0);
115 c = blobmsg_open_array(&b, "results");
116 avl_for_each_element(&rings, r, node)
117 if (udebug_list_match(r, tb))
118 udebug_list_add_ring(r);
119 blobmsg_close_array(&b, c);
120 ubus_send_reply(ctx, req, b.head);
121
122 return 0;
123 }
124
125 enum {
126 CFG_ATTR_SERVICE,
127 __CFG_ATTR_MAX
128 };
129 static const struct blobmsg_policy config_policy[__CFG_ATTR_MAX] = {
130 [CFG_ATTR_SERVICE] = { "service", BLOBMSG_TYPE_TABLE },
131 };
132
133 static struct blob_attr *
134 udebug_fill_config(void)
135 {
136 blob_buf_init(&b, 0);
137 if (service_config)
138 blobmsg_add_blob(&b, service_config);
139 else
140 blobmsg_close_table(&b, blobmsg_open_table(&b, "service"));
141
142 return b.head;
143 }
144
145 static int
146 udebug_set_config(struct ubus_context *ctx, struct ubus_object *obj,
147 struct ubus_request_data *req, const char *method,
148 struct blob_attr *msg)
149 {
150 struct blob_attr *tb[__CFG_ATTR_MAX], *cur;
151
152 blobmsg_parse_attr(config_policy, __CFG_ATTR_MAX, tb, msg);
153 if ((cur = tb[CFG_ATTR_SERVICE]) != NULL) {
154 free(service_config);
155 service_config = blob_memdup(cur);
156 ubus_notify(ctx, obj, "config", udebug_fill_config(), -1);
157 }
158
159 return 0;
160 }
161
162 static int
163 udebug_get_config(struct ubus_context *ctx, struct ubus_object *obj,
164 struct ubus_request_data *req, const char *method,
165 struct blob_attr *msg)
166 {
167 ubus_send_reply(ctx, req, udebug_fill_config());
168 return 0;
169 }
170
171 static const struct ubus_method udebug_methods[] = {
172 UBUS_METHOD("list", udebug_list, list_policy),
173 UBUS_METHOD("set_config", udebug_set_config, config_policy),
174 UBUS_METHOD_NOARG("get_config", udebug_get_config),
175 };
176
177 static struct ubus_object_type udebug_object_type =
178 UBUS_OBJECT_TYPE("udebug", udebug_methods);
179
180 static struct ubus_object udebug_object = {
181 .name = "udebug",
182 .type = &udebug_object_type,
183 .methods = udebug_methods,
184 .n_methods = ARRAY_SIZE(udebug_methods),
185 };
186
187 static void ubus_connect_cb(struct ubus_context *ctx)
188 {
189 ubus_add_object(ctx, &udebug_object);
190 }
191
192 void udebug_ubus_init(void)
193 {
194 conn.cb = ubus_connect_cb;
195 ubus_auto_connect(&conn);
196 }
197
198 void udebug_ubus_free(void)
199 {
200 ubus_auto_shutdown(&conn);
201 }