nfs-ganesha 1.4

config_parsing.c

Go to the documentation of this file.
00001 /* ----------------------------------------------------------------------------
00002  * Copyright CEA/DAM/DIF  (2007)
00003  * contributeur : Thomas LEIBOVICI  thomas.leibovici@cea.fr
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Lesser General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 3 of the License, or (at your option) any later version.
00009  * 
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Lesser General Public License for more details.
00014  * 
00015  * You should have received a copy of the GNU Lesser General Public
00016  * License along with this library; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00018  * 
00019  * ---------------------------------------
00020  */
00021 #include "config.h"
00022 #include "config_parsing.h"
00023 #include "analyse.h"
00024 #include <stdio.h>
00025 #include <errno.h>
00026 
00027 #if HAVE_STRING_H
00028 #include <string.h>
00029 #endif
00030 
00031 /* case unsensitivity */
00032 #define STRNCMP   strncasecmp
00033 
00034 typedef struct config_struct_t
00035 {
00036 
00037   /* Syntax tree */
00038 
00039   list_items *syntax_tree;
00040 
00041 } config_struct_t;
00042 
00043 /***************************************
00044  * ACCES AUX VARIABLES EXTERNES
00045  ***************************************/
00046 
00047 /* fichier d'entree du lexer */
00048 extern FILE *ganesha_yyin;
00049 
00050 /* routine de parsing */
00051 int ganesha_yyparse();
00052 
00053 /* routine de reinitialization */
00054 void ganesha_yyreset(void);
00055 
00056 /* indique le fichier parse (pour la trace en cas d'erreur) */
00057 void ganesha_yy_set_current_file(char *file);
00058 
00059 /* variable renseignee lors du parsing */
00060 extern list_items *program_result;
00061 
00062 /* message d'erreur */
00063 extern char extern_errormsg[1024];
00064 
00065 /* config_ParseFile:
00066  * Reads the content of a configuration file and
00067  * stores it in a memory structure.
00068  */
00069 config_file_t config_ParseFile(char *file_path)
00070 {
00071 
00072   FILE *configuration_file;
00073   config_struct_t *output_struct;
00074 
00075   /* Inits error message */
00076 
00077   extern_errormsg[0] = '\0';
00078 
00079   /* Sanity check */
00080 
00081   if(!file_path || !file_path[0])
00082     {
00083       strcpy(extern_errormsg, "Invalid arguments");
00084       return NULL;
00085     }
00086 
00087   /* First, opens the file. */
00088 
00089   configuration_file = fopen(file_path, "r");
00090 
00091   if(!configuration_file)
00092     {
00093       strcpy(extern_errormsg, strerror(errno));
00094       return NULL;
00095     }
00096 
00097   /* Then, parse the file. */
00098   program_result = NULL;
00099 
00100   ganesha_yyreset();
00101 
00102   ganesha_yy_set_current_file(file_path);
00103   ganesha_yyin = configuration_file;
00104 
00105   if(ganesha_yyparse())
00106     {
00107       fclose(configuration_file);
00108       return NULL;
00109     }
00110 
00113   /* Finally, build the output struct. */
00114 
00115   output_struct = (config_struct_t *) malloc(sizeof(config_struct_t));
00116 
00117   if(!output_struct)
00118     {
00119       strcpy(extern_errormsg, strerror(errno));
00120       fclose(configuration_file);
00121       return NULL;
00122     }
00123 
00124   output_struct->syntax_tree = program_result;
00125 
00126   /* converts pointer to pointer */
00127   fclose(configuration_file);
00128   return (config_file_t) output_struct;
00129 
00130 }
00131 
00132 /* If config_ParseFile returns a NULL pointer,
00133  * config_GetErrorMsg returns a detailled message
00134  * to indicate the reason for this error.
00135  */
00136 char *config_GetErrorMsg()
00137 {
00138 
00139   return extern_errormsg;
00140 
00141 }
00142 
00148 void config_Print(FILE * output, config_file_t config)
00149 {
00150 
00151   /* sanity check */
00152   if(!config)
00153     return;
00154 
00155   config_print_list(output, ((config_struct_t *) config)->syntax_tree);
00156 
00157 }
00158 
00164 void config_Free(config_file_t config)
00165 {
00166 
00167   config_struct_t *config_struct = (config_struct_t *) config;
00168 
00169   if(!config_struct)
00170     return;
00171 
00172   config_free_list(config_struct->syntax_tree);
00173 
00174   free(config_struct);
00175 
00176   return;
00177 
00178 }
00179 
00184 int config_GetNbBlocks(config_file_t config)
00185 {
00186 
00187   config_struct_t *config_struct = (config_struct_t *) config;
00188 
00189   if(!config_struct)
00190     return -EFAULT;
00191 
00192   /* on regarde si la liste est vide */
00193   if(!(*config_struct->syntax_tree))
00194     {
00195       return 0;
00196     }
00197   /* on compte le nombre d'elements */
00198   else
00199     {
00200       /* il y a au moins un element : le premier */
00201       generic_item *curr_block = (*config_struct->syntax_tree);
00202       int nb = 1;
00203 
00204       while((curr_block = curr_block->next) != NULL)
00205         {
00206           nb++;
00207         }
00208 
00209       return nb;
00210     }
00211 }
00212 
00213 /* retrieves a given block from the config file, from its index */
00214 config_item_t config_GetBlockByIndex(config_file_t config, unsigned int block_no)
00215 {
00216   config_struct_t *config_struct = (config_struct_t *) config;
00217   generic_item *curr_block;
00218   unsigned int i;
00219 
00220   if(!config_struct->syntax_tree || !(*config_struct->syntax_tree))
00221     return NULL;
00222 
00223   for(i = 0, curr_block = (*config_struct->syntax_tree);
00224       curr_block != NULL; curr_block = curr_block->next, i++)
00225     {
00226       if(i == block_no)
00227         return (config_item_t) curr_block;
00228     }
00229 
00230   /* not found */
00231   return NULL;
00232 }
00233 
00234 /* Return the name of a block */
00235 char *config_GetBlockName(config_item_t block)
00236 {
00237   generic_item *curr_block = (generic_item *) block;
00238 
00239   if(!curr_block || (curr_block->type != TYPE_BLOCK))
00240     return NULL;
00241 
00242   return curr_block->item.block.block_name;
00243 }
00244 
00245 /* Indicates how many items are defines in a block */
00246 int config_GetNbItems(config_item_t block)
00247 {
00248   generic_item *the_block = (generic_item *) block;
00249 
00250   if(!the_block || (the_block->type != TYPE_BLOCK))
00251     return -1;
00252 
00253   /* on regarde si la liste est vide */
00254   if(!(the_block->item.block.block_content))
00255     {
00256       return 0;
00257     }
00258   /* on compte le nombre d'elements */
00259   else
00260     {
00261       /* il y a au moins un element : le premier */
00262       generic_item *curr_block = the_block->item.block.block_content;
00263       int nb = 1;
00264 
00265       while((curr_block = curr_block->next) != NULL)
00266         {
00267           nb++;
00268         }
00269 
00270       return nb;
00271     }
00272 
00273 }
00274 
00275 /* retrieves a given block from the config file, from its index */
00276 config_item_t config_GetItemByIndex(config_item_t block, unsigned int item_no)
00277 {
00278   generic_item *the_block = (generic_item *) block;
00279   generic_item *curr_item;
00280   unsigned int i;
00281 
00282   if(!the_block || (the_block->type != TYPE_BLOCK))
00283     return NULL;
00284 
00285   for(i = 0, curr_item = the_block->item.block.block_content;
00286       curr_item != NULL; curr_item = curr_item->next, i++)
00287     {
00288       if(i == item_no)
00289         return (config_item_t) curr_item;
00290     }
00291 
00292   /* not found */
00293   return NULL;
00294 }
00295 
00296 /* indicates which type of item it is */
00297 config_item_type config_ItemType(config_item_t item)
00298 {
00299   generic_item *the_item = (generic_item *) item;
00300 
00301   if(the_item->type == TYPE_BLOCK)
00302     return CONFIG_ITEM_BLOCK;
00303   else if(the_item->type == TYPE_AFFECT)
00304     return CONFIG_ITEM_VAR;
00305   else
00306     return 0;
00307 }
00308 
00309 /* Retrieves a key-value peer from a CONFIG_ITEM_VAR */
00310 int config_GetKeyValue(config_item_t item, char **var_name, char **var_value)
00311 {
00312   generic_item *var = (generic_item *) item;
00313 
00314   if(!var || (var->type != TYPE_AFFECT))
00315     return -1;
00316 
00317   *var_name = var->item.affect.varname;
00318   *var_value = var->item.affect.varvalue;
00319 
00320   return 0;
00321 }
00322 
00323 /* get an item from a list with the given name */
00324 static generic_item *GetItemFromList(generic_item * list, const char *name)
00325 {
00326   generic_item *curr;
00327 
00328   if(!list)
00329     return NULL;
00330 
00331   for(curr = list; curr != NULL; curr = curr->next)
00332     {
00333       if((curr->type == TYPE_BLOCK)
00334          && !STRNCMP(curr->item.block.block_name, name, MAXSTRLEN))
00335         return curr;
00336       if((curr->type == TYPE_AFFECT)
00337          && !STRNCMP(curr->item.affect.varname, name, MAXSTRLEN))
00338         return curr;
00339     }
00340   /* not found */
00341   return NULL;
00342 
00343 }
00344 
00349 static int CheckDuplicateEntry(generic_item * list, const char *name)
00350 {
00351     generic_item *curr;
00352     unsigned int found=0;
00353 
00354     if(!list)
00355         return 0;
00356 
00357     for(curr = list; curr != NULL; curr = curr->next)
00358     {
00359       if((curr->type == TYPE_BLOCK)
00360          && !STRNCMP(curr->item.block.block_name, name, MAXSTRLEN))
00361         found++;
00362       if((curr->type == TYPE_AFFECT)
00363          && !STRNCMP(curr->item.affect.varname, name, MAXSTRLEN))
00364         found++;
00365         if ( found > 1 )
00366             break;
00367     }
00368   return ( found > 1 );
00369 }
00370 
00371 /* Returns the block with the specified name. This name can be "BLOCK::SUBBLOCK::SUBBLOCK" */
00372 config_item_t internal_FindItemByName(config_file_t config, const char *name, int * unique)
00373 {
00374   config_struct_t *config_struct = (config_struct_t *) config;
00375   generic_item *block;
00376   generic_item *list;
00377   char *separ;
00378   char *current;
00379   char tmp_name[MAXSTRLEN];
00380 
00381   /* connot be found if empty */
00382   if(!config_struct->syntax_tree || !(*config_struct->syntax_tree))
00383     return NULL;
00384 
00385   list = *config_struct->syntax_tree;
00386 
00387   strncpy(tmp_name, name, MAXSTRLEN);
00388   tmp_name[MAXSTRLEN - 1] = '\0';
00389   current = tmp_name;
00390 
00391   while(current)
00392     {
00393       /* first, split the name into BLOCK/SUBBLOC/SUBBLOC */
00394       separ = strstr(current, "::");
00395 
00396       /* it is a whole name */
00397       if(!separ)
00398       {
00399         if (unique) {
00400                 *unique = !CheckDuplicateEntry(list, current);
00401                 sprintf(extern_errormsg, "Configuration item '%s' is not unique", name);
00402         }
00403         return (config_item_t) GetItemFromList(list, current);
00404       }
00405       else
00406         {
00407           /* split the name */
00408           *separ = '\0';
00409 
00410           if((separ - tmp_name) < MAXSTRLEN - 2)
00411             separ += 2;
00412           else
00413             return NULL;        /* overflow */
00414 
00415           block = GetItemFromList(list, current);
00416 
00417           /* not found or not a block ? */
00418           if(!block || (block->type != TYPE_BLOCK))
00419             return NULL;
00420 
00421           list = block->item.block.block_content;
00422 
00423           /* "::" was found, must have something after */
00424           current = separ;
00425         }
00426     }
00427 
00428   /* not found */
00429   return NULL;
00430 }
00431 
00432 config_item_t config_FindItemByName(config_file_t config, const char *name)
00433 {
00434         return internal_FindItemByName(config, name, NULL);
00435 }
00436 
00437 config_item_t config_FindItemByName_CheckUnique(config_file_t config, const char *name, int * unique)
00438 {
00439         return internal_FindItemByName(config, name, unique);
00440 }
00441 
00442 /* Directly returns the value of the key with the specified name.
00443  * This name can be "BLOCK::SUBBLOCK::SUBBLOCK::VARNAME"
00444  */
00445 char *config_FindKeyValueByName(config_file_t config, const char *key_name)
00446 {
00447   generic_item *var;
00448 
00449   var = (generic_item *) config_FindItemByName(config, key_name);
00450 
00451   if(!var || (var->type != TYPE_AFFECT))
00452     return NULL;
00453   else
00454     return var->item.affect.varvalue;
00455 
00456 }
00457 
00458 /* Returns a block or variable with the specified name from the given block" */
00459 config_item_t config_GetItemByName(config_item_t block, const char *name)
00460 {
00461   generic_item *curr_block = (generic_item *) block;
00462   generic_item *list;
00463   char *separ;
00464   char *current;
00465   char tmp_name[MAXSTRLEN];
00466 
00467   /* cannot be found if empty or non block */
00468   if(!curr_block || (curr_block->type != TYPE_BLOCK))
00469     return NULL;
00470 
00471   list = curr_block->item.block.block_content;
00472 
00473   strncpy(tmp_name, name, MAXSTRLEN);
00474   tmp_name[MAXSTRLEN - 1] = '\0';
00475   current = tmp_name;
00476 
00477   while(current)
00478     {
00479       /* first, split the name into BLOCK/SUBBLOC/SUBBLOC */
00480       separ = strstr(current, "::");
00481 
00482       /* it is a whole name */
00483       if(!separ)
00484         return (config_item_t) GetItemFromList(list, current);
00485       else
00486         {
00487           /* split the name */
00488           *separ = '\0';
00489 
00490           if((separ - tmp_name) < MAXSTRLEN - 2)
00491             separ += 2;
00492           else
00493             return NULL;        /* overflow */
00494 
00495           curr_block = GetItemFromList(list, current);
00496 
00497           /* not found or not a block ? */
00498           if(!curr_block || (curr_block->type != TYPE_BLOCK))
00499             return NULL;
00500 
00501           list = curr_block->item.block.block_content;
00502 
00503           /* "::" was found, must have something after */
00504           current = separ;
00505         }
00506     }
00507 
00508   /* not found */
00509   return NULL;
00510 
00511 }
00512 
00513 /* Directly returns the value of the key with the specified name
00514  * relative to the given block.
00515  */
00516 char *config_GetKeyValueByName(config_item_t block, const char *key_name)
00517 {
00518   generic_item *var;
00519 
00520   var = (generic_item *) config_GetItemByName(block, key_name);
00521 
00522   if(!var || (var->type != TYPE_AFFECT))
00523     return NULL;
00524   else
00525     return var->item.affect.varvalue;
00526 
00527 }