2 * Copyright (C) 2013 Intel Corporation.
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.
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.
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
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>
35 #include <sys/types.h>
43 #ifndef NOT_MULTI_THREAD_SAFE
48 #define CONFIGPATH "/etc/tizen-platform.conf"
51 #include "tzplatform_variables.h"
52 #include "tzplatform_config.h"
60 #define _HAS_IDS_ ( _FOREIGN_HAS_(UID) \
61 || _FOREIGN_HAS_(EUID) \
62 || _FOREIGN_HAS_(GID) )
64 #define _HAS_PWS_ ( _FOREIGN_HAS_(HOME) \
65 || _FOREIGN_HAS_(USER) \
66 || _FOREIGN_HAS_(EHOME) \
67 || _FOREIGN_HAS_(EUSER) )
69 #define _USER_NOT_SET_ ((uid_t)-1)
71 /* local and static variables */
72 static const char metafilepath[] = CONFIGPATH;
73 static const char emptystring[] = "";
74 static const char *var_names[_TZPLATFORM_VARIABLES_COUNT_];
76 enum STATE { RESET=0, ERROR, VALID };
78 struct tzplatform_context {
79 #ifndef NOT_MULTI_THREAD_SAFE
80 pthread_mutex_t mutex;
85 const char *values[_TZPLATFORM_VARIABLES_COUNT_];
88 /* structure for reading config files */
91 struct tzplatform_context *context;
92 size_t dynvars[_FOREIGN_COUNT_];
93 size_t offsets[_TZPLATFORM_VARIABLES_COUNT_];
96 static struct tzplatform_context global_context = {
97 #ifndef NOT_MULTI_THREAD_SAFE
98 .mutex = PTHREAD_MUTEX_INITIALIZER,
101 .user = _USER_NOT_SET_
106 /* write the error message */
107 static void writerror( const char *format, ...)
110 fprintf( stderr, "tzplatform_config ERROR: ");
111 va_start(ap, format);
112 vfprintf(stderr, format, ap);
114 fprintf( stderr, "\n");
117 static uid_t get_uid(struct tzplatform_context *context)
121 result = context->user;
122 if (result == _USER_NOT_SET_)
128 #if _FOREIGN_HAS_(EUID)
129 static uid_t get_euid(struct tzplatform_context *context)
133 result = context->user;
134 if (result == _USER_NOT_SET_)
141 #if _FOREIGN_HAS_(GID)
142 static gid_t get_gid(struct tzplatform_context *context)
149 /* fill the foreign variables for ids */
150 static void foreignid( struct reading *reading)
155 #if _FOREIGN_HAS_(UID)
157 if (reading->dynvars[UID] == HNULL) {
158 n = snprintf( buffer, sizeof buffer, "%d", (int)get_uid(reading->context));
159 if (0 < n && n < (int)(sizeof buffer))
160 reading->dynvars[UID] = heap_strndup( &reading->context->heap, buffer, (size_t)n);
164 #if _FOREIGN_HAS_(EUID)
166 if (reading->dynvars[EUID] == HNULL) {
167 n = snprintf( buffer, sizeof buffer, "%d", (int)get_euid(reading->context));
168 if (0 < n && n < (int)(sizeof buffer))
169 reading->dynvars[EUID] = heap_strndup( &reading->context->heap, buffer, (size_t)n);
173 #if _FOREIGN_HAS_(GID)
175 if (reading->dynvars[GID] == HNULL) {
176 n = snprintf( buffer, sizeof buffer, "%d", (int)get_gid(reading->context));
177 if (0 < n && n < (int)(sizeof buffer))
178 reading->dynvars[GID] = heap_strndup( &reading->context->heap, buffer, (size_t)n);
185 /* fill the foreign variables for home and user */
186 static void foreignpw( struct reading *reading)
189 struct pwget *array[3];
190 #if _FOREIGN_HAS_(HOME) || _FOREIGN_HAS_(USER)
194 #if _FOREIGN_HAS_(EHOME) || _FOREIGN_HAS_(EUSER)
199 #if _FOREIGN_HAS_(HOME) || _FOREIGN_HAS_(USER)
201 #if _FOREIGN_HAS_(HOME)
202 reading->dynvars[HOME] == HNULL
204 #if _FOREIGN_HAS_(HOME) && _FOREIGN_HAS_(USER)
207 #if _FOREIGN_HAS_(USER)
208 reading->dynvars[USER] == HNULL
211 snprintf( suid, sizeof suid, "%u", (unsigned)get_uid(reading->context));
220 #if _FOREIGN_HAS_(EHOME) || _FOREIGN_HAS_(EUSER)
222 #if _FOREIGN_HAS_(EHOME)
223 reading->dynvars[EHOME] == HNULL
225 #if _FOREIGN_HAS_(EHOME) && _FOREIGN_HAS_(USER)
228 #if _FOREIGN_HAS_(EUSER)
229 reading->dynvars[EUSER] == HNULL
232 snprintf( seuid, sizeof seuid, "%u", (unsigned)get_euid(reading->context));
243 if (pw_get( &reading->context->heap, array) == 0) {
244 #if _FOREIGN_HAS_(HOME)
246 reading->dynvars[HOME] = uid.home;
248 #if _FOREIGN_HAS_(USER)
250 reading->dynvars[USER] = uid.user;
252 #if _FOREIGN_HAS_(EHOME)
254 reading->dynvars[EHOME] = euid.home;
256 #if _FOREIGN_HAS_(EUSER)
258 reading->dynvars[EUSER] = euid.user;
265 /* get the foreign variable */
266 static const char *foreignvar( struct reading *reading,
267 const char *name, size_t length)
269 enum fkey key = foreign( name, length);
274 #if _FOREIGN_HAS_(HOME)
277 #if _FOREIGN_HAS_(USER)
280 #if _FOREIGN_HAS_(EHOME)
283 #if _FOREIGN_HAS_(EUSER)
291 #if _FOREIGN_HAS_(UID)
294 #if _FOREIGN_HAS_(GID)
297 #if _FOREIGN_HAS_(EUID)
307 offset = reading->dynvars[key];
308 return offset==HNULL ? NULL : heap_address( &reading->context->heap, offset);
311 /* callback for parsing errors */
312 static int errcb( struct parsing *parsing,
313 size_t position, const char *message)
315 struct parsinfo info;
316 struct reading *reading = parsing->data;
318 /* count the error */
321 /* print the error */
322 parse_utf8_info( parsing, &info, position);
323 writerror( "%s (file %s line %d)", message, metafilepath, info.lino);
325 /* continue to parse */
329 /* callback for solving variables */
330 static const char *getcb( struct parsing *parsing,
331 const char *key, size_t length,
332 size_t begin_pos, size_t end_pos)
334 struct parsinfo info;
336 const struct varassoc *vara;
338 struct reading *reading = parsing->data;
340 /* try to find a tzplatform variable */
341 vara = hashvar( key, length);
343 /* found: try to use it */
344 offset = reading->offsets[(int)vara->id];
346 result = heap_address( &reading->context->heap, offset);
351 /* that is a foreign variable */
352 result = foreignvar( reading, key, length);
355 /* emit the error and then return */
356 if (result == NULL) {
358 parse_utf8_info( parsing, &info, begin_pos);
359 writerror( "undefined value for %.*s (file %s line %d)",
360 length, key, metafilepath, info.lino);
361 result = emptystring; /* avoid error of the parser */
366 /* callback to define variables */
367 static int putcb( struct parsing *parsing,
368 const char *key, size_t key_length,
369 const char *value, size_t value_length,
370 size_t begin_pos, size_t end_pos)
372 struct parsinfo info;
373 const struct varassoc *vara;
376 struct reading *reading = parsing->data;
378 /* try to find a tzplatform variable */
379 vara = hashvar( key, key_length);
381 /* check that the variable isn't already defined */
382 offset = reading->offsets[(int)vara->id];
383 if (offset != HNULL) {
385 parse_utf8_info( parsing, &info, begin_pos);
386 writerror( "redefinition of variable %.*s (file %s line %d)",
387 key_length, key, metafilepath, info.lino);
390 /* allocate the variable value */
391 offset = heap_alloc( &reading->context->heap, value_length+1);
392 if (offset == HNULL) {
393 /* error of allocation */
395 writerror( "out of memory");
398 /* record the variable value */
399 reading->offsets[(int)vara->id] = offset;
400 string = heap_address( &reading->context->heap, offset);
401 memcpy( string, value, value_length);
402 string[value_length] = 0;
406 /* forbidden variable */
407 parse_utf8_info( parsing, &info, begin_pos);
408 writerror( "forbidden variable name %.*s (file %s line %d)",
409 key_length, key, metafilepath, info.lino);
413 /* continue to parse */
417 /* initialize the environment */
418 static void initialize(struct tzplatform_context *context)
420 struct buffer buffer;
421 struct parsing parsing;
422 struct reading reading;
426 /* clear the variables */
427 reading.errcount = 0;
428 reading.context = context;
429 for (i = 0 ; i < (int)_FOREIGN_COUNT_ ; i++) {
430 reading.dynvars[i] = HNULL;
432 for (i = 0 ; i < (int)_TZPLATFORM_VARIABLES_COUNT_ ; i++) {
433 context->values[i] = NULL;
434 reading.offsets[i] = HNULL;
437 /* read the configuration file */
438 result = buffer_create( &buffer, metafilepath);
440 writerror( "can't read file %s",metafilepath);
441 context->state = ERROR;
445 /* create the heap */
446 result = heap_create( &context->heap, 1);
448 buffer_destroy( &buffer);
449 writerror( "out of memory");
450 context->state = ERROR;
455 parsing.buffer = buffer.buffer;
456 parsing.length = buffer.length;
457 parsing.maximum_data_size = 0;
458 parsing.should_escape = 0;
459 parsing.data = &reading;
462 parsing.error = errcb;
463 result = parse_utf8_config( &parsing);
464 buffer_destroy( &buffer);
465 if (result != 0 || reading.errcount != 0) {
466 writerror( "%d errors while parsing file %s",
467 reading.errcount, metafilepath);
470 /* set the variables */
471 heap_read_only( &context->heap);
472 for (i = 0 ; i < (int)_TZPLATFORM_VARIABLES_COUNT_ ; i++) {
473 offset = reading.offsets[i];
475 context->values[i] = heap_address( &context->heap, offset);
477 writerror( "the variable %s isn't defined in file %s",
478 tzplatform_getname((enum tzplatform_variable)i), metafilepath);
479 /* TODO undefined variable */;
481 context->state = VALID;
484 inline static void lock(struct tzplatform_context *context)
486 #ifndef NOT_MULTI_THREAD_SAFE
487 pthread_mutex_lock( &context->mutex);
491 inline static void unlock(struct tzplatform_context *context)
493 #ifndef NOT_MULTI_THREAD_SAFE
494 pthread_mutex_unlock( &context->mutex);
498 static const char *get_lock(struct tzplatform_context *context, enum tzplatform_variable id)
505 if (offset < 0 || (int)_TZPLATFORM_VARIABLES_COUNT_ <= offset) {
506 /*error("invalid id"); TODO*/
510 if (context->state == RESET)
511 initialize( context);
512 result = context->state == ERROR ? NULL : context->values[offset];
517 int tzplatform_context_create(struct tzplatform_context **result)
519 struct tzplatform_context *context;
521 context = malloc( sizeof * context);
526 context->state = RESET;
527 context->user = _USER_NOT_SET_;
528 #ifndef NOT_MULTI_THREAD_SAFE
529 pthread_mutex_init( &context->mutex, NULL);
534 void tzplatform_context_destroy(struct tzplatform_context *context)
536 if (context->state == VALID)
537 heap_destroy( &context->heap);
538 context->state = ERROR;
542 void tzplatform_reset()
544 tzplatform_context_reset( &global_context);
547 void tzplatform_context_reset(struct tzplatform_context *context)
550 if (context->state != RESET) {
551 if (context->state == VALID)
552 heap_destroy( &context->heap);
553 context->state = RESET;
558 int tzplatform_getcount()
560 return (int)_TZPLATFORM_VARIABLES_COUNT_;
563 const char* tzplatform_getname(enum tzplatform_variable id)
565 const struct varassoc *iter, *end;
570 if (offset < 0 || (int)_TZPLATFORM_VARIABLES_COUNT_ <= offset) {
571 /*error("invalid id"); TODO*/
577 end = iter + (sizeof namassoc / sizeof namassoc[0]);
578 while (iter != end) {
579 if (iter->offset >= 0)
580 var_names[(int)iter->id] = varpool + iter->offset;
584 result = var_names[offset];
589 enum tzplatform_variable tzplatform_getid(const char *name)
591 const struct varassoc *vara = hashvar( name, strlen(name));
592 return vara ? vara->id : _TZPLATFORM_VARIABLES_INVALID_;
595 const char* tzplatform_getenv(enum tzplatform_variable id)
597 return tzplatform_context_getenv( &global_context, id);
600 const char* tzplatform_context_getenv(struct tzplatform_context *context, enum tzplatform_variable id)
602 const char *array[2];
603 const char *result = get_lock( context, id);
604 if (result != NULL) {
607 result = scratchcat( 0, array);
613 int tzplatform_getenv_int(enum tzplatform_variable id)
615 return tzplatform_context_getenv_int( &global_context, id);
618 int tzplatform_context_getenv_int(struct tzplatform_context *context, enum tzplatform_variable id)
620 const char *value = get_lock( context, id);
621 int result = value==NULL ? -1 : atoi(value);
626 const char* tzplatform_mkstr(enum tzplatform_variable id, const char * str)
628 return tzplatform_context_mkstr( &global_context, id, str);
631 const char* tzplatform_context_mkstr(struct tzplatform_context *context, enum tzplatform_variable id, const char *str)
633 const char *array[3];
634 const char *result = get_lock( context, id);
635 if (result != NULL) {
639 result = scratchcat( 0, array);
645 const char* tzplatform_mkpath(enum tzplatform_variable id, const char * path)
647 return tzplatform_context_mkpath( &global_context, id, path);
650 const char* tzplatform_context_mkpath(struct tzplatform_context *context, enum tzplatform_variable id, const char *path)
652 const char *array[3];
653 const char *result = get_lock( context, id);
654 if (result != NULL) {
658 result = scratchcat( 1, array);
664 const char* tzplatform_mkpath3(enum tzplatform_variable id, const char * path,
667 return tzplatform_context_mkpath3( &global_context, id, path, path2);
670 const char* tzplatform_context_mkpath3(struct tzplatform_context *context, enum tzplatform_variable id, const char *path,
673 const char *array[4];
674 const char *result = get_lock( context, id);
675 if (result != NULL) {
680 result = scratchcat( 1, array);
686 const char* tzplatform_mkpath4(enum tzplatform_variable id, const char * path,
687 const char* path2, const char *path3)
689 return tzplatform_context_mkpath4( &global_context, id, path, path2, path3);
692 const char* tzplatform_context_mkpath4(struct tzplatform_context *context, enum tzplatform_variable id, const char *path,
693 const char *path2, const char *path3)
695 const char *array[5];
696 const char *result = get_lock( context, id);
697 if (result != NULL) {
703 result = scratchcat( 1, array);
709 uid_t tzplatform_getuid(enum tzplatform_variable id)
711 return tzplatform_context_getuid( &global_context, id);
714 uid_t tzplatform_context_getuid(struct tzplatform_context *context, enum tzplatform_variable id)
716 uid_t result = (uid_t)-1;
717 const char *value = get_lock( context, id);
719 pw_get_uid( value, &result);
725 gid_t tzplatform_getgid(enum tzplatform_variable id)
727 return tzplatform_context_getgid( &global_context, id);
730 gid_t tzplatform_context_getgid(struct tzplatform_context *context, enum tzplatform_variable id)
732 gid_t result = (uid_t)-1;
733 const char *value = get_lock( context, id);
735 pw_get_gid( value, &result);
741 int tzplatform_set_user(uid_t uid)
743 return tzplatform_context_set_user( &global_context, uid);
746 int tzplatform_context_set_user(struct tzplatform_context *context, uid_t uid)
752 if (context->user != uid) {
753 if (uid != _USER_NOT_SET_ && !pw_has_uid( uid))
756 if (context->state == VALID)
757 heap_destroy( &context->heap);
758 context->state = RESET;
767 uid_t tzplatform_get_user()
769 return tzplatform_context_get_user( &global_context);
772 uid_t tzplatform_context_get_user(struct tzplatform_context *context)
777 result = get_uid( context);
783 void tzplatform_reset_user()
785 tzplatform_context_reset_user( &global_context);
788 void tzplatform_context_reset_user(struct tzplatform_context *context)
790 tzplatform_context_set_user( context, _USER_NOT_SET_);
796 struct tzplatform_context *context;
797 enum tzplatform_variable id;
804 while(i != tzplatform_getcount()) {
805 id = (enum tzplatform_variable)i;
806 name = tzplatform_getname(id);
807 value = tzplatform_getenv(id);
808 xid = (int)tzplatform_getid(name);
809 printf("%d=%d\t%s=%s\n",i,xid,name,value?value:"<null>");
813 printf("------------------------\n");
814 i = tzplatform_context_create(&context);
816 printf("error while creating context %d\n",i);
821 i = tzplatform_context_set_user(context, uid);
823 printf("error %d while switching to user %d\n",i,(int)uid);
827 while(i != tzplatform_getcount()) {
828 id = (enum tzplatform_variable)i;
829 name = tzplatform_getname(id);
830 value = tzplatform_context_getenv(context, id);
831 xid = (int)tzplatform_getid(name);
832 printf("%d=%d\t%s=%s\n",i,xid,name,value?value:"<null>");
835 tzplatform_context_destroy(context);