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
17WvLockDev::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/LCK..%s", p);
28}
29
30
31WvLockDev::~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
45bool 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
61void 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.
79bool 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
136void WvLockDev::unlock()
137{
138 if (!lock_count) return;
139
140 if (!--lock_count)
141 unlink(filename);
142}
143
144
145#endif /* !USE_LOCKDEV */
WvFile implements a stream connected to a file or Unix device.
Definition wvfile.h:29
WvString is an implementation of a simple and efficient printable-string class.
Definition wvstring.h:330
char * trim_string(char *string)
Trims whitespace from the beginning and end of the character string, including carriage return / line...
Definition strutils.cc:59