diff --git a/common/exception/Errnum.cpp b/common/exception/Errnum.cpp
index ceb4dac62aaab2fb819f766ae59223185f3b557f..b92077cd9c85fd828dc725f643ac707033e50ae8 100644
--- a/common/exception/Errnum.cpp
+++ b/common/exception/Errnum.cpp
@@ -40,7 +40,7 @@ void Errnum::ErrnumConstructorBottomHalf(const std::string & what) {
   if (what.size())
     w2 << what << " ";
   w2 << "Errno=" << m_errnum << ": " << m_strerror;
-  getMessage().str(w2.str());
+  getMessage() << w2.str();
 }
 
 void Errnum::throwOnReturnedErrno (const int err, const std::string &context) {
diff --git a/common/threading/SocketPairTest.cpp b/common/threading/SocketPairTest.cpp
index 31b357bee09a1ad8c11bbbc378e1b3a1272582bb..ed4b5276cfd59b6ad78dd2c9400aeff3ee28b988 100644
--- a/common/threading/SocketPairTest.cpp
+++ b/common/threading/SocketPairTest.cpp
@@ -96,7 +96,6 @@ TEST(cta_threading_SocketPair, MaxLength) {
   ASSERT_EQ(smallMessage, sp.receive(SocketPair::Side::child));
   ASSERT_EQ(bigMessage, sp.receive(SocketPair::Side::child));
   ASSERT_EQ(hugeMessage, sp.receive(SocketPair::Side::child));
-  //ASSERT_THROW(sp.receive(SocketPair::Side::child), SocketPair::Overflow);
   ASSERT_EQ(smallMessage, sp.receive(SocketPair::Side::child));
 }
 
diff --git a/tapeserver/cta-taped.cpp b/tapeserver/cta-taped.cpp
index f8fbe66235be986d178dee61f41da6b295f1f898..2132b6978a9be2233c1a780f42800a85c5302180 100644
--- a/tapeserver/cta-taped.cpp
+++ b/tapeserver/cta-taped.cpp
@@ -22,7 +22,7 @@
 #include "common/processCap/ProcessCap.hpp"
 #include "tapeserver/daemon/CommandLineParams.hpp"
 #include "tapeserver/daemon/TapedConfiguration.hpp"
-#include "tapeserver/daemon/TpconfigLines.hpp"
+#include "tapeserver/daemon/Tpconfig.hpp"
 #include "tapeserver/daemon/TapeDaemon.hpp"
 
 #include "version.h"
diff --git a/tapeserver/daemon/CMakeLists.txt b/tapeserver/daemon/CMakeLists.txt
index ae3e08dd3ccd70b4392546895bafde8a50f93a37..0708bceb23317bd060213e2388c5dc244edef671 100644
--- a/tapeserver/daemon/CMakeLists.txt
+++ b/tapeserver/daemon/CMakeLists.txt
@@ -7,11 +7,12 @@ add_library(ctatapedaemon
   TapedConfiguration.cpp
   TapeDaemon.cpp
   TpconfigLine.cpp
-  TpconfigLines.cpp)
+  Tpconfig.cpp)
 
 add_library(ctadaemonunittests SHARED
   ConfigurationFileTests.cpp
-  TapedConfigurationTests.cpp)
+  TapedConfigurationTests.cpp
+  TpconfigTests.cpp)
 
 target_link_libraries(ctadaemonunittests
   ctatapedaemon
diff --git a/tapeserver/daemon/Tpconfig.cpp b/tapeserver/daemon/Tpconfig.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cdda65ea915dc76dd8a5c670346f21a146c97f9e
--- /dev/null
+++ b/tapeserver/daemon/Tpconfig.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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/Tpconfig.hpp"
+#include "common/utils/utils.hpp"
+#include "common/exception/Errnum.hpp"
+
+#include <errno.h>
+#include <memory>
+#include <fstream>
+#include <algorithm>
+
+//------------------------------------------------------------------------------
+// parseTpconfigFile
+//------------------------------------------------------------------------------
+cta::tape::daemon::Tpconfig 
+cta::tape::daemon::Tpconfig::parseFile(const std::string &filename) {
+  Tpconfig ret;
+  // Try to open the configuration file, throwing an exception if there is a
+  // failure
+  std::ifstream file(filename);
+  if (file.fail()) {
+    cta::exception::Errnum ex;
+    ex.getMessage() << " In Tpconfig::parseFile()"
+      ": Failed to open tpConfig file"
+      ": filename=" << filename;
+    throw ex;
+  }
+  
+  std::string line;
+  size_t lineNumber=0;
+  while(++lineNumber, std::getline(file, line)) {
+    // If there is a comment, then remove it from the line
+    line = line.substr(0, line.find('#'));
+    // get rid of potential tabs
+    std::replace(line.begin(),line.end(),'\t',' ');
+    std::istringstream sline(line);
+    // This is the expected fields in the line. 
+    std::string unitName, logicalLibarry, devFilePath, librarySlot;
+    // If there is nothing on the line, ignore it.
+    if (!(sline >> unitName)) continue;
+    // But if there is anything, we expect all parameters.
+    if (!( (sline >> logicalLibarry)
+         &&(sline >> devFilePath)
+         &&(sline >> librarySlot))) {
+      cta::exception::Exception ex;
+      ex.getMessage() << "In Tpconfig::parseFile(): " <<
+        "missing parameter(s) from line=" << line <<
+        " filename=" << filename;
+      throw ex;
+    }
+    std::string extra;
+    if ( sline >> extra) {
+      cta::exception::Exception ex;
+      ex.getMessage() << "In Tpconfig::parseFile(): " <<
+        "extra parameter(s) from line=" << line <<
+        " filename=" << filename;
+      throw ex;
+    }
+    // The constructor implicitly validates the lengths 
+    const TpconfigLine configLine(unitName, logicalLibarry, devFilePath, librarySlot);
+    // Store the value of the data-columns in the output list parameter
+    ret.push_back(TpconfigLine(configLine));
+  }
+  return ret;
+}
diff --git a/tapeserver/daemon/TpconfigLines.hpp b/tapeserver/daemon/Tpconfig.hpp
similarity index 91%
rename from tapeserver/daemon/TpconfigLines.hpp
rename to tapeserver/daemon/Tpconfig.hpp
index 0810f48a01137238daaa3e33fb178d0d309fc856..ed497be9d91ba023e995bbb0cf3df315e09ed6a0 100644
--- a/tapeserver/daemon/TpconfigLines.hpp
+++ b/tapeserver/daemon/Tpconfig.hpp
@@ -28,7 +28,7 @@ namespace cta { namespace tape { namespace daemon {
 /**
  * A list of lines parsed from a TPCONFIG file.
  */
-class TpconfigLines: public std::list<TpconfigLine> {
+class Tpconfig: public std::list<TpconfigLine> {
 public:
 
   CTA_GENERATE_EXCEPTION_CLASS(InvalidArgument);
@@ -38,7 +38,7 @@ public:
    * @param filename The filename of the TPCONFIG file.
    * @return The result of parsing the TPCONFIG file.
    */
-  static TpconfigLines parseFile(const std::string &filename);
+  static Tpconfig parseFile(const std::string &filename);
 }; // class TpconfigLines
 
 }}} // namespace cta::tape::daemon
diff --git a/tapeserver/daemon/TpconfigLine.cpp b/tapeserver/daemon/TpconfigLine.cpp
index 9f30af84c48cb8c0504b4d598881a5dce276ec8c..0026913df0cae35bb42a30a683300fd918128cbf 100644
--- a/tapeserver/daemon/TpconfigLine.cpp
+++ b/tapeserver/daemon/TpconfigLine.cpp
@@ -17,6 +17,7 @@
  */
 
 #include "tapeserver/daemon/TpconfigLine.hpp"
+#include "common/exception/Exception.hpp"
 
 //------------------------------------------------------------------------------
 // Constructor.
@@ -25,9 +26,17 @@ cta::tape::daemon::TpconfigLine::TpconfigLine(
   const std::string &unitName,
   const std::string &logicalLibrary,
   const std::string &devFilename,
-  const std::string &librarySlot) throw():
+  const std::string &librarySlot):
   unitName(unitName),
   logicalLibrary(logicalLibrary),
   devFilename(devFilename),
   librarySlot(librarySlot) {
+  if (unitName.size() > maxNameLen)
+    throw cta::exception::Exception("In TpconfigLine::TpconfigLine: unitName too long");
+  if (logicalLibrary.size() > maxNameLen)
+    throw cta::exception::Exception("In TpconfigLine::TpconfigLine: logicalLibrary too long");
+  if (devFilename.size() > maxNameLen)
+    throw cta::exception::Exception("In TpconfigLine::TpconfigLine: devFilename too long");
+  if (librarySlot.size() > maxNameLen)
+    throw cta::exception::Exception("In TpconfigLine::TpconfigLine: librarySlot too long");
 }
diff --git a/tapeserver/daemon/TpconfigLine.hpp b/tapeserver/daemon/TpconfigLine.hpp
index 50c8a43823649d68284332e8484b7210c40299dd..9c77107edbbda2a7fc12647f0241dfa8f9c80834 100644
--- a/tapeserver/daemon/TpconfigLine.hpp
+++ b/tapeserver/daemon/TpconfigLine.hpp
@@ -60,10 +60,9 @@ struct TpconfigLine {
     const std::string &unitName,
     const std::string &logicalLibrary,
     const std::string &devFilename,
-    const std::string &librarySlot) throw();
+    const std::string &librarySlot);
   
