Im have a little C program which executes bash commands (kind of shell program).
When user sends command such a:
ls -l | grep .[c,h]$ | wc –l
ls
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:
- 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....
- 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!