Fedora 30 packaging fix issu
[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[];
77 };
78
79 /**
80  *
81  */
82 struct api_class
83 {
84         struct api_class *next;
85         struct api_array providers;
86         char name[];
87 };
88
89 /**
90  *
91  */
92 struct api_depend
93 {
94         struct afb_apiset *set;
95         char name[];
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[];                    /**< 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) + 1 + 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) + 1 + 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  * @return 0 in case of success or -1 if it had created a loop
432  */
433 int afb_apiset_subset_set(struct afb_apiset *set, struct afb_apiset *subset)
434 {
435         struct afb_apiset *tmp;
436
437         /* avoid infinite loop */
438         for (tmp = subset ; tmp ; tmp = tmp->subset)
439                 if (tmp == set)
440                         return -1;
441
442         tmp = set->subset;
443         set->subset = afb_apiset_addref(subset);
444         afb_apiset_unref(tmp);
445
446         return 0;
447 }
448
449 void afb_apiset_onlack_set(struct afb_apiset *set, int (*callback)(void*, struct afb_apiset*, const char*), void *closure, void (*cleanup)(void*))
450 {
451         if (set->onlack.cleanup)
452                 set->onlack.cleanup(set->onlack.closure);
453         set->onlack.callback = callback;
454         set->onlack.closure = closure;
455         set->onlack.cleanup = cleanup;
456 }
457
458 /**
459  * Adds the api of 'name' described by 'api'.
460  * @param set the api set
461  * @param name the name of the api to add (have to survive, not copied!)
462  * @param api the api
463  * @returns 0 in case of success or -1 in case
464  * of error with errno set:
465  *   - EEXIST if name already registered
466  *   - ENOMEM when out of memory
467  */
468 int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api_item api)
469 {
470         struct api_desc *desc;
471         int i, c;
472
473         /* check whether it exists already */
474         if (search(set, name)) {
475                 ERROR("api of name %s already exists", name);
476                 errno = EEXIST;
477                 goto error;
478         }
479
480         /* search insertion place */
481         for (i = 0 ; i < set->apis.count ; i++) {
482                 c = strcasecmp(set->apis.apis[i]->name, name);
483                 if (c > 0)
484                         break;
485         }
486
487         /* allocates memory */
488         desc = calloc(1, sizeof *desc);
489         if (!desc)
490                 goto oom;
491
492         desc->status = -1;
493         desc->api = api;
494         desc->name = name;
495
496         if (api_array_insert(&set->apis, desc, i) < 0) {
497                 free(desc);
498                 goto error;
499         }
500
501         desc->next = all_apis;
502         all_apis = desc;
503
504         if (afb_api_is_public(name))
505                 INFO("API %s added", name);
506
507         return 0;
508
509 oom:
510         ERROR("out of memory");
511         errno = ENOMEM;
512 error:
513         return -1;
514 }
515
516 /**
517  * Adds a the 'alias' name to the api of 'name'.
518  * @params set the api set
519  * @param name the name of the api to alias
520  * @param alias the aliased name to add to the api of name
521  * @returns 0 in case of success or -1 in case
522  * of error with errno set:
523  *   - ENOENT if the api doesn't exist
524  *   - EEXIST if name (of alias) already registered
525  *   - ENOMEM when out of memory
526  */
527 int afb_apiset_add_alias(struct afb_apiset *set, const char *name, const char *alias)
528 {
529         struct api_desc *api;
530         struct api_alias *ali, **pali;
531
532         /* check alias doesn't already exist */
533         if (search(set, alias)) {
534                 ERROR("api of name %s already exists", alias);
535                 errno = EEXIST;
536                 goto error;
537         }
538
539         /* check aliased api exists */
540         api = search(set, name);
541         if (api == NULL) {
542                 ERROR("api of name %s doesn't exists", name);
543                 errno = ENOENT;
544                 goto error;
545         }
546
547         /* allocates and init the struct */
548         ali = malloc(sizeof *ali + strlen(alias) + 1);
549         if (ali == NULL) {
550                 ERROR("out of memory");
551                 errno = ENOMEM;
552                 goto error;
553         }
554         ali->api = api;
555         strcpy(ali->name, alias);
556
557         /* insert the alias in the sorted order */
558         pali = &set->aliases;
559         while(*pali && strcmp((*pali)->name, alias) < 0)
560                 pali = &(*pali)->next;
561         ali->next = *pali;
562         *pali = ali;
563         return 0;
564 error:
565         return -1;
566 }
567
568 int afb_apiset_is_alias(struct afb_apiset *set, const char *name)
569 {
570         struct api_desc *api = searchrec(set, name);
571         return api && strcasecmp(api->name, name);
572 }
573
574 const char *afb_apiset_unalias(struct afb_apiset *set, const char *name)
575 {
576         struct api_desc *api = searchrec(set, name);
577         return api ? api->name : NULL;
578 }
579
580 /**
581  * Delete from the 'set' the api of 'name'.
582  * @param set the set to be changed
583  * @param name the name of the API to remove
584  * @return 0 in case of success or -1 in case where the API doesn't exist.
585  */
586 int afb_apiset_del(struct afb_apiset *set, const char *name)
587 {
588         struct api_class *cla;
589         struct api_alias *ali, **pali;
590         struct api_desc *desc, **pdesc, *odesc;
591         int i, c;
592
593         /* search the alias */
594         pali = &set->aliases;
595         while ((ali = *pali)) {
596                 c = strcasecmp(ali->name, name);
597                 if (!c) {
598                         *pali = ali->next;
599                         free(ali);
600                         return 0;
601                 }
602                 if (c > 0)
603                         break;
604                 pali = &ali->next;
605         }
606
607         /* search the api */
608         for (i = 0 ; i < set->apis.count ; i++) {
609                 desc = set->apis.apis[i];
610                 c = strcasecmp(desc->name, name);
611                 if (c == 0) {
612                         /* remove from classes */
613                         for (cla = all_classes ; cla ; cla = cla->next)
614                                 api_array_del(&cla->providers, desc);
615
616                         /* unlink from the whole set and their requires */
617                         pdesc = &all_apis;
618                         while ((odesc = *pdesc) != desc) {
619                                 pdesc = &odesc->next;
620                         }
621                         *pdesc = odesc = desc->next;
622                         while (odesc) {
623                                 odesc = odesc->next;
624                         }
625
626                         /* remove references from classes */
627                         free(desc->require.classes.classes);
628
629                         /* drop the aliases */
630                         pali = &set->aliases;
631                         while ((ali = *pali)) {
632                                 if (ali->api != desc)
633                                         pali = &ali->next;
634                                 else {
635                                         *pali = ali->next;
636                                         free(ali);
637                                 }
638                         }
639
640                         /* unref the api */
641                         if (desc->api.itf->unref)
642                                 desc->api.itf->unref(desc->api.closure);
643
644                         set->apis.count--;
645                         while(i < set->apis.count) {
646                                 set->apis.apis[i] = set->apis.apis[i + 1];
647                                 i++;
648                         }
649                         free(desc);
650                         return 0;
651                 }
652                 if (c > 0)
653                         break;
654         }
655         errno = ENOENT;
656         return -1;
657 }
658
659 /**
660  * Get from the 'set' the API of 'name' in 'api' with fallback to subset or default api
661  * @param set the set of API
662  * @param name the name of the API to get
663  * @param rec if not zero look also recursively in subsets
664  * @return the api pointer in case of success or NULL in case of error
665  */
666 static struct api_desc *lookup(struct afb_apiset *set, const char *name, int rec)
667 {
668         struct api_desc *result;
669
670         result = search(set, name);
671         while (!result) {
672                 /* lacking the api, try onlack behaviour */
673                 if (set->onlack.callback && set->onlack.callback(set->onlack.closure, set, name) > 0) {
674                         result = search(set, name);
675                         if (result)
676                                 break;
677                 }
678                 if (!rec || !(set = set->subset))
679                         break;
680                 result = search(set, name);
681         }
682         return result;
683 }
684
685 /**
686  * Get from the 'set' the API of 'name' in 'api'
687  * @param set the set of API
688  * @param name the name of the API to get
689  * @param rec if not zero look also recursively in subsets
690  * @return the api pointer in case of success or NULL in case of error
691  */
692 const struct afb_api_item *afb_apiset_lookup(struct afb_apiset *set, const char *name, int rec)
693 {
694         struct api_desc *i;
695
696         i = lookup(set, name, rec);
697         if (i)
698                 return &i->api;
699         errno = ENOENT;
700         return NULL;
701 }
702
703 static int start_api(struct api_desc *api);
704
705 /**
706  * Start the apis of the 'array'
707  */
708 static int start_array_apis(struct api_array *array)
709 {
710         int i, rc = 0, rc2;
711
712         i = array->count;
713         while (i) {
714                 rc2 = start_api(array->apis[--i]);
715                 if (rc2 < 0) {
716                         rc = rc2;
717                 }
718         }
719         return rc;
720 }
721
722 /**
723  * Start the class 'cla' (start the apis that provide it).
724  */
725 static int start_class(struct api_class *cla)
726 {
727         return start_array_apis(&cla->providers);
728 }
729
730 /**
731  * Start the classes of the 'array'
732  */
733 static int start_array_classes(struct api_array *array)
734 {
735         int i, rc = 0, rc2;
736
737         i = array->count;
738         while (i) {
739                 rc2 = start_class(array->classes[--i]);
740                 if (rc2 < 0) {
741                         rc = rc2;
742                 }
743         }
744         return rc;
745 }
746
747 /**
748  * Start the depends of the 'array'
749  */
750 static int start_array_depends(struct api_array *array)
751 {
752         struct api_desc *api;
753         int i, rc = 0, rc2;
754
755         i = array->count;
756         while (i) {
757                 i--;
758                 api = searchrec(array->depends[i]->set, array->depends[i]->name);
759                 if (!api)
760                         rc = -1;
761                 else {
762                         rc2 = start_api(api);
763                         if (rc2 < 0) {
764                                 rc = rc2;
765                         }
766                 }
767         }
768         return rc;
769 }
770
771 /**
772  * Starts the service 'api'.
773  * @param api the api
774  * @return a positive number on success
775  */
776 static int start_api(struct api_desc *api)
777 {
778         int rc;
779
780         if (api->status == 0)
781                 return 0;
782         else if (api->status > 0) {
783                 errno = api->status;
784                 return -1;
785         }
786
787         NOTICE("API %s starting...", api->name);
788         api->status = EBUSY;
789         rc = start_array_classes(&api->require.classes);
790         if (rc < 0)
791                 ERROR("Cannot start classes needed by api %s", api->name);
792         else {
793                 rc = start_array_depends(&api->require.apis);
794                 if (rc < 0)
795                         ERROR("Cannot start apis needed by api %s", api->name);
796                 else if (api->api.itf->service_start) {
797                         rc = api->api.itf->service_start(api->api.closure);
798                         if (rc < 0)
799                                 ERROR("The api %s failed to start", api->name);
800                 }
801         }
802         if (rc < 0) {
803                 api->status = errno ?: ECANCELED;
804                 return -1;
805         }
806         INFO("API %s started", api->name);
807         api->status = 0;
808         return 0;
809 }
810
811 /**
812  * Get from the 'set' the API of 'name' in 'api'
813  * @param set the set of API
814  * @param name the name of the API to get
815  * @param rec if not zero look also recursively in subsets
816  * @return 0 in case of success or -1 in case of error
817  */
818 const struct afb_api_item *afb_apiset_lookup_started(struct afb_apiset *set, const char *name, int rec)
819 {
820         struct api_desc *i;
821
822         i = lookup(set, name, rec);
823         if (i)
824                 return i->status && start_api(i) ? NULL : &i->api;
825         errno = ENOENT;
826         return NULL;
827 }
828
829 /**
830  * Starts a service by its 'api' name.
831  * @param set the api set
832  * @param name name of the service to start
833  * @return a positive number on success
834  */
835 int afb_apiset_start_service(struct afb_apiset *set, const char *name)
836 {
837         struct api_desc *a;
838
839         a = searchrec(set, name);
840         if (!a) {
841                 ERROR("can't find service %s", name);
842                 errno = ENOENT;
843                 return -1;
844         }
845
846         return start_api(a);
847 }
848
849 /**
850  * Starts all possible services but stops at first error.
851  * @param set the api set
852  * @return 0 on success or a negative number when an error is found
853  */
854 int afb_apiset_start_all_services(struct afb_apiset *set)
855 {
856         int rc, ret;
857         int i;
858
859         ret = 0;
860         while (set) {
861                 i = 0;
862                 while (i < set->apis.count) {
863                         rc = start_api(set->apis.apis[i]);
864                         if (rc < 0)
865                                 ret = rc;
866                         i++;
867                 }
868                 set = set->subset;
869         }
870         return ret;
871 }
872
873 /**
874  * Ask to update the hook flags of the 'api'
875  * @param set the api set
876  * @param name the api to update (NULL updates all)
877  */
878 void afb_apiset_update_hooks(struct afb_apiset *set, const char *name)
879 {
880         struct api_desc **i, **e, *d;
881
882         if (!name) {
883                 i = set->apis.apis;
884                 e = &set->apis.apis[set->apis.count];
885                 while (i != e) {
886                         d = *i++;
887                         if (d->api.itf->update_hooks)
888                                 d->api.itf->update_hooks(d->api.closure);
889                 }
890         } else {
891                 d = searchrec(set, name);
892                 if (d && d->api.itf->update_hooks)
893                         d->api.itf->update_hooks(d->api.closure);
894         }
895 }
896
897 /**
898  * Set the logmask of the 'api' to 'mask'
899  * @param set the api set
900  * @param name the api to set (NULL set all)
901  */
902 void afb_apiset_set_logmask(struct afb_apiset *set, const char *name, int mask)
903 {
904         int i;
905         struct api_desc *d;
906
907         if (!name) {
908                 for (i = 0 ; i < set->apis.count ; i++) {
909                         d = set->apis.apis[i];;
910                         if (d->api.itf->set_logmask)
911                                 d->api.itf->set_logmask(d->api.closure, mask);
912                 }
913         } else {
914                 d = searchrec(set, name);
915                 if (d && d->api.itf->set_logmask)
916                         d->api.itf->set_logmask(d->api.closure, mask);
917         }
918 }
919
920 /**
921  * Get the logmask level of the 'api'
922  * @param set the api set
923  * @param name the api to get
924  * @return the logmask level or -1 in case of error
925  */
926 int afb_apiset_get_logmask(struct afb_apiset *set, const char *name)
927 {
928         const struct api_desc *i;
929
930         i = name ? searchrec(set, name) : NULL;
931         if (!i) {
932                 errno = ENOENT;
933                 return -1;
934         }
935
936         if (!i->api.itf->get_logmask)
937                 return logmask;
938
939         return i->api.itf->get_logmask(i->api.closure);
940 }
941
942 /**
943  * Get the description of the API of 'name'
944  * @param set the api set
945  * @param name the api whose description is required
946  * @return the description or NULL
947  */
948 struct json_object *afb_apiset_describe(struct afb_apiset *set, const char *name)
949 {
950         const struct api_desc *i;
951
952         i = name ? searchrec(set, name) : NULL;
953         return i && i->api.itf->describe ? i->api.itf->describe(i->api.closure) : NULL;
954 }
955
956 struct get_names {
957         union  {
958                 struct {
959                         size_t count;
960                         size_t size;
961                 };
962                 struct {
963                         const char **ptr;
964                         char *data;
965                 };
966         };
967         int type;
968 };
969
970 static void get_names_count(void *closure, struct afb_apiset *set, const char *name, int isalias)
971 {
972         struct get_names *gc = closure;
973         if ((1 + isalias) & gc->type) {
974                 gc->size += strlen(name);
975                 gc->count++;
976         }
977 }
978
979 static void get_names_value(void *closure, struct afb_apiset *set, const char *name, int isalias)
980 {
981         struct get_names *gc = closure;
982         if ((1 + isalias) & gc->type) {
983                 *gc->ptr++ = gc->data;
984                 gc->data = stpcpy(gc->data, name) + 1;
985         }
986 }
987
988 #if !defined(APISET_NO_SORT)
989 static int get_names_sortcb(const void *a, const void *b)
990 {
991         return strcasecmp(*(const char **)a, *(const char **)b);
992 }
993 #endif
994
995 /**
996  * Get the list of api names
997  * @param set the api set
998  * @param rec recursive
999  * @param type expected type: 1 names, 3 names+aliases, 2 aliases
1000  * @return a NULL terminated array of api names. Must be freed.
1001  */
1002 const char **afb_apiset_get_names(struct afb_apiset *set, int rec, int type)
1003 {
1004         struct get_names gc;
1005         size_t size;
1006         const char **names;
1007
1008         gc.count = gc.size = 0;
1009         gc.type = type >= 1 && type <= 3 ? type : 1;
1010         afb_apiset_enum(set, rec, get_names_count, &gc);
1011
1012         size = gc.size + gc.count * (1 + sizeof *names) + sizeof(*names);
1013         names = malloc(size);
1014
1015         if (!names)
1016                 errno = ENOMEM;
1017         else {
1018                 gc.data = (char*)&names[gc.count + 1];
1019                 gc.ptr = names;
1020                 afb_apiset_enum(set, rec, get_names_value, &gc);
1021 #if !defined(APISET_NO_SORT)
1022                 qsort(names, gc.ptr - names, sizeof *names, get_names_sortcb);
1023 #endif
1024                 *gc.ptr = NULL;
1025         }
1026         return names;
1027 }
1028
1029 /**
1030  * Enumerate the api names to a callback.
1031  * @param set the api set
1032  * @param rec should the enumeration be recursive
1033  * @param callback the function to call for each name
1034  * @param closure the closure for the callback
1035  */
1036 void afb_apiset_enum(
1037         struct afb_apiset *set,
1038         int rec,
1039         void (*callback)(void *closure, struct afb_apiset *set, const char *name, int isalias),
1040         void *closure)
1041 {
1042         int i;
1043         struct afb_apiset *iset;
1044         struct api_desc *d;
1045         struct api_alias *a;
1046
1047         iset = set;
1048         while (iset) {
1049                 for (i = 0 ; i < set->apis.count ; i++) {
1050                         d = set->apis.apis[i];;
1051                         if (searchrec(set, d->name) == d)
1052                                 callback(closure, iset, d->name, 0);
1053                 }
1054                 a = iset->aliases;
1055                 while (a) {
1056                         if (searchrec(set, a->name) == a->api)
1057                                 callback(closure, iset, a->name, 1);
1058                         a = a->next;
1059                 }
1060                 iset = rec ? iset->subset : NULL;
1061         }
1062 }
1063
1064 /**
1065  * Declare that the api of 'name' requires the api of name 'required'.
1066  * The api is searched in the apiset 'set' and if 'rec' isn't null also in its subset.
1067  * Returns 0 if the declaration successed or -1 in case of failure
1068  * (ENOMEM: allocation failure, ENOENT: api name not found)
1069  */
1070 int afb_apiset_require(struct afb_apiset *set, const char *name, const char *required)
1071 {
1072         struct api_desc *a;
1073         struct api_depend *d;
1074         int rc = -1;
1075
1076         a = searchrec(set, name);
1077         if (!a)
1078                 errno = ENOENT;
1079         else {
1080                 d = malloc(strlen(required) + 1 + sizeof *d);
1081                 if (!d)
1082                         errno = ENOMEM;
1083                 else {
1084                         d->set = set;
1085                         strcpy(d->name, required);
1086                         rc = api_array_add(&a->require.apis, d);
1087                 }
1088         }
1089         return rc;
1090 }
1091
1092 /**
1093  * Declare that the api of name 'apiname' requires the class of name 'classname'.
1094  * Returns 0 if the declaration successed or -1 in case of failure
1095  * (ENOMEM: allocation failure, ENOENT: api name not found)
1096  */
1097 int afb_apiset_require_class(struct afb_apiset *set, const char *apiname, const char *classname)
1098 {
1099         struct api_desc *a = searchrec(set, apiname);
1100         struct api_class *c = class_search(classname, 1);
1101         return a && c ? api_array_add(&a->require.classes, c) : (errno = ENOENT, -1);
1102 }
1103
1104 /**
1105  * Declare that the api of name 'apiname' provides the class of name 'classname'
1106  * Returns 0 if the declaration successed or -1 in case of failure
1107  * (ENOMEM: allocation failure, ENOENT: api name not found)
1108  */
1109 int afb_apiset_provide_class(struct afb_apiset *set, const char *apiname, const char *classname)
1110 {
1111         struct api_desc *a = searchrec(set, apiname);
1112         struct api_class *c = class_search(classname, 1);
1113         return a && c ? api_array_add(&c->providers, a) : (errno = ENOENT, -1);
1114 }
1115
1116 /**
1117  * Start any API that provides the class of name 'classname'
1118  */
1119 int afb_apiset_class_start(const char *classname)
1120 {
1121         struct api_class *cla = class_search(classname, 0);
1122         return cla ? start_class(cla) : (errno = ENOENT, -1);
1123 }
1124