简体   繁体   中英

shell in C, input & pipes

I've been making a mini shell in C, that has to receive commands with at least 3 arguments, parsing them, then applying fork() and exec(), if you just press enter it should print the prompt back again. Also it has to accept multiple pipes, that's where i have been stuck. This is my code

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/wait.h>

int main(){

char command[50];
char* token;
char* param[50][50];
int i,j,k;


 while(1){
        printf("shell:~");
        fgets(command, sizeof(command), stdin);

        i=0,j=0;                        
        token = strtok(command," \n\0\t");      
    while(1){
        if(token==NULL) break;  
        else if(strcmp(token,"|")==0){
            param[i][j]=0;
            i = i+1;
            j=0;
            token = strtok(NULL," \n\0\t");
        }
        else{
            param[i][j]=token;                      
            token = strtok(NULL," \n\0\t");
            j = j+1;
        }
        }
        param[i][j]=0;

Everythig work fine till here.

    pid_t pid1,pid2;
    int fd1[2],fd2[2];
    //int numpipe = i-1;

    pipe(fd1);
    pipe(fd2);
    int status;

    pid1 = fork();
    if(pid1==0){
        k=0;
        while(k<i+1){
            pid2 = fork();
            if(pid2==0){

                if(k==0){// if it is first
                    if(k==i){//and last one
                        execvp(param[k][0],param[k]);

                    }else{
                        dup2(fd1[1],STDOUT_FILENO);
                        close(fd1[0]);
                        execvp(param[k][0],param[k]);

                        }                       
                }else if(0<k<i){//if it is in the middle
                    if(k%2==0){ // position odd
                        dup2(fd2[0],STDIN_FILENO);
                        close(fd2[1]);
                        dup2(fd1[1],STDOUT_FILENO);
                        close(fd1[0]);
                        execvp(param[k][0],param[k]);
                    }else{ //position 
                        dup2(fd1[0],STDIN_FILENO);
                        close(fd1[1]);
                        dup2(fd2[1],STDOUT_FILENO);
                        close(fd2[0]);
                        execvp(param[k][0],param[k]);   
                    }   
                }else{//if it is lasts
                    if(k%2==0){
                        dup2(fd2[0],STDIN_FILENO);
                        close(fd2[1]);
                        execvp(param[k][0],param[k]);
                    }else{
                        dup2(fd1[1],STDIN_FILENO);
                        close(fd1[1]);
                        execvp(param[k][0],param[k]);
                    }
                }                                   
            }else{
                k++;
                wait(NULL);
            }
    }
}
    else{
        wait(NULL);
    }
}
return 0;
}

The code works good if I use only 1 command, but when i put a pipe it doesnt get the input,for example:

    shell:~ls -l
    total 112
    -rw-r--r-- 1 cristian cristian 72018 mar 28 13:25 (107315)proyecto1-SO2017-1.pdf
    -rw-rw-r-- 1 cristian cristian     0 abr  2 12:23 a.out
    -rw-rw-r-- 1 cristian cristian  1082 abr  1 23:47 reaspaldo2
    -rw-rw-r-- 1 cristian cristian  1217 abr  2 03:00 reaspaldo2.c
    -rw-rw-r-- 1 cristian cristian   962 abr  1 19:40 respaldo1
    -rw-rw-r-- 1 cristian cristian   636 abr  2 01:10 respaldo1.c
    -rwxrwxr-x 1 cristian cristian 13200 abr  2 12:35 shell
    -rw-r--r-- 1 cristian cristian  1984 abr  2 12:36 shell.c
    -rw-r--r-- 1 cristian cristian   807 mar 29 11:41 shell.c~
    shell:~ls -l | wc
    wc: 'standard input': Bad file descriptor
          0       0       0
    shell:~

Its related to the STDIN_FILE, but also I'm sure I'm not implementing well the pipes and the forks.

Reducing your problem to a minimal reproducible case:

#include <unistd.h>
#include <stdio.h>

int main(void) 
{
        char *argv[] = {"wc", NULL};
        int fd1[2];
        pipe(fd1);
        dup2(fd1[1],STDIN_FILENO); /* Wrong end of the pipe !! */
        close(fd1[1]);
        execvp(argv[0], argv);
        perror(argv[0]);
        return 1;
}

The problem is that fd1[1] is the write side of a pipe, but wc is trying to read from it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM