зеркало из https://github.com/mozilla/pjs.git
Bug 151188. Use fcntl for profile locking on Linux/Unix, with symlinks as a backup. We'll continue to also take the symlink, so that older builds are still locked out, but we mark the symlink so that if a newer fcntl-build leaves a stale symlink lock we detect and remove it.
This commit is contained in:
Родитель
fb5a61177c
Коммит
e4c9b4148c
|
@ -253,7 +253,58 @@ nsresult nsProfileLock::LockWithFcntl(const nsACString& lockFilePath)
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsProfileLock::LockWithSymlink(const nsACString& lockFilePath)
|
||||
static PRBool IsSymlinkStaleLock(struct in_addr* aAddr, const char* aFileName,
|
||||
PRBool aHaveFcntlLock)
|
||||
{
|
||||
// the link exists; see if it's from this machine, and if
|
||||
// so if the process is still active
|
||||
char buf[1024];
|
||||
int len = readlink(aFileName, buf, sizeof buf - 1);
|
||||
if (len > 0)
|
||||
{
|
||||
buf[len] = '\0';
|
||||
char *colon = strchr(buf, ':');
|
||||
if (colon)
|
||||
{
|
||||
*colon++ = '\0';
|
||||
unsigned long addr = inet_addr(buf);
|
||||
if (addr != (unsigned long) -1)
|
||||
{
|
||||
if (colon[0] == '+' && aHaveFcntlLock) {
|
||||
// This lock was placed by a Firefox build which would have
|
||||
// taken the fnctl lock, and we've already taken the fcntl lock,
|
||||
// so the process that created this obsolete lock must be gone
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
char *after = nsnull;
|
||||
pid_t pid = strtol(colon, &after, 0);
|
||||
if (pid != 0 && *after == '\0')
|
||||
{
|
||||
if (addr != aAddr->s_addr)
|
||||
{
|
||||
// Remote lock: give up even if stuck.
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// kill(pid,0) is a neat trick to check if a
|
||||
// process exists
|
||||
if (kill(pid, 0) == 0 || errno != ESRCH)
|
||||
{
|
||||
// Local process appears to be alive, ass-u-me it
|
||||
// is another Mozilla instance, or a compatible
|
||||
// derivative, that's currently using the profile.
|
||||
// XXX need an "are you Mozilla?" protocol
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsresult nsProfileLock::LockWithSymlink(const nsACString& lockFilePath, PRBool aHaveFcntlLock)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
|
@ -272,7 +323,8 @@ nsresult nsProfileLock::LockWithSymlink(const nsACString& lockFilePath)
|
|||
}
|
||||
|
||||
char *signature =
|
||||
PR_smprintf("%s:%lu", inet_ntoa(inaddr), (unsigned long)getpid());
|
||||
PR_smprintf("%s:%s%lu", inet_ntoa(inaddr), aHaveFcntlLock ? "+" : "",
|
||||
(unsigned long)getpid());
|
||||
const nsPromiseFlatCString& flat = PromiseFlatCString(lockFilePath);
|
||||
const char *fileName = flat.get();
|
||||
int symlink_rv, symlink_errno, tries = 0;
|
||||
|
@ -284,44 +336,8 @@ nsresult nsProfileLock::LockWithSymlink(const nsACString& lockFilePath)
|
|||
if (symlink_errno != EEXIST)
|
||||
break;
|
||||
|
||||
// the link exists; see if it's from this machine, and if
|
||||
// so if the process is still active
|
||||
char buf[1024];
|
||||
int len = readlink(fileName, buf, sizeof buf - 1);
|
||||
if (len > 0)
|
||||
{
|
||||
buf[len] = '\0';
|
||||
char *colon = strchr(buf, ':');
|
||||
if (colon)
|
||||
{
|
||||
*colon++ = '\0';
|
||||
unsigned long addr = inet_addr(buf);
|
||||
if (addr != (unsigned long) -1)
|
||||
{
|
||||
char *after = nsnull;
|
||||
pid_t pid = strtol(colon, &after, 0);
|
||||
if (pid != 0 && *after == '\0')
|
||||
{
|
||||
if (addr != inaddr.s_addr)
|
||||
{
|
||||
// Remote lock: give up even if stuck.
|
||||
break;
|
||||
}
|
||||
|
||||
// kill(pid,0) is a neat trick to check if a
|
||||
// process exists
|
||||
if (kill(pid, 0) == 0 || errno != ESRCH)
|
||||
{
|
||||
// Local process appears to be alive, ass-u-me it
|
||||
// is another Mozilla instance, or a compatible
|
||||
// derivative, that's currently using the profile.
|
||||
// XXX need an "are you Mozilla?" protocol
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!IsSymlinkStaleLock(&inaddr, fileName, aHaveFcntlLock))
|
||||
break;
|
||||
|
||||
// Lock seems to be bogus: try to claim it. Give up after a large
|
||||
// number of attempts (100 comes from the 4.x codebase).
|
||||
|
@ -424,7 +440,7 @@ nsresult nsProfileLock::Lock(nsILocalFile* aProfileDir,
|
|||
rv = lockFile->Append(LOCKFILE_NAME);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
// First, try locking using fcntl. It is more reliable on
|
||||
// a local machine, but may not be supported by an NFS server.
|
||||
|
@ -432,13 +448,15 @@ nsresult nsProfileLock::Lock(nsILocalFile* aProfileDir,
|
|||
rv = lockFile->GetNativePath(filePath);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
rv = LockWithFcntl(filePath);
|
||||
if (NS_FAILED(rv) && (rv != NS_ERROR_FILE_ACCESS_DENIED))
|
||||
{
|
||||
// If that failed for any reason other than NS_ERROR_FILE_ACCESS_DENIED,
|
||||
// assume we tried an NFS that does not support it. Now, try with symlink.
|
||||
rv = LockWithSymlink(filePath);
|
||||
rv = LockWithSymlink(filePath, PR_FALSE);
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
// Check for the old-style lock used by pre-mozilla 1.3 builds.
|
||||
|
@ -483,6 +501,43 @@ nsresult nsProfileLock::Lock(nsILocalFile* aProfileDir,
|
|||
}
|
||||
rv = NS_OK; // Don't propagate error from OpenNSPRFileDesc.
|
||||
}
|
||||
#elif defined(XP_UNIX)
|
||||
nsCAutoString filePath;
|
||||
rv = lockFile->GetNativePath(filePath);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// Get the old lockfile name
|
||||
nsCOMPtr<nsIFile> oldLockFile;
|
||||
rv = aProfileDir->Clone(getter_AddRefs(oldLockFile));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
rv = oldLockFile->Append(OLD_LOCKFILE_NAME);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
nsCAutoString oldFilePath;
|
||||
rv = oldLockFile->GetNativePath(oldFilePath);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// First, try locking using fcntl. It is more reliable on
|
||||
// a local machine, but may not be supported by an NFS server.
|
||||
rv = LockWithFcntl(filePath);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Check to see whether there is a symlink lock held by an older
|
||||
// Firefox build, and also place our own symlink lock --- but
|
||||
// mark it "obsolete" so that other newer builds can break the lock
|
||||
// if they obtain the fcntl lock
|
||||
rv = LockWithSymlink(oldFilePath, PR_TRUE);
|
||||
}
|
||||
else if (rv != NS_ERROR_FILE_ACCESS_DENIED)
|
||||
{
|
||||
// If that failed for any reason other than NS_ERROR_FILE_ACCESS_DENIED,
|
||||
// assume we tried an NFS that does not support it. Now, try with symlink
|
||||
// using the old symlink path
|
||||
rv = LockWithSymlink(oldFilePath, PR_FALSE);
|
||||
}
|
||||
|
||||
#elif defined(XP_WIN)
|
||||
nsCAutoString filePath;
|
||||
rv = lockFile->GetNativePath(filePath);
|
||||
|
@ -539,38 +594,7 @@ nsresult nsProfileLock::Lock(nsILocalFile* aProfileDir,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
#elif defined(XP_UNIX)
|
||||
nsCOMPtr<nsIFile> oldLockFile;
|
||||
rv = aProfileDir->Clone(getter_AddRefs(oldLockFile));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
rv = oldLockFile->Append(OLD_LOCKFILE_NAME);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
nsCAutoString filePath;
|
||||
rv = oldLockFile->GetNativePath(filePath);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
// First, try the 4.x-compatible symlink technique, which works
|
||||
// with NFS without depending on (broken or missing, too often)
|
||||
// lockd.
|
||||
rv = LockWithSymlink(filePath);
|
||||
if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ACCESS_DENIED)
|
||||
{
|
||||
// If that failed with an error other than
|
||||
// NS_ERROR_FILE_ACCESS_DENIED, symlinks aren't
|
||||
// supported (for example, on Win32 SAMBA servers).
|
||||
// Try locking with fcntl.
|
||||
rv = lockFile->GetNativePath(filePath);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = LockWithFcntl(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
#endif /* XP_UNIX */
|
||||
#endif
|
||||
|
||||
mHaveLock = PR_TRUE;
|
||||
|
||||
|
|
|
@ -96,7 +96,12 @@ private:
|
|||
static PRCList mPidLockList;
|
||||
|
||||
nsresult LockWithFcntl(const nsACString& lockFilePath);
|
||||
nsresult LockWithSymlink(const nsACString& lockFilePath);
|
||||
|
||||
/**
|
||||
* @param aHaveFcntlLock if true, we've already acquired an fcntl lock so this
|
||||
* lock is merely an "obsolete" lock to keep out old Firefoxes
|
||||
*/
|
||||
nsresult LockWithSymlink(const nsACString& lockFilePath, PRBool aHaveFcntlLock);
|
||||
|
||||
char* mPidLockFileName;
|
||||
int mLockFileDesc;
|
||||
|
|
Загрузка…
Ссылка в новой задаче