Logo AND Algorithmique Numérique Distribuée

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