4 author: José Bollo <jose.bollo@iot.bzh>
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
26 #include <sys/types.h>
30 #include "utils-json.h"
35 * The structure afm_apps records the data about applications
36 * for several accesses.
39 struct json_object *pubarr; /* array of the public data of applications */
40 struct json_object *direct; /* hash of applications by their id */
41 struct json_object *byapp; /* hash of versions of applications by their appid */
45 * Two types of directory are handled:
46 * - root directories: contains subdirectories appid/versio containing the applications
47 * - application directories: it contains an application
50 type_root, /* type for root directory */
51 type_app /* type for application directory */
55 * Structure for recording a path to application(s)
56 * in the list of directories.
59 struct afm_db_dir *next; /* link to the next item of the list */
60 enum dir_type type; /* the type of the path */
61 char path[1]; /* the path of the directory */
65 * The structure afm_db records the applications
66 * for a set of directories recorded as a linked list
69 int refcount; /* count of references to the structure */
70 struct afm_db_dir *dirhead; /* first directory of the set of directories */
71 struct afm_db_dir *dirtail; /* last directory of the set of directories */
72 struct afm_apps applications; /* the data about applications */
76 * The structure enumdata records data used when enumerating
77 * application directories of a root directory.
80 char path[PATH_MAX]; /* "current" computed path */
81 int length; /* length of path */
82 struct afm_apps apps; /* */
86 * Release the data of the afm_apps object 'apps'.
88 static void apps_put(struct afm_apps *apps)
90 json_object_put(apps->pubarr);
91 json_object_put(apps->direct);
92 json_object_put(apps->byapp);
96 * Adds the application widget 'desc' of the directory 'path' to the
97 * afm_apps object 'apps'.
98 * Returns 0 in case of success.
99 * Returns -1 and set errno in case of error
101 static int addwgt(struct afm_apps *apps, const char *path, const struct wgt_desc *desc)
103 const struct wgt_desc_feature *feat;
104 struct json_object *priv, *pub, *bya, *plugs, *str;
106 /* create the application structure */
107 priv = json_object_new_object();
111 pub = j_add_new_object(priv, "public");
115 plugs = j_add_new_array(priv, "plugins");
119 if(!j_add_string(priv, "id", desc->id)
120 || !j_add_string(priv, "path", path)
121 || !j_add_string(priv, "content", desc->content_src)
122 || !j_add_string(priv, "type", desc->content_type)
123 || !j_add_string(pub, "id", desc->idaver)
124 || !j_add_string(pub, "version", desc->version)
125 || !j_add_integer(pub, "width", desc->width)
126 || !j_add_integer(pub, "height", desc->height)
127 || !j_add_string(pub, "name", desc->name)
128 || !j_add_string(pub, "description", desc->description)
129 || !j_add_string(pub, "shortname", desc->name_short)
130 || !j_add_string(pub, "author", desc->author))
133 /* extract plugins from features */
134 feat = desc->features;
136 static const char prefix[] = FWK_PREFIX_PLUGIN;
137 if (!memcmp(feat->name, prefix, sizeof prefix - 1)) {
138 str = json_object_new_string (feat->name + sizeof prefix - 1);
141 if (json_object_array_add(plugs, str)) {
142 json_object_put(str);
149 /* record the application structure */
150 if (!j_add(apps->direct, desc->idaver, priv))
153 if (json_object_array_add(apps->pubarr, pub))
155 json_object_get(pub);
157 if (!json_object_object_get_ex(apps->byapp, desc->id, &bya)) {
158 bya = j_add_new_object(apps->byapp, desc->id);
163 if (!j_add(bya, desc->version, priv))
165 json_object_get(priv);
169 json_object_put(priv);
174 * Adds the application widget in the directory 'path' to the
175 * afm_apps object 'apps'.
176 * Returns 0 in case of success.
177 * Returns -1 and set errno in case of error
179 static int addapp(struct afm_apps *apps, const char *path)
182 struct wgt_info *info;
184 /* connect to the widget */
185 info = wgt_info_createat(AT_FDCWD, path, 0, 1, 0);
188 return 0; /* silently ignore bad directories */
191 /* adds the widget */
192 rc = addwgt(apps, path, wgt_info_desc(info));
193 wgt_info_unref(info);
198 * Enumerate the directories designated by 'data' and call the
199 * function 'callto' for each of them.
201 static int enumentries(struct enumdata *data, int (*callto)(struct enumdata *))
206 struct dirent entry, *e;
209 /* opens the directory */
210 dir = opendir(data->path);
214 /* prepare appending entry names */
215 beg = data->path + data->length;
218 /* enumerate entries */
219 rc = readdir_r(dir, &entry, &e);
221 if (entry.d_name[0] != '.' || (entry.d_name[1] && (entry.d_name[1] != '.' || entry.d_name[2]))) {
223 len = strlen(entry.d_name);
224 if (beg + len >= data->path + sizeof data->path) {
225 errno = ENAMETOOLONG;
228 data->length = stpcpy(beg, entry.d_name) - data->path;
229 /* call the function */
234 rc = readdir_r(dir, &entry, &e);
241 * called for each version directory.
243 static int recordapp(struct enumdata *data)
245 return addapp(&data->apps, data->path);
249 * called for each application directory.
250 * enumerate directories of the existing versions.
252 static int enumvers(struct enumdata *data)
254 int rc = enumentries(data, recordapp);
255 return !rc || errno != ENOTDIR ? 0 : rc;
259 * Adds the directory of 'path' and 'type' to the afm_db object 'afdb'.
260 * Returns 0 in case of success.
261 * Returns -1 and set errno in case of error
262 * Possible errno values: ENOMEM, ENAMETOOLONG
264 static int add_dir(struct afm_db *afdb, const char *path, enum dir_type type)
266 struct afm_db_dir *dir;
273 if (len >= PATH_MAX) {
274 errno = ENAMETOOLONG;
278 /* avoiding duplications */
280 while(dir != NULL && (strcmp(dir->path, path) || dir->type != type))
285 /* allocates the structure */
286 dir = malloc(strlen(path) + sizeof * dir);
295 strcpy(dir->path, path);
296 if (afdb->dirtail == NULL)
299 afdb->dirtail->next = dir;
305 * Creates an afm_db object and returns it with one reference added.
306 * Return NULL with errno = ENOMEM if memory exhausted.
308 struct afm_db *afm_db_create()
310 struct afm_db *afdb = malloc(sizeof * afdb);
315 afdb->dirhead = NULL;
316 afdb->dirtail = NULL;
317 afdb->applications.pubarr = NULL;
318 afdb->applications.direct = NULL;
319 afdb->applications.byapp = NULL;
325 * Adds a reference to an existing afm_db.
327 void afm_db_addref(struct afm_db *afdb)
334 * Removes a reference to an existing afm_db object.
335 * Removes the objet if there no more reference to it.
337 void afm_db_unref(struct afm_db *afdb)
339 struct afm_db_dir *dir;
342 if (!--afdb->refcount) {
343 /* no more reference, clean the memory used by the object */
344 apps_put(&afdb->applications);
345 while (afdb->dirhead != NULL) {
347 afdb->dirhead = dir->next;
355 * Adds the root directory of 'path' to the afm_db object 'afdb'.
356 * Be aware that no check is done on the directory of 'path' that will
357 * only be used within calls to the function 'afm_db_update_applications'.
358 * Returns 0 in case of success.
359 * Returns -1 and set errno in case of error
360 * Possible errno values: ENOMEM, ENAMETOOLONG
362 int afm_db_add_root(struct afm_db *afdb, const char *path)
364 return add_dir(afdb, path, type_root);
368 * Adds the application directory of 'path' to the afm_db object 'afdb'.
369 * Be aware that no check is done on the directory of 'path' that will
370 * only be used within calls to the function 'afm_db_update_applications'.
371 * Returns 0 in case of success.
372 * Returns -1 and set errno in case of error
373 * Possible errno values: ENOMEM, ENAMETOOLONG
375 int afm_db_add_application(struct afm_db *afdb, const char *path)
377 return add_dir(afdb, path, type_app);
381 * Regenerate the list of applications of the afm_bd object 'afdb'.
382 * Returns 0 in case of success.
383 * Returns -1 and set errno in case of error
385 int afm_db_update_applications(struct afm_db *afdb)
388 struct enumdata edata;
389 struct afm_apps oldapps;
390 struct afm_db_dir *dir;
392 /* create the result */
393 edata.apps.pubarr = json_object_new_array();
394 edata.apps.direct = json_object_new_object();
395 edata.apps.byapp = json_object_new_object();
396 if (edata.apps.pubarr == NULL || edata.apps.direct == NULL || edata.apps.byapp == NULL) {
400 /* for each directory of afdb */
401 for (dir = afdb->dirhead ; dir != NULL ; dir = dir->next) {
402 if (dir->type == type_root) {
403 edata.length = stpcpy(edata.path, dir->path) - edata.path;
404 assert(edata.length < sizeof edata.path);
405 /* enumerate the applications */
406 rc = enumentries(&edata, enumvers);
410 rc = addapp(&edata.apps, dir->path);
413 /* commit the result */
414 oldapps = afdb->applications;
415 afdb->applications = edata.apps;
420 apps_put(&edata.apps);
425 * Ensure that applications of the afm_bd object 'afdb' are listed.
426 * Returns 0 in case of success.
427 * Returns -1 and set errno in case of error
429 int afm_db_ensure_applications(struct afm_db *afdb)
431 return afdb->applications.pubarr ? 0 : afm_db_update_applications(afdb);
435 * Get the list of the applications public data of the afm_db object 'afdb'.
436 * The list is returned as a JSON-array that must be released using 'json_object_put'.
437 * Returns NULL in case of error.
439 struct json_object *afm_db_application_list(struct afm_db *afdb)
441 return afm_db_ensure_applications(afdb) ? NULL : json_object_get(afdb->applications.pubarr);
445 * Get the private data of the applications of 'id' in the afm_db object 'afdb'.
446 * It returns a JSON-object that must be released using 'json_object_put'.
447 * Returns NULL in case of error.
449 struct json_object *afm_db_get_application(struct afm_db *afdb, const char *id)
451 struct json_object *result;
452 if (!afm_db_ensure_applications(afdb) && json_object_object_get_ex(afdb->applications.direct, id, &result))
453 return json_object_get(result);
458 * Get the public data of the applications of 'id' in the afm_db object 'afdb'.
459 * It returns a JSON-object that must be released using 'json_object_put'.
460 * Returns NULL in case of error.
462 struct json_object *afm_db_get_application_public(struct afm_db *afdb, const char *id)
464 struct json_object *result;
465 struct json_object *priv = afm_db_get_application(afdb, id);
468 if (json_object_object_get_ex(priv, "public", &result))
469 json_object_get(result);
472 json_object_put(priv);
479 #if defined(TESTAPPFWK)
483 struct afm_db *afdb = afm_db_create();
484 afm_db_add_root(afdb,FWK_APP_DIR);
485 afm_db_update_applications(afdb);
486 printf("array = %s\n", json_object_to_json_string_ext(afdb->applications.pubarr, 3));
487 printf("direct = %s\n", json_object_to_json_string_ext(afdb->applications.direct, 3));
488 printf("byapp = %s\n", json_object_to_json_string_ext(afdb->applications.byapp, 3));