# the library search path.
lib_LTLIBRARIES = libi2ncommon.la
include_HEADERS = containerfunc.hpp daemonfunc.hxx filefunc.hxx \
- insocketstream.hxx ip_type.hxx ipfunc.hxx logread.hxx oftmpstream.hxx pidfile.hxx \
+ insocketstream.hxx ip_type.hxx ipfunc.hxx logread.hxx oftmpstream.hxx pidfile.hpp \
pipestream.hxx stringfunc.hxx timefunc.hxx userfunc.hxx
libi2ncommon_la_SOURCES = containerfunc.cpp daemonfunc.cpp filefunc.cpp \
ipfunc.cpp logread.cpp oftmpstream.cpp pidfile.cpp stringfunc.cpp timefunc.cpp \
# example, the version is 2.1.2. (3:2:1)
libi2ncommon_la_LIBADD = @LIBGETTEXT_LIBS@ @LIBICONV_LIBS@
-_SOURCES = containerfunc.hxx
+++ /dev/null
-// for those who are used to .hxx files...
-
-#include "containerfunc.hpp"
\ No newline at end of file
-/***************************************************************************
- * Copyright (C) 2008 by Intra2net AG - Thomas Jarosch *
- * thomas.jarosch@intra2net.com *
- * http://www.intra2net.com *
- ***************************************************************************/
-#include "pidfile.hxx"
+/**
+ Pid file handling
+
+ @copyright Intra2net AG
+ @license commerical
+*/
+#include "pidfile.hpp"
#include <sys/types.h>
-#include <unistd.h>
+
#include <signal.h>
#include <fstream>
#include <sstream>
#include <iostream>
#include <stdexcept>
+#include "filefunc.hxx"
+#include <unistd.h>
+
using namespace std;
+using namespace I2n;
/**
- * Constructor. Creates the pid file. If there is already a pid file
- * with the same name it checks if the program is still alive.
- *
- * There are two ways to use this class:
- * "Throwing mode" which throws an exception if another instance is already running
- * or "non-throwing mode" where you have to check via is_already_running() if
- * the pid file got created. In any case no pid file gets written if an instance is already running.
- * Note: Don't use the throwing mode in a global variable.
+ * Constructor.
* @param filename Full path to the pid file
- * @param throw_exception Throw exception if another instance is already running
- * @param unlink_file_on_destruction Remove pid file on destruction of the object. Only useful if running as root.
+ * @param remove_file_on_destruction Remove pid file on destruction of the object. Only useful if running as root.
*/
-pidfile::pidfile(const std::string &filename, bool throw_exception, bool unlink_file_on_destruction)
+PidFile::PidFile(const std::string &filename, bool remove_file_on_destruction)
{
- this->filename = filename;
- this->unlink_file_on_destruction = unlink_file_on_destruction;
-
- already_running = false;
- already_running_pid = 0;
-
- if (!check_already_running(throw_exception)) {
- ofstream of(filename.c_str());
- of << getpid() << endl;
- }
+ Filename = filename;
+ RemoveFileOnDestruction = remove_file_on_destruction;
+ WroteFile = false;
}
/**
- * Destructor. We delete the pid file if #unlink_file_on_destruction is set.
+ * Destructor. We delete the pid file if #RemoveFileOnDestruction is set
+ * and we actually wrote a file (#WroteFile).
* This is only possible if we run with root priviledges as /var/run
* is root writable only.
*/
-pidfile::~pidfile()
+PidFile::~PidFile()
{
- if (unlink_file_on_destruction) {
- unlink(filename.c_str());
- }
+ if (RemoveFileOnDestruction && WroteFile)
+ unlink(Filename);
}
/**
- * Check if another instance is already running
- * if the constructor is used in non-throwing mode.
- * @return true if another instance is running, false otherwise
+ * Checks if the pid file for this program already exists.
+ * If yes it does a "kill" probe to see if it is alive.
+ * @param running_pid[out] Store pid number of instance if already running
+ * @return true if running, false otherweise
*/
-bool pidfile::is_already_running()
+bool PidFile::check_already_running(pid_t *running_pid)
{
- return already_running;
-}
+ // Check if there is an existing pid file
+ ifstream in(Filename.c_str());
+ if (!in)
+ return false;
-/**
- * Get already running pid. See is_already_running().
- * @return pid of the already running instance or zero if not running.
- */
-pid_t pidfile::get_already_running_pid()
-{
- return already_running_pid;
+ pid_t read_pid = 0;
+ if (!(in >> read_pid))
+ return false;
+
+ // Ok, we got an existing pid file.
+ // Check if program is still alive
+ if (kill(read_pid, 0) == 0)
+ {
+ if (running_pid)
+ *running_pid = read_pid;
+
+ // State: running
+ return true;
+ }
+
+ // Default state: not running
+ return false;
}
/**
- * Checks if the pid file for this program already exists.
- * If yes it does a "kill" probe to see if it is alive.
+ * Write pid file
+ * @return true if file was written, false otherwise
*/
-bool pidfile::check_already_running(bool throw_exception)
+bool PidFile::write()
{
- // Check if there is an existing pid file
- ifstream in(filename.c_str());
- if (!in) {
- return false;
- }
-
- pid_t read_pid = 0;
- if (!(in >> read_pid)) {
- return false;
- }
-
- // Ok, we got an existing pid file.
- // Check if program is still alive
- if (kill(read_pid, 0) == 0) {
- already_running_pid = read_pid;
- already_running = true;
-
- if (throw_exception) {
- ostringstream out;
- out << "Another instance running with pid " << read_pid << ". Aborting";
+ ofstream out(Filename.c_str());
+ if (!out)
+ return false;
- throw runtime_error(out.str());
- }
+ out << getpid() << endl;
- // State: running
- return true;
- }
+ WroteFile = true;
- // Default state: not running
- return false;
+ return true;
}
--- /dev/null
+#ifndef PIDFILE_H
+#define PIDFILE_H
+
+#include <string>
+#include <sys/types.h>
+
+/// Pid file handling
+/**
+ @copyright Intra2net AG
+ @license commerical
+*/
+class PidFile
+{
+public:
+ PidFile(const std::string &filename, bool remove_file_on_destruction=true);
+ ~PidFile();
+
+ bool check_already_running(pid_t *running_pid=NULL);
+ bool write();
+
+private:
+ /// Full path to the pid file
+ std::string Filename;
+ /// Remove pid file on destruction
+ bool RemoveFileOnDestruction;
+ /// Indicates if we wrote the file (gets set by write())
+ bool WroteFile;
+};
+
+#endif
+++ /dev/null
-/***************************************************************************
- * Copyright (C) 2008 by Intra2net AG - Thomas Jarosch *
- * thomas.jarosch@intra2net.com *
- * http://www.intra2net.com *
- ***************************************************************************/
-#ifndef PIDFILE_H
-#define PIDFILE_H
-
-#include <string>
-#include <sys/types.h>
-
-/// Pid file handling
-/**
- Creates a pid file in the constructor.
- Optionally removes it in the destructor.
-
- @author Intra2net AG - Thomas Jarosch <thomas.jarosch@intra2net.com>
-*/
-class pidfile
-{
-public:
- pidfile(const std::string &filename, bool throw_exception=true, bool remove_file_on_destruction=true);
- ~pidfile();
-
- bool is_already_running();
- pid_t get_already_running_pid();
-
-private:
- bool check_already_running(bool throw_exception);
-
-private:
- /// Full path to the pid file
- std::string filename;
- /// Remove pid file on destruction
- bool unlink_file_on_destruction;
- /// Indicates if the program is already running
- bool already_running;
- /// pid number of the already running instance. Default 0
- pid_t already_running_pid;
-};
-
-#endif
METASOURCES = AUTO
check_PROGRAMS = test
test_SOURCES = ip_range.cpp stringfunc.cpp test.cpp test_containerfunc.cpp \
- test_filefunc.cpp
+ test_filefunc.cpp test_pidfile.cpp
test_LDADD = $(top_builddir)/src/libi2ncommon.la @CPPUNIT_LIBS@
TESTS = test
--- /dev/null
+/**
+ Pid file handling unit tests
+
+ @copyright Intra2net AG
+ @license commerical
+*/
+
+#include <unistd.h>
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <stdexcept>
+
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+#include <pidfile.hpp>
+#include <filefunc.hxx>
+
+using namespace std;
+using namespace CppUnit;
+
+class TestPidFile : public TestFixture
+{
+ CPPUNIT_TEST_SUITE(TestPidFile);
+
+ CPPUNIT_TEST(WriteFile);
+ CPPUNIT_TEST(AutoRemoval);
+ CPPUNIT_TEST(NoAutoRemoval);
+ CPPUNIT_TEST(NotRunning);
+ CPPUNIT_TEST(IsAlreadyRunning);
+
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void setUp()
+ {
+ ostringstream out;
+ out << "/var/run/test_pidfile.run." << getpid();
+
+ Filename = out.str();
+ }
+
+ void tearDown()
+ {
+ }
+
+ void WriteFile()
+ {
+ PidFile pidfile(Filename);
+ bool rtn_write = pidfile.write();
+
+ CPPUNIT_ASSERT_EQUAL(rtn_write, true);
+ }
+
+ void AutoRemoval()
+ {
+ bool rtn_write = false;
+ {
+ PidFile pidfile(Filename);
+ rtn_write = pidfile.write();
+ }
+ bool exists = I2n::file_exists(Filename);
+
+ CPPUNIT_ASSERT_EQUAL(rtn_write, true);
+ CPPUNIT_ASSERT_EQUAL(exists, false);
+ }
+
+ void NoAutoRemoval()
+ {
+ bool rtn_write = false;
+ {
+ PidFile pidfile(Filename, false);
+ rtn_write = pidfile.write();
+ }
+ bool exists = I2n::file_exists(Filename);
+ I2n::unlink(Filename);
+
+ CPPUNIT_ASSERT_EQUAL(rtn_write, true);
+ CPPUNIT_ASSERT_EQUAL(exists, true);
+ }
+
+ void NotRunning()
+ {
+ PidFile pidfile(Filename);
+ bool rtn_check = pidfile.check_already_running();
+
+ CPPUNIT_ASSERT_EQUAL(rtn_check, false);
+ }
+
+ void IsAlreadyRunning()
+ {
+ PidFile pidfile1(Filename);
+ bool rtn_file1_check = pidfile1.check_already_running();
+ bool rtn_file1_write = pidfile1.write();
+
+ CPPUNIT_ASSERT_EQUAL(rtn_file1_check, false);
+ CPPUNIT_ASSERT_EQUAL(rtn_file1_write, true);
+
+ PidFile pidfile2(Filename);
+ bool rtn_file2_check = pidfile2.check_already_running();
+
+ CPPUNIT_ASSERT_EQUAL(rtn_file2_check, true);
+ }
+
+private:
+ string Filename;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TestPidFile);