From fe53701228db0390daa50be847aadc572dd21e71 Mon Sep 17 00:00:00 2001 From: cherierm Date: Mon, 7 Apr 2008 13:26:23 +0000 Subject: [PATCH] last version of tesh git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@5326 48e7efb5-ca39-0410-a469-dd3cf9ba447f --- tools/tesh2/include/com.h | 15 +- tools/tesh2/include/def.h | 17 +- tools/tesh2/include/directories.h | 8 +- tools/tesh2/include/directory.h | 2 +- tools/tesh2/include/error.h | 66 +- tools/tesh2/include/fstream.h | 2 +- tools/tesh2/include/global.h | 2 +- tools/tesh2/include/types.h | 60 +- tools/tesh2/include/unit.h | 7 +- tools/tesh2/include/variable.h | 16 +- tools/tesh2/include/variables.h | 6 +- tools/tesh2/src/allocator.c | 25 +- tools/tesh2/src/command.c | 195 +++--- tools/tesh2/src/dictionary.c | 6 +- tools/tesh2/src/directories.c | 115 +--- tools/tesh2/src/directory.c | 38 +- tools/tesh2/src/error.c | 133 ++-- tools/tesh2/src/excludes.c | 6 +- tools/tesh2/src/fstream.c | 44 +- tools/tesh2/src/fstreams.c | 30 +- tools/tesh2/src/htable.c | 25 +- tools/tesh2/src/lstrings.c | 5 +- tools/tesh2/src/main.c | 605 +++++++++-------- tools/tesh2/src/reader.c | 5 +- tools/tesh2/src/runner.c | 163 ++++- tools/tesh2/src/unit.c | 1038 ++++++++++++++++++++++++++--- tools/tesh2/src/units.c | 8 +- tools/tesh2/src/variable.c | 75 ++- tools/tesh2/src/variables.c | 7 +- tools/tesh2/src/vector.c | 63 +- tools/tesh2/src/writer.c | 52 +- 31 files changed, 2000 insertions(+), 839 deletions(-) diff --git a/tools/tesh2/include/com.h b/tools/tesh2/include/com.h index 80ff496bd9..85197227a6 100644 --- a/tools/tesh2/include/com.h +++ b/tools/tesh2/include/com.h @@ -49,13 +49,14 @@ units_sem; /* the dlist of tesh include directories */ extern vector_t -includes; +include_dirs; extern int interrupted; -extern int +/*extern int exit_code; +*/ extern int want_silent; @@ -72,6 +73,16 @@ dont_want_display_directory; extern directory_t root_directory; +extern int +want_detail_summary; + +extern int +exit_code; + +extern pid_t +pid; + + #ifdef __cplusplus } diff --git a/tools/tesh2/include/def.h b/tools/tesh2/include/def.h index d5b45aa749..273c02f17c 100644 --- a/tools/tesh2/include/def.h +++ b/tools/tesh2/include/def.h @@ -47,16 +47,17 @@ extern "C" { #endif -#define INDEFINITE ((int)-1) -#define INDEFINITE_SIGNAL NULL +#define INDEFINITE ((int)-1) +#define INDEFINITE_SIGNAL NULL -#define DEFAULT_FSTREAMS_CAPACITY ((int)128) -#define DEFAULT_INCLUDES_CAPACITY DEFAULT_FSTREAMS_CAPACITY -#define DEFAULT_UNITS_CAPACITY ((int)64) -#define DEFAULT_COMMANDS_CAPACITY ((int)1024) -#define DEFAULT_SUITES_CAPACITY ((int)128) +#define DEFAULT_FSTREAMS_CAPACITY ((int)128) +#define DEFAULT_INCLUDE_DIRS_CAPACITY DEFAULT_FSTREAMS_CAPACITY +#define DEFAULT_UNITS_CAPACITY ((int)64) +#define DEFAULT_INCLUDES ((int)8) +#define DEFAULT_COMMANDS_CAPACITY ((int)512) +#define DEFAULT_SUITES_CAPACITY ((int)32) -#define MAX_SUFFIX ((unsigned int)9) +#define MAX_SUFFIX ((unsigned int)9) #ifdef __cplusplus } diff --git a/tools/tesh2/include/directories.h b/tools/tesh2/include/directories.h index d000f77546..223029f16e 100644 --- a/tools/tesh2/include/directories.h +++ b/tools/tesh2/include/directories.h @@ -23,17 +23,15 @@ directories_load(directories_t directories, fstreams_t fstreams, lstrings_t suff int directories_free(void** directoriesptr); -directory_t -directories_get_back(directories_t directories); +/*directory_t +directories_get_back(directories_t directories);*/ -directory_t -directories_search_fstream_directory(directories_t directories, const char* name); int directories_get_size(directories_t directories); int -directories_has_directories_to_load(directories_t directories); +directories_is_empty(directories_t directories); #ifdef __cplusplus } diff --git a/tools/tesh2/include/directory.h b/tools/tesh2/include/directory.h index 42fd920a06..ff0e057efa 100644 --- a/tools/tesh2/include/directory.h +++ b/tools/tesh2/include/directory.h @@ -8,7 +8,7 @@ extern "C" { #endif directory_t -directory_new(const char* name, int load); +directory_new(const char* name); int directory_open(directory_t directory); diff --git a/tools/tesh2/include/error.h b/tools/tesh2/include/error.h index 6b0eb84f28..8dba6d78f9 100644 --- a/tools/tesh2/include/error.h +++ b/tools/tesh2/include/error.h @@ -8,39 +8,43 @@ extern "C" { #include -#define EREAD ((int)2000) /* a read pipe operation failed */ -#define EREADPIPE ((int)2001) /* the pipe used to read from the stdout of the command is broken */ -#define ETIMEOUT ((int)2002) /* the command is timeouted */ -#define EWRITE ((int)2003) /* a write operation failed */ -#define EWRITEPIPE ((int)2004) /* the pipe used to write to the stdin of the command is broken */ -#define EEXEC ((int)2005) /* can't execute the command */ -#define EWAIT ((int)2006) /* the wait function failed */ -#define ECMDNOTFOUND ((int)2007) /* the command is not found */ -#define EEXITCODENOTMATCH ((int)2008) /* the exit codes don't match */ -#define EOUTPUTNOTMATCH ((int)2009) /* the outputs don't match */ -#define ESIGNOTMATCH ((int)2010) /* the signals don't match */ -#define EUNEXPECTEDSIG ((int)2011) /* unexpected signal caught */ -#define ESIGNOTRECEIPT ((int)2012) /* the expected signal is not receipt */ -#define EFILENOTFOUND ((int)2013) /* the specified tesh file is not found */ -#define EGETCWD ((int)2014) /* this is a system error : the getcwd() function failed (impossible) */ -#define EDIRNOTFOUND ((int)2015) /* the specified directory is not found */ -#define ECHDIR ((int)2016) /* this is a system error : the chdir() function failed (impossible) */ -#define EPROCESSCMDLINE ((int)2017) /* this is an internal error : the process_command_line() function failed */ -#define EARGNOTSPEC ((int)2018) /* a none optional argument is not specified in the command line */ -#define ENOTPOSITIVENUM ((int)2019) /* the argument of the option is not strictly positive */ -#define ESYNTAX ((int)2020) /* syntax error */ -#define EINVALIDTIMEOUT ((int)2021) /* the timeout value specified by the metacommand is invalid */ -#define EINVALIDEXITCODE ((int)2022) /* the expected exit code value specified by the metacommand is invalid */ -#define ESIGNOTSUPP ((int)2023) /* the signal specified by the metacommand is not supported */ -#define ELEADTIME ((int)2024) /* global timeout */ -#define EREADMENOTFOUND ((int)2025) /* unable to locate the README.txt file */ -#define EINCLUDENOTFOUND ((int)2026) /* the include file specified by a metacommand is not found */ -#define ESUFFIXTOOLONG ((int)2027) /* the suffix is too long */ -#define EFILENOTINSPECDIR ((int)2028) /* file not found in the specified directories */ -#define EFILENOTINCURDIR ((int)2029) /* file not found in the current directory */ +#define EREAD ((int)100) /* a read pipe operation failed */ +#define EREADPIPE ((int)101) /* the pipe used to read from the stdout of the command is broken */ +#define ETIMEOUT ((int)102) /* the command is timeouted */ +#define EWRITE ((int)103) /* a write operation failed */ +#define EWRITEPIPE ((int)104) /* the pipe used to write to the stdin of the command is broken */ +#define EEXEC ((int)105) /* can't execute the command */ +#define EWAIT ((int)106) /* the wait function failed */ +#define ECMDNOTFOUND ((int)107) /* the command is not found */ +#define EEXITCODENOTMATCH ((int)108) /* the exit codes don't match */ +#define EOUTPUTNOTMATCH ((int)109) /* the outputs don't match */ +#define ESIGNOTMATCH ((int)110) /* the signals don't match */ +#define EUNEXPECTEDSIG ((int)111) /* unexpected signal caught */ +#define ESIGNOTRECEIPT ((int)112) /* the expected signal is not receipt */ +#define EFILENOTFOUND ((int)113) /* the specified tesh file is not found */ +#define EGETCWD ((int)114) /* this is a system error : the getcwd() function failed (impossible) */ +#define EDIRNOTFOUND ((int)115) /* the specified directory is not found */ +#define ECHDIR ((int)116) /* this is a system error : the chdir() function failed (impossible) */ +#define EPROCCMDLINE ((int)117) /* this is an internal error : the process_command_line() function failed */ +#define ENOARG ((int)118) /* a none optional argument is not specified in the command line */ +#define ENOTPOSITIVENUM ((int)119) /* the argument of the option is not strictly positive */ +#define ESYNTAX ((int)120) /* syntax error */ +#define EINVALIDTIMEOUT ((int)121) /* the timeout value specified by the metacommand is invalid */ +#define EINVALIDEXITCODE ((int)122) /* the expected exit code value specified by the metacommand is invalid */ +#define ESIGNOTSUPP ((int)123) /* the signal specified by the metacommand is not supported */ +#define ELEADTIME ((int)124) /* global timeout */ +#define EREADMENOTFOUND ((int)125) /* unable to locate the README.txt file */ +#define EINCLUDENOTFOUND ((int)126) /* the include file specified by a metacommand is not found */ +#define ESUFFIXTOOLONG ((int)127) /* the suffix is too long */ +#define EFILENOTINSPECDIR ((int)128) /* file not found in the specified directories */ +#define EFILENOTINCURDIR ((int)129) /* file not found in the current directory */ + + +const char* +error_get_at(int pos, int* code); const char* -error_to_string(int error); +error_to_string(int errcode); #ifdef __cplusplus } diff --git a/tools/tesh2/include/fstream.h b/tools/tesh2/include/fstream.h index 689d1cca62..4c1c0fcd2a 100644 --- a/tools/tesh2/include/fstream.h +++ b/tools/tesh2/include/fstream.h @@ -20,7 +20,7 @@ int fstream_free(void** fstreamptr); void -fstream_parse(fstream_t fstream, unit_t unit); +fstream_parse(fstream_t fstream, unit_t unit, xbt_os_mutex_t mutex); #ifdef __cplusplus } diff --git a/tools/tesh2/include/global.h b/tools/tesh2/include/global.h index aca4c0bdb0..5d1416d717 100644 --- a/tools/tesh2/include/global.h +++ b/tools/tesh2/include/global.h @@ -47,7 +47,7 @@ units_sem; /* the dlist of tesh include directories */ extern vector_t -includes; +include_dirs; extern int interrupted; diff --git a/tools/tesh2/include/types.h b/tools/tesh2/include/types.h index 6c4cff8d0c..86d908233c 100644 --- a/tools/tesh2/include/types.h +++ b/tools/tesh2/include/types.h @@ -71,6 +71,10 @@ struct s_writer; struct s_reader; struct s_timer; struct s_context; +struct s_command; +struct s_variable; +struct s_variables; + /* @@ -111,11 +115,19 @@ typedef enum e_command_status_raison csr_pipe_function_failed = 16 /* the function pipe() or CreatePipe() fails */ }cs_reason_t; +typedef struct s_variable +{ + char* name; + char* val; + int used:1; + int env:1; + int err:1; +}s_variable_t,* variable_t; -struct s_command; -struct s_variable; -struct s_variables; - +typedef struct s_variables +{ + dictionary_t items; +}s_variables_t,* variables_t; /* * declaration of the tesh timer type @@ -137,6 +149,7 @@ typedef struct s_reader struct s_command* command; /* the command of the reader */ int failed; /* if 1, the reader failed */ int broken_pipe; /* if 1, the pipe used by the reader is broken */ + int done; xbt_os_sem_t started; }s_reader_t,* reader_t; @@ -149,9 +162,12 @@ typedef struct s_writer struct s_command* command; /* the command of the writer */ int failed; /* if 1, the writer failed */ int broken_pipe; /* if 1, the pipe used by the writer is broken */ - xbt_os_sem_t started; + xbt_os_sem_t written; + xbt_os_sem_t can_write; + int done; }s_writer_t,* writer_t; + typedef struct s_units { vector_t items; /* used to store the units */ @@ -165,6 +181,8 @@ typedef struct s_units */ typedef struct s_unit { + char* description; + int is_suite; struct s_fstream* fstream; struct s_runner* runner; /* the runner of the unit */ vector_t commands; @@ -174,6 +192,7 @@ typedef struct s_unit int number_of_failed_commands; /* number of failed commands of the unit */ int number_of_successeded_commands; /* number of successeded commands of the unit */ int number_of_terminated_commands; /* number of ended commands */ + int number_of_waiting_commands; xbt_os_thread_t thread; /* all the units run in its own thread */ xbt_os_sem_t sem; /* used by the commands of the unit to signal the end of the unit */ xbt_os_mutex_t mutex; /* used to synchronously access to the properties of the runner */ @@ -183,14 +202,18 @@ typedef struct s_unit int parsed; /* if 1, the tesh file of the unit is parsed */ int released; int parsing_include_file; - struct s_suite* owner; /* the suite containing the unit if any */ + struct s_unit* owner; /* the unit containing the unit if any */ + struct s_unit* root; vector_t suites; int number; /* the number of suites */ int capacity; /* the number of suites that the unit can contain */ - int running_suite; /* if 1, the suite running a suite */ + int running_suite; /* if 1, the suite running a suite */ + vector_t includes; }s_unit_t,* unit_t; + + /* * declaration of tesh suite type */ @@ -211,7 +234,7 @@ typedef struct s_suite typedef struct s_runner { - /*vector_t units;*/ /* the vector containing all the units launched by the runner */ + /*vector_t units;*/ /* the vector containing all the units launched by the runner */ struct s_units* units; int timeouted; /* if 1, the runner is timeouted */ int timeout; /* the timeout of the runner */ @@ -220,6 +243,22 @@ typedef struct s_runner int number_of_ended_units; /* the number of ended units */ int waiting; /* if 1, the runner is waiting the end of all the units */ xbt_os_thread_t thread; /* the timer thread */ + vector_t variables; + + int total_of_tests; + int total_of_successeded_tests; + int total_of_failed_tests; + int total_of_interrupted_tests; + + int total_of_units; + int total_of_successeded_units; + int total_of_failed_units; + int total_of_interrupted_units; + + int total_of_suites; + int total_of_successeded_suites; + int total_of_failed_suites; + int total_of_interrupted_suites; }s_runner_t,* runner_t; @@ -245,7 +284,6 @@ typedef struct s_directory { char* name; DIR* stream; - int load; }s_directory_t,* directory_t; typedef struct s_directories @@ -276,6 +314,8 @@ typedef struct s_context int async; /* if 1, the command is asynchronous */ }s_context_t,* context_t; + +typedef void (*fn_sig_io_handler_t)(int); /* * declaration of the tesh command type */ @@ -307,6 +347,8 @@ typedef struct s_command #ifndef WIN32 int killed; /* if 1, the command was killed */ #endif + + fn_sig_io_handler_t fn_sig_io_handler; }s_command_t,* command_t; #ifdef _cplusplus diff --git a/tools/tesh2/include/unit.h b/tools/tesh2/include/unit.h index 3eb17f3a68..8f7ddbe6c5 100644 --- a/tools/tesh2/include/unit.h +++ b/tools/tesh2/include/unit.h @@ -8,7 +8,7 @@ extern "C" { #endif unit_t -unit_new(runner_t runner, suite_t owner, fstream_t fstream); +unit_new(runner_t runner, unit_t root, unit_t owner, fstream_t fstream); int unit_free(void** unitptr); @@ -36,7 +36,7 @@ void unit_pushline(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* filepos, char kind, char *line); void -unit_handle_include(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* file_name); +unit_handle_include(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* file_name, const char* description); void unit_parse(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* file_name, FILE* stream); @@ -44,6 +44,9 @@ unit_parse(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* fil void unit_handle_suite(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* description); +void +display_title(const char* description); + #ifdef __cplusplus } #endif diff --git a/tools/tesh2/include/variable.h b/tools/tesh2/include/variable.h index bd3e5ac5f4..7f3dbc0d46 100644 --- a/tools/tesh2/include/variable.h +++ b/tools/tesh2/include/variable.h @@ -1,12 +1,23 @@ #ifndef __VARIABLE_H #define __VARIABLE_H -#include +#include #ifdef __cplusplus extern "C" { #endif +variable_t +variable_new(const char* name, const char* val); + +int +variable_free(variable_t* variableptr); + +int +variable_is_used(variable_t variable); + +int +variable_set_used(variable_t variable); #ifdef __cplusplus @@ -14,4 +25,5 @@ extern "C" { #endif -#endif /*!__VARIABLE_H */ \ No newline at end of file +#endif /*!__VARIABLE_H */ + diff --git a/tools/tesh2/include/variables.h b/tools/tesh2/include/variables.h index 1b522ec455..2bc50ca74d 100644 --- a/tools/tesh2/include/variables.h +++ b/tools/tesh2/include/variables.h @@ -1,13 +1,17 @@ #ifndef __VARIABLES_H #define __VARIABLES_H -#include +#include #ifdef __cplusplus extern "C" { #endif +variables_t +variables_new(void); +int +variables_free(variables_t* variablesptr); #ifdef __cplusplus diff --git a/tools/tesh2/src/allocator.c b/tools/tesh2/src/allocator.c index 7121ba6538..125cd8e95d 100644 --- a/tools/tesh2/src/allocator.c +++ b/tools/tesh2/src/allocator.c @@ -69,7 +69,7 @@ allocator_new(int block_capacity, int type_size, fn_finalize_t fn_finalize) /* first block allocation */ - if((errno = resize(allocator))) + if(resize(allocator)) { free(allocator); return NULL; @@ -88,6 +88,7 @@ allocator_free(allocator_t* allocator_ptr) int pos, node_size; fn_finalize_t fn_finalize; void* type; + int rv; if(!(*allocator_ptr)) return EINVAL; @@ -113,8 +114,8 @@ allocator_free(allocator_t* allocator_ptr) /* apply the fn_finalize function to the first type */ - if((errno = (*fn_finalize)(&type))) - return errno; + if((rv = (*fn_finalize)(&type))) + return rv; } /*clear all the other types */ @@ -128,8 +129,8 @@ allocator_free(allocator_t* allocator_ptr) /* apply the fn_finalize function to the first type */ - if((errno = (*fn_finalize)(&type))) - return errno; + if((rv = (*fn_finalize)(&type))) + return rv; } } @@ -182,6 +183,7 @@ allocator_alloc(allocator_t allocator) int allocator_dealloc(allocator_t allocator, void* block) { + int rv; allocator_node_t node; if(!allocator || !block) @@ -189,8 +191,8 @@ allocator_dealloc(allocator_t allocator, void* block) if(allocator->fn_finalize) { - if((errno = (*(allocator->fn_finalize))(&block))) - return errno; + if((rv = (*(allocator->fn_finalize))(&block))) + return rv; memset(block, 0, allocator->type_size); node->is_allocated = 0; @@ -304,6 +306,7 @@ allocator_clear(allocator_t allocator) fn_finalize_t fn_finalize; void* type; register int pos; + int rv; if(!allocator) @@ -331,8 +334,8 @@ allocator_clear(allocator_t allocator) /* apply the fn_finalize function to the first type */ - if((errno = (*fn_finalize)(&type))) - return errno; + if((rv = (*fn_finalize)(&type))) + return rv; memset(type, 0, type_size); node->is_allocated = 0; @@ -349,8 +352,8 @@ allocator_clear(allocator_t allocator) /* apply the fn_finalize function to the first type */ - if((errno = (*fn_finalize)(&type))) - return errno; + if((rv = (*fn_finalize)(&type))) + return rv; memset(type, 0, type_size); node->is_allocated = 0; diff --git a/tools/tesh2/src/command.c b/tools/tesh2/src/command.c index 15cc6eb7ff..7d27d54b75 100644 --- a/tools/tesh2/src/command.c +++ b/tools/tesh2/src/command.c @@ -13,12 +13,17 @@ #include "../include/_signal.h" + XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh); +static void sig_io_handler(int status) +{ + INFO0("*************************Got a SIGIO**************************************"); +} + static void* command_start(void* p); - command_t command_new(unit_t unit, context_t context, xbt_os_mutex_t mutex) { @@ -50,7 +55,7 @@ command_new(unit_t unit, context_t context, xbt_os_mutex_t mutex) command->stat_val = -1; /* set the unit of the command */ - command->unit = unit; + command->unit = unit->root ? unit->root : unit; /* all the commands are runned in a thread */ command->thread = NULL; @@ -81,14 +86,20 @@ command_new(unit_t unit, context_t context, xbt_os_mutex_t mutex) /* register the command */ xbt_os_mutex_acquire(mutex); - /*unit->commands[(unit->number_of_commands)++] = command;*/ + vector_push_back(unit->commands, command); - (unit->number_of_commands)++; + + (command->unit->number_of_commands)++; + xbt_os_mutex_release(mutex); + command->fn_sig_io_handler = sig_io_handler; + #ifndef WIN32 command->killed = 0; #endif + + return command; } @@ -365,7 +376,7 @@ command_exec(command_t command, const char* command_line) } command->pid= fork(); - + if(command->pid < 0) { close(child_stdin_fd[0]); @@ -381,12 +392,18 @@ command_exec(command_t command, const char* command_line) { if(command->pid) {/* father */ + + close(child_stdin_fd[0]); close(child_stdout_fd[1]); command->stdin_fd = child_stdin_fd[1]; + command->stdout_fd = child_stdout_fd[0]; - + + /* on indique que c'est le processus parent qui doit recevoir le signal */ + /*fcntl(command->stdin_fd,F_SETOWN, pid);*/ + if(command->reader) { /* launch the reader */ @@ -411,31 +428,58 @@ command_exec(command_t command, const char* command_line) } else {/* child */ - + + close(child_stdin_fd[1]); + close(child_stdout_fd[0]); - dup2(child_stdin_fd[0],0); + if(dup2(child_stdin_fd[0],STDIN_FILENO/*0*/) < 0) + { + exit_code = EEXEC; + ERROR1("dup2() failed (%d)",errno); + command_handle_failure(command,csr_exec_failure); + } - close(child_stdin_fd[0]); + /*close(child_stdin_fd[0]); + */ - close(child_stdout_fd[0]); + if(dup2(child_stdout_fd[1],STDOUT_FILENO/*1*/) < 0) + { + exit_code = EEXEC; + ERROR1("dup2() failed (%d)",errno); + command_handle_failure(command,csr_exec_failure); + } - dup2(child_stdout_fd[1],1); + if(dup2(child_stdout_fd[1], STDERR_FILENO/*2*/) < 0) + { + exit_code = EEXEC; + ERROR1("dup2() failed (%d)",errno); + command_handle_failure(command,csr_exec_failure); + } - dup2(child_stdout_fd[1],2); + fcntl(command->stdin_fd, F_SETFL, fcntl(command->stdin_fd, F_GETFL) | O_NONBLOCK); + + + if(command->writer) + xbt_os_sem_release(command->writer->can_write); - close(child_stdout_fd[1]); + /*close(child_stdout_fd[1]);*/ if(command->reader) xbt_os_sem_acquire(command->reader->started); if(command->writer) - xbt_os_sem_acquire(command->writer->started); + xbt_os_sem_acquire(command->writer->written); if(command->timer) - xbt_os_sem_acquire(command->timer->started); + xbt_os_sem_acquire(command->timer->started); - execlp ("/bin/sh", "sh", "-c", command->context->command_line, NULL); + if(execlp("/bin/sh", "sh", "-c", command->context->command_line, NULL) < 0) + { + exit_code = EEXEC; + ERROR1("execlp() failed (%d)",errno); + command_handle_failure(command,csr_exec_failure); + } } } } @@ -477,8 +521,18 @@ command_wait(command_t command) /* let this thread wait for the child so that the main thread can detect the timeout without blocking on the wait */ + + xbt_os_mutex_acquire(command->unit->mutex); + command->unit->number_of_waiting_commands++; + xbt_os_mutex_release(command->unit->mutex); + pid = waitpid(command->pid, &(command->stat_val), 0); + + xbt_os_mutex_acquire(command->unit->mutex); + command->unit->number_of_waiting_commands--; + xbt_os_mutex_release(command->unit->mutex); + /*printf("The %p command ended\n",command);*/ if(pid != command->pid) { @@ -491,6 +545,8 @@ command_wait(command_t command) if(WIFEXITED(command->stat_val)) command->exit_code = WEXITSTATUS(command->stat_val); } + + } #endif @@ -504,7 +560,7 @@ command_check(command_t command) if(WIFSIGNALED(command->stat_val)) { command->signal = strdup(signal_name(WTERMSIG(command->stat_val),command->context->signal)); - INFO3("the command -PID %d %s receive the signal : %s",command->pid, command->context->command_line, command->signal); + /*INFO3("the command -PID %d %s receive the signal : %s",command->pid, command->context->command_line, command->signal);*/ } /* we have a signal and not signal is expected */ @@ -547,20 +603,23 @@ command_check(command_t command) if(success && oh_check == command->context->output_handling && command->reader) { /* make sure the reader done */ - while(!command->reader->broken_pipe) + while(!command->reader->done) xbt_os_thread_yield(); + + close(command->stdout_fd); + command->stdout_fd = INDEFINITE_FD; - xbt_strbuff_chomp(command->output); - xbt_strbuff_chomp(command->context->output); - xbt_strbuff_trim(command->output); - xbt_strbuff_trim(command->context->output); + xbt_strbuff_chomp(command->output); + xbt_strbuff_chomp(command->context->output); + xbt_strbuff_trim(command->output); + xbt_strbuff_trim(command->context->output); - if(command->output->used != command->context->output->used || strcmp(command->output->data, command->context->output->data)) - { - success = 0; - exit_code = EOUTPUTNOTMATCH; - reason = csr_outputs_dont_match; - } + if(command->output->used != command->context->output->used || strcmp(command->output->data, command->context->output->data)) + { + success = 0; + exit_code = EOUTPUTNOTMATCH; + reason = csr_outputs_dont_match; + } } if(success) @@ -650,34 +709,15 @@ command_interrupt(command_t command) void command_display_status(command_t command) { - #ifdef WIN32 - printf("\nCommand : PID - %p\n%s\n",command->pid,command->context->command_line); - #else - printf("\nCommand : PID - %d\n%s\n",command->pid,command->context->command_line); - #endif - printf("Status informations :\n"); - printf(" position in the tesh file : %s\n",command->context->line); - /* the command successeded */ - if(cs_successeded == command->status) - { - /* status */ - printf(" status : success\n"); - } - else + /*printf("\033[1m");*/ + + if(cs_successeded != command->status) { - - /* display if the command is interrupted, failed or in a unknown status */ - if(cs_interrupted == command->status) - printf(" status : interrupted\n"); - else if(cs_failed == command->status) - printf(" status : failed\n"); - else - printf(" status : unknown\n"); #ifndef WIN32 if(command->killed) - printf(" \n"); + printf(" \n"); #endif /* display the reason of the status of the command */ @@ -685,83 +725,83 @@ command_display_status(command_t command) { /* the function pipe or CreatePipe() fails */ case csr_pipe_function_failed : - printf(" reason : pipe() or CreatePipe() function failed (system error)\n"); + printf(" reason : pipe() or CreatePipe() function failed (system error)\n"); break; /* reader failure reasons*/ case csr_read_pipe_broken : - printf(" reason : command read pipe broken\n"); + printf(" reason : command read pipe broken\n"); break; case csr_read_failure : - printf(" reason : command stdout read failed\n"); + printf(" reason : command stdout read failed\n"); break; /* writer failure reasons */ case csr_write_failure : - printf(" reason : command stdin write failed\n"); + printf(" reason : command stdin write failed\n"); break; case csr_write_pipe_broken : - printf(" reason : command write pipe broken\n"); + printf(" reason : command write pipe broken\n"); break; /* timer reason */ case csr_timeout : - printf(" reason : command timeouted\n"); + printf(" reason : command timeouted\n"); break; /* command failure reason */ case csr_command_not_found : - printf(" reason : command not found\n"); + printf(" reason : command not found\n"); break; /* context failure reasons */ case csr_exit_codes_dont_match : - printf(" reason : exit codes don't match\n"); + printf(" reason : exit codes don't match\n"); break; case csr_outputs_dont_match : { char *diff; - printf(" reason : ouputs don't match\n"); + printf(" reason : ouputs don't match\n"); diff = xbt_str_diff(command->context->output->data,command->output->data); - printf(" output diff :\n%s\n",diff); + printf(" output diff :\n%s\n",diff); free(diff); } break; case csr_signals_dont_match : - printf(" reason : signals don't match\n"); + printf(" reason : signals don't match\n"); break; case csr_unexpected_signal_caught: - printf(" reason : unexpected signal caught\n"); + printf(" reason : unexpected signal caught\n"); break; case csr_expected_signal_not_receipt : - printf(" reason : expected signal not receipt\n"); + printf(" reason : expected signal not receipt\n"); break; /* system failure reasons */ case csr_exec_failure : - printf(" reason : can't excute the command\n"); + printf(" reason : can't excute the command\n"); break; case csr_wait_failure : - printf(" reason : wait command failure\n"); + printf(" reason : wait command failure\n"); break; /* global/local interruption */ case csr_interruption_request : - printf(" reason : the command receive a interruption request\n"); + printf(" reason : the command receive a interruption request\n"); break; /* unknown ? */ case csr_unknown : - printf(" reason : unknown \n"); + printf(" reason : unknown \n"); } } @@ -769,23 +809,23 @@ command_display_status(command_t command) { if(INDEFINITE != command->exit_code) /* the command exit code */ - printf(" exit code : %d\n",command->exit_code); + printf(" exit code : %d\n",command->exit_code); /* if an expected exit code was specified display it */ if(INDEFINITE != command->context->exit_code) - printf(" expected exit code : %d\n",command->context->exit_code); + printf(" expected exit code : %d\n",command->context->exit_code); else - printf(" no expected exit code specified\n"); + printf(" no expected exit code specified\n"); /* if an expected exit code was specified display it */ if(NULL == command->context->signal) - printf(" no expected signal specified\n"); + printf(" no expected signal specified\n"); else { if(NULL != command->signal) - printf(" signal : %s\n",command->signal); + printf(" signal : %s\n",command->signal); - printf(" expected signal : %s\n",command->context->signal); + printf(" expected signal : %s\n",command->context->signal); } /* if the command has out put and the metacommand display output is specified display it */ @@ -794,16 +834,21 @@ command_display_status(command_t command) xbt_dynar_t a = xbt_str_split(command->output->data, "\n"); char *out = xbt_str_join(a,"\n||"); xbt_dynar_free(&a); - printf(" output :\n||%s",out); + printf(" output :\n||%s",out); free(out); } } printf("\n"); + + /*printf("\033[0m");*/ } + + + void command_handle_failure(command_t command, cs_reason_t reason) { diff --git a/tools/tesh2/src/dictionary.c b/tools/tesh2/src/dictionary.c index 8c0c5b6bcc..9e5f99b42a 100644 --- a/tools/tesh2/src/dictionary.c +++ b/tools/tesh2/src/dictionary.c @@ -76,11 +76,13 @@ dictionary_get(dictionary_t dictionary, const char* key) int dictionary_free(dictionary_t* dictionaryptr) { + int rv; + if(!(*dictionaryptr)) return EINVAL; - if((errno = htable_free(&((*dictionaryptr)->htable)))) - return errno; + if((rv = htable_free(&((*dictionaryptr)->htable)))) + return rv; free(*dictionaryptr); *dictionaryptr = NULL; diff --git a/tools/tesh2/src/directories.c b/tools/tesh2/src/directories.c index 83726a71bf..3afc543925 100644 --- a/tools/tesh2/src/directories.c +++ b/tools/tesh2/src/directories.c @@ -29,6 +29,18 @@ directories_get_size(directories_t directories) return vector_get_size(directories->items); } +int +directories_is_empty(directories_t directories) +{ + if(!directories) + { + errno = EINVAL; + return -1; + } + + return vector_is_empty(directories->items); +} + int directories_add(directories_t directories, directory_t directory) { @@ -71,48 +83,11 @@ directories_contains(directories_t directories, directory_t directory) return 0; } -directory_t -directories_search_fstream_directory(directories_t directories, const char* name) -{ - - struct stat buffer = {0}; - char* prev; - directory_t directory; - - if(!directories) - { - errno = EINVAL; - return NULL; - } - - prev = getcwd(NULL, 0); - - vector_rewind(directories->items); - - while((directory = vector_get(directories->items))) - { - chdir(directory->name); - - if(!stat(name, &buffer) || S_ISREG(buffer.st_mode)) - { - chdir(prev); - free(prev); - return directory; - } - - vector_move_next(directories->items); - } - - chdir(prev); - free(prev); - errno = ESRCH; - return NULL; -} - int directories_load(directories_t directories, fstreams_t fstreams, lstrings_t suffixes) { directory_t directory; + int rv; if(!directories || !fstreams || !suffixes) return EINVAL; @@ -121,21 +96,14 @@ directories_load(directories_t directories, fstreams_t fstreams, lstrings_t suff while((directory = vector_get(directories->items))) { - if(directory->load) - { - if((errno = directory_open(directory))) - return errno; - - chdir(directory->name); - - if((errno = directory_load(directory, fstreams, suffixes))) - return errno; - - if((errno = directory_close(directory))) - return errno; + if((rv = directory_open(directory))) + return rv; + + if((rv = directory_load(directory, fstreams, suffixes))) + return rv; - chdir(root_directory->name); - } + if((rv = directory_close(directory))) + return rv; vector_move_next(directories->items); @@ -145,51 +113,16 @@ directories_load(directories_t directories, fstreams_t fstreams, lstrings_t suff return 0; } -int -directories_has_directories_to_load(directories_t directories) -{ - directory_t directory; - - if(!directories) - { - errno = EINVAL; - return 0; - } - - vector_rewind(directories->items); - - while((directory = vector_get(directories->items))) - { - if(directory->load) - return 1; - - vector_move_next(directories->items); - - } - - return 0; -} - -directory_t -directories_get_back(directories_t directories) -{ - if(!directories) - { - errno = EINVAL; - return NULL; - } - - return vector_get_back(directories->items); -} - int directories_free(void** directoriesptr) { + int rv; + if(!(*directoriesptr)) return EINVAL; - if((errno = vector_free(&((*((directories_t*)directoriesptr))->items)))) - return errno; + if((rv = vector_free(&((*((directories_t*)directoriesptr))->items)))) + return rv; free(*directoriesptr); *directoriesptr = NULL; diff --git a/tools/tesh2/src/directory.c b/tools/tesh2/src/directory.c index 6033aa07fa..ea93e7fd77 100644 --- a/tools/tesh2/src/directory.c +++ b/tools/tesh2/src/directory.c @@ -5,10 +5,9 @@ XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh); directory_t -directory_new(const char* name, int load) +directory_new(const char* name) { directory_t directory; - struct stat buffer = {0}; if(!name) { @@ -16,37 +15,13 @@ directory_new(const char* name, int load) return NULL; } - if(stat(name, &buffer)) - return NULL; - - if(!S_ISDIR(buffer.st_mode)) - { - errno = ENOTDIR; - return NULL; - } - directory = xbt_new0(s_directory_t, 1); - if(!strcmp(".",name)) - { - directory->name = getcwd(NULL, 0); - } - else if(!strcmp("..",name)) - { - char* buffer = getcwd(NULL, 0); - chdir(name); - directory->name = getcwd(NULL, 0); - chdir(buffer); - free(buffer); - } - else - { - directory->name = strdup(name); - } - + directory->name = strdup(name); + + directory->stream = NULL; - directory->load = load; return directory; } @@ -88,6 +63,7 @@ directory_load(directory_t directory, fstreams_t fstreams, lstrings_t suffixes) const char* suffix; int has_valid_suffix; int is_empty = 1; + int rv; if(!directory || !fstreams) return EINVAL; @@ -128,12 +104,12 @@ directory_load(directory_t directory, fstreams_t fstreams, lstrings_t suffixes) } /* add the fstream to the list of file streams to run */ - if((errno = fstreams_add(fstreams, fstream_new(directory->name, entry->d_name)))) + if((rv = fstreams_add(fstreams, fstream_new(directory->name, entry->d_name)))) { INFO0("fstreams_add() failed"); free(sfstream.directory); free(sfstream.name); - return errno; + return rv; } is_empty = 0; diff --git a/tools/tesh2/src/error.c b/tools/tesh2/src/error.c index 1f7a7959a0..c7fcf6b4e0 100644 --- a/tools/tesh2/src/error.c +++ b/tools/tesh2/src/error.c @@ -1,57 +1,76 @@ -#include - -typedef struct s_entry -{ - int code; - const char* string; -}entry_t; - -static const -entry_t err[] = -{ - {EREAD, "a read pipe operation failed"}, - {EREADPIPE, "a pipe used to read from the stdout of a command is broken"}, - {ETIMEOUT, "a command is timeouted"}, - {EWRITE, "a write operation failed"}, - {EWRITEPIPE, "a pipe used to write to the stdin of a command is broken"}, - {EEXEC, "can't execute a command"}, - {EWAIT, "wait function failed"}, - {ECMDNOTFOUND, "command is not found"}, - {EEXITCODENOTMATCH, "exit codes don't match"}, - {EOUTPUTNOTMATCH, "outputs don't match"}, - {ESIGNOTMATCH, "signals don't match"}, - {EUNEXPECTEDSIG, "unexpected signal caught"}, - {ESIGNOTRECEIPT, "expected signal not receipt"}, - {EFILENOTFOUND, "specified tesh file not found"}, - {EGETCWD, "system error : the getcwd() function failed"}, - {EDIRNOTFOUND, "specified directory not found"}, - {ECHDIR, "system error : the chdir() function failed"}, - {EPROCESSCMDLINE, "internal error : the process_command_line() function failed"}, - {EARGNOTSPEC, "none optional argument not specified in the command line"}, - {ENOTPOSITIVENUM, "argument option not strictly positive"}, - {ESYNTAX, "syntax error"}, - {EINVALIDTIMEOUT, "timeout value specified by metacommand invalid"}, - {EINVALIDEXITCODE, "expected exit code value specified by the metacommand invalid"}, - {ESIGNOTSUPP, "signal specified by the metacommand not supported (Windows specific)"}, - {ELEADTIME, "lead time"}, - {EREADMENOTFOUND, "unable to locate the README.txt file"}, - {EINCLUDENOTFOUND, "include file specified by a metacommand is not found"}, - {ESUFFIXTOOLONG, "suffix is too long"}, - {EFILENOTINSPECDIR,"file not found in the specified directories"}, - {EFILENOTINCURDIR,"file not found in the current directory"}, - {-1, "unknown"} -}; - -const char* -error_to_string(int error) -{ - int i; - - for(i = 0; error >= 0 && err[i].code != -1; i++) - { - if(err[i].code == error) - return err[i].string; - } - - return "unknow error"; -} +#include + +typedef struct s_entry +{ + const char* name; + int code; + const char* string; +}entry_t; + + +static const +entry_t err[] = +{ + {"ENOENT", ENOENT, "No such file of directory."}, + {"ENOMEM", ENOMEM,"Insufficient memory is available."}, + {"EACCES", EACCES, "Read or search permission was denied for a component of the pathname."}, + {"ENOTDIR", ENOTDIR, "Not a directory."}, + {"EREAD", EREAD, "a read pipe operation failed"}, + {"EREADPIPE", EREADPIPE, "a pipe used to read from the stdout of a command is broken"}, + {"ETIMEOUT", ETIMEOUT, "a command is timeouted"}, + {"EWRITE", EWRITE, "a write operation failed"}, + {"EWRITEPIPE", EWRITEPIPE, "a pipe used to write to the stdin of a command is broken"}, + {"EEXEC", EEXEC, "can't execute a command"}, + {"EWAIT", EWAIT, "wait function failed"}, + {"ECMDNOTFOUND", ECMDNOTFOUND, "command is not found"}, + {"EEXITCODENOTMATCH", EEXITCODENOTMATCH, "exit codes don't match"}, + {"EOUTPUTNOTMATCH", EOUTPUTNOTMATCH, "outputs don't match"}, + {"ESIGNOTMATCH", ESIGNOTMATCH, "signals don't match"}, + {"EUNEXPECTEDSIG", EUNEXPECTEDSIG, "unexpected signal caught"}, + {"ESIGNOTRECEIPT", ESIGNOTRECEIPT, "expected signal not receipt"}, + {"EFILENOTFOUND", EFILENOTFOUND, "specified tesh file not found"}, + {"EGETCWD", EGETCWD, "system error : the getcwd() function failed"}, + {"EDIRNOTFOUND", EDIRNOTFOUND, "specified directory not found"}, + {"ECHDIR", ECHDIR, "system error : the chdir() function failed"}, + {"EPROCCMDLINE", EPROCCMDLINE, "process_command_line() failed : internal error"}, + {"ENOARG", ENOARG, "none optional argument not specified"}, + {"ENOTPOSITIVENUM", ENOTPOSITIVENUM, "argument option not strictly positive"}, + {"ESYNTAX", ESYNTAX, "syntax error"}, + {"EINVALIDTIMEOUT", EINVALIDTIMEOUT, "timeout value specified by metacommand invalid"}, + {"EINVALIDEXITCODE", EINVALIDEXITCODE, "expected exit code value specified by the metacommand invalid"}, + {"ESIGNOTSUPP", ESIGNOTSUPP, "signal specified by the metacommand not supported (Windows specific)"}, + {"ELEADTIME", ELEADTIME, "lead time"}, + {"EREADMENOTFOUND", EREADMENOTFOUND, "unable to locate the README.txt file"}, + {"EINCLUDENOTFOUND", EINCLUDENOTFOUND, "include file specified by a metacommand is not found"}, + {"ESUFFIXTOOLONG", ESUFFIXTOOLONG, "suffix is too long"}, + {"EFILENOTINSPECDIR", EFILENOTINSPECDIR,"file not found in the specified directories"}, + {"EFILENOTINCURDIR", EFILENOTINCURDIR,"file not found in the current directory"}, + {"unkwown", -1, "unknown"} +}; + +#include + +const char* +error_to_string(int errcode) +{ + int i; + + for(i = 0; err[i].code != -1; i++) + if(err[i].code == errcode) + return err[i].string; + + return "unknow error"; +} + +const char* +error_get_at(int pos, int* code) +{ + if(pos < 0 || (pos > (sizeof(err)/sizeof(entry_t)) - 2)) + { + errno = ERANGE; + return NULL; + } + + *code = err[pos].code; + return err[pos].name; +} diff --git a/tools/tesh2/src/excludes.c b/tools/tesh2/src/excludes.c index 332997468a..e2a33cb123 100644 --- a/tools/tesh2/src/excludes.c +++ b/tools/tesh2/src/excludes.c @@ -110,11 +110,13 @@ excludes_check(excludes_t excludes, fstreams_t fstreams) int excludes_free(void** excludesptr) { + int rv; + if(!(*excludesptr)) return EINVAL; - if((errno =vector_free((&(*((excludes_t*)excludesptr))->items)))) - return errno; + if((rv =vector_free((&(*((excludes_t*)excludesptr))->items)))) + return rv; free(*excludesptr); *excludesptr = NULL; diff --git a/tools/tesh2/src/fstream.c b/tools/tesh2/src/fstream.c index 1349a98ccc..18d3c1aaa3 100644 --- a/tools/tesh2/src/fstream.c +++ b/tools/tesh2/src/fstream.c @@ -10,8 +10,7 @@ fstream_t fstream_new(const char* directory, const char* name) { fstream_t fstream; - /*struct stat buffer = {0};*/ - + if(!name) { errno = EINVAL; @@ -30,15 +29,6 @@ fstream_new(const char* directory, const char* name) return NULL; } - /*if(stat(name, &buffer)) - return NULL; - - if(!S_ISREG(buffer.st_mode)) - { - errno = ENOENT; - return NULL; - }*/ - fstream = xbt_new0(s_fstream_t, 1); fstream->name = strdup(name); @@ -53,6 +43,8 @@ fstream_new(const char* directory, const char* name) int fstream_open(fstream_t fstream) { + char path[MAX_PATH] = {0}; + if(!fstream || fstream->stream) return EINVAL; @@ -62,7 +54,9 @@ fstream_open(fstream_t fstream) return 0; } - if(!(fstream->stream = fopen(fstream->name, "r"))) + sprintf(path,"%s/%s",fstream->directory, fstream->name); + + if(!(fstream->stream = fopen(path, "r"))) return errno; return 0; @@ -105,7 +99,7 @@ fstream_free(void** fstreamptr) } void -fstream_parse( fstream_t fstream, unit_t unit) +fstream_parse(fstream_t fstream, unit_t unit, xbt_os_mutex_t mutex) { size_t len; char * line = NULL; @@ -114,7 +108,6 @@ fstream_parse( fstream_t fstream, unit_t unit) xbt_strbuff_t buff; int buffbegin = 0; context_t context; - xbt_os_mutex_t mutex = unit->mutex; /* Count the line length while checking wheather it's blank */ int blankline; @@ -125,8 +118,9 @@ fstream_parse( fstream_t fstream, unit_t unit) buff=xbt_strbuff_new(); context = context_new(); - while(!unit->interrupted && getline(&line, &len, fstream->stream) != -1) + while(!(unit->root->interrupted) && getline(&line, &len, fstream->stream) != -1) { + blankline=1; linelen = 0; to_be_continued = 0; @@ -146,16 +140,16 @@ fstream_parse( fstream_t fstream, unit_t unit) if(!context->command_line && (context->input->used || context->output->used)) { ERROR1("[%d] Error: no command found in this chunk of lines.",buffbegin); - - if(unit->parsing_include_file) - ERROR1("Unit `%s': NOK (syntax error)", fstream->name); - else - ERROR2("Unit `%s' inclued in `%s' : NOK (syntax error)", fstream->name, fstream->name); + ERROR1("Unit `%s': NOK (syntax error)", fstream->name); + exit_code = ESYNTAX; unit_handle_failure(unit); break; } + else if(unit->running_suite) + unit->running_suite = 0; + if(context->command_line) { @@ -163,19 +157,18 @@ fstream_parse( fstream_t fstream, unit_t unit) { command_t command = command_new(unit, context, mutex); command_run(command); + } context_reset(context); } - continue; - } if(linelen>1 && line[linelen-2]=='\\') { - if (linelen>2 && line[linelen-3] == '\\') + if(linelen>2 && line[linelen-3] == '\\') { /* Damn. Escaped \ */ line[linelen-2] = '\n'; @@ -210,6 +203,8 @@ fstream_parse( fstream_t fstream, unit_t unit) } } + + /* Check that last command of the file ran well */ if(context->command_line) { @@ -221,12 +216,15 @@ fstream_parse( fstream_t fstream, unit_t unit) context_reset(context); } + + /* Clear buffers */ if (line) free(line); xbt_strbuff_free(buff); + context_free(&context); } diff --git a/tools/tesh2/src/fstreams.c b/tools/tesh2/src/fstreams.c index 27905ee3e0..510121ae64 100644 --- a/tools/tesh2/src/fstreams.c +++ b/tools/tesh2/src/fstreams.c @@ -8,7 +8,9 @@ fstreams_t fstreams_new(int capacity, fn_finalize_t fn_finalize) { fstreams_t fstreams; - fstreams = xbt_new0(s_fstreams_t, 1); + + if(!(fstreams = (fstreams_t) calloc(1, sizeof(s_fstreams_t)))) + return NULL; if(!(fstreams->items = vector_new(capacity, fn_finalize))) { @@ -34,8 +36,6 @@ fstreams_exclude(fstreams_t fstreams, excludes_t excludes) if(!(to_erase = vector_new(8, NULL))) return errno; - INFO0("excluding file streams"); - /* collecte the file streams to exclude */ vector_rewind(fstreams->items); @@ -93,8 +93,6 @@ int fstreams_load(fstreams_t fstreams) { register fstream_t fstream; - const char* directory = NULL; - if(!fstreams ) return EINVAL; @@ -103,24 +101,11 @@ fstreams_load(fstreams_t fstreams) while((fstream = vector_get(fstreams->items))) { - chdir(root_directory->name); - - if(!directory || strcmp(directory, fstream->directory)) - { - directory = fstream->directory; - - if(!dont_want_display_directory) - INFO1("entering directory \"%s\"",directory); - - } - - chdir(fstream->directory); - fstream_open(fstream); - vector_move_next(fstreams->items); } + return 0; } @@ -140,12 +125,13 @@ fstreams_add(fstreams_t fstreams, fstream_t fstream) int fstreams_free(void** fstreamsptr) { + int rv; + if(!(* fstreamsptr)) return EINVAL; - - if((errno = vector_free(&((*((fstreams_t*)fstreamsptr))->items)))) - return errno; + if(EAGAIN != (rv = vector_free(&((*((fstreams_t*)fstreamsptr))->items)))) + return rv; free(*fstreamsptr); diff --git a/tools/tesh2/src/htable.c b/tools/tesh2/src/htable.c index 5b7cb606ca..5c1abebb85 100644 --- a/tools/tesh2/src/htable.c +++ b/tools/tesh2/src/htable.c @@ -141,7 +141,7 @@ htable_remove(htable_t htable, const void* key) *prev = hassoc->next; val = (void*)hassoc->val; - if((errno = allocator_dealloc(htable->allocator,hassoc))) + if(allocator_dealloc(htable->allocator,hassoc)) return NULL; return val; @@ -162,6 +162,7 @@ htable_erase(htable_t htable, const void* key) hassoc_t* prev; fn_cmp_key_t fn_cmp_key; void* val; + int rv; if(!htable || !key) return EINVAL; @@ -177,13 +178,13 @@ htable_erase(htable_t htable, const void* key) *prev = hassoc->next; val = (void*)hassoc->val; - if((errno = allocator_dealloc(htable->allocator,hassoc))) - return errno; + if((rv = allocator_dealloc(htable->allocator,hassoc))) + return rv; if(htable->fn_finalize) { - if((errno = (*(htable->fn_finalize))(&val))) - return errno; + if((rv = (*(htable->fn_finalize))(&val))) + return rv; } return 0; @@ -199,6 +200,7 @@ int htable_free(htable_t* htableptr) { htable_t htable; + int rv; if(!(*htableptr)) return EINVAL; @@ -221,16 +223,16 @@ htable_free(htable_t* htableptr) for(hassoc = content[pos]; hassoc; hassoc = hassoc->next) { val = (void*)hassoc->val; - if((errno = (*(htable->fn_finalize))(&val))) - return errno; + if((rv = (*(htable->fn_finalize))(&val))) + return rv; } } } free(htable->content); - if((errno = allocator_free(&(htable->allocator)))) - return errno; + if((rv = allocator_free(&(htable->allocator)))) + return rv; free(*htableptr); *htableptr = NULL; @@ -246,6 +248,7 @@ htable_clear(htable_t htable) register int pos; int size; void* val; + int rv; if(!htable) return EINVAL; @@ -261,8 +264,8 @@ htable_clear(htable_t htable) for(hassoc = content[pos]; hassoc; hassoc = hassoc->next) { val = (void*)hassoc->val; - if((errno = (*(htable->fn_finalize))(&val))) - return errno; + if((rv = (*(htable->fn_finalize))(&val))) + return rv; } content[pos] = NULL; diff --git a/tools/tesh2/src/lstrings.c b/tools/tesh2/src/lstrings.c index b87f2bf202..1d5c6d95b0 100644 --- a/tools/tesh2/src/lstrings.c +++ b/tools/tesh2/src/lstrings.c @@ -140,9 +140,10 @@ lstrings_clear(lstrings_t lstrings) return EINVAL; if(!lstrings->size) - return EAGAIN; + return 0; - while(lstrings_pop_back(lstrings)); + while(lstrings->size) + lstrings_pop_back(lstrings); return 0; } diff --git a/tools/tesh2/src/main.c b/tools/tesh2/src/main.c index 94e9599491..135e328ac0 100644 --- a/tools/tesh2/src/main.c +++ b/tools/tesh2/src/main.c @@ -8,6 +8,7 @@ #include #include +#include /* * entry used to define the parameter of a tesh option. @@ -44,8 +45,12 @@ prev_error_mode = 0; directory_t root_directory = NULL; -int +/*int exit_code = 0; +*/ + +int +want_detail_summary = 0; /* the current version of tesh */ static const char* @@ -86,7 +91,7 @@ directories = NULL; /* the include directories : see the !i metacommand */ vector_t -includes = NULL; +include_dirs = NULL; /* the list of tesh files to run */ static fstreams_t @@ -133,12 +138,6 @@ want_display_version = 0; static int want_check_syntax = 0; -/* if 1, all the tesh file of the current directory - * are runned - */ -static int -want_load_directory = 0; - /* if 1, the status of all the units is display at * the end. */ @@ -183,25 +182,31 @@ xbt_os_sem_t units_sem = NULL; static int -prepared = 0; - +loaded = 0; int -interrupted = 0; +interrupted = 0; + +int +exit_code = 0; + +pid_t +pid =0; /* the table of the entries of the options */ static const struct s_optentry opt_entries[] = { - { 'C', string, (byte*)&directories, 0, "directory" }, + { 'C', string, (byte*)NULL, 0, "directory" }, { 'x', string, (byte*)&suffixes, 0, "suffix" }, { 'e', flag, (byte*)&env_overrides, 0, "environment-overrides", }, { 'f', string, (byte*)&fstreams, 0, "file" }, { 'h', flag, (byte*)&want_display_usage, 0, "help" }, { 'a', flag, (byte*)&want_display_semantic, 0, "semantic" }, { 'i', flag, (byte*)&want_keep_going_unit, 0, "keep-going-unit" }, - { 'I', string, (byte*)&includes, 0, "include-dir" }, + { 'I', string, (byte*)&include_dirs, 0, "include-dir" }, { 'j', number, (byte*)&number_of_jobs, (byte*) &optional_number_of_jobs, "jobs" }, { 'k', flag, (byte*)&want_keep_going, 0, "keep-going" }, + { 'm', flag, (byte*)&want_detail_summary, 0, "detail-summary" }, { 'c', flag, (byte*)&want_just_display, 0, "just-display" }, { 'd', flag, (byte*)&display_data_base, 0,"display-data-base" }, { 'q', flag, (byte*)&question, 0, "question" }, @@ -211,7 +216,7 @@ static const struct s_optentry opt_entries[] = { 'n', flag, (byte*)&want_dry_run, 0, "dry-run"}, { 't', number, (byte*)&timeout, 0, "timeout" }, { 'S', flag, (byte*)&want_check_syntax, 0, "check-syntax"}, - { 'r', flag, (byte*)&want_load_directory, 0, "load-directory"}, + { 'r', string, (byte*)&directories, 0, "load-directory"}, { 'v', flag, (byte*)&want_verbose, 0, "verbose"}, { 'F', string,(byte*)&excludes, 0, "exclude"}, { 'l', string,(byte*)&logs,0,"log"}, @@ -259,6 +264,7 @@ static const char* usage[] = " -b, --build-file Build a tesh file.\n", " -r, --load-directory Run all the tesh files located in the directories specified by the option --directory.\n", " -v, --verbose Display the status of the commands.\n", + " -m, --detail-summary Detail the summary of the run.\n", " -F file , --exclude=FILE Ignore the tesh file FILE.\n", " -l format, --log Format of the xbt logs.\n", NULL @@ -278,11 +284,11 @@ init_options(void); static int process_command_line(int argc, char** argv); -static int +static void load(void); static void -display_usage(int exit_code); +display_usage(void); static void display_version(void); @@ -301,16 +307,21 @@ init(void); int main(int argc, char* argv[]) { - init(); - + if(init() < 0) + finalize(); + /* process the command line */ - if((exit_code = process_command_line(argc, argv))) + if(process_command_line(argc, argv) < 0) finalize(); + + /* move to the root directory (the directory may change during the command line processing) */ + chdir(root_directory->name); /* initialize the xbt library * for thread portability layer */ + /* xbt initialization */ if(!lstrings_is_empty(logs)) { int size = lstrings_get_size(logs); @@ -342,16 +353,12 @@ main(int argc, char* argv[]) finalize(); } - if(!directories_has_directories_to_load(directories) && want_load_directory) - WARN0("--load-directory specified but no directory specified"); + /* load tesh files */ + load(); - excludes_check(excludes, fstreams); - /* load tesh */ - if((exit_code = load())) - finalize(); - - prepared = 1; + /* use by the finalize function to known if it must display the tesh usage */ + loaded = 1; if(-2 == number_of_jobs) {/* --jobs is not specified (use the default value) */ @@ -365,27 +372,22 @@ main(int argc, char* argv[]) if(number_of_jobs > fstreams_get_size(fstreams)) {/* --jobs = N is specified and N is more than the number of tesh files */ - WARN0("number of requested jobs exceed the number of files"); + WARN0("Number of requested jobs exceed the number of files to run"); /* assume one job per file */ number_of_jobs = fstreams_get_size(fstreams); } - /* initialize the semaphore used to synchronize the jobs */ + /* initialize the semaphore used to synchronize all the units */ jobs_sem = xbt_os_sem_init(number_of_jobs); /* initialize the semaphore used by the runner to wait for the end of all units */ units_sem = xbt_os_sem_init(0); /* initialize the runner */ - if((0 != (exit_code = runner_init( - want_check_syntax, - timeout, - fstreams)))) - { + if(runner_init(want_check_syntax, timeout, fstreams)) finalize(); - } - + if(want_just_display && want_silent) want_silent = 0; @@ -393,17 +395,17 @@ main(int argc, char* argv[]) WARN0("mismatch in the syntax : --just-check-syntax and --just-display options at same time"); /* run all the units */ - runner_run(); + runner_run(); + /* show the result of the units */ if(want_verbose || want_dry_run) runner_display_status(); - /* all the test are runned, destroy the runner */ runner_destroy(); - /* then, finalize tesh */ + /* then, finalize tesh (release all the allocated memory and exits) */ finalize(); #ifndef WIN32 @@ -412,10 +414,21 @@ main(int argc, char* argv[]) } +/* init -- initialize tesh : allocated all the objects needed by tesh to run + * the tesh files specified in the command line. + * + * return If successful the function returns zero. Otherwise the function returns + * -1 and sets the global variable errno to the appropriate error code. + */ + + + static int init(void) { - char* buffer = getcwd(NULL, 0); + char* buffer; + + #ifdef WIN32 /* Windows specific : don't display the general-protection-fault message box and @@ -425,99 +438,176 @@ init(void) prev_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); #endif - /* used to store the file streams to run */ - fstreams = fstreams_new(DEFAULT_FSTREAMS_CAPACITY, fstream_free); + /* used to store the files to run */ + if(!(fstreams = fstreams_new(DEFAULT_FSTREAMS_CAPACITY, fstream_free))) + { + ERROR0("Insufficient memory is available to initialize tesh : system error"); + return -1; + } + + /* register the current directory */ + if(!(buffer = getcwd(NULL, 0))) + { + exit_code = errno; + + if(EACCES == errno) + ERROR0("tesh initialization failed - Insufficient permission to read the current directory"); + else + ERROR0("Insufficient memory is available to initialize tesh : system error"); + + return -1; + } + + /* save the root directory */ + if(!(root_directory = directory_new(buffer))) + { + ERROR0("Insufficient memory is available to initialize tesh : system error"); + return -1; + } - root_directory = directory_new(buffer,want_load_directory); free(buffer); - /* used to store the directories to loads */ - directories = directories_new(); - /* register the current directory */ - directories_add(directories, root_directory); + /* the directories to loads */ + if(!(directories = directories_new())) + { + ERROR0("Insufficient memory is available to initialize tesh : system error"); + return -1; + } - /* used to store the includes directories */ - includes = vector_new(DEFAULT_INCLUDES_CAPACITY, directory_free); + /* the include directories */ + if(!(include_dirs = vector_new(DEFAULT_INCLUDE_DIRS_CAPACITY, directory_free))) + { + ERROR0("Insufficient memory is available to initialize tesh : system error"); + return -1; + } - /* xbt logs */ - logs = lstrings_new(); + /* xbt logs option */ + if(!(logs = lstrings_new())) + { + ERROR0("Insufficient memory is available to initialize tesh : system error"); + return -1; + } - /* used to to store all the excluded file streams */ - excludes = excludes_new(); + /* the excluded files */ + if(!(excludes = excludes_new())) + { + ERROR0("Insufficient memory is available to initialize tesh : system error"); + return -1; + } - /* list of file streams suffixes */ - suffixes = lstrings_new(); + /* the suffixes */ + if(!(suffixes = lstrings_new())) + { + ERROR0("Insufficient memory is available to initialize tesh : system error"); + return -1; + } - lstrings_push_back(suffixes,".tesh"); + /* register the default suffix ".tesh" */ + if(lstrings_push_back(suffixes,".tesh")) + { + ERROR0("Insufficient memory is available to initialize tesh : system error"); + return -1; + } + + pid = getpid(); return 0; } -static int +/* load -- load the tesh files to run */ +static void load(void) { - chdir(directory_get_name(root_directory)); - if(want_load_directory) + /* if the directories object is not empty load all the tesh files contained in + * the directories specified in the command line (this tesh files must have the + * a suffix specified in the suffixes object. + */ + if(!directories_is_empty(directories)) directories_load(directories, fstreams, suffixes); - /* on a aucun fichier specifie dans la ligne de commande - * l'option --run-current-directory n'a pas ete specifie ou aucun fichier ne se trouve dans le repertoire a charger + /* if no tesh file has been specified in the command line try to load the default tesh file + * teshfile from the current directory */ if(fstreams_is_empty(fstreams)) { struct stat buffer = {0}; - /* add the default tesh file if it exists */ + /* add the default tesh file if it exists in the current directory */ if(!stat("teshfile", &buffer) && S_ISREG(buffer.st_mode)) fstreams_add(fstreams, fstream_new(getcwd(NULL, 0), "teshfile")); } + /* excludes the files specified in the command line and stored in the excludes object */ if(!excludes_is_empty(excludes) && !fstreams_is_empty(fstreams)) + { + /* check the files to excludes before */ + excludes_check(excludes, fstreams); + + /* exclude the specified tesh files */ fstreams_exclude(fstreams, excludes); + } + /* if the fstreams object is empty use the stdin */ if(fstreams_is_empty(fstreams)) fstreams_add(fstreams, fstream_new(NULL, "stdin")); + /* load the tesh files (open them) */ fstreams_load(fstreams); - return 0; } +/* finalize -- cleanup all the allocated objects and display the tesh usage if needed */ static void finalize(void) { - if((!exit_code && want_display_usage) || (!exit_code && !prepared)) - display_usage(exit_code); + /* if there is not an error and the user wants display the usage or + * if there is an error and all the files to load are loaded, display the usage + */ + if((!exit_code && want_display_usage) || (!exit_code && !loaded)) + display_usage(); + /* delete the fstreams object */ if(fstreams) fstreams_free((void**)&fstreams); + /* delete the excludes object */ if(excludes) excludes_free((void**)&excludes); + /* delete the directories object */ if(directories) directories_free((void**)&directories); - - if(includes) - vector_free(&includes); + /* delete the root directory object */ + if(root_directory) + directory_free((void**)&root_directory); + + /* delete the include directories object */ + if(include_dirs) + vector_free(&include_dirs); + + /* delete the list of tesh files suffixes */ if(suffixes) lstrings_free(&suffixes); + /* delete the xbt log options list */ if(logs) lstrings_free(&logs); + - /* destroy the semaphore used to synchronize the jobs */ + /* destroy the semaphore used to synchronize the units */ if(jobs_sem) xbt_os_sem_destroy(jobs_sem); - + + /* destroy the semaphore used by the runner used to wait for the end of the units */ if(units_sem) xbt_os_sem_destroy(units_sem); /* exit from the xbt framework */ xbt_exit(); + /* Windows specific (restore the previouse error mode */ #ifdef WIN32 SetErrorMode(prev_error_mode); #endif @@ -525,56 +615,50 @@ finalize(void) if(!want_verbose && !want_dry_run && !want_silent && !want_just_display) INFO2("tesh terminated with exit code %d : %s",exit_code, (!exit_code ? "success" : error_to_string(exit_code))); + /* exit with the last error code */ exit(exit_code); } +/* init_options -- initialize the options string */ static void init_options (void) { char *p; unsigned int i; + /* the function has been already called */ if(optstring[0] != '\0') - /* déjà traité. */ return; p = optstring; - /* Return switch and non-switch args in order, regardless of - POSIXLY_CORRECT. Non-switch args are returned as option 1. */ - /* le premier caractère de la chaîne d'options vaut -. - * les arguments ne correspondant pas à une option sont - * manipulés comme s'ils étaient des arguments d'une option - * dont le caractère est le caractère de code 1 - */ *p++ = '-'; for (i = 0; opt_entries[i].c != '\0'; ++i) { - /* initialize le nom de l'option longue*/ + /* initialize the long name of the option*/ longopts[i].name = (opt_entries[i].long_name == 0 ? "" : opt_entries[i].long_name); - /* getopt_long() retourne la valeur de val */ + /* getopt_long returns the value of val */ longopts[i].flag = 0; - /* la valeur de l'option courte est le caractère spécifié dans opt_entries[i].c */ + /* the short option */ longopts[i].val = opt_entries[i].c; - /* on l'ajoute à la chaine des optstring */ + /* add the short option in the options string */ *p++ = opt_entries[i].c; switch (opt_entries[i].type) { - /* si c'est une option qui sert a positionner un flag ou que l'on doit ignorée, elle n'a pas d'argument */ + /* if this option is used to set a flag or if the argument must be ignored + * the option has no argument + */ case flag: longopts[i].has_arg = no_argument; break; - /* c'est une option qui attent un argument : - * une chaine de caractères, un nombre flottant, - * ou un entier positif - */ + /* the option has an argument */ case string: case number: @@ -597,6 +681,18 @@ init_options (void) longopts[i].name = 0; } +/* process_command_line -- process the command line + * + * param argc the number of the arguments contained by the command line. + * param The array of C strings containing all the arguments of the command + * line. + * + * return If successful, the function returns 0. Otherwise -1 is returned + * and sets the global variable errno to indicate the error. + * + * errors [ENOENT] A file name specified in the command line does not exist + */ + static int process_command_line(int argc, char** argv) { @@ -605,17 +701,18 @@ process_command_line(int argc, char** argv) directory_t directory; fstream_t fstream; - /* initialize the options table of tesh */ + /* initialize the options string of tesh */ init_options(); - /* display the errors of the function getopt_long() */ + /* let the function getopt_long display the errors if any */ opterr = 1; + /* set option index to zero */ optind = 0; while (optind < argc) { - c = getopt_long (argc, argv, optstring, longopts, (int *) 0); + c = getopt_long(argc, argv, optstring, longopts, (int *) 0); if(c == EOF) { @@ -624,72 +721,54 @@ process_command_line(int argc, char** argv) } else if (c == 1) { - /* the argument of the command line is not an option (no "-"), assume it's a tesh file */ - /*struct stat buffer = {0}; - char* prev = getcwd(NULL, 0); + /* no option specified, assume it's a tesh file to run */ + char* path; + char* delimiter; - directory = directories_get_back(directories); - - chdir(directory->name); - - if(stat(optarg, &buffer) || !S_ISREG(buffer.st_mode)) + /* getpath returns -1 when the file to get the path doesn't exist */ + if(getpath(optarg, &path) < 0) { - chdir(prev); - free(prev); - ERROR1("file %s not found", optarg); - return EFILENOTFOUND; + exit_code = errno; + + if(ENOENT == errno) + ERROR1("File %s does not exist", optarg); + else + ERROR0("Insufficient memory is available to parse the command line : system error"); + + return -1; } - chdir(prev); - free(prev);*/ + /* get to the last / (if any) to get the short name of the file */ + delimiter = strrchr(optarg,'/'); - directory = directories_search_fstream_directory(directories, optarg); + /* create a new file stream which represents the tesh file to run */ + fstream = fstream_new(path, delimiter ? delimiter + 1 : optarg); - if(!directory) - { - if(1 == directories_get_size(directories)) - { - ERROR1("file %s not found in the current directory",optarg); - return EFILENOTINCURDIR; - } - else - { - ERROR1("file %s not found in the specified directories",optarg); - return EFILENOTINSPECDIR; - } - } + free(path); - if(!(fstream = fstream_new(directory_get_name(directory), optarg))) + /* if the list of all tesh files to run already contains this file + * destroy it and display a warning, otherwise add it in the list. + */ + if(fstreams_contains(fstreams, fstream)) { - ERROR1("command line processing failed with the error code %d", errno); - return EPROCESSCMDLINE; + fstream_free((void**)&fstream); + WARN1("File %s already specified to be run", optarg); } else - { - if(fstreams_contains(fstreams, fstream)) - { - fstream_free((void**)&fstream); - WARN1("file %s already specified", optarg); - } - else - { - if((errno = fstreams_add(fstreams, fstream))) - { - fstream_free((void**)&fstream); - ERROR1("command line processing failed with the error code %d", errno); - return EPROCESSCMDLINE; - } - } - } + fstreams_add(fstreams, fstream); + + + + } else if (c == '?') { - /* unknown option, getopt_long() displays the error */ - return 1; + /* unknown option, let getopt_long() displays the error */ + return -1; } else { - for (entry = opt_entries; entry->c != '\0'; ++entry) + for(entry = opt_entries; entry->c != '\0'; ++entry) if(c == entry->c) { @@ -698,8 +777,9 @@ process_command_line(int argc, char** argv) { /* impossible */ default: - ERROR0("command line processing failed : internal error"); - return EPROCESSCMDLINE; + ERROR0("Command line processing failed : internal error"); + exit_code = EPROCCMDLINE; + return -1; /* flag options */ @@ -720,51 +800,79 @@ process_command_line(int argc, char** argv) else if (*optarg == '\0') { /* a non optional argument is not specified */ - ERROR2("the option %c \"%s\"requires an argument",entry->c,entry->long_name); - return EARGNOTSPEC; + ERROR2("Option %c \"%s\"requires an argument",entry->c,entry->long_name); + exit_code = ENOARG; + return -1; } - /* --directory option */ - if(!strcmp(entry->long_name,"directory")) + /* --load-directory option */ + if(!strcmp(entry->long_name,"load-directory")) { - if(!(directory = directory_new(optarg, want_load_directory))) + char* path; + + if(translatepath(optarg, &path) < 0) { + exit_code = errno; + if(ENOTDIR == errno) - { - ERROR1("directory %s not found",optarg); - return EDIRNOTFOUND; - } + ERROR1("%s is not a directory",optarg); else - { - ERROR1("command line processing failed with the error code %d", errno); - return EPROCESSCMDLINE; - } + ERROR0("Insufficient memory is available to process the command line - system error"); + + return -1; + } else { + directory = directory_new(path); + free(path); + if(directories_contains(directories, directory)) { directory_free((void**)&directory); - WARN1("directory %s already specified",optarg); + WARN1("Directory %s already specified to be load",optarg); } else - { - if((errno = directories_add(directories, directory))) - { - directory_free((void**)&directory); - ERROR1("command line processing failed with the error code %d", errno); - return EPROCESSCMDLINE; - } - } + directories_add(directories, directory); + + } } + else if(!strcmp(entry->long_name,"directory")) + { + char* path ; + + if(translatepath(optarg, &path) < 0) + { + exit_code = errno; + + if(ENOTDIR == errno) + ERROR1("%s is not a directory",optarg); + else + ERROR0("Insufficient memory is available to process the command line - system error"); + + return -1; + } + else + { + if(!dont_want_display_directory) + INFO1("Entering directory \"%s\"",path); + + chdir(path); + free(path); + + + } + } + /* --suffix option */ else if(!strcmp(entry->long_name,"suffix")) { if(strlen(optarg) > MAX_SUFFIX) { - ERROR1("suffix %s too long",optarg); - return ESUFFIXTOOLONG; + ERROR1("Suffix %s too long",optarg); + exit_code = ESUFFIXTOOLONG; + return -1; } if(optarg[0] == '.') @@ -773,14 +881,14 @@ process_command_line(int argc, char** argv) sprintf(suffix,".%s",optarg); if(lstrings_contains(suffixes, suffix)) - WARN1("suffix %s already specified", optarg); + WARN1("Suffix %s already specified to be used", optarg); else lstrings_push_back(suffixes, suffix); } else { if(lstrings_contains(suffixes, optarg)) - WARN1("suffix %s already specified", optarg); + WARN1("Suffix %s already specified to be used", optarg); else lstrings_push_back(suffixes, optarg); } @@ -788,135 +896,100 @@ process_command_line(int argc, char** argv) /* --file option */ else if(!strcmp(entry->long_name,"file")) { + char* path; + char* delimiter; - /* the argument of the command line is not an option (no "-"), assume it's a tesh file */ - /*struct stat buffer = {0}; - char* prev = getcwd(NULL, 0); - - directory = directories_get_back(directories); - - chdir(directory->name); - - if(stat(optarg, &buffer) || !S_ISREG(buffer.st_mode)) + if(getpath(optarg, &path) < 0) { - chdir(prev); - free(prev); - ERROR1("file %s not found", optarg); - return EFILENOTFOUND; + exit_code = errno; + + if(ENOENT == errno) + ERROR1("File %s does not exist", optarg); + else + ERROR0("Insufficient memory is available to process the command line - system error"); + + return -1; } - chdir(prev); - free(prev);*/ + delimiter = strrchr(optarg,'/'); - directory = directories_search_fstream_directory(directories, optarg); - - if(!directory) - { - if(1 == directories_get_size(directories)) - { - ERROR1("file %s not found in the current directory",optarg); - return EFILENOTINCURDIR; - } - else - { - ERROR1("file %s not found in the specified directories",optarg); - return EFILENOTINSPECDIR; - } - } + fstream = fstream_new(path, delimiter ? delimiter + 1 : optarg); - if(!(fstream = fstream_new(directory_get_name(directory),optarg))) + free(path); + + if(fstreams_contains(fstreams, fstream)) { - ERROR1("command line processing failed with the error code %d", errno); - return EPROCESSCMDLINE; + fstream_free((void**)&fstream); + WARN1("File %s already specified to run", optarg); } else - { - if(fstreams_contains(fstreams, fstream)) - { - fstream_free((void**)&fstream); - WARN1("file %s already specified", optarg); - } - else - { - if((errno = fstreams_add(fstreams, fstream))) - { - fstream_free((void**)&fstream); - ERROR1("command line processing failed with the error code %d", errno); - return EPROCESSCMDLINE; - } - } - } + fstreams_add(fstreams, fstream); } /* --include-dir option */ else if(!strcmp(entry->long_name,"include-dir")) { - if(!(directory = directory_new(optarg, want_load_directory))) + + char* path ; + + if(translatepath(optarg, &path) < 0) { + exit_code = errno; + if(ENOTDIR == errno) - { ERROR1("%s is not a directory",optarg); - return EDIRNOTFOUND; - } else - { - ERROR1("command line processing failed with the error code %d", errno); - return EPROCESSCMDLINE; - } + ERROR0("Insufficient memory is available to process the command line - system error"); + + return -1; } else { - if(vector_contains(includes, directory)) + + directory = directory_new(path); + free(path); + + if(vector_contains(include_dirs, directory)) { directory_free((void**)&directory); - WARN1("include directory %s already specified",optarg); + WARN1("Include directory %s already specified to be used",optarg); } else - { - if((errno = vector_push_back(includes, directory))) - { - directory_free((void**)&directory); - ERROR1("command line processing failed with the error code %d", errno); - return EPROCESSCMDLINE; - } - } + vector_push_back(include_dirs, directory); } } /* --exclude option */ else if(!strcmp(entry->long_name,"exclude")) { - directory = directories_get_back(directories); - if(!(fstream = fstream_new(directory_get_name(directory), optarg))) + char* path; + char* delimiter; + + if(getpath(optarg, &path) < 0) { + exit_code = errno; + if(ENOENT == errno) - { - ERROR1("file to exclude %s not found", optarg); - return EFILENOTFOUND; - } + ERROR1("file %s does not exist", optarg); else - { - ERROR1("command line processing failed with the error code %d", errno); - return EPROCESSCMDLINE; - } + ERROR0("Insufficient memory is available to process the command line - system error"); + + return -1; } - else + + delimiter = strrchr(optarg,'/'); + + fstream = fstream_new(path, delimiter ? delimiter + 1 : optarg); + free(path); + + if(excludes_contains(excludes, fstream)) { - if(excludes_contains(excludes, fstream)) - { - fstream_free((void**)&fstream); - WARN1("file to exclude %s already specified", optarg); - } - else - { - if((errno = excludes_add(excludes, fstream))) - { - fstream_free((void**)&fstream); - ERROR1("command line processing failed with the error code %d", errno); - return EPROCESSCMDLINE; - } - } - } + fstream_free((void**)&fstream); + WARN1("File %s already specified to be exclude", optarg); + } + else + excludes_add(excludes, fstream); + } /* --log option */ else if(!strcmp(entry->long_name,"log")) @@ -925,7 +998,8 @@ process_command_line(int argc, char** argv) } else { - /* TODO */ + INFO1("Unexpected option %s", optarg); + return -1; } @@ -953,8 +1027,9 @@ process_command_line(int argc, char** argv) if (i < 1 || cp[0] != '\0') { - ERROR2("option %c \"%s\" requires an strictly positive integer as argument",entry->c, entry->long_name); - return ENOTPOSITIVENUM; + ERROR2("Option %c \"%s\" requires an strictly positive integer as argument",entry->c, entry->long_name); + exit_code = ENOTPOSITIVENUM; + return -1; } else *(int*)entry->value = i; @@ -975,7 +1050,7 @@ process_command_line(int argc, char** argv) } static void -display_usage(int exit_code) +display_usage(void) { const char **cpp; FILE* stream; diff --git a/tools/tesh2/src/reader.c b/tools/tesh2/src/reader.c index 29b1c9555f..4b962a7f8a 100644 --- a/tools/tesh2/src/reader.c +++ b/tools/tesh2/src/reader.c @@ -15,6 +15,7 @@ reader_new(command_t command) reader->command = command; reader->broken_pipe = 0; reader->failed = 0; + reader->done = 0; reader->started = xbt_os_sem_init(0); @@ -127,9 +128,7 @@ reader_start_routine(void* p) command_handle_failure(command, csr_read_failure); } - reader->broken_pipe = 1; - - /*printf("the reader of the command %p is ended\n",command);*/ + reader->done = 1; return NULL; } diff --git a/tools/tesh2/src/runner.c b/tools/tesh2/src/runner.c index aeec092fba..d71d459851 100644 --- a/tools/tesh2/src/runner.c +++ b/tools/tesh2/src/runner.c @@ -1,13 +1,20 @@ #include #include +#include #include +#include #include /* for error code */ #include /* for calloc() */ -#include +#include + +#include XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh); +extern char** +environ; + /* the unique tesh runner */ static runner_t runner = NULL; @@ -24,7 +31,7 @@ runner_start_routine(void* p); * the want_check_syntax is specified. Returns * 0 if the syntax is clean. */ -static int +static void check_syntax(void); #ifdef WIN32 @@ -96,19 +103,19 @@ int runner_init(int want_check_syntax, int timeout, fstreams_t fstreams) { - if(runner) - { - ERROR0("Runner is already initialized"); - return EEXIST; - } - + int i; + char* val; + char buffer[MAX_PATH + 1] = {0}; + int code; + const char* cstr; + variable_t variable; - runner = xbt_new0(s_runner_t, 1); + if(!(runner = (runner_t)calloc(1, sizeof(s_runner_t)))) + return errno; + if(!(runner->units = units_new(runner, fstreams))) { - ERROR0("Runner initialization failed"); - free(runner); runner = NULL; return errno; @@ -121,13 +128,60 @@ runner_init(int want_check_syntax, int timeout, fstreams_t fstreams) runner->number_of_runned_units = 0; runner->waiting = 0; - if(want_check_syntax) + runner->total_of_tests = 0; + runner->total_of_successeded_tests = 0; + runner->total_of_failed_tests = 0; + runner->total_of_interrupted_tests = 0; + + runner->total_of_units = 0; + runner->total_of_successeded_units = 0; + runner->total_of_failed_units = 0; + runner->total_of_interrupted_units = 0; + + runner->total_of_suites = 0; + runner->total_of_successeded_suites = 0; + runner->total_of_failed_suites = 0; + runner->total_of_interrupted_suites = 0; + + /* initialize the vector of variables */ + runner->variables = vector_new(32, (fn_finalize_t)variable_free); + + + for(i = 0; environ[i] != NULL; i++) + { + val = strchr(environ[i], '='); + + if(val) + { + val++; + + if(val[0] != '\0') + strncpy(buffer, environ[i], (val - environ[i] -1)); + + variable = variable_new(buffer, val); + variable->env = 1; + + /*printf("Add the environment variable %s %s\n", variable->name, variable->val);*/ + + vector_push_back(runner->variables, variable); + } + } + + i = 0; + + while((cstr = error_get_at(i++, &code))) { - if((errno = check_syntax())) - return errno; + sprintf(buffer,"%d",code); + variable = variable_new(cstr, buffer); + variable->err = 1; + vector_push_back(runner->variables, variable); } + + + if(want_check_syntax) + check_syntax(); - return 0; + return exit_code; } @@ -135,6 +189,8 @@ void runner_destroy(void) { units_free((void**)(&(runner->units))); + vector_free(&runner->variables); + #ifdef WIN32 CloseHandle(timer_handle); @@ -202,29 +258,85 @@ runner_interrupt(void) void runner_display_status(void) { + if(!want_dry_run) { + struct rusage r_usage; - /*unit_t unit;*/ - - printf("Runner\n"); - printf("Status informations :\n"); - - printf(" number of units %d\n",units_get_size(runner->units)); - printf(" exit code %d (%s)\n",exit_code, exit_code ? error_to_string(exit_code) : "success"); + /*printf("\033[1m");*/ + printf("\n TEst SHell utility - mini shell specialized in running test units.\n"); + printf(" =============================================================================\n"); + /*printf("\033[0m");*/ units_verbose(runner->units); + + /*printf("\033[1m");*/ + printf(" =====================================================================%s\n", + runner->total_of_failed_tests ? "== FAILED": (runner->total_of_interrupted_tests || runner->total_of_interrupted_units) ? "==== INTR" : "====== OK"); + + printf(" TOTAL : Suite(s): %.0f%% ok (%d suite(s): %d ok", + (runner->total_of_suites ? (1-((double)runner->total_of_failed_suites + (double)runner->total_of_interrupted_suites)/(double)runner->total_of_suites)*100.0 : 100.0), + runner->total_of_suites, runner->total_of_successeded_suites); + + if(runner->total_of_failed_suites > 0) + printf(", %d failed", runner->total_of_failed_suites); + + if(runner->total_of_interrupted_suites > 0) + printf(", %d interrupted)", runner->total_of_interrupted_suites); + + printf(")\n"); + + printf(" Unit(s): %.0f%% ok (%d unit(s): %d ok", + (runner->total_of_units ? (1-((double)runner->total_of_failed_units + (double)runner->total_of_interrupted_units)/(double)runner->total_of_units)*100.0 : 100.0), + runner->total_of_units, runner->total_of_successeded_units); + + if(runner->total_of_failed_units > 0) + printf(", %d failed", runner->total_of_failed_units); + + if(runner->total_of_interrupted_units > 0) + printf(", %d interrupted)", runner->total_of_interrupted_units); + + printf(")\n"); + + printf(" Test(s): %.0f%% ok (%d test(s): %d ok", + (runner->total_of_tests ? (1-((double)runner->total_of_failed_tests + (double)runner->total_of_interrupted_tests)/(double)runner->total_of_tests)*100.0 : 100.0), + runner->total_of_tests, runner->total_of_successeded_tests); + + if(runner->total_of_failed_tests > 0) + printf(", %d failed", runner->total_of_failed_tests); + + if(runner->total_of_interrupted_tests > 0) + printf(", %d interrupted)", runner->total_of_interrupted_tests); + + printf(")\n\n"); + + + if(!getrusage(RUSAGE_SELF, &r_usage)) + { + + printf(" Total tesh user time used: %ld second(s) %ld microsecond(s)\n", r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec); + printf(" Total tesh system time used: %ld second(s) %ld microsecond(s)\n\n", r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec); + + if(!getrusage(RUSAGE_CHILDREN, &r_usage)) + { + printf(" Total children user time used: %ld second(s) %ld microsecond(s)\n", r_usage.ru_utime.tv_sec, r_usage.ru_utime.tv_usec); + printf(" Total children system time used: %ld second(s) %ld microsecond(s)\n\n", r_usage.ru_stime.tv_sec, r_usage.ru_stime.tv_usec); + + } + } + + /*printf("\033[0m");*/ } else { if(exit_code) ERROR0("Syntax error detected"); - else if(exit_code == 0) + else if(!exit_code) INFO0("Syntax 0K"); } } -static int +static void check_syntax(void) { if(!want_dry_run) @@ -235,7 +347,7 @@ check_syntax(void) want_dry_run = 0; - if(0 == exit_code) + if(!exit_code) { if(!want_silent) INFO0("syntax checked (OK)"); @@ -250,5 +362,4 @@ check_syntax(void) WARN0("mismatch in the syntax : --just-check-syntax and --check-syntax options at same time"); } - return exit_code; } diff --git a/tools/tesh2/src/unit.c b/tools/tesh2/src/unit.c index 1f540d65f5..fefd585efa 100644 --- a/tools/tesh2/src/unit.c +++ b/tools/tesh2/src/unit.c @@ -3,18 +3,49 @@ #include #include #include - - +#include +#include XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh); +static void +replace_variables(unit_t unit, char** line) +{ + variable_t variable; + char name[MAX_PATH + 1] = {0}; + + /* check if some commands have setted some environment variables */ + /* TODO */ + + /*printf("repalce all the variables of the line %s\n", *line);*/ + + + xbt_os_mutex_acquire(unit->mutex); + + vector_rewind(unit->runner->variables); + + while((variable = vector_get(unit->runner->variables))) + { + sprintf(name, "$%s", variable->name); + /*printf("try to replace all the variable %s\n",name);*/ + str_replace_all(line, name, variable->val); + + vector_move_next(unit->runner->variables); + memset(name, 0, MAX_PATH + 1); + } + + xbt_os_mutex_release(unit->mutex); + + /*printf("line after the variables replacement %s\n",*line);*/ + +} /* the unit thread start routine */ static void* unit_start(void* p); unit_t -unit_new(runner_t runner, suite_t owner, fstream_t fstream) +unit_new(runner_t runner, unit_t root, unit_t owner, fstream_t fstream) { unit_t unit = xbt_new0(s_unit_t, 1); @@ -26,6 +57,7 @@ unit_new(runner_t runner, suite_t owner, fstream_t fstream) unit->sem = NULL; unit->commands = vector_new(DEFAULT_COMMANDS_CAPACITY, (fn_finalize_t)command_free); + unit->includes = vector_new(DEFAULT_INCLUDES, (fn_finalize_t)unit_free); unit->thread = NULL; @@ -34,6 +66,7 @@ unit_new(runner_t runner, suite_t owner, fstream_t fstream) unit->number_of_failed_commands = 0; unit->number_of_successeded_commands = 0; unit->number_of_terminated_commands = 0; + unit->number_of_waiting_commands = 0; unit->interrupted = 0; unit->failed = 0; unit->successeded = 0; @@ -43,21 +76,27 @@ unit_new(runner_t runner, suite_t owner, fstream_t fstream) unit->owner = owner; + + unit->root = root ? root : unit; + + unit->number = 0; - unit->suites = vector_new(DEFAULT_COMMANDS_CAPACITY, (fn_finalize_t)suite_free); + unit->suites = vector_new(DEFAULT_SUITES_CAPACITY, (fn_finalize_t)unit_free); unit->owner = owner; unit->running_suite = 0; + unit->is_suite = 0; + unit->description = NULL; return unit; } -void +/*void unit_add_suite(unit_t unit, suite_t suite) { vector_push_back(unit->suites, suite); -} +}*/ int unit_free(void** unitptr) @@ -66,13 +105,17 @@ unit_free(void** unitptr) vector_free(&((*__unitptr)->commands)); + vector_free(&((*__unitptr)->includes)); + vector_free(&((*__unitptr)->suites)); /* if the unit is interrupted during its run, the semaphore is NULL */ if((*__unitptr)->sem) xbt_os_sem_destroy((*__unitptr)->sem); - + if((*__unitptr)->description) + free((*__unitptr)->description); + free((*__unitptr)->suites); free(*__unitptr); @@ -88,10 +131,11 @@ unit_start(void* p) xbt_os_thread_t thread; xbt_os_mutex_t mutex; - context_t context; - int i; + /*context_t context;*/ + int i, j; unit_t unit = (unit_t)p; + unit_t include; xbt_os_mutex_acquire(unit->mutex); unit->runner->number_of_runned_units++; @@ -101,17 +145,22 @@ unit_start(void* p) xbt_os_sem_acquire(jobs_sem); mutex = xbt_os_mutex_init(); - context = context_new(); + /*context = context_new();*/ if(want_dry_run) INFO1("checking unit %s...",unit->fstream->name); /* parse the file */ - unit_parse(unit, context, mutex, unit->fstream->name, unit->fstream->stream); + /*unit_parse(unit, context, mutex, unit->fstream->name, unit->fstream->stream);*/ + + fstream_parse(unit->fstream, unit, mutex); + /* if the unit is not interrupted and not failed the unit, all the file is parsed * so all the command are launched */ + + if(!unit->interrupted) { unit->parsed = 1; @@ -120,37 +169,86 @@ unit_start(void* p) * so the unit release the semaphore itself */ if(!unit->released && (unit->number_of_started_commands == (unit->number_of_failed_commands + unit->number_of_interrupted_commands + unit->number_of_successeded_commands))) + { + /*INFO1("the unit %s is released", unit->fstream->name);*/ xbt_os_sem_release(unit->sem); + } + else + { + + INFO1("the unit %s is not released", unit->fstream->name); + INFO1("number of started commands %d", unit->number_of_started_commands); + INFO1("number of failed commands %d", unit->number_of_failed_commands); + INFO1("number of interrupted commands %d", unit->number_of_interrupted_commands); + INFO1("number of successeded commands %d", unit->number_of_successeded_commands); + INFO1("number of waiting commands %d", unit->number_of_waiting_commands); + + + if(unit->number_of_waiting_commands) + { + command_t command; + int i, j; + + for(i = 0; i < vector_get_size(unit->includes) ; i++) + { + include = vector_get_at(unit->includes, i); + + for(j = 0; j < vector_get_size(include->commands); j++) + { + command = vector_get_at(include->commands, j); + + if(command->status == cs_in_progress) + { + INFO2("the command %s PID %d is in process", command->context->command_line, command->pid); + + if(command->writer->done) + INFO2("the writer of the command %s PID %d done", command->context->command_line, command->pid); + else + INFO2("the writer of the command %s PID %d doesn't done", command->context->command_line, command->pid); + } + } + + } + } + } } /* wait the end of all the commands or a command failure or an interruption */ - - xbt_os_sem_acquire(unit->sem); + if(unit->interrupted) { command_t command; - + /* interrupt all the running commands of the unit */ - for(i = 0; i < unit->number_of_commands; i++) + for(i = 0; i < vector_get_size(unit->commands); i++) { - /*command = unit->commands[i];*/ command = vector_get_at(unit->commands, i); if(command->status == cs_in_progress) - /*command_interrupt(unit->commands[i]);*/ command_interrupt(command); } + + for(i = 0; i < vector_get_size(unit->includes); i++) + { + include = vector_get_at(unit->includes, i); + + for(j = 0; j < vector_get_size(include->commands); j++) + { + command = vector_get_at(include->commands, j); + + if(command->status == cs_in_progress) + command_interrupt(command); + } + } + } - /* wait the end of the threads */ - for(i = 0; i < unit->number_of_commands; i++) + for(i = 0; i < vector_get_size(unit->commands); i++) { - /*thread = unit->commands[i]->thread;*/ - command_t command = vector_get_at(unit->commands, i); thread = command->thread; @@ -158,10 +256,25 @@ unit_start(void* p) xbt_os_thread_join(thread,NULL); } - context_free(&context); - + for(i = 0; i < vector_get_size(unit->includes); i++) + { + include = vector_get_at(unit->includes, i); + + for(j = 0; j < vector_get_size(include->commands); j++) + { + command_t command = vector_get_at(include->commands, j); + thread = command->thread; + + if(thread) + xbt_os_thread_join(thread,NULL); + } + } + + /*context_free(&context);*/ + xbt_os_mutex_destroy(mutex); + xbt_os_mutex_acquire(unit->mutex); /* increment the number of ended units */ @@ -175,11 +288,12 @@ unit_start(void* p) /* first release the mutex */ xbt_os_mutex_release(unit->mutex); + xbt_os_sem_release(units_sem); } else xbt_os_mutex_release(unit->mutex); - + /* release the jobs semaphore, then the next unit can start */ xbt_os_sem_release(jobs_sem); @@ -236,6 +350,11 @@ unit_parse(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* fil unit_handle_failure(unit); break; } + else if(unit->running_suite) + { + /* TODO */ + } + if(context->command_line) { @@ -309,13 +428,20 @@ unit_parse(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* fil xbt_strbuff_free(buff); } + + void unit_handle_line(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char * filepos, char *line) { + char* line2; /* Search end */ xbt_str_rtrim(line+2,"\n"); - switch (line[0]) + line2 = strdup(line); + + replace_variables(unit, &line2); + + switch (line2[0]) { case '#': break; @@ -323,17 +449,18 @@ unit_handle_line(unit_t unit, context_t context, xbt_os_mutex_t mutex, const cha case '$': case '&': - context->async = (line[0] == '&'); + context->async = (line2[0] == '&'); /* further trim useless chars which are significant for in/output */ - xbt_str_rtrim(line+2," \t"); + xbt_str_rtrim(line2+2," \t"); /* Deal with CD commands here, not in rctx */ - if (!strncmp("cd ",line+2,3)) + if(!strncmp("cd ",line2 + 2, 3)) { - char *dir=line+4; - - if (context->command_line) + /*char *dir=line2+4; */ + char* dir = strdup(line2 + 4); + + if(context->command_line) { if(!want_dry_run) { @@ -351,12 +478,10 @@ unit_handle_line(unit_t unit, context_t context, xbt_os_mutex_t mutex, const cha VERB1("Saw cd '%s'",dir); - /*if(want_dry_run) - { - unit->number_of_successeded_commands++; - }*/ + if(!want_dry_run) { + if(chdir(dir)) { ERROR2("Chdir to %s failed: %s",dir,strerror(errno)); @@ -364,39 +489,50 @@ unit_handle_line(unit_t unit, context_t context, xbt_os_mutex_t mutex, const cha exit_code = ECHDIR; unit_handle_failure(unit); } + + } break; } /* else, pushline */ else { - unit_pushline(unit, context, mutex, filepos, line[0], line+2 /* pass '$ ' stuff*/); + unit_pushline(unit, context, mutex, filepos, line2[0], line2+2 /* pass '$ ' stuff*/); break; } case '<': case '>': case '!': - unit_pushline(unit, context, mutex, filepos, line[0], line+2 /* pass '$ ' stuff*/); + unit_pushline(unit, context, mutex, filepos, line2[0], line2+2 /* pass '$ ' stuff*/); break; case 'p': if(!want_dry_run) - INFO2("[%s] %s",filepos,line+2); + INFO2("[%s] %s",filepos,line2+2); break; case 'P': if(!want_dry_run) - CRITICAL2("[%s] %s",filepos,line+2); + CRITICAL2("[%s] %s",filepos,line2+2); + break; + + case 'D': + if(unit->description) + WARN2("description already specified %s %s", filepos, line2); + else + unit->description = strdup(line2 + 2); break; default: - ERROR2("[%s] Syntax error: %s",filepos, line); + ERROR2("[%s] Syntax error: %s",filepos, line2); ERROR1("Test suite `%s': NOK (syntax error)",unit->fstream->name); exit_code = ESYNTAX; unit_handle_failure(unit); break; } + + free(line2); } void @@ -540,23 +676,292 @@ unit_pushline(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* VERB1("[%s] (ignore output of next command)", filepos); } - else if(!strncmp(line,"include", strlen("include"))) + else if(!strncmp(line,"include ", strlen("include "))) { - unit_handle_include(unit, context, mutex, line + strlen("include ")); + char* p1; + char* p2; + + p1 = line + strlen("include"); + + while(*p1 == ' ' || *p1 == '\t') + p1++; + + + if(p1[0] == '\0') + { + + exit_code = ESYNTAX; + ERROR1("include file not specified %s ", filepos); + unit_handle_failure(unit); + } + else + { + char file_name[MAX_PATH + 1] = {0}; + + /*INFO1("p1 is %s",p1);*/ + + p2 = p1; + + while(*p2 != '\0' && *p2 != ' ' && *p2 != '\t') + { + /*INFO1("p2 is %s",p2);*/ + p2++; + + } + /*INFO1("p2 is %s",p2);*/ + + strncpy(file_name, p1, p2 - p1); + + /*INFO1("filename is %s", file_name);*/ + + if(p2[0] != '\0') + while(*p2 == ' ' || *p2 == '\t') + p2++; + + unit_handle_include(unit, context, mutex, file_name, p2[0] != '\0' ? p2 : NULL); + + } } - - else if(!strncmp(line,"suite", strlen("suite"))) + else if(!strncmp(line,"suite ", strlen("suite "))) { unit_handle_suite(unit, context, mutex, line + strlen("suite ")); } - else + else if(!strncmp(line,"unsetenv ", strlen("unsetenv "))) + { + int i; + int number_of_variables; + int exists = 0; + int env; + variable_t variable; + char* name = line + strlen("unsetenv "); + + xbt_os_mutex_acquire(unit->mutex); + + number_of_variables = vector_get_size(unit->runner->variables); + + for(i = 0; i < number_of_variables; i++) + { + variable = vector_get_at(unit->runner->variables, i); + + if(!strcmp(variable->name, name)) + { + env = variable->env; + exists = 1; + break; + } + } + + if(env) + { + if(exists) + vector_erase_at(unit->runner->variables, i); + else + WARN3("environment variable %s not found %s %s", name, line, filepos); + } + else + { + if(exists) + WARN3("%s is an not environment variable use unset metacommand to delete it %s %s", name, line, filepos); + else + WARN3("%s environment variable not found %s %s", name, line, filepos); + } + + xbt_os_mutex_release(unit->mutex); + + + } + else if(!strncmp(line,"setenv ", strlen("setenv "))) + { + char* val; + char name[MAX_PATH + 1] = {0}; + char* p; + + p = line + strlen("setenv "); + + val = strchr(p, '='); + + if(val) + { + variable_t variable; + int exists = 0; + int env = 0; + val++; + + /* syntax error */ + if(val[0] == '\0') + { + + exit_code = ESYNTAX; + ERROR2("indefinite variable value %s %s", line, filepos); + unit_handle_failure(unit); + } + + + + strncpy(name, p, (val - p -1)); + + /* test if the variable is already registred */ + + xbt_os_mutex_acquire(unit->mutex); + + vector_rewind(unit->runner->variables); + + while((variable = vector_get(unit->runner->variables))) + { + + if(!strcmp(variable->name, name)) + { + variable->env = 1; + exists = 1; + break; + } + + vector_move_next(unit->runner->variables); + } + + /* if the variable is already registred, update its value; + * otherwise register it. + */ + if(exists) + { + if(env) + { + free(variable->val); + variable->val = strdup(val); + setenv(variable->name, variable->val, 1); + } + else + WARN3("%s variable already exists %s %s", name, line, filepos); + } + else + { + variable = variable_new(name, val); + variable->env = 1; + + vector_push_back(unit->runner->variables, variable); + + setenv(variable->name, variable->val, 0); + } + + xbt_os_mutex_release(unit->mutex); + + } + } + else if(!strncmp(line,"unset ", strlen("unset "))) { - ERROR2("%s: Malformed metacommand: %s",filepos,line); - ERROR1("Test suite `%s': NOK (syntax error)",unit->fstream->name); - exit_code = ESYNTAX; - unit_handle_failure(unit); - return; + int i; + int number_of_variables; + int exists = 0; + int env; + int err; + variable_t variable; + char* name = line + strlen("unset "); + + xbt_os_mutex_acquire(unit->mutex); + + number_of_variables = vector_get_size(unit->runner->variables); + + for(i = 0; i < number_of_variables; i++) + { + variable = vector_get_at(unit->runner->variables, i); + + if(!strcmp(variable->name, name)) + { + env = variable->env; + err = variable->err; + exists = 1; + break; + } + } + + if(!env) + { + if(exists) + vector_erase_at(unit->runner->variables, i); + else + WARN3("variable %s not found %s %s", name, line, filepos); + } + else if(env) + { + WARN3("%s is an environment variable use unsetenv metacommand to delete it %s %s", name, line, filepos); + } + else + { + WARN3("%s is an error variable : you are not allowed to delete it %s %s", name, line, filepos); + } + xbt_os_mutex_release(unit->mutex); + } + else + { + /* may be a variable */ + char* val; + char name[MAX_PATH + 1] = {0}; + + val = strchr(line, '='); + + if(val) + { + variable_t variable; + int exists = 0; + val++; + + /* syntax error */ + if(val[0] == '\0') + { + + exit_code = ESYNTAX; + ERROR2("indefinite variable value %s %s", line, filepos); + unit_handle_failure(unit); + } + + + /* assume it's a varibale */ + strncpy(name, line, (val - line -1)); + + xbt_os_mutex_acquire(unit->mutex); + + /* test if the variable is already registred */ + + vector_rewind(unit->runner->variables); + + while((variable = vector_get(unit->runner->variables))) + { + + if(!strcmp(variable->name, name)) + { + exists = 1; + break; + } + + vector_move_next(unit->runner->variables); + } + + /* if the variable is already registred, update its value; + * otherwise register it. + */ + if(exists) + { + free(variable->val); + variable->val = strdup(val); + } + else + vector_push_back(unit->runner->variables,variable_new(name, val)); + + xbt_os_mutex_release(unit->mutex); + + } + else + { + ERROR2("%s: Malformed metacommand: %s",filepos,line); + ERROR1("Test suite `%s': NOK (syntax error)",unit->fstream->name); + + exit_code = ESYNTAX; + unit_handle_failure(unit); + return; + } + } + break; } @@ -566,15 +971,18 @@ unit_pushline(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* void unit_handle_failure(unit_t unit) { + if(!want_keep_going_unit) { - if(!unit->interrupted) + unit_t root = unit->root ? unit->root : unit; + + if(!root->interrupted) { /* the unit interrupted (exit for the loop) */ - unit->interrupted = 1; + root->interrupted = 1; /* release the unit */ - xbt_os_sem_release(unit->sem); + xbt_os_sem_release(root->sem); } /* if the --keep-going option is not specified */ @@ -622,59 +1030,466 @@ unit_interrupt(unit_t unit) xbt_os_sem_release(unit->sem); } +void +display_title(const char* description) +{ + int i; + char title[80]; + int len = strlen(description); + + title[0]=' '; + + for (i = 1; i < 79; i++) + title[i]='='; + + title[i++]='\n'; + title[79]='\0'; + + sprintf(title + 40 - (len + 4)/2, "[ %s ]",description); + title[40 + (len + 5 ) / 2] = '='; + + printf("\n%s\n",title); +} + void unit_verbose(unit_t unit) { - int i, test_count; + int i, j, k; command_t command; - - printf("\nUnit : %s (%s)\n", unit->fstream->name, unit->fstream->directory); - printf("Status informations :"); - - if(unit->parsed && unit->number_of_successeded_commands == unit->number_of_started_commands) - printf(" - (success)"); + unit_t include; + unit_t suite; + char* p; + char title[MAX_PATH + 1] = {0}; + + int number_of_tests = 0; /* number of tests of a unit contained by this unit */ + int number_of_failed_tests = 0; /* number of failed test of a unit contained by this unit */ + int number_of_successeded_tests = 0; /* number of successeded tests of a unit contained by this unit */ + int number_of_interrupted_tests = 0; /* number of interrupted tests of a unit contained by this unit */ + + int number_of_tests_of_suite = 0; /* number of tests of a suite contained by this unit */ + int number_of_interrupted_tests_of_suite = 0; /* number of interrupted tests of a suite contained by this unit */ + int number_of_failed_tests_of_suite = 0; /* number of failed tests of a suite contained by this unit */ + int number_of_successeded_tests_of_suite = 0; /* number of successeded tests of a suite contained by this */ + + int number_of_units = 0; /* number of units contained by a suite */ + int number_of_failed_units = 0; /* number of failed units contained by a suite */ + int number_of_successeded_units = 0; /* number of successeded units contained by a suite */ + int number_of_interrupted_units = 0; /* number of interrupted units contained by a suite */ + + int total_of_tests = 0; /* total of the tests contained by this unit */ + int total_of_failed_tests = 0; /* total of failed tests contained by this unit */ + int total_of_successeded_tests = 0; /* total of successeded tests contained by this unit */ + int total_of_interrupted_tests = 0; /* total of interrupted tests contained by this unit */ + + int total_of_units = 0; /* total of units contained by this unit */ + int total_of_failed_units = 0; /* total of failed units contained by this unit */ + int total_of_successeded_units = 0; /* total of successeded units contained by this unit */ + int total_of_interrupted_units = 0; /* total of interrutped units contained by this unit */ + + int total_of_suites = 0; /* total of suites contained by this unit */ + int total_of_failed_suites = 0; /* total of failed suites contained by this unit */ + int total_of_successeded_suites = 0; /* total of successeded suites contained by this unit */ + int total_of_interrupted_suites = 0; /* total of interrupted suites contained by this unit */ + + + if(unit->description) + strcpy(title, unit->description); else + sprintf(title, "file : %s",unit->fstream->name); + + if(unit->interrupted) + strcat(title, " (interrupted)"); + + display_title(title); + + number_of_tests = vector_get_size(unit->commands); + + + /* tests */ + for(i = 0; i < number_of_tests; i++) { - if(unit->interrupted) - printf(" - (interruped)"); - else - printf(" - (failed)"); + command = vector_get_at(unit->commands, i); + + if(command->status == cs_interrupted) + number_of_interrupted_tests++; + else if(command->status == cs_failed) + number_of_failed_tests++; + else if(command->status == cs_successeded) + number_of_successeded_tests++; + } - printf("\n"); - - printf(" number of commands : %d\n", unit->number_of_commands); - printf(" number of runned commands : %d\n", unit->number_of_started_commands); - printf(" number of successeded commands : %d\n", unit->number_of_successeded_commands); - printf(" number of failed commands : %d\n", unit->number_of_failed_commands); - printf(" number of interrupted commands : %d\n", unit->number_of_interrupted_commands); + if(number_of_tests) + { + asprintf(&p," Test(s): ........................................................................."); + + p[70] = '\0'; + printf("%s", p); + free(p); + + if(number_of_failed_tests > 0) + printf(".. failed\n"); + else if(number_of_interrupted_tests > 0) + printf("interrupt\n"); + else + printf(".... ..ok\n"); + + + for(i = 0; i < number_of_tests; i++) + { + command = vector_get_at(unit->commands, i); + + printf(" %s: %s [%s]\n", + command->status == cs_interrupted ? "INTR " + : command->status == cs_failed ? "FAILED" + : command->status == cs_successeded ? "PASS " + : "UNKNWN", + command->context->command_line, + command->context->line); + + if(want_detail_summary) + command_display_status(command); + + } + + printf(" =====================================================================%s\n", + number_of_failed_tests ? "== FAILED": number_of_interrupted_tests ? "==== INTR" : "====== OK"); + + printf(" Summary: Test(s): %.0f%% ok (%d test(s): %d ok", + ((1-((double)number_of_failed_tests + (double)number_of_interrupted_tests)/(double)number_of_tests)*100.0), + number_of_tests, number_of_successeded_tests); + + if(number_of_failed_tests > 0) + printf(", %d failed", number_of_failed_tests); + + if(number_of_interrupted_tests > 0) + printf(", %d interrupted)", number_of_interrupted_tests); + + printf(")\n\n"); + + total_of_tests = number_of_tests; + total_of_failed_tests = number_of_failed_tests; + total_of_interrupted_tests = number_of_interrupted_tests; + total_of_successeded_tests = number_of_successeded_tests; + } - test_count = unit->number_of_commands; - for(i = 0; i < test_count; i++) + /* includes */ + + total_of_failed_units = total_of_interrupted_units = total_of_successeded_units = 0; + + number_of_failed_units = number_of_successeded_units = number_of_interrupted_units = 0; + + number_of_units = vector_get_size(unit->includes); + + for(i = 0; i < number_of_units ; i++) { - command = vector_get_at(unit->commands, i); + include = vector_get_at(unit->includes, i); + + number_of_interrupted_tests = number_of_failed_tests = number_of_successeded_tests = 0; + + number_of_tests = vector_get_size(include->commands); + + for(j = 0; j < number_of_tests; j++) + { + command = vector_get_at(include->commands, j); + + if(command->status == cs_interrupted) + number_of_interrupted_tests++; + else if(command->status == cs_failed) + number_of_failed_tests++; + else if(command->status == cs_successeded) + number_of_successeded_tests++; + } + + asprintf(&p," Unit: %s ............................................................................", include->description ? include->description : include->fstream->name); + + p[70] = '\0'; + printf("%s", p); + free(p); + + + if(number_of_failed_tests > 0) + { + total_of_failed_units++; + printf(".. failed\n"); + } + else if(number_of_interrupted_tests > 0) + { + total_of_interrupted_units++; + printf("interrupt\n"); + } + else + { + total_of_successeded_units++; + printf(".... ..ok\n"); + } + + if(want_detail_summary) + { + + for(j = 0; j < vector_get_size(include->commands); j++) + { + command = vector_get_at(include->commands, j); + + printf(" %s: %s [%s]\n", + command->status == cs_interrupted ? "INTR " + : command->status == cs_failed ? "FAILED" + : command->status == cs_successeded ? "PASS " + : "UNKNWN", + command->context->command_line, + command->context->line); + + command_display_status(command); + } + + + } - /*command_display_status(unit->commands[i]);*/ - command_display_status(command); + printf(" =====================================================================%s\n", + number_of_failed_tests ? "== FAILED": number_of_interrupted_tests ? "==== INTR" : "====== OK"); + + + printf(" Summary: Test(s): %.0f%% ok (%d test(s): %d ok", + (number_of_tests ? (1-((double)number_of_failed_tests + (double)number_of_interrupted_tests)/(double)number_of_tests)*100.0 : 100.0), + number_of_tests, number_of_successeded_tests); + + if(number_of_failed_tests > 0) + printf(", %d failed", number_of_failed_tests); + + if(number_of_interrupted_tests > 0) + printf(", %d interrupted)", number_of_interrupted_tests); + + printf(")\n\n"); + + + total_of_tests += number_of_tests; + total_of_failed_tests += number_of_failed_tests; + total_of_interrupted_tests += number_of_interrupted_tests; + total_of_successeded_tests += number_of_successeded_tests; + } + + /* suites */ + + total_of_units = number_of_units; + + total_of_failed_suites = total_of_successeded_suites = total_of_interrupted_suites = 0; + + total_of_suites = vector_get_size(unit->suites); + + for(k = 0; k < total_of_suites; k++) + { + suite = vector_get_at(unit->suites, k); + + display_title(suite->description); + + number_of_tests_of_suite = number_of_interrupted_tests_of_suite = number_of_failed_tests_of_suite = number_of_successeded_tests_of_suite = 0; + + number_of_interrupted_units = number_of_failed_units = number_of_successeded_units = 0; + + number_of_units = vector_get_size(suite->includes); + + for(i = 0; i < number_of_units; i++) + { + number_of_interrupted_tests = number_of_failed_tests = number_of_successeded_tests = 0; + + number_of_tests = vector_get_size(include->commands); + + for(j = 0; j < vector_get_size(include->commands); j++) + { + command = vector_get_at(include->commands, j); + + if(command->status == cs_interrupted) + number_of_interrupted_tests++; + else if(command->status == cs_failed) + number_of_failed_tests++; + else if(command->status == cs_successeded) + number_of_successeded_tests++; + + } + + + include = vector_get_at(suite->includes, i); + asprintf(&p," Unit: %s ............................................................................", include->description ? include->description : include->fstream->name); + + p[70] = '\0'; + printf("%s", p); + free(p); + + if(number_of_failed_tests > 0) + { + number_of_failed_units++; + printf(".. failed\n"); + } + else if(number_of_interrupted_tests > 0) + { + number_of_interrupted_units++; + printf("interrupt\n"); + } + else + { + number_of_successeded_units++; + printf(".... ..ok\n"); + } + + number_of_interrupted_tests_of_suite += number_of_interrupted_tests; + number_of_failed_tests_of_suite += number_of_failed_tests; + number_of_successeded_tests_of_suite += number_of_successeded_tests; + + number_of_tests_of_suite += number_of_tests; + + total_of_tests += number_of_tests; + total_of_failed_tests += number_of_failed_tests; + total_of_interrupted_tests += number_of_interrupted_tests; + total_of_successeded_tests += number_of_successeded_tests; + + if(want_detail_summary) + { + for(j = 0; j < vector_get_size(include->commands); j++) + { + command = vector_get_at(include->commands, j); + + printf(" %s: %s [%s]\n", + command->status == cs_interrupted ? "INTR " + : command->status == cs_failed ? "FAILED" + : command->status == cs_successeded ? "PASS " + : "UNKNWN", + command->context->command_line, + command->context->line); + + command_display_status(command); + + } + + + } + + } + + + + printf(" =====================================================================%s\n", + number_of_failed_tests_of_suite ? "== FAILED": number_of_interrupted_tests_of_suite ? "==== INTR" : "====== OK"); + + if(number_of_failed_tests_of_suite > 0) + total_of_failed_suites++; + else if(number_of_interrupted_tests_of_suite) + total_of_interrupted_suites++; + else + total_of_successeded_suites++; + + total_of_failed_units += number_of_failed_units; + total_of_interrupted_units += number_of_interrupted_units; + total_of_successeded_units += number_of_successeded_units; + + total_of_units += number_of_units; + + printf(" Summary: Unit(s): %.0f%% ok (%d unit(s): %d ok", + (number_of_units ? (1-((double)number_of_failed_units + (double)number_of_interrupted_units)/(double)number_of_units)*100.0 : 100.0), + number_of_units, number_of_successeded_units); + + if(number_of_failed_units > 0) + printf(", %d failed", number_of_failed_units); + + if(number_of_interrupted_units > 0) + printf(", %d interrupted)", number_of_interrupted_units); + + printf(")\n"); + + printf(" Test(s): %.0f%% ok (%d test(s): %d ok", + (number_of_tests_of_suite ? (1-((double)number_of_failed_tests_of_suite + (double)number_of_interrupted_tests_of_suite)/(double)number_of_tests_of_suite)*100.0 : 100.0), + number_of_tests_of_suite, number_of_successeded_tests_of_suite); + + if(number_of_failed_tests_of_suite > 0) + printf(", %d failed", number_of_failed_tests_of_suite); + + if(number_of_interrupted_tests_of_suite > 0) + printf(", %d interrupted)", number_of_interrupted_tests_of_suite); + + printf(")\n\n"); } + + printf(" TOTAL : Suite(s): %.0f%% ok (%d suite(s): %d ok", + (total_of_suites ? (1-((double)total_of_failed_suites + (double)total_of_interrupted_suites)/(double)total_of_suites)*100.0 : 100.0), + total_of_suites, total_of_successeded_suites); + + if(total_of_failed_suites > 0) + printf(", %d failed", total_of_failed_suites); + + if(total_of_interrupted_suites > 0) + printf(", %d interrupted)", total_of_interrupted_suites); + + printf(")\n"); + + printf(" Unit(s): %.0f%% ok (%d unit(s): %d ok", + (total_of_units ? (1-((double)total_of_failed_units + (double)total_of_interrupted_units)/(double)total_of_units)*100.0 : 100.0), + total_of_units, total_of_successeded_units); + + if(total_of_failed_units > 0) + printf(", %d failed", total_of_failed_units); + + if(total_of_interrupted_units > 0) + printf(", %d interrupted)", total_of_interrupted_units); + + printf(")\n"); + + printf(" Test(s): %.0f%% ok (%d test(s): %d ok", + (total_of_tests ? (1-((double)total_of_failed_tests + (double)total_of_interrupted_tests)/(double)total_of_tests)*100.0 : 100.0), + total_of_tests, total_of_successeded_tests); + + if(total_of_failed_tests > 0) + printf(", %d failed", total_of_failed_tests); + + if(total_of_interrupted_tests > 0) + printf(", %d interrupted)", total_of_interrupted_tests); + + printf(")\n\n"); + + + if(unit->interrupted) + unit->runner->total_of_interrupted_units++; + else if(total_of_failed_tests > 0) + unit->runner->total_of_failed_units++; + else + unit->runner->total_of_successeded_units++; + + + unit->runner->total_of_tests += total_of_tests; + unit->runner->total_of_failed_tests += total_of_failed_tests; + unit->runner->total_of_successeded_tests += total_of_successeded_tests; + unit->runner->total_of_interrupted_tests += total_of_interrupted_tests; + + + unit->runner->total_of_units += total_of_units + 1; + unit->runner->total_of_successeded_units += total_of_successeded_units; + unit->runner->total_of_failed_units += total_of_failed_units; + unit->runner->total_of_interrupted_units += total_of_interrupted_units; + + + unit->runner->total_of_suites += total_of_suites; + unit->runner->total_of_successeded_suites += total_of_successeded_suites; + unit->runner->total_of_failed_suites += total_of_failed_suites; + unit->runner->total_of_interrupted_suites += total_of_interrupted_suites; + + + +} + -} void -unit_handle_include(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* file_name) +unit_handle_include(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* file_name, const char* description) { - directory_t include; + directory_t dir; char* prev_directory = NULL; fstream_t fstream = NULL; struct stat buffer = {0}; - if(!stat(file_name, &buffer) && S_ISREG(buffer.st_mode)) { - INFO1("the file stream %s is in the current directory", file_name); + /* the file is in the current directory */ fstream = fstream_new(getcwd(NULL, 0), file_name); fstream_open(fstream); @@ -684,21 +1499,21 @@ unit_handle_include(unit_t unit, context_t context, xbt_os_mutex_t mutex, const { prev_directory = getcwd(NULL, 0); - vector_rewind(includes); + vector_rewind(include_dirs); - while((include = vector_get(includes))) + while((dir = vector_get(include_dirs))) { - chdir(include->name); + chdir(dir->name); if(!stat(file_name, &buffer) && S_ISREG(buffer.st_mode)) { - fstream = fstream_new(include->name, file_name); + fstream = fstream_new(dir->name, file_name); fstream_open(fstream); break; } - vector_move_next(includes); + vector_move_next(include_dirs); } chdir(prev_directory); @@ -716,34 +1531,53 @@ unit_handle_include(unit_t unit, context_t context, xbt_os_mutex_t mutex, const } else { - /* parse the include file */ - - /*unit_t __unit = unit_new(unit->runner, NULL, fstream);*/ - unit->parsing_include_file = 1; - /* add the unit to the list of the runned units */ + if(!unit->running_suite) + {/* it's the unit of a suite */ + unit_t include = unit_new(unit->runner,unit->root, unit, fstream); + + include->mutex = unit->root->mutex; - /*xbt_os_mutex_acquire(unit->mutex); - vector_push_back(__unit->runner->units->items, __unit); - xbt_os_mutex_release(unit->mutex);*/ + if(description) + include->description = strdup(description); + vector_push_back(unit->includes, include); - if(want_dry_run) - INFO2("checking unit %s including in %s...",fstream->name, unit->fstream->name); + fstream_parse(fstream, include, mutex); + } + else + {/* it's a include */ + unit_t owner = vector_get_back(unit->suites); + unit_t include = unit_new(unit->runner,unit->root, owner, fstream); + + include->mutex = unit->root->mutex; + + if(description) + include->description = strdup(description); - unit_parse(unit, context_new(), mutex, fstream->name, fstream->stream); + vector_push_back(owner->includes, include); - fstream_free((void**)&fstream); - unit->parsing_include_file = 0; + fstream_parse(fstream, include, mutex); + } } } void unit_handle_suite(unit_t unit, context_t context, xbt_os_mutex_t mutex, const char* description) { - suite_t suite = suite_new(unit, description); - unit_add_suite(unit, suite); - unit->running_suite = 1; + if(unit->running_suite) + { + exit_code = ESYNTAX; + unit_handle_failure(unit); + } + else + { + unit_t suite = unit_new(unit->runner, unit->root, unit, NULL); + suite->is_suite = 1; + suite->description = strdup(description); + vector_push_back(unit->suites, suite); + unit->running_suite = 1; + } } int diff --git a/tools/tesh2/src/units.c b/tools/tesh2/src/units.c index 500846ffdc..6ed01b4ac5 100644 --- a/tools/tesh2/src/units.c +++ b/tools/tesh2/src/units.c @@ -22,7 +22,7 @@ units_new(runner_t runner, fstreams_t fstreams) while((fstream = vector_get(fstreams->items))) { - if((errno = vector_push_back(units->items, unit_new(runner, NULL, fstream)))) + if(vector_push_back(units->items, unit_new(runner, NULL, NULL, fstream))) { vector_free(&(units->items)); free(units); @@ -191,11 +191,13 @@ units_reset_all(units_t units) int units_free(void** unitsptr) { + int rv; + if(!(*unitsptr)) return EINVAL; - if((errno = vector_free(&((*((units_t*)unitsptr))->items)))) - return errno; + if((rv = vector_free(&((*((units_t*)unitsptr))->items)))) + return rv; free(*unitsptr); *unitsptr = NULL; diff --git a/tools/tesh2/src/variable.c b/tools/tesh2/src/variable.c index e2f66a716d..229ab7e6b8 100644 --- a/tools/tesh2/src/variable.c +++ b/tools/tesh2/src/variable.c @@ -1,8 +1,67 @@ -#include - -typedef struct s_variable -{ - char* name; - char* val; - int used; -}s_variable_t; \ No newline at end of file +#include + +XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh); + +variable_t +variable_new(const char* name, const char* val) +{ + variable_t variable; + + if(!name || !val) + { + errno = EINVAL; + return NULL; + } + + if(!(variable = (variable_t)calloc(1, sizeof(s_variable_t)))) + return NULL; + + variable->name = strdup(name); + variable->val = strdup(val); + variable->used = 0; + variable->env = 0; + variable->err = 0; + + return variable; + +} + +int +variable_free(variable_t* variableptr) +{ + if(!(*variableptr)) + return EINVAL; + + free((*((variable_t*)(variableptr)))->name); + free((*((variable_t*)(variableptr)))->val); + + free(*variableptr); + + *variableptr = NULL; + return 0; +} + + +int +variable_is_used(variable_t variable) +{ + if(!variable) + { + errno = EINVAL; + return 0; + } + + return variable->used; +} + + +int +variable_set_used(variable_t variable) +{ + if(!variable) + return EINVAL; + + variable->used = 1; + + return 0; +} diff --git a/tools/tesh2/src/variables.c b/tools/tesh2/src/variables.c index dff1472f1e..164d199e44 100644 --- a/tools/tesh2/src/variables.c +++ b/tools/tesh2/src/variables.c @@ -1,6 +1 @@ -#include - -typedef struct s_variables -{ - dictionary_t items; -}s_variables_t; \ No newline at end of file +#include \ No newline at end of file diff --git a/tools/tesh2/src/vector.c b/tools/tesh2/src/vector.c index ca8f8907de..a9c67664d6 100644 --- a/tools/tesh2/src/vector.c +++ b/tools/tesh2/src/vector.c @@ -5,6 +5,8 @@ #include #include +#include + #ifdef _MSC_VER #define inline _inline #endif @@ -54,11 +56,13 @@ vector_new(int capacity, fn_finalize_t fn_finalize) int vector_clear(vector_t vector) { + int rv; + if(!vector) return EINVAL; if(!vector->size) - return EAGAIN; + return 0; if(vector->fn_finalize) { @@ -69,8 +73,8 @@ vector_clear(vector_t vector) for(pos = 0; pos < size; pos++) { - if((errno = (*(fn_finalize))(&(items[pos])))) - return errno; + if((rv = (*(fn_finalize))(&(items[pos])))) + return rv; else vector->size--; } @@ -88,11 +92,13 @@ vector_clear(vector_t vector) int vector_free(vector_t* vector_ptr) { + int rv; + if(!(*vector_ptr)) return EINVAL; - if((errno = vector_clear(*vector_ptr))) - return errno; + if((rv = vector_clear(*vector_ptr))) + return rv; free(*vector_ptr); *vector_ptr = NULL; @@ -175,15 +181,16 @@ vector_get_capacity_available(vector_t vector) int vector_push_back(vector_t vector, void* item) { + int rv; + if(!vector || !item) return EINVAL; - /* if all capacity is used, resize the vector */ if(vector->capacity <= vector->size) { - if(!resize(vector)) - return errno; + if((rv = resize(vector))) + return rv; } /* increment the item count and push the new item at the end of the vector */ @@ -191,6 +198,7 @@ vector_push_back(vector_t vector, void* item) vector->pos = -1; + return 0; } @@ -263,6 +271,8 @@ vector_set_at(vector_t vector, int pos, void* item) int vector_insert(vector_t vector, int pos, void* item) { + int rv; + if(!vector) return EINVAL; @@ -280,8 +290,8 @@ vector_insert(vector_t vector, int pos, void* item) if(vector->size >= vector->capacity) { - if(!resize(vector)) - return errno; + if((rv = resize(vector))) + return rv; } if(vector->size) @@ -300,6 +310,8 @@ vector_insert(vector_t vector, int pos, void* item) int vector_erase_at(vector_t vector, int pos) { + int rv; + if(!vector) return EINVAL; @@ -317,8 +329,8 @@ vector_erase_at(vector_t vector, int pos) if(vector->fn_finalize) { - if((errno = (*(vector->fn_finalize))(&(vector->items[pos])))) - return errno; + if((rv = (*(vector->fn_finalize))(&(vector->items[pos])))) + return rv; } if(pos != (vector->size - 1)) @@ -336,7 +348,7 @@ vector_erase_at(vector_t vector, int pos) int vector_erase(vector_t vector, void* item) { - int pos; + int pos, rv; if(!vector || !item) return EINVAL; @@ -349,8 +361,8 @@ vector_erase(vector_t vector, void* item) if(vector->fn_finalize) { - if((errno = (*(vector->fn_finalize))(&item))) - return errno; + if((rv = (*(vector->fn_finalize))(&item))) + return rv; } if(pos != (vector->size - 1)) @@ -368,7 +380,8 @@ int vector_erase_range(vector_t vector, int first, int last) { register int width; - + int rv; + if(!vector || first >= last) return EINVAL; @@ -382,8 +395,8 @@ vector_erase_range(vector_t vector, int first, int last) while(width--) { - if((errno = vector_erase_at(vector,first))) - return errno; + if((rv = vector_erase_at(vector,first))) + return rv; } return 0; @@ -454,6 +467,7 @@ vector_assign(vector_t dst,vector_t src) register int pos; int size; void** items; + int rv; if(!dst || !src ||(dst == src)) @@ -467,13 +481,13 @@ vector_assign(vector_t dst,vector_t src) /* if the destination vector has not enough capacity resize it */ if(size > dst->capacity) { - if((errno = vector_reserve(dst, size - dst->capacity))) - return errno; + if((rv = vector_reserve(dst, size - dst->capacity))) + return rv; } /* clear the destination vector */ - if((errno = vector_clear(dst))) - return errno; + if((rv = vector_clear(dst))) + return rv; dst->fn_finalize = NULL; @@ -481,8 +495,8 @@ vector_assign(vector_t dst,vector_t src) /* file the destination vector */ for(pos = 0; pos < size; pos++) - if((errno = vector_push_back(dst,items[pos]))) - return errno; + if((rv = vector_push_back(dst,items[pos]))) + return rv; dst->pos = -1; @@ -613,6 +627,7 @@ vector_reserve(vector_t vector, int size) if(!(items = (void**)realloc(vector->items, size * sizeof(void*)))) return errno; + vector->capacity = size; vector->items = items; diff --git a/tools/tesh2/src/writer.c b/tools/tesh2/src/writer.c index 97aa2dcc1e..c3ba975f59 100644 --- a/tools/tesh2/src/writer.c +++ b/tools/tesh2/src/writer.c @@ -13,7 +13,10 @@ writer_new(command_t command) writer->thread = NULL; writer->command = command; - writer->started = xbt_os_sem_init(0); + writer->written = xbt_os_sem_init(0); + writer->can_write = xbt_os_sem_init(0); + + writer->done = 0; return writer; } @@ -21,6 +24,10 @@ writer_new(command_t command) void writer_free(writer_t* writer) { + + /*xbt_os_sem_destroy((*writer)->started); + xbt_os_sem_destroy((*writer)->can_write);*/ + free(*writer); *writer = NULL; } @@ -145,21 +152,33 @@ writer_start_routine(void* p) { writer_t writer = (writer_t)p; command_t command = writer->command; - long number_of_bytes_to_write = command->context->input->used; + int number_of_bytes_to_write = command->context->input->used; char* input = (char*)(command->context->input->data); int got; + int released = 0; + + + xbt_os_sem_acquire(writer->can_write); - xbt_os_sem_release(writer->started); while(!command->failed && !command->interrupted && !command->successeded && number_of_bytes_to_write > 0) { - got = number_of_bytes_to_write > SSIZE_MAX ? SSIZE_MAX : number_of_bytes_to_write; - got = write( writer->command->stdin_fd, input, got ); - + got = number_of_bytes_to_write > PIPE_BUF ? PIPE_BUF : number_of_bytes_to_write; + got = write(writer->command->stdin_fd, input, got ); + if(got < 0) { - if(EINTR == errno || EAGAIN == errno) - { + if(EINTR == errno) + continue; + + else if(EAGAIN == errno) + {/* the pipe is full */ + if(!released) + { + xbt_os_sem_release(writer->written); + released = 1; + } + continue; } else if(EPIPE == errno) @@ -179,9 +198,20 @@ writer_start_routine(void* p) input += got; if(got == 0) - usleep(100); + xbt_os_thread_yield(); + + } + + if(!released) + { + xbt_os_sem_release(writer->written); + released = 1; } + + close(command->stdin_fd); + command->stdin_fd = INDEFINITE_FD; + command->context->input->data[0]='\0'; command->context->input->used=0; @@ -198,9 +228,7 @@ writer_start_routine(void* p) command_handle_failure(command, csr_write_pipe_broken); } - - close(command->stdin_fd); - command->stdin_fd = INDEFINITE_FD; + writer->done = 1; return NULL; -- 2.30.2