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
);