13 #include "../include/_signal.h"
16 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);
19 command_start(void* p);
23 command_new(unit_t unit, context_t context, xbt_os_mutex_t mutex)
25 command_t command = xbt_new0(s_command_t, 1);
27 /* get the context of the execution of the command */
28 command->context = context_dup(context);
30 /* the exit code of the command is indefinite */
31 command->exit_code = INDEFINITE;
33 /* the signal of the command is indefinite */
34 command->signal = INDEFINITE_SIGNAL;
37 command->interrupted = 0;
39 /* the mutex used to safetly access to the command unit properties */
40 command->mutex = mutex;
42 if(context->output->used)
43 /* instantiate the buffer filled with the content of the command stdout */
44 command->output = xbt_strbuff_new();
46 command->output = NULL;
48 command->pid = INDEFINITE_PID;
50 command->stat_val = -1;
52 /* set the unit of the command */
55 /* all the commands are runned in a thread */
56 command->thread = NULL;
58 command->successeded = 0;
60 if(context->output->used)
61 command->reader = reader_new(command);
63 command->reader = NULL;
65 if(context->input->used)
66 command->writer = writer_new(command);
68 command->writer = NULL;
70 if(context->timeout != INDEFINITE)
71 command->timer = timer_new(command);
73 command->timer = NULL;
75 command->status = cs_initialized;
76 command->reason = csr_unknown;
78 command->stdin_fd = INDEFINITE_FD;
79 command->stdout_fd = INDEFINITE_FD;
82 /* register the command */
83 xbt_os_mutex_acquire(mutex);
84 /*unit->commands[(unit->number_of_commands)++] = command;*/
85 vector_push_back(unit->commands, command);
86 (unit->number_of_commands)++;
87 xbt_os_mutex_release(mutex);
97 command_run(command_t command)
100 INFO1("tesh %s",command->context->command_line);
102 if(!want_just_display)
106 /* start the command */
108 if(command->context->async)
110 command->thread = xbt_os_thread_create("", command_start, command);
113 ERROR0("xbt_os_thread_create() failed\n");
116 command_start(command);
120 command_interrupt(command);
127 command_start(void* p)
129 command_t command = (command_t)p;
130 unit_t unit = command->unit;
132 /* the command is started */
133 command->status = cs_started;
135 /* increment the number of started commands of the unit */
136 xbt_os_mutex_acquire(command->mutex);
137 (command->unit->number_of_started_commands)++;
138 xbt_os_mutex_release(command->mutex);
140 /* execute the command of the test */
141 command_exec(command, command->context->command_line);
143 if(cs_in_progress == command->status)
145 /*printf("the command %p is in progress\n",command);*/
147 /* on attend la fin de la commande.
148 * la command peut soit se terminée normalement,
149 * 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
150 * soit à la suit d'une demande d'interruption
153 command_wait(command);
155 if(cs_failed != command->status && cs_interrupted != command->status)
157 /*printf("checking the command %p\n",command);*/
158 command_check(command);
163 xbt_os_mutex_acquire(command->mutex);
165 /* if it's the last command release its unit */
166 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)))
168 /* first release the mutex */
170 xbt_os_mutex_release(command->mutex);
171 /* the last command release the unit */
172 xbt_os_sem_release(command->unit->sem);
175 xbt_os_mutex_release(command->mutex);
178 /* wait the end of the timer, the reader and the writer */
179 if(command->timer && command->timer->thread)
180 timer_wait(command->timer);
182 if(command->writer && command->writer->thread)
183 writer_wait(command->writer);
185 if(command->reader && command->reader->thread)
186 reader_wait(command->reader);
193 command_exec(command_t command, const char* command_line)
196 STARTUPINFO si = {0}; /* contains the informations about the child process windows*/
197 PROCESS_INFORMATION pi = {0}; /* contains child process informations */
198 SECURITY_ATTRIBUTES sa = {0}; /* contains the security descriptor for the pipe handles */
199 HANDLE child_stdin_handle[2] = {NULL}; /* child_stdin_handle[1] <-> stdout of the child process */
200 HANDLE child_stdout_handle[2] = {NULL}; /* child_stdout_handle[0] <-> stdin of the child process */
201 HANDLE child_stderr = NULL;
203 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
204 sa.lpSecurityDescriptor = NULL; /* use default security for the pipe handles */
206 sa.bInheritHandle = TRUE; /* the pipe handles can be inherited */
208 if(!CreatePipe(&(child_stdin_handle[0]),&(child_stdin_handle[1]),&sa,0))
210 ERROR1("CreatePipe1() failed (%lu)",GetLastError());
212 command->status = cs_failed;
218 if(!DuplicateHandle(GetCurrentProcess(),(child_stdin_handle[1]),GetCurrentProcess(),&(child_stderr),0,TRUE,DUPLICATE_SAME_ACCESS))
220 ERROR1("DuplicateHandle1() failed (%lu)",GetLastError());
222 CloseHandle(child_stdin_handle[0]);
223 CloseHandle(child_stdin_handle[1]);
226 command->status = cs_failed;
231 if(!CreatePipe(&(child_stdout_handle[0]),&(child_stdout_handle[1]),&sa,0))
233 ERROR1("CreatePipe2() failed (%lu)",GetLastError());
235 CloseHandle(child_stdout_handle[0]);
236 CloseHandle(child_stdout_handle[1]);
237 CloseHandle(child_stdin_handle[0]);
238 CloseHandle(child_stdin_handle[1]);
241 command->status = cs_failed;
246 /* Read handle for read operations on the child std output. */
247 if(!DuplicateHandle(GetCurrentProcess(),(child_stdin_handle[0]),GetCurrentProcess(),&(command->stdout_fd),0,FALSE, DUPLICATE_SAME_ACCESS))
249 CloseHandle(child_stdout_handle[0]);
250 CloseHandle(child_stdout_handle[1]);
251 CloseHandle(child_stdin_handle[0]);
252 CloseHandle(child_stdin_handle[1]);
255 command->status = cs_failed;
257 ERROR1("DuplicateHandle2() failed (%lu)",GetLastError());
261 /* Write handle for write operations on the child std input. */
262 if(!DuplicateHandle(GetCurrentProcess(),(child_stdout_handle[1]),GetCurrentProcess(),&(command->stdin_fd), 0,FALSE,DUPLICATE_SAME_ACCESS))
264 CloseHandle(child_stdout_handle[0]);
265 CloseHandle(child_stdout_handle[1]);
266 CloseHandle(child_stdin_handle[0]);
267 CloseHandle(child_stdin_handle[1]);
270 command->status = cs_failed;
272 ERROR1("DuplicateHandle3() failed (%lu)",GetLastError());
276 CloseHandle(child_stdin_handle[0]);
277 CloseHandle(child_stdout_handle[1]);
281 /* launch the timer */
282 timer_time(command->timer);
287 /* launch the reader */
288 reader_read(command->reader);
294 /* launch the writer */
295 writer_write(command->writer);
298 si.cb = sizeof(STARTUPINFO);
300 si.dwFlags |= STARTF_USESTDHANDLES;
301 si.hStdOutput = child_stdin_handle[1];
302 si.hStdInput = child_stdout_handle[0];
303 si.hStdError = child_stderr;
305 /* launch the process */
320 if(ERROR_FILE_NOT_FOUND == GetLastError())
322 exit_code = ECMDNOTFOUND;
323 command_handle_failure(command,csr_command_not_found);
328 command_handle_failure(command,csr_exec_failure);
333 /* the command is running */
334 command->status = cs_in_progress;
336 /* save the pid of the command */
337 command->pid = pi.hProcess;
339 /* close non used thread handle */
340 CloseHandle(pi.hThread);
345 /* close non used handles */
346 CloseHandle(child_stdin_handle[1]);
347 CloseHandle(child_stdout_handle[0]);
348 CloseHandle(child_stderr);
354 command_exec(command_t command, const char* command_line)
356 int child_stdin_fd[2] ;
357 int child_stdout_fd[2];
359 if(pipe(child_stdin_fd) || pipe(child_stdout_fd))
361 ERROR1("pipe() failed (%d)",errno);
362 command_handle_failure(command, csr_pipe_function_failed);
367 command->pid= fork();
371 close(child_stdin_fd[0]);
372 close(child_stdin_fd[1]);
373 close(child_stdout_fd[0]);
374 close(child_stdout_fd[1]);
377 ERROR1("fork() failed (%d)",errno);
378 command_handle_failure(command,csr_exec_failure);
384 close(child_stdin_fd[0]);
385 close(child_stdout_fd[1]);
387 command->stdin_fd = child_stdin_fd[1];
388 command->stdout_fd = child_stdout_fd[0];
392 /* launch the reader */
393 reader_read(command->reader);
398 /* launch the writer */
399 writer_write(command->writer);
404 /* launch the timer */
405 timer_time(command->timer);
408 /* the command is running */
409 command->status = cs_in_progress;
415 close(child_stdin_fd[1]);
417 dup2(child_stdin_fd[0],0);
419 close(child_stdin_fd[0]);
421 close(child_stdout_fd[0]);
423 dup2(child_stdout_fd[1],1);
425 dup2(child_stdout_fd[1],2);
427 close(child_stdout_fd[1]);
430 xbt_os_sem_acquire(command->reader->started);
433 xbt_os_sem_acquire(command->writer->started);
436 xbt_os_sem_acquire(command->timer->started);
438 execlp ("/bin/sh", "sh", "-c", command->context->command_line, NULL);
446 command_wait(command_t command)
448 /* wait for the command terminaison */
451 if(WAIT_FAILED == WaitForSingleObject(command->pid, INFINITE))
453 ERROR0("WaitForSingleObject() failed");
454 /* TODO : see for the interruption */
458 /* don't take care of the timer or the writer or the reader failue */
459 if(cs_failed != command->status && cs_interrupted != command->status)
461 if(!GetExitCodeProcess(command->pid,&rv))
463 ERROR1("GetExitCodeProcess() failed for the child %s",command->context->command_line);
464 /* TODO : see for the interruption */
467 command->stat_val = command->exit_code = rv;
473 command_wait(command_t command)
478 /* let this thread wait for the child so that the main thread can detect the timeout without blocking on the wait */
480 pid = waitpid(command->pid, &(command->stat_val), 0);
482 /*printf("The %p command ended\n",command);*/
483 if(pid != command->pid)
485 ERROR1("waitpid() failed for the child %s",command->context->command_line);
487 command_handle_failure(command, csr_wait_failure);
491 if(WIFEXITED(command->stat_val))
492 command->exit_code = WEXITSTATUS(command->stat_val);
498 command_check(command_t command)
503 /* we have a signal, store it */
504 if(WIFSIGNALED(command->stat_val))
506 command->signal = strdup(signal_name(WTERMSIG(command->stat_val),command->context->signal));
507 INFO3("the command -PID %d %s receive the signal : %s",command->pid, command->context->command_line, command->signal);
510 /* we have a signal and not signal is expected */
511 if(WIFSIGNALED(command->stat_val) && !command->context->signal)
514 exit_code = EUNEXPECTEDSIG;
515 reason = csr_unexpected_signal_caught;
518 /* we have a signal that differ form the expected signal */
519 if(success && WIFSIGNALED(command->stat_val) && command->context->signal && strcmp(signal_name(WTERMSIG(command->stat_val),command->context->signal),command->context->signal))
522 exit_code = ESIGNOTMATCH;
523 reason = csr_signals_dont_match;
526 /* we don't receipt the expected signal */
527 if(success && !WIFSIGNALED(command->stat_val) && command->context->signal)
530 exit_code = ESIGNOTRECEIPT;
531 reason = csr_expected_signal_not_receipt;
534 /* if the command exit normaly and we expect a exit code : test it */
535 if(success && WIFEXITED(command->stat_val) /* && INDEFINITE != command->context->exit_code*/)
537 /* the exit codes don't match */
538 if(WEXITSTATUS(command->stat_val) != command->context->exit_code)
541 exit_code = EEXITCODENOTMATCH;
542 reason = csr_exit_codes_dont_match;
546 /* if ouput handling flag is specified check the output */
547 if(success && oh_check == command->context->output_handling && command->reader)
549 /* make sure the reader done */
550 while(!command->reader->broken_pipe)
551 xbt_os_thread_yield();
553 xbt_strbuff_chomp(command->output);
554 xbt_strbuff_chomp(command->context->output);
555 xbt_strbuff_trim(command->output);
556 xbt_strbuff_trim(command->context->output);
558 if(command->output->used != command->context->output->used || strcmp(command->output->data, command->context->output->data))
561 exit_code = EOUTPUTNOTMATCH;
562 reason = csr_outputs_dont_match;
568 xbt_os_mutex_acquire(command->mutex);
570 if(command->status != cs_interrupted)
573 /* signal the success of the command */
574 command->status = cs_successeded;
575 command->successeded = 1;
577 /* increment the number of successeded command of the unit */
578 /*xbt_os_mutex_acquire(command->mutex);*/
579 (command->unit->number_of_successeded_commands)++;
582 xbt_os_mutex_release(command->mutex);
587 command_handle_failure(command,reason);
593 command_kill(command_t command)
595 if(INDEFINITE_PID != command->pid)
596 TerminateProcess(command->pid, INDEFINITE);
600 command_kill(command_t command)
602 if(INDEFINITE_PID != command->pid)
604 /*INFO1("Kill the command - PID %d",command->pid);*/
606 kill(command->pid,SIGTERM);
608 if(!command->context->signal)
609 command->context->signal = strdup("SIGTERM");
611 command->exit_code = INDEFINITE;
615 kill(command->pid,SIGKILL);
623 command_interrupt(command_t command)
625 xbt_os_mutex_acquire(command->mutex);
627 if((command->status != cs_interrupted) && (command->status != cs_failed) && (command->status != cs_successeded))
629 /*INFO1("Begin interrupt the command - PID %d",command->pid);*/
631 command->status = cs_interrupted;
632 command->reason = csr_interruption_request;
633 command->interrupted = 1;
634 xbt_os_mutex_acquire(command->unit->mutex);
635 (command->unit->number_of_interrupted_commands)++;
636 xbt_os_mutex_release(command->unit->mutex);
638 if(command->pid != INDEFINITE_PID)
639 command_kill(command);
642 /*INFO1("End interrupt the command - PID %d",command->pid);*/
645 xbt_os_mutex_release(command->mutex);
651 command_display_status(command_t command)
654 printf("\nCommand : PID - %p\n%s\n",command->pid,command->context->command_line);
656 printf("\nCommand : PID - %d\n%s\n",command->pid,command->context->command_line);
658 printf("Status informations :\n");
659 printf(" position in the tesh file : %s\n",command->context->line);
661 /* the command successeded */
662 if(cs_successeded == command->status)
665 printf(" status : success\n");
670 /* display if the command is interrupted, failed or in a unknown status */
671 if(cs_interrupted == command->status)
672 printf(" status : interrupted\n");
673 else if(cs_failed == command->status)
674 printf(" status : failed\n");
676 printf(" status : unknown\n");
680 printf(" <killed command>\n");
683 /* display the reason of the status of the command */
684 switch(command->reason)
686 /* the function pipe or CreatePipe() fails */
687 case csr_pipe_function_failed :
688 printf(" reason : pipe() or CreatePipe() function failed (system error)\n");
691 /* reader failure reasons*/
692 case csr_read_pipe_broken :
693 printf(" reason : command read pipe broken\n");
696 case csr_read_failure :
697 printf(" reason : command stdout read failed\n");
700 /* writer failure reasons */
701 case csr_write_failure :
702 printf(" reason : command stdin write failed\n");
705 case csr_write_pipe_broken :
706 printf(" reason : command write pipe broken\n");
711 printf(" reason : command timeouted\n");
714 /* command failure reason */
715 case csr_command_not_found :
716 printf(" reason : command not found\n");
719 /* context failure reasons */
720 case csr_exit_codes_dont_match :
721 printf(" reason : exit codes don't match\n");
725 case csr_outputs_dont_match :
728 printf(" reason : ouputs don't match\n");
729 diff = xbt_str_diff(command->context->output->data,command->output->data);
730 printf(" output diff :\n%s\n",diff);
736 case csr_signals_dont_match :
737 printf(" reason : signals don't match\n");
740 case csr_unexpected_signal_caught:
741 printf(" reason : unexpected signal caught\n");
744 case csr_expected_signal_not_receipt :
745 printf(" reason : expected signal not receipt\n");
748 /* system failure reasons */
749 case csr_exec_failure :
750 printf(" reason : can't excute the command\n");
753 case csr_wait_failure :
754 printf(" reason : wait command failure\n");
757 /* global/local interruption */
758 case csr_interruption_request :
759 printf(" reason : the command receive a interruption request\n");
764 printf(" reason : unknown \n");
768 if(csr_command_not_found != command->reason && csr_exec_failure != command->reason)
770 if(INDEFINITE != command->exit_code)
771 /* the command exit code */
772 printf(" exit code : %d\n",command->exit_code);
774 /* if an expected exit code was specified display it */
775 if(INDEFINITE != command->context->exit_code)
776 printf(" expected exit code : %d\n",command->context->exit_code);
778 printf(" no expected exit code specified\n");
780 /* if an expected exit code was specified display it */
781 if(NULL == command->context->signal)
782 printf(" no expected signal specified\n");
785 if(NULL != command->signal)
786 printf(" signal : %s\n",command->signal);
788 printf(" expected signal : %s\n",command->context->signal);
791 /* if the command has out put and the metacommand display output is specified display it */
792 if(command->output && (0 != command->output->used) && (oh_display == command->context->output_handling))
794 xbt_dynar_t a = xbt_str_split(command->output->data, "\n");
795 char *out = xbt_str_join(a,"\n||");
797 printf(" output :\n||%s",out);
808 command_handle_failure(command_t command, cs_reason_t reason)
811 unit_t unit = command->unit;
813 xbt_os_mutex_acquire(command->mutex);
815 if((command->status != cs_interrupted) && (command->status != cs_failed))
817 command->status = cs_failed;
818 command->reason = reason;
821 xbt_os_mutex_acquire(unit->mutex);
823 /* increment the number of failed command of the unit */
824 unit->number_of_failed_commands++;
826 /* if the --ignore-failures option is not specified */
827 if(!want_keep_going_unit)
829 if(!unit->interrupted)
831 /* the unit interrupted (exit for the loop) */
832 unit->interrupted = 1;
834 /* release the unit */
835 xbt_os_sem_release(unit->sem);
838 /* if the --keep-going option is not specified */
843 /* request an global interruption by the runner */
846 /* release the runner */
847 xbt_os_sem_release(units_sem);
852 xbt_os_mutex_release(unit->mutex);
855 xbt_os_mutex_release(command->mutex);
859 command_free(command_t* command)
861 /* close the stdin and the stdout pipe handles */
864 if((*command)->stdin_fd != INDEFINITE_FD)
865 CloseHandle((*command)->stdin_fd);
866 if((*command)->stdout_fd != INDEFINITE_FD)
867 CloseHandle((*command)->stdout_fd);
869 if((*command)->stdin_fd != INDEFINITE_FD)
870 close((*command)->stdin_fd);
872 if((*command)->stdout_fd != INDEFINITE_FD)
873 close((*command)->stdout_fd);
876 timer_free(&((*command)->timer));
877 writer_free(&((*command)->writer));
878 reader_free(&((*command)->reader));
879 xbt_strbuff_free((*command)->output);
880 context_free(&((*command)->context));
882 if((*command)->signal)
883 free((*command)->signal);