1 /*
2     INI LIBRARY
3 
4     Value interpretation functions for single values
5     and corresponding memory cleanup functions.
6 
7     Copyright (C) Dmitri Pal <dpal@redhat.com> 2010
8 
9     INI Library is free software: you can redistribute it and/or modify
10     it under the terms of the GNU Lesser General Public License as published by
11     the Free Software Foundation, either version 3 of the License, or
12     (at your option) any later version.
13 
14     INI Library is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU Lesser General Public License for more details.
18 
19     You should have received a copy of the GNU Lesser General Public License
20     along with INI Library.  If not, see <http://www.gnu.org/licenses/>.
21 */
22 
23 #include "config.h"
24 #include <stdio.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include "trace.h"
30 #include "collection.h"
31 #include "collection_tools.h"
32 #include "ini_defines.h"
33 #include "ini_config.h"
34 
35 /* Function to get value from the configuration handle */
get_config_item(const char * section,const char * name,struct collection_item * ini_config,struct collection_item ** item)36 int get_config_item(const char *section,
37                     const char *name,
38                     struct collection_item *ini_config,
39                     struct collection_item **item)
40 {
41     int error = EOK;
42     struct collection_item *section_handle = NULL;
43     const char *to_find;
44     char default_section[] = INI_DEFAULT_SECTION;
45 
46     TRACE_FLOW_STRING("get_config_item", "Entry");
47 
48     /* Do we have the accepting memory ? */
49     if (item == NULL) {
50         TRACE_ERROR_NUMBER("No buffer - invalid argument.", EINVAL);
51         return EINVAL;
52     }
53 
54     /* Is the collection of a right type */
55     if ((col_is_of_class(ini_config, COL_CLASS_INI_CONFIG) == 0) &&
56         (col_is_of_class(ini_config, COL_CLASS_INI_META) == 0)) {
57         TRACE_ERROR_NUMBER("Wrong collection type", EINVAL);
58         return EINVAL;
59     }
60 
61     *item = NULL;
62 
63     if (section == NULL) to_find = default_section;
64     else to_find = section;
65 
66     TRACE_INFO_STRING("Getting Name:", name);
67     TRACE_INFO_STRING("In Section:", section);
68 
69     /* Get Subcollection */
70     error = col_get_collection_reference(ini_config, &section_handle, to_find);
71     /* Check error */
72     if (error && (error != ENOENT)) {
73         TRACE_ERROR_NUMBER("Failed to get section", error);
74         return error;
75     }
76 
77     /* Did we find a section */
78     if ((error == ENOENT) || (section_handle == NULL)) {
79         /* We have not found section - return success */
80         TRACE_FLOW_STRING("get_value_from_config", "No such section");
81         return EOK;
82     }
83 
84     /* Get item */
85     error = col_get_item(section_handle, name,
86                          COL_TYPE_STRING, COL_TRAVERSE_ONELEVEL, item);
87 
88     /* Make sure we free the section we found */
89     col_destroy_collection(section_handle);
90 
91     TRACE_FLOW_NUMBER("get_config_item returning", error);
92     return error;
93 }
94 
95 /* Get long long value from config item */
get_llong_config_value(struct collection_item * item,int strict,long long def,int * error)96 static long long get_llong_config_value(struct collection_item *item,
97                                         int strict,
98                                         long long def,
99                                         int *error)
100 {
101     int err;
102     const char *str;
103     char *endptr;
104     long long val = 0;
105 
106     TRACE_FLOW_STRING("get_llong_config_value", "Entry");
107 
108     /* Do we have the item ? */
109     if ((item == NULL) ||
110        (col_get_item_type(item) != COL_TYPE_STRING)) {
111         TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
112         if (error) *error = EINVAL;
113         return def;
114     }
115 
116     if (error) *error = EOK;
117 
118     /* Try to parse the value */
119     str = (const char *)col_get_item_data(item);
120     errno = 0;
121     val = strtoll(str, &endptr, 10);
122     err = errno;
123 
124     /* Check for various possible errors */
125     if (err != 0) {
126         TRACE_ERROR_NUMBER("Conversion failed", err);
127         if (error) *error = err;
128         return def;
129     }
130 
131     /* Other error cases */
132     if ((endptr == str) || (strict && (*endptr != '\0'))) {
133         TRACE_ERROR_NUMBER("More characters or nothing processed", EIO);
134         if (error) *error = EIO;
135         return def;
136     }
137 
138     TRACE_FLOW_NUMBER("get_llong_config_value returning", (long)val);
139     return val;
140 }
141 
142 /* Get unsigned long long value from config item */
get_ullong_config_value(struct collection_item * item,int strict,unsigned long long def,int * error)143 static unsigned long long get_ullong_config_value(struct collection_item *item,
144                                                   int strict,
145                                                   unsigned long long def,
146                                                   int *error)
147 {
148     int err;
149     const char *str;
150     char *endptr;
151     unsigned long long val = 0;
152 
153     TRACE_FLOW_STRING("get_ullong_config_value", "Entry");
154 
155     /* Do we have the item ? */
156     if ((item == NULL) ||
157        (col_get_item_type(item) != COL_TYPE_STRING)) {
158         TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
159         if (error) *error = EINVAL;
160         return def;
161     }
162 
163     if (error) *error = EOK;
164 
165     /* Try to parse the value */
166     str = (const char *)col_get_item_data(item);
167     errno = 0;
168     val = strtoull(str, &endptr, 10);
169     err = errno;
170 
171     /* Check for various possible errors */
172     if (err != 0) {
173         TRACE_ERROR_NUMBER("Conversion failed", err);
174         if (error) *error = err;
175         return def;
176     }
177 
178     /* Other error cases */
179     if ((endptr == str) || (strict && (*endptr != '\0'))) {
180         TRACE_ERROR_NUMBER("More characters or nothing processed", EIO);
181         if (error) *error = EIO;
182         return def;
183     }
184 
185     TRACE_FLOW_NUMBER("get_ullong_config_value returning", val);
186     return val;
187 }
188 
189 
190 /* Get integer value from config item */
get_int_config_value(struct collection_item * item,int strict,int def,int * error)191 int get_int_config_value(struct collection_item *item,
192                          int strict,
193                          int def,
194                          int *error)
195 {
196     long long val = 0;
197     int err = 0;
198 
199     TRACE_FLOW_STRING("get_int_config_value", "Entry");
200 
201     val = get_llong_config_value(item, strict, def, &err);
202     if (err == 0) {
203         if ((val > INT_MAX) || (val < INT_MIN)) {
204             val = def;
205             err = ERANGE;
206         }
207     }
208 
209     if (error) *error = err;
210 
211     TRACE_FLOW_NUMBER("get_int_config_value returning", (int)val);
212     return (int)val;
213 }
214 
215 /* Get unsigned integer value from config item */
get_unsigned_config_value(struct collection_item * item,int strict,unsigned def,int * error)216 unsigned get_unsigned_config_value(struct collection_item *item,
217                                    int strict,
218                                    unsigned def,
219                                    int *error)
220 {
221     unsigned long long val = 0;
222     int err = 0;
223 
224     TRACE_FLOW_STRING("get_unsigned_config_value", "Entry");
225 
226     val = get_ullong_config_value(item, strict, def, &err);
227     if (err == 0) {
228         if (val > UINT_MAX) {
229             val = def;
230             err = ERANGE;
231         }
232     }
233 
234     if (error) *error = err;
235 
236     TRACE_FLOW_NUMBER("get_unsigned_config_value returning",
237                       (unsigned)val);
238     return (unsigned)val;
239 }
240 
241 /* Get long value from config item */
get_long_config_value(struct collection_item * item,int strict,long def,int * error)242 long get_long_config_value(struct collection_item *item,
243                            int strict,
244                            long def,
245                            int *error)
246 {
247     long long val = 0;
248     int err = 0;
249 
250     TRACE_FLOW_STRING("get_long_config_value", "Entry");
251 
252     val = get_llong_config_value(item, strict, def, &err);
253     if (err == 0) {
254         if ((val > LONG_MAX) || (val < LONG_MIN)) {
255             val = def;
256             err = ERANGE;
257         }
258     }
259 
260     if (error) *error = err;
261 
262     TRACE_FLOW_NUMBER("get_long_config_value returning",
263                       (long)val);
264     return (long)val;
265 }
266 
267 /* Get unsigned long value from config item */
get_ulong_config_value(struct collection_item * item,int strict,unsigned long def,int * error)268 unsigned long get_ulong_config_value(struct collection_item *item,
269                                      int strict,
270                                      unsigned long def,
271                                      int *error)
272 {
273     unsigned long long val = 0;
274     int err = 0;
275 
276     TRACE_FLOW_STRING("get_ulong_config_value", "Entry");
277 
278     val = get_ullong_config_value(item, strict, def, &err);
279     if (err == 0) {
280         if (val > ULONG_MAX) {
281             val = def;
282             err = ERANGE;
283         }
284     }
285 
286     if (error) *error = err;
287 
288     TRACE_FLOW_NUMBER("get_ulong_config_value returning",
289                       (unsigned long)val);
290     return (unsigned long)val;
291 }
292 
293 /* Get int32_t value from config item */
get_int32_config_value(struct collection_item * item,int strict,int32_t def,int * error)294 int32_t get_int32_config_value(struct collection_item *item,
295                                int strict,
296                                int32_t def,
297                                int *error)
298 {
299     int val = 0;
300 
301     TRACE_FLOW_STRING("get_int32_config_value", "Entry");
302 
303     val = get_int_config_value(item, strict, (int)def, error);
304 
305     TRACE_FLOW_SNUMBER("get_int32_config_value returning", (int32_t)val);
306     return (int32_t)val;
307 }
308 
309 /* Get uint32_t value from config item */
get_uint32_config_value(struct collection_item * item,int strict,uint32_t def,int * error)310 uint32_t get_uint32_config_value(struct collection_item *item,
311                                  int strict,
312                                  uint32_t def,
313                                  int *error)
314 {
315     unsigned val = 0;
316 
317     TRACE_FLOW_STRING("get_uint32_config_value", "Entry");
318 
319     val = get_unsigned_config_value(item, strict, (unsigned)def, error);
320 
321     TRACE_FLOW_NUMBER("get_uint32_config_value returning", (uint32_t)val);
322     return (uint32_t)val;
323 }
324 
325 /* Get int64_t value from config item */
get_int64_config_value(struct collection_item * item,int strict,int64_t def,int * error)326 int64_t get_int64_config_value(struct collection_item *item,
327                                int strict,
328                                int64_t def,
329                                int *error)
330 {
331     long long val = 0;
332 
333     TRACE_FLOW_STRING("get_int64_config_value", "Entry");
334 
335     val = get_llong_config_value(item, strict, (long long)def, error);
336 
337     TRACE_FLOW_SLNUMBER("get_int64_config_value returning", (int64_t)val);
338     return (int64_t)val;
339 }
340 
341 /* Get uint64_t value from config item */
get_uint64_config_value(struct collection_item * item,int strict,uint64_t def,int * error)342 uint64_t get_uint64_config_value(struct collection_item *item,
343                                  int strict,
344                                  uint64_t def,
345                                  int *error)
346 {
347     unsigned long long val = 0;
348 
349     TRACE_FLOW_STRING("get_uint64_config_value", "Entry");
350 
351     val = get_ullong_config_value(item,
352                                   strict,
353                                   (unsigned long long)def,
354                                   error);
355 
356     TRACE_FLOW_LNUMBER("get_uint64_config_value returning", (uint64_t)val);
357     return (uint64_t)val;
358 }
359 
360 /* Get double value */
get_double_config_value(struct collection_item * item,int strict,double def,int * error)361 double get_double_config_value(struct collection_item *item,
362                                int strict, double def, int *error)
363 {
364     const char *str;
365     char *endptr;
366     double val = 0;
367 
368     TRACE_FLOW_STRING("get_double_config_value", "Entry");
369 
370     /* Do we have the item ? */
371     if ((item == NULL) ||
372         (col_get_item_type(item) != COL_TYPE_STRING)) {
373         TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
374         if (error) *error = EINVAL;
375         return def;
376     }
377 
378     if (error) *error = EOK;
379 
380     /* Try to parse the value */
381     str = (const char *)col_get_item_data(item);
382     errno = 0;
383     val = strtod(str, &endptr);
384 
385     /* Check for various possible errors */
386     if ((errno == ERANGE) ||
387         ((errno != 0) && (val == 0)) ||
388         (endptr == str)) {
389         TRACE_ERROR_NUMBER("Conversion failed", EIO);
390         if (error) *error = EIO;
391         return def;
392     }
393 
394     if (strict && (*endptr != '\0')) {
395         TRACE_ERROR_NUMBER("More characters than expected", EIO);
396         if (error) *error = EIO;
397         val = def;
398     }
399 
400     TRACE_FLOW_DOUBLE("get_double_config_value returning", val);
401     return val;
402 }
403 
404 /* Get boolean value */
get_bool_config_value(struct collection_item * item,unsigned char def,int * error)405 unsigned char get_bool_config_value(struct collection_item *item,
406                                     unsigned char def, int *error)
407 {
408     const char *str;
409     int len;
410 
411     TRACE_FLOW_STRING("get_bool_config_value", "Entry");
412 
413     /* Do we have the item ? */
414     if ((item == NULL) ||
415         (col_get_item_type(item) != COL_TYPE_STRING)) {
416         TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
417         if (error) *error = EINVAL;
418         return def;
419     }
420 
421     if (error) *error = EOK;
422 
423     str = (const char *)col_get_item_data(item);
424     len = col_get_item_length(item);
425 
426     /* Try to parse the value */
427     if ((strncasecmp(str, "true", len) == 0) ||
428         (strncasecmp(str, "yes", len) == 0)) {
429         TRACE_FLOW_STRING("Returning", "true");
430         return '\1';
431     }
432     else if ((strncasecmp(str, "false", len) == 0) ||
433              (strncasecmp(str, "no", len) == 0)) {
434         TRACE_FLOW_STRING("Returning", "false");
435         return '\0';
436     }
437 
438     TRACE_ERROR_STRING("Returning", "error");
439     if (error) *error = EIO;
440     return def;
441 }
442 
443 /* Return a string out of the value */
get_string_config_value(struct collection_item * item,int * error)444 char *get_string_config_value(struct collection_item *item,
445                               int *error)
446 {
447     char *str = NULL;
448 
449     TRACE_FLOW_STRING("get_string_config_value", "Entry");
450 
451     /* Do we have the item ? */
452     if ((item == NULL) ||
453         (col_get_item_type(item) != COL_TYPE_STRING)) {
454         TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
455         if (error) *error = EINVAL;
456         return NULL;
457     }
458 
459     str = strdup((const char *)col_get_item_data(item));
460     if (str == NULL) {
461         TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
462         if (error) *error = ENOMEM;
463         return NULL;
464     }
465 
466     if (error) *error = EOK;
467 
468     TRACE_FLOW_STRING("get_string_config_value returning", str);
469     return str;
470 }
471 
472 /* Get string from item */
get_const_string_config_value(struct collection_item * item,int * error)473 const char *get_const_string_config_value(struct collection_item *item, int *error)
474 {
475     const char *str;
476 
477     TRACE_FLOW_STRING("get_const_string_config_value", "Entry");
478 
479     /* Do we have the item ? */
480     if ((item == NULL) ||
481         (col_get_item_type(item) != COL_TYPE_STRING)) {
482         TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
483         if (error) *error = EINVAL;
484         return NULL;
485     }
486 
487     str = (const char *)col_get_item_data(item);
488 
489     if (error) *error = EOK;
490 
491     TRACE_FLOW_STRING("get_const_string_config_value returning", str);
492     return str;
493 }
494 
495 /* A special hex format is assumed.
496  * The string should be taken in single quotes
497  * and consist of hex encoded value two hex digits per byte.
498  * Example: '0A2BFECC'
499  * Case does not matter.
500  */
get_bin_config_value(struct collection_item * item,int * length,int * error)501 char *get_bin_config_value(struct collection_item *item,
502                            int *length, int *error)
503 {
504     unsigned i;
505     char *value = NULL;
506     const char *buff;
507     int size = 0;
508     unsigned char hex;
509     unsigned len;
510     const char *str;
511 
512     TRACE_FLOW_STRING("get_bin_config_value", "Entry");
513 
514     /* Do we have the item ? */
515     if ((item == NULL) ||
516         (col_get_item_type(item) != COL_TYPE_STRING)) {
517         TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
518         if (error) *error = EINVAL;
519         return NULL;
520     }
521 
522     /* Check the length */
523     len = col_get_item_length(item)-1;
524     if ((len%2) != 0) {
525         TRACE_ERROR_STRING("Invalid length for binary data", "");
526         if (error) *error = EINVAL;
527         return NULL;
528     }
529 
530     str = (const char *)col_get_item_data(item);
531 
532     /* Is the format correct ? */
533     if ((*str != '\'') ||
534         (str[len -1] != '\'')) {
535         TRACE_ERROR_STRING("String is not escaped","");
536         if (error) *error = EIO;
537         return NULL;
538     }
539 
540     /* Check that all the symbols are ok */
541     buff = str + 1;
542     len -= 2;
543     for (i = 0; i < len; i += 2) {
544         if (!isxdigit(buff[i]) || !isxdigit(buff[i + 1])) {
545             TRACE_ERROR_STRING("Invalid encoding for binary data", buff + i);
546             if (error) *error = EIO;
547             return NULL;
548         }
549     }
550 
551     /* The value is good so we can allocate memory for it */
552     value = malloc(len / 2);
553     if (value == NULL) {
554         TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
555         if (error) *error = ENOMEM;
556         return NULL;
557     }
558 
559     /* Convert the value */
560     for (i = 0; i < len; i += 2) {
561         if (isdigit(buff[i])) {
562             if (isdigit(buff[i+1]))
563                 hex = 16 * (buff[i] - '0') + (buff[i+1] - '0');
564             else
565                 hex = 16 * (buff[i] - '0') + (tolower(buff[i+1]) - 'a' + 10);
566         }
567         else {
568             if (isdigit(buff[i+1]))
569                 hex = 16 * (tolower(buff[i]) - 'a') + (buff[i+1] - '0');
570             else
571                 hex = 16 * (tolower(buff[i]) - 'a' + 10) + (tolower(buff[i+1]) - 'a' + 10);
572         }
573 
574         value[size] = (char)(hex);
575         size++;
576     }
577 
578     if (error) *error = EOK;
579     if (length) *length = size;
580     TRACE_FLOW_STRING("get_bin_config_value", "Exit");
581     return value;
582 }
583 
584 /* Function to free binary configuration value */
free_bin_config_value(char * value)585 void free_bin_config_value(char *value)
586 {
587     if (value) free(value);
588 }
589