1

I'm spawning a child process with stdin and stdout set up as pipes between parent and child. I want to pipe lines into the child and - for now - echo them. With standard cat it's working, but with my own cat-clone based on getline() it's not. I can't see what the problem is.

These are actually MCVEs for another problem, but now I cannot get them to work.

The forking program based on https://jineshkj.wordpress.com/2006/12/22/how-to-capture-stdin-stdout-and-stderr-of-child-program/

#include <unistd.h>
#include <stdio.h>

/* since pipes are unidirectional, we need two pipes.
one for data to flow from parent's stdout to child's
stdin and the other for child's stdout to flow to
parent's stdin */

#define NUM_PIPES          2

#define PARENT_WRITE_PIPE  0
#define PARENT_READ_PIPE   1


int pipes[NUM_PIPES][2];

/* always in a pipe[], pipe[0] is for read and
pipe[1] is for write */
#define READ_FD  0
#define WRITE_FD 1

#define PARENT_READ_FD  ( pipes[PARENT_READ_PIPE][READ_FD]   )
#define PARENT_WRITE_FD ( pipes[PARENT_WRITE_PIPE][WRITE_FD] )

#define CHILD_READ_FD   ( pipes[PARENT_WRITE_PIPE][READ_FD]  )
#define CHILD_WRITE_FD  ( pipes[PARENT_READ_PIPE][WRITE_FD]  )

void
main()
{
    int stdout_copy = dup(STDOUT_FILENO);
    int stdin_copy = dup(STDERR_FILENO);

    printf("Starting\n");

    int outfd[2];
    int infd[2];

    // pipes for parent to write and read
    pipe(pipes[PARENT_READ_PIPE]);
    pipe(pipes[PARENT_WRITE_PIPE]);

    if(!fork()) {
//        char *argv[]={ "/usr/bin/cat", 0};
        char *argv[]={ "./getline", 0};
        printf("Child\n");

        dup2(CHILD_READ_FD, STDIN_FILENO);
        dup2(CHILD_WRITE_FD, STDOUT_FILENO);

        /* Close fds not required by child. Also, we don't
        want the exec'ed program to know these existed */
        close(CHILD_READ_FD);
        close(CHILD_WRITE_FD);
        close(PARENT_READ_FD);
        close(PARENT_WRITE_FD);

        execv(argv[0], argv);
    } else {
        printf("Parent\n");
        char buffer[100];
        int count;

        /* close fds not required by parent */
        close(CHILD_READ_FD);
        close(CHILD_WRITE_FD);

        // Write to child’s stdin
        write(PARENT_WRITE_FD, "2^32\n", 5);
        write(PARENT_WRITE_FD, "\n\4", 2);

        // Read from child’s stdout
        sleep(1);
        count = read(PARENT_READ_FD, buffer, sizeof(buffer)-1);

        dup2(stdout_copy, STDOUT_FILENO);
        dup2(stdin_copy,  STDIN_FILENO);

        fprintf(stderr, "E:Read %i\n", count);
        printf("Read %i\n", count);
        if (count >= 0) {
            buffer[count] = 0;
            printf("%s", buffer);
        } else {
            printf("IO Error\n");
        }
    }
}

My cat clone:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char** argv) {
    char* buffer = malloc(1024);
    size_t n=0;
    int r=0;

    FILE* f = stdin;

    while( r>=0 ) {
        r=getline(&buffer, &n, f);
        printf("%i/%i: %s\n", r, n, buffer);
        buffer[0]=0;
    }

    return 0;
}

Output with cat:

Starting
Parent
Child
E:Read 7
Read 7
2^32

Output with cat-clone "getline":

Starting
Parent
Child

I'm in MinGW on Windows 10.

Jann Poppinga
  • 444
  • 4
  • 18
  • 2
    `getline()` waits for a newline or EOF. You aren't closing the pipe, and haven't end the second message with a newline. Try rewriting your pseudo-`cat` using `read()` instead. – Jonathan Leffler Oct 25 '20 at 13:15
  • @JonathanLeffler Thanks. Using `getline()` was part of the point of the exercise, but closing `PARENT_WRITE_FD` after writing did the trick. – Jann Poppinga Oct 26 '20 at 06:12

0 Answers0