Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
last change of Tesh2
[simgrid.git] / tools / tesh2 / src / command.c
index 7d27d54..ab86d56 100644 (file)
@@ -1,4 +1,17 @@
-
+/*
+ * src/command.c - type representing a command.
+ *
+ * Copyright 2008,2009 Martin Quinson, Malek Cherier All right reserved. 
+ *
+ * This program is free software; you can redistribute it and/or modify it 
+ * under the terms of the license (GNU LGPL) which comes with this package.
+ *
+ * Purpose:
+ *             This file contains all the definitions of the functions related with
+ *             the tesh command type.
+ *
+ */
+#include <unit.h>
 #include <command.h>
 #include <context.h>
 #include <writer.h>
 #ifndef WIN32
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#else
+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
+}
 #endif
 
-#include "../include/_signal.h"
+#include <com.h>
 
+#include <xsignal.h>
 
+#include <is_cmd.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)
 {
-       command_t command = xbt_new0(s_command_t, 1);
+       command_t command;
+       
+       command = xbt_new0(s_command_t, 1);
        
        /* get the context of the execution of the command */
-       command->context = context_dup(context);
+       if(!(command->context = context_dup(context)))
+       {
+               free(command);
+               return NULL;
+       }
        
        /* the exit code of the command is indefinite */
        command->exit_code = INDEFINITE;
@@ -43,29 +108,23 @@ command_new(unit_t unit, context_t context, xbt_os_mutex_t mutex)
        
        /* 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->output = xbt_strbuff_new();
 
        command->pid = INDEFINITE_PID;
        
        command->stat_val = -1;
        
        /* set the unit of the command */
-       command->unit = unit->root ? unit->root : unit; 
+       command->root = unit->root ? unit->root : unit; 
+       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;
+       command->reader = reader_new(command);
 
        if(context->input->used)
                command->writer = writer_new(command);
@@ -87,50 +146,50 @@ command_new(unit_t unit, context_t context, xbt_os_mutex_t mutex)
        /* register the command */
        xbt_os_mutex_acquire(mutex);
        
-       vector_push_back(unit->commands, command);
-       
-       (command->unit->number_of_commands)++;
-       
+       xbt_dynar_push(unit->commands, &command);
+       command->root->cmd_nb++;
        xbt_os_mutex_release(mutex);
        
-       command->fn_sig_io_handler = sig_io_handler;
-       
        #ifndef WIN32
        command->killed = 0;
+       command->execlp_errno = 0;
        #endif
        
-       
 
        return command;
 }
 
-void
+int
 command_run(command_t command)
 {
-       if(!want_silent)
-               INFO1("tesh %s",command->context->command_line);
+       if(!silent_flag)
+               INFO2("[%s] %s",command->context->pos, command->context->command_line);
        
-       if(!want_just_display)
+       if(!just_print_flag)
        {       
                if(!interrupted)
                {
-                       /* start the command */
-                       
+                       /* start the command in a thread*/
                        if(command->context->async)
                        {
                                command->thread = xbt_os_thread_create("", command_start, command);
                        
-                               if(!command->thread)
-                                       ERROR0("xbt_os_thread_create() failed\n");
                        }
                        else
+                       {
+                               /* start the command in the main thread */
                                command_start(command);
+                       }
                }
                else
                {
                        command_interrupt(command);             
                }
+
+               
        }
+       
+       return 0;
 
 }
 
@@ -138,14 +197,14 @@ static void*
 command_start(void* p)
 {
        command_t command = (command_t)p;
-       unit_t unit = command->unit;
+       unit_t root = command->root;
        
        /* 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)++;
+       (root->started_cmd_nb)++;
        xbt_os_mutex_release(command->mutex);
        
        /* execute the command of the test */
@@ -153,34 +212,23 @@ command_start(void* p)
        
        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
-                */
-               
+               /* wait the process if it is in progress */
                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)))
