Logo AND Algorithmique Numérique Distribuée

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