Search code examples
cpipeexecvp

Reading the right amount of data out of a pipe when your receiving output from execvp


This is just a small part of a bigger program but Im trying to get the output from execvp I have execvp set up correctly with dup2 that directs it into a pipe. My problem comes when it comes to using read to read the full length of the pipe I don't know how large the output of execvp is each time cause it can be different depending on the input.

    int fd[2];
    pipe(fd);
    pid_t pid = fork();
    if (pid == 0) {
        close(fd[0]);
        dup2(fd[1], 1);
        execvp(msg.v,(char *[]){msg.v,NULL});
    } else if (pid > 0) {
        close(fd[1]);
        read(fd[0],msg.v,....);
    }

I have tried a few different sizes for read but its either not enough or I end up getting random junk at the end I know you can use popen and a few other things from stdio but its required for the assignment that we do not use them Im blanking on other ways to go about getting the output.

A little more useless info the whole program is part of a server. Im making a server and a client.. start the server give the client a terminal command it sends it over to the server over a INET stream and sending the output back to the client to display output all without stdio.


Solution

  • You have to pay attention to how much data read returns into your buffer. While read is returning positive numbers, you have more data. When the program is done, it will close its end of the pipe, and your read will return 0.

    } else if (pid > 0) {
        close(fd[1]);
        ssize_t r = read(fd[0],buf,bufsz);
        if (r > 0) do {
            /* ... do something with r bytes in buf */
            r = read(fd[0],buf,bufsz);
        } while (r > 0);
        if (r < 0) {
            perror("read");
            /*...*/
        }
    }
    

    If you see read give an "Interrupted system call" error, then you have encountered the EINTR case that caf mentioned. You restart your read again in that case.

            for (;;) {
                r = read(fd[0],buf,bufsz);
                if (r != -1 || errno != EINTR) break;
            }
    

    I am assuming you are not doing non-blocking I/O, so you will not encounter the "Resource temporarily unavailable" message.