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 }