- /* launch the writer if any */\r
- if(command->writer)\r
- writer_write(command->writer);\r
- \r
- /* launch the timer if any */\r
- if(command->timer)\r
- timer_time(command->timer);\r
- \r
- /* if there is a reader wait for its starting */\r
- if(command->reader)\r
- xbt_os_sem_acquire(command->reader->started);\r
- \r
- /* if there is a reader wait for its ending */\r
- if(command->writer)\r
- xbt_os_sem_acquire(command->writer->written);\r
- \r
- /* if there is a reader wait for its starting */\r
- if(command->timer)\r
- xbt_os_sem_acquire(command->timer->started);\r
- \r
- /* update the state of the command, assume it is in progress */\r
- command->status = cs_in_progress;\r
- \r
- command->pid= fork();\r
- \r
- if(command->pid < 0) \r
- {/* error */\r
- if(command->writer)\r
- {\r
- close(child_stdin_fd[0]);\r
- close(child_stdin_fd[1]);\r
- }\r
- \r
- if(command->reader)\r
- {\r
- close(child_stdout_fd[0]);\r
- close(child_stdout_fd[1]);\r
- }\r
- \r
- ERROR2("[%s] Cannot fork the command `%s'", command->context->pos, command->context->command_line);\r
- unit_set_error(command->unit, errno, 0, command->context->pos);\r
- command_handle_failure(command,csr_fork_function_failure);\r
- }\r
- else\r
- {\r
- if(command->pid) \r
- {/* father */\r
- \r
- /* close unused file descriptors */\r
- if(command->writer)\r
- close(child_stdin_fd[0]);\r
- \r
- if(command->reader)\r
- close(child_stdout_fd[1]);\r
- } \r
- else \r
- {/* child */\r
- \r
- /* close unused file descriptors */\r
- if(command->writer)\r
- close(child_stdin_fd[1]);\r
- \r
- if(command->reader)\r
- close(child_stdout_fd[0]);\r
- \r
- if(command->writer)\r
- {\r
- /* redirect stdin to child_stdin_fd[0] (now fgets(), getchar() ... read from the pipe */ \r
- if(dup2(child_stdin_fd[0],STDIN_FILENO) < 0)\r
- {\r
- ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));\r
- command->unit->exit_code = errno;\r
-\r
- unit_set_error(command->unit, errno, 0, command->context->pos);\r
- command_handle_failure(command,csr_dup2_function_failure);\r
- }\r
- \r
- /* close the unused file descriptor */\r
- close(child_stdin_fd[0]);\r
- }\r
- \r
- if(command->reader)\r
- {\r
- \r
- /* redirect stdout and stderr to child_stdout_fd[1] (now printf(), perror()... write to the pipe */ \r
- if(dup2(child_stdout_fd[1],STDOUT_FILENO) < 0)\r
- {\r
- ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));\r
-\r
- unit_set_error(command->unit, errno, 0, command->context->pos);\r
- command_handle_failure(command, csr_dup2_function_failure);\r
- }\r
- \r
- if(dup2(child_stdout_fd[1], STDERR_FILENO) < 0)\r
- {\r
- ERROR3("[%s] `%s' : NOK (%s)", command->context->pos, command->context->command_line, error_to_string(errno, 0));\r
- unit_set_error(command->unit, errno, 0, command->context->pos);\r
- command_handle_failure(command, csr_dup2_function_failure);\r
- }\r
- \r
- /* close the unused file descriptor */\r
- close(child_stdout_fd[1]);\r
- }\r
- \r
- /* launch the command */\r
- if(execlp("/bin/sh", "sh", "-c", command->context->command_line, NULL) < 0)\r
- command->execlp_errno = errno;\r
- }\r
- }\r
-}\r
-#endif\r
-\r
-#ifdef WIN32\r
-void\r
-command_wait(command_t command)\r
-{\r
- /* wait for the command terminaison */\r
- DWORD rv;\r
-\r
- if(WAIT_FAILED == WaitForSingleObject(command->pid, INFINITE))\r
- {\r
- ERROR2("[%s] Cannot wait for the child`%s'", command->context->pos, command->context->command_line);\r
- \r
- unit_set_error(command->unit, (int)GetLastError(), 0, command->context->pos);\r
-\r
- command_handle_failure(command, csr_wait_failure );\r
- /* TODO : see for the interruption */ \r
- }\r
- else\r
- {\r
- /* don't take care of the timer or the writer or the reader failue */\r
- if(cs_failed != command->status && cs_interrupted != command->status)\r
- {\r
- if(!GetExitCodeProcess(command->pid,&rv))\r
- {\r
- ERROR2("[%s] Cannot get the exit code of the process `%s'",command->context->pos, command->context->command_line);\r
- \r
- unit_set_error(command->unit, (int)GetLastError(), 0, command->context->pos);\r
-\r
- command_handle_failure(command, csr_get_exit_code_process_function_failure ); \r
- }\r
- else\r
- command->stat_val = command->exit_code = rv;\r
- }\r
- }\r
-}\r
-#else\r
-void\r
-command_wait(command_t command)\r
-{\r
- if(!command->execlp_errno)\r
- {\r
- /* let this thread wait for the child so that the main thread can detect the timeout without blocking on the wait */\r
- int pid = waitpid(command->pid, &(command->stat_val), 0);\r
- \r
- if(pid != command->pid) \r
- {\r
- ERROR2("[%s] Cannot wait for the child`%s'", command->context->pos, command->context->command_line);\r
-\r
- unit_set_error(command->unit, errno, 0, command->context->pos);\r
-\r
- command_handle_failure(command, csr_waitpid_function_failure);\r
- }\r
- else\r
- {\r
- if(WIFEXITED(command->stat_val))\r
- command->exit_code = WEXITSTATUS(command->stat_val);\r
- }\r
- }\r
- else\r
- {\r
- ERROR2("[%s] Cannot execute the command `%s'", command->context->pos, command->context->command_line);\r
-\r
- unit_set_error(command->unit, command->execlp_errno, 0, command->context->pos);\r
-\r
- command_handle_failure(command, csr_execlp_function_failure);\r
- }\r
-}\r
-#endif\r
-\r
-void\r
-command_check(command_t command)\r
-{\r
- int success = 1;\r
- cs_reason_t reason;\r
- \r
- /* we have a signal, store it */\r
- if(WIFSIGNALED(command->stat_val))\r
- {\r
- command->signal = strdup(signal_name(WTERMSIG(command->stat_val),command->context->signal));\r
- }\r
- \r
- /* we have a signal and no signal is expected */\r
- if(WIFSIGNALED(command->stat_val) && !command->context->signal) \r
- {\r
- success = 0;\r
- ERROR3("[%s] `%s' : NOK (unexpected signal `%s' caught)", command->context->pos, command->context->command_line, command->signal);\r
-\r
- unit_set_error(command->unit, EUNXPSIG, 1, command->context->pos);\r
-\r
- reason = csr_unexpected_signal_caught;\r
- }\r
- \r
- /* we have a signal that differ form the expected signal */\r
- if(WIFSIGNALED(command->stat_val) && command->context->signal && strcmp(signal_name(WTERMSIG(command->stat_val),command->context->signal),command->context->signal)) \r
- {\r
-\r
- ERROR4("[%s] `%s' : NOK (got signal `%s' instead of `%s')", command->context->pos, command->context->command_line, command->signal, command->context->signal);\r
- \r
- if(success)\r
- {\r
- success = 0;\r
- unit_set_error(command->unit, ESIGNOTMATCH, 1, command->context->pos);\r
- }\r
- \r
- reason = csr_signals_dont_match;\r
- }\r
- \r
- /* we don't receipt the expected signal */\r
- if(!WIFSIGNALED(command->stat_val) && command->context->signal) \r
- {\r
- \r
- ERROR3("[%s] `%s' : NOK (expected `%s' not receipt)", command->context->pos, command->context->command_line, command->context->signal);\r
- \r
- if(success)\r
- {\r
- success = 0;\r
- unit_set_error(command->unit, ESIGNOTRECEIPT, 1, command->context->pos);\r
- }\r
- \r
- reason = csr_expected_signal_not_receipt;\r
- }\r
- \r
- /* if the command exit normaly and we expect a exit code : test it */\r
- if(WIFEXITED(command->stat_val) /* && INDEFINITE != command->context->exit_code*/)\r
- {\r
- /* the exit codes don't match */\r
- if(WEXITSTATUS(command->stat_val) != command->context->exit_code)\r
- {\r
- 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
- \r
- if(success)\r
- {\r
- success = 0;\r
- unit_set_error(command->unit, EEXITCODENOTMATCH, 1, command->context->pos);\r
- }\r
- \r
- reason = csr_exit_codes_dont_match;\r
- }\r
- }\r
-\r
- /* make sure the reader done */\r
- while(!command->reader->done)\r
- xbt_os_thread_yield();\r
- \r
- #ifdef WIN32\r
- CloseHandle(command->stdout_fd);\r
- #else\r
- close(command->stdout_fd);\r
- #endif\r
-\r
- command->stdout_fd = INDEFINITE_FD;\r
-\r
- xbt_strbuff_chomp(command->output);\r
- xbt_strbuff_chomp(command->context->output);\r
- xbt_strbuff_trim(command->output);\r
- xbt_strbuff_trim(command->context->output);\r
-\r
- if(!success && !strcmp(command->output->data, command->context->output->data))\r
- {\r
- xbt_dynar_t a = xbt_str_split(command->output->data, "\n");\r
- char *out = xbt_str_join(a,"\n||");\r
- xbt_dynar_free(&a);\r
- INFO2("Output of <%s> so far: \n||%s", command->context->pos,out);\r
- free(out); \r
- }\r
- /* if ouput handling flag is specified check the output */\r
- else if(oh_check == command->context->output_handling && command->reader)\r
- {\r
- if(command->output->used != command->context->output->used || strcmp(command->output->data, command->context->output->data))\r
- {\r
- char *diff;\r
-\r
- \r
- ERROR2("[%s] `%s' : NOK (outputs mismatch):", command->context->pos, command->context->command_line);\r
- \r
- if(success)\r
- {\r
- unit_set_error(command->unit, EOUTPUTNOTMATCH, 1, command->context->pos);\r
- success = 0;\r
- }\r
-\r
- reason = csr_outputs_dont_match;\r
-\r
- /* display the diff */\r
- diff = xbt_str_diff(command->context->output->data,command->output->data); \r
- INFO1("%s",diff);\r
- free(diff);\r
- }\r
- }\r
- else if (oh_ignore == command->context->output_handling) \r
- {\r
- INFO1("(ignoring the output of <%s> as requested)",command->context->line);\r
- } \r
- else if (oh_display == command->context->output_handling) \r
- {\r
- xbt_dynar_t a = xbt_str_split(command->output->data, "\n");\r
- char *out = xbt_str_join(a,"\n||");\r
- xbt_dynar_free(&a);\r
- INFO3("[%s] Here is the (ignored) command `%s' output: \n||%s",command->context->pos, command->context->command_line, out);\r
- free(out);\r
- } \r
- \r
- if(success)\r
- {\r
- xbt_os_mutex_acquire(command->mutex);\r
- \r
- if(command->status != cs_interrupted)\r
- {\r
- /* signal the success of the command */\r
- command->status = cs_successeded;\r
- command->successeded = 1;\r
-\r
- /* increment the number of successeded command of the unit */\r
- (command->root->successeded_cmd_nb)++;\r
- }\r
- \r
- xbt_os_mutex_release(command->mutex); \r
- }\r
- else\r
- {\r
- command_handle_failure(command, reason);\r
- }\r
-}\r
-\r
-#ifdef WIN32\r
-void\r
-command_kill(command_t command)\r
-{\r
- if(INDEFINITE_PID != command->pid)\r
- {\r
- INFO2("[%s] Kill the process `%s'", command->context->pos, command->context->command_line);\r
- TerminateProcess(command->pid, INDEFINITE);\r
- }\r
-}\r
-#else\r
-void\r
-command_kill(command_t command)\r
-{\r
- if(INDEFINITE_PID != command->pid)\r
- {\r
- kill(command->pid,SIGTERM);\r
- \r
- if(!command->context->signal)\r
- command->context->signal = strdup("SIGTERM");\r
- \r
- command->exit_code = INDEFINITE;\r
- command->killed = 1;\r
- \r
- usleep(100);\r
-\r
- INFO2("[%s] Kill the process `%s'", command->context->pos, command->context->command_line);\r
- kill(command->pid,SIGKILL); \r
-\r
- \r
- }\r
-}\r
-#endif\r
-\r
-void\r
-command_interrupt(command_t command)\r
-{\r
- xbt_os_mutex_acquire(command->mutex);\r
- \r
- if((command->status != cs_interrupted) && (command->status != cs_failed) && (command->status != cs_successeded))\r
- {\r
- command->status = cs_interrupted; \r
- command->reason = csr_interruption_request;\r
- command->interrupted = 1;\r
- command->unit->interrupted = 1;\r
-\r
- xbt_os_mutex_acquire(command->root->mutex);\r
- (command->root->interrupted_cmd_nb)++;\r
- xbt_os_mutex_release(command->root->mutex);\r
- \r
- if(command->pid != INDEFINITE_PID)\r
- command_kill(command);\r
- }\r
- \r
- xbt_os_mutex_release(command->mutex);\r
- \r
- \r
-}\r
-\r
-void\r
-command_summarize(command_t command)\r
-{\r
- if(cs_successeded != command->status)\r
- {\r
- \r
- #ifndef WIN32\r
- if(command->killed)\r
- printf(" <killed command>\n");\r
- #endif\r
- \r
- /* display the reason of the status of the command */\r
- switch(command->reason)\r
- {\r
- /* the function pipe or CreatePipe() fails */\r
- case csr_pipe_function_failed :\r
- printf(" reason : pipe() or CreatePipe() function failed (system error)\n");\r
- break;\r
- \r
- case csr_shell_failed :\r
- printf(" reason : shell failed (may be command not found)\n");\r
- break;\r
-\r
- case csr_get_exit_code_process_function_failure :\r
- printf(" reason : ExitCodeProcess() function failed (system error)\n");\r
- break;\r
- \r
- /* reader failure reasons*/\r
- case csr_read_pipe_broken :\r
- printf(" reason : command read pipe broken\n");\r
- break;\r
-\r
- case csr_read_failure :\r
- printf(" reason : command stdout read failed\n");\r
- break;\r
- \r
- /* writer failure reasons */\r
- case csr_write_failure :\r
- printf(" reason : command stdin write failed\n");\r
- break;\r
-\r
- case csr_write_pipe_broken :\r
- printf(" reason : command write pipe broken\n");\r
- break;\r
- \r
- /* timer reason */\r
- case csr_timeout :\r
- printf(" reason : command timeouted\n");\r
- break;\r
- \r
- /* command failure reason */\r
- case csr_command_not_found :\r
- printf(" reason : command not found\n");\r
- break;\r
- \r
- /* context failure reasons */\r
- case csr_exit_codes_dont_match :\r
- printf(" reason : exit codes don't match\n");\r
- \r
- break;\r
- \r
- /* dup2 function failure reasons */\r
- case csr_dup2_function_failure :\r
- printf(" reason : dup2() function failed\n");\r
- \r
- break;\r
- \r
- /* execlp function failure reasons */\r
- case csr_execlp_function_failure :\r
- printf(" reason : execlp() function failed\n");\r
- \r
- break;\r
- \r
- /* waitpid function failure reasons */\r
- case csr_waitpid_function_failure :\r
- printf(" reason : waitpid() function failed\n");\r
- \r
- break;\r
- \r
- /* CreateProcess function failure reasons */\r
- case csr_create_process_function_failure :\r
- printf(" reason : CreateProcesss() function failed\n");\r
- \r
- break;\r
- \r
- case csr_outputs_dont_match :\r
- {\r
- char *diff;\r
- printf(" reason : ouputs don't match\n");\r
- diff = xbt_str_diff(command->context->output->data,command->output->data); \r
- printf(" output diff :\n%s\n",diff);\r
- free(diff);\r
- } \r
-\r
- break;\r
-\r
- case csr_signals_dont_match :\r
- printf(" reason : signals don't match\n"); \r
- break;\r
- \r
- case csr_unexpected_signal_caught:\r
- printf(" reason : unexpected signal caught\n");\r
- break;\r
- \r
- case csr_expected_signal_not_receipt :\r
- printf(" reason : expected signal not receipt\n");\r
- break;\r
-\r
- /* system failure reasons */\r
- case csr_fork_function_failure :\r
- printf(" reason : fork function failed\n");\r
- break;\r
- \r
- case csr_wait_failure :\r
- printf(" reason : wait command failure\n");\r
- break;\r
- \r
- /* global/local interruption */\r
- case csr_interruption_request :\r
- printf(" reason : the command receive a interruption request\n");\r
- break;\r
- \r
- /* unknown ? */\r
- case csr_unknown :\r
- printf(" reason : unknown \n");\r
- }\r
- }\r
-\r
- if(csr_command_not_found != command->reason && csr_fork_function_failure != command->reason && csr_execlp_function_failure != command->reason)\r
- {\r
- if(INDEFINITE != command->exit_code)\r
- /* the command exit code */\r
- printf(" exit code : %d\n",command->exit_code);\r
- \r
- /* if an expected exit code was specified display it */\r
- if(INDEFINITE != command->context->exit_code)\r
- printf(" expected exit code : %d\n",command->context->exit_code);\r
- else\r
- printf(" no expected exit code specified\n");\r
- \r
- /* no expected signal expected */\r
- if(NULL == command->context->signal)\r
- {\r
- printf(" no expected signal specified\n");\r
-\r
- if(command->signal)\r
- printf(" but got signal : %s\n",command->signal);\r
- \r
- }\r
- /* if an expected exit code was specified display it */\r
- else\r
- {\r
- if(NULL != command->signal)\r
- printf(" signal : %s\n",command->signal);\r
- else\r
- printf(" no signal caugth\n");\r
- }\r
- \r
- /* if the command has out put and the metacommand display output is specified display it */\r
- if(command->output && (0 != command->output->used) && (oh_display == command->context->output_handling))\r
- {\r
- xbt_dynar_t a = xbt_str_split(command->output->data, "\n");\r
- char *out = xbt_str_join(a,"\n||");\r
- xbt_dynar_free(&a);\r
- printf(" output :\n||%s",out);\r
- free(out);\r
- }\r
- }\r
-\r
- printf("\n");\r
-}\r
-\r
-void\r
-command_handle_failure(command_t command, cs_reason_t reason)\r
-{\r
- unit_t root = command->root;\r
- \r
- xbt_os_mutex_acquire(command->mutex);\r
-\r
- if((command->status != cs_interrupted) && (command->status != cs_failed))\r
- {\r
- command->status = cs_failed;\r
- command->reason = reason;\r
- command->failed = 1;\r
-\r
- command->unit->failed = 1;\r
- \r
- xbt_os_mutex_acquire(root->mutex);\r
- \r
- /* increment the number of failed command of the unit */\r
- root->failed_cmd_nb++;\r
- \r
- /* if the --ignore-failures option is not specified */\r
- if(!keep_going_unit_flag)\r
- {\r
- if(!root->interrupted)\r
- {\r
- /* the unit interrupted (exit for the loop) */\r
- root->interrupted = 1;\r
-\r
- /* release the unit */\r
- xbt_os_sem_release(root->sem);\r
- }\r
- \r
- /* if the --keep-going option is not specified */\r
- if(!keep_going_flag)\r
- {\r
- if(!interrupted)\r
- {\r
- /* request an global interruption by the runner */\r
- interrupted = 1;\r
- \r
- /* release the runner */\r
- xbt_os_sem_release(units_sem);\r
- }\r
- }\r
- }\r
-\r
- xbt_os_mutex_release(root->mutex);\r
- }\r
-\r
- xbt_os_mutex_release(command->mutex);\r
-}\r
-\r
-int\r
-command_free(command_t* ptr)\r
-{\r
- /* close the stdin and the stdout pipe handles */\r
-\r
- #ifdef WIN32\r
- if((*ptr)->stdin_fd != INDEFINITE_FD)\r
- CloseHandle((*ptr)->stdin_fd);\r
- \r
- if((*ptr)->stdout_fd != INDEFINITE_FD)\r
- CloseHandle((*ptr)->stdout_fd);\r
- \r
- #else\r
- \r
- if((*ptr)->stdin_fd != INDEFINITE_FD)\r
- close((*ptr)->stdin_fd);\r
- \r
- if((*ptr)->stdout_fd != INDEFINITE_FD) \r
- close((*ptr)->stdout_fd);\r
- #endif\r
- \r
- if((*ptr)->timer)\r
- {\r
- if(timer_free(&((*ptr)->timer)) < 0)\r
- return -1;\r
- }\r
- \r
- if((*ptr)->writer)\r
- {\r
- if(writer_free(&((*ptr)->writer)) < 0)\r
- return -1;\r
- }\r
- \r
- if((*ptr)->reader)\r
- {\r
- if(reader_free(&((*ptr)->reader)) < 0)\r
- return -1;\r
- }\r
- \r
- if((*ptr)->output)\r
- xbt_strbuff_free((*ptr)->output);\r
- \r
- if((*ptr)->context)\r
- {\r
- if(context_free(&((*ptr)->context)) < 0)\r
- return -1;\r
- }\r
-\r
- if((*ptr)->signal)\r
- free((*ptr)->signal);\r
-\r
- free(*ptr);\r
- \r
- *ptr = NULL;\r
- \r
- return 0;\r
-}\r
-\r
-\r
-\r
+ /* launch the reader */ \r
+ reader_read(command->reader);
+ \r}
+ \r\r\rif (command->writer)
+ \r {
+ \r
+ /* launch the writer */ \r
+ writer_write(command->writer);
+ \r}
+ \r\r
+ /* if there is a reader wait for its starting */ \r
+ if (command->reader)
+ \rxbt_os_sem_acquire(command->reader->started);
+ \r\r
+ /* if there is a reader wait for its ending */ \r
+ if (command->writer)
+ \rxbt_os_sem_acquire(command->writer->written);
+ \r\r
+ /* if there is a reader wait for its starting */ \r
+ if (command->timer)
+ \rxbt_os_sem_acquire(command->timer->started);
+ \r\rsi.cb = sizeof(STARTUPINFO);
+ \r\rsi.dwFlags |= STARTF_USESTDHANDLES;
+ \rsi.hStdOutput = child_stdin_handle[1];
+ \rsi.hStdInput = child_stdout_handle[0];
+ \rsi.hStdError = child_stderr;
+ \r\r
+ /* launch the process */ \r
+ if (!CreateProcess
+ (\rNULL, \rtow32cmd(command_line), \rNULL, \rNULL, \rTRUE,
+ \rCREATE_NO_WINDOW, \rNULL, \rNULL, \r&si, \r&pi) \r)
+ \r {
+ \r\rif (ERROR_FILE_NOT_FOUND == GetLastError())
+ \r {
+ \rERROR3("[%s] `%s' : NOK (%s)", command->context->pos,
+ command->context->command_line, error_to_string(ECMDNOTFOUND,
+ 1));
+ \runit_set_error(command->unit, ECMDNOTFOUND, 1,
+ command->context->pos);
+ \rcommand_handle_failure(command, csr_command_not_found);
+ \r}
+ \r
+ else
+ \r {
+ \rERROR3("[%s] `%s' : NOK (%s)", command->context->pos,
+ command->context->command_line,
+ error_to_string((int) GetLastError(), 0));
+ \r\runit_set_error(command->unit, (int) GetLastError(), 0,
+ command->context->pos);
+ \rcommand_handle_failure(command,
+ csr_create_process_function_failure);
+ \r} \r\r}
+ \r
+ else
+ \r {
+ \r
+ /* the command is running */ \r
+ command->status = cs_in_progress;
+ \r\r
+ /* save the pid of the command */ \r
+ command->pid = pi.hProcess;
+ \r\r
+ /* close non used thread handle */ \r
+ CloseHandle(pi.hThread);
+ \r\r}
+ \r\r\r
+ /* close non used handles */ \r
+ CloseHandle(child_stdin_handle[1]);
+ \rCloseHandle(child_stdout_handle[0]);
+ \rCloseHandle(child_stderr);
+\r\r\r}
+
+\r
+#else /* \r */
+void \r command_exec(command_t command, const char *command_line) \r
+{
+ \rint child_stdin_fd[2];
+ \rint child_stdout_fd[2];
+ \r\r
+#ifdef __CHKCMD\r
+ int rv =
+ is_cmd(command->unit->runner->path, command->unit->runner->builtin,
+ command_line);
+ \r\rif (rv != 0)
+ \r {
+ \r\rif (rv == EINVAL)
+ \r {
+ \rERROR3("[%s] `%s' : NOK (%s)", command->context->pos,
+ command->context->command_line, error_to_string(rv, 0));
+ \runit_set_error(command->unit, rv, 0, command->context->pos);
+ \r}
+ \r
+ else
+ \r {
+ \rERROR3("[%s] `%s' : NOK (%s)", command->context->pos,
+ command->context->command_line, error_to_string(rv, 1));
+ \runit_set_error(command->unit, rv, 1, command->context->pos);
+ \r}
+ \r\rcommand_handle_failure(command, csr_command_not_found);
+ \r\rreturn;
+ \r}
+ \r\r
+#endif /* \r */
+ \r\rif (command->writer)
+ \r {
+ \rif (pipe(child_stdin_fd))
+ \r {
+ \rERROR3("[%s] `%s' : NOK (%s)", command->context->pos,
+ command->context->command_line, error_to_string(errno, 0));
+ \r\runit_set_error(command->unit, errno, 0, command->context->pos);
+ \r\rcommand_handle_failure(command, csr_pipe_function_failed);
+ \r\r\r\rreturn;
+ \r}
+ \r}
+ \r\rif (command->reader)
+ \r {
+ \rif (pipe(child_stdout_fd))
+ \r {
+ \rERROR3("[%s] `%s' : NOK (%s)", command->context->pos,
+ command->context->command_line, error_to_string(errno, 0));
+ \r\rif (command->writer)
+ \r {
+ \rclose(child_stdin_fd[0]);
+ \rclose(child_stdin_fd[1]);
+ \r}
+ \r\runit_set_error(command->unit, errno, 0, command->context->pos);
+ \r\rcommand_handle_failure(command, csr_pipe_function_failed);
+ \r\rreturn;
+ \r}
+ \r}
+ \r\rif (command->writer)
+ \r {
+ \rif (fcntl
+ (child_stdin_fd[1], F_SETFL,
+ fcntl(child_stdin_fd[1], F_GETFL) | O_NONBLOCK) < 0)
+ \r {
+ \r\rERROR3("[%s] `%s' : NOK (%s)", command->context->pos,
+ command->context->command_line, error_to_string(errno, 0));
+ \r\rclose(child_stdin_fd[0]);
+ \rclose(child_stdin_fd[1]);
+ \r\rif (command->reader)
+ \r {
+ \rclose(child_stdout_fd[0]);
+ \rclose(child_stdout_fd[1]);
+ \r}
+ \r\runit_set_error(command->unit, errno, 0, command->context->pos);
+ \r\rcommand_handle_failure(command, csr_fcntl_function_failed);
+ \r\rreturn;
+ \r}
+ \r}
+ \r\r
+ /* to write to the child stdin */ \r
+ command->stdin_fd = child_stdin_fd[1];
+ \r\r
+ /* to read from the child stdout */ \r
+ command->stdout_fd = child_stdout_fd[0];
+ \r\r
+ /* launch the reader if any */ \r
+ if (command->reader)
+ \rreader_read(command->reader);
+ \r\r
+ /* launch the writer if any */ \r
+ if (command->writer)
+ \rwriter_write(command->writer);
+ \r\r
+ /* launch the timer if any */ \r
+ if (command->timer)
+ \rtimer_time(command->timer);
+ \r\r
+ /* if there is a reader wait for its starting */ \r
+ if (command->reader)
+ \rxbt_os_sem_acquire(command->reader->started);
+ \r\r
+ /* if there is a reader wait for its ending */ \r
+ if (command->writer)
+ \rxbt_os_sem_acquire(command->writer->written);
+ \r\r
+ /* if there is a reader wait for its starting */ \r
+ if (command->timer)
+ \rxbt_os_sem_acquire(command->timer->started);
+ \r\r
+ /* update the state of the command, assume it is in progress */ \r
+ command->status = cs_in_progress;
+ \r\rcommand->pid = fork();
+ \r\rif (command->pid < 0)
+ \r { /* error */
+ \rif (command->writer)
+ \r {
+ \rclose(child_stdin_fd[0]);
+ \rclose(child_stdin_fd[1]);
+ \r}
+ \r\rif (command->reader)
+ \r {
+ \rclose(child_stdout_fd[0]);
+ \rclose(child_stdout_fd[1]);
+ \r}
+ \r\rERROR2("[%s] Cannot fork the command `%s'", command->context->pos,
+ command->context->command_line);
+ \runit_set_error(command->unit, errno, 0, command->context->pos);
+ \rcommand_handle_failure(command, csr_fork_function_failure);
+ \r}
+ \r
+ else
+ \r {
+ \rif (command->pid)
+ \r { /* father */
+ \r\r
+ /* close unused file descriptors */ \r
+ if (command->writer)
+ \rclose(child_stdin_fd[0]);
+ \r\rif (command->reader)
+ \rclose(child_stdout_fd[1]);
+ \r}
+ \r
+ else
+ \r { /* child */
+ \r\r
+ /* close unused file descriptors */ \r
+ if (command->writer)
+ \rclose(child_stdin_fd[1]);
+ \r\rif (command->reader)
+ \rclose(child_stdout_fd[0]);
+ \r\rif (command->writer)
+ \r {
+ \r
+ /* redirect stdin to child_stdin_fd[0] (now fgets(), getchar() ... read from the pipe */ \r
+ if (dup2(child_stdin_fd[0], STDIN_FILENO) < 0)
+ \r {
+ \rERROR3("[%s] `%s' : NOK (%s)", command->context->pos,
+ command->context->command_line, error_to_string(errno,
+ 0));
+ \rcommand->unit->exit_code = errno;
+ \r\runit_set_error(command->unit, errno, 0, command->context->pos);
+ \rcommand_handle_failure(command, csr_dup2_function_failure);
+ \r}
+ \r\r
+ /* close the unused file descriptor */ \r
+ close(child_stdin_fd[0]);
+ \r}
+ \r\rif (command->reader)
+ \r {
+ \r\r
+ /* redirect stdout and stderr to child_stdout_fd[1] (now printf(), perror()... write to the pipe */ \r
+ if (dup2(child_stdout_fd[1], STDOUT_FILENO) < 0)
+ \r {
+ \rERROR3("[%s] `%s' : NOK (%s)", command->context->pos,
+ command->context->command_line, error_to_string(errno,
+ 0));
+ \r\runit_set_error(command->unit, errno, 0, command->context->pos);
+ \rcommand_handle_failure(command, csr_dup2_function_failure);
+ \r}
+ \r\rif (dup2(child_stdout_fd[1], STDERR_FILENO) < 0)
+ \r {
+ \rERROR3("[%s] `%s' : NOK (%s)", command->context->pos,
+ command->context->command_line, error_to_string(errno,
+ 0));
+ \runit_set_error(command->unit, errno, 0, command->context->pos);
+ \rcommand_handle_failure(command, csr_dup2_function_failure);
+ \r}
+ \r\r
+ /* close the unused file descriptor */ \r
+ close(child_stdout_fd[1]);
+ \r}
+ \r\r
+ /* launch the command */ \r
+ if (execlp
+ ("/bin/sh", "sh", "-c", command->context->command_line,
+ NULL) < 0)
+ \rcommand->execlp_errno = errno;
+ \r}
+ \r}
+\r}
+
+\r
+#endif /* \r */
+ \r
+#ifdef _XBT_WIN32\r
+void \r command_wait(command_t command) \r
+{
+ \r
+ /* wait for the command terminaison */ \r
+ DWORD rv;
+ \r\rif (WAIT_FAILED == WaitForSingleObject(command->pid, INFINITE))
+ \r {
+ \rERROR2("[%s] Cannot wait for the child`%s'", command->context->pos,
+ command->context->command_line);
+ \r\runit_set_error(command->unit, (int) GetLastError(), 0,
+ command->context->pos);
+ \r\rcommand_handle_failure(command, csr_wait_failure);
+ \r
+ /* TODO : see for the interruption */ \r
+ }
+ \r
+ else
+ \r {
+ \r
+ /* don't take care of the timer or the writer or the reader failue */ \r
+ if (cs_failed != command->status
+ && cs_interrupted != command->status)
+ \r {
+ \rif (!GetExitCodeProcess(command->pid, &rv))
+ \r {
+ \rERROR2("[%s] Cannot get the exit code of the process `%s'",
+ command->context->pos, command->context->command_line);
+ \r\runit_set_error(command->unit, (int) GetLastError(), 0,
+ command->context->pos);
+ \r\rcommand_handle_failure(command,
+ csr_get_exit_code_process_function_failure);
+ \r}
+ \r
+ else
+ \rcommand->stat_val = command->exit_code = rv;
+ \r}
+ \r}
+\r}
+
+\r
+#else /* \r */
+void \r command_wait(command_t command) \r
+{
+ \rif (!command->execlp_errno)
+ \r {
+ \r
+ /* let this thread wait for the child so that the main thread can detect the timeout without blocking on the wait */ \r
+ int pid = waitpid(command->pid, &(command->stat_val), 0);
+ \r\rif (pid != command->pid)
+ \r {
+ \rERROR2("[%s] Cannot wait for the child`%s'", command->context->pos,
+ command->context->command_line);
+ \r\runit_set_error(command->unit, errno, 0, command->context->pos);
+ \r\rcommand_handle_failure(command, csr_waitpid_function_failure);
+ \r}
+ \r
+ else
+ \r {
+ \rif (WIFEXITED(command->stat_val))
+ \rcommand->exit_code = WEXITSTATUS(command->stat_val);
+ \r}
+ \r}
+ \r
+ else
+ \r {
+ \rERROR2("[%s] Cannot execute the command `%s'", command->context->pos,
+ command->context->command_line);
+ \r\runit_set_error(command->unit, command->execlp_errno, 0,
+ command->context->pos);
+ \r\rcommand_handle_failure(command, csr_execlp_function_failure);
+ \r}
+\r}
+
+\r
+#endif /* \r */
+\rvoid \r command_check(command_t command) \r
+{
+ \rint success = 1;
+ \rcs_reason_t reason;
+ \r\r
+ /* we have a signal, store it */ \r
+ if (WIFSIGNALED(command->stat_val))
+ \r {
+ \rcommand->signal =
+ strdup(signal_name
+ (WTERMSIG(command->stat_val), command->context->signal));
+ \r}
+ \r\r
+ /* we have a signal and no signal is expected */ \r
+ if (WIFSIGNALED(command->stat_val) && !command->context->signal)
+ \r {
+ \rsuccess = 0;
+ \rERROR3("[%s] `%s' : NOK (unexpected signal `%s' caught)",
+ command->context->pos, command->context->command_line,
+ command->signal);
+ \r\runit_set_error(command->unit, EUNXPSIG, 1, command->context->pos);
+ \r\rreason = csr_unexpected_signal_caught;
+ \r}
+ \r\r
+ /* we have a signal that differ form the expected signal */ \r
+ if (WIFSIGNALED(command->stat_val) && command->context->signal
+ &&
+ strcmp(signal_name
+ (WTERMSIG(command->stat_val), command->context->signal),
+ command->context->signal))
+ \r {
+ \r\rERROR4("[%s] `%s' : NOK (got signal `%s' instead of `%s')",
+ command->context->pos, command->context->command_line,
+ command->signal, command->context->signal);
+ \r\rif (success)
+ \r {
+ \rsuccess = 0;
+ \runit_set_error(command->unit, ESIGNOTMATCH, 1,
+ command->context->pos);
+ \r}
+ \r\rreason = csr_signals_dont_match;
+ \r}
+ \r\r
+ /* we don't receive the expected signal */ \r
+ if (!WIFSIGNALED(command->stat_val) && command->context->signal)
+ \r {
+ \r\rERROR3("[%s] `%s' : NOK (expected `%s' not received)",
+ command->context->pos, command->context->command_line,
+ command->context->signal);
+ \r\rif (success)
+ \r {
+ \rsuccess = 0;
+ \runit_set_error(command->unit, ESIGNOTRECEIVED, 1,
+ command->context->pos);
+ \r}
+ \r\rreason = csr_expected_signal_not_received;
+ \r}
+ \r\r
+ /* if the command exit normaly and we expect a exit code : test it */ \r
+ if (WIFEXITED(command->stat_val)
+ /* && INDEFINITE != command->context->exit_code */ )
+ \r {
+ \r
+ /* the exit codes don't match */ \r
+ if (WEXITSTATUS(command->stat_val) != command->context->exit_code)
+ \r {
+ \rERROR4("[%s] %s : NOK (returned code `%d' instead `%d')",
+ command->context->pos, command->context->command_line,
+ WEXITSTATUS(command->stat_val), command->context->exit_code);
+ \r\rif (success)
+ \r {
+ \rsuccess = 0;
+ \runit_set_error(command->unit, EEXITCODENOTMATCH, 1,
+ command->context->pos);
+ \r}
+ \r\rreason = csr_exit_codes_dont_match;
+ \r}
+ \r}
+ \r\r
+ /* make sure the reader done */ \r
+ while (!command->reader->done)
+ \rxbt_os_thread_yield();
+ \r\r
+#ifdef _XBT_WIN32\r
+ CloseHandle(command->stdout_fd);
+ \r
+#else /* \r */
+ close(command->stdout_fd);
+ \r
+#endif /* \r */
+ \rcommand->stdout_fd = INDEFINITE_FD;
+ \r\rxbt_strbuff_chomp(command->output);
+ \rxbt_strbuff_chomp(command->context->output);
+ \rxbt_strbuff_trim(command->output);
+ \rxbt_strbuff_trim(command->context->output);
+ \r\rif (!success
+ && !strcmp(command->output->data, command->context->output->data))
+ \r {
+ \rxbt_dynar_t a = xbt_str_split(command->output->data, "\n");
+ \rchar *out = xbt_str_join(a, "\n||");
+ \rxbt_dynar_free(&a);
+ \rINFO2("Output of <%s> so far: \n||%s", command->context->pos, out);
+ \rfree(out);
+ \r}
+ \r
+ /* if ouput handling flag is specified check the output */ \r
+ else if (oh_check == command->context->output_handling
+ && command->reader)
+ \r {
+ \rif (command->output->used != command->context->output->used
+ || strcmp(command->output->data, command->context->output->data))
+ \r {
+ \rchar *diff;
+ \r\r\rERROR2("[%s] `%s' : NOK (outputs mismatch):",
+ command->context->pos, command->context->command_line);
+ \r\rif (success)
+ \r {
+ \runit_set_error(command->unit, EOUTPUTNOTMATCH, 1,
+ command->context->pos);
+ \rsuccess = 0;
+ \r}
+ \r\rreason = csr_outputs_dont_match;
+ \r\r
+ /* display the diff */ \r
+ diff =
+ xbt_str_diff(command->context->output->data,
+ command->output->data);
+ \rINFO1("%s", diff);
+ \rfree(diff);
+ \r}
+ \r}
+ \r
+ else if (oh_ignore == command->context->output_handling)
+ \r {
+ \rINFO1("(ignoring the output of <%s> as requested)",
+ command->context->line);
+ \r}
+ \r
+ else if (oh_display == command->context->output_handling)
+ \r {
+ \rxbt_dynar_t a = xbt_str_split(command->output->data, "\n");
+ \rchar *out = xbt_str_join(a, "\n||");
+ \rxbt_dynar_free(&a);
+ \rINFO3("[%s] Here is the (ignored) command `%s' output: \n||%s",
+ command->context->pos, command->context->command_line, out);
+ \rfree(out);
+ \r}
+ \r\rif (success)
+ \r {
+ \rxbt_os_mutex_acquire(command->mutex);
+ \r\rif (command->status != cs_interrupted)
+ \r {
+ \r
+ /* signal the success of the command */ \r
+ command->status = cs_successeded;
+ \rcommand->successeded = 1;
+ \r\r
+ /* increment the number of successeded command of the unit */ \r
+ (command->root->successeded_cmd_nb)++;
+ \r}
+ \r\rxbt_os_mutex_release(command->mutex);
+ \r}
+ \r
+ else
+ \r {
+ \rcommand_handle_failure(command, reason);
+ \r}
+\r}
+
+\r\r
+#ifdef _XBT_WIN32\r
+void \r command_kill(command_t command) \r
+{
+ \rif (INDEFINITE_PID != command->pid)
+ \r {
+ \rINFO2("[%s] Kill the process `%s'", command->context->pos,
+ command->context->command_line);
+ \rTerminateProcess(command->pid, INDEFINITE);
+ \r}
+\r}
+
+\r
+#else /* \r */
+void \r command_kill(command_t command) \r
+{
+ \rif (INDEFINITE_PID != command->pid)
+ \r {
+ \rkill(command->pid, SIGTERM);
+ \r\rif (!command->context->signal)
+ \rcommand->context->signal = strdup("SIGTERM");
+ \r\rcommand->exit_code = INDEFINITE;
+ \rcommand->killed = 1;
+ \r\rusleep(100);
+ \r\rINFO2("[%s] Kill the process `%s'", command->context->pos,
+ command->context->command_line);
+ \rkill(command->pid, SIGKILL);
+ \r\r\r}
+\r}
+
+\r
+#endif /* \r */
+\rvoid \r command_interrupt(command_t command) \r
+{
+ \rxbt_os_mutex_acquire(command->mutex);
+ \r\rif ((command->status != cs_interrupted)
+ && (command->status != cs_failed)
+ && (command->status != cs_successeded))
+ \r {
+ \rcommand->status = cs_interrupted;
+ \rcommand->reason = csr_interruption_request;
+ \rcommand->interrupted = 1;
+ \rcommand->unit->interrupted = 1;
+ \r\rxbt_os_mutex_acquire(command->root->mutex);
+ \r(command->root->interrupted_cmd_nb)++;
+ \rxbt_os_mutex_release(command->root->mutex);
+ \r\rif (command->pid != INDEFINITE_PID)
+ \rcommand_kill(command);
+ \r}
+ \r\rxbt_os_mutex_release(command->mutex);
+\r\r\r}
+
+\r\rvoid \r command_summarize(command_t command) \r
+{
+ \rif (cs_successeded != command->status)
+ \r {
+ \r\r
+#ifndef _XBT_WIN32\r
+ if (command->killed)
+ \rprintf(" <killed command>\n");
+ \r
+#endif /* \r */
+ \r
+ /* display the reason of the status of the command */ \r
+ switch (command->reason)
+ \r {
+ \r
+ /* the function pipe or CreatePipe() fails */ \r
+ case csr_pipe_function_failed:
+
+ \rprintf
+ (" reason : pipe() or CreatePipe() function failed (system error)\n");
+ \rbreak;
+ \r\rcase csr_shell_failed:
+ \rprintf
+ (" reason : shell failed (may be command not found)\n");
+ \rbreak;
+ \r\rcase csr_get_exit_code_process_function_failure:
+ \rprintf
+ (" reason : ExitCodeProcess() function failed (system error)\n");
+ \rbreak;
+ \r\r
+ /* reader failure reasons */ \r
+ case csr_read_pipe_broken:
+
+ \rprintf
+ (" reason : command read pipe broken\n");
+ \rbreak;
+ \r\rcase csr_read_failure:
+ \rprintf
+ (" reason : command stdout read failed\n");
+ \rbreak;
+ \r\r
+ /* writer failure reasons */ \r
+ case csr_write_failure:
+
+ \rprintf
+ (" reason : command stdin write failed\n");
+ \rbreak;
+ \r\rcase csr_write_pipe_broken:
+ \rprintf
+ (" reason : command write pipe broken\n");
+ \rbreak;
+ \r\r
+ /* timer reason */ \r
+ case csr_timeout:
+
+ \rprintf
+ (" reason : command timeouted\n");
+ \rbreak;
+ \r\r
+ /* command failure reason */ \r
+ case csr_command_not_found:
+
+ \rprintf
+ (" reason : command not found\n");
+ \rbreak;
+ \r\r
+ /* context failure reasons */ \r
+ case csr_exit_codes_dont_match:
+
+ \rprintf
+ (" reason : exit codes don't match\n");
+ \r\rbreak;
+ \r\r
+ /* dup2 function failure reasons */ \r
+ case csr_dup2_function_failure:
+
+ \rprintf
+ (" reason : dup2() function failed\n");
+ \r\rbreak;
+ \r\r
+ /* execlp function failure reasons */ \r
+ case csr_execlp_function_failure:
+
+ \rprintf
+ (" reason : execlp() function failed\n");
+ \r\rbreak;
+ \r\r
+ /* waitpid function failure reasons */ \r
+ case csr_waitpid_function_failure:
+
+ \rprintf
+ (" reason : waitpid() function failed\n");
+ \r\rbreak;
+ \r\r
+ /* CreateProcess function failure reasons */ \r
+ case csr_create_process_function_failure:
+
+ \rprintf
+ (" reason : CreateProcesss() function failed\n");
+ \r\rbreak;
+ \r\rcase csr_outputs_dont_match:
+ \r {
+ \r
+ /*char *diff; */ \r
+ printf
+ (" reason : ouputs don't match\n");
+ \r
+ /*diff = xbt_str_diff(command->context->output->data,command->output->data);\r
+ printf(" output diff :\n%s\n",diff);\r
+ free(diff); */ \r
+ }
+ \r\rbreak;
+ \r\rcase csr_signals_dont_match:
+ \rprintf
+ (" reason : signals don't match\n");
+ \rbreak;
+ \r\rcase csr_unexpected_signal_caught:
+ \rprintf
+ (" reason : unexpected signal caught\n");
+ \rbreak;
+ \r\rcase csr_expected_signal_not_received:
+ \rprintf
+ (" reason : expected signal not receipt\n");
+ \rbreak;
+ \r\r
+ /* system failure reasons */ \r
+ case csr_fork_function_failure:
+
+ \rprintf
+ (" reason : fork function failed\n");
+ \rbreak;
+ \r\rcase csr_wait_failure:
+ \rprintf
+ (" reason : wait command failure\n");
+ \rbreak;
+ \r\r
+ /* global/local interruption */ \r
+ case csr_interruption_request:
+
+ \rprintf
+ (" reason : the command receive a interruption request\n");
+ \rbreak;
+ \r\r
+ /* unknown ? */ \r
+ case csr_unknown:
+ \rprintf(" reason : unknown \n");
+ \r}
+ \r}
+ \r\rif (csr_command_not_found != command->reason
+ && csr_fork_function_failure != command->reason
+ && csr_execlp_function_failure != command->reason)
+ \r {
+ \rif (INDEFINITE != command->exit_code)
+ \r
+ /* the command exit code */ \r
+ printf(" exit code : %d\n",
+ command->exit_code);
+ \r\r
+ /* if an expected exit code was specified display it */ \r
+ if (INDEFINITE != command->context->exit_code)
+ \rprintf(" expected exit code : %d\n",
+ command->context->exit_code);
+ \r
+ else
+ \rprintf(" no expected exit code specified\n");
+ \r\r
+ /* no expected signal expected */ \r
+ if (NULL == command->context->signal)
+ \r {
+ \rprintf(" no expected signal specified\n");
+ \r\rif (command->signal)
+ \rprintf(" but got signal : %s\n",
+ command->signal);
+ \r\r}
+ \r
+ /* if an expected exit code was specified display it */ \r
+ else
+ \r {
+ \rif (NULL != command->signal)
+ \rprintf(" signal : %s\n",
+ command->signal);
+ \r
+ else
+ \rprintf(" no signal caugth\n");
+ \r}
+ \r\r
+ /* if the command has out put and the metacommand display output is specified display it */ \r
+ if (command->output && (0 != command->output->used)
+ && (oh_display == command->context->output_handling))
+ \r {
+ \rxbt_dynar_t a = xbt_str_split(command->output->data, "\n");
+ \rchar *out = xbt_str_join(a, "\n||");
+ \rxbt_dynar_free(&a);
+ \rprintf(" output :\n||%s", out);
+ \rfree(out);
+ \r}
+ \r}
+ \r\rprintf("\n");
+\r} \r\rvoid \r command_handle_failure(command_t command, cs_reason_t reason) \r
+{
+ \runit_t root = command->root;
+ \r\rxbt_os_mutex_acquire(command->mutex);
+ \r\rif ((command->status != cs_interrupted)
+ && (command->status != cs_failed))
+ \r {
+ \rcommand->status = cs_failed;
+ \rcommand->reason = reason;
+ \rcommand->failed = 1;
+ \r\rcommand->unit->failed = 1;
+ \r\rxbt_os_mutex_acquire(root->mutex);
+ \r\r
+ /* increment the number of failed command of the unit */ \r
+ root->failed_cmd_nb++;
+ \r\r
+ /* if the --ignore-failures option is not specified */ \r
+ if (!keep_going_unit_flag)
+ \r {
+ \rif (!root->interrupted)
+ \r {
+ \r
+ /* the unit interrupted (exit for the loop) */ \r
+ root->interrupted = 1;
+ \r\r
+ /* release the unit */ \r
+ xbt_os_sem_release(root->sem);
+ \r}
+ \r\r
+ /* if the --keep-going option is not specified */ \r
+ if (!keep_going_flag)
+ \r {
+ \rif (!interrupted)
+ \r {
+ \r
+ /* request an global interruption by the runner */ \r
+ interrupted = 1;
+ \r\r
+ /* release the runner */ \r
+ xbt_os_sem_release(units_sem);
+ \r}
+ \r}
+ \r}
+ \r\rxbt_os_mutex_release(root->mutex);
+ \r}
+ \r\rxbt_os_mutex_release(command->mutex);
+\r}
+
+\r\rint \r command_free(command_t * ptr) \r
+{
+ \r
+ /* close the stdin and the stdout pipe handles */ \r
+ \r
+#ifdef _XBT_WIN32\r
+ if ((*ptr)->stdin_fd != INDEFINITE_FD)
+ \rCloseHandle((*ptr)->stdin_fd);
+ \r\rif ((*ptr)->stdout_fd != INDEFINITE_FD)
+ \rCloseHandle((*ptr)->stdout_fd);
+ \r\r
+#else /* \r */
+ \rif ((*ptr)->stdin_fd != INDEFINITE_FD)
+ \rclose((*ptr)->stdin_fd);
+ \r\rif ((*ptr)->stdout_fd != INDEFINITE_FD)
+ \rclose((*ptr)->stdout_fd);
+ \r
+#endif /* \r */
+ \rif ((*ptr)->timer)
+ \r {
+ \rif (timer_free(&((*ptr)->timer)) < 0)
+ \rreturn -1;
+ \r}
+ \r\rif ((*ptr)->writer)
+ \r {
+ \rif (writer_free(&((*ptr)->writer)) < 0)
+ \rreturn -1;
+ \r}
+ \r\rif ((*ptr)->reader)
+ \r {
+ \rif (reader_free(&((*ptr)->reader)) < 0)
+ \rreturn -1;
+ \r}
+ \r\rif ((*ptr)->output)
+ \rxbt_strbuff_free((*ptr)->output);
+ \r\rif ((*ptr)->context)
+ \r {
+ \rif (context_free(&((*ptr)->context)) < 0)
+ \rreturn -1;
+ \r}
+ \r\rif ((*ptr)->signal)
+ \rfree((*ptr)->signal);
+ \r\rfree(*ptr);
+ \r\r*ptr = NULL;
+ \r\rreturn 0;
+\r}
+
+\r\r\r\r