+       /* if it's the last command of the root unit */
+       if(!root->interrupted && root->parsed && (root->started_cmd_nb == (root->failed_cmd_nb + root->interrupted_cmd_nb + root->successeded_cmd_nb)))
        {
                /* first release the mutex */
-               unit->released = 1;
+               root->released = 1;
                xbt_os_mutex_release(command->mutex);
                /* the last command release the unit */
-               xbt_os_sem_release(command->unit->sem);
+               xbt_os_sem_release(root->sem);
        }
        else
                xbt_os_mutex_release(command->mutex);
@@ -189,17 +237,25 @@ command_start(void* p)
        /* wait the end of the timer, the reader and the writer */
        if(command->timer && command->timer->thread)
                timer_wait(command->timer);
-
+       
+       /* wait the end of the writer */
        if(command->writer && command->writer->thread)
                writer_wait(command->writer);
-
+       
+       /* wait the end of the reader */
        if(command->reader && command->reader->thread)
                reader_wait(command->reader);
        
+
+       
        return NULL;
 }
 
 #ifdef WIN32
+
+#ifndef BUFSIZE
+#define BUFSIZE        4096\r
+#endif
 void
 command_exec(command_t command, const char* command_line)
 {
@@ -211,6 +267,7 @@ command_exec(command_t command, const char* command_line)
        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                            */
        
@@ -218,17 +275,22 @@ command_exec(command_t command, const char* command_line)
        
        if(!CreatePipe(&(child_stdin_handle[0]),&(child_stdin_handle[1]),&sa,0))
     {
-               ERROR1("CreatePipe1() failed (%lu)",GetLastError());
-               command->failed = 1;
-               command->status = cs_failed;    
+               ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));
+               
+               unit_set_error(command->unit, (int)GetLastError(), 0);
 
+               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());
+               ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));
+               
+               unit_set_error(command->unit, (int)GetLastError(), 0);
                
                CloseHandle(child_stdin_handle[0]);
                CloseHandle(child_stdin_handle[1]);
@@ -241,7 +303,8 @@ command_exec(command_t command, const char* command_line)
        
        if(!CreatePipe(&(child_stdout_handle[0]),&(child_stdout_handle[1]),&sa,0))
     {
-               ERROR1("CreatePipe2() failed (%lu)",GetLastError()); 
+               ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));
+               unit_set_error(command->unit, (int)GetLastError(), 0);
                
                CloseHandle(child_stdout_handle[0]);
                CloseHandle(child_stdout_handle[1]);
@@ -264,9 +327,12 @@ command_exec(command_t command, const char* command_line)
 
                command->failed = 1;
                command->status = cs_failed;    
-
-               ERROR1("DuplicateHandle2() failed (%lu)",GetLastError()); 
-    }
+               
+               ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));
+               unit_set_error(command->unit, (int)GetLastError(), 0);
+       
+               return;
+       }
        
        
        /* Write handle for write operations on the child std input. */
@@ -279,13 +345,17 @@ command_exec(command_t command, const char* command_line)
 
                command->failed = 1;
                command->status = cs_failed;    
+               
+               ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));
 
-               ERROR1("DuplicateHandle3() failed (%lu)",GetLastError());
-    }
+               unit_set_error(command->unit, (int)GetLastError(), 0);
 
+               return;
+    }
        
        CloseHandle(child_stdin_handle[0]);
        CloseHandle(child_stdout_handle[1]);
+
        
        if(command->timer)
        {
@@ -306,6 +376,18 @@ command_exec(command_t command, const char* command_line)
                writer_write(command->writer);
        }
 
+       /* if there is a reader wait for its starting */
+       if(command->reader)
+               xbt_os_sem_acquire(command->reader->started);
+       
+       /* if there is a reader wait for its ending */
+       if(command->writer)
+               xbt_os_sem_acquire(command->writer->written);
+       
+       /* if there is a reader wait for its starting */
+       if(command->timer)
+               xbt_os_sem_acquire(command->timer->started);
+
     si.cb = sizeof(STARTUPINFO);
        
        si.dwFlags |= STARTF_USESTDHANDLES;
