rares04
rares04

Reputation: 11

Named pipes in C program (unix)

I have to use 3 processes in order to solve the problem. First processes gets input from (entered via keyboard) and sends it to the second procces The second process replaces all the vocals from the text with 12345 (a with 1, e with 2, ...). I got a well working sh script (tested it) that uses sed to do this task. I will put it here. Thrid process outputs on the screen only the alphanumeric lines. I also got a script that uses grep to do this task and also works fine (tested it). This processes should communicate trough a named pipe (a FIFO file) and i'm running into some difficulties sending and receiving the data trough the FIFO. When i use the write function to write the data to the FIFO it outputs the data on the screen and when i'm in the second process and i try to read the data from the FIFO it just waits for a new input entered by me.

First process:

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

int main() {
    char text[500];  // buffer for the inputed text
    char aux[100];  // Also a buffer to save multi-line input into text buffer

    char* myfifo = "myfifo";
    int fd_text;  

    printf("\nInput: (to stop giving input just type 0 on a new line):\n");
    // Forming the text
    while(scanf("%[^\n]%*c", aux) == 1) {
        if(strcmp(aux, "0") == 0) 
            break;
        strcat(aux, "\n");
        strcat(text, aux);
        }
    strcat(text, "\0");
    // Everything works well reading the input 


    int returnValue = mkfifo(myfifo, 0666);
    if(returnValue < 0) {
        printf("mkfifo() failed\nerrno = %d\n", errno);
        if(errno == EEXIST) 
            printf("That file already exists.\n");
    }

    if(fd_text = open(myfifo, O_WRONLY) < 0) {
        printf("error while opening FIFO");
        exit(0);
    } 

    int indicator = write(fd_text, text, strlen(text) + 1);
    if(indicator == 0) {
        printf("error while writing to FIFO");
    }

    close(fd_text);
    return 0;
}

Second process:

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

int main() {
    char text[500];  
    char* myfifo = "myfifo";

    int fd_text2;  

    if (fd_text2 = open(myfifo, O_RDONLY) < 0) {
        printf("error while opening FIFO");
        exit(1);
    }

    int result = read(fd_text2, text, 500);
    if (result < 0)
        printf("ERROR WHILE READING FROM THE FILE\n");
    printf("\n%d bytes were read from the file\n", result);
    printf("\nText read from FIFO:\n%s\n", text);

    // Saving the text into a txt to perfom the sed command on it
    FILE *fp_replace_text;
    fp_replace_text = fopen("replace_text.txt", "w");
    fprintf(fp_replace_text, "%s", text);
    fclose(fp_replace_text);

    system("chmod 777 replace.sh"); 
    system("./replace.sh replace_text.txt");  

    close(fd_text2);
    unlink(myfifo);
    return 0;
}

replace.sh

#!/bin/sh

sed -i 's/a/1/gi' $1
sed -i 's/e/2/gi' $1
sed -i 's/i/3/gi' $1
sed -i 's/o/4/gi' $1
sed -i 's/u/5/gi' $1

If i can figure out why communication between process 1 and 2 is not working, process 3 will be the same, so i'm not posting it anymore.

Edit:

Second Process

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

int main() {
    char text[500]; 
    char* myfifo = "myfifo";
    int fd_text2; 

    if ((fd_text2 = open(myfifo, O_RDWR)) < 0) {
        printf("error while opening pipe");
        exit(1);
    }

    int result = read(fd_text2, text, 500);
    if (result < 0)
        printf("ERROR WHILE READING FROM THE FILE\n");


    FILE *fp_replace_text;
    fp_replace_text = fopen("replace_text.txt", "w");
    fprintf(fp_replace_text, "%s", text);
    fclose(fp_replace_text);

    system("chmod 777 replace.sh");  
    system("./replace.sh replace_text.txt");  

    fp_replace_text = fopen("replace_text.txt", "r");
    fread(text, 500, 1, fp_replace_text);
    fclose(fp_replace_text);

    write(fd_text2, text, strlen(text) + 1);    
    close(fd_text2);
    return 0;
}

Third process

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

int main() {
    char text[500];  
    char* myfifo = "myfifo";
    int fd_text3;  

    if ((fd_text3 = open(myfifo, O_RDONLY)) < 0) {
        printf("error while opening pipe");
        exit(1);
    }

    int result = read(fd_text3, text, 500);
    if (result < 0)
        printf("ERROR WHILE READING FROM THE FILE\n");

    FILE *fp_replace_text;
    fp_replace_text = fopen("replace_text.txt", "r");
    fread(text, 500, 1, fp_replace_text);
    fclose(fp_replace_text);

    printf("Textul final este:\n");
    system("chmod 777 output.sh");
    system("./output.sh replace_text.txt"); 

    unlink(myfifo);
    return 0;
}

I'm also trying to send the content of the txt filo to the third process trough FIFO (i know i could just use the txt file, but i want to use the FIFO file and read from it again). So i'm use the shell script on the txt file, i read from and and then i want to send what i read from the txt file to the thrid process to FIFO, but after i run the second process the execution stops and doesn't blocks. When i'm writing to the FIFO in the first process, it blocks until the second process reads from the FIFO. Second process keeps executing and third process can't get anything. I guess there has to be something wrong with FIFO principles, that if u want to perform input/output operations on a FIFO both ends should be opened.

Upvotes: 0

Views: 969

Answers (1)

Beta
Beta

Reputation: 99164

The problem (which ought to have cause a warning from your compiler) is in statements like this:

if(fd_text = open(myfifo, O_WRONLY) < 0)

You seem to assume that this will be evaluated from left to right, first assigning a value to fd_text, then testing that value against 0 to give a boolean value which will determine whether to enter the if block. But in C, relational operators (like <) take precedence over assignment operators (like =). So first we compare the result of the open command to 0, then assign the boolean result of that comparison to fd_text. So the file descriptor is lost, and further attempts to reach the fifo will fail. We can correct this with a pair of parentheses:

if((fd_text = open(myfifo, O_WRONLY)) < 0)

More generally, it's a good idea to develop new functionality in isolation as much as possible. If you want to send text to a fifo and receive it, just hard-code some text in the first module, don't have all that code to read user input, and don't attempt the further step of sending the text from the second module to some other process for modification, not until the fifo is working perfectly. Small steps.

Upvotes: 2

Related Questions