LCOV - code coverage report
Current view: top level - ini - ini_config.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 219 290 75.5 %
Date: 2014-04-01 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /*
       2             :     INI LIBRARY
       3             : 
       4             :     Reading configuration from INI file
       5             :     and storing as a collection.
       6             : 
       7             :     Copyright (C) Dmitri Pal <dpal@redhat.com> 2009
       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 <errno.h>
      25             : #include <string.h>
      26             : #include <stdlib.h>
      27             : #include <ctype.h>
      28             : #include "trace.h"
      29             : #include "collection.h"
      30             : #include "collection_tools.h"
      31             : #include "path_utils.h"
      32             : #include "ini_defines.h"
      33             : #include "ini_metadata.h"
      34             : #include "ini_config.h"
      35             : 
      36             : /* Temporarily move the parsing function here */
      37             : /* THIS FUNCTION WILL BE REMOVED AS SOON AS WE SWITCH TO THE NEW INTERFACE */
      38             : /* Reads a line from the file */
      39         651 : static int read_line(FILE *file,
      40             :                      char *buf,
      41             :                      int read_size,
      42             :                      char **key, char **value,
      43             :                      int *length,
      44             :                      int *ext_error)
      45             : {
      46             : 
      47             :     char *res;
      48             :     int len;
      49             :     char *buffer;
      50             :     int i;
      51             :     char *eq;
      52             : 
      53             :     TRACE_FLOW_STRING("read_line", "Entry");
      54             : 
      55         651 :     *ext_error = 0;
      56             : 
      57         651 :     buffer = buf;
      58             : 
      59             :     /* Get data from file */
      60         651 :     res = fgets(buffer, read_size - 1, file);
      61         651 :     if (res == NULL) {
      62             :         TRACE_ERROR_STRING("Read nothing", "");
      63             :         return RET_EOF;
      64             :     }
      65             : 
      66             :     /* Make sure the buffer is NULL terminated */
      67         640 :     buffer[read_size - 1] = '\0';
      68             : 
      69         640 :     len = strlen(buffer);
      70         640 :     if (len == 0) {
      71             :         TRACE_ERROR_STRING("Nothing was read.", "");
      72             :         return RET_EMPTY;
      73             :     }
      74             : 
      75             :     /* Added \r just in case we deal with Windows in future */
      76         640 :     if ((buffer[len - 1] != '\n') && (buffer[len - 1] != '\r')) {
      77             :         TRACE_ERROR_STRING("String it too big!", "");
      78           0 :         *ext_error = ERR_LONGDATA;
      79           0 :         return RET_ERROR;
      80             :     }
      81             : 
      82             :     /* Ingnore comments */
      83         640 :     if ((*buffer == ';') || (*buffer == '#')) {
      84             :         TRACE_FLOW_STRING("Comment", buf);
      85             :         return RET_COMMENT;
      86             :     }
      87             : 
      88             :     TRACE_INFO_STRING("BUFFER before trimming:", buffer);
      89             : 
      90             :     /* Trucate trailing spaces and CRs */
      91             :     /* Make sure not to step before the beginning */
      92        1644 :     while (len && isspace(buffer[len - 1])) {
      93        1027 :         buffer[len - 1] = '\0';
      94        1027 :         len--;
      95             :     }
      96             : 
      97             :     TRACE_INFO_STRING("BUFFER after trimming trailing spaces:", buffer);
      98             : 
      99             :     /* Trucate leading spaces  */
     100         776 :     while (isspace(*buffer)) {
     101         159 :         buffer++;
     102         159 :         len--;
     103             :     }
     104             : 
     105             :     TRACE_INFO_STRING("BUFFER after trimming leading spaces:", buffer);
     106             :     TRACE_INFO_NUMBER("BUFFER length:", len);
     107             : 
     108             :     /* Empty line */
     109         617 :     if (len == 0) {
     110             :         TRACE_FLOW_STRING("Empty line", buf);
     111             :         return RET_EMPTY;
     112             :     }
     113             : 
     114             :     /* Section */
     115         408 :     if (*buffer == '[') {
     116          75 :         if (buffer[len-1] != ']') {
     117             :             TRACE_ERROR_STRING("Invalid format for section", buf);
     118          14 :             *ext_error = ERR_NOCLOSESEC;
     119          14 :             return RET_ERROR;
     120             :         }
     121          61 :         buffer++;
     122          61 :         len--;
     123         489 :         while (isspace(*buffer)) {
     124         367 :             buffer++;
     125         367 :             len--;
     126             :         }
     127          61 :         if (len == 0) {
     128             :             TRACE_ERROR_STRING("Invalid format for section", buf);
     129           0 :             *ext_error = ERR_NOSECTION;
     130           0 :             return RET_ERROR;
     131             :         }
     132             : 
     133          61 :         buffer[len - 1] = '\0';
     134          61 :         len--;
     135         297 :         while (isspace(buffer[len - 1])) {
     136         175 :             buffer[len - 1] = '\0';
     137         175 :             len--;
     138             :         }
     139          61 :         if (len >= MAX_KEY) {
     140             :             TRACE_ERROR_STRING("Section name is too long", buf);
     141           7 :             *ext_error = ERR_SECTIONLONG;
     142           7 :             return RET_ERROR;
     143             :         }
     144             : 
     145          54 :         *key = buffer;
     146          54 :         return RET_SECTION;
     147             :     }
     148             : 
     149             :     /* Assume we are dealing with the K-V here */
     150             :     /* Find "=" */
     151         333 :     eq = strchr(buffer, '=');
     152         333 :     if (eq == NULL) {
     153             :         TRACE_ERROR_STRING("No equal sign", buf);
     154          38 :         *ext_error = ERR_NOEQUAL;
     155          38 :         return RET_INVALID;
     156             :     }
     157             : 
     158         295 :     len -= eq-buffer;
     159             : 
     160             :     /* Strip spaces around "=" */
     161         295 :     i = eq - buffer - 1;
     162         295 :     while ((i >= 0) && isspace(buffer[i])) i--;
     163         295 :     if (i < 0) {
     164             :         TRACE_ERROR_STRING("No key", buf);
     165           8 :         *ext_error = ERR_NOKEY;
     166           8 :         return RET_INVALID;
     167             :     }
     168             : 
     169             :     /* Copy key into provided buffer */
     170         287 :     if(i >= MAX_KEY) {
     171             :         TRACE_ERROR_STRING("Key name is too long", buf);
     172           7 :         *ext_error = ERR_LONGKEY;
     173           7 :         return RET_INVALID;
     174             :     }
     175         280 :     *key = buffer;
     176         280 :     buffer[i + 1] = '\0';
     177             :     TRACE_INFO_STRING("KEY:", *key);
     178             : 
     179         280 :     eq++;
     180         280 :     len--;
     181         787 :     while (isspace(*eq)) {
     182         227 :         eq++;
     183         227 :         len--;
     184             :     }
     185             : 
     186         280 :     *value = eq;
     187             :     /* Make sure we include trailing 0 into data */
     188         280 :     *length = len + 1;
     189             : 
     190             :     TRACE_INFO_STRING("VALUE:", *value);
     191             :     TRACE_INFO_NUMBER("LENGTH:", *length);
     192             : 
     193             :     TRACE_FLOW_STRING("read_line", "Exit");
     194         280 :     return RET_PAIR;
     195             : }
     196             : 
     197             : /************************************************************/
     198             : /* REMOVE FUNCTION ABOVE                                    */
     199             : /************************************************************/
     200             : 
     201             : 
     202             : /***************************************************************************/
     203             : /* Function to read single ini file and pupulate
     204             :  * the provided collection with subcollcetions from the file */
     205          11 : static int ini_to_collection(FILE *file,
     206             :                              const char *config_filename,
     207             :                              struct collection_item *ini_config,
     208             :                              int error_level,
     209             :                              struct collection_item **error_list,
     210             :                              struct collection_item *lines)
     211             : {
     212             :     int error;
     213             :     int status;
     214          11 :     int section_count = 0;
     215          11 :     char *key = NULL;
     216          11 :     char *value = NULL;
     217          11 :     struct collection_item *current_section = NULL;
     218             :     int length;
     219          11 :     int ext_err = -1;
     220             :     struct parse_error pe;
     221          11 :     int line = 0;
     222          11 :     int created = 0;
     223             :     char buf[BUFFER_SIZE+1];
     224             : 
     225             : 
     226             :     TRACE_FLOW_STRING("ini_to_collection", "Entry");
     227             : 
     228             :     /* Open the collection of errors */
     229          11 :     if (error_list != NULL) {
     230          11 :         *error_list = NULL;
     231          11 :         error = col_create_collection(error_list, INI_ERROR, COL_CLASS_INI_PERROR);
     232          11 :         if (error) {
     233             :             TRACE_ERROR_NUMBER("Failed to create error collection", error);
     234             :             return error;
     235             :         }
     236             :         /* Add file name as the first item */
     237          11 :         error = col_add_str_property(*error_list, NULL, INI_ERROR_NAME, config_filename, 0);
     238          11 :         if (error) {
     239             :             TRACE_ERROR_NUMBER("Failed to and name to collection", error);
     240           0 :             col_destroy_collection(*error_list);
     241             :             return error;
     242             :         }
     243             :         created = 1;
     244             :     }
     245             : 
     246             :     /* Read file lines */
     247             :     while (1) {
     248             :         /* Always read one less than the buffer */
     249         651 :         status = read_line(file, buf, BUFFER_SIZE+1, &key, &value, &length, &ext_err);
     250         651 :         if (status == RET_EOF) break;
     251             : 
     252         640 :         line++;
     253             : 
     254         640 :         switch (status) {
     255             :         case RET_PAIR:
     256             : 
     257             : #ifdef HAVE_VALIDATION
     258             : 
     259             :             /* Add line to the collection of lines.
     260             :              * It is pretty safe in this case to just type cast the value to
     261             :              * int32_t since it is unrealistic that ini file will ever have
     262             :              * so many lines.
     263             :              */
     264             :             if (lines) {
     265             :                 error = col_add_int_property(lines, NULL, key, (int32_t)line);
     266             :                 if (error) {
     267             :                     TRACE_ERROR_NUMBER("Failed to add line to line collection", error);
     268             :                     col_destroy_collection(current_section);
     269             :                     if (created) {
     270             :                         col_destroy_collection(*error_list);
     271             :                         *error_list = NULL;
     272             :                     }
     273             :                     return error;
     274             :                 }
     275             :             }
     276             : 
     277             : #endif /* HAVE_VALIDATION */
     278             : 
     279             :             /* Do we have a section at the top of the file ? */
     280         280 :             if (section_count == 0) {
     281             :                 /* Check if collection already exists */
     282           8 :                 error = col_get_collection_reference(ini_config, &current_section,
     283             :                                                      INI_DEFAULT_SECTION);
     284           8 :                 if (error != EOK) {
     285             :                     /* Create default collection */
     286           7 :                     if ((error = col_create_collection(&current_section,
     287             :                                                        INI_DEFAULT_SECTION,
     288           7 :                                                        COL_CLASS_INI_SECTION)) ||
     289           7 :                         (error = col_add_collection_to_collection(ini_config,
     290             :                                                                   NULL,NULL,
     291             :                                                                   current_section,
     292             :                                                                   COL_ADD_MODE_REFERENCE))) {
     293             :                         TRACE_ERROR_NUMBER("Failed to create collection", error);
     294           0 :                         col_destroy_collection(current_section);
     295           0 :                         if (created) {
     296           0 :                             col_destroy_collection(*error_list);
     297           0 :                             *error_list = NULL;
     298             :                         }
     299             :                         return error;
     300             :                     }
     301             :                 }
     302           8 :                 section_count++;
     303             :             }
     304             : 
     305             :             /* Put value into the collection */
     306         280 :             error = col_insert_str_property(current_section,
     307             :                                             NULL,
     308             :                                             COL_DSP_END,
     309             :                                             NULL,
     310             :                                             0,
     311             :                                             COL_INSERT_DUPOVER,
     312             :                                             key,
     313             :                                             value,
     314             :                                             length);
     315         280 :             if (error != EOK) {
     316             :                 TRACE_ERROR_NUMBER("Failed to add pair to collection", error);
     317           0 :                 col_destroy_collection(current_section);
     318           0 :                 if (created) {
     319           0 :                     col_destroy_collection(*error_list);
     320           0 :                     *error_list = NULL;
     321             :                 }
     322             :                 return error;
     323             :             }
     324             :             break;
     325             : 
     326             :         case RET_SECTION:
     327             : 
     328             : #ifdef HAVE_VALIDATION
     329             : 
     330             :             /* Add line to the collection of lines */
     331             :             if (lines) {
     332             :                 /* For easier search make line numbers for the sections negative.
     333             :                  * This would allow differentiating sections and attributes.
     334             :                  * It is pretty safe in this case to just type cast the value to
     335             :                  * int32_t since it is unrealistic that ini file will ever have
     336             :                  * so many lines.
     337             :                  */
     338             :                 error = col_add_int_property(lines, NULL, key, (int32_t)(-1 * line));
     339             :                 if (error) {
     340             :                     TRACE_ERROR_NUMBER("Failed to add line to line collection", error);
     341             :                     col_destroy_collection(current_section);
     342             :                     if (created) {
     343             :                         col_destroy_collection(*error_list);
     344             :                         *error_list = NULL;
     345             :                     }
     346             :                     return error;
     347             :                 }
     348             :             }
     349             : 
     350             : #endif /* HAVE_VALIDATION */
     351             : 
     352             :             /* Read a new section */
     353          54 :             col_destroy_collection(current_section);
     354          54 :             current_section = NULL;
     355             : 
     356          54 :             error = col_get_collection_reference(ini_config, &current_section, key);
     357          54 :             if (error != EOK) {
     358             :                 /* Create default collection */
     359          46 :                 if ((error = col_create_collection(&current_section, key,
     360          46 :                                                    COL_CLASS_INI_SECTION)) ||
     361          46 :                     (error = col_add_collection_to_collection(ini_config,
     362             :                                                               NULL, NULL,
     363             :                                                               current_section,
     364             :                                                               COL_ADD_MODE_REFERENCE))) {
     365             :                     TRACE_ERROR_NUMBER("Failed to add collection", error);
     366           0 :                     col_destroy_collection(current_section);
     367           0 :                     if (created) {
     368           0 :                         col_destroy_collection(*error_list);
     369           0 :                         *error_list = NULL;
     370             :                     }
     371             :                     return error;
     372             :                 }
     373             :             }
     374          54 :             section_count++;
     375             :             break;
     376             : 
     377             :         case RET_EMPTY:
     378             :             TRACE_INFO_STRING("Empty string", "");
     379             :             break;
     380             : 
     381             :         case RET_COMMENT:
     382             :             TRACE_INFO_STRING("Comment", "");
     383             :             break;
     384             : 
     385             :         case RET_ERROR:
     386             :             /* Try to add to the error list only if it is present */
     387          21 :             if (error_list) {
     388          21 :                 pe.line = line;
     389          21 :                 pe.error = ext_err;
     390          21 :                 error = col_add_binary_property(*error_list, NULL,
     391          21 :                                                 ERROR_TXT, &pe, sizeof(pe));
     392          21 :                 if (error) {
     393             :                     TRACE_ERROR_NUMBER("Failed to add error to collection",
     394             :                                        error);
     395           0 :                     col_destroy_collection(current_section);
     396           0 :                     if (created) {
     397           0 :                         col_destroy_collection(*error_list);
     398           0 :                         *error_list = NULL;
     399             :                     }
     400             :                     return error;
     401             :                 }
     402             :             }
     403             : 
     404             :             /* Exit if there was an error parsing file */
     405          21 :             if (error_level != INI_STOP_ON_NONE) {
     406             :                 TRACE_ERROR_STRING("Invalid format of the file", "");
     407           0 :                 col_destroy_collection(current_section);
     408             :                 return EIO;
     409             :             }
     410             :             break;
     411             : 
     412             :         case RET_INVALID:
     413             :         default:
     414             :             /* Try to add to the error list only if it is present */
     415          53 :             if (error_list) {
     416          53 :                 pe.line = line;
     417          53 :                 pe.error = ext_err;
     418          53 :                 error = col_add_binary_property(*error_list, NULL,
     419          53 :                                                 WARNING_TXT, &pe, sizeof(pe));
     420          53 :                 if (error) {
     421             :                     TRACE_ERROR_NUMBER("Failed to add warning to collection",
     422             :                                        error);
     423           0 :                     col_destroy_collection(current_section);
     424           0 :                     if (created) {
     425           0 :                         col_destroy_collection(*error_list);
     426           0 :                         *error_list = NULL;
     427             :                     }
     428             :                     return error;
     429             :                 }
     430             :             }
     431             : 
     432             :             /* Exit if we are told to exit on warnings */
     433          53 :             if (error_level == INI_STOP_ON_ANY) {
     434             :                 TRACE_ERROR_STRING("Invalid format of the file", "");
     435           0 :                 if (created) col_destroy_collection(current_section);
     436             :                 return EIO;
     437             :             }
     438             :             TRACE_ERROR_STRING("Invalid string", "");
     439             :             break;
     440             :         }
     441         640 :         ext_err = -1;
     442             :     }
     443             : 
     444             :     /* Note: File is not closed on this level any more.
     445             :      * It opened on the level above, checked and closed there.
     446             :      * It is not the responsibility of this function to close
     447             :      * file any more.
     448             :      */
     449             : 
     450             :     COL_DEBUG_COLLECTION(ini_config);
     451             : 
     452          11 :     col_destroy_collection(current_section);
     453             : 
     454             :     COL_DEBUG_COLLECTION(ini_config);
     455             : 
     456             :     TRACE_FLOW_STRING("ini_to_collection", "Success Exit");
     457             : 
     458             :     return EOK;
     459             : }
     460             : 
     461             : /*********************************************************************/
     462             : /* Function to free configuration */
     463          10 : void free_ini_config(struct collection_item *ini_config)
     464             : {
     465             :     TRACE_FLOW_STRING("free_ini_config", "Entry");
     466          10 :     col_destroy_collection(ini_config);
     467             :     TRACE_FLOW_STRING("free_ini_config", "Exit");
     468          10 : }
     469             : 
     470             : /* Function to free configuration error list */
     471           9 : void free_ini_config_errors(struct collection_item *error_set)
     472             : {
     473             :     TRACE_FLOW_STRING("free_ini_config_errors", "Entry");
     474           9 :     col_destroy_collection(error_set);
     475             :     TRACE_FLOW_STRING("free_ini_config_errors", "Exit");
     476           9 : }
     477             : 
     478             : #ifdef HAVE_VALIDATION
     479             : 
     480             : /* Function to free configuration lines list.
     481             :  *
     482             :  * The following doxygen description is moved here.
     483             :  * When the function gets exposed move it into
     484             :  * the header file.
     485             :  */
     486             : /**
     487             :  * @brief Function to free lines object.
     488             :  *
     489             :  * EXPERIMENTAL. Reserved for future use.
     490             :  *
     491             :  * @param[in] lines       Lines object.
     492             :  *
     493             :  */
     494             : 
     495             : void free_ini_config_lines(struct collection_item *lines)
     496             : {
     497             :     TRACE_FLOW_STRING("free_ini_config_lines", "Entry");
     498             :     col_destroy_collection(lines);
     499             :     TRACE_FLOW_STRING("free_ini_config_lines", "Exit");
     500             : }
     501             : 
     502             : #endif /* HAVE_VALIDATION */
     503             : 
     504             : 
     505             : /* Read configuration information from a file */
     506           2 : int config_from_file(const char *application,
     507             :                      const char *config_filename,
     508             :                      struct collection_item **ini_config,
     509             :                      int error_level,
     510             :                      struct collection_item **error_list)
     511             : {
     512             :     int error;
     513             : 
     514             :     TRACE_FLOW_STRING("config_from_file", "Entry");
     515           2 :     error = config_from_file_with_metadata(application,
     516             :                                            config_filename,
     517             :                                            ini_config,
     518             :                                            error_level,
     519             :                                            error_list,
     520             :                                            0,
     521             :                                            NULL);
     522             :     TRACE_FLOW_NUMBER("config_from_file. Returns", error);
     523           2 :     return error;
     524             : }
     525             : 
     526             : /* Read configuration information from a file descriptor */
     527           1 : int config_from_fd(const char *application,
     528             :                    int fd,
     529             :                    const char *config_source,
     530             :                    struct collection_item **ini_config,
     531             :                    int error_level,
     532             :                    struct collection_item **error_list)
     533             : {
     534             :     int error;
     535             : 
     536             :     TRACE_FLOW_STRING("config_from_fd", "Entry");
     537           1 :     error = config_from_fd_with_metadata(application,
     538             :                                          fd,
     539             :                                          config_source,
     540             :                                          ini_config,
     541             :                                          error_level,
     542             :                                          error_list,
     543             :                                          0,
     544             :                                          NULL);
     545             :     TRACE_FLOW_NUMBER("config_from_fd. Returns", error);
     546           1 :     return error;
     547             : }
     548             : 
     549             : 
     550             : 
     551             : /* Low level function that prepares the collection
     552             :  * and calls parser.
     553             :  */
     554          11 : static int config_with_metadata(const char *application,
     555             :                                 FILE *config_file,
     556             :                                 const char *config_source,
     557             :                                 struct collection_item **ini_config,
     558             :                                 int error_level,
     559             :                                 struct collection_item **error_list,
     560             :                                 uint32_t metaflags,
     561             :                                 struct collection_item **metadata)
     562             : {
     563             :     int error;
     564          11 :     int created = 0;
     565          11 :     struct collection_item *lines = NULL;
     566             : 
     567             : #ifdef HAVE_VALIDATION
     568             :     int created_lines = 0;
     569             : #endif
     570             : 
     571             :     TRACE_FLOW_STRING("config_from_file", "Entry");
     572             : 
     573             :     /* Now we check arguments in the calling functions. */
     574             : 
     575             :     /* Create collection if needed */
     576          11 :     if (*ini_config == NULL) {
     577           5 :         error = col_create_collection(ini_config,
     578             :                                       application,
     579             :                                       COL_CLASS_INI_CONFIG);
     580           5 :         if (error != EOK) {
     581             :             TRACE_ERROR_NUMBER("Failed to create collection", error);
     582             :             return error;
     583             :         }
     584             :         created = 1;
     585             :     }
     586             :     /* Is the collection of the right class? */
     587           6 :     else if (((col_is_of_class(*ini_config, COL_CLASS_INI_CONFIG))== 0) &&
     588           0 :              ((col_is_of_class(*ini_config, COL_CLASS_INI_META))== 0)) {
     589             :         TRACE_ERROR_NUMBER("Wrong collection type", EINVAL);
     590             :         return EINVAL;
     591             :     }
     592             : 
     593             : #ifdef HAVE_VALIDATION
     594             :     /* This code is preserved for future use */
     595             :     error = col_create_collection(lines,
     596             :                                     application,
     597             :                                     COL_CLASS_INI_LINES);
     598             :     if (error != EOK) {
     599             :         TRACE_ERROR_NUMBER("Failed to create collection", error);
     600             :         if (created) {
     601             :             col_destroy_collection(*ini_config);
     602             :             *ini_config = NULL;
     603             :         }
     604             :         return error;
     605             :     }
     606             :     created_lines = 1;
     607             : #else
     608             :     /* Until we implement validation do not read the lines. */
     609          11 :     lines = NULL;
     610             : #endif /* HAVE_VALIDATION */
     611             : 
     612             :     /* Do the actual work - for now do not read lines.*/
     613          11 :     error = ini_to_collection(config_file, config_source,
     614             :                               *ini_config, error_level,
     615             :                               error_list, lines);
     616             :     /* In case of error when we created collection - delete it */
     617          11 :     if (error && created) {
     618           0 :         col_destroy_collection(*ini_config);
     619           0 :         *ini_config = NULL;
     620             :     }
     621             : 
     622             :     /* FIXME - put lines collection into the metadata */
     623             : 
     624             :     TRACE_FLOW_NUMBER("config_from_file. Returns", error);
     625             :     return error;
     626             : }
     627             : 
     628             : /* Function to read the ini file from fd
     629             :  * with meta data.
     630             :  */
     631          19 : int config_from_fd_with_metadata(const char *application,
     632             :                                  int ext_fd,
     633             :                                  const char *config_filename,
     634             :                                  struct collection_item **ini_config,
     635             :                                  int error_level,
     636             :                                  struct collection_item **error_list,
     637             :                                  uint32_t metaflags,
     638             :                                  struct collection_item **metadata)
     639             : {
     640          19 :     int error = EOK;
     641          19 :     int file_error = EOK;
     642          19 :     int save_error = 0;
     643          19 :     int fd = -1;
     644          19 :     FILE *config_file = NULL;
     645             :     char abs_name[PATH_MAX + 1];
     646             :     char buff[CONVERSION_BUFFER];
     647             : 
     648             :     TRACE_FLOW_STRING("config_from_fd_with_metadata", "Entry");
     649             : 
     650             :     /* We need to check arguments before we can move on,
     651             :      * and start allocating memory.
     652             :      */
     653          38 :     if ((ini_config == NULL) ||
     654          19 :         (application == NULL)) {
     655             :         TRACE_ERROR_NUMBER("Invalid argument", EINVAL);
     656             :         return EINVAL;
     657             :     }
     658             : 
     659             :     /* Prepare meta data */
     660          19 :     error = prepare_metadata(metaflags, metadata, &save_error);
     661          19 :     if (error) {
     662             :         TRACE_ERROR_NUMBER("Failed to prepare metadata", error);
     663             :         return error;
     664             :     }
     665             : 
     666          19 :     errno = 0;
     667             : 
     668          19 :     if (ext_fd == -1) {
     669             :         /* No file descriptor so use name */
     670          15 :         config_file = fopen(config_filename, "r");
     671             :     }
     672             :     else {
     673             :         /* Create a copy of the descriptor so that we can close it if needed */
     674           4 :         fd = dup(ext_fd);
     675           4 :         if (fd != -1) config_file = fdopen(fd, "r");
     676             :     }
     677          19 :     file_error = errno;
     678             : 
     679          19 :     if (save_error) {
     680             :         /* Record the result of the open file operation in metadata */
     681           3 :         snprintf(buff, CONVERSION_BUFFER, "%d", file_error);
     682           3 :         error = col_add_str_property(*metadata,
     683             :                                      INI_META_SEC_ERROR,
     684             :                                      INI_META_KEY_READ_ERROR,
     685             :                                      buff,
     686             :                                      0);
     687           3 :         if (error) {
     688             :             /* Something is really wrong if we failed here */
     689             :             TRACE_ERROR_NUMBER("Failed to save file open error", error);
     690           0 :             if (config_file) fclose(config_file);
     691           0 :             return error;
     692             :         }
     693             :     }
     694             : 
     695          19 :     if(!config_file) {
     696             :         TRACE_ERROR_NUMBER("Failed to open file", file_error);
     697             :         return file_error;
     698             :     }
     699             : 
     700             :     /* Normalize path for reporting purposes */
     701          15 :     error = make_normalized_absolute_path(abs_name,
     702             :                                           PATH_MAX,
     703             :                                           config_filename);
     704          15 :     if(error) {
     705             :         TRACE_ERROR_NUMBER("Failed to resolve path", error);
     706           0 :         fclose(config_file);
     707           0 :         return error;
     708             :     }
     709             : 
     710             : 
     711          15 :     if (metadata) {
     712             :         /* Collect meta data before actually parsing the file */
     713           5 :         error = collect_metadata(metaflags,
     714             :                                  metadata,
     715             :                                  config_file,
     716             :                                  abs_name);
     717           5 :         if(error) {
     718             :             TRACE_ERROR_NUMBER("Failed to collect metadata", error);
     719           0 :             fclose(config_file);
     720           0 :             return error;
     721             :         }
     722             :     }
     723             : 
     724          15 :     if (!(metaflags & INI_META_ACTION_NOPARSE)) {
     725             :         /* Parse data if needed */
     726          11 :         error = config_with_metadata(application,
     727             :                                      config_file,
     728             :                                      abs_name,
     729             :                                      ini_config,
     730             :                                      error_level,
     731             :                                      error_list,
     732             :                                      metaflags,
     733             :                                      metadata);
     734             :     }
     735             : 
     736             :     /* We opened the file we close it */
     737          15 :     fclose(config_file);
     738             : 
     739             :     TRACE_FLOW_NUMBER("config_from_fd_with_metadata. Returns", error);
     740          15 :     return error;
     741             : }
     742             : 
     743             : /* Function to read the ini file with metadata
     744             :  * using file name.
     745             :  */
     746          15 : int config_from_file_with_metadata(const char *application,
     747             :                                    const char *config_filename,
     748             :                                    struct collection_item **ini_config,
     749             :                                    int error_level,
     750             :                                    struct collection_item **error_list,
     751             :                                    uint32_t metaflags,
     752             :                                    struct collection_item **metadata)
     753             : {
     754          15 :     int error = EOK;
     755             :     TRACE_FLOW_STRING("config_from_file_with_metadata", "Entry");
     756             : 
     757          15 :     error = config_from_fd_with_metadata(application,
     758             :                                          -1,
     759             :                                          config_filename,
     760             :                                          ini_config,
     761             :                                          error_level,
     762             :                                          error_list,
     763             :                                          metaflags,
     764             :                                          metadata);
     765             : 
     766             :     TRACE_FLOW_STRING("config_from_file_with_metadata", "Exit");
     767          15 :     return error;
     768             : }
     769             : 
     770             : 
     771             : /* Read default config file and then overwrite it with a specific one
     772             :  * from the directory */
     773          10 : int config_for_app_with_metadata(const char *application,
     774             :                                  const char *config_file,
     775             :                                  const char *config_dir,
     776             :                                  struct collection_item **ini_config,
     777             :                                  int error_level,
     778             :                                  struct collection_item **error_set,
     779             :                                  uint32_t metaflags,
     780             :                                  struct collection_item **meta_default,
     781             :                                  struct collection_item **meta_appini)
     782             : {
     783          10 :     int error = EOK;
     784             :     char *file_name;
     785          10 :     struct collection_item *error_list_common = NULL;
     786          10 :     struct collection_item *error_list_specific = NULL;
     787          10 :     struct collection_item **pass_common = NULL;
     788          10 :     struct collection_item **pass_specific = NULL;
     789          10 :     int created = 0;
     790          10 :     int tried = 0;
     791          10 :     int noents = 0;
     792             : 
     793             :     TRACE_FLOW_STRING("config_for_app", "Entry");
     794             : 
     795          10 :     if (ini_config == NULL) {
     796             :         TRACE_ERROR_NUMBER("Invalid parameter", EINVAL);
     797             :         return EINVAL;
     798             :     }
     799             : 
     800           7 :     if ((config_file == NULL) && (config_dir == NULL)) {
     801             :         TRACE_ERROR_NUMBER("Noop call of the function is invalid", EINVAL);
     802             :         return EINVAL;
     803             :     }
     804             : 
     805             :     /* Prepare error collection pointers */
     806           6 :     if (error_set != NULL) {
     807             :         TRACE_INFO_STRING("Error set is not NULL", "preparing error set");
     808           5 :         pass_common = &error_list_common;
     809           5 :         pass_specific = &error_list_specific;
     810           5 :         *error_set = NULL;
     811             :         /* Construct the overarching error collection */
     812           5 :         error = col_create_collection(error_set,
     813             :                                       FILE_ERROR_SET,
     814             :                                       COL_CLASS_INI_PESET);
     815           5 :         if (error != EOK) {
     816             :             TRACE_ERROR_NUMBER("Failed to create collection", error);
     817             :             return error;
     818             :         }
     819             :     }
     820             :     else {
     821             :         TRACE_INFO_STRING("No error set. Errors will not be captured", "");
     822             :         pass_common = NULL;
     823             :         pass_specific = NULL;
     824             :     }
     825             : 
     826             :     /* Create collection if needed */
     827           6 :     if (*ini_config == NULL) {
     828             :         TRACE_INFO_STRING("New config collection. Allocate.", "");
     829           6 :         error = col_create_collection(ini_config,
     830             :                                       application,
     831             :                                       COL_CLASS_INI_CONFIG);
     832           6 :         if (error != EOK) {
     833             :             TRACE_ERROR_NUMBER("Failed to create collection", error);
     834           0 :             if (error_set) {
     835           0 :                 col_destroy_collection(*error_set);
     836           0 :                 *error_set = NULL;
     837             :             }
     838           0 :             return error;
     839             :         }
     840             :         created = 1;
     841             :     }
     842             :     /* Is the collection of the right class? */
     843           0 :     else if ((col_is_of_class(*ini_config, COL_CLASS_INI_CONFIG) == 0) &&
     844           0 :              (col_is_of_class(*ini_config, COL_CLASS_INI_META) == 0)) {
     845             :         TRACE_ERROR_NUMBER("Wrong collection type", EINVAL);
     846             :         return EINVAL;
     847             :     }
     848             : 
     849             :     /* Read master file */
     850           6 :     if (config_file != NULL) {
     851             :         TRACE_INFO_STRING("Reading master file:", config_file);
     852             :         /* Get configuration information from the file */
     853           4 :         error = config_from_file_with_metadata(application,
     854             :                                                config_file,
     855             :                                                ini_config,
     856             :                                                error_level,
     857             :                                                pass_common,
     858             :                                                metaflags,
     859             :                                                meta_default);
     860           4 :         tried++;
     861             :         /* ENOENT and EOK are Ok */
     862           4 :         if (error) {
     863           2 :             if (error != ENOENT) {
     864             :                 TRACE_ERROR_NUMBER("Failed to read master file", error);
     865             :                 /* In case of error when we created collection - delete it */
     866           0 :                 if(error && created) {
     867           0 :                     col_destroy_collection(*ini_config);
     868           0 :                     *ini_config = NULL;
     869             :                 }
     870             :                 /* We do not clear the error_set here */
     871           0 :                 return error;
     872             :             }
     873             :             else noents++;
     874             :         }
     875             :         /* Add error results if any to the overarching error collection */
     876           4 :         if ((pass_common != NULL) && (*pass_common != NULL)) {
     877             :             TRACE_INFO_STRING("Process errors resulting from file:", config_file);
     878           2 :             error = col_add_collection_to_collection(*error_set, NULL, NULL,
     879             :                                                      *pass_common,
     880             :                                                      COL_ADD_MODE_EMBED);
     881           2 :             if (error) {
     882           0 :                 if (created) {
     883           0 :                     col_destroy_collection(*ini_config);
     884           0 :                     *ini_config = NULL;
     885             :                 }
     886           0 :                 if (error_set) {
     887           0 :                     col_destroy_collection(*error_set);
     888           0 :                     *error_set = NULL;
     889             :                 }
     890             :                 TRACE_ERROR_NUMBER("Failed to add error collection to another error collection", error);
     891           0 :                 return error;
     892             :             }
     893             :         }
     894             :     }
     895             : 
     896           6 :     if (config_dir != NULL) {
     897             :         /* Get specific application file */
     898           5 :         file_name = malloc(strlen(config_dir) + strlen(application) + NAME_OVERHEAD);
     899           5 :         if (file_name == NULL) {
     900           0 :             error = ENOMEM;
     901             :             TRACE_ERROR_NUMBER("Failed to allocate memory for file name", error);
     902             :             /* In case of error when we created collection - delete it */
     903           0 :             if(created) {
     904           0 :                 col_destroy_collection(*ini_config);
     905           0 :                 *ini_config = NULL;
     906             :             }
     907           0 :             if (error_set) {
     908           0 :                 col_destroy_collection(*error_set);
     909           0 :                 *error_set = NULL;
     910             :             }
     911             :             return error;
     912             :         }
     913             : 
     914             :         /* It is safe to use sprintf() here */
     915           5 :         sprintf(file_name, "%s%s%s.conf", config_dir, SLASH, application);
     916             :         TRACE_INFO_STRING("Opening file:", file_name);
     917             :         /* Read specific file */
     918           5 :         error = config_from_file_with_metadata(application,
     919             :                                                file_name,
     920             :                                                ini_config,
     921             :                                                error_level,
     922             :                                                pass_specific,
     923             :                                                metaflags,
     924             :                                                meta_appini);
     925           5 :         tried++;
     926           5 :         free(file_name);
     927             :         /* ENOENT and EOK are Ok */
     928           5 :         if (error) {
     929           1 :             if (error != ENOENT) {
     930             :                 TRACE_ERROR_NUMBER("Failed to read specific application file", error);
     931             :                 /* In case of error when we created collection - delete it */
     932           0 :                 if (error && created) {
     933           0 :                     col_destroy_collection(*ini_config);
     934           0 :                     *ini_config = NULL;
     935             :                 }
     936             :                 /* We do not clear the error_set here */
     937           0 :                 return error;
     938             :             }
     939           1 :             else noents++;
     940             :         }
     941             :         /* Add error results if any to the overarching error collection */
     942           5 :         if ((pass_specific != NULL) && (*pass_specific != NULL)) {
     943           4 :             error = col_add_collection_to_collection(*error_set, NULL, NULL,
     944             :                                                      *pass_specific,
     945             :                                                      COL_ADD_MODE_EMBED);
     946           4 :             if (error) {
     947           0 :                 if (created) {
     948           0 :                     col_destroy_collection(*ini_config);
     949           0 :                     *ini_config = NULL;
     950             :                 }
     951           0 :                 if (error_set) {
     952           0 :                     col_destroy_collection(*error_set);
     953           0 :                     *error_set = NULL;
     954             :                 }
     955             :                 TRACE_ERROR_NUMBER("Failed to add error collection to another error collection", error);
     956           0 :                 return error;
     957             :             }
     958             :         }
     959             :     }
     960             : 
     961             :     /* If we failed to read or access file as many
     962             :      * times as we tried and we told to stop on any errors
     963             :      * we should report an error.
     964             :      */
     965             :     TRACE_INFO_NUMBER("Tried:", tried);
     966             :     TRACE_INFO_NUMBER("Noents:", noents);
     967             : 
     968           6 :     if ((tried == noents) && (error_level == INI_STOP_ON_ANY)) {
     969             :         TRACE_ERROR_NUMBER("Fail to read or access all the files tried", ENOENT);
     970           1 :         if (created) {
     971           1 :             col_destroy_collection(*ini_config);
     972           1 :             *ini_config = NULL;
     973             :         }
     974           1 :         if (error_set) {
     975           1 :             col_destroy_collection(*error_set);
     976           1 :             *error_set = NULL;
     977             :         }
     978             :         return ENOENT;
     979             :     }
     980             : 
     981             :     TRACE_FLOW_STRING("config_to_collection", "Exit");
     982             :     return EOK;
     983             : }
     984             : 
     985             : 
     986             : /* Function to return configuration data
     987             :  * for the application without meta data.
     988             :  */
     989          10 : int config_for_app(const char *application,
     990             :                    const char *config_file,
     991             :                    const char *config_dir,
     992             :                    struct collection_item **ini_config,
     993             :                    int error_level,
     994             :                    struct collection_item **error_set)
     995             : {
     996          10 :     int error = EOK;
     997             :     TRACE_FLOW_STRING("config_for_app", "Entry");
     998             : 
     999          10 :     error = config_for_app_with_metadata(application,
    1000             :                                          config_file,
    1001             :                                          config_dir,
    1002             :                                          ini_config,
    1003             :                                          error_level,
    1004             :                                          error_set,
    1005             :                                          0,
    1006             :                                          NULL,
    1007             :                                          NULL);
    1008             : 
    1009             :     TRACE_FLOW_NUMBER("config_for_app. Returning", error);
    1010          10 :     return error;
    1011             : }

Generated by: LCOV version 1.10