added info retrieval
[src/app-framework-main.git] / src / wgt.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 #define _GNU_SOURCE
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <assert.h>
25 #include <limits.h>
26 #include <string.h>
27 #include <ctype.h>
28
29
30 #include "wgt.h"
31
32 struct wgt {
33         int refcount;
34         int rootfd;
35         int nrlocales;
36         char **locales;
37 };
38
39 static int validsubpath(const char *subpath)
40 {
41         int l = 0, i = 0;
42         if (subpath[i] == '/')
43                 return 0;
44         while(subpath[i]) {
45                 switch(subpath[i++]) {
46                 case '.':
47                         if (!subpath[i])
48                                 break;
49                         if (subpath[i] == '/') {
50                                 i++;
51                                 break;
52                         }
53                         if (subpath[i++] == '.') {
54                                 if (!subpath[i]) {
55                                         l--;
56                                         break;
57                                 }
58                                 if (subpath[i++] == '/') {
59                                         l--;
60                                         break;
61                                 }
62                         }
63                 default:
64                         while(subpath[i] && subpath[i] != '/')
65                                 i++;
66                         l++;
67                 case '/':
68                         break;
69                 }
70         }
71         return l >= 0;
72 }
73
74 struct wgt *wgt_create()
75 {
76         struct wgt *wgt = malloc(sizeof * wgt);
77         if (!wgt)
78                 errno = ENOMEM;
79         else {
80                 wgt->refcount = 1;
81                 wgt->rootfd = -1;
82                 wgt->nrlocales = 0;
83                 wgt->locales = NULL;
84         }
85         return wgt;
86 }
87
88 void wgt_disconnect(struct wgt *wgt)
89 {
90         assert(wgt);
91         if (wgt->rootfd >= 0)
92                 close(wgt->rootfd);
93         wgt->rootfd = -1;
94 }
95
96 void wgt_locales_reset(struct wgt *wgt)
97 {
98         assert(wgt);
99         while(wgt->nrlocales)
100                 free(wgt->locales[--wgt->nrlocales]);
101 }
102
103 void wgt_addref(struct wgt *wgt)
104 {
105         assert(wgt);
106         wgt->refcount++;
107 }
108
109 void wgt_unref(struct wgt *wgt)
110 {
111         assert(wgt);
112         if (!--wgt->refcount) {
113                 wgt_disconnect(wgt);
114                 wgt_locales_reset(wgt);
115                 free(wgt->locales);
116                 free(wgt);
117         }
118 }
119
120 int wgt_connectat(struct wgt *wgt, int dirfd, const char *pathname)
121 {
122         int rfd;
123
124         assert(wgt);
125
126         rfd = dirfd;
127         if (pathname) {
128                 rfd = openat(rfd, pathname, O_PATH|O_DIRECTORY);
129                 if (rfd < 0)
130                         return rfd;
131         }
132         if (wgt->rootfd >= 0)
133                 close(wgt->rootfd);
134         wgt->rootfd = rfd;
135         return 0;
136 }
137
138 int wgt_connect(struct wgt *wgt, const char *pathname)
139 {
140         return wgt_connectat(wgt, AT_FDCWD, pathname);
141 }
142
143 int wgt_is_connected(struct wgt *wgt)
144 {
145         assert(wgt);
146         return wgt->rootfd != -1;
147 }
148
149 int wgt_has(struct wgt *wgt, const char *filename)
150 {
151         assert(wgt);
152         assert(wgt_is_connected(wgt));
153         if (!validsubpath(filename)) {
154                 errno = EINVAL;
155                 return -1;
156         }
157         return 0 == faccessat(wgt->rootfd, filename, F_OK, 0);
158 }
159
160 int wgt_open_read(struct wgt *wgt, const char *filename)
161 {
162         assert(wgt);
163         assert(wgt_is_connected(wgt));
164         if (!validsubpath(filename)) {
165                 errno = EINVAL;
166                 return -1;
167         }
168         return openat(wgt->rootfd, filename, O_RDONLY);
169 }
170
171 static int locadd(struct wgt *wgt, const char *locstr, int length)
172 {
173         int i;
174         char *item, **ptr;
175
176         item = strndup(locstr, length);
177         if (item != NULL) {
178                 for (i = 0 ; item[i] ; i++)
179                         item[i] = tolower(item[i]);
180                 for (i = 0 ; i < wgt->nrlocales ; i++)
181                         if (!strcmp(item, wgt->locales[i])) {
182                                 free(item);
183                                 return 0;
184                         }
185
186                 ptr = realloc(wgt->locales, (1 + wgt->nrlocales) * sizeof(wgt->locales[0]));
187                 if (ptr) {
188                         wgt->locales = ptr;
189                         wgt->locales[wgt->nrlocales++] = item;
190                         return 0;
191                 }
192                 free(item);
193         }
194         errno = ENOMEM;
195         return -1;
196 }
197
198 int wgt_locales_add(struct wgt *wgt, const char *locstr)
199 {
200         const char *stop, *next;
201         assert(wgt);
202         while (*locstr) {
203                 stop = strchrnul(locstr, ',');
204                 next = stop + !!*stop;
205                 while (locstr != stop) {
206                         if (locadd(wgt, locstr, stop - locstr))
207                                 return -1;
208                         do { stop--; } while(stop > locstr && *stop != '-');
209                 }
210                 locstr = next;
211         }
212         return 0;
213 }
214
215 int wgt_locales_score(struct wgt *wgt, const char *lang)
216 {
217         int i;
218
219         assert(wgt);
220         if (lang)
221                 for (i = 0 ; i < wgt->nrlocales ; i++)
222                         if (!strcasecmp(lang, wgt->locales[i]))
223                                 return i;
224
225         return INT_MAX;
226 }
227
228 static const char *localize(struct wgt *wgt, const char *filename, char path[PATH_MAX])
229 {
230         int i;
231
232         if (!validsubpath(filename)) {
233                 errno = EINVAL;
234                 return NULL;
235         }
236         for (i = 0 ; i < wgt->nrlocales ; i++) {
237                 if (snprintf(path, PATH_MAX, "locales/%s/%s", wgt->locales[i], filename) >= PATH_MAX) {
238                         errno = EINVAL;
239                         return NULL;
240                 }
241                 if (0 == faccessat(wgt->rootfd, path, F_OK, 0))
242                         return path;
243         }
244         if (0 == faccessat(wgt->rootfd, filename, F_OK, 0))
245                 return filename;
246         errno = ENOENT;
247         return NULL;
248 }
249
250 char *wgt_locales_locate(struct wgt *wgt, const char *filename)
251 {
252         char path[PATH_MAX];
253         char * result;
254         const char * loc;
255
256         assert(wgt);
257         assert(wgt_is_connected(wgt));
258         loc = localize(wgt, filename, path);
259         if (!loc)
260                 result = NULL;
261         else {
262                 result = strdup(loc);
263                 if (!result)
264                         errno = ENOMEM;
265         }
266         return result;
267 }
268
269
270 int wgt_locales_open_read(struct wgt *wgt, const char *filename)
271 {
272         char path[PATH_MAX];
273         const char *loc;
274
275         assert(wgt);
276         assert(wgt_is_connected(wgt));
277         loc = localize(wgt, filename, path);
278         if (!loc)
279                 return -1;
280
281         return openat(wgt->rootfd, loc, O_RDONLY);
282 }
283
284