0
votes

I am tring to write the shortest code to have a blocking file descriptor.

I set first: O_NONBLOCK
second: ICANON, [VMIN], [VTIME] for my file descriptor...

What else options I need to set to have a blocking file descriptor ?

(sample.txt is empty & open() with different mode does not chance anything)


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


void set_blocking(int fd, int blocking) {

    int flags = fcntl(fd, F_GETFL, 0);

    if (blocking)
        flags &= ~O_NONBLOCK;
    else
        flags |= O_NONBLOCK;

    fcntl(fd, F_SETFL, flags);

    return;
}

int main(){

        int fd;
        char buff[100];
        struct termios options;

        options.c_lflag &= ~ICANON;

        options.c_cc[VMIN] = 2;
        options.c_cc[VTIME] = 0;

        fd = open("sample.txt",O_RDWR);

        tcsetattr(fd, TCSANOW, &options);

        set_blocking(fd,1);

        read(fd,buff,2);

        printf("%s\n",buff);

        return 0;
}

1
Recommend using fcntl() to get and save the original terminal settings so you can restore them before exiting. And modify those rather than setting them from scratch. - Jonathan Leffler
tcsetattr only works on special terminal device files, not on ordinary files. I doubt that your "sample.txt" is a terminal. - Ian Abbott
You do not check for error returns of any system call. If you want to know why system calls fail to work as expected, you must diagnose error returns. At a minimum, use perror to show the error reason. Please do this before posting here. - rici
After I delete codes about terminos and terminos options, (because as i understand, i don't need them) code still do not wait for empty sample.txt which is ordinary text file. I would appreciate if i had a minimalist sample code which has a waiting read function when called for a ordinary text file. - C. Y.

1 Answers

0
votes

Your code is modifying only parts of an uninitialized struct termios options variable. When your code calls tcsetattr, most of the options variable will be set to random bits, so tcsetattr is likely to either return an error or apply bogus settings to the terminal.

Since your code only modifies certain terminal settings explicitly, the best way to initialize the options variable would be to read the old settings into it using a call to tcgetattr:

    ret = tcgetattr(fd, &options);
    if (ret < 0) {
        perror("tcgetattr");
        exit(1);
    }

    options.c_lflag &= ~ICANON;

    options.c_cc[VMIN] = 2;
    options.c_cc[VTIME] = 0;

    ret = tcsetattr(fd, TCSANOW, &options);
    if (ret < 0) {
        perror("tcsetattr");
        exit(1);
    }

The code sample above assumes that the file descriptor fd is linked to a terminal, so that isatty(fd) returns 1. It does not apply at all when fd is linked to an ordinary file.

In your posted code, fd is linked to a file called "sample.txt" in the current directory, which is unlikely to be a terminal. In that case, the tcgetattr and tcsetattr calls will return -1 and set errno to ENOTTY.