# HG changeset patch # User Sascha Wilde # Date 1405334807 -7200 # Node ID 20ca946800033f3b104caccd2684059e265d90e8 # Parent 2c69298b418837eb02db957307c7bfe51d2b7f69 Implemented detection of running instance on linux using a lock file. diff -r 2c69298b4188 -r 20ca94680003 common/CMakeLists.txt --- a/common/CMakeLists.txt Thu Jul 10 19:16:21 2014 +0200 +++ b/common/CMakeLists.txt Mon Jul 14 12:46:47 2014 +0200 @@ -16,6 +16,7 @@ util.c binverify.c selftest.c + linuxlockfile.c ) if(WIN32) diff -r 2c69298b4188 -r 20ca94680003 common/linuxlockfile.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/linuxlockfile.c Mon Jul 14 12:46:47 2014 +0200 @@ -0,0 +1,72 @@ +#ifndef WIN32 + +#include +#include +#include +#include + +#include "logging.h" + +int +open_lockfile(char *path) +{ + int fd; + char pidstr[20]; + size_t pidstrlen; + struct flock lk; + fd = open(path, O_RDWR | O_CREAT, 0600); + if (fd != -1) + { + /* Get an exclusive lock on the whole file. */ + lk.l_type = F_WRLCK; + lk.l_whence = SEEK_SET; + lk.l_start = 0; + lk.l_len = 0; + if (fcntl(fd, F_SETLK, &lk) != -1) + { + /* FIXME: For extra security we should check if there is + already a pid in the file. If so we should check in + /proc/$PID if there is still a process of the same name + as ours running... */ + ftruncate(fd, 0); + pidstrlen = (size_t)snprintf(pidstr, sizeof(pidstr), "%d", getpid()); + write(fd, pidstr, pidstrlen); + } + else + { + /* Lock can not be acquired. Bail out... */ + close(fd); + DEBUGPRINTF("Could not get an exclusive lock on %s.\n", path); + return -1; + } + } + else + { + DEBUGPRINTF("Failed to open lock file: %s.\n", path); + } + return fd; +} + +void +close_lockfile(int fd) +{ + struct flock lk; + + /* Delete the PID from file. */ + /* We do this instead of trying to unlink the file. */ + ftruncate(fd, 0); + + /* Remove lock from the file. */ + lk.l_type = F_UNLCK; + lk.l_whence = SEEK_SET; + lk.l_start = 0; + lk.l_len = 0; + if (fcntl(fd, F_SETLK, &lk) == -1) + { + /* Lock can not be removed?!? WTF? */ + DEBUGPRINTF("Could not remove lock from pid file. STRANGE!\n"); + } + close(fd); +} + +#endif /* Not WIN32 */ diff -r 2c69298b4188 -r 20ca94680003 common/linuxlockfile.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/linuxlockfile.h Mon Jul 14 12:46:47 2014 +0200 @@ -0,0 +1,38 @@ +/** + * @file linuxlockfile.h + * @brief Linux specific functions for lock file handling. + * @details Functions to handle procsss specific lock files, these are + * only used on GNU Linux as on windows different mechanisms are + * utilized to ensure only a single instance runs at a time. + */ + +#ifndef LINUXLOCKFILE_H +#define LINUXLOCKFILE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief create a lockfile + * @details create and lock a lockfile containing the pid of the + * current process. fcntl is used for locking, to work in most cases + * (e.g. NFS). + * @param[in] path to the lockfile + * @returns the file descriptor of the lockfile or -1 on error + */ +int open_lockfile(char *path); + +/** + * @brief close a lockfile + * @details unlock and close a lockfile for the given file descriptor. + * @param[in] path to the lockfile + * @returns the file descriptor of the lockfile or -1 on error + */ +void close_lockfile(int fd); + +#ifdef __cplusplus +} +#endif + +#endif diff -r 2c69298b4188 -r 20ca94680003 ui/mainwindow.cpp --- a/ui/mainwindow.cpp Thu Jul 10 19:16:21 2014 +0200 +++ b/ui/mainwindow.cpp Mon Jul 14 12:46:47 2014 +0200 @@ -1172,6 +1172,7 @@ void MainWindow::closeApp() { + ProcessHelp::cleanUp(); qApp->quit(); } diff -r 2c69298b4188 -r 20ca94680003 ui/processhelp.h --- a/ui/processhelp.h Thu Jul 10 19:16:21 2014 +0200 +++ b/ui/processhelp.h Mon Jul 14 12:46:47 2014 +0200 @@ -45,5 +45,11 @@ * @param [in] executableName executableName (without path and .exe extension) */ void activateWindowForProcess(const QString &executableName); + +/** +* @brief Clean up internaly used infrastructure like pid/lock files. +*/ + void cleanUp(void); } + #endif // PROCESSHELP_H diff -r 2c69298b4188 -r 20ca94680003 ui/processhelp_linux.cpp --- a/ui/processhelp_linux.cpp Thu Jul 10 19:16:21 2014 +0200 +++ b/ui/processhelp_linux.cpp Mon Jul 14 12:46:47 2014 +0200 @@ -8,6 +8,19 @@ #ifndef WIN32 #include "processhelp.h" +#include "linuxlockfile.h" + +#include +#include + +#include +#include +#include + +namespace ProcessHelp +{ + int lockFileFD = -1; +} const QList ProcessHelp::getProcessesIdForName(const QString &processName) { // TODO @@ -16,8 +29,17 @@ } bool ProcessHelp::otherProcessesExist(const QString &processName) { - // TODO - Q_UNUSED(processName); + // FIXME: We are using lock file semantics on GNU Linux so the + // name of this method is rather misleading. + + QDir dataDir(QStandardPaths::writableLocation(QStandardPaths::DataLocation)); + dataDir.mkpath("."); + QString lockFilePath = dataDir.filePath(processName + ".pid"); + lockFileFD = open_lockfile(lockFilePath.toLocal8Bit().data()); + if (lockFileFD == -1) + // Creating the lock file failed, so we assume another + // instance is runnning. + return true; return false; } @@ -27,4 +49,8 @@ return; } +void ProcessHelp::cleanUp() { + close_lockfile(lockFileFD); +} + #endif /* Not WIN32 */ diff -r 2c69298b4188 -r 20ca94680003 ui/processhelp_win.cpp --- a/ui/processhelp_win.cpp Thu Jul 10 19:16:21 2014 +0200 +++ b/ui/processhelp_win.cpp Mon Jul 14 12:46:47 2014 +0200 @@ -130,5 +130,10 @@ } SetForegroundWindow(winStruct.windowId); } + +void ProcessHelp::cleanUp() { + // Nothing to do on Windows. + return; +} + #endif // WIN32 -