Logo AND Algorithmique Numérique Distribuée

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