Home > Back-end >  Redirecting stdin and stdout using dup2
Redirecting stdin and stdout using dup2

Time:04-27

I'm writing my own custom shell, and as a part of my project, when the program reads either "<" or ">" character from user input, it needs to redirect stdin and stdout to a custom file. I wrote a function for this below. The part where I'm struggling is that even though I wrote the code for input and output redirections pretty much in the same manner, output redirection seems to work as expected, while input redirection does not. See the code below:

void inOutReDirector(char **toks, char *inputFile, char *outputFile, int *fd0, int *fd1, int *in, int *out) {
    fflush(0);
    for (int i = 0; toks[i] != NULL; i  ) {
        if (strcmp(toks[i], "<") == 0) {
            toks[i] = NULL;
            strcpy(inputFile, toks[i   1]);
            toks[i   1] = NULL;
            *in = 1;
        }

        if (strcmp(toks[i], ">") == 0) {
            toks[i] = NULL;
            strcpy(outputFile, toks[i   1]);
            toks[i   1] = NULL;
            *out = 1;
        }
    }
    //input redirection
    if (*in == 1) {

        if ((*fd0 = open(inputFile, O_RDONLY, 0)) < 0) {
            printf("Couldn't open input file: %s", strerror(errno));
            exit(1);
        }
        dup2(*fd0, STDIN_FILENO);
        close(*fd0);
    }
    //output redirection
    if (*out == 1) {

        if ((*fd1 = creat(outputFile, 0644)) < 0) {
            printf("Couldn't open output file: %s", strerror(errno));
            exit(1);
        }
        dup2(*fd1, STDOUT_FILENO);
        close(*fd1);
    }
}

And here is how I call this function from my main:

int main() {
    char *toks[STD_INPUT_SIZE] = {0};
    int fd0, fd1, in = 0, out = 0;
    char inputFile[64], outputFile[64];
    pid_t pid;
    while (1) {

//print prompt
//get user input

        pid = fork();

        if (pid < 0) {
            printf("%s \n", strerror(errno));
            exit(1);
        }
        int stopNeeded = strcmp(toks[0], "exit") == 0;

        if (pid == 0 && !stopNeeded) {

            pathFinder(toks, shellInput, currentDir); //finding path for execv input
            inOutReDirector(toks, inputFile, outputFile, &fd0, &fd1, &in, &out); // I/O redirection

            if (execv(shellInput, toks) != 0) {
                char *errMsg = strerror(errno);
                printf("%s \n", errMsg);
                //clean the old contents of toks
                for (int i = 0; i < STD_INPUT_SIZE;   i) {
                    free(toks[i]);
                    toks[i] = NULL;
                }
                exit(1);
            }
        }

        if (pid > 0) {
            pid_t childPid = waitpid(pid, NULL, 0);
            (void) childPid;
        }
    }
    return 0;
}

And here is an example of output redirection from my terminal screen

$ ls > output.txt
$ 

This creates "output.txt" file and prints the result inside this file in the current directory.

And here is an example of input redirection from my terminal screen

$ cat < output.txt
$ 

Input redirection does not work correctly. It prints the prompt and waits for the input instead of showing the contents of output.txt in my terminal.

I appreciate any help you can provide in advance!

CodePudding user response:

The problem should be on this line of the function inOutReDirector

if (strcmp(toks[i], ">") == 0) {

should be changed to

else if (strcmp(toks[i], ">") == 0) {

When toks[i] is equal to "<", toks[i] will be set to NULL above, this line calling strcmp will cause SIGSEGV, so the child process will exit, and the subsequent execv will not be executed.

  • Related