📄 dhcp-conf.c
字号:
/* $Header: /cvsroot/dhcp-agent/dhcp-agent/src/dhcp-conf.c,v 1.12 2003/07/13 04:52:48 actmodern Exp $ * * Copyright 2002 Thamer Alharbash <tmh@whitefang.com> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. The names of the authors may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Configuration file parser. * * Our parsing is more complicated than what the varfile does. * Here we accept an array of structures which tell us what to * expect. We build directive lists from these structures and * pass them up. * */#define MODULE_NAME "dhcp-conf.c"#include "dhcp-local.h"#include "dhcp-libutil.h"#include "dhcp-tokenizer.h"#include "dhcp-conf.h"/* forward declaration of argument drivers. */static void *compile_arg_identifier(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols);static void *compile_arg_ip_address(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols);static void *compile_arg_hw_address(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols);static void *compile_arg_assignment(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols);static void *compile_arg_boolean(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols);static void *compile_arg_string(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols);static void *compile_arg_string_list(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols);static void *compile_arg_group(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols);/* forward declaration of argument destroyers *//* we only need these two. */static void destroy_arg_string_list(void *data);static void destroy_arg_group(void *data);/* argument_compiler_dispatch table -- these are indexed by the types in dhcp-conf.h */argument_compiler_t argument_compilers[] = { compile_arg_identifier, compile_arg_ip_address, compile_arg_hw_address, compile_arg_assignment, compile_arg_boolean, compile_arg_string, compile_arg_string_list, compile_arg_group,};/* argument destroyer dispatch table -- these are indexed by the types in dhcp-conf.h */argument_destroy_t argument_destroyers[] = { xfree, xfree, xfree, xfree, xfree, xfree, destroy_arg_string_list, destroy_arg_group,};/* * * * * * * * * * * * * * * * constructors/destructors * * * * * * * * * * * * * * * */static directive_t *directive_create(void){ directive_t *directive; directive = xcalloc(sizeof(directive_t)); directive->argument_types = list_create(); directive->arguments = list_create(); return directive;}static arg_type_t *arg_type_create(arg_type_t arg){ arg_type_t *arg_type = xmalloc(sizeof(arg_type_t)); *arg_type = arg; return arg_type;}static void arg_type_destroy(arg_type_t *arg){ xfree(arg); return;}static void directive_destroy(directive_t *directive){ list_t *arg_ptr; list_t *type_ptr; arg_type_t *arg_type; void *arg_data; arg_ptr = directive->arguments; type_ptr = directive->argument_types; /* iterate through the list of arguments. * and call the destroy routine per argument. */ list_rewind(type_ptr); list_rewind(arg_ptr); while((arg_type = list_next(type_ptr)) != NULL) { /* each arg_type tells us which destructor to call on the * argument data. */ arg_data = list_next(arg_ptr); /* we're automatically rewound after any removal. */ /* this won't free up the datums themselves. */ list_remove_by_datum(type_ptr, arg_type); list_remove_by_datum(arg_ptr, arg_data); /* now destroy ourselves. */ argument_destroyers[*arg_type](arg_data); arg_type_destroy((arg_type_t *)arg_type); } list_destroy(type_ptr, NULL); list_destroy(arg_ptr, NULL); return;}static void directive_destroy_l(void *p){ directive_destroy(p);}conf_t *conf_create(const command_t **commands, const char *filename){ conf_t *conf; conf = xmalloc(sizeof(conf_t)); conf->tokenizer = tokenizer_create(filename); if(conf->tokenizer == NULL) { ERROR_MESSAGE("could not open configuration file: %s", filename); xfree(conf); return NULL; } conf->filename = xstrdup(filename); conf->commands = commands; conf->directives = list_create(); return conf;}void conf_destroy(conf_t *conf){ xfree(conf->filename); tokenizer_destroy(conf->tokenizer); list_destroy(conf->directives, directive_destroy_l); xfree(conf); return;}/* * * * * * * * * * * * * argument compilers * * * * * * * * * * * * */static void *compile_arg_identifier(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols){ arg_symbol_t *identifier_symbol = NULL; const char *string; token_t token; const char **ptr; int i; token = tokenizer_get_next_token_ignore_newlines(conf->tokenizer); /* identifiers are strings. so check for that type and do * a comparison against our data. */ if(token != TOKEN_STRING) return NULL; string = tokenizer_get_data(conf->tokenizer); i = 0; for(ptr = argument_strings; *ptr != NULL; ptr++) { if(!strcmp(string, *ptr)) { identifier_symbol = xmalloc(sizeof(arg_symbol_t)); *identifier_symbol = argument_symbols[i]; break; } i++; } if(identifier_symbol == NULL) ERROR_MESSAGE("unknown identifier: %s\n", string); return identifier_symbol;}static void *compile_arg_ip_address(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols){ ip_addr_t *ip_addr = NULL; const char *string; token_t token; token = tokenizer_get_next_token_ignore_newlines(conf->tokenizer); if(token != TOKEN_STRING) return NULL; string = tokenizer_get_data(conf->tokenizer); ip_addr = string_ip_to_ip_addr(string); return ip_addr;}static void *compile_arg_hw_address(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols){ eth_addr_t *eth_addr = NULL; const char *string; token_t token; token = tokenizer_get_next_token_ignore_newlines(conf->tokenizer); if(token != TOKEN_STRING) return NULL; string = tokenizer_get_data(conf->tokenizer); eth_addr = string_eth_addr_to_eth_addr(string); return eth_addr;}static void *compile_arg_assignment(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols){ uint8_t *placeholder; token_t token; /* this is fairly easy check if the atom is an assignment and just return an empty placeholder. * we really don't care what kind of assignment it is since we only have one. in the future * we may create more. */ token = tokenizer_get_next_token_ignore_newlines(conf->tokenizer); if(token != TOKEN_ASSIGNMENT) return NULL; placeholder = xmalloc(sizeof(uint8_t)); *placeholder = 1; return placeholder;}static void *compile_arg_boolean(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols){ uint8_t *bool_val; token_t token; const char *string; token = tokenizer_get_next_token_ignore_newlines(conf->tokenizer); if(token != TOKEN_STRING) return NULL; string = tokenizer_get_data(conf->tokenizer); if(!strcmp(string, "yes")) { bool_val = xmalloc(sizeof(uint8_t)); *bool_val = 1; } else if(!strcmp(string, "no")) { bool_val = xmalloc(sizeof(uint8_t)); *bool_val = 0; } else { ERROR_MESSAGE("%s is not a boolean value as expected. legal boolean values are \"yes\" and \"no\""); bool_val = NULL; } return bool_val;}static void *compile_arg_string(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols){ char *string_arg; const char *string; token_t token; token = tokenizer_get_next_token_ignore_newlines(conf->tokenizer); if(token != TOKEN_STRING) return NULL; string = tokenizer_get_data(conf->tokenizer); string_arg = xstrdup(string); return string_arg;}static void *compile_arg_string_list(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols){ list_t *string_list; char *string; token_t token; string_list = list_create(); /* ask compile_arg_string_list to do the work for us. * we peek for commas but that's about it. */ while(1) { /* next one should be string or it's a parser error. */ string = compile_arg_string(conf, argument_strings, argument_symbols); if(string == NULL) { ERROR_MESSAGE("no string list found at %d\n", conf_get_line_no(conf)); list_destroy(string_list, xfree); return NULL; } list_add_to_end(string_list, string); /* now peek for a comma, if available keep going. */ token = tokenizer_peek_next_token_ignore_newlines(conf->tokenizer); if(token == TOKEN_COMMA) { token = tokenizer_get_next_token_ignore_newlines(conf->tokenizer); } else { break; } } return string_list;}/* compile the command. follow the command argument types and store them. */static directive_t *compile_command(conf_t *conf, const command_t *command){ directive_t *directive; void *args; token_t token; int i; arg_type_t *arg_type; /* create a new directive. */ directive = directive_create(); /* set the command code. */ directive->command_code = command->command_code; for(i = 0;i < command->argument_len; i++) { /* now try to compile the arguments based on the type. */ args = argument_compilers[command->argument_types[i]](conf, command->argument_strings[i], command->argument_symbols[i]); if(args == NULL) { ERROR_MESSAGE("unable to compile directive at line %d\n", conf_get_line_no(conf)); directive_destroy(directive); return NULL; } arg_type = arg_type_create(command->argument_types[i]); list_add_to_end(directive->argument_types, arg_type); list_add_to_end(directive->arguments, args); } /* we're done. now we need a semicolon to end this directive. */ token = tokenizer_get_next_token_ignore_newlines(conf->tokenizer); if(token != TOKEN_SEMICOLON) { ERROR_MESSAGE("semi colon terminator not present where expected at line: %d\n", conf_get_line_no(conf)); directive_destroy(directive); return NULL; } return directive;}static directive_t *compile_directive(conf_t *conf){ const char *token_string; directive_t *directive; const command_t *command; int i; /* we expect the string is already read from the parser * before we're called. */ token_string = tokenizer_get_data(conf->tokenizer); /* now do a comparison and find our command_t. */ for(i = 0;;i++) { command = conf->commands[i]; if(command == NULL) break; if(!strcmp(command->command_name, token_string)) { /* we have a match. try to parse the rest so we have a new command_t filled out. */ directive = compile_command(conf, command); if(command == NULL) break; return directive; } } /* we didn't match a command name. */ return NULL;}/* a group is just a grouping of additional commands. we create a directive list and pass it up.*/static void *compile_arg_group(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols){ token_t token; directive_t *directive; list_t *directive_list; directive_list = list_create(); /* if we have a brace, go ahead and read in a command list. by compiling each command under it * as per the commands allowed in the group. */ token = tokenizer_get_next_token_ignore_newlines(conf->tokenizer); if(token != TOKEN_BLOCK_OPEN) return NULL; /* FIXME: currently empty groups are going to return the same error as a missing brace. */ while(1) { token = tokenizer_get_next_token_ignore_newlines(conf->tokenizer); if(token == TOKEN_BLOCK_CLOSE) return directive_list; /* we should always start with a string. */ if(token != TOKEN_STRING) goto error; directive = compile_directive(conf); if(directive == NULL) goto error; list_add_to_end(directive_list, directive); } error: list_destroy(directive_list, directive_destroy_l); return NULL;}/* * * * * * * * * * * * * * * * * * argument destruction routines * * * * * * * * * * * * * * * * * *//* most are just freed with xfree. these two are special because * they contain lists. */static void destroy_arg_string_list(void *data){ list_t *list = data; list_destroy(list, xfree); /* just free up a list of strings. */}static void destroy_arg_group(void *data){ list_t *list = data; list_destroy(list, directive_destroy_l); /* free up a list of directives. */ return;}/* compile the file into a list of directives. */int conf_compile_directives(conf_t *conf){ token_t token; directive_t *directive; while(1) { token = tokenizer_get_next_token_ignore_newlines(conf->tokenizer); if(token == TOKEN_EOF) /* end of file */ return CONF_OK; /* we should always start with a string. */ if(token != TOKEN_STRING) return CONF_ERROR; directive = compile_directive(conf); if(directive == NULL) return CONF_ERROR; /* if we got a string it should match or error. */ list_add_to_end(conf->directives, directive); } /* we should never get here. */ FATAL_MESSAGE("i don't know why i'm here. this is a bug. report me."); exit(1); /* do away with compiler warning. */}list_t *conf_get_directives(conf_t *conf){ return conf->directives;}int conf_get_line_no(conf_t *conf){ return tokenizer_get_line_no(conf->tokenizer);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -