0

Im have a little C program which executes bash commands (kind of shell program).

When user sends command such a:

  1. ls -l | grep .[c,h]$ | wc –l

  2. ls

  3. echo | ls

I have decides to use linked list data sturcture, and this is the function that execute

int execute(command *c) {
//create new procces and execute command 

int numOfPipe = getNumOfPipes(c);   // gets how many commands there is seperated by | (for 1 command with no pipes. getNumOfPipes returns 1
int fds[numOfPipe][2];

pid_t pids[numOfPipe];
int i;
int status;

// create pipes
for( i = 0; i < numOfPipe; i++ ) {
    pipe(fds[i]);
}

i=0;

// p set to be the head of the list (first command)
Pipe* p = c->pl->head;  

// running throw all nodes
while(i<numOfPipe) {

    if ((pids[i] = fork()) < 0) {
            perror("fork");
            abort();
    } else if (pids[i] == 0) {
        // children processes

        // there is more then one command
        if (numOfPipe > 1) {    
            if (p==c->pl->head) // first node (will be first command)
                dup2(fds[i][1],STDOUT_FILENO);
            else if(p->next!=NULL) {    // not first / last command
                dup2(fds[i-1][0],STDIN_FILENO);
                dup2(fds[i][1],STDOUT_FILENO);

            } else if(p->next==NULL)    // last command
                dup2(fds[i-1][0],STDIN_FILENO);


            // closing all pipes
            int j;
            for( j = 0; j < numOfPipe; j++ ){
                close(fds[j][0]);
                close(fds[j][1]);
            }
        }

        // execute command
        execvp(p->params[0],p->params);

        // on execute error will print this messege and returns COMMAND_ERROR
        fprintf(stderr, "%s: command not found\n",p->params[0]);    
        destroyShell(c);
        free(c);
        exit(COMMAND_ERROR);    
    }

    // parent closing all end of pipes
    int j;
    for( j = 0; j < numOfPipe && numOfPipe > 1; j++ ){
        close(fds[j][0]);
        close(fds[j][1]);
    }

    // waiting each process
    while(wait(&status)!=pids[i]);

    // if the command is valid
    if (WIFEXITED(status) && WEXITSTATUS(status)==COMMAND_ERROR) {
        destroyShell(c);
        return WEXITSTATUS(status);
    }

    p=p->next;
    i++;


}

// closing all end of pipes (necessary here????)
int j;
for (j = 0; j < numOfPipe; j++) {
    close(fds[j][0]);
    close(fds[j][1]);
}

// returns all command's return code
if (WIFEXITED(status))
    return WEXITSTATUS(status);

return 0;
}

By now this code working in unpredicted way, for single command its working, for serval sometimes it working and sometimes not.... Spent many hours on this block of code and google didnt helped at all!!

Few notes:

  1. When user sends command such as:

echo|ls|123

return code will be COMMAND_ERROR macro define, and there suposed to be this error message:

123: command not found

but somehow my code will execute 'echo | ls' and show the output of the 2 first commands and after that will show the the error message for '123' command. Also for few bad commands - its suposed to show error message only for the first one it founds and its not suposed to continue to exec the next commands...

and for this command:

ls -l | grep .[c,h]$ | wc –l

it seems like it stocked in endless loop....

  1. Command *c is helding the linked list, each node in the list will be one command and each node will keep array call params which keep all the parameters of the command. exmaple:

echo 1234 | ls /home

 ___________                 ___________
|           |               |           |
| COMMAND 1 |      --->     | COMMAND 2 |
|___________|               |___________|
      |                           |
      |                           |
    ______                     _______
   |      |                   |       |
   | ECHO |                   |  LS   |
   |______|                   |_______|
   |      |                   |       |
   | 1234 |                   | /HOME |
   |______|                   |_______|

I hope i was clear enought and explained my issues well. Thank you very much!

sharonooo
  • 684
  • 3
  • 8
  • 25
  • Let me tell you that bash commands are executed in right to left manner... Hope you know that... – Hiren Pandya Apr 12 '13 at 12:38
  • And as you are using `fork()`.. The behavior you mentioned `but somehow my code will execute 'echo | ls' and will show the output of the 2 first commands` is due to that only. Parent process and child process... – Hiren Pandya Apr 12 '13 at 12:40
  • I know that...my assigment is to take the STDOUT of the command before the '|' sign and redirect it to the STDIN of the next one... got confiused which one is the command before and which one is after.... – sharonooo Apr 12 '13 at 12:44
  • `echo | ls` here the right most command will work as an input for the immediate left command to it... – Hiren Pandya Apr 12 '13 at 12:49
  • OK i think ive got the idea and its working.. the issues around the 'bad command' return code - it working good.. but there is still little issue about using wait() function and the pid[i]... where should i put this check? thanks – sharonooo Apr 12 '13 at 16:13

0 Answers0