WvStreams
wvlockdev.cc
1 /*
2  * Worldvisions Weaver Software:
3  * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4  *
5  * Some handy functions to create/remove /var/lock lockfiles.
6  */
7 #include "wvlockdev.h"
8 #include "wvfile.h"
9 #include "strutils.h"
10 #include <signal.h>
11 #include <string.h>
12 #include <sys/types.h>
13 #include <fcntl.h>
14 #include <sys/stat.h>
15 #include <errno.h>
16 
17 WvLockDev::WvLockDev(WvString _devicename)
18  : devicename(_devicename)
19 {
20  const char *p = strrchr(devicename, '/');
21  if (p)
22  p++;
23  else
24  p = devicename;
25 
26  lock_count = 0;
27  filename = WvString("/var/lock/serial/LCK..%s", p);
28 }
29 
30 
31 WvLockDev::~WvLockDev()
32 {
33  if (lock_count)
34  {
35  lock_count = 1;
36  unlock();
37  }
38 }
39 
40 
41 #if USE_LOCKDEV /* use the liblockdev.a locking routines */
42 
43 #include <lockdev.h>
44 
45 bool WvLockDev::lock()
46 {
47  if (lock_count)
48  {
49  lock_count++;
50  return true;
51  }
52 
53  if (dev_lock(devicename))
54  return false;
55 
56  lock_count++;
57  return true;
58 }
59 
60 
61 void WvLockDev::unlock()
62 {
63  if (!lock_count) return;
64 
65  if (!--lock_count)
66  dev_unlock(devicename, getpid());
67 }
68 
69 
70 #else /* !USE_LOCKDEV -- implement our own locking routines */
71 
72 
73 // note: this function uses the O_EXCL flag to open(), and thus assumes
74 // that /var/lock is not an NFS-mounted drive (according to the open() man
75 // page, you need to follow a special procedure to ensure successful NFS
76 // locking)
77 //
78 // Actually there may be other race conditions that we should look into.
79 bool WvLockDev::lock()
80 {
81  pid_t pid;
82 
83  if (lock_count)
84  {
85  lock_count++;
86  return true;
87  }
88 
89  WvFile fd(filename, O_RDWR | O_EXCL | O_CREAT, 0644);
90 
91  if (fd.isok())
92  {
93  // We made a lock file...
94  fd.print("%10s\n", getpid());
95  }
96  else if (fd.geterr() == EEXIST)
97  {
98  char *inbuf;
99 
100  // Lock file is already there! Check for staleness...
101  sleep(1); // preventing race condition...
102 
103  fd.open(filename, O_RDONLY);
104  //fprintf(stderr, "ok: %d\n", fd.isok());
105  inbuf = trim_string(fd.blocking_getline(-1));
106  //fprintf(stderr, "blocking_getline: '%s'\n", inbuf);
107 
108  if (inbuf)
109  pid = atoi(inbuf);
110  else
111  pid = 0;
112 
113  //fprintf(stderr, "pid: '%d'\n", pid);
114 
115  if (pid && pid != -1 && kill(pid, 0) == -1 && errno == ESRCH)
116  {
117  // we can create a lockfile now
118  fd.close();
119  if (unlink(filename))
120  return false; // cannot remove lockfile
121  fd.open(filename, O_RDWR | O_EXCL | O_CREAT, 0644);
122  fd.print("%10s\n", getpid());
123  }
124  else
125  return false; // device already locked
126  }
127  else // some other unexpected error
128  return false;
129 
130  lock_count++;
131  return true;
132 }
133 
134 
135 
136 void WvLockDev::unlock()
137 {
138  if (!lock_count) return;
139 
140  if (!--lock_count)
141  unlink(filename);
142 }
143 
144 
145 #endif /* !USE_LOCKDEV */
WvFile
WvFile implements a stream connected to a file or Unix device.
Definition: wvfile.h:28
trim_string
char * trim_string(char *string)
Trims whitespace from the beginning and end of the character string, including carriage return / line...
Definition: strutils.cc:59
WvString
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:329