From bfe781cd36fff56b8f54747aabac47776554c34d Mon Sep 17 00:00:00 2001
From: Eric Cano <Eric.Cano@cern.ch>
Date: Thu, 11 Feb 2016 18:54:37 +0100
Subject: [PATCH] Created the embryo of the new cta-taped daemon, importing
 many daemon utilities from castor in the exercise.

---
 CMakeLists.txt                                |  10 +
 common/CMakeLists.txt                         |  38 +-
 common/Configuration.cpp                      | 330 ++++++++++++
 common/Configuration.hpp                      | 270 ++++++++++
 common/ProcessCap.cpp                         | 135 +++++
 common/exception/Errnum.cpp                   |   2 +-
 common/exception/Errnum.hpp                   |   2 +-
 common/exception/Exception.hpp                | 210 ++++----
 common/exception/Serrnum.cpp                  |  68 ---
 common/exception/Serrnum.hpp                  |  44 --
 common/log/CMakeLists.txt                     |  23 +
 common/log/DummyLogger.cpp                    |  95 ++++
 common/log/DummyLogger.hpp                    | 159 ++++++
 common/log/LogContext.cpp                     | 114 ++++
 common/log/LogContext.hpp                     | 164 ++++++
 common/log/LogContextTest.cpp                 |  72 +++
 common/log/Logger.cpp                         |  44 ++
 common/log/Logger.hpp                         | 293 +++++++++++
 common/log/Message.cpp                        |  26 +
 common/log/Message.hpp                        |  47 ++
 common/log/Param.cpp                          |  40 ++
 common/log/Param.hpp                          | 108 ++++
 common/log/ParamTest.cpp                      |  59 +++
 common/log/StringLogger.cpp                   | 324 ++++++++++++
 common/log/StringLogger.hpp                   | 385 ++++++++++++++
 common/log/StringLoggerTest.cpp               |  37 ++
 common/log/SyslogLogger.cpp                   | 493 ++++++++++++++++++
 common/log/SyslogLogger.hpp                   | 474 +++++++++++++++++
 common/log/SyslogLoggerTest.cpp               | 149 ++++++
 common/log/TestingSyslogLogger.hpp            |  46 ++
 common/processCap/ProcessCap.cpp              | 138 +++++
 common/processCap/ProcessCap.hpp              |  98 ++++
 common/processCap/ProcessCapDummy.cpp         |  45 ++
 common/processCap/ProcessCapDummy.hpp         |  73 +++
 common/processCap/SmartCap.cpp                |  97 ++++
 common/processCap/SmartCap.hpp                | 119 +++++
 common/processCap/SmartCapTest.cpp            |  88 ++++
 common/threading/Daemon.cpp                   | 202 +++++++
 common/threading/Daemon.hpp                   | 140 +++++
 common/threading/DaemonTest.cpp               | 101 ++++
 common/threading/MutexLocker.hpp              |  64 +++
 common/threading/System.cpp                   | 193 +++++++
 common/threading/System.hpp                   |  64 +++
 common/{ => utils}/Utils.cpp                  |  86 ++-
 common/{ => utils}/Utils.hpp                  |  38 ++
 common/{ => utils}/UtilsTest.cpp              | 134 ++++-
 common/{ => utils}/strerror_r_wrapper.cpp     |   2 +-
 common/{ => utils}/strerror_r_wrapper.hpp     |   0
 nameserver/mockNS/MockNameServer.cpp          |   2 +-
 .../mockNS/makeMockNameServerBasePath.cpp     |   2 +-
 objectstore/BackendFactory.cpp                |   2 +-
 objectstore/BackendVFS.cpp                    |   2 +-
 remotens/EosNS.cpp                            |   2 +-
 remotens/MockRemoteNS.cpp                     |   2 +-
 scheduler/Scheduler.cpp                       |   3 +-
 scheduler/_old_prototype_DummyScheduler.cpp   |   2 +-
 tapeserver/CMakeLists.txt                     |   8 +
 tapeserver/castor/exception/Errnum.cpp        |   2 +-
 tapeserver/castor/io/IoTest.cpp               |   2 +-
 tapeserver/castor/io/io.cpp                   |   2 +-
 {common => tapeserver/castor/io}/marshall.h   |   0
 tapeserver/castor/messages/messages.cpp       |   2 +-
 tapeserver/castor/server/ProcessCap.cpp       |  12 +-
 tapeserver/castor/server/ProcessCap.hpp       |  25 +-
 .../tape/tapeserver/daemon/CMakeLists.txt     |   4 +-
 .../daemon/DataTransferSessionTest.cpp        |   2 +-
 .../tape/tapeserver/daemon/ProcessForker.cpp  |   2 +-
 tapeserver/castor/utils/utils.cpp             |   4 +-
 tapeserver/cta-taped.cpp                      | 197 +++++++
 .../tapeserverd.init => cta-taped.init}       |   0
 ...r-server.logrotate => cta-taped.logrotate} |   0
 .../daemon/tapeserverd.man => cta-taped.man}  |   0
 ...eserverd.sysconfig => cta-taped.sysconfig} |   0
 tapeserver/daemon/CMakeLists.txt              |   7 +
 tapeserver/daemon/DriveConfiguration.hpp      |  96 ++++
 tapeserver/daemon/GlobalConfiguration.cpp     |  36 ++
 tapeserver/daemon/GlobalConfiguration.hpp     |  47 ++
 tapeserver/daemon/TapeDaemon.cpp              | 172 ++++++
 tapeserver/daemon/TapeDaemon.hpp              | 266 ++++++++++
 tapeserver/daemon/TpconfigLine.cpp            |  33 ++
 tapeserver/daemon/TpconfigLine.hpp            |  69 +++
 tapeserver/daemon/TpconfigLines.cpp           | 167 ++++++
 tapeserver/daemon/TpconfigLines.hpp           |  44 ++
 version.hpp.in                                |  22 +
 84 files changed, 6905 insertions(+), 276 deletions(-)
 create mode 100644 common/Configuration.cpp
 create mode 100644 common/Configuration.hpp
 create mode 100644 common/ProcessCap.cpp
 delete mode 100644 common/exception/Serrnum.cpp
 delete mode 100644 common/exception/Serrnum.hpp
 create mode 100644 common/log/CMakeLists.txt
 create mode 100644 common/log/DummyLogger.cpp
 create mode 100644 common/log/DummyLogger.hpp
 create mode 100644 common/log/LogContext.cpp
 create mode 100644 common/log/LogContext.hpp
 create mode 100644 common/log/LogContextTest.cpp
 create mode 100644 common/log/Logger.cpp
 create mode 100644 common/log/Logger.hpp
 create mode 100644 common/log/Message.cpp
 create mode 100644 common/log/Message.hpp
 create mode 100644 common/log/Param.cpp
 create mode 100644 common/log/Param.hpp
 create mode 100644 common/log/ParamTest.cpp
 create mode 100644 common/log/StringLogger.cpp
 create mode 100644 common/log/StringLogger.hpp
 create mode 100644 common/log/StringLoggerTest.cpp
 create mode 100644 common/log/SyslogLogger.cpp
 create mode 100644 common/log/SyslogLogger.hpp
 create mode 100644 common/log/SyslogLoggerTest.cpp
 create mode 100644 common/log/TestingSyslogLogger.hpp
 create mode 100644 common/processCap/ProcessCap.cpp
 create mode 100644 common/processCap/ProcessCap.hpp
 create mode 100644 common/processCap/ProcessCapDummy.cpp
 create mode 100644 common/processCap/ProcessCapDummy.hpp
 create mode 100644 common/processCap/SmartCap.cpp
 create mode 100644 common/processCap/SmartCap.hpp
 create mode 100644 common/processCap/SmartCapTest.cpp
 create mode 100644 common/threading/Daemon.cpp
 create mode 100644 common/threading/Daemon.hpp
 create mode 100644 common/threading/DaemonTest.cpp
 create mode 100644 common/threading/MutexLocker.hpp
 create mode 100644 common/threading/System.cpp
 create mode 100644 common/threading/System.hpp
 rename common/{ => utils}/Utils.cpp (86%)
 rename common/{ => utils}/Utils.hpp (82%)
 rename common/{ => utils}/UtilsTest.cpp (73%)
 rename common/{ => utils}/strerror_r_wrapper.cpp (96%)
 rename common/{ => utils}/strerror_r_wrapper.hpp (100%)
 rename {common => tapeserver/castor/io}/marshall.h (100%)
 create mode 100644 tapeserver/cta-taped.cpp
 rename tapeserver/{castor/tape/tapeserver/daemon/tapeserverd.init => cta-taped.init} (100%)
 rename tapeserver/{castor/tape/tapeserver/daemon/castor-tapeserver-server.logrotate => cta-taped.logrotate} (100%)
 rename tapeserver/{castor/tape/tapeserver/daemon/tapeserverd.man => cta-taped.man} (100%)
 rename tapeserver/{castor/tape/tapeserver/daemon/tapeserverd.sysconfig => cta-taped.sysconfig} (100%)
 create mode 100644 tapeserver/daemon/CMakeLists.txt
 create mode 100644 tapeserver/daemon/DriveConfiguration.hpp
 create mode 100644 tapeserver/daemon/GlobalConfiguration.cpp
 create mode 100644 tapeserver/daemon/GlobalConfiguration.hpp
 create mode 100644 tapeserver/daemon/TapeDaemon.cpp
 create mode 100644 tapeserver/daemon/TapeDaemon.hpp
 create mode 100644 tapeserver/daemon/TpconfigLine.cpp
 create mode 100644 tapeserver/daemon/TpconfigLine.hpp
 create mode 100644 tapeserver/daemon/TpconfigLines.cpp
 create mode 100644 tapeserver/daemon/TpconfigLines.hpp
 create mode 100644 version.hpp.in

diff --git a/CMakeLists.txt b/CMakeLists.txt
index de23a79950..fa45613cd3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,6 +11,12 @@ set(CMAKE_C_FLAGS "-fPIC -pedantic -Wall -Wextra -Werror -Wno-unused-parameter")
 #
 #   ClientSimulator.hpp:65: error: ISO C++ prohibits anonymous structs
 set(CMAKE_CXX_FLAGS "-fPIC -pedantic -Wall -Wextra -Werror -Wno-unused-parameter -Wno-long-long -std=c++0x -fms-extensions -fstack-protector-all")
+#
+# A maximalist error checking parameter combo has been suggested by S. Ponce and D. Come:
+# to be tested once we have a stable compilation on CC7:
+#-Wno-unused-parameter -Wlogical-op -Wfloat-equal -Wdeclaration-after- statement -Wundef -Wno-endif-labels -Wshadow -Wunsafe-loop- optimizations -Wpointer-arith -Wbad-function-cast -Wcast-align -Wwrite- strings -Wconversion -Wmissing-field-initializers -Wredundant-decls -Wnested-externs -Wunreachable-code -Winline -Wvariadic-macros -Wtraditional -Wmissing-prototypes -Wmissing-declarations -Wold-style- definition -Wc++-compat -Wstrict-prototypes -Wpadded -Wcast-qual -Wnon-virtual-dtor -Wlogical-op -Wmissing-declarations -Wsign-conversion -Wredundant-decls -Wold-style-cast -Wshadow
+
+
 
 
 # Explicitly setting the C and C++ compiler flags for the RelWithDebInfo build
@@ -77,6 +83,10 @@ ELSE(DEFINED PackageOnly)
   add_subdirectory(tapeserver)
   add_subdirectory(tests)
   add_subdirectory(xroot_plugins)
+  
+  #Generate version information
+  configure_file(${PROJECT_SOURCE_DIR}/version.hpp.in
+    ${CMAKE_BINARY_DIR}/version.h)
 ENDIF(DEFINED PackageOnly)
 
 ################################################################################
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index e51c291224..ff3fc504d0 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -45,30 +45,41 @@ set (COMMON_LIB_SRC_FILES
   archiveNS/StorageClass.cpp
   archiveNS/Tape.cpp
   archiveNS/TapeFileLocation.cpp
-  ArchiveRequest.cpp
-  CreationLog.cpp
   checksum/Checksum.cpp
   exception/Backtrace.cpp
   exception/DiskException.hpp
   exception/Errnum.cpp
   exception/Exception.cpp
-  exception/Serrnum.cpp
   exception/TapeException.cpp
+  log/DummyLogger.cpp
+  log/LogContext.cpp
+  log/Logger.cpp
+  log/Message.cpp
+  log/Param.cpp
+  log/StringLogger.cpp
+  log/SyslogLogger.cpp
   priorities/DriveQuota.cpp
   priorities/MountCriteria.cpp
   priorities/UserGroup.cpp
+  processCap/ProcessCap.cpp
+  processCap/SmartCap.cpp
   remoteFS/RemoteFileStatus.cpp
   remoteFS/RemotePath.cpp
   remoteFS/RemotePathAndStatus.cpp
-  SecurityIdentity.cpp
-  strerror_r_wrapper.cpp
-  TapePool.cpp
-  Timer.cpp
   threading/ChildProcess.cpp
+  threading/Daemon.cpp
   threading/Mutex.cpp
+  threading/System.cpp
   threading/Threading.cpp
+  utils/Utils.cpp
+  utils/strerror_r_wrapper.cpp
+  ArchiveRequest.cpp
+  CreationLog.cpp
+  Configuration.cpp
+  SecurityIdentity.cpp
+  TapePool.cpp
+  Timer.cpp
   UserIdentity.cpp
-  Utils.cpp
   VO.cpp)
 
 add_library (ctacommon SHARED
@@ -81,13 +92,18 @@ target_link_libraries (ctacommon
   ${SQLITE3_LIBRARY_RELEASE}
   uuid
   z
-  Utils)
+  Utils
+  cap)
 
 set (COMMON_UNIT_TESTS_LIB_SRC_FILES
   checksum/ChecksumTest.cpp
+  log/LogContextTest.cpp
+  log/ParamTest.cpp
+  log/SyslogLoggerTest.cpp
   remoteFS/RemotePathTest.cpp
-  UserIdentityTest.cpp
-  UtilsTest.cpp)
+  threading/DaemonTest.cpp
+  utils/UtilsTest.cpp
+  UserIdentityTest.cpp)
 
 add_library (ctacommonunittests SHARED
   ${COMMON_UNIT_TESTS_LIB_SRC_FILES})
diff --git a/common/Configuration.cpp b/common/Configuration.cpp
new file mode 100644
index 0000000000..4e3dc12fa3
--- /dev/null
+++ b/common/Configuration.cpp
@@ -0,0 +1,330 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Configuration.hpp"
+#include "common/exception/Errnum.hpp"
+
+#include <algorithm>
+#include <fstream>
+#include <errno.h>
+
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+cta::common::Configuration::Configuration(std::string fileName)
+   : m_fileName(fileName),
+  m_lastUpdateTime(0) {
+  // create internal r/w lock
+  int rc = pthread_rwlock_init(&m_lock, NULL);
+  if (0 != rc) {
+    cta::exception::Errnum e(rc);
+    e.getMessage() << "CastorConfiguration constructor Failed"
+      ": Failed to create internal r/w lock";
+    throw e;
+  }
+}
+
+//------------------------------------------------------------------------------
+// copy constructor
+//------------------------------------------------------------------------------
+cta::common::Configuration::Configuration(
+  const Configuration & other) :
+  m_fileName(other.m_fileName), m_lastUpdateTime(other.m_lastUpdateTime),
+  m_config(other.m_config) {
+  // create a new internal r/w lock
+  int rc = pthread_rwlock_init(&m_lock, NULL);
+  if (0 != rc) {
+    cta::exception::Errnum e(rc);
+    e.getMessage() << "CastorConfiguration copy constructor failed"
+      ": Failed to create a new internal r/w lock";
+    throw e;
+  }
+}
+
+//------------------------------------------------------------------------------
+// destructor
+//------------------------------------------------------------------------------
+cta::common::Configuration::~Configuration() {
+  // relase read write lock
+  pthread_rwlock_destroy(&m_lock);
+}
+
+//------------------------------------------------------------------------------
+// assignment operator
+//------------------------------------------------------------------------------
+cta::common::Configuration &
+  cta::common::Configuration::operator=(
+    const cta::common::Configuration & other)
+   {
+  m_fileName = other.m_fileName;
+  m_lastUpdateTime = other.m_lastUpdateTime;
+  m_config = other.m_config;
+  // create a new internal r/w lock
+  int rc = pthread_rwlock_init(&m_lock, NULL);
+  if (0 != rc) {
+    cta::exception::Errnum e(rc);
+    e.getMessage() << "Assignment operator of CastorConfiguration object failed"
+      ": Failed to create a new internal r/w lock";
+    throw e;
+  }
+  return *this;
+}
+
+//------------------------------------------------------------------------------
+// getConfEntString
+//------------------------------------------------------------------------------
+const std::string& cta::common::Configuration::getConfEntString(
+  const std::string &category, const std::string &key,
+  const std::string &defaultValue, log::Logger *const log) {
+  try {
+    if (isStale()) {
+      tryToRenewConfig();
+    }
+    // get read lock
+    int rc = pthread_rwlock_rdlock(&m_lock);
+    if (0 != rc) {
+      cta::exception::Errnum e(rc);
+      e.getMessage() << "Failed to get configuration entry " << category << ":"
+                     << key << ": Failed to get read lock";
+      throw e;
+    }
+    // get the entry
+    std::map<std::string, ConfCategory>::const_iterator catIt = m_config.find(category);
+    if (m_config.end() != catIt) {
+      // get the entry
+      ConfCategory::const_iterator entIt = catIt->second.find(key);
+      if (catIt->second.end() != entIt) {
+        // release the lock
+        pthread_rwlock_unlock(&m_lock);
+        if(NULL != log) {           
+          log::Param params[] = {   
+            log::Param("category", category),
+            log::Param("key", key),
+            log::Param("value", entIt->second),
+            log::Param("source", m_fileName)};
+          (*log)(LOG_INFO, "Configuration entry", params);
+        }
+        return entIt->second;
+      }
+    }
+    // no entry found
+    if(NULL != log) {
+      log::Param params[] = {
+        log::Param("category", category),
+        log::Param("key", key),
+        log::Param("value", defaultValue),
+        log::Param("source", "DEFAULT")};
+      (*log)(LOG_INFO, "Configuration entry", params);
+    }
+    // Unlock and return default
+    pthread_rwlock_unlock(&m_lock);
+  } catch (cta::exception::Exception ex) {
+    // exception caught : Unlock and return default
+    pthread_rwlock_unlock(&m_lock);
+    // log the exception
+    if(NULL != log) {
+      log::Param params[] = {
+        log::Param("category", category),
+        log::Param("key", key),
+        log::Param("value", defaultValue),
+        log::Param("source", "DEFAULT")};
+      (*log)(LOG_INFO, "Configuration entry", params);
+    }
+  } catch (...) {
+    // release the lock
+    pthread_rwlock_unlock(&m_lock);
+    throw;
+  }
+  return defaultValue;
+}
+
+//------------------------------------------------------------------------------
+// getConfEntString
+//------------------------------------------------------------------------------
+const std::string& cta::common::Configuration::getConfEntString(
+  const std::string &category, const std::string &key, log::Logger *const log) {
+  // check whether we need to reload the configuration
+  if (isStale()) {
+    tryToRenewConfig();
+  }
+  // get read lock
+  int rc = pthread_rwlock_rdlock(&m_lock);
+  if (0 != rc) {
+    cta::exception::Errnum e(rc);
+    e.getMessage() << "Failed to get configuration entry " << category << ":"
+      << key << ": Failed to get read lock";
+    throw e;
+  }
+  // get the entry
+  try {
+    std::map<std::string, ConfCategory>::const_iterator catIt =
+      m_config.find(category);
+    if (m_config.end() == catIt) {
+      NoEntry e;
+      e.getMessage() << "Failed to get configuration entry " << category << ":"
+        << key << ": Failed to find " << category << " category";
+      throw e;
+    }
+    // get the entry
+    ConfCategory::const_iterator entIt = catIt->second.find(key);
+    if (catIt->second.end() == entIt) {
+      NoEntry e;
+      e.getMessage() << "Failed to get configuration entry " << category << ":"
+        << key << ": Failed to find " << key << " key";
+      throw e;
+    }
+
+    if(NULL != log) {
+      log::Param params[] = {
+        log::Param("category", category),
+        log::Param("key", key),
+        log::Param("value", entIt->second),
+        log::Param("source", m_fileName)};
+      (*log)(LOG_INFO, "Configuration entry", params);
+    }
+
+    // release the lock
+    pthread_rwlock_unlock(&m_lock);
+    return entIt->second;
+  } catch (...) {
+    // release the lock
+    pthread_rwlock_unlock(&m_lock);
+    throw;
+  }
+}
+
+//------------------------------------------------------------------------------
+// isStale
+//------------------------------------------------------------------------------
+bool cta::common::Configuration::isStale()
+   {
+  // get read lock
+  int rc = pthread_rwlock_rdlock(&m_lock);
+  if (0 != rc) {
+    cta::exception::Errnum e(rc);
+    e.getMessage() << "Failed to determine if CASTOR configuration is stale"
+      ": Failed to get read lock";
+    throw e;
+  }
+  try {
+    // get the timeout
+    int timeout = getTimeoutNolock();
+    // release the lock
+    pthread_rwlock_unlock(&m_lock);
+    // return whether we should renew  
+    return time(0) > m_lastUpdateTime + timeout;
+  } catch (...) {
+    // release the lock
+    pthread_rwlock_unlock(&m_lock);
+    throw;
+  }   
+}
+
+//------------------------------------------------------------------------------
+// tryToRenewConfig
+//------------------------------------------------------------------------------
+void cta::common::Configuration::tryToRenewConfig()
+   {
+  // we should probably renew. First take the write lock.
+  int rc = pthread_rwlock_wrlock(&m_lock);
+  if (0 != rc) {
+    cta::exception::Errnum e(rc);
+    e.getMessage() << "Failed to renew configuration cache"
+      ": Failed to take write lock";
+    throw e;
+  }
+  // now check that we should really renew, because someone may have done it
+  // while we waited for the lock
+  try {
+    if (time(0) > m_lastUpdateTime + getTimeoutNolock()) {
+      // now we should really renew
+      renewConfigNolock();
+    }
+  } catch (...) {
+    // release the lock
+    pthread_rwlock_unlock(&m_lock);
+    throw;
+  }
+  // release the lock
+  pthread_rwlock_unlock(&m_lock);
+  return;
+}
+
+//------------------------------------------------------------------------------
+// getTimeoutNolock
+//------------------------------------------------------------------------------
+int cta::common::Configuration::getTimeoutNolock()
+   {
+  // start with the default (300s = 5mn)
+  int timeout = 300;
+  // get value from config
+  std::map<std::string, ConfCategory>::const_iterator catIt =
+    m_config.find("Config");
+  if (m_config.end() != catIt) {
+    ConfCategory::const_iterator entIt = catIt->second.find("ExpirationDelay");
+    if (catIt->second.end() != entIt) {
+      // parse the timeout into an integer
+      timeout = atoi(entIt->second.c_str());
+    }
+  }
+  // return timeout
+  return timeout;
+}
+
+//------------------------------------------------------------------------------
+// renewConfigNolock
+//------------------------------------------------------------------------------
+void cta::common::Configuration::renewConfigNolock()
+   {
+  // reset the config
+  m_config.clear();
+
+  // try to open the configuration file, throwing an exception if there is a
+  // failure
+  std::ifstream file(m_fileName.c_str());
+  if(file.fail()) {
+    cta::exception::Errnum ex(EIO);
+    ex.getMessage() << __FUNCTION__ << " failed"
+      ": Failed to open file"
+      ": m_fileName=" << m_fileName;
+    throw ex;
+  }
+
+  std::string line;
+  while(std::getline(file, line)) {
+    // get rid of potential tabs
+    std::replace(line.begin(),line.end(),'\t',' ');
+    // get the category
+    std::istringstream sline(line);
+    std::string category;
+    if (!(sline >> category)) continue; // empty line
+    if (category[0] == '#') continue;   // comment
+    // get the key
+    std::string key;
+    if (!(sline >> key)) continue;      // no key on line
+    if (key[0] == '#') continue;        // key commented
+    // get and store value
+    while (sline.get() == ' '){}; sline.unget(); // skip spaces
+    std::string value;
+    std::getline(sline, value, '#');
+    value.erase(value.find_last_not_of(" \n\r\t")+1); // right trim
+    m_config[category][key] = value;
+  }
+  m_lastUpdateTime = time(0);
+}
diff --git a/common/Configuration.hpp b/common/Configuration.hpp
new file mode 100644
index 0000000000..c69ac2f180
--- /dev/null
+++ b/common/Configuration.hpp
@@ -0,0 +1,270 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "common/exception/Exception.hpp"
+#include "common/log/Logger.hpp"
+#include "common/utils/Utils.hpp"
+
+#include <string>
+#include <map>
+
+namespace cta { namespace common {
+    
+    /**
+     * represents a category from the CTA configuration file
+     */
+    typedef std::map<std::string, std::string> ConfCategory;
+
+    /**
+     * a class representing the configuration of castor.
+     * This configurations is obtained from the local file given in the
+     * constructor and will be updated regularly. The time between two
+     * updates is taken from the Config/ExpirationDelay entry of the
+     * configuration itself and defaults to 5mn if no such entry is found
+     */
+    class Configuration {
+
+    public:
+      
+      /**
+       * Private exceptions for this 
+       */
+      CTA_GENERATE_EXCEPTION_CLASS(InvalidConfigEntry);
+      CTA_GENERATE_EXCEPTION_CLASS(NoEntry);
+        
+    public:
+      
+      /**
+       * constructor
+       * @param fileName the file that should be used to build the configuration
+       */
+      Configuration(std::string fileName = "/etc/cta/cta.conf");
+
+      /**
+       * copy constructor
+       * @param other instance of CastorConfiguration class
+       */
+      Configuration(const Configuration & other);
+
+      /**
+       * destructor
+       */
+      virtual ~Configuration();
+
+      /**
+       * assignment operator
+       * @param other instance of CastorConfiguration class
+       */
+      Configuration & operator=(const Configuration & other);
+
+      /**
+       * Retrieves a configuration entry.
+       *
+       * If this method is passed a logger object then it will log the value
+       * of the configuration entry together with an indication of whether the
+       * value was found in the castor configuration file or whether the
+       * specified default value was used instead.
+       *
+       * @param category the category of the entry
+       * @param key the key of the entry
+       * @param defaultValue the value to be returned if the configuration entry
+       * is not in the configuration file
+       * @param log pointer to NULL or an optional logger object
+       */
+      const std::string& getConfEntString(const std::string &category,
+        const std::string &key, const std::string &defaultValue,
+        log::Logger *const log = NULL);
+
+      /**
+       * Retrieves a configuration entry.
+       *
+       * Besides other possible exceptions, this method throws a
+       * castor::exception::NoEntry exception if the specified configuration
+       * entry is not in the configuration file.
+       *
+       * If this method is passed a logger object then this method will log the
+       * the value of the configuration entry.
+       *
+       * @param category the category of the entry
+       * @param key the key of the entry
+       * @param log pointer to NULL or an optional logger object
+       */
+      const std::string& getConfEntString(const std::string &category,
+        const std::string &key, log::Logger *const log = NULL);
+
+      /**
+       * Retrieves a configuration entry as an integer.
+       *
+       * If this method is passed a logger object then it will log the value
+       * of the configuration entry together with an indication of whether the
+       * value was found in the castor configuration file or whether the
+       * specified default value was used instead.
+       *
+       * @param category category of the configuration parameter
+       * @param name category of the configuration parameter
+       * @param defaultValue the value to be returned if the configuration entry
+       * is not in the configuration file
+       * @param log pointer to NULL or an optional logger object
+       * @return the integer value
+       */
+      template<typename T> T getConfEntInt(const std::string &category,
+        const std::string &key, const T defaultValue,
+        log::Logger *const log = NULL)  {
+        std::string strValue;
+        try {
+          strValue = getConfEntString(category, key);
+        } catch(cta::exception::Exception &ex) {
+          if(NULL != log) {
+            log::Param params[] = {
+              log::Param("category", category),
+              log::Param("key", key),
+              log::Param("value", defaultValue),
+              log::Param("source", "DEFAULT")};
+            (*log)(LOG_INFO, "Configuration entry", params);
+          }
+          return defaultValue;
+        }
+
+        if (!Utils::isValidUInt(strValue.c_str())) {
+          InvalidConfigEntry ex(category.c_str(),
+            key.c_str(), strValue.c_str());
+          ex.getMessage() << "Failed to get configuration entry " << category <<
+            ":" << key << ": Value is not a valid unsigned integer: value=" <<
+            strValue;
+          throw ex;
+        }
+
+        T value;
+        std::stringstream ss;
+        ss << strValue.c_str();
+        ss >> value;
+
+        if(NULL != log) {
+          log::Param params[] = {
+            log::Param("category", category),
+            log::Param("key", key),
+            log::Param("value", value),
+            log::Param("source", m_fileName)};
+          (*log)(LOG_INFO, "Configuration entry", params);
+        }
+
+        return value;
+      }
+
+      /**
+       * Retrieves a configuration entry as an integer.
+       *
+       * Besides other possible exceptions, this method throws a
+       * castor::exception::NoEntry exception if the specified configuration
+       * entry is not in the configuration file.
+       *
+       * @param category category of the configuration parameter
+       * @param name category of the configuration parameter
+       * @param log pointer to NULL or an optional logger object
+       * @return the integer value
+       */
+      template<typename T> T getConfEntInt(const std::string &category,
+        const std::string &key, log::Logger *const log = NULL)  {
+        const std::string strValue = getConfEntString(category, key);
+
+        if (!Utils::isValidUInt(strValue.c_str())) {
+          InvalidConfigEntry ex(category.c_str(),
+            key.c_str(), strValue.c_str());
+          ex.getMessage() << "Failed to get configuration entry " << category <<
+            ":" << key << ": Value is not a valid unsigned integer: value=" <<
+            strValue;
+          throw ex;
+        }
+
+        T value;
+        std::stringstream ss;
+        ss << strValue.c_str();
+        ss >> value;
+
+        if(NULL != log) {
+          log::Param params[] = {
+            log::Param("category", category),
+            log::Param("key", key),
+            log::Param("value", value),
+            log::Param("source", m_fileName)};
+          (*log)(LOG_INFO, "Configuration entry", params);
+        }
+
+        return value;
+      }
+
+    private:
+
+      /**
+       * check whether the configuration should be renewed
+       */
+      bool isStale() ;
+
+      /**
+       * tries to renew the configuration.
+       * That is : take the write lock to do it, check whether it's needed
+       * and do it only if needed before releasing the lock
+       */
+      void tryToRenewConfig() ;
+
+      /**
+       * gets current timeout value (in seconds)
+       * this function does not take any lock while reading the
+       * configuration. So it should never be called without holding
+       * a read or a write lock
+       */
+      int getTimeoutNolock() ;
+
+      /**
+       * renews the configuration
+       * this function does not take any lock while renewing the
+       * configuration. So it should never be called without holding
+       * the write lock
+       */
+      void renewConfigNolock() ;
+
+    private:
+
+      /**
+       * fileName to be used when updating the configuration
+       */
+      std::string m_fileName;
+
+      /**
+       * last time we've updated the configuration
+       */
+      time_t m_lastUpdateTime;
+
+      /**
+       * the dictionnary of configuration items
+       * actually a dictionnary of ConfCategories, which are dictionnaries of entries
+       */
+      std::map<std::string, ConfCategory> m_config;
+
+      /**
+       * lock to garantee safe access to the configuration, lastUpdateTime and timeout
+       */
+      pthread_rwlock_t m_lock;
+
+    };
+
+  } // namespace common
+} // namespace castor  
+
diff --git a/common/ProcessCap.cpp b/common/ProcessCap.cpp
new file mode 100644
index 0000000000..5b5d49c710
--- /dev/null
+++ b/common/ProcessCap.cpp
@@ -0,0 +1,135 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "common/exception/Exception.hpp"
+#include "common/ProcessCap.hpp"
+#include "castor/server/SmartCap.hpp"
+#include "common/Utils.hpp"
+
+#include <errno.h>
+
+//------------------------------------------------------------------------------
+// destructor
+//------------------------------------------------------------------------------
+castor::server::ProcessCap::~ProcessCap()
+  throw() {
+}
+
+//------------------------------------------------------------------------------
+// getProcText
+//------------------------------------------------------------------------------
+std::string castor::server::ProcessCap::getProcText() {
+  try {
+    SmartCap cap(getProc());
+    return toText((cap_t)cap.get());
+  } catch(castor::exception::Exception &ne) {
+    castor::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to get text representation of the capabilities of the process: "
+      << ne.getMessage().str();
+    throw ex;
+  }
+}
+
+//------------------------------------------------------------------------------
+// getProc
+//------------------------------------------------------------------------------
+cap_t castor::server::ProcessCap::getProc() {
+  cap_t cap = cap_get_proc();
+  if(NULL == cap) {
+    castor::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to get the capabilities of the process: " 
+        << cta::Utils::errnoToString(errno);
+    throw ex;
+  }
+  return cap;
+}
+
+//------------------------------------------------------------------------------
+// toText
+//------------------------------------------------------------------------------
+std::string castor::server::ProcessCap::toText(
+  const cap_t cap) {
+  // Create a C++ string with the result of calling cap_to_text()
+  char *const text = cap_to_text(cap, NULL);
+  if(NULL == text) {
+    castor::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to create string representation of capability state: " 
+        << cta::Utils::errnoToString(errno);
+    throw ex;
+  }
+  std::string result(text);
+
+  // Free the memory allocated by cap_to_text()
+  if(cap_free(text)) {
+    castor::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to free string representation of capability state: " 
+        << cta::Utils::errnoToString(errno);
+    throw ex;
+  }
+
+  // Return the C++ string
+  return result;
+}
+
+//------------------------------------------------------------------------------
+// setProcText
+//------------------------------------------------------------------------------
+void castor::server::ProcessCap::setProcText(const std::string &text) {
+  try {
+    SmartCap cap(fromText(text));
+    setProc(cap.get());
+  } catch(castor::exception::Exception &ne) {
+    castor::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to set capabilities of process: " << ne.getMessage().str();
+    throw ex;
+  }
+}
+
+//------------------------------------------------------------------------------
+// fromText
+//------------------------------------------------------------------------------
+cap_t castor::server::ProcessCap::fromText(const std::string &text) {
+  const cap_t cap = cap_from_text(text.c_str());
+  if(NULL == cap) {
+    castor::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to create capability state from string representation"
+      ": text='" << text << "': " << cta::Utils::errnoToString(errno);
+    throw ex;
+  }
+
+  return cap;
+}
+
+//------------------------------------------------------------------------------
+// setProc
+//------------------------------------------------------------------------------
+void castor::server::ProcessCap::setProc(const cap_t cap) {
+  if(cap_set_proc(cap)) {
+    castor::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to set the capabilities of the process: " 
+        << cta::Utils::errnoToString(errno);
+    throw ex;
+  }
+}
diff --git a/common/exception/Errnum.cpp b/common/exception/Errnum.cpp
index 254ebf47b7..5f47876384 100644
--- a/common/exception/Errnum.cpp
+++ b/common/exception/Errnum.cpp
@@ -17,7 +17,7 @@
  */
 
 #include "common/exception/Errnum.hpp"
