• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdecore
 

tdecore

  • tdecore
klockfile.cpp
1/*
2 This file is part of the KDE libraries
3 Copyright (c) 2004 Waldo Bastian <bastian@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License version 2 as published by the Free Software Foundation.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18*/
19
20#include <klockfile.h>
21
22#include <config.h>
23
24#include <sys/types.h>
25#ifdef HAVE_SYS_STAT_H
26#include <sys/stat.h>
27#endif
28#ifdef HAVE_SYS_TIME_H
29#include <sys/time.h>
30#endif
31#include <signal.h>
32#include <errno.h>
33#include <stdlib.h>
34#include <unistd.h>
35
36#include <tqfile.h>
37#include <tqtextstream.h>
38
39#include <kde_file.h>
40#include <tdeapplication.h>
41#include <tdecmdlineargs.h>
42#include <tdeglobal.h>
43#include <tdetempfile.h>
44
45// TODO: http://www.spinnaker.de/linux/nfs-locking.html
46// TODO: Make regression test
47
48class TDELockFile::TDELockFilePrivate {
49public:
50 TQString file;
51 int staleTime;
52 bool isLocked;
53 bool recoverLock;
54 bool linkCountSupport;
55 TQTime staleTimer;
56 KDE_struct_stat statBuf;
57 int pid;
58 TQString hostname;
59 TQString instance;
60 TQString lockRecoverFile;
61};
62
63
64// 30 seconds
65TDELockFile::TDELockFile(const TQString &file)
66{
67 d = new TDELockFilePrivate();
68 d->file = file;
69 d->staleTime = 30;
70 d->isLocked = false;
71 d->recoverLock = false;
72 d->linkCountSupport = true;
73}
74
75TDELockFile::~TDELockFile()
76{
77 unlock();
78 delete d;
79}
80
81int
82TDELockFile::staleTime() const
83{
84 return d->staleTime;
85}
86
87
88void
89TDELockFile::setStaleTime(int _staleTime)
90{
91 d->staleTime = _staleTime;
92}
93
94static bool statResultIsEqual(KDE_struct_stat &st_buf1, KDE_struct_stat &st_buf2)
95{
96#define FIELD_EQ(what) (st_buf1.what == st_buf2.what)
97 return FIELD_EQ(st_dev) && FIELD_EQ(st_ino) &&
98 FIELD_EQ(st_uid) && FIELD_EQ(st_gid) && FIELD_EQ(st_nlink);
99#undef FIELD_EQ
100}
101
102static bool testLinkCountSupport(const TQCString &fileName)
103{
104 KDE_struct_stat st_buf;
105 // Check if hardlinks raise the link count at all?
106 ::link( fileName, fileName+".test" );
107 int result = KDE_lstat( fileName, &st_buf );
108 ::unlink( fileName+".test" );
109 return ((result == 0) && (st_buf.st_nlink == 2));
110}
111
112static TDELockFile::LockResult lockFile(const TQString &lockFile, KDE_struct_stat &st_buf, bool &linkCountSupport)
113{
114 TQCString lockFileName = TQFile::encodeName( lockFile );
115 int result = KDE_lstat( lockFileName, &st_buf );
116 if (result == 0)
117 return TDELockFile::LockFail;
118
119 KTempFile uniqueFile(lockFile, TQString::null, 0644);
120 uniqueFile.setAutoDelete(true);
121 if (uniqueFile.status() != 0)
122 return TDELockFile::LockError;
123
124 char hostname[256];
125 hostname[0] = 0;
126 gethostname(hostname, 255);
127 hostname[255] = 0;
128 TQCString instanceName = TDECmdLineArgs::appName();
129
130 (*(uniqueFile.textStream())) << TQString::number(getpid()) << endl
131 << instanceName << endl
132 << hostname << endl;
133 uniqueFile.close();
134
135 TQCString uniqueName = TQFile::encodeName( uniqueFile.name() );
136
137#ifdef Q_OS_UNIX
138 // Create lock file
139 result = ::link( uniqueName, lockFileName );
140 if (result != 0)
141 return TDELockFile::LockError;
142
143 if (!linkCountSupport)
144 return TDELockFile::LockOK;
145#else
146 //TODO for win32
147 return TDELockFile::LockOK;
148#endif
149
150 KDE_struct_stat st_buf2;
151 result = KDE_lstat( uniqueName, &st_buf2 );
152 if (result != 0)
153 return TDELockFile::LockError;
154
155 result = KDE_lstat( lockFileName, &st_buf );
156 if (result != 0)
157 return TDELockFile::LockError;
158
159 if (!statResultIsEqual(st_buf, st_buf2) || S_ISLNK(st_buf.st_mode) || S_ISLNK(st_buf2.st_mode))
160 {
161 // SMBFS supports hardlinks by copying the file, as a result the above test will always fail
162 if ((st_buf.st_nlink == 1) && (st_buf2.st_nlink == 1) && (st_buf.st_ino != st_buf2.st_ino))
163 {
164 linkCountSupport = testLinkCountSupport(uniqueName);
165 if (!linkCountSupport)
166 return TDELockFile::LockOK; // Link count support is missing... assume everything is OK.
167 }
168 return TDELockFile::LockFail;
169 }
170
171 return TDELockFile::LockOK;
172}
173
174static TDELockFile::LockResult deleteStaleLock(const TQString &lockFile, KDE_struct_stat &st_buf, bool &linkCountSupport)
175{
176 // This is dangerous, we could be deleting a new lock instead of
177 // the old stale one, let's be very careful
178
179 // Create temp file
180 KTempFile ktmpFile(lockFile);
181 if (ktmpFile.status() != 0)
182 return TDELockFile::LockError;
183
184 TQCString lckFile = TQFile::encodeName(lockFile);
185 TQCString tmpFile = TQFile::encodeName(ktmpFile.name());
186 ktmpFile.close();
187 ktmpFile.unlink();
188
189#ifdef Q_OS_UNIX
190 // link to lock file
191 if (::link(lckFile, tmpFile) != 0)
192 return TDELockFile::LockFail; // Try again later
193#else
194 //TODO for win32
195 return TDELockFile::LockOK;
196#endif
197
198 // check if link count increased with exactly one
199 // and if the lock file still matches
200 KDE_struct_stat st_buf1;
201 KDE_struct_stat st_buf2;
202 memcpy(&st_buf1, &st_buf, sizeof(KDE_struct_stat));
203 st_buf1.st_nlink++;
204 if ((KDE_lstat(tmpFile, &st_buf2) == 0) && statResultIsEqual(st_buf1, st_buf2))
205 {
206 if ((KDE_lstat(lckFile, &st_buf2) == 0) && statResultIsEqual(st_buf1, st_buf2))
207 {
208 // - - if yes, delete lock file, delete temp file, retry lock
209 tqWarning("[tdecore] Deleting stale lockfile %s", lckFile.data());
210 ::unlink(lckFile);
211 ::unlink(tmpFile);
212 return TDELockFile::LockOK;
213 }
214 }
215
216 // SMBFS supports hardlinks by copying the file, as a result the above test will always fail
217 if (linkCountSupport)
218 {
219 linkCountSupport = testLinkCountSupport(tmpFile);
220 }
221
222 if (!linkCountSupport &&
223 (KDE_lstat(lckFile, &st_buf2) == 0) &&
224 statResultIsEqual(st_buf, st_buf2))
225 {
226 // Without support for link counts we will have a little race condition
227 tqWarning("[tdecore] Deleting stale lockfile %s", lckFile.data());
228 ::unlink(lckFile);
229 ::unlink(tmpFile);
230 return TDELockFile::LockOK;
231 }
232
233 // Failed to delete stale lock file
234 tqWarning("[tdecore] WARNING: Problem deleting stale lockfile %s", lckFile.data());
235 ::unlink(tmpFile);
236 return TDELockFile::LockFail;
237}
238
239
240TDELockFile::LockResult TDELockFile::lock(int options)
241{
242 if (d->isLocked)
243 return TDELockFile::LockOK;
244
245 TDELockFile::LockResult result;
246 int hardErrors = 5;
247 int n = 5;
248 while(true)
249 {
250 KDE_struct_stat st_buf;
251 result = lockFile(d->file, st_buf, d->linkCountSupport);
252 if (result == TDELockFile::LockOK)
253 {
254 d->staleTimer = TQTime();
255 break;
256 }
257 else if (result == TDELockFile::LockError)
258 {
259 d->staleTimer = TQTime();
260 if (--hardErrors == 0)
261 {
262 break;
263 }
264 }
265 else // TDELockFile::Fail
266 {
267 if (!d->staleTimer.isNull() && !statResultIsEqual(d->statBuf, st_buf))
268 d->staleTimer = TQTime();
269
270 if (!d->staleTimer.isNull())
271 {
272 bool isStale = false;
273 if ((d->pid > 0) && !d->hostname.isEmpty())
274 {
275 // Check if hostname is us
276 char hostname[256];
277 hostname[0] = 0;
278 gethostname(hostname, 255);
279 hostname[255] = 0;
280
281 if (d->hostname == hostname)
282 {
283 // Check if pid still exists
284 int res = ::kill(d->pid, 0);
285 if ((res == -1) && (errno == ESRCH))
286 isStale = true;
287 }
288 }
289 if (d->staleTimer.elapsed() > (d->staleTime*1000))
290 isStale = true;
291
292 if (isStale)
293 {
294 if ((options & LockForce) == 0)
295 return TDELockFile::LockStale;
296
297 result = deleteStaleLock(d->file, d->statBuf, d->linkCountSupport);
298
299 if (result == TDELockFile::LockOK)
300 {
301 // Lock deletion successful
302 d->staleTimer = TQTime();
303 continue; // Now try to get the new lock
304 }
305 else if (result != TDELockFile::LockFail)
306 {
307 return result;
308 }
309 }
310 }
311 else
312 {
313 memcpy(&(d->statBuf), &st_buf, sizeof(KDE_struct_stat));
314 d->staleTimer.start();
315
316 d->pid = -1;
317 d->hostname = TQString::null;
318 d->instance = TQString::null;
319
320 TQFile file(d->file);
321 if (file.open(IO_ReadOnly))
322 {
323 TQTextStream ts(&file);
324 if (!ts.atEnd())
325 d->pid = ts.readLine().toInt();
326 if (!ts.atEnd())
327 d->instance = ts.readLine();
328 if (!ts.atEnd())
329 d->hostname = ts.readLine();
330 }
331 }
332 }
333
334 if ((options & LockNoBlock) != 0)
335 break;
336
337 struct timeval tv;
338 tv.tv_sec = 0;
339 tv.tv_usec = n*((TDEApplication::random() % 200)+100);
340 if (n < 2000)
341 n = n * 2;
342
343#ifdef Q_OS_UNIX
344 select(0, 0, 0, 0, &tv);
345#else
346 //TODO for win32
347#endif
348 }
349 if (result == LockOK)
350 d->isLocked = true;
351 return result;
352}
353
354bool TDELockFile::isLocked() const
355{
356 return d->isLocked;
357}
358
359void TDELockFile::unlock()
360{
361 if (d->isLocked)
362 {
363 ::unlink(TQFile::encodeName(d->file));
364 d->isLocked = false;
365 }
366}
367
368bool TDELockFile::getLockInfo(int &pid, TQString &hostname, TQString &appname)
369{
370 if (d->pid == -1)
371 return false;
372 pid = d->pid;
373 hostname = d->hostname;
374 appname = d->instance;
375 return true;
376}
KTempFile
The KTempFile class creates and opens a unique file for temporary use.
Definition: tdetempfile.h:56
TDEApplication::random
static int random()
Generates a uniform random number.
Definition: tdeapplication.cpp:3393
TDECmdLineArgs::appName
static const char * appName()
Get the appname according to argv[0].
Definition: tdecmdlineargs.cpp:199
TDELockFile::LockResult
LockResult
Possible return values of the lock function.
Definition: klockfile.h:48
TDELockFile::LockStale
@ LockStale
A stale lock has been detected.
Definition: klockfile.h:67
TDELockFile::LockError
@ LockError
The lock could not be acquired due to an error.
Definition: klockfile.h:62
TDELockFile::LockOK
@ LockOK
Lock was acquired successfully.
Definition: klockfile.h:52
TDELockFile::LockFail
@ LockFail
The lock could not be acquired because it is held by another process.
Definition: klockfile.h:57
TDELockFile::LockForce
@ LockForce
Automatically remove a lock when a lock is detected that is stale for more than staleTime() seconds.
Definition: klockfile.h:80
TDELockFile::LockNoBlock
@ LockNoBlock
Return immediately, do not wait for the lock to become available.
Definition: klockfile.h:74
TDELockFile::isLocked
bool isLocked() const
Returns whether the lock is held or not.
Definition: klockfile.cpp:354
TDELockFile::unlock
void unlock()
Release the lock.
Definition: klockfile.cpp:359
TDELockFile::staleTime
int staleTime() const
Return the time in seconds after which a lock is considered stale The default is 30.
Definition: klockfile.cpp:82
TDELockFile::lock
LockResult lock(int options=0)
Attempt to acquire the lock.
Definition: klockfile.cpp:240
TDELockFile::setStaleTime
void setStaleTime(int _staleTime)
Set the time in seconds after which a lock is considered stale.
Definition: klockfile.cpp:89
TDELockFile::~TDELockFile
~TDELockFile()
Destroys the object, releasing the lock if held.
Definition: klockfile.cpp:75
TDELockFile::getLockInfo
bool getLockInfo(int &pid, TQString &hostname, TQString &appname)
Returns the pid, hostname and appname of the process holding the lock after the lock functon has retu...
Definition: klockfile.cpp:368
TDEGlobal::endl
kdbgstream & endl(kdbgstream &s)
Prints an "\n".
Definition: kdebug.h:430
KNotifyClient::instance
TDEInstance * instance()
Shortcut to KNotifyClient::Instance::current() :)
Definition: knotifyclient.cpp:280

tdecore

Skip menu "tdecore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.9.4
This website is maintained by Timothy Pearson.