da7fbe44368977dccbf83aad76c66d04cdb11833
[platform/core/system/tizen-platform-wrapper.git] / src / tzplatform_config.c
1 /*
2  * Copyright (C) 2013 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
43 #ifndef NOT_MULTI_THREAD_SAFE
44 #include <pthread.h>
45 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
46 static inline void lock() { pthread_mutex_lock(&mutex); }
47 static inline void unlock() { pthread_mutex_unlock(&mutex); }
48 #else
49 static inline void lock() { }
50 static inline void unlock() { }
51 #endif
52
53 #ifndef CONFIGPATH
54 #define CONFIGPATH "/etc/tizen-platform.conf"
55 #endif
56
57 #include "tzplatform_variables.h"
58 #include "tzplatform_config.h"
59 #include "parser.h"
60 #include "heap.h"
61 #include "buffer.h"
62 #include "foreign.h"
63 #include "scratch.h"
64 #include "passwd.h"
65
66 #define _HAS_IDS_   (  _FOREIGN_HAS_(UID)  \
67                     || _FOREIGN_HAS_(EUID) \
68                     || _FOREIGN_HAS_(GID)  )
69
70 #define _HAS_PWS_   (  _FOREIGN_HAS_(HOME)  \
71                     || _FOREIGN_HAS_(USER)  \
72                     || _FOREIGN_HAS_(EHOME) \
73                     || _FOREIGN_HAS_(EUSER) )
74
75 /* structure for reading config files */
76 struct reading {
77     int errcount;
78     size_t dynvars[_FOREIGN_COUNT_];
79     size_t offsets[_TZPLATFORM_VARIABLES_COUNT_];
80 };
81
82 /* local and static variables */
83 static const char metafilepath[] = CONFIGPATH;
84 static const char emptystring[] = "";
85 static struct heap heap;
86 static enum { RESET=0, ERROR, VALID } state = RESET;
87 static const char *var_values[_TZPLATFORM_VARIABLES_COUNT_];
88 static const char *var_names[_TZPLATFORM_VARIABLES_COUNT_];
89
90 #include "hash.inc"
91
92 /* write the error message */
93 static void writerror( const char *format, ...)
94 {
95     va_list ap;
96     fprintf( stderr, "tzplatform_config ERROR: ");
97     va_start(ap, format);
98     vfprintf(stderr, format, ap);
99     va_end(ap);
100     fprintf( stderr, "\n");
101 }
102
103 #if _HAS_IDS_
104 /* fill the foreign variables for ids */
105 static void foreignid( struct reading *reading)
106 {
107     int n;
108     char buffer[50];
109
110 #if _FOREIGN_HAS_(UID)
111     /* set the uid */
112     if (reading->dynvars[UID] == HNULL) {
113         n = snprintf( buffer, sizeof buffer, "%d", (int)getuid());
114         if (0 < n && n < (int)(sizeof buffer))
115             reading->dynvars[UID] = heap_strndup( &heap, buffer, (size_t)n);
116     }
117 #endif
118
119 #if _FOREIGN_HAS_(EUID)
120     /* set the euid */
121     if (reading->dynvars[EUID] == HNULL) {
122         n = snprintf( buffer, sizeof buffer, "%d", (int)geteuid());
123         if (0 < n && n < (int)(sizeof buffer))
124             reading->dynvars[EUID] = heap_strndup( &heap, buffer, (size_t)n);
125     }
126 #endif
127
128 #if _FOREIGN_HAS_(GID)
129     /* set the gid */
130     if (reading->dynvars[GID] == HNULL) {
131         n = snprintf( buffer, sizeof buffer, "%d", (int)getgid());
132         if (0 < n && n < (int)(sizeof buffer))
133             reading->dynvars[GID] = heap_strndup( &heap, buffer, (size_t)n);
134     }
135 #endif
136 }
137 #endif
138
139 #if _HAS_PWS_
140 /* fill the foreign variables for home and user */
141 static void foreignpw( struct reading *reading)
142 {
143     int n = 0;
144     struct pwget *array[3];
145 #if _FOREIGN_HAS_(HOME) || _FOREIGN_HAS_(USER)
146     struct pwget uid;
147     char suid[50];
148 #endif
149 #if _FOREIGN_HAS_(EHOME) || _FOREIGN_HAS_(EUSER)
150     struct pwget euid;
151     char seuid[50];
152 #endif
153
154 #if _FOREIGN_HAS_(HOME) || _FOREIGN_HAS_(USER)
155     if (
156 #if _FOREIGN_HAS_(HOME)
157         reading->dynvars[HOME] == HNULL
158 #endif
159 #if _FOREIGN_HAS_(HOME) && _FOREIGN_HAS_(USER)
160         ||
161 #endif
162 #if _FOREIGN_HAS_(USER)
163         reading->dynvars[USER] == HNULL
164 #endif
165     ) {
166         snprintf( suid, sizeof suid, "%u", (unsigned)getuid());
167         uid.id = suid;
168         array[n++] = &uid;
169     }
170     else {
171         uid.set = 0;
172     }
173 #endif
174
175 #if _FOREIGN_HAS_(EHOME) || _FOREIGN_HAS_(EUSER)
176     if (
177 #if _FOREIGN_HAS_(EHOME)
178         reading->dynvars[EHOME] == HNULL
179 #endif
180 #if _FOREIGN_HAS_(EHOME) && _FOREIGN_HAS_(USER)
181         ||
182 #endif
183 #if _FOREIGN_HAS_(EUSER)
184         reading->dynvars[EUSER] == HNULL
185 #endif
186     ) {
187         snprintf( seuid, sizeof seuid, "%u", (unsigned)geteuid());
188         euid.id = seuid;
189         array[n++] = &euid;
190     }
191     else {
192         euid.set = 0;
193     }
194 #endif
195
196     if (n) {
197         array[n] = NULL;
198         if (pw_get( &heap, array) == 0) {
199 #if _FOREIGN_HAS_(HOME)
200             if (uid.set)
201                 reading->dynvars[HOME] = uid.home;
202 #endif
203 #if _FOREIGN_HAS_(USER)
204             if (uid.set)
205                 reading->dynvars[USER] = uid.user;
206 #endif
207 #if _FOREIGN_HAS_(EHOME)
208             if (euid.set)
209                 reading->dynvars[EHOME] = euid.home;
210 #endif
211 #if _FOREIGN_HAS_(EUSER)
212             if (euid.set)
213                 reading->dynvars[EUSER] = euid.user;
214 #endif
215         }
216     }
217 }
218 #endif
219
220 /* get the foreign variable */
221 static const char *foreignvar( struct reading *reading, 
222                                             const char *name, size_t length)
223 {
224     enum fkey key = foreign( name, length);
225     size_t offset;
226
227     switch (key) {
228 #if _HAS_PWS_
229 #if _FOREIGN_HAS_(HOME)
230     case HOME:
231 #endif
232 #if _FOREIGN_HAS_(USER)
233     case USER:
234 #endif
235 #if _FOREIGN_HAS_(EHOME)
236     case EHOME:
237 #endif
238 #if _FOREIGN_HAS_(EUSER)
239     case EUSER:
240 #endif
241         foreignpw( reading);
242         break;
243 #endif
244  
245 #if _HAS_IDS_
246 #if _FOREIGN_HAS_(UID)
247     case UID:
248 #endif
249 #if _FOREIGN_HAS_(GID)
250     case GID:
251 #endif
252 #if _FOREIGN_HAS_(EUID)
253     case EUID:
254 #endif
255         foreignid( reading);
256         break;
257 #endif
258
259     default:
260         return NULL;
261     }
262     offset = reading->dynvars[key];
263     return offset==HNULL ? NULL : heap_address( &heap, offset);
264 }
265
266 /* callback for parsing errors */
267 static int errcb( struct parsing *parsing, 
268             size_t position, const char *message)
269 {
270     struct parsinfo info;
271     struct reading *reading = parsing->data;
272
273     /* count the error */
274     reading->errcount++;
275
276     /* print the error */
277     parse_utf8_info( parsing, &info, position);
278     writerror( "%s (file %s line %d)", message, metafilepath, info.lino);
279
280     /* continue to parse */
281     return 0;
282 }
283
284 /* callback for solving variables */
285 static const char *getcb( struct parsing *parsing, 
286             const char *key, size_t length,
287             size_t begin_pos, size_t end_pos)
288 {
289     struct parsinfo info;
290     const char *result;
291     const struct varassoc *vara;
292     size_t offset;
293     struct reading *reading = parsing->data;
294
295     /* try to find a tzplatform variable */
296     vara = hashvar( key, length);
297     if (vara) {
298         /* found: try to use it */
299         offset = reading->offsets[(int)vara->id];
300         if (offset != HNULL)
301             result = heap_address( &heap, offset);
302         else 
303             result = NULL;
304     }
305     else {
306         /* that is a foreign variable */
307         result = foreignvar( reading, key, length);
308     }
309
310     /* emit the error and then return */
311     if (result == NULL) {
312         reading->errcount++;
313         parse_utf8_info( parsing, &info, begin_pos);
314         writerror( "undefined value for %.*s (file %s line %d)",
315             length, key, metafilepath, info.lino);
316         result = emptystring; /* avoid error of the parser */
317     }
318     return result;
319 }
320
321 /* callback to define variables */
322 static int putcb( struct parsing *parsing, 
323             const char *key, size_t key_length, 
324             const char *value, size_t value_length,
325             size_t begin_pos, size_t end_pos)
326 {
327     struct parsinfo info;
328     const struct varassoc *vara;
329     size_t offset;
330     char *string;
331     struct reading *reading = parsing->data;
332
333     /* try to find a tzplatform variable */
334     vara = hashvar( key, key_length);
335     if (vara) {
336         /* check that the variable isn't already defined */
337         offset = reading->offsets[(int)vara->id];
338         if (offset != HNULL) {
339             reading->errcount++;
340             parse_utf8_info( parsing, &info, begin_pos);
341             writerror( "redefinition of variable %.*s (file %s line %d)",
342                     key_length, key, metafilepath, info.lino);
343         }
344
345         /* allocate the variable value */
346         offset = heap_alloc( &heap, value_length+1);
347         if (offset == HNULL) {
348             /* error of allocation */
349             reading->errcount++;
350             writerror( "out of memory");
351         }
352         else {
353             /* record the variable value */
354             reading->offsets[(int)vara->id] = offset;
355             string = heap_address( &heap, offset);
356             memcpy( string, value, value_length);
357             string[value_length] = 0;
358         }
359     }
360     else {
361         /* forbidden variable */
362         parse_utf8_info( parsing, &info, begin_pos);
363         writerror( "forbidden variable name %.*s (file %s line %d)",
364             key_length, key, metafilepath, info.lino);
365         
366     }
367
368     /* continue to parse */
369     return 0;
370 }
371
372 /* initialize the environment */
373 static void initialize()
374 {
375     struct buffer buffer;
376     struct parsing parsing;
377     struct reading reading;
378     size_t offset;
379     int i, result;
380
381     /* clear the variables */
382     reading.errcount = 0;
383     for (i = 0 ; i < (int)_FOREIGN_COUNT_ ; i++) {
384         reading.dynvars[i] = HNULL;
385     }
386     for (i = 0 ; i < (int)_TZPLATFORM_VARIABLES_COUNT_ ; i++) {
387         var_values[i] = NULL;
388         reading.offsets[i] = HNULL;
389     }
390
391     /* read the configuration file */
392     result = buffer_create( &buffer, metafilepath);
393     if (result != 0) {
394         writerror( "can't read file %s",metafilepath);
395         state = ERROR;
396         return;
397     }
398
399     /* create the heap */
400     result = heap_create( &heap, 1);
401     if (result != 0) {
402         buffer_destroy( &buffer);
403         writerror( "out of memory");
404         state = ERROR;
405         return;
406     }
407
408     /* read the file */
409     parsing.buffer = buffer.buffer;
410     parsing.length = buffer.length;
411     parsing.maximum_data_size = 0;
412     parsing.should_escape = 0;
413     parsing.data = &reading;
414     parsing.get = getcb;
415     parsing.put = putcb;
416     parsing.error = errcb;
417     result = parse_utf8_config( &parsing);
418     buffer_destroy( &buffer);
419     if (result != 0 || reading.errcount != 0) {
420         writerror( "%d errors while parsing file %s",
421                                             reading.errcount, metafilepath);
422     }
423
424     /* set the variables */
425     heap_read_only( &heap);
426     for (i = 0 ; i < (int)_TZPLATFORM_VARIABLES_COUNT_ ; i++) {
427         offset = reading.offsets[i];
428         if (offset != HNULL)
429             var_values[i] = heap_address( &heap, offset);
430         else
431             writerror( "the variable %s isn't defined in file %s",
432                 tzplatform_getname((enum tzplatform_variable)i), metafilepath);
433             /* TODO undefined variable */;
434     }
435     state = VALID;
436 }
437
438 static const char *get_lock(enum tzplatform_variable id)
439 {
440     const char *result;
441     int offset;
442
443     lock();
444     offset = (int)id;
445     if (offset < 0 || (int)_TZPLATFORM_VARIABLES_COUNT_ <= offset) {
446         /*error("invalid id"); TODO*/
447         result = NULL;
448     }
449     else {
450         if (state == RESET)
451             initialize();
452         result = var_values[offset];
453     }
454     return result;
455 }
456
457 /* reset the state of the environement */
458 void tzplatform_reset()
459 {
460     lock();
461     if (state != RESET) {
462         if (state == VALID)
463             heap_destroy( &heap);
464         state = RESET;
465     }
466     unlock();
467 }
468
469 int tzplatform_getcount()
470 {
471     return (int)_TZPLATFORM_VARIABLES_COUNT_;
472 }
473
474 const char* tzplatform_getname(enum tzplatform_variable id)
475 {
476     const struct varassoc *iter, *end;
477     const char *result;
478     int offset;
479
480     offset = (int)id;
481     if (offset < 0 || (int)_TZPLATFORM_VARIABLES_COUNT_ <= offset) {
482         /*error("invalid id"); TODO*/
483         result = NULL;
484     }
485     else {
486         if (!var_names[0]) {
487             iter = namassoc;
488             end = iter + (sizeof namassoc / sizeof namassoc[0]);
489             while (iter != end) {
490                 if (iter->offset >= 0) 
491                     var_names[(int)iter->id] = varpool + iter->offset;
492                 iter++;
493             }
494         }
495         result = var_names[offset];
496     }
497     return result;
498 }
499
500 enum tzplatform_variable tzplatform_getid(const char *name)
501 {
502     const struct varassoc *vara = hashvar( name, strlen(name));
503     return vara ? vara->id : _TZPLATFORM_VARIABLES_INVALID_;
504 }
505
506 const char* tzplatform_getenv(enum tzplatform_variable id) 
507 {
508     const char *result = get_lock( id);
509     unlock();
510     return result;
511 }
512
513 int tzplatform_getenv_int(enum tzplatform_variable id)
514 {
515     const char *value = get_lock( id);
516     int result = value==NULL ? -1 : atoi(value);
517     unlock();
518     return result;
519 }
520
521 const char* tzplatform_mkstr(enum tzplatform_variable id, const char * str)
522 {
523     const char *array[3];
524     const char *result = get_lock( id);
525     if (result != NULL) {
526         array[0] = result;
527         array[1] = str;
528         array[2] = NULL;
529         result = scratchcat( 0, array);
530     }
531     unlock();
532     return result;
533 }
534
535 const char* tzplatform_mkpath(enum tzplatform_variable id, const char * path)
536 {
537     const char *array[3];
538     const char *result = get_lock( id);
539     if (result != NULL) {
540         array[0] = result;
541         array[1] = path;
542         array[2] = NULL;
543         result = scratchcat( 1, array);
544     }
545     unlock();
546     return result;
547 }
548
549 const char* tzplatform_mkpath3(enum tzplatform_variable id, const char * path, const char* path2)
550 {
551     const char *array[4];
552     const char *result = get_lock( id);
553     if (result != NULL) {
554         array[0] = result;
555         array[1] = path;
556         array[2] = path2;
557         array[3] = NULL;
558         result = scratchcat( 1, array);
559     }
560     unlock();
561     return result;
562 }
563
564 uid_t tzplatform_getuid(enum tzplatform_variable id)
565 {
566     uid_t result = (uid_t)-1;
567     const char *value = get_lock( id);
568     if (value != NULL) {
569         pw_get_uid( value, &result);
570     }
571     unlock();
572     return result;
573 }
574
575 gid_t tzplatform_getgid(enum tzplatform_variable id)
576 {
577     gid_t result = (uid_t)-1;
578     const char *value = get_lock( id);
579     if (value != NULL) {
580         pw_get_gid( value, &result);
581     }
582     unlock();
583     return result;
584 }
585
586 #ifdef TEST
587 int main() {
588     int i = 0;
589     while(i != (int)_TZPLATFORM_VARIABLES_COUNT_) {
590         enum tzplatform_variable id = (enum tzplatform_variable)i;
591         const char*name = tzplatform_getname(id);
592         const char*value = tzplatform_getenv(id);
593         int xid = (int)tzplatform_getid(name);
594         printf("%d=%d\t%s=%s\n",i,xid,name,value);
595         i++;
596     }
597     return 0;
598 }
599 #endif