From abe3ac474e56866eacb80d920bd3fb3b50f2942c Mon Sep 17 00:00:00 2001
From: Michael Davis <michael.davis@cern.ch>
Date: Thu, 17 Aug 2017 11:36:18 +0200
Subject: [PATCH] [cta_admin] Parses cta_admin admin command

---
 cmdline/CtaAdminCmd.cpp     | 412 +++++++++++++++++-------------------
 cmdline/CtaAdminCmd.hpp     | 182 ++++++++--------
 cmdline/CtaAdminCmdMain.cpp |   4 +-
 3 files changed, 286 insertions(+), 312 deletions(-)

diff --git a/cmdline/CtaAdminCmd.cpp b/cmdline/CtaAdminCmd.cpp
index 05af4d27d1..84ba742361 100644
--- a/cmdline/CtaAdminCmd.cpp
+++ b/cmdline/CtaAdminCmd.cpp
@@ -42,7 +42,9 @@
 #endif
 
 #include <iostream> // for debug output
-#include <sstream>
+
+#include "common/optional.hpp"
+using cta::optional;
 
 #include "CtaAdminCmd.hpp"
 
@@ -50,22 +52,29 @@
 
 CtaAdminCmd::CtaAdminCmd(int argc, const char *const *const argv)
 {
-   // Check we have at least one parameter
+   // Tokenize the command
 
-   if(argc < 2) throw std::runtime_error(getGenericHelp(argv[0]));
+   std::string filename(argv[0]);
 
-   // Tokenize the command
+   size_t p = filename.find_last_of('/');
+   if(p != std::string::npos) filename.erase(0, p+1);
+
+   m_requestTokens.push_back(filename);
 
-   for(int i = 0; i < argc; ++i)
+   for(int i = 1; i < argc; ++i)
    {
       m_requestTokens.push_back(argv[i]);
    }
 
+   // Check we have at least one parameter
+
+   if(argc < 2) throwUsage();
+
    // Parse the command
 
    std::string &command = m_requestTokens.at(1);
   
-   if     ("ad"   == command || "admin"                  == command) xCom_notimpl(); //{authorizeAdmin(); return xCom_admin();}
+   if     ("ad"   == command || "admin"                  == command) xCom_admin();
    else if("ah"   == command || "adminhost"              == command) xCom_notimpl(); //{authorizeAdmin(); return xCom_adminhost();}
    else if("tp"   == command || "tapepool"               == command) xCom_notimpl(); //{authorizeAdmin(); return xCom_tapepool();}
    else if("ar"   == command || "archiveroute"           == command) xCom_notimpl(); //{authorizeAdmin(); return xCom_archiveroute();}
@@ -93,82 +102,200 @@ CtaAdminCmd::CtaAdminCmd(int argc, const char *const *const argv)
    else if("ufsc" == command || "updatefilestorageclass" == command) xCom_notimpl(); //{return xCom_updatefilestorageclass();}
    else if("lsc"  == command || "liststorageclass"       == command) xCom_notimpl(); //{return xCom_liststorageclass();}
 
-   else {
-     throw std::runtime_error(getGenericHelp(m_requestTokens.at(0)));
+   else throwUsage();
+}
+
+
+
+void CtaAdminCmd::xCom_admin()
+{
+   m_help << "Usage: " << m_requestTokens.at(0) << " ad/admin add/ch/rm/ls:" << std::endl
+          << "\tadd --username/-u <user_name> --comment/-m <\"comment\">"   << std::endl
+          << "\tch  --username/-u <user_name> --comment/-m <\"comment\">"   << std::endl
+          << "\trm  --username/-u <user_name>"                              << std::endl
+          << "\tls  [--header/-h]"                                          << std::endl;
+
+   if(m_requestTokens.size() < 3) {
+      throw std::runtime_error(m_help.str());
+   }
+
+   if("add" == m_requestTokens.at(2) || "ch" == m_requestTokens.at(2) || "rm" == m_requestTokens.at(2))
+   {
+      optional<std::string> username = getOptionValue<std::string>("-u", "--username", true, false);
+
+      if("add" == m_requestTokens.at(2) || "ch" == m_requestTokens.at(2))
+      {
+         optional<std::string> comment = getOptionValue<std::string>("-m", "--comment", true, false);
+         checkOptions();
+      }
+#if 0
+         if("add" == m_requestTokens.at(2)) { //add
+           m_catalogue->createAdminUser(m_cliIdentity, username.value(), comment.value());
+         }
+         else { //ch
+           m_catalogue->modifyAdminUserComment(m_cliIdentity, username.value(), comment.value());
+         }
+      }
+      else // rm
+      {
+         checkOptions(help.str());
+         m_catalogue->deleteAdminUser(username.value());
+      }
+#endif
+   }
+   else if("ls" == m_requestTokens.at(2))
+   {
+      bool is_option_header = hasOption("-h", "--header");
+      if(is_option_header) {}
+#if 0
+      std::list<cta::common::dataStructures::AdminUser> list= m_catalogue->getAdminUsers();
+      if(list.size()>0)
+      {
+        std::vector<std::vector<std::string>> responseTable;
+        std::vector<std::string> header = {"user","c.user","c.host","c.time","m.user","m.host","m.time","comment"};
+        if(hasOption("-h", "--header")) responseTable.push_back(header);    
+        for(auto it = list.cbegin(); it != list.cend(); it++) {
+          std::vector<std::string> currentRow;
+          currentRow.push_back(it->name);
+          addLogInfoToResponseRow(currentRow, it->creationLog, it->lastModificationLog);
+          currentRow.push_back(it->comment);
+          responseTable.push_back(currentRow);
+        }
+        cmdlineOutput << formatResponse(responseTable, hasOption("-h", "--header"));
+      }
+#endif
+   }
+   else
+   {
+      throw std::runtime_error(m_help.str());
    }
 }
 
 
 
