Commit 38563f95707b1ee5ff57fc0a6457e5d2d493c937

Authored by Wiebe Cazemier
1 parent d68708d3

Only allow one instance (per user) to run

CMakeLists.txt
@@ -35,6 +35,7 @@ add_executable(FlashMQ @@ -35,6 +35,7 @@ add_executable(FlashMQ
35 unscopedlock.cpp 35 unscopedlock.cpp
36 scopedsocket.cpp 36 scopedsocket.cpp
37 bindaddr.cpp 37 bindaddr.cpp
  38 + oneinstancelock.cpp
38 ) 39 )
39 40
40 target_link_libraries(FlashMQ pthread dl ssl crypto) 41 target_link_libraries(FlashMQ pthread dl ssl crypto)
mainapp.cpp
@@ -378,6 +378,13 @@ MainApp *MainApp::getMainApp() @@ -378,6 +378,13 @@ MainApp *MainApp::getMainApp()
378 378
379 void MainApp::start() 379 void MainApp::start()
380 { 380 {
  381 +#ifndef NDEBUG
  382 + if (fuzzFilePath.empty())
  383 + {
  384 + oneInstanceLock.lock();
  385 + }
  386 +#endif
  387 +
381 timer.start(); 388 timer.start();
382 389
383 std::map<int, std::shared_ptr<Listener>> listenerMap; // For finding listeners by fd. 390 std::map<int, std::shared_ptr<Listener>> listenerMap; // For finding listeners by fd.
@@ -516,6 +523,8 @@ void MainApp::start() @@ -516,6 +523,8 @@ void MainApp::start()
516 } 523 }
517 } 524 }
518 525
  526 + oneInstanceLock.unlock();
  527 +
519 for(std::shared_ptr<ThreadData> &thread : threads) 528 for(std::shared_ptr<ThreadData> &thread : threads)
520 { 529 {
521 thread->queueQuit(); 530 thread->queueQuit();
mainapp.h
@@ -23,6 +23,7 @@ @@ -23,6 +23,7 @@
23 #include "configfileparser.h" 23 #include "configfileparser.h"
24 #include "timer.h" 24 #include "timer.h"
25 #include "scopedsocket.h" 25 #include "scopedsocket.h"
  26 +#include "oneinstancelock.h"
26 27
27 class MainApp 28 class MainApp
28 { 29 {
@@ -44,6 +45,7 @@ class MainApp @@ -44,6 +45,7 @@ class MainApp
44 std::mutex quitMutex; 45 std::mutex quitMutex;
45 std::string fuzzFilePath; 46 std::string fuzzFilePath;
46 bool fuzzWebsockets = false; 47 bool fuzzWebsockets = false;
  48 + OneInstanceLock oneInstanceLock;
47 49
48 Logger *logger = Logger::getInstance(); 50 Logger *logger = Logger::getInstance();
49 51
oneinstancelock.cpp 0 → 100644
  1 +#include "oneinstancelock.h"
  2 +
  3 +#include <stdexcept>
  4 +
  5 +#include "utils.h"
  6 +
  7 +OneInstanceLock::OneInstanceLock()
  8 +{
  9 + std::string dir("/tmp");
  10 +
  11 + char *d = getenv("HOME");
  12 + if (d != NULL && d[0] == '/')
  13 + {
  14 + dir = std::string(d);
  15 + }
  16 + lockFilePath = dir + "/.FlashMQ.lock";
  17 +}
  18 +
  19 +OneInstanceLock::~OneInstanceLock()
  20 +{
  21 + unlock();
  22 +}
  23 +
  24 +void OneInstanceLock::lock()
  25 +{
  26 + fd = open(lockFilePath.c_str(), O_RDWR | O_CREAT, 0600);
  27 + if (fd < 0)
  28 + throw std::runtime_error(formatString("Can't create '%s': %s", lockFilePath.c_str(), strerror(errno)));
  29 +
  30 + struct flock fl;
  31 + fl.l_start = 0;
  32 + fl.l_len = 0;
  33 + fl.l_type = F_WRLCK;
  34 + fl.l_whence = SEEK_SET;
  35 + if (fcntl(fd, F_SETLK, &fl) < 0)
  36 + {
  37 + throw std::runtime_error("Can't acquire lock: another instance is already running?");
  38 + }
  39 +}
  40 +
  41 +void OneInstanceLock::unlock()
  42 +{
  43 + if (fd > 0)
  44 + {
  45 + close(fd);
  46 + fd = 0;
  47 + if (!lockFilePath.empty())
  48 + {
  49 + if (unlink(lockFilePath.c_str()) < 0)
  50 + {
  51 + logger->logf(LOG_ERR, "Can't delete '%': %s", lockFilePath.c_str(), strerror(errno));
  52 + }
  53 + lockFilePath.clear();
  54 + }
  55 + }
  56 +}
oneinstancelock.h 0 → 100644
  1 +#ifndef ONEINSTANCELOCK_H
  2 +#define ONEINSTANCELOCK_H
  3 +
  4 +#include <fcntl.h>
  5 +#include <string.h>
  6 +#include <unistd.h>
  7 +#include <string>
  8 +#include "logger.h"
  9 +
  10 +class OneInstanceLock
  11 +{
  12 + int fd = -1;
  13 + std::string lockFilePath;
  14 + Logger *logger = Logger::getInstance();
  15 +
  16 +public:
  17 + OneInstanceLock();
  18 + ~OneInstanceLock();
  19 + void lock();
  20 + void unlock();
  21 +};
  22 +
  23 +#endif // ONEINSTANCELOCK_H