@@ -316,7 +398,7 @@ command_exec(command_t command, const char* command_line)
        /* launch the process */
        if(!CreateProcess(
                                                NULL,
-                                               (char*)command_line,
+                                               tow32cmd(command_line),
                                                NULL,
                                                NULL,
                                                TRUE,
@@ -327,17 +409,21 @@ command_exec(command_t command, const char* command_line)
                                                &pi)
        )
        {
-               
+
                if(ERROR_FILE_NOT_FOUND == GetLastError())
                {
-                       exit_code = ECMDNOTFOUND;
-                       command_handle_failure(command,csr_command_not_found);
+                       ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(ECMDNOTFOUND, 1));
+                       unit_set_error(command->unit, ECMDNOTFOUND, 1);
+                       command_handle_failure(command, csr_command_not_found);
                }
                else
                {
-                       exit_code = EEXEC;
-                       command_handle_failure(command,csr_exec_failure);
+                       ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));
+
+                       unit_set_error(command->unit, (int)GetLastError(), 0);
+                       command_handle_failure(command, csr_create_process_function_failure);
                }
+               
     }
        else
        {
@@ -367,119 +453,208 @@ 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)) 
+       #ifdef __CHKCMD
+       int rv = is_cmd(command->unit->runner->path, command->unit->runner->builtin, command_line);
+
+       if(rv != 0)
        {
-               ERROR1("pipe() failed (%d)",errno);
-               command_handle_failure(command, csr_pipe_function_failed);      
 
+               if(rv == EINVAL)
+               {
+                       ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(rv, 0));
+                       unit_set_error(command->unit, rv, 0);
+               }
+               else
+               {
+                       ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(rv, 1));
+                       unit_set_error(command->unit, rv, 1);
+               }
+
+               command_handle_failure(command, csr_command_not_found);
+       
                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
+       #endif
+       
+       
+       if(command->writer)
        {
-               if(command->pid) 
-               {/* father */
+               if(pipe(child_stdin_fd)) 
+               {
+                       ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));
                        
+                       unit_set_error(command->unit, errno, 0);
+
+                       command_handle_failure(command, csr_pipe_function_failed);
+
                        
-                       close(child_stdin_fd[0]);
-                       close(child_stdout_fd[1]);
+       
+                       return;
+               }
+       }       
+       
+       if(command->reader)
+       {
+               if(pipe(child_stdout_fd)) 
+               {
+                       ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));
+                               
+                       if(command->writer)
+                       {
+                               close(child_stdin_fd[0]);
+                               close(child_stdin_fd[1]);
+                       }
                        
-                       command->stdin_fd = child_stdin_fd[1];
+                       unit_set_error(command->unit, errno, 0);
+
+                       command_handle_failure(command, csr_pipe_function_failed);
                        
-                       command->stdout_fd = child_stdout_fd[0];
+                       return;
+               }
+       }
+       
+       if(command->writer)
+       {
+               if(fcntl(child_stdin_fd[1], F_SETFL, fcntl(child_stdin_fd[1], F_GETFL) | O_NONBLOCK) < 0)
+               {
+
+                       ERROR3("[%s] `%s'  : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));
                        
-                       /* on indique que c'est le processus parent qui doit recevoir le signal */
-                       /*fcntl(command->stdin_fd,F_SETOWN, pid);*/
+                       close(child_stdin_fd[0]);
+                       close(child_stdin_fd[1]);
                        
                        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);
+                               close(child_stdout_fd[0]);
+                               close(child_stdout_fd[1]);
                        }
                        
-                       /* the command is running */
-                       command->status = cs_in_progress;
+                       unit_set_error(command->unit, errno, 0);
+
+                       command_handle_failure(command, csr_fcntl_function_failed);     
+                               
+                       return;
+               }
+       }
+       
+       /* to write to the child stdin */
+       command->stdin_fd = child_stdin_fd[1];
+       
+       /* to read from the child stdout */
+       command->stdout_fd = child_stdout_fd[0];
+       
+       /* launch the reader if any*/
+       if(command->reader)
+               reader_read(command->reader);
+    
+    /* launch the writer if any */
+       if(command->writer)
+               writer_write(command->writer);
+       
+       /* launch the timer if any */
+       if(command->timer)
+               timer_time(command->timer);
                
