Fix coding rule violation
[platform/core/system/tizen-platform-config.git] / src / init.c
1 /*
2  * Copyright (C) 2013-2014 Intel Corporation.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  * Authors:
19  *       José Bollo <jose.bollo@open.eurogiciel.org>
20  *       Stéphane Desneux <stephane.desneux@open.eurogiciel.org>
21  *       Jean-Benoit Martin <jean-benoit.martin@open.eurogiciel.org>
22  *
23  */
24 #define _GNU_SOURCE
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <stdint.h>
33 #include <string.h>
34 #include <pthread.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 #include <ctype.h>
39 #include <stdarg.h>
40 #include <alloca.h>
41 #include <pwd.h>
42 #include <assert.h>
43
44 #ifndef NOT_MULTI_THREAD_SAFE
45 #include <pthread.h>
46 #endif
47
48 #ifndef CONFIGPATH
49 #define CONFIGPATH "/etc/tizen-platform.conf"
50 #endif
51
52 #include "tzplatform_variables.h"
53 #include "tzplatform_config.h"
54 #include "parser.h"
55 #include "heap.h"
56 #include "buffer.h"
57 #include "foreign.h"
58 #include "scratch.h"
59 #include "passwd.h"
60 #include "context.h"
61 #include "hashing.h"
62 #include "init.h"
63
64 #define _HAS_IDS_       (_FOREIGN_HAS_(UID)  \
65                                         || _FOREIGN_HAS_(EUID) \
66                                         || _FOREIGN_HAS_(GID))
67
68 #define _HAS_PWS_       (_FOREIGN_HAS_(HOME)    \
69                                         || _FOREIGN_HAS_(USER)  \
70                                         || _FOREIGN_HAS_(EHOME) \
71                                         || _FOREIGN_HAS_(EUSER))
72
73 /* local and static variables */
74 static const char metafilepath[] = CONFIGPATH;
75 static const char emptystring[] = "";
76
77 /* structure for reading config files */
78 struct reading {
79         int errcount;
80         struct tzplatform_context *context;
81         size_t dynvars[_FOREIGN_COUNT_];
82         size_t offsets[_TZPLATFORM_VARIABLES_COUNT_];
83 };
84
85 /* write the error message */
86 static void writerror(const char *format, ...)
87 {
88         va_list ap;
89         fprintf(stderr, "tzplatform_config ERROR: ");
90         va_start(ap, format);
91         vfprintf(stderr, format, ap);
92         va_end(ap);
93         fprintf(stderr, "\n");
94 }
95
96 #if _HAS_IDS_
97 /* fill the foreign variables for ids */
98 static void foreignid(struct reading *reading)
99 {
100         int n;
101         char buffer[50];
102
103 #if _FOREIGN_HAS_(UID)
104         /* set the uid */
105         if (reading->dynvars[UID] == HNULL) {
106                 n = snprintf(buffer, sizeof buffer, "%d", (int)get_uid(reading->context));
107                 if (0 < n && n < (int)(sizeof buffer))
108                         reading->dynvars[UID] = heap_strndup(&reading->context->heap, buffer, (size_t)n);
109         }
110 #endif
111
112 #if _FOREIGN_HAS_(EUID)
113         /* set the euid */
114         if (reading->dynvars[EUID] == HNULL) {
115                 n = snprintf(buffer, sizeof buffer, "%d", (int)get_euid(reading->context));
116                 if (0 < n && n < (int)(sizeof buffer))
117                         reading->dynvars[EUID] = heap_strndup(&reading->context->heap, buffer, (size_t)n);
118         }
119 #endif
120
121 #if _FOREIGN_HAS_(GID)
122         /* set the gid */
123         if (reading->dynvars[GID] == HNULL) {
124                 n = snprintf(buffer, sizeof buffer, "%d", (int)get_gid(reading->context));
125                 if (0 < n && n < (int)(sizeof buffer))
126                         reading->dynvars[GID] = heap_strndup(&reading->context->heap, buffer, (size_t)n);
127         }
128 #endif
129 }
130 #endif
131
132 #if _HAS_PWS_
133 /* fill the foreign variables for home and user */
134 static void foreignpw(struct reading *reading)
135 {
136         int n = 0;
137         struct pwget *array[3];
138 #if _FOREIGN_HAS_(HOME) || _FOREIGN_HAS_(USER)
139         struct pwget uid;
140         char suid[50];
141 #endif
142 #if _FOREIGN_HAS_(EHOME) || _FOREIGN_HAS_(EUSER)
143         struct pwget euid;
144         char seuid[50];
145 #endif
146
147 #if _FOREIGN_HAS_(HOME) || _FOREIGN_HAS_(USER)
148         if (
149 #if _FOREIGN_HAS_(HOME)
150                 reading->dynvars[HOME] == HNULL
151 #endif
152 #if _FOREIGN_HAS_(HOME) && _FOREIGN_HAS_(USER)
153                 ||
154 #endif
155 #if _FOREIGN_HAS_(USER)
156                 reading->dynvars[USER] == HNULL
157 #endif
158         ) {
159                 snprintf(suid, sizeof suid, "%u", (unsigned)get_uid(reading->context));
160                 uid.id = suid;
161                 array[n++] = &uid;
162         } else {
163                 uid.set = 0;
164         }
165 #endif
166
167 #if _FOREIGN_HAS_(EHOME) || _FOREIGN_HAS_(EUSER)
168         if (
169 #if _FOREIGN_HAS_(EHOME)
170                 reading->dynvars[EHOME] == HNULL
171 #endif
172 #if _FOREIGN_HAS_(EHOME) && _FOREIGN_HAS_(USER)
173                 ||
174 #endif
175 #if _FOREIGN_HAS_(EUSER)
176                 reading->dynvars[EUSER] == HNULL
177 #endif
178         ) {
179                 snprintf(seuid, sizeof seuid, "%u", (unsigned)get_euid(reading->context));
180                 euid.id = seuid;
181                 array[n++] = &euid;
182         } else {
183                 euid.set = 0;
184         }
185 #endif
186
187         if (n) {
188                 array[n] = NULL;
189                 if (pw_get(&reading->context->heap, array) == 0) {
190 #if _FOREIGN_HAS_(HOME)
191                         if (uid.set)
192                                 reading->dynvars[HOME] = uid.home;
193 #endif
194 #if _FOREIGN_HAS_(USER)
195                         if (uid.set)
196                                 reading->dynvars[USER] = uid.user;
197 #endif
198 #if _FOREIGN_HAS_(EHOME)
199                         if (euid.set)
200                                 reading->dynvars[EHOME] = euid.home;
201 #endif
202 #if _FOREIGN_HAS_(EUSER)
203                         if (euid.set)
204                                 reading->dynvars[EUSER] = euid.user;
205 #endif
206                 }
207         }
208 }
209 #endif
210
211 /* get the foreign variable */
212 static const char *foreignvar(struct reading *reading,
213                                                                                         const char *name, size_t length)
214 {
215         enum fkey key = foreign(name, length);
216         size_t offset;
217
218         switch (key) {
219 #if _HAS_PWS_
220 #if _FOREIGN_HAS_(HOME)
221         case HOME:
222 #endif
223 #if _FOREIGN_HAS_(USER)
224         case USER:
225 #endif
226 #if _FOREIGN_HAS_(EHOME)
227         case EHOME:
228 #endif
229 #if _FOREIGN_HAS_(EUSER)
230         case EUSER:
231 #endif
232                 foreignpw(reading);
233                 break;
234 #endif
235
236 #if _HAS_IDS_
237 #if _FOREIGN_HAS_(UID)
238         case UID:
239 #endif
240 #if _FOREIGN_HAS_(GID)
241         case GID:
242 #endif
243 #if _FOREIGN_HAS_(EUID)
244         case EUID:
245 #endif
246                 foreignid(reading);
247                 break;
248 #endif
249
250         default:
251                 return NULL;
252         }
253         offset = reading->dynvars[key];
254         return (offset == HNULL) ? NULL : heap_address(&reading->context->heap, offset);
255 }
256
257 /* callback for parsing errors */
258 static int errcb(struct parsing *parsing,
259                         size_t position, const char *message)
260 {
261         struct parsinfo info;
262         struct reading *reading = parsing->data;
263
264         /* count the error */
265         reading->errcount++;
266
267         /* print the error */
268         parse_utf8_info(parsing, &info, position);
269         writerror("%s (file %s line %d)", message, metafilepath, info.lino);
270
271         /* continue to parse */
272         return 0;
273 }
274
275 /* callback for solving variables */
276 static const char *getcb(struct parsing *parsing,
277                         const char *key, size_t length,
278                         size_t begin_pos, size_t end_pos)
279 {
280         struct parsinfo info;
281         const char *result;
282         size_t offset;
283         struct reading *reading = parsing->data;
284         int id;
285
286         /* try to find a tzplatform variable */
287         id = hashid(key, length);
288         if (id >= 0) {
289                 /* found: try to use it */
290                 offset = reading->offsets[id];
291                 if (offset != HNULL)
292                         result = heap_address(&reading->context->heap, offset);
293                 else
294                         result = NULL;
295         } else {
296                 /* that is a foreign variable */
297                 result = foreignvar(reading, key, length);
298         }
299
300         /* emit the error and then return */
301         if (result == NULL) {
302                 reading->errcount++;
303                 parse_utf8_info(parsing, &info, begin_pos);
304                 writerror("undefined value for %.*s (file %s line %d)",
305                         length, key, metafilepath, info.lino);
306                 result = emptystring; /* avoid error of the parser */
307         }
308         return result;
309 }
310
311 /* callback to define variables */
312 static int putcb(struct parsing *parsing,
313                         const char *key, size_t key_length,
314                         const char *value, size_t value_length,
315                         size_t begin_pos, size_t end_pos)
316 {
317         struct parsinfo info;
318         size_t offset;
319         char *string;
320         struct reading *reading = parsing->data;
321         int id;
322
323         /* try to find a tzplatform variable */
324         id = hashid(key, key_length);
325         if (id >= 0) {
326                 /* check that the variable isn't already defined */
327                 offset = reading->offsets[id];
328                 if (offset != HNULL) {
329                         reading->errcount++;
330                         parse_utf8_info(parsing, &info, begin_pos);
331                         writerror("redefinition of variable %.*s (file %s line %d)",
332                                         key_length, key, metafilepath, info.lino);
333                 }
334
335                 /* allocate the variable value */
336                 offset = heap_alloc(&reading->context->heap, value_length+1);
337                 if (offset == HNULL) {
338                         /* error of allocation */
339                         reading->errcount++;
340                         writerror("out of memory");
341                 } else {
342                         /* record the variable value */
343                         reading->offsets[id] = offset;
344                         string = heap_address(&reading->context->heap, offset);
345                         memcpy(string, value, value_length);
346                         string[value_length] = 0;
347                 }
348         } else {
349                 /* forbidden variable */
350                 parse_utf8_info(parsing, &info, begin_pos);
351                 writerror("forbidden variable name %.*s (file %s line %d)",
352                         key_length, key, metafilepath, info.lino);
353         }
354
355         /* continue to parse */
356         return 0;
357 }
358
359 /* initialize the environment */
360 void initialize(struct tzplatform_context *context)
361 {
362         struct buffer buffer;
363         struct parsing parsing;
364         struct reading reading;
365         size_t offset;
366         int i, result;
367
368         /* clear the variables */
369         reading.errcount = 0;
370         reading.context = context;
371         for (i = 0 ; i < (int)_FOREIGN_COUNT_ ; i++)
372                 reading.dynvars[i] = HNULL;
373
374         for (i = 0 ; i < (int)_TZPLATFORM_VARIABLES_COUNT_ ; i++) {
375                 context->values[i] = NULL;
376                 reading.offsets[i] = HNULL;
377         }
378
379         /* read the configuration file */
380         result = buffer_create(&buffer, metafilepath);
381         if (result != 0) {
382                 writerror("can't read file %s", metafilepath);
383                 context->state = ERROR;
384                 return;
385         }
386
387         /* create the heap */
388         result = heap_create(&context->heap, 1);
389         if (result != 0) {
390                 buffer_destroy(&buffer);
391                 writerror("out of memory");
392                 context->state = ERROR;
393                 return;
394         }
395
396         /* read the file */
397         parsing.buffer = buffer.buffer;
398         parsing.length = buffer.length;
399         parsing.maximum_data_size = 0;
400         parsing.should_escape = 0;
401         parsing.data = &reading;
402         parsing.get = getcb;
403         parsing.put = putcb;
404         parsing.error = errcb;
405         result = parse_utf8_config(&parsing);
406         buffer_destroy(&buffer);
407         if (result != 0 || reading.errcount != 0) {
408                 writerror("%d errors while parsing file %s",
409                                                                                         reading.errcount, metafilepath);
410         }
411
412         /* set the variables */
413         heap_read_only(&context->heap);
414         for (i = 0 ; i < (int)_TZPLATFORM_VARIABLES_COUNT_ ; i++) {
415                 offset = reading.offsets[i];
416                 if (offset != HNULL)
417                         context->values[i] = heap_address(&context->heap, offset);
418                 else
419                         writerror("the variable %s isn't defined in file %s",
420                                 keyname(i), metafilepath);
421                         /* TODO undefined variable */;
422         }
423         context->state = VALID;
424 }
425