tags:

views:

86

answers:

3

In the below program write() returns -1 while writing to a file.

   #include<sys/types.h>
   #include<sys/stat.h> 
   #include<fcntl.h>   
   #include<stdio.h>   
   #include<unistd.h> 
   #include<stdlib.h>
   int main() {

   int fd_r=0,fd_w=0;
   int w_ret=100;
   fd_r = open("reader.txt", O_RDONLY);

   fd_w = open("writer.txt",O_CREAT,S_IRWXU);

   char *buf = (char *)malloc(50);

   while(read(fd_r,buf,30))
   {

          w_ret =   write(fd_w,buf,30);
          printf("%d", w_ret);
   }
}

Questions: I am unable to debug why this is happening. Correction of code and suggestions as to how to debug such issues are highly appreciated

+4  A: 

I don't believe that O_CREAT is valid by itself for the flags: try O_CREAT | O_WRONLY.

One way to debug would be checking that the fd_w file descriptor is valid when you first open it.

"The parameter flags is one of O_RDONLY, O_WRONLY or O_RDWR which request opening the file read-only, write-only or read/write, respectively, bitwise-or'd with zero or more of the following..." http://www.linuxmanpages.com/man2/open.2.php

If you don't specify any read/write flags then `O_RDONLY` is assumed, since its value is `0`.
Ignacio Vazquez-Abrams
which isn't very useful for a file opened for writing ;)
KevinDTimm
This seems like the most likely.
MarkR
+2  A: 

at the top of your program

#include <errno.h>

when your open or read returns -1, print the value of errno (defined in errno.h), then look in errno.h for what that error means (you will need this throughout your C life, so I gave you all of this rather than just the solution to this problem)

KevinDTimm
no, write returns -1 on all errors and an integer value greater than or equal to 0 on success. errno will contain the reason for the failure.
KevinDTimm
@Kevin - +1 Very cool and informative explanation , thanks.
Eternal Learner
You **cannot** declare `extern int errno;` or your program has undefined behavior (most likely, a compile-time error, thankfully). `errno.h` defines `errno` and you must use its definition.
R..
@R.. on linux errno.h declares errno as an extern int, so there is no problem redeclaring it
PiedPiper
@PiedPiper: You're wrong on two levels. First, writing code that's gratuitously specific to a particular implementation and breaks on others is just a stupid idea. And second, the last time any userspace implementation on Linux declared `errno` like that was probably around 1998, 12 years ago. Maybe you mean the Linux kernelspace headers, but I doubt they even have an `errno`.
R..
despite the error of declaring errno "extern int", this is still the right thing to do in principle. The OP should check errno.
MarkR
Edited to reflect current usage and definitions of errno
KevinDTimm
@PiedPiper No, linux does not declare errno as extern int. Think about how that would work for a multithreaded program. errno is a define for a function call on linux
nos
Why not just print `strerror(errno)`? And, if you `#include <errno.h>` then it is incorrect `extern int errno`.
Jonathan
@Jonathan - corrected before your comment
KevinDTimm
ok I was wrong. I took a quick look at /usr/include/errno.h and missed the '#ifndef errno' around 'extern int errno'
PiedPiper
+1  A: 

If you add some error handling, you can learn more. e.g.

  #include<sys/types.h>
   #include<sys/stat.h>
   #include<fcntl.h>
   #include<stdio.h>
   #include<unistd.h>
   #include<stdlib.h>
   int main() {

   int fd_r=0,fd_w=0;
   int w_ret=100;
   fd_r = open("reader.txt", O_RDONLY);
   if(fd_r == -1)
     perror("fd_r open");

   fd_w = open("writer.txt",O_CREAT,S_IRWXU);
   if(fd_w == -1)
     perror("fd_w open");

   char *buf = (char *)malloc(50);

   while(read(fd_r,buf,30))
   {

          w_ret =   write(fd_w,buf,30);
          if(w_ret == -1) {
            perror("write");
            break;
          }
          printf("%d", w_ret);
   }
}

When run , if "reader.txt" does not exist:

$ ./a.out
fd_r open: No such file or directory
write: Bad file descriptor

I.e. not surprisingly, open() failed because the file is missing.

When run, and "reader.txt" does exist:

$ ./a.out
write: Bad file descriptor

This is a bit more subtle, but the documentation for write (man 2 write) says:

EBADF fd is not a valid file descriptor or is not open for writing.

Well. open() didn't fail, so we do have a valid file descriptor. So it's "is not open for writing."

And indeed:

 open("writer.txt",O_CREAT,S_IRWXU);

Should be:

  open("writer.txt",O_CREAT|O_WRONLY,S_IRWXU);
nos