X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/4f3c5f06ff074f4cd466e8d6b0c69e7b7ce7e142..668e3f703e9e7e44d55b393cfc588ec39037042c:/src/unix/snglinst.cpp diff --git a/src/unix/snglinst.cpp b/src/unix/snglinst.cpp index 8b569946b1..ef2f83ac95 100644 --- a/src/unix/snglinst.cpp +++ b/src/unix/snglinst.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Name: unix/snglinst.cpp +// Name: src/unix/snglinst.cpp // Purpose: implements wxSingleInstanceChecker class for Unix using // lock files with fcntl(2) or flock(2) // Author: Vadim Zeitlin @@ -7,7 +7,7 @@ // Created: 09.06.01 // RCS-ID: $Id$ // Copyright: (c) 2001 Vadim Zeitlin -// License: wxWindows license +// Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// // ============================================================================ @@ -18,10 +18,6 @@ // headers // ---------------------------------------------------------------------------- -#ifdef __GNUG__ - #pragma implementation "snglinst.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -35,17 +31,18 @@ #include "wx/string.h" #include "wx/log.h" #include "wx/intl.h" - #include "wx/file.h" + #include "wx/utils.h" // wxGetHomeDir() #endif //WX_PRECOMP -#include "wx/utils.h" // wxGetHomeDir() +#include "wx/file.h" #include "wx/snglinst.h" #include #include -#include +#include // for S_I[RW]USR #include // for kill() +#include #ifdef HAVE_FCNTL #include @@ -57,15 +54,28 @@ #endif // fcntl()/flock() // ---------------------------------------------------------------------------- -// private functions: (exclusively) lock/unlock the file +// constants // ---------------------------------------------------------------------------- +// argument of wxLockFile() enum LockOperation { LOCK, UNLOCK }; +// return value of CreateLockFile() +enum LockResult +{ + LOCK_ERROR = -1, + LOCK_EXISTS, + LOCK_CREATED +}; + +// ---------------------------------------------------------------------------- +// private functions: (exclusively) lock/unlock the file +// ---------------------------------------------------------------------------- + #ifdef HAVE_FCNTL static int wxLockFile(int fd, LockOperation lock) @@ -75,9 +85,9 @@ static int wxLockFile(int fd, LockOperation lock) fl.l_type = lock == LOCK ? F_WRLCK : F_UNLCK; // lock the entire file - fl.l_whence = fl.l_start = - fl.l_len = 0; + fl.l_len = + fl.l_whence = 0; // is this needed? fl.l_pid = getpid(); @@ -115,7 +125,7 @@ public: private: // try to create and lock the file - bool CreateLockFile(); + LockResult CreateLockFile(); // unlock and remove the lock file void Unlock(); @@ -134,12 +144,12 @@ private: // wxSingleInstanceCheckerImpl implementation // ============================================================================ -bool wxSingleInstanceCheckerImpl::CreateLockFile() +LockResult wxSingleInstanceCheckerImpl::CreateLockFile() { // try to open the file - m_fdLock = open(m_nameLock, + m_fdLock = open(m_nameLock.fn_str(), O_WRONLY | O_CREAT | O_EXCL, - S_IREAD | S_IWRITE); + S_IRUSR | S_IWUSR); if ( m_fdLock != -1 ) { @@ -152,7 +162,7 @@ bool wxSingleInstanceCheckerImpl::CreateLockFile() // use char here, not wxChar! char buf[256]; // enough for any PID size - int len = sprintf(buf, "%d", m_pidLocker) + 1; + int len = sprintf(buf, "%d", (int)m_pidLocker) + 1; if ( write(m_fdLock, buf, len) != len ) { @@ -161,33 +171,86 @@ bool wxSingleInstanceCheckerImpl::CreateLockFile() Unlock(); - return FALSE; + return LOCK_ERROR; } fsync(m_fdLock); - return TRUE; + // change file's permission so that only this user can access it: + if ( chmod(m_nameLock.fn_str(), S_IRUSR | S_IWUSR) != 0 ) + { + wxLogSysError(_("Failed to set permissions on lock file '%s'"), + m_nameLock.c_str()); + + Unlock(); + + return LOCK_ERROR; + } + + return LOCK_CREATED; } + else // failure: see what exactly happened + { + close(m_fdLock); + m_fdLock = -1; - // couldn't lock: this might have happened because of a race - // condition: maybe another instance opened and locked the file - // between our calls to open() and flock() - close(m_fdLock); - m_fdLock = -1; + if ( errno != EACCES && errno != EAGAIN ) + { + wxLogSysError(_("Failed to lock the lock file '%s'"), + m_nameLock.c_str()); + + unlink(m_nameLock.fn_str()); + + return LOCK_ERROR; + } + //else: couldn't lock because the lock is held by another process: + // this might have happened because of a race condition: + // maybe another instance opened and locked the file between + // our calls to open() and flock(), so don't give an error + } } // we didn't create and lock the file - return FALSE; + return LOCK_EXISTS; } bool wxSingleInstanceCheckerImpl::Create(const wxString& name) { m_nameLock = name; - if ( CreateLockFile() ) + switch ( CreateLockFile() ) { - // nothing more to do - return TRUE; + case LOCK_EXISTS: + // there is a lock file, check below if it is still valid + break; + + case LOCK_CREATED: + // nothing more to do + return true; + + case LOCK_ERROR: + // oops... + return false; + } + + // Check if the file is owned by current user and has 0600 permissions. + // If it doesn't, it's a fake file, possibly meant as a DoS attack, and + // so we refuse to touch it: + wxStructStat stats; + if ( wxStat(name, &stats) != 0 ) + { + wxLogSysError(_("Failed to inspect the lock file '%s'"), name.c_str()); + return false; + } + if ( stats.st_uid != getuid() ) + { + wxLogError(_("Lock file '%s' has incorrect owner."), name.c_str()); + return false; + } + if ( stats.st_mode != (S_IFREG | S_IRUSR | S_IWUSR) ) + { + wxLogError(_("Lock file '%s' has incorrect permissions."), name.c_str()); + return false; } // try to open the file for reading and get the PID of the process @@ -206,27 +269,27 @@ bool wxSingleInstanceCheckerImpl::Create(const wxString& name) // rarely in practice that we don't care wxLogError(_("Failed to access lock file.")); - return FALSE; + return false; } char buf[256]; - off_t count = file.Read(buf, WXSIZEOF(buf)); + ssize_t count = file.Read(buf, WXSIZEOF(buf)); if ( count == wxInvalidOffset ) { wxLogError(_("Failed to read PID from lock file.")); } else { - if ( sscanf(buf, "%d", &m_pidLocker) == 1 ) + if ( sscanf(buf, "%d", (int *)&m_pidLocker) == 1 ) { if ( kill(m_pidLocker, 0) != 0 ) { - if ( unlink(name) != 0 ) + if ( unlink(name.fn_str()) != 0 ) { wxLogError(_("Failed to remove stale lock file '%s'."), name.c_str()); - // return TRUE in this case for now... + // return true in this case for now... } else { @@ -241,11 +304,11 @@ bool wxSingleInstanceCheckerImpl::Create(const wxString& name) } else { - wxLogWarning(_("Invalid lock file '%s'.")); + wxLogWarning(_("Invalid lock file '%s'."), name.c_str()); } } - // return TRUE if we could get the PID of the process owning the lock file + // return true if we could get the PID of the process owning the lock file // (whether it is still running or not), FALSE otherwise as it is // unexpected return m_pidLocker != 0; @@ -255,7 +318,7 @@ void wxSingleInstanceCheckerImpl::Unlock() { if ( m_fdLock != -1 ) { - if ( unlink(m_nameLock) != 0 ) + if ( unlink(m_nameLock.fn_str()) != 0 ) { wxLogSysError(_("Failed to remove lock file '%s'"), m_nameLock.c_str()); @@ -285,17 +348,22 @@ bool wxSingleInstanceChecker::Create(const wxString& name, const wxString& path) { wxASSERT_MSG( !m_impl, - _T("calling wxSingleInstanceChecker::Create() twice?") ); + wxT("calling wxSingleInstanceChecker::Create() twice?") ); // must have the file name to create a lock file - wxASSERT_MSG( !name.empty(), _T("lock file name can't be empty") ); + wxASSERT_MSG( !name.empty(), wxT("lock file name can't be empty") ); m_impl = new wxSingleInstanceCheckerImpl; wxString fullname = path; if ( fullname.empty() ) { - fullname << wxGetHomeDir() << _T('/'); + fullname = wxGetHomeDir(); + } + + if ( fullname.Last() != wxT('/') ) + { + fullname += wxT('/'); } fullname << name; @@ -303,13 +371,23 @@ bool wxSingleInstanceChecker::Create(const wxString& name, return m_impl->Create(fullname); } -bool wxSingleInstanceChecker::IsAnotherRunning() const +bool wxSingleInstanceChecker::DoIsAnotherRunning() const { - wxCHECK_MSG( m_impl, FALSE, _T("must call Create() first") ); + wxCHECK_MSG( m_impl, false, wxT("must call Create() first") ); + + const pid_t lockerPid = m_impl->GetLockerPID(); + + if ( !lockerPid ) + { + // we failed to open the lock file, return false as we're definitely + // not sure that another our process is running and so it's better not + // to prevent this one from starting up + return false; + } // if another instance is running, it must own the lock file - otherwise // we have it and the locker PID is ours one - return m_impl->GetLockerPID() != getpid(); + return lockerPid != getpid(); } wxSingleInstanceChecker::~wxSingleInstanceChecker() @@ -318,4 +396,3 @@ wxSingleInstanceChecker::~wxSingleInstanceChecker() } #endif // wxUSE_SNGLINST_CHECKER -