• 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 
48 class TDELockFile::TDELockFilePrivate {
49 public:
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
65 TDELockFile::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 
75 TDELockFile::~TDELockFile()
76 {
77  unlock();
78  delete d;
79 }
80 
81 int
82 TDELockFile::staleTime() const
83 {
84  return d->staleTime;
85 }
86 
87 
88 void
89 TDELockFile::setStaleTime(int _staleTime)
90 {
91  d->staleTime = _staleTime;
92 }
93 
94 static 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 
102 static 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 
112 static 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 
174 static 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 
240 TDELockFile::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 
354 bool TDELockFile::isLocked() const
355 {
356  return d->isLocked;
357 }
358 
359 void TDELockFile::unlock()
360 {
361  if (d->isLocked)
362  {
363  ::unlink(TQFile::encodeName(d->file));
364  d->isLocked = false;
365  }
366 }
367 
368 bool 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 }
TDELockFile::~TDELockFile
~TDELockFile()
Destroys the object, releasing the lock if held.
Definition: klockfile.cpp:75
TDELockFile::isLocked
bool isLocked() const
Returns whether the lock is held or not.
Definition: klockfile.cpp:354
TDELockFile::LockFail
The lock could not be acquired because it is held by another process.
Definition: klockfile.h:57
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::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
KNotifyClient::instance
TDEInstance * instance()
Shortcut to KNotifyClient::Instance::current() :)
Definition: knotifyclient.cpp:280
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
KTempFile
The KTempFile class creates and opens a unique file for temporary use.
Definition: tdetempfile.h:55
TDELockFile::LockError
The lock could not be acquired due to an error.
Definition: klockfile.h:62
TDELockFile::LockNoBlock
Return immediately, do not wait for the lock to become available.
Definition: klockfile.h:74
TDELockFile::LockStale
A stale lock has been detected.
Definition: klockfile.h:67
TDEApplication::random
static int random()
Generates a uniform random number.
Definition: tdeapplication.cpp:3395
TDELockFile::setStaleTime
void setStaleTime(int _staleTime)
Set the time in seconds after which a lock is considered stale.
Definition: klockfile.cpp:89
TDELockFile::lock
LockResult lock(int options=0)
Attempt to acquire the lock.
Definition: klockfile.cpp:240
TDELockFile::LockOK
Lock was acquired successfully.
Definition: klockfile.h:52
TDELockFile::LockForce
Automatically remove a lock when a lock is detected that is stale for more than staleTime() seconds...
Definition: klockfile.h:80
TDEGlobal::endl
kdbgstream & endl(kdbgstream &s)
Definition: kdebug.h:430

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
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.8.8
This website is maintained by Timothy Pearson.