c6a874ec12879c363e8cb56be579275088d84615
[src/app-framework-main.git] / src / appfwk.c
1 /*
2  Copyright 2015 IoT.bzh
3
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7
8      http://www.apache.org/licenses/LICENSE-2.0
9
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16
17 #include <stdlib.h>
18 #include <assert.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <dirent.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25
26 #include <json.h>
27
28 #include <wgt-info.h>
29
30 struct appfwk {
31         int refcount;
32         int nrroots;
33         char **roots;
34         struct json_object *applications;
35 };
36
37 struct appfwk *appfwk_create()
38 {
39         struct appfwk *appfwk = malloc(sizeof * appfwk);
40         if (!appfwk)
41                 errno = ENOMEM;
42         else {
43                 appfwk->refcount = 1;
44                 appfwk->nrroots = 0;
45                 appfwk->roots = NULL;
46                 appfwk->applications = NULL;
47         }
48         return appfwk;
49 }
50
51 void appfwk_addref(struct appfwk *appfwk)
52 {
53         assert(appfwk);
54         appfwk->refcount++;
55 }
56
57 void appfwk_unref(struct appfwk *appfwk)
58 {
59         assert(appfwk);
60         if (!--appfwk->refcount) {
61                 while (appfwk->nrroots)
62                         free(appfwk->roots[--appfwk->nrroots]);
63                 free(appfwk->roots);
64                 free(appfwk);
65         }
66 }
67
68 int appfwk_add_root(struct appfwk *appfwk, const char *path)
69 {
70         int i, n;
71         char *r, **roots;
72
73         assert(appfwk);
74
75         /* don't depend on the cwd and unique name */
76         r = realpath(path, NULL);
77         if (!r)
78                 return -1;
79
80         /* avoiding duplications */
81         n = appfwk->nrroots;
82         roots = appfwk->roots;
83         for (i = 0 ; i < n ; i++) {
84                 if (!strcmp(r, roots[i])) {
85                         free(r);
86                         return 0;
87                 }
88         }
89
90         /* add */
91         roots = realloc(roots, (n + 1) * sizeof(roots[0]));
92         if (!roots) {
93                 free(r);
94                 errno = ENOMEM;
95                 return -1;
96         }
97         roots[n++] = r;
98         appfwk->roots = roots;
99         appfwk->nrroots = n;
100         return 0;
101 }
102
103
104 static int json_add(struct json_object *obj, const char *key, struct json_object *val)
105 {
106         json_object_object_add(obj, key, val);
107         return 0;
108 }
109
110 static int json_add_str(struct json_object *obj, const char *key, const char *val)
111 {
112         struct json_object *str = json_object_new_string (val ? val : "");
113         return str ? json_add(obj, key, str) : -1;
114 }
115
116 static int json_add_int(struct json_object *obj, const char *key, int val)
117 {
118         struct json_object *v = json_object_new_int (val);
119         return v ? json_add(obj, key, v) : -1;
120 }
121
122 static struct json_object *read_app_desc(const char *path)
123 {
124         struct wgt_info *info;
125         const struct wgt_desc *desc;
126         struct json_object *result;
127         char *appid, *end;
128
129         result = json_object_new_object();
130         if (!result)
131                 goto error;
132
133         info = wgt_info_createat(AT_FDCWD, path, 0, 0, 0);
134         if (info == NULL)
135                 goto error2;
136         desc = wgt_info_desc(info);
137
138         appid = alloca(2 + strlen(desc->id) + strlen(desc->version));
139         end = stpcpy(appid, desc->id);
140         *end++ = '@';
141         strcpy(end, desc->version);
142
143         if(json_add_str(result, "appid", appid)
144         || json_add_str(result, "id", desc->id)
145         || json_add_str(result, "version", desc->version)
146         || json_add_str(result, "path", path)
147         || json_add_int(result, "width", desc->width)
148         || json_add_int(result, "height", desc->height)
149         || json_add_str(result, "name", desc->name)
150         || json_add_str(result, "description", desc->description)
151         || json_add_str(result, "shortname", desc->name_short)
152         || json_add_str(result, "author", desc->author))
153                 goto error3;
154
155         wgt_info_unref(info);
156         return result;
157
158 error3:
159         wgt_info_unref(info);
160 error2:
161         json_object_put(result);
162 error:
163         return NULL;
164 }
165
166 static int add_appdesc(struct json_object *appset, struct json_object *app)
167 {
168         struct json_object *appid;
169
170         if (!json_object_object_get_ex(app, "appid", &appid)) {
171                 errno = EINVAL;
172                 return -1;
173         }
174
175         return json_add(appset, json_object_get_string(appid), app);
176 }
177
178 struct enumdata {
179         char path[PATH_MAX];
180         int length;
181         struct json_object *apps;
182 };
183
184 static int enumentries(struct enumdata *data, int (*callto)(struct enumdata *))
185 {
186         DIR *dir;
187         int rc;
188         char *beg, *end;
189         struct dirent entry, *e;
190
191         /* opens the directory */
192         dir = opendir(data->path);
193         if (!dir)
194                 return -1;
195
196         /* prepare appending entry names */
197         beg = data->path + data->length;
198         *beg++ = '/';
199
200         /* enumerate entries */
201         rc = readdir_r(dir, &entry, &e);
202         while (!rc && e) {
203                 if (entry.d_name[0] != '.' || (entry.d_name[1] && (entry.d_name[1] != '.' || entry.d_name[2]))) {
204                         /* prepare callto */
205                         end = stpcpy(beg, entry.d_name);
206                         data->length = end - data->path;
207                         /* call the function */
208                         rc = callto(data);
209                         if (rc)
210                                 break;
211                 }       
212                 rc = readdir_r(dir, &entry, &e);
213         }
214         closedir(dir);
215         return rc;
216 }
217
218 static int recordapp(struct enumdata *data)
219 {
220         struct json_object *app;
221
222         app = read_app_desc(data->path);
223         if (app != NULL) {
224                 if (!add_appdesc(data->apps, app))
225                         return 0;
226                 json_object_put(app);
227         }
228         return -1;
229 }
230
231 /* enumerate the versions */
232 static int enumvers(struct enumdata *data)
233 {
234         int rc = enumentries(data, recordapp);
235         return !rc || errno != ENOTDIR ? 0 : rc;
236 }
237
238 /* regenerate the list of applications */
239 int appfwk_update_applications(struct appfwk *af)
240 {
241         int rc, iroot;
242         struct enumdata edata;
243         struct json_object *oldapps;
244
245         /* create the result */
246         edata.apps = json_object_new_object();
247         if (edata.apps == NULL) {
248                 errno = ENOMEM;
249                 return -1;
250         }
251         /* for each root */
252         for (iroot = 0 ; iroot < af->nrroots ; iroot++) {
253                 edata.length = stpcpy(edata.path, af->roots[iroot]) - edata.path;
254                 assert(edata.length < sizeof edata.path);
255                 /* enumerate the applications */
256                 rc = enumentries(&edata, enumvers);
257                 if (rc) {
258                         json_object_put(edata.apps);
259                         return rc;
260                 }
261         }
262         /* commit the result */
263         oldapps = af->applications;
264         af->applications = edata.apps;
265         if (oldapps)
266                 json_object_put(oldapps);
267         return 0;
268 }
269
270 int main()
271 {
272 struct appfwk *af = appfwk_create();
273 appfwk_add_root(af,"af/apps/");
274 appfwk_update_applications(af);
275 json_object_to_file("/dev/stdout", af->applications);
276 return 0;
277 }
278