Wise
Wise

Reputation: 658

Program gets stuck while trying to read a file using read() system call

Here is my code snippet:

int fd;
bufsize = 30;
char buf[bufsize];
char cmd[100] = "file.txt";
int newfd = 1;

if (fd = open(cmd,O_RDONLY) >=0){
    puts("wanna read");
    while (read(fd,&bin_buf,bufsize)==1){
        puts("reading");
        write(newfd,&bin_buf,bufsize);
    }
    close(fd);
}

So here the program prints "wanna read" but never prints "reading". I have also tried opening using nonblock flag, but no use. Can anybody help me? I must use open() and read() system calls only. Thanks. Edit: I have made some clarifications in the code. Actually the newfd that I'm writing to is a socket descriptor, but I don't think that is important for this problem because it sticks on the read which is before the write.

Upvotes: 0

Views: 5446

Answers (3)

chqrlie
chqrlie

Reputation: 144550

Your read() call attempts to read bufsize bytes and returns the number of bytes actually read. Unless bufsize ==, it is quite unlikely read() will return 1, so the block is almost always skipped and nothing get written.

Also note that if (fd = open(cmd, O_RDONLY) >= 0) is incorrect and would set fd to 1, the handle for standard output, if the file exists, causing the read to fail as standard input is most likely not opened for reading.

Note that reading with the read system call is tricky on some environments, because a return value of -1 may be restartable.

Here is an improved version:

int catenate_file(const char *cmd, int newfd, size_t bufsize) {
    int fd;
    char buf[bufsize];

    if ((fd = open(cmd, O_RDONLY)) >= 0) {
        puts("wanna read");
        ssize_t nc;
        while ((nc = read(fd, buf, bufsize)) != 0) {
            if (nc < 0) {
                if (errno == EINTR)
                    continue;
                else
                    break;
            }
            printf("read %zd bytes\n", nc);
            write(newfd, buf, nc);
        }
        close(fd);
        return 0;
    }
    return -1;
}

Upvotes: 1

Jonathan Leffler
Jonathan Leffler

Reputation: 753475

The first problem is your if statement. You forgot to use enough parentheses, so if the open() works, the read tries to read from file descriptor 1, aka standard output. If that's your terminal (it probably is) on a Unix box, then that works — surprising though that may be; the program is waiting for you to type something.

Fix: use parentheses!

if ((fd = open(cmd, O_RDONLY)) >= 0)

The assignment is done before, not after, the comparison.

I observe in passing that you don't show how you set cmd, but if you see the 'wanna read' message, it must be OK. You don't show how newfd is initialized; maybe that's 1 too.

You also have the issue with 'what the read() call returns'. You probably need:

int fd;
char buf[bufsize];
int newfd = 1;

if ((fd = open(cmd, O_RDONLY)) >= 0)
{
    puts("wanna read");
    int nbytes;   // ssize_t if you prefer
    while ((nbytes = read(fd, buf, sizeof(buf))) > 0)
    {
        puts("reading");
        write(newfd, buf, nbytes);
    }
    close(fd);
}

You can demonstrate my primary observation by typing something ('Surprise', or 'Terminal file descriptors are often readable and writable' or something) with your original if but my loop body and then writing that somewhere.

Upvotes: 2

Paolo
Paolo

Reputation: 15827

read returns the number of bytes read from file that can be bufsize or less if the remainder of the file that has to be read is shorter than bufsize.

In your case most probably bufsize is bigger than 1 and the file is bigger than 1 byte so the condition of the while loop is evaluated false, the code is skipped to the point where file is closed.

You should check if there if there are more bytes to be read:

while( read(fd,&bin_buf,bufsize) > 0 ) {

Upvotes: 1

Related Questions