I want to create a UNIX based shell
that supports commands with 1 pipe.
For example, the command ls | wc
I have wrote the following code but when I try an input like the one above, the program actes weird and can't figure out where the fault is.
To be more specific, it appears to fork()
properly, then exec()
with the proper parameters but only the command before the pipe (ls) exits properly. The command after the pipe (wc) never exits actually and as a result there is no output from the program.
I 've put some printf
to help me figure out where is the fault in the code.
Functions fetch_input
and string_tokenizer
are tested and work fine.
The fault must be somewhere below the point pointed in the code. Any suggestion to help me find what is the fault would be appreciated.
Thanks in advance.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define ANSI_COLOR_GREEN "\x1b[32m"
#define ANSI_COLOR_CYAN "\x1b[36m"
#define ANSI_COLOR_RESET "\x1b[0m"
char * fetch_input(char * buffer);
char * trim(char * string);
char ** string_tokenizer(char * string, char c);
int main(int arc, char * argv[]){
char *input, *init_input, **commands, **com1, **com2;
pid_t fork_pid_1, fork_pid_2, ret_pid;
int stat,i, fd[2];
init_input = (char *)malloc(sizeof(char)*256);
input = init_input;
input = fetch_input(input);
while(strcmp(input,"exit")!=0){
commands = string_tokenizer(input,'|');
com1 = string_tokenizer(commands[0],' ');
if(commands[1]==0){
fork_pid_1 = fork();
if(fork_pid_1<0){
printf("Fork Error!\n");
_exit(1);
}
else if(fork_pid_1==0){
execvp(com1[0],com1);
printf("Exec Error!\n");
_exit(1);
}
else{
ret_pid=wait(&stat);
}
}
else{ //the fault is probably somewhere below that point
if(pipe(fd)<0){ _exit(1);}
fork_pid_1 = fork();
if(fork_pid_1<0){
printf("Fork Error!\n");
_exit(1);
}
else if(fork_pid_1==0){
printf("First command, ready to exec...(pid:%d)\n",getpid());
close(fd[0]);
dup2(fd[1],1);
close(fd[1]);
execvp(com1[0],com1);
printf("Exec Error!\n");
_exit(1);
}
else{
com2 = string_tokenizer(commands[1],' ');
fork_pid_2=fork();
if(fork_pid_2<0){
printf("Fork Error!\n");
_exit(1);
}
else if(fork_pid_2==0){
printf("Second command, ready to exec...(pid:%d)\n",getpid());
close(fd[1]);
dup2(fd[0],0);
close(fd[0]);
execvp(com2[0],com2);
printf("Exec Error!\n");
_exit(1);
}
else{
printf("Now we 're in the parent process...(p_pid:%d)\n",getpid());
while( (ret_pid=waitpid(-1,&stat,0)) >0 ){
printf("Child process (%d) exited with status:%d\n",ret_pid,stat);
}
}
}
}
input = init_input;
input = fetch_input(input);
}
return 0;
}
char * fetch_input(char * buffer){
int i, sum;
do{
printf(ANSI_COLOR_CYAN "$" ANSI_COLOR_RESET);
fflush(stdin);
fgets(buffer,256,stdin);
if(buffer[strlen(buffer)-1]=='\n'){
buffer[strlen(buffer)-1]='\0';
}
sum=0;
for(i=0;i<strlen(buffer);i++){
if(buffer[i]==' '){sum++;}
}
}while(strlen(buffer)==sum);
buffer = trim(buffer);
return buffer;
}
char * trim(char * string){
int i;
i=strlen(string);
while(string[i-1]==' '){
i--;
}
*(string+i)='\0';
while(isspace(*string)){string++;}
return string;
}
char ** string_tokenizer(char * string, char c){
int j=0,k,i,done,found,first,last;
char ** ret, *str;
str=string;
if( (str==0) || (strlen(str)==0) ) return NULL;
ret = (char **)malloc(sizeof(char*));
do{
done=0;
found=0;
i=0;
first=-1;
last=-1;
while( (str[i]!='\0') && (done==0) ){
if( (str[i]==c) && (found==0) ){
i++;
}
else if( (str[i]!=c) && (found==0) ){
found=1;
first=i;
i++;
}
else if( (str[i]!=c) && (found!=0) ){
i++;
}
else if( (str[i]==c) && (found!=0) ){
done=1;
last=i;
}
}
if(done!=0){
*(ret+j) = (char *)malloc(sizeof(char)*(last-first+1));
for(k=first;k<last;k++){
*(*(ret+j)+(k-first)) = str[k];
}
*(*(ret+j)+(k-first)) = '\0';
*(ret+j) = trim(*(ret+j));
j++;
str=str+last;
}
}while(done!=0);
if( (done==0) && (found==0) ){
*(ret+j)=NULL;
}
else if( (done==0) && (found!=0) ){
*(ret+j) = (char *)malloc(sizeof(char)*(i-first+1));
for(k=first;k<i;k++){
*(*(ret+j)+(k-first)) = str[k];
}
*(*(ret+j)+(k-first)) = '\0';
*(ret+j)=trim(*(ret+j));
*(ret+j+1) = NULL;
}
return ret;
}