-#include "common/Utils.hpp"
+#include "common/utils/Utils.hpp"
 
 #include <errno.h>
 #include <string.h>
diff --git a/common/exception/Errnum.hpp b/common/exception/Errnum.hpp
index 080d67a074..926acbfef5 100644
--- a/common/exception/Errnum.hpp
+++ b/common/exception/Errnum.hpp
@@ -25,7 +25,7 @@ namespace exception {
   class Errnum: public cta::exception::Exception {
   public:
     Errnum(std::string what = "");
-	  Errnum (int err, std::string what = "");
+    Errnum (int err, std::string what = "");
     virtual ~Errnum() throw() {};
     int errorNumber() const { return m_errnum; }
     std::string strError() const { return m_strerror; }
diff --git a/common/exception/Exception.hpp b/common/exception/Exception.hpp
index 5063156463..0bf77aa29e 100644
--- a/common/exception/Exception.hpp
+++ b/common/exception/Exception.hpp
@@ -23,112 +23,106 @@
 #include <exception>
 #include <sstream>
 
-namespace cta {
-
-  namespace exception {
-
-    /**
-     * class Exception
-     * A simple exception used for error handling in castor
-     */
-    class Exception: public std::exception {
-
-    public:
-
-      /**
-       * Constructor.
-       *
-       * @param context optional context string added to the message
-       * at initialisation time.
-       * @param embedBacktrace whether to embed a backtrace of where the
-       * exception was throw in the message
-       */
-      Exception(const std::string &context="", const bool embedBacktrace=true);
-      
-      /**
-       * Copy Constructor
-       */
-      Exception(const Exception& rhs);
-
-      /**
-       * Assignment operator
-       */
-      Exception& operator=(const Exception &rhs);
-
-      /**
-       * Empty Destructor, explicitely non-throwing (needed for std::exception
-       * inheritance)
-       */
-      virtual ~Exception() throw ();
-
-      /**
-       * Get the value of m_message
-       * A message explaining why this exception was raised
-       * @return the value of m_message
-       */
-      std::ostringstream& getMessage() {
-        return m_message;
-      }
-
-      /**
-       * Get the value of m_message
-       * A message explaining why this exception was raised
-       * @return the value of m_message
-       */
-      const std::ostringstream& getMessage() const {
-        return m_message;
-      }
-      
-      /**
-       * Get the value of m_message as a sting, for const-c orrectness
-       * @return the value as a string.
-       */
-      std::string getMessageValue() const {
-        return m_message.str();
-      }
-      
-      /**
-       * Get the backtrace's contents
-       * @return backtrace in a standard string.
-       */
-      std::string const backtrace() const {
-        return (std::string)m_backtrace;
-      }
-      
-      /**
-       * Updates the m_what member with a concatenation of the message and
-       * the stack trace.
-       * @return pointer to m_what's contents
-       */
-      virtual const char * what() const throw ();
-
-    private:
-      /// A message explaining why this exception was raised
-      std::ostringstream m_message;
-      
-      /**
-       * Placeholder for the what result. It has to be a member
-       * of the object, and not on the stack of the "what" function.
-       */
-      mutable std::string m_what;
-      
-    protected:  
-      void setWhat(const std::string &w);
-      
-      /**
-       * Backtrace object. Its constructor does the heavy lifting of
-       * generating the backtrace.
-       */
-      Backtrace m_backtrace;
-
-    };
-
-  } // end of exception namespace
-
-} // end of castor namespace
-
-#define CTA_GENERATE_EXCEPTION_CLASS(A)                     \
-class A: public cta::exception::Exception {                 \
-public:                                                     \
-  A(const std::string & w): cta::exception::Exception(w) {} \
+namespace cta { namespace exception {
+/**
+ * class Exception
+ * A simple exception used for error handling in castor
+ */
+class Exception : public std::exception {
+public:
+
+  /**
+   * Constructor.
+   *
+   * @param context optional context string added to the message
+   * at initialisation time.
+   * @param embedBacktrace whether to embed a backtrace of where the
+   * exception was throw in the message
+   */
+  Exception(const std::string &context = "", const bool embedBacktrace = true);
+
+  /**
+   * Copy Constructor
+   */
+  Exception(const Exception& rhs);
+
+  /**
+   * Assignment operator
+   */
+  Exception& operator=(const Exception &rhs);
+
+  /**
+   * Empty Destructor, explicitely non-throwing (needed for std::exception
+   * inheritance)
+   */
+  virtual ~Exception() throw ();
+  
+  /**
+   * Get the value of m_message
+   * A message explaining why this exception was raised
+   * @return the value of m_message
+   */
+  std::ostringstream& getMessage() {
+    return m_message;
+  }
+  
+  /**
+   * Get the value of m_message
+   * A message explaining why this exception was raised
+   * @return the value of m_message
+   */
+  
+  const std::ostringstream& getMessage() const {
+    return m_message;
+  }
+  /**
+   * Get the value of m_message as a sting, for const-c orrectness
+   * @return the value as a string.
+   */
+  
+  std::string getMessageValue() const {
+    return m_message.str();
+  }
+  /**
+   * Get the backtrace's contents
+   * @return backtrace in a standard string.
+   */
+  std::string const backtrace() const {
+    return (std::string)m_backtrace;
+  }
+
+  /**
+   * Updates the m_what member with a concatenation of the message and
+   * the stack trace.
+   * @return pointer to m_what's contents
+   */
+  virtual const char * what() const throw ();
+
+private:
+  /// A message explaining why this exception was raised
+  std::ostringstream m_message;
+
+  /**
+   * Placeholder for the what result. It has to be a member
+   * of the object, and not on the stack of the "what" function.
+   */
+  mutable std::string m_what;
+
+protected:
+  void setWhat(const std::string &w);
+
+  /**
+   * Backtrace object. Its constructor does the heavy lifting of
+   * generating the backtrace.
+   */
+  Backtrace m_backtrace;
+
+} ;
+
+}} // namespace cta::exception
+
+#define CTA_GENERATE_EXCEPTION_CLASS(A)                          \
+class A: public cta::exception::Exception {                      \
+public:                                                          \
+  A(const std::string & w = ""): cta::exception::Exception(w) {} \
 }
diff --git a/common/exception/Serrnum.cpp b/common/exception/Serrnum.cpp
deleted file mode 100644
index 333ebaf3be..0000000000
--- a/common/exception/Serrnum.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * The CERN Tape Archive (CTA) project
- * Copyright (C) 2015  CERN
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "common/exception/Serrnum.hpp"
-#include "common/Utils.hpp"
-
-#include <errno.h>
-#include <string.h>
-
-using namespace cta::exception;
-
-Serrnum::Serrnum(std::string what):Exception("") {
-  m_serrnum = errno;
-  SerrnumConstructorBottomHalf(what);
-}
-
-Serrnum::Serrnum(int err, std::string what):Exception("") {
-  m_serrnum = err;
-  SerrnumConstructorBottomHalf(what);
-}
-
-void Serrnum::SerrnumConstructorBottomHalf(const std::string & what) {
-  m_strerror = Utils::errnoToString(m_serrnum);
-  std::stringstream w2;
-  if (what.size())
-    w2 << what << " ";
-  w2 << "Errno=" << m_serrnum << ": " << m_strerror;
-  getMessage().str(w2.str());
-}
-
-void Serrnum::throwOnReturnedErrno (const int err, const std::string &context) {
-  if (err) throw Serrnum(err, context);
-}
-
-void Serrnum::throwOnNonZero(const int status, const std::string &context) {
-  if (status) throw Serrnum(context);
-}
-
-void Serrnum::throwOnZero(const int status, const std::string &context) {
-  if (!status) throw Serrnum(context);
-}
-
-void Serrnum::throwOnNull(const void *const f, const std::string &context) {
-  if (NULL == f) throw Serrnum(context);
-}
-
-void Serrnum::throwOnNegative(const int ret, const std::string &context) {
-  if (ret < 0) throw Serrnum(context);
-}
-
-void Serrnum::throwOnMinusOne(const int ret, const std::string &context) {
-  if (-1 == ret) throw Serrnum(context);
-}
diff --git a/common/exception/Serrnum.hpp b/common/exception/Serrnum.hpp
deleted file mode 100644
index 1dd46b01f5..0000000000
--- a/common/exception/Serrnum.hpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * The CERN Tape Archive (CTA) project
- * Copyright (C) 2015  CERN
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include "Exception.hpp"
-
-namespace cta {
-namespace exception {
-  class Serrnum: public cta::exception::Exception {
-  public:
-    Serrnum(std::string what = "");
-	  Serrnum (int err, std::string what = "");
-    virtual ~Serrnum() throw() {};
-    int serrorNumber() const { return m_serrnum; }
-    std::string strError() const { return m_strerror; }
-    static void throwOnReturnedErrno(const int err, const std::string &context = "");
-    static void throwOnNonZero(const int status, const std::string &context = "");
-    static void throwOnZero(const int status, const std::string &context = "");
-    static void throwOnNull(const void *const f, const std::string &context = "");
-    static void throwOnNegative(const int ret, const std::string &context = "");
-    static void throwOnMinusOne(const int ret, const std::string &context = "");
-  protected:
-    void SerrnumConstructorBottomHalf(const std::string & what);
-    int m_serrnum;
-    std::string m_strerror;
-  };
-}
-}
diff --git a/common/log/CMakeLists.txt b/common/log/CMakeLists.txt
new file mode 100644
index 0000000000..3fcad0947e
--- /dev/null
+++ b/common/log/CMakeLists.txt
@@ -0,0 +1,23 @@
+cmake_minimum_required (VERSION 2.6)
+
+include_directories(${PROJECT_SOURCE_DIR}/tapeserver)
+include_directories(${PROJECT_SOURCE_DIR}/tapeserver/h)
+
+add_library (ctalogutils SHARED
+  DummyLogger.cpp)
+
+set (LOG_LIB_SRC_FILES
+  DummyLogger.cpp
+  Logger.cpp
+  StringLogger.cpp
+  SyslogLogger.cpp
+  LogContext.cpp
+  Message.cpp
+  Param.cpp)
+add_library (ctalog ${LOG_LIB_SRC_FILES})
+
+add_library (ctalogunittests SHARED
+  ParamTest.cpp
+  LogContextTest.cpp
+  StringLoggerTest.cpp
+  SyslogLoggerTest.cpp)
diff --git a/common/log/DummyLogger.cpp b/common/log/DummyLogger.cpp
new file mode 100644
index 0000000000..7156eff7d2
--- /dev/null
+++ b/common/log/DummyLogger.cpp
@@ -0,0 +1,95 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "common/log/DummyLogger.hpp"
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+cta::log::DummyLogger::DummyLogger(const std::string &programName) :
+Logger(programName) { }
+
+//------------------------------------------------------------------------------
+// destructor
+//------------------------------------------------------------------------------
+cta::log::DummyLogger::~DummyLogger() { }
+
+//------------------------------------------------------------------------------
+// prepareForFork
+//------------------------------------------------------------------------------
+void cta::log::DummyLogger::prepareForFork() {}
+
+//------------------------------------------------------------------------------
+// operator() 
+//------------------------------------------------------------------------------
+void cta::log::DummyLogger::operator()(
+    const int priority,
+    const std::string &msg,
+    const std::vector<Param> &params,
+    const struct timeval &timeStamp) {}
+
+//------------------------------------------------------------------------------
+// operator() 
+//------------------------------------------------------------------------------
+void cta::log::DummyLogger::operator() (
+  const int priority,
+  const std::string &msg,
+  const std::list<Param> &params,
+  const struct timeval &timeStamp) {}
+
+//------------------------------------------------------------------------------
+// operator() 
+//------------------------------------------------------------------------------
+void cta::log::DummyLogger::operator() (
+  const int priority,
+  const std::string &msg,
+  const int numParams,
+  const log::Param params[],
+  const struct timeval &timeStamp) {}
+
+//------------------------------------------------------------------------------
+// operator() 
+//------------------------------------------------------------------------------
+void cta::log::DummyLogger::operator() (
+  const int priority,
+  const std::string &msg,
+  const std::vector<Param> &params) {}
+
+//------------------------------------------------------------------------------
+// operator() 
+//------------------------------------------------------------------------------
+void cta::log::DummyLogger::operator() (
+  const int priority,
+  const std::string &msg,
+  const std::list<Param> &params) {}
+
+//------------------------------------------------------------------------------
+// operator() 
+//------------------------------------------------------------------------------
+void cta::log::DummyLogger::operator() (
+  const int priority,
+  const std::string &msg,
+  const int numParams,
+  const log::Param params[]) {}
+
+//------------------------------------------------------------------------------
+// operator() 
+//------------------------------------------------------------------------------
+void cta::log::DummyLogger::operator() (
+  const int priority,
+  const std::string &msg) {}
diff --git a/common/log/DummyLogger.hpp b/common/log/DummyLogger.hpp
new file mode 100644
index 0000000000..52eee7d85c
--- /dev/null
+++ b/common/log/DummyLogger.hpp
@@ -0,0 +1,159 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "common/log/Logger.hpp"
+
+#include <map>
+#include <pthread.h>
+#include <syslog.h>
+#include <sys/time.h>
+
+namespace cta { namespace log {
+
+/**
+ * A dummy logger class whose implementation of the API of the CASTOR logging
+ * system does nothing.
+ *
+ * The primary purpose of this class is to facilitate the unit testing of
+ * classes that require a logger object.  Using an instance of this class
+ * during unit testing means that no logs will actually be written to a log
+ * file.
+ */
+class DummyLogger: public Logger {
+public:
+
+  /**
+   * Constructor
+   *
+   * @param programName The name of the program to be prepended to every log
+   * message.
+   */
+  DummyLogger(const std::string &programName);
+
+  /**
+   * Destructor.
+   */
+  ~DummyLogger();
+
+  /**
+   * Prepares the logger object for a call to fork().
+   *
+   * No further calls to operator() should be made after calling this
+   * method until the call to fork() has completed.
+   */
+  void prepareForFork() ;
+
+  /**
+   * Dummy operator() method that does nothing.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   * @param timeStamp the time stamp of the log message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg,
+    const std::vector<Param> &params,
+    const struct timeval &timeStamp);
+
+  /**
+   * Dummy operator() method that does nothing.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   * @param timeStamp the time stamp of the log message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg,
+    const std::list<Param> &params,
+    const struct timeval &timeStamp);
+
+  /**
+   * Dummy operator() method that does nothing.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param numParams the number of parameters in the message.
+   * @param params the parameters of the message.
+   * @param timeStamp the time stamp of the log message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg,
+    const int numParams,
+    const Param params[],
+    const struct timeval &timeStamp);
+
+  /**
+   * Dummy operator() method that does nothing.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg,
+    const std::vector<Param> &params);
+
+  /**
+   * Dummy operator() method that does nothing.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg,
+    const std::list<Param> &params);
+
+  /**
+   * Dummy operator() method that does nothing.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param numParams the number of parameters in the message.
+   * @param params the parameters of the message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg,
+    const int numParams,
+    const Param params[]);
+
+  /**
+   * Dummy operator() method that does nothing.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg);
+
+}; // class DummyLogger
+
+} // namespace log
+} // namespace castor
+
diff --git a/common/log/LogContext.cpp b/common/log/LogContext.cpp
new file mode 100644
index 0000000000..c1cf6deafa
--- /dev/null
+++ b/common/log/LogContext.cpp
@@ -0,0 +1,114 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Interface to the CASTOR logging system
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#include "common/log/LogContext.hpp"
+#include "common/log/Param.hpp"
+#include "common/log/Logger.hpp"
+
+#include <list>
+#include <algorithm>
+#include <bfd.h>
+
+cta::log::LogContext::LogContext(cta::log::Logger& logger):
+m_log(logger) {}
+
+void cta::log::LogContext::pushOrReplace(const Param& param) {
+  ParamNameMatcher match(param.getName());
+  std::list<Param>::iterator i = 
+      std::find_if(m_params.begin(), m_params.end(), match);
+  if (i != m_params.end()) {
+    i->setValue(param.getValue());
+  } else {
+    m_params.push_back(param);
+  }
+}
+
+void cta::log::LogContext::erase(const std::string& paramName) {
+  ParamNameMatcher match(paramName);
+  m_params.erase(std::remove_if(m_params.begin(), m_params.end(), match), m_params.end());
+}
+
+void cta::log::LogContext::log(const int priority, const std::string& msg) {
+  m_log(priority, msg, m_params);
+}
+
+void cta::log::LogContext::log(const int priority, const std::string& msg, 
+    const timeval& timeStamp) {
+  m_log(priority, msg, m_params, timeStamp);
+}
+
+void cta::log::LogContext::logBacktrace(const int priority, 
+    const std::string& backtrace) {
+  // Sanity check to prevent substr from throwing exceptions
+  if (!backtrace.size())
+    return;
+  size_t position = 0;
+  int lineNumber = 0;
+  bool stillGoing = true;
+  while(stillGoing) {
+    size_t next = backtrace.find_first_of("\n", position);
+    std::string line;
+    if(next != std::string::npos) { 
+      line = backtrace.substr(position, next - position);
+      // If our position is out of range, substr would throw an exception
+      // so we check here if we would get out of range.
+      position = next + 1;
+      if (position >= backtrace.size())
+        stillGoing = false;
+    } else {
+      stillGoing=false;
+      line = backtrace.substr(position);
+    }
+    if (line.size()) {
+      ScopedParam sp1 (*this, cta::log::Param("traceFrameNumber", lineNumber++));
+      ScopedParam sp2 (*this, cta::log::Param("traceFrame", line));
+      log(priority, "Stack trace");
+    }
+  }
+}
+
+cta::log::LogContext::ScopedParam::ScopedParam(
+    LogContext& context, 
+    const Param& param) : 
+    m_context(context), m_name(param.getName()) {
+  m_context.pushOrReplace(param);
+}
+
+cta::log::LogContext::ScopedParam::~ScopedParam() {
+   m_context.erase(m_name);
+}
+
+std::ostream & cta::log::operator << (std::ostream & os, 
+    const cta::log::LogContext & lc) {
+  bool first=true;
+  for (std::list<Param>::const_iterator p = lc.m_params.begin(); 
+      p != lc.m_params.end(); ++p) {
+    if (!first) {
+      os << " ";
+    } else {
+      first = false;
+    }
+    os << p->getName() << "=" << p->getValue();
+  }
+  return os;
+}
diff --git a/common/log/LogContext.hpp b/common/log/LogContext.hpp
new file mode 100644
index 0000000000..a30525a7ce
--- /dev/null
+++ b/common/log/LogContext.hpp
@@ -0,0 +1,164 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <ostream>
+#include "common/log/Logger.hpp"
+
+namespace cta { namespace log {
+
+/**
+ * Container for a set of parameters to be used repetitively in logs. The
+ * container is ordered , by order of inclusion. There can be only one
+ * parameter value per parameter name.
+ */
+class LogContext {
+  friend std::ostream & operator << (std::ostream & os , const LogContext & lc);
+public:
+  /**
+   * Constructor
+   *
+   * @param programName The name of the program to be prepended to every log
+   * message.
+   */
+  LogContext(cta::log::Logger &logger);
+
+  /**
+   * Destructor.
+   */
+  virtual ~LogContext() throw() {};
+  
+  /**
+   * Access to the logger object.
+   * @return  reference to this context's logger
+   */
+  cta::log::Logger & logger() throw() { return m_log; }
+
+  /**
+   * Add a parameter to the container. Replaces any parameter going by the same
+   * name. Does not throw exceptions (fails silently).
+   * @param param
+   */
+  void pushOrReplace(const Param & param);
+
+  /**
+   * Removes a parameter from the list.
+   * @param paramName value of param.getName();
+   */
+  void erase(const std::string & paramName);
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of logMsg() implicitly uses the current time as
+   * the time stamp of the message.
+   * 
+   * All the parameters present in the context will be added to the log message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   */
+  virtual void log(
+    const int priority,
+    const std::string &msg);
+  
+  /**
+   * Logs a multiline backtrace as multiple entries in the logs, without
+   * the context
+   * @param priority the logging priority
+   * @param backtrace the multi-line (\n separated) stack trace
+   */
+  virtual void logBacktrace(
+    const int priority,
+    const std::string &backtrace);
+  
+  /**
+   * Small introspection function to help in tests
+   * @return size
+   */
+  size_t size() const { return m_params.size(); }
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   * 
+   * All the parameters present in the context will be added to the log message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   */
+  virtual void log(
+    const int priority,
+    const std::string &msg,
+    const struct timeval &timeStamp);
+  /**
+   * Helper class to find parameters by name.
+   */
+  class ParamNameMatcher {
+  public:
+    ParamNameMatcher(const std::string & name) throw(): m_name(name) {}
+    bool operator() (const Param & p) throw() { return m_name == p.getName(); }
+  private:
+    std::string m_name;
+  };
+  
+  /**
+   * Scoped parameter addition to the context. Constructor adds the parameter,
+   * destructor erases it.
+   */
+  class ScopedParam {
+  public:
+    ScopedParam(LogContext & context, const Param &param);
+    ~ScopedParam();
+  private:
+    LogContext & m_context;
+    std::string m_name;
+  };
+private:
+  Logger & m_log;
+  std::list<Param> m_params;
+}; // class LogContext
+
+class ScopedParamContainer{
+  public:
+    ScopedParamContainer(LogContext & context):m_context(context) {}
+    ~ScopedParamContainer() {
+      for(std::vector<std::string>::const_iterator it=m_names.begin();it!=m_names.end();++it)
+      {  m_context.erase(*it);
+      }
+    }
+
+    template <class T> ScopedParamContainer& add(const std::string& s,const T& t){
+      m_context.pushOrReplace(Param(s,t));
+      m_names.push_back(s);
+      return *this;
+    }
+  private:
+        
+    LogContext & m_context;
+    std::vector<std::string> m_names;
+};
+
+std::ostream & operator << (std::ostream & os , const LogContext & lc);
+
+} // namespace log
+} // namespace castor
diff --git a/common/log/LogContextTest.cpp b/common/log/LogContextTest.cpp
new file mode 100644
index 0000000000..570ca17a52
--- /dev/null
+++ b/common/log/LogContextTest.cpp
@@ -0,0 +1,72 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "common/log/DummyLogger.hpp"
+#include "common/log/StringLogger.hpp"
+#include "common/log/LogContext.hpp"
+
+#include <gtest/gtest.h>
+
+using namespace cta::log;
+
+namespace unitTests {
+  TEST(cta_log_LogContextTest, additionScopedRemove) {
+    DummyLogger dl("castor_log_LogContextTest");
+    LogContext lc(dl);
+    lc.pushOrReplace(Param("MigrationRequestId", 123));
+    ASSERT_EQ(1U, lc.size());
+    {
+      // Create an anonymous variable (for its scope)
+      LogContext::ScopedParam sp(lc, Param("NSFILEID", 12345));
+      ASSERT_EQ(2U, lc.size());
+      lc.log(LOG_DEBUG, "Two params message");
+      {
+        // Test that we do not allow duplicate params
+        LogContext::ScopedParam sp(lc, Param("NSFILEID", 123456));
+        ASSERT_EQ(2U, lc.size());
+        LogContext::ScopedParam sp2(lc, Param("TPVID", "T1234"));
+        ASSERT_EQ(3U, lc.size());
+      }
+    }
+    ASSERT_EQ(1U, lc.size());
+    lc.log(LOG_DEBUG, "One param message");
+    lc.erase("MigrationRequestId");
+    ASSERT_EQ(0U, lc.size());
+  }
+  
+  TEST(cta_log_LogContextTest, paramsFound) {
+    StringLogger sl ("castor_log_LogContextTest");
+    LogContext lc(sl);
+    lc.pushOrReplace(Param("MigrationRequestId", 123));
+    lc.log(LOG_INFO, "First log");
+    std::string first = sl.getLog();
+    ASSERT_NE(std::string::npos, first.find("MigrationRequestId"));
+    {
+      LogContext::ScopedParam sp(lc, Param("NSFILEID", 12345));
+      lc.log(LOG_INFO, "Second log");
+    }
+    std::string second = sl.getLog();
+    ASSERT_NE(std::string::npos, second.find("NSFILEID"));
+    // We expect the NSFILEID parameter to show up only once (i.e, not after 
+    // offset, which marks the end of its first occurrence).
+    lc.log(LOG_INFO, "Third log");
+    std::string third = sl.getLog();
+    size_t offset  = third.find("NSFILEID") + strlen("NSFILEID");
+    ASSERT_EQ(std::string::npos, third.find("NSFILEID", offset));
+  }
+}
diff --git a/common/log/Logger.cpp b/common/log/Logger.cpp
new file mode 100644
index 0000000000..3221f44fdc
--- /dev/null
+++ b/common/log/Logger.cpp
@@ -0,0 +1,44 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Interface to the CASTOR logging system
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#include "common/log/Logger.hpp"
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+cta::log::Logger::Logger(const std::string &programName):
+  m_programName(programName) {
+}
+
+//------------------------------------------------------------------------------
+// getProgramName
+//------------------------------------------------------------------------------
+const std::string &cta::log::Logger::getProgramName() const {
+  return m_programName;
+}
+
+//------------------------------------------------------------------------------
+// destructor
+//------------------------------------------------------------------------------
+cta::log::Logger::~Logger() {
+}
diff --git a/common/log/Logger.hpp b/common/log/Logger.hpp
new file mode 100644
index 0000000000..0cc2ef7ddc
--- /dev/null
+++ b/common/log/Logger.hpp
@@ -0,0 +1,293 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+// Include Files
+#include "common/log/Param.hpp"
+#include "common/exception/Exception.hpp"
+
+#include <list>
+#include <map>
+#include <pthread.h>
+#include <syslog.h>
+#include <sys/time.h>
+#include <vector>
+
+/**
+ * It is a convention of CTA to use syslog level of LOG_NOTICE to label
+ * user errors.  This macro helps enforce that convention and document it in
+ * the code.
+ */
+#define LOG_USERERR LOG_NOTICE
+
+namespace cta { namespace log {
+
+/**
+ * Abstract class representing the API of the CASTOR logging system.
+ *
+ * The intended way to use the CASTOR logging API is as follows:
+ *
+ * 1. Keep a reference to a Logger object, for example:
+ * \code{.cpp}
+ *
+ * class MyClassThatWillLog {
+ * protected:
+ *   Logger & m_log;
+ *
+ * public:
+ *   MyClassThatWillLog(Logger &log): m_log(log) {
+ *     ....
+ *   }
+ * }
+ *
+ * \endcode
+ *
+ * 2. To log a message, use the reference to the Logger object like a function.
+ *    In other words the Logger object implements operator() and therefore
+ *    behaves like a functor:
+ * \code{.cpp}
+ *
+ * void MyClassThatWillLog::aMethodThatWillLog() {
+ *   ....
+ *   m_log(LOG_INFO, "My log message");
+ *   ....
+ * }
+ *
+ * \endcode
+ *
+ * The Logger object implements operator() in order to avoid the following long
+ * winded syntax (which does not work by the way, so please do NOT copy and
+ * paste the following example):
+ * \code{.cpp}
+ *
+ * m_log.logMsg(LOG_INFO, "My log message");
+ *
+ * \endcode
+ */
+class Logger {
+public:
+
+  CTA_GENERATE_EXCEPTION_CLASS(InvalidArgument);
+  /**
+   * Constructor
+   *
+   * @param programName The name of the program to be prepended to every log
+   * message.
+   */
+  Logger(const std::string &programName);
+
+  /**
+   * Destructor.
+   */
+  virtual ~Logger() = 0;
+
+  /**
+   * Prepares the logger object for a call to fork().
+   *
+   * No further calls to operator() should be made after calling this
+   * method until the call to fork() has completed.
+   */
+  virtual void prepareForFork()  = 0;
+
+  /**
+   * Returns the name of the program that is to  be prepended to every log
+   * message.
+   */
+  const std::string &getProgramName() const;
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() allows the caller to specify the
+   * time stamp of the log message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   * @param timeStamp the time stamp of the log message.
+   */
+  virtual void operator() (
+    const int priority,
+    const std::string &msg,
+    const std::vector<Param> &params,
+    const struct timeval &timeStamp) = 0;
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() allows the caller to specify the
+   * time stamp of the log message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   * @param timeStamp the time stamp of the log message.
+   */
+  virtual void operator() (
+    const int priority,
+    const std::string &msg,
+    const std::list<Param> &params,
+    const struct timeval &timeStamp) = 0;
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() allows the caller to specify the
+   * time stamp of the log message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param numParams the number of parameters in the message.
+   * @param params the parameters of the message.
+   * @param timeStamp the time stamp of the log message.
+   */
+  virtual void operator() (
+    const int priority,
+    const std::string &msg,
+    const int numParams,
+    const Param params[],
+    const struct timeval &timeStamp) = 0;
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() implicitly uses the current time as
+   * the time stamp of the message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   */
+  virtual void operator() (
+    const int priority,
+    const std::string &msg,
+    const std::vector<Param> &params) = 0;
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() implicitly uses the current time as
+   * the time stamp of the message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   */
+  virtual void operator() (
+    const int priority,
+    const std::string &msg,
+    const std::list<Param> &params) = 0;
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() implicitly uses the current time as
+   * the time stamp of the message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param numParams the number of parameters in the message.
+   * @param params the parameters of the message.
+   */
+  virtual void operator() (
+    const int priority,
+    const std::string &msg,
+    const int numParams,
+    const Param params[]) = 0;
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() implicitly uses the current time as
+   * the time stamp of the message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   */
+  virtual void operator() (
+    const int priority,
+    const std::string &msg) = 0;
+
+  /**
+   * A template function that wraps operator() in order to get the compiler
+   * to automatically determine the size of the params parameter, therefore
+   *
+   * Note that this version of operator() allows the caller to specify the
+   * time stamp of the log message.
+   *
+   * @param priority the priority of the message as defined by the syslog
+   * API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   * @param timeStamp the time stamp of the log message.
+   */
+  template<int numParams> void operator() (
+    const int priority,
+    const std::string &msg,
+    const log::Param(&params)[numParams],
+    const struct timeval &timeStamp) throw() {
+    operator() (priority, msg, numParams, params, timeStamp);
+  }
+
+  /**
+   * A template function that wraps operator() in order to get the compiler
+   * to automatically determine the size of the params parameter, therefore
+   * removing the need for the devloper to provide it explicity.
+   *
+   * Note that this version of operator() implicitly uses the current time as
+   * the time stamp of the message.
+   *
+   * @param priority the priority of the message as defined by the syslog
+   * API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   */
+  template<int numParams> void operator() (
+    const int priority,
+    const std::string &msg,
+    const log::Param(&params)[numParams]) throw() {
+    operator() (priority, msg, numParams, params);
+  }
+
+protected:
+
+  /**
+   * The name of the program to be prepended to every log message.
+   */
+  const std::string m_programName;
+
+}; // class Logger
+
+} // namespace log
+} // namespace castor
+
diff --git a/common/log/Message.cpp b/common/log/Message.cpp
new file mode 100644
index 0000000000..476466c7e0
--- /dev/null
+++ b/common/log/Message.cpp
@@ -0,0 +1,26 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Container for a CASTOR log message
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+// Include Files
+#include "common/log/Message.hpp"
diff --git a/common/log/Message.hpp b/common/log/Message.hpp
new file mode 100644
index 0000000000..7c571cdec9
--- /dev/null
+++ b/common/log/Message.hpp
@@ -0,0 +1,47 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Container for a CASTOR log message
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#pragma once
+
+// Include Files
+#include <string>
+
+namespace castor {
+
+  namespace log {
+
+    /**
+     * Container for a CASTOR log message
+     */
+    struct Message {
+      /// Message number
+      int number;
+      /// Message text
+      std::string text;
+    }; 
+    
+  } // end of namespace log
+
+} // end of namespace castor
+
diff --git a/common/log/Param.cpp b/common/log/Param.cpp
new file mode 100644
index 0000000000..84b34c412a
--- /dev/null
+++ b/common/log/Param.cpp
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * A parameter for the CASTOR logging system
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#include "common/log/Param.hpp"
+#include <cstdio>
+
+//------------------------------------------------------------------------------
+// getName
+//------------------------------------------------------------------------------
+const std::string &cta::log::Param::getName() const throw() {
+  return m_name;
+}
+
+//------------------------------------------------------------------------------
+// getValue
+//------------------------------------------------------------------------------
+const std::string &cta::log::Param::getValue() const throw() {
+  return m_value;
+}
+
diff --git a/common/log/Param.hpp b/common/log/Param.hpp
new file mode 100644
index 0000000000..bd6ff65b37
--- /dev/null
+++ b/common/log/Param.hpp
@@ -0,0 +1,108 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <sstream>
+#include <string.h>
+#include <cstdio>
+
+namespace cta { namespace log {
+
+/**
+ * A name/value parameter for the CASTOR logging system.
+ */
+class Param {
+
+public:
+
+  /**
+   * Constructor.
+   *
+   * @param name The name of the parameter.
+   * @param value The value of the parameter that will be converted to a string
+   * using std::ostringstream.
+   */
+  template <typename T> Param(const std::string &name, const T &value) throw():
+    m_name(name) {
+    std::ostringstream oss;
+    oss << value;
+    m_value = oss.str();
+  }
+  
+  /**
+   * Constructor.
+   *
+   * @param name The name of the parameter.
+   * @param value The value of the parameter that will be converted to a string
+   * using snprintf for doubles
+   */
+  Param (const std::string &name, const double value) throw():
+  m_name(name) {
+    char buf[100];
+    std::snprintf(buf, sizeof(buf), "%f", value);
+    // Just in case we overflow
+    buf[sizeof(buf)-1]='\0';
+    m_value = buf;
+  }
+    
+  /**
+   * Value changer. Useful for log contexts.
+   * @param value
+   */
+  template <typename T>
+  void setValue (const T &value) throw() {
+    std::stringstream oss;
+    oss << value;
+    m_value = oss.str();
+  }
+
+  /**
+   * Returns a const reference to the name of the parameter.
+   */
+  const std::string &getName() const throw();
+
+  /**
+   * Returns a const reference to the value of the parameter.
+   */
+  const std::string &getValue() const throw();
+
+protected:
+
+  /**
+   * Name of the parameter
+   */
+  std::string m_name;
+
+  /**
+   * The value of the parameter.
+   */
+  std::string m_value;
+
+}; // class Param
+
+/**
+ * An helper class allowing the construction of a Param class with sprintf
+ * formatting for a double.
+ */
+class ParamDoubleSnprintf: public Param {
+public:
+  ParamDoubleSnprintf(const std::string &name, const double value);
+}; // class ParamDoubleSnprintf
+
+}} //namespace cta::log
diff --git a/common/log/ParamTest.cpp b/common/log/ParamTest.cpp
new file mode 100644
index 0000000000..549a7fe228
--- /dev/null
+++ b/common/log/ParamTest.cpp
@@ -0,0 +1,59 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#include "common/log/Param.hpp"
+
+#include <gtest/gtest.h>
+#include <memory>
+
+namespace unitTests {
+
+class cta_log_ParamTest: public ::testing::Test {
+protected:
+
+  void SetUp() {
+  }
+
+  void TearDown() {
+  }
+}; // cta_log_ParamTest
+
+TEST_F(cta_log_ParamTest, testConstructorWithAString) {
+  using namespace cta::log;
+  std::unique_ptr<Param> param;
+
+  ASSERT_NO_THROW(param.reset(new Param("Name", "Value")));
+  ASSERT_EQ(std::string("Name"), param->getName());
+  ASSERT_EQ(std::string("Value"), param->getValue());
+}
+
+TEST_F(cta_log_ParamTest, testConstructorWithAnInt) {
+  using namespace cta::log;
+  std::unique_ptr<Param> param;
+
+  ASSERT_NO_THROW(param.reset(new Param("Name", 1234)));
+  ASSERT_EQ(std::string("Name"), param->getName());
+  ASSERT_EQ(std::string("1234"), param->getValue());
+}
+
+} // namespace unitTests
diff --git a/common/log/StringLogger.cpp b/common/log/StringLogger.cpp
new file mode 100644
index 0000000000..10726b061c
--- /dev/null
+++ b/common/log/StringLogger.cpp
@@ -0,0 +1,324 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Interface to the CASTOR logging system, with string output.
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#include "common/log/StringLogger.hpp"
+#include "common/utils/Utils.hpp"
+
+#include <errno.h>
+#include <sstream>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/un.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+cta::log::StringLogger::StringLogger(
+  const std::string &programName):
+  Logger(programName),
+  m_maxMsgLen(determineMaxMsgLen()),
+  m_priorityToText(generatePriorityToTextMap()) {
+  initMutex();
+}
+
+//------------------------------------------------------------------------------
+// determineMaxMsgLen
+//------------------------------------------------------------------------------
+size_t cta::log::StringLogger::determineMaxMsgLen() const {
+  return DEFAULT_SYSLOG_MSGLEN;
+}
+
+//------------------------------------------------------------------------------
+// generatePriorityToTextMap
+//------------------------------------------------------------------------------
+std::map<int, std::string>
+  cta::log::StringLogger::generatePriorityToTextMap() const 
+   {
+  std::map<int, std::string> m;
+
+  try {
+    m[LOG_EMERG]   = "Emerg";
+    m[LOG_ALERT]   = "Alert";
+    m[LOG_CRIT]    = "Crit";
+    m[LOG_ERR]     = "Error";
+    m[LOG_WARNING] = "Warn";
+    m[LOG_NOTICE]  = "Notice";
+    m[LOG_INFO]    = "Info";
+    m[LOG_DEBUG]   = "Debug";
+  } catch(std::exception &se) {
+    cta::exception::Exception ex;
+    ex.getMessage() << "Failed to generate priority to text mapping: " <<
+      se.what();
+    throw ex;
+  }
+
+  return m;
+}
+
+//------------------------------------------------------------------------------
+// initMutex
+//------------------------------------------------------------------------------
+void cta::log::StringLogger::initMutex() {
+  pthread_mutexattr_t attr;
+  int rc = pthread_mutexattr_init(&attr);
+  if(0 != rc) {
+    cta::exception::Exception ex;
+    ex.getMessage() << "Failed to initialize mutex attribute for m_mutex: " <<
+      Utils::errnoToString(rc);
+    throw ex;
+  }
+  rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
+  if(0 != rc) {
+    cta::exception::Exception ex;
+    ex.getMessage() << "Failed to set mutex type of m_mutex: " <<
+      Utils::errnoToString(rc);
+    throw ex;
+  }
+  rc = pthread_mutex_init(&m_mutex, NULL);
+   if(0 != rc) {
+     cta::exception::Exception ex;
+     ex.getMessage() << "Failed to initialize m_mutex: " <<
+       Utils::errnoToString(rc);
+     throw ex;
+   }
+  rc = pthread_mutexattr_destroy(&attr);
+  if(0 != rc) {
+    pthread_mutex_destroy(&m_mutex);
+    cta::exception::Exception ex;
+    ex.getMessage() << "Failed to destroy mutex attribute of m_mutex: " <<
+      Utils::errnoToString(rc);
+    throw ex;
+  }
+}
+
+//------------------------------------------------------------------------------
+// destructor
+//------------------------------------------------------------------------------
+cta::log::StringLogger::~StringLogger() {
+}
+
+//------------------------------------------------------------------------------
+// prepareForFork
+//------------------------------------------------------------------------------
+void cta::log::StringLogger::prepareForFork() {
+}
+
+//-----------------------------------------------------------------------------
+// operator() 
+//-----------------------------------------------------------------------------
+void cta::log::StringLogger::operator() (
+  const int priority,
+  const std::string &msg,
+  const std::vector<Param> &params,
+  const struct timeval &timeStamp) {
+  operator() (priority, msg, params.begin(), params.end(), timeStamp);
+}
+
+//-----------------------------------------------------------------------------
+// operator() 
+//-----------------------------------------------------------------------------
+void cta::log::StringLogger::operator() (
+  const int priority,
+  const std::string &msg,
+  const std::list<Param> &params,
+  const struct timeval &timeStamp) {
+  operator() (priority, msg, params.begin(), params.end(), timeStamp);
+}
+
+//-----------------------------------------------------------------------------
+// operator() 
+//-----------------------------------------------------------------------------
+void cta::log::StringLogger::operator() (
+  const int priority,
+  const std::string &msg,
+  const int numParams,
+  const log::Param params[],
+  const struct timeval &timeStamp) {
+  operator() (priority, msg, params, params+numParams, timeStamp);
+}
+
+//-----------------------------------------------------------------------------
+// buildSyslogHeader
+//-----------------------------------------------------------------------------
+std::string cta::log::StringLogger::buildSyslogHeader(
+  const int priority,
+  const struct timeval &timeStamp,
+  const int pid) const throw() {
+  char buf[80];
+  int bufLen = sizeof(buf);
+  int len = 0;
+  std::ostringstream oss;
+
+  oss << "<" << priority << ">";
+
+  struct tm localTime;
+  localtime_r(&(timeStamp.tv_sec), &localTime);
+  len += strftime(buf, bufLen, "%Y-%m-%dT%T", &localTime);
+  len += snprintf(buf + len, bufLen - len, ".%06ld",
+    (unsigned long)timeStamp.tv_usec);
+  len += strftime(buf + len, bufLen - len, "%z: ", &localTime);
+  // dirty trick to have the proper timezone format (':' between hh and mm)
+  buf[len-2] = buf[len-3];
+  buf[len-3] = buf[len-4];
+  buf[len-4] = ':';
+  buf[sizeof(buf) - 1] = '\0';
+  oss << buf << m_programName.c_str() << "[" << pid << "]: ";
+  return oss.str();
+}
+
+//-----------------------------------------------------------------------------
+// cleanString
+//-----------------------------------------------------------------------------
+std::string cta::log::StringLogger::cleanString(const std::string &s,
+  const bool replaceSpaces) {
+
+  //find first non white char
+  const std::string& spaces="\t\n\v\f\r ";
+  size_t beginpos = s.find_first_not_of(spaces);
+  std::string::const_iterator it1;
+  if (std::string::npos != beginpos)
+    it1 = beginpos + s.begin();
+  else
+    it1 = s.begin();
+  
+  //find last non white char
+  std::string::const_iterator it2;
+  size_t endpos = s.find_last_not_of(spaces);
+  if (std::string::npos != endpos) 
+    it2 = endpos + 1 + s.begin();
+  else 
+    it2 = s.end();
+  
+  std::string result(it1, it2);
+  
+//  if (s.begin() == it1 && it2 == s.end()) 
+//    result="";
+  
+  for (std::string::iterator it = result.begin(); it != result.end(); ++it) {
+
+    // Replace newline and tab with a space
+    if (replaceSpaces) {
+      if ('\t' == *it) 
+        *it = ' ';
+      
+      if ('\n' == *it) 
+        *it = ' ';
+      
+      // Replace spaces with underscore
+      if (' ' == *it) 
+        *it = '_';
+    }
+    // Replace double quotes with single quotes
+    if ('"' == *it) 
+      *it = '\'';
+  }
+  return result;
+   
+}
+
+//-----------------------------------------------------------------------------
+// reducedSyslog
+//-----------------------------------------------------------------------------
+void cta::log::StringLogger::reducedSyslog(std::string msg) {
+  // Truncate the log message if it exceeds the permitted maximum
+  if(msg.length() > m_maxMsgLen) {
+    msg.resize(m_maxMsgLen);
+    msg[msg.length() - 1] = '\n';
+  }
+
+  // enter critical section
+  const int mutex_lock_rc = pthread_mutex_lock(&m_mutex);
+  // Do nothing if we failed to enter the critical section
+  if(0 != mutex_lock_rc) {
+    return;
+  }
+
+  // Append the message to the log
+  m_log << msg << std::endl;
+  
+  // Temporary hack: also print them out:
+  printf (msg.c_str());
+
+  // Leave critical section.
+  pthread_mutex_unlock(&m_mutex);
+}
+
+//-----------------------------------------------------------------------------
+// operator() 
+//-----------------------------------------------------------------------------
+void cta::log::StringLogger::operator() (
+  const int priority,
+  const std::string &msg,
+  const std::vector<Param> &params) {
+
+  struct timeval timeStamp;
+  gettimeofday(&timeStamp, NULL);
+
+  operator() (priority, msg, params.begin(), params.end(), timeStamp);
+}
+
+//-----------------------------------------------------------------------------
+// operator() 
+//-----------------------------------------------------------------------------
+void cta::log::StringLogger::operator() (
+  const int priority,
+  const std::string &msg,
+  const std::list<Param> &params) {
+
+  struct timeval timeStamp;
+  gettimeofday(&timeStamp, NULL);
+
+  operator() (priority, msg, params.begin(), params.end(), timeStamp);
+}
+
+//-----------------------------------------------------------------------------
+// operator() 
+//-----------------------------------------------------------------------------
+void cta::log::StringLogger::operator() (
+  const int priority,
+  const std::string &msg,
+  const int numParams,
+  const log::Param params[]) {
+
+  struct timeval timeStamp;
+  gettimeofday(&timeStamp, NULL);
+
+  operator() (priority, msg, numParams, params, timeStamp);
+}
+
+//-----------------------------------------------------------------------------
+// operator() 
+//-----------------------------------------------------------------------------
+void cta::log::StringLogger::operator() (
+  const int priority,
+  const std::string &msg) {
+
+  Param *emptyParams = NULL;
+  operator() (priority, msg, 0, emptyParams);
+}
diff --git a/common/log/StringLogger.hpp b/common/log/StringLogger.hpp
new file mode 100644
index 0000000000..bb58ffb706
--- /dev/null
+++ b/common/log/StringLogger.hpp
@@ -0,0 +1,385 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once 
+
+#include "common/log/Logger.hpp"
+
+#include <map>
+#include <pthread.h>
+#include <syslog.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#include <mach/mach.h>
+#endif
+
+namespace cta { namespace log {
+
+/**
+ * Class implementing the API of the CASTOR logging system.
+ */
+class StringLogger: public Logger {
+public:
+
+  /**
+   * Constructor
+   *
+   * @param programName The name of the program to be prepended to every log
+   * message.
+   */
+  StringLogger(const std::string &programName);
+
+  /**
+   * Destructor.
+   */
+  ~StringLogger();
+
+  /**
+   * Prepares the logger object for a call to fork().
+   *
+   * No further calls to operator() should be made after calling this
+   * method until the call to fork() has completed.
+   */
+  void prepareForFork() ;
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() allows the caller to specify the
+   * time stamp of the log message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   * @param timeStamp the time stamp of the log message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg,
+    const std::vector<Param> &params,
+    const struct timeval &timeStamp);
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() allows the caller to specify the
+   * time stamp of the log message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   * @param timeStamp the time stamp of the log message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg,
+    const std::list<Param> &params,
+    const struct timeval &timeStamp);
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() allows the caller to specify the
+   * time stamp of the log message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param numParams the number of parameters in the message.
+   * @param params the parameters of the message.
+   * @param timeStamp the time stamp of the log message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg,
+    const int numParams,
+    const Param params[],
+    const struct timeval &timeStamp);
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() implicitly uses the current time as
+   * the time stamp of the message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg,
+    const std::vector<Param> &params);
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() implicitly uses the current time as
+   * the time stamp of the message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg,
+    const std::list<Param> &params);
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() implicitly uses the current time as
+   * the time stamp of the message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param numParams the number of parameters in the message.
+   * @param params the parameters of the message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg,
+    const int numParams,
+    const Param params[]);
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() implicitly uses the current time as
+   * the time stamp of the message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg);
+  
+  /**
+   * Extractor for the resulting logs.
+   */
+  
+  std::string getLog() { return m_log.str(); }
+
+private:
+
+  /**
+   * Default size of a syslog message.
+   */
+  static const size_t DEFAULT_SYSLOG_MSGLEN = 1024;
+
+  /**
+   * Default size of a rsyslog message.
+   */
+  static const size_t DEFAULT_RSYSLOG_MSGLEN = 2000;
+
+  /**
+   * Maximum length of a parameter name.
+   */
+  static const size_t LOG_MAX_PARAMNAMELEN = 20;
+
+  /**
+   * Maximum length of a string value.
+   */
+  static const size_t LOG_MAX_PARAMSTRLEN = 1024;
+
+  /**
+   * Maximum length of a log message.
+   */
+  static const size_t LOG_MAX_LINELEN = 8192;
+
+  /**
+   * The maximum message length that the client syslog server can handle.
+   */
+  const size_t m_maxMsgLen;
+
+  /**
+   * Mutex used to protect the critical section of the StringLogger
+   * object.
+   */
+  pthread_mutex_t m_mutex;
+
+  /**
+   * The file descriptor of the socket used to send messages to syslog.
+   */
+  std::stringstream m_log;
+
+  /**
+   * Map from syslog integer priority to textual representation.
+   */
+  const std::map<int, std::string> m_priorityToText;
+
+  /**
+   * Determines the maximum message length that the client syslog server can
+   * handle.
+   *
+   * @return The maximum message length that the client syslog server can
+   * handle.
+   */
+  size_t determineMaxMsgLen() const;
+
+  /**
+   * Generates and returns the mapping between syslog priorities and their
+   * textual representations.
+   */
+  std::map<int, std::string> generatePriorityToTextMap() const
+    ;
+
+  /**
+   * Initializes the mutex used to protect the critical section of the
+   * StringLogger object.
+   */
+  void initMutex() ;
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() allows the caller to specify the
+   * time stamp of the log message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param paramsBegin the first parameters of the message.
+   * @param paramsEnd one past the end of the parameters of the message.
+   * @param timeStamp the time stamp of the log message.
+   */
+  template<typename ParamIterator> void operator() (
+    const int priority,
+    const std::string &msg,
+    ParamIterator paramsBegin,
+    ParamIterator paramsEnd,
+    const struct timeval &timeStamp) throw() {
+    //-------------------------------------------------------------------------
+    // Note that we do here part of the work of the real syslog call, by
+    // building the message ourselves. We then only call a reduced version of
+    // syslog (namely reducedSyslog). The reason behind it is to be able to set
+    // the message timestamp ourselves, in case we log messages asynchronously,
+    // as we do when retrieving logs from the DB
+    //-------------------------------------------------------------------------
+
+    // Try to find the textual representation of the syslog priority
+    std::map<int, std::string>::const_iterator priorityTextPair =
+      m_priorityToText.find(priority);
+
+    // Do nothing if the log priority is not valid
+    if(m_priorityToText.end() == priorityTextPair) {
+      return;
+    }
+
+    // Safe to get a reference to the textual representation of the priority
+    const std::string &priorityText = priorityTextPair->second;
+
+    std::ostringstream logMsg;
+
+    // Start message with priority, time, program and PID (syslog standard
+    // format)
+    logMsg << buildSyslogHeader(priority | LOG_LOCAL3, timeStamp, getpid());
+
+    // Determine the thread id
+#ifdef __APPLE__
+    const int tid = mach_thread_self();
+#else
+    const int tid = syscall(__NR_gettid);
+#endif
+
+    // Append the log level, the thread id and the message text
+    logMsg << "LVL=" << priorityText << " TID=" << tid << " MSG=\"" << msg <<
+      "\" ";
+
+    // Process parameters
+    for(ParamIterator itor = paramsBegin; itor != paramsEnd; itor++) {
+      const Param &param = *itor;
+
+      // Check the parameter name, if it's an empty string set the value to
+      // "Undefined".
+      const std::string name = param.getName() == "" ? "Undefined" :
+        cleanString(param.getName(), true);
+
+      // Process the parameter value
+      const std::string value = cleanString(param.getValue(), false);
+
+      // Write the name and value to the buffer
+      logMsg << name << "=\"" << value << "\" ";
+    }
+
+    // Terminate the string
+    logMsg << "\n";
+
+    reducedSyslog(logMsg.str());
+  }
+
+  /**
+   * Build the header of a syslog message.
+   *
+   * @param priority The priority of the message.
+   * @param timeStamp The time stamp of the message.
+   * @param pid The process ID of the process logging the message.
+   * @return The header of the syslog message.
+   */
+  std::string buildSyslogHeader(
+    const int priority,
+    const struct timeval &timeStamp,
+    const int pid) const throw();
+
+  /**
+   * Creates a clean version of the specified string ready for use with syslog.
+   *
+   * @param s The string to be cleaned.
+   * @param replaceSpaces Set to true if spaces should be replaced by
+   * underscores.
+   * @return A cleaned version of the string.
+   */
+  std::string cleanString(const std::string &s, const bool replaceSpaces);
+
+  /**
+   * A reduced version of syslog.  This method is able to set the message
+   * timestamp.  This is necessary when logging messages asynchronously of there
+   * creation, such as when retrieving logs from the DB.
+   *
+   * @param msg The message to be logged.
+   */
+  void reducedSyslog(std::string msg);
+
+}; // class StringLogger
+
+} // namespace log
+} // namespace castor
+
+
+
+
diff --git a/common/log/StringLoggerTest.cpp b/common/log/StringLoggerTest.cpp
new file mode 100644
index 0000000000..34adf5e70d
--- /dev/null
+++ b/common/log/StringLoggerTest.cpp
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Interface to the CASTOR logging system
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#include "StringLogger.hpp"
+
+#include <gtest/gtest.h>
+
+using namespace castor::log;
+
+namespace unitTests {
+  TEST(castor_log_StringLogger, basicTest) {
+    std::string jat = "Just a test";
+    StringLogger sl("castor_log_StringLogger");
+    sl(LOG_INFO, jat);
+    ASSERT_NE(std::string::npos, sl.getLog().find(jat));
+  }
+}
diff --git a/common/log/SyslogLogger.cpp b/common/log/SyslogLogger.cpp
new file mode 100644
index 0000000000..99c23c20fe
--- /dev/null
+++ b/common/log/SyslogLogger.cpp
@@ -0,0 +1,493 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Interface to the CASTOR logging system
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#include "common/log/SyslogLogger.hpp"
+#include "common/utils/Utils.hpp"
+#include "common/Configuration.hpp"
+
+#include <errno.h>
+#include <sstream>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/un.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+cta::log::SyslogLogger::SyslogLogger(
+  const std::string &programName):
+  Logger(programName),
+  m_maxMsgLen(determineMaxMsgLen()),
+  m_logFile(-1),
+  m_priorityToText(generatePriorityToTextMap()),
+  m_configTextToPriority(generateConfigTextToPriorityMap()) {
+  initMutex();
+}
+
+//------------------------------------------------------------------------------
+// determineMaxMsgLen
+//------------------------------------------------------------------------------
+size_t cta::log::SyslogLogger::determineMaxMsgLen() const{
+  size_t msgSize = 0;
+  // Determine the size automatically, this is not guaranteed to work!
+  FILE *const fp = fopen("/etc/rsyslog.conf", "r");
+  if(fp) {
+    char buffer[1024];
+
+    // The /etc/rsyslog.conf file exists so we assume the default message
+    // size of 2K.
+    msgSize = DEFAULT_RSYSLOG_MSGLEN;
+
+    // In rsyslog versions >= 3.21.4, the maximum size of a message became
+    // configurable through the $MaxMessageSize global config directive.
+    // Here we attempt to find out if the user has increased the size!
+    while(fgets(buffer, sizeof(buffer), fp) != NULL) {
+      if(strncasecmp(buffer, "$MaxMessageSize", 15)) {
+        continue; // Option not of interest
+      }
+      msgSize = atol(&buffer[15]);
+    }
+    fclose(fp);
+  }
+  // If the /etc/rsyslog.conf file is missing which implies that we are
+  // running on a stock syslogd system, therefore the message size is
+  // governed by the syslog RFC: http://www.faqs.org/rfcs/rfc3164.html
+
+  // Check that the size of messages falls within acceptable limits
+  if((msgSize >= DEFAULT_SYSLOG_MSGLEN) && (msgSize <= LOG_MAX_LINELEN)) {
+    return msgSize;
+  } else {
+    return DEFAULT_SYSLOG_MSGLEN;
+  }
+}
+
+//------------------------------------------------------------------------------
+// generatePriorityToTextMap
+//------------------------------------------------------------------------------
+std::map<int, std::string>
+  cta::log::SyslogLogger::generatePriorityToTextMap() const {
+  std::map<int, std::string> m;
+
+  try {
+    m[LOG_EMERG]   = "Emerg";
+    m[LOG_ALERT]   = "Alert";
+    m[LOG_CRIT]    = "Crit";
+    m[LOG_ERR]     = "Error";
+    m[LOG_WARNING] = "Warn";
+    m[LOG_NOTICE]  = "Notice";
+    m[LOG_INFO]    = "Info";
+    m[LOG_DEBUG]   = "Debug";
+  } catch(std::exception &se) {
+    cta::exception::Exception ex;
+    ex.getMessage() << "Failed to generate priority to text mapping: " <<
+      se.what();
+    throw ex;
+  }
+
+  return m;
+}
+
+//------------------------------------------------------------------------------
+// generateConfigTextToPriorityMap
+//------------------------------------------------------------------------------
+std::map<std::string, int>
+  cta::log::SyslogLogger::generateConfigTextToPriorityMap() const {
+  std::map<std::string, int> m;
+
+  try {
+    m["LOG_EMERG"]   = LOG_EMERG;
+    m["LOG_ALERT"]   = LOG_ALERT;
+    m["LOG_CRIT"]    = LOG_CRIT;
+    m["LOG_ERR"]     = LOG_ERR;
+    m["LOG_WARNING"] = LOG_WARNING;
+    m["LOG_NOTICE"]  = LOG_NOTICE;
+    m["LOG_INFO"]    = LOG_INFO;
+    m["LOG_DEBUG"]   = LOG_DEBUG;
+  } catch(std::exception &se) {
+    cta::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to generate configuration text to priority mapping: " <<
+      se.what();
+    throw ex;
+  }
+
+  return m;
+}
+
+//------------------------------------------------------------------------------
+// initMutex
+//------------------------------------------------------------------------------
+void cta::log::SyslogLogger::initMutex() {
+  pthread_mutexattr_t attr;
+  int rc = pthread_mutexattr_init(&attr);
+  if(0 != rc) {
+    cta::exception::Exception ex;
+    ex.getMessage() << "Failed to initialize mutex attribute for m_mutex: " <<
+      Utils::errnoToString(rc);
+    throw ex;
+  }
+  rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
+  if(0 != rc) {
+    cta::exception::Exception ex;
+    ex.getMessage() << "Failed to set mutex type of m_mutex: " <<
+      Utils::errnoToString(rc);
+    throw ex;
+  }
+  rc = pthread_mutex_init(&m_mutex, NULL);
+   if(0 != rc) {
+     cta::exception::Exception ex;
+     ex.getMessage() << "Failed to initialize m_mutex: " <<
+       Utils::errnoToString(rc);
+     throw ex;
+   }
+  rc = pthread_mutexattr_destroy(&attr);
+  if(0 != rc) {
+    pthread_mutex_destroy(&m_mutex);
+    cta::exception::Exception ex;
+    ex.getMessage() << "Failed to destroy mutex attribute of m_mutex: " <<
+      Utils::errnoToString(rc);
+    throw ex;
+  }
+}
+
+//------------------------------------------------------------------------------
+// destructor
+//------------------------------------------------------------------------------
+cta::log::SyslogLogger::~SyslogLogger() {
+  closeLog();
+}
+
+//------------------------------------------------------------------------------
+// prepareForFork
+//------------------------------------------------------------------------------
+void cta::log::SyslogLogger::prepareForFork() {
+  // Enter critical section
+  {
+    const int mutex_lock_rc = pthread_mutex_lock(&m_mutex);
+    if(0 != mutex_lock_rc) {
+      cta::exception::Exception ex;
+      ex.getMessage() << "Failed to lock mutex of logger's critcial section: "
+        << Utils::errnoToString(mutex_lock_rc);
+      throw ex;
+    }
+  }
+
+  closeLog();
+
+  // Leave critical section.
+  {
+    const int mutex_unlock_rc = pthread_mutex_unlock(&m_mutex);
+    if(0 != mutex_unlock_rc) {
+      cta::exception::Exception ex;
+      ex.getMessage() << "Failed to unlock mutex of logger's critcial section: "
+        << Utils::errnoToString(mutex_unlock_rc);
+      throw ex;
+    }
+  }
+}
+
+//------------------------------------------------------------------------------
+// openLog
+//------------------------------------------------------------------------------
+void cta::log::SyslogLogger::openLog() {
+  if(-1 != m_logFile) {
+    return;
+  }
+
+  {
+    struct sockaddr_un syslogAddr;
+    syslogAddr.sun_family = AF_UNIX;
+    strncpy(syslogAddr.sun_path, _PATH_LOG, sizeof(syslogAddr.sun_path));
+    m_logFile = socket(AF_UNIX, SOCK_DGRAM, 0);
+  }
+  if(-1 == m_logFile) {
+    return;
+  }
+
+  if(-1 == fcntl(m_logFile, F_SETFD, FD_CLOEXEC)) {
+    close(m_logFile);
+    m_logFile = -1;
+    return;
+  }
+
+  {
+    struct sockaddr_un syslogAddr;
+    syslogAddr.sun_family = AF_UNIX;
+    strncpy(syslogAddr.sun_path, _PATH_LOG, sizeof(syslogAddr.sun_path));
+    if(-1 == connect(m_logFile, (struct sockaddr *)&syslogAddr,
+      sizeof(syslogAddr))) {
+      close(m_logFile);
+      m_logFile = -1;
+      return;
+    }
+  }
+
+#ifdef __APPLE__
+  {
+    // MAC has has no MSG_NOSIGNAL
+    // but >= 10.2 comes with SO_NOSIGPIPE
+    int set = 1;
+    if(0 != setsockopt(m_logFile, SOL_SOCKET, SO_NOSIGPIPE, &set,
+      sizeof(int))) {
+      close(m_logFile);
+      m_logFile = -1;
+      return;
+    }
+  }
+#endif
+}
+
+//------------------------------------------------------------------------------
+// closeLog
+//------------------------------------------------------------------------------
+void cta::log::SyslogLogger::closeLog() {
+  if(-1 == m_logFile) {
+    return;
+  }
+  close(m_logFile);
+  m_logFile = -1;
+}
+
+//-----------------------------------------------------------------------------
+// operator() 
+//-----------------------------------------------------------------------------
+void cta::log::SyslogLogger::operator() (
+  const int priority,
+  const std::string &msg,
+  const std::vector<Param> &params,
+  const struct timeval &timeStamp) {
+  operator() (priority, msg, params.begin(), params.end(), timeStamp);
+}
+
+//-----------------------------------------------------------------------------
+// operator() 
+//-----------------------------------------------------------------------------
+void cta::log::SyslogLogger::operator() (
+  const int priority,
+  const std::string &msg,
+  const std::list<Param> &params,
+  const struct timeval &timeStamp) {
+  operator() (priority, msg, params.begin(), params.end(), timeStamp);
+}
+
+//-----------------------------------------------------------------------------
+// operator() 
+//-----------------------------------------------------------------------------
+void cta::log::SyslogLogger::operator() (
+  const int priority,
+  const std::string &msg,
+  const int numParams,
+  const log::Param params[],
+  const struct timeval &timeStamp) {
+  operator() (priority, msg, params, params+numParams, timeStamp);
+}
+
+//-----------------------------------------------------------------------------
+// buildSyslogHeader
+//-----------------------------------------------------------------------------
+std::string cta::log::SyslogLogger::buildSyslogHeader(
+  const int priority,
+  const struct timeval &timeStamp,
+  const int pid) const {
+  char buf[80];
+  int bufLen = sizeof(buf);
+  int len = 0;
+  std::ostringstream oss;
+
+  oss << "<" << priority << ">";
+
+  struct tm localTime;
+  localtime_r(&(timeStamp.tv_sec), &localTime);
+  len += strftime(buf, bufLen, "%Y-%m-%dT%T", &localTime);
+  len += snprintf(buf + len, bufLen - len, ".%06ld",
+    (unsigned long)timeStamp.tv_usec);
+  len += strftime(buf + len, bufLen - len, "%z: ", &localTime);
+  // dirty trick to have the proper timezone format (':' between hh and mm)
+  buf[len-2] = buf[len-3];
+  buf[len-3] = buf[len-4];
+  buf[len-4] = ':';
+  buf[sizeof(buf) - 1] = '\0';
+  oss << buf << m_programName.c_str() << "[" << pid << "]: ";
+  return oss.str();
+}
+
+//-----------------------------------------------------------------------------
+// cleanString
+//-----------------------------------------------------------------------------
+std::string cta::log::SyslogLogger::cleanString(const std::string &s,
+  const bool replaceUnderscores) const {
+  // Trim both left and right white-space
+  std::string result = Utils::trimString(s);
+  
+  for (std::string::iterator it = result.begin(); it != result.end(); ++it) {
+
+    // Replace double quote with single quote
+    if ('"' == *it) {
+      *it = '\'';
+    }
+    
+    // Replace newline and tab with a space
+    if ('\t' == *it || '\n' == *it) {
+      *it = ' ';
+    }
+
+    // If requested, replace spaces with underscores
+    if(replaceUnderscores && ' ' == *it) {
+      *it = '_';
+    }
+  }
+
+  return result;
+}
+
+//-----------------------------------------------------------------------------
+// reducedSyslog
+//-----------------------------------------------------------------------------
+void cta::log::SyslogLogger::reducedSyslog(std::string msg) {
+  // Truncate the log message if it exceeds the permitted maximum
+  if(msg.length() > m_maxMsgLen) {
+    msg.resize(m_maxMsgLen);
+    msg[msg.length() - 1] = '\n';
+  }
+
+  int send_flags = 0;
+#ifndef __APPLE__
+  // MAC has has no MSG_NOSIGNAL
+  // but >= 10.2 comes with SO_NOSIGPIPE
+  send_flags = MSG_NOSIGNAL;
+#endif
+  // enter critical section
+  const int mutex_lock_rc = pthread_mutex_lock(&m_mutex);
+  // Do nothing if we failed to enter the critical section
+  if(0 != mutex_lock_rc) {
+    return;
+  }
+
+  // Try to connect if not already connected
+  openLog();
+
+  // If connected
+  if(-1 != m_logFile) {
+    // If sending the log message fails then try to reopen the syslog
+    // connection and try again
+    if(0 > send(m_logFile, msg.c_str(), msg.length(), send_flags)) {
+      closeLog();
+      openLog();
+      if (-1 != m_logFile) {
+        // If the second attempt to send the log message fails then give up and
+        // attempt re-open next time
+        if(0 > send(m_logFile, msg.c_str(), msg.length(), send_flags)) {
+          closeLog();
+        }
+      }
+    }
+  }
+
+  // Leave critical section.
+  pthread_mutex_unlock(&m_mutex);
+}
+
+//-----------------------------------------------------------------------------
+// operator() 
+//-----------------------------------------------------------------------------
+void cta::log::SyslogLogger::operator() (
+  const int priority,
+  const std::string &msg,
+  const std::vector<Param> &params) {
+
+  struct timeval timeStamp;
+  gettimeofday(&timeStamp, NULL);
+
+  operator() (priority, msg, params.begin(), params.end(), timeStamp);
+}
+
+//-----------------------------------------------------------------------------
+// operator() 
+//-----------------------------------------------------------------------------
+void cta::log::SyslogLogger::operator() (
+  const int priority,
+  const std::string &msg,
+  const std::list<Param> &params) {
+
+  struct timeval timeStamp;
+  gettimeofday(&timeStamp, NULL);
+
+  operator() (priority, msg, params.begin(), params.end(), timeStamp);
+}
+
+//-----------------------------------------------------------------------------
+// operator() 
+//-----------------------------------------------------------------------------
+void cta::log::SyslogLogger::operator() (
+  const int priority,
+  const std::string &msg,
+  const int numParams,
+  const log::Param params[]) {
+
+  struct timeval timeStamp;
+  gettimeofday(&timeStamp, NULL);
+
+  operator() (priority, msg, numParams, params, timeStamp);
+}
+
+//-----------------------------------------------------------------------------
+// operator() 
+//-----------------------------------------------------------------------------
+void cta::log::SyslogLogger::operator() (
+  const int priority,
+  const std::string &msg) {
+
+  Param *emptyParams = NULL;
+  operator() (priority, msg, 0, emptyParams);
+}
+
+//------------------------------------------------------------------------------
+// logMask
+//------------------------------------------------------------------------------
+int cta::log::SyslogLogger::logMask() const {
+  cta::common::Configuration conf;
+  const std::string confEnt =  conf.getConfEntString("LogMask", m_programName, 0);
+
+  // If the configuration file defines the log mask to use
+  if (!confEnt.empty()) {
+    // Try to find the corresponding integer priority value
+    std::map<std::string, int>::const_iterator itor =
+      m_configTextToPriority.find(confEnt);
+
+    // Return the priority if it was found else return the default INFO level
+    if(m_configTextToPriority.end() != itor) {
+      return itor->second;
+    } else {
+      return LOG_INFO;
+    }
+  }
+
+  // If the priority wasn't found, default is INFO level
+  return LOG_INFO;
+}
diff --git a/common/log/SyslogLogger.hpp b/common/log/SyslogLogger.hpp
new file mode 100644
index 0000000000..76f58afe69
--- /dev/null
+++ b/common/log/SyslogLogger.hpp
@@ -0,0 +1,474 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Interface to the CASTOR logging system
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#pragma once
+
+#include "common/log/Logger.hpp"
+
+#include <map>
+#include <pthread.h>
+#include <syslog.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#include <mach/mach.h>
+#endif
+
+namespace cta { namespace log {
+
+/**
+ * Class implementaing the API of the CASTOR logging system.
+ */
+class SyslogLogger: public Logger {
+public:
+
+  /**
+   * Constructor
+   *
+   * @param programName The name of the program to be prepended to every log
+   * message.
+   */
+  SyslogLogger(const std::string &programName);
+
+  /**
+   * Destructor.
+   */
+  ~SyslogLogger();
+
+  /**
+   * Prepares the logger object for a call to fork().
+   *
+   * No further calls to operator() should be made after calling this
+   * method until the call to fork() has completed.
+   */
+  void prepareForFork();
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() allows the caller to specify the
+   * time stamp of the log message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   * @param timeStamp the time stamp of the log message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg,
+    const std::vector<Param> &params,
+    const struct timeval &timeStamp);
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() allows the caller to specify the
+   * time stamp of the log message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   * @param timeStamp the time stamp of the log message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg,
+    const std::list<Param> &params,
+    const struct timeval &timeStamp);
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() allows the caller to specify the
+   * time stamp of the log message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param numParams the number of parameters in the message.
+   * @param params the parameters of the message.
+   * @param timeStamp the time stamp of the log message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg,
+    const int numParams,
+    const Param params[],
+    const struct timeval &timeStamp);
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() implicitly uses the current time as
+   * the time stamp of the message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg,
+    const std::vector<Param> &params);
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() implicitly uses the current time as
+   * the time stamp of the message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg,
+    const std::list<Param> &params);
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() implicitly uses the current time as
+   * the time stamp of the message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param numParams the number of parameters in the message.
+   * @param params the parameters of the message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg,
+    const int numParams,
+    const Param params[]);
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() implicitly uses the current time as
+   * the time stamp of the message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   */
+  void operator() (
+    const int priority,
+    const std::string &msg);
+
+  /**
+   * A template function that wraps operator() in order to get the compiler
+   * to automatically determine the size of the params parameter, therefore
+   *
+   * Note that this version of operator() allows the caller to specify the
+   * time stamp of the log message.
+   *
+   * @param priority the priority of the message as defined by the syslog
+   * API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   * @param timeStamp the time stamp of the log message.
+   */
+  template<int numParams> void operator() (
+    const int priority,
+    const std::string &msg,
+    cta::log::Param(&params)[numParams],
+    const struct timeval &timeStamp) {
+    operator() (priority, msg, numParams, params, timeStamp);
+  }
+
+  /**
+   * A template function that wraps operator() in order to get the compiler
+   * to automatically determine the size of the params parameter, therefore
+   * removing the need for the devloper to provide it explicity.
+   *
+   * Note that this version of operator() implicitly uses the current time as
+   * the time stamp of the message.
+   *
+   * @param priority the priority of the message as defined by the syslog
+   * API.
+   * @param msg the message.
+   * @param params the parameters of the message.
+   */
+  template<int numParams> void operator() (
+    const int priority,
+    const std::string &msg,
+    cta::log::Param(&params)[numParams]) {
+    operator() (priority, msg, numParams, params);
+  }
+
+protected:
+
+  /**
+   * Default size of a syslog message.
+   */
+  static const size_t DEFAULT_SYSLOG_MSGLEN = 1024;
+
+  /**
+   * Default size of a rsyslog message.
+   */
+  static const size_t DEFAULT_RSYSLOG_MSGLEN = 2000;
+
+  /**
+   * Maximum length of a parameter name.
+   */
+  static const size_t LOG_MAX_PARAMNAMELEN = 20;
+
+  /**
+   * Maximum length of a string value.
+   */
+  static const size_t LOG_MAX_PARAMSTRLEN = 1024;
+
+  /**
+   * Maximum length of a log message.
+   */
+  static const size_t LOG_MAX_LINELEN = 8192;
+
+  /**
+   * The maximum message length that the client syslog server can handle.
+   */
+  const size_t m_maxMsgLen;
+
+  /**
+   * Mutex used to protect the critical section of the SyslogLogger
+   * object.
+   */
+  pthread_mutex_t m_mutex;
+
+  /**
+   * The file descriptor of the socket used to send messages to syslog.
+   */
+  int m_logFile;
+
+  /**
+   * Map from syslog integer priority to textual representation.
+   */
+  const std::map<int, std::string> m_priorityToText;
+
+  /**
+   * Map from the possible string values of the LogMask parameters of
+   * /etc/castor.conf and their equivalent syslog priorities.
+   */
+  const std::map<std::string, int> m_configTextToPriority;
+
+  /**
+   * Returns the log mask for the program.
+   */
+  int logMask() const ;
+
+  /**
+   * Determines the maximum message length that the client syslog server can
+   * handle.
+   *
+   * @return The maximum message length that the client syslog server can
+   * handle.
+   */
+  size_t determineMaxMsgLen() const;
+
+  /**
+   * Generates and returns the mapping between syslog priorities and their
+   * textual representations.
+   */
+  std::map<int, std::string> generatePriorityToTextMap() const
+    ;
+
+  /**
+   * Generates and returns the mapping between the possible string values
+   * of the LogMask parameters of /etc/castor.conf and their equivalent
+   * syslog priorities.
+   */
+  std::map<std::string, int> generateConfigTextToPriorityMap() const
+    ;
+
+  /**
+   * Initializes the mutex used to protect the critical section of the
+   * SyslogLogger object.
+   */
+  void initMutex() ;
+
+  /**
+   * Connects to syslog.
+   *
+   * Please note that this method must be called from within the critical
+   * section of the SyslogLogger object.
+   *
+   * If the connection with syslog is already open then this method does
+   * nothing.
+   *
+   * This method does not throw an exception if the connection cannot be made
+   * to syslog.  In this case the internal state of the SyslogLogger
+   * object reflects the fact that no connection was made.
+   */
+  void openLog();
+
+  /**
+   * Writes a message into the CASTOR logging system. Note that no exception
+   * will ever be thrown in case of failure. Failures will actually be
+   * silently ignored in order to not impact the processing.
+   *
+   * Note that this version of operator() allows the caller to specify the
+   * time stamp of the log message.
+   *
+   * @param priority the priority of the message as defined by the syslog API.
+   * @param msg the message.
+   * @param paramsBegin the first parameters of the message.
+   * @param paramsEnd one past the end of the parameters of the message.
+   * @param timeStamp the time stamp of the log message.
+   */
+  template<typename ParamIterator> void operator() (
+    const int priority,
+    const std::string &msg,
+    ParamIterator paramsBegin,
+    ParamIterator paramsEnd,
+    const struct timeval &timeStamp) {
+    //-------------------------------------------------------------------------
+    // Note that we do here part of the work of the real syslog call, by
+    // building the message ourselves. We then only call a reduced version of
+    // syslog (namely reducedSyslog). The reason behind it is to be able to set
+    // the message timestamp ourselves, in case we log messages asynchronously,
+    // as we do when retrieving logs from the DB
+    //-------------------------------------------------------------------------
+
+    // Ignore messages whose priority is not of interest
+    if(priority > logMask()) {
+      return;
+    }
+
+    // Try to find the textual representation of the syslog priority
+    std::map<int, std::string>::const_iterator priorityTextPair =
+      m_priorityToText.find(priority);
+
+    // Do nothing if the log priority is not valid
+    if(m_priorityToText.end() == priorityTextPair) {
+      return;
+    }
+
+    // Safe to get a reference to the textual representation of the priority
+    const std::string &priorityText = priorityTextPair->second;
+
+    std::ostringstream logMsg;
+
+    // Start message with priority, time, program and PID (syslog standard
+    // format)
+    logMsg << buildSyslogHeader(priority | LOG_LOCAL3, timeStamp, getpid());
+
+    // Determine the thread id
+#ifdef __APPLE__
+    const int tid = mach_thread_self();
+#else
+    const int tid = syscall(__NR_gettid);
+#endif
+
+    // Append the log level, the thread id and the message text
+    logMsg << "LVL=" << priorityText << " TID=" << tid << " MSG=\"" << msg <<
+      "\" ";
+
+    // Process parameters
+    for(ParamIterator itor = paramsBegin; itor != paramsEnd; itor++) {
+      const Param &param = *itor;
+
+      // Check the parameter name, if it's an empty string set the value to
+      // "Undefined".
+      const std::string name = (param.getName() == "" ? "Undefined" :
+        cleanString(param.getName(), true));
+
+      // Process the parameter value
+      const std::string value = cleanString(param.getValue(), false);
+
+      // Write the name and value to the buffer
+      logMsg << name << "=\"" << value << "\" ";
+    }
+
+    // Terminate the string
+    logMsg << "\n";
+
+    reducedSyslog(logMsg.str());
+  }
+
+  /**
+   * Build the header of a syslog message.
+   *
+   * @param priority The priority of the message.
+   * @param timeStamp The time stamp of the message.
+   * @param pid The process ID of the process logging the message.
+   * @return The header of the syslog message.
+   */
+  std::string buildSyslogHeader(
+    const int priority,
+    const struct timeval &timeStamp,
+    const int pid) const ;
+
+  /**
+   * Creates a clean version of the specified string ready for use with syslog.
+   *
+   * @param s The string to be cleaned.
+   * @param replaceUnderscores Set to true if spaces should be replaced by
+   * underscores.
+   * @return A cleaned version of the string.
+   */
+  std::string cleanString(const std::string &s, const bool replaceUnderscores)
+    const ;
+
+  /**
+   * A reduced version of syslog.  This method is able to set the message
+   * timestamp.  This is necessary when logging messages asynchronously of there
+   * creation, such as when retrieving logs from the DB.
+   *
+   * @param msg The message to be logged.
+   */
+  void reducedSyslog(std::string msg);
+
+  /**
+   * Closes the connection to syslog.
+   *
+   * Please note that this method must be called from within the critical
+   * section of the SyslogLogger object.
+   *
+   * If the connection to syslog is already closed then this method does
+   * nothing.
+   */
+  void closeLog();
+
+}; // class SyslogLogger
+
+} // namespace log
+} // namespace castor
+
diff --git a/common/log/SyslogLoggerTest.cpp b/common/log/SyslogLoggerTest.cpp
new file mode 100644
index 0000000000..62a55502c3
--- /dev/null
+++ b/common/log/SyslogLoggerTest.cpp
@@ -0,0 +1,149 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#include "common/log/SyslogLogger.hpp"
+#include "common/log/TestingSyslogLogger.hpp"
+
+#include <gtest/gtest.h>
+#include <memory>
+#include <sys/time.h>
+
+namespace unitTests {
+
+class cta_log__SyslogLoggerTest: public ::testing::Test {
+public:
+  cta_log__SyslogLoggerTest(): m_log("unitttests") {
+  }
+protected:
+
+  virtual void SetUp() {
+  }
+
+  virtual void TearDown() {
+  }
+
+  cta::log::TestingSyslogLogger m_log;
+}; // class SyslogLoggerTest
+
+TEST_F(cta_log__SyslogLoggerTest, logMsgParamsVectorAndTimeStamp) {
+  using namespace cta::log;
+  std::vector<Param> params;
+  params.push_back(Param("testParam", "value of test param"));
+  struct timeval timeStamp;
+
+  ASSERT_EQ(0, gettimeofday(&timeStamp, NULL));
+
+  ASSERT_NO_THROW(m_log(
+    LOG_INFO,
+    "cta_log__SyslogLoggerTest logMsgParamsVectorAndTimeStamp",
+    params,
+    timeStamp));
+}
+
+TEST_F(cta_log__SyslogLoggerTest, logMsgParamsListAndTimeStamp) {
+  using namespace cta::log;
+  std::list<Param> params;
+  params.push_back(Param("testParam", "value of test param"));
+  struct timeval timeStamp;
+
+  ASSERT_EQ(0, gettimeofday(&timeStamp, NULL));
+
+  ASSERT_NO_THROW(m_log(
+    LOG_INFO,
+    "cta_log__SyslogLoggerTest logMsgParamsListAndTimeStamp",
+    params,
+    timeStamp));
+}
+
+TEST_F(cta_log__SyslogLoggerTest, logMsgParamsArrayAndTimeStamp) {
+  using namespace cta::log;
+  const int numParams = 1;
+  const Param params[1] = {Param("testParam", "value of test param")};
+  struct timeval timeStamp;
+
+  ASSERT_EQ(0, gettimeofday(&timeStamp, NULL));
+
+  ASSERT_NO_THROW(m_log(
+    LOG_INFO,
+    "cta_log__SyslogLoggerTest logMsgParamsArrayAndTimeStamp",
+    numParams,
+    params,
+    timeStamp));
+}
+
+TEST_F(cta_log__SyslogLoggerTest, logMsgAndParamsVector) {
+  using namespace cta::log;
+  std::vector<Param> params;
+  params.push_back(Param("testParam", "value of test param"));
+
+  ASSERT_NO_THROW(m_log(
+      LOG_INFO,
+      "cta_log__SyslogLoggerTest logMsgAndParamsVector",
+      params));
+}
+
+TEST_F(cta_log__SyslogLoggerTest, logMsgAndParamsList) {
+  using namespace cta::log;
+  std::list<Param> params;
+  params.push_back(Param("testParam", "value of test param"));
+
+  ASSERT_NO_THROW(
+    m_log(
+      LOG_INFO,
+      "cta_log__SyslogLoggerTest logMsgAndParamsList",
+      params));
+}
+
+TEST_F(cta_log__SyslogLoggerTest, logMsgAndParamsArray) {
+  using namespace cta::log;
+  const int numParams = 1;
+  const Param params[1] = {Param("testParam", "value of test param")};
+
+  ASSERT_NO_THROW(
+    m_log(
+      LOG_INFO,
+      "cta_log__SyslogLoggerTest logMsgAndParamsArray",
+      numParams,
+      params));
+}
+
+TEST_F(cta_log__SyslogLoggerTest, logMsg) {
+  using namespace cta::log;
+
+  ASSERT_NO_THROW(
+    m_log(LOG_INFO, "Calling logger without parameters or time stamp"));
+}   
+
+TEST_F(cta_log__SyslogLoggerTest, cleanStringWithoutReplacingUnderscores) {
+  const std::string s("  \t\t\n\n\"Hello there\tWorld\"  \t\t\n\n");
+  const std::string cleaned = m_log.cleanString(s, false);
+  ASSERT_EQ(std::string("'Hello there World'"), cleaned);
+}
+
+TEST_F(cta_log__SyslogLoggerTest, cleanStringReplacingUnderscores) {
+  const std::string s("  \t\t\n\n\"Hello there\tWorld\"  \t\t\n\n");
+  const std::string cleaned = m_log.cleanString(s, true);
+  ASSERT_EQ(std::string("'Hello_there_World'"), cleaned);
+}
+
+} // namespace unitTests
diff --git a/common/log/TestingSyslogLogger.hpp b/common/log/TestingSyslogLogger.hpp
new file mode 100644
index 0000000000..8fe0d1340a
--- /dev/null
+++ b/common/log/TestingSyslogLogger.hpp
@@ -0,0 +1,46 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "common/log/SyslogLogger.hpp"
+
+namespace cta { namespace log {
+
+/**
+ * Class used to facilitate unit testing by making public one or more of the
+ * protected members of its super class.
+ */
+class TestingSyslogLogger: public SyslogLogger {
+public:
+
+  /**
+   * Constructor
+   *
+   * @param programName The name of the program to be prepended to every log
+   * message.
+   */
+  TestingSyslogLogger(const std::string &programName): SyslogLogger(programName)  {}
+
+  using SyslogLogger::cleanString;
+
+}; // class TestingSyslogLogger
+
+}} // namespace cta::log
+
+
diff --git a/common/processCap/ProcessCap.cpp b/common/processCap/ProcessCap.cpp
new file mode 100644
index 0000000000..719fe028cc
--- /dev/null
+++ b/common/processCap/ProcessCap.cpp
@@ -0,0 +1,138 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#include "common/exception/Exception.hpp"
+#include "common/processCap/ProcessCap.hpp"
+#include "common/processCap/SmartCap.hpp"
+#include "common/utils/Utils.hpp"
+
+#include <errno.h>
+
+//------------------------------------------------------------------------------
+// destructor
+//------------------------------------------------------------------------------
+cta::server::ProcessCap::~ProcessCap() {}
+
+//------------------------------------------------------------------------------
+// getProcText
+//------------------------------------------------------------------------------
+std::string cta::server::ProcessCap::getProcText() {
+  try {
+    SmartCap cap(getProc());
+    return toText((cap_t)cap.get());
+  } catch(cta::exception::Exception &ne) {
+    cta::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to get text representation of the capabilities of the process: "
+      << ne.getMessage().str();
+    throw ex;
+  }
+}
+
+//------------------------------------------------------------------------------
+// getProc
+//------------------------------------------------------------------------------
+cap_t cta::server::ProcessCap::getProc() {
+  cap_t cap = cap_get_proc();
+  if(NULL == cap) {
+    cta::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to get the capabilities of the process: " 
+        << cta::Utils::errnoToString(errno);
+    throw ex;
+  }
+  return cap;
+}
+
+//------------------------------------------------------------------------------
+// toText
+//------------------------------------------------------------------------------
+std::string cta::server::ProcessCap::toText(
+  const cap_t cap) {
+  // Create a C++ string with the result of calling cap_to_text()
+  char *const text = cap_to_text(cap, NULL);
+  if(NULL == text) {
+    cta::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to create string representation of capability state: " 
+        << cta::Utils::errnoToString(errno);
+    throw ex;
+  }
+  std::string result(text);
+
+  // Free the memory allocated by cap_to_text()
+  if(cap_free(text)) {
+    cta::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to free string representation of capability state: " 
+        << cta::Utils::errnoToString(errno);
+    throw ex;
+  }
+
+  // Return the C++ string
+  return result;
+}
+
+//------------------------------------------------------------------------------
+// setProcText
+//------------------------------------------------------------------------------
+void cta::server::ProcessCap::setProcText(const std::string &text) {
+  try {
+    SmartCap cap(fromText(text));
+    setProc(cap.get());
+  } catch(cta::exception::Exception &ne) {
+    cta::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to set capabilities of process: " << ne.getMessage().str();
+    throw ex;
+  }
+}
+
+//------------------------------------------------------------------------------
+// fromText
+//------------------------------------------------------------------------------
+cap_t cta::server::ProcessCap::fromText(const std::string &text) {
+  const cap_t cap = cap_from_text(text.c_str());
+  if(NULL == cap) {
+    cta::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to create capability state from string representation"
+      ": text='" << text << "': " << cta::Utils::errnoToString(errno);
+    throw ex;
+  }
+
+  return cap;
+}
+
+//------------------------------------------------------------------------------
+// setProc
+//------------------------------------------------------------------------------
+void cta::server::ProcessCap::setProc(const cap_t cap) {
+  if(cap_set_proc(cap)) {
+    cta::exception::Exception ex;
+    ex.getMessage() <<
+      "Failed to set the capabilities of the process: " 
+        << cta::Utils::errnoToString(errno);
+    throw ex;
+  }
+}
diff --git a/common/processCap/ProcessCap.hpp b/common/processCap/ProcessCap.hpp
new file mode 100644
index 0000000000..b04d920161
--- /dev/null
+++ b/common/processCap/ProcessCap.hpp
@@ -0,0 +1,98 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#pragma once
+
+#include <string>
+#include <sys/capability.h>
+
+namespace cta { namespace server  {
+
+/**
+ * Class providing support for UNIX capabilities.
+ *
+ * This class is used to provide support for UNIX capbilities, so that
+ * subclasses can be created that override its virtual member functions.
+ * Unit testing is the primary use-case where you may want a dummy capabilities
+ * object that does nothing.
+ *
+ * Please note that process capabilities are not supported on Mac OS X.
+ */
+class ProcessCap {
+public:
+
+  /**
+   * Destructor.
+   */
+  virtual ~ProcessCap();
+
+  /**
+   * C++ wrapper around the C functions cap_get_proc() and cap_to_text().
+   *
+   * @return The string representation the capabilities of the current
+   * process.
+   */
+  virtual std::string getProcText();
+
+  /**
+   * C++ wrapper around the C functions cap_from_text() and cap_set_proc().
+   *
+   * @text The string representation the capabilities that the current
+   * process should have.
+   */
+  virtual void setProcText(const std::string &text);
+
+private:
+
+  /**
+   * C++ wrapper around the C function cap_get_proc().
+   *
+   * @return The capability state.
+   */
+  cap_t getProc();
+
+  /**
+   * C++ wrapper around the C function cap_to_text().
+   *
+   * @param cap The capability state.
+   */
+  std::string toText(const cap_t cap);
+
+  /**
+   * C++ wrapper around the C function cap_from_text().
+   *
+   * @return The capability state.
+   */
+  cap_t fromText(const std::string &text);
+
+  /**
+   * C++ wrapper around the C function cap_set_proc().
+   *
+   * @param cap The capability state.
+   */
+  void setProc(const cap_t cap);
+
+}; // class ProcessCap
+
+} // namespace server
+} // namespace castor
diff --git a/common/processCap/ProcessCapDummy.cpp b/common/processCap/ProcessCapDummy.cpp
new file mode 100644
index 0000000000..ae1e6a27bc
--- /dev/null
+++ b/common/processCap/ProcessCapDummy.cpp
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#include "castor/server/ProcessCapDummy.hpp"
+
+//------------------------------------------------------------------------------
+// destructor
+//------------------------------------------------------------------------------
+castor::server::ProcessCapDummy::~ProcessCapDummy()
+  throw() {
+}
+
+//------------------------------------------------------------------------------
+// getProcText
+//------------------------------------------------------------------------------
+std::string castor::server::ProcessCapDummy::getProcText() {
+  return m_text;
+}
+
+//------------------------------------------------------------------------------
+// setProcText
+//------------------------------------------------------------------------------
+void castor::server::ProcessCapDummy::setProcText(const std::string &text) {
+  m_text = text;
+}
diff --git a/common/processCap/ProcessCapDummy.hpp b/common/processCap/ProcessCapDummy.hpp
new file mode 100644
index 0000000000..6da07c2e97
--- /dev/null
+++ b/common/processCap/ProcessCapDummy.hpp
@@ -0,0 +1,73 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#pragma once
+
+#include "castor/server/ProcessCap.hpp"
+
+#include <string>
+#include <sys/capability.h>
+
+namespace castor {
+namespace server  {
+
+/**
+ * A dummy class that pretends to provide support for UNIX capabilities.
+ *
+ * This primary goal of this class is to facilitate unit testing.
+ */
+class ProcessCapDummy: public ProcessCap {
+public:
+
+  /**
+   * Destructor.
+   */
+  ~ProcessCapDummy() throw();
+
+  /**
+   * C++ wrapper around the C functions cap_get_proc() and cap_to_text().
+   *
+   * @return The string representation the capabilities of the current
+   * process.
+   */
+  std::string getProcText();
+
+  /**
+   * C++ wrapper around the C functions cap_from_text() and cap_set_proc().
+   *
+   * @text The string representation the capabilities that the current
+   * process should have.
+   */
+  void setProcText(const std::string &text);
+
+private:
+
+  /**
+   * The string representation of the current capability state.
+   */
+  std::string m_text;
+
+}; // class ProcessCapDummy
+
+} // namespace server
+} // namespace castor
diff --git a/common/processCap/SmartCap.cpp b/common/processCap/SmartCap.cpp
new file mode 100644
index 0000000000..a6f23dd425
--- /dev/null
+++ b/common/processCap/SmartCap.cpp
@@ -0,0 +1,97 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#include "common/exception/Exception.hpp"
+#include "common/processCap/SmartCap.hpp"
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+cta::server::SmartCap::SmartCap() throw():
+  m_cap(NULL) {
+}
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+cta::server::SmartCap::SmartCap(cap_t cap) throw():
+  m_cap(cap) {
+}
+
+//------------------------------------------------------------------------------
+// reset
+//------------------------------------------------------------------------------
+void cta::server::SmartCap::reset(cap_t cap) throw() {
+  // If the new capability state is not the one already owned
+  if(cap != m_cap) {
+
+    // If this smart pointer still owns a capability state then free it using
+    // cap_free()
+    if(NULL != m_cap) {
+      cap_free(m_cap);
+    }
+
+    // Take ownership of the new capability state
+    m_cap = cap;
+  }
+}
+
+//------------------------------------------------------------------------------
+// operator=
+//------------------------------------------------------------------------------
+cta::server::SmartCap &cta::server::SmartCap::operator=(SmartCap& obj) {
+  reset(obj.release());
+  return *this;
+}
+
+//------------------------------------------------------------------------------
+// destructor
+//------------------------------------------------------------------------------
+cta::server::SmartCap::~SmartCap() throw() {
+  reset();
+}
+
+//------------------------------------------------------------------------------
+// get
+//------------------------------------------------------------------------------
+cap_t cta::server::SmartCap::get() const throw() {
+  return m_cap;
+}
+
+//------------------------------------------------------------------------------
+// release
+//------------------------------------------------------------------------------
+cap_t cta::server::SmartCap::release() {
+  // If this smart pointer does not own a capbility state
+  if(NULL == m_cap) {
+    cta::exception::Exception ex;
+    ex.getMessage() << "Smart pointer does not own a capbility state";
+    throw(ex);
+  }
+
+  // Assigning NULL to m_cap indicates this smart pointer does not own a
+  // capability state
+  cap_t tmpCap = m_cap;
+  m_cap = NULL;
+  return tmpCap;
+}
diff --git a/common/processCap/SmartCap.hpp b/common/processCap/SmartCap.hpp
new file mode 100644
index 0000000000..d0500d3d2e
--- /dev/null
+++ b/common/processCap/SmartCap.hpp
@@ -0,0 +1,119 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#pragma once
+
+#include <stddef.h>
+#include <sys/capability.h>
+
+namespace cta { namespace server {
+
+/**
+ * A smart pointer that owns a capability state.
+ *
+ * This smart pointer will call cap_free() if it needs to free the owned
+ * resource.
+ *
+ * Please note that process capabilities are not supported on Mac OS X.
+ */
+class SmartCap {
+public:
+
+  /**
+   * Constructor.
+   */
+  SmartCap() throw();
+
+  /**
+   * Constructor.
+   *
+   * @param cap The capability state to be owned.
+   */
+  SmartCap(cap_t cap) throw();
+
+  /**
+   * Takes ownership of the specified capability state.  If this smart pointer
+   * already owns a capbility state that is not the same as the one specified
+   * then it will be freed using cap_free().
+   *
+   * @param cap The capability state to be owned.  If a capabibility state is
+   * not specified then the default value of NULL will be used.  In this default
+   * case the smart pointer will not own a capbility state after the reset()
+   * method returns.
+   */
+  void reset(cap_t cap = NULL) throw();
+
+  /**
+   * SmartCap assignment operator.
+   *
+   * This function does the following:
+   * <ul>
+   * <li> Calls release on the previous owner (obj);
+   * <li> Resets this smart pointer to the released pointer of the previous
+   * owner (obj).
+   * </ul>
+   */
+  SmartCap &operator=(SmartCap& obj);
+
+  /**
+   * Destructor.
+   *
+   * Resets this smart pointer with the default value of NULL.
+   */
+  ~SmartCap() throw();
+
+  /**
+   * Returns the owned capbility state or NULL if this smart pointer does not
+   * own one.
+   *
+   * @return The owned capbility state or NULL if this smart pointer does not
+   * own one.
+   */
+  cap_t get() const throw();
+
+  /**
+   * Releases the owned capability state.
+   *
+   * @return The released capability state.
+   */
+  cap_t release();
+
+private:
+
+  /**
+   * The owned capbility state or NULL if this smart pointer does not own one.
+   */ 
+  cap_t m_cap;
+
+  /**
+   * Private copy-constructor to prevent users from trying to create a new
+   * copy of an object of this class.
+   *
+   * Not implemented so that it cannot be called.
+   */
+  SmartCap(const SmartCap &obj) throw();
+
+}; // class SmartCap
+
+}} // namespace cta::server
+
diff --git a/common/processCap/SmartCapTest.cpp b/common/processCap/SmartCapTest.cpp
new file mode 100644
index 0000000000..5094bd4f96
--- /dev/null
+++ b/common/processCap/SmartCapTest.cpp
@@ -0,0 +1,88 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#include "castor/exception/Exception.hpp"
+#include "castor/server/SmartCap.hpp"
+
+#include <gtest/gtest.h>
+
+namespace unitTests {
+
+class castor_server_SmartCapTest : public ::testing::Test {
+protected:
+
+  virtual void SetUp() {
+  }
+
+  virtual void TearDown() {
+  }
+};
+
+TEST_F(castor_server_SmartCapTest, default_constructor) {
+  castor::server::SmartCap smartPtr;
+  ASSERT_EQ((cap_t)NULL, smartPtr.get());
+}
+
+TEST_F(castor_server_SmartCapTest, constructor) {
+  cap_t cap = cap_get_proc();
+  ASSERT_NE((cap_t)NULL, cap);
+
+  castor::server::SmartCap smartPtr(cap);
+  ASSERT_EQ(cap, smartPtr.get());
+}
+
+TEST_F(castor_server_SmartCapTest, reset) {
+  castor::server::SmartCap smartPtr;
+  ASSERT_EQ((cap_t)NULL, smartPtr.get());
+
+  cap_t cap = cap_get_proc();
+  ASSERT_NE((cap_t)NULL, cap);
+
+  smartPtr.reset(cap);
+  ASSERT_EQ(cap, smartPtr.get());
+}
+
+TEST_F(castor_server_SmartCapTest, assignment) {
+  cap_t cap = cap_get_proc();
+  ASSERT_NE((cap_t)NULL, cap);
+
+  castor::server::SmartCap smartPtr1;
+  castor::server::SmartCap smartPtr2;
+
+  ASSERT_EQ((cap_t)NULL, smartPtr1.get());
+  ASSERT_EQ((cap_t)NULL, smartPtr2.get());
+
+  smartPtr1.reset(cap);
+  ASSERT_EQ(cap, smartPtr1.get());
+
+  smartPtr2 = smartPtr1;
+  ASSERT_EQ((cap_t)NULL, smartPtr1.get());
+  ASSERT_EQ(cap, smartPtr2.get());
+}
+
+TEST_F(castor_server_SmartCapTest, releaseNull) {
+  castor::server::SmartCap smartPtr;
+  ASSERT_THROW(smartPtr.release(), castor::exception::Exception);
+}
+
+} // namespace unitTests
diff --git a/common/threading/Daemon.cpp b/common/threading/Daemon.cpp
new file mode 100644
index 0000000000..358746784b
--- /dev/null
+++ b/common/threading/Daemon.cpp
@@ -0,0 +1,202 @@
+/*******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ ******************************************************************************/
+
+#include "common/exception/Errnum.hpp"
+#include "common/threading/Daemon.hpp"
+#include "common/threading/System.hpp"
+#include <getopt.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+//------------------------------------------------------------------------------
+// constructor
+//------------------------------------------------------------------------------
+cta::server::Daemon::Daemon(std::ostream &stdOut, std::ostream &stdErr,
+  log::Logger &log) throw():
+  m_stdOut(stdOut),
+  m_stdErr(stdErr),
+  m_log(log),
+  m_foreground(false),
+  m_commandLineHasBeenParsed(false) {
+}
+
+//------------------------------------------------------------------------------
+// destructor
+//------------------------------------------------------------------------------
+cta::server::Daemon::~Daemon() {
+}
+
+//------------------------------------------------------------------------------
+// parseCommandLine
+//------------------------------------------------------------------------------
+void cta::server::Daemon::parseCommandLine(int argc,
+  char *argv[])  {
+  struct ::option longopts[4];
+
+  longopts[0].name = "foreground";
+  longopts[0].has_arg = no_argument;
+  longopts[0].flag = NULL;
+  longopts[0].val = 'f';
+
+  longopts[1].name = "config";
+  longopts[1].has_arg = required_argument;
+  longopts[1].flag = NULL;
+  longopts[1].val = 'c';
+
+  longopts[2].name = "help";
+  longopts[2].has_arg = no_argument;
+  longopts[2].flag = NULL;
+  longopts[2].val = 'h';
+
+  longopts[3].name = 0;
+
+  char c;
+  while ((c = getopt_long(argc, argv, "fc:h", longopts, NULL)) != -1) {
+    switch (c) {
+    case 'f':
+      m_foreground = true;
+      break;
+    case 'c':
+      setenv("PATH_CONFIG", optarg, 1);
+      m_stdOut << "Using configuration file " << optarg << std::endl;
+      break;
+    case 'h':
+      help(argv[0]);
+      exit(0);
+      break;
+    default:
+      break;
+    }
+  }
+
+  m_commandLineHasBeenParsed = true;
+}
+
+//------------------------------------------------------------------------------
+// help
+//------------------------------------------------------------------------------
+void cta::server::Daemon::help(const std::string &programName)
+  throw() {
+  m_stdOut << "Usage: " << programName << " [options]\n"
+    "\n"
+    "where options can be:\n"
+    "\n"
+    "\t--foreground            or -f         \tRemain in the Foreground\n"
+    "\t--config <config-file>  or -c         \tConfiguration file\n"
+    "\t--metrics               or -m         \tEnable metrics collection\n"
+    "\t--help                  or -h         \tPrint this help and exit\n"
+    "\n"
+    "Comments to: Castor.Support@cern.ch\n";
+}
+
+//------------------------------------------------------------------------------
+// getServerName
+//------------------------------------------------------------------------------
+const std::string &cta::server::Daemon::getServerName() const throw() {
+  return m_log.getProgramName();
+}
+
+//------------------------------------------------------------------------------
+// getForeground
+//------------------------------------------------------------------------------
+bool cta::server::Daemon::getForeground() const
+   {
+  if(!m_commandLineHasBeenParsed) {
+    CommandLineNotParsed ex;
+    ex.getMessage() <<
+      "Failed to determine whether or not the daemon should run in the"
+      " foreground because the command-line has not yet been parsed";
+    throw ex;
+  }
+
+  return m_foreground;
+}
+
+//-----------------------------------------------------------------------------
+// setCommandLineParsed
+//-----------------------------------------------------------------------------
+void cta::server::Daemon::setCommandLineHasBeenParsed(const bool foreground)
+  throw() {
+  m_foreground = foreground;
+  m_commandLineHasBeenParsed = true;
+}
+
+//------------------------------------------------------------------------------
+// daemonizeIfNotRunInForeground
+//------------------------------------------------------------------------------
+void cta::server::Daemon::daemonizeIfNotRunInForeground(
+  const bool runAsStagerSuperuser) {
+  // Do nothing if already a daemon
+  if (1 == getppid())  {
+    return;
+  }
+
+  // If the daemon is to be run in the background
+  if (!m_foreground) {
+    m_log.prepareForFork();
+
+    {
+      pid_t pid = 0;
+      cta::exception::Errnum::throwOnNegative(pid = fork(),
+        "Failed to daemonize: Failed to fork");
+      // If we got a good PID, then we can exit the parent process
+      if (0 < pid) {
+        exit(EXIT_SUCCESS);
+      }
+    }
+
+    // We could set our working directory to '/' here with a call to chdir(2).
+    // For the time being we don't and leave it to the initd script to change
+    // to a suitable directory for us!
+
+    // Change the file mode mask
+    umask(0);
+
+    // Run the daemon in a new session
+    cta::exception::Errnum::throwOnNegative(setsid(),
+      "Failed to daemonize: Failed to run daemon is a new session");
+
+    // Redirect standard files to /dev/null
+    cta::exception::Errnum::throwOnNull(
+      freopen("/dev/null", "r", stdin),
+      "Failed to daemonize: Falied to freopen stdin");
+    cta::exception::Errnum::throwOnNull(
+      freopen("/dev/null", "w", stdout),
+      "Failed to daemonize: Failed to freopen stdout");
+    cta::exception::Errnum::throwOnNull(
+      freopen("/dev/null", "w", stderr),
+      "Failed to daemonize: Failed to freopen stderr");
+  } // if (!m_foreground)
+
+  // Change the user of the daemon process to the Castor superuser if requested
+  if (runAsStagerSuperuser) {
+    cta::System::switchToCtaSuperuser();
+  }
+
+  // Ignore SIGPIPE (connection lost with client)
+  // and SIGXFSZ (a file is too big)
+  signal(SIGPIPE, SIG_IGN);
+  signal(SIGXFSZ, SIG_IGN);
+}
+
diff --git a/common/threading/Daemon.hpp b/common/threading/Daemon.hpp
new file mode 100644
index 0000000000..542dca8a3b
--- /dev/null
+++ b/common/threading/Daemon.hpp
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ ******************************************************************************/
+
+#pragma once
+
+#include "common/exception/Exception.hpp"
+#include "common/log/Logger.hpp"
+
+#include <ostream>
+
+namespace cta { namespace server {
+
+/**
+ * This class contains the code common to all daemon classes.
+ *
+ * The code common to all daemon classes includes daemonization and logging.
+ */
+class Daemon {
+
+public:
+  
+  CTA_GENERATE_EXCEPTION_CLASS(CommandLineNotParsed);
+
+  /**
+   * Constructor
+   *
+   * @param stdOut Stream representing standard out.
+   * @param stdErr Stream representing standard error.
+   * @param log Object representing the API of the CASTOR logging system.
+   */
+  Daemon(std::ostream &stdOut, std::ostream &stdErr, log::Logger &log)
+    throw();
+
+  /**
+   * Destructor.
+   */
+  virtual ~Daemon();
+
+  /**
+   * Parses a command line to set the server options.
+   *
+   * @param argc The size of the command-line vector.
+   * @param argv The command-line vector.
+   */
+  virtual void parseCommandLine(int argc, char *argv[])
+    ;
+
+  /**
+   * Prints out the online help
+   */
+  virtual void help(const std::string &programName) throw();
+
+  /**
+   * Returns this server's name as used by the CASTOR logging system.
+   */
+  const std::string &getServerName() const throw();
+
+  /**
+   * Returns true if the daemon is configured to run in the foreground.
+   */
+  bool getForeground() const ;
+
+protected:
+
+  /**
+   * Tells the daemon object that the command-line has been parsed.  This
+   * method allows subclasses to implement their own command-line parsing logic,
+   * whilst enforcing the fact that they must provide values for the options and
+   * arguments this class requires.
+   *
+   * @param foreground Set to true if the daemon should run in the foreground.
+   */
+  void setCommandLineHasBeenParsed(const bool foreground) throw();
+
+  /**
+   * Daemonizes the daemon if it has not been configured to run in the
+   * foreground.
+   *
+   * Please make sure that the setForeground() method has been called as
+   * appropriate before this method is called.
+   *
+   * This method takes into account whether or not the dameon should run in
+   * foregreound or background mode (m_foreground).
+   *
+   * @param runAsStagerSuperuser Set to true if the user ID and group ID of the
+   * daemon should be set to those of the stager superuser.
+   */
+  void daemonizeIfNotRunInForeground(const bool runAsStagerSuperuser);
+
+  /**
+   * Stream representing standard out.
+   */
+  std::ostream &m_stdOut;
+
+  /**
+   * Stream representing standard in.
+   */
+  std::ostream &m_stdErr;
+
+  /**
+   * Object representing the API of the CASTOR logging system.
+   */
+  log::Logger &m_log;
+
+private:
+
+  /**
+   * Flag indicating whether the server should run in foreground or background
+   * mode.
+   */
+  bool m_foreground;
+
+  /**
+   * True if the command-line has been parsed.
+   */
+  bool m_commandLineHasBeenParsed;
+
+}; // class Daemon
+
+} // namespace server
+} // namespace castor
+
diff --git a/common/threading/DaemonTest.cpp b/common/threading/DaemonTest.cpp
new file mode 100644
index 0000000000..c68782bbf2
--- /dev/null
+++ b/common/threading/DaemonTest.cpp
@@ -0,0 +1,101 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * 
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#include "common/log/DummyLogger.hpp"
+#include "common/threading/Daemon.hpp"
+
+#include <gtest/gtest.h>
+#include <sstream>
+#include <stdio.h>
+#include <string.h>
+
+namespace unitTests {
+
+class cta_threading_DaemonTest : public ::testing::Test {
+protected:
+
+  const std::string m_programName;
+  int m_argc;
+  char **m_argv;
+
+  cta_threading_DaemonTest() :
+    m_programName("testdaemon"),
+    m_argc(0),
+    m_argv(NULL) {
+  }
+
+  virtual void SetUp() {
+    m_argc = 0;
+    m_argv = NULL;
+  }
+
+  virtual void TearDown() {
+    for(int i = 0; i < m_argc; i++) {
+      free(m_argv[i]);
+    }
+
+    delete[] m_argv;
+  }
+};
+
+TEST_F(cta_threading_DaemonTest, getForegroundBeforeParseCommandLine) {
+  std::ostringstream dummyStdOut;
+  std::ostringstream dummyStdErr;
+  cta::log::DummyLogger log(m_programName);
+  cta::server::Daemon daemon(dummyStdOut, dummyStdErr, log);
+  
+  ASSERT_THROW(daemon.getForeground(), cta::server::Daemon::CommandLineNotParsed);
+}
+
+TEST_F(cta_threading_DaemonTest, parseEmptyCmdLine) {
+  m_argv = new char *[2];
+  m_argv[0] = strdup(m_programName.c_str());
+  m_argv[1] = NULL;
+  m_argc = 1;
+
+  std::ostringstream dummyStdOut;
+  std::ostringstream dummyStdErr;
+  cta::log::DummyLogger log(m_programName);
+  cta::server::Daemon daemon(dummyStdOut, dummyStdErr, log);
+
+  ASSERT_NO_THROW(daemon.parseCommandLine(m_argc, m_argv));
+  ASSERT_EQ(false, daemon.getForeground());
+}
+
+TEST_F(cta_threading_DaemonTest, parseFOnCmdLine) {
+  m_argv = new char *[3];
+  m_argv[0] = strdup(m_programName.c_str());
+  m_argv[1] = strdup("-f");
+  m_argv[2] = NULL;
+  m_argc = 2;
+
+  std::ostringstream dummyStdOut;
+  std::ostringstream dummyStdErr;
+  cta::log::DummyLogger log(m_programName);
+  cta::server::Daemon daemon(dummyStdOut, dummyStdErr, log);
+
+  ASSERT_NO_THROW(daemon.parseCommandLine(m_argc, m_argv));
+  ASSERT_EQ(true, daemon.getForeground());
+}
+
+} // namespace unitTests
diff --git a/common/threading/MutexLocker.hpp b/common/threading/MutexLocker.hpp
new file mode 100644
index 0000000000..2d799d31c5
--- /dev/null
+++ b/common/threading/MutexLocker.hpp
@@ -0,0 +1,64 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+
+#include "Mutex.hpp"
+
+#include <pthread.h>
+#include <semaphore.h>
+
+namespace cta { namespace threading {
+
+/**
+ * A simple scoped locker for mutexes. Highly recommended as
+ * the mutex will be released in all cases (exception, mid-code return, etc...)
+ * To use, simply instantiate and forget.
+ */
+class MutexLocker {
+public:
+
+  /**
+   * Constructor.
+   *
+   * @param m pointer to Mutex to be owned.
+   */
+  MutexLocker(Mutex & m): m_mutex(m) {
+    m.lock();
+  }
+
+  /**
+   * Destructor.
+   */
+  ~MutexLocker() {
+    try {
+      m_mutex.unlock();
+    } catch (...) {
+      // Ignore any exceptions
+    }
+  }
+
+private:
+
+  /**
+   * The mutex owened by this MutexLocker.
+   */
+  Mutex & m_mutex;
+
+}; // class MutexLocker
+  
+}} // namespace cta::threading
diff --git a/common/threading/System.cpp b/common/threading/System.cpp
new file mode 100644
index 0000000000..3f890890cb
--- /dev/null
+++ b/common/threading/System.cpp
@@ -0,0 +1,193 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * @(#)BaseClient.cpp,v 1.37 $Release$ 2006/02/16 15:56:58 sponcec3
+ *
+ * A class with static methods for system level utilities.
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+// Include Files
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+
+// Local includes
+#include "System.hpp"
+#include "common/exception/Errnum.hpp"
+
+#define STAGERSUPERGROUP "st"
+#define STAGERSUPERUSER "stage"
+
+
+//------------------------------------------------------------------------------
+// getHostName
+//------------------------------------------------------------------------------
+std::string cta::System::getHostName() 
+{
+  // All this to get the hostname, thanks to C !
+  int len = 64;
+  char* hostname;
+  hostname = (char*) calloc(len, 1);
+  if (0 == hostname) {
+    OutOfMemory ex;
+    ex.getMessage() << "Could not allocate hostname with length " << len;
+    throw ex;
+  }
+  if (gethostname(hostname, len) < 0) {
+    // Test whether error is due to a name too long
+    // The errno depends on the glibc version
+    if (EINVAL != errno &&
+        ENAMETOOLONG != errno) {
+      free(hostname);
+      cta::exception::Errnum e(errno);
+      e.getMessage() << "gethostname error";
+      throw e;
+    }
+    // So the name was too long
+    while (hostname[len - 1] != 0) {
+      len *= 2;
+      char *hostnameLonger = (char*) realloc(hostname, len);
+      if (0 == hostnameLonger) {
+        free(hostname);
+        cta::exception::Errnum e(ENOMEM);
+        e.getMessage() << "Could not allocate memory for hostname";
+        throw e;
+
+      }
+      hostname = hostnameLonger;
+      memset(hostname, 0, len);
+      if (gethostname(hostname, len) < 0) {
+        // Test whether error is due to a name too long
+        // The errno depends on the glibc version
+        if (EINVAL != errno &&
+            ENAMETOOLONG != errno) {
+          free(hostname);
+          cta::exception::Errnum e(errno);
+          e.getMessage() << "Could not get hostname"
+                         <<  strerror(errno);
+          throw e;
+        }
+      }
+    }
+  }
+  std::string res(hostname);   // copy the string
+  free(hostname);
+  return res;
+}
+
+//------------------------------------------------------------------------------
+// porttoi
+//------------------------------------------------------------------------------
+int cta::System::porttoi(char* str)
+   {
+  char* dp = str;
+  errno = 0;
+  int iport = strtoul(str, &dp, 0);
+  if (*dp != 0) {
+    cta::exception::Errnum e(errno);
+    e.getMessage() << "Bad port value." << std::endl;
+    throw e;
+  }
+  if ((iport > 65535) || (iport < 0)) {
+    cta::exception::Errnum e(errno);
+    e.getMessage()
+      << "Invalid port value : " << iport
+      << ". Must be < 65535 and > 0." << std::endl;
+    throw e;
+  }
+  return iport;
+}
+
+//------------------------------------------------------------------------------
+// switchToCastorSuperuser
+//------------------------------------------------------------------------------
+void cta::System::switchToCtaSuperuser()
+   {
+  struct passwd *stage_passwd;    // password structure pointer
+  struct group  *stage_group;     // group structure pointer
+
+  uid_t ruid, euid;               // Original uid/euid
+  gid_t rgid, egid;               // Original gid/egid
+
+  // Save original values
+  ruid = getuid();
+  euid = geteuid();
+  rgid = getgid();
+  egid = getegid();
+
+  // Get information on generic stage account from password file
+  if ((stage_passwd = getpwnam(STAGERSUPERUSER)) == NULL) {
+    cta::exception::Exception e;
+    e.getMessage() << "CTA super user " << STAGERSUPERUSER
+                   << " not found in password file";
+    throw e;
+  }
+  // verify existence of its primary group id
+  if (getgrgid(stage_passwd->pw_gid) == NULL) {
+    cta::exception::Exception e;
+    e.getMessage() << "CTA super user group does not exist";
+    throw e;
+  }
+  // Get information on generic stage account from group file
+  if ((stage_group = getgrnam(STAGERSUPERGROUP)) == NULL) {
+    cta::exception::Exception e;
+    e.getMessage() << "CTA super user group " << STAGERSUPERGROUP
+                   << " not found in group file";
+    throw e;
+  }
+  // Verify consistency
+  if (stage_group->gr_gid != stage_passwd->pw_gid) {
+    cta::exception::Exception e;
+    e.getMessage() << "Inconsistent password file. The group of the "
+                   << "castor superuser " << STAGERSUPERUSER
+                   << " should be " << stage_group->gr_gid
+                   << "(" << STAGERSUPERGROUP << "), but is "
+                   << stage_passwd->pw_gid;
+    throw e;
+  }
+  // Undo group privilege
+  if (setregid (egid, rgid) < 0) {
+    cta::exception::Exception e;
+    e.getMessage() << "Unable to undo group privilege";
+    throw e;
+  }
+  // Undo user privilege
+  if (setreuid (euid, ruid) < 0) {
+    cta::exception::Exception e;
+    e.getMessage() << "Unable to undo user privilege";
+    throw e;
+  }
+  // set the effective privileges to superuser
+  if (setegid(stage_passwd->pw_gid) < 0) {
+    cta::exception::Exception e;
+    e.getMessage() << "Unable to set group privileges of CTA Superuser. "
+                   << "You may want to check that the suid bit is set properly";
+    throw e;
+  }
+  if (seteuid(stage_passwd->pw_uid) < 0) {
+    cta::exception::Exception e;
+    e.getMessage() << "Unable to set privileges of CTA Superuser.";
+    throw e;
+  }
+}
diff --git a/common/threading/System.hpp b/common/threading/System.hpp
new file mode 100644
index 0000000000..42af73af1e
--- /dev/null
+++ b/common/threading/System.hpp
@@ -0,0 +1,64 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * A class with static methods for system level utilities.
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#pragma once
+
+#include "common/exception/Exception.hpp"
+#include <string>
+
+namespace cta {
+
+  class System {
+
+  public:
+    
+    CTA_GENERATE_EXCEPTION_CLASS(OutOfMemory);
+
+    /**
+     * Gets the host name. Handles all errors that may occur with 
+     * the gethostname() API.  
+     * @exception in case of an error 
+     */
+    static std::string getHostName() ;
+
+    /**
+     * Converts a string into a port number, checking
+     * that the value is in range [0-65535]
+     * @param str the string giving the port number
+     * @return the port as an int
+     * @exception in case of invalid value
+     */
+    static int porttoi(char* str) ;
+
+    /**
+     * Switches the current process to use the CTA superuser
+     * (typically stage:st). 
+     * @exception in case of an error
+     */
+    static void switchToCtaSuperuser() ;
+     
+  };
+
+} // end of namespace castor
+
diff --git a/common/Utils.cpp b/common/utils/Utils.cpp
similarity index 86%
rename from common/Utils.cpp
rename to common/utils/Utils.cpp
index 4d1cecd807..f3aa1f96b9 100644
--- a/common/Utils.cpp
+++ b/common/utils/Utils.cpp
@@ -18,8 +18,8 @@
 
 #include "common/exception/Exception.hpp"
 #include "common/exception/Errnum.hpp"
-#include "common/strerror_r_wrapper.hpp"
-#include "common/Utils.hpp"
+#include "common/utils/strerror_r_wrapper.hpp"
+#include "common/utils/Utils.hpp"
 
 #include <attr/xattr.h>
 #include <limits>
@@ -32,6 +32,7 @@
 #include <uuid/uuid.h>
 #include <zlib.h>
 #include <sys/utsname.h>
+#include <sys/prctl.h>
 
 using cta::exception::Exception;
 
@@ -226,6 +227,33 @@ void cta::Utils::splitString(const std::string &str, const char separator,
   }
 }
 