-               } 
-               else 
-               {/* child */
-                       
-                       
+       /* if there is a reader wait for its starting */
+       if(command->reader)
+               xbt_os_sem_acquire(command->reader->started);
+       
+       /* if there is a reader wait for its ending */
+       if(command->writer)
+               xbt_os_sem_acquire(command->writer->written);
+       
+       /* if there is a reader wait for its starting */
+       if(command->timer)
+               xbt_os_sem_acquire(command->timer->started);
+       
+       /* update the state of the command, assume it is in progress */
+       command->status = cs_in_progress;
+                               
+       command->pid= fork();
+                               
+       if(command->pid < 0) 
+       {/* error */
+               if(command->writer)
+               {
+                       close(child_stdin_fd[0]);
                        close(child_stdin_fd[1]);
+               }
+               
+               if(command->reader)
+               {
                        close(child_stdout_fd[0]);
+                       close(child_stdout_fd[1]);
+               }
+               
+               ERROR2("[%s] Cannot fork the command `%s'", command->context->pos, command->context->command_line);
+               unit_set_error(command->unit, errno, 0);
+               command_handle_failure(command,csr_fork_function_failure);
+       }
+       else
+       {
+               if(command->pid) 
+               {/* father */
                        
-                       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 unused file descriptors */
+                       if(command->writer)
+                               close(child_stdin_fd[0]);
+                               
+                       if(command->reader)
+                               close(child_stdout_fd[1]);
+               } 
+               else 
+               {/* child */
                        
-                       /*close(child_stdin_fd[0]);
-                       */
+                       /* close unused file descriptors */
+                       if(command->writer)
+                               close(child_stdin_fd[1]);
+                               
+                       if(command->reader)
+                               close(child_stdout_fd[0]);
                        
-                       if(dup2(child_stdout_fd[1],STDOUT_FILENO/*1*/) < 0)
+                       if(command->writer)
                        {
-                               exit_code = EEXEC;
-                               ERROR1("dup2() failed (%d)",errno);
-                               command_handle_failure(command,csr_exec_failure);
-                       }
+                               /* redirect stdin to child_stdin_fd[0] (now fgets(), getchar() ... read from the pipe */  
+                               if(dup2(child_stdin_fd[0],STDIN_FILENO) < 0)
+                               {
+                                       ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));
+                                       command->unit->exit_code = errno;
+
+                                       unit_set_error(command->unit, errno, 0);
+                                       command_handle_failure(command,csr_dup2_function_failure);
+                               }
                        
-                       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);
+                               /* close the unused file descriptor  */
+                               close(child_stdin_fd[0]);
                        }
                        
-                       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]);*/
-                       
                        if(command->reader)
-                               xbt_os_sem_acquire(command->reader->started);
+                       {
                        
-                       if(command->writer)
-                               xbt_os_sem_acquire(command->writer->written);
+                               /* redirect stdout and stderr to child_stdout_fd[1] (now printf(), perror()... write to the pipe */  
+                               if(dup2(child_stdout_fd[1],STDOUT_FILENO) < 0)
+                               {
+                                       ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));
+
+                                       unit_set_error(command->unit, errno, 0);
+                                       command_handle_failure(command, csr_dup2_function_failure);
+                               }
                                
