Search code examples
cscanfnamed-pipeskali-linux

Scanf is reading ctrl+c on named-pipes program


I'm trying to make a named pipe or FIFO with a 2 C program (read & write). Both of this program is running on a while(1) loop. These programs should be terminated when ctrl+c is pressed, but when I press ctrl+c on the write program, it still sending something to the read program. Its work fine if I input normal numbers, but when i press ctrl+c on the write program to terminate, it gives this random number to the read program

#normal numbers shows:
BMI: 16.1, Overweight

#on ctrl+c input:
BMI = 165534.6 (some random numbers)

This is the code for the write program

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

int main()
{
    int fd, fd1, fd2;
    
    //FIFO file path
    char * myfifo = "/tmp/myfifo";

    mkfifo(myfifo,0666);

    float weight, height, bmi = 0;
    char arr1[80];
    while(1)
    {
        //open
        fd = open(myfifo, O_WRONLY);
        fd1 = open(myfifo, O_WRONLY);
        fd2 = open(myfifo, O_WRONLY);

        printf("Name            : ");
        scanf("%[^\n]", arr1);
        getchar();
        write(fd, arr1, strlen(arr1)+1);
        close(fd);
        
        printf("Body Weight in kg    : ");
        scanf("%f",  &weight);
        getchar();
        write(fd1, &weight, sizeof(weight));
        printf("%f\n", weight);
        close(fd1);

        printf("Body Height in cm    : ");
        scanf("%f",  &height);
        getchar();
        printf("\n---------------------------\n\n");
        write(fd2, &height, sizeof(height));
        printf("%f\n", height);
        close(fd2);

    }
    return 0;
}

This is the code for read program, it goes on a while(1) loop

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

int main()
{
    int fd, fd1, fd2;
    char * myfifo = "/tmp/myfifo";
    mkfifo(myfifo,0666);
    float weight, height, bmi = 0;
    char str1[80];
    while(1)
    {
        //First open in read only and read
        fd = open(myfifo, O_RDONLY);
        fd1 = open(myfifo, O_RDONLY);
        fd2 = open(myfifo, O_RDONLY);
        read(fd, str1, 80);
        read(fd1, &weight, sizeof(weight));
        read(fd2, &height, sizeof(height));
        
        height = (height / 100);
        
        bmi = weight / (height * height);

        //Print the read string and close
        printf("%s BMI : %.1f\n", str1, bmi);
        close(fd);
        close(fd1);
        close(fd2);

        if(bmi < 18.5)
        {
            printf("Details = Underweight\n");
        }
        else if(bmi >= 18.5 && bmi <= 22.9)
        {
            printf("Details = Normal\n");
        }
        else if(bmi >= 23.0 && bmi <= 24.9)
        {
            printf("Details = Overweight\n");
        }
        else if(bmi >= 25.0 && bmi <= 29.9)
        {
            printf("Details = Obese I (Obesitas Class I)\n");
        }
        else
        {
            printf("Details = Obese II (Obesitas Class II)\n");
        }

    }
    return 0;
}

So, I wonder, is there a way to make ctrl+c terminate both of those processes? So that the write program won't send anything after cttrl+c is pressed. I think this problem occurs because the read program keeps reading some input from write even when ctrl+c is pressed.


Solution

  • It is because you don't check that read() may return 0 in the reader. So, when it returns 0 (= 0 chars read), you display any garbage from your buffer. When read() returns 0, you should terminate the reader because it means that the other side is closed (the writer exited).

    As a general rule, try to check all the return codes from the services/syscalls. You may make a first draft without checking anything. But when it appears to dysfunction, add the checks on the return codes. This usually helps...