+//-----------------------------------------------------------------------------
+// trimString
+//-----------------------------------------------------------------------------
+std::string cta::Utils::trimString(const std::string &s) throw() {
+  const std::string& spaces="\t\n\v\f\r ";
+
+  // Find first non white character
+  size_t beginpos = s.find_first_not_of(spaces);
+  std::string::const_iterator it1;
+  if (std::string::npos != beginpos) {
+    it1 = beginpos + s.begin();
+  } else {
+    it1 = s.begin();
+  }
+
+  // Find last non white chararacter
+  std::string::const_iterator it2;
+  size_t endpos = s.find_last_not_of(spaces);
+  if (std::string::npos != endpos) {
+    it2 = endpos + 1 + s.begin();
+  } else {
+    it2 = s.end();
+  }
+
+  return std::string(it1, it2);
+}
+
 //-----------------------------------------------------------------------------
 // generateUuid
 //-----------------------------------------------------------------------------
@@ -482,4 +510,58 @@ std::string cta::Utils::getShortHostname() {
   return snn.at(0);
 }
 
+//------------------------------------------------------------------------------
+// getDumpableProcessAttribute
+//------------------------------------------------------------------------------
+bool cta::Utils::getDumpableProcessAttribute() {
+  const int rc = prctl(PR_GET_DUMPABLE);
+  switch(rc) {
+  case -1:
+    {
+      const std::string errStr = errnoToString(errno);
+      cta::exception::Exception ex;
+      ex.getMessage() <<
+        "Failed to get the dumpable attribute of the process: " << errStr;
+      throw ex;
+    }
+  case 0: return false;
+  case 1: return true;
+  case 2: return true;
+  default:
+    {
+      cta::exception::Exception ex;
+      ex.getMessage() <<
+        "Failed to get the dumpable attribute of the process"
+        ": Unknown value returned by prctl(): rc=" << rc;
+      throw ex;
+    }
+  }
+}
+
+//------------------------------------------------------------------------------
+// setDumpableProcessAttribute
+//------------------------------------------------------------------------------
+ void cta::Utils::setDumpableProcessAttribute(const bool dumpable) {
+  const int rc = prctl(PR_SET_DUMPABLE, dumpable ? 1 : 0);
+  switch(rc) {
+  case -1:
+    {
+      const std::string errStr = errnoToString(errno);
+      cta::exception::Exception ex;
+      ex.getMessage() <<
+        "Failed to set the dumpable attribute of the process: " << errStr;
+      throw ex;
+    }
+  case 0: return;
+  default:
+    {
+      cta::exception::Exception ex;
+      ex.getMessage() <<
+        "Failed to set the dumpable attribute of the process"
+        ": Unknown value returned by prctl(): rc=" << rc;
+      throw ex;
+    }
+  }
+}
+
 
