0

I want a program which reads a file in the child process and send the string/content to the parent process using simple pipe.

Here is what I have tried, I have read a file and tried to write into the pipe line by line in the while loop. But It doesn't seem to work that way. Your help will be highly appreciated.

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

int main(int argc, char *argv[])
{
    FILE * fptr;
    fptr = fopen(argv[1],"r");
    char str1;

    int pipefds[2];
    char buffer[5];

    if(pipe(pipefds) == -1)
    {
        perror("PIPE ERROR");
        exit(EXIT_FAILURE);
    }

    pid_t pid = fork();

    if(pid == 0)
    {
        char singleLine[150];
        close(pipefds[0]);  
        while(!feof(fptr))
        {
            fgets(singleLine, 150, fptr);
            //puts(singleLine);
            write(pipefds[1], singleLine, sizeof(singleLine));

        }

        fclose(fptr);
                    //Close read file descriptor

        exit(EXIT_SUCCESS);
    }
    else if(pid > 0)
    {
        //wait(NULL);                       //Wait for child process to finish
        close(pipefds[1]);              //Close write file descriptor
        read(pipefds[0], buffer, 100);  //Read pin from pipe
        close(pipefds[0]);              //Close read file descriptor

        printf("%s",buffer);
    }


    return 0;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 2
    You need to loop the reading part of the process? You need to capture the length reported by `read()` so you know how many bytes you can print (or otherwise process). Note that [`while (!feof(file))` is always wrong](https://stackoverflow.com/q/5431941/15168). – Jonathan Leffler Apr 08 '20 at 14:05
  • 1
    One major problem is that you have `char buffer[5];` and yet you use `read(pipefds[0], buffer, 100);` — buffer overflow! Undefined behaviour. – Jonathan Leffler Apr 08 '20 at 14:13
  • 2
    Also, why do you open the file before forking? – pat Apr 08 '20 at 15:01
  • 1
    @pat — One plausible reason to open the file before forking is to check that it is available before forking, so that there's only one process involved in the error handling. However, that then makes a mockery of sending the information from the child to the parent — except as an exercise. The parent should close the file after forking to avoid accusations of cheating. – Jonathan Leffler Apr 08 '20 at 18:15

1 Answers1

1

Check for Program Argument

To ensure that the filename parameter is provided, you could check as follows:

if (argc < 2) {
    fprintf(stderr, "usage: progname <filename>");
    exit(EXIT_FAILURE);
}

Opening the File

Presumably it makes sense to check whether fopen is successful or not.

You could do a check e.g. like this:

if ((fptr = fopen(argv[1], "r")) == NULL) {
    perror("error opening file");
    exit(EXIT_FAILURE);
}

Also like mentioned by @pat in the comments this code can be moved to the child.

Reading the file

Reading the file could be done like this:

while (fgets(singleLine, sizeof(singleLine), fptr)) {
    write(pipefds[1], singleLine, strlen(singleLine));
}

Like mentioned by Jonathan Leffler in the comments one should not check feof upfront. Also important to note that you don't want to write sizeof(singleLine) bytes, because lines can have variable size and be shorter then the buffer size, so better to use strlen(singleLine) here.

Reading the Data

Reading the data must happen in a loop - as long as data is available. The call of read returns the number of bytes read.

    ssize_t n;
    while ((n = read(pipefds[0], buffer, sizeof(buffer) - 1)) > 0) {
        buffer[n] = '\0';
        printf("%s", buffer);

    }

To make sure that you don't save data beyond the end of the buffer, you can use sizeof(buffer) - 1 as the third argument to the read call.

Programm

So your program, slightly modified regarding the above points, could look like this:

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


int main(int argc, char *argv[]) {
    int pipefds[2];
    char buffer[100];

    if (argc < 2) {
        fprintf(stderr, "usage: progname <filename>");
        exit(EXIT_FAILURE);
    }

    if (pipe(pipefds) == -1) {
        perror("PIPE ERROR");
        exit(EXIT_FAILURE);
    }

    pid_t pid = fork();

    if (pid == 0) {
        FILE *fptr;
        if ((fptr = fopen(argv[1], "r")) == NULL) {
            perror("error opening file");
            exit(EXIT_FAILURE);
        }

        char singleLine[150];
        close(pipefds[0]);
        while (fgets(singleLine, sizeof(singleLine), fptr)) {
            write(pipefds[1], singleLine, strlen(singleLine));
        }
        int error = ferror(fptr);
        fclose(fptr);
        if (error) {
            perror("error reading file");
            exit(EXIT_FAILURE);
        }
        exit(EXIT_SUCCESS);
    } else if (pid > 0) {
        close(pipefds[1]);

        ssize_t n;
        while ((n = read(pipefds[0], buffer, sizeof(buffer) - 1)) > 0) {
            buffer[n] = '\0';
            printf("%s", buffer);

        }
        close(pipefds[0]);
    }

    return 0;
}
Stephan Schlecht
  • 26,556
  • 1
  • 33
  • 47