changeset 782:20ca94680003

Implemented detection of running instance on linux using a lock file.
author Sascha Wilde <wilde@intevation.de>
date Mon, 14 Jul 2014 12:46:47 +0200
parents 2c69298b4188
children e65e2a0be7c8
files common/CMakeLists.txt common/linuxlockfile.c common/linuxlockfile.h ui/mainwindow.cpp ui/processhelp.h ui/processhelp_linux.cpp ui/processhelp_win.cpp
diffstat 7 files changed, 152 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- 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)
--- /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 <fcntl.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#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 */
--- /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
--- 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();
 }
 
--- 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
--- 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 <fcntl.h>
+#include <semaphore.h>
+
+#include <QDebug>
+#include <QDir>
+#include <QStandardPaths>
+
+namespace ProcessHelp
+{
+    int lockFileFD = -1;
+}
 
 const QList<int> 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 */
--- 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
-

http://wald.intevation.org/projects/trustbridge/