0

I have been trying to understand the reason and cannot find a valid reason for Invalid Argument error given on the use of perror. Can anyone suggest the reason for this error?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

int main(int argc,char *argv[])
{ 

    int fd;
    char buffer[255];
    struct flock fvar;

    if(argc==1)
    {
        printf("usage:./a.out filename\n");
        return -1;
    }

    if((fd=open(argv[1],O_RDWR))==-1)
    {
        perror("open");
        exit(1);
    }

    fvar.l_type=F_WRLCK;
    fvar.l_whence=SEEK_END;
    fvar.l_start=SEEK_END-100;
    fvar.l_len=100;

    printf("press enter to set lock\n");
    getchar();
    printf("trying to get lock..\n");

  **if((fcntl(fd,F_SETLK,&fvar))==-1)
    {
         perror("fcntl") ;
         fcntl(fd,F_GETLK,&fvar);**
         printf("\nFile already locked by process (pid): \t%d\n",fvar.l_pid);
         return -1;
    }

    printf("locked\n");

    if((lseek(fd,SEEK_END-50,SEEK_END))==-1)
    {
        perror("lseek");
        exit(1);
    }

    if((read(fd,buffer,100))==-1)
    {
        perror("read");
        exit(1);
    }

    printf("data read from file..\n");
    puts(buffer);
    printf("press enter to release lock\n");

    getchar();

    fvar.l_type = F_UNLCK;
    fvar.l_whence = SEEK_SET;
    fvar.l_start = 0;
    fvar.l_len = 0;

    if((fcntl(fd,F_UNLCK,&fvar))==-1)
    {
        perror("fcntl");
        exit(0);
    }

    printf("Unlocked\n");
    close(fd);

    return 0;
}

I have tried checking the arguments. The file descriptor looks good and the arguments of flock are double , triple, quadruple ... times checked. I just can't understand where the problem is.

aakansha
  • 695
  • 5
  • 18

2 Answers2

2

You are setting:

fvar.l_type=F_WRLCK;
fvar.l_whence=SEEK_END;
fvar.l_start=SEEK_END-100;
fvar.l_len=100;

The man page for fcntl (on Linux, at least) says:

l_start is the starting offset for the lock, and is interpreted relative to either: the start of the file (if l_whence is SEEK_SET); the current file offset (if l_whence is SEEK_CUR); or the end of the file (if l_whence is SEEK_END). In the final two cases, l_start can be a negative number provided the offset does not lie before the start of the file.

You are setting l_start to SEEK_END-100. Since SEEK_END is equal to 2 (again, on Linux, though other systems are likely to be similar), that means you're setting l_start to -98. If the file length is less than 98 bytes, that will be before the start of the file - which, as the man page says, is not allowed. This is likely to be the source of the EINVAL.

Instead you should:

  1. Make sure you're using offsets that are within the file
  2. Not use SEEK_END-100 (or SEEK_END-50) for fcntl or lseek - that's not how they work - just use -100 or -50 instead.
psmears
  • 26,070
  • 4
  • 40
  • 48
  • So, your point is not to use SEEK_END-100(or 50) and instead use -100 or -50 for the offset set to SEEK_END or simply change the offset to SEEK_SET? Also, why can't I use 'SEEK_END - 50' for lseek? Your input was helpful. – priyadarshi1729 Jun 07 '15 at 17:44
  • Yes, use `-100` or `-50` (or switch to `SEEK_SET`). You can't use `SEEK_END-50` for `lseek()` because again, that's not how `SEEK_END` works - you need to use `SEEK_END` for the `whence` parameter, but just `-50` for the `offset`. Glad you found the answer helpful :) – psmears Jun 08 '15 at 07:07
0

If fvar.l_whence is set to SEEK_END, fvar.l_start is an offset from the end of the file. If you want the lock to start 100 bytes before the end then l_start should be -100 (not SEEK_END-100).

mark4o
  • 58,919
  • 18
  • 87
  • 102
  • This is true, but since `SEEK_END` is typically a small positive integer (on Linux it's 2), that means the code is using -98 as the offset, which will work if the file is 98 bytes or more long (though it might not lock what the OP was expecting). If the file is shorter than that, changing to -100 is less wrong, but won't remove the error... – psmears Jun 05 '15 at 15:24