diff --git a/common/Utils.hpp b/common/utils/Utils.hpp
similarity index 82%
rename from common/Utils.hpp
rename to common/utils/Utils.hpp
index 1a919c1c01..d61bde7afb 100644
--- a/common/Utils.hpp
+++ b/common/utils/Utils.hpp
@@ -106,6 +106,26 @@ public:
    */
   static void splitString(const std::string &str, const char separator,
     std::vector<std::string> &result);
+  
+
+  /**
+   * Returns the result of trimming both left and right white-space from the
+   * specified string.
+   *
+   * @param s The string to be trimmed.
+   * @return The result of trimming the string.
+   */
+  static std::string trimString(const std::string &s) throw();
+
+  /**
+   * Creates and returns an std::string which is the result of replacing each
+   * occurance of whitespace (a collection of on or more space and tab
+   * characters) with a single space character.
+   *
+   * @param str The original string.
+   * @return    The newly created string with single spaces.
+   */
+  static std::string singleSpaceString(const std::string &str) throw();
 
   /**
    * Returns uuid in the form of a string.
@@ -212,6 +232,24 @@ public:
    */
   static uint32_t getAdler32(const uint8_t *buf, const uint32_t len) throw();
 
+  /**
+   * Returns true if the attributes of the current process indicate that it will
+   * produce a core dump if it receives a signal whose behaviour is to produce a
+   * core dump.
+   *
+   * This method is implemented using prctl().
+   *
+   * @return true if the current program is dumpable.
+   */
+  static bool getDumpableProcessAttribute();
+
+  /**
+   * Sets the attributes of the current process to indicate hat it will produce a
+   * core dump if it receives a signal whose behaviour is to produce a core dump.
+   *
+   * @param dumpable true if the current program should be dumpable.
+   */
+  static void setDumpableProcessAttribute(const bool dumpable);
 }; // class Utils
 
 } // namespace cta
