ucode: check for errors in ftruncate()
[project/udebug.git] / lib.c
1 #include "udebug.h"
2
3 static struct blob_attr *
4 find_attr(struct blob_attr *attr, const char *name, enum blobmsg_type type)
5 {
6 struct blobmsg_policy policy = { name, type };
7 struct blob_attr *ret;
8
9 if (!attr)
10 return NULL;
11
12 blobmsg_parse_attr(&policy, 1, &ret, attr);
13 return ret;
14 }
15
16 static void
17 udebug_ubus_msg_cb(struct udebug_ubus *ctx, struct blob_attr *data)
18 {
19 struct blob_attr *en_attr;
20 bool enabled;
21
22 data = find_attr(data, "service", BLOBMSG_TYPE_TABLE);
23 data = find_attr(data, ctx->service, BLOBMSG_TYPE_TABLE);
24 if (!data)
25 return;
26
27 en_attr = find_attr(data, "enabled", BLOBMSG_TYPE_STRING);
28 enabled = en_attr && !!atoi(blobmsg_get_string(en_attr));
29 ctx->cb(ctx, data, enabled);
30 }
31
32 static int
33 udebug_ubus_notify_cb(struct ubus_context *ubus, struct ubus_object *obj,
34 struct ubus_request_data *req, const char *method,
35 struct blob_attr *msg)
36 {
37 struct udebug_ubus *ctx = container_of(obj, struct udebug_ubus, sub.obj);
38
39 if (!strcmp(method, "config"))
40 udebug_ubus_msg_cb(ctx, msg);
41
42 return 0;
43 }
44
45 static void
46 udebug_ubus_req_cb(struct ubus_request *req, int type, struct blob_attr *msg)
47 {
48 udebug_ubus_msg_cb(req->priv, msg);
49 }
50
51 static bool
52 udebug_ubus_new_obj_cb(struct ubus_context *ubus, struct ubus_subscriber *sub,
53 const char *path)
54 {
55 struct udebug_ubus *ctx = container_of(sub, struct udebug_ubus, sub);
56
57 if (strcmp(path, "udebug") != 0)
58 return false;
59
60 uloop_timeout_set(&ctx->t, 1);
61 return true;
62 }
63
64 static void udebug_ubus_get_config(struct uloop_timeout *t)
65 {
66 struct udebug_ubus *ctx = container_of(t, struct udebug_ubus, t);
67 uint32_t id;
68
69 if (ubus_lookup_id(ctx->ubus, "udebug", &id))
70 return;
71
72 ubus_invoke(ctx->ubus, id, "get_config", NULL, udebug_ubus_req_cb, ctx, 1000);
73 }
74
75 void udebug_ubus_ring_init(struct udebug *ud, struct udebug_ubus_ring *ring)
76 {
77 if (!ring->size)
78 ring->size = ring->default_size;
79 if (!ring->entries)
80 ring->entries = ring->default_entries;
81 udebug_buf_init(ring->buf, ring->entries, ring->size);
82 udebug_buf_add(ud, ring->buf, ring->meta);
83 }
84
85 void udebug_ubus_apply_config(struct udebug *ud, struct udebug_ubus_ring *rings, int n,
86 struct blob_attr *data, bool enabled)
87 {
88 enum {
89 CFG_ATTR_ENABLE,
90 CFG_ATTR_SIZE,
91 CFG_ATTR_ENTRIES,
92 __CFG_ATTR_MAX,
93 };
94 static struct blobmsg_policy policy[] = {
95 [CFG_ATTR_ENABLE] = { NULL, BLOBMSG_TYPE_STRING },
96 [CFG_ATTR_SIZE] = { NULL, BLOBMSG_TYPE_STRING },
97 [CFG_ATTR_ENTRIES] = { NULL, BLOBMSG_TYPE_STRING },
98 };
99
100 for (size_t i = 0; i < n; i++) {
101 struct blob_attr *tb[__CFG_ATTR_MAX], *cur;
102 struct udebug_buf *buf = rings[i].buf;
103 const char *name = rings[i].meta->name;
104 int name_len = strlen(name);
105 unsigned int size, entries;
106 bool cur_enabled = enabled;
107 char *str;
108
109 policy[CFG_ATTR_ENABLE].name = name;
110
111 #define SIZE_FMT "%s_size"
112 str = alloca(sizeof(SIZE_FMT) + name_len);
113 sprintf(str, SIZE_FMT, name);
114 policy[CFG_ATTR_SIZE].name = str;
115
116 #define ENTRIES_FMT "%s_entries"
117 str = alloca(sizeof(ENTRIES_FMT) + name_len);
118 sprintf(str, ENTRIES_FMT, name);
119 policy[CFG_ATTR_ENTRIES].name = str;
120
121 blobmsg_parse_attr(policy, __CFG_ATTR_MAX, tb, data);
122
123 if (enabled && (cur = tb[CFG_ATTR_ENABLE]) != NULL)
124 cur_enabled = !!atoi(blobmsg_get_string(cur));
125
126 if ((cur = tb[CFG_ATTR_SIZE]) != NULL)
127 size = atoi(blobmsg_get_string(cur));
128 else
129 size = rings[i].default_size;
130
131 if ((cur = tb[CFG_ATTR_ENTRIES]) != NULL)
132 entries = atoi(blobmsg_get_string(cur));
133 else
134 entries = rings[i].default_entries;
135
136 if (udebug_buf_valid(buf) == cur_enabled &&
137 size == rings[i].size &&
138 entries == rings[i].entries)
139 continue;
140
141 if (udebug_buf_valid(buf))
142 udebug_buf_free(buf);
143
144 rings[i].size = size;
145 rings[i].entries = entries;
146 if (!cur_enabled)
147 continue;
148
149 udebug_ubus_ring_init(ud, &rings[i]);
150 }
151 }
152
153 void udebug_netlink_msg(struct udebug_buf *buf, uint16_t proto, const void *data, size_t len)
154 {
155 struct {
156 uint16_t pkttype;
157 uint16_t arphdr;
158 uint16_t _pad[5];
159 uint16_t proto;
160 } hdr = {
161 .arphdr = cpu_to_be16(824),
162 .proto = cpu_to_be16(proto),
163 };
164
165 if (!udebug_buf_valid(buf))
166 return;
167
168 udebug_entry_init(buf);
169 udebug_entry_append(buf, &hdr, sizeof(hdr));
170 udebug_entry_append(buf, data, len);
171 udebug_entry_add(buf);
172 }
173
174 void udebug_ubus_init(struct udebug_ubus *ctx, struct ubus_context *ubus,
175 const char *service, udebug_config_cb cb)
176 {
177 ctx->ubus = ubus;
178 ctx->service = service;
179 ctx->cb = cb;
180 ctx->sub.new_obj_cb = udebug_ubus_new_obj_cb;
181 ctx->sub.cb = udebug_ubus_notify_cb;
182 ubus_register_subscriber(ubus, &ctx->sub);
183
184 ctx->t.cb = udebug_ubus_get_config;
185 }
186
187 void udebug_ubus_free(struct udebug_ubus *ctx)
188 {
189 if (!ctx->ubus)
190 return;
191
192 uloop_timeout_cancel(&ctx->t);
193 ubus_unregister_subscriber(ctx->ubus, &ctx->sub);
194 }