klockfile.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <klockfile.h>
00021
00022 #include <config.h>
00023
00024 #include <sys/types.h>
00025 #ifdef HAVE_SYS_STAT_H
00026 #include <sys/stat.h>
00027 #endif
00028 #ifdef HAVE_SYS_TIME_H
00029 #include <sys/time.h>
00030 #endif
00031 #include <signal.h>
00032 #include <errno.h>
00033 #include <stdlib.h>
00034 #include <unistd.h>
00035
00036 #include <qfile.h>
00037 #include <qtextstream.h>
00038
00039 #include <kde_file.h>
00040 #include <kapplication.h>
00041 #include <kcmdlineargs.h>
00042 #include <kglobal.h>
00043 #include <ktempfile.h>
00044
00045
00046
00047
00048 class KLockFile::KLockFilePrivate {
00049 public:
00050 QString file;
00051 int staleTime;
00052 bool isLocked;
00053 bool recoverLock;
00054 QTime staleTimer;
00055 KDE_struct_stat statBuf;
00056 int pid;
00057 QString hostname;
00058 QString instance;
00059 QString lockRecoverFile;
00060 };
00061
00062
00063
00064 KLockFile::KLockFile(const QString &file)
00065 {
00066 d = new KLockFilePrivate();
00067 d->file = file;
00068 d->staleTime = 30;
00069 d->isLocked = false;
00070 d->recoverLock = false;
00071 }
00072
00073 KLockFile::~KLockFile()
00074 {
00075 unlock();
00076 delete d;
00077 }
00078
00079 int
00080 KLockFile::staleTime() const
00081 {
00082 return d->staleTime;
00083 }
00084
00085
00086 void
00087 KLockFile::setStaleTime(int _staleTime)
00088 {
00089 d->staleTime = _staleTime;
00090 }
00091
00092 static bool statResultIsEqual(KDE_struct_stat &st_buf1, KDE_struct_stat &st_buf2)
00093 {
00094 #define FIELD_EQ(what) (st_buf1.what == st_buf2.what)
00095 return FIELD_EQ(st_dev) && FIELD_EQ(st_ino) &&
00096 FIELD_EQ(st_uid) && FIELD_EQ(st_gid) && FIELD_EQ(st_nlink);
00097 #undef FIELD_EQ
00098 }
00099
00100 static KLockFile::LockResult lockFile(const QString &lockFile, KDE_struct_stat &st_buf)
00101 {
00102 QCString lockFileName = QFile::encodeName( lockFile );
00103 int result = KDE_lstat( lockFileName, &st_buf );
00104 if (result == 0)
00105 return KLockFile::LockFail;
00106
00107 KTempFile uniqueFile(lockFile, QString::null, 0644);
00108 uniqueFile.setAutoDelete(true);
00109 if (uniqueFile.status() != 0)
00110 return KLockFile::LockError;
00111
00112 char hostname[256];
00113 hostname[0] = 0;
00114 gethostname(hostname, 255);
00115 hostname[255] = 0;
00116 QCString instanceName = KCmdLineArgs::appName();
00117
00118 (*(uniqueFile.textStream())) << QString::number(getpid()) << endl
00119 << instanceName << endl
00120 << hostname << endl;
00121 uniqueFile.close();
00122
00123 QCString uniqueName = QFile::encodeName( uniqueFile.name() );
00124
00125 #ifdef Q_OS_UNIX
00126
00127 result = ::link( uniqueName, lockFileName );
00128 if (result != 0)
00129 return KLockFile::LockError;
00130
00131 #else
00132
00133 return KLockFile::LockOK;
00134 #endif
00135
00136 KDE_struct_stat st_buf2;
00137 result = KDE_lstat( uniqueName, &st_buf2 );
00138 if (result != 0)
00139 return KLockFile::LockError;
00140
00141 result = KDE_lstat( lockFileName, &st_buf );
00142 if (result != 0)
00143 return KLockFile::LockError;
00144
00145 if (!statResultIsEqual(st_buf, st_buf2) || S_ISLNK(st_buf.st_mode) || S_ISLNK(st_buf2.st_mode))
00146 return KLockFile::LockFail;
00147
00148 return KLockFile::LockOK;
00149 }
00150
00151 static KLockFile::LockResult deleteStaleLock(const QString &lockFile, KDE_struct_stat &st_buf)
00152 {
00153
00154
00155
00156
00157 KTempFile ktmpFile(lockFile);
00158 if (ktmpFile.status() != 0)
00159 return KLockFile::LockError;
00160
00161 QCString lckFile = QFile::encodeName( lockFile );
00162 QCString tmpFile = QFile::encodeName(ktmpFile.name());
00163 ktmpFile.close();
00164 ktmpFile.unlink();
00165
00166 #ifdef Q_OS_UNIX
00167
00168 if (::link(lckFile, tmpFile) != 0)
00169 return KLockFile::LockFail;
00170 #else
00171
00172 return KLockFile::LockOK;
00173 #endif
00174
00175
00176
00177 KDE_struct_stat st_buf1;
00178 KDE_struct_stat st_buf2;
00179 memcpy(&st_buf1, &st_buf, sizeof(KDE_struct_stat));
00180 st_buf1.st_nlink++;
00181 if ((KDE_lstat(tmpFile, &st_buf2) == 0) && statResultIsEqual(st_buf1, st_buf2))
00182 {
00183 if ((KDE_lstat(lckFile, &st_buf2) == 0) && statResultIsEqual(st_buf1, st_buf2))
00184 {
00185
00186 qWarning("WARNING: deleting stale lockfile %s", lckFile.data());
00187 ::unlink(lckFile);
00188 ::unlink(tmpFile);
00189 return KLockFile::LockOK;
00190 }
00191 }
00192
00193 qWarning("WARNING: Problem deleting stale lockfile %s", lckFile.data());
00194 ::unlink(tmpFile);
00195 return KLockFile::LockFail;
00196 }
00197
00198
00199 KLockFile::LockResult KLockFile::lock(int options)
00200 {
00201 if (d->isLocked)
00202 return KLockFile::LockOK;
00203
00204 KLockFile::LockResult result;
00205 int hardErrors = 5;
00206 int n = 5;
00207 while(true)
00208 {
00209 KDE_struct_stat st_buf;
00210 result = lockFile(d->file, st_buf);
00211 if (result == KLockFile::LockOK)
00212 {
00213 d->staleTimer = QTime();
00214 break;
00215 }
00216 else if (result == KLockFile::LockError)
00217 {
00218 d->staleTimer = QTime();
00219 if (--hardErrors == 0)
00220 {
00221 break;
00222 }
00223 }
00224 else
00225 {
00226 if (!d->staleTimer.isNull() && !statResultIsEqual(d->statBuf, st_buf))
00227 d->staleTimer = QTime();
00228
00229 if (!d->staleTimer.isNull())
00230 {
00231 bool isStale = false;
00232 if ((d->pid > 0) && !d->hostname.isEmpty())
00233 {
00234
00235 char hostname[256];
00236 hostname[0] = 0;
00237 gethostname(hostname, 255);
00238 hostname[255] = 0;
00239
00240 if (d->hostname == hostname)
00241 {
00242
00243 int res = ::kill(d->pid, 0);
00244 if ((res == -1) && (errno == ESRCH))
00245 isStale = true;
00246 }
00247 }
00248 if (d->staleTimer.elapsed() > (d->staleTime*1000))
00249 isStale = true;
00250
00251 if (isStale)
00252 {
00253 if ((options & LockForce) == 0)
00254 return KLockFile::LockStale;
00255
00256 result = deleteStaleLock(d->file, d->statBuf);
00257
00258 if (result == KLockFile::LockOK)
00259 {
00260
00261 d->staleTimer = QTime();
00262 continue;
00263 }
00264 else if (result != KLockFile::LockFail)
00265 {
00266 return result;
00267 }
00268 }
00269 }
00270 else
00271 {
00272 memcpy(&(d->statBuf), &st_buf, sizeof(KDE_struct_stat));
00273 d->staleTimer.start();
00274
00275 d->pid = -1;
00276 d->hostname = QString::null;
00277 d->instance = QString::null;
00278
00279 QFile file(d->file);
00280 if (file.open(IO_ReadOnly))
00281 {
00282 QTextStream ts(&file);
00283 if (!ts.atEnd())
00284 d->pid = ts.readLine().toInt();
00285 if (!ts.atEnd())
00286 d->instance = ts.readLine();
00287 if (!ts.atEnd())
00288 d->hostname = ts.readLine();
00289 }
00290 }
00291 }
00292
00293 if ((options & LockNoBlock) != 0)
00294 break;
00295
00296 struct timeval tv;
00297 tv.tv_sec = 0;
00298 tv.tv_usec = n*((KApplication::random() % 200)+100);
00299 if (n < 2000)
00300 n = n * 2;
00301
00302 #ifdef Q_OS_UNIX
00303 select(0, 0, 0, 0, &tv);
00304 #else
00305
00306 #endif
00307 }
00308 if (result == LockOK)
00309 d->isLocked = true;
00310 return result;
00311 }
00312
00313 bool KLockFile::isLocked() const
00314 {
00315 return d->isLocked;
00316 }
00317
00318 void KLockFile::unlock()
00319 {
00320 if (d->isLocked)
00321 {
00322 ::unlink(QFile::encodeName(d->file));
00323 d->isLocked = false;
00324 }
00325 }
00326
00327 bool KLockFile::getLockInfo(int &pid, QString &hostname, QString &appname)
00328 {
00329 if (d->pid == -1)
00330 return false;
00331 pid = d->pid;
00332 hostname = d->hostname;
00333 appname = d->instance;
00334 return true;
00335 }
This file is part of the documentation for kdecore Library Version 3.4.1.