ucode: check for errors in ftruncate()
[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 blobmsg_add_u32(&b, "ring_size", r->ring_size);
83 blobmsg_add_u32(&b, "data_size", r->data_size);
84 if (r->flags)
85 blobmsg_add_blob(&b, r->flags);
86 }
87
88 void udebug_ubus_ring_notify(struct client_ring *r, bool add)
89 {
90 blob_buf_init(&b, 0);
91 udebug_list_add_ring_data(r);
92 ubus_notify(&conn.ctx, &udebug_object, add ? "add" : "remove", b.head, -1);
93 }
94
95 static void
96 udebug_list_add_ring(struct client_ring *r)
97 {
98 void *c;
99
100 c = blobmsg_open_table(&b, NULL);
101 udebug_list_add_ring_data(r);
102 blobmsg_close_table(&b, c);
103 }
104
105 static int
106 udebug_list(struct ubus_context *ctx, struct ubus_object *obj,
107 struct ubus_request_data *req, const char *method,
108 struct blob_attr *msg)
109 {
110 struct blob_attr *tb[__LIST_ATTR_MAX];
111 struct client_ring *r;
112 void *c;
113
114 blobmsg_parse_attr(list_policy, __LIST_ATTR_MAX, tb, msg);
115
116 blob_buf_init(&b, 0);
117 c = blobmsg_open_array(&b, "results");
118 avl_for_each_element(&rings, r, node)
119 if (udebug_list_match(r, tb))
120 udebug_list_add_ring(r);
121 blobmsg_close_array(&b, c);
122 ubus_send_reply(ctx, req, b.head);
123
124 return 0;
125 }
126
127 enum {
128 CFG_ATTR_SERVICE,
129 __CFG_ATTR_MAX
130 };
131 static const struct blobmsg_policy config_policy[__CFG_ATTR_MAX] = {
132 [CFG_ATTR_SERVICE] = { "service", BLOBMSG_TYPE_TABLE },
133 };
134
135 static struct blob_attr *
136 udebug_fill_config(void)
137 {
138 blob_buf_init(&b, 0);
139 if (service_config)
140 blobmsg_add_blob(&b, service_config);
141 else
142 blobmsg_close_table(&b, blobmsg_open_table(&b, "service"));
143
144 return b.head;
145 }
146
147 static int
148 udebug_set_config(struct ubus_context *ctx, struct ubus_object *obj,
149 struct ubus_request_data *req, const char *method,
150 struct blob_attr *msg)
151 {
152 struct blob_attr *tb[__CFG_ATTR_MAX], *cur;
153
154 blobmsg_parse_attr(config_policy, __CFG_ATTR_MAX, tb, msg);
155 if ((cur = tb[CFG_ATTR_SERVICE]) != NULL) {
156 free(service_config);
157 service_config = blob_memdup(cur);
158 ubus_notify(ctx, obj, "config", udebug_fill_config(), -1);
159 }
160
161 return 0;
162 }
163
164 static int
165 udebug_get_config(struct ubus_context *ctx, struct ubus_object *obj,
166 struct ubus_request_data *req, const char *method,
167 struct blob_attr *msg)
168 {
169 ubus_send_reply(ctx, req, udebug_fill_config());
170 return 0;
171 }
172
173 static const struct ubus_method udebug_methods[] = {
174 UBUS_METHOD("list", udebug_list, list_policy),
175 UBUS_METHOD("set_config", udebug_set_config, config_policy),
176 UBUS_METHOD_NOARG("get_config", udebug_get_config),
177 };
178
179 static struct ubus_object_type udebug_object_type =
180 UBUS_OBJECT_TYPE("udebug", udebug_methods);
181
182 static struct ubus_object udebug_object = {
183 .name = "udebug",
184 .type = &udebug_object_type,
185 .methods = udebug_methods,
186 .n_methods = ARRAY_SIZE(udebug_methods),
187 };
188
189 static void ubus_connect_cb(struct ubus_context *ctx)
190 {
191 ubus_add_object(ctx, &udebug_object);
192 }
193
194 void udebug_ubus_init(void)
195 {
196 conn.cb = ubus_connect_cb;
197 ubus_auto_connect(&conn);
198 }
199
200 void udebug_ubus_free(void)
201 {
202 ubus_auto_shutdown(&conn);
203 }