WvStreams
wvlockdev.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  *
00005  * Some handy functions to create/remove /var/lock lockfiles.
00006  */
00007 #include "wvlockdev.h"
00008 #include "wvfile.h"
00009 #include "strutils.h"
00010 #include <signal.h>
00011 #include <string.h>
00012 #include <sys/types.h>
00013 #include <fcntl.h>
00014 #include <sys/stat.h>
00015 #include <errno.h>
00016 
00017 WvLockDev::WvLockDev(WvString _devicename)
00018         : devicename(_devicename)
00019 {
00020     const char *p = strrchr(devicename, '/');
00021     if (p)
00022         p++;
00023     else
00024         p = devicename;
00025     
00026     lock_count = 0;
00027     filename = WvString("/var/lock/serial/LCK..%s", p);
00028 }
00029 
00030 
00031 WvLockDev::~WvLockDev()
00032 {
00033     if (lock_count)
00034     {
00035         lock_count = 1;
00036         unlock();
00037     }
00038 }
00039 
00040 
00041 #if USE_LOCKDEV /* use the liblockdev.a locking routines */
00042 
00043 #include <lockdev.h>
00044 
00045 bool WvLockDev::lock()
00046 {
00047     if (lock_count)
00048     {
00049         lock_count++;
00050         return true;
00051     }
00052     
00053     if (dev_lock(devicename))
00054         return false;
00055 
00056     lock_count++;
00057     return true;
00058 }
00059 
00060 
00061 void WvLockDev::unlock()
00062 {
00063     if (!lock_count) return;
00064 
00065     if (!--lock_count)
00066         dev_unlock(devicename, getpid());
00067 }
00068 
00069 
00070 #else /* !USE_LOCKDEV -- implement our own locking routines */
00071 
00072 
00073 // note: this function uses the O_EXCL flag to open(), and thus assumes
00074 // that /var/lock is not an NFS-mounted drive (according to the open() man
00075 // page, you need to follow a special procedure to ensure successful NFS
00076 // locking)
00077 //
00078 // Actually there may be other race conditions that we should look into.
00079 bool WvLockDev::lock()
00080 {
00081     pid_t pid;
00082     
00083     if (lock_count)
00084     {
00085         lock_count++;
00086         return true;
00087     }
00088 
00089     WvFile fd(filename, O_RDWR | O_EXCL | O_CREAT, 0644);
00090 
00091     if (fd.isok()) 
00092     {
00093         // We made a lock file...
00094         fd.print("%10s\n", getpid());
00095     }
00096     else if (fd.geterr() == EEXIST)
00097     {
00098         char *inbuf;
00099         
00100         // Lock file is already there!  Check for staleness...
00101         sleep(1);       // preventing race condition...
00102         
00103         fd.open(filename, O_RDONLY);
00104         //fprintf(stderr, "ok: %d\n", fd.isok());
00105         inbuf = trim_string(fd.blocking_getline(-1));
00106         //fprintf(stderr, "blocking_getline: '%s'\n", inbuf);
00107         
00108         if (inbuf)
00109             pid = atoi(inbuf);
00110         else
00111             pid = 0;
00112         
00113         //fprintf(stderr, "pid: '%d'\n", pid);
00114         
00115         if (pid && pid != -1 && kill(pid, 0) == -1 && errno == ESRCH)
00116         {
00117             // we can create a lockfile now
00118             fd.close();
00119             if (unlink(filename))
00120                 return false; // cannot remove lockfile
00121             fd.open(filename, O_RDWR | O_EXCL | O_CREAT, 0644);
00122             fd.print("%10s\n", getpid());
00123         }
00124         else
00125             return false; // device already locked
00126     }
00127     else // some other unexpected error
00128         return false;
00129 
00130     lock_count++;
00131     return true;
00132 }
00133 
00134 
00135 
00136 void WvLockDev::unlock()
00137 {
00138     if (!lock_count) return;
00139 
00140     if (!--lock_count)
00141         unlink(filename);
00142 }
00143 
00144 
00145 #endif /* !USE_LOCKDEV */