Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
s/NOTRECEIPT/NOTRECEIVED/ (plus some reindent)
[simgrid.git] / tools / tesh2 / src / command.c
index 15cc6eb..3f911f6 100644 (file)
-
-#include <command.h>
-#include <context.h>
-#include <writer.h>
-#include <reader.h>
-#include <timer.h>
-
-#ifndef WIN32
-#include <sys/types.h>
-#include <sys/wait.h>
-#endif
-
-#include "../include/_signal.h"
-
-
-XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);
-
-static void*
-command_start(void* p);
-
-
-command_t
-command_new(unit_t unit, context_t context, xbt_os_mutex_t mutex)
-{
-       command_t command = xbt_new0(s_command_t, 1);
-       
-       /* get the context of the execution of the command */
-       command->context = context_dup(context);
-       
-       /* the exit code of the command is indefinite */
-       command->exit_code = INDEFINITE;
-       
-       /* the signal of the command is indefinite */
-       command->signal = INDEFINITE_SIGNAL;
-       
-       command->failed = 0;
-       command->interrupted = 0;
-       
-       /* the mutex used to safetly access to the command unit properties */
-       command->mutex = mutex;
-       
-       if(context->output->used)
-               /* instantiate the buffer filled with the content of the command stdout */
-               command->output = xbt_strbuff_new();
-       else
-               command->output = NULL;
-
-       command->pid = INDEFINITE_PID;
-       
-       command->stat_val = -1;
-       
-       /* set the unit of the command */
-       command->unit = unit; 
-       
-       /* all the commands are runned in a thread */
-       command->thread = NULL;
-       
-       command->successeded = 0;
-       
-       if(context->output->used)
-               command->reader = reader_new(command);
-       else
-               command->reader = NULL;
-
-       if(context->input->used)
-               command->writer = writer_new(command);
-       else
-               command->writer = NULL;
-
-       if(context->timeout != INDEFINITE)
-               command->timer = timer_new(command);
-       else
-               command->timer = NULL;
-
-       command->status = cs_initialized;
-       command->reason = csr_unknown;
-       
-       command->stdin_fd = INDEFINITE_FD;
-       command->stdout_fd = INDEFINITE_FD;
-       
-       
-       /* 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)++;
-       xbt_os_mutex_release(mutex);
-       
-       #ifndef WIN32
-       command->killed = 0;
-       #endif
-
-       return command;
-}
-
-void
-command_run(command_t command)
-{
-       if(!want_silent)
-               INFO1("tesh %s",command->context->command_line);
-       
-       if(!want_just_display)
-       {       
-               if(!interrupted)
-               {
-                       /* start the command */
-                       
-                       if(command->context->async)
-                       {
-                               command->thread = xbt_os_thread_create("", command_start, command);
-                       
-                               if(!command->thread)
-                                       ERROR0("xbt_os_thread_create() failed\n");
-                       }
-                       else
-                               command_start(command);
-               }
-               else
-               {
-                       command_interrupt(command);             
-               }
-       }
-
-}
-
-static void*
-command_start(void* p)
-{
-       command_t command = (command_t)p;
-       unit_t unit = command->unit;
-       
-       /* the command is started */
-       command->status = cs_started;
-       
-       /* increment the number of started commands of the unit */
-       xbt_os_mutex_acquire(command->mutex);
-       (command->unit->number_of_started_commands)++;
-       xbt_os_mutex_release(command->mutex);
-       
-       /* execute the command of the test */
-       command_exec(command, command->context->command_line);
-       
-       if(cs_in_progress == command->status)
-       {
-               /*printf("the command %p is in progress\n",command);*/
-               
-               /* on attend la fin de la commande.
-                * la command peut soit se terminée normalement,
-                * soit se terminée à la suite d'un timeout, d'une erreur de lecture des son reader ou d'une erreur d'écriture de son writer
-                * soit à la suit d'une demande d'interruption
-                */
-               
-               command_wait(command);
-       
-               if(cs_failed != command->status && cs_interrupted != command->status)
-               {
-                       /*printf("checking the command %p\n",command);*/
-                       command_check(command);
-               }
-       }
-       
-       
-       xbt_os_mutex_acquire(command->mutex);
-       
-       /* if it's the last command release its unit */
-       if(!unit->interrupted && unit->parsed && (unit->number_of_started_commands == (unit->number_of_failed_commands + unit->number_of_interrupted_commands + unit->number_of_successeded_commands)))
-       {
-               /* first release the mutex */
-               unit->released = 1;
-               xbt_os_mutex_release(command->mutex);
-               /* the last command release the unit */
-               xbt_os_sem_release(command->unit->sem);
-       }
-       else
-               xbt_os_mutex_release(command->mutex);
-               
-       
-       /* wait the end of the timer, the reader and the writer */
-       if(command->timer && command->timer->thread)
-               timer_wait(command->timer);
-
-       if(command->writer && command->writer->thread)
-               writer_wait(command->writer);
-
-       if(command->reader && command->reader->thread)
-               reader_wait(command->reader);
-       
-       return NULL;
-}
-
-#ifdef WIN32
-void
-command_exec(command_t command, const char* command_line)
-{
-       
-       STARTUPINFO si = {0};                                   /* contains the informations about the child process windows*/
-       PROCESS_INFORMATION pi = {0};                   /* contains child process informations                                          */
-       SECURITY_ATTRIBUTES sa = {0};                   /* contains the security descriptor for the pipe handles        */
-       HANDLE child_stdin_handle[2] = {NULL};  /* child_stdin_handle[1]        <-> stdout of the child process */
-       HANDLE child_stdout_handle[2] = {NULL}; /* child_stdout_handle[0]       <-> stdin of the child process  */
-       HANDLE child_stderr = NULL;
-       
-       sa.nLength = sizeof(SECURITY_ATTRIBUTES);
-    sa.lpSecurityDescriptor = NULL;                    /* use default security for the pipe handles                            */
-       
-       sa.bInheritHandle = TRUE;                               /* the pipe handles can be inherited                                            */
-       
-       if(!CreatePipe(&(child_stdin_handle[0]),&(child_stdin_handle[1]),&sa,0))
-    {
-               ERROR1("CreatePipe1() failed (%lu)",GetLastError());
-               command->failed = 1;
-               command->status = cs_failed;    
-
-               return;
-    }
-       
-       
-       if(!DuplicateHandle(GetCurrentProcess(),(child_stdin_handle[1]),GetCurrentProcess(),&(child_stderr),0,TRUE,DUPLICATE_SAME_ACCESS))
-    {
-               ERROR1("DuplicateHandle1() failed (%lu)",GetLastError());
-               
-               CloseHandle(child_stdin_handle[0]);
-               CloseHandle(child_stdin_handle[1]);
-
-               command->failed = 1;
-               command->status = cs_failed;    
-
-               return;
-    }
-       
-       if(!CreatePipe(&(child_stdout_handle[0]),&(child_stdout_handle[1]),&sa,0))
-    {
-               ERROR1("CreatePipe2() failed (%lu)",GetLastError()); 
-               
-               CloseHandle(child_stdout_handle[0]);
-               CloseHandle(child_stdout_handle[1]);
-               CloseHandle(child_stdin_handle[0]);
-               CloseHandle(child_stdin_handle[1]);
-
-               command->failed = 1;
-               command->status = cs_failed;    
-
-               return;
-    }
-               
-       /* Read handle for read operations on the child std output. */
-       if(!DuplicateHandle(GetCurrentProcess(),(child_stdin_handle[0]),GetCurrentProcess(),&(command->stdout_fd),0,FALSE, DUPLICATE_SAME_ACCESS))
-    {
-               CloseHandle(child_stdout_handle[0]);
-               CloseHandle(child_stdout_handle[1]);
-               CloseHandle(child_stdin_handle[0]);
-               CloseHandle(child_stdin_handle[1]);
-
-               command->failed = 1;
-               command->status = cs_failed;    
-
-               ERROR1("DuplicateHandle2() failed (%lu)",GetLastError()); 
-    }
-       
-       
-       /* Write handle for write operations on the child std input. */
-       if(!DuplicateHandle(GetCurrentProcess(),(child_stdout_handle[1]),GetCurrentProcess(),&(command->stdin_fd), 0,FALSE,DUPLICATE_SAME_ACCESS))
-    {
-               CloseHandle(child_stdout_handle[0]);
-               CloseHandle(child_stdout_handle[1]);
-               CloseHandle(child_stdin_handle[0]);
-               CloseHandle(child_stdin_handle[1]);
-
-               command->failed = 1;
-               command->status = cs_failed;    
-
-               ERROR1("DuplicateHandle3() failed (%lu)",GetLastError());
-    }
-
-       
-       CloseHandle(child_stdin_handle[0]);
-       CloseHandle(child_stdout_handle[1]);
-       
-       if(command->timer)
-       {
-               /* launch the timer */
-               timer_time(command->timer);
-       }
-       
-       if(command->reader)
-       {
-               /* launch the reader */
-               reader_read(command->reader);
-       }
-    
-
-       if(command->writer)
-       {
-               /* launch the writer */
-               writer_write(command->writer);
-       }
-
-    si.cb = sizeof(STARTUPINFO);
-       
-       si.dwFlags |= STARTF_USESTDHANDLES;
-       si.hStdOutput = child_stdin_handle[1];
-       si.hStdInput  = child_stdout_handle[0];
-       si.hStdError  = child_stderr;
-
-       /* launch the process */
-       if(!CreateProcess(
-                                               NULL,
-                                               (char*)command_line,
-                                               NULL,
-                                               NULL,
-                                               TRUE,
-                                               CREATE_NO_WINDOW,
-                                               NULL,
-                                               NULL,
-                                               &si,
-                                               &pi)
-       )
-       {
-               
-               if(ERROR_FILE_NOT_FOUND == GetLastError())
-               {
-                       exit_code = ECMDNOTFOUND;
-                       command_handle_failure(command,csr_command_not_found);
-               }
-               else
-               {
-                       exit_code = EEXEC;
-                       command_handle_failure(command,csr_exec_failure);
-               }
-    }
-       else
-       {
-               /* the command is running */
-               command->status = cs_in_progress;
-
-               /* save the pid of the command */
-               command->pid = pi.hProcess;
-
-               /* close non used thread handle */
-               CloseHandle(pi.hThread);
-               
-       }
-
-       
-       /* close non used handles */
-       CloseHandle(child_stdin_handle[1]);
-    CloseHandle(child_stdout_handle[0]);
-       CloseHandle(child_stderr);
-
-
-}
-#else
-void
-command_exec(command_t command, const char* command_line)
-{
-       int child_stdin_fd[2] ;
-       int child_stdout_fd[2];
-       
-       if(pipe(child_stdin_fd) || pipe(child_stdout_fd)) 
-       {
-               ERROR1("pipe() failed (%d)",errno);
-               command_handle_failure(command, csr_pipe_function_failed);      
-
-               return;
-       }
-       
-       command->pid= fork();
-       
-       if(command->pid < 0) 
-       {
-               close(child_stdin_fd[0]);
-               close(child_stdin_fd[1]);
-               close(child_stdout_fd[0]);
-               close(child_stdout_fd[1]);
-               
-               exit_code = EEXEC;
-               ERROR1("fork() failed (%d)",errno);
-               command_handle_failure(command,csr_exec_failure);
-       }
-       else
-       {
-               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];
-
-                       if(command->reader)
-                       {
-                               /* launch the reader */
-                               reader_read(command->reader);
-                       }
-                   
-                       if(command->writer)
-                       {
-                               /* launch the writer */
-                               writer_write(command->writer);
-                       }
-                       
-                       if(command->timer)
-                       {
-                               /* launch the timer */
-                               timer_time(command->timer);
-                       }
-                       
-                       /* the command is running */
-                       command->status = cs_in_progress;
-               
-               } 
-               else 
-               {/* child */
-               
-                       close(child_stdin_fd[1]);
-                       
-                       dup2(child_stdin_fd[0],0);
-                       
-                       close(child_stdin_fd[0]);
-                       
-                       close(child_stdout_fd[0]);
-                       
-                       dup2(child_stdout_fd[1],1);
-                       
-                       dup2(child_stdout_fd[1],2);
-                       
-                       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);
-                               
-                       if(command->timer)
-                               xbt_os_sem_acquire(command->timer->started);    
-                       
-                       execlp ("/bin/sh", "sh", "-c", command->context->command_line, NULL);
-               }
-       }
-}
-#endif
-
-#ifdef WIN32
-void
-command_wait(command_t command)
-{
-       /* wait for the command terminaison */
-       DWORD rv;
-
-       if(WAIT_FAILED == WaitForSingleObject(command->pid, INFINITE))
-       {
-               ERROR0("WaitForSingleObject() failed");
-               /* TODO : see for the interruption      */      
-       }
-       else
-       {
-               /* don't take care of the timer or the writer or the reader failue */
-               if(cs_failed != command->status && cs_interrupted != command->status)
-               {
-                       if(!GetExitCodeProcess(command->pid,&rv))
-                       {
-                               ERROR1("GetExitCodeProcess() failed for the child %s",command->context->command_line);
-                               /* TODO : see for the interruption      */      
-                       }
-                       else
-                               command->stat_val = command->exit_code = rv;
-               }
-       }
-}
-#else
-void
-command_wait(command_t command)
-{
-       
-       int pid;
-       
-       /* let this thread wait for the child so that the main thread can detect the timeout without blocking on the wait */
-       
-       pid = waitpid(command->pid, &(command->stat_val), 0);
-       
-       /*printf("The %p command ended\n",command);*/
-       if(pid != command->pid) 
-       {
-               ERROR1("waitpid() failed for the child %s",command->context->command_line);
-               exit_code = EWAIT;
-               command_handle_failure(command, csr_wait_failure);
-       }
-       else
-       {
-               if(WIFEXITED(command->stat_val))
-                       command->exit_code = WEXITSTATUS(command->stat_val);    
-       }
-}
-#endif
-
-void
-command_check(command_t command)
-{
-       int success = 1;
-       cs_reason_t reason;
-       
-       /* we have a signal, store it */
-       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);
-       }
-       
-       /* we have a signal and not signal is expected */
-       if(WIFSIGNALED(command->stat_val) && !command->context->signal) 
-       {
-               success = 0;
-               exit_code = EUNEXPECTEDSIG;
-               reason = csr_unexpected_signal_caught;
-       }
-       
-       /* we have a signal that differ form the expected signal */
-       if(success && WIFSIGNALED(command->stat_val) && command->context->signal && strcmp(signal_name(WTERMSIG(command->stat_val),command->context->signal),command->context->signal)) 
-       {
-               success = 0;
-               exit_code = ESIGNOTMATCH;
-               reason = csr_signals_dont_match;
-       }
-       
-       /* we don't receipt the expected signal */
-       if(success && !WIFSIGNALED(command->stat_val) && command->context->signal) 
-       {
-               success = 0;
-               exit_code = ESIGNOTRECEIPT;
-               reason = csr_expected_signal_not_receipt;
-       }
-       
-       /* if the command exit normaly and we expect a exit code : test it */
-       if(success && WIFEXITED(command->stat_val) /* && INDEFINITE != command->context->exit_code*/)
-       {
-               /* the exit codes don't match */
-               if(WEXITSTATUS(command->stat_val) != command->context->exit_code)
-               {
-                       success = 0;
-                       exit_code = EEXITCODENOTMATCH;
-                       reason = csr_exit_codes_dont_match;
-               }
-       }
-       
-       /* if ouput handling flag is specified check the output */
-       if(success && oh_check == command->context->output_handling && command->reader)
-       {
-               /* make sure the reader done */
-               while(!command->reader->broken_pipe)
-                       xbt_os_thread_yield();
-
-                       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(success)
-       {
-               xbt_os_mutex_acquire(command->mutex);
-               
-               if(command->status != cs_interrupted)
-               {
-               
-                       /* signal the success of the command */
-                       command->status = cs_successeded;
-                       command->successeded = 1;
-
-                       /* increment the number of successeded command of the unit */
-                       /*xbt_os_mutex_acquire(command->mutex);*/
-                       (command->unit->number_of_successeded_commands)++;
-               }
-               
-               xbt_os_mutex_release(command->mutex);
-                       
-       }
-       else
-       {
-               command_handle_failure(command,reason);
-       }
-}
-
-#ifdef WIN32
-void
-command_kill(command_t command)
-{
-       if(INDEFINITE_PID != command->pid)
-               TerminateProcess(command->pid, INDEFINITE);
-}
-#else
-void
-command_kill(command_t command)
-{
-       if(INDEFINITE_PID != command->pid)
-       {
-               /*INFO1("Kill the command - PID %d",command->pid);*/
-               
-               kill(command->pid,SIGTERM);
-               
-               if(!command->context->signal)
-                       command->context->signal = strdup("SIGTERM");
-                       
-               command->exit_code = INDEFINITE;
-               command->killed = 1;
-               
-               usleep(100);
-               kill(command->pid,SIGKILL); 
-
-               
-       }
-}
-#endif
-
-void
-command_interrupt(command_t command)
-{
-       xbt_os_mutex_acquire(command->mutex);
-       
-       if((command->status != cs_interrupted) && (command->status != cs_failed) && (command->status != cs_successeded))
-       {
-               /*INFO1("Begin interrupt the command - PID %d",command->pid);*/
-               
-               command->status = cs_interrupted;       
-               command->reason = csr_interruption_request;
-               command->interrupted = 1;
-               xbt_os_mutex_acquire(command->unit->mutex);
-               (command->unit->number_of_interrupted_commands)++;
-               xbt_os_mutex_release(command->unit->mutex);
-               
-               if(command->pid != INDEFINITE_PID)
-                       command_kill(command);
-               
-               
-               /*INFO1("End interrupt the command - PID %d",command->pid);*/
-       }
-       
-       xbt_os_mutex_release(command->mutex);
-       
-       
-}
-
-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
-       {
-               
-               /* 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("    <killed command>\n");
-               #endif
-               
-               /* display the reason of the status of the command */
-               switch(command->reason)
-               {
-                       /* the function pipe or CreatePipe() fails */
-                       case csr_pipe_function_failed :
-                       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");
-                       break;
-
-                       case csr_read_failure :
-                       printf("    reason                      : command stdout read failed\n");
-                       break;
-       
-                       /* writer failure reasons */
-                       case csr_write_failure :
-                       printf("    reason                      : command stdin write failed\n");
-                       break;
-
-                       case csr_write_pipe_broken :
-                       printf("    reason                      : command write pipe broken\n");
-                       break;
-                       
-                       /* timer reason */
-                       case csr_timeout :
-                       printf("    reason                      : command timeouted\n");
-                       break;
-                       
-                       /* command failure reason */
-                       case csr_command_not_found :
-                       printf("    reason                      : command not found\n");
-                       break;
-                       
-                       /* context failure reasons */
-                       case csr_exit_codes_dont_match :
-                       printf("    reason                      : exit codes don't match\n");
-                       
-                       break;
-
-                       case csr_outputs_dont_match :
-                       {
-                               char *diff;
-                               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);
-                               free(diff);
-                       }     
-
-                       break;
-
-                       case csr_signals_dont_match :
-                       printf("    reason                      : signals don't match\n"); 
-                       break;
-                       
-                       case csr_unexpected_signal_caught:
-                       printf("    reason                      : unexpected signal caught\n");
-                       break;
-                       
-                       case csr_expected_signal_not_receipt :
-                       printf("    reason                      : expected signal not receipt\n");
-                       break;
-
-                       /* system failure reasons */
-                       case csr_exec_failure :
-                       printf("    reason                      : can't excute the command\n");
-                       break;
-                       
-                       case csr_wait_failure :
-                       printf("    reason                      : wait command failure\n");
-                       break;
-                       
-                       /* global/local interruption */
-                       case csr_interruption_request :
-                       printf("    reason                      : the command receive a interruption request\n");
-                       break;
-                       
-                       /* unknown ? */
-                       case csr_unknown :
-                       printf("    reason                      : unknown \n");
-               }
-       }
-
-       if(csr_command_not_found != command->reason && csr_exec_failure != command->reason)
-       {
-               if(INDEFINITE != command->exit_code)
-                       /* the 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);
-               else
-                       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");
-               else
-               {
-                       if(NULL != command->signal)
-                               printf("    signal                      : %s\n",command->signal);
-                       
-                       printf("    expected signal             : %s\n",command->context->signal);
-               }
-               
-               /* if the command has out put and the metacommand display output is specified display it  */
-               if(command->output && (0 != command->output->used) && (oh_display == command->context->output_handling))
-               {
-                       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);
-                       free(out);
-               }
-       }
-
-       printf("\n");
-               
-
-}
-
-void
-command_handle_failure(command_t command, cs_reason_t reason)
-{
-       
-       unit_t unit = command->unit;
-       
-       xbt_os_mutex_acquire(command->mutex);
-
-       if((command->status != cs_interrupted) && (command->status != cs_failed))
-       {
-               command->status = cs_failed;
-               command->reason = reason;
-               command->failed = 1;
-               
-               xbt_os_mutex_acquire(unit->mutex);
-               
-               /* increment the number of failed command of the unit */
-               unit->number_of_failed_commands++;
-               
-               /* if the --ignore-failures option is not specified */
-               if(!want_keep_going_unit)
-               {
-                       if(!unit->interrupted)
-                       {
-                               /* the unit interrupted (exit for the loop) */
-                               unit->interrupted = 1;
-
-                               /* release the unit */
-                               xbt_os_sem_release(unit->sem);
-                       }
-                       
-                       /* if the --keep-going option is not specified */
-                       if(!want_keep_going)
-                       {
-                               if(!interrupted)
-                               {
-                                       /* request an global interruption by the runner */
-                                       interrupted = 1;
-                                       
-                                       /* release the runner */
-                                       xbt_os_sem_release(units_sem);
-                               }
-                       }
-               }
-
-               xbt_os_mutex_release(unit->mutex);
-       }
-
-       xbt_os_mutex_release(command->mutex);
-}
-
-void
-command_free(command_t* command)
-{
-       /* close the stdin and the stdout pipe handles */
-
-       #ifdef WIN32
-       if((*command)->stdin_fd != INDEFINITE_FD)
-               CloseHandle((*command)->stdin_fd);
-       if((*command)->stdout_fd != INDEFINITE_FD)
-               CloseHandle((*command)->stdout_fd);
-       #else
-       if((*command)->stdin_fd != INDEFINITE_FD)
-               close((*command)->stdin_fd);
-       
-       if((*command)->stdout_fd != INDEFINITE_FD)      
-               close((*command)->stdout_fd);
-       #endif
-
-       timer_free(&((*command)->timer));
-       writer_free(&((*command)->writer));
-       reader_free(&((*command)->reader));
-       xbt_strbuff_free((*command)->output);
-       context_free(&((*command)->context));
-
-       if((*command)->signal)
-               free((*command)->signal);
-
-       free(*command);
-       *command = NULL;
-}
-
-
-
+/*\r
+ * src/command.c - type representing a command.\r
+ *\r
+ * Copyright 2008,2009 Martin Quinson, Malek Cherier All right reserved.\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify it\r
+ * under the terms of the license (GNU LGPL) which comes with this package.\r
+ *\r
+ * Purpose:\r
+ *             This file contains all the definitions of the functions related with\r
+ *             the tesh command type.\r
+ *\r
+ */\r
+#include <unit.h>\r
+#include <command.h>\r
+#include <context.h>\r
+#include <writer.h>\r
+#include <reader.h>\r
+#include <timer.h>\r
+\r
+#ifndef WIN32\r
+#include <sys/types.h>\r
+#include <sys/wait.h>\r
+#include <sys/stat.h>\r
+#include <unistd.h>\r
+#else\r
+char *\r
+tow32cmd(const char* cmd)\r
+{\r
+       static char w32cmd[PATH_MAX + 1] = {0};\r
+       char cmd_buf[PATH_MAX + 1] = {0};\r
+    size_t i,j, len;\r
+\r
+    if(!cmd)\r
+    {\r
+       errno = EINVAL;\r
+               return NULL;\r
+       }\r
+\r
+       /* TODO : if ~*/\r
+       if(cmd[0] != '.')\r
+       {\r
+               strcpy(w32cmd, cmd);\r
+               return w32cmd;\r
+       }\r
+\r
+       i = j = 0;\r
+       len = strlen(cmd);\r
+\r
+       while(i < len)\r
+       {\r
+               if(cmd[i] != ' ' && cmd[i] != '\t' && cmd[i] != '>')\r
+                       cmd_buf[j++] = cmd[i];\r
+               else\r
+                       break;\r
+\r
+               i++;\r
+       }\r
+\r
+   _fullpath(w32cmd, cmd_buf, sizeof(w32cmd));\r
+\r
+   if(!strstr(w32cmd, ".exe"))\r
+               strcat(w32cmd, ".exe ");\r
+\r
+   strcat(w32cmd, cmd + i);\r
+\r
+\r
+   /*printf("w32cmd : %s", w32cmd);*/\r
+\r
+   return w32cmd;\r
+}\r
+#endif\r
+\r
+#include <com.h>\r
+\r
+#include <xsignal.h>\r
+\r
+#include <is_cmd.h>\r
+\r
+XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);\r
+\r
+static void*\r
+command_start(void* p);\r
+\r
+\r
+command_t\r
+command_new(unit_t unit, context_t context, xbt_os_mutex_t mutex)\r
+{\r
+       command_t command;\r
+\r
+       command = xbt_new0(s_command_t, 1);\r
+\r
+       /* get the context of the execution of the command */\r
+       if(!(command->context = context_dup(context)))\r
+       {\r
+               free(command);\r
+               return NULL;\r
+       }\r
+\r
+       /* the exit code of the command is indefinite */\r
+       command->exit_code = INDEFINITE;\r
+\r
+       /* the signal of the command is indefinite */\r
+       command->signal = INDEFINITE_SIGNAL;\r
+\r
+       command->failed = 0;\r
+       command->interrupted = 0;\r
+\r
+       /* the mutex used to safetly access to the command unit properties */\r
+       command->mutex = mutex;\r
+\r
+       command->output = xbt_strbuff_new();\r
+\r
+       command->pid = INDEFINITE_PID;\r
+\r
+       command->stat_val = -1;\r
+\r
+       /* set the unit of the command */\r
+       command->root = unit->root ? unit->root : unit;\r
+       command->unit = unit;\r
+\r
+       /* all the commands are runned in a thread */\r
+       command->thread = NULL;\r
+\r
+       command->successeded = 0;\r
+\r
+       command->reader = reader_new(command);\r
+\r
+       if(context->input->used)\r
+               command->writer = writer_new(command);\r
+       else\r
+               command->writer = NULL;\r
+\r
+       if(context->timeout != INDEFINITE)\r
+               command->timer = timer_new(command);\r
+       else\r
+               command->timer = NULL;\r
+\r
+       command->status = cs_initialized;\r
+       command->reason = csr_unknown;\r
+\r
+       command->stdin_fd = INDEFINITE_FD;\r
+       command->stdout_fd = INDEFINITE_FD;\r
+\r
+\r
+       /* register the command */\r
+       xbt_os_mutex_acquire(mutex);\r
+\r
+       xbt_dynar_push(unit->commands, &command);\r
+       command->root->cmd_nb++;\r
+       xbt_os_mutex_release(mutex);\r
+\r
+       #ifndef WIN32\r
+       command->killed = 0;\r
+       command->execlp_errno = 0;\r
+       #endif\r
+\r
+\r
+       return command;\r
+}\r
+\r
+int\r
+command_run(command_t command)\r
+{\r
+       if(!silent_flag && !interrupted)\r
+               INFO2("[%s] %s",command->context->pos, command->context->command_line);\r
+\r
+       if(!just_print_flag)\r
+       {\r
+               if(!interrupted)\r
+               {\r
+                       /* start the command in a thread*/\r
+                       if(command->context->async)\r
+                       {\r
+                               command->thread = xbt_os_thread_create("", command_start, command);\r
+\r
+                       }\r
+                       else\r
+                       {\r
+                               /* start the command in the main thread */\r
+                               command_start(command);\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       command_interrupt(command);\r
+               }\r
+\r
+\r
+       }\r
+\r
+       return 0;\r
+\r
+}\r
+\r
+static void*\r
+command_start(void* p)\r
+{\r
+       command_t command = (command_t)p;\r
+       unit_t root = command->root;\r
+\r
+       /* the command is started */\r
+       command->status = cs_started;\r
+\r
+       /* increment the number of started commands of the unit */\r
+       xbt_os_mutex_acquire(command->mutex);\r
+       (root->started_cmd_nb)++;\r
+       xbt_os_mutex_release(command->mutex);\r
+\r
+       /* execute the command of the test */\r
+\r
+       #ifndef WIN32\r
+       command_exec(command, command->context->command_line);\r
+       #else\r
+       /* play the translated command line on Windows */\r
+       command_exec(command, command->context->t_command_line);\r
+       #endif\r
+\r
+       if(cs_in_progress == command->status)\r
+       {\r
+               /* wait the process if it is in progress */\r
+               command_wait(command);\r
+\r
+               if(cs_failed != command->status && cs_interrupted != command->status)\r
+                       command_check(command);\r
+       }\r
+\r
+       xbt_os_mutex_acquire(command->mutex);\r
+\r
+       /* if it's the last command of the root unit */\r
+       if(!root->interrupted && root->parsed && (root->started_cmd_nb == (root->failed_cmd_nb + root->interrupted_cmd_nb + root->successeded_cmd_nb)))\r
+       {\r
+               /* first release the mutex */\r
+               root->released = 1;\r
+               xbt_os_mutex_release(command->mutex);\r
+               /* the last command release the unit */\r
+               xbt_os_sem_release(root->sem);\r
+       }\r
+       else\r
+               xbt_os_mutex_release(command->mutex);\r
+\r
+\r
+       /* wait the end of the timer, the reader and the writer */\r
+       if(command->timer && command->timer->thread)\r
+               timer_wait(command->timer);\r
+\r
+       /* wait the end of the writer */\r
+       if(command->writer && command->writer->thread)\r
+               writer_wait(command->writer);\r
+\r
+       /* wait the end of the reader */\r
+       if(command->reader && command->reader->thread)\r
+               reader_wait(command->reader);\r
+\r
+\r
+\r
+       return NULL;\r
+}\r
+\r
+#ifdef WIN32\r
+\r
+#ifndef BUFSIZE\r
+#define BUFSIZE        4096\r
+#endif\r
+void\r
+command_exec(command_t command, const char* command_line)\r
+{\r
+\r
+       STARTUPINFO si = {0};                                   /* contains the informations about the child process windows*/\r
+       PROCESS_INFORMATION pi = {0};                   /* contains child process informations                                          */\r
+       SECURITY_ATTRIBUTES sa = {0};                   /* contains the security descriptor for the pipe handles        */\r
+       HANDLE child_stdin_handle[2] = {NULL};  /* child_stdin_handle[1]        <-> stdout of the child process */\r
+       HANDLE child_stdout_handle[2] = {NULL}; /* child_stdout_handle[0]       <-> stdin of the child process  */\r
+       HANDLE child_stderr = NULL;\r
+\r
+\r
+       sa.nLength = sizeof(SECURITY_ATTRIBUTES);\r
+    sa.lpSecurityDescriptor = NULL;                    /* use default security for the pipe handles                            */\r
+\r
+       sa.bInheritHandle = TRUE;                               /* the pipe handles can be inherited                                            */\r
+\r
+       if(!CreatePipe(&(child_stdin_handle[0]),&(child_stdin_handle[1]),&sa,0))\r
+    {\r
+               ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));\r
+\r
+               unit_set_error(command->unit, (int)GetLastError(), 0, command->context->pos);\r
+\r
+               command->failed = 1;\r
+               command->status = cs_failed;\r
+\r
+               return;\r
+    }\r
+\r
+\r
+       if(!DuplicateHandle(GetCurrentProcess(),(child_stdin_handle[1]),GetCurrentProcess(),&(child_stderr),0,TRUE,DUPLICATE_SAME_ACCESS))\r
+    {\r
+               ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));\r
+\r
+               unit_set_error(command->unit, (int)GetLastError(), 0, command->context->pos);\r
+\r
+               CloseHandle(child_stdin_handle[0]);\r
+               CloseHandle(child_stdin_handle[1]);\r
+\r
+               command->failed = 1;\r
+               command->status = cs_failed;\r
+\r
+               return;\r
+    }\r
+\r
+       if(!CreatePipe(&(child_stdout_handle[0]),&(child_stdout_handle[1]),&sa,0))\r
+    {\r
+               ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));\r
+               unit_set_error(command->unit, (int)GetLastError(), 0, command->context->pos);\r
+\r
+               CloseHandle(child_stdout_handle[0]);\r
+               CloseHandle(child_stdout_handle[1]);\r
+               CloseHandle(child_stdin_handle[0]);\r
+               CloseHandle(child_stdin_handle[1]);\r
+\r
+               command->failed = 1;\r
+               command->status = cs_failed;\r
+\r
+               return;\r
+    }\r
+\r
+       /* Read handle for read operations on the child std output. */\r
+       if(!DuplicateHandle(GetCurrentProcess(),(child_stdin_handle[0]),GetCurrentProcess(),&(command->stdout_fd),0,FALSE, DUPLICATE_SAME_ACCESS))\r
+    {\r
+               CloseHandle(child_stdout_handle[0]);\r
+               CloseHandle(child_stdout_handle[1]);\r
+               CloseHandle(child_stdin_handle[0]);\r
+               CloseHandle(child_stdin_handle[1]);\r
+\r
+               command->failed = 1;\r
+               command->status = cs_failed;\r
+\r
+               ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));\r
+               unit_set_error(command->unit, (int)GetLastError(), 0, command->context->pos);\r
+\r
+               return;\r
+       }\r
+\r
+\r
+       /* Write handle for write operations on the child std input. */\r
+       if(!DuplicateHandle(GetCurrentProcess(),(child_stdout_handle[1]),GetCurrentProcess(),&(command->stdin_fd), 0,FALSE,DUPLICATE_SAME_ACCESS))\r
+    {\r
+               CloseHandle(child_stdout_handle[0]);\r
+               CloseHandle(child_stdout_handle[1]);\r
+               CloseHandle(child_stdin_handle[0]);\r
+               CloseHandle(child_stdin_handle[1]);\r
+\r
+               command->failed = 1;\r
+               command->status = cs_failed;\r
+\r
+               ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));\r
+\r
+               unit_set_error(command->unit, (int)GetLastError(), 0, command->context->pos);\r
+\r
+               return;\r
+    }\r
+\r
+       CloseHandle(child_stdin_handle[0]);\r
+       CloseHandle(child_stdout_handle[1]);\r
+\r
+\r
+       if(command->timer)\r
+       {\r
+               /* launch the timer */\r
+               timer_time(command->timer);\r
+       }\r
+\r
+       if(command->reader)\r
+       {\r
+               /* launch the reader */\r
+               reader_read(command->reader);\r
+       }\r
+\r
+\r
+       if(command->writer)\r
+       {\r
+               /* launch the writer */\r
+               writer_write(command->writer);\r
+       }\r
+\r
+       /* if there is a reader wait for its starting */\r
+       if(command->reader)\r
+               xbt_os_sem_acquire(command->reader->started);\r
+\r
+       /* if there is a reader wait for its ending */\r
+       if(command->writer)\r
+               xbt_os_sem_acquire(command->writer->written);\r
+\r
+       /* if there is a reader wait for its starting */\r
+       if(command->timer)\r
+               xbt_os_sem_acquire(command->timer->started);\r
+\r
+    si.cb = sizeof(STARTUPINFO);\r
+\r
+       si.dwFlags |= STARTF_USESTDHANDLES;\r
+       si.hStdOutput = child_stdin_handle[1];\r
+       si.hStdInput  = child_stdout_handle[0];\r
+       si.hStdError  = child_stderr;\r
+\r
+       /* launch the process */\r
+       if(!CreateProcess(\r
+                                               NULL,\r
+                                               tow32cmd(command_line),\r
+                                               NULL,\r
+                                               NULL,\r
+                                               TRUE,\r
+                                               CREATE_NO_WINDOW,\r
+                                               NULL,\r
+                                               NULL,\r
+                                               &si,\r
+                                               &pi)\r
+       )\r
+       {\r
+\r
+               if(ERROR_FILE_NOT_FOUND == GetLastError())\r
+               {\r
+                       ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(ECMDNOTFOUND, 1));\r
+                       unit_set_error(command->unit, ECMDNOTFOUND, 1, command->context->pos);\r
+                       command_handle_failure(command, csr_command_not_found);\r
+               }\r
+               else\r
+               {\r
+                       ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));\r
+\r
+                       unit_set_error(command->unit, (int)GetLastError(), 0, command->context->pos);\r
+                       command_handle_failure(command, csr_create_process_function_failure);\r
+               }\r
+\r
+    }\r
+       else\r
+       {\r
+               /* the command is running */\r
+               command->status = cs_in_progress;\r
+\r
+               /* save the pid of the command */\r
+               command->pid = pi.hProcess;\r
+\r
+               /* close non used thread handle */\r
+               CloseHandle(pi.hThread);\r
+\r
+       }\r
+\r
+\r
+       /* close non used handles */\r
+       CloseHandle(child_stdin_handle[1]);\r
+    CloseHandle(child_stdout_handle[0]);\r
+       CloseHandle(child_stderr);\r
+\r
+\r
+}\r
+#else\r
+void\r
+command_exec(command_t command, const char* command_line)\r
+{\r
+       int child_stdin_fd[2] ;\r
+       int child_stdout_fd[2];\r
+\r
+       #ifdef __CHKCMD\r
+       int rv = is_cmd(command->unit->runner->path, command->unit->runner->builtin, command_line);\r
+\r
+       if(rv != 0)\r
+       {\r
+\r
+               if(rv == EINVAL)\r
+               {\r
+                       ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(rv, 0));\r
+                       unit_set_error(command->unit, rv, 0, command->context->pos);\r
+               }\r
+               else\r
+               {\r
+                       ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(rv, 1));\r
+                       unit_set_error(command->unit, rv, 1, command->context->pos);\r
+               }\r
+\r
+               command_handle_failure(command, csr_command_not_found);\r
+\r
+               return;\r
+       }\r
+\r
+       #endif\r
+\r
+\r
+       if(command->writer)\r
+       {\r
+               if(pipe(child_stdin_fd))\r
+               {\r
+                       ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));\r
+\r
+                       unit_set_error(command->unit, errno, 0, command->context->pos);\r
+\r
+                       command_handle_failure(command, csr_pipe_function_failed);\r
+\r
+\r
+\r
+                       return;\r
+               }\r
+       }\r
+\r
+       if(command->reader)\r
+       {\r
+               if(pipe(child_stdout_fd))\r
+               {\r
+                       ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));\r
+\r
+                       if(command->writer)\r
+                       {\r
+                               close(child_stdin_fd[0]);\r
+                               close(child_stdin_fd[1]);\r
+                       }\r
+\r
+                       unit_set_error(command->unit, errno, 0, command->context->pos);\r
+\r
+                       command_handle_failure(command, csr_pipe_function_failed);\r
+\r
+                       return;\r
+               }\r
+       }\r
+\r
+       if(command->writer)\r
+       {\r
+               if(fcntl(child_stdin_fd[1], F_SETFL, fcntl(child_stdin_fd[1], F_GETFL) | O_NONBLOCK) < 0)\r
+               {\r
+\r
+                       ERROR3("[%s] `%s'  : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));\r
+\r
+                       close(child_stdin_fd[0]);\r
+                       close(child_stdin_fd[1]);\r
+\r
+                       if(command->reader)\r
+                       {\r
+                               close(child_stdout_fd[0]);\r
+                               close(child_stdout_fd[1]);\r
+                       }\r
+\r
+                       unit_set_error(command->unit, errno, 0, command->context->pos);\r
+\r
+                       command_handle_failure(command, csr_fcntl_function_failed);\r
+\r
+                       return;\r
+               }\r
+       }\r
+\r
+       /* to write to the child stdin */\r
+       command->stdin_fd = child_stdin_fd[1];\r
+\r
+       /* to read from the child stdout */\r
+       command->stdout_fd = child_stdout_fd[0];\r
+\r
+       /* launch the reader if any*/\r
+       if(command->reader)\r
+               reader_read(command->reader);\r
+\r
+    /* launch the writer if any */\r
+       if(command->writer)\r
+               writer_write(command->writer);\r
+\r
+       /* launch the timer if any */\r
+       if(command->timer)\r
+               timer_time(command->timer);\r
+\r
+       /* if there is a reader wait for its starting */\r
+       if(command->reader)\r
+               xbt_os_sem_acquire(command->reader->started);\r
+\r
+       /* if there is a reader wait for its ending */\r
+       if(command->writer)\r
+               xbt_os_sem_acquire(command->writer->written);\r
+\r
+       /* if there is a reader wait for its starting */\r
+       if(command->timer)\r
+               xbt_os_sem_acquire(command->timer->started);\r
+\r
+       /* update the state of the command, assume it is in progress */\r
+       command->status = cs_in_progress;\r
+\r
+       command->pid= fork();\r
+\r
+       if(command->pid < 0)\r
+       {/* error */\r
+               if(command->writer)\r
+               {\r
+                       close(child_stdin_fd[0]);\r
+                       close(child_stdin_fd[1]);\r
+               }\r
+\r
+               if(command->reader)\r
+               {\r
+                       close(child_stdout_fd[0]);\r
+                       close(child_stdout_fd[1]);\r
+               }\r
+\r
+               ERROR2("[%s] Cannot fork the command `%s'", command->context->pos, command->context->command_line);\r
+               unit_set_error(command->unit, errno, 0, command->context->pos);\r
+               command_handle_failure(command,csr_fork_function_failure);\r
+       }\r
+       else\r
+       {\r
+               if(command->pid)\r
+               {/* father */\r
+\r
+                       /* close unused file descriptors */\r
+                       if(command->writer)\r
+                               close(child_stdin_fd[0]);\r
+\r
+                       if(command->reader)\r
+                               close(child_stdout_fd[1]);\r
+               }\r
+               else\r
+               {/* child */\r
+\r
+                       /* close unused file descriptors */\r
+                       if(command->writer)\r
+                               close(child_stdin_fd[1]);\r
+\r
+                       if(command->reader)\r
+                               close(child_stdout_fd[0]);\r
+\r
+                       if(command->writer)\r
+                       {\r
+                               /* redirect stdin to child_stdin_fd[0] (now fgets(), getchar() ... read from the pipe */\r
+                               if(dup2(child_stdin_fd[0],STDIN_FILENO) < 0)\r
+                               {\r
+                                       ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));\r
+                                       command->unit->exit_code = errno;\r
+\r
+                                       unit_set_error(command->unit, errno, 0, command->context->pos);\r
+                                       command_handle_failure(command,csr_dup2_function_failure);\r
+                               }\r
+\r
+                               /* close the unused file descriptor  */\r
+                               close(child_stdin_fd[0]);\r
+                       }\r
+\r
+                       if(command->reader)\r
+                       {\r
+\r
+                               /* redirect stdout and stderr to child_stdout_fd[1] (now printf(), perror()... write to the pipe */\r
+                               if(dup2(child_stdout_fd[1],STDOUT_FILENO) < 0)\r
+                               {\r
+                                       ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));\r
+\r
+                                       unit_set_error(command->unit, errno, 0, command->context->pos);\r
+                                       command_handle_failure(command, csr_dup2_function_failure);\r
+                               }\r
+\r
+                               if(dup2(child_stdout_fd[1], STDERR_FILENO) < 0)\r
+                               {\r
+                                       ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));\r
+                                       unit_set_error(command->unit, errno, 0, command->context->pos);\r
+                                       command_handle_failure(command, csr_dup2_function_failure);\r
+                               }\r
+\r
+                               /* close the unused file descriptor  */\r
+                               close(child_stdout_fd[1]);\r
+                       }\r
+\r
+                       /* launch the command */\r
+                       if(execlp("/bin/sh", "sh", "-c", command->context->command_line, NULL) < 0)\r
+                               command->execlp_errno = errno;\r
+               }\r
+       }\r
+}\r
+#endif\r
+\r
+#ifdef WIN32\r
+void\r
+command_wait(command_t command)\r
+{\r
+       /* wait for the command terminaison */\r
+       DWORD rv;\r
+\r
+       if(WAIT_FAILED == WaitForSingleObject(command->pid, INFINITE))\r
+       {\r
+               ERROR2("[%s] Cannot wait for the child`%s'", command->context->pos, command->context->command_line);\r
+\r
+               unit_set_error(command->unit, (int)GetLastError(), 0, command->context->pos);\r
+\r
+               command_handle_failure(command, csr_wait_failure );\r
+               /* TODO : see for the interruption      */\r
+       }\r
+       else\r
+       {\r
+               /* don't take care of the timer or the writer or the reader failue */\r
+               if(cs_failed != command->status && cs_interrupted != command->status)\r
+               {\r
+                       if(!GetExitCodeProcess(command->pid,&rv))\r
+                       {\r
+                               ERROR2("[%s] Cannot get the exit code of the process `%s'",command->context->pos, command->context->command_line);\r
+\r
+                               unit_set_error(command->unit, (int)GetLastError(), 0, command->context->pos);\r
+\r
+                               command_handle_failure(command, csr_get_exit_code_process_function_failure );\r
+                       }\r
+                       else\r
+                               command->stat_val = command->exit_code = rv;\r
+               }\r
+       }\r
+}\r
+#else\r
+void\r
+command_wait(command_t command)\r
+{\r
+       if(!command->execlp_errno)\r
+       {\r
+               /* let this thread wait for the child so that the main thread can detect the timeout without blocking on the wait */\r
+               int pid = waitpid(command->pid, &(command->stat_val), 0);\r
+\r
+               if(pid != command->pid)\r
+               {\r
+                       ERROR2("[%s] Cannot wait for the child`%s'", command->context->pos, command->context->command_line);\r
+\r
+                       unit_set_error(command->unit, errno, 0, command->context->pos);\r
+\r
+                       command_handle_failure(command, csr_waitpid_function_failure);\r
+               }\r
+               else\r
+               {\r
+                       if(WIFEXITED(command->stat_val))\r
+                               command->exit_code = WEXITSTATUS(command->stat_val);\r
+               }\r
+       }\r
+       else\r
+       {\r
+               ERROR2("[%s] Cannot execute the command `%s'", command->context->pos, command->context->command_line);\r
+\r
+               unit_set_error(command->unit, command->execlp_errno, 0, command->context->pos);\r
+\r
+               command_handle_failure(command, csr_execlp_function_failure);\r
+       }\r
+}\r
+#endif\r
+\r
+void\r
+command_check(command_t command)\r
+{\r
+       int success = 1;\r
+       cs_reason_t reason;\r
+\r
+       /* we have a signal, store it */\r
+       if(WIFSIGNALED(command->stat_val))\r
+       {\r
+               command->signal = strdup(signal_name(WTERMSIG(command->stat_val),command->context->signal));\r
+       }\r
+\r
+       /* we have a signal and no signal is expected */\r
+       if(WIFSIGNALED(command->stat_val) && !command->context->signal)\r
+       {\r
+               success = 0;\r
+               ERROR3("[%s] `%s' : NOK (unexpected signal `%s' caught)", command->context->pos, command->context->command_line, command->signal);\r
+\r
+               unit_set_error(command->unit, EUNXPSIG, 1, command->context->pos);\r
+\r
+               reason = csr_unexpected_signal_caught;\r
+       }\r
+\r
+       /* we have a signal that differ form the expected signal */\r
+       if(WIFSIGNALED(command->stat_val) && command->context->signal && strcmp(signal_name(WTERMSIG(command->stat_val),command->context->signal),command->context->signal))\r
+       {\r
+\r
+               ERROR4("[%s] `%s' : NOK (got signal `%s' instead of `%s')", command->context->pos, command->context->command_line, command->signal, command->context->signal);\r
+\r
+               if(success)\r
+               {\r
+                       success = 0;\r
+                       unit_set_error(command->unit, ESIGNOTMATCH, 1, command->context->pos);\r
+               }\r
+\r
+               reason = csr_signals_dont_match;\r
+       }\r
+\r
+       /* we don't receive the expected signal */\r
+       if(!WIFSIGNALED(command->stat_val) && command->context->signal)\r
+       {\r
+\r
+               ERROR3("[%s] `%s' : NOK (expected `%s' not received)", command->context->pos, command->context->command_line, command->context->signal);\r
+\r
+               if(success)\r
+               {\r
+                       success = 0;\r
+                       unit_set_error(command->unit, ESIGNOTRECEIVED, 1, command->context->pos);\r
+               }\r
+\r
+               reason = csr_expected_signal_not_received;\r
+       }\r
+\r
+       /* if the command exit normaly and we expect a exit code : test it */\r
+       if(WIFEXITED(command->stat_val) /* && INDEFINITE != command->context->exit_code*/)\r
+       {\r
+               /* the exit codes don't match */\r
+               if(WEXITSTATUS(command->stat_val) != command->context->exit_code)\r
+               {\r
+                       ERROR4("[%s] %s : NOK (returned code `%d' instead `%d')", command->context->pos, command->context->command_line, WEXITSTATUS(command->stat_val), command->context->exit_code);\r
+\r
+                       if(success)\r
+                       {\r
+                               success = 0;\r
+                               unit_set_error(command->unit, EEXITCODENOTMATCH, 1, command->context->pos);\r
+                       }\r
+\r
+                       reason = csr_exit_codes_dont_match;\r
+               }\r
+       }\r
+\r
+       /* make sure the reader done */\r
+       while(!command->reader->done)\r
+               xbt_os_thread_yield();\r
+\r
+       #ifdef WIN32\r
+       CloseHandle(command->stdout_fd);\r
+       #else\r
+       close(command->stdout_fd);\r
+       #endif\r
+\r
+       command->stdout_fd = INDEFINITE_FD;\r
+\r
+       xbt_strbuff_chomp(command->output);\r
+       xbt_strbuff_chomp(command->context->output);\r
+       xbt_strbuff_trim(command->output);\r
+       xbt_strbuff_trim(command->context->output);\r
+\r
+       if(!success &&  !strcmp(command->output->data, command->context->output->data))\r
+       {\r
+               xbt_dynar_t a = xbt_str_split(command->output->data, "\n");\r
+               char *out = xbt_str_join(a,"\n||");\r
+               xbt_dynar_free(&a);\r
+               INFO2("Output of <%s> so far: \n||%s", command->context->pos,out);\r
+               free(out);\r
+       }\r
+       /* if ouput handling flag is specified check the output */\r
+       else if(oh_check == command->context->output_handling && command->reader)\r
+       {\r
+               if(command->output->used != command->context->output->used || strcmp(command->output->data, command->context->output->data))\r
+               {\r
+                       char *diff;\r
+\r
+\r
+                       ERROR2("[%s] `%s' : NOK (outputs mismatch):", command->context->pos, command->context->command_line);\r
+\r
+                       if(success)\r
+                       {\r
+                               unit_set_error(command->unit, EOUTPUTNOTMATCH, 1, command->context->pos);\r
+                               success = 0;\r
+                       }\r
+\r
+                       reason = csr_outputs_dont_match;\r
+\r
+                       /* display the diff */\r
+                       diff = xbt_str_diff(command->context->output->data,command->output->data);\r
+                       INFO1("%s",diff);\r
+                       free(diff);\r
+               }\r
+       }\r
+       else if (oh_ignore == command->context->output_handling)\r
+       {\r
+               INFO1("(ignoring the output of <%s> as requested)",command->context->line);\r
+       }\r
+       else if (oh_display == command->context->output_handling)\r
+       {\r
+               xbt_dynar_t a = xbt_str_split(command->output->data, "\n");\r
+               char *out = xbt_str_join(a,"\n||");\r
+               xbt_dynar_free(&a);\r
+               INFO3("[%s] Here is the (ignored) command `%s' output: \n||%s",command->context->pos, command->context->command_line, out);\r
+               free(out);\r
+       }\r
+\r
+       if(success)\r
+       {\r
+               xbt_os_mutex_acquire(command->mutex);\r
+\r
+               if(command->status != cs_interrupted)\r
+               {\r
+                       /* signal the success of the command */\r
+                       command->status = cs_successeded;\r
+                       command->successeded = 1;\r
+\r
+                       /* increment the number of successeded command of the unit */\r
+                       (command->root->successeded_cmd_nb)++;\r
+               }\r
+\r
+               xbt_os_mutex_release(command->mutex);\r
+       }\r
+       else\r
+       {\r
+               command_handle_failure(command, reason);\r
+       }\r
+}\r
+\r
+#ifdef WIN32\r
+void\r
+command_kill(command_t command)\r
+{\r
+       if(INDEFINITE_PID != command->pid)\r
+       {\r
+               INFO2("[%s] Kill the process `%s'", command->context->pos, command->context->command_line);\r
+               TerminateProcess(command->pid, INDEFINITE);\r
+       }\r
+}\r
+#else\r
+void\r
+command_kill(command_t command)\r
+{\r
+       if(INDEFINITE_PID != command->pid)\r
+       {\r
+               kill(command->pid,SIGTERM);\r
+\r
+               if(!command->context->signal)\r
+                       command->context->signal = strdup("SIGTERM");\r
+\r
+               command->exit_code = INDEFINITE;\r
+               command->killed = 1;\r
+\r
+               usleep(100);\r
+\r
+               INFO2("[%s] Kill the process `%s'", command->context->pos, command->context->command_line);\r
+               kill(command->pid,SIGKILL);\r
+\r
+\r
+       }\r
+}\r
+#endif\r
+\r
+void\r
+command_interrupt(command_t command)\r
+{\r
+       xbt_os_mutex_acquire(command->mutex);\r
+\r
+       if((command->status != cs_interrupted) && (command->status != cs_failed) && (command->status != cs_successeded))\r
+       {\r
+               command->status = cs_interrupted;\r
+               command->reason = csr_interruption_request;\r
+               command->interrupted = 1;\r
+               command->unit->interrupted = 1;\r
+\r
+               xbt_os_mutex_acquire(command->root->mutex);\r
+               (command->root->interrupted_cmd_nb)++;\r
+               xbt_os_mutex_release(command->root->mutex);\r
+\r
+               if(command->pid != INDEFINITE_PID)\r
+                       command_kill(command);\r
+       }\r
+\r
+       xbt_os_mutex_release(command->mutex);\r
+\r
+\r
+}\r
+\r
+void\r
+command_summarize(command_t command)\r
+{\r
+       if(cs_successeded != command->status)\r
+       {\r
+\r
+               #ifndef WIN32\r
+               if(command->killed)\r
+                       printf("          <killed command>\n");\r
+               #endif\r
+\r
+               /* display the reason of the status of the command */\r
+               switch(command->reason)\r
+               {\r
+                       /* the function pipe or CreatePipe() fails */\r
+                       case csr_pipe_function_failed :\r
+                       printf("          reason                      : pipe() or CreatePipe() function failed (system error)\n");\r
+                       break;\r
+\r
+                       case csr_shell_failed :\r
+                       printf("          reason                      : shell failed (may be command not found)\n");\r
+                       break;\r
+\r
+                       case csr_get_exit_code_process_function_failure :\r
+                       printf("          reason                      : ExitCodeProcess() function failed (system error)\n");\r
+                       break;\r
+\r
+                       /* reader failure reasons*/\r
+                       case csr_read_pipe_broken :\r
+                       printf("          reason                      : command read pipe broken\n");\r
+                       break;\r
+\r
+                       case csr_read_failure :\r
+                       printf("          reason                      : command stdout read failed\n");\r
+                       break;\r
+\r
+                       /* writer failure reasons */\r
+                       case csr_write_failure :\r
+                       printf("          reason                      : command stdin write failed\n");\r
+                       break;\r
+\r
+                       case csr_write_pipe_broken :\r
+                       printf("          reason                      : command write pipe broken\n");\r
+                       break;\r
+\r
+                       /* timer reason */\r
+                       case csr_timeout :\r
+                       printf("          reason                      : command timeouted\n");\r
+                       break;\r
+\r
+                       /* command failure reason */\r
+                       case csr_command_not_found :\r
+                       printf("          reason                      : command not found\n");\r
+                       break;\r
+\r
+                       /* context failure reasons */\r
+                       case csr_exit_codes_dont_match :\r
+                       printf("          reason                      : exit codes don't match\n");\r
+\r
+                       break;\r
+\r
+                       /* dup2 function failure reasons */\r
+                       case csr_dup2_function_failure :\r
+                       printf("          reason                      : dup2() function failed\n");\r
+\r
+                       break;\r
+\r
+                       /* execlp function failure reasons */\r
+                       case csr_execlp_function_failure :\r
+                       printf("          reason                      : execlp() function failed\n");\r
+\r
+                       break;\r
+\r
+                       /* waitpid function failure reasons */\r
+                       case csr_waitpid_function_failure :\r
+                       printf("          reason                      : waitpid() function failed\n");\r
+\r
+                       break;\r
+\r
+                       /* CreateProcess function failure reasons */\r
+                       case csr_create_process_function_failure :\r
+                       printf("          reason                      : CreateProcesss() function failed\n");\r
+\r
+                       break;\r
+\r
+                       case csr_outputs_dont_match :\r
+                       {\r
+                               /*char *diff;*/\r
+                               printf("          reason                      : ouputs don't match\n");\r
+                               /*diff = xbt_str_diff(command->context->output->data,command->output->data);\r
+                               printf("          output diff :\n%s\n",diff);\r
+                               free(diff);*/\r
+                       }\r
+\r
+                       break;\r
+\r
+                       case csr_signals_dont_match :\r
+                       printf("          reason                      : signals don't match\n");\r
+                       break;\r
+\r
+                       case csr_unexpected_signal_caught:\r
+                       printf("          reason                      : unexpected signal caught\n");\r
+                       break;\r
+\r
+                       case csr_expected_signal_not_received :\r
+                       printf("          reason                      : expected signal not receipt\n");\r
+                       break;\r
+\r
+                       /* system failure reasons */\r
+                       case csr_fork_function_failure :\r
+                       printf("          reason                      : fork function failed\n");\r
+                       break;\r
+\r
+                       case csr_wait_failure :\r
+                       printf("          reason                      : wait command failure\n");\r
+                       break;\r
+\r
+                       /* global/local interruption */\r
+                       case csr_interruption_request :\r
+                       printf("          reason                      : the command receive a interruption request\n");\r
+                       break;\r
+\r
+                       /* unknown ? */\r
+                       case csr_unknown :\r
+                       printf("          reason                      : unknown \n");\r
+               }\r
+       }\r
+\r
+       if(csr_command_not_found != command->reason && csr_fork_function_failure != command->reason  && csr_execlp_function_failure != command->reason)\r
+       {\r
+               if(INDEFINITE != command->exit_code)\r
+                       /* the command exit code */\r
+                       printf("          exit code                   : %d\n",command->exit_code);\r
+\r
+               /* if an expected exit code was specified display it */\r
+               if(INDEFINITE != command->context->exit_code)\r
+                       printf("          expected exit code          : %d\n",command->context->exit_code);\r
+               else\r
+                       printf("          no expected exit code specified\n");\r
+\r
+               /* no expected signal expected */\r
+               if(NULL == command->context->signal)\r
+               {\r
+                       printf("          no expected signal specified\n");\r
+\r
+                       if(command->signal)\r
+                               printf("          but got signal              : %s\n",command->signal);\r
+\r
+               }\r
+               /* if an expected exit code was specified display it */\r
+               else\r
+               {\r
+                       if(NULL != command->signal)\r
+                               printf("          signal                      : %s\n",command->signal);\r
+                       else\r
+                               printf("          no signal caugth\n");\r
+               }\r
+\r
+               /* if the command has out put and the metacommand display output is specified display it  */\r
+               if(command->output && (0 != command->output->used) && (oh_display == command->context->output_handling))\r
+               {\r
+                       xbt_dynar_t a = xbt_str_split(command->output->data, "\n");\r
+                       char *out = xbt_str_join(a,"\n||");\r
+                       xbt_dynar_free(&a);\r
+                       printf("          output :\n||%s",out);\r
+                       free(out);\r
+               }\r
+       }\r
+\r
+       printf("\n");\r
+}\r
+\r
+void\r
+command_handle_failure(command_t command, cs_reason_t reason)\r
+{\r
+       unit_t root = command->root;\r
+\r
+       xbt_os_mutex_acquire(command->mutex);\r
+\r
+       if((command->status != cs_interrupted) && (command->status != cs_failed))\r
+       {\r
+               command->status = cs_failed;\r
+               command->reason = reason;\r
+               command->failed = 1;\r
+\r
+               command->unit->failed = 1;\r
+\r
+               xbt_os_mutex_acquire(root->mutex);\r
+\r
+               /* increment the number of failed command of the unit */\r
+               root->failed_cmd_nb++;\r
+\r
+               /* if the --ignore-failures option is not specified */\r
+               if(!keep_going_unit_flag)\r
+               {\r
+                       if(!root->interrupted)\r
+                       {\r
+                               /* the unit interrupted (exit for the loop) */\r
+                               root->interrupted = 1;\r
+\r
+                               /* release the unit */\r
+                               xbt_os_sem_release(root->sem);\r
+                       }\r
+\r
+                       /* if the --keep-going option is not specified */\r
+                       if(!keep_going_flag)\r
+                       {\r
+                               if(!interrupted)\r
+                               {\r
+                                       /* request an global interruption by the runner */\r
+                                       interrupted = 1;\r
+\r
+                                       /* release the runner */\r
+                                       xbt_os_sem_release(units_sem);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               xbt_os_mutex_release(root->mutex);\r
+       }\r
+\r
+       xbt_os_mutex_release(command->mutex);\r
+}\r
+\r
+int\r
+command_free(command_t* ptr)\r
+{\r
+       /* close the stdin and the stdout pipe handles */\r
+\r
+       #ifdef WIN32\r
+       if((*ptr)->stdin_fd != INDEFINITE_FD)\r
+               CloseHandle((*ptr)->stdin_fd);\r
+\r
+       if((*ptr)->stdout_fd != INDEFINITE_FD)\r
+               CloseHandle((*ptr)->stdout_fd);\r
+\r
+       #else\r
+\r
+       if((*ptr)->stdin_fd != INDEFINITE_FD)\r
+               close((*ptr)->stdin_fd);\r
+\r
+       if((*ptr)->stdout_fd != INDEFINITE_FD)\r
+               close((*ptr)->stdout_fd);\r
+       #endif\r
+\r
+       if((*ptr)->timer)\r
+       {\r
+               if(timer_free(&((*ptr)->timer)) < 0)\r
+                       return -1;\r
+       }\r
+\r
+       if((*ptr)->writer)\r
+       {\r
+               if(writer_free(&((*ptr)->writer)) < 0)\r
+                       return -1;\r
+       }\r
+\r
+       if((*ptr)->reader)\r
+       {\r
+               if(reader_free(&((*ptr)->reader)) < 0)\r
+                       return -1;\r
+       }\r
+\r
+       if((*ptr)->output)\r
+               xbt_strbuff_free((*ptr)->output);\r
+\r
+       if((*ptr)->context)\r
+       {\r
+               if(context_free(&((*ptr)->context)) < 0)\r
+                       return -1;\r
+       }\r
+\r
+       if((*ptr)->signal)\r
+               free((*ptr)->signal);\r
+\r
+       free(*ptr);\r
+\r
+       *ptr = NULL;\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+\r