-std::string CtaAdminCmd::getGenericHelp(const std::string &programName) const
+void CtaAdminCmd::throwUsage()
 {
-   std::stringstream help;
-
-   help << "CTA ADMIN commands:"                                                 << std::endl
-                                                                                 << std::endl
-        << "For each command there is a short version and a long one. "
-        << "Subcommands (add/rm/ls/ch/reclaim) do not have short versions."      << std::endl
-                                                                                 << std::endl;
-
-   help << programName << " admin/ad                 add/ch/rm/ls"               << std::endl
-        << programName << " adminhost/ah             add/ch/rm/ls"               << std::endl
-        << programName << " archivefile/af           ls"                         << std::endl
-        << programName << " archiveroute/ar          add/ch/rm/ls"               << std::endl
-        << programName << " drive/dr                 up/down/ls"                 << std::endl
-        << programName << " groupmountrule/gmr       add/rm/ls/err"              << std::endl
-        << programName << " listpendingarchives/lpa"                             << std::endl
-        << programName << " listpendingretrieves/lpr"                            << std::endl
-        << programName << " logicallibrary/ll        add/ch/rm/ls"               << std::endl
-        << programName << " mountpolicy/mp           add/ch/rm/ls"               << std::endl
-        << programName << " repack/re                add/rm/ls/err"              << std::endl
-        << programName << " requestermountrule/rmr   add/rm/ls/err"              << std::endl
-        << programName << " shrink/sh"                                           << std::endl
-        << programName << " storageclass/sc          add/ch/rm/ls"               << std::endl
-        << programName << " tape/ta                  add/ch/rm/reclaim/ls/label" << std::endl
-        << programName << " tapepool/tp              add/ch/rm/ls"               << std::endl
-        << programName << " test/te                  read/write"                 << std::endl
-        << programName << " verify/ve                add/rm/ls/err"              << std::endl
-                                                                                 << std::endl;
-
-   help << "CTA EOS commands: [NOT IMPLEMENTED]"                                 << std::endl
-                                                                                 << std::endl
-        << "For each command there is a short version and a long one."           << std::endl
-                                                                                 << std::endl
-        << programName << " archive/a"                                           << std::endl
-        << programName << " cancelretrieve/cr"                                   << std::endl
-        << programName << " deletearchive/da"                                    << std::endl
-        << programName << " liststorageclass/lsc"                                << std::endl
-        << programName << " retrieve/r"                                          << std::endl
-        << programName << " updatefileinfo/ufi"                                  << std::endl
-        << programName << " updatefilestorageclass/ufsc"                         << std::endl
-                                                                                 << std::endl
-        << "Special option for running " << programName
-        << " within the EOS workflow engine:"                                    << std::endl
-                                                                                 << std::endl
-        << programName << " ... --stderr" << std::endl
-                                                                                 << std::endl
-        << "The option tells " << programName
-        << " to write results to both standard out and standard error."          << std::endl
-        << "The option must be specified as the very last command-line argument of "
-        << programName << "."                                                    << std::endl;
-
-   return help.str();
+   std::string &programName = m_requestTokens.at(0);
+
+   m_help << "CTA ADMIN commands:"                                                 << std::endl
+                                                                                   << std::endl
+          << "For each command there is a short version and a long one. "
+          << "Subcommands (add/rm/ls/ch/reclaim) do not have short versions."      << std::endl
+                                                                                   << std::endl;
+
+   m_help << programName << " admin/ad                 add/ch/rm/ls"               << std::endl
+          << programName << " adminhost/ah             add/ch/rm/ls"               << std::endl
+          << programName << " archivefile/af           ls"                         << std::endl
+          << programName << " archiveroute/ar          add/ch/rm/ls"               << std::endl
+          << programName << " drive/dr                 up/down/ls"                 << std::endl
+          << programName << " groupmountrule/gmr       add/rm/ls/err"              << std::endl
+          << programName << " listpendingarchives/lpa"                             << std::endl
+          << programName << " listpendingretrieves/lpr"                            << std::endl
+          << programName << " logicallibrary/ll        add/ch/rm/ls"               << std::endl
+          << programName << " mountpolicy/mp           add/ch/rm/ls"               << std::endl
+          << programName << " repack/re                add/rm/ls/err"              << std::endl
+          << programName << " requestermountrule/rmr   add/rm/ls/err"              << std::endl
+          << programName << " shrink/sh"                                           << std::endl
+          << programName << " storageclass/sc          add/ch/rm/ls"               << std::endl
+          << programName << " tape/ta                  add/ch/rm/reclaim/ls/label" << std::endl
+          << programName << " tapepool/tp              add/ch/rm/ls"               << std::endl
+          << programName << " test/te                  read/write"                 << std::endl
+          << programName << " verify/ve                add/rm/ls/err"              << std::endl
+                                                                                   << std::endl;
+
+   m_help << "CTA EOS commands: [NOT IMPLEMENTED]"                                 << std::endl
+                                                                                   << std::endl
+          << "For each command there is a short version and a long one."           << std::endl
+                                                                                   << std::endl
+          << programName << " archive/a"                                           << std::endl
+          << programName << " cancelretrieve/cr"                                   << std::endl
+          << programName << " deletearchive/da"                                    << std::endl
+          << programName << " liststorageclass/lsc"                                << std::endl
+          << programName << " retrieve/r"                                          << std::endl
+          << programName << " updatefileinfo/ufi"                                  << std::endl
+          << programName << " updatefilestorageclass/ufsc"                         << std::endl
+                                                                                   << std::endl
+          << "Special option for running " << programName
+          << " within the EOS workflow engine:"                                    << std::endl
+                                                                                   << std::endl
+          << programName << " ... --stderr" << std::endl
+                                                                                   << std::endl
+          << "The option tells " << programName
+          << " to write results to both standard out and standard error."          << std::endl
+          << "The option must be specified as the very last command-line argument of "
+          << programName << "."                                                    << std::endl;
+
+   throw std::runtime_error(m_help.str());
 }
 
 
 