diff --git a/common/UtilsTest.cpp b/common/utils/UtilsTest.cpp
similarity index 73%
rename from common/UtilsTest.cpp
rename to common/utils/UtilsTest.cpp
index 490cac80c1..5c9377c20a 100644
--- a/common/UtilsTest.cpp
+++ b/common/utils/UtilsTest.cpp
@@ -16,7 +16,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "common/Utils.hpp"
+#include "common/utils/Utils.hpp"
 
 #include <gtest/gtest.h>
 
@@ -467,4 +467,136 @@ TEST_F(cta_UtilsTest, adler32_buf_of_character_1) {
 }
 
 
+/**
+ * Tests the good day senario of passing a multi-column string to the
+ * splitString() method.
+ */
+TEST_F(cta_UtilsTest, testGoodDaySplitString) {
+  using cta::Utils;
+  const std::string line("col0 col1 col2 col3 col4 col5 col6 col7");
+  std::vector<std::string> columns;
+
+  ASSERT_NO_THROW(Utils::splitString(line, ' ', columns));
+  ASSERT_EQ((std::vector<std::string>::size_type)8, columns.size());
+  ASSERT_EQ(std::string("col0"), columns[0]);
+  ASSERT_EQ(std::string("col1"), columns[1]);
+  ASSERT_EQ(std::string("col2"), columns[2]);
+  ASSERT_EQ(std::string("col3"), columns[3]);
+  ASSERT_EQ(std::string("col4"), columns[4]);
+  ASSERT_EQ(std::string("col5"), columns[5]);
+  ASSERT_EQ(std::string("col6"), columns[6]);
+  ASSERT_EQ(std::string("col7"), columns[7]);
+}
+
+/**
+ * Test the case of an empty string being passed to the splitString() method.
+ */
+TEST_F(cta_UtilsTest, testSplitStringWithEmptyString) {
+  using cta::Utils;
+  const std::string emptyString;
+  std::vector<std::string> columns;
+
+  ASSERT_NO_THROW(Utils::splitString(emptyString, ' ', columns));
+  ASSERT_EQ((std::vector<std::string>::size_type)0, columns.size());
+}
+
+/**
+ * Test the case of a non-empty string containing no separator character
+ * passed to the splitString() method.
+ */
+TEST_F(cta_UtilsTest, testSplitStringWithNoSeparatorInString) {
+  using cta::Utils;
+  const std::string stringContainingNoSeparator =
+    "stringContainingNoSeparator";
+  std::vector<std::string> columns;
+
+  ASSERT_NO_THROW(Utils::splitString(stringContainingNoSeparator, ' ', columns));
+  ASSERT_EQ((std::vector<std::string>::size_type)1, columns.size());
+  ASSERT_EQ(stringContainingNoSeparator, columns[0]);
+}
+
+TEST_F(cta_UtilsTest, testTrimStringWithEmptyString) {
+  using cta::Utils;
+  const std::string s;
+  const std::string trimmedString = Utils::trimString(s);
+  ASSERT_EQ(s, trimmedString);
+}
+
+TEST_F(cta_UtilsTest, testTrimStringContainingNoSpaces) {
+  using cta::Utils;
+  const std::string s("NO_SPACES");
+  const std::string trimmedString = Utils::trimString(s);
+  ASSERT_EQ(s, trimmedString);
+}
+
+TEST_F(cta_UtilsTest, testTrimStringContainingLeftSpace) {
+  using cta::Utils;
+  const std::string s(" VALUE");
+  const std::string trimmedString = Utils::trimString(s);
+  ASSERT_EQ(std::string("VALUE"), trimmedString);
+}
+
+TEST_F(cta_UtilsTest, testTrimStringContainingRightSpace) {
+  using cta::Utils;
+  const std::string s("VALUE ");
+  const std::string trimmedString = Utils::trimString(s);
+  ASSERT_EQ(std::string("VALUE"), trimmedString);
+}
+
+TEST_F(cta_UtilsTest, testTrimStringContainingLeftAndRightSpace) {
+  using cta::Utils;
+  const std::string s(" VALUE ");
+  const std::string trimmedString = Utils::trimString(s);
+  ASSERT_EQ(std::string("VALUE"), trimmedString);
+}
+
+TEST_F(cta_UtilsTest, testTrimStringContainingLeftTab) {
+  using cta::Utils;
+  const std::string s("\tVALUE");
+  const std::string trimmedString = Utils::trimString(s);
+  ASSERT_EQ(std::string("VALUE"), trimmedString);
+}
+
+TEST_F(cta_UtilsTest, testTrimStringContainingRightTab) {
+  using cta::Utils;
+  const std::string s("VALUE\t");
+  const std::string trimmedString = Utils::trimString(s);
+  ASSERT_EQ(std::string("VALUE"), trimmedString);
+}
+
+TEST_F(cta_UtilsTest, testTrimStringContainingLeftAndRightTab) {
+  using cta::Utils;
+  const std::string s("\tVALUE\t");
+  const std::string trimmedString = Utils::trimString(s);
+  ASSERT_EQ(std::string("VALUE"), trimmedString);
+}
+
+TEST_F(cta_UtilsTest, testTrimStringContainingLeftNewLine) {
+  using cta::Utils;
+  const std::string s("\nVALUE");
+  const std::string trimmedString = Utils::trimString(s);
+  ASSERT_EQ(std::string("VALUE"), trimmedString);
+}
+
+TEST_F(cta_UtilsTest, testTrimStringContainingRightNewLine) {
+  using cta::Utils;
+  const std::string s("VALUE\n");
+  const std::string trimmedString = Utils::trimString(s);
+  ASSERT_EQ(std::string("VALUE"), trimmedString);
+}
+
+TEST_F(cta_UtilsTest, testTrimStringContainingLeftAndRightNewLine) {
+  using cta::Utils;
+  const std::string s("\nVALUE\n");
+  const std::string trimmedString = Utils::trimString(s);
+  ASSERT_EQ(std::string("VALUE"), trimmedString);
+}
+
+TEST_F(cta_UtilsTest, testTrimStringContainingLeftAndRightWhiteSpace) {
+  using cta::Utils;
+  const std::string s("  \t\t\n\nVALUE  \t\t\n\n");
+  const std::string trimmedString = Utils::trimString(s);
+  ASSERT_EQ(std::string("VALUE"), trimmedString);
+}
+
 } // namespace unitTests
