views:

115

answers:

2

I am using popen to execute a command under linux, then 4 process wile use the same output. I am trying to duplicate the file descriptor again to pass it to each process. here is my code:

FILE* file_source = (FILE*) popen(source_command, "r");
int fd = fileno(file_source);
fdatasync(fd);

int dest_fd[4], y, total = 4;
    for (y = 0; y < total; y++) {
        dest_fd[y] = dup(fd);
    }

actually if total set to 1 it work fin, after changing total = 4 it does not work anymore. this answer is too close to what i need: link

A: 

From reading the question you linked to, it seems to be talking about dup() and creating a new file descriptor that is completely separate from eachother (they don't share file offset among other things). If this is what you want, you'll need to do what they suggest in the question.

You'll need to open/reopen the output as many times as you'd like to have duplicates. It looks like they work around the limitation by opening a new file which the output is directed to. My guess is that you simply need to redirect the output of the source_command to a file and then open the output file multiple times rather than using dup().

xyld
A: 

Your current approach probably won't do what you want. When you just duplicate the file descriptors, they all refer to the same pipe - no data is going to get duplicated. For each block of data sent by the source command, exactly one process is going to read it.

If you want to duplicate the data (like the tee utility does), then you will need to explicitly do so:

#define TOTAL 4

int dest_fd[TOTAL];
int dest_fd_wr[TOTAL];
int y;

/* Build pipes for reading the data from the child process */
for (y = 0; y < TOTAL; y++)
{
    int p[2];

    pipe(p);
    dest_fd[y] = p[0];
    dest_fd_wr[y] = p[1];
}

/* Create a child process to handle the "tee"-style duplication */
if (fork() == 0)
{
    /* Child process */
    FILE *file_source = popen(source_command, "r");
    FILE *file_sink[TOTAL];
    char buffer[2048];
    size_t nbytes;

    for (y = 0; y < TOTAL; y++)
    {
        close(dest_fd[y]);
        file_sink[y] = fdopen(dest_fd_wr[y], "w");
    }

    while ((nbytes = fread(buffer, 1, sizeof buffer, file_source)) > 0)
    {
        for (y = 0; y < TOTAL; y++)
        {
            fwrite(buffer, 1, nbytes, file_sink[y]);
        }
    }

    _exit(0);
}

for (y = 0; y < TOTAL; y++)
{
    close(dest_fd_wr[y]);
}

/* Now have a set of file descriptors in dest_fd[0..TOTAL-1] that each have
 * a copy of the data from the source_command process. */

Error-handling is left as an exercise for the reader ;)

caf
excellent, thanks
alaamh