Logo AND Algorithmique Numérique Distribuée

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