0

I am doing a simple shell program in Linux. I am trying to implement the pipe operator for shell. I cant seem to find the problem and solution. The execvp didnt read from the previous pipe pipi. So if i do ls -l | more, the more prints bad usage instead of the list of files

Here is my code below.

  • execCommands handles the commands.
  • command.h parse the command.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <wait.h>
#include "modules/token.h"
#include "modules/command.h"

#define BUFSIZE 10000

int tokenSize = 0;
int cmdSize = 0;
char promptSymbol[BUFSIZE] = "%";
char cwd[BUFSIZE];

// execute commands accordingly to the apropriate function
void execCommands(Command command[]){
    int fd = 0;
    char dir[BUFSIZE];
    pid_t pid, p2;
    int pipi[2];

    for(int i = 0;i < cmdSize;i++){
        //start executing commands
        if(strcmp(command[i].argv[0], "prompt") == 0){
            strcpy(promptSymbol, command[i].argv[1]);   //change prompt symbol
        }else if(strcmp(command[i].argv[0], "pwd") == 0){
            if(getcwd(cwd, sizeof(cwd)) != NULL){
                    printf("%s\n", cwd );
            }else{
                perror("getcwd() error\n");
            }
        }else if(strcmp(command[i].argv[0], "cd") == 0){
            if(command[i].argv[1] == NULL){
                strcpy(dir, "/home");
            }else if(strcmp(command[i].argv[1], "~") == 0 || strcmp(command[i].argv[1], "~/") == 0){
                strcpy(dir, "/home");
            }else{
                strcpy(dir, command[i].argv[1]);
            }

            if(chdir(dir) < 0){
                printf("No such directory/file %s found\n", dir);
            }
        }else{
            pid = fork();
            if(pid < 0){
                perror("pid fork failed\n");
            }
            
            if(pid == 0){
                if(command[i].stdin_file || command[i].stdout_file){
                    //check for stdin redirection
                    if(command[i].stdin_file){
                        fd = open(command[i].stdin_file, O_RDONLY);
                        dup2(fd, STDIN_FILENO);
                    }

                    //check for stdout redirection
                    if(command[i].stdout_file){
                        fd = open(command[i].stdout_file, O_WRONLY | O_CREAT, 0777);
                        dup2(fd, STDOUT_FILENO);
                    }
                }
            
                if(strcmp(command[i].sep,"|") == 0){
                    if(pipe(pipi) == -1){
                        perror("pipi pipe failed\n");
                    }

                    close(pipi[0]);
                    dup2(pipi[1], STDOUT_FILENO);
                    close(pipi[1]);
                    execvp(command[i].argv[0], command[i].argv);

                    p2 = fork();
                    if(p2 > 0){
                        close(pipi[1]);
                        dup2(pipi[0], STDIN_FILENO);
                        close(pipi[0]);
                        execvp(command[i].argv[0], command[i].argv);
                    }
                }else{
                    execvp(command[i].argv[0], command[i].argv);
                }
                close(fd);
                exit(0);
            }else{
                if(strcmp(command[i].sep, "&") != 0){
                    wait(0);
                }
            } // end of first fork()
        } //end of command check
    } //end of for loop
} //end of execCommands

//handles SIGINT, SIGTSTP and SIGQUIT
void handler(int num){
    printf("\nEnter 'exit' to end shell program\n");
}

main code

int main(){
    char cmdLine[BUFSIZE];
    char *token[BUFSIZE];
    Command command[BUFSIZE];

    //Runs untill user wants to exit
    while(strcmp(cmdLine, "exit") != 0){
        signal(SIGTSTP, handler);   //Ignores SIGTSTP signal(ctrl+z)
        signal(SIGINT, handler);    //Ignores SIGINT signal(ctrl+c)
        signal(SIGQUIT, handler);   //Ignores SIGQUIT signal(ctrl+\)
    
        //get current directory
        if(getcwd(cwd, sizeof(cwd)) != NULL){
            strcat(cwd, promptSymbol);
        }else{
            perror("getcwd error");
            return 1;
        }
        //prompts user for icommand
        printf("%s ", cwd);
        scanf(" %[^\n]", cmdLine);
        
        // split command line into tokens
        tokenSize = tokenise(cmdLine, token);
        
        //split the tokens into commands
        initCommand(command);
        cmdSize = seperateCommands(token, command);
    
        //execute commands accordingly
        execCommands(command);
        
    }
    return 0;
}
agengwan
  • 1
  • 1
  • 'having trouble with the stdin dup2' doesn't explain what your question is. Could you be more clear please? – user438383 Nov 28 '21 at 15:41
  • Also please try and make your title as informative as possible, as to help people with a similar issue,. – user438383 Nov 28 '21 at 15:48
  • For a version of a shell that handles a pipe, see my answer: https://stackoverflow.com/questions/52823093/fd-leak-custom-shell/52825582#52825582 For a more elaborate implementation, see my answer: https://stackoverflow.com/questions/35569673/implementing-input-output-redirection-in-a-linux-shell-using-c/35570162#35570162 – Craig Estey Nov 28 '21 at 15:52
  • Sorry but i got confused with that – agengwan Nov 28 '21 at 18:00
  • `echo` doesn't read its statndard input anyway. – Davis Herring Nov 29 '21 at 03:56
  • I see. But ls -l | more doesnt work – agengwan Nov 29 '21 at 04:00
  • Have you stepped through your code with a debugger and checked what the commands really are you are actually calling? As your code is incomplete, we cannot do that for you. We don't even know what Command looks like or if the string is correctly tokenized. – Mecki Nov 29 '21 at 17:52
  • It is tokenise properly. The pupe is the only issue – agengwan Nov 30 '21 at 09:20

0 Answers0