1 #include <libubox/avl-cmp.h>
5 struct avl_tree services;
6 static struct blob_buf b;
9 start_instance(struct service_instance *in)
15 instance_timeout(struct uloop_timeout *t)
17 struct service_instance *in;
19 in = container_of(t, struct service_instance, timeout);
20 kill(in->proc.pid, SIGKILL);
21 uloop_process_delete(&in->proc);
22 in->proc.cb(&in->proc, -1);
26 instance_exit(struct uloop_process *p, int ret)
28 struct service_instance *in;
30 in = container_of(p, struct service_instance, proc);
31 uloop_timeout_cancel(&in->timeout);
37 stop_instance(struct service_instance *in, bool restart)
39 if (!in->proc.pending)
42 kill(in->proc.pid, SIGTERM);
46 instance_config_changed(struct service_instance *in, struct service_instance *in_new)
48 int len = blob_pad_len(in->config);
50 if (len != blob_pad_len(in_new->config))
53 if (memcmp(in->config, in_new->config, blob_pad_len(in->config)) != 0)
60 update_instance(struct service_instance *in, struct service_instance *in_new)
62 bool changed = instance_config_changed(in, in_new);
64 in->config = in_new->config;
68 stop_instance(in, true);
73 free_instance(struct service_instance *in)
75 uloop_process_delete(&in->proc);
76 uloop_timeout_cancel(&in->timeout);
81 init_instance(struct service_instance *in, struct blob_attr *config)
84 in->timeout.cb = instance_timeout;
85 in->proc.cb = instance_exit;
89 service_instance_add(struct service *s, struct blob_attr *attr)
91 struct service_instance *in;
92 const char *name = blobmsg_name(attr);
94 if (blobmsg_type(attr) != BLOBMSG_TYPE_TABLE)
97 in = calloc(1, sizeof(*in));
101 init_instance(in, attr);
102 vlist_add(&s->instances, &in->node, (void *) name);
106 service_instance_update(struct vlist_tree *tree, struct vlist_node *node_new,
107 struct vlist_node *node_old)
109 struct service_instance *in_o = NULL, *in_n = NULL;
112 in_o = container_of(node_old, struct service_instance, node);
115 in_n = container_of(node_new, struct service_instance, node);
118 update_instance(in_o, in_n);
121 stop_instance(in_o, false);
124 start_instance(in_n);
128 static struct service *
129 service_alloc(const char *name)
133 s = calloc(1, sizeof(*s));
134 vlist_init(&s->instances, avl_strcmp, service_instance_update);
135 s->instances.keep_old = true;
143 SERVICE_ATTR_INSTANCES,
147 static const struct blobmsg_policy service_attrs[__SERVICE_ATTR_MAX] = {
148 [SERVICE_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING },
149 [SERVICE_ATTR_SCRIPT] = { "script", BLOBMSG_TYPE_STRING },
150 [SERVICE_ATTR_INSTANCES] = { "instances", BLOBMSG_TYPE_TABLE },
155 service_update(struct service *s, struct blob_attr *config, struct blob_attr **tb)
157 struct blob_attr *old_config = s->config;
158 struct blob_attr *cur;
161 /* only the pointer changes, the content stays the same,
162 * no avl update necessary */
163 s->name = s->avl.key = blobmsg_data(tb[SERVICE_ATTR_NAME]);
166 if (tb[SERVICE_ATTR_INSTANCES]) {
167 vlist_update(&s->instances);
168 blobmsg_for_each_attr(cur, tb[SERVICE_ATTR_INSTANCES], rem) {
169 service_instance_add(s, cur);
171 vlist_flush(&s->instances);
180 service_delete(struct service *s)
182 vlist_flush_all(&s->instances);
183 avl_delete(&services, &s->avl);
189 service_handle_set(struct ubus_context *ctx, struct ubus_object *obj,
190 struct ubus_request_data *req, const char *method,
191 struct blob_attr *msg)
193 struct blob_attr *tb[__SERVICE_ATTR_MAX], *cur;
194 struct service *s = NULL;
196 int ret = UBUS_STATUS_INVALID_ARGUMENT;
198 msg = blob_memdup(msg);
200 return UBUS_STATUS_UNKNOWN_ERROR;
202 blobmsg_parse(service_attrs, __SERVICE_ATTR_MAX, tb, blob_data(msg), blob_len(msg));
203 cur = tb[SERVICE_ATTR_NAME];
207 name = blobmsg_data(cur);
209 s = avl_find_element(&services, name, s, avl);
211 return service_update(s, msg, tb);
213 s = service_alloc(name);
215 return UBUS_STATUS_UNKNOWN_ERROR;
217 ret = service_update(s, msg, tb);
221 avl_insert(&services, &s->avl);
231 service_handle_list(struct ubus_context *ctx, struct ubus_object *obj,
232 struct ubus_request_data *req, const char *method,
233 struct blob_attr *msg)
237 blob_buf_init(&b, 0);
238 avl_for_each_element(&services, s, avl) {
241 c = blobmsg_open_table(&b, s->name);
242 blobmsg_close_table(&b, c);
245 ubus_send_reply(ctx, req, b.head);
255 static const struct blobmsg_policy service_del_attrs[__SERVICE_DEL_MAX] = {
256 [SERVICE_DEL_NAME] = { "name", BLOBMSG_TYPE_STRING },
261 service_handle_delete(struct ubus_context *ctx, struct ubus_object *obj,
262 struct ubus_request_data *req, const char *method,
263 struct blob_attr *msg)
265 struct blob_attr *tb[__SERVICE_DEL_MAX], *cur;
266 struct service *s, *tmp;
268 blobmsg_parse(service_del_attrs, __SERVICE_DEL_MAX, tb, blob_data(msg), blob_len(msg));
270 cur = tb[SERVICE_ATTR_NAME];
272 avl_for_each_element_safe(&services, s, avl, tmp)
277 s = avl_find_element(&services, blobmsg_data(cur), s, avl);
279 return UBUS_STATUS_NOT_FOUND;
285 static struct ubus_method main_object_methods[] = {
286 { .name = "list", .handler = service_handle_list },
287 { .name = "set", .handler = service_handle_set },
288 { .name = "delete", .handler = service_handle_delete },
291 static struct ubus_object_type main_object_type =
292 UBUS_OBJECT_TYPE("service", main_object_methods);
294 static struct ubus_object main_object = {
296 .type = &main_object_type,
297 .methods = main_object_methods,
298 .n_methods = ARRAY_SIZE(main_object_methods),
301 void procd_init_service(struct ubus_context *ctx)
303 avl_init(&services, avl_strcmp, false, NULL);
304 ubus_add_object(ctx, &main_object);