[dhcp-agent-commits] dhcp-agent/src dhcp-conf.c,NONE,1.1 dhcp-conf.h,NONE,1.1 Makefile.am,1.9,1.10 d
Status: Alpha
Brought to you by:
actmodern
Update of /cvsroot/dhcp-agent/dhcp-agent/src In directory sc8-pr-cvs1:/tmp/cvs-serv28336/src Modified Files: Makefile.am dhcp-client.c dhcp-libutil.h dhcp-parser.c dhcp-parser.h dhcp-util.c Added Files: dhcp-conf.c dhcp-conf.h Log Message: new recursive configuration parser --- NEW FILE: dhcp-conf.c --- /* $Header: /cvsroot/dhcp-agent/dhcp-agent/src/dhcp-conf.c,v 1.1 2002/12/15 00:22:02 actmodern Exp $ * * Copyright 2002 Thamer Alharbash <tm...@wh...> * * 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-parser.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_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); /* argument_compiler_dispatch table -- these are indexed by the types in dhcp-conf.h */ argument_compiler_t argument_compilers[] = { compile_arg_identifier, compile_arg_address, compile_arg_assignment, compile_arg_boolean, compile_arg_string, compile_arg_string_list, compile_arg_group, }; /* * * * * * * * * * * * * * * * constructors/destructors * * * * * * * * * * * * * * * */ conf_t *conf_create(command_t **commands, const char *filename) { conf_t *conf; conf = xmalloc(sizeof(conf_t)); conf->parser = create_parser(filename); if(conf->parser == NULL) { ERROR_MESSAGE("could not open configuration file: %s", filename); xfree(conf); return NULL; } conf->filename = xstrdup(filename); conf->commands = commands; conf->directives = NULL; return conf; } void conf_destroy(conf_t *conf) { return; /* TODO: write cleanup code. */ } static directive_t *directive_create(void) { directive_t *directive; directive = xcalloc(sizeof(directive_t)); 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) { arg_type_destroy(NULL); return; } static void directive_destroy_l(void *p) { directive_destroy(p); } /* * * * * * * * * * * * * 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; atom_t atom; const char **ptr; int i; atom = get_next_atom_ignore_newlines(conf->parser); /* identifiers are strings. so check for that type and do * a comparison against our data. */ if(atom != PARSER_ATOM_STRING) return NULL; string = parser_get_data(conf->parser); 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++; } return identifier_symbol; } static void *compile_arg_address(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols) { ip_addr_t *ip_addr = NULL; eth_addr_t *eth_addr = NULL; const char *string; atom_t atom; atom = get_next_atom_ignore_newlines(conf->parser); if(atom != PARSER_ATOM_STRING) return NULL; string = parser_get_data(conf->parser); if(strchr(string, '.') != NULL) { /* ip addr. */ ip_addr = string_ip_to_ip_addr(string); return ip_addr; } else if(strchr(string, ':') != NULL) { /* eth addr. */ eth_addr = string_eth_addr_to_eth_addr(string); return eth_addr; } else { return NULL; } } static void *compile_arg_assignment(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols) { uint8_t *placeholder; atom_t atom; /* 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. */ atom = get_next_atom_ignore_newlines(conf->parser); if(atom != PARSER_ATOM_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; atom_t atom; const char *string; atom = get_next_atom_ignore_newlines(conf->parser); if(atom != PARSER_ATOM_STRING) return NULL; string = parser_get_data(conf->parser); 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 { 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; atom_t atom; atom = get_next_atom_ignore_newlines(conf->parser); if(atom != PARSER_ATOM_STRING) return NULL; string = parser_get_data(conf->parser); 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 = NULL; char *string; atom_t atom; /* 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) { purge_list(string_list, NULL); return NULL; } string_list = add_to_end_of_list(string_list, string); /* now peek for a comma, if available keep going. */ atom = parser_peek_next_atom(conf->parser); if(atom == PARSER_ATOM_COMMA) { atom = get_next_atom_ignore_newlines(conf->parser); } else { break; } } return string_list; } /* compile the command. follow the command argument types and store them. */ static directive_t *compile_command(conf_t *conf, command_t *command) { directive_t *directive; void *args; atom_t atom; 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) { directive_destroy(directive); return NULL; } arg_type = arg_type_create(command->argument_types[i]); directive->argument_types = add_to_end_of_list(directive->argument_types, arg_type); directive->arguments = add_to_end_of_list(directive->arguments, args); } /* we're done. now we need a semicolon to end this directive. */ atom = get_next_atom_ignore_newlines(conf->parser); if(atom != PARSER_ATOM_SEMICOLON) { directive_destroy(directive); return NULL; } return directive; } static directive_t *compile_directive(conf_t *conf) { const char *token_string; directive_t *directive; command_t *command; int i; /* we expect the string is already read from the parser * before we're called. */ token_string = parser_get_data(conf->parser); /* 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) continue; /* try to compile any other matching command: this lets us set the same command name with different arguments. */ 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) { atom_t atom; directive_t *directive; list_t *directive_list = NULL; /* 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. */ atom = get_next_atom_ignore_newlines(conf->parser); if(atom != PARSER_ATOM_BLOCK_OPEN) return NULL; /* FIXME: currently empty groups are going to return the same error as a missing brace. */ while(1) { atom = get_next_atom_ignore_newlines(conf->parser); if(atom == PARSER_ATOM_BLOCK_CLOSE) return directive_list; /* we should always start with a string. */ if(atom != PARSER_ATOM_STRING) goto error; directive = compile_directive(conf); if(directive == NULL) goto error; directive_list = add_to_end_of_list(directive_list, directive); } error: purge_list(directive_list, directive_destroy_l); return NULL; } /* compile the file into a list of directives. */ int conf_compile_directives(conf_t *conf) { atom_t atom; directive_t *directive; while(1) { atom = get_next_atom_ignore_newlines(conf->parser); if(atom == PARSER_ATOM_EOF) /* end of file */ return CONF_OK; /* we should always start with a string. */ if(atom != PARSER_ATOM_STRING) return CONF_ERROR; directive = compile_directive(conf); if(directive == NULL) return CONF_ERROR; /* if we got a string it should match or error. */ conf->directives = add_to_end_of_list(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; } --- NEW FILE: dhcp-conf.h --- /* $Header: /cvsroot/dhcp-agent/dhcp-agent/src/dhcp-conf.h,v 1.1 2002/12/15 00:22:02 actmodern Exp $ * * Copyright 2002 Thamer Alharbash * * 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. */ #ifndef DHCP_CONF_H #define DHCP_CONF_H /* native types. */ typedef uint32_t command_code_t; typedef uint32_t arg_len_t; typedef uint32_t arg_type_t; typedef uint32_t arg_symbol_t; /* compiled directive. */ typedef struct { command_code_t command_code; /* the command code. */ list_t *argument_types; /* type of argument: need this to free up arguments later. */ list_t *arguments; /* argument data. */ } directive_t; /* command syntax object. */ typedef struct { const command_code_t command_code; const char *command_name; const arg_len_t argument_len; const char ***argument_strings; const arg_type_t *argument_types; const arg_symbol_t **argument_symbols; } command_t; /* conf object. */ typedef struct { char *filename; parser_t *parser; command_t **commands; /* list of permissible commands. */ list_t *directives; } conf_t; /* typedef of configuration drivers. */ typedef void *(*argument_compiler_t)(conf_t *conf, const char **argument_strings, const arg_symbol_t *argument_symbols); /* conf return types. */ enum conf_return_types { CONF_OK = 0, CONF_ERROR }; /* conf argument types -- these index the argument drivers. */ enum conf_argument_type { CONF_IDENTIFIER = 0, CONF_ADDRESS, CONF_ASSIGNMENT, CONF_BOOLEAN, CONF_STRING, CONF_STRING_LIST, CONF_GROUP }; /* prototypes. */ extern conf_t *conf_create(command_t **commands, const char *filename); extern void conf_destroy(conf_t *conf); extern int conf_compile_directives(conf_t *conf); extern list_t *conf_get_directives(conf_t *conf); #endif /* DHCP_CONF_H */ Index: Makefile.am =================================================================== RCS file: /cvsroot/dhcp-agent/dhcp-agent/src/Makefile.am,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** Makefile.am 24 Nov 2002 01:10:35 -0000 1.9 --- Makefile.am 15 Dec 2002 00:22:02 -0000 1.10 *************** *** 16,20 **** dhcp-libutil.h dhcp-local.h dhcp-options-strings.h dhcp-print.h dhcp-cache-entry.h \ dhcp-client-conf.h dhcp-convert.h dhcp-globconf.h dhcp-librawnet.h dhcp-limits.h dhcp-log.h \ ! dhcp-parser.h dhcp-sysconf.h --- 16,20 ---- dhcp-libutil.h dhcp-local.h dhcp-options-strings.h dhcp-print.h dhcp-cache-entry.h \ dhcp-client-conf.h dhcp-convert.h dhcp-globconf.h dhcp-librawnet.h dhcp-limits.h dhcp-log.h \ ! dhcp-parser.h dhcp-sysconf.h dhcp-conf.h *************** *** 60,64 **** dhcp-globconf.c ! dhcp_client_LDADD = -ldhcputil -lefence dhcp_sniff_LDADD = -ldhcputil libdhcputil_la_LIBADD = @PCAP_LIB@ @DNET_LIB@ --- 60,65 ---- dhcp-globconf.c ! dhcp_client_LDADD = -ldhcputil dhcp_sniff_LDADD = -ldhcputil + libdhcputil_la_LIBADD = @PCAP_LIB@ @DNET_LIB@ Index: dhcp-client.c =================================================================== RCS file: /cvsroot/dhcp-agent/dhcp-agent/src/dhcp-client.c,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** dhcp-client.c 24 Nov 2002 01:10:00 -0000 1.7 --- dhcp-client.c 15 Dec 2002 00:22:02 -0000 1.8 *************** *** 97,101 **** #endif /* HAVE_PROGNAME */ ! /* local vars for dhcpclient. */ static char *interface = NULL; /* the interface we're concerned with. */ static unsigned char want_background = 1; /* whether we should go into the background. */ --- 97,101 ---- #endif /* HAVE_PROGNAME */ ! /* local vars for dhcp-client. */ static char *interface = NULL; /* the interface we're concerned with. */ static unsigned char want_background = 1; /* whether we should go into the background. */ *************** *** 394,398 **** if(client_process_exists(interface)) { ! FATAL_MESSAGE("dhcpclient already exists on interface %s use -k to kill it", interface); } --- 394,398 ---- if(client_process_exists(interface)) { ! FATAL_MESSAGE("%s already exists on interface %s use -k to kill it", getprogname(), interface); } Index: dhcp-libutil.h =================================================================== RCS file: /cvsroot/dhcp-agent/dhcp-agent/src/dhcp-libutil.h,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** dhcp-libutil.h 24 Nov 2002 03:06:47 -0000 1.9 --- dhcp-libutil.h 15 Dec 2002 00:22:02 -0000 1.10 *************** *** 130,134 **** extern char *splice_many_strings(int num, char *s, ...); extern int string_matches(const char *s1, const char *s2); ! extern int hex_string_to_value(char *string, unsigned char *dst); extern int is_string(const char *string, int len); extern char *xstrdup(const char *string); --- 130,134 ---- extern char *splice_many_strings(int num, char *s, ...); extern int string_matches(const char *s1, const char *s2); ! extern int hex_string_to_value(const char *string, unsigned char *dst); extern int is_string(const char *string, int len); extern char *xstrdup(const char *string); *************** *** 142,145 **** --- 142,147 ---- extern const char *getprogname(void); extern int resolv(char *address, uint32_t *addr); + extern ip_addr_t *string_ip_to_ip_addr(const char *string_ip); + extern eth_addr_t *string_eth_addr_to_eth_addr(const char *eth_ip); extern int is_seven_bit_clean(const char *data, int len); Index: dhcp-parser.c =================================================================== RCS file: /cvsroot/dhcp-agent/dhcp-agent/src/dhcp-parser.c,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** dhcp-parser.c 24 Nov 2002 20:54:31 -0000 1.4 --- dhcp-parser.c 15 Dec 2002 00:22:02 -0000 1.5 *************** *** 31,35 **** /* these characters are special. we only allow them in a quoted string. */ ! static char special_characters[] = ";{}="; /* forward declaration of parsers. */ --- 31,35 ---- /* these characters are special. we only allow them in a quoted string. */ ! static char special_characters[] = ",;{}="; /* forward declaration of parsers. */ *************** *** 49,61 **** parser_input_t parsers[] = { ! { ';', parse_semicolon, }, ! { '\\', parse_gobble_line }, ! { '#' , parse_comment }, ! { '\"', parse_quoted_string }, ! { '\n', parse_newline }, ! { '=', parse_assignment }, ! { '{' , parse_block_open }, ! { '}', parse_block_close }, ! { ',', parse_comma }, }; --- 49,62 ---- parser_input_t parsers[] = { ! /* char val */ /* routine. */ /* peek val. */ ! { ';', parse_semicolon, PARSER_ATOM_SEMICOLON }, ! { '\\', parse_gobble_line, PARSER_ATOM_NEWLINE}, ! { '#' , parse_comment, PARSER_ATOM_NEWLINE }, ! { '\"', parse_quoted_string, PARSER_ATOM_STRING }, ! { '\n', parse_newline, PARSER_ATOM_NEWLINE }, ! { '=', parse_assignment, PARSER_ATOM_ASSIGNMENT }, ! { '{' , parse_block_open, PARSER_ATOM_BLOCK_OPEN }, ! { '}', parse_block_close, PARSER_ATOM_BLOCK_CLOSE }, ! { ',', parse_comma, PARSER_ATOM_COMMA, }, }; *************** *** 240,245 **** } ! /* get the next atom. */ ! atom_t get_next_atom(parser_t *input) { int c, c2; --- 241,245 ---- } ! static atom_t parser_get_next_atom_proc(parser_t *input, uint8_t peeking) { int c, c2; *************** *** 279,286 **** for(i = 0;i < NELMS(parsers); i++) { ! if(parsers[i].character == c) ! return parsers[i].do_parse(input); } /* if we have an alphanumeric it's a string. read it in. */ --- 279,301 ---- for(i = 0;i < NELMS(parsers); i++) { ! if(parsers[i].character == c) { ! ! if(peeking) { ! ! /* if we're just peeking ungetc before we return peek value. */ ! ungetc(c, input->fp); ! return parsers[i].peek_val; ! ! } ! ! return parsers[i].do_parse(input); ! } } + /* otherwise we default to trying a string. */ + + if(peeking) + return PARSER_ATOM_STRING; /* or at least we assume it's a string. */ + /* if we have an alphanumeric it's a string. read it in. */ *************** *** 294,298 **** return PARSER_ATOM_ERROR; } ! } } --- 309,333 ---- return PARSER_ATOM_ERROR; } ! } ! } ! ! /* get the next atom. */ ! atom_t get_next_atom(parser_t *input) ! { ! return(parser_get_next_atom_proc(input, 0)); ! } ! ! atom_t parser_peek_next_atom(parser_t *input) ! { ! return(parser_get_next_atom_proc(input, 1)); ! } ! ! atom_t get_next_atom_ignore_newlines(parser_t *input) ! { ! atom_t atom; ! ! while((atom = get_next_atom(input)) == PARSER_ATOM_NEWLINE); ! ! return atom; } Index: dhcp-parser.h =================================================================== RCS file: /cvsroot/dhcp-agent/dhcp-agent/src/dhcp-parser.h,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** dhcp-parser.h 24 Nov 2002 20:54:31 -0000 1.4 --- dhcp-parser.h 15 Dec 2002 00:22:02 -0000 1.5 *************** *** 36,46 **** char character; parse_input do_parse; } parser_input_t; - extern void destroy_parser(parser_t *parser); extern parser_t *create_parser(const char *filename); extern atom_t get_next_atom(parser_t *input); extern const char *parser_get_data(parser_t *input); extern int parser_get_line_no(parser_t *parser); /* parser return values. */ --- 36,52 ---- char character; parse_input do_parse; + atom_t peek_val; } parser_input_t; extern parser_t *create_parser(const char *filename); + extern void destroy_parser(parser_t *parser); + extern atom_t get_next_atom(parser_t *input); + extern atom_t get_next_atom_ignore_newlines(parser_t *input); + extern atom_t parser_peek_next_atom(parser_t *input); + extern const char *parser_get_data(parser_t *input); extern int parser_get_line_no(parser_t *parser); + /* parser return values. */ Index: dhcp-util.c =================================================================== RCS file: /cvsroot/dhcp-agent/dhcp-agent/src/dhcp-util.c,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** dhcp-util.c 16 Nov 2002 00:23:44 -0000 1.7 --- dhcp-util.c 15 Dec 2002 00:22:02 -0000 1.8 *************** *** 335,339 **** /* parse hex string (0x:0x...0x) to value. (not fun to write) */ ! int hex_string_to_value(char *string, unsigned char *dst) { char *sep, *ptr; --- 335,339 ---- /* parse hex string (0x:0x...0x) to value. (not fun to write) */ ! int hex_string_to_value(const char *string, unsigned char *dst) { char *sep, *ptr; *************** *** 492,494 **** --- 492,527 ---- interactive = interactive_arg; return; + } + + /* convert a string ip to ip_addr_t */ + ip_addr_t *string_ip_to_ip_addr(const char *string_ip) + { + ip_addr_t *ip; + + ip = xmalloc(sizeof(ip_addr_t)); + + /* FIXME: use inet_aton if available */ + *(ip) = inet_addr(string_ip); + + if(*(ip) == INADDR_NONE) { + xfree(ip); + return NULL; + } + + return ip; + } + + /* convert a string ip to ip_addr_t */ + eth_addr_t *string_eth_addr_to_eth_addr(const char *eth_addr) + { + eth_addr_t *eth; + + eth = xmalloc(sizeof(eth_addr_t)); + + if(hex_string_to_value(eth_addr, eth->data)) { + xfree(eth); + return NULL; + } + + return eth; } |