nsresult nsProfileLock::LockWithSymlink(nsIFile *aLockFile, bool aHaveFcntlLock) { nsresult rv; nsAutoCString lockFilePath; rv = aLockFile->GetNativePath(lockFilePath); if (NS_FAILED(rv)) { NS_ERROR("Could not get native path"); return rv; } // don't replace an existing lock time if fcntl already got one if (!mReplacedLockTime) aLockFile->GetLastModifiedTimeOfLink(&mReplacedLockTime); struct in_addr inaddr; inaddr.s_addr = htonl(INADDR_LOOPBACK); char hostname[256]; PRStatus status = PR_GetSystemInfo(PR_SI_HOSTNAME, hostname, sizeof hostname); if (status == PR_SUCCESS) { char netdbbuf[PR_NETDB_BUF_SIZE]; PRHostEnt hostent; status = PR_GetHostByName(hostname, netdbbuf, sizeof netdbbuf, &hostent); if (status == PR_SUCCESS) memcpy(&inaddr, hostent.h_addr, sizeof inaddr); } char *signature = PR_smprintf("%s:%s%lu", inet_ntoa(inaddr), aHaveFcntlLock ? "+" : "", (unsigned long)getpid()); const char *fileName = lockFilePath.get(); int symlink_rv, symlink_errno = 0, tries = 0; // use ns4.x-compatible symlinks if the FS supports them while ((symlink_rv = symlink(signature, fileName)) < 0) { symlink_errno = errno; if (symlink_errno != EEXIST) 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). (void) unlink(fileName); if (++tries > 100) break; } PR_smprintf_free(signature); signature = nullptr; if (symlink_rv == 0) { // We exclusively created the symlink: record its name for eventual // unlock-via-unlink. rv = NS_OK; mHaveLock = true; mPidLockFileName = strdup(fileName); if (mPidLockFileName) { PR_APPEND_LINK(this, &mPidLockList); if (!setupPidLockCleanup++) { // Clean up on normal termination. // This instanciates a dummy class, and will trigger the class // destructor when libxul is unloaded. This is equivalent to atexit(), // but gracefully handles dlclose(). static RemovePidLockFilesExiting r; // Clean up on abnormal termination, using POSIX sigaction. // Don't arm a handler if the signal is being ignored, e.g., // because mozilla is run via nohup. if (!sDisableSignalHandling) { struct sigaction act, oldact; #ifdef SA_SIGINFO act.sa_sigaction = FatalSignalHandler; act.sa_flags = SA_SIGINFO; #else act.sa_handler = FatalSignalHandler; #endif sigfillset(&act.sa_mask); #define CATCH_SIGNAL(signame) \ PR_BEGIN_MACRO \ if (sigaction(signame, nullptr, &oldact) == 0 && \ oldact.sa_handler != SIG_IGN) \ { \ sigaction(signame, &act, &signame##_oldact); \ } \ PR_END_MACRO CATCH_SIGNAL(SIGHUP); CATCH_SIGNAL(SIGINT); CATCH_SIGNAL(SIGQUIT); CATCH_SIGNAL(SIGILL); CATCH_SIGNAL(SIGABRT); CATCH_SIGNAL(SIGSEGV); CATCH_SIGNAL(SIGTERM); #undef CATCH_SIGNAL } } } } else if (symlink_errno == EEXIST) rv = NS_ERROR_FILE_ACCESS_DENIED; else { #ifdef DEBUG printf("symlink() failed. errno = %d\n", errno); #endif rv = NS_ERROR_FAILURE; } return rv; }
nsresult nsProfileLock::LockWithSymlink(const nsACString& lockFilePath, PRBool aHaveFcntlLock) { nsresult rv; struct in_addr inaddr; inaddr.s_addr = htonl(INADDR_LOOPBACK); char hostname[256]; PRStatus status = PR_GetSystemInfo(PR_SI_HOSTNAME, hostname, sizeof hostname); if (status == PR_SUCCESS) { char netdbbuf[PR_NETDB_BUF_SIZE]; PRHostEnt hostent; status = PR_GetHostByName(hostname, netdbbuf, sizeof netdbbuf, &hostent); if (status == PR_SUCCESS) memcpy(&inaddr, hostent.h_addr, sizeof inaddr); } char *signature = 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 = 0, tries = 0; // use ns4.x-compatible symlinks if the FS supports them while ((symlink_rv = symlink(signature, fileName)) < 0) { symlink_errno = errno; if (symlink_errno != EEXIST) 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). (void) unlink(fileName); if (++tries > 100) break; } PR_smprintf_free(signature); signature = nsnull; if (symlink_rv == 0) { // We exclusively created the symlink: record its name for eventual // unlock-via-unlink. rv = NS_OK; mHaveLock = PR_TRUE; mPidLockFileName = strdup(fileName); if (mPidLockFileName) { PR_APPEND_LINK(this, &mPidLockList); if (!setupPidLockCleanup++) { // Clean up on normal termination. atexit(RemovePidLockFilesExiting); // Clean up on abnormal termination, using POSIX sigaction. // Don't arm a handler if the signal is being ignored, e.g., // because mozilla is run via nohup. if (!sDisableSignalHandling) { struct sigaction act, oldact; #ifdef SA_SIGINFO act.sa_sigaction = FatalSignalHandler; act.sa_flags = SA_SIGINFO; #else act.sa_handler = FatalSignalHandler; #endif sigfillset(&act.sa_mask); #define CATCH_SIGNAL(signame) \ PR_BEGIN_MACRO \ if (sigaction(signame, NULL, &oldact) == 0 && \ oldact.sa_handler != SIG_IGN) \ { \ sigaction(signame, &act, &signame##_oldact); \ } \ PR_END_MACRO CATCH_SIGNAL(SIGHUP); CATCH_SIGNAL(SIGINT); CATCH_SIGNAL(SIGQUIT); CATCH_SIGNAL(SIGILL); CATCH_SIGNAL(SIGABRT); CATCH_SIGNAL(SIGSEGV); CATCH_SIGNAL(SIGTERM); #undef CATCH_SIGNAL } } } } else if (symlink_errno == EEXIST) rv = NS_ERROR_FILE_ACCESS_DENIED; else { #ifdef DEBUG printf("symlink() failed. errno = %d\n", errno); #endif rv = NS_ERROR_FAILURE; } return rv; }