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