-  static const size_t maxUnitNameLen;
-  static const size_t maxLogicalLibraryNameLen;
+  static const size_t maxNameLen = 100;
 }; // struct TpconfigLine
 
 }}} // namespace cta::tape::daemon
diff --git a/tapeserver/daemon/TpconfigLines.cpp b/tapeserver/daemon/TpconfigLines.cpp
deleted file mode 100644
index 0657752f5ae7d30c7e4ea0c17d0c99361c7159ac..0000000000000000000000000000000000000000
--- a/tapeserver/daemon/TpconfigLines.cpp
+++ /dev/null
@@ -1,161 +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 "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/TpconfigTests.cpp b/tapeserver/daemon/TpconfigTests.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b79eea25ace0244a86815c5bc1a0b785287d0d7a
--- /dev/null
+++ b/tapeserver/daemon/TpconfigTests.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "tapeserver/daemon/Tpconfig.hpp"
+#include "tests/TempFile.hpp"
+#include "common/exception/Errnum.hpp"
+
+namespace unitTests {
+
+TEST(cta_Daemon, Tpconfig_base) {
+  TempFile tf;
+  // Test with empty file
+  tf.stringFill("");
+  cta::tape::daemon::Tpconfig tpc = cta::tape::daemon::Tpconfig::parseFile(tf.path());
+  ASSERT_EQ(0, tpc.size());
+  // Test with file full of comments (but no valid line)
+  tf.stringFill("# some comment\n"
+      "\t   \t # Some non-empty line (spaces)\n"
+      "\t\t\t                   \n");
+  tpc = cta::tape::daemon::Tpconfig::parseFile(tf.path());
+  ASSERT_EQ(0, tpc.size());
+  
+  // Test with non-existing file
+  ASSERT_THROW(cta::tape::daemon::Tpconfig::parseFile("/no/such/file"), cta::exception::Errnum);
+  // Check we get the expected Errno.
+  try {
+    cta::tape::daemon::Tpconfig::parseFile("/no/such/file");
+    ASSERT_TRUE(false); // We should never get here.
+  } catch (cta::exception::Errnum & ex) {
+    ASSERT_NE(std::string::npos, ex.getMessageValue().find("Errno=2:"));
+  }
+  
+  // Test with a line too short
+  tf.stringFill("TapeDrive");
+  ASSERT_THROW(cta::tape::daemon::Tpconfig::parseFile(tf.path()), cta::exception::Exception);
+  try {
+    cta::tape::daemon::Tpconfig::parseFile(tf.path());
+    ASSERT_TRUE(false); // We should never get here.
+  } catch (cta::exception::Exception & ex) {
+    ASSERT_NE(std::string::npos, ex.getMessageValue().find("missing"));
+  }
+  
+  // Test with line too long
+  tf.stringFill("TapeDrive lib /dev/tape libSlot ExtraArgument");
+  ASSERT_THROW(cta::tape::daemon::Tpconfig::parseFile(tf.path()), cta::exception::Exception);
+  try {
+    cta::tape::daemon::Tpconfig::parseFile(tf.path());
+    ASSERT_TRUE(false); // We should never get here.
+  } catch (cta::exception::Exception & ex) {
+    ASSERT_NE(std::string::npos, ex.getMessageValue().find("extra parameter"));
+  }
+  
+  // Test with several entries (valid file with various extra blanks)
+  tf.stringFill("         drive0 lib0 \t\t\t /dev/tape0       lib0slot0\n"
+      "drive1 lib0 /dev/tape1 lib0slot1         \n"
+  "drive2 lib0 /dev/tape2 lib0slot2");
+  tpc = cta::tape::daemon::Tpconfig::parseFile(tf.path());
+  ASSERT_EQ(3, tpc.size());
+  int i=0;
+  for(auto & t: tpc) {
+    ASSERT_EQ("drive", t.unitName.substr(0,5));
+    ASSERT_EQ("lib0", t.logicalLibrary);
+    ASSERT_EQ("/dev/tape", t.devFilename.substr(0,9));
+    ASSERT_EQ("lib0slot", t.librarySlot.substr(0,8));
+    ASSERT_EQ('0'+i, t.unitName.back());
+    ASSERT_EQ('0'+i, t.devFilename.back());
+    ASSERT_EQ('0'+i, t.librarySlot.back());
+    i++;
+  }
+}
+
+} // namespace unitTests