Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
some new files used to check Tesh
[simgrid.git] / tools / tesh2 / src / command.c
1 /*
2  * src/command.c - type representing a command.
3  *
4  * Copyright 2008,2009 Martin Quinson, Malek Cherier All right reserved. 
5  *
6  * This program is free software; you can redistribute it and/or modify it 
7  * under the terms of the license (GNU LGPL) which comes with this package.
8  *
9  * Purpose:
10  *              This file contains all the definitions of the functions related with
11  *              the tesh command type.
12  *
13  */
14 #include <unit.h>
15 #include <command.h>
16 #include <context.h>
17 #include <writer.h>
18 #include <reader.h>
19 #include <timer.h>
20
21 #ifndef WIN32
22 #include <sys/types.h>
23 #include <sys/wait.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #endif
27
28 #include <com.h>
29
30 #include <xsignal.h>
31
32 #include <is_cmd.h>
33
34 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(tesh);
35
36 static void*
37 command_start(void* p);
38
39
40 command_t
41 command_new(unit_t unit, context_t context, xbt_os_mutex_t mutex)
42 {
43         command_t command;
44         
45         command = xbt_new0(s_command_t, 1);
46         
47         /* get the context of the execution of the command */
48         if(!(command->context = context_dup(context)))
49         {
50                 free(command);
51                 return NULL;
52         }
53         
54         /* the exit code of the command is indefinite */
55         command->exit_code = INDEFINITE;
56         
57         /* the signal of the command is indefinite */
58         command->signal = INDEFINITE_SIGNAL;
59         
60         command->failed = 0;
61         command->interrupted = 0;
62         
63         /* the mutex used to safetly access to the command unit properties */
64         command->mutex = mutex;
65
66         command->output = xbt_strbuff_new();
67
68         command->pid = INDEFINITE_PID;
69         
70         command->stat_val = -1;
71         
72         /* set the unit of the command */
73         command->root = unit->root ? unit->root : unit; 
74         command->unit = unit;
75         
76         /* all the commands are runned in a thread */
77         command->thread = NULL;
78         
79         command->successeded = 0;
80         
81         command->reader = reader_new(command);
82
83         if(context->input->used)
84                 command->writer = writer_new(command);
85         else
86                 command->writer = NULL;
87
88         if(context->timeout != INDEFINITE)
89                 command->timer = timer_new(command);
90         else
91                 command->timer = NULL;
92
93         command->status = cs_initialized;
94         command->reason = csr_unknown;
95         
96         command->stdin_fd = INDEFINITE_FD;
97         command->stdout_fd = INDEFINITE_FD;
98         
99         
100         /* register the command */
101         xbt_os_mutex_acquire(mutex);
102         
103         xbt_dynar_push(unit->commands, &command);
104         command->root->cmd_nb++;
105         xbt_os_mutex_release(mutex);
106         
107         #ifndef WIN32
108         command->killed = 0;
109         command->execlp_errno = 0;
110         #endif
111         
112
113         return command;
114 }
115
116 int
117 command_run(command_t command)
118 {
119         
120         if(!silent_flag)
121                 INFO2("[%s] %s",command->context->pos, command->context->command_line);
122         
123         if(!just_print_flag)
124         {       
125                 if(!interrupted)
126                 {
127                         /* start the command in a thread*/
128                         if(command->context->async)
129                         {
130                                 command->thread = xbt_os_thread_create("", command_start, command);
131                         
132                         }
133                         else
134                         {
135                                 /* start the command in the main thread */
136                                 command_start(command);
137                         }
138                 }
139                 else
140                 {
141                         command_interrupt(command);             
142                 }
143         }
144         
145         return 0;
146
147 }
148
149 static void*
150 command_start(void* p)
151 {
152         command_t command = (command_t)p;
153         unit_t root = command->root;
154         
155         /* the command is started */
156         command->status = cs_started;
157         
158         /* increment the number of started commands of the unit */
159         xbt_os_mutex_acquire(command->mutex);
160         (root->started_cmd_nb)++;
161         xbt_os_mutex_release(command->mutex);
162         
163         /* execute the command of the test */
164         command_exec(command, command->context->command_line);
165         
166         if(cs_in_progress == command->status)
167         {
168                 /* wait the process if it is in progress */
169                 command_wait(command);
170         
171                 if(cs_failed != command->status && cs_interrupted != command->status)
172                         command_check(command);
173         }
174         
175         xbt_os_mutex_acquire(command->mutex);
176         
177         /* if it's the last command of the root unit */
178         if(!root->interrupted && root->parsed && (root->started_cmd_nb == (root->failed_cmd_nb + root->interrupted_cmd_nb + root->successeded_cmd_nb)))
179         {
180                 /* first release the mutex */
181                 root->released = 1;
182                 xbt_os_mutex_release(command->mutex);
183                 /* the last command release the unit */
184                 xbt_os_sem_release(root->sem);
185         }
186         else
187                 xbt_os_mutex_release(command->mutex);
188                 
189         
190         /* wait the end of the timer, the reader and the writer */
191         if(command->timer && command->timer->thread)
192                 timer_wait(command->timer);
193         
194         /* wait the end of the writer */
195         if(command->writer && command->writer->thread)
196                 writer_wait(command->writer);
197         
198         /* wait the end of the reader */
199         if(command->reader && command->reader->thread)
200                 reader_wait(command->reader);
201         
202
203         
204         return NULL;
205 }
206
207 #ifdef WIN32
208 void
209 command_exec(command_t command, const char* command_line)
210 {
211         
212         STARTUPINFO si = {0};                                   /* contains the informations about the child process windows*/
213         PROCESS_INFORMATION pi = {0};                   /* contains child process informations                                          */
214         SECURITY_ATTRIBUTES sa = {0};                   /* contains the security descriptor for the pipe handles        */
215         HANDLE child_stdin_handle[2] = {NULL};  /* child_stdin_handle[1]        <-> stdout of the child process */
216         HANDLE child_stdout_handle[2] = {NULL}; /* child_stdout_handle[0]       <-> stdin of the child process  */
217         HANDLE child_stderr = NULL;
218         
219         sa.nLength = sizeof(SECURITY_ATTRIBUTES);
220     sa.lpSecurityDescriptor = NULL;                     /* use default security for the pipe handles                            */
221         
222         sa.bInheritHandle = TRUE;                               /* the pipe handles can be inherited                                            */
223         
224         if(!CreatePipe(&(child_stdin_handle[0]),&(child_stdin_handle[1]),&sa,0))
225     {
226                 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));
227                 
228                 unit_set_error(command->unit, (int)GetLastError(), 0);
229
230                 command->failed = 1;
231                 command->status = cs_failed;
232                 
233                 return;
234     }
235         
236         
237         if(!DuplicateHandle(GetCurrentProcess(),(child_stdin_handle[1]),GetCurrentProcess(),&(child_stderr),0,TRUE,DUPLICATE_SAME_ACCESS))
238     {
239                 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));
240                 
241                 unit_set_error(command->unit, (int)GetLastError(), 0);
242                 
243                 CloseHandle(child_stdin_handle[0]);
244                 CloseHandle(child_stdin_handle[1]);
245
246                 command->failed = 1;
247                 command->status = cs_failed;    
248
249                 return;
250     }
251         
252         if(!CreatePipe(&(child_stdout_handle[0]),&(child_stdout_handle[1]),&sa,0))
253     {
254                 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));
255                 unit_set_error(command->unit, (int)GetLastError(), 0);
256                 
257                 CloseHandle(child_stdout_handle[0]);
258                 CloseHandle(child_stdout_handle[1]);
259                 CloseHandle(child_stdin_handle[0]);
260                 CloseHandle(child_stdin_handle[1]);
261
262                 command->failed = 1;
263                 command->status = cs_failed;    
264
265                 return;
266     }
267                 
268         /* Read handle for read operations on the child std output. */
269         if(!DuplicateHandle(GetCurrentProcess(),(child_stdin_handle[0]),GetCurrentProcess(),&(command->stdout_fd),0,FALSE, DUPLICATE_SAME_ACCESS))
270     {
271                 CloseHandle(child_stdout_handle[0]);
272                 CloseHandle(child_stdout_handle[1]);
273                 CloseHandle(child_stdin_handle[0]);
274                 CloseHandle(child_stdin_handle[1]);
275
276                 command->failed = 1;
277                 command->status = cs_failed;    
278                 
279                 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));
280                 unit_set_error(command->unit, (int)GetLastError(), 0);
281         
282                 return;
283         }
284         
285         
286         /* Write handle for write operations on the child std input. */
287         if(!DuplicateHandle(GetCurrentProcess(),(child_stdout_handle[1]),GetCurrentProcess(),&(command->stdin_fd), 0,FALSE,DUPLICATE_SAME_ACCESS))
288     {
289                 CloseHandle(child_stdout_handle[0]);
290                 CloseHandle(child_stdout_handle[1]);
291                 CloseHandle(child_stdin_handle[0]);
292                 CloseHandle(child_stdin_handle[1]);
293
294                 command->failed = 1;
295                 command->status = cs_failed;    
296                 
297                 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));
298
299                 unit_set_error(command->unit, (int)GetLastError(), 0);
300
301                 return;
302     }
303
304         
305         CloseHandle(child_stdin_handle[0]);
306         CloseHandle(child_stdout_handle[1]);
307         
308         if(command->timer)
309         {
310                 /* launch the timer */
311                 timer_time(command->timer);
312         }
313         
314         if(command->reader)
315         {
316                 /* launch the reader */
317                 reader_read(command->reader);
318         }
319     
320
321         if(command->writer)
322         {
323                 /* launch the writer */
324                 writer_write(command->writer);
325         }
326
327     si.cb = sizeof(STARTUPINFO);
328         
329         si.dwFlags |= STARTF_USESTDHANDLES;
330         si.hStdOutput = child_stdin_handle[1];
331         si.hStdInput  = child_stdout_handle[0];
332         si.hStdError  = child_stderr;
333
334         /* launch the process */
335         if(!CreateProcess(
336                                                 NULL,
337                                                 (char*)command_line,
338                                                 NULL,
339                                                 NULL,
340                                                 TRUE,
341                                                 CREATE_NO_WINDOW,
342                                                 NULL,
343                                                 NULL,
344                                                 &si,
345                                                 &pi)
346         )
347         {
348                 ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string((int)GetLastError(), 0));
349
350                 command_handle_failure(command,csr_create_process_function_failure);
351
352                 unit_set_error(command->unit, (int)GetLastError(), 0);
353     }
354         else
355         {
356                 /* the command is running */
357                 command->status = cs_in_progress;
358
359                 /* save the pid of the command */
360                 command->pid = pi.hProcess;
361
362                 /* close non used thread handle */
363                 CloseHandle(pi.hThread);
364                 
365         }
366
367         
368         /* close non used handles */
369         CloseHandle(child_stdin_handle[1]);
370     CloseHandle(child_stdout_handle[0]);
371         CloseHandle(child_stderr);
372
373
374 }
375 #else
376 void
377 command_exec(command_t command, const char* command_line)
378 {
379         int child_stdin_fd[2] ;
380         int child_stdout_fd[2];
381         
382         #ifdef __CHKCMD
383         int rv = is_cmd(command->unit->runner->path, command->unit->runner->builtin, command_line);
384
385         if(rv != 0)
386         {
387
388                 if(rv == EINVAL)
389                 {
390                         ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(rv, 0));
391                         unit_set_error(command->unit, rv, 0);
392                 }
393                 else
394                 {
395                         ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(rv, 1));
396                         unit_set_error(command->unit, rv, 1);
397                 }
398
399                 command_handle_failure(command, csr_command_not_found);
400         
401                 return;
402         }
403         
404         #endif
405         
406         
407         if(command->writer)
408         {
409                 if(pipe(child_stdin_fd)) 
410                 {
411                         ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));
412                         
413                         unit_set_error(command->unit, errno, 0);
414
415                         command_handle_failure(command, csr_pipe_function_failed);
416
417                         
418         
419                         return;
420                 }
421         }       
422         
423         if(command->reader)
424         {
425                 if(pipe(child_stdout_fd)) 
426                 {
427                         ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));
428                                 
429                         if(command->writer)
430                         {
431                                 close(child_stdin_fd[0]);
432                                 close(child_stdin_fd[1]);
433                         }
434                         
435                         unit_set_error(command->unit, errno, 0);
436
437                         command_handle_failure(command, csr_pipe_function_failed);
438                         
439                         return;
440                 }
441         }
442         
443         if(command->writer)
444         {
445                 if(fcntl(child_stdin_fd[1], F_SETFL, fcntl(child_stdin_fd[1], F_GETFL) | O_NONBLOCK) < 0)
446                 {
447
448                         ERROR3("[%s] `%s'  : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));
449                         
450                         close(child_stdin_fd[0]);
451                         close(child_stdin_fd[1]);
452                         
453                         if(command->reader)
454                         {
455                                 close(child_stdout_fd[0]);
456                                 close(child_stdout_fd[1]);
457                         }
458                         
459                         unit_set_error(command->unit, errno, 0);
460
461                         command_handle_failure(command, csr_fcntl_function_failed);     
462                                 
463                         return;
464                 }
465         }
466         
467         /* to write to the child stdin */
468         command->stdin_fd = child_stdin_fd[1];
469         
470         /* to read from the child stdout */
471         command->stdout_fd = child_stdout_fd[0];
472         
473         /* launch the reader if any*/
474         if(command->reader)
475                 reader_read(command->reader);
476     
477     /* launch the writer if any */
478         if(command->writer)
479                 writer_write(command->writer);
480         
481         /* launch the timer if any */
482         if(command->timer)
483                 timer_time(command->timer);
484                 
485         /* if there is a reader wait for its starting */
486         if(command->reader)
487                 xbt_os_sem_acquire(command->reader->started);
488         
489         /* if there is a reader wait for its ending */
490         if(command->writer)
491                 xbt_os_sem_acquire(command->writer->written);
492         
493         /* if there is a reader wait for its starting */
494         if(command->timer)
495                 xbt_os_sem_acquire(command->timer->started);
496         
497         /* update the state of the command, assume it is in progress */
498         command->status = cs_in_progress;
499                                 
500         command->pid= fork();
501                                 
502         if(command->pid < 0) 
503         {/* error */
504                 if(command->writer)
505                 {
506                         close(child_stdin_fd[0]);
507                         close(child_stdin_fd[1]);
508                 }
509                 
510                 if(command->reader)
511                 {
512                         close(child_stdout_fd[0]);
513                         close(child_stdout_fd[1]);
514                 }
515                 
516                 ERROR2("[%s] Cannot fork the command `%s'", command->context->pos, command->context->command_line);
517                 unit_set_error(command->unit, errno, 0);
518                 command_handle_failure(command,csr_fork_function_failure);
519         }
520         else
521         {
522                 if(command->pid) 
523                 {/* father */
524                         
525                         /* close unused file descriptors */
526                         if(command->writer)
527                                 close(child_stdin_fd[0]);
528                                 
529                         if(command->reader)
530                                 close(child_stdout_fd[1]);
531                 } 
532                 else 
533                 {/* child */
534                         
535                         /* close unused file descriptors */
536                         if(command->writer)
537                                 close(child_stdin_fd[1]);
538                                 
539                         if(command->reader)
540                                 close(child_stdout_fd[0]);
541                         
542                         if(command->writer)
543                         {
544                                 /* redirect stdin to child_stdin_fd[0] (now fgets(), getchar() ... read from the pipe */  
545                                 if(dup2(child_stdin_fd[0],STDIN_FILENO) < 0)
546                                 {
547                                         ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));
548                                         command->unit->exit_code = errno;
549
550                                         unit_set_error(command->unit, errno, 0);
551                                         command_handle_failure(command,csr_dup2_function_failure);
552                                 }
553                         
554                                 /* close the unused file descriptor  */
555                                 close(child_stdin_fd[0]);
556                         }
557                         
558                         if(command->reader)
559                         {
560                         
561                                 /* redirect stdout and stderr to child_stdout_fd[1] (now printf(), perror()... write to the pipe */  
562                                 if(dup2(child_stdout_fd[1],STDOUT_FILENO) < 0)
563                                 {
564                                         ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));
565
566                                         unit_set_error(command->unit, errno, 0);
567                                         command_handle_failure(command, csr_dup2_function_failure);
568                                 }
569                                 
570                                 if(dup2(child_stdout_fd[1], STDERR_FILENO) < 0)
571                                 {
572                                         ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));
573                                         unit_set_error(command->unit, errno, 0);
574                                         command_handle_failure(command, csr_dup2_function_failure);
575                                 }
576                         
577                                 /* close the unused file descriptor  */
578                                 close(child_stdout_fd[1]);
579                         }
580                         
581                         /* launch the command */
582                         if(execlp("/bin/sh", "sh", "-c", command->context->command_line, NULL) < 0)
583                                 command->execlp_errno = errno;
584                 }
585         }
586 }
587 #endif
588
589 #ifdef WIN32
590 void
591 command_wait(command_t command)
592 {
593         /* wait for the command terminaison */
594         DWORD rv;
595
596         if(WAIT_FAILED == WaitForSingleObject(command->pid, INFINITE))
597         {
598                 ERROR2("[%s] Cannot wait for the child`%s'", command->context->pos, command->context->command_line);
599                 
600                 unit_set_error(command->unit, (int)GetLastError(), 0);
601
602                 command_handle_failure(command, csr_wait_failure );
603                 /* TODO : see for the interruption      */      
604         }
605         else
606         {
607                 /* don't take care of the timer or the writer or the reader failue */
608                 if(cs_failed != command->status && cs_interrupted != command->status)
609                 {
610                         if(!GetExitCodeProcess(command->pid,&rv))
611                         {
612                                 ERROR2("[%s] Cannot get the exit code of the process `%s'",command->context->pos, command->context->command_line);
613                                 
614                                 unit_set_error(command->unit, (int)GetLastError(), 0);
615
616                                 command_handle_failure(command, csr_get_exit_code_process_function_failure );   
617                         }
618                         else
619                                 command->stat_val = command->exit_code = rv;
620                 }
621         }
622 }
623 #else
624 void
625 command_wait(command_t command)
626 {
627         if(!command->execlp_errno)
628         {
629                 /* let this thread wait for the child so that the main thread can detect the timeout without blocking on the wait */
630                 int pid = waitpid(command->pid, &(command->stat_val), 0);
631         
632                 if(pid != command->pid) 
633                 {
634                         ERROR2("[%s] Cannot wait for the child`%s'", command->context->pos, command->context->command_line);
635
636                         unit_set_error(command->unit, errno, 0);
637
638                         command_handle_failure(command, csr_waitpid_function_failure);
639                 }
640                 else
641                 {
642                         if(WIFEXITED(command->stat_val))
643                                 command->exit_code = WEXITSTATUS(command->stat_val);
644                 }
645         }
646         else
647         {
648                 ERROR2("[%s] Cannot execute the command `%s'", command->context->pos, command->context->command_line);
649
650                 unit_set_error(command->unit, command->execlp_errno, 0);
651
652                 command_handle_failure(command, csr_execlp_function_failure);
653         }
654 }
655 #endif
656
657 void
658 command_check(command_t command)
659 {
660         int success = 1;
661         cs_reason_t reason;
662         
663         /* we have a signal, store it */
664         if(WIFSIGNALED(command->stat_val))
665         {
666                 command->signal = strdup(signal_name(WTERMSIG(command->stat_val),command->context->signal));
667         }
668         
669         /* we have a signal and no signal is expected */
670         if(WIFSIGNALED(command->stat_val) && !command->context->signal) 
671         {
672                 success = 0;
673                 ERROR3("[%s] `%s' : NOK (unexpected signal `%s' caught)", command->context->pos, command->context->command_line, command->signal);
674
675                 unit_set_error(command->unit, EUNXPSIG, 1);
676
677                 reason = csr_unexpected_signal_caught;
678         }
679         
680         /* we have a signal that differ form the expected signal */
681         if(WIFSIGNALED(command->stat_val) && command->context->signal && strcmp(signal_name(WTERMSIG(command->stat_val),command->context->signal),command->context->signal)) 
682         {
683
684                 ERROR4("[%s] `%s' : NOK (got signal `%s' instead of `%s')", command->context->pos, command->context->command_line, command->signal, command->context->signal);
685                 
686                 if(success)
687                 {
688                         success = 0;
689                         unit_set_error(command->unit, ESIGNOTMATCH, 1);
690                 }
691                 
692                 reason = csr_signals_dont_match;
693         }
694         
695         /* we don't receipt the expected signal */
696         if(!WIFSIGNALED(command->stat_val) && command->context->signal) 
697         {
698                 
699                 ERROR3("[%s] `%s' : NOK (expected `%s' not receipt)", command->context->pos, command->context->command_line, command->context->signal);
700                 
701                 if(success)
702                 {
703                         success = 0;
704                         unit_set_error(command->unit, ESIGNOTRECEIPT, 1);
705                 }
706                 
707                 reason = csr_expected_signal_not_receipt;
708         }
709         
710         /* if the command exit normaly and we expect a exit code : test it */
711         if(WIFEXITED(command->stat_val) /* && INDEFINITE != command->context->exit_code*/)
712         {
713                 /* the exit codes don't match */
714                 if(WEXITSTATUS(command->stat_val) != command->context->exit_code)
715                 {
716                         ERROR4("[%s] %s : NOK (returned code `%d' instead `%d')", command->context->pos, command->context->command_line, WEXITSTATUS(command->stat_val), command->context->exit_code);
717                         
718                         if(success)
719                         {
720                                 success = 0;
721                                 unit_set_error(command->unit, EEXITCODENOTMATCH, 1);
722                         }
723         
724                         reason = csr_exit_codes_dont_match;
725                 }
726         }
727
728         /* make sure the reader done */
729         while(!command->reader->done)
730                 xbt_os_thread_yield();
731         
732         #ifdef WIN32
733         CloseHandle(command->stdout_fd);
734         #else
735         close(command->stdout_fd);
736         #endif
737
738         command->stdout_fd = INDEFINITE_FD;
739
740         xbt_strbuff_chomp(command->output);
741         xbt_strbuff_chomp(command->context->output);
742         xbt_strbuff_trim(command->output);
743         xbt_strbuff_trim(command->context->output);
744
745         if(!success)
746         {
747                 xbt_dynar_t a = xbt_str_split(command->output->data, "\n");
748                 char *out = xbt_str_join(a,"\n||");
749                 xbt_dynar_free(&a);
750                 INFO2("Output of <%s> so far: \n||%s", command->context->pos,out);
751                 free(out);    
752         }
753         /* if ouput handling flag is specified check the output */
754         else if(oh_check == command->context->output_handling && command->reader)
755         {
756                 if(command->output->used != command->context->output->used || strcmp(command->output->data, command->context->output->data))
757                 {
758                         char *diff;
759                         
760                         ERROR2("[%s] `%s' : NOK (outputs mismatch):", command->context->pos, command->context->command_line);
761                         
762                         if(success)
763                         {
764                                 unit_set_error(command->unit, EOUTPUTNOTMATCH, 1);
765                                 success = 0;
766                         }
767
768                         reason = csr_outputs_dont_match;
769
770                         /* display the diff */
771                         diff = xbt_str_diff(command->context->output->data,command->output->data);              
772                         INFO1("%s",diff);
773                         free(diff);
774                 }
775         }
776         else if (oh_ignore == command->context->output_handling) 
777         {
778                 INFO1("(ignoring the output of <%s> as requested)",command->context->line);
779         } 
780         else if (oh_display == command->context->output_handling) 
781         {
782                 xbt_dynar_t a = xbt_str_split(command->output->data, "\n");
783                 char *out = xbt_str_join(a,"\n||");
784                 xbt_dynar_free(&a);
785                 INFO3("[%s] Here is the (ignored) command `%s' output: \n||%s",command->context->pos, command->context->command_line, out);
786                 free(out);
787         } 
788         
789         if(success)
790         {
791                 xbt_os_mutex_acquire(command->mutex);
792                 
793                 if(command->status != cs_interrupted)
794                 {
795                         /* signal the success of the command */
796                         command->status = cs_successeded;
797                         command->successeded = 1;
798
799                         /* increment the number of successeded command of the unit */
800                         (command->root->successeded_cmd_nb)++;
801                 }
802                 
803                 xbt_os_mutex_release(command->mutex);   
804         }
805         else
806         {
807                 command_handle_failure(command, reason);
808         }
809 }
810
811 #ifdef WIN32
812 void
813 command_kill(command_t command)
814 {
815         if(INDEFINITE_PID != command->pid)
816         {
817                 INFO2("[%s] Kill the process `%s'", command->context->pos, command->context->command_line);
818                 TerminateProcess(command->pid, INDEFINITE);
819         }
820 }
821 #else
822 void
823 command_kill(command_t command)
824 {
825         if(INDEFINITE_PID != command->pid)
826         {
827                 kill(command->pid,SIGTERM);
828                 
829                 if(!command->context->signal)
830                         command->context->signal = strdup("SIGTERM");
831                         
832                 command->exit_code = INDEFINITE;
833                 command->killed = 1;
834                 
835                 usleep(100);
836
837                 INFO2("[%s] Kill the process `%s'", command->context->pos, command->context->command_line);
838                 kill(command->pid,SIGKILL); 
839
840                 
841         }
842 }
843 #endif
844
845 void
846 command_interrupt(command_t command)
847 {
848         xbt_os_mutex_acquire(command->mutex);
849         
850         if((command->status != cs_interrupted) && (command->status != cs_failed) && (command->status != cs_successeded))
851         {
852                 command->status = cs_interrupted;       
853                 command->reason = csr_interruption_request;
854                 command->interrupted = 1;
855                 command->unit->interrupted = 1;
856
857                 xbt_os_mutex_acquire(command->root->mutex);
858                 (command->root->interrupted_cmd_nb)++;
859                 xbt_os_mutex_release(command->root->mutex);
860                 
861                 if(command->pid != INDEFINITE_PID)
862                         command_kill(command);
863         }
864         
865         xbt_os_mutex_release(command->mutex);
866         
867         
868 }
869
870 void
871 command_summarize(command_t command)
872 {
873         if(cs_successeded != command->status)
874         {
875                         
876                 #ifndef WIN32
877                 if(command->killed)
878                         printf("          <killed command>\n");
879                 #endif
880                 
881                 /* display the reason of the status of the command */
882                 switch(command->reason)
883                 {
884                         /* the function pipe or CreatePipe() fails */
885                         case csr_pipe_function_failed :
886                         printf("          reason                      : pipe() or CreatePipe() function failed (system error)\n");
887                         break;
888                         
889                         case csr_shell_failed :
890                         printf("          reason                      : shell failed (may be command not found)\n");
891                         break;
892
893                         case csr_get_exit_code_process_function_failure :
894                         printf("          reason                      : ExitCodeProcess() function failed (system error)\n");
895                         break;
896                         
897                         /* reader failure reasons*/
898                         case csr_read_pipe_broken :
899                         printf("          reason                      : command read pipe broken\n");
900                         break;
901
902                         case csr_read_failure :
903                         printf("          reason                      : command stdout read failed\n");
904                         break;
905         
906                         /* writer failure reasons */
907                         case csr_write_failure :
908                         printf("          reason                      : command stdin write failed\n");
909                         break;
910
911                         case csr_write_pipe_broken :
912                         printf("          reason                      : command write pipe broken\n");
913                         break;
914                         
915                         /* timer reason */
916                         case csr_timeout :
917                         printf("          reason                      : command timeouted\n");
918                         break;
919                         
920                         /* command failure reason */
921                         case csr_command_not_found :
922                         printf("          reason                      : command not found\n");
923                         break;
924                         
925                         /* context failure reasons */
926                         case csr_exit_codes_dont_match :
927                         printf("          reason                      : exit codes don't match\n");
928                         
929                         break;
930                         
931                         /* dup2 function failure reasons */
932                         case csr_dup2_function_failure :
933                         printf("          reason                      : dup2() function failed\n");
934                         
935                         break;
936                         
937                         /* execlp function failure reasons */
938                         case csr_execlp_function_failure :
939                         printf("          reason                      : execlp() function failed\n");
940                         
941                         break;
942                         
943                         /* waitpid function failure reasons */
944                         case csr_waitpid_function_failure :
945                         printf("          reason                      : waitpid() function failed\n");
946                         
947                         break;
948                         
949                         /* CreateProcess function failure reasons */
950                         case csr_create_process_function_failure :
951                         printf("          reason                      : CreateProcesss() function failed\n");
952                         
953                         break;
954                         
955                         case csr_outputs_dont_match :
956                         {
957                                 char *diff;
958                                 printf("          reason                      : ouputs don't match\n");
959                                 diff = xbt_str_diff(command->context->output->data,command->output->data);              
960                                 printf("          output diff :\n%s\n",diff);
961                                 free(diff);
962                         }     
963
964                         break;
965
966                         case csr_signals_dont_match :
967                         printf("          reason                      : signals don't match\n"); 
968                         break;
969                         
970                         case csr_unexpected_signal_caught:
971                         printf("                reason                      : unexpected signal caught\n");
972                         break;
973                         
974                         case csr_expected_signal_not_receipt :
975                         printf("          reason                      : expected signal not receipt\n");
976                         break;
977
978                         /* system failure reasons */
979                         case csr_fork_function_failure :
980                         printf("          reason                      : fork function failed\n");
981                         break;
982                         
983                         case csr_wait_failure :
984                         printf("          reason                      : wait command failure\n");
985                         break;
986                         
987                         /* global/local interruption */
988                         case csr_interruption_request :
989                         printf("          reason                      : the command receive a interruption request\n");
990                         break;
991                         
992                         /* unknown ? */
993                         case csr_unknown :
994                         printf("          reason                      : unknown \n");
995                 }
996         }
997
998         if(csr_command_not_found != command->reason && csr_fork_function_failure != command->reason  && csr_execlp_function_failure != command->reason)
999         {
1000                 if(INDEFINITE != command->exit_code)
1001                         /* the command exit code */
1002                         printf("          exit code                   : %d\n",command->exit_code);
1003                 
1004                 /* if an expected exit code was specified display it */
1005                 if(INDEFINITE != command->context->exit_code)
1006                         printf("          expected exit code          : %d\n",command->context->exit_code);
1007                 else
1008                         printf("          no expected exit code specified\n");
1009                 
1010                 /* if an expected exit code was specified display it */
1011                 if(NULL == command->context->signal)
1012                         printf("          no expected signal specified\n");
1013                 else
1014                 {
1015                         if(NULL != command->signal)
1016                                 printf("          signal                      : %s\n",command->signal);
1017                         
1018                         printf("          expected signal             : %s\n",command->context->signal);
1019                 }
1020                 
1021                 /* if the command has out put and the metacommand display output is specified display it  */
1022                 if(command->output && (0 != command->output->used) && (oh_display == command->context->output_handling))
1023                 {
1024                         xbt_dynar_t a = xbt_str_split(command->output->data, "\n");
1025                         char *out = xbt_str_join(a,"\n||");
1026                         xbt_dynar_free(&a);
1027                         printf("          output :\n||%s",out);
1028                         free(out);
1029                 }
1030         }
1031
1032         printf("\n");
1033 }
1034
1035 void
1036 command_handle_failure(command_t command, cs_reason_t reason)
1037 {
1038         
1039         unit_t root = command->root;
1040         
1041         xbt_os_mutex_acquire(command->mutex);
1042
1043         if((command->status != cs_interrupted) && (command->status != cs_failed))
1044         {
1045                 command->status = cs_failed;
1046                 command->reason = reason;
1047                 command->failed = 1;
1048
1049                 command->unit->failed = 1;
1050                 
1051                 xbt_os_mutex_acquire(root->mutex);
1052                 
1053                 /* increment the number of failed command of the unit */
1054                 root->failed_cmd_nb++;
1055                 
1056                 /* if the --ignore-failures option is not specified */
1057                 if(!keep_going_unit_flag)
1058                 {
1059                         if(!root->interrupted)
1060                         {
1061                                 /* the unit interrupted (exit for the loop) */
1062                                 root->interrupted = 1;
1063
1064                                 /* release the unit */
1065                                 xbt_os_sem_release(root->sem);
1066                         }
1067                         
1068                         /* if the --keep-going option is not specified */
1069                         if(!keep_going_flag)
1070                         {
1071                                 if(!interrupted)
1072                                 {
1073                                         /* request an global interruption by the runner */
1074                                         interrupted = 1;
1075                                         
1076                                         /* release the runner */
1077                                         xbt_os_sem_release(units_sem);
1078                                 }
1079                         }
1080                 }
1081
1082                 xbt_os_mutex_release(root->mutex);
1083         }
1084
1085         xbt_os_mutex_release(command->mutex);
1086 }
1087
1088 int
1089 command_free(command_t* ptr)
1090 {
1091         /* close the stdin and the stdout pipe handles */
1092
1093         #ifdef WIN32
1094         if((*ptr)->stdin_fd != INDEFINITE_FD)
1095                 CloseHandle((*ptr)->stdin_fd);
1096                 
1097         if((*ptr)->stdout_fd != INDEFINITE_FD)
1098                 CloseHandle((*ptr)->stdout_fd);
1099         
1100         #else
1101         
1102         if((*ptr)->stdin_fd != INDEFINITE_FD)
1103                 close((*ptr)->stdin_fd);
1104         
1105         if((*ptr)->stdout_fd != INDEFINITE_FD)  
1106                 close((*ptr)->stdout_fd);
1107         #endif
1108         
1109         if((*ptr)->timer)
1110         {
1111                 if(timer_free(&((*ptr)->timer)) < 0)
1112                         return -1;
1113         }
1114         
1115         if((*ptr)->writer)
1116         {
1117                 if(writer_free(&((*ptr)->writer)) < 0)
1118                         return -1;
1119         }
1120         
1121         if((*ptr)->reader)
1122         {
1123                 if(reader_free(&((*ptr)->reader)) < 0)
1124                         return -1;
1125         }
1126         
1127         if((*ptr)->output)
1128                 xbt_strbuff_free((*ptr)->output);
1129         
1130         if((*ptr)->context)
1131         {
1132                 if(context_free(&((*ptr)->context)) < 0)
1133                         return -1;
1134         }
1135
1136         if((*ptr)->signal)
1137                 free((*ptr)->signal);
1138
1139         free(*ptr);
1140         
1141         *ptr = NULL;
1142         
1143         return 0;
1144 }
1145
1146
1147