-#if 0
-/*!
- * checkOptions
- */
-void CtaAdminCmd::checkOptions(const std::string &helpString) {
-  if(!m_missingRequiredOptions.empty()||(!m_missingOptionalOptions.empty() && m_optionalOptions.empty())) {
-    throw cta::exception::UserError(helpString);
-  }
+template<typename T>
+optional<T> CtaAdminCmd::getOptionValue(const std::string& optionShortName, const std::string& optionLongName,
+   const bool required, const bool useDefaultIfMissing, const std::string& defaultValue)
+{
+   std::string option = getOption(optionShortName, optionLongName);
+   if(option.empty() && useDefaultIfMissing) {
+      option = defaultValue;
+   }
+   if(option.empty()) {
+      if(required) {
+         m_missingRequiredOptions.push_back(optionLongName);
+      }
+      else {
+         m_missingOptionalOptions.push_back(optionLongName);
+      }
+      return optional<T>();
+   }
+   if(!required) {
+      m_optionalOptions.push_back(optionLongName);
+   }
+   return optional<T>(option);
+}
+
+
+
+std::string CtaAdminCmd::getOption(const std::string& optionShortName, const std::string& optionLongName)
+{
+   for(auto it = m_requestTokens.cbegin(); it != m_requestTokens.cend(); it++)
+   {
+      if(optionShortName == *it || optionLongName == *it)
+      {
+         auto it_next = it + 1;
+         if(it_next != m_requestTokens.cend())
+         {
+            std::string value = *it_next;
+            return value;
+         }
+         break;
+      }
+   }
+   return "";
 }
 
 
 
+bool CtaAdminCmd::hasOption(const std::string& optionShortName, const std::string& optionLongName) {
+   for(auto it=m_requestTokens.cbegin(); it!=m_requestTokens.cend(); it++) {
+      if(optionShortName == *it || optionLongName == *it) {
+        return true;
+      }
+   }
+   return false;
+}
+
+
+
+void CtaAdminCmd::checkOptions()
+{
+   if(!m_missingRequiredOptions.empty() || (!m_missingOptionalOptions.empty() && m_optionalOptions.empty())) {
+      throw std::runtime_error(m_help.str());
+   }
+}
+
+
+
+#if 0
 /*!
  * logRequestAndSetCmdlineResult
  */
@@ -328,60 +455,6 @@ void CtaAdminCmd::replaceAll(std::string& str, const std::string& from, const st
 
 
 
-/*!
- * getOption
- */
-std::string CtaAdminCmd::getOption(const std::string& optionShortName, const std::string& optionLongName) {
-  bool encoded = false;
-  for(auto it=m_requestTokens.cbegin(); it!=m_requestTokens.cend(); it++) {
-    if(optionShortName == *it || optionLongName == *it || optionLongName+":base64" == *it) {
-      if(optionLongName+":base64" == *it) {
-        encoded = true;
-      }
-      auto it_next=it+1;
-      if(it_next!=m_requestTokens.cend()) {
-        std::string value = *it_next;
-        if(!encoded) return value;
-        else return decode(value.erase(0,7)); //erasing the first 7 characters "base64:" and decoding the rest
-      }
-      else {
-        return "";
-      }
-    }
-  }
-  return "";
-}
-
-
-
-/*!
- * getOptionStringValue
- */
-optional<std::string> CtaAdminCmd::getOptionStringValue(const std::string& optionShortName, 
-        const std::string& optionLongName,
-        const bool required, 
-        const bool useDefaultIfMissing, 
-        const std::string& defaultValue) {
-  std::string option = getOption(optionShortName, optionLongName);
-  if(option.empty()&&useDefaultIfMissing) {
-    option = defaultValue;
-  }
-  if(option.empty()) {
-    if(required) {
-      m_missingRequiredOptions.push_back(optionLongName);
-    }
-    else {
-      m_missingOptionalOptions.push_back(optionLongName);
-    }
-    return optional<std::string>();
-  }
-  if(!required) {
-    m_optionalOptions.push_back(optionLongName);
-  }
-  return optional<std::string>(option);
-}
-
-
 
 /*!
  * getOptionUint64Value
@@ -470,18 +543,6 @@ optional<time_t> CtaAdminCmd::getOptionTimeValue(const std::string& optionShortN
 
 
 
-/*!
- * hasOption
- */
-bool CtaAdminCmd::hasOption(const std::string& optionShortName, const std::string& optionLongName) {
-  for(auto it=m_requestTokens.cbegin(); it!=m_requestTokens.cend(); it++) {
-    if(optionShortName == *it || optionLongName == *it) {
-      return true;
-    }
-  }
-  return false;
-}
-
 
 
 /*!
@@ -623,68 +684,11 @@ optional<std::string> CtaAdminCmd::EOS2CTAChecksumValue(const optional<std::stri
 
 
 
-/*!
- * xCom_admin
- */
-std::string CtaAdminCmd::xCom_admin() {
-  std::stringstream cmdlineOutput;
-  std::stringstream help;
-  help << m_requestTokens.at(0) << " ad/admin add/ch/rm/ls:" << std::endl
-       << "\tadd --username/-u <user_name> --comment/-m <\"comment\">" << std::endl
-       << "\tch  --username/-u <user_name> --comment/-m <\"comment\">" << std::endl
-       << "\trm  --username/-u <user_name>" << std::endl
-       << "\tls  [--header/-h]" << std::endl;
-  if(m_requestTokens.size() < 3) {
-    throw cta::exception::UserError(help.str());
-  }
-  if("add" == m_requestTokens.at(2) || "ch" == m_requestTokens.at(2) || "rm" == m_requestTokens.at(2)) {
-    optional<std::string> username = getOptionStringValue("-u", "--username", true, false);
-    if("add" == m_requestTokens.at(2) || "ch" == m_requestTokens.at(2)) {
-      optional<std::string> comment = getOptionStringValue("-m", "--comment", true, false);
-      if("add" == m_requestTokens.at(2)) { //add
-        checkOptions(help.str());
-        m_catalogue->createAdminUser(m_cliIdentity, username.value(), comment.value());
-      }
-      else { //ch
-        checkOptions(help.str());
-        m_catalogue->modifyAdminUserComment(m_cliIdentity, username.value(), comment.value());
-      }
-    }
-    else { //rm
-      checkOptions(help.str());
-      m_catalogue->deleteAdminUser(username.value());
-    }
-  }
-  else if("ls" == m_requestTokens.at(2)) { //ls
-    std::list<cta::common::dataStructures::AdminUser> list= m_catalogue->getAdminUsers();
-    if(list.size()>0) {
-      std::vector<std::vector<std::string>> responseTable;
-      std::vector<std::string> header = {"user","c.user","c.host","c.time","m.user","m.host","m.time","comment"};
-      if(hasOption("-h", "--header")) responseTable.push_back(header);    
-      for(auto it = list.cbegin(); it != list.cend(); it++) {
-        std::vector<std::string> currentRow;
-        currentRow.push_back(it->name);
-        addLogInfoToResponseRow(currentRow, it->creationLog, it->lastModificationLog);
-        currentRow.push_back(it->comment);
-        responseTable.push_back(currentRow);
-      }
-      cmdlineOutput << formatResponse(responseTable, hasOption("-h", "--header"));
-    }
-  }
-  else {
-    throw cta::exception::UserError(help.str());
-  }
-  return cmdlineOutput.str();
-}
-
-
-
 /*!
  * xCom_adminhost
  */
 std::string CtaAdminCmd::xCom_adminhost() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " ah/adminhost add/ch/rm/ls:" << std::endl
        << "\tadd --name/-n <host_name> --comment/-m <\"comment\">" << std::endl
        << "\tch  --name/-n <host_name> --comment/-m <\"comment\">" << std::endl
@@ -740,7 +744,6 @@ std::string CtaAdminCmd::xCom_adminhost() {
  */
 std::string CtaAdminCmd::xCom_tapepool() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " tp/tapepool add/ch/rm/ls:" << std::endl
        << "\tadd --name/-n <tapepool_name> --partialtapesnumber/-p <number_of_partial_tapes> --encrypted/-e <\"true\" or \"false\"> --comment/-m <\"comment\">" << std::endl
        << "\tch  --name/-n <tapepool_name> [--partialtapesnumber/-p <number_of_partial_tapes>] [--encrypted/-e <\"true\" or \"false\">] [--comment/-m <\"comment\">]" << std::endl
@@ -809,7 +812,6 @@ std::string CtaAdminCmd::xCom_tapepool() {
  */
 std::string CtaAdminCmd::xCom_archiveroute() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " ar/archiveroute add/ch/rm/ls:" << std::endl
        << "\tadd --instance/-i <instance_name> --storageclass/-s <storage_class_name> --copynb/-c <copy_number> --tapepool/-t <tapepool_name> --comment/-m <\"comment\">" << std::endl
        << "\tch  --instance/-i <instance_name> --storageclass/-s <storage_class_name> --copynb/-c <copy_number> [--tapepool/-t <tapepool_name>] [--comment/-m <\"comment\">]" << std::endl
@@ -876,7 +878,6 @@ std::string CtaAdminCmd::xCom_archiveroute() {
  */
 std::string CtaAdminCmd::xCom_logicallibrary() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " ll/logicallibrary add/ch/rm/ls:" << std::endl
        << "\tadd --name/-n <logical_library_name> --comment/-m <\"comment\">" << std::endl
        << "\tch  --name/-n <logical_library_name> --comment/-m <\"comment\">" << std::endl
@@ -932,7 +933,6 @@ std::string CtaAdminCmd::xCom_logicallibrary() {
  */
 std::string CtaAdminCmd::xCom_tape() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " ta/tape add/ch/rm/reclaim/ls/label:" << std::endl
        << "\tadd     --vid/-v <vid> --logicallibrary/-l <logical_library_name> --tapepool/-t <tapepool_name> --capacity/-c <capacity_in_bytes>" << std::endl
        << "\t        --disabled/-d <\"true\" or \"false\"> --full/-f <\"true\" or \"false\"> [--comment/-m <\"comment\">] " << std::endl
@@ -1085,7 +1085,6 @@ std::string CtaAdminCmd::xCom_tape() {
  */
 std::string CtaAdminCmd::xCom_storageclass() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " sc/storageclass add/ch/rm/ls:" << std::endl
        << "\tadd --instance/-i <instance_name> --name/-n <storage_class_name> --copynb/-c <number_of_tape_copies> --comment/-m <\"comment\">" << std::endl
        << "\tch  --instance/-i <instance_name> --name/-n <storage_class_name> [--copynb/-c <number_of_tape_copies>] [--comment/-m <\"comment\">]" << std::endl
@@ -1155,7 +1154,6 @@ std::string CtaAdminCmd::xCom_storageclass() {
  */
 std::string CtaAdminCmd::xCom_requestermountrule() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " rmr/requestermountrule add/ch/rm/ls:" << std::endl
        << "\tadd --instance/-i <instance_name> --name/-n <user_name> --mountpolicy/-u <policy_name> --comment/-m <\"comment\">" << std::endl
        << "\tch  --instance/-i <instance_name> --name/-n <user_name> [--mountpolicy/-u <policy_name>] [--comment/-m <\"comment\">]" << std::endl
@@ -1221,7 +1219,6 @@ std::string CtaAdminCmd::xCom_requestermountrule() {
  */
 std::string CtaAdminCmd::xCom_groupmountrule() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " gmr/groupmountrule add/ch/rm/ls:" << std::endl
        << "\tadd --instance/-i <instance_name> --name/-n <user_name> --mountpolicy/-u <policy_name> --comment/-m <\"comment\">" << std::endl
        << "\tch  --instance/-i <instance_name> --name/-n <user_name> [--mountpolicy/-u <policy_name>] [--comment/-m <\"comment\">]" << std::endl
@@ -1287,7 +1284,6 @@ std::string CtaAdminCmd::xCom_groupmountrule() {
  */
 std::string CtaAdminCmd::xCom_mountpolicy() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " mp/mountpolicy add/ch/rm/ls:" << std::endl
        << "\tadd --name/-n <mountpolicy_name> --archivepriority/--ap <priority_value> --minarchiverequestage/--aa <minRequestAge> --retrievepriority/--rp <priority_value>" << std::endl
        << "\t    --minretrieverequestage/--ra <minRequestAge> --maxdrivesallowed/-d <maxDrivesAllowed> --comment/-m <\"comment\">" << std::endl
@@ -1377,7 +1373,6 @@ std::string CtaAdminCmd::xCom_mountpolicy() {
  */
 std::string CtaAdminCmd::xCom_repack() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " re/repack add/rm/ls/err:" << std::endl
        << "\tadd --vid/-v <vid> [--justexpand/-e or --justrepack/-r] [--tag/-t <tag_name>]" << std::endl
        << "\trm  --vid/-v <vid>" << std::endl
@@ -1486,7 +1481,6 @@ std::string CtaAdminCmd::xCom_repack() {
  */
 std::string CtaAdminCmd::xCom_shrink() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " sh/shrink --tapepool/-t <tapepool_name>" << std::endl;
   optional<std::string> tapepool = getOptionStringValue("-t", "--tapepool", true, false);
   checkOptions(help.str());
@@ -1501,7 +1495,6 @@ std::string CtaAdminCmd::xCom_shrink() {
  */
 std::string CtaAdminCmd::xCom_verify() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " ve/verify add/rm/ls/err:" << std::endl
        << "\tadd --vid/-v <vid> [--nbfiles <number_of_files_per_tape>] [--tag/-t <tag_name>]" << std::endl
        << "\trm  --vid/-v <vid>" << std::endl
@@ -1583,7 +1576,6 @@ std::string CtaAdminCmd::xCom_verify() {
  */
 std::string CtaAdminCmd::xCom_archivefile() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " af/archivefile ls [--header/-h] [--id/-I <archive_file_id>] [--diskid/-d <disk_id>] [--copynb/-c <copy_no>] [--vid/-v <vid>] [--tapepool/-t <tapepool>] "
           "[--owner/-o <owner>] [--group/-g <group>] [--storageclass/-s <class>] [--path/-p <fullpath>] [--instance/-i <instance>] [--summary/-S] [--all/-a] (default gives error)" << std::endl;  
   if(m_requestTokens.size() < 3) {
@@ -1666,7 +1658,6 @@ std::string CtaAdminCmd::xCom_archivefile() {
  */
 std::string CtaAdminCmd::xCom_test() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " te/test read/write/write_auto (to be run on an empty self-dedicated drive; it is a synchronous command that returns performance stats and errors; all locations are local to the tapeserver):" << std::endl
        << "\tread  --drive/-d <drive_name> --vid/-v <vid> --firstfseq/-f <first_fseq> --lastfseq/-l <last_fseq> --checkchecksum/-c --output/-o <\"null\" or output_dir> [--tag/-t <tag_name>]" << std::endl
        << "\twrite --drive/-d <drive_name> --vid/-v <vid> --file/-f <filename> [--tag/-t <tag_name>]" << std::endl
@@ -1767,7 +1758,6 @@ std::string CtaAdminCmd::xCom_test() {
 std::string CtaAdminCmd::xCom_drive() {
   log::LogContext lc(m_log);
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " dr/drive up/down/ls (it is a synchronous command):"    << std::endl
        << "Set the requested state of the drive. The drive will complete any running mount" << std::endl
        << "unless it is preempted with the --force option."                                 << std::endl
@@ -1908,7 +1898,6 @@ std::string CtaAdminCmd::xCom_drive() {
  */
 std::string CtaAdminCmd::xCom_listpendingarchives() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " lpa/listpendingarchives [--header/-h] [--tapepool/-t <tapepool_name>] [--extended/-x]" << std::endl;
   optional<std::string> tapepool = getOptionStringValue("-t", "--tapepool", false, false);
   bool extended = hasOption("-x", "--extended");
@@ -1975,7 +1964,6 @@ std::string CtaAdminCmd::xCom_listpendingarchives() {
  */
 std::string CtaAdminCmd::xCom_listpendingretrieves() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " lpr/listpendingretrieves [--header/-h] [--vid/-v <vid>] [--extended/-x]" << std::endl;
   optional<std::string> vid = getOptionStringValue("-v", "--vid", false, false);
   bool extended = hasOption("-x", "--extended");
@@ -2041,7 +2029,6 @@ std::string CtaAdminCmd::xCom_listpendingretrieves() {
  */
 std::string CtaAdminCmd::xCom_showqueues() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " sq/showqueues [--header/-h]" << std::endl;
   log::LogContext lc(m_log);
   auto queuesAndMounts=m_scheduler->getQueuesAndMountSummaries(lc);
@@ -2099,7 +2086,6 @@ std::string CtaAdminCmd::xCom_showqueues() {
  */
 std::string CtaAdminCmd::xCom_archive() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " a/archive --user <user> --group <group> --diskid <disk_id> --srcurl <src_URL> --size <size> --checksumtype <checksum_type>" << std::endl
        << "\t--checksumvalue <checksum_value> --storageclass <storage_class> --diskfilepath <disk_filepath> --diskfileowner <disk_fileowner>" << std::endl
        << "\t--diskfilegroup <disk_filegroup> --recoveryblob <recovery_blob> --reportURL <reportURL>" << std::endl
@@ -2152,7 +2138,6 @@ std::string CtaAdminCmd::xCom_archive() {
  */
 std::string CtaAdminCmd::xCom_retrieve() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " r/retrieve --user <user> --group <group> --id <CTA_ArchiveFileID> --dsturl <dst_URL> --diskfilepath <disk_filepath>" << std::endl
        << "\t--diskfileowner <disk_fileowner> --diskfilegroup <disk_filegroup> --recoveryblob <recovery_blob>" << std::endl
        << "\tNote: apply the postfix \":base64\" to long option names whose values are base64 encoded" << std::endl;
@@ -2192,7 +2177,6 @@ std::string CtaAdminCmd::xCom_retrieve() {
  * xCom_deletearchive
  */
 std::string CtaAdminCmd::xCom_deletearchive() {
-  std::stringstream help;
   help << m_requestTokens.at(0) << " da/deletearchive --user <user> --group <group> --id <CTA_ArchiveFileID>" << std::endl
        << "\tNote: apply the postfix \":base64\" to long option names whose values are base64 encoded" << std::endl;
   optional<std::string> user = getOptionStringValue("", "--user", true, false);
@@ -2220,7 +2204,6 @@ std::string CtaAdminCmd::xCom_deletearchive() {
  */
 std::string CtaAdminCmd::xCom_cancelretrieve() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " cr/cancelretrieve --user <user> --group <group> --id <CTA_ArchiveFileID> --dsturl <dst_URL> --diskfilepath <disk_filepath>" << std::endl
        << "\t--diskfileowner <disk_fileowner> --diskfilegroup <disk_filegroup> --recoveryblob <recovery_blob>" << std::endl
        << "\tNote: apply the postfix \":base64\" to long option names whose values are base64 encoded" << std::endl;
@@ -2257,7 +2240,6 @@ std::string CtaAdminCmd::xCom_cancelretrieve() {
  */
 std::string CtaAdminCmd::xCom_updatefilestorageclass() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " ufsc/updatefilestorageclass --user <user> --group <group> --id <CTA_ArchiveFileID> --storageclass <storage_class> --diskfilepath <disk_filepath>" << std::endl
        << "\t--diskfileowner <disk_fileowner> --diskfilegroup <disk_filegroup> --recoveryblob <recovery_blob>" << std::endl
        << "\tNote: apply the postfix \":base64\" to long option names whose values are base64 encoded" << std::endl;
@@ -2294,7 +2276,6 @@ std::string CtaAdminCmd::xCom_updatefilestorageclass() {
  */
 std::string CtaAdminCmd::xCom_updatefileinfo() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " ufi/updatefileinfo --id <CTA_ArchiveFileID> --diskfilepath <disk_filepath>" << std::endl
        << "\t--diskfileowner <disk_fileowner> --diskfilegroup <disk_filegroup> --recoveryblob <recovery_blob>" << std::endl
        << "\tNote: apply the postfix \":base64\" to long option names whose values are base64 encoded" << std::endl;
@@ -2323,7 +2304,6 @@ std::string CtaAdminCmd::xCom_updatefileinfo() {
  */
 std::string CtaAdminCmd::xCom_liststorageclass() {
   std::stringstream cmdlineOutput;
-  std::stringstream help;
   help << m_requestTokens.at(0) << " lsc/liststorageclass --user <user> --group <group>" << std::endl
        << "\tNote: apply the postfix \":base64\" to long option names whose values are base64 encoded" << std::endl;
   optional<std::string> user = getOptionStringValue("", "--user", true, false);
@@ -2338,4 +2318,4 @@ std::string CtaAdminCmd::xCom_liststorageclass() {
   return cmdlineOutput.str();
 }
 #endif
-  
+
diff --git a/cmdline/CtaAdminCmd.hpp b/cmdline/CtaAdminCmd.hpp
index 37d692897e..f86d0504c8 100644
--- a/cmdline/CtaAdminCmd.hpp
+++ b/cmdline/CtaAdminCmd.hpp
@@ -22,8 +22,12 @@
 
 #include <stdexcept>
 #include <string>
+#include <sstream>
 #include <vector>
 
+#include "common/optional.hpp"
+using cta::optional;
+
 
 
 class CtaAdminCmd
@@ -33,14 +37,10 @@ public:
 
 private:
    /*!
-    * Returns the help string
-    * 
-    * @param      programName    The name of the client program
-    *
-    * @returns    the help string
+    * Throw an exception with generic usage help
     */
-   std::string getGenericHelp(const std::string &programName) const;
-  
+   void throwUsage();
+
    /*!
     * Placeholder for admin commands which have not been implemented yet
     */
@@ -48,8 +48,65 @@ private:
       throw std::runtime_error("Command not implemented.");
    }
 
+   /*!
+    * cta admin command
+    */
+   void xCom_admin();
+
+   /*!
+    * Return the value of the specified option
+    * 
+    * @param optionShortName      The short name of the required option
+    * @param optionLongName       The long name of the required option
+    * @param required             True if the option is required, false otherwise
+    * @param useDefaultIfMissing  True if the default value (next parameter) is to be used if option
+    *                             is missing from cmdline, false otherwise
+    * @param default              Value of the default in case option is missing from cmdline (and
+    *                             useDefaultIfMissing is true)
+    *
+    * @return the option value (empty if absent)
+    */
+   template<typename T>
+   optional<T> getOptionValue(const std::string& optionShortName, const std::string& optionLongName,
+      const bool required, const bool useDefaultIfMissing, const std::string& defaultValue="-");
+
+   /*!
+    * Return the string value of the specified option
+    * 
+    * @param optionShortName The short name of the required option
+    * @param optionLongName  The long name of the required option
+    * @return the option value (empty if absent)
+    */
+   std::string getOption(const std::string& optionShortName, const std::string& optionLongName);
+
+   /*!
+    * Given the command line string vector it returns true if the specified option is present, false otherwise
+    * 
+    * @param optionShortName The short name of the required option
+    * @param optionLongName  The long name of the required option
+    * @return true if the specified option is present, false otherwise
+    */
+   bool hasOption(const std::string& optionShortName, const std::string& optionLongName);
+
+   /*!
+    * Checks if all needed options are present. Throws an exception otherwise.
+    */
+   void checkOptions();
+
+   //! Help string
+   std::stringstream m_help;
+
    //! The command line parameters represented as a vector of strings
    std::vector<std::string> m_requestTokens;
+
+   //! Vector containing optional options which are present in the user command
+   std::vector<std::string> m_optionalOptions;
+
+   //! Vector containing required options which are missing from the user command
+   std::vector<std::string> m_missingRequiredOptions;
+
+   //! Vector containing optional options which are missing from the user command
+   std::vector<std::string> m_missingOptionalOptions;
 };
 
 #if 0
@@ -74,9 +131,9 @@ namespace cta { namespace xrootPlugins {
  * documentation can be found in XrdSfs/XrdSfsInterface.hh.
  */
 class XrdCtaFile : public XrdSfsFile {
-  
+
 public:
-  
+
   virtual int open(const char *fileName, XrdSfsFileOpenMode openMode, mode_t createMode, const XrdSecEntity *client = 0, const char *opaque = 0);
   virtual int close();
   virtual int fctl(const int cmd, const char *args, XrdOucErrInfo &eInfo);
@@ -94,59 +151,44 @@ public:
   virtual int getCXinfo(char cxtype[4], int &cxrsz);
   XrdCtaFile(cta::catalogue::Catalogue *catalogue, cta::Scheduler *scheduler, cta::log::Logger *log, const char *user=0, int MonID=0);
   ~XrdCtaFile();
-  
+
 protected:
 
   /**
    * The catalogue object pointer.
    */
   cta::catalogue::Catalogue *m_catalogue;
-  
+
   /**
    * The scheduler object pointer
    */
   cta::Scheduler *m_scheduler;
-  
+
   /**
    * The scheduler object pointer
    */
   cta::log::Logger &m_log;
-  
+
   /**
    * This is the string holding the result of the command
    */
   std::string m_cmdlineOutput;
-  
+
   /**
    * The client identity info: username and host
    */
   cta::common::dataStructures::SecurityIdentity m_cliIdentity;  
-  
+
   /**
    * The protocol used by the xroot client
    */
   std::string m_protocol;  
-  
-  /**
-   * Vector containing required options which are missing from the user command
-   */
-  std::vector<std::string> m_missingRequiredOptions;
-  
-  /**
-   * Vector containing optional options which are missing from the user command
-   */
-  std::vector<std::string> m_missingOptionalOptions;
-  
-  /**
-   * Vector containing optional options which are present in the user command
-   */
-  std::vector<std::string> m_optionalOptions;
-  
+
   /**
    * Flag used to suppress missing optional options. Set to false by default (used only in file and tape listings)
    */
   bool m_suppressOptionalOptionsWarning;
-  
+
   /**
    * Points to a ListArchiveFilesCmd object if the current command is to list archive files.
    */
@@ -169,14 +211,14 @@ protected:
    * @return decoded string
    */
   std::string decode(const std::string msg) const;
-  
+
   /**
    * Checks whether client has correct permissions and fills the corresponding SecurityIdentity structure
    * 
    * @param client  The client security entity
    */
   void checkClient(const XrdSecEntity *client);
-  
+
   /**
    * Replaces all occurrences in a string "str" of a substring "from" with the string "to"
    * 
@@ -185,7 +227,7 @@ protected:
    * @param to   The replacement string
    */
   void replaceAll(std::string& str, const std::string& from, const std::string& to) const;
-  
+
   /**
    * Parses the command line, dispatches it to the relevant function and returns
    * the output for the command-line.
@@ -194,49 +236,6 @@ protected:
    * @return           The output for the command-line.
    */
   std::string dispatchCommand();
-  
-  /**
-   * Set of functions that, given the command line string vector, return the string/numerical/boolean/time value of the specified option
-   * 
-   * @param optionShortName      The short name of the required option
-   * @param optionLongName       The long name of the required option
-   * @param required             True if the option is required, false otherwise
-   * @param useDefaultIfMissing  True if the default value (next parameter) is to be used if option is missing from cmdline, false otherwise
-   * @param default              Value of the default in case option is missing from cmdline (and useDefaultIfMissing is true)
-   * @return the option value (empty if absent)
-   */
-  optional<std::string> getOptionStringValue(const std::string& optionShortName, const std::string& optionLongName, 
-    const bool required, const bool useDefaultIfMissing, const std::string& defaultValue="-");
-  optional<uint64_t> getOptionUint64Value(const std::string& optionShortName, const std::string& optionLongName, 
-    const bool required, const bool useDefaultIfMissing, const std::string& defaultValue="0");
-  optional<bool> getOptionBoolValue(const std::string& optionShortName, const std::string& optionLongName, 
-    const bool required, const bool useDefaultIfMissing, const std::string& defaultValue="false");
-  optional<time_t> getOptionTimeValue(const std::string& optionShortName, const std::string& optionLongName, 
-    const bool required, const bool useDefaultIfMissing, const std::string& defaultValue="01/01/1970");
-  
-  /**
-   * Returns the string/numerical/boolean value of the specified option
-   * 
-   * @param optionShortName The short name of the required option
-   * @param optionLongName  The long name of the required option
-   * @return the option value (empty if absent)
-   */
-  std::string getOption(const std::string& optionShortName, const std::string& optionLongName);
-  
-  /**
-   * Given the command line string vector it returns true if the specified option is present, false otherwise
-   * 
-   * @param optionShortName The short name of the required option
-   * @param optionLongName  The long name of the required option
-   * @return true if the specified option is present, false otherwise
-   */
-  bool hasOption(const std::string& optionShortName, const std::string& optionLongName);
-
-  /**
-   * Executes a command and returns the output for the command-line.
-   * @return The output for the command-line.
-   */
-  std::string xCom_admin();
 
   /**
    * Executes a command and returns the output for the command-line.
@@ -345,7 +344,7 @@ protected:
    * @return The output for the command-line.
    */
   std::string xCom_showqueues();
-  
+
   /**
    * Executes a command and returns the output for the command-line.
    * @return The output for the command-line.
@@ -392,7 +391,7 @@ protected:
    * Checks whether the user that issued the admin command is an authorized admin (throws an exception if it's not).
    */
   void authorizeAdmin();
-  
+
   /**
    * Returns the response string properly formatted in a table
    * 
@@ -400,7 +399,7 @@ protected:
    * @return the response string properly formatted in a table
    */
   std::string formatResponse(const std::vector<std::vector<std::string>> &responseTable, const bool withHeader);
-  
+
   /**
    * Returns a string representation of the time
    * 
@@ -408,7 +407,7 @@ protected:
    * @return a string representation of the time
    */
   std::string timeToString(const time_t &time);
-  
+
   /**
    * Returns a string representation for bytes in Mbytes with .00 precision
    *
@@ -425,7 +424,7 @@ protected:
    * @param  lastModificationLog the last modification log
    */
   void addLogInfoToResponseRow(std::vector<std::string> &responseRow, const cta::common::dataStructures::EntryLog &creationLog, const cta::common::dataStructures::EntryLog &lastModificationLog);
-  
+
   /**
    * Converts a parameter string into a uint64_t (throws a cta::exception if it fails)
    * 
@@ -434,7 +433,7 @@ protected:
    * @return the conversion result
    */
   uint64_t stringParameterToUint64(const std::string &parameterName, const std::string &parameterValue) const;
-  
+
   /**
    * Converts a parameter string into a bool (throws a cta::exception if it fails)
    * 
@@ -443,7 +442,7 @@ protected:
    * @return the conversion result
    */
   bool stringParameterToBool(const std::string &parameterName, const std::string &parameterValue) const;
-  
+
   /**
    * Converts a parameter string into a time_t (throws a cta::exception if it fails)
    * 
@@ -452,7 +451,7 @@ protected:
    * @return the conversion result
    */
   time_t stringParameterToTime(const std::string &parameterName, const std::string &parameterValue) const;
-  
+
   /**
    * Sets the return code of the cmdline client and its output.
    * Logs the original request and any error in processing it.
@@ -461,14 +460,7 @@ protected:
    * @param  returnString The output of the cmdline client
    */
   void logRequestAndSetCmdlineResult(const cta::common::dataStructures::FrontendReturnCode rc, const std::string &returnString);
-  
-  /**
-   * Checks if all needed options are present. Throws UserError otherwise.
-   * 
-   * @param  helpString The help string to be included in the exception message
-   */
-  void checkOptions(const std::string &helpString);
-  
+
   /**
    * Converts the checksum type string format from EOS to CTA
    * 
@@ -476,7 +468,7 @@ protected:
    * @return the checksum type string converted to CTA format
    */
   optional<std::string> EOS2CTAChecksumType(const optional<std::string> &EOSChecksumType);
-  
+
   /**
    * Converts the checksum value string format from EOS to CTA
    * 
diff --git a/cmdline/CtaAdminCmdMain.cpp b/cmdline/CtaAdminCmdMain.cpp
index 2ae41adbad..3b72b724fa 100644
--- a/cmdline/CtaAdminCmdMain.cpp
+++ b/cmdline/CtaAdminCmdMain.cpp
@@ -147,12 +147,14 @@ int main(int argc, const char **argv)
       std::cerr << "Error in Google Protocol Buffers: " << ex.what() << std::endl;
    } catch (XrdSsiPb::XrdSsiException &ex) {
       std::cerr << "Error from XRootD SSI Framework: " << ex.what() << std::endl;
+   } catch (std::runtime_error &ex) {
+      std::cerr << ex.what() << std::endl;
    } catch (std::exception &ex) {
       std::cerr << "Caught exception: " << ex.what() << std::endl;
    } catch (...) {
       std::cerr << "Caught an unknown exception" << std::endl;
    }
 
-   return cta::common::dataStructures::FrontendReturnCode::ctaErrorNoRetry;
+   return 1;
 }
 
-- 
GitLab