diff --git a/common/strerror_r_wrapper.cpp b/common/utils/strerror_r_wrapper.cpp
similarity index 96%
rename from common/strerror_r_wrapper.cpp
rename to common/utils/strerror_r_wrapper.cpp
index 538464ff00..0f27181516 100644
--- a/common/strerror_r_wrapper.cpp
+++ b/common/utils/strerror_r_wrapper.cpp
@@ -15,7 +15,7 @@
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
-#include "common/strerror_r_wrapper.hpp"
+#include "common/utils/strerror_r_wrapper.hpp"
 
 /*
  * Undefine _GNU_SOURCE and define _XOPEN_SOURCE as being 600 so that the
diff --git a/common/strerror_r_wrapper.hpp b/common/utils/strerror_r_wrapper.hpp
similarity index 100%
rename from common/strerror_r_wrapper.hpp
rename to common/utils/strerror_r_wrapper.hpp
diff --git a/nameserver/mockNS/MockNameServer.cpp b/nameserver/mockNS/MockNameServer.cpp
index 7c36ef081d..58f1c83830 100644
--- a/nameserver/mockNS/MockNameServer.cpp
+++ b/nameserver/mockNS/MockNameServer.cpp
@@ -30,7 +30,7 @@
 #include "common/exception/Exception.hpp"
 #include "common/exception/Errnum.hpp"
 #include "nameserver/mockNS/SmartFd.hpp"
-#include "common/Utils.hpp"
+#include "common/utils/Utils.hpp"
 #include "nameserver/mockNS/MockNameServer.hpp"
 
 //------------------------------------------------------------------------------
diff --git a/nameserver/mockNS/makeMockNameServerBasePath.cpp b/nameserver/mockNS/makeMockNameServerBasePath.cpp
index 0910d5afa1..f8be00e5e3 100644
--- a/nameserver/mockNS/makeMockNameServerBasePath.cpp
+++ b/nameserver/mockNS/makeMockNameServerBasePath.cpp
@@ -29,7 +29,7 @@
 
 #include "common/exception/Errnum.hpp"
 #include "common/exception/Exception.hpp"
-#include "common/Utils.hpp"
+#include "common/utils/Utils.hpp"
 
 namespace {
 
diff --git a/objectstore/BackendFactory.cpp b/objectstore/BackendFactory.cpp
index 687f694fda..d88a9824ef 100644
--- a/objectstore/BackendFactory.cpp
+++ b/objectstore/BackendFactory.cpp
@@ -19,7 +19,7 @@
 #include "BackendFactory.hpp"
 #include "BackendRados.hpp"
 #include "BackendVFS.hpp"
-#include "common/Utils.hpp"
+#include "common/utils/Utils.hpp"
 #include "tapeserver/castor/tape/tapeserver/utils/Regex.hpp"
 
 auto cta::objectstore::BackendFactory::createBackend(const std::string& URL)
diff --git a/objectstore/BackendVFS.cpp b/objectstore/BackendVFS.cpp
index 1964f81048..4f0a1105c7 100644
--- a/objectstore/BackendVFS.cpp
+++ b/objectstore/BackendVFS.cpp
@@ -18,7 +18,7 @@
 
 #include "BackendVFS.hpp"
 #include "common/exception/Errnum.hpp"
-#include "common/Utils.hpp"
+#include "common/utils/Utils.hpp"
 #include "tapeserver/castor/tape/tapeserver/utils/Regex.hpp"
 
 #include <fstream>
diff --git a/remotens/EosNS.cpp b/remotens/EosNS.cpp
index fae40c2049..266ba16f7d 100644
--- a/remotens/EosNS.cpp
+++ b/remotens/EosNS.cpp
@@ -25,7 +25,7 @@
 
 #include "common/exception/Exception.hpp"
 #include "common/remoteFS/RemotePath.hpp"
-#include "common/Utils.hpp"
+#include "common/utils/Utils.hpp"
 #include "remotens/EosNS.hpp"
 
 #include "XrdCl/XrdClFileSystem.hh"
diff --git a/remotens/MockRemoteNS.cpp b/remotens/MockRemoteNS.cpp
index d0d5b8e8dd..8f944f8d88 100644
--- a/remotens/MockRemoteNS.cpp
+++ b/remotens/MockRemoteNS.cpp
@@ -24,7 +24,7 @@
 
 #include "common/exception/Exception.hpp"
 #include "common/remoteFS/RemotePath.hpp"
-#include "common/Utils.hpp"
+#include "common/utils/Utils.hpp"
 #include "remotens/MockRemoteNS.hpp"
 
 
diff --git a/scheduler/Scheduler.cpp b/scheduler/Scheduler.cpp
index 39872f730a..3f97092fd7 100644
--- a/scheduler/Scheduler.cpp
+++ b/scheduler/Scheduler.cpp
@@ -18,6 +18,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+
 #include "scheduler/Scheduler.hpp"
 #include "catalogue/MockCatalogue.hpp"
 
@@ -726,4 +727,4 @@ std::unique_ptr<cta::common::dataStructures::TapeMount> cta::Scheduler::getNextM
 std::unique_ptr<cta::TapeMount> cta::Scheduler::_old_getNextMount(const std::string &logicalLibraryName, const std::string & driveName) {
   throw cta::exception::Exception(std::string(__FUNCTION__)+" Error: not implemented!");
   return std::unique_ptr<TapeMount>();
-}
\ No newline at end of file
+}
diff --git a/scheduler/_old_prototype_DummyScheduler.cpp b/scheduler/_old_prototype_DummyScheduler.cpp
index 46b60a0af1..40f897d2b5 100644
--- a/scheduler/_old_prototype_DummyScheduler.cpp
+++ b/scheduler/_old_prototype_DummyScheduler.cpp
@@ -24,7 +24,7 @@
 #include "common/exception/Exception.hpp"
 #include "common/remoteFS/RemotePathAndStatus.hpp"
 #include "common/UserIdentity.hpp"
-#include "common/Utils.hpp"
+#include "common/utils/Utils.hpp"
 #include "common/SecurityIdentity.hpp"
 #include "common/TapePool.hpp"
 #include "nameserver/NameServer.hpp"
diff --git a/tapeserver/CMakeLists.txt b/tapeserver/CMakeLists.txt
index 02f4382f42..8984496ca8 100644
--- a/tapeserver/CMakeLists.txt
+++ b/tapeserver/CMakeLists.txt
@@ -1,4 +1,12 @@
 cmake_minimum_required (VERSION 2.6)
 
+# Old CASTOR's tapeserverd daemon code
 add_subdirectory (castor)
 add_subdirectory (test)
+
+# CTA's cta-taped code
+add_subdirectory (daemon)
+
+add_executable (cta-taped cta-taped.cpp)
+target_link_libraries(cta-taped
+  ctatapedaemon ctacommon protobuf)
diff --git a/tapeserver/castor/exception/Errnum.cpp b/tapeserver/castor/exception/Errnum.cpp
index e1de0c9353..e2d786d235 100644
--- a/tapeserver/castor/exception/Errnum.cpp
+++ b/tapeserver/castor/exception/Errnum.cpp
@@ -22,7 +22,7 @@
  * @author Castor Dev team, castor-dev@cern.ch
  *****************************************************************************/
 #include "castor/exception/Errnum.hpp"
