- const char* name;
- int number;
-}s_signal_entry_t,* signal_entry_t;
-
-static const s_signal_entry_t signals[] =
-{
- {"SIGHUP" ,1},
- {"SIGINT" ,2},
- {"SIGQUIT" ,3},
- {"SIGILL" ,4},
- {"SIGTRAP" ,5},
- {"SIGABRT" ,6},
- {"SIGEMT" ,7},
- {"SIGFPE" ,8},
- {"SIGKILL" ,9},
- {"SIGBUS" ,10},
- {"SIGSEGV" ,11},
- {"SIGSYS" ,12},
- {"SIGPIPE" ,13},
- {"SIGALRM" ,14},
- {"SIGTERM" ,15},
- {"SIGURG" ,16},
- {"SIGSTOP" ,17},
- {"SIGTSTP" ,18},
- {"SIGCONT" ,19},
- {"SIGCHLD" ,20},
- {"SIGTTIN" ,21},
- {"SIGTTOU" ,22},
- {"SIGIO" ,23},
- {"SIGXCPU" ,24},
- {"SIGXFSZ" ,25},
- {"SIGVTALRM",26},
- {"SIGPROF" ,27},
- {"SIGWINCH" ,28},
- {"SIGINFO" ,29},
- {"SIGUSR1" ,30},
- {"SIGUSR2" ,31}
-};
-
-#define SIGMAX 31
-#define SIGUNKNW SIGMAX + 1
-
-/* returns the name of the signal from it number */
-const char*
-signal_name(unsigned int number);
-
-/**
- ** Options
- **/
-int timeout_value = 5; /* child timeout value */
-char* expected_signal=NULL; /* !=NULL if the following command should raise a signal */
-int expected_return=0; /* the exepeted return code of following command */
-int verbose=0; /* wheather we should wine on problems */
-
-/**
- ** Dealing with timeouts
- **/
-int timeouted;
-static void timeout_handler(int sig) {
- timeouted = 1;
-}
-/**
- ** Dealing with timeouts
- **/
-int brokenpipe;
-static void pipe_handler(int sig) {
- brokenpipe = 1;
-}
-
-/**
- ** Launching a child
- **/
-buff_t *input;
-buff_t *output_wanted;
-buff_t *output_got;
-
-static void check_output() {
- if (output_wanted->used==0
- && output_got->used==0)
- return;
- buff_chomp(output_got);
- buff_chomp(output_wanted);
- buff_trim(output_got);
-buff_trim(output_wanted);
-
- if ( output_got->used != output_wanted->used
- || strcmp(output_got->data, output_wanted->data)) {
- fprintf(stderr,"Output don't match expectations\n");
- fprintf(stderr,">>>>> Expected %d chars:\n%s\n<<<<< Expected\n",
- output_wanted->used,output_wanted->data);
- fprintf(stderr,">>>>> Got %d chars:\n%s\n<<<<< Got\n",
- output_got->used,output_got->data);
- exit(2);
- }
- buff_empty(output_wanted);
- buff_empty(output_got);
-
-}
-
-static void exec_cmd(char *cmd) {
- int child_stdin[2];
- int child_stdout[2];
-
- if (pipe(child_stdin) || pipe(child_stdout)) {
- perror("Cannot open the pipes");
- exit(4);
- }
-
- int pid=fork();
- if (pid<0) {
- perror("Cannot fork the command");
- exit(4);
- }
-
- if (pid) { /* father */
- char buffout[4096];
- int posw,posr;
- int status;
- close(child_stdin[0]);
- fcntl(child_stdin[1], F_SETFL, O_NONBLOCK);
- close(child_stdout[1]);
- fcntl(child_stdout[0], F_SETFL, O_NONBLOCK);
-
- brokenpipe = 0;
- for (posw=0; posw<input->used && !brokenpipe; ) {
- int got;
- // fprintf(stderr,"Still %d chars to write\n",input->used-posw);
- got=write(child_stdin[1],input->data+posw,input->used-posw);
- if (got>0)
- posw+=got;
- if (got<0 && errno!=EINTR && errno!=EAGAIN && errno!=EPIPE) {
- perror("Error while writing input to child");
- exit(4);
- }
- // fprintf(stderr,"written %d chars so far\n",posw);
-
- posr=read(child_stdout[0],&buffout,4096);
- // fprintf(stderr,"got %d chars\n",posr);
- if (posr<0 && errno!=EINTR && errno!=EAGAIN) {
- perror("Error while reading output of child");
- exit(4);
- }
- if (posr>0) {
- buffout[posr]='\0';
- buff_append(output_got,buffout);
- }
-
- if (got <= 0 && posr <= 0)
- usleep(100);
- }
- input->data[0]='\0';
- input->used=0;
- close(child_stdin[1]);
-
- timeouted = 0;
- alarm(timeout_value);
- do {
- posr=read(child_stdout[0],&buffout,4096);
- if (posr<0 && errno!=EINTR && errno!=EAGAIN) {
- perror("Error while reading output of child");
- exit(4);
- }
- if (posr>0) {
- buffout[posr]='\0';
- buff_append(output_got,buffout);
- } else {
- usleep(100);
- }
- } while (!timeouted && posr!=0);
-
- /* Check for broken pipe */
- if (brokenpipe && verbose) {
- fprintf(stderr,"Warning: Child did not consume all its input (I got broken pipe)\n");
- }
-
- /* Check for timeouts */
- if (timeouted) {
- fprintf(stderr,"Child timeouted (waited %d sec)\n",timeout_value);
- exit(3);
- }
- alarm(0);
-
-
- /* Wait for child, and check why it terminated */
- wait(&status);
-
- if (WIFSIGNALED(status) && strcmp(signal_name(WTERMSIG(status)),expected_signal)) {
- fprintf(stderr,"Child got signal %s instead of signal %s\n",signal_name(WTERMSIG(status)), expected_signal);
- exit(WTERMSIG(status)+4);
- }
-
- if (!WIFSIGNALED(status) && expected_signal) {
- fprintf(stderr,"Child didn't got expected signal %s\n",
- expected_signal);
- exit(5);
- }
-
- if (WIFEXITED(status) && WEXITSTATUS(status) != expected_return ) {
- if (expected_return)
- fprintf(stderr,"Child returned code %d instead of %d\n",
- WEXITSTATUS(status), expected_return);
- else
- fprintf(stderr,"Child returned code %d\n", WEXITSTATUS(status));
- exit(40+WEXITSTATUS(status));
- }
- expected_return = 0;
-
- if(expected_signal){
- free(expected_signal);
- expected_signal = NULL;
- }
-
- } else { /* child */
-
- close(child_stdin[1]);
- close(child_stdout[0]);
- dup2(child_stdin[0],0);
- close(child_stdin[0]);
- dup2(child_stdout[1],1);
- dup2(child_stdout[1],2);
- close(child_stdout[1]);
-
- execlp ("/bin/sh", "sh", "-c", cmd, NULL);
- }
-}