X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/e969452e161afbe2ec6220ecce30bd5d27cabb8c..7a2df1bb215ba4fe6dd20a73a510366fd47b1d17:/tools/tesh/tesh.c diff --git a/tools/tesh/tesh.c b/tools/tesh/tesh.c index 794fd390a8..bf02bf5d6d 100644 --- a/tools/tesh/tesh.c +++ b/tools/tesh/tesh.c @@ -13,388 +13,90 @@ #pragma hdrstop #endif -#include "portable.h" -#include "xbt/sysdep.h" -#include "xbt/function_types.h" -#include "xbt/log.h" -#include "xbt/str.h" - -#include -#include - -/** - ** Buffer code - **/ -typedef struct { - char *data; - int used,size; -} buff_t; - -static void buff_empty(buff_t *b) { - b->used=0; - b->data[0]='\n'; - b->data[1]='\0'; -} -static buff_t *buff_new(void) { - buff_t *res=malloc(sizeof(buff_t)); - res->data=malloc(512); - res->size=512; - buff_empty(res); - return res; -} -static void buff_free(buff_t *b) { - if (b) { - if (b->data) - free(b->data); - free(b); - } -} -static void buff_append(buff_t *b, char *toadd) { - int addlen=strlen(toadd); - int needed_space=b->used+addlen+1; - - if (needed_space > b->size) { - b->data = realloc(b->data, needed_space); - b->size = needed_space; - } - strcpy(b->data+b->used, toadd); - b->used += addlen; -} -static void buff_chomp(buff_t *b) { - while (b->data[b->used] == '\n') { - b->data[b->used] = '\0'; - if (b->used) - b->used--; - } -} +#include "tesh.h" +#include "xbt.h" -static void buff_trim(buff_t* b) -{ - xbt_str_trim(b->data," "); - b->used = strlen(b->data); -} +XBT_LOG_NEW_DEFAULT_CATEGORY(tesh,"TEst SHell utility"); -typedef struct s_signal_entry -{ - const char* name; - int number; -}s_signal_entry_t,* signal_entry_t; - -static const s_signal_entry_t signals[] = -{ - {"SIGHUP" ,1}, - {"SIGINT" ,2}, - {"SIGQUIT" ,3}, - {"SIGILL" ,4}, - {"SIGTRAP" ,5}, - {"SIGABRT" ,6}, - {"SIGEMT" ,7}, - {"SIGFPE" ,8}, - {"SIGKILL" ,9}, - {"SIGBUS" ,10}, - {"SIGSEGV" ,11}, - {"SIGSYS" ,12}, - {"SIGPIPE" ,13}, - {"SIGALRM" ,14}, - {"SIGTERM" ,15}, - {"SIGURG" ,16}, - {"SIGSTOP" ,17}, - {"SIGTSTP" ,18}, - {"SIGCONT" ,19}, - {"SIGCHLD" ,20}, - {"SIGTTIN" ,21}, - {"SIGTTOU" ,22}, - {"SIGIO" ,23}, - {"SIGXCPU" ,24}, - {"SIGXFSZ" ,25}, - {"SIGVTALRM",26}, - {"SIGPROF" ,27}, - {"SIGWINCH" ,28}, - {"SIGINFO" ,29}, - {"SIGUSR1" ,30}, - {"SIGUSR2" ,31} -}; - -#define SIGMAX 31 -#define SIGUNKNW SIGMAX + 1 - -/* returns the name of the signal from it number */ -const char* -signal_name(unsigned int number); - -/** - ** Options - **/ +/*** Options ***/ int timeout_value = 5; /* child timeout value */ -char* expected_signal=NULL; /* !=NULL if the following command should raise a signal */ -int expected_return=0; /* the exepeted return code of following command */ -int verbose=0; /* wheather we should wine on problems */ - -/** - ** Dealing with timeouts - **/ -int timeouted; -static void timeout_handler(int sig) { - timeouted = 1; -} -/** - ** Dealing with timeouts - **/ -int brokenpipe; -static void pipe_handler(int sig) { - brokenpipe = 1; -} -/** - ** Launching a child - **/ -buff_t *input; -buff_t *output_wanted; -buff_t *output_got; - -static void check_output() { - if (output_wanted->used==0 - && output_got->used==0) - return; - buff_chomp(output_got); - buff_chomp(output_wanted); - buff_trim(output_got); -buff_trim(output_wanted); - - if ( output_got->used != output_wanted->used - || strcmp(output_got->data, output_wanted->data)) { - fprintf(stderr,"Output don't match expectations\n"); - fprintf(stderr,">>>>> Expected %d chars:\n%s\n<<<<< Expected\n", - output_wanted->used,output_wanted->data); - fprintf(stderr,">>>>> Got %d chars:\n%s\n<<<<< Got\n", - output_got->used,output_got->data); - exit(2); - } - buff_empty(output_wanted); - buff_empty(output_got); - -} +char *testsuite_name; +static void handle_line(const char * filepos, char *line) { + /* Search end */ + xbt_str_rtrim(line+2,"\n"); -static void exec_cmd(char *cmd) { - int child_stdin[2]; - int child_stdout[2]; + /* + DEBUG7("rctx={%s,in={%d,>>%10s<<},exp={%d,>>%10s<<},got={%d,>>%10s<<}}", + rctx->cmd, + rctx->input->used, rctx->input->data, + rctx->output_wanted->used,rctx->output_wanted->data, + rctx->output_got->used, rctx->output_got->data); + */ + DEBUG2("[%s] %s",filepos,line); - if (pipe(child_stdin) || pipe(child_stdout)) { - perror("Cannot open the pipes"); - exit(4); - } + switch (line[0]) { + case '#': break; - int pid=fork(); - if (pid<0) { - perror("Cannot fork the command"); - exit(4); - } + case '$': + /* further trim useless chars which are significant for in/output */ + xbt_str_rtrim(line+2," \t"); - if (pid) { /* father */ - char buffout[4096]; - int posw,posr; - int status; - close(child_stdin[0]); - fcntl(child_stdin[1], F_SETFL, O_NONBLOCK); - close(child_stdout[1]); - fcntl(child_stdout[0], F_SETFL, O_NONBLOCK); - - brokenpipe = 0; - for (posw=0; poswused && !brokenpipe; ) { - int got; - // fprintf(stderr,"Still %d chars to write\n",input->used-posw); - got=write(child_stdin[1],input->data+posw,input->used-posw); - if (got>0) - posw+=got; - if (got<0 && errno!=EINTR && errno!=EAGAIN && errno!=EPIPE) { - perror("Error while writing input to child"); - exit(4); - } - // fprintf(stderr,"written %d chars so far\n",posw); + /* Deal with CD commands here, not in rctx */ + if (!strncmp("cd ",line+2,3)) { + char *dir=line+4; - posr=read(child_stdout[0],&buffout,4096); - // fprintf(stderr,"got %d chars\n",posr); - if (posr<0 && errno!=EINTR && errno!=EAGAIN) { - perror("Error while reading output of child"); - exit(4); - } - if (posr>0) { - buffout[posr]='\0'; - buff_append(output_got,buffout); - } - - if (got <= 0 && posr <= 0) - usleep(100); - } - input->data[0]='\0'; - input->used=0; - close(child_stdin[1]); - - timeouted = 0; - alarm(timeout_value); - do { - posr=read(child_stdout[0],&buffout,4096); - if (posr<0 && errno!=EINTR && errno!=EAGAIN) { - perror("Error while reading output of child"); + if (rctx->cmd) + rctx_start(); + + /* search begining */ + while (*(dir++) == ' '); + dir--; + VERB1("Saw cd '%s'",dir); + if (chdir(dir)) { + char buff[256]; + strerror_r(errno, buff, 256); + + perror(bprintf("Chdir to %s failed: %s",dir,buff)); + ERROR1("Test suite `%s': NOK (system error)",testsuite_name); exit(4); } - if (posr>0) { - buffout[posr]='\0'; - buff_append(output_got,buffout); - } else { - usleep(100); - } - } while (!timeouted && posr!=0); - - /* Check for broken pipe */ - if (brokenpipe && verbose) { - fprintf(stderr,"Warning: Child did not consume all its input (I got broken pipe)\n"); - } - - /* Check for timeouts */ - if (timeouted) { - fprintf(stderr,"Child timeouted (waited %d sec)\n",timeout_value); - exit(3); - } - alarm(0); - - - /* Wait for child, and check why it terminated */ - wait(&status); - - if (WIFSIGNALED(status) && strcmp(signal_name(WTERMSIG(status)),expected_signal)) { - fprintf(stderr,"Child got signal %s instead of signal %s\n",signal_name(WTERMSIG(status)), expected_signal); - exit(WTERMSIG(status)+4); - } - - if (!WIFSIGNALED(status) && expected_signal) { - fprintf(stderr,"Child didn't got expected signal %s\n", - expected_signal); - exit(5); - } - - if (WIFEXITED(status) && WEXITSTATUS(status) != expected_return ) { - if (expected_return) - fprintf(stderr,"Child returned code %d instead of %d\n", - WEXITSTATUS(status), expected_return); - else - fprintf(stderr,"Child returned code %d\n", WEXITSTATUS(status)); - exit(40+WEXITSTATUS(status)); - } - expected_return = 0; - - if(expected_signal){ - free(expected_signal); - expected_signal = NULL; - } - - } else { /* child */ - - close(child_stdin[1]); - close(child_stdout[0]); - dup2(child_stdin[0],0); - close(child_stdin[0]); - dup2(child_stdout[1],1); - dup2(child_stdout[1],2); - close(child_stdout[1]); - - execlp ("/bin/sh", "sh", "-c", cmd, NULL); - } -} - -static void run_cmd(char *cmd) { - if (cmd[0] == 'c' && cmd[1] == 'd' && cmd[2] == ' ') { - int pos = 2; - /* Search end */ - pos = strlen(cmd)-1; - while (cmd[pos] == '\n' || cmd[pos] == ' ' || cmd[pos] == '\t') - cmd[pos--] = '\0'; - /* search begining */ - pos = 2; - while (cmd[pos++] == ' '); - pos--; - // fprintf(stderr,"Saw cd '%s'\n",cmd+pos); - if (chdir(cmd+pos)) { - perror("Chdir failed"); - exit(4); - } - - } else { - exec_cmd(cmd); - } -} - -static void handle_line(int nl, char *line) { - - // printf("%d: %s",nl,line); fflush(stdout); - switch (line[0]) { - case '#': break; - case '$': - check_output(); /* Check that last command ran well */ - - printf("[%d] %s",nl,line); - fflush(stdout); - run_cmd(line+2); - break; - + break; + } /* else, pushline */ + case '&': case '<': - buff_append(input,line+2); - break; - case '>': - buff_append(output_wanted,line+2); - break; - case '!': - if (!strncmp(line+2,"set timeout ",strlen("set timeout "))) { - timeout_value=atoi(line+2+strlen("set timeout")); - printf("[%d] (new timeout value: %d)\n", - nl,timeout_value); - - } else if (!strncmp(line+2,"expect signal ",strlen("expect signal "))) { - expected_signal = strdup(line+2 + strlen("expect signal ")); - xbt_str_trim(expected_signal," \n"); - printf("[%d] (next command must raise signal %s)\n", nl, expected_signal); - - } else if (!strncmp(line+2,"expect return ",strlen("expect return "))) { - expected_return = atoi(line+2+strlen("expect return ")); - printf("[%d] (next command must return code %d)\n", - nl, expected_return); - - } else if (!strncmp(line+2,"verbose on",strlen("verbose on"))) { - verbose = 1; - printf("[%d] (increase verbosity)\n", nl); - - } else if (!strncmp(line+2,"verbose off",strlen("verbose off"))) { - verbose = 1; - printf("[%d] (decrease verbosity)\n", nl); - - } else { - fprintf(stderr,"%d: Malformed metacommand: %s",nl,line); - exit(1); - } + rctx_pushline(filepos, line[0], line+2 /* pass '$ ' stuff*/); break; case 'p': - printf("[%d] %s",nl,line+2); + INFO2("[%s] %s",filepos,line+2); + break; + case 'P': + CRITICAL2("[%s] %s",filepos,line+2); break; default: - fprintf(stderr,"Syntax error line %d: %s",nl, line); + ERROR2("[%s] Syntax error: %s",filepos, line); + ERROR1("Test suite `%s': NOK (syntax error)",testsuite_name); exit(1); break; } } -static int handle_suite(FILE* IN) { - int len; +static void handle_suite(const char* filename, FILE* IN) { + size_t len; char * line = NULL; int line_num=0; + char file_pos[256]; - buff_t *buff=buff_new(); + buff_t buff=buff_new(); int buffbegin = 0; - while (getline(&line,(size_t*) &len, IN) != -1) { + rctx = rctx_new(); + + while (getline(&line, &len, IN) != -1) { line_num++; /* Count the line length while checking wheather it's blank */ @@ -406,8 +108,18 @@ static int handle_suite(FILE* IN) { linelen++; } - if (blankline) + if (blankline) { + if (!rctx->cmd && !rctx->is_empty) { + ERROR1("[%d] Error: no command found in this chunk of lines.", + buffbegin); + ERROR1("Test suite `%s': NOK (syntax error)",testsuite_name); + exit(1); + } + if (rctx->cmd) + rctx_start(); + continue; + } /* Deal with \ at the end of the line, and call handle_line on result */ int to_be_continued = 0; @@ -429,78 +141,81 @@ static int handle_suite(FILE* IN) { buff_append(buff,line); if (!to_be_continued) { - handle_line(buffbegin, buff->data); + snprintf(file_pos,256,"%s:%d",filename,buffbegin); + handle_line(file_pos, buff->data); buff_empty(buff); } } else { - handle_line(line_num,line); + snprintf(file_pos,256,"%s:%d",filename,line_num); + handle_line(file_pos, line); } } - check_output(); /* Check that last command ran well */ + /* Check that last command of the file ran well */ + if (rctx->cmd) + rctx_start(); + + /* Wait all background commands */ + + rctx_free(rctx); /* Clear buffers */ if (line) free(line); buff_free(buff); - return 1; + } int main(int argc,char *argv[]) { - /* Setup the signal handlers */ - struct sigaction newact,oldact; - memset(&newact,0,sizeof(newact)); - newact.sa_handler=timeout_handler; - sigaction(SIGALRM,&newact,&oldact); + FILE *IN; - newact.sa_handler=pipe_handler; - sigaction(SIGPIPE,&newact,&oldact); + /* Ignore pipe issues. + They will show up when we try to send data to dead buddies, + but we will stop doing so when we're done with provided input */ + struct sigaction newact; + memset(&newact,0, sizeof(newact)); + newact.sa_handler=SIG_IGN; + sigaction(SIGPIPE,&newact,NULL); - /* Setup the input/output buffers */ - input=buff_new(); - output_wanted=buff_new(); - output_got=buff_new(); + xbt_init(&argc,argv); + rctx_init(); /* Find the description file */ - FILE *IN; - if (argc == 1) { - printf("Test suite from stdin\n");fflush(stdout); - handle_suite(stdin); - fprintf(stderr,"Test suite from stdin OK\n"); + INFO0("Test suite from stdin"); + handle_suite("stdin",stdin); + INFO0("Test suite from stdin OK"); } else { int i; for (i=1; ileads to segfault on amd64... - fprintf(stderr,"Test suite `%s' OK\n",argv[i]); + handle_suite(suitename,IN); + rctx_wait_bg(); + fclose(IN); //->leads to segfault on amd64... + INFO1("Test suite `%s' OK",suitename); + free(suitename); } } - - buff_free(input); - buff_free(output_wanted); - buff_free(output_got); + + rctx_exit(); + xbt_exit(); return 0; } -const char* -signal_name(unsigned int number) -{ - if(number > SIGMAX) - return "SIGUNKNW"; - - /* special case of SIGSEGV and SIGBUS (be conditional of the implementation)*/ - if((number == SIGBUS) && strcmp("SIGBUS",expected_signal)) - number = SIGSEGV; - - return (signals[number - 1].name); -}