Logo AND Algorithmique Numérique Distribuée

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