#include #include #include #include #include #include #include #include #include #include #include #include #include #include "snet.h" #include "nefu.h" #define SPACECHARS " ,\t" #define BUF_BLOCK 512 #define PARSE_MACHINES 0 #define PARSE_DEPENDENCY 1 #define PARSE_RCODES 2 #define PARSE_TESTS 3 #define PARSE_TEST_ARGS 4 struct machine *m_list; struct machine *m; struct rcode *r; char *parse_fname = "-"; char *port; char *e; int argc; int match; int errs = 0; int nefu_lineno = 0; int is_word_char( char ); char *word_end( char * ); struct rcode *get_rcode( char ** ); struct machine* get_machine( char ** ); char* skip_ws( char * ); void parse_error( char *, char * ); void depend( struct machine *m, struct machine *dependency ) { struct test *t; struct test *dep; /* have we been previously defined, if so, is it the same? */ if ( m->m_defined != 0 ) { if ( m->m_parent != dependency ) { fprintf( stderr, "can't redefine %s dependency from line %d\n", m->m_name, m->m_defined ); } return; } /* can't be our own dependency */ if ( m == dependency ) { fprintf( stderr, "%s can't be it's own dependency\n", m->m_name ); return; } m->m_defined = nefu_lineno; m->m_parent = dependency; t = m->m_test; /* insert a root node */ if ( dependency == NULL ) { t->t_peer = root_nodes; t->t_prev = NULL; root_nodes = t; if ( t->t_peer != NULL ) { t->t_peer->t_prev = t; } return; } dep = dependency->m_test; t->t_parent = dep; if (( dep->t_child == NULL ) || ( dep->t_child->t_machine != dep->t_machine )) { /* dependency only has ping */ t->t_peer = dep->t_child; dep->t_child = t; t->t_prev = NULL; if ( t->t_peer != NULL ) { t->t_peer->t_prev = t; } } else { /* place dep on dependency machine's last "internal" test */ for ( dep = dep->t_child; (( dep->t_peer != NULL ) && ( dep->t_peer->t_machine == dep->t_machine )); dep = dep->t_peer ); t->t_peer = dep->t_peer; if ( t->t_peer != NULL ) { t->t_peer->t_prev = t; } t->t_prev = dep; dep->t_peer = t; } } void parse_error( char *s1, char *s2 ) { if ( s2 != NULL ) { syslog( LOG_ERR, "file %s line %d error: %s: %s", parse_fname, nefu_lineno, s1, s2 ); fprintf( stderr, "file %s line %d error: %s: %s\n", parse_fname, nefu_lineno, s1, s2 ); } else { syslog( LOG_ERR, "file %s line %d error: %s", parse_fname, nefu_lineno, s1 ); fprintf( stderr, "file %s line %d error: %s\n", parse_fname, nefu_lineno, s1 ); } return; } int nefu_read_config( char *fname ) { int fd = 0; int line_continue = 0; int mode = PARSE_MACHINES; char swap; char *token_start; char *test_name = NULL; char *line; char *start; SNET *snet; struct rcode *r_list = NULL; struct rcode *r_match; struct machine *m_list = NULL; struct machine *m_check; struct machine *m; struct machine *dependency = NULL; char *test_argv[ TEST_MAX_ARGS + 1 ]; int test_argc = 0; int n_tests = 0; memset( test_argv, 0, TEST_MAX_ARGS + 1 ); if ( fname != NULL ) { /* open fname */ if (( fd = open( fname, O_RDONLY, 0 )) < 0 ) { if ( errno == ENOENT ) { errno = 0; syslog( LOG_NOTICE, "%s: nefu config file not found", fname ); return( 1 ); } perror( fname ); return( -1 ); } parse_fname = fname; } if (( snet = snet_attach( fd, 1024 * 1024 )) == NULL ) { perror( "nefu_read_config: snet_attach" ); close( fd ); return( -1 ); } while (( line = snet_getline( snet, NULL )) != NULL ) { nefu_lineno++; if ( *line == '#' ) { continue; } if ( line_continue == 0 ) { /* tab as first character on line is special */ if ( *line == '\t' ) { start = line; } else { start = skip_ws( line ); if (( *start == '#' ) || ( *start == '\0' )) { continue; } } } else { start = skip_ws( line ); } line_continue = 0; if ( strcmp( start, "\\" ) == 0 ) { line_continue = 1; continue; } /* parse data on line, has to be a machine or a test */ for ( ; ; ) { switch ( mode ) { case PARSE_MACHINES: if ( *start == ':' ) { start++; /* check to see that we have at least one machine */ if ( m_list == NULL ) { parse_error( "No target machines defined", NULL ); goto error; } mode = PARSE_DEPENDENCY; } else { new_machine: if (( m = get_machine( &start )) == NULL ) { goto error; } for ( m_check = m_list; m_check != NULL; m_check = m_check->m_next ) { if ( m_check == m ) { parse_error( "Duplicate machine in target list", m->m_name ); goto error; } } m->m_next = m_list; m_list = m; mode = PARSE_MACHINES; } break; case PARSE_DEPENDENCY: if ( *start == ':' ) { start++; mode = PARSE_RCODES; } else { /* make sure we have only 1 dependency */ if ( dependency != NULL ) { parse_error( "Only one dependency allowed", NULL ); goto error; } if (( dependency = get_machine( &start )) == NULL ) { goto error; } mode = PARSE_DEPENDENCY; } break; case PARSE_RCODES: if (( r = get_rcode( &start )) == NULL ) { goto error; } /* add rcode to current rcode list, check for dups */ for ( r_match = r_list; r_match != NULL; r_match = r_match->r_next ) { if ( r_match == r ) { parse_error( "Rcode defined twice", r->r_code ); goto error; } } r->r_next = r_list; r_list = r; mode = PARSE_RCODES; break; case PARSE_TESTS: if ( *start == '\t' ) { start++; token_start = start; if (( start = word_end( token_start )) == NULL ) { parse_error( "Test name expected", NULL ); goto error; } if ( *start == ':' ) { start++; if ( isdigit( *start ) == 0 ) { parse_error( "Port expected after colon", NULL ); goto error; } for ( start++; isdigit( *start ); start++ ) ; } swap = *start; *start = '\0'; test_name = strdup( token_start ); *start = swap; if ( test_name == NULL ) { parse_error( "malloc", NULL ); goto error; } mode = PARSE_TEST_ARGS; break; } else { if ( n_tests == 0 ) { parse_error( "Test expected", NULL ); goto error; } /* start new machine target */ dependency = NULL; r_list = NULL; m_list = NULL; goto new_machine; } break; case PARSE_TEST_ARGS: if ( test_argc == TEST_MAX_ARGS ) { parse_error( "too many test arguments", NULL ); goto error; } token_start = start; if (( start = word_end( token_start )) == NULL ) { parse_error( "Test arg expected", NULL ); goto error; } swap = *start; *start = '\0'; if (( test_argv[ test_argc ] = strdup( token_start )) == NULL ) { parse_error( "malloc", NULL ); goto error; } test_argc++; *start = swap; mode = PARSE_TEST_ARGS; break; default: parse_error( "nefu_read_config: unreachable code", NULL ); goto error; } start = skip_ws( start ); if ( *start == '\0' ) { if ( mode == PARSE_RCODES ) { if ( r_list == NULL ) { if (( r_list = rcode_get( NEFU_DEFAULT_RCODE )) == NULL ) { parse_error( "rcode_get error", NULL ); goto error; } } /* do all machine assignment here */ for ( m = m_list; m != NULL; m = m->m_next ) { depend( m, dependency ); machine_rcode_assign( m, r_list ); } n_tests = 0; mode = PARSE_TESTS; } else if ( mode == PARSE_TEST_ARGS ) { for ( m = m_list; m != NULL; m = m->m_next ) { if (( e = test( m, r_list, test_name, nefu_lineno, test_argv )) != NULL ) { parse_error( e, NULL ); goto error; } } /* clear all old machine vars */ free( test_name ); test_name = NULL; while ( test_argc > 0 ) { test_argc--; free( test_argv[ test_argc ]); test_argv[ test_argc ] = NULL; } n_tests++; mode = PARSE_TESTS; } else { parse_error( "unexpected EOF", NULL ); goto error; } break; } if ( strcmp( start, "\\" ) == 0 ) { line_continue = 1; break; } } } if (( mode != PARSE_TESTS ) || ( n_tests == 0 )) { parse_error( "Unexpected EOF", NULL ); goto error; } if ( snet_close( snet ) != 0 ) { perror( "simta_domain_config: snet_close" ); return( -1 ); } return( 0 ); error: snet_close( snet ); return( -1 ); } char * skip_ws( char *start ) { while (( *start == ' ' ) || ( *start == '\t' )) { start++; } return( start ); } char * word_end( char *start ) { if ( is_word_char( *start ) == 0 ) { return( NULL ); } for ( start++; is_word_char( *start ); start++ ) ; return( start ); } int is_word_char( char c ) { if ( isalnum( c )) { return( 1 ); } switch ( c ) { case '~': case '/': case '!': case '.': case '_': case '@': case '-': case '+': return( 1 ); default: return( 0 ); } } struct machine * get_machine( char **start ) { char *end; char swap; struct machine *m; for ( end = *start; is_word_char( *end ); end++ ) ; if ( *start == end ) { parse_error( "Illegal tokens: Machine expected", NULL ); return( NULL ); } swap = *end; *end = '\0'; /* find/add machine to list */ if (( m = machine_lookup( *start )) == NULL ) { if (( e = machine_create( *start )) != NULL ) { parse_error( "machine_create failed", NULL ); return( NULL ); } if (( m = machine_lookup( *start )) == NULL ) { parse_error( "machine_lookup failed", NULL ); return( NULL ); } } *end = swap; *start = end; return( m ); } struct rcode * get_rcode( char **start ) { char *end; char swap; struct rcode *r; if ( is_word_char( **start ) == 0 ) { printf( "%s\n", *start ); parse_error( "Illegal tokens: Rcode expected", NULL ); return( NULL ); } for ( end = *start; is_word_char( *(end + 1)); end++ ) ; end++; swap = *end; *end = '\0'; if (( r = rcode_get( *start )) == NULL ) { parse_error( "rcode_get failed", NULL ); return( NULL ); } *end = swap; *start = end; return( r ); }