-                       if(command->timer)
-                               xbt_os_sem_acquire(command->timer->started);
+                               if(dup2(child_stdout_fd[1], STDERR_FILENO) < 0)
+                               {
+                                       ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));
+                                       unit_set_error(command->unit, errno, 0);
+                                       command_handle_failure(command, csr_dup2_function_failure);
+                               }
                        
-                       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);
+                               /* close the unused file descriptor  */
+                               close(child_stdout_fd[1]);
                        }
+                       
+                       /* launch the command */
+                       if(execlp("/bin/sh", "sh", "-c", command->context->command_line, NULL) < 0)
+                               command->execlp_errno = errno;
                }
        }
 }
@@ -494,7 +669,11 @@ command_wait(command_t command)
 
        if(WAIT_FAILED == WaitForSingleObject(command->pid, INFINITE))
        {
-               ERROR0("WaitForSingleObject() failed");
+               ERROR2("[%s] Cannot wait for the child`%s'", command->context->pos, command->context->command_line);
+               
+               unit_set_error(command->unit, (int)GetLastError(), 0);
+
+               command_handle_failure(command, csr_wait_failure );
                /* TODO : see for the interruption      */      
        }
        else
@@ -504,8 +683,11 @@ command_wait(command_t command)
                {
                        if(!GetExitCodeProcess(command->pid,&rv))
                        {
-                               ERROR1("GetExitCodeProcess() failed for the child %s",command->context->command_line);
-                               /* TODO : see for the interruption      */      
+                               ERROR2("[%s] Cannot get the exit code of the process `%s'",command->context->pos, command->context->command_line);
+                               
+                               unit_set_error(command->unit, (int)GetLastError(), 0);
+
+                               command_handle_failure(command, csr_get_exit_code_process_function_failure );   
                        }
                        else
                                command->stat_val = command->exit_code = rv;
@@ -516,37 +698,33 @@ command_wait(command_t command)
 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 */
-       
-       
-       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) 
+       if(!command->execlp_errno)
        {
-               ERROR1("waitpid() failed for the child %s",command->context->command_line);
-               exit_code = EWAIT;
-               command_handle_failure(command, csr_wait_failure);
+               /* let this thread wait for the child so that the main thread can detect the timeout without blocking on the wait */
+               int pid = waitpid(command->pid, &(command->stat_val), 0);
+       
+               if(pid != command->pid) 
+               {
+                       ERROR2("[%s] Cannot wait for the child`%s'", command->context->pos, command->context->command_line);
+
+                       unit_set_error(command->unit, errno, 0);
+
+                       command_handle_failure(command, csr_waitpid_function_failure);
+               }
+               else
+               {
+                       if(WIFEXITED(command->stat_val))
+                               command->exit_code = WEXITSTATUS(command->stat_val);
+               }
        }
        else
        {
-               if(WIFEXITED(command->stat_val))
-                       command->exit_code = WEXITSTATUS(command->stat_val);    
+               ERROR2("[%s] Cannot execute the command `%s'", command->context->pos, command->context->command_line);
+
+               unit_set_error(command->unit, command->execlp_errno, 0);
+
+               command_handle_failure(command, csr_execlp_function_failure);
        }
-       
-       
 }
 #endif
 
@@ -560,67 +738,127 @@ 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);*/
        }
        
-       /* we have a signal and not signal is expected */
+       /* we have a signal and no signal is expected */
        if(WIFSIGNALED(command->stat_val) && !command->context->signal) 
        {
                success = 0;
-               exit_code = EUNEXPECTEDSIG;
+               ERROR3("[%s] `%s' : NOK (unexpected signal `%s' caught)", command->context->pos, command->context->command_line, command->signal);
+
+               unit_set_error(command->unit, EUNXPSIG, 1);
+
                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)) 
+       if(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;
+
+               ERROR4("[%s] `%s' : NOK (got signal `%s' instead of `%s')", command->context->pos, command->context->command_line, command->signal, command->context->signal);
+               
+               if(success)
+               {
+                       success = 0;
+                       unit_set_error(command->unit, ESIGNOTMATCH, 1);
+               }
+               
                reason = csr_signals_dont_match;
        }
        
        /* we don't receipt the expected signal */
-       if(success && !WIFSIGNALED(command->stat_val) && command->context->signal) 
+       if(!WIFSIGNALED(command->stat_val) && command->context->signal) 
        {
-               success = 0;
-               exit_code = ESIGNOTRECEIPT;
+               
+               ERROR3("[%s] `%s' : NOK (expected `%s' not receipt)", command->context->pos, command->context->command_line, command->context->signal);
+               
+               if(success)
+               {
+                       success = 0;
+                       unit_set_error(command->unit, ESIGNOTRECEIPT, 1);
+               }
+               
                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*/)
+       if(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;
+                       ERROR4("[%s] %s : NOK (returned code `%d' instead `%d')", command->context->pos, command->context->command_line, WEXITSTATUS(command->stat_val), command->context->exit_code);
+                       
+                       if(success)
+                       {
+                               success = 0;
+                               unit_set_error(command->unit, EEXITCODENOTMATCH, 1);
+                       }
+       
                        reason = csr_exit_codes_dont_match;
                }
        }
+
+       /* make sure the reader done */
+       while(!command->reader->done)
+               xbt_os_thread_yield();
        
-       /* 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->done)
-                       xbt_os_thread_yield();
-                       
-               close(command->stdout_fd);
-               command->stdout_fd = INDEFINITE_FD;
+       #ifdef WIN32
+       CloseHandle(command->stdout_fd);
+       #else
+       close(command->stdout_fd);
+       #endif
 
-               xbt_strbuff_chomp(command->output);
-               xbt_strbuff_chomp(command->context->output);
-               xbt_strbuff_trim(command->output);
-               xbt_strbuff_trim(command->context->output);
+       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);
+
+       if(!success)
+       {
+               xbt_dynar_t a = xbt_str_split(command->output->data, "\n");
+               char *out = xbt_str_join(a,"\n||");
+               xbt_dynar_free(&a);
+               INFO2("Output of <%s> so far: \n||%s", command->context->pos,out);
+               free(out);    
+       }
+       /* if ouput handling flag is specified check the output */
+       else if(oh_check == command->context->output_handling && command->reader)
+       {
                if(command->output->used != command->context->output->used || strcmp(command->output->data, command->context->output->data))
                {
-                       success = 0;
-                       exit_code = EOUTPUTNOTMATCH;
+                       char *diff;
+                       
+                       ERROR2("[%s] `%s' : NOK (outputs mismatch):", command->context->pos, command->context->command_line);
+                       
+                       if(success)
+                       {
+                               unit_set_error(command->unit, EOUTPUTNOTMATCH, 1);
+                               success = 0;
+                       }
+
                        reason = csr_outputs_dont_match;
+
+                       /* display the diff */
+                       diff = xbt_str_diff(command->context->output->data,command->output->data);              
+                       INFO1("%s",diff);
+                       free(diff);
                }
        }
+       else if (oh_ignore == command->context->output_handling) 
+       {
+               INFO1("(ignoring the output of <%s> as requested)",command->context->line);
+       } 
+       else if (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);
+               INFO3("[%s] Here is the (ignored) command `%s' output: \n||%s",command->context->pos, command->context->command_line, out);
+               free(out);
+       } 
        
        if(success)
        {
@@ -628,22 +866,19 @@ command_check(command_t command)
                
                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)++;
+                       (command->root->successeded_cmd_nb)++;
                }
                
-               xbt_os_mutex_release(command->mutex);
-                       
+               xbt_os_mutex_release(command->mutex);   
        }
        else
        {
-               command_handle_failure(command,reason);
+               command_handle_failure(command, reason);
        }
 }
 
@@ -652,7 +887,10 @@ void
 command_kill(command_t command)
 {
        if(INDEFINITE_PID != command->pid)
+       {
+               INFO2("[%s] Kill the process `%s'", command->context->pos, command->context->command_line);
                TerminateProcess(command->pid, INDEFINITE);
+       }
 }
 #else
 void
@@ -660,8 +898,6 @@ 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)
@@ -671,6 +907,8 @@ command_kill(command_t command)
                command->killed = 1;
                
                usleep(100);
+
+               INFO2("[%s] Kill the process `%s'", command->context->pos, command->context->command_line);
                kill(command->pid,SIGKILL); 
 
                
@@ -685,20 +923,17 @@ command_interrupt(command_t command)
        
        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);
+               command->unit->interrupted = 1;
+
+               xbt_os_mutex_acquire(command->root->mutex);
+               (command->root->interrupted_cmd_nb)++;
+               xbt_os_mutex_release(command->root->mutex);
                
                if(command->pid != INDEFINITE_PID)
                        command_kill(command);
-               
-               
-               /*INFO1("End interrupt the command - PID %d",command->pid);*/
        }
        
        xbt_os_mutex_release(command->mutex);
@@ -707,11 +942,8 @@ command_interrupt(command_t command)
 }
 
 void
-command_display_status(command_t command)
+command_summarize(command_t command)
 {
-       
-       /*printf("\033[1m");*/
-       
        if(cs_successeded != command->status)
        {
                        
@@ -728,6 +960,14 @@ command_display_status(command_t command)
                        printf("          reason                      : pipe() or CreatePipe() function failed (system error)\n");
                        break;
                        
+                       case csr_shell_failed :
+                       printf("          reason                      : shell failed (may be command not found)\n");
+                       break;
+
+                       case csr_get_exit_code_process_function_failure :
+                       printf("          reason                      : ExitCodeProcess() function failed (system error)\n");
+                       break;
+                       
                        /* reader failure reasons*/
                        case csr_read_pipe_broken :
                        printf("          reason                      : command read pipe broken\n");
@@ -761,7 +1001,31 @@ command_display_status(command_t command)
                        printf("          reason                      : exit codes don't match\n");
                        
                        break;
-
+                       
+                       /* dup2 function failure reasons */
+                       case csr_dup2_function_failure :
+                       printf("          reason                      : dup2() function failed\n");
+                       
+                       break;
+                       
+                       /* execlp function failure reasons */
+                       case csr_execlp_function_failure :
+                       printf("          reason                      : execlp() function failed\n");
+                       
+                       break;
+                       
+                       /* waitpid function failure reasons */
+                       case csr_waitpid_function_failure :
+                       printf("          reason                      : waitpid() function failed\n");
+                       
+                       break;
+                       
+                       /* CreateProcess function failure reasons */
+                       case csr_create_process_function_failure :
+                       printf("          reason                      : CreateProcesss() function failed\n");
+                       
+                       break;
+                       
                        case csr_outputs_dont_match :
                        {
                                char *diff;
@@ -778,7 +1042,7 @@ command_display_status(command_t command)
                        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 :
@@ -786,8 +1050,8 @@ command_display_status(command_t command)
                        break;
 
                        /* system failure reasons */
-                       case csr_exec_failure :
-                       printf("          reason                      : can't excute the command\n");
+                       case csr_fork_function_failure :
+                       printf("          reason                      : fork function failed\n");
                        break;
                        
                        case csr_wait_failure :
@@ -805,7 +1069,7 @@ command_display_status(command_t command)
                }
        }
 
-       if(csr_command_not_found != command->reason && csr_exec_failure != command->reason)
+       if(csr_command_not_found != command->reason && csr_fork_function_failure != command->reason  && csr_execlp_function_failure != command->reason)
        {
                if(INDEFINITE != command->exit_code)
                        /* the command exit code */
@@ -817,15 +1081,22 @@ command_display_status(command_t command)
                else
                        printf("          no expected exit code specified\n");
                
-               /* if an expected exit code was specified display it */
+               /* no expected signal expected */
                if(NULL == command->context->signal)
+               {
                        printf("          no expected signal specified\n");
+
+                       if(command->signal)
+                               printf("          but got signal              : %s\n",command->signal);
+                               
+               }
+               /* if an expected exit code was specified display it */
                else
                {
                        if(NULL != command->signal)
                                printf("          signal                      : %s\n",command->signal);
-                       
-                       printf("          expected signal             : %s\n",command->context->signal);
+                       else
+                               printf("          no signal caugth\n");
                }
                
                /* if the command has out put and the metacommand display output is specified display it  */
@@ -840,20 +1111,12 @@ command_display_status(command_t command)
        }
 
        printf("\n");
-       
-       /*printf("\033[0m");*/
-               
-
 }
 
