X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/f2e52e70789159e58204f2cc770dc5f7a4c6498b..db9e1e77f7d08a187ac8e5588e42b3358879de9f:/tools/tesh2/src/command.c diff --git a/tools/tesh2/src/command.c b/tools/tesh2/src/command.c index bb78758d47..3f911f6aea 100644 --- a/tools/tesh2/src/command.c +++ b/tools/tesh2/src/command.c @@ -1,1147 +1,1234 @@ -/* - * 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 -#include -#include -#include -#include -#include - -#ifndef WIN32 -#include -#include -#include -#include -#endif - -#include - -#include - -#include - -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; - - command = xbt_new0(s_command_t, 1); - - /* get the context of the execution of the command */ - if(!(command->context = context_dup(context))) - { - free(command); - return NULL; - } - - /* 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; - - command->output = xbt_strbuff_new(); - - command->pid = INDEFINITE_PID; - - command->stat_val = -1; - - /* set the unit of the command */ - command->root = unit->root ? unit->root : unit; - command->unit = unit; - - /* all the commands are runned in a thread */ - command->thread = NULL; - - command->successeded = 0; - - command->reader = reader_new(command); - - 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); - - xbt_dynar_push(unit->commands, &command); - command->root->cmd_nb++; - xbt_os_mutex_release(mutex); - - #ifndef WIN32 - command->killed = 0; - command->execlp_errno = 0; - #endif - - - return command; -} - -int -command_run(command_t command) -{ - - if(!silent_flag) - INFO2("[%s] %s",command->context->pos, command->context->command_line); - - if(!just_print_flag) - { - if(!interrupted) - { - /* start the command in a thread*/ - if(command->context->async) - { - command->thread = xbt_os_thread_create("", command_start, command); - - } - else - { - /* start the command in the main thread */ - command_start(command); - } - } - else - { - command_interrupt(command); - } - } - - return 0; - -} - -static void* -command_start(void* p) -{ - command_t command = (command_t)p; - 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); - (root->started_cmd_nb)++; - 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) - { - /* wait the process if it is in progress */ - command_wait(command); - - if(cs_failed != command->status && cs_interrupted != command->status) - command_check(command); - } - - xbt_os_mutex_acquire(command->mutex); - - /* 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 */ - root->released = 1; - xbt_os_mutex_release(command->mutex); - /* the last command release the unit */ - xbt_os_sem_release(root->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); - - /* 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 -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)) - { - 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)) - { - 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]); - - command->failed = 1; - command->status = cs_failed; - - return; - } - - if(!CreatePipe(&(child_stdout_handle[0]),&(child_stdout_handle[1]),&sa,0)) - { - 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]); - 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; - - 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. */ - 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; - - 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; - } - - - 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) - ) - { - ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0)); - - command_handle_failure(command,csr_create_process_function_failure); - - unit_set_error(command->unit, (int)GetLastError(), 0); - } - 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]; - - #ifdef __CHKCMD - int rv = is_cmd(command->unit->runner->path, command->unit->runner->builtin, command_line); - - if(rv != 0) - { - - 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; - } - - #endif - - - if(command->writer) - { - 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); - - - - 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]); - } - - unit_set_error(command->unit, errno, 0); - - command_handle_failure(command, csr_pipe_function_failed); - - 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)); - - close(child_stdin_fd[0]); - close(child_stdin_fd[1]); - - if(command->reader) - { - close(child_stdout_fd[0]); - close(child_stdout_fd[1]); - } - - 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); - - /* 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 */ - - /* close unused file descriptors */ - if(command->writer) - close(child_stdin_fd[0]); - - if(command->reader) - close(child_stdout_fd[1]); - } - else - {/* child */ - - /* close unused file descriptors */ - if(command->writer) - close(child_stdin_fd[1]); - - if(command->reader) - close(child_stdout_fd[0]); - - if(command->writer) - { - /* 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); - } - - /* close the unused file descriptor */ - close(child_stdin_fd[0]); - } - - if(command->reader) - { - - /* 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(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); - } - - /* 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; - } - } -} -#endif - -#ifdef WIN32 -void -command_wait(command_t command) -{ - /* wait for the command terminaison */ - DWORD rv; - - if(WAIT_FAILED == WaitForSingleObject(command->pid, INFINITE)) - { - 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 - { - /* 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)) - { - 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; - } - } -} -#else -void -command_wait(command_t command) -{ - if(!command->execlp_errno) - { - /* 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 - { - 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 - -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)); - } - - /* we have a signal and no signal is expected */ - if(WIFSIGNALED(command->stat_val) && !command->context->signal) - { - success = 0; - 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(WIFSIGNALED(command->stat_val) && command->context->signal && strcmp(signal_name(WTERMSIG(command->stat_val),command->context->signal),command->context->signal)) - { - - 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(!WIFSIGNALED(command->stat_val) && command->context->signal) - { - - 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(WIFEXITED(command->stat_val) /* && INDEFINITE != command->context->exit_code*/) - { - /* the exit codes don't match */ - if(WEXITSTATUS(command->stat_val) != command->context->exit_code) - { - 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(); - - #ifdef WIN32 - CloseHandle(command->stdout_fd); - #else - close(command->stdout_fd); - #endif - - 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)) - { - 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) - { - 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 */ - (command->root->successeded_cmd_nb)++; - } - - 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) - { - INFO2("[%s] Kill the process `%s'", command->context->pos, command->context->command_line); - TerminateProcess(command->pid, INDEFINITE); - } -} -#else -void -command_kill(command_t command) -{ - if(INDEFINITE_PID != command->pid) - { - kill(command->pid,SIGTERM); - - if(!command->context->signal) - command->context->signal = strdup("SIGTERM"); - - command->exit_code = INDEFINITE; - command->killed = 1; - - usleep(100); - - INFO2("[%s] Kill the process `%s'", command->context->pos, command->context->command_line); - 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)) - { - command->status = cs_interrupted; - command->reason = csr_interruption_request; - command->interrupted = 1; - 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); - } - - xbt_os_mutex_release(command->mutex); - - -} - -void -command_summarize(command_t command) -{ - if(cs_successeded != command->status) - { - - #ifndef WIN32 - if(command->killed) - printf(" \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; - - 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"); - 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; - - /* 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; - 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_fork_function_failure : - printf(" reason : fork function failed\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_fork_function_failure != command->reason && csr_execlp_function_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 root = command->root; - - 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; - - command->unit->failed = 1; - - xbt_os_mutex_acquire(root->mutex); - - /* increment the number of failed command of the unit */ - root->failed_cmd_nb++; - - /* if the --ignore-failures option is not specified */ - if(!keep_going_unit_flag) - { - if(!root->interrupted) - { - /* the unit interrupted (exit for the loop) */ - root->interrupted = 1; - - /* release the unit */ - xbt_os_sem_release(root->sem); - } - - /* if the --keep-going option is not specified */ - if(!keep_going_flag) - { - if(!interrupted) - { - /* request an global interruption by the runner */ - interrupted = 1; - - /* release the runner */ - xbt_os_sem_release(units_sem); - } - } - } - - xbt_os_mutex_release(root->mutex); - } - - xbt_os_mutex_release(command->mutex); -} - -int -command_free(command_t* ptr) -{ - /* close the stdin and the stdout pipe handles */ - - #ifdef WIN32 - if((*ptr)->stdin_fd != INDEFINITE_FD) - CloseHandle((*ptr)->stdin_fd); - - if((*ptr)->stdout_fd != INDEFINITE_FD) - CloseHandle((*ptr)->stdout_fd); - - #else - - 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; - } - - if((*ptr)->signal) - free((*ptr)->signal); - - free(*ptr); - - *ptr = NULL; - - return 0; -} - - - +/* + * 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 +#include +#include +#include +#include +#include + +#ifndef WIN32 +#include +#include +#include +#include +#else +char * +tow32cmd(const char* cmd) +{ + static char w32cmd[PATH_MAX + 1] = {0}; + char cmd_buf[PATH_MAX + 1] = {0}; + size_t i,j, len; + + if(!cmd) + { + errno = EINVAL; + return NULL; + } + + /* TODO : if ~*/ + if(cmd[0] != '.') + { + strcpy(w32cmd, cmd); + return w32cmd; + } + + i = j = 0; + len = strlen(cmd); + + while(i < len) + { + if(cmd[i] != ' ' && cmd[i] != '\t' && cmd[i] != '>') + cmd_buf[j++] = cmd[i]; + else + break; + + i++; + } + + _fullpath(w32cmd, cmd_buf, sizeof(w32cmd)); + + if(!strstr(w32cmd, ".exe")) + strcat(w32cmd, ".exe "); + + strcat(w32cmd, cmd + i); + + + /*printf("w32cmd : %s", w32cmd);*/ + + return w32cmd; +} +#endif + +#include + +#include + +#include + +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; + + command = xbt_new0(s_command_t, 1); + + /* get the context of the execution of the command */ + if(!(command->context = context_dup(context))) + { + free(command); + return NULL; + } + + /* 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; + + command->output = xbt_strbuff_new(); + + command->pid = INDEFINITE_PID; + + command->stat_val = -1; + + /* set the unit of the command */ + command->root = unit->root ? unit->root : unit; + command->unit = unit; + + /* all the commands are runned in a thread */ + command->thread = NULL; + + command->successeded = 0; + + command->reader = reader_new(command); + + 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); + + xbt_dynar_push(unit->commands, &command); + command->root->cmd_nb++; + xbt_os_mutex_release(mutex); + + #ifndef WIN32 + command->killed = 0; + command->execlp_errno = 0; + #endif + + + return command; +} + +int +command_run(command_t command) +{ + if(!silent_flag && !interrupted) + INFO2("[%s] %s",command->context->pos, command->context->command_line); + + if(!just_print_flag) + { + if(!interrupted) + { + /* start the command in a thread*/ + if(command->context->async) + { + command->thread = xbt_os_thread_create("", command_start, command); + + } + else + { + /* start the command in the main thread */ + command_start(command); + } + } + else + { + command_interrupt(command); + } + + + } + + return 0; + +} + +static void* +command_start(void* p) +{ + command_t command = (command_t)p; + 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); + (root->started_cmd_nb)++; + xbt_os_mutex_release(command->mutex); + + /* execute the command of the test */ + + #ifndef WIN32 + command_exec(command, command->context->command_line); + #else + /* play the translated command line on Windows */ + command_exec(command, command->context->t_command_line); + #endif + + if(cs_in_progress == command->status) + { + /* wait the process if it is in progress */ + command_wait(command); + + if(cs_failed != command->status && cs_interrupted != command->status) + command_check(command); + } + + xbt_os_mutex_acquire(command->mutex); + + /* 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 */ + root->released = 1; + xbt_os_mutex_release(command->mutex); + /* the last command release the unit */ + xbt_os_sem_release(root->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); + + /* 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 +#endif +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)) + { + 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->context->pos); + + command->failed = 1; + command->status = cs_failed; + + return; + } + + + if(!DuplicateHandle(GetCurrentProcess(),(child_stdin_handle[1]),GetCurrentProcess(),&(child_stderr),0,TRUE,DUPLICATE_SAME_ACCESS)) + { + 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->context->pos); + + 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)) + { + 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->context->pos); + + 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; + + 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->context->pos); + + return; + } + + + /* 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; + + 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->context->pos); + + return; + } + + 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); + } + + /* 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; + si.hStdOutput = child_stdin_handle[1]; + si.hStdInput = child_stdout_handle[0]; + si.hStdError = child_stderr; + + /* launch the process */ + if(!CreateProcess( + NULL, + tow32cmd(command_line), + NULL, + NULL, + TRUE, + CREATE_NO_WINDOW, + NULL, + NULL, + &si, + &pi) + ) + { + + if(ERROR_FILE_NOT_FOUND == GetLastError()) + { + 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->context->pos); + command_handle_failure(command, csr_command_not_found); + } + else + { + 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->context->pos); + command_handle_failure(command, csr_create_process_function_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]; + + #ifdef __CHKCMD + int rv = is_cmd(command->unit->runner->path, command->unit->runner->builtin, command_line); + + if(rv != 0) + { + + 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, command->context->pos); + } + 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->context->pos); + } + + command_handle_failure(command, csr_command_not_found); + + return; + } + + #endif + + + if(command->writer) + { + 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->context->pos); + + command_handle_failure(command, csr_pipe_function_failed); + + + + 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]); + } + + unit_set_error(command->unit, errno, 0, command->context->pos); + + command_handle_failure(command, csr_pipe_function_failed); + + 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)); + + close(child_stdin_fd[0]); + close(child_stdin_fd[1]); + + if(command->reader) + { + close(child_stdout_fd[0]); + close(child_stdout_fd[1]); + } + + unit_set_error(command->unit, errno, 0, command->context->pos); + + 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); + + /* 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->context->pos); + command_handle_failure(command,csr_fork_function_failure); + } + else + { + if(command->pid) + {/* father */ + + /* close unused file descriptors */ + if(command->writer) + close(child_stdin_fd[0]); + + if(command->reader) + close(child_stdout_fd[1]); + } + else + {/* child */ + + /* close unused file descriptors */ + if(command->writer) + close(child_stdin_fd[1]); + + if(command->reader) + close(child_stdout_fd[0]); + + if(command->writer) + { + /* 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->context->pos); + command_handle_failure(command,csr_dup2_function_failure); + } + + /* close the unused file descriptor */ + close(child_stdin_fd[0]); + } + + if(command->reader) + { + + /* 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->context->pos); + command_handle_failure(command, csr_dup2_function_failure); + } + + 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->context->pos); + command_handle_failure(command, csr_dup2_function_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; + } + } +} +#endif + +#ifdef WIN32 +void +command_wait(command_t command) +{ + /* wait for the command terminaison */ + DWORD rv; + + if(WAIT_FAILED == WaitForSingleObject(command->pid, INFINITE)) + { + ERROR2("[%s] Cannot wait for the child`%s'", command->context->pos, command->context->command_line); + + unit_set_error(command->unit, (int)GetLastError(), 0, command->context->pos); + + command_handle_failure(command, csr_wait_failure ); + /* 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)) + { + 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->context->pos); + + command_handle_failure(command, csr_get_exit_code_process_function_failure ); + } + else + command->stat_val = command->exit_code = rv; + } + } +} +#else +void +command_wait(command_t command) +{ + if(!command->execlp_errno) + { + /* 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->context->pos); + + command_handle_failure(command, csr_waitpid_function_failure); + } + else + { + if(WIFEXITED(command->stat_val)) + command->exit_code = WEXITSTATUS(command->stat_val); + } + } + else + { + ERROR2("[%s] Cannot execute the command `%s'", command->context->pos, command->context->command_line); + + unit_set_error(command->unit, command->execlp_errno, 0, command->context->pos); + + command_handle_failure(command, csr_execlp_function_failure); + } +} +#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)); + } + + /* we have a signal and no signal is expected */ + if(WIFSIGNALED(command->stat_val) && !command->context->signal) + { + success = 0; + ERROR3("[%s] `%s' : NOK (unexpected signal `%s' caught)", command->context->pos, command->context->command_line, command->signal); + + unit_set_error(command->unit, EUNXPSIG, 1, command->context->pos); + + reason = csr_unexpected_signal_caught; + } + + /* we have a signal that differ form the expected signal */ + if(WIFSIGNALED(command->stat_val) && command->context->signal && strcmp(signal_name(WTERMSIG(command->stat_val),command->context->signal),command->context->signal)) + { + + 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, command->context->pos); + } + + reason = csr_signals_dont_match; + } + + /* we don't receive the expected signal */ + if(!WIFSIGNALED(command->stat_val) && command->context->signal) + { + + ERROR3("[%s] `%s' : NOK (expected `%s' not received)", command->context->pos, command->context->command_line, command->context->signal); + + if(success) + { + success = 0; + unit_set_error(command->unit, ESIGNOTRECEIVED, 1, command->context->pos); + } + + reason = csr_expected_signal_not_received; + } + + /* if the command exit normaly and we expect a exit code : test it */ + 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) + { + 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, command->context->pos); + } + + reason = csr_exit_codes_dont_match; + } + } + + /* make sure the reader done */ + while(!command->reader->done) + xbt_os_thread_yield(); + + #ifdef WIN32 + CloseHandle(command->stdout_fd); + #else + close(command->stdout_fd); + #endif + + 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 && !strcmp(command->output->data, command->context->output->data)) + { + 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)) + { + char *diff; + + + ERROR2("[%s] `%s' : NOK (outputs mismatch):", command->context->pos, command->context->command_line); + + if(success) + { + unit_set_error(command->unit, EOUTPUTNOTMATCH, 1, command->context->pos); + 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) + { + 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 */ + (command->root->successeded_cmd_nb)++; + } + + 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) + { + INFO2("[%s] Kill the process `%s'", command->context->pos, command->context->command_line); + TerminateProcess(command->pid, INDEFINITE); + } +} +#else +void +command_kill(command_t command) +{ + if(INDEFINITE_PID != command->pid) + { + kill(command->pid,SIGTERM); + + if(!command->context->signal) + command->context->signal = strdup("SIGTERM"); + + command->exit_code = INDEFINITE; + command->killed = 1; + + usleep(100); + + INFO2("[%s] Kill the process `%s'", command->context->pos, command->context->command_line); + 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)) + { + command->status = cs_interrupted; + command->reason = csr_interruption_request; + command->interrupted = 1; + 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); + } + + xbt_os_mutex_release(command->mutex); + + +} + +void +command_summarize(command_t command) +{ + if(cs_successeded != command->status) + { + + #ifndef WIN32 + if(command->killed) + printf(" \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; + + 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"); + 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; + + /* 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;*/ + 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_received : + printf(" reason : expected signal not receipt\n"); + break; + + /* system failure reasons */ + case csr_fork_function_failure : + printf(" reason : fork function failed\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_fork_function_failure != command->reason && csr_execlp_function_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"); + + /* 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); + else + printf(" no signal caugth\n"); + } + + /* 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 root = command->root; + + 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; + + command->unit->failed = 1; + + xbt_os_mutex_acquire(root->mutex); + + /* increment the number of failed command of the unit */ + root->failed_cmd_nb++; + + /* if the --ignore-failures option is not specified */ + if(!keep_going_unit_flag) + { + if(!root->interrupted) + { + /* the unit interrupted (exit for the loop) */ + root->interrupted = 1; + + /* release the unit */ + xbt_os_sem_release(root->sem); + } + + /* if the --keep-going option is not specified */ + if(!keep_going_flag) + { + if(!interrupted) + { + /* request an global interruption by the runner */ + interrupted = 1; + + /* release the runner */ + xbt_os_sem_release(units_sem); + } + } + } + + xbt_os_mutex_release(root->mutex); + } + + xbt_os_mutex_release(command->mutex); +} + +int +command_free(command_t* ptr) +{ + /* close the stdin and the stdout pipe handles */ + + #ifdef WIN32 + if((*ptr)->stdin_fd != INDEFINITE_FD) + CloseHandle((*ptr)->stdin_fd); + + if((*ptr)->stdout_fd != INDEFINITE_FD) + CloseHandle((*ptr)->stdout_fd); + + #else + + 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; + } + + if((*ptr)->signal) + free((*ptr)->signal); + + free(*ptr); + + *ptr = NULL; + + return 0; +} + + +