Provided by: liblockfile-dev_1.09-6ubuntu1_amd64 bug

NAME

       lockfile_create, lockfile_remove, lockfile_touch, lockfile_check - manage lockfiles

SYNOPSIS

       #include <lockfile.h>

       cc [ flag ... ] file ... -llockfile [ library ]

       int lockfile_create( const char *lockfile, int retrycnt, int flags );
       int lockfile_remove( const char *lockfile );
       int lockfile_touch( const char *lockfile );
       int lockfile_check( const char *lockfile, int flags  );

DESCRIPTION

       The lockfile_create function creates a lockfile in an NFS safe way.

       If  flags  is  set  to  L_PID  then  lockfile_create  will  not only check for an existing
       lockfile, but it will read the contents as well to see if it  contains  a  process  id  in
       ASCII. If so, the lockfile is only valid if that process still exists.

       If  the  lockfile  is on a shared filesystem, it might have been created by a process on a
       remote host. Thus the process-id checking is useless and the L_PID flag should not be set.
       In  this  case,  there  is  no  good  way  to see if a lockfile is stale. Therefore if the
       lockfile is older then 5 minutes, it will be  removed.  That  is  why  the  lockfile_touch
       function  is  provided:  while  holding the lock, it needs to be refreshed regulary (every
       minute or so) by calling lockfile_touch ()  .

       The lockfile_check function checks if a valid lockfile is already present  without  trying
       to create a new lockfile.

       Finally the lockfile_remove function removes the lockfile.

RETURN VALUES

       lockfile_create returns one of the following status codes:

          #define L_SUCCESS   0    /* Lockfile created                     */
          #define L_NAMELEN   1    /* Recipient name too long (> 13 chars) */
          #define L_TMPLOCK   2    /* Error creating tmp lockfile          */
          #define L_TMPWRITE  3    /* Can't write pid int tmp lockfile     */
          #define L_MAXTRYS   4    /* Failed after max. number of attempts */
          #define L_ERROR     5    /* Unknown error; check errno           */

       lockfile_check  returns  0  if  a  valid  lockfile  is present. If no lockfile or no valid
       lockfile is present, -1 is returned.

       lockfile_touch and lockfile_remove return 0 on success. On  failure  -1  is  returned  and
       errno  is  set  appropriately.  It  is  not  an  error to lockfile_remove() a non-existing
       lockfile.

ALGORITHM

       The algorithm that is used to create a lockfile in an atomic way, even  over  NFS,  is  as
       follows:

       1      A  unique  file  is created. In printf format, the name of the file is .lk%05d%x%s.
              The first argument (%05d) is the current  process  id.  The  second  argument  (%x)
              consists of the 4 minor bits of the value returned by time(2). The last argument is
              the system hostname.

       2      Then the lockfile is created using link(2). The return value of link is ignored.

       3      Now the lockfile is stat()ed. If the stat fails, we go to step 6.

       4      The stat value of the lockfile is compared with that of the temporary file. If they
              are  the  same,  we  have  the lock. The temporary file is deleted and a value of 0
              (success) is returned to the caller.

       5      A check is made to see if the existing lockfile is a valid one. If it isn't  valid,
              the stale lockfile is deleted.

       6      Before  retrying, we sleep for n seconds. n is initially 5 seconds, but after every
              retry 5 extra seconds is added up to  a  maximum  of  60  seconds  (an  incremental
              backoff). Then we go to step 2 up to retries times.

REMOTE FILE SYSTEMS AND THE KERNEL ATTRIBUTE CACHE

       These functions do not lock a file - they generate a lockfile.  However in a lot of cases,
       such as Unix mailboxes, all concerned programs accessing the mailboxes agree on  the  fact
       that the presence of <filename>.lock means that <filename> is locked.

       If  you  are  using  lockfile_create  to  create a lock on a file that resides on a remote
       server, and you already have that file open, you need to flush  the  NFS  attribute  cache
       after locking. This is needed to prevent the following scenario:

       o  open /var/mail/USERNAME
       o  attributes, such as size, inode, etc are now cached in the kernel!
       o  meanwhile, another remote system appends data to /var/mail/USERNAME
       o  grab lock using lockfile_create()
       o  seek to end of file
       o  write data

       Now  the  end  of  the  file  really  isn't  the  end  of the file - the kernel cached the
       attributes on open, and st_size is not the end of the file anymore. So after  locking  the
       file, you need to tell the kernel to flush the NFS file attribute cache.

       The  only portable way to do this is the POSIX fcntl() file locking primitives - locking a
       file using fcntl() has the fortunate side-effect of invalidating the  NFS  file  attribute
       cache of the kernel.

       lockfile_create() cannot do this for you for two reasons. One, it just creates a lockfile-
       it doesn't know which file you are actually trying to lock! Two, even if it  could  deduce
       the  file  you're  locking  from  the  filename,  by just opening and closing it, it would
       invalidate any existing POSIX locks the program might already  have  on  that  file  (yes,
       POSIX locking semantics are insane!).

       So basically what you need to do is something like this:

         fd = open("/var/mail/USER");
         .. program code ..

         lockfile_create("/var/mail/USER.lock", x, y);

         /* Invalidate NFS attribute cache using POSIX locks */
         if (lockf(fd, F_TLOCK, 0) == 0) lockf(fd, F_ULOCK, 0);

       You  have to be careful with this if you're putting this in an existing program that might
       already be using fcntl(), flock() or lockf() locking- you might invalidate existing locks.

       There is also a non-portable way. A lot of NFS operations return the updated attributes  -
       and  the  Linux  kernel  actually  uses  these to update the attribute cache. One of these
       operations is chmod(2).

       So stat()ing a file and then chmod()ing it to st.st_mode  will  not  actually  change  the
       file,  nor  will  it  interfere  with  any  locks  on the file, but it will invalidate the
       attribute cache. The equivalent to use from a shell script would be

         chmod u=u /var/mail/USER

PERMISSIONS

       If you are on a system that has a mail spool directory that is only writable by a  special
       group  (usually  "mail")  you cannot create a lockfile directly in the mailspool directory
       without special permissions.

       Lockfile_create and lockfile_remove check if the lockfile ends in $USERNAME.lock,  and  if
       the  directory  the  lockfile is writable by group "mail". If so, an external set group-id
       mail executable (dotlockfile(1) ) is spawned to do the actual locking / unlocking.

FILES

       /usr/lib/liblockfile.so.1

AUTHOR

       Miquel van Smoorenburg <miquels@cistron.nl>

SEE ALSO

       dotlockfile(1), maillock(3), touchlock (3), mailunlock(3)