-
-
-
 void
 command_handle_failure(command_t command, cs_reason_t reason)
 {
-       
-       unit_t unit = command->unit;
+       unit_t root = command->root;
        
        xbt_os_mutex_acquire(command->mutex);
 
@@ -862,26 +1125,28 @@ command_handle_failure(command_t command, cs_reason_t reason)
                command->status = cs_failed;
                command->reason = reason;
                command->failed = 1;
+
+               command->unit->failed = 1;
                
-               xbt_os_mutex_acquire(unit->mutex);
+               xbt_os_mutex_acquire(root->mutex);
                
                /* increment the number of failed command of the unit */
-               unit->number_of_failed_commands++;
+               root->failed_cmd_nb++;
                
                /* if the --ignore-failures option is not specified */
-               if(!want_keep_going_unit)
+               if(!keep_going_unit_flag)
                {
-                       if(!unit->interrupted)
+                       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 */
-                       if(!want_keep_going)
+                       if(!keep_going_flag)
                        {
                                if(!interrupted)
                                {
@@ -894,41 +1159,68 @@ command_handle_failure(command_t command, cs_reason_t reason)
                        }
                }
 
-               xbt_os_mutex_release(unit->mutex);
+               xbt_os_mutex_release(root->mutex);
        }
 
        xbt_os_mutex_release(command->mutex);
 }
 
-void
-command_free(command_t* command)
+int
+command_free(command_t* ptr)
 {
        /* 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);
+       if((*ptr)->stdin_fd != INDEFINITE_FD)
+               CloseHandle((*ptr)->stdin_fd);
+               
+       if((*ptr)->stdout_fd != INDEFINITE_FD)
+               CloseHandle((*ptr)->stdout_fd);
+       
        #else
-       if((*command)->stdin_fd != INDEFINITE_FD)
-               close((*command)->stdin_fd);
        
-       if((*command)->stdout_fd != INDEFINITE_FD)      
-               close((*command)->stdout_fd);
+       if((*ptr)->stdin_fd != INDEFINITE_FD)
+               close((*ptr)->stdin_fd);
+       
+       if((*ptr)->stdout_fd != INDEFINITE_FD)  
+               close((*ptr)->stdout_fd);
        #endif
+       
+       if((*ptr)->timer)
+       {
+               if(timer_free(&((*ptr)->timer)) < 0)
+                       return -1;
+       }
+       
+       if((*ptr)->writer)
+       {
+               if(writer_free(&((*ptr)->writer)) < 0)
+                       return -1;
+       }
+       
+       if((*ptr)->reader)
+       {
+               if(reader_free(&((*ptr)->reader)) < 0)
+                       return -1;
+       }
+       
+       if((*ptr)->output)
+               xbt_strbuff_free((*ptr)->output);
+       
+       if((*ptr)->context)
+       {
+               if(context_free(&((*ptr)->context)) < 0)
+                       return -1;
+       }
 
-       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);
+       if((*ptr)->signal)
+               free((*ptr)->signal);
 
-       free(*command);
-       *command = NULL;
+       free(*ptr);
+       
+       *ptr = NULL;
+       
+       return 0;
 }