• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/procd/service/service.c

  1 /*
  2  * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
  3  * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
  4  *
  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
  8  *
  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.
 13  */
 14 
 15 #include <sys/types.h>
 16 #include <sys/stat.h>
 17 #include <sys/utsname.h>
 18 #include <sys/types.h>
 19 #include <fcntl.h>
 20 
 21 #include <unistd.h>
 22 #include <sched.h>
 23 
 24 #include <libubox/blobmsg_json.h>
 25 #include <libubox/avl-cmp.h>
 26 
 27 #include "../procd.h"
 28 
 29 #include "service.h"
 30 #include "instance.h"
 31 
 32 #include "../rcS.h"
 33 
 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;
 39 
 40 static void
 41 service_instance_add(struct service *s, struct blob_attr *attr)
 42 {
 43         struct service_instance *in;
 44 
 45         if (blobmsg_type(attr) != BLOBMSG_TYPE_TABLE)
 46                 return;
 47 
 48         in = calloc(1, sizeof(*in));
 49         if (!in)
 50                 return;
 51 
 52         instance_init(in, s, attr);
 53         vlist_add(&s->instances, &in->node, (void *) in->name);
 54 }
 55 
 56 static void
 57 service_instance_update(struct vlist_tree *tree, struct vlist_node *node_new,
 58                         struct vlist_node *node_old)
 59 {
 60         struct service_instance *in_o = NULL, *in_n = NULL;
 61 
 62         if (node_old)
 63                 in_o = container_of(node_old, struct service_instance, node);
 64 
 65         if (node_new)
 66                 in_n = container_of(node_new, struct service_instance, node);
 67 
 68         if (in_o && in_n) {
 69                 DEBUG(2, "Update instance %s::%s\n", in_o->srv->name, in_o->name);
 70                 instance_update(in_o, in_n);
 71                 instance_free(in_n);
 72         } else if (in_o) {
 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);
 77                 instance_start(in_n);
 78         }
 79         blob_buf_init(&b, 0);
 80         trigger_event("instance.update", b.head);
 81 }
 82 
 83 static struct service *
 84 service_alloc(const char *name)
 85 {
 86         struct service *s;
 87         char *new_name;
 88 
 89         s = calloc_a(sizeof(*s), &new_name, strlen(name) + 1);
 90         strcpy(new_name, name);
 91 
 92         vlist_init(&s->instances, avl_strcmp, service_instance_update);
 93         s->instances.no_delete = true;
 94         s->name = new_name;
 95         s->avl.key = s->name;
 96         INIT_LIST_HEAD(&s->validators);
 97         blobmsg_list_simple_init(&s->data_blob);
 98 
 99         return s;
100 }
101 
102 enum {
103         SERVICE_SET_NAME,
104         SERVICE_SET_SCRIPT,
105         SERVICE_SET_INSTANCES,
106         SERVICE_SET_TRIGGER,
107         SERVICE_SET_VALIDATE,
108         SERVICE_SET_AUTOSTART,
109         SERVICE_SET_DATA,
110         __SERVICE_SET_MAX
111 };
112 
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 },
121 };
122 
123 static int
124 service_update(struct service *s, struct blob_attr **tb, bool add)
125 {
126         struct blob_attr *cur;
127         int rem;
128 
129         if (s->trigger) {
130                 trigger_del(s);
131                 free(s->trigger);
132                 s->trigger = NULL;
133         }
134 
135         if (s->data) {
136                 blobmsg_list_free(&s->data_blob);
137                 free(s->data);
138                 s->data = NULL;
139         }
140 
141         service_validate_del(s);
142 
143         if (tb[SERVICE_SET_AUTOSTART] && !blobmsg_get_bool(tb[SERVICE_SET_AUTOSTART]))
144                 s->autostart = false;
145         else
146                 s->autostart = true;
147 
148         if (tb[SERVICE_SET_TRIGGER] && blobmsg_data_len(tb[SERVICE_SET_TRIGGER])) {
149                 s->trigger = blob_memdup(tb[SERVICE_SET_TRIGGER]);
150                 if (!s->trigger)
151                         return -1;
152                 trigger_add(s->trigger, s);
153         }
154 
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);
158         }
159 
160         if (tb[SERVICE_SET_INSTANCES]) {
161                 if (!add)
162                         vlist_update(&s->instances);
163                 blobmsg_for_each_attr(cur, tb[SERVICE_SET_INSTANCES], rem) {
164                         service_instance_add(s, cur);
165                 }
166                 if (!add)
167                         vlist_flush(&s->instances);
168         }
169 
170         if (tb[SERVICE_SET_DATA] && blobmsg_data_len(tb[SERVICE_SET_DATA])) {
171                 s->data = blob_memdup(tb[SERVICE_SET_DATA]);
172                 if (!s->data)
173                         return -1;
174                 blobmsg_list_fill(&s->data_blob, blobmsg_data(s->data),
175                                 blobmsg_data_len(s->data), false);
176         }
177 
178         s->deleted = false;
179 
180         rc(s->name, "running");
181 
182         return 0;
183 }
184 
185 static void _service_stopped(struct service *s, bool container);
186 
187 static void
188 service_delete(struct service *s, bool container)
189 {
190         blobmsg_list_free(&s->data_blob);
191         free(s->data);
192         vlist_flush_all(&s->instances);
193         s->deleted = true;
194         _service_stopped(s, container);
195 }
196 
197 enum {
198         SERVICE_ATTR_NAME,
199         __SERVICE_ATTR_MAX,
200 };
201 
202 static const struct blobmsg_policy service_attrs[__SERVICE_ATTR_MAX] = {
203         [SERVICE_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING },
204 };
205 
206 enum {
207         SERVICE_DEL_ATTR_NAME,
208         SERVICE_DEL_ATTR_INSTANCE,
209         __SERVICE_DEL_ATTR_MAX,
210 };
211 
212 static const struct blobmsg_policy service_del_attrs[__SERVICE_DEL_ATTR_MAX] = {
213         [SERVICE_DEL_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING },
214         [SERVICE_DEL_ATTR_INSTANCE] = { "instance", BLOBMSG_TYPE_STRING },
215 };
216 
217 enum {
218         SERVICE_LIST_ATTR_NAME,
219         SERVICE_LIST_ATTR_VERBOSE,
220         __SERVICE_LIST_ATTR_MAX,
221 };
222 
223 static const struct blobmsg_policy service_list_attrs[__SERVICE_LIST_ATTR_MAX] = {
224         [SERVICE_LIST_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING },
225         [SERVICE_LIST_ATTR_VERBOSE] = { "verbose", BLOBMSG_TYPE_BOOL },
226 };
227 
228 enum {
229         SERVICE_SIGNAL_ATTR_NAME,
230         SERVICE_SIGNAL_ATTR_INSTANCE,
231         SERVICE_SIGNAL_ATTR_SIGNAL,
232         __SERVICE_SIGNAL_ATTR_MAX,
233 };
234 
235 static const struct blobmsg_policy service_signal_attrs[__SERVICE_SIGNAL_ATTR_MAX] = {
236         [SERVICE_SIGNAL_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING },
237         [SERVICE_SIGNAL_ATTR_INSTANCE] = { "instance", BLOBMSG_TYPE_STRING },
238         [SERVICE_SIGNAL_ATTR_SIGNAL] = { "signal", BLOBMSG_TYPE_INT32 },
239 };
240 
241 enum {
242         SERVICE_STATE_ATTR_SPAWN,
243         SERVICE_STATE_ATTR_NAME,
244         __SERVICE_STATE_ATTR_MAX,
245 };
246 
247 static const struct blobmsg_policy service_state_attrs[__SERVICE_STATE_ATTR_MAX] = {
248         [SERVICE_STATE_ATTR_SPAWN] = { "spawn", BLOBMSG_TYPE_BOOL },
249         [SERVICE_STATE_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING },
250 };
251 
252 enum {
253         EVENT_TYPE,
254         EVENT_DATA,
255         __EVENT_MAX
256 };
257 
258 static const struct blobmsg_policy event_policy[__EVENT_MAX] = {
259         [EVENT_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_STRING },
260         [EVENT_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE },
261 };
262 
263 enum {
264         VALIDATE_PACKAGE,
265         VALIDATE_TYPE,
266         VALIDATE_SERVICE,
267         __VALIDATE_MAX
268 };
269 
270 static const struct blobmsg_policy validate_policy[__VALIDATE_MAX] = {
271         [VALIDATE_PACKAGE] = { .name = "package", .type = BLOBMSG_TYPE_STRING },
272         [VALIDATE_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_STRING },
273         [VALIDATE_SERVICE] = { .name = "service", .type = BLOBMSG_TYPE_STRING },
274 };
275 
276 enum {
277         DATA_NAME,
278         DATA_INSTANCE,
279         DATA_TYPE,
280         __DATA_MAX
281 };
282 
283 static const struct blobmsg_policy get_data_policy[] = {
284         [DATA_NAME] = { "name", BLOBMSG_TYPE_STRING },
285         [DATA_INSTANCE] = { "instance", BLOBMSG_TYPE_STRING },
286         [DATA_TYPE] = { "type", BLOBMSG_TYPE_STRING },
287 };
288 
289 enum {
290         CONTAINER_CONSOLE_NAME,
291         CONTAINER_CONSOLE_INSTANCE,
292         __CONTAINER_CONSOLE_MAX,
293 };
294 
295 static const struct blobmsg_policy container_console_policy[__CONTAINER_CONSOLE_MAX] = {
296         [CONTAINER_CONSOLE_NAME] = { "name", BLOBMSG_TYPE_STRING },
297         [CONTAINER_CONSOLE_INSTANCE] = { "instance", BLOBMSG_TYPE_STRING },
298 };
299 
300 static inline bool is_container_obj(struct ubus_object *obj)
301 {
302         return (obj && (strcmp(obj->name, "container") == 0));
303 }
304 
305 static inline void put_namespace(struct blob_buf *b, char *name)
306 {
307         char nsfname[32];
308         struct stat statbuf;
309 
310         snprintf(nsfname, sizeof(nsfname), "/proc/self/ns/%s", name);
311 
312         if (!stat(nsfname, &statbuf))
313                 blobmsg_add_string(b, NULL, name);
314 }
315 
316 static void put_cgroups(struct blob_buf *b)
317 {
318         int fd, ret;
319         static char buf[512] = "";
320         char *t, *z;
321 
322         fd = open("/sys/fs/cgroup/cgroup.controllers", O_RDONLY);
323         if (fd == -1)
324                 return;
325 
326         ret = read(fd, &buf, sizeof(buf));
327         close(fd);
328 
329         if (ret < 2)
330                 return;
331 
332         t = buf;
333         while(t) {
334                 z = t;
335                 /* replace space with \0 and direct next entry */
336                 t = strchr(z, ' ');
337                 if (t) {
338                         *(t++) = '\0';
339                 } else { /* replace trailing new-line with \0 */
340                         t = strchr(z, '\n');
341                         if (!t) /* shouldn't happen, but don't segfault if it does */
342                                 break;
343 
344                         *t = '\0';
345                         t = NULL;
346                 }
347                 blobmsg_add_string(b, NULL, z);
348         }
349 }
350 
351 static int
352 container_handle_features(struct ubus_context *ctx, struct ubus_object *obj,
353                     struct ubus_request_data *req, const char *method,
354                     struct blob_attr *msg)
355 {
356         struct utsname utsbuf;
357         struct stat statbuf;
358         void *nsarray, *cgarray;
359 
360         if (stat("/sbin/ujail", &statbuf))
361                 return UBUS_STATUS_NOT_SUPPORTED;
362 
363         if (uname(&utsbuf) < 0)
364                 return UBUS_STATUS_UNKNOWN_ERROR;
365 
366         blob_buf_init(&b, 0);
367         blobmsg_add_string(&b, "machine", utsbuf.machine);
368 
369 #ifdef SECCOMP_SUPPORT
370         blobmsg_add_u8(&b, "seccomp", true);
371 #else
372         blobmsg_add_u8(&b, "seccomp", false);
373 #endif
374 
375         cgarray = blobmsg_open_array(&b, "cgroup");
376         put_cgroups(&b);
377         blobmsg_close_array(&b, cgarray);
378 
379         nsarray = blobmsg_open_array(&b, "namespaces");
380         put_namespace(&b, "cgroup");
381         put_namespace(&b, "ipc");
382         put_namespace(&b, "mnt");
383         put_namespace(&b, "net");
384         put_namespace(&b, "pid");
385 #ifdef CLONE_NEWTIME
386         put_namespace(&b, "time");
387 #endif
388         put_namespace(&b, "user");
389         put_namespace(&b, "uts");
390         blobmsg_close_array(&b, nsarray);
391         ubus_send_reply(ctx, req, b.head);
392 
393         return UBUS_STATUS_OK;
394 }
395 
396 static int
397 service_handle_set(struct ubus_context *ctx, struct ubus_object *obj,
398                    struct ubus_request_data *req, const char *method,
399                    struct blob_attr *msg)
400 {
401         struct blob_attr *tb[__SERVICE_SET_MAX], *cur;
402         struct service *s = NULL;
403         const char *name;
404         bool container = is_container_obj(obj);
405         bool add = !strcmp(method, "add");
406         int ret;
407 
408         blobmsg_parse(service_set_attrs, __SERVICE_SET_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
409         cur = tb[SERVICE_SET_NAME];
410         if (!cur)
411                 return UBUS_STATUS_INVALID_ARGUMENT;
412 
413         name = blobmsg_data(cur);
414 
415         if (container)
416                 s = avl_find_element(&containers, name, s, avl);
417         else
418                 s = avl_find_element(&services, name, s, avl);
419 
420         if (s) {
421                 DEBUG(2, "Update service %s\n", name);
422                 return service_update(s, tb, add);
423         }
424 
425         DEBUG(2, "Create service %s\n", name);
426         s = service_alloc(name);
427         if (!s)
428                 return UBUS_STATUS_UNKNOWN_ERROR;
429 
430         ret = service_update(s, tb, add);
431         if (ret)
432                 return ret;
433 
434         if (container) {
435                 avl_insert(&containers, &s->avl);
436 
437                 service_event("container.start", s->name, NULL);
438         } else {
439                 avl_insert(&services, &s->avl);
440 
441                 service_event("service.start", s->name, NULL);
442         }
443         return 0;
444 }
445 
446 static void
447 service_dump(struct service *s, bool verbose)
448 {
449         struct service_instance *in;
450         void *c, *i;
451 
452         c = blobmsg_open_table(&b, s->name);
453 
454         if (!s->autostart)
455                 blobmsg_add_u8(&b, "autostart", false);
456 
457         if (!avl_is_empty(&s->data_blob.avl)) {
458                 struct blobmsg_list_node *var;
459                 i = blobmsg_open_table(&b, "data");
460                 blobmsg_list_for_each(&s->data_blob, var)
461                         blobmsg_add_blob(&b, var->data);
462                 blobmsg_close_table(&b, i);
463         }
464 
465         if (!avl_is_empty(&s->instances.avl)) {
466                 i = blobmsg_open_table(&b, "instances");
467                 vlist_for_each_element(&s->instances, in, node)
468                         instance_dump(&b, in, verbose);
469                 blobmsg_close_table(&b, i);
470         }
471         if (verbose && s->trigger)
472                 blobmsg_add_blob(&b, s->trigger);
473         if (verbose && !list_empty(&s->validators))
474                 service_validate_dump(&b, s);
475         blobmsg_close_table(&b, c);
476 }
477 
478 static int
479 service_handle_list(struct ubus_context *ctx, struct ubus_object *obj,
480                     struct ubus_request_data *req, const char *method,
481                     struct blob_attr *msg)
482 {
483         struct blob_attr *tb[__SERVICE_LIST_ATTR_MAX];
484         struct service *s;
485         const char *name = NULL;
486         bool verbose = false;
487         bool container = is_container_obj(obj);
488         const struct avl_tree *tree = container?&containers:&services;
489 
490         blobmsg_parse(service_list_attrs, __SERVICE_LIST_ATTR_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
491 
492         if (tb[SERVICE_LIST_ATTR_VERBOSE])
493                 verbose = blobmsg_get_bool(tb[SERVICE_LIST_ATTR_VERBOSE]);
494         if (tb[SERVICE_LIST_ATTR_NAME])
495                 name = blobmsg_get_string(tb[SERVICE_LIST_ATTR_NAME]);
496 
497         blob_buf_init(&b, 0);
498         avl_for_each_element(tree, s, avl) {
499                 if (name && strcmp(s->name, name) != 0)
500                         continue;
501 
502                 service_dump(s, verbose);
503         }
504 
505         ubus_send_reply(ctx, req, b.head);
506 
507         return 0;
508 }
509 
510 static int
511 service_handle_delete(struct ubus_context *ctx, struct ubus_object *obj,
512                     struct ubus_request_data *req, const char *method,
513                     struct blob_attr *msg)
514 {
515         struct blob_attr *tb[__SERVICE_DEL_ATTR_MAX], *cur;
516         struct service *s;
517         struct service_instance *in;
518         bool container = is_container_obj(obj);
519 
520         blobmsg_parse(service_del_attrs, __SERVICE_DEL_ATTR_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
521 
522         cur = tb[SERVICE_DEL_ATTR_NAME];
523         if (!cur)
524                 return UBUS_STATUS_NOT_FOUND;
525 
526         if (container)
527                 s = avl_find_element(&containers, blobmsg_data(cur), s, avl);
528         else
529                 s = avl_find_element(&services, blobmsg_data(cur), s, avl);
530 
531         if (!s)
532                 return UBUS_STATUS_NOT_FOUND;
533 
534         cur = tb[SERVICE_DEL_ATTR_INSTANCE];
535         if (!cur) {
536                 service_delete(s, container);
537                 return 0;
538         }
539 
540         in = vlist_find(&s->instances, blobmsg_data(cur), in, node);
541         if (!in) {
542                 ERROR("instance %s not found\n", (char *) blobmsg_data(cur));
543                 return UBUS_STATUS_NOT_FOUND;
544         }
545 
546         vlist_delete(&s->instances, &in->node);
547 
548         return 0;
549 }
550 
551 static int
552 service_handle_kill(struct service_instance *in, int sig)
553 {
554         if (kill(in->proc.pid, sig) == 0)
555                 return 0;
556 
557         switch (errno) {
558         case EINVAL: return UBUS_STATUS_INVALID_ARGUMENT;
559         case EPERM:  return UBUS_STATUS_PERMISSION_DENIED;
560         case ESRCH:  return UBUS_STATUS_NOT_FOUND;
561         }
562 
563         return UBUS_STATUS_UNKNOWN_ERROR;
564 }
565 
566 static int
567 service_handle_signal(struct ubus_context *ctx, struct ubus_object *obj,
568                     struct ubus_request_data *req, const char *method,
569                     struct blob_attr *msg)
570 {
571         struct blob_attr *tb[__SERVICE_SIGNAL_ATTR_MAX], *cur;
572         struct service *s;
573         struct service_instance *in;
574         bool container = is_container_obj(obj);
575         int sig = SIGHUP;
576         int rv = 0;
577 
578         blobmsg_parse(service_signal_attrs, __SERVICE_SIGNAL_ATTR_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
579 
580         cur = tb[SERVICE_SIGNAL_ATTR_SIGNAL];
581         if (cur)
582                 sig = blobmsg_get_u32(cur);
583 
584         cur = tb[SERVICE_SIGNAL_ATTR_NAME];
585         if (!cur)
586                 return UBUS_STATUS_NOT_FOUND;
587 
588         if (container)
589                 s = avl_find_element(&containers, blobmsg_data(cur), s, avl);
590         else
591                 s = avl_find_element(&services, blobmsg_data(cur), s, avl);
592 
593         if (!s)
594                 return UBUS_STATUS_NOT_FOUND;
595 
596         cur = tb[SERVICE_SIGNAL_ATTR_INSTANCE];
597         if (!cur) {
598                 vlist_for_each_element(&s->instances, in, node)
599                         rv = service_handle_kill(in, sig);
600 
601                 return rv;
602         }
603 
604         in = vlist_find(&s->instances, blobmsg_data(cur), in, node);
605         if (!in) {
606                 ERROR("instance %s not found\n", blobmsg_get_string(cur));
607                 return UBUS_STATUS_NOT_FOUND;
608         }
609 
610         return service_handle_kill(in, sig);
611 }
612 
613 static int
614 service_handle_state(struct ubus_context *ctx, struct ubus_object *obj,
615                      struct ubus_request_data *req, const char *method,
616                      struct blob_attr *msg)
617 {
618         struct blob_attr *tb[__SERVICE_STATE_ATTR_MAX];
619         struct service *s;
620         struct service_instance *in;
621         bool container = is_container_obj(obj);
622         int spawn;
623 
624         blobmsg_parse(service_state_attrs, __SERVICE_STATE_ATTR_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
625 
626         if (!tb[SERVICE_STATE_ATTR_SPAWN])
627                 return UBUS_STATUS_INVALID_ARGUMENT;
628 
629         if (!tb[SERVICE_STATE_ATTR_NAME])
630                 return UBUS_STATUS_NOT_FOUND;
631 
632         if (container)
633                 s = avl_find_element(&containers, blobmsg_data(tb[SERVICE_STATE_ATTR_NAME]), s, avl);
634         else
635                 s = avl_find_element(&services, blobmsg_data(tb[SERVICE_STATE_ATTR_NAME]), s, avl);
636 
637         if (!s)
638                 return UBUS_STATUS_NOT_FOUND;
639 
640         spawn = !!blobmsg_get_u8(tb[SERVICE_STATE_ATTR_SPAWN]);
641         vlist_for_each_element(&s->instances, in, node) {
642                 if (!!in->proc.pending == !!spawn)
643                         continue;
644                 else if (!in->proc.pending)
645                         instance_start(in);
646                 else
647                         instance_stop(in, false);
648         }
649 
650         return UBUS_STATUS_OK;
651 }
652 
653 static int
654 service_handle_update(struct ubus_context *ctx, struct ubus_object *obj,
655                       struct ubus_request_data *req, const char *method,
656                       struct blob_attr *msg)
657 {
658         struct blob_attr *tb[__SERVICE_ATTR_MAX], *cur;
659         struct service *s;
660         bool container = is_container_obj(obj);
661 
662         blobmsg_parse(service_attrs, __SERVICE_ATTR_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
663 
664         cur = tb[SERVICE_SET_NAME];
665         if (!cur)
666                 return UBUS_STATUS_INVALID_ARGUMENT;
667 
668         if (container)
669                 s = avl_find_element(&containers, blobmsg_data(cur), s, avl);
670         else
671                 s = avl_find_element(&services, blobmsg_data(cur), s, avl);
672 
673         if (!s)
674                 return UBUS_STATUS_NOT_FOUND;
675 
676         if (!strcmp(method, "update_start"))
677                 vlist_update(&s->instances);
678         else
679                 vlist_flush(&s->instances);
680 
681         return 0;
682 }
683 
684 static void ubus_event_bcast(const char *type, const char *param1, const char *val1,
685                              const char *param2, const char *val2)
686 {
687         if (!ctx)
688                 return;
689 
690         blob_buf_init(&b, 0);
691         if (param1 && val1)
692                 blobmsg_add_string(&b, param1, val1);
693         if (param2 && val2)
694                 blobmsg_add_string(&b, param2, val2);
695         ubus_notify(ctx, &main_object, type, b.head, -1);
696 }
697 
698 static int
699 service_handle_event(struct ubus_context *ctx, struct ubus_object *obj,
700                         struct ubus_request_data *req, const char *method,
701                         struct blob_attr *msg)
702 {
703         struct blob_attr *tb[__EVENT_MAX];
704         const char *event;
705 
706         if (!msg)
707                 return UBUS_STATUS_INVALID_ARGUMENT;
708 
709         blobmsg_parse(event_policy, __EVENT_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
710         if (!tb[EVENT_TYPE] || !tb[EVENT_DATA])
711                 return UBUS_STATUS_INVALID_ARGUMENT;
712 
713         event = blobmsg_get_string(tb[EVENT_TYPE]);
714         trigger_event(event, tb[EVENT_DATA]);
715 
716         if (!strcmp(event, "config.change")) {
717                 struct blob_attr *tb2[__VALIDATE_MAX];
718 
719                 blobmsg_parse(validate_policy, __VALIDATE_MAX, tb2,
720                               blobmsg_data(tb[EVENT_DATA]), blobmsg_data_len(tb[EVENT_DATA]));
721                 if (tb2[VALIDATE_PACKAGE])
722                         ubus_event_bcast("config.change", "config",
723                                          blobmsg_get_string(tb2[VALIDATE_PACKAGE]), NULL, NULL);
724         }
725         return 0;
726 }
727 
728 static int
729 service_handle_validate(struct ubus_context *ctx, struct ubus_object *obj,
730                         struct ubus_request_data *req, const char *method,
731                         struct blob_attr *msg)
732 {
733         struct blob_attr *tb[__VALIDATE_MAX];
734         char *p = NULL, *t = NULL;
735 
736         if (!msg)
737                 return UBUS_STATUS_INVALID_ARGUMENT;
738 
739         blobmsg_parse(validate_policy, __VALIDATE_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
740         if (tb[VALIDATE_SERVICE]) {
741                 return 0;
742         }
743         if (tb[VALIDATE_PACKAGE])
744                 p = blobmsg_get_string(tb[VALIDATE_PACKAGE]);
745 
746         if (tb[VALIDATE_TYPE])
747                 t = blobmsg_get_string(tb[VALIDATE_TYPE]);
748 
749         blob_buf_init(&b, 0);
750         service_validate_dump_all(&b, p, t);
751         ubus_send_reply(ctx, req, b.head);
752 
753         return 0;
754 }
755 
756 static int
757 service_get_data(struct ubus_context *ctx, struct ubus_object *obj,
758                  struct ubus_request_data *req, const char *method,
759                  struct blob_attr *msg)
760 {
761         struct service_instance *in;
762         struct service *s;
763         struct blob_attr *tb[__DATA_MAX];
764         const char *name = NULL;
765         const char *instance = NULL;
766         const char *type = NULL;
767 
768         blobmsg_parse(get_data_policy, __DATA_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
769         if (tb[DATA_NAME])
770                 name = blobmsg_data(tb[DATA_NAME]);
771         if (tb[DATA_INSTANCE])
772                 instance = blobmsg_data(tb[DATA_INSTANCE]);
773         if (tb[DATA_TYPE])
774                 type = blobmsg_data(tb[DATA_TYPE]);
775 
776         blob_buf_init(&b, 0);
777         avl_for_each_element(&services, s, avl) {
778                 void *cs = NULL;
779                 void *ci = NULL;
780                 struct blobmsg_list_node *var;
781 
782                 if (name && strcmp(name, s->name))
783                         continue;
784 
785                 blobmsg_list_for_each(&s->data_blob, var) {
786                         if (type && strcmp(blobmsg_name(var->data), type))
787                                 continue;
788 
789                         if (!cs)
790                                 cs = blobmsg_open_table(&b, s->name);
791 
792                         blobmsg_add_blob(&b, var->data);
793                 }
794 
795                 vlist_for_each_element(&s->instances, in, node) {
796                         ci = NULL;
797 
798                         if (instance && strcmp(instance, in->name))
799                                 continue;
800 
801                         blobmsg_list_for_each(&in->data, var) {
802                                 if (type &&
803                                     strcmp(blobmsg_name(var->data), type))
804                                         continue;
805 
806                                 if (!cs)
807                                         cs = blobmsg_open_table(&b, s->name);
808                                 if (!ci)
809                                         ci = blobmsg_open_table(&b, in->name);
810 
811                                 blobmsg_add_blob(&b, var->data);
812                         }
813 
814                         if (ci)
815                                 blobmsg_close_table(&b, ci);
816                 }
817 
818                 if (cs)
819                         blobmsg_close_table(&b, cs);
820         }
821 
822         ubus_send_reply(ctx, req, b.head);
823         return 0;
824 }
825 
826 static int
827 container_handle_console(struct ubus_context *ctx, struct ubus_object *obj,
828                          struct ubus_request_data *req, const char *method,
829                          struct blob_attr *msg)
830 {
831         bool attach = !strcmp(method, "console_attach");
832         struct blob_attr *tb[__CONTAINER_CONSOLE_MAX];
833         struct service *s;
834         struct service_instance *in;
835         int console_fd = -1;
836 
837         console_fd = ubus_request_get_caller_fd(req);
838         if (console_fd < 0)
839                 return UBUS_STATUS_INVALID_ARGUMENT;
840 
841         if (!msg)
842                 goto err_console_fd;
843 
844         blobmsg_parse(container_console_policy, __CONTAINER_CONSOLE_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
845         if (!tb[CONTAINER_CONSOLE_NAME])
846                 goto err_console_fd;
847 
848         s = avl_find_element(&containers, blobmsg_data(tb[CONTAINER_CONSOLE_NAME]), s, avl);
849         if (!s)
850                 goto err_console_fd;
851 
852         if (tb[CONTAINER_CONSOLE_INSTANCE]) {
853                 in = vlist_find(&s->instances, blobmsg_data(tb[CONTAINER_CONSOLE_INSTANCE]), in, node);
854         } else {
855                 /* use first element in instances list */
856                 vlist_for_each_element(&s->instances, in, node)
857                         break;
858         }
859         if (!in)
860                 goto err_console_fd;
861 
862         if (attach) {
863                 if (in->console.fd.fd < 0) {
864                         close(console_fd);
865                         return UBUS_STATUS_NOT_SUPPORTED;
866                 }
867 
868                 /* close and replace existing attached console */
869                 if (in->console_client.fd.fd > -1)
870                         close(in->console_client.fd.fd);
871 
872                 ustream_fd_init(&in->console_client, console_fd);
873         } else {
874                 ustream_fd_init(&in->console, console_fd);
875         }
876 
877         return UBUS_STATUS_OK;
878 err_console_fd:
879         close(console_fd);
880         return UBUS_STATUS_INVALID_ARGUMENT;
881 }
882 
883 enum {
884         SERVICE_WATCHDOG_MODE,
885         SERVICE_WATCHDOG_TIMEOUT,
886         SERVICE_WATCHDOG_NAME,
887         SERVICE_WATCHDOG_INSTANCE,
888         __SERVICE_WATCHDOG_MAX,
889 };
890 
891 static const struct blobmsg_policy service_watchdog_policy[__SERVICE_WATCHDOG_MAX] = {
892         [SERVICE_WATCHDOG_MODE] = { "mode", BLOBMSG_TYPE_INT32 },
893         [SERVICE_WATCHDOG_NAME] = { "name", BLOBMSG_TYPE_STRING },
894         [SERVICE_WATCHDOG_TIMEOUT] = { "timeout", BLOBMSG_TYPE_INT32 },
895         [SERVICE_WATCHDOG_INSTANCE] = { "instance", BLOBMSG_TYPE_STRING },
896 };
897 
898 static int
899 service_handle_watchdog(struct ubus_context *ctx, struct ubus_object *obj,
900                     struct ubus_request_data *req, const char *method,
901                     struct blob_attr *msg)
902 {
903         struct blob_attr *tb[__SERVICE_WATCHDOG_MAX] = {0};
904         struct service *s;
905         struct blob_attr *cur;
906         struct service_instance *in;
907 
908         blobmsg_parse(service_watchdog_policy, __SERVICE_WATCHDOG_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
909         cur = tb[SERVICE_WATCHDOG_NAME];
910         if (!cur)
911                 return UBUS_STATUS_NOT_FOUND;
912 
913         s = avl_find_element(&services, blobmsg_data(cur), s, avl);
914         if (!s)
915                 return UBUS_STATUS_NOT_FOUND;
916 
917         cur = tb[SERVICE_WATCHDOG_INSTANCE];
918         if (!cur)
919                 return UBUS_STATUS_NOT_FOUND;
920 
921         in = vlist_find(&s->instances, blobmsg_data(cur), in, node);
922         if (!in) {
923                 ERROR("instance %s not found\n", blobmsg_get_string(cur));
924                 return UBUS_STATUS_NOT_FOUND;
925         }
926 
927         if (tb[SERVICE_WATCHDOG_MODE])
928                 in->watchdog.mode = blobmsg_get_u32(tb[SERVICE_WATCHDOG_MODE]);
929 
930         if (tb[SERVICE_WATCHDOG_TIMEOUT])
931                 in->watchdog.freq = blobmsg_get_u32(tb[SERVICE_WATCHDOG_TIMEOUT]);
932 
933         if (in->watchdog.mode == INSTANCE_WATCHDOG_MODE_DISABLED)
934                 uloop_timeout_cancel(&in->watchdog.timeout);
935         else
936                 uloop_timeout_set(&in->watchdog.timeout, in->watchdog.freq * 1000);
937 
938         blob_buf_init(&b, 0);
939         blobmsg_add_string(&b, "name", blobmsg_get_string(tb[SERVICE_WATCHDOG_NAME]));
940         blobmsg_add_string(&b, "instance", blobmsg_get_string(tb[SERVICE_WATCHDOG_INSTANCE]));
941         blobmsg_add_u32(&b, "mode", in->watchdog.mode);
942         blobmsg_add_u32(&b, "timeout", in->watchdog.freq);
943 
944         ubus_send_reply(ctx, req, b.head);
945 
946         return UBUS_STATUS_OK;
947 }
948 
949 static struct ubus_method main_object_methods[] = {
950         UBUS_METHOD("set", service_handle_set, service_set_attrs),
951         UBUS_METHOD("add", service_handle_set, service_set_attrs),
952         UBUS_METHOD("list", service_handle_list, service_list_attrs),
953         UBUS_METHOD("delete", service_handle_delete, service_del_attrs),
954         UBUS_METHOD("signal", service_handle_signal, service_signal_attrs),
955         UBUS_METHOD("update_start", service_handle_update, service_attrs),
956         UBUS_METHOD("update_complete", service_handle_update, service_attrs),
957         UBUS_METHOD("event", service_handle_event, event_policy),
958         UBUS_METHOD("validate", service_handle_validate, validate_policy),
959         UBUS_METHOD("get_data", service_get_data, get_data_policy),
960         UBUS_METHOD("state", service_handle_state, service_state_attrs),
961         UBUS_METHOD("watchdog", service_handle_watchdog, service_watchdog_policy),
962 };
963 
964 static struct ubus_object_type main_object_type =
965         UBUS_OBJECT_TYPE("service", main_object_methods);
966 
967 static struct ubus_object main_object = {
968         .name = "service",
969         .type = &main_object_type,
970         .methods = main_object_methods,
971         .n_methods = ARRAY_SIZE(main_object_methods),
972 };
973 
974 int
975 service_start_early(char *name, char *cmdline, char *user, char *group)
976 {
977         void *instances, *instance, *command, *respawn;
978         char *t;
979 
980         blob_buf_init(&b, 0);
981         blobmsg_add_string(&b, "name", name);
982         instances = blobmsg_open_table(&b, "instances");
983         instance = blobmsg_open_table(&b, "instance1");
984         command = blobmsg_open_array(&b, "command");
985         t = strtok(cmdline, " ");
986         while (t) {
987                 blobmsg_add_string(&b, NULL, t);
988                 t = strtok(NULL, " ");
989         }
990         blobmsg_close_array(&b, command);
991         respawn = blobmsg_open_array(&b, "respawn");
992         blobmsg_add_string(&b, NULL, "3600");
993         blobmsg_add_string(&b, NULL, "1");
994         blobmsg_add_string(&b, NULL, "");
995         blobmsg_close_array(&b, respawn);
996         if (user)
997                 blobmsg_add_string(&b, "user", user);
998         if (group)
999                 blobmsg_add_string(&b, "group", group);
1000 
1001         blobmsg_close_table(&b, instance);
1002         blobmsg_close_table(&b, instances);
1003 
1004         return service_handle_set(NULL, NULL, NULL, "add", b.head);
1005 }
1006 
1007 void service_stopped(struct service *s)
1008 {
1009         _service_stopped(s, false);
1010 }
1011 
1012 static void _service_stopped(struct service *s, bool container)
1013 {
1014         if (s->deleted && avl_is_empty(&s->instances.avl)) {
1015                 if (container) {
1016                         service_event("container.stop", s->name, NULL);
1017                         avl_delete(&containers, &s->avl);
1018                 } else {
1019                         service_event("service.stop", s->name, NULL);
1020                         avl_delete(&services, &s->avl);
1021                 }
1022                 trigger_del(s);
1023                 service_validate_del(s);
1024                 free(s->trigger);
1025                 free(s);
1026         }
1027 }
1028 
1029 void service_event(const char *type, const char *service, const char *instance)
1030 {
1031         ubus_event_bcast(type, "service", service, "instance", instance);
1032 }
1033 
1034 static struct ubus_method container_object_methods[] = {
1035         UBUS_METHOD("set", service_handle_set, service_set_attrs),
1036         UBUS_METHOD("add", service_handle_set, service_set_attrs),
1037         UBUS_METHOD("list", service_handle_list, service_list_attrs),
1038         UBUS_METHOD("delete", service_handle_delete, service_del_attrs),
1039         UBUS_METHOD("state", service_handle_state, service_state_attrs),
1040         UBUS_METHOD_NOARG("get_features", container_handle_features),
1041         UBUS_METHOD("console_set", container_handle_console, container_console_policy),
1042         UBUS_METHOD("console_attach", container_handle_console, container_console_policy),
1043 };
1044 
1045 static struct ubus_object_type container_object_type =
1046         UBUS_OBJECT_TYPE("container", container_object_methods);
1047 
1048 static struct ubus_object container_object = {
1049         .name = "container",
1050         .type = &container_object_type,
1051         .methods = container_object_methods,
1052         .n_methods = ARRAY_SIZE(container_object_methods),
1053 };
1054 
1055 void ubus_init_service(struct ubus_context *_ctx)
1056 {
1057         struct stat statbuf;
1058 
1059         ctx = _ctx;
1060         ubus_add_object(ctx, &main_object);
1061 
1062         if (!stat("/sbin/ujail", &statbuf))
1063                 ubus_add_object(ctx, &container_object);
1064 }
1065 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt