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>
17 #include <sys/utsname.h>
18 #include <sys/types.h>
24 #include <libubox/blobmsg_json.h>
25 #include <libubox/avl-cmp.h>
34 AVL_TREE(services
, avl_strcmp
, false, NULL
);
35 AVL_TREE(containers
, avl_strcmp
, false, NULL
);
36 static struct blob_buf b
;
37 static struct ubus_context
*ctx
;
38 static struct ubus_object main_object
;
41 service_instance_add(struct service
*s
, struct blob_attr
*attr
)
43 struct service_instance
*in
;
45 if (blobmsg_type(attr
) != BLOBMSG_TYPE_TABLE
)
48 in
= calloc(1, sizeof(*in
));
52 instance_init(in
, s
, attr
);
53 vlist_add(&s
->instances
, &in
->node
, (void *) in
->name
);
57 service_instance_update(struct vlist_tree
*tree
, struct vlist_node
*node_new
,
58 struct vlist_node
*node_old
)
60 struct service_instance
*in_o
= NULL
, *in_n
= NULL
;
63 in_o
= container_of(node_old
, struct service_instance
, node
);
66 in_n
= container_of(node_new
, struct service_instance
, node
);
69 DEBUG(2, "Update instance %s::%s\n", in_o
->srv
->name
, in_o
->name
);
70 instance_update(in_o
, in_n
);
73 DEBUG(2, "Stop instance %s::%s\n", in_o
->srv
->name
, in_o
->name
);
74 instance_stop(in_o
, true);
75 } else if (in_n
&& in_n
->srv
->autostart
) {
76 DEBUG(2, "Start instance %s::%s\n", in_n
->srv
->name
, in_n
->name
);
80 trigger_event("instance.update", b
.head
);
83 static struct service
*
84 service_alloc(const char *name
)
89 s
= calloc_a(sizeof(*s
), &new_name
, strlen(name
) + 1);
90 strcpy(new_name
, name
);
92 vlist_init(&s
->instances
, avl_strcmp
, service_instance_update
);
93 s
->instances
.no_delete
= true;
96 INIT_LIST_HEAD(&s
->validators
);
97 blobmsg_list_simple_init(&s
->data_blob
);
105 SERVICE_SET_INSTANCES
,
107 SERVICE_SET_VALIDATE
,
108 SERVICE_SET_AUTOSTART
,
113 static const struct blobmsg_policy service_set_attrs
[__SERVICE_SET_MAX
] = {
114 [SERVICE_SET_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
115 [SERVICE_SET_SCRIPT
] = { "script", BLOBMSG_TYPE_STRING
},
116 [SERVICE_SET_INSTANCES
] = { "instances", BLOBMSG_TYPE_TABLE
},
117 [SERVICE_SET_TRIGGER
] = { "triggers", BLOBMSG_TYPE_ARRAY
},
118 [SERVICE_SET_VALIDATE
] = { "validate", BLOBMSG_TYPE_ARRAY
},
119 [SERVICE_SET_AUTOSTART
] = { "autostart", BLOBMSG_TYPE_BOOL
},
120 [SERVICE_SET_DATA
] = { "data", BLOBMSG_TYPE_TABLE
},
124 service_update(struct service
*s
, struct blob_attr
**tb
, bool add
)
126 struct blob_attr
*cur
;
136 blobmsg_list_free(&s
->data_blob
);
141 service_validate_del(s
);
143 if (tb
[SERVICE_SET_AUTOSTART
] && !blobmsg_get_bool(tb
[SERVICE_SET_AUTOSTART
]))
144 s
->autostart
= false;
148 if (tb
[SERVICE_SET_TRIGGER
] && blobmsg_data_len(tb
[SERVICE_SET_TRIGGER
])) {
149 s
->trigger
= blob_memdup(tb
[SERVICE_SET_TRIGGER
]);
152 trigger_add(s
->trigger
, s
);
155 if (tb
[SERVICE_SET_VALIDATE
] && blobmsg_data_len(tb
[SERVICE_SET_VALIDATE
])) {
156 blobmsg_for_each_attr(cur
, tb
[SERVICE_SET_VALIDATE
], rem
)
157 service_validate_add(s
, cur
);
160 if (tb
[SERVICE_SET_INSTANCES
]) {
162 vlist_update(&s
->instances
);
163 blobmsg_for_each_attr(cur
, tb
[SERVICE_SET_INSTANCES
], rem
) {
164 service_instance_add(s
, cur
);
167 vlist_flush(&s
->instances
);
170 if (tb
[SERVICE_SET_DATA
] && blobmsg_data_len(tb
[SERVICE_SET_DATA
])) {
171 s
->data
= blob_memdup(tb
[SERVICE_SET_DATA
]);
174 blobmsg_list_fill(&s
->data_blob
, blobmsg_data(s
->data
),
175 blobmsg_data_len(s
->data
), false);
180 rc(s
->name
, "running");
186 service_delete(struct service
*s
, bool container
)
188 blobmsg_list_free(&s
->data_blob
);
190 vlist_flush_all(&s
->instances
);
200 static const struct blobmsg_policy service_attrs
[__SERVICE_ATTR_MAX
] = {
201 [SERVICE_ATTR_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
205 SERVICE_DEL_ATTR_NAME
,
206 SERVICE_DEL_ATTR_INSTANCE
,
207 __SERVICE_DEL_ATTR_MAX
,
210 static const struct blobmsg_policy service_del_attrs
[__SERVICE_DEL_ATTR_MAX
] = {
211 [SERVICE_DEL_ATTR_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
212 [SERVICE_DEL_ATTR_INSTANCE
] = { "instance", BLOBMSG_TYPE_STRING
},
216 SERVICE_LIST_ATTR_NAME
,
217 SERVICE_LIST_ATTR_VERBOSE
,
218 __SERVICE_LIST_ATTR_MAX
,
221 static const struct blobmsg_policy service_list_attrs
[__SERVICE_LIST_ATTR_MAX
] = {
222 [SERVICE_LIST_ATTR_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
223 [SERVICE_LIST_ATTR_VERBOSE
] = { "verbose", BLOBMSG_TYPE_BOOL
},
227 SERVICE_SIGNAL_ATTR_NAME
,
228 SERVICE_SIGNAL_ATTR_INSTANCE
,
229 SERVICE_SIGNAL_ATTR_SIGNAL
,
230 __SERVICE_SIGNAL_ATTR_MAX
,
233 static const struct blobmsg_policy service_signal_attrs
[__SERVICE_SIGNAL_ATTR_MAX
] = {
234 [SERVICE_SIGNAL_ATTR_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
235 [SERVICE_SIGNAL_ATTR_INSTANCE
] = { "instance", BLOBMSG_TYPE_STRING
},
236 [SERVICE_SIGNAL_ATTR_SIGNAL
] = { "signal", BLOBMSG_TYPE_INT32
},
240 SERVICE_STATE_ATTR_SPAWN
,
241 SERVICE_STATE_ATTR_NAME
,
242 __SERVICE_STATE_ATTR_MAX
,
245 static const struct blobmsg_policy service_state_attrs
[__SERVICE_STATE_ATTR_MAX
] = {
246 [SERVICE_STATE_ATTR_SPAWN
] = { "spawn", BLOBMSG_TYPE_BOOL
},
247 [SERVICE_STATE_ATTR_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
256 static const struct blobmsg_policy event_policy
[__EVENT_MAX
] = {
257 [EVENT_TYPE
] = { .name
= "type", .type
= BLOBMSG_TYPE_STRING
},
258 [EVENT_DATA
] = { .name
= "data", .type
= BLOBMSG_TYPE_TABLE
},
268 static const struct blobmsg_policy validate_policy
[__VALIDATE_MAX
] = {
269 [VALIDATE_PACKAGE
] = { .name
= "package", .type
= BLOBMSG_TYPE_STRING
},
270 [VALIDATE_TYPE
] = { .name
= "type", .type
= BLOBMSG_TYPE_STRING
},
271 [VALIDATE_SERVICE
] = { .name
= "service", .type
= BLOBMSG_TYPE_STRING
},
281 static const struct blobmsg_policy get_data_policy
[] = {
282 [DATA_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
283 [DATA_INSTANCE
] = { "instance", BLOBMSG_TYPE_STRING
},
284 [DATA_TYPE
] = { "type", BLOBMSG_TYPE_STRING
},
288 CONTAINER_CONSOLE_NAME
,
289 CONTAINER_CONSOLE_INSTANCE
,
290 __CONTAINER_CONSOLE_MAX
,
293 static const struct blobmsg_policy container_console_policy
[__CONTAINER_CONSOLE_MAX
] = {
294 [CONTAINER_CONSOLE_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
295 [CONTAINER_CONSOLE_INSTANCE
] = { "instance", BLOBMSG_TYPE_STRING
},
298 static inline bool is_container_obj(struct ubus_object
*obj
)
300 return (obj
&& (strcmp(obj
->name
, "container") == 0));
303 static inline void put_namespace(struct blob_buf
*b
, char *name
)
308 snprintf(nsfname
, sizeof(nsfname
), "/proc/self/ns/%s", name
);
310 if (!stat(nsfname
, &statbuf
))
311 blobmsg_add_string(b
, NULL
, name
);
314 static void put_cgroups(struct blob_buf
*b
)
317 static char buf
[512] = "";
320 fd
= open("/sys/fs/cgroup/cgroup.controllers", O_RDONLY
);
324 ret
= read(fd
, &buf
, sizeof(buf
));
325 /* make sure buffer is NULL-terminated */
326 buf
[sizeof(buf
)-1] = '\0';
336 /* replace space with \0 and direct next entry */
340 } else { /* replace trailing new-line with \0 */
342 if (!t
) /* shouldn't happen, but don't segfault if it does */
348 blobmsg_add_string(b
, NULL
, z
);
353 container_handle_features(struct ubus_context
*ctx
, struct ubus_object
*obj
,
354 struct ubus_request_data
*req
, const char *method
,
355 struct blob_attr
*msg
)
357 struct utsname utsbuf
;
359 void *nsarray
, *cgarray
;
361 if (stat("/sbin/ujail", &statbuf
))
362 return UBUS_STATUS_NOT_SUPPORTED
;
364 if (uname(&utsbuf
) < 0)
365 return UBUS_STATUS_UNKNOWN_ERROR
;
367 blob_buf_init(&b
, 0);
368 blobmsg_add_string(&b
, "machine", utsbuf
.machine
);
370 #ifdef SECCOMP_SUPPORT
371 blobmsg_add_u8(&b
, "seccomp", true);
373 blobmsg_add_u8(&b
, "seccomp", false);
376 cgarray
= blobmsg_open_array(&b
, "cgroup");
378 blobmsg_close_array(&b
, cgarray
);
380 nsarray
= blobmsg_open_array(&b
, "namespaces");
381 put_namespace(&b
, "cgroup");
382 put_namespace(&b
, "ipc");
383 put_namespace(&b
, "mnt");
384 put_namespace(&b
, "net");
385 put_namespace(&b
, "pid");
387 put_namespace(&b
, "time");
389 put_namespace(&b
, "user");
390 put_namespace(&b
, "uts");
391 blobmsg_close_array(&b
, nsarray
);
392 ubus_send_reply(ctx
, req
, b
.head
);
394 return UBUS_STATUS_OK
;
398 service_handle_set(struct ubus_context
*ctx
, struct ubus_object
*obj
,
399 struct ubus_request_data
*req
, const char *method
,
400 struct blob_attr
*msg
)
402 struct blob_attr
*tb
[__SERVICE_SET_MAX
], *cur
;
403 struct service
*s
= NULL
;
405 bool container
= is_container_obj(obj
);
406 bool add
= !strcmp(method
, "add");
409 blobmsg_parse(service_set_attrs
, __SERVICE_SET_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
410 cur
= tb
[SERVICE_SET_NAME
];
412 return UBUS_STATUS_INVALID_ARGUMENT
;
414 name
= blobmsg_data(cur
);
417 s
= avl_find_element(&containers
, name
, s
, avl
);
419 s
= avl_find_element(&services
, name
, s
, avl
);
422 DEBUG(2, "Update service %s\n", name
);
423 return service_update(s
, tb
, add
);
426 DEBUG(2, "Create service %s\n", name
);
427 s
= service_alloc(name
);
429 return UBUS_STATUS_UNKNOWN_ERROR
;
431 s
->container
= container
;
433 ret
= service_update(s
, tb
, add
);
438 avl_insert(&containers
, &s
->avl
);
440 service_event("container.start", s
->name
, NULL
);
442 avl_insert(&services
, &s
->avl
);
444 service_event("service.start", s
->name
, NULL
);
450 service_dump(struct service
*s
, bool verbose
)
452 struct service_instance
*in
;
455 c
= blobmsg_open_table(&b
, s
->name
);
458 blobmsg_add_u8(&b
, "autostart", false);
460 if (!avl_is_empty(&s
->data_blob
.avl
)) {
461 struct blobmsg_list_node
*var
;
462 i
= blobmsg_open_table(&b
, "data");
463 blobmsg_list_for_each(&s
->data_blob
, var
)
464 blobmsg_add_blob(&b
, var
->data
);
465 blobmsg_close_table(&b
, i
);
468 if (!avl_is_empty(&s
->instances
.avl
)) {
469 i
= blobmsg_open_table(&b
, "instances");
470 vlist_for_each_element(&s
->instances
, in
, node
)
471 instance_dump(&b
, in
, verbose
);
472 blobmsg_close_table(&b
, i
);
474 if (verbose
&& s
->trigger
)
475 blobmsg_add_blob(&b
, s
->trigger
);
476 if (verbose
&& !list_empty(&s
->validators
))
477 service_validate_dump(&b
, s
);
478 blobmsg_close_table(&b
, c
);
482 service_handle_list(struct ubus_context
*ctx
, struct ubus_object
*obj
,
483 struct ubus_request_data
*req
, const char *method
,
484 struct blob_attr
*msg
)
486 struct blob_attr
*tb
[__SERVICE_LIST_ATTR_MAX
];
488 const char *name
= NULL
;
489 bool verbose
= false;
490 bool container
= is_container_obj(obj
);
491 const struct avl_tree
*tree
= container
?&containers
:&services
;
493 blobmsg_parse(service_list_attrs
, __SERVICE_LIST_ATTR_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
495 if (tb
[SERVICE_LIST_ATTR_VERBOSE
])
496 verbose
= blobmsg_get_bool(tb
[SERVICE_LIST_ATTR_VERBOSE
]);
497 if (tb
[SERVICE_LIST_ATTR_NAME
])
498 name
= blobmsg_get_string(tb
[SERVICE_LIST_ATTR_NAME
]);
500 blob_buf_init(&b
, 0);
501 avl_for_each_element(tree
, s
, avl
) {
502 if (name
&& strcmp(s
->name
, name
) != 0)
505 service_dump(s
, verbose
);
508 ubus_send_reply(ctx
, req
, b
.head
);
514 service_handle_delete(struct ubus_context
*ctx
, struct ubus_object
*obj
,
515 struct ubus_request_data
*req
, const char *method
,
516 struct blob_attr
*msg
)
518 struct blob_attr
*tb
[__SERVICE_DEL_ATTR_MAX
], *cur
;
520 struct service_instance
*in
;
521 bool container
= is_container_obj(obj
);
523 blobmsg_parse(service_del_attrs
, __SERVICE_DEL_ATTR_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
525 cur
= tb
[SERVICE_DEL_ATTR_NAME
];
527 return UBUS_STATUS_NOT_FOUND
;
530 s
= avl_find_element(&containers
, blobmsg_data(cur
), s
, avl
);
532 s
= avl_find_element(&services
, blobmsg_data(cur
), s
, avl
);
535 return UBUS_STATUS_NOT_FOUND
;
537 cur
= tb
[SERVICE_DEL_ATTR_INSTANCE
];
539 service_delete(s
, container
);
543 in
= vlist_find(&s
->instances
, blobmsg_data(cur
), in
, node
);
545 ERROR("instance %s not found\n", (char *) blobmsg_data(cur
));
546 return UBUS_STATUS_NOT_FOUND
;
549 vlist_delete(&s
->instances
, &in
->node
);
555 service_handle_kill(struct service_instance
*in
, int sig
)
557 if (kill(in
->proc
.pid
, sig
) == 0)
561 case EINVAL
: return UBUS_STATUS_INVALID_ARGUMENT
;
562 case EPERM
: return UBUS_STATUS_PERMISSION_DENIED
;
563 case ESRCH
: return UBUS_STATUS_NOT_FOUND
;
566 return UBUS_STATUS_UNKNOWN_ERROR
;
570 service_handle_signal(struct ubus_context
*ctx
, struct ubus_object
*obj
,
571 struct ubus_request_data
*req
, const char *method
,
572 struct blob_attr
*msg
)
574 struct blob_attr
*tb
[__SERVICE_SIGNAL_ATTR_MAX
], *cur
;
576 struct service_instance
*in
;
577 bool container
= is_container_obj(obj
);
581 blobmsg_parse(service_signal_attrs
, __SERVICE_SIGNAL_ATTR_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
583 cur
= tb
[SERVICE_SIGNAL_ATTR_SIGNAL
];
585 sig
= blobmsg_get_u32(cur
);
587 cur
= tb
[SERVICE_SIGNAL_ATTR_NAME
];
589 return UBUS_STATUS_NOT_FOUND
;
592 s
= avl_find_element(&containers
, blobmsg_data(cur
), s
, avl
);
594 s
= avl_find_element(&services
, blobmsg_data(cur
), s
, avl
);
597 return UBUS_STATUS_NOT_FOUND
;
599 cur
= tb
[SERVICE_SIGNAL_ATTR_INSTANCE
];
601 vlist_for_each_element(&s
->instances
, in
, node
)
602 rv
= service_handle_kill(in
, sig
);
607 in
= vlist_find(&s
->instances
, blobmsg_data(cur
), in
, node
);
609 ERROR("instance %s not found\n", blobmsg_get_string(cur
));
610 return UBUS_STATUS_NOT_FOUND
;
613 return service_handle_kill(in
, sig
);
617 service_handle_state(struct ubus_context
*ctx
, struct ubus_object
*obj
,
618 struct ubus_request_data
*req
, const char *method
,
619 struct blob_attr
*msg
)
621 struct blob_attr
*tb
[__SERVICE_STATE_ATTR_MAX
];
623 struct service_instance
*in
;
624 bool container
= is_container_obj(obj
);
627 blobmsg_parse(service_state_attrs
, __SERVICE_STATE_ATTR_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
629 if (!tb
[SERVICE_STATE_ATTR_SPAWN
])
630 return UBUS_STATUS_INVALID_ARGUMENT
;
632 if (!tb
[SERVICE_STATE_ATTR_NAME
])
633 return UBUS_STATUS_NOT_FOUND
;
636 s
= avl_find_element(&containers
, blobmsg_data(tb
[SERVICE_STATE_ATTR_NAME
]), s
, avl
);
638 s
= avl_find_element(&services
, blobmsg_data(tb
[SERVICE_STATE_ATTR_NAME
]), s
, avl
);
641 return UBUS_STATUS_NOT_FOUND
;
643 spawn
= !!blobmsg_get_u8(tb
[SERVICE_STATE_ATTR_SPAWN
]);
644 vlist_for_each_element(&s
->instances
, in
, node
) {
645 if (!!in
->proc
.pending
== !!spawn
)
647 else if (!in
->proc
.pending
)
650 instance_stop(in
, false);
653 return UBUS_STATUS_OK
;
657 service_handle_update(struct ubus_context
*ctx
, struct ubus_object
*obj
,
658 struct ubus_request_data
*req
, const char *method
,
659 struct blob_attr
*msg
)
661 struct blob_attr
*tb
[__SERVICE_ATTR_MAX
], *cur
;
663 bool container
= is_container_obj(obj
);
665 blobmsg_parse(service_attrs
, __SERVICE_ATTR_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
667 cur
= tb
[SERVICE_SET_NAME
];
669 return UBUS_STATUS_INVALID_ARGUMENT
;
672 s
= avl_find_element(&containers
, blobmsg_data(cur
), s
, avl
);
674 s
= avl_find_element(&services
, blobmsg_data(cur
), s
, avl
);
677 return UBUS_STATUS_NOT_FOUND
;
679 if (!strcmp(method
, "update_start"))
680 vlist_update(&s
->instances
);
682 vlist_flush(&s
->instances
);
687 static void ubus_event_bcast(const char *type
, const char *param1
, const char *val1
,
688 const char *param2
, const char *val2
)
693 blob_buf_init(&b
, 0);
695 blobmsg_add_string(&b
, param1
, val1
);
697 blobmsg_add_string(&b
, param2
, val2
);
698 ubus_notify(ctx
, &main_object
, type
, b
.head
, -1);
702 service_handle_event(struct ubus_context
*ctx
, struct ubus_object
*obj
,
703 struct ubus_request_data
*req
, const char *method
,
704 struct blob_attr
*msg
)
706 struct blob_attr
*tb
[__EVENT_MAX
];
710 return UBUS_STATUS_INVALID_ARGUMENT
;
712 blobmsg_parse(event_policy
, __EVENT_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
713 if (!tb
[EVENT_TYPE
] || !tb
[EVENT_DATA
])
714 return UBUS_STATUS_INVALID_ARGUMENT
;
716 event
= blobmsg_get_string(tb
[EVENT_TYPE
]);
717 trigger_event(event
, tb
[EVENT_DATA
]);
719 if (!strcmp(event
, "config.change")) {
720 struct blob_attr
*tb2
[__VALIDATE_MAX
];
722 blobmsg_parse(validate_policy
, __VALIDATE_MAX
, tb2
,
723 blobmsg_data(tb
[EVENT_DATA
]), blobmsg_data_len(tb
[EVENT_DATA
]));
724 if (tb2
[VALIDATE_PACKAGE
])
725 ubus_event_bcast("config.change", "config",
726 blobmsg_get_string(tb2
[VALIDATE_PACKAGE
]), NULL
, NULL
);
732 service_handle_validate(struct ubus_context
*ctx
, struct ubus_object
*obj
,
733 struct ubus_request_data
*req
, const char *method
,
734 struct blob_attr
*msg
)
736 struct blob_attr
*tb
[__VALIDATE_MAX
];
737 char *p
= NULL
, *t
= NULL
;
740 return UBUS_STATUS_INVALID_ARGUMENT
;
742 blobmsg_parse(validate_policy
, __VALIDATE_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
743 if (tb
[VALIDATE_SERVICE
]) {
746 if (tb
[VALIDATE_PACKAGE
])
747 p
= blobmsg_get_string(tb
[VALIDATE_PACKAGE
]);
749 if (tb
[VALIDATE_TYPE
])
750 t
= blobmsg_get_string(tb
[VALIDATE_TYPE
]);
752 blob_buf_init(&b
, 0);
753 service_validate_dump_all(&b
, p
, t
);
754 ubus_send_reply(ctx
, req
, b
.head
);
760 service_get_data(struct ubus_context
*ctx
, struct ubus_object
*obj
,
761 struct ubus_request_data
*req
, const char *method
,
762 struct blob_attr
*msg
)
764 struct service_instance
*in
;
766 struct blob_attr
*tb
[__DATA_MAX
];
767 const char *name
= NULL
;
768 const char *instance
= NULL
;
769 const char *type
= NULL
;
771 blobmsg_parse(get_data_policy
, __DATA_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
773 name
= blobmsg_data(tb
[DATA_NAME
]);
774 if (tb
[DATA_INSTANCE
])
775 instance
= blobmsg_data(tb
[DATA_INSTANCE
]);
777 type
= blobmsg_data(tb
[DATA_TYPE
]);
779 blob_buf_init(&b
, 0);
780 avl_for_each_element(&services
, s
, avl
) {
783 struct blobmsg_list_node
*var
;
785 if (name
&& strcmp(name
, s
->name
))
788 blobmsg_list_for_each(&s
->data_blob
, var
) {
789 if (type
&& strcmp(blobmsg_name(var
->data
), type
))
793 cs
= blobmsg_open_table(&b
, s
->name
);
795 blobmsg_add_blob(&b
, var
->data
);
798 vlist_for_each_element(&s
->instances
, in
, node
) {
801 if (instance
&& strcmp(instance
, in
->name
))
804 blobmsg_list_for_each(&in
->data
, var
) {
806 strcmp(blobmsg_name(var
->data
), type
))
810 cs
= blobmsg_open_table(&b
, s
->name
);
812 ci
= blobmsg_open_table(&b
, in
->name
);
814 blobmsg_add_blob(&b
, var
->data
);
818 blobmsg_close_table(&b
, ci
);
822 blobmsg_close_table(&b
, cs
);
825 ubus_send_reply(ctx
, req
, b
.head
);
830 container_handle_console(struct ubus_context
*ctx
, struct ubus_object
*obj
,
831 struct ubus_request_data
*req
, const char *method
,
832 struct blob_attr
*msg
)
834 bool attach
= !strcmp(method
, "console_attach");
835 struct blob_attr
*tb
[__CONTAINER_CONSOLE_MAX
];
837 struct service_instance
*in
;
840 console_fd
= ubus_request_get_caller_fd(req
);
842 return UBUS_STATUS_INVALID_ARGUMENT
;
847 blobmsg_parse(container_console_policy
, __CONTAINER_CONSOLE_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
848 if (!tb
[CONTAINER_CONSOLE_NAME
])
851 s
= avl_find_element(&containers
, blobmsg_data(tb
[CONTAINER_CONSOLE_NAME
]), s
, avl
);
855 if (tb
[CONTAINER_CONSOLE_INSTANCE
]) {
856 in
= vlist_find(&s
->instances
, blobmsg_data(tb
[CONTAINER_CONSOLE_INSTANCE
]), in
, node
);
858 /* use first element in instances list */
859 vlist_for_each_element(&s
->instances
, in
, node
)
866 if (in
->console
.fd
.fd
< 0) {
868 return UBUS_STATUS_NOT_SUPPORTED
;
871 /* close and replace existing attached console */
872 if (in
->console_client
.fd
.fd
> -1)
873 close(in
->console_client
.fd
.fd
);
875 ustream_fd_init(&in
->console_client
, console_fd
);
877 ustream_fd_init(&in
->console
, console_fd
);
880 return UBUS_STATUS_OK
;
883 return UBUS_STATUS_INVALID_ARGUMENT
;
887 SERVICE_WATCHDOG_MODE
,
888 SERVICE_WATCHDOG_TIMEOUT
,
889 SERVICE_WATCHDOG_NAME
,
890 SERVICE_WATCHDOG_INSTANCE
,
891 __SERVICE_WATCHDOG_MAX
,
894 static const struct blobmsg_policy service_watchdog_policy
[__SERVICE_WATCHDOG_MAX
] = {
895 [SERVICE_WATCHDOG_MODE
] = { "mode", BLOBMSG_TYPE_INT32
},
896 [SERVICE_WATCHDOG_NAME
] = { "name", BLOBMSG_TYPE_STRING
},
897 [SERVICE_WATCHDOG_TIMEOUT
] = { "timeout", BLOBMSG_TYPE_INT32
},
898 [SERVICE_WATCHDOG_INSTANCE
] = { "instance", BLOBMSG_TYPE_STRING
},
902 service_handle_watchdog(struct ubus_context
*ctx
, struct ubus_object
*obj
,
903 struct ubus_request_data
*req
, const char *method
,
904 struct blob_attr
*msg
)
906 struct blob_attr
*tb
[__SERVICE_WATCHDOG_MAX
] = {0};
908 struct blob_attr
*cur
;
909 struct service_instance
*in
;
911 blobmsg_parse(service_watchdog_policy
, __SERVICE_WATCHDOG_MAX
, tb
, blobmsg_data(msg
), blobmsg_data_len(msg
));
912 cur
= tb
[SERVICE_WATCHDOG_NAME
];
914 return UBUS_STATUS_NOT_FOUND
;
916 s
= avl_find_element(&services
, blobmsg_data(cur
), s
, avl
);
918 return UBUS_STATUS_NOT_FOUND
;
920 cur
= tb
[SERVICE_WATCHDOG_INSTANCE
];
922 return UBUS_STATUS_NOT_FOUND
;
924 in
= vlist_find(&s
->instances
, blobmsg_data(cur
), in
, node
);
926 ERROR("instance %s not found\n", blobmsg_get_string(cur
));
927 return UBUS_STATUS_NOT_FOUND
;
930 if (tb
[SERVICE_WATCHDOG_MODE
])
931 in
->watchdog
.mode
= blobmsg_get_u32(tb
[SERVICE_WATCHDOG_MODE
]);
933 if (tb
[SERVICE_WATCHDOG_TIMEOUT
])
934 in
->watchdog
.freq
= blobmsg_get_u32(tb
[SERVICE_WATCHDOG_TIMEOUT
]);
936 if (in
->watchdog
.mode
== INSTANCE_WATCHDOG_MODE_DISABLED
)
937 uloop_timeout_cancel(&in
->watchdog
.timeout
);
939 uloop_timeout_set(&in
->watchdog
.timeout
, in
->watchdog
.freq
* 1000);
941 blob_buf_init(&b
, 0);
942 blobmsg_add_string(&b
, "name", blobmsg_get_string(tb
[SERVICE_WATCHDOG_NAME
]));
943 blobmsg_add_string(&b
, "instance", blobmsg_get_string(tb
[SERVICE_WATCHDOG_INSTANCE
]));
944 blobmsg_add_u32(&b
, "mode", in
->watchdog
.mode
);
945 blobmsg_add_u32(&b
, "timeout", in
->watchdog
.freq
);
947 ubus_send_reply(ctx
, req
, b
.head
);
949 return UBUS_STATUS_OK
;
952 static struct ubus_method main_object_methods
[] = {
953 UBUS_METHOD("set", service_handle_set
, service_set_attrs
),
954 UBUS_METHOD("add", service_handle_set
, service_set_attrs
),
955 UBUS_METHOD("list", service_handle_list
, service_list_attrs
),
956 UBUS_METHOD("delete", service_handle_delete
, service_del_attrs
),
957 UBUS_METHOD("signal", service_handle_signal
, service_signal_attrs
),
958 UBUS_METHOD("update_start", service_handle_update
, service_attrs
),
959 UBUS_METHOD("update_complete", service_handle_update
, service_attrs
),
960 UBUS_METHOD("event", service_handle_event
, event_policy
),
961 UBUS_METHOD("validate", service_handle_validate
, validate_policy
),
962 UBUS_METHOD("get_data", service_get_data
, get_data_policy
),
963 UBUS_METHOD("state", service_handle_state
, service_state_attrs
),
964 UBUS_METHOD("watchdog", service_handle_watchdog
, service_watchdog_policy
),
967 static struct ubus_object_type main_object_type
=
968 UBUS_OBJECT_TYPE("service", main_object_methods
);
970 static struct ubus_object main_object
= {
972 .type
= &main_object_type
,
973 .methods
= main_object_methods
,
974 .n_methods
= ARRAY_SIZE(main_object_methods
),
978 service_start_early(char *name
, char *cmdline
, char *user
, char *group
)
980 void *instances
, *instance
, *command
, *respawn
;
983 blob_buf_init(&b
, 0);
984 blobmsg_add_string(&b
, "name", name
);
985 instances
= blobmsg_open_table(&b
, "instances");
986 instance
= blobmsg_open_table(&b
, "instance1");
987 command
= blobmsg_open_array(&b
, "command");
988 t
= strtok(cmdline
, " ");
990 blobmsg_add_string(&b
, NULL
, t
);
991 t
= strtok(NULL
, " ");
993 blobmsg_close_array(&b
, command
);
994 respawn
= blobmsg_open_array(&b
, "respawn");
995 blobmsg_add_string(&b
, NULL
, "3600");
996 blobmsg_add_string(&b
, NULL
, "1");
997 blobmsg_add_string(&b
, NULL
, "0");
998 blobmsg_close_array(&b
, respawn
);
1000 blobmsg_add_string(&b
, "user", user
);
1002 blobmsg_add_string(&b
, "group", group
);
1004 blobmsg_close_table(&b
, instance
);
1005 blobmsg_close_table(&b
, instances
);
1007 return service_handle_set(NULL
, NULL
, NULL
, "add", b
.head
);
1010 void service_stopped(struct service
*s
)
1012 if (s
->deleted
&& avl_is_empty(&s
->instances
.avl
)) {
1014 service_event("container.stop", s
->name
, NULL
);
1015 avl_delete(&containers
, &s
->avl
);
1017 service_event("service.stop", s
->name
, NULL
);
1018 avl_delete(&services
, &s
->avl
);
1021 service_validate_del(s
);
1027 void service_event(const char *type
, const char *service
, const char *instance
)
1029 ubus_event_bcast(type
, "service", service
, "instance", instance
);
1032 static struct ubus_method container_object_methods
[] = {
1033 UBUS_METHOD("set", service_handle_set
, service_set_attrs
),
1034 UBUS_METHOD("add", service_handle_set
, service_set_attrs
),
1035 UBUS_METHOD("list", service_handle_list
, service_list_attrs
),
1036 UBUS_METHOD("delete", service_handle_delete
, service_del_attrs
),
1037 UBUS_METHOD("state", service_handle_state
, service_state_attrs
),
1038 UBUS_METHOD_NOARG("get_features", container_handle_features
),
1039 UBUS_METHOD("console_set", container_handle_console
, container_console_policy
),
1040 UBUS_METHOD("console_attach", container_handle_console
, container_console_policy
),
1043 static struct ubus_object_type container_object_type
=
1044 UBUS_OBJECT_TYPE("container", container_object_methods
);
1046 static struct ubus_object container_object
= {
1047 .name
= "container",
1048 .type
= &container_object_type
,
1049 .methods
= container_object_methods
,
1050 .n_methods
= ARRAY_SIZE(container_object_methods
),
1053 void ubus_init_service(struct ubus_context
*_ctx
)
1055 struct stat statbuf
;
1058 ubus_add_object(ctx
, &main_object
);
1060 if (!stat("/sbin/ujail", &statbuf
))
1061 ubus_add_object(ctx
, &container_object
);