Redirecting stdout to file after a fork()

Ryan Washburn picture Ryan Washburn · Apr 1, 2011 · Viewed 8.6k times · Source

I'm working on a simple shell, but right now I am just trying to understand redirection. I'm just hard coding an ls command and trying to write it to a file for now. Currently, the ls runs, and the output file is created, but the output still goes to stdout and the file is blank. I'm confused as to why. Thanks in advance.

Here is my code:

int main()
{
    int ls_pid; /* The new process id for ls*/
    char *const ls_params[] = {"/bin/ls", NULL}; /* for ls */
    int file; /* file for writing */

    /* Open file check user permissions */
    if (file = open("outfile", O_WRONLY|O_CREAT) == -1) /* , S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP */
    {
        perror("Failed to open file");
        _exit(EXIT_FAILURE);
    } 

    ls_pid = fork(); /* Create new process for ls */

    if (ls_pid == -1) /* error check */
    {
        perror("Error forking ls (pid == -1)");
        _exit(EXIT_FAILURE);
    }
    else if (ls_pid == 0) /* Child of ls */
    {
        /* Redirect output to file */
        if (dup2(file, STDOUT_FILENO) == -1) /* STDOUT_FILENO = 1 */
        {
            perror("Error duping to file");
            _exit(EXIT_FAILURE);
        }
        close(file);

        execvp("ls", ls_params); /* create the sort process */
        /* execlp("ls", "ls", NULL); */

        /* if this does not end the program, something is wrong */
        perror("Exec failed at sort");
        _exit(EXIT_FAILURE);
    }
    else /* ls parent (1) */
    {
        /* wait for child */
        if (wait(NULL) == -1)
        {
            perror("fork failed on parent");
            _exit(EXIT_FAILURE);
        }
    }

}

Answer

Jinghao Shi picture Jinghao Shi · Mar 10, 2012

I don't see any problem. I tried your code by myself. And it works! My simplified code looks like:

int main(void) {
    int fd;

    char* const param[] = {"/bin/ls", NULL};

    fd = open("outfile", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);

    if (fd < 0) {
        perror("open failed\n");
        exit(0);
    }

    pid_t pid = fork();

    if (pid < 0) {
        perror("fork failed\n");
        exit(0);
    }
    else if (pid == 0) {
        dup2(fd, STDOUT_FILENO);

        close(fd);

        execvp("ls", param);
    }
    else {
        wait(NULL);
    }
}

I compile an execute it, and find the expected results in outfile.

The only difference is that I feed open with the S_IRUSER | S_IWUSER permission options since otherwise the open fails. I see similar thing in your code but somehow you commented them...