From b9b39e2061d7035a9d84eecbb4a4613deaf6d03f Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 20 May 2020 15:26:08 +0100 Subject: [PATCH] jail: handle containers seperately To make the API more clean and running containers less of a hidden feature offer new object ubus 'containers' to handle container operations similar to how services are handled. Signed-off-by: Daniel Golle --- jail/console.c | 16 +++--- jail/jail.c | 2 +- service/service.c | 138 ++++++++++++++++++++++++++++++++++++---------- service/service.h | 1 + 4 files changed, 118 insertions(+), 39 deletions(-) diff --git a/jail/console.c b/jail/console.c index d03edc5..eacb2fa 100644 --- a/jail/console.c +++ b/jail/console.c @@ -56,14 +56,14 @@ static inline int setup_tios(int fd, struct termios *oldtios) -#define OPT_ARGS "i:s:" +#define OPT_ARGS "i:c:" static struct ustream_fd cufd; static struct ustream_fd lufd; static void usage() { - fprintf(stderr, "ujail-console -s [-i ]\n"); + fprintf(stderr, "ujail-console -c [-i ]\n"); exit(1); } @@ -115,7 +115,7 @@ int main(int argc, char **argv) struct ubus_context *ctx; uint32_t id; static struct blob_buf req; - char *service_name = NULL, *instance_name = NULL; + char *container_name = NULL, *instance_name = NULL; int client_fd, server_fd, tty_fd; struct termios oldtermios; int ch; @@ -125,15 +125,15 @@ int main(int argc, char **argv) case 'i': instance_name = optarg; break; - case 's': - service_name = optarg; + case 'c': + container_name = optarg; break; default: usage(); } } - if (!service_name) + if (!container_name) usage(); ctx = ubus_connect(NULL); @@ -166,11 +166,11 @@ int main(int argc, char **argv) /* register server-side with procd */ blob_buf_init(&req, 0); - blobmsg_add_string(&req, "name", service_name); + blobmsg_add_string(&req, "name", container_name); if (instance_name) blobmsg_add_string(&req, "instance", instance_name); - if (ubus_lookup_id(ctx, "service", &id) || + if (ubus_lookup_id(ctx, "container", &id) || ubus_invoke_fd(ctx, id, "console_attach", req.head, NULL, NULL, 3000, server_fd)) { fprintf(stderr, "ubus request failed\n"); close(server_fd); diff --git a/jail/jail.c b/jail/jail.c index 540b8d4..4590690 100644 --- a/jail/jail.c +++ b/jail/jail.c @@ -199,7 +199,7 @@ static void pass_console(int console_fd) blob_buf_init(&req, 0); blobmsg_add_string(&req, "name", opts.name); - if (ubus_lookup_id(ctx, "service", &id) || + if (ubus_lookup_id(ctx, "container", &id) || ubus_invoke_fd(ctx, id, "console_set", req.head, NULL, NULL, 3000, console_fd)) INFO("ubus request failed\n"); else diff --git a/service/service.c b/service/service.c index 1d26291..fcf0215 100644 --- a/service/service.c +++ b/service/service.c @@ -12,6 +12,10 @@ * GNU General Public License for more details. */ +#include +#include +#include + #include #include @@ -23,6 +27,7 @@ #include "../rcS.h" AVL_TREE(services, avl_strcmp, false, NULL); +AVL_TREE(containers, avl_strcmp, false, NULL); static struct blob_buf b; static struct ubus_context *ctx; static struct ubus_object main_object; @@ -172,14 +177,16 @@ service_update(struct service *s, struct blob_attr **tb, bool add) return 0; } +static void _service_stopped(struct service *s, bool container); + static void -service_delete(struct service *s) +service_delete(struct service *s, bool container) { blobmsg_list_free(&s->data_blob); free(s->data); vlist_flush_all(&s->instances); s->deleted = true; - service_stopped(s); + _service_stopped(s, container); } enum { @@ -275,16 +282,21 @@ static const struct blobmsg_policy get_data_policy[] = { }; enum { - SERVICE_CONSOLE_NAME, - SERVICE_CONSOLE_INSTANCE, - __SERVICE_CONSOLE_MAX, + CONTAINER_CONSOLE_NAME, + CONTAINER_CONSOLE_INSTANCE, + __CONTAINER_CONSOLE_MAX, }; -static const struct blobmsg_policy service_console_policy[__SERVICE_CONSOLE_MAX] = { - [SERVICE_CONSOLE_NAME] = { "name", BLOBMSG_TYPE_STRING }, - [SERVICE_CONSOLE_INSTANCE] = { "instance", BLOBMSG_TYPE_STRING }, +static const struct blobmsg_policy container_console_policy[__CONTAINER_CONSOLE_MAX] = { + [CONTAINER_CONSOLE_NAME] = { "name", BLOBMSG_TYPE_STRING }, + [CONTAINER_CONSOLE_INSTANCE] = { "instance", BLOBMSG_TYPE_STRING }, }; +static inline bool is_container_obj(struct ubus_object *obj) +{ + return (obj && (strcmp(obj->name, "container") == 0)); +} + static int service_handle_set(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, @@ -293,6 +305,7 @@ service_handle_set(struct ubus_context *ctx, struct ubus_object *obj, struct blob_attr *tb[__SERVICE_SET_MAX], *cur; struct service *s = NULL; const char *name; + bool container = is_container_obj(obj); bool add = !strcmp(method, "add"); int ret; @@ -303,7 +316,11 @@ service_handle_set(struct ubus_context *ctx, struct ubus_object *obj, name = blobmsg_data(cur); - s = avl_find_element(&services, name, s, avl); + if (container) + s = avl_find_element(&containers, name, s, avl); + else + s = avl_find_element(&services, name, s, avl); + if (s) { DEBUG(2, "Update service %s\n", name); return service_update(s, tb, add); @@ -318,10 +335,15 @@ service_handle_set(struct ubus_context *ctx, struct ubus_object *obj, if (ret) return ret; - avl_insert(&services, &s->avl); + if (container) { + avl_insert(&containers, &s->avl); - service_event("service.start", s->name, NULL); + service_event("container.start", s->name, NULL); + } else { + avl_insert(&services, &s->avl); + service_event("service.start", s->name, NULL); + } return 0; } @@ -366,6 +388,8 @@ service_handle_list(struct ubus_context *ctx, struct ubus_object *obj, struct service *s; const char *name = NULL; bool verbose = false; + bool container = is_container_obj(obj); + const struct avl_tree *tree = container?&containers:&services; blobmsg_parse(service_list_attrs, __SERVICE_LIST_ATTR_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg)); @@ -375,7 +399,7 @@ service_handle_list(struct ubus_context *ctx, struct ubus_object *obj, name = blobmsg_get_string(tb[SERVICE_LIST_ATTR_NAME]); blob_buf_init(&b, 0); - avl_for_each_element(&services, s, avl) { + avl_for_each_element(tree, s, avl) { if (name && strcmp(s->name, name) != 0) continue; @@ -395,6 +419,7 @@ service_handle_delete(struct ubus_context *ctx, struct ubus_object *obj, struct blob_attr *tb[__SERVICE_DEL_ATTR_MAX], *cur; struct service *s; struct service_instance *in; + bool container = is_container_obj(obj); blobmsg_parse(service_del_attrs, __SERVICE_DEL_ATTR_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg)); @@ -402,13 +427,17 @@ service_handle_delete(struct ubus_context *ctx, struct ubus_object *obj, if (!cur) return UBUS_STATUS_NOT_FOUND; - s = avl_find_element(&services, blobmsg_data(cur), s, avl); + if (container) + s = avl_find_element(&containers, blobmsg_data(cur), s, avl); + else + s = avl_find_element(&services, blobmsg_data(cur), s, avl); + if (!s) return UBUS_STATUS_NOT_FOUND; cur = tb[SERVICE_DEL_ATTR_INSTANCE]; if (!cur) { - service_delete(s); + service_delete(s, container); return 0; } @@ -446,6 +475,7 @@ service_handle_signal(struct ubus_context *ctx, struct ubus_object *obj, struct blob_attr *tb[__SERVICE_SIGNAL_ATTR_MAX], *cur; struct service *s; struct service_instance *in; + bool container = is_container_obj(obj); int sig = SIGHUP; int rv = 0; @@ -459,7 +489,11 @@ service_handle_signal(struct ubus_context *ctx, struct ubus_object *obj, if (!cur) return UBUS_STATUS_NOT_FOUND; - s = avl_find_element(&services, blobmsg_data(cur), s, avl); + if (container) + s = avl_find_element(&containers, blobmsg_data(cur), s, avl); + else + s = avl_find_element(&services, blobmsg_data(cur), s, avl); + if (!s) return UBUS_STATUS_NOT_FOUND; @@ -488,6 +522,7 @@ service_handle_state(struct ubus_context *ctx, struct ubus_object *obj, struct blob_attr *tb[__SERVICE_STATE_ATTR_MAX]; struct service *s; struct service_instance *in; + bool container = is_container_obj(obj); int spawn; blobmsg_parse(service_state_attrs, __SERVICE_STATE_ATTR_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg)); @@ -498,7 +533,11 @@ service_handle_state(struct ubus_context *ctx, struct ubus_object *obj, if (!tb[SERVICE_STATE_ATTR_NAME]) return UBUS_STATUS_NOT_FOUND; - s = avl_find_element(&services, blobmsg_data(tb[SERVICE_STATE_ATTR_NAME]), s, avl); + if (container) + s = avl_find_element(&containers, blobmsg_data(tb[SERVICE_STATE_ATTR_NAME]), s, avl); + else + s = avl_find_element(&services, blobmsg_data(tb[SERVICE_STATE_ATTR_NAME]), s, avl); + if (!s) return UBUS_STATUS_NOT_FOUND; @@ -522,6 +561,7 @@ service_handle_update(struct ubus_context *ctx, struct ubus_object *obj, { struct blob_attr *tb[__SERVICE_ATTR_MAX], *cur; struct service *s; + bool container = is_container_obj(obj); blobmsg_parse(service_attrs, __SERVICE_ATTR_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg)); @@ -529,7 +569,11 @@ service_handle_update(struct ubus_context *ctx, struct ubus_object *obj, if (!cur) return UBUS_STATUS_INVALID_ARGUMENT; - s = avl_find_element(&services, blobmsg_data(cur), s, avl); + if (container) + s = avl_find_element(&containers, blobmsg_data(cur), s, avl); + else + s = avl_find_element(&services, blobmsg_data(cur), s, avl); + if (!s) return UBUS_STATUS_NOT_FOUND; @@ -684,12 +728,12 @@ service_get_data(struct ubus_context *ctx, struct ubus_object *obj, } static int -service_handle_console(struct ubus_context *ctx, struct ubus_object *obj, - struct ubus_request_data *req, const char *method, - struct blob_attr *msg) +container_handle_console(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) { bool attach = !strcmp(method, "console_attach"); - struct blob_attr *tb[__SERVICE_CONSOLE_MAX]; + struct blob_attr *tb[__CONTAINER_CONSOLE_MAX]; struct service *s; struct service_instance *in; int console_fd = -1; @@ -701,16 +745,16 @@ service_handle_console(struct ubus_context *ctx, struct ubus_object *obj, if (!msg) goto err_console_fd; - blobmsg_parse(service_console_policy, __SERVICE_CONSOLE_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg)); - if (!tb[SERVICE_CONSOLE_NAME]) + blobmsg_parse(container_console_policy, __CONTAINER_CONSOLE_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg)); + if (!tb[CONTAINER_CONSOLE_NAME]) goto err_console_fd; - s = avl_find_element(&services, blobmsg_data(tb[SERVICE_CONSOLE_NAME]), s, avl); + s = avl_find_element(&containers, blobmsg_data(tb[CONTAINER_CONSOLE_NAME]), s, avl); if (!s) goto err_console_fd; - if (tb[SERVICE_CONSOLE_INSTANCE]) { - in = vlist_find(&s->instances, blobmsg_data(tb[SERVICE_CONSOLE_INSTANCE]), in, node); + if (tb[CONTAINER_CONSOLE_INSTANCE]) { + in = vlist_find(&s->instances, blobmsg_data(tb[CONTAINER_CONSOLE_INSTANCE]), in, node); } else { /* use first element in instances list */ vlist_for_each_element(&s->instances, in, node) @@ -753,8 +797,6 @@ static struct ubus_method main_object_methods[] = { UBUS_METHOD("validate", service_handle_validate, validate_policy), UBUS_METHOD("get_data", service_get_data, get_data_policy), UBUS_METHOD("state", service_handle_state, service_state_attrs), - UBUS_METHOD("console_set", service_handle_console, service_console_policy), - UBUS_METHOD("console_attach", service_handle_console, service_console_policy), }; static struct ubus_object_type main_object_type = @@ -796,10 +838,20 @@ service_start_early(char *name, char *cmdline) } void service_stopped(struct service *s) +{ + _service_stopped(s, false); +} + +static void _service_stopped(struct service *s, bool container) { if (s->deleted && avl_is_empty(&s->instances.avl)) { - service_event("service.stop", s->name, NULL); - avl_delete(&services, &s->avl); + if (container) { + service_event("container.stop", s->name, NULL); + avl_delete(&containers, &s->avl); + } else { + service_event("service.stop", s->name, NULL); + avl_delete(&services, &s->avl); + } trigger_del(s); service_validate_del(s); free(s->trigger); @@ -812,8 +864,34 @@ void service_event(const char *type, const char *service, const char *instance) ubus_event_bcast(type, "service", service, "instance", instance); } +static struct ubus_method container_object_methods[] = { + UBUS_METHOD("set", service_handle_set, service_set_attrs), + UBUS_METHOD("add", service_handle_set, service_set_attrs), + UBUS_METHOD("list", service_handle_list, service_list_attrs), + UBUS_METHOD("delete", service_handle_delete, service_del_attrs), + UBUS_METHOD("signal", service_handle_signal, service_signal_attrs), + UBUS_METHOD("state", service_handle_state, service_state_attrs), + UBUS_METHOD("console_set", container_handle_console, container_console_policy), + UBUS_METHOD("console_attach", container_handle_console, container_console_policy), +}; + +static struct ubus_object_type container_object_type = + UBUS_OBJECT_TYPE("container", container_object_methods); + +static struct ubus_object container_object = { + .name = "container", + .type = &container_object_type, + .methods = container_object_methods, + .n_methods = ARRAY_SIZE(container_object_methods), +}; + void ubus_init_service(struct ubus_context *_ctx) { + struct stat statbuf; + ctx = _ctx; ubus_add_object(ctx, &main_object); + + if (!stat("/sbin/ujail", &statbuf)) + ubus_add_object(ctx, &container_object); } diff --git a/service/service.h b/service/service.h index 8f94ecd..fac5da9 100644 --- a/service/service.h +++ b/service/service.h @@ -21,6 +21,7 @@ #include "../utils/utils.h" extern struct avl_tree services; +extern struct avl_tree containers; struct vrule { struct avl_node avl; -- 2.25.1