Commit d80d6922 authored by Steven Murray's avatar Steven Murray
Browse files

Moved XXXXMountCmd::parseCmdLine() to MountCmdLine()

parent 4424f89c
......@@ -38,7 +38,7 @@ castor::acs::Acs::~Acs() throw() {
//------------------------------------------------------------------------------
// str2DriveId
//------------------------------------------------------------------------------
DRIVEID castor::acs::Acs::str2DriveId(const std::string &str) const {
DRIVEID castor::acs::Acs::str2DriveId(const std::string &str) {
std::vector<std::string> components;
castor::utils::splitString(str, ':', components);
......@@ -116,8 +116,7 @@ DRIVEID castor::acs::Acs::str2DriveId(const std::string &str) const {
//------------------------------------------------------------------------------
// onlyContainsNumerals
//------------------------------------------------------------------------------
bool castor::acs::Acs::onlyContainsNumerals(const std::string &str) const
throw() {
bool castor::acs::Acs::onlyContainsNumerals(const std::string &str) throw() {
for(std::string::const_iterator itor = str.begin(); itor != str.end();
itor++) {
if(*itor < '0' || *itor > '9') {
......@@ -131,8 +130,7 @@ bool castor::acs::Acs::onlyContainsNumerals(const std::string &str) const
// alpd2DriveId
//------------------------------------------------------------------------------
DRIVEID castor::acs::Acs::alpd2DriveId(const uint32_t acs,
const uint32_t lsm, const uint32_t panel, const uint32_t drive)
const throw () {
const uint32_t lsm, const uint32_t panel, const uint32_t drive) throw () {
DRIVEID driveId;
driveId.panel_id.lsm_id.acs = (ACS)acs;
......@@ -146,8 +144,7 @@ DRIVEID castor::acs::Acs::alpd2DriveId(const uint32_t acs,
//------------------------------------------------------------------------------
// str2Volid
//------------------------------------------------------------------------------
VOLID castor::acs::Acs::str2Volid(const std::string &str) const
{
VOLID castor::acs::Acs::str2Volid(const std::string &str) {
if(EXTERNAL_LABEL_SIZE < str.length()) {
castor::exception::InvalidArgument ex;
ex.getMessage() << "Failed to convert string to volume identifier"
......@@ -165,8 +162,7 @@ VOLID castor::acs::Acs::str2Volid(const std::string &str) const
//------------------------------------------------------------------------------
// driveId2Str
//------------------------------------------------------------------------------
std::string castor::acs::Acs::driveId2Str(const DRIVEID &driveId)
const throw() {
std::string castor::acs::Acs::driveId2Str(const DRIVEID &driveId) throw() {
std::ostringstream oss;
oss << std::setfill('0') <<
std::setw(3) << (int32_t)driveId.panel_id.lsm_id.acs << ":" <<
......
......@@ -56,7 +56,7 @@ public:
* @param str The string to be parsed.
* @return The drive ID object.
*/
DRIVEID str2DriveId(const std::string &str) const;
static DRIVEID str2DriveId(const std::string &str);
/**
* Converts acs, lsm, panel, drive numbers to the corresponding
......@@ -68,8 +68,8 @@ public:
* @param drive The integer for drive.
* @return The drive ID object.
*/
DRIVEID alpd2DriveId(const uint32_t acs, const uint32_t lsm,
const uint32_t panel, const uint32_t drive) const throw();
static DRIVEID alpd2DriveId(const uint32_t acs, const uint32_t lsm,
const uint32_t panel, const uint32_t drive) throw();
/**
* Returns the VOLID equibvalent of the specified string.
......@@ -80,7 +80,7 @@ public:
* @param str The string representation of the volume identifier.
* @return The VOLID representation of the volume identifier.
*/
VOLID str2Volid(const std::string &str) const;
static VOLID str2Volid(const std::string &str);
/**
* Returns the string reprsentation of the specified drive identifier.
......@@ -90,7 +90,7 @@ public:
* @param driveId The drive identifier.
* @return The string representation.
*/
std::string driveId2Str(const DRIVEID &driveId) const throw();
static std::string driveId2Str(const DRIVEID &driveId) throw();
/**
* C++ wrapper around the acs_mount() function of the ACSLS C-API.
......@@ -177,7 +177,7 @@ protected:
*
* @return True if the specified string only contains numerals else false.
*/
bool onlyContainsNumerals(const std::string &str) const throw();
static bool onlyContainsNumerals(const std::string &str) throw();
}; // class Acs
......
......@@ -21,32 +21,60 @@
* @author Castor Dev team, castor-dev@cern.ch
*****************************************************************************/
#pragma once
#include "castor/acs/AcsCmdLine.hpp"
#include "castor/exception/InvalidArgument.hpp"
#include "castor/exception/MissingOperand.hpp"
#include "castor/acs/AcsMountCmd.hpp"
#include <stdlib.h>
namespace castor {
namespace acs {
class TestingAcsMountCmd: public AcsMountCmd {
public:
/**
* Constructor.
*
* @param inStream Standard input stream.
* @param outStream Standard output stream.
* @param errStream Standard error stream.
* @param acs Wrapper around the ACSLS C-API.
*/
TestingAcsMountCmd(std::istream &inStream, std::ostream &outStream,
std::ostream &errStream, Acs &acs) throw():
AcsMountCmd(inStream, outStream, errStream, acs) {
//------------------------------------------------------------------------------
// parseQueryInterval
//------------------------------------------------------------------------------
int castor::acs::AcsCmdLine::parseQueryInterval(const std::string &s) {
const int queryInterval = atoi(s.c_str());
if(0 >= queryInterval) {
castor::exception::InvalidArgument ex;
ex.getMessage() << "Query value must be an integer greater than 0"
": value=" << queryInterval;
throw ex;
}
using AcsMountCmd::parseCmdLine;
return queryInterval;
}
}; // class TestingAcsMountCmd
//------------------------------------------------------------------------------
// parseTimeout
//------------------------------------------------------------------------------
int castor::acs::AcsCmdLine::parseTimeout(const std::string &s) {
const int timeout = atoi(s.c_str());
if(0 >= timeout) {
castor::exception::InvalidArgument ex;
ex.getMessage() << "Timeout value must be an integer greater than 0"
": value=" << timeout;
throw ex;
}
return timeout;
}
} // namespace acs
} // namespace castor
//------------------------------------------------------------------------------
// handleMissingParameter
//------------------------------------------------------------------------------
void castor::acs::AcsCmdLine::handleMissingParameter(const int option) {
castor::exception::MissingOperand ex;
ex.getMessage() << "The -" << (char)optopt
<< " option requires a parameter";
throw ex;
}
//------------------------------------------------------------------------------
// handleUnknownOption
//------------------------------------------------------------------------------
void castor::acs::AcsCmdLine::handleUnknownOption(const int option) {
castor::exception::InvalidArgument ex;
if(0 == optopt) {
ex.getMessage() << "Unknown command-line option";
} else {
ex.getMessage() << "Unknown command-line option: -" << (char)optopt;
}
throw ex;
}
......@@ -23,30 +23,46 @@
#pragma once
#include "castor/acs/AcsDismountCmd.hpp"
#include <string>
namespace castor {
namespace acs {
class TestingAcsDismountCmd: public AcsDismountCmd {
public:
/**
* Class containing the code common to the parsed command-line of the ACS
* command-line tools provided by CASTOR.
*/
struct AcsCmdLine {
/**
* Constructor.
* Parses the specified query interval.
*
* @param inStream Standard input stream.
* @param outStream Standard output stream.
* @param errStream Standard error stream.
* @param acs Wrapper around the ACSLS C-API.
* @return The parse query interval.
*/
TestingAcsDismountCmd(std::istream &inStream, std::ostream &outStream,
std::ostream &errStream, Acs &acs) throw():
AcsDismountCmd(inStream, outStream, errStream, acs) {
}
static int parseQueryInterval(const std::string &s);
using AcsDismountCmd::parseCmdLine;
/**
* Parses the specified timeout.
*
* @return The parse query interval.
*/
static int parseTimeout(const std::string &s);
/**
* Handles the specified parameter that is missing a parameter.
*
* @param option The option.
*/
static void handleMissingParameter(const int option);
/**
* Handles the specified unknown option.
*
* @param option The option.
*/
static void handleUnknownOption(const int option);
}; // class TestingAcsDismountCmd
}; // class AcsCmdLine
} // namespace acs
} // namespace castor
......@@ -49,7 +49,8 @@ castor::acs::AcsDismountCmd::~AcsDismountCmd() throw() {
int castor::acs::AcsDismountCmd::main(const int argc, char *const *const argv)
throw() {
try {
m_cmdLine = parseCmdLine(argc, argv);
m_cmdLine = AcsDismountCmdLine(argc, argv, m_defaultQueryInterval,
m_defaultTimeout);
} catch(castor::exception::InvalidArgument &ia) {
m_err << "Aborting: Invalid command-line: " << ia.getMessage().str() <<
std::endl;
......@@ -133,123 +134,6 @@ void castor::acs::AcsDismountCmd::usage(std::ostream &os) const throw() {
"Comments to: Castor.Support@cern.ch" << std::endl;
}
//------------------------------------------------------------------------------
// parseCmdLine
//------------------------------------------------------------------------------
castor::acs::AcsDismountCmdLine castor::acs::AcsDismountCmd::parseCmdLine(
const int argc, char *const *const argv) {
static struct option longopts[] = {
{"debug", 0, NULL, 'd'},
{"force", 0, NULL, 'f'},
{"help" , 0, NULL, 'h'},
{"query" , required_argument, NULL, 'q'},
{"timeout" , required_argument, NULL, 't'},
{NULL , 0, NULL, 0 }
};
AcsDismountCmdLine cmdLine;
char c;
// Set the query option to the default value
cmdLine.queryInterval = m_defaultQueryInterval;
// Set timeout option to the default value
cmdLine.timeout = m_defaultTimeout;
// Prevent getopt() from printing an error message if it does not recognize
// an option character
opterr = 0;
while((c = getopt_long(argc, argv, ":dfhq:t:", longopts, NULL)) != -1) {
switch (c) {
case 'd':
cmdLine.debug = true;
break;
case 'f':
cmdLine.force = TRUE;
break;
case 'h':
cmdLine.help = true;
break;
case 'q':
cmdLine.queryInterval = atoi(optarg);
if(0 >= cmdLine.queryInterval) {
castor::exception::InvalidArgument ex;
ex.getMessage() << "Query value must be an integer greater than 0"
": value=" << cmdLine.queryInterval;
throw ex;
}
break;
case 't':
cmdLine.timeout = atoi(optarg);
if(0 >= cmdLine.timeout) {
castor::exception::InvalidArgument ex;
ex.getMessage() << "Timeout value must be an integer greater than 0"
": value=" << cmdLine.timeout;
throw ex;
}
break;
case ':':
{
castor::exception::InvalidArgument ex;
ex.getMessage() << "The -" << (char)optopt
<< " option requires a parameter";
throw ex;
}
break;
case '?':
{
castor::exception::InvalidArgument ex;
if(optopt == 0) {
ex.getMessage() << "Unknown command-line option";
} else {
ex.getMessage() << "Unknown command-line option: -" << (char)optopt;
}
throw ex;
}
break;
default:
{
castor::exception::Exception ex;
ex.getMessage() <<
"getopt_long returned the following unknown value: 0x" <<
std::hex << (int)c;
throw ex;
}
} // switch (c)
} // while ((c = getopt_long( ... )) != -1)
// There is no need to continue parsing when the help option is set
if(cmdLine.help) {
return cmdLine;
}
// Calculate the number of non-option ARGV-elements
const int nbArgs = argc-optind;
// Check that both VID and DRIVE has been specified
if(nbArgs < 2) {
castor::exception::MissingOperand ex;
ex.getMessage() <<
"Both VID and DRIVE must be specified";
throw ex;
}
// Parse the volume identifier of the command-line argument
cmdLine.volId = m_acs.str2Volid(argv[optind]);
// Move on to the next command-line argument
optind++;
// Parse the drive-identifier command-line argument
cmdLine.driveId = m_acs.str2DriveId(argv[optind]);
return cmdLine;
}
//------------------------------------------------------------------------------
// syncDismount
//------------------------------------------------------------------------------
......
......@@ -73,15 +73,6 @@ protected:
*/
void usage(std::ostream &os) const throw();
/**
* Parses the specified command-line arguments.
*
* @param argc Argument count from the executable's entry function: main().
* @param argv Argument vector from the executable's entry function: main().
* @return The parsed command-line.
*/
AcsDismountCmdLine parseCmdLine(const int argc, char *const *const argv);
/**
* Dismounts the tape with the specified VID into the drive with the specified
* drive ID.
......
......@@ -21,8 +21,14 @@
* @author Castor Dev team, castor-dev@cern.ch
*****************************************************************************/
#include "castor/acs/Acs.hpp"
#include "castor/acs/AcsCmdLine.hpp"
#include "castor/acs/AcsDismountCmdLine.hpp"
#include "castor/exception/InvalidArgument.hpp"
#include "castor/exception/MissingOperand.hpp"
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
//-----------------------------------------------------------------------------
......@@ -40,3 +46,107 @@ castor::acs::AcsDismountCmdLine::AcsDismountCmdLine() throw():
driveId.drive = (DRIVE)0;
memset(volId.external_label, '\0', sizeof(volId.external_label));
}
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
castor::acs::AcsDismountCmdLine::AcsDismountCmdLine(const int argc,
char *const *const argv, const int defaultQueryInterval,
const int defaultTimeout):
debug(false),
force(FALSE),
help(false),
queryInterval(defaultQueryInterval),
timeout(defaultTimeout) {
driveId.panel_id.lsm_id.acs = (ACS)0;
driveId.panel_id.lsm_id.lsm = (LSM)0;
driveId.panel_id.panel = (PANEL)0;
driveId.drive = (DRIVE)0;
memset(volId.external_label, '\0', sizeof(volId.external_label));
static struct option longopts[] = {
{"debug", 0, NULL, 'd'},
{"force", 0, NULL, 'f'},
{"help" , 0, NULL, 'h'},
{"query" , required_argument, NULL, 'q'},
{"timeout" , required_argument, NULL, 't'},
{NULL , 0, NULL, 0 }
};
// Set the query option to the default value
queryInterval = defaultQueryInterval;
// Set timeout option to the default value
timeout = defaultTimeout;
// Prevent getopt() from printing an error message if it does not recognize
// an option character
opterr = 0;
int opt = 0;
while((opt = getopt_long(argc, argv, ":dfhq:t:", longopts, NULL)) != -1) {
processOption(opt);
}
// There is no need to continue parsing when the help option is set
if(help) {
return;
}
// Calculate the number of non-option ARGV-elements
const int nbArgs = argc-optind;
// Check that both VID and DRIVE has been specified
if(nbArgs < 2) {
castor::exception::MissingOperand ex;
ex.getMessage() <<
"Both VID and DRIVE must be specified";
throw ex;
}
// Parse the volume identifier of the command-line argument
volId = Acs::str2Volid(argv[optind]);
// Move on to the next command-line argument
optind++;
// Parse the drive-identifier command-line argument
driveId = Acs::str2DriveId(argv[optind]);
}
//------------------------------------------------------------------------------
// processOption
//------------------------------------------------------------------------------
void castor::acs::AcsDismountCmdLine::processOption(const int opt) {
switch (opt) {
case 'd':
debug = true;
break;
case 'f':
force = TRUE;
break;
case 'h':
help = true;
break;
case 'q':
queryInterval = AcsCmdLine::parseQueryInterval(optarg);
break;
case 't':
timeout = AcsCmdLine::parseTimeout(optarg);
break;
case ':':
return AcsCmdLine::handleMissingParameter(optopt);
case '?':
return AcsCmdLine::handleUnknownOption(optopt);
default:
{
castor::exception::Exception ex;
ex.getMessage() <<
"getopt_long returned the following unknown value: 0x" <<
std::hex << (int)opt;
throw ex;
}
} // switch(opt)
}
......@@ -37,14 +37,6 @@ namespace acs {
* Data type used to store the results of parsing the command-line.
*/
struct AcsDismountCmdLine {
/**
* Constructor.
*
* Initialises all boolean member-variables to false, all integer
* member-variables to 0 and the volume identifier to an empty string.
*/
AcsDismountCmdLine() throw();
/**
* True if the debug option has been set.
*/
......@@ -83,6 +75,38 @@ struct AcsDismountCmdLine {
*/
DRIVEID driveId;
/**
* Constructor.
*
* Initialises all boolean member-variables to false, all integer
* member-variables to 0 and the volume identifier to an empty string.
*/
AcsDismountCmdLine() throw();
/**
* Constructor.
*
* Parses the specified command-line arguments.
*
* @param argc Argument count from the executable's entry function: main().
* @param argv Argument vector from the executable's entry function: main().
* @param defaultQueryInterval The default time in seconds to wait between
* queries to ACS for responses.
* @param defaultTimeout The default timeout value in seconds for the mount
* to conclude either success or failure.
*/
AcsDismountCmdLine(const int argc, char *const *const argv,
const int defaultQueryInterval, const int defaultTimeout);
private:
/**
* Processes the specified option that was returned by getopt_long().
*
* @param opt The option that was returned by getopt_long().
*/
void processOption(const int opt);
}; // class AcsDismountCmdLine
} // namespace acs
......
......@@ -22,8 +22,14 @@
*****************************************************************************/
#include "castor/acs/AcsDismountCmdLine.hpp"
#include "castor/exception/InvalidArgument.hpp"
#include "castor/exception/MissingOperand.hpp"
#include <gtest/gtest.h>
#include <list>
#include <memory>
#include <sstream>
#include <string.h>
namespace unitTests {
......@@ -33,9 +39,40 @@ protected:
virtual void SetUp() {
}
virtual void TearDown() {
// Allow getopt_long to be called again
optind = 0;
for(ArgcvList::const_iterator itor = m_argsList.begin();
itor != m_argsList.end(); itor++) {
for(int i=0; i < (*itor)->argc; i++) {
delete[] (*itor)->argv[i];
}
delete[] (*itor)->argv;
delete *itor;
}
}
struct Argcv {
int argc;
char **argv;
Argcv(): argc(0), argv(NULL) {
}
};
typedef std::list<Argcv*> ArgcvList;
ArgcvList m_argsList;
/**
* Creates a duplicate string usin the new operator.
*/
char *dupString(const char *str) {
const size_t len = strlen(str);
char *duplicate = new char[len+1];
strncpy(duplicate, str, len);