Simplify starting of services
[src/app-framework-binder.git] / src / afb-apiset.c
1 /*
2  * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
3  * Author José Bollo <jose.bollo@iot.bzh>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #define _GNU_SOURCE
19
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <errno.h>
24
25 #include "afb-session.h"
26 #include "verbose.h"
27 #include "afb-api.h"
28 #include "afb-apiset.h"
29 #include "afb-context.h"
30 #include "afb-xreq.h"
31
32 #define INCR 8          /* CAUTION: must be a power of 2 */
33
34 struct afb_apiset;
35 struct api_desc;
36 struct api_class;
37 struct api_alias;
38 struct api_depend;
39
40 /**
41  * array of items
42  */
43 struct api_array {
44         int count;                      /* count of items */
45         union {
46                 void **anys;
47                 struct api_desc **apis;
48                 struct api_class **classes;
49                 struct api_alias **aliases;
50                 struct api_depend **depends;
51         };
52 };
53
54 /**
55  * Internal description of an api
56  */
57 struct api_desc
58 {
59         struct api_desc *next;
60         const char *name;               /**< name of the api */
61         int status;                     /**< initialisation status */
62         struct afb_api_item api;        /**< handler of the api */
63         struct {
64                 struct api_array classes;
65                 struct api_array apis;
66         } require;
67 };
68
69 /**
70  * internal description of aliases
71  */
72 struct api_alias
73 {
74         struct api_alias *next;
75         struct api_desc *api;
76         char name[1];
77 };
78
79 /**
80  *
81  */
82 struct api_class
83 {
84         struct api_class *next;
85         struct api_array providers;
86         char name[1];
87 };
88
89 /**
90  *
91  */
92 struct api_depend
93 {
94         struct afb_apiset *set;
95         char name[1];
96 };
97
98 /**
99  * Data structure for apiset
100  */
101 struct afb_apiset
102 {
103         struct api_array apis;          /**< the apis */
104         struct api_alias *aliases;      /**< the aliases */
105         struct afb_apiset *subset;      /**< subset if any */
106         struct {
107                 int (*callback)(void*, struct afb_apiset*, const char*); /* not found handler */
108                 void *closure;
109                 void (*cleanup)(void*);
110         } onlack;                       /** not found handler */
111         int timeout;                    /**< the timeout in second for the apiset */
112         int refcount;                   /**< reference count for freeing resources */
113         char name[1];                   /**< name of the apiset */
114 };
115
116 /**
117  * global apis
118  */
119 static struct api_desc *all_apis;
120
121 /**
122  * global classes
123  */
124 static struct api_class *all_classes;
125
126 /**
127  * Ensure enough room in 'array' for 'count' items
128  */
129 static int api_array_ensure_count(struct api_array *array, int count)
130 {
131         int c;
132         void **anys;
133
134         c = (count + INCR - 1) & ~(INCR - 1);
135         anys = realloc(array->anys, c * sizeof *anys);
136         if (!anys) {
137                 errno = ENOMEM;
138                 return -1;
139         }
140
141         array->count = count;
142         array->anys = anys;
143         return 0;
144 }
145
146 /**
147  * Insert in 'array' the item 'any' at the 'index'
148  */
149 static int api_array_insert(struct api_array *array, void *any, int index)
150 {
151         int n = array->count;
152
153         if (api_array_ensure_count(array, n + 1) < 0)
154                 return -1;
155
156         while (index < n) {
157                 array->anys[n] = array->anys[n - 1];
158                 n--;
159         }
160
161         array->anys[index] = any;
162         return 0;
163 }
164
165 /**
166  * Add the item 'any' to the 'array'
167  */
168 static int api_array_add(struct api_array *array, void *any)
169 {
170         int i, n = array->count;
171
172         for (i = 0 ; i < n ; i++) {
173                 if (array->anys[i] == any)
174                         return 0;
175         }
176
177         if (api_array_ensure_count(array, n + 1) < 0)
178                 return -1;
179
180         array->anys[n] = any;
181         return 0;
182 }
183
184 /**
185  * Delete the 'api' from the 'array'
186  * Returns 1 if delete or 0 if not found
187  */
188 static int api_array_del(struct api_array *array, void *any)
189 {
190         int i = array->count;
191         while (i) {
192                 if (array->anys[--i] == any) {
193                         array->anys[i] = array->anys[--array->count];
194                         return 1;
195                 }
196         }
197         return 0;
198 }
199
200 /**
201  * Search the class of 'name' and return it.
202  * In case where the class of 'namle' isn't found, it returns
203  * NULL when 'create' is null or a fresh created instance if 'create' isn't
204  * zero (but NULL on allocation failure).
205  */
206 static struct api_class *class_search(const char *name, int create)
207 {
208         struct api_class *c;
209
210         for (c= all_classes ; c ; c = c->next) {
211                 if (!strcasecmp(name, c->name))
212                         return c;
213         }
214
215         if (!create)
216                 return NULL;
217
218         c = calloc(1, strlen(name) + sizeof *c);
219         if (!c)
220                 errno = ENOMEM;
221         else {
222                 strcpy(c->name, name);
223                 c->next = all_classes;
224                 all_classes = c;
225         }
226         return c;
227 }
228
229 /**
230  * Search the api of 'name'.
231  * @param set the api set
232  * @param name the api name to search
233  * @return the descriptor if found or NULL otherwise
234  */
235 static struct api_desc *search(struct afb_apiset *set, const char *name)
236 {
237         int i, c, up, lo;
238         struct api_desc *a;
239         struct api_alias *aliases;
240
241         /* dichotomic search of the api */
242         /* initial slice */
243         lo = 0;
244         up = set->apis.count;
245         while (lo < up) {
246                 /* check the mid of the slice */
247                 i = (lo + up) >> 1;
248                 a = set->apis.apis[i];
249                 c = strcasecmp(a->name, name);
250                 if (c == 0) {
251                         /* found */
252                         return a;
253                 }
254                 /* update the slice */
255                 if (c < 0)
256                         lo = i + 1;
257                 else
258                         up = i;
259         }
260
261         /* linear search of aliases */
262         aliases = set->aliases;
263         for(;;) {
264                 if (!aliases)
265                         break;
266                 c = strcasecmp(aliases->name, name);
267                 if (!c)
268                         return aliases->api;
269                 if (c > 0)
270                         break;
271                 aliases = aliases->next;
272         }
273         return NULL;
274 }
275
276 /**
277  * Search the api of 'name' in the apiset and in its subsets.
278  * @param set the api set
279  * @param name the api name to search
280  * @return the descriptor if found or NULL otherwise
281  */
282 static struct api_desc *searchrec(struct afb_apiset *set, const char *name)
283 {
284         struct api_desc *result;
285
286         do {
287                 result = search(set, name);
288         } while (result == NULL && (set = set->subset) != NULL);
289
290         return result;
291 }
292
293 /**
294  * Increases the count of references to the apiset and return its address
295  * @param set the set whose reference count is to be increased
296  * @return the given apiset
297  */
298 struct afb_apiset *afb_apiset_addref(struct afb_apiset *set)
299 {
300         if (set)
301                 __atomic_add_fetch(&set->refcount, 1, __ATOMIC_RELAXED);
302         return set;
303 }
304
305 /**
306  * Decreases the count of references to the apiset and frees its
307  * resources when no more references exists.
308  * @param set the set to unrefrence
309  */
310 void afb_apiset_unref(struct afb_apiset *set)
311 {
312         struct api_alias *a;
313         struct api_desc *d;
314
315         if (set && !__atomic_sub_fetch(&set->refcount, 1, __ATOMIC_RELAXED)) {
316                 afb_apiset_unref(set->subset);
317                 if (set->onlack.cleanup)
318                         set->onlack.cleanup(set->onlack.closure);
319                 while((a = set->aliases)) {
320                         set->aliases = a->next;
321                         free(a);
322                 }
323                 while (set->apis.count) {
324                         d = set->apis.apis[--set->apis.count];
325                         if (d->api.itf->unref)
326                                 d->api.itf->unref(d->api.closure);
327                         free(d);
328                 }
329                 free(set->apis.apis);
330                 free(set);
331         }
332 }
333
334 /**
335  * Create an apiset
336  * @param name the name of the apiset
337  * @param timeout the default timeout in seconds for the apiset
338  * @return the created apiset or NULL in case of error
339  */
340 struct afb_apiset *afb_apiset_create(const char *name, int timeout)
341 {
342         struct afb_apiset *set;
343
344         set = calloc(1, (name ? strlen(name) : 0) + sizeof *set);
345         if (set) {
346                 set->timeout = timeout;
347                 set->refcount = 1;
348                 if (name)
349                         strcpy(set->name, name);
350         }
351         return set;
352 }
353
354 /**
355  * Create an apiset being the last subset of 'set'
356  * @param set     the set to extend with the created subset (can be NULL)
357  * @param name    the name of the created apiset (can be NULL)
358  * @param timeout the default timeout in seconds for the created apiset
359  * @return the created apiset or NULL in case of error
360  */
361 struct afb_apiset *afb_apiset_create_subset_last(struct afb_apiset *set, const char *name, int timeout)
362 {
363         if (set)
364                 while (set->subset)
365                         set = set->subset;
366         return afb_apiset_create_subset_first(set, name, timeout);
367 }
368
369 /**
370  * Create an apiset being the first subset of 'set'
371  * @param set     the set to extend with the created subset (can be NULL)
372  * @param name    the name of the created apiset (can be NULL)
373  * @param timeout the default timeout in seconds for the created apiset
374  * @return the created apiset or NULL in case of error
375  */
376 struct afb_apiset *afb_apiset_create_subset_first(struct afb_apiset *set, const char *name, int timeout)
377 {
378         struct afb_apiset *result = afb_apiset_create(name, timeout);
379         if (result && set) {
380                 result->subset = set->subset;
381                 set->subset = result;
382         }
383         return result;
384 }
385
386 /**
387  * the name of the apiset
388  * @param set the api set
389  * @return the name of the set
390  */
391 const char *afb_apiset_name(struct afb_apiset *set)
392 {
393         return set->name;
394 }
395
396 /**
397  * Get the API timeout of the set
398  * @param set the api set
399  * @return the timeout in seconds
400  */
401 int afb_apiset_timeout_get(struct afb_apiset *set)
402 {
403         return set->timeout;
404 }
405
406 /**
407  * Set the API timeout of the set
408  * @param set the api set
409  * @param to the timeout in seconds
410  */
411 void afb_apiset_timeout_set(struct afb_apiset *set, int to)
412 {
413         set->timeout = to;
414 }
415
416 /**
417  * Get the subset of the set
418  * @param set the api set
419  * @return the subset of set
420  */
421 struct afb_apiset *afb_apiset_subset_get(struct afb_apiset *set)
422 {
423         return set->subset;
424 }
425
426 /**
427  * Set the subset of the set
428  * @param set the api set
429  * @param subset the subset to set
430  */
431 void afb_apiset_subset_set(struct afb_apiset *set, struct afb_apiset *subset)
432 {
433         struct afb_apiset *tmp;
434         if (subset == set) {
435                 /* avoid infinite loop */
436                 subset = NULL;
437         }
438         tmp = set->subset;
439         set->subset = afb_apiset_addref(subset);
440         afb_apiset_unref(tmp);
441 }
442
443 void afb_apiset_onlack_set(struct afb_apiset *set, int (*callback)(void*, struct afb_apiset*, const char*), void *closure, void (*cleanup)(void*))
444 {
445         if (set->onlack.cleanup)
446                 set->onlack.cleanup(set->onlack.closure);
447         set->onlack.callback = callback;
448         set->onlack.closure = closure;
449         set->onlack.cleanup = cleanup;
450 }
451
452 /**
453  * Adds the api of 'name' described by 'api'.
454  * @param set the api set
455  * @param name the name of the api to add (have to survive, not copied!)
456  * @param api the api
457  * @returns 0 in case of success or -1 in case
458  * of error with errno set:
459  *   - EEXIST if name already registered
460  *   - ENOMEM when out of memory
461  */
462 int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api_item api)
463 {
464         struct api_desc *desc;
465         int i, c;
466
467         /* check whether it exists already */
468         if (search(set, name)) {
469                 ERROR("api of name %s already exists", name);
470                 errno = EEXIST;
471                 goto error;
472         }
473
474         /* search insertion place */
475         for (i = 0 ; i < set->apis.count ; i++) {
476                 c = strcasecmp(set->apis.apis[i]->name, name);
477                 if (c > 0)
478                         break;
479         }
480
481         /* allocates memory */
482         desc = calloc(1, sizeof *desc);
483         if (!desc)
484                 goto oom;
485
486         desc->status = -1;
487         desc->api = api;
488         desc->name = name;
489
490         if (api_array_insert(&set->apis, desc, i) < 0) {
491                 free(desc);
492                 goto error;
493         }
494
495         desc->next = all_apis;
496         all_apis = desc;
497
498         INFO("API %s added", name);
499
500         return 0;
501
502 oom:
503         ERROR("out of memory");
504         errno = ENOMEM;
505 error:
506         return -1;
507 }
508
509 /**
510  * Adds a the 'alias' name to the api of 'name'.
511  * @params set the api set
512  * @param name the name of the api to alias
513  * @param alias the aliased name to add to the api of name
514  * @returns 0 in case of success or -1 in case
515  * of error with errno set:
516  *   - ENOENT if the api doesn't exist
517  *   - EEXIST if name (of alias) already registered
518  *   - ENOMEM when out of memory
519  */
520 int afb_apiset_add_alias(struct afb_apiset *set, const char *name, const char *alias)
521 {
522         struct api_desc *api;
523         struct api_alias *ali, **pali;
524
525         /* check alias doesn't already exist */
526         if (search(set, alias)) {
527                 ERROR("api of name %s already exists", alias);
528                 errno = EEXIST;
529                 goto error;
530         }
531
532         /* check aliased api exists */
533         api = search(set, name);
534         if (api == NULL) {
535                 ERROR("api of name %s doesn't exists", name);
536                 errno = ENOENT;
537                 goto error;
538         }
539
540         /* allocates and init the struct */
541         ali = malloc(sizeof *ali + strlen(alias));
542         if (ali == NULL) {
543                 ERROR("out of memory");
544                 errno = ENOMEM;
545                 goto error;
546         }
547         ali->api = api;
548         strcpy(ali->name, alias);
549
550         /* insert the alias in the sorted order */
551         pali = &set->aliases;
552         while(*pali && strcmp((*pali)->name, alias) < 0)
553                 pali = &(*pali)->next;
554         ali->next = *pali;
555         *pali = ali;
556         return 0;
557 error:
558         return -1;
559 }
560
561 int afb_apiset_is_alias(struct afb_apiset *set, const char *name)
562 {
563         struct api_desc *api = searchrec(set, name);
564         return api && strcasecmp(api->name, name);
565 }
566
567 const char *afb_apiset_unalias(struct afb_apiset *set, const char *name)
568 {
569         struct api_desc *api = searchrec(set, name);
570         return api ? api->name : NULL;
571 }
572
573 /**
574  * Delete from the 'set' the api of 'name'.
575  * @param set the set to be changed
576  * @param name the name of the API to remove
577  * @return 0 in case of success or -1 in case where the API doesn't exist.
578  */
579 int afb_apiset_del(struct afb_apiset *set, const char *name)
580 {
581         struct api_class *cla;
582         struct api_alias *ali, **pali;
583         struct api_desc *desc, **pdesc, *odesc;
584         int i, c;
585
586         /* search the alias */
587         pali = &set->aliases;
588         while ((ali = *pali)) {
589                 c = strcasecmp(ali->name, name);
590                 if (!c) {
591                         *pali = ali->next;
592                         free(ali);
593                         return 0;
594                 }
595                 if (c > 0)
596                         break;
597                 pali = &ali->next;
598         }
599
600         /* search the api */
601         for (i = 0 ; i < set->apis.count ; i++) {
602                 desc = set->apis.apis[i];
603                 c = strcasecmp(desc->name, name);
604                 if (c == 0) {
605                         /* remove from classes */
606                         for (cla = all_classes ; cla ; cla = cla->next)
607                                 api_array_del(&cla->providers, desc);
608
609                         /* unlink from the whole set and their requires */
610                         pdesc = &all_apis;
611                         while ((odesc = *pdesc) != desc) {
612                                 pdesc = &odesc->next;
613                         }
614                         *pdesc = odesc = desc->next;
615                         while (odesc) {
616                                 odesc = odesc->next;
617                         }
618
619                         /* remove references from classes */
620                         free(desc->require.classes.classes);
621
622                         /* drop the aliases */
623                         pali = &set->aliases;
624                         while ((ali = *pali)) {
625                                 if (ali->api != desc)
626                                         pali = &ali->next;
627                                 else {
628                                         *pali = ali->next;
629                                         free(ali);
630                                 }
631                         }
632
633                         /* unref the api */
634                         if (desc->api.itf->unref)
635                                 desc->api.itf->unref(desc->api.closure);
636
637                         set->apis.count--;
638                         while(i < set->apis.count) {
639                                 set->apis.apis[i] = set->apis.apis[i + 1];
640                                 i++;
641                         }
642                         free(desc);
643                         return 0;
644                 }
645                 if (c > 0)
646                         break;
647         }
648         errno = ENOENT;
649         return -1;
650 }
651
652 /**
653  * Get from the 'set' the API of 'name' in 'api' with fallback to subset or default api
654  * @param set the set of API
655  * @param name the name of the API to get
656  * @param rec if not zero look also recursively in subsets
657  * @return the api pointer in case of success or NULL in case of error
658  */
659 static struct api_desc *lookup(struct afb_apiset *set, const char *name, int rec)
660 {
661         struct api_desc *result;
662
663         result = search(set, name);
664         while (!result) {
665                 /* lacking the api, try onlack behaviour */
666                 if (set->onlack.callback && set->onlack.callback(set->onlack.closure, set, name) > 0) {
667                         result = search(set, name);
668                         if (result)
669                                 break;
670                 }
671                 if (!rec || !(set = set->subset))
672                         break;
673                 result = search(set, name);
674         }
675         return result;
676 }
677
678 /**
679  * Get from the 'set' the API of 'name' in 'api'
680  * @param set the set of API
681  * @param name the name of the API to get
682  * @param rec if not zero look also recursively in subsets
683  * @return the api pointer in case of success or NULL in case of error
684  */
685 const struct afb_api_item *afb_apiset_lookup(struct afb_apiset *set, const char *name, int rec)
686 {
687         struct api_desc *i;
688
689         i = lookup(set, name, rec);
690         if (i)
691                 return &i->api;
692         errno = ENOENT;
693         return NULL;
694 }
695
696 static int start_api(struct api_desc *api);
697
698 /**
699  * Start the apis of the 'array'
700  */
701 static int start_array_apis(struct api_array *array)
702 {
703         int i, rc = 0, rc2;
704
705         i = array->count;
706         while (i) {
707                 rc2 = start_api(array->apis[--i]);
708                 if (rc2 < 0) {
709                         rc = rc2;
710                 }
711         }
712         return rc;
713 }
714
715 /**
716  * Start the class 'cla' (start the apis that provide it).
717  */
718 static int start_class(struct api_class *cla)
719 {
720         return start_array_apis(&cla->providers);
721 }
722
723 /**
724  * Start the classes of the 'array'
725  */
726 static int start_array_classes(struct api_array *array)
727 {
728         int i, rc = 0, rc2;
729
730         i = array->count;
731         while (i) {
732                 rc2 = start_class(array->classes[--i]);
733                 if (rc2 < 0) {
734                         rc = rc2;
735                 }
736         }
737         return rc;
738 }
739
740 /**
741  * Start the depends of the 'array'
742  */
743 static int start_array_depends(struct api_array *array)
744 {
745         struct api_desc *api;
746         int i, rc = 0, rc2;
747
748         i = array->count;
749         while (i) {
750                 i--;
751                 api = searchrec(array->depends[i]->set, array->depends[i]->name);
752                 if (!api)
753                         rc = -1;
754                 else {
755                         rc2 = start_api(api);
756                         if (rc2 < 0) {
757                                 rc = rc2;
758                         }
759                 }
760         }
761         return rc;
762 }
763
764 /**
765  * Starts the service 'api'.
766  * @param api the api
767  * @return a positive number on success
768  */
769 static int start_api(struct api_desc *api)
770 {
771         int rc;
772
773         if (api->status == 0)
774                 return 0;
775         else if (api->status > 0) {
776                 errno = api->status;
777                 return -1;
778         }
779
780         INFO("API %s starting...", api->name);
781         api->status = EBUSY;
782         rc = start_array_classes(&api->require.classes);
783         if (rc < 0)
784                 ERROR("Can start classes needed by api %s", api->name);
785         else {
786                 rc = start_array_depends(&api->require.apis);
787                 if (rc < 0)
788                         ERROR("Can start apis needed by api %s", api->name);
789                 else if (api->api.itf->service_start) {
790                         rc = api->api.itf->service_start(api->api.closure);
791                         if (rc < 0)
792                                 ERROR("The api %s failed to start", api->name);
793                 }
794         }
795         if (rc < 0) {
796                 api->status = errno ?: ECANCELED;
797                 return -1;
798         }
799         NOTICE("API %s started", api->name);
800         api->status = 0;
801         return 0;
802 }
803
804 /**
805  * Get from the 'set' the API of 'name' in 'api'
806  * @param set the set of API
807  * @param name the name of the API to get
808  * @param rec if not zero look also recursively in subsets
809  * @return 0 in case of success or -1 in case of error
810  */
811 const struct afb_api_item *afb_apiset_lookup_started(struct afb_apiset *set, const char *name, int rec)
812 {
813         struct api_desc *i;
814
815         i = lookup(set, name, rec);
816         if (i)
817                 return i->status && start_api(i) ? NULL : &i->api;
818         errno = ENOENT;
819         return NULL;
820 }
821
822 /**
823  * Starts a service by its 'api' name.
824  * @param set the api set
825  * @param name name of the service to start
826  * @return a positive number on success
827  */
828 int afb_apiset_start_service(struct afb_apiset *set, const char *name)
829 {
830         struct api_desc *a;
831
832         a = searchrec(set, name);
833         if (!a) {
834                 ERROR("can't find service %s", name);
835                 errno = ENOENT;
836                 return -1;
837         }
838
839         return start_api(a);
840 }
841
842 /**
843  * Starts all possible services but stops at first error.
844  * @param set the api set
845  * @return 0 on success or a negative number when an error is found
846  */
847 int afb_apiset_start_all_services(struct afb_apiset *set)
848 {
849         int rc, ret;
850         int i;
851
852         ret = 0;
853         while (set) {
854                 i = 0;
855                 while (i < set->apis.count) {
856                         rc = start_api(set->apis.apis[i]);
857                         if (rc < 0)
858                                 ret = rc;
859                         i++;
860                 }
861                 set = set->subset;
862         }
863         return ret;
864 }
865
866 /**
867  * Ask to update the hook flags of the 'api'
868  * @param set the api set
869  * @param name the api to update (NULL updates all)
870  */
871 void afb_apiset_update_hooks(struct afb_apiset *set, const char *name)
872 {
873         struct api_desc **i, **e, *d;
874
875         if (!name) {
876                 i = set->apis.apis;
877                 e = &set->apis.apis[set->apis.count];
878                 while (i != e) {
879                         d = *i++;
880                         if (d->api.itf->update_hooks)
881                                 d->api.itf->update_hooks(d->api.closure);
882                 }
883         } else {
884                 d = searchrec(set, name);
885                 if (d && d->api.itf->update_hooks)
886                         d->api.itf->update_hooks(d->api.closure);
887         }
888 }
889
890 /**
891  * Set the logmask of the 'api' to 'mask'
892  * @param set the api set
893  * @param name the api to set (NULL set all)
894  */
895 void afb_apiset_set_logmask(struct afb_apiset *set, const char *name, int mask)
896 {
897         int i;
898         struct api_desc *d;
899
900         if (!name) {
901                 for (i = 0 ; i < set->apis.count ; i++) {
902                         d = set->apis.apis[i];;
903                         if (d->api.itf->set_logmask)
904                                 d->api.itf->set_logmask(d->api.closure, mask);
905                 }
906         } else {
907                 d = searchrec(set, name);
908                 if (d && d->api.itf->set_logmask)
909                         d->api.itf->set_logmask(d->api.closure, mask);
910         }
911 }
912
913 /**
914  * Get the logmask level of the 'api'
915  * @param set the api set
916  * @param name the api to get
917  * @return the logmask level or -1 in case of error
918  */
919 int afb_apiset_get_logmask(struct afb_apiset *set, const char *name)
920 {
921         const struct api_desc *i;
922
923         i = name ? searchrec(set, name) : NULL;
924         if (!i) {
925                 errno = ENOENT;
926                 return -1;
927         }
928
929         if (!i->api.itf->get_logmask)
930                 return logmask;
931
932         return i->api.itf->get_logmask(i->api.closure);
933 }
934
935 /**
936  * Get the description of the API of 'name'
937  * @param set the api set
938  * @param name the api whose description is required
939  * @return the description or NULL
940  */
941 struct json_object *afb_apiset_describe(struct afb_apiset *set, const char *name)
942 {
943         const struct api_desc *i;
944
945         i = name ? searchrec(set, name) : NULL;
946         return i && i->api.itf->describe ? i->api.itf->describe(i->api.closure) : NULL;
947 }
948
949 struct get_names {
950         union  {
951                 struct {
952                         size_t count;
953                         size_t size;
954                 };
955                 struct {
956                         const char **ptr;
957                         char *data;
958                 };
959         };
960         int type;
961 };
962
963 static void get_names_count(void *closure, struct afb_apiset *set, const char *name, int isalias)
964 {
965         struct get_names *gc = closure;
966         if ((1 + isalias) & gc->type) {
967                 gc->size += strlen(name);
968                 gc->count++;
969         }
970 }
971
972 static void get_names_value(void *closure, struct afb_apiset *set, const char *name, int isalias)
973 {
974         struct get_names *gc = closure;
975         if ((1 + isalias) & gc->type) {
976                 *gc->ptr++ = gc->data;
977                 gc->data = stpcpy(gc->data, name) + 1;
978         }
979 }
980
981 #if !defined(APISET_NO_SORT)
982 static int get_names_sortcb(const void *a, const void *b)
983 {
984         return strcasecmp(*(const char **)a, *(const char **)b);
985 }
986 #endif
987
988 /**
989  * Get the list of api names
990  * @param set the api set
991  * @param rec recursive
992  * @param type expected type: 1 names, 3 names+aliases, 2 aliases
993  * @return a NULL terminated array of api names. Must be freed.
994  */
995 const char **afb_apiset_get_names(struct afb_apiset *set, int rec, int type)
996 {
997         struct get_names gc;
998         size_t size;
999         const char **names;
1000
1001         gc.count = gc.size = 0;
1002         gc.type = type >= 1 && type <= 3 ? type : 1;
1003         afb_apiset_enum(set, rec, get_names_count, &gc);
1004
1005         size = gc.size + gc.count * (1 + sizeof *names) + sizeof(*names);
1006         names = malloc(size);
1007
1008         if (!names)
1009                 errno = ENOMEM;
1010         else {
1011                 gc.data = (char*)&names[gc.count + 1];
1012                 gc.ptr = names;
1013                 afb_apiset_enum(set, rec, get_names_value, &gc);
1014 #if !defined(APISET_NO_SORT)
1015                 qsort(names, gc.ptr - names, sizeof *names, get_names_sortcb);
1016 #endif
1017                 *gc.ptr = NULL;
1018         }
1019         return names;
1020 }
1021
1022 /**
1023  * Enumerate the api names to a callback.
1024  * @param set the api set
1025  * @param rec should the enumeration be recursive
1026  * @param callback the function to call for each name
1027  * @param closure the closure for the callback
1028  */
1029 void afb_apiset_enum(
1030         struct afb_apiset *set,
1031         int rec,
1032         void (*callback)(void *closure, struct afb_apiset *set, const char *name, int isalias),
1033         void *closure)
1034 {
1035         int i;
1036         struct afb_apiset *iset;
1037         struct api_desc *d;
1038         struct api_alias *a;
1039
1040         iset = set;
1041         while (iset) {
1042                 for (i = 0 ; i < set->apis.count ; i++) {
1043                         d = set->apis.apis[i];;
1044                         if (searchrec(set, d->name) == d)
1045                                 callback(closure, iset, d->name, 0);
1046                 }
1047                 a = iset->aliases;
1048                 while (a) {
1049                         if (searchrec(set, a->name) == a->api)
1050                                 callback(closure, iset, a->name, 1);
1051                         a = a->next;
1052                 }
1053                 iset = rec ? iset->subset : NULL;
1054         }
1055 }
1056
1057 /**
1058  * Declare that the api of 'name' requires the api of name 'required'.
1059  * The api is searched in the apiset 'set' and if 'rec' isn't null also in its subset.
1060  * Returns 0 if the declaration successed or -1 in case of failure
1061  * (ENOMEM: allocation failure, ENOENT: api name not found)
1062  */
1063 int afb_apiset_require(struct afb_apiset *set, const char *name, const char *required)
1064 {
1065         struct api_desc *a;
1066         struct api_depend *d;
1067         int rc = -1;
1068
1069         a = searchrec(set, name);
1070         if (!a)
1071                 errno = ENOENT;
1072         else {
1073                 d = malloc(strlen(required) + sizeof *d);
1074                 if (!d)
1075                         errno = ENOMEM;
1076                 else {
1077                         d->set = set;
1078                         strcpy(d->name, required);
1079                         rc = api_array_add(&a->require.apis, d);
1080                 }
1081         }
1082         return rc;
1083 }
1084
1085 /**
1086  * Declare that the api of name 'apiname' requires the class of name 'classname'.
1087  * Returns 0 if the declaration successed or -1 in case of failure
1088  * (ENOMEM: allocation failure, ENOENT: api name not found)
1089  */
1090 int afb_apiset_require_class(struct afb_apiset *set, const char *apiname, const char *classname)
1091 {
1092         struct api_desc *a = searchrec(set, apiname);
1093         struct api_class *c = class_search(classname, 1);
1094         return a && c ? api_array_add(&a->require.classes, c) : (errno = ENOENT, -1);
1095 }
1096
1097 /**
1098  * Declare that the api of name 'apiname' provides the class of name 'classname'
1099  * Returns 0 if the declaration successed or -1 in case of failure
1100  * (ENOMEM: allocation failure, ENOENT: api name not found)
1101  */
1102 int afb_apiset_provide_class(struct afb_apiset *set, const char *apiname, const char *classname)
1103 {
1104         struct api_desc *a = searchrec(set, apiname);
1105         struct api_class *c = class_search(classname, 1);
1106         return a && c ? api_array_add(&c->providers, a) : (errno = ENOENT, -1);
1107 }
1108
1109 /**
1110  * Start any API that provides the class of name 'classname'
1111  */
1112 int afb_apiset_class_start(const char *classname)
1113 {
1114         struct api_class *cla = class_search(classname, 0);
1115         return cla ? start_class(cla) : (errno = ENOENT, -1);
1116 }
1117