-#include "common/Utils.hpp"
+#include "common/utils/Utils.hpp"
 
 #include <errno.h>
 #include <string.h>
diff --git a/tapeserver/castor/io/IoTest.cpp b/tapeserver/castor/io/IoTest.cpp
index 5cd64c6175..8dc6b7b692 100644
--- a/tapeserver/castor/io/IoTest.cpp
+++ b/tapeserver/castor/io/IoTest.cpp
@@ -23,7 +23,7 @@
 
 #include "castor/io/io.hpp"
 #include "castor/utils/SmartFd.hpp"
-#include "common/marshall.h"
+#include "castor/io/marshall.h"
 
 #include <fcntl.h>
 #include <gtest/gtest.h>
diff --git a/tapeserver/castor/io/io.cpp b/tapeserver/castor/io/io.cpp
index 1f407b1067..3eece19e94 100644
--- a/tapeserver/castor/io/io.cpp
+++ b/tapeserver/castor/io/io.cpp
@@ -27,7 +27,7 @@
 #include "castor/io/io.hpp"
 #include "castor/utils/SmartFd.hpp"
 #include "castor/utils/utils.hpp"
-#include "common/Utils.hpp"
+#include "common/utils/Utils.hpp"
 #include "common/Timer.hpp"
 #include "common/exception/Errnum.hpp"
 
diff --git a/common/marshall.h b/tapeserver/castor/io/marshall.h
similarity index 100%
rename from common/marshall.h
rename to tapeserver/castor/io/marshall.h
diff --git a/tapeserver/castor/messages/messages.cpp b/tapeserver/castor/messages/messages.cpp
index 14c7f69302..b5bc5a966f 100644
--- a/tapeserver/castor/messages/messages.cpp
+++ b/tapeserver/castor/messages/messages.cpp
@@ -23,7 +23,7 @@
 
 #include "castor/messages/messages.hpp"
 #include "castor/utils/utils.hpp"
-#include "common/strerror_r_wrapper.hpp"
+#include "common/utils/strerror_r_wrapper.hpp"
 #include "castor/legacymsg/TapeConstants.h"
 
 #include <string.h>
diff --git a/tapeserver/castor/server/ProcessCap.cpp b/tapeserver/castor/server/ProcessCap.cpp
index 34189aa3dd..368929f216 100644
--- a/tapeserver/castor/server/ProcessCap.cpp
+++ b/tapeserver/castor/server/ProcessCap.cpp
@@ -24,7 +24,7 @@
 #include "castor/exception/Exception.hpp"
 #include "castor/server/ProcessCap.hpp"
 #include "castor/server/SmartCap.hpp"
-#include "common/Utils.hpp"
+#include "castor/utils/utils.hpp"
 
 #include <errno.h>
 
@@ -60,7 +60,7 @@ cap_t castor::server::ProcessCap::getProc() {
     castor::exception::Exception ex;
     ex.getMessage() <<
       "Failed to get the capabilities of the process: " 
-        << cta::Utils::errnoToString(errno);
+        << castor::utils::errnoToString(errno);
     throw ex;
   }
   return cap;
@@ -77,7 +77,7 @@ std::string castor::server::ProcessCap::toText(
     castor::exception::Exception ex;
     ex.getMessage() <<
       "Failed to create string representation of capability state: " 
-        << cta::Utils::errnoToString(errno);
+        << castor::utils::errnoToString(errno);
     throw ex;
   }
   std::string result(text);
@@ -87,7 +87,7 @@ std::string castor::server::ProcessCap::toText(
     castor::exception::Exception ex;
     ex.getMessage() <<
       "Failed to free string representation of capability state: " 
-        << cta::Utils::errnoToString(errno);
+        << castor::utils::errnoToString(errno);
     throw ex;
   }
 
@@ -119,7 +119,7 @@ cap_t castor::server::ProcessCap::fromText(const std::string &text) {
     castor::exception::Exception ex;
     ex.getMessage() <<
       "Failed to create capability state from string representation"
-      ": text='" << text << "': " << cta::Utils::errnoToString(errno);
+      ": text='" << text << "': " << castor::utils::errnoToString(errno);
     throw ex;
   }
 
@@ -134,7 +134,7 @@ void castor::server::ProcessCap::setProc(const cap_t cap) {
     castor::exception::Exception ex;
     ex.getMessage() <<
       "Failed to set the capabilities of the process: " 
-        << cta::Utils::errnoToString(errno);
+        << castor::utils::errnoToString(errno);
     throw ex;
   }
 }
diff --git a/tapeserver/castor/server/ProcessCap.hpp b/tapeserver/castor/server/ProcessCap.hpp
index 2740a58f2b..3ff9b80dd7 100644
--- a/tapeserver/castor/server/ProcessCap.hpp
+++ b/tapeserver/castor/server/ProcessCap.hpp
@@ -1,25 +1,20 @@
-/******************************************************************************
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
  *
- * This file is part of the Castor project.
- * See http://castor.web.cern.ch/castor
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
  *
- * Copyright (C) 2003  CERN
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- *
  *
- * @author Castor Dev team, castor-dev@cern.ch
- *****************************************************************************/
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
 
 #pragma once
 
diff --git a/tapeserver/castor/tape/tapeserver/daemon/CMakeLists.txt b/tapeserver/castor/tape/tapeserver/daemon/CMakeLists.txt
index cd008703a6..0d467286ba 100644
--- a/tapeserver/castor/tape/tapeserver/daemon/CMakeLists.txt
+++ b/tapeserver/castor/tape/tapeserver/daemon/CMakeLists.txt
@@ -70,13 +70,13 @@ add_library(ctaTapeServerDaemon
   TpconfigLine.cpp
   TpconfigLines.cpp)
 
