2 * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
3 * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License version 2.1
7 * as published by the Free Software Foundation
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <sys/types.h>
19 #include <libubox/blobmsg_json.h>
20 #include <libubox/avl-cmp.h>
29 AVL_TREE(services
, avl_strcmp
, false, NULL
);
30 AVL_TREE(containers
, avl_strcmp
, false, NULL
);
31 static struct blob_buf b
;
32 static struct ubus_context
*ctx
;
33 static struct ubus_object main_object
;
36 service_instance_add(struct service
*s
, struct blob_attr
*attr
)
38 struct service_instance
*in
;
40 if (blobmsg_type(attr
) != BLOBMSG_TYPE_TABLE
)
43 in
= calloc(1, sizeof(*in
));
47 instance_init(in
, s
, attr
);
48 vlist_add(&s
->instances
, &in
->node
, (void *) in
->name
);
52 service_instance_update(struct vlist_tree
*tree
, struct vlist_node
*node_new
,
53 struct vlist_node
*node_old
)
55 struct service_instance
*in_o
= NULL
, *in_n
= NULL
;
58 in_o
= container_of(node_old
, struct service_instance
, node
);
61 in_n
= container_of(node_new
, struct service_instance
, node
);
64 DEBUG(2, "Update instance %s::%s\n", in_o
->srv
->name
, in_o
->name
);
65 instance_update(in_o
, in_n
);
68 DEBUG(2, "Stop instance %s::%s\n", in_o
->srv
->name
, in_o
->name
);
69 instance_stop(in_o
, true);
70 } else if (in_n
&& in_n
->srv
->autostart
) {
71 DEBUG(2, "Start instance %s::%s\n", in_n
->srv
->name
, in_n
->name
);
75 trigger_event("instance.update", b
.head
);
78 static struct service
*
79 service_alloc(const char *name
)
84 s
= calloc_a(sizeof(*s
), &new_name
, strlen(name
) + 1);
85 strcpy(new_name
, name
);
87 vlist_init(&s
->instances
, avl_strcmp
, service_instance_update
);
88 s
->instances
.no_delete
= true;
91 INIT_LIST_HEAD(&s
->validators
);
92 blobmsg_list_simple_init(&s
->data_blob
);
100 SERVICE_SET_INSTANCES
,
102 SERVICE_SET_VALIDATE
,
103 SERVICE_SET_AUTOSTART
,
108 static const struct blobmsg_policy service_set_attrs
[__SERVICE_SET_MAX
] = {
109 [SERVICE_SET_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
110 [SERVICE_SET_SCRIPT
] = { "script", BLOBMSG_TYPE_STRING
},
111 [SERVICE_SET_INSTANCES
] = { "instances", BLOBMSG_TYPE_TABLE
},
112 [SERVICE_SET_TRIGGER
] = { "triggers", BLOBMSG_TYPE_ARRAY
},
113 [SERVICE_SET_VALIDATE
] = { "validate", BLOBMSG_TYPE_ARRAY
},
114 [SERVICE_SET_AUTOSTART
] = { "autostart", BLOBMSG_TYPE_BOOL
},
115 [SERVICE_SET_DATA
] = { "data", BLOBMSG_TYPE_TABLE
},
119 service_update(struct service
*s
, struct blob_attr
**tb
, bool add
)
121 struct blob_attr
*cur
;
131 blobmsg_list_free(&s
->data_blob
);
136 service_validate_del(s
);
138 if (tb
[SERVICE_SET_AUTOSTART
] && !blobmsg_get_bool(tb
[SERVICE_SET_AUTOSTART
]))
139 s
->autostart
= false;
143 if (tb
[SERVICE_SET_TRIGGER
] && blobmsg_data_len(tb
[SERVICE_SET_TRIGGER
])) {
144 s
->trigger
= blob_memdup(tb
[SERVICE_SET_TRIGGER
]);
147 trigger_add(s
->trigger
, s
);
150 if (tb
[SERVICE_SET_VALIDATE
] && blobmsg_data_len(tb
[SERVICE_SET_VALIDATE
])) {
151 blobmsg_for_each_attr(cur
, tb
[SERVICE_SET_VALIDATE
], rem
)
152 service_validate_add(s
, cur
);
155 if (tb
[SERVICE_SET_INSTANCES
]) {
157 vlist_update(&s
->instances
);
158 blobmsg_for_each_attr(cur
, tb
[SERVICE_SET_INSTANCES
], rem
) {
159 service_instance_add(s
, cur
);
162 vlist_flush(&s
->instances
);
165 if (tb
[SERVICE_SET_DATA
] && blobmsg_data_len(tb
[SERVICE_SET_DATA
])) {
166 s
->data
= blob_memdup(tb
[SERVICE_SET_DATA
]);
169 blobmsg_list_fill(&s
->data_blob
, blobmsg_data(s
->data
),
170 blobmsg_data_len(s
->data
), false);
175 rc(s
->name
, "running");
180 static void _service_stopped(struct service
*s
, bool container
);
183 service_delete(struct service
*s
, bool container
)
185 blobmsg_list_free(&s
->data_blob
);
187 vlist_flush_all(&s
->instances
);
189 _service_stopped(s
, container
);
197 static const struct blobmsg_policy service_attrs
[__SERVICE_ATTR_MAX
] = {
198 [SERVICE_ATTR_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
202 SERVICE_DEL_ATTR_NAME
,
203 SERVICE_DEL_ATTR_INSTANCE
,
204 __SERVICE_DEL_ATTR_MAX
,
207 static const struct blobmsg_policy service_del_attrs
[__SERVICE_DEL_ATTR_MAX
] = {
208 [SERVICE_DEL_ATTR_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
209 [SERVICE_DEL_ATTR_INSTANCE
] = { "instance", BLOBMSG_TYPE_STRING
},
213 SERVICE_LIST_ATTR_NAME
,
214 SERVICE_LIST_ATTR_VERBOSE
,
215 __SERVICE_LIST_ATTR_MAX
,
218 static const struct blobmsg_policy service_list_attrs
[__SERVICE_LIST_ATTR_MAX
] = {
219 [SERVICE_LIST_ATTR_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
220 [SERVICE_LIST_ATTR_VERBOSE
] = { "verbose", BLOBMSG_TYPE_BOOL
},
224 SERVICE_SIGNAL_ATTR_NAME
,
225 SERVICE_SIGNAL_ATTR_INSTANCE
,
226 SERVICE_SIGNAL_ATTR_SIGNAL
,
227 __SERVICE_SIGNAL_ATTR_MAX
,
230 static const struct blobmsg_policy service_signal_attrs
[__SERVICE_SIGNAL_ATTR_MAX
] = {
231 [SERVICE_SIGNAL_ATTR_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
232 [SERVICE_SIGNAL_ATTR_INSTANCE
] = { "instance", BLOBMSG_TYPE_STRING
},
233 [SERVICE_SIGNAL_ATTR_SIGNAL
] = { "signal", BLOBMSG_TYPE_INT32
},
237 SERVICE_STATE_ATTR_SPAWN
,
238 SERVICE_STATE_ATTR_NAME
,
239 __SERVICE_STATE_ATTR_MAX
,
242 static const struct blobmsg_policy service_state_attrs
[__SERVICE_STATE_ATTR_MAX
] = {
243 [SERVICE_STATE_ATTR_SPAWN
] = { "spawn", BLOBMSG_TYPE_BOOL
},
244 [SERVICE_STATE_ATTR_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
253 static const struct blobmsg_policy event_policy
[__EVENT_MAX
] = {
254 [EVENT_TYPE
] = { .name
= "type", .type
= BLOBMSG_TYPE_STRING
},
255 [EVENT_DATA
] = { .name
= "data", .type
= BLOBMSG_TYPE_TABLE
},
265 static const struct blobmsg_policy validate_policy
[__VALIDATE_MAX
] = {
266 [VALIDATE_PACKAGE
] = { .name
= "package", .type
= BLOBMSG_TYPE_STRING
},
267 [VALIDATE_TYPE
] = { .name
= "type", .type
= BLOBMSG_TYPE_STRING
},
268 [VALIDATE_SERVICE
] = { .name
= "service", .type
= BLOBMSG_TYPE_STRING
},
278 static const struct blobmsg_policy get_data_policy
[] = {
279 [DATA_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
280 [DATA_INSTANCE
] = { "instance", BLOBMSG_TYPE_STRING
},
281 [DATA_TYPE
] = { "type", BLOBMSG_TYPE_STRING
},
285 CONTAINER_CONSOLE_NAME
,
286 CONTAINER_CONSOLE_INSTANCE
,
287 __CONTAINER_CONSOLE_MAX
,
290 static const struct blobmsg_policy container_console_policy
[__CONTAINER_CONSOLE_MAX
] = {
291 [CONTAINER_CONSOLE_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
292 [CONTAINER_CONSOLE_INSTANCE
] = { "instance", BLOBMSG_TYPE_STRING
},
295 static inline bool is_container_obj(struct ubus_object
*obj
)
297 return (obj
&& (strcmp(obj
->name
, "container") == 0));
301 service_handle_set(struct ubus_context
*ctx
, struct ubus_object
*obj
,
302 struct ubus_request_data
*req
, const char *method
,
303 struct blob_attr
*msg
)
305 struct blob_attr
*tb
[__SERVICE_SET_MAX
], *cur
;
306 struct service
*s
= NULL
;
308 bool container
= is_container_obj(obj
);
309 bool add
= !strcmp(method
, "add");
312 blobmsg_parse(service_set_attrs
, __SERVICE_SET_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
313 cur
= tb
[SERVICE_SET_NAME
];
315 return UBUS_STATUS_INVALID_ARGUMENT
;
317 name
= blobmsg_data(cur
);
320 s
= avl_find_element(&containers
, name
, s
, avl
);
322 s
= avl_find_element(&services
, name
, s
, avl
);
325 DEBUG(2, "Update service %s\n", name
);
326 return service_update(s
, tb
, add
);
329 DEBUG(2, "Create service %s\n", name
);
330 s
= service_alloc(name
);
332 return UBUS_STATUS_UNKNOWN_ERROR
;
334 ret
= service_update(s
, tb
, add
);
339 avl_insert(&containers
, &s
->avl
);
341 service_event("container.start", s
->name
, NULL
);
343 avl_insert(&services
, &s
->avl
);
345 service_event("service.start", s
->name
, NULL
);
351 service_dump(struct service
*s
, bool verbose
)
353 struct service_instance
*in
;
356 c
= blobmsg_open_table(&b
, s
->name
);
359 blobmsg_add_u8(&b
, "autostart", false);
361 if (!avl_is_empty(&s
->data_blob
.avl
)) {
362 struct blobmsg_list_node
*var
;
363 i
= blobmsg_open_table(&b
, "data");
364 blobmsg_list_for_each(&s
->data_blob
, var
)
365 blobmsg_add_blob(&b
, var
->data
);
366 blobmsg_close_table(&b
, i
);
369 if (!avl_is_empty(&s
->instances
.avl
)) {
370 i
= blobmsg_open_table(&b
, "instances");
371 vlist_for_each_element(&s
->instances
, in
, node
)
372 instance_dump(&b
, in
, verbose
);
373 blobmsg_close_table(&b
, i
);
375 if (verbose
&& s
->trigger
)
376 blobmsg_add_blob(&b
, s
->trigger
);
377 if (verbose
&& !list_empty(&s
->validators
))
378 service_validate_dump(&b
, s
);
379 blobmsg_close_table(&b
, c
);
383 service_handle_list(struct ubus_context
*ctx
, struct ubus_object
*obj
,
384 struct ubus_request_data
*req
, const char *method
,
385 struct blob_attr
*msg
)
387 struct blob_attr
*tb
[__SERVICE_LIST_ATTR_MAX
];
389 const char *name
= NULL
;
390 bool verbose
= false;
391 bool container
= is_container_obj(obj
);
392 const struct avl_tree
*tree
= container
?&containers
:&services
;
394 blobmsg_parse(service_list_attrs
, __SERVICE_LIST_ATTR_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
396 if (tb
[SERVICE_LIST_ATTR_VERBOSE
])
397 verbose
= blobmsg_get_bool(tb
[SERVICE_LIST_ATTR_VERBOSE
]);
398 if (tb
[SERVICE_LIST_ATTR_NAME
])
399 name
= blobmsg_get_string(tb
[SERVICE_LIST_ATTR_NAME
]);
401 blob_buf_init(&b
, 0);
402 avl_for_each_element(tree
, s
, avl
) {
403 if (name
&& strcmp(s
->name
, name
) != 0)
406 service_dump(s
, verbose
);
409 ubus_send_reply(ctx
, req
, b
.head
);
415 service_handle_delete(struct ubus_context
*ctx
, struct ubus_object
*obj
,
416 struct ubus_request_data
*req
, const char *method
,
417 struct blob_attr
*msg
)
419 struct blob_attr
*tb
[__SERVICE_DEL_ATTR_MAX
], *cur
;
421 struct service_instance
*in
;
422 bool container
= is_container_obj(obj
);
424 blobmsg_parse(service_del_attrs
, __SERVICE_DEL_ATTR_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
426 cur
= tb
[SERVICE_DEL_ATTR_NAME
];
428 return UBUS_STATUS_NOT_FOUND
;
431 s
= avl_find_element(&containers
, blobmsg_data(cur
), s
, avl
);
433 s
= avl_find_element(&services
, blobmsg_data(cur
), s
, avl
);
436 return UBUS_STATUS_NOT_FOUND
;
438 cur
= tb
[SERVICE_DEL_ATTR_INSTANCE
];
440 service_delete(s
, container
);
444 in
= vlist_find(&s
->instances
, blobmsg_data(cur
), in
, node
);
446 ERROR("instance %s not found\n", (char *) blobmsg_data(cur
));
447 return UBUS_STATUS_NOT_FOUND
;
450 vlist_delete(&s
->instances
, &in
->node
);
456 service_handle_kill(struct service_instance
*in
, int sig
)
458 if (kill(in
->proc
.pid
, sig
) == 0)
462 case EINVAL
: return UBUS_STATUS_INVALID_ARGUMENT
;
463 case EPERM
: return UBUS_STATUS_PERMISSION_DENIED
;
464 case ESRCH
: return UBUS_STATUS_NOT_FOUND
;
467 return UBUS_STATUS_UNKNOWN_ERROR
;
471 service_handle_signal(struct ubus_context
*ctx
, struct ubus_object
*obj
,
472 struct ubus_request_data
*req
, const char *method
,
473 struct blob_attr
*msg
)
475 struct blob_attr
*tb
[__SERVICE_SIGNAL_ATTR_MAX
], *cur
;
477 struct service_instance
*in
;
478 bool container
= is_container_obj(obj
);
482 blobmsg_parse(service_signal_attrs
, __SERVICE_SIGNAL_ATTR_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
484 cur
= tb
[SERVICE_SIGNAL_ATTR_SIGNAL
];
486 sig
= blobmsg_get_u32(cur
);
488 cur
= tb
[SERVICE_SIGNAL_ATTR_NAME
];
490 return UBUS_STATUS_NOT_FOUND
;
493 s
= avl_find_element(&containers
, blobmsg_data(cur
), s
, avl
);
495 s
= avl_find_element(&services
, blobmsg_data(cur
), s
, avl
);
498 return UBUS_STATUS_NOT_FOUND
;
500 cur
= tb
[SERVICE_SIGNAL_ATTR_INSTANCE
];
502 vlist_for_each_element(&s
->instances
, in
, node
)
503 rv
= service_handle_kill(in
, sig
);
508 in
= vlist_find(&s
->instances
, blobmsg_data(cur
), in
, node
);
510 ERROR("instance %s not found\n", blobmsg_get_string(cur
));
511 return UBUS_STATUS_NOT_FOUND
;
514 return service_handle_kill(in
, sig
);
518 service_handle_state(struct ubus_context
*ctx
, struct ubus_object
*obj
,
519 struct ubus_request_data
*req
, const char *method
,
520 struct blob_attr
*msg
)
522 struct blob_attr
*tb
[__SERVICE_STATE_ATTR_MAX
];
524 struct service_instance
*in
;
525 bool container
= is_container_obj(obj
);
528 blobmsg_parse(service_state_attrs
, __SERVICE_STATE_ATTR_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
530 if (!tb
[SERVICE_STATE_ATTR_SPAWN
])
531 return UBUS_STATUS_INVALID_ARGUMENT
;
533 if (!tb
[SERVICE_STATE_ATTR_NAME
])
534 return UBUS_STATUS_NOT_FOUND
;
537 s
= avl_find_element(&containers
, blobmsg_data(tb
[SERVICE_STATE_ATTR_NAME
]), s
, avl
);
539 s
= avl_find_element(&services
, blobmsg_data(tb
[SERVICE_STATE_ATTR_NAME
]), s
, avl
);
542 return UBUS_STATUS_NOT_FOUND
;
544 spawn
= !!blobmsg_get_u8(tb
[SERVICE_STATE_ATTR_SPAWN
]);
545 vlist_for_each_element(&s
->instances
, in
, node
) {
546 if (!!in
->proc
.pending
== !!spawn
)
548 else if (!in
->proc
.pending
)
551 instance_stop(in
, false);
554 return UBUS_STATUS_OK
;
558 service_handle_update(struct ubus_context
*ctx
, struct ubus_object
*obj
,
559 struct ubus_request_data
*req
, const char *method
,
560 struct blob_attr
*msg
)
562 struct blob_attr
*tb
[__SERVICE_ATTR_MAX
], *cur
;
564 bool container
= is_container_obj(obj
);
566 blobmsg_parse(service_attrs
, __SERVICE_ATTR_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
568 cur
= tb
[SERVICE_SET_NAME
];
570 return UBUS_STATUS_INVALID_ARGUMENT
;
573 s
= avl_find_element(&containers
, blobmsg_data(cur
), s
, avl
);
575 s
= avl_find_element(&services
, blobmsg_data(cur
), s
, avl
);
578 return UBUS_STATUS_NOT_FOUND
;
580 if (!strcmp(method
, "update_start"))
581 vlist_update(&s
->instances
);
583 vlist_flush(&s
->instances
);
588 static void ubus_event_bcast(const char *type
, const char *param1
, const char *val1
,
589 const char *param2
, const char *val2
)
594 blob_buf_init(&b
, 0);
596 blobmsg_add_string(&b
, param1
, val1
);
598 blobmsg_add_string(&b
, param2
, val2
);
599 ubus_notify(ctx
, &main_object
, type
, b
.head
, -1);
603 service_handle_event(struct ubus_context
*ctx
, struct ubus_object
*obj
,
604 struct ubus_request_data
*req
, const char *method
,
605 struct blob_attr
*msg
)
607 struct blob_attr
*tb
[__EVENT_MAX
];
611 return UBUS_STATUS_INVALID_ARGUMENT
;
613 blobmsg_parse(event_policy
, __EVENT_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
614 if (!tb
[EVENT_TYPE
] || !tb
[EVENT_DATA
])
615 return UBUS_STATUS_INVALID_ARGUMENT
;
617 event
= blobmsg_get_string(tb
[EVENT_TYPE
]);
618 trigger_event(event
, tb
[EVENT_DATA
]);
620 if (!strcmp(event
, "config.change")) {
621 struct blob_attr
*tb2
[__VALIDATE_MAX
];
623 blobmsg_parse(validate_policy
, __VALIDATE_MAX
, tb2
,
624 blobmsg_data(tb
[EVENT_DATA
]), blobmsg_data_len(tb
[EVENT_DATA
]));
625 if (tb2
[VALIDATE_PACKAGE
])
626 ubus_event_bcast("config.change", "config",
627 blobmsg_get_string(tb2
[VALIDATE_PACKAGE
]), NULL
, NULL
);
633 service_handle_validate(struct ubus_context
*ctx
, struct ubus_object
*obj
,
634 struct ubus_request_data
*req
, const char *method
,
635 struct blob_attr
*msg
)
637 struct blob_attr
*tb
[__VALIDATE_MAX
];
638 char *p
= NULL
, *t
= NULL
;
641 return UBUS_STATUS_INVALID_ARGUMENT
;
643 blobmsg_parse(validate_policy
, __VALIDATE_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
644 if (tb
[VALIDATE_SERVICE
]) {
647 if (tb
[VALIDATE_PACKAGE
])
648 p
= blobmsg_get_string(tb
[VALIDATE_PACKAGE
]);
650 if (tb
[VALIDATE_TYPE
])
651 t
= blobmsg_get_string(tb
[VALIDATE_TYPE
]);
653 blob_buf_init(&b
, 0);
654 service_validate_dump_all(&b
, p
, t
);
655 ubus_send_reply(ctx
, req
, b
.head
);
661 service_get_data(struct ubus_context
*ctx
, struct ubus_object
*obj
,
662 struct ubus_request_data
*req
, const char *method
,
663 struct blob_attr
*msg
)
665 struct service_instance
*in
;
667 struct blob_attr
*tb
[__DATA_MAX
];
668 const char *name
= NULL
;
669 const char *instance
= NULL
;
670 const char *type
= NULL
;
672 blobmsg_parse(get_data_policy
, __DATA_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
674 name
= blobmsg_data(tb
[DATA_NAME
]);
675 if (tb
[DATA_INSTANCE
])
676 instance
= blobmsg_data(tb
[DATA_INSTANCE
]);
678 type
= blobmsg_data(tb
[DATA_TYPE
]);
680 blob_buf_init(&b
, 0);
681 avl_for_each_element(&services
, s
, avl
) {
684 struct blobmsg_list_node
*var
;
686 if (name
&& strcmp(name
, s
->name
))
689 blobmsg_list_for_each(&s
->data_blob
, var
) {
690 if (type
&& strcmp(blobmsg_name(var
->data
), type
))
694 cs
= blobmsg_open_table(&b
, s
->name
);
696 blobmsg_add_blob(&b
, var
->data
);
699 vlist_for_each_element(&s
->instances
, in
, node
) {
702 if (instance
&& strcmp(instance
, in
->name
))
705 blobmsg_list_for_each(&in
->data
, var
) {
707 strcmp(blobmsg_name(var
->data
), type
))
711 cs
= blobmsg_open_table(&b
, s
->name
);
713 ci
= blobmsg_open_table(&b
, in
->name
);
715 blobmsg_add_blob(&b
, var
->data
);
719 blobmsg_close_table(&b
, ci
);
723 blobmsg_close_table(&b
, cs
);
726 ubus_send_reply(ctx
, req
, b
.head
);
731 container_handle_console(struct ubus_context
*ctx
, struct ubus_object
*obj
,
732 struct ubus_request_data
*req
, const char *method
,
733 struct blob_attr
*msg
)
735 bool attach
= !strcmp(method
, "console_attach");
736 struct blob_attr
*tb
[__CONTAINER_CONSOLE_MAX
];
738 struct service_instance
*in
;
741 console_fd
= ubus_request_get_caller_fd(req
);
743 return UBUS_STATUS_INVALID_ARGUMENT
;
748 blobmsg_parse(container_console_policy
, __CONTAINER_CONSOLE_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
749 if (!tb
[CONTAINER_CONSOLE_NAME
])
752 s
= avl_find_element(&containers
, blobmsg_data(tb
[CONTAINER_CONSOLE_NAME
]), s
, avl
);
756 if (tb
[CONTAINER_CONSOLE_INSTANCE
]) {
757 in
= vlist_find(&s
->instances
, blobmsg_data(tb
[CONTAINER_CONSOLE_INSTANCE
]), in
, node
);
759 /* use first element in instances list */
760 vlist_for_each_element(&s
->instances
, in
, node
)
767 if (in
->console
.fd
.fd
< 0) {
769 return UBUS_STATUS_NOT_SUPPORTED
;
772 /* close and replace existing attached console */
773 if (in
->console_client
.fd
.fd
> -1)
774 close(in
->console_client
.fd
.fd
);
776 ustream_fd_init(&in
->console_client
, console_fd
);
778 ustream_fd_init(&in
->console
, console_fd
);
781 return UBUS_STATUS_OK
;
784 return UBUS_STATUS_INVALID_ARGUMENT
;
788 static struct ubus_method main_object_methods
[] = {
789 UBUS_METHOD("set", service_handle_set
, service_set_attrs
),
790 UBUS_METHOD("add", service_handle_set
, service_set_attrs
),
791 UBUS_METHOD("list", service_handle_list
, service_list_attrs
),
792 UBUS_METHOD("delete", service_handle_delete
, service_del_attrs
),
793 UBUS_METHOD("signal", service_handle_signal
, service_signal_attrs
),
794 UBUS_METHOD("update_start", service_handle_update
, service_attrs
),
795 UBUS_METHOD("update_complete", service_handle_update
, service_attrs
),
796 UBUS_METHOD("event", service_handle_event
, event_policy
),
797 UBUS_METHOD("validate", service_handle_validate
, validate_policy
),
798 UBUS_METHOD("get_data", service_get_data
, get_data_policy
),
799 UBUS_METHOD("state", service_handle_state
, service_state_attrs
),
802 static struct ubus_object_type main_object_type
=
803 UBUS_OBJECT_TYPE("service", main_object_methods
);
805 static struct ubus_object main_object
= {
807 .type
= &main_object_type
,
808 .methods
= main_object_methods
,
809 .n_methods
= ARRAY_SIZE(main_object_methods
),
813 service_start_early(char *name
, char *cmdline
)
815 void *instances
, *instance
, *command
, *respawn
;
818 blob_buf_init(&b
, 0);
819 blobmsg_add_string(&b
, "name", name
);
820 instances
= blobmsg_open_table(&b
, "instances");
821 instance
= blobmsg_open_table(&b
, "instance1");
822 command
= blobmsg_open_array(&b
, "command");
823 t
= strtok(cmdline
, " ");
825 blobmsg_add_string(&b
, NULL
, t
);
826 t
= strtok(NULL
, " ");
828 blobmsg_close_array(&b
, command
);
829 respawn
= blobmsg_open_array(&b
, "respawn");
830 blobmsg_add_string(&b
, NULL
, "3600");
831 blobmsg_add_string(&b
, NULL
, "1");
832 blobmsg_add_string(&b
, NULL
, "0");
833 blobmsg_close_array(&b
, respawn
);
834 blobmsg_close_table(&b
, instance
);
835 blobmsg_close_table(&b
, instances
);
837 return service_handle_set(NULL
, NULL
, NULL
, "add", b
.head
);
840 void service_stopped(struct service
*s
)
842 _service_stopped(s
, false);
845 static void _service_stopped(struct service
*s
, bool container
)
847 if (s
->deleted
&& avl_is_empty(&s
->instances
.avl
)) {
849 service_event("container.stop", s
->name
, NULL
);
850 avl_delete(&containers
, &s
->avl
);
852 service_event("service.stop", s
->name
, NULL
);
853 avl_delete(&services
, &s
->avl
);
856 service_validate_del(s
);
862 void service_event(const char *type
, const char *service
, const char *instance
)
864 ubus_event_bcast(type
, "service", service
, "instance", instance
);
867 static struct ubus_method container_object_methods
[] = {
868 UBUS_METHOD("set", service_handle_set
, service_set_attrs
),
869 UBUS_METHOD("add", service_handle_set
, service_set_attrs
),
870 UBUS_METHOD("list", service_handle_list
, service_list_attrs
),
871 UBUS_METHOD("delete", service_handle_delete
, service_del_attrs
),
872 UBUS_METHOD("signal", service_handle_signal
, service_signal_attrs
),
873 UBUS_METHOD("state", service_handle_state
, service_state_attrs
),
874 UBUS_METHOD("console_set", container_handle_console
, container_console_policy
),
875 UBUS_METHOD("console_attach", container_handle_console
, container_console_policy
),
878 static struct ubus_object_type container_object_type
=
879 UBUS_OBJECT_TYPE("container", container_object_methods
);
881 static struct ubus_object container_object
= {
883 .type
= &container_object_type
,
884 .methods
= container_object_methods
,
885 .n_methods
= ARRAY_SIZE(container_object_methods
),
888 void ubus_init_service(struct ubus_context
*_ctx
)
893 ubus_add_object(ctx
, &main_object
);
895 if (!stat("/sbin/ujail", &statbuf
))
896 ubus_add_object(ctx
, &container_object
);