-target_link_libraries(ctaTapeServerDaemon ctamessages ctatapereactor  ctacommon ctanameserver ctaremotens protobuf ctascheduler ctalegacymsg ctacatalogue)
+target_link_libraries(ctaTapeServerDaemon ctamessages ctatapereactor  ctacommon ctanameserver ctaremotens protobuf ctascheduler ctalegacymsg ctaserverutils ctacatalogue)
 add_dependencies(ctaTapeServerDaemon ctamessagesprotobuf)
 
 add_executable(cta-tapeserverd TapeDaemon.cpp)
 target_link_libraries(cta-tapeserverd ctaTapeServerDaemon SCSI System Utils 
   File TapeDrive ctacommon ctatapereactor ${LIBCAP_LIB} ${ZLIB_LIBRARIES} 
-  ctamessages zmq ctaio ctautils)
+  ctamessages zmq ctaio ctautils ctaserverutils)
 install (TARGETS cta-tapeserverd DESTINATION usr/bin)
 
 add_library(ctatapeserverdaemonutils SHARED
diff --git a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp
index 1693d28cf0..732f177aa5 100644
--- a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp
+++ b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp
@@ -41,7 +41,7 @@
 #include "castor/tape/tapeserver/file/File.hpp"
 #include "castor/tape/tapeserver/drive/FakeDrive.hpp"
 #include "common/exception/Exception.hpp"
-#include "common/Utils.hpp"
+#include "common/utils/Utils.hpp"
 #include "scheduler/Scheduler.hpp"
 #include "smc_struct.h"
 #include "nameserver/mockNS/MockNameServer.hpp"
diff --git a/tapeserver/castor/tape/tapeserver/daemon/ProcessForker.cpp b/tapeserver/castor/tape/tapeserver/daemon/ProcessForker.cpp
index fe2ee3c81c..c185ee2650 100644
--- a/tapeserver/castor/tape/tapeserver/daemon/ProcessForker.cpp
+++ b/tapeserver/castor/tape/tapeserver/daemon/ProcessForker.cpp
@@ -470,7 +470,7 @@ castor::tape::tapeserver::daemon::Session::EndOfSessionAction
   castor::tape::tapeserver::daemon::ProcessForker::runCleanerSession(
   const messages::ForkCleaner &rqst) {
   try {
-    server::ProcessCap capUtils;
+    castor::server::ProcessCap capUtils;
 
     const DriveConfig driveConfig = getDriveConfig(rqst);
     std::list<log::Param> params;
diff --git a/tapeserver/castor/utils/utils.cpp b/tapeserver/castor/utils/utils.cpp
index 72ef342ca7..c5c76eeb9b 100644
--- a/tapeserver/castor/utils/utils.cpp
+++ b/tapeserver/castor/utils/utils.cpp
@@ -20,7 +20,7 @@
  *****************************************************************************/
 
 #include "castor/utils/utils.hpp"
-#include "common/strerror_r_wrapper.hpp"
+#include "common/utils/strerror_r_wrapper.hpp"
 #include "h/Castor_limits.h"
 
 #include <algorithm>
@@ -391,7 +391,7 @@ bool castor::utils::getDumpableProcessAttribute() {
 //------------------------------------------------------------------------------
 // setDumpableProcessAttribute
 //------------------------------------------------------------------------------
-void castor::utils::setDumpableProcessAttribute(const bool dumpable) {
+ void castor::utils::setDumpableProcessAttribute(const bool dumpable) {
   const int rc = prctl(PR_SET_DUMPABLE, dumpable ? 1 : 0);
   switch(rc) {
   case -1:
diff --git a/tapeserver/cta-taped.cpp b/tapeserver/cta-taped.cpp
new file mode 100644
index 0000000000..760727bab6
--- /dev/null
+++ b/tapeserver/cta-taped.cpp
@@ -0,0 +1,197 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "common/Configuration.hpp"
+#include "common/log/SyslogLogger.hpp"
+#include "common/processCap/ProcessCap.hpp"
+#include "tapeserver/daemon/GlobalConfiguration.hpp"
+#include "tapeserver/daemon/TpconfigLines.hpp"
+#include "tapeserver/daemon/TapeDaemon.hpp"
+
+#include "version.h"
+
+#include <google/protobuf/stubs/common.h>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <iostream>
+
+//------------------------------------------------------------------------------
+// exceptionThrowingMain
+//
+// The main() function delegates the bulk of its implementation to this
+// exception throwing version.
+//
+// @param argc The number of command-line arguments.
+// @param argv The command-line arguments.
+// @param log The logging system.
+//------------------------------------------------------------------------------
+static int exceptionThrowingMain(const int argc, char **const argv,
+  cta::log::Logger &log);
+
+//------------------------------------------------------------------------------
+// main
+//------------------------------------------------------------------------------
+int main(const int argc, char **const argv) {
+  // Try to instantiate the logging system API
+  std::unique_ptr<cta::log::SyslogLogger> logPtr;
+  try {
+    logPtr.reset(new cta::log::SyslogLogger("tapeserverd"));
+  } catch(cta::exception::Exception &ex) {
+    std::cerr <<
+      "Failed to instantiate object representing CTA logging system: " <<
+      ex.getMessage().str() << std::endl;
+    return 1;
+  }
+  cta::log::Logger &log = *logPtr;
+
+  int programRc = 1; // Be pessimistic
+  try {
+    programRc = exceptionThrowingMain(argc, argv, log);
+  } catch(cta::exception::Exception &ex) {
+    cta::log::Param params[] = {
+      cta::log::Param("message", ex.getMessage().str())};
+    log(LOG_ERR, "Caught an unexpected CASTOR exception", params);
+  } catch(std::exception &se) {
+    cta::log::Param params[] = {cta::log::Param("what", se.what())};
+    log(LOG_ERR, "Caught an unexpected standard exception", params);
+  } catch(...) {
+    log(LOG_ERR, "Caught an unexpected and unknown exception");
+  }
+
+  google::protobuf::ShutdownProtobufLibrary();
+  return programRc;
+}
+
+//------------------------------------------------------------------------------
+// Logs the start of the daemon.
+//------------------------------------------------------------------------------
+static void logStartOfDaemon(cta::log::Logger &log, const int argc,
+  const char *const *const argv);
+
+//------------------------------------------------------------------------------
+// Creates a string that contains the specified command-line arguments
+// separated by single spaces.
+//
+// @param argc The number of command-line arguments.
+// @param argv The array of command-line arguments.
+//------------------------------------------------------------------------------
+static std::string argvToString(const int argc, const char *const *const argv);
+
+////------------------------------------------------------------------------------
+//// Writes the specified TPCONFIG lines to the specified logging system.
+////
+//// @param log The logging system.
+//// @param lines The lines parsed from /etc/castor/TPCONFIG.
+////------------------------------------------------------------------------------
+//static void logTpconfigLines(cta::log::Logger &log,
+//  const cta::tape::daemon::TpconfigLines &lines);
+//
+////------------------------------------------------------------------------------
+//// Writes the specified TPCONFIG lines to the logging system.
+////
+//// @param log The logging system.
+//// @param line The line parsed from /etc/castor/TPCONFIG.
+////------------------------------------------------------------------------------
+//static void logTpconfigLine(cta::log::Logger &log,
+//  const cta::tape::daemon::TpconfigLine &line);
+
+//------------------------------------------------------------------------------
+// exceptionThrowingMain
+//------------------------------------------------------------------------------
+static int exceptionThrowingMain(const int argc, char **const argv,
+  cta::log::Logger &log) {
+  using namespace cta::tape::daemon;
+
+  logStartOfDaemon(log, argc, argv);
+
+  // Parse /etc/cta/cta.conf and /etc/cta/TPCONFIG for global parameters
+  const GlobalConfiguration globalConfig =
+    GlobalConfiguration::createFromCtaConf(log);
+
+  // Create the object providing utilities for working with UNIX capabilities
+  cta::server::ProcessCap capUtils;
+
+  // Create the main tapeserverd object
+  cta::tape::daemon::TapeDaemon daemon(
+    argc,
+    argv,
+    std::cout,
+    std::cerr,
+    log,
+    globalConfig,
+    capUtils);
+
+  // Run the tapeserverd daemon
+  return daemon.main();
+}
+
+//------------------------------------------------------------------------------
+// logStartOfDaemon
+//------------------------------------------------------------------------------
+static void logStartOfDaemon(cta::log::Logger &log, const int argc,
+  const char *const *const argv) {
+
+  const std::string concatenatedArgs = argvToString(argc, argv);
+  cta::log::Param params[] = {
+    cta::log::Param("version", CTA_VERSION),
+    cta::log::Param("argv", concatenatedArgs)};
+  log(LOG_INFO, "tapeserverd started", params);
+}
+
+//------------------------------------------------------------------------------
+// argvToString
+//------------------------------------------------------------------------------
+static std::string argvToString(const int argc, const char *const *const argv) {
+  std::string str;
+
+  for(int i=0; i < argc; i++) {
+    if(i != 0) {
+      str += " ";
+    }
+
+    str += argv[i];
+  }
+  return str;
+}
+
+////------------------------------------------------------------------------------
+//// logTpconfigLines
+////------------------------------------------------------------------------------
+//static void logTpconfigLines(cta::log::Logger &log,
+//  const cta::tape::daemon::TpconfigLines &lines) {
+//  using namespace cta::tape::daemon;
+//
+//  for(TpconfigLines::const_iterator itor = lines.begin();
+//    itor != lines.end(); itor++) {
+//    logTpconfigLine(log, *itor);
+//  }
+//}
+//
+////------------------------------------------------------------------------------
+//// logTpconfigLine
+////------------------------------------------------------------------------------
+//static void logTpconfigLine(cta::log::Logger &log,
+//  const cta::tape::daemon::TpconfigLine &line) {
+//  cta::log::Param params[] = {
+//    cta::log::Param("unitName", line.unitName),
+//    cta::log::Param("logicalLibrary", line.logicalLibrary),
+//    cta::log::Param("devFilename", line.devFilename),
+//    cta::log::Param("librarySlot", line.librarySlot)};
+//  log(LOG_INFO, "TPCONFIG line", params);
+//}
diff --git a/tapeserver/castor/tape/tapeserver/daemon/tapeserverd.init b/tapeserver/cta-taped.init
similarity index 100%
rename from tapeserver/castor/tape/tapeserver/daemon/tapeserverd.init
rename to tapeserver/cta-taped.init
diff --git a/tapeserver/castor/tape/tapeserver/daemon/castor-tapeserver-server.logrotate b/tapeserver/cta-taped.logrotate
similarity index 100%
rename from tapeserver/castor/tape/tapeserver/daemon/castor-tapeserver-server.logrotate
rename to tapeserver/cta-taped.logrotate
diff --git a/tapeserver/castor/tape/tapeserver/daemon/tapeserverd.man b/tapeserver/cta-taped.man
similarity index 100%
rename from tapeserver/castor/tape/tapeserver/daemon/tapeserverd.man
rename to tapeserver/cta-taped.man
diff --git a/tapeserver/castor/tape/tapeserver/daemon/tapeserverd.sysconfig b/tapeserver/cta-taped.sysconfig
similarity index 100%
rename from tapeserver/castor/tape/tapeserver/daemon/tapeserverd.sysconfig
rename to tapeserver/cta-taped.sysconfig
diff --git a/tapeserver/daemon/CMakeLists.txt b/tapeserver/daemon/CMakeLists.txt
new file mode 100644
index 0000000000..cd4e6782e1
--- /dev/null
+++ b/tapeserver/daemon/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required (VERSION 2.6)
+
+add_library(ctatapedaemon
+  GlobalConfiguration.cpp
+  TapeDaemon.cpp
+  TpconfigLine.cpp
+  TpconfigLines.cpp)
\ No newline at end of file
diff --git a/tapeserver/daemon/DriveConfiguration.hpp b/tapeserver/daemon/DriveConfiguration.hpp
new file mode 100644
index 0000000000..a93713cced
--- /dev/null
+++ b/tapeserver/daemon/DriveConfiguration.hpp
@@ -0,0 +1,96 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+#include <string>
+#include <cstdint>
+#include "common/log/DummyLogger.hpp"
+
+namespace cta { namespace tape { namespace daemon {
+/**
+ * Class containing all the parameters needed by the transfer process
+ * to manage its drive
+ */
+struct DriveConfiguration {
+  /** The name of the drive */
+  std::string unitName;
+  
+  /** The logical library to which the drive belongs */
+  std::string logicalLibrary;
+  
+  /** The filename of the device file of the tape drive. */
+  std::string devFilename;
+
+  /** The slot in the tape library that contains the tape drive. */
+  std::string librarySlot;
+
+  /** The size in bytes of a data-transfer buffer. */
+  uint32_t bufferSize;
+
+  /** The total number of data-transfer buffers to be instantiated. */
+  uint32_t bufferCount;
+  
+  /** The structure representing the maximum number of bytes and files 
+   cta-taped will fetch or report in one access to the object store*/
+  struct fetchReportOrFLushLimits {
+    uint64_t maxBytes;
+    uint64_t maxFiles;
+    fetchReportOrFLushLimits(): maxBytes(0), maxFiles(0) {}
+  };
+  
+  /** Archive jobs fetch/report limits */
+  fetchReportOrFLushLimits bulkArchive;
+  
+  /** Retrieve jobs fetch/report limits */
+  fetchReportOrFLushLimits bulkRetrieve;
+
+  /** Amount of data/files after which we will flush data to tape (archive only) */
+  fetchReportOrFLushLimits flushData;
+
+  /** The number of disk I/O threads. */
+  uint32_t nbDiskThreads;
+
+  /** Constructor that sets all integer member-variables to 0 and all string
+   * member-variables to the empty string. */
+  DriveConfiguration(): bufferSize(0), bufferCount(0), nbDiskThreads(0) {};
+
+  /** Returns a configuration structure based on the contents of
+   * /etc/cta/cta.conf, /etc/cta/TPCONFIG and compile-time constants.
+   *
+   * @param log pointer to NULL or an optional logger object.
+   * @return The configuration structure. */
+  static DriveConfiguration createFromCtaConf(
+    cta::log::Logger & log = gDummyLogger);
+  
+  /** Returns a configuration structure based on the contents of
+   * /etc/cta/cta.conf, /etc/cta/TPCONFIG and compile-time constants.
+   *
+   * @param log pointer to NULL or an optional logger object.
+   * @return The configuration structure. */
+  static DriveConfiguration createFromCtaConf(
+    const std::string & generalConfigPath,
+    const std::string & tapeConfigFile,
+    cta::log::Logger & log = gDummyLogger);
+  
+private:
+  /** A private dummy logger which will simplify the implementaion of the 
+   * functions (just unconditionally log things). */
+  static cta::log::DummyLogger gDummyLogger;
+}; // DriveConfiguration
+
+}}} // namespace cta::tape::daemon
\ No newline at end of file
diff --git a/tapeserver/daemon/GlobalConfiguration.cpp b/tapeserver/daemon/GlobalConfiguration.cpp
new file mode 100644
index 0000000000..6d14b9f24e
--- /dev/null
+++ b/tapeserver/daemon/GlobalConfiguration.cpp
@@ -0,0 +1,36 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "GlobalConfiguration.hpp"
+
+namespace cta { namespace tape { namespace daemon {
+  
+GlobalConfiguration GlobalConfiguration::createFromCtaConf(cta::log::Logger& log) {
+  return createFromCtaConf("/etc/cta/cta.conf", "/etc/cta/TPCONFIG", log);
+}
+
+GlobalConfiguration GlobalConfiguration::createFromCtaConf(
+  const std::string& generalConfigPath, 
+  const std::string& tapeConfigFile, cta::log::Logger& log) {
+  GlobalConfiguration ret;
+  return ret;
+}
+
+cta::log::DummyLogger GlobalConfiguration::gDummyLogger("");
+
+}}} // namespace cta::tape::daemon
diff --git a/tapeserver/daemon/GlobalConfiguration.hpp b/tapeserver/daemon/GlobalConfiguration.hpp
new file mode 100644
index 0000000000..d136c0cffc
--- /dev/null
+++ b/tapeserver/daemon/GlobalConfiguration.hpp
@@ -0,0 +1,47 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+#include <string>
+#include <map>
+#include "DriveConfiguration.hpp"
+#include "common/log/DummyLogger.hpp"
+
+namespace cta {
+namespace tape {
+namespace daemon {
+/**
+ * Class containing all the parameters needed by the watchdog process
+ * to spawn a transfer session per drive.
+ */
+struct GlobalConfiguration {
+  static GlobalConfiguration createFromCtaConf(
+          cta::log::Logger &log = gDummyLogger);
+  static GlobalConfiguration createFromCtaConf(
+          const std::string & generalConfigPath,
+          const std::string & tapeConfigFile,
+          cta::log::Logger & log = gDummyLogger);
+  std::map<std::string, DriveConfiguration> driveConfigs;
+private:
+  /** A private dummy logger which will simplify the implementaion of the 
+   * functions (just unconditionally log things). */
+  static cta::log::DummyLogger gDummyLogger;
+} ;
+}
+}
+} // namespace cta::tape::daemon
\ No newline at end of file
diff --git a/tapeserver/daemon/TapeDaemon.cpp b/tapeserver/daemon/TapeDaemon.cpp
new file mode 100644
index 0000000000..b943333917
--- /dev/null
+++ b/tapeserver/daemon/TapeDaemon.cpp
@@ -0,0 +1,172 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "TapeDaemon.hpp"
+#include "common/exception/Errnum.hpp"
+#include "common/utils/Utils.hpp"
+#include <google/protobuf/service.h>
+
+namespace cta { namespace tape { namespace daemon {
+
+TapeDaemon::TapeDaemon(const int argc, char* * const argv, 
+    std::ostream& stdOut, std::ostream& stdErr, 
+    log::Logger& log, 
+    const GlobalConfiguration& globalConfig, 
+    cta::server::ProcessCap& capUtils): 
+    cta::server::Daemon(stdOut, stdErr, log),
+    m_argc(argc), m_argv(argv),
+    m_globalConfiguration(globalConfig), m_capUtils(capUtils),
+    m_programName("cta-taped"), m_hostName(getHostName()) { }
+
+TapeDaemon::~TapeDaemon() {
+  google::protobuf::ShutdownProtobufLibrary();
+}
+
+//------------------------------------------------------------------------------
+// main
+//------------------------------------------------------------------------------
+int TapeDaemon::main() {
+  try {
+
+    exceptionThrowingMain(m_argc, m_argv);
+
+  } catch (cta::exception::Exception &ex) {
+    // Write the error to standard error
+    m_stdErr << std::endl << "Aborting: " << ex.getMessage().str() << std::endl
+      << std::endl;
+
+    // Log the error
+    log::Param params[] = {
+      log::Param("Message", ex.getMessage().str())};
+    m_log(LOG_ERR, "Aborting", params);
+
+    return 1;
+  }
+
+  return 0;
+}
+
+//------------------------------------------------------------------------------
+// getHostName
+//------------------------------------------------------------------------------
+std::string cta::tape::daemon::TapeDaemon::getHostName() const {
+  char nameBuf[81];
+  if(gethostname(nameBuf, sizeof(nameBuf)))
+    throw cta::exception::Errnum("Failed to get host name");
+  return nameBuf;
+}
+
+//------------------------------------------------------------------------------
+// exceptionThrowingMain
+//------------------------------------------------------------------------------
+void  cta::tape::daemon::TapeDaemon::exceptionThrowingMain(
+  const int argc, char **const argv)  {
+  parseCommandLine(argc, argv);
+
+  if(m_globalConfiguration.driveConfigs.empty())
+    throw cta::exception::Exception("/etc/cta/TPCONFIG is empty");
+
+  // Process must be able to change user now and should be permitted to perform
+  // raw IO in the future
+  setProcessCapabilities("cap_setgid,cap_setuid+ep cap_sys_rawio+p");
+
+  const bool runAsStagerSuperuser = true;
+  daemonizeIfNotRunInForeground(runAsStagerSuperuser);
+  setDumpable();
+
+  // There is no longer any need for the process to be able to change user,
+  // however the process should still be permitted to perform raw IO in the
+  // future
+  setProcessCapabilities("cap_sys_rawio+p");
+
+  blockSignals();
+  mainEventLoop();
+}
+
+//------------------------------------------------------------------------------
+// mainEventLoop
+//------------------------------------------------------------------------------
+void cta::tape::daemon::TapeDaemon::mainEventLoop() {
+  throw cta::exception::Exception("cta::tape::daemon::TapeDaemon::mainEventLoop: not implemented");
+//  while (handleIOEvents() && handleTick() && handlePendingSignals()) {
+//  }
+}
+
+//------------------------------------------------------------------------------
+// setDumpable
+//------------------------------------------------------------------------------
+void cta::tape::daemon::TapeDaemon::setDumpable() {
+  cta::Utils::setDumpableProcessAttribute(true);
+  const bool dumpable = cta::Utils::getDumpableProcessAttribute();
+  log::Param params[] = {
+    log::Param("dumpable", dumpable ? "true" : "false")};
+  m_log(LOG_INFO, "Got dumpable attribute of process", params);
+  if(!dumpable) {
+    cta::exception::Exception ex;
+    ex.getMessage() << "Failed to set dumpable attribute of process to true";
+    throw ex;
+  }
+}
+
+//------------------------------------------------------------------------------
+// setProcessCapabilities
+//------------------------------------------------------------------------------
+void cta::tape::daemon::TapeDaemon::setProcessCapabilities(
+  const std::string &text) {
+  try {
+    m_capUtils.setProcText(text);
+    log::Param params[] =
+      {log::Param("capabilities", m_capUtils.getProcText())};
+    m_log(LOG_INFO, "Set process capabilities", params);
+  } catch(cta::exception::Exception &ne) {
+    cta::exception::Exception ex;
+    ex.getMessage() << "Failed to set process capabilities to '" << text <<
+      "': " << ne.getMessage().str();
+    throw ex;
+  }
+}
+
+//------------------------------------------------------------------------------
+// blockSignals
+//------------------------------------------------------------------------------
+void cta::tape::daemon::TapeDaemon::blockSignals() const {
+  sigset_t sigs;
+  sigemptyset(&sigs);
+  // The signals that should not asynchronously disturb the daemon
+  sigaddset(&sigs, SIGHUP);
+  sigaddset(&sigs, SIGINT);
+  sigaddset(&sigs, SIGQUIT);
+  sigaddset(&sigs, SIGPIPE);
+  sigaddset(&sigs, SIGTERM);
+  sigaddset(&sigs, SIGUSR1);
+  sigaddset(&sigs, SIGUSR2);
+  sigaddset(&sigs, SIGCHLD);
+  sigaddset(&sigs, SIGTSTP);
+  sigaddset(&sigs, SIGTTIN);
+  sigaddset(&sigs, SIGTTOU);
+  sigaddset(&sigs, SIGPOLL);
+  sigaddset(&sigs, SIGURG);
+  sigaddset(&sigs, SIGVTALRM);
+  cta::exception::Errnum::throwOnNonZero(
+    sigprocmask(SIG_BLOCK, &sigs, NULL),
+    "Failed to block signals: sigprocmask() failed");
+}
+
+
+
+}}} // namespace cta::tape::daemon
\ No newline at end of file
diff --git a/tapeserver/daemon/TapeDaemon.hpp b/tapeserver/daemon/TapeDaemon.hpp
new file mode 100644
index 0000000000..dea03694a3
--- /dev/null
+++ b/tapeserver/daemon/TapeDaemon.hpp
@@ -0,0 +1,266 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "common/threading/Daemon.hpp"
+#include "tapeserver/daemon/GlobalConfiguration.hpp"
+#include "common/processCap/ProcessCap.hpp"
+#include <signal.h>
+
+
+namespace cta { namespace tape { namespace  daemon {
+
+/** Daemon responsible for reading and writing data from and to one or more tape
+ * drives drives connected to a tape server. */
+
+class TapeDaemon : public cta::server::Daemon {
+
+public:
+
+  /** Constructor.
+   * @param argc The argc of main().
+   * @param argv The argv of main().
+   * @param stdOut Stream representing standard out.
+   * @param stdErr Stream representing standard error.
+   * @param log The object representing the API of the CTA logging system.
+   * @param globalConfig The configuration of the tape server.
+   * @param capUtils Object providing utilities for working UNIX capabilities. */
+  TapeDaemon(
+    const int argc,
+    char **const argv,
+    std::ostream &stdOut,
+    std::ostream &stdErr,
+    log::Logger &log,
+    const GlobalConfiguration &globalConfig,
+    cta::server::ProcessCap &capUtils);
+  
+  virtual ~TapeDaemon();
+
+  /** The main entry function of the daemon.
+   * @return The return code of the process. */
+  int main();
+  
+protected:
+
+  /** Enumeration of the possible tape-daemon states. */
+  enum State {
+    TAPEDAEMON_STATE_RUNNING,
+    TAPEDAEMON_STATE_SHUTTINGDOWN};
+
+  /** Return the string representation of the specified tape-daemon state.
+   * @param The tape-daemon state.
+   * @return The string representation. */
+  static const char *stateToStr(const State state) throw();
+
+  /** The current state of the tape-server daemon. */
+  State m_state;
+
+  /** The absolute time at which the shutdown sequence was started. */
+  time_t m_startOfShutdown;
+
+  /** Returns the name of the host on which the daemon is running. */
+  std::string getHostName() const;
+
+  /** Exception throwing main() function.
+   * @param argc The number of command-line arguments.
+   * @param argv The array of command-line arguments. */
+  void exceptionThrowingMain(const int argc, char **const argv);
+
+  /** Sets the dumpable attribute of the current process to true. */
+  void setDumpable();
+
+  /** Sets the capabilities of the current process.
+   *
+   * @text The string representation the capabilities that the current
+   * process should have. */
+  void setProcessCapabilities(const std::string &text);
+
+  /** Socket pair used to send commands to the DriveProcess. */
+  struct DriveSocketPair {
+    /** Bi-directional socket used by the TapeDaemon parent process to send
+     * commands to the process forker and receive replies in return. */
+    int tapeDaemon;
+
+    /** Bi-directional socket used by the ProcessForker to receive commands
+     * from the TapeDaemon parent process and send back replies.  */
+    int driveProcess;
+
+    /** Constructor.
+     * Sets members to -1 which represents an invalid file descriptor. */
+    DriveSocketPair(): tapeDaemon(-1), driveProcess(-1) {
+    }
+    /** Close utility. Closes both sockets */
+    void closeBoth();
+    /** Close utility. Closes drive's socket */
+    void closeDriveEnd();
+    /** Close utility. Closes daemon's socket */
+    void closeDaemonEnd();
+  }; // struct DriveSocketPair
+
+  /** Creates the socket pair to be used to control the ProcessForker.
+   * @return The socket pair. */
+  DriveSocketPair createDriveSocketPair();
+
+  /**
+   * Forks a drive process.
+   *
+   * PLEASE NOTE: No sockets should be registered with m_reactor before this
+   * method is called.  This method will NOT call m_reactor.clear() in the
+   * client process.  This is because it is possible to put ZMQ sockets into the
+   * reactor and one should not manipulate such sockets in two difefrent threads
+   * or processes.  Specifically do not call setUpReactor() until
+   * forkProcessForker() has been called.
+   *
+   * @param cmdPair Socket pair used to send commands to the ProcessForker.
+   * @param reaperPair Socket pair used by the ProcessForker to notify the
+   * TapeDaemon parent process of the termination of ProcessForker child
+   * processes.
+   * by the ProcessForker.
+   * @return The process identifier of the ProcessForker.
+   */
+  pid_t forkDriveProcess(const DriveSocketPair &drivePair);
+
+  /** Runs the driveProcess after fork
+   *
+   * @param heartbeatSocket The socket used to send heartbeat to.
+   * @return the exit code to be used for the process running the DriveProcess. */
+  int runDriveProcess(const int heartbeatSocket);
+
+  /** Blocks the signals that should not asynchronously disturb the daemon. */
+  void blockSignals() const;
+
+  /**
+   * Creates the handler to handle the incoming connection from the
+   * ProcessForker.
+   *
+   * @param reaperSocket The TapeDaemon side of the socket pair used by the
+   * ProcessForker  to report the termination of its child processes.
+   */
+  void createAndRegisterProcessForkerConnectionHandler(const int reaperSocket);
+
+  /**
+   * Creates the handler to handle messages from forked sessions.
+   */
+  void createAndRegisterTapeMessageHandler();
+  
+  /**
+   * The main event loop of the daemon.
+   */
+  void mainEventLoop();
+
+  /**
+   * Handles any pending IO events.
+   *
+   * @return True if the main event loop should continue, else false.
+   */
+  bool handleIOEvents() throw();
+
+  /**
+   * Handles a tick in time.  Time driven actions such as alarms should be
+   * implemented here.
+   *
+   * This method does not have to be called at any time precise interval,
+   * though it should be called at least twice as fast as the quickest reaction
+   * time imposed on the catalogue.
+   *
+   * @return True if the main event loop should continue, else false.
+   */
+  bool handleTick() throw();
+
+  /**
+   * Handles any pending signals.
+   *
+   * @return True if the main event loop should continue, else false.
+   */
+  bool handlePendingSignals() throw();
+
+  /**
+   * Handles the specified signals.
+   *
+   * @param sig The number of the signal.
+   * @param sigInfo Information about the signal.
+   * @return True if the main event loop should continue, else false.
+   */
+  bool handleSignal(const int sig, const siginfo_t &sigInfo);
+
+  /**
+   * Handles a SIGINT signal.
+   *
+   * @param sigInfo Information about the signal.
+   * @return True if the main event loop should continue, else false.
+   */
+  bool handleSIGINT(const siginfo_t &sigInfo);
+
+  /**
+   * Handles a SIGTERM signal.
+   *
+   * @param sigInfo Information about the signal.
+   * @return True if the main event loop should continue, else false.
+   */
+  bool handleSIGTERM(const siginfo_t &sigInfo);
+
+  /**
+   * Handles a SIGCHLD signal.
+   *
+   * @param sigInfo Information about the signal.
+   * @return True if the main event loop should continue, else false.
+   */
+  bool handleSIGCHLD(const siginfo_t &sigInfo);
+
+  /**
+   * Logs the fact that the specified child process has terminated.
+   *
+   * @param pid The process ID of the child process.
+   * @param waitpidStat The status information given by a call to waitpid().
+   */
+  void logChildProcessTerminated(const pid_t pid, const int waitpidStat)
+    throw();
+  
+  /**
+   * The argc of main().
+   */
+  const int m_argc;
+
+  /**
+   * The argv of main().
+   */
+  char **const m_argv;
+  
+  /** The tape server's configuration */
+  const GlobalConfiguration& m_globalConfiguration;
+
+  /**
+   * Object providing utilities for working UNIX capabilities.
+   */
+  cta::server::ProcessCap &m_capUtils;
+
+  /**
+   * The program name of the daemon.
+   */
+  const std::string m_programName;
+
+  /**
+   * The name of the host on which the daemon is running.  This name is
+   * needed to fill in messages to be sent to the vdqmd daemon.
+   */
+  const std::string m_hostName;
+
+}; // class TapeDaemon
+
+}}} // namespace cta::tape::daemon
diff --git a/tapeserver/daemon/TpconfigLine.cpp b/tapeserver/daemon/TpconfigLine.cpp
new file mode 100644
index 0000000000..9f30af84c4
--- /dev/null
+++ b/tapeserver/daemon/TpconfigLine.cpp
@@ -0,0 +1,33 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "tapeserver/daemon/TpconfigLine.hpp"
+
+//------------------------------------------------------------------------------
+// Constructor.
+//------------------------------------------------------------------------------
+cta::tape::daemon::TpconfigLine::TpconfigLine(
+  const std::string &unitName,
+  const std::string &logicalLibrary,
+  const std::string &devFilename,
+  const std::string &librarySlot) throw():
+  unitName(unitName),
+  logicalLibrary(logicalLibrary),
+  devFilename(devFilename),
+  librarySlot(librarySlot) {
+}
diff --git a/tapeserver/daemon/TpconfigLine.hpp b/tapeserver/daemon/TpconfigLine.hpp
new file mode 100644
index 0000000000..a481da6777
--- /dev/null
+++ b/tapeserver/daemon/TpconfigLine.hpp
@@ -0,0 +1,69 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace cta { namespace tape { namespace daemon {
+
+/**
+ * The data stored in a data-line (as opposed to a comment-line) from a
+ * TPCONFIG file (/etc/castor/TPCONFIG).
+ */
+struct TpconfigLine {
+  /**
+   * The unit name of the tape drive.
+   */
+  std::string unitName;
+
+  /**
+   * The logical library of the tape drive.
+   */
+  std::string logicalLibrary;
+
+  /**
+   * The filename of the device file of the tape drive.
+   */
+  std::string devFilename;
+
+  /**
+   * The slot in the tape library that contains the tape drive.
+   */
+  std::string librarySlot;
+
+  /**
+   * Constructor.
+   *
+   * @param unitName The unit name of the tape drive.
+   * @param dgn The Device Group Name (DGN) of the tape drive.
+   * @param devFilename The filename of the device file of the tape drive.
+   * @param librarySlot The slot in the tape library that contains the tape
+   * drive.
+   */
+  TpconfigLine(
+    const std::string &unitName,
+    const std::string &logicalLibrary,
+    const std::string &devFilename,
+    const std::string &librarySlot) throw();
+  
+  static const size_t maxUnitNameLen;
+  static const size_t maxLogicalLibraryNameLen;
+}; // struct TpconfigLine
+
+}}} // namespace cta::tape::daemon
diff --git a/tapeserver/daemon/TpconfigLines.cpp b/tapeserver/daemon/TpconfigLines.cpp
new file mode 100644
index 0000000000..1364226913
--- /dev/null
+++ b/tapeserver/daemon/TpconfigLines.cpp
@@ -0,0 +1,167 @@
+/******************************************************************************
+ *
+ * This file is part of the Castor project.
+ * See http://castor.web.cern.ch/castor
+ *
+ * Copyright (C) 2003  CERN
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ *
+ *
+ * @author Castor Dev team, castor-dev@cern.ch
+ *****************************************************************************/
+
+#include "tapeserver/daemon/TpconfigLines.hpp"
+#include "common/utils/Utils.hpp"
+#include "common/exception/Errnum.hpp"
+
+#include <errno.h>
+#include <memory>
+
+//------------------------------------------------------------------------------
+// parseTpconfigFile
+//------------------------------------------------------------------------------
+cta::tape::daemon::TpconfigLines 
+cta::tape::daemon::TpconfigLines::parseFile(const std::string &filename) {
+  TpconfigLines lines;
+
+  // Open the TPCONFIG file for reading
+  std::unique_ptr<FILE, decltype(&::fclose)> file(fopen(filename.c_str(), "r"), &::fclose);
+  {
+    const int savedErrno = errno;
+
+    // Throw an exception if the file could not be opened
+    if(file.get() == NULL) {
+      cta::exception::Errnum ex(savedErrno);
+
+      ex.getMessage() <<
+        "Failed to parse TPCONFIG file"
+        ": Failed to open file"
+        ": filename='" << filename << "'"
+        ": " << cta::Utils::errnoToString(savedErrno);
+
+      throw ex;
+    }
+  }
+
+  // Line buffer
+  char lineBuf[1024];
+
+  // The error number recorded immediately after fgets is called
+  int fgetsErrno = 0;
+
+  // For each line was read
+  for(int lineNb = 1; fgets(lineBuf, sizeof(lineBuf), file.get()); lineNb++) {
+    fgetsErrno = errno;
+
+    // Create a std::string version of the line
+    std::string line(lineBuf);
+
+    // Remove the newline character if there is one
+    {
+      const std::string::size_type newlinePos = line.find("\n");
+      if(newlinePos != std::string::npos) {
+        line = line.substr(0, newlinePos);
+      }
+    }
+
+    // If there is a comment, then remove it from the line
+    {
+      const std::string::size_type startOfComment = line.find("#");
+      if(startOfComment != std::string::npos) {
+        line = line.substr(0, startOfComment);
+      }
+    }
+
+    // Left and right trim the line of whitespace
+    line = cta::Utils::trimString(std::string(line));
+
+    // If the line is not empty
+    if(line != "") {
+
+      // Replace each occurance of whitespace with a single space
+      line = cta::Utils::singleSpaceString(line);
+
+      // Split the line into its component data-columns
+      std::vector<std::string> columns;
+      cta::Utils::splitString(line, ' ', columns);
+
+      // The expected number of data-columns in a TPCONFIG data-line is 4:
+      //   unitName dgn devFilename librarySlot
+      const unsigned int expectedNbOfColumns = 4;
+
+      // Throw an exception if the number of data-columns is invalid
+      if(columns.size() != expectedNbOfColumns) {
+        InvalidArgument ex;
+        ex.getMessage() <<
+          "Failed to parse TPCONFIG file"
+          ": Invalid number of data columns in TPCONFIG line"
+          ": filename='" << filename << "'"
+          " lineNb=" << lineNb <<
+          " expectedNbColumns=" << expectedNbOfColumns <<
+          " actualNbColumns=" << columns.size() <<
+          " expectedFormat='unitName dgn devFilename librarySlot'";
+        throw ex;
+      }
+
+      const TpconfigLine configLine(
+        columns[0], // unitName
+        columns[1], // logicalLibrary
+        columns[2], // devFilename
+        columns[3]  // librarySlot
+      );
+
+      if(TpconfigLine::maxUnitNameLen < configLine.unitName.length()) {
+        InvalidArgument ex;
+        ex.getMessage() <<
+          "Failed to parse TPCONFIG file"
+          ": Tape-drive unit-name is too long"
+          ": filename='" << filename << "'"
+          " lineNb=" << lineNb <<
+          " unitName=" << configLine.unitName <<
+          " maxUnitNameLen=" << TpconfigLine::maxUnitNameLen <<
+          " actualUnitNameLen=" << configLine.unitName.length();
+        throw ex;
+      }
+
+      if(TpconfigLine::maxLogicalLibraryNameLen < configLine.logicalLibrary.length()) {
+        InvalidArgument ex;
+        ex.getMessage() <<
+          "Failed to parse TPCONFIG file"
+          ": logical library is too long"
+          ": filename='" << filename << "'"
+          " lineNb=" << lineNb <<
+          " logicalLibrary=" << configLine.logicalLibrary <<
+          " maxLogicalLibraryLen=" << TpconfigLine::maxLogicalLibraryNameLen <<
+          " actualLogicalLibraryLen=" << configLine.logicalLibrary.length();
+        throw ex;
+      }
+
+      // Store the value of the data-columns in the output list parameter
+      lines.push_back(TpconfigLine(configLine));
+    }
+  }
+
+  // Throw an exception if there was error whilst reading the file
+  if(ferror(file.get())) {
+    std::stringstream err;
+    err <<"Failed to parse TPCONFIG file"
+          ": Failed to read file"
+          ": filename='" << filename << "'";
+    cta::exception::Errnum ex(fgetsErrno, err.str());
+    throw ex;
+  }
+
+  return lines;
+}
diff --git a/tapeserver/daemon/TpconfigLines.hpp b/tapeserver/daemon/TpconfigLines.hpp
new file mode 100644
index 0000000000..0810f48a01
--- /dev/null
+++ b/tapeserver/daemon/TpconfigLines.hpp
@@ -0,0 +1,44 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "tapeserver/daemon/TpconfigLine.hpp"
+#include "common/exception/Exception.hpp"
+
+#include <list>
+
+namespace cta { namespace tape { namespace daemon {
+
+/**
+ * A list of lines parsed from a TPCONFIG file.
+ */
+class TpconfigLines: public std::list<TpconfigLine> {
+public:
+
+  CTA_GENERATE_EXCEPTION_CLASS(InvalidArgument);
+  /**
+   * Parses the specified TPCONFIG file.
+   *
+   * @param filename The filename of the TPCONFIG file.
+   * @return The result of parsing the TPCONFIG file.
+   */
+  static TpconfigLines parseFile(const std::string &filename);
+}; // class TpconfigLines
+
+}}} // namespace cta::tape::daemon
diff --git a/version.hpp.in b/version.hpp.in
new file mode 100644
index 0000000000..d9e67f98f4
--- /dev/null
+++ b/version.hpp.in
@@ -0,0 +1,22 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#define CTA_VERSION "@CTA_VERSION@-@CTA_REPLEASE@"
+
-- 
GitLab