diff --git a/.gitignore b/.gitignore index aa35b98a520e40a764474b7ebb4e13c807c5ff40..77d49d817d45162549968cadda3fe9259939ed23 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,9 @@ castor/scheduler/Makefile castor/stager/daemon/stagerd castor/tape/mighunter/mighunterd castor/tape/rechandler/rechandlerd +castor/tape/rmc/castor-tape-acs-dismount +castor/tape/rmc/castor-tape-acs-mount +castor/tape/rmc/castor-tape-acs-queryvolume castor/tape/tapebridge/tapebridged castor/tape/tapegateway/tapegatewayd castor/tape/tpcp/dumptp diff --git a/castor/tape/Imakefile b/castor/tape/Imakefile index c7fa71a6725e1f51d6a3e993232982270975ceef..4365f3152fe3898d5d7f837d64263bd8f6901dd5 100644 --- a/castor/tape/Imakefile +++ b/castor/tape/Imakefile @@ -29,3 +29,4 @@ include LOCAL_PATH/utils/Makefile include LOCAL_PATH/legacymsg/Makefile include LOCAL_PATH/net/Makefile include LOCAL_PATH/tapebridge/Makefile +COMM include LOCAL_PATH/rmc/Makefile diff --git a/castor/tape/rmc/Acs.cpp b/castor/tape/rmc/Acs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9e907143ca5e1a64b32bf3f651a5947c9c93828d --- /dev/null +++ b/castor/tape/rmc/Acs.cpp @@ -0,0 +1,162 @@ +/****************************************************************************** + * castor/tape/rmc/Acs.cpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "castor/tape/rmc/Acs.hpp" +#include "castor/tape/utils/utils.hpp" + +#include <iomanip> +#include <sstream> +#include <stdint.h> + +//------------------------------------------------------------------------------ +// destructor +//------------------------------------------------------------------------------ +castor::tape::rmc::Acs::~Acs() throw() { +} + +//------------------------------------------------------------------------------ +// str2DriveId +//------------------------------------------------------------------------------ +DRIVEID castor::tape::rmc::Acs::str2DriveId(const std::string &str) + const throw(castor::exception::InvalidArgument) { + std::vector<std::string> components; + utils::splitString(str, ':', components); + + // The drive ID should consist of 4 components: ACS, LSM, Panel and Transport + if(4 != components.size()) { + castor::exception::InvalidArgument ex; + ex.getMessage() << "Invalid number of components in drive ID" + ": expected=4, actual=" << components.size(); + throw(ex); + } + + const std::string &acsStr = components[0]; + const std::string &lsmStr = components[1]; + const std::string &panStr = components[2]; + const std::string &drvStr = components[3]; + + // Each of the 4 components must be between 1 and than 3 characters long + if(1 > acsStr.length() || 3 < acsStr.length()) { + castor::exception::InvalidArgument ex; + ex.getMessage() << "Invalid ACS string length" + ": expected=1..3, actual=" << acsStr.length(); + throw(ex); + } + if(1 > lsmStr.length() || 3 < lsmStr.length()) { + castor::exception::InvalidArgument ex; + ex.getMessage() << "Invalid LSM string length" + ": expected=1..3, actual=" << lsmStr.length(); + throw(ex); + } + if(1 > panStr.length() || 3 < panStr.length()) { + castor::exception::InvalidArgument ex; + ex.getMessage() << "Invalid panel string length" + ": expected=1..3, actual=" << panStr.length(); + throw(ex); + } + if(1 > drvStr.length() || 3 < drvStr.length()) { + castor::exception::InvalidArgument ex; + ex.getMessage() << "Invalid drive string length" + ": expected=1..3, actual=" << drvStr.length(); + throw(ex); + } + + // Each of the 4 components must only contain numerals + if(!onlyContainsNumerals(acsStr)) { + castor::exception::InvalidArgument ex; + ex.getMessage() << "ACS must only contain numerals: value=" << acsStr; + throw(ex); + } + if(!onlyContainsNumerals(lsmStr)) { + castor::exception::InvalidArgument ex; + ex.getMessage() << "LSM must only contain numerals: value=" << acsStr; + throw(ex); + } + if(!onlyContainsNumerals(panStr)) { + castor::exception::InvalidArgument ex; + ex.getMessage() << "Panel must only contain numerals: value=" << acsStr; + throw(ex); + } + if(!onlyContainsNumerals(drvStr)) { + castor::exception::InvalidArgument ex; + ex.getMessage() << "Drive/Transport must only contain numerals: value=" << + acsStr; + throw(ex); + } + + DRIVEID driveId; + driveId.panel_id.lsm_id.acs = (ACS)atoi(acsStr.c_str()); + driveId.panel_id.lsm_id.lsm = (LSM)atoi(lsmStr.c_str()); + driveId.panel_id.panel = (PANEL)atoi(panStr.c_str()); + driveId.drive = (DRIVE)atoi(drvStr.c_str()); + + return driveId; +} + +//------------------------------------------------------------------------------ +// str2Volid +//------------------------------------------------------------------------------ +VOLID castor::tape::rmc::Acs::str2Volid(const std::string &str) const + throw(castor::exception::InvalidArgument) { + if(EXTERNAL_LABEL_SIZE < str.length()) { + castor::exception::InvalidArgument ex; + ex.getMessage() << "Failed to convert string to volume identifier" + ": String is longer than the " << EXTERNAL_LABEL_SIZE << + " character maximum"; + throw ex; + } + + VOLID v; + strncpy(v.external_label, str.c_str(), sizeof(v.external_label)); + v.external_label[sizeof(v.external_label) - 1] = '\0'; + return v; +} + +//------------------------------------------------------------------------------ +// onlyContainsNumerals +//------------------------------------------------------------------------------ +bool castor::tape::rmc::Acs::onlyContainsNumerals( + const std::string &str) const throw() { + for(std::string::const_iterator itor = str.begin(); itor != str.end(); + itor++) { + if(*itor < '0' || *itor > '9') { + return false; + } + } + return true; +} + +//------------------------------------------------------------------------------ +// driveId2Str +//------------------------------------------------------------------------------ +std::string castor::tape::rmc::Acs::driveId2Str(const DRIVEID &driveId) + const throw() { + std::ostringstream oss; + oss << std::setfill('0') << + std::setw(3) << (int32_t)driveId.panel_id.lsm_id.acs << ":" << + std::setw(3) << (int32_t)driveId.panel_id.lsm_id.lsm << ":" << + std::setw(3) << (int32_t)driveId.panel_id.panel << ":" << + std::setw(3) << (int32_t)driveId.drive; + return oss.str(); +} diff --git a/castor/tape/rmc/Acs.hpp b/castor/tape/rmc/Acs.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6579b88a953311edfad9d919b39c0b3ea349fe09 --- /dev/null +++ b/castor/tape/rmc/Acs.hpp @@ -0,0 +1,177 @@ +/****************************************************************************** + * castor/tape/rmc/Acs.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#ifndef CASTOR_TAPE_RMC_ACS_HPP +#define CASTOR_TAPE_RMC_ACS_HPP 1 + +#include "castor/exception/InvalidArgument.hpp" + +extern "C" { +#include "acssys.h" +#include "acsapi.h" +} + +#include <string> + +namespace castor { +namespace tape { +namespace rmc { + +/** + * Abstract class that defines the interface to an object that wraps the ACLS + * C-API. + */ +class Acs { +public: + /** + * Pure-virtual destructor to ensure this class is abstract. + */ + virtual ~Acs() throw() = 0; + + /** + * Parses the specified string and returns the corresponding drive ID object. + * + * This method throws a castor::exception::InvalidArgument if the syntax of + * the string is invalid. + * + * @param str The string to be parsed. + * @return The drive ID object. + */ + DRIVEID str2DriveId(const std::string &str) const + throw(castor::exception::InvalidArgument); + + /** + * Returns the VOLID equibvalent of the specified string. + * + * This method throws a castor::exception::InvalidArgument if the string is + * longer than EXTERNAL_LABEL_SIZE. + * + * @param str The string representation of the volume identifier. + * @return The VOLID representation of the volume identifier. + */ + VOLID str2Volid(const std::string &str) const + throw(castor::exception::InvalidArgument); + + /** + * Returns true if the specified string only contains numerals else false. + * + * @return True if the specified string only contains numerals else false. + */ + bool onlyContainsNumerals(const std::string &str) const throw(); + + /** + * Returns the string reprsentation of the specified drive identifier. + * + * The string format is ACS:LSM:panel:drive + * + * @param driveId The drive identifier. + * @return The string representation. + */ + std::string driveId2Str(const DRIVEID &driveId) const throw(); + + /** + * C++ wrapper around the acs_mount() function of the ACSLS C-API. + * + * @param seqNumber Client supplied sequence number. + * @param lockId Lock identifier or 0 meaning no lock. + * @param volId The indentifier of volume to be mounted. + * @param driveId The ID of the drive into which the volume is to be mounted. + * @param readOnly Set to true to request the volume be mounted for read-only + * access. + * @param bypass Set to true to override the ACSLS verification of + * compatibility between the drive and the media type of the volume. + * @return status value returned by acs_mount(). + */ + virtual STATUS mount( + const SEQ_NO seqNumber, + const LOCKID lockId, + const VOLID &volId, + const DRIVEID &driveId, + const BOOLEAN readOnly, + const BOOLEAN bypass) + throw() = 0; + + /** + * C++ wrapper around the acs_dismount() function of the ACSLS C-API. + * + * @param seqNumber Client supplied sequence number. + * @param lockId Lock identifier or 0 meaning no lock. + * @param volId The identifier of the volume to be mounted. + * @param driveId The ID of the drive into which the volume is to be mounted. + * @param force Set to true if the dismount should be forced. Forcing a + * dismount means dismounting the volume from the specified drive without + * checking the identifier of the volume. + * @return status value returned by acs_dismount(). + */ + virtual STATUS dismount( + const SEQ_NO seqNumber, + const LOCKID lockId, + const VOLID &volId, + const DRIVEID &driveId, + const BOOLEAN force) + throw() = 0; + + /** + * C++ wrapper around the acs_response() function of the ACSLS C-API. + * + * @param timeout Time in seconds to wait for a response. A value of -1 + * means block indefinitely and an a value of 0 means poll for the existence + * of a response. + * @param seqNumber Output parameter. If a response exists then seqNumber + * is set. + * @param reqId Output parameter. For an acknowledge response reqId is set + * to the request identifier of the original request. For an intermediate or + * final response reqId will be set to 0. + * @param rType Output parameter. Set to the type of the response. + * @param rBuf Output parameter. Set to the response information. + * @return status value returned by acs_response(). + */ + virtual STATUS response( + const int timeout, + SEQ_NO &seqNumber, + REQ_ID &reqId, + ACS_RESPONSE_TYPE &rType, + ALIGNED_BYTES rBuf) throw() = 0; + + /** + * C++ wrapper around the acs_query_volume() function of the ACSLS C-API. + * + * @param seqNumber Client supplied sequence number. + * @param volIds Array of the volume identifiers to be queried. + * @param count The number of volume identifiers contained iwthin the volId + * parameter. + * @return status value returned by acs_response(). + */ + virtual STATUS queryVolume( + const SEQ_NO seqNumber, + VOLID (&volIds)[MAX_ID], + const unsigned short count) throw() = 0; +}; // class Acs + +} // namespace rmc +} // namespace tape +} // namespace castor + + +#endif // CASTOR_TAPE_RMC_ACS_HPP diff --git a/castor/tape/rmc/AcsCmd.cpp b/castor/tape/rmc/AcsCmd.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c70d9f64aa1eb3797a29fb358ed147fb71bb9c5a --- /dev/null +++ b/castor/tape/rmc/AcsCmd.cpp @@ -0,0 +1,143 @@ +/****************************************************************************** + * castor/tape/rmc/AcsCmd.cpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "castor/tape/rmc/AcsCmd.hpp" +#include "castor/tape/utils/utils.hpp" + +#include <stdlib.h> + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +castor::tape::rmc::AcsCmd::AcsCmd(std::istream &inStream, + std::ostream &outStream, std::ostream &errStream, Acs &acs) throw(): + m_in(inStream), m_out(outStream), m_err(errStream), m_acs(acs), + m_debugBuf(outStream), m_dbg(&m_debugBuf) { +} + +//------------------------------------------------------------------------------ +// destructor +//------------------------------------------------------------------------------ +castor::tape::rmc::AcsCmd::~AcsCmd() throw() { +} + +//------------------------------------------------------------------------------ +// bool2Str +//------------------------------------------------------------------------------ +std::string castor::tape::rmc::AcsCmd::bool2Str(bool &value) const + throw() { + if(value) { + return "TRUE"; + } else { + return "FALSE"; + } +} + +//------------------------------------------------------------------------------ +// bool2Str +//------------------------------------------------------------------------------ +std::string castor::tape::rmc::AcsCmd::bool2Str(BOOLEAN &value) const + throw() { + if(value) { + return "TRUE"; + } else { + return "FALSE"; + } +} + +//------------------------------------------------------------------------------ +// requestResponsesUntilFinal +//------------------------------------------------------------------------------ +void castor::tape::rmc::AcsCmd::requestResponsesUntilFinal( + const SEQ_NO requestSeqNumber, + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)], + const int queryInterval, const int timeout) + throw (castor::exception::RequestFailed) { + ACS_RESPONSE_TYPE responseType = RT_NONE; + int elapsedTime = 0; + do { + const int remainingTime = timeout - elapsedTime; + const int responseTimeout = remainingTime > queryInterval ? + queryInterval : remainingTime; + + const time_t startTime = time(NULL); + responseType = requestResponse(responseTimeout, requestSeqNumber, buf); + elapsedTime += time(NULL) - startTime; + + if(RT_ACKNOWLEDGE == responseType) { + m_dbg << "Received RT_ACKNOWLEDGE" << std::endl; + } + + if(elapsedTime >= timeout) { + castor::exception::RequestFailed ex; + ex.getMessage() << "Timed out after " << timeout << " seconds"; + throw(ex); + } + } while(RT_FINAL != responseType); + + m_dbg << "Received RT_FINAL" << std::endl; +} + +//------------------------------------------------------------------------------ +// requestResponse +//------------------------------------------------------------------------------ +ACS_RESPONSE_TYPE castor::tape::rmc::AcsCmd::requestResponse( + const int timeout, const SEQ_NO requestSeqNumber, + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) + throw(castor::exception::RequestFailed) { + SEQ_NO responseSeqNumber = 0; + REQ_ID reqId = (REQ_ID)0; + ACS_RESPONSE_TYPE responseType = RT_NONE; + + m_dbg << "Calling Acs::response()" << std::endl; + const STATUS s = m_acs.response(timeout, responseSeqNumber, reqId, + responseType, buf); + m_dbg << "Acs::response() returned " << acs_status(s) << std::endl; + + switch(s) { + case STATUS_SUCCESS: + checkResponseSeqNumber(requestSeqNumber, responseSeqNumber); + return responseType; + case STATUS_PENDING: + return RT_NONE; + default: + castor::exception::RequestFailed ex; + ex.getMessage() << "Failed to request response: " << acs_status(s); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// checkSeqNumber +//------------------------------------------------------------------------------ +void castor::tape::rmc::AcsCmd::checkResponseSeqNumber( + const SEQ_NO requestSeqNumber, const SEQ_NO responseSeqNumber) + throw(castor::exception::Mismatch) { + if(requestSeqNumber != responseSeqNumber) { + castor::exception::Mismatch ex; + ex.getMessage() << ": Sequence number mismatch: requestSeqNumber=" + << requestSeqNumber << " responseSeqNumber=" << responseSeqNumber; + throw(ex); + } +} diff --git a/castor/tape/rmc/AcsCmd.hpp b/castor/tape/rmc/AcsCmd.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0dfceeba22fc9e1ffcfa337c7dc20a84c39f4e07 --- /dev/null +++ b/castor/tape/rmc/AcsCmd.hpp @@ -0,0 +1,165 @@ +/****************************************************************************** + * castor/tape/rmc/AcsCmd.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#ifndef CASTOR_TAPE_RMC_ACSCMD_HPP +#define CASTOR_TAPE_RMC_ACSCMD_HPP 1 + +#include "castor/exception/InvalidArgument.hpp" +#include "castor/exception/Mismatch.hpp" +#include "castor/exception/RequestFailed.hpp" +#include "castor/tape/rmc/Acs.hpp" +#include "castor/tape/rmc/DebugBuf.hpp" + +#include <istream> +#include <ostream> +#include <string> + +extern "C" { +#include "acssys.h" +#include "acsapi.h" +} + +namespace castor { +namespace tape { +namespace rmc { + +/** + * Abstract class implementing common code and data structures for command-line + * tools that interact with ACLS compatible tape libraries. + */ +class AcsCmd { +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. + */ + AcsCmd(std::istream &inStream, std::ostream &outStream, + std::ostream &errStream, Acs &acs) throw(); + + /** + * Pure-virtual destructor to guarantee this class is abstract. + */ + virtual ~AcsCmd() throw() = 0; + +protected: + + /** + * Standard input stream. + */ + std::istream &m_in; + + /** + * Standard output stream. + */ + std::ostream &m_out; + + /** + * Standard error stream. + */ + std::ostream &m_err; + + /** + * Wrapper around the ACSLS C-API. + */ + Acs &m_acs; + + /** + * Debug stream buffer that inserts a standard debug preamble before each + * message-line written to it. + */ + DebugBuf m_debugBuf; + + /** + * Stream used to write debug messages. + * + * This stream will insert a standard debug preamble before each message-line + * written to it. + */ + std::ostream m_dbg; + + /** + * Returns the string representation of the specfied boolean value. + */ + std::string bool2Str(bool &value) const throw(); + + /** + * Returns the string representation of the specfied boolean value. + */ + std::string bool2Str(BOOLEAN &value) const throw(); + + /** + * Requests responses from ACSLS in a loop until the RT_FINAL response is + * received. + * + * @param requestSeqNumber The sequemce number that was sent in the initial + * request to the ACSLS. + * @param buf Output parameter. Message buffer into which the RT_FINAL + * response shall be written. + * @param queryInterval Time in seconds to wait between queries to ACS for + * responses. + * @param timeout The time in seconds to spend trying to get the RT_FINAL + * response. + */ + void requestResponsesUntilFinal(const SEQ_NO requestSeqNumber, + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)], + const int queryInterval, const int timeout) + throw (castor::exception::RequestFailed); + + /** + * Sends a request for a response to the ACSLS. + * + * @param timeout The timeout. + * @param requestSeqNumber The sequemce number that was sent in the initial + * request to the ACSLS. + * @param buf Output parameter. The response message if there is one. + * @return The type of the response message if there is one or RT_NONE if + * there isn't one. + */ + ACS_RESPONSE_TYPE requestResponse(const int timeout, + const SEQ_NO requestSeqNumber, + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) + throw(castor::exception::RequestFailed); + + /** + * Throws castor::exception::Mismatch if the specified request and + * response sequence-numbers do not match. + * + * @param requestSeqNumber Request sequence-number. + * @param responseSeqNumber Response sequence-number. + */ + void checkResponseSeqNumber(const SEQ_NO requestSeqNumber, + const SEQ_NO responseSeqNumber) throw(castor::exception::Mismatch); + +}; // class AcsCmd + +} // namespace rmc +} // namespace tape +} // namespace castor + + +#endif // CASTOR_TAPE_RMC_ACSCMD_HPP diff --git a/castor/tape/rmc/AcsDismountCmd.cpp b/castor/tape/rmc/AcsDismountCmd.cpp new file mode 100644 index 0000000000000000000000000000000000000000..07f7487c71c25755fd21ec65b5f8eef516659255 --- /dev/null +++ b/castor/tape/rmc/AcsDismountCmd.cpp @@ -0,0 +1,305 @@ +/****************************************************************************** + * castor/tape/rmc/AcsDismountCmd.cpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "castor/tape/rmc/AcsDismountCmd.hpp" +#include "castor/tape/utils/utils.hpp" + +#include <getopt.h> + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +castor::tape::rmc::AcsDismountCmd::AcsDismountCmd( + std::istream &inStream, std::ostream &outStream, std::ostream &errStream, + Acs &acs) throw(): + AcsCmd(inStream, outStream, errStream, acs), m_defaultQueryInterval(10), + m_defaultTimeout(600) { +} + +//------------------------------------------------------------------------------ +// destructor +//------------------------------------------------------------------------------ +castor::tape::rmc::AcsDismountCmd::~AcsDismountCmd() throw() { + // Do nothing +} + +//------------------------------------------------------------------------------ +// main +//------------------------------------------------------------------------------ +int castor::tape::rmc::AcsDismountCmd::main(const int argc, + char *const *const argv) throw() { + try { + m_cmdLine = parseCmdLine(argc, argv); + } catch(castor::exception::InvalidArgument &ia) { + m_err << "Aborting: Invalid command-line: " << ia.getMessage().str() << + std::endl; + m_err << std::endl; + usage(m_err); + return 1; + } catch(castor::exception::MissingOperand &mo) { + m_err << "Aborting: Missing operand: " << mo.getMessage().str() << + std::endl; + m_err << std::endl; + usage(m_err); + return 1; + } catch(castor::exception::Internal &ie) { + m_err << "Aborting: Internal error: " << ie.getMessage().str() << + std::endl; + return 1; + } + + // Display the usage message to standard out and exit with success if the + // user requested help + if(m_cmdLine.help) { + usage(m_out); + return 0; + } + + // Setup debug mode to be on or off depending on the command-line arguments + m_debugBuf.setDebug(m_cmdLine.debug); + + m_dbg << "force = " << (m_cmdLine.force ? "TRUE" : "FALSE") << std::endl; + m_dbg << "query = " << m_cmdLine.queryInterval << std::endl; + m_dbg << "timeout = " << m_cmdLine.timeout << std::endl; + m_dbg << "VID = " << m_cmdLine.volId.external_label << std::endl; + m_dbg << "DRIVE = " << m_acs.driveId2Str(m_cmdLine.driveId) << std::endl; + + try { + syncDismount(); + } catch(castor::exception::Exception &ex) { + m_err << "Aborting: " << ex.getMessage().str() << std::endl; + return 1; + } + + return 0; +} + +//------------------------------------------------------------------------------ +// usage +//------------------------------------------------------------------------------ +void castor::tape::rmc::AcsDismountCmd::usage(std::ostream &os) + const throw() { + os << + "Usage:\n" + " dismountacs [options] VID DRIVE\n" + "\n" + "Where:\n" + "\n" + " VID The VID of the volume to be dismounted.\n" + " DRIVE The drive from which the volume is to be dismounted.\n" + "\n" + "Options:\n" + "\n" + " -d|--debug Turn on the printing of debug information.\n" + " -f|--force Force the dismount.\n" + " -h|--help Print this help message and exit.\n" + " -q|--query SECONDS Time to wait between queries to ACS for responses.\n" + " SECONDS must be an integer value greater than 0.\n" + " The default value of SECONDS is " + << m_defaultQueryInterval << ".\n" + " -t|--timeout SECONDS Time to wait for the dismount to conclude. SECONDS\n" + " must be an integer value greater than 0. The\n" + " default value of SECONDS is " + << m_defaultTimeout << ".\n" + "\n" + "Comments to: Castor.Support@cern.ch" << std::endl; +} + +//------------------------------------------------------------------------------ +// parseCmdLine +//------------------------------------------------------------------------------ +castor::tape::rmc::AcsDismountCmdLine + castor::tape::rmc::AcsDismountCmd::parseCmdLine( + const int argc, char *const *const argv) + throw(castor::exception::Internal, castor::exception::InvalidArgument, + castor::exception::MissingOperand) { + + 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::Internal 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 +//------------------------------------------------------------------------------ +void castor::tape::rmc::AcsDismountCmd::syncDismount() + throw(castor::exception::DismountFailed) { + const SEQ_NO requestSeqNumber = 1; + ALIGNED_BYTES buf[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]; + + try { + sendDismountRequest(requestSeqNumber); + requestResponsesUntilFinal(requestSeqNumber, buf, m_cmdLine.queryInterval, + m_cmdLine.timeout); + processDismountResponse(buf); + } catch(castor::exception::Exception &ex) { + castor::exception::DismountFailed df; + df.getMessage() << "Failed to dismount volume " << + m_cmdLine.volId.external_label << ": " << ex.getMessage().str(); + throw df; + } +} + +//------------------------------------------------------------------------------ +// sendDismountRequest +//------------------------------------------------------------------------------ +void castor::tape::rmc::AcsDismountCmd::sendDismountRequest( + const SEQ_NO seqNumber) throw (castor::exception::DismountFailed) { + const LOCKID lockId = 0; // No lock + + m_dbg << "Calling Acs::dismount()" << std::endl; + const STATUS s = m_acs.dismount(seqNumber, lockId, m_cmdLine.volId, + m_cmdLine.driveId, m_cmdLine.force); + m_dbg << "Acs::dismount() returned " << acs_status(s) << std::endl; + if(STATUS_SUCCESS != s) { + castor::exception::DismountFailed ex; + ex.getMessage() << "Failed to send request to dismount volume " << + m_cmdLine.volId.external_label << " from drive " << + m_acs.driveId2Str(m_cmdLine.driveId) << ": force=" << + (m_cmdLine.force ? "TRUE" : "FALSE") << ": " << acs_status(s); + throw(ex); + } +} + +//------------------------------------------------------------------------------ +// processDismountResponse +//------------------------------------------------------------------------------ +void castor::tape::rmc::AcsDismountCmd::processDismountResponse( + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) + throw(castor::exception::DismountFailed) { + const ACS_DISMOUNT_RESPONSE *const msg = (ACS_DISMOUNT_RESPONSE *)buf; + + if(STATUS_SUCCESS != msg->dismount_status) { + castor::exception::DismountFailed ex; + ex.getMessage() << "Status of dismount response is not success: " << + acs_status(msg->dismount_status); + throw(ex); + } +} diff --git a/castor/tape/rmc/AcsDismountCmd.hpp b/castor/tape/rmc/AcsDismountCmd.hpp new file mode 100644 index 0000000000000000000000000000000000000000..02cfe6dc2c932124c1959f2f3a8a30143d8f8be4 --- /dev/null +++ b/castor/tape/rmc/AcsDismountCmd.hpp @@ -0,0 +1,150 @@ +/****************************************************************************** + * castor/tape/rmc/AcsDismountCmd.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#ifndef CASTOR_TAPE_RMC_ACSDISMOUNTCMD_HPP +#define CASTOR_TAPE_RMC_ACSDISMOUNTCMD_HPP 1 + +#include "castor/exception/DismountFailed.hpp" +#include "castor/exception/Internal.hpp" +#include "castor/exception/InvalidArgument.hpp" +#include "castor/exception/MissingOperand.hpp" +#include "castor/tape/rmc/AcsCmd.hpp" +#include "castor/tape/rmc/AcsDismountCmdLine.hpp" + +namespace castor { +namespace tape { +namespace rmc { + +/** + * The class implementing the mount command. + */ +class AcsDismountCmd: public AcsCmd { +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. + */ + AcsDismountCmd(std::istream &inStream, std::ostream &outStream, + std::ostream &errStream, Acs &acs) throw(); + + /** + * Destructor. + */ + virtual ~AcsDismountCmd() throw(); + + /** + * The entry function of the command. + * + * This method sets the m_cmdLine member-variable. + * + * @param argc The number of command-line arguments. + * @param argv The command-line arguments. + */ + int main(const int argc, char *const *const argv) throw(); + +protected: + + /** + * Writes the command-line usage message of to the specified output stream. + * + * @param os Output stream to be written to. + */ + 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) + throw(castor::exception::Internal, castor::exception::InvalidArgument, + castor::exception::MissingOperand); + + /** + * Dismounts the tape with the specified VID into the drive with the specified + * drive ID. + * + * This method does not return until the mount has either suceeded, failed or + * the specified timeout has been reached. + * + * @param dismountTimeout The maximum amount of time in seconds to wait for + * the dismount operation to conclude. + * @param queryInterval The amount of time in seconds to wait between + * querying ACS for responses. + */ + void syncDismount() throw(castor::exception::DismountFailed); + + /** + * Sends the dismount request to ACSLS. + * + * @param seqNumber The sequence number to be used in the request. + */ + void sendDismountRequest(const SEQ_NO seqNumber) + throw(castor::exception::DismountFailed); + + /** + * Throws castor::exception::DismountFailed if the mount was not + * successful. + * + * @param buf The mount-response message. + */ + void processDismountResponse( + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) + throw(castor::exception::DismountFailed); + +private: + + /** + * The parsed command-line. + * + * This member-variable is set by the main() method of this class. + */ + AcsDismountCmdLine m_cmdLine; + + /** + * The default time in seconds to wait between queries to ACS for responses. + */ + const int m_defaultQueryInterval; + + /** + * The default timeout value in seconds for the dismount to conclude either + * success or failure. + */ + const int m_defaultTimeout; + +}; // class AcsDismountCmd + +} // namespace rmc +} // namespace tape +} // namespace castor + + +#endif // CASTOR_TAPE_RMC_ACSDISMOUNTCMD_HPP diff --git a/castor/tape/rmc/AcsDismountCmdLine.cpp b/castor/tape/rmc/AcsDismountCmdLine.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9a5b6e30a428941bf938f8f5b22fca0503c58496 --- /dev/null +++ b/castor/tape/rmc/AcsDismountCmdLine.cpp @@ -0,0 +1,41 @@ +/****************************************************************************** + * castor/tape/rmc/AcsDismountCmdLine.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "castor/tape/rmc/AcsDismountCmdLine.hpp" + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +castor::tape::rmc::AcsDismountCmdLine::AcsDismountCmdLine() throw(): + debug(false), + force(FALSE), + help(false), + queryInterval(0), + timeout(0) { + 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)); +} diff --git a/castor/tape/rmc/AcsDismountCmdLine.hpp b/castor/tape/rmc/AcsDismountCmdLine.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4c1a58174037914b5ff9d429f6b93aae4b096eaa --- /dev/null +++ b/castor/tape/rmc/AcsDismountCmdLine.hpp @@ -0,0 +1,96 @@ +/****************************************************************************** + * castor/tape/rmc/AcsDismountCmdLine.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#ifndef CASTOR_TAPE_RMC_ACSDISMOUNTCMDLINE_HPP +#define CASTOR_TAPE_RMC_ACSDISMOUNTCMDLINE_HPP 1 + +extern "C" { +#include "acssys.h" +#include "acsapi.h" +} + +#include <string> + +namespace castor { +namespace tape { +namespace rmc { + +/** + * 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. + */ + bool debug; + + /** + * True if the dismount should be forced. + * + * Forcing a dismount means dismounting the tape in the specified drive + * without checking the volume identifier of the tape. + */ + BOOLEAN force; + + /** + * True if the help option has been set. + */ + bool help; + + /** + * Time in seconds to wait between queries to ACS for responses. + */ + int queryInterval; + + /** + * Time in seconds to wait for the dismount to conclude. + */ + int timeout; + + /** + * The volume identifier of the tape to be mounted. + */ + VOLID volId; + + /** + * The drive into which the tape is to be mounted. + */ + DRIVEID driveId; + +}; // class AcsDismountCmdLine + +} // namespace rmc +} // namespace tape +} // namespace castor + + +#endif // CASTOR_TAPE_RMC_ACSDISMOUNTCMDLINE_HPP diff --git a/castor/tape/rmc/AcsDismountMain.cpp b/castor/tape/rmc/AcsDismountMain.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f93dfa9c8e1c1b442faf627eaedde1e33587e4d1 --- /dev/null +++ b/castor/tape/rmc/AcsDismountMain.cpp @@ -0,0 +1,39 @@ +/****************************************************************************** + * castor/tape/rmc/AcsDismountMain.cpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "castor/tape/rmc/AcsImpl.hpp" +#include "castor/tape/rmc/AcsDismountCmd.hpp" + +#include <iostream> + +//------------------------------------------------------------------------------ +// main +//------------------------------------------------------------------------------ +int main(const int argc, char *const *const argv) { + castor::tape::rmc::AcsImpl acs; + castor::tape::rmc::AcsDismountCmd + cmd(std::cin, std::cout, std::cerr, acs); + + return cmd.main(argc, argv); +} diff --git a/castor/tape/rmc/AcsImpl.cpp b/castor/tape/rmc/AcsImpl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..73ff227865f3240680b8ce83238c9ae0c406acca --- /dev/null +++ b/castor/tape/rmc/AcsImpl.cpp @@ -0,0 +1,84 @@ +/****************************************************************************** + * castor/tape/rmc/AcsImpl.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "castor/tape/rmc/AcsImpl.hpp" + +#include <errno.h> +#include <sstream> +#include <string.h> + +//------------------------------------------------------------------------------ +// destructor +//------------------------------------------------------------------------------ +castor::tape::rmc::AcsImpl::~AcsImpl() throw() { +} + +//------------------------------------------------------------------------------ +// mount +//------------------------------------------------------------------------------ +STATUS castor::tape::rmc::AcsImpl::mount( + const SEQ_NO seqNumber, + const LOCKID lockId, + const VOLID &volId, + const DRIVEID &driveId, + const BOOLEAN readOnly, + const BOOLEAN bypass) + throw() { + return acs_mount(seqNumber, lockId, volId, driveId, readOnly, bypass); +} + +//------------------------------------------------------------------------------ +// dismount +//------------------------------------------------------------------------------ +STATUS castor::tape::rmc::AcsImpl::dismount( + const SEQ_NO seqNumber, + const LOCKID lockId, + const VOLID &volId, + const DRIVEID &driveId, + const BOOLEAN force) + throw() { + return acs_dismount(seqNumber, lockId, volId, driveId, force); +} + +//------------------------------------------------------------------------------ +// response +//------------------------------------------------------------------------------ +STATUS castor::tape::rmc::AcsImpl::response( + const int timeout, + SEQ_NO &seqNumber, + REQ_ID &reqId, + ACS_RESPONSE_TYPE &rType, + ALIGNED_BYTES rBuf) throw() { + return acs_response(timeout, &seqNumber, &reqId, &rType, rBuf); +} + +//------------------------------------------------------------------------------ +// queryVolume +//------------------------------------------------------------------------------ +STATUS castor::tape::rmc::AcsImpl::queryVolume( + const SEQ_NO seqNumber, + VOLID (&volIds)[MAX_ID], + const unsigned short count) throw() { + return acs_query_volume(seqNumber, volIds, count); +} diff --git a/castor/tape/rmc/AcsImpl.hpp b/castor/tape/rmc/AcsImpl.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0b2824669e581e32851dda4c1b99ab5af5c43fd8 --- /dev/null +++ b/castor/tape/rmc/AcsImpl.hpp @@ -0,0 +1,129 @@ +/****************************************************************************** + * castor/tape/rmc/AcsImpl.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#ifndef CASTOR_TAPE_RMC_ACSIMPL_HPP +#define CASTOR_TAPE_RMC_ACSIMPL_HPP 1 + +#include "castor/tape/rmc/Acs.hpp" + +namespace castor { +namespace tape { +namespace rmc { + +/** + * Concrete class that wraps the ACLS C-API. + */ +class AcsImpl: public Acs { +public: + /** + * Destructor. + */ + ~AcsImpl() throw(); + + /** + * C++ wrapper around the acs_mount() function of the ACSLS C-API. + * + * @param seqNumber Client supplied sequence number. + * @param lockId Lock identifier or 0 meaning no lock. + * @param volId The identifier of the volume to be mounted. + * @param driveId The ID of the drive into which the volume is to be mounted. + * @param readOnly Set to true to request the volume be mounted for read-only + * access. + * @param bypass Set to true to override the ACSLS verification of + * compatibility between the drive and the media type of the volume. + * @return status value returned by acs_mount(). + */ + STATUS mount( + const SEQ_NO seqNumber, + const LOCKID lockId, + const VOLID &volId, + const DRIVEID &driveId, + const BOOLEAN readOnly, + const BOOLEAN bypass) + throw(); + + /** + * C++ wrapper around the acs_dismount() function of the ACSLS C-API. + * + * @param seqNumber Client supplied sequence number. + * @param lockId Lock identifier or 0 meaning no lock. + * @param volId The identifier of the volume to be mounted. + * @param driveId The ID of the drive into which the volume is to be mounted. + * @param force Set to true if the dismount should be forced. Forcing a + * dismount means dismounting the volume from the specified drive without + * checking the identifier of the volume. + * @return status value returned by acs_dismount(). + */ + STATUS dismount( + const SEQ_NO seqNumber, + const LOCKID lockId, + const VOLID &volId, + const DRIVEID &driveId, + const BOOLEAN force) + throw(); + + /** + * C++ wrapper around the acs_response() function of the ACSLS C-API. + * + * @param timeout Time in seconds to wait for a response. A value of -1 + * means block indefinitely and an a value of 0 means poll for the existence + * of a response. + * @param seqNumber Output parameter. If a response exists then seqNumber + * is set. + * @param reqId Output parameter. For an acknowledge response reqId is set + * to the request identifier of the original request. For an intermediate or + * final response reqId will be set to 0. + * @param rType Output parameter. Set to the type of the response. + * @param rBuf Output parameter. Set to the response information. + * @return status value returned by acs_response(). + */ + STATUS response( + const int timeout, + SEQ_NO &seqNumber, + REQ_ID &reqId, + ACS_RESPONSE_TYPE &rType, + ALIGNED_BYTES rBuf) throw(); + + /** + * C++ wrapper around the acs_query_volume() function of the ACSLS C-API. + * + * @param seqNumber Client supplied sequence number. + * @param volIds Array of the volume identifiers to be queried. + * @param count The number of volume identifiers contained iwthin the volId + * parameter. + * @return status value returned by acs_response(). + */ + STATUS queryVolume( + const SEQ_NO seqNumber, + VOLID (&volIds)[MAX_ID], + const unsigned short count) throw(); + +}; // class AcsImpl + +} // namespace rmc +} // namespace tape +} // namespace castor + + +#endif // CASTOR_TAPE_RMC_ACSIMPL_HPP diff --git a/castor/tape/rmc/AcsMountCmd.cpp b/castor/tape/rmc/AcsMountCmd.cpp new file mode 100644 index 0000000000000000000000000000000000000000..62589bc05eb052c890f83049e9ad36788818dd9f --- /dev/null +++ b/castor/tape/rmc/AcsMountCmd.cpp @@ -0,0 +1,306 @@ +/****************************************************************************** + * castor/tape/rmc/AcsMountCmd.cpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "castor/tape/rmc/AcsMountCmd.hpp" +#include "castor/tape/utils/utils.hpp" + +#include <getopt.h> +#include <iostream> + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +castor::tape::rmc::AcsMountCmd::AcsMountCmd( + std::istream &inStream, std::ostream &outStream, std::ostream &errStream, + Acs &acs) throw(): + AcsCmd(inStream, outStream, errStream, acs), m_defaultQueryInterval(10), + m_defaultTimeout(600) { +} + +//------------------------------------------------------------------------------ +// destructor +//------------------------------------------------------------------------------ +castor::tape::rmc::AcsMountCmd::~AcsMountCmd() throw() { + // Do nothing +} + +//------------------------------------------------------------------------------ +// main +//------------------------------------------------------------------------------ +int castor::tape::rmc::AcsMountCmd::main(const int argc, + char *const *const argv) throw() { + try { + m_cmdLine = parseCmdLine(argc, argv); + } catch(castor::exception::InvalidArgument &ia) { + m_err << "Aborting: Invalid command-line: " << ia.getMessage().str() << + std::endl; + m_err << std::endl; + usage(m_err); + return 1; + } catch(castor::exception::MissingOperand &mo) { + m_err << "Aborting: Missing operand: " << mo.getMessage().str() << + std::endl; + m_err << std::endl; + usage(m_err); + return 1; + } catch(castor::exception::Internal &ie) { + m_err << "Aborting: Internal error: " << ie.getMessage().str() << + std::endl; + return 1; + } + + // Display the usage message to standard out and exit with success if the + // user requested help + if(m_cmdLine.help) { + usage(m_out); + return 0; + } + + // Setup debug mode to be on or off depending on the command-line arguments + m_debugBuf.setDebug(m_cmdLine.debug); + + m_dbg << "query = " << m_cmdLine.queryInterval << std::endl; + m_dbg << "readonly = " << bool2Str(m_cmdLine.readOnly) << std::endl; + m_dbg << "timeout = " << m_cmdLine.timeout << std::endl; + m_dbg << "VID = " << m_cmdLine.volId.external_label << std::endl; + m_dbg << "DRIVE = " << m_acs.driveId2Str(m_cmdLine.driveId) << std::endl; + + try { + syncMount(); + } catch(castor::exception::Exception &ex) { + m_err << "Aborting: " << ex.getMessage().str() << std::endl; + return 1; + } + + return 0; +} + +//------------------------------------------------------------------------------ +// parseCmdLine +//------------------------------------------------------------------------------ +castor::tape::rmc::AcsMountCmdLine + castor::tape::rmc::AcsMountCmd::parseCmdLine( + const int argc, char *const *const argv) + throw(castor::exception::Internal, castor::exception::InvalidArgument, + castor::exception::MissingOperand) { + + static struct option longopts[] = { + {"debug", 0, NULL, 'd'}, + {"help" , 0, NULL, 'h'}, + {"query" , required_argument, NULL, 'q'}, + {"readonly" , 0, NULL, 'r'}, + {"timeout" , required_argument, NULL, 't'}, + {NULL, 0, NULL, 0} + }; + AcsMountCmdLine 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, ":dhq:rt:", longopts, NULL)) != -1) { + + switch (c) { + case 'd': + cmdLine.debug = 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 'r': + cmdLine.readOnly = TRUE; + 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::Internal 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 VID command-line argument + cmdLine.volId = m_acs.str2Volid(argv[optind]); + + // Move on to the next command-line argument + optind++; + + // Parse the DRIVE command-line argument + cmdLine.driveId = m_acs.str2DriveId(argv[optind]); + + return cmdLine; +} + +//------------------------------------------------------------------------------ +// usage +//------------------------------------------------------------------------------ +void castor::tape::rmc::AcsMountCmd::usage(std::ostream &os) + const throw() { + os << + "Usage:\n" + " mountacs [options] VID DRIVE\n" + "\n" + "Where:\n" + "\n" + " VID The VID of the volume to be mounted.\n" + " DRIVE The ID of the drive into which the volume is to be mounted.\n" + " Drive ID format is ACS:LSM:panel:transport\n" + "\n" + "Options:\n" + "\n" + " -d|--debug Turn on the printing of debug information.\n" + " -h|--help Print this help message and exit.\n" + " -q|--query SECONDS Time to wait between queries to ACS for responses.\n" + " SECONDS must be an integer value greater than 0.\n" + " The default value of SECONDS is " + << m_defaultQueryInterval << ".\n" + " -r|--readOnly Request the volume is mounted for read-only access\n" + " -t|--timeout SECONDS Time to wait for the mount to conclude. SECONDS\n" + " must be an integer value greater than 0. The\n" + " default value of SECONDS is " + << m_defaultTimeout << ".\n" + "\n" + "Comments to: Castor.Support@cern.ch" << std::endl; +} + +//------------------------------------------------------------------------------ +// syncMount +//------------------------------------------------------------------------------ +void castor::tape::rmc::AcsMountCmd::syncMount() + throw(castor::exception::MountFailed) { + const SEQ_NO requestSeqNumber = 1; + ALIGNED_BYTES buf[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]; + + try { + sendMountRequest(requestSeqNumber); + requestResponsesUntilFinal(requestSeqNumber, buf, m_cmdLine.queryInterval, + m_cmdLine.timeout); + processMountResponse(buf); + } catch(castor::exception::Exception &ex) { + castor::exception::MountFailed mf; + mf.getMessage() << "Failed to mount volume " << + m_cmdLine.volId.external_label << ": " << ex.getMessage().str(); + throw mf; + } +} + +//------------------------------------------------------------------------------ +// sendMountRequest +//------------------------------------------------------------------------------ +void castor::tape::rmc::AcsMountCmd::sendMountRequest( + const SEQ_NO seqNumber) throw(castor::exception::MountFailed) { + const LOCKID lockId = 0; // No lock + const BOOLEAN bypass = FALSE; + + m_dbg << "Calling Acs::mount()" << std::endl; + const STATUS s = m_acs.mount(seqNumber, lockId, m_cmdLine.volId, + m_cmdLine.driveId, m_cmdLine.readOnly, bypass); + m_dbg << "Acs::mount() returned " << acs_status(s) << std::endl; + + if(STATUS_SUCCESS != s) { + castor::exception::MountFailed ex; + ex.getMessage() << "Failed to send request to mount volume " << + m_cmdLine.volId.external_label << " into drive " << + m_acs.driveId2Str(m_cmdLine.driveId) << ": readOnly=" << + (m_cmdLine.readOnly ? "TRUE" : "FALSE") << ": " << acs_status(s); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// processMountResponse +//------------------------------------------------------------------------------ +void castor::tape::rmc::AcsMountCmd::processMountResponse( + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) + throw(castor::exception::MountFailed) { + const ACS_MOUNT_RESPONSE *const msg = (ACS_MOUNT_RESPONSE *)buf; + + if(STATUS_SUCCESS != msg->mount_status) { + castor::exception::MountFailed ex; + ex.getMessage() << "Status of mount response is not success: " << + acs_status(msg->mount_status); + throw(ex); + } +} diff --git a/castor/tape/rmc/AcsMountCmd.hpp b/castor/tape/rmc/AcsMountCmd.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1ac0f7e22637f6ad08a10bcdee82e00b2090d336 --- /dev/null +++ b/castor/tape/rmc/AcsMountCmd.hpp @@ -0,0 +1,144 @@ +/****************************************************************************** + * castor/tape/rmc/AcsMountCmd.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#ifndef CASTOR_TAPE_RMC_ACSMOUNTCMD_HPP +#define CASTOR_TAPE_RMC_ACSMOUNTCMD_HPP 1 + +#include "castor/exception/Internal.hpp" +#include "castor/exception/InvalidArgument.hpp" +#include "castor/exception/MissingOperand.hpp" +#include "castor/exception/MountFailed.hpp" +#include "castor/tape/rmc/AcsCmd.hpp" +#include "castor/tape/rmc/AcsMountCmdLine.hpp" + +#include <stdint.h> + +namespace castor { +namespace tape { +namespace rmc { + +/** + * The class implementing the mount command. + */ +class AcsMountCmd: public AcsCmd { +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. + */ + AcsMountCmd(std::istream &inStream, std::ostream &outStream, + std::ostream &errStream, Acs &acs) throw(); + + /** + * Destructor. + */ + virtual ~AcsMountCmd() throw(); + + /** + * The entry function of the command. + * + * @param argc The number of command-line arguments. + * @param argv The command-line arguments. + */ + int main(const int argc, char *const *const argv) throw(); + +protected: + + /** + * 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. + */ + AcsMountCmdLine parseCmdLine(const int argc, char *const *const argv) + throw(castor::exception::Internal, castor::exception::InvalidArgument, + castor::exception::MissingOperand); + + /** + * Writes the command-line usage message of to the specified output stream. + * + * @param os Output stream to be written to. + */ + void usage(std::ostream &os) const throw(); + + /** + * Mounts the tape with the specified VID into the drive with the specified + * drive ID. + * + * This method does not return until the mount has either suceeded, failed or + * the specified timeout has been reached. + */ + void syncMount() throw(castor::exception::MountFailed); + + /** + * Sends the mount request to ACSLS. + * + * @param seqNumber The sequence number to be used in the request. + */ + void sendMountRequest(const SEQ_NO seqNumber) + throw(castor::exception::MountFailed); + + /** + * Throws castor::exception::DismountFailed if the mount was not + * successful. + * + * @param buf The mount-response message. + */ + void processMountResponse( + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) + throw(castor::exception::MountFailed); + +private: + + /** + * The parsed command-line. + * + * The value of this member variable is set within the main() method of this + * class. + */ + AcsMountCmdLine m_cmdLine; + + /** + * The default time in seconds to wait between queries to ACS for responses. + */ + const int m_defaultQueryInterval; + + /** + * The default timeout value in seconds for the mount to conclude either + * success or failure. + */ + const int m_defaultTimeout; +}; // class AcsMountCmd + +} // namespace rmc +} // namespace tape +} // namespace castor + +#endif // CASTOR_TAPE_RMC_ACSMOUNTCMD_HPP diff --git a/castor/tape/rmc/AcsMountCmdLine.cpp b/castor/tape/rmc/AcsMountCmdLine.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6e27e6dc287b15d0c055ab846459bee6f078799d --- /dev/null +++ b/castor/tape/rmc/AcsMountCmdLine.cpp @@ -0,0 +1,41 @@ +/****************************************************************************** + * castor/tape/rmc/AcsMountCmdLine.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "castor/tape/rmc/AcsMountCmdLine.hpp" + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +castor::tape::rmc::AcsMountCmdLine::AcsMountCmdLine() throw(): + debug(false), + help(false), + queryInterval(0), + readOnly(FALSE), + timeout(0) { + 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)); +} diff --git a/castor/tape/rmc/AcsMountCmdLine.hpp b/castor/tape/rmc/AcsMountCmdLine.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ab140dd1347cd024d77b358c1cebd354060006e2 --- /dev/null +++ b/castor/tape/rmc/AcsMountCmdLine.hpp @@ -0,0 +1,93 @@ +/****************************************************************************** + * castor/tape/rmc/AcsMountCmdLine.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#ifndef CASTOR_TAPE_RMC_ACSMOUNTCMDLINE_HPP +#define CASTOR_TAPE_RMC_ACSMOUNTCMDLINE_HPP 1 + +extern "C" { +#include "acssys.h" +#include "acsapi.h" +} + +#include <string> + +namespace castor { +namespace tape { +namespace rmc { + +/** + * Data type used to store the results of parsing the command-line. + */ +struct AcsMountCmdLine { + /** + * Constructor. + * + * Initialises all BOOLEAN member-variables to FALSE, all integer + * member-variables to 0 and the volume identifier to an empty string. + */ + AcsMountCmdLine() throw(); + + /** + * True if the debug option has been set. + */ + bool debug; + + /** + * True if the help option has been set. + */ + bool help; + + /** + * Time in seconds to wait between queries to ACS for responses. + */ + int queryInterval; + + /** + * True if the tape is to be mount for read-only access. + */ + BOOLEAN readOnly; + + /** + * Time in seconds to wait for the dismount to conclude. + */ + int timeout; + + /** + * The volume identifier of the tape to be mounted. + */ + VOLID volId; + + /** + * The identifier of the drive into which the tape is to be mounted. + */ + DRIVEID driveId; + +}; // class AcsMountCmdLine + +} // namespace rmc +} // namespace tape +} // namespace castor + + +#endif // CASTOR_TAPE_RMC_ACSMOUNTCMDLINE_HPP diff --git a/castor/tape/rmc/AcsMountMain.cpp b/castor/tape/rmc/AcsMountMain.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e3b7d16b887785a081e1daf09ddbed824bd565f4 --- /dev/null +++ b/castor/tape/rmc/AcsMountMain.cpp @@ -0,0 +1,40 @@ +/****************************************************************************** + * castor/tape/rmc/AcsMountMain.cpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "castor/tape/rmc/AcsImpl.hpp" +#include "castor/tape/rmc/AcsMountCmd.hpp" + +#include <iostream> + +//------------------------------------------------------------------------------ +// main +//------------------------------------------------------------------------------ +int main(const int argc, char *const *const argv) { + + castor::tape::rmc::AcsImpl acs; + castor::tape::rmc::AcsMountCmd + cmd(std::cin, std::cout, std::cerr, acs); + + return cmd.main(argc, argv); +} diff --git a/castor/tape/rmc/AcsQueryVolumeCmd.cpp b/castor/tape/rmc/AcsQueryVolumeCmd.cpp new file mode 100644 index 0000000000000000000000000000000000000000..019532e939b904291493fc70e94cbb7b56508ee4 --- /dev/null +++ b/castor/tape/rmc/AcsQueryVolumeCmd.cpp @@ -0,0 +1,352 @@ +/****************************************************************************** + * castor/tape/rmc/AcsQueryVolumeCmd.cpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "castor/tape/rmc/AcsQueryVolumeCmd.hpp" +#include "castor/tape/utils/utils.hpp" + +#include <getopt.h> +#include <iostream> +#include <string.h> + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +castor::tape::rmc::AcsQueryVolumeCmd::AcsQueryVolumeCmd( + std::istream &inStream, std::ostream &outStream, std::ostream &errStream, + Acs &acs) throw(): + AcsCmd(inStream, outStream, errStream, acs), m_defaultQueryInterval(1), + m_defaultTimeout(20) { +} + +//------------------------------------------------------------------------------ +// destructor +//------------------------------------------------------------------------------ +castor::tape::rmc::AcsQueryVolumeCmd::~AcsQueryVolumeCmd() throw() { + // Do nothing +} + +//------------------------------------------------------------------------------ +// main +//------------------------------------------------------------------------------ +int castor::tape::rmc::AcsQueryVolumeCmd::main(const int argc, + char *const *const argv) throw() { + try { + m_cmdLine = parseCmdLine(argc, argv); + } catch(castor::exception::InvalidArgument &ia) { + m_err << "Aborting: Invalid command-line: " << ia.getMessage().str() << + std::endl; + m_err << std::endl; + usage(m_err); + return 1; + } catch(castor::exception::MissingOperand &mo) { + m_err << "Aborting: Missing operand: " << mo.getMessage().str() << + std::endl; + m_err << std::endl; + usage(m_err); + return 1; + } catch(castor::exception::Internal &ie) { + m_err << "Aborting: Internal error: " << ie.getMessage().str() << + std::endl; + return 1; + } + + // Display the usage message to standard out and exit with success if the + // user requested help + if(m_cmdLine.help) { + usage(m_out); + return 0; + } + + // Setup debug mode to be on or off depending on the command-line arguments + m_debugBuf.setDebug(m_cmdLine.debug); + + m_dbg << "query = " << m_cmdLine.queryInterval << std::endl; + m_dbg << "timeout = " << m_cmdLine.timeout << std::endl; + m_dbg << "VID = " << m_cmdLine.volId.external_label << std::endl; + + try { + syncQueryVolume(); + } catch(castor::exception::QueryVolumeFailed &ex) { + m_err << "Aborting: " << ex.getMessage().str() << std::endl; + return 1; + } + + return 0; +} + +//------------------------------------------------------------------------------ +// parseCmdLine +//------------------------------------------------------------------------------ +castor::tape::rmc::AcsQueryVolumeCmdLine + castor::tape::rmc::AcsQueryVolumeCmd::parseCmdLine( + const int argc, char *const *const argv) + throw(castor::exception::Internal, castor::exception::InvalidArgument, + castor::exception::MissingOperand) { + + static struct option longopts[] = { + {"debug", 0, NULL, 'd'}, + {"help" , 0, NULL, 'h'}, + {"query" , required_argument, NULL, 'q'}, + {"timeout" , required_argument, NULL, 't'}, + {NULL, 0, NULL, 0} + }; + AcsQueryVolumeCmdLine 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, ":dhq:t:", longopts, NULL)) != -1) { + + switch (c) { + case 'd': + cmdLine.debug = 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::Internal 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 VID has been specified + if(nbArgs < 1) { + castor::exception::MissingOperand ex; + ex.getMessage() << "VID must be specified"; + throw ex; + } + + // Parse the VID command-line argument + cmdLine.volId = m_acs.str2Volid(argv[optind]); + + return cmdLine; +} + +//------------------------------------------------------------------------------ +// usage +//------------------------------------------------------------------------------ +void castor::tape::rmc::AcsQueryVolumeCmd::usage(std::ostream &os) + const throw() { + os << + "Usage:\n" + " queryvolumeacs [options] VID\n" + "\n" + "Where:\n" + "\n" + " VID The VID of the volume to be queried.\n" + "\n" + "Options:\n" + "\n" + " -d|--debug Turn on the printing of debug information.\n" + " -h|--help Print this help message and exit.\n" + " -q|--query SECONDS Time to wait between queries to ACS for responses.\n" + " SECONDS must be an integer value greater than 0.\n" + " The default value of SECONDS is " + << m_defaultQueryInterval << ".\n" + " -t|--timeout SECONDS Time to wait for the query to conclude. SECONDS\n" + " must be an integer value greater than 0. The\n" + " default value of SECONDS in " + << m_defaultTimeout << ".\n" + "\n" + "Comments to: Castor.Support@cern.ch" << std::endl; +} + +//------------------------------------------------------------------------------ +// syncQueryVolume +//------------------------------------------------------------------------------ +void castor::tape::rmc::AcsQueryVolumeCmd::syncQueryVolume() + throw(castor::exception::QueryVolumeFailed) { + const SEQ_NO requestSeqNumber = 1; + ALIGNED_BYTES buf[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]; + + try { + sendQueryVolumeRequest(requestSeqNumber); + requestResponsesUntilFinal(requestSeqNumber, buf, m_cmdLine.queryInterval, + m_cmdLine.timeout); + processQueryResponse(m_out, buf); + } catch(castor::exception::Exception &ex) { + castor::exception::QueryVolumeFailed qf; + qf.getMessage() << "Failed to query volume " << + m_cmdLine.volId.external_label << ": " << ex.getMessage().str(); + throw qf; + } +} + +//------------------------------------------------------------------------------ +// sendQueryVolumeRequest +//------------------------------------------------------------------------------ +void castor::tape::rmc::AcsQueryVolumeCmd::sendQueryVolumeRequest( + const SEQ_NO seqNumber) throw (castor::exception::QueryVolumeFailed) { + VOLID volIds[MAX_ID]; + + memset(volIds, '\0', sizeof(volIds)); + strncpy(volIds[0].external_label, m_cmdLine.volId.external_label, + sizeof(volIds[0].external_label)); + volIds[0].external_label[sizeof(volIds[0].external_label) - 1] = '\0'; + + m_dbg << "Calling Acs::queryVolume()" << std::endl; + const STATUS s = m_acs.queryVolume(seqNumber, volIds, 1); + m_dbg << "Acs::queryVolume() returned " << acs_status(s) << std::endl; + + if(STATUS_SUCCESS != s) { + castor::exception::QueryVolumeFailed ex; + ex.getMessage() << "Failed to send query request for volume " << + m_cmdLine.volId.external_label << ": " << acs_status(s); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// processQueryResponse +//------------------------------------------------------------------------------ +void castor::tape::rmc::AcsQueryVolumeCmd::processQueryResponse( + std::ostream &os, + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) + throw(castor::exception::QueryVolumeFailed) { + + const ACS_QUERY_VOL_RESPONSE *const msg = (ACS_QUERY_VOL_RESPONSE *)buf; + + if(STATUS_SUCCESS != msg->query_vol_status) { + castor::exception::QueryVolumeFailed ex; + ex.getMessage() << "Status of query response is not success: " << + acs_status(msg->query_vol_status); + throw(ex); + } + + if((unsigned short)1 != msg->count) { + castor::exception::QueryVolumeFailed ex; + ex.getMessage() << "Query response does not contain a single volume: count=" + << msg->count; + throw ex; + } + + // count is 1 so it is safe to make a reference to the single volume status + const QU_VOL_STATUS &volStatus = msg->vol_status[0]; + + if(strcmp(m_cmdLine.volId.external_label, volStatus.vol_id.external_label)) { + castor::exception::QueryVolumeFailed ex; + ex.getMessage() << + "Volume identifier of query response does not match that of request" + ": requestVID=" << m_cmdLine.volId.external_label << + " responseVID=" << volStatus.vol_id.external_label; + throw ex; + } + + writeVolumeStatus(os, volStatus); +} + +//------------------------------------------------------------------------------ +// writeVolumeStatus +//------------------------------------------------------------------------------ +void castor::tape::rmc::AcsQueryVolumeCmd::writeVolumeStatus( + std::ostream &os, const QU_VOL_STATUS &s) throw() { + os << "Volume identifier: " << s.vol_id.external_label << std::endl; + os << "Media type (media_types.dat): " << (int)s.media_type << std::endl; + + switch(s.location_type) { + case LOCATION_CELL: { + os << "Location type: cell" << std::endl; + const CELLID &cellId = s.location.cell_id; + os << "ACS: " << (int)cellId.panel_id.lsm_id.acs << std::endl; + os << "LSM: " << (int)cellId.panel_id.lsm_id.lsm << std::endl; + os << "Panel: " << (int)cellId.panel_id.panel << std::endl; + os << "Row: " << (int)cellId.row << std::endl; + os << "Column: " << (int)cellId.col << std::endl; + break; + } + case LOCATION_DRIVE: { + os << "Location type: drive" << std::endl; + const DRIVEID &driveId = s.location.drive_id; + os << "ACS: " << (int)driveId.panel_id.lsm_id.acs << std::endl; + os << "LSM: " << (int)driveId.panel_id.lsm_id.lsm << std::endl; + os << "Panel: " << (int)driveId.panel_id.panel << std::endl; + os << "Drive: " << (int)driveId.drive << std::endl; + break; + } + default: + os << "Location type: UNKNOWN" << std::endl; + break; + } + + os << "Status: " << acs_status(s.status) << std::endl; +} diff --git a/castor/tape/rmc/AcsQueryVolumeCmd.hpp b/castor/tape/rmc/AcsQueryVolumeCmd.hpp new file mode 100644 index 0000000000000000000000000000000000000000..139650c015a912a18f7dcc18c9bba0ab8eb5f2ac --- /dev/null +++ b/castor/tape/rmc/AcsQueryVolumeCmd.hpp @@ -0,0 +1,159 @@ +/****************************************************************************** + * castor/tape/rmc/AcsQueryVolumeCmd.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#ifndef CASTOR_TAPE_RMC_ACSQUERYVOLUMECMD_HPP +#define CASTOR_TAPE_RMC_ACSQUERYVOLUMECMD_HPP 1 + +#include "castor/exception/Internal.hpp" +#include "castor/exception/InvalidArgument.hpp" +#include "castor/exception/MissingOperand.hpp" +#include "castor/exception/QueryVolumeFailed.hpp" +#include "castor/tape/rmc/AcsCmd.hpp" +#include "castor/tape/rmc/AcsQueryVolumeCmdLine.hpp" + +#include <stdint.h> + +namespace castor { +namespace tape { +namespace rmc { + +/** + * The class implementing the mount command. + */ +class AcsQueryVolumeCmd: public AcsCmd { +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. + */ + AcsQueryVolumeCmd(std::istream &inStream, std::ostream &outStream, + std::ostream &errStream, Acs &acs) throw(); + + /** + * Destructor. + */ + virtual ~AcsQueryVolumeCmd() throw(); + + /** + * The entry function of the command. + * + * @param argc The number of command-line arguments. + * @param argv The command-line arguments. + */ + int main(const int argc, char *const *const argv) throw(); + +protected: + + /** + * 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. + */ + AcsQueryVolumeCmdLine parseCmdLine(const int argc, char *const *const argv) + throw(castor::exception::Internal, castor::exception::InvalidArgument, + castor::exception::MissingOperand); + + /** + * Writes the command-line usage message of to the specified output stream. + * + * @param os Output stream to be written to. + */ + void usage(std::ostream &os) const throw(); + + /** + * Queries ACS for information about the volume identifier specified on the + * command-line. + * + * This method does not return until the information has been successfully + * retrieved, an error has occurred or the specified timeout has been + * reached. + * + * @return The volume status of the volume identifier specified on the + * command-line. + */ + void syncQueryVolume() throw(castor::exception::QueryVolumeFailed); + + /** + * Sends the query volume request to ACSLS. + * + * @param seqNumber The sequence number to be used in the request. + */ + void sendQueryVolumeRequest(const SEQ_NO seqNumber) + throw (castor::exception::QueryVolumeFailed); + + /** + * Extracts the volume status from the specified query-response message and + * writes it in human-readable form to the specified output stream. + * + * @param os The output stream. + * @param buf The query-response message. + */ + void processQueryResponse(std::ostream &os, + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) + throw(castor::exception::QueryVolumeFailed); + + /** + * Writes a human readable representation of the specified volume status to + * the specified output stream. + * + * @param os The output stream. + * @param s The volume status. + */ + void writeVolumeStatus(std::ostream &os, const QU_VOL_STATUS &s) throw(); + +private: + + /** + * The parsed command-line. + * + * The value of this member variable is set within the main() method of this + * class. + */ + AcsQueryVolumeCmdLine m_cmdLine; + + /** + * The default time in seconds to wait between queries to ACS for responses. + */ + const int m_defaultQueryInterval; + + /** + * The default timeout value in seconds for the query to conclude either + * success or failure. + */ + const int m_defaultTimeout; + +}; // class AcsQueryVolumeCmd + +} // namespace rmc +} // namespace tape +} // namespace castor + +#endif // CASTOR_TAPE_RMC_ACSQUERYVOLUMECMD_HPP diff --git a/castor/tape/rmc/AcsQueryVolumeCmdLine.cpp b/castor/tape/rmc/AcsQueryVolumeCmdLine.cpp new file mode 100644 index 0000000000000000000000000000000000000000..870adc3d1fdc5b78ad4c0e0c4d01e8a03c53a79d --- /dev/null +++ b/castor/tape/rmc/AcsQueryVolumeCmdLine.cpp @@ -0,0 +1,37 @@ +/****************************************************************************** + * castor/tape/rmc/AcsQueryVolumeCmdLine.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "castor/tape/rmc/AcsQueryVolumeCmdLine.hpp" + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +castor::tape::rmc::AcsQueryVolumeCmdLine::AcsQueryVolumeCmdLine() + throw(): + debug(FALSE), + help(FALSE), + queryInterval(0), + timeout(0) { + memset(volId.external_label, '\0', sizeof(volId.external_label)); +} diff --git a/castor/tape/rmc/AcsQueryVolumeCmdLine.hpp b/castor/tape/rmc/AcsQueryVolumeCmdLine.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b9bda6e2a570819867d7a73320b5e7984b65157a --- /dev/null +++ b/castor/tape/rmc/AcsQueryVolumeCmdLine.hpp @@ -0,0 +1,83 @@ +/****************************************************************************** + * castor/tape/rmc/AcsQueryVolumeCmdLine.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#ifndef CASTOR_TAPE_RMC_ACSQUERYVOLUMECMDLINE_HPP +#define CASTOR_TAPE_RMC_ACSQUERYVOLUMECMDLINE_HPP 1 + +extern "C" { +#include "acssys.h" +#include "acsapi.h" +} + +#include <string> + +namespace castor { +namespace tape { +namespace rmc { + +/** + * Data type used to store the results of parsing the command-line. + */ +struct AcsQueryVolumeCmdLine { + /** + * Constructor. + * + * Initialises all BOOLEAN member-variables to FALSE, all integer + * member-variables to 0 and the volume identifier to an empty string. + */ + AcsQueryVolumeCmdLine() throw(); + + /** + * True if the debug option has been set. + */ + BOOLEAN debug; + + /** + * True if the help option has been set. + */ + BOOLEAN help; + + /** + * Time in seconds to wait between queries to ACS for responses. + */ + int queryInterval; + + /** + * Time in seconds to wait for the dismount to conclude. + */ + int timeout; + + /** + * The volume identifier of the tape to be mounted. + */ + VOLID volId; + +}; // class AcsQueryVolumeCmdLine + +} // namespace rmc +} // namespace tape +} // namespace castor + + +#endif // CASTOR_TAPE_RMC_ACSQUERYVOLUMECMDLINE_HPP diff --git a/castor/tape/rmc/AcsQueryVolumeMain.cpp b/castor/tape/rmc/AcsQueryVolumeMain.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6cb852a1da5d0d547584408f31ec25af70d6544f --- /dev/null +++ b/castor/tape/rmc/AcsQueryVolumeMain.cpp @@ -0,0 +1,40 @@ +/****************************************************************************** + * castor/tape/rmc/AcsQueryVolumeMain.cpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "castor/tape/rmc/AcsImpl.hpp" +#include "castor/tape/rmc/AcsQueryVolumeCmd.hpp" + +#include <iostream> + +//------------------------------------------------------------------------------ +// main +//------------------------------------------------------------------------------ +int main(const int argc, char *const *const argv) { + + castor::tape::rmc::AcsImpl acs; + castor::tape::rmc::AcsQueryVolumeCmd + cmd(std::cin, std::cout, std::cerr, acs); + + return cmd.main(argc, argv); +} diff --git a/castor/tape/rmc/DebugBuf.cpp b/castor/tape/rmc/DebugBuf.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fdcb37f13dd76fa985249d35eeb179bdc5342907 --- /dev/null +++ b/castor/tape/rmc/DebugBuf.cpp @@ -0,0 +1,75 @@ +/****************************************************************************** + * castor/tape/rmc/DebugBuf.cpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "castor/tape/rmc/DebugBuf.hpp" + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +castor::tape::rmc::DebugBuf::DebugBuf(std::ostream &os): + m_debug(false), m_os(os), m_writePreamble(true) { +} + +//------------------------------------------------------------------------------ +// destructor +//------------------------------------------------------------------------------ +castor::tape::rmc::DebugBuf::~DebugBuf() { +} + +//------------------------------------------------------------------------------ +// setDebug +//------------------------------------------------------------------------------ +void castor::tape::rmc::DebugBuf::setDebug(const bool value) throw() { + m_debug = value; +} + +//------------------------------------------------------------------------------ +// overflow +//------------------------------------------------------------------------------ +std::streambuf::int_type castor::tape::rmc::DebugBuf::overflow( + const int_type c) { + // Only write something if debug mode is on + if(m_debug) { + if(m_writePreamble) { + writePreamble(); + m_writePreamble = false; + } + m_os << (char)c; + } + + // If an end of line was encountered then the next write should be preceeded + // with a preamble + if('\n' == (char)c) { + m_writePreamble = true; + } + + return c; +} + +//------------------------------------------------------------------------------ +// writePreamble +//------------------------------------------------------------------------------ +void castor::tape::rmc::DebugBuf::writePreamble() throw() { + m_os << "DEBUG: "; +} diff --git a/castor/tape/rmc/DebugBuf.hpp b/castor/tape/rmc/DebugBuf.hpp new file mode 100644 index 0000000000000000000000000000000000000000..11a98cb2cf6b313be4157c7589c8449698afc594 --- /dev/null +++ b/castor/tape/rmc/DebugBuf.hpp @@ -0,0 +1,105 @@ +/****************************************************************************** + * castor/tape/rmc/DebugBuf.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#ifndef CASTOR_TAPE_RMC_DEBUGBUF_HPP +#define CASTOR_TAPE_RMC_DEBUGBUF_HPP 1 + +#include <ostream> +#include <streambuf> + +namespace castor { +namespace tape { +namespace rmc { + +/** + * Stream buffer class used to prepend a standard preamble to debug + * message-lines. + * + * This stream buffer does not write any output if debug mode has not been + * turned on by calling setDebugMode(true). Any debug message written to this + * stream buffer will be discarded if debug mode is off. + */ +class DebugBuf : public std::streambuf { +public: + + /** + * Constructor. + * + * Initialises the the debug mode to be off. + * + * @param os The output stream to which each debug message-line togther with + * its standard preamble shall be written. + */ + DebugBuf(std::ostream &os); + + /** + * Destructor. + */ + ~DebugBuf(); + + /** + * Set the debug mode to be on (true) or off (false). + * + * The default set in the constructor is off (false). + */ + void setDebug(const bool value) throw(); + +protected: + + /** + * Sends the specified character to the output channnel. + */ + int_type overflow (const int_type c); + + /** + * Writes the standard preamble to the output stream. + */ + void writePreamble() throw(); + +private: + + /** + * True if debug mode is on. + */ + bool m_debug; + + /** + * The output stream to which each debug message-line togther with its + * standard preamble shall be written. + */ + std::ostream &m_os; + + /** + * True is a preamble should be written. + */ + bool m_writePreamble; + +}; // class DebugBuf + +} // namespace rmc +} // namespace tape +} // namespace castor + + +#endif // CASTOR_TAPE_RMC_DEBUGBUF_HPP diff --git a/castor/tape/rmc/Imakefile b/castor/tape/rmc/Imakefile new file mode 100644 index 0000000000000000000000000000000000000000..cd015165cbcf45115c0849db0dbf4935b2f82ac9 --- /dev/null +++ b/castor/tape/rmc/Imakefile @@ -0,0 +1,100 @@ +COMM +COMM castor/tape/mediachanger/Imakefile +COMM +COMM This file is part of the Castor project. +COMM See http://castor.web.cern.ch/castor +COMM +COMM Copyright (C) 2003 CERN +COMM This program is free software; you can redistribute it and/or +COMM modify it under the terms of the GNU General Public License +COMM as published by the Free Software Foundation; either version 2 +COMM of the License, or (at your option) any later version. +COMM This program is distributed in the hope that it will be useful, +COMM but WITHOUT ANY WARRANTY; without even the implied warranty of +COMM MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +COMM GNU General Public License for more details. +COMM You should have received a copy of the GNU General Public License +COMM along with this program; if not, write to the Free Software +COMM Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +COMM +COMM +COMM @author Steven.Murray@cern.ch +COMM + +COMM For licencing reasons the castor-tape-acs-dismount, castor-tape-acs-mount +COMM and castor-tape-acs-queryvolume commands are not statically linked with +COMM the CDK software provided by Oracle. However if static linking would be +COMM used then the following comments show how it could be done. +COMM +COMM libutl.a and libapi.a are circularly dependent on each other. The +COMM -Wl,--start-group -Wl,--end-group options of gcc are used to encompass a +COMM list of objects that should be passed several times in order to resolve +COMM their interdependencies. +COMM CDKLIB = \ +COMM -Wl,--start-group \ +COMM $(LIBDIR)/CDK/libutl.a \ +COMM $(LIBDIR)/CDK/libapi.a \ +COMM -Wl,--end-group \ +COMM $(LIBDIR)/CDK/libipc.a \ +COMM $(LIBDIR)/CDK/libcl.a + +CDKLIB = -L $(LIBDIR)/CDK -lapi -lutl -lipc -lcl + +DependsOnLibrary(castor/tape/utils,castortapeutils) +DependsOnLibrary(common,castorcommon) + +ACS_SRCS = \ + Acs.cpp \ + AcsImpl.cpp + +COMPILECPP(Acs.cpp, -DLINUX -I/usr/include/CDK) +COMPILECPP(AcsImpl.cpp, -DLINUX -I/usr/include/CDK) + +ACSCOMMAND_SRCS = \ + AcsCmd.cpp \ + DebugBuf.cpp + +COMPILECPP(AcsCmd.cpp, -DLINUX -I/usr/include/CDK) + +ACSMOUNTBIN_SRCS = \ + $(ACS_SRCS) \ + $(ACSCOMMAND_SRCS) \ + AcsMountCmd.cpp \ + AcsMountCmdLine.cpp \ + AcsMountMain.cpp +ACSMOUNTBIN_OBJS = $(ACSMOUNTBIN_SRCS:.cpp=.o) + +COMPILECPP(AcsMountCmd.cpp, -DLINUX -I/usr/include/CDK) +COMPILECPP(AcsMountCmdLine.cpp, -DLINUX -I/usr/include/CDK) +COMPILECPP(AcsMountMain.cpp, -DLINUX -I/usr/include/CDK) + +NormalProgramTarget(castor-tape-acs-mount,$(ACSMOUNTBIN_OBJS),,$(CDKLIB),755) +EXEMANPAGE(castor-tape-acs-mount) + +ACSDISMOUNTBIN_SRCS = \ + $(ACS_SRCS) \ + $(ACSCOMMAND_SRCS) \ + AcsDismountCmd.cpp \ + AcsDismountCmdLine.cpp \ + AcsDismountMain.cpp +ACSDISMOUNTBIN_OBJS = $(ACSDISMOUNTBIN_SRCS:.cpp=.o) +COMPILECPP(AcsDismountCmd.cpp, -DLINUX -I/usr/include/CDK) +COMPILECPP(AcsDismountCmdLine.cpp, -DLINUX -I/usr/include/CDK) +COMPILECPP(AcsDismountMain.cpp, -DLINUX -I/usr/include/CDK) + +NormalProgramTarget(castor-tape-acs-dismount,$(ACSDISMOUNTBIN_OBJS),,$(CDKLIB),755) +EXEMANPAGE(castor-tape-acs-dismount) + +ACSQUERYVOLUMEBIN_SRCS = \ + $(ACS_SRCS) \ + $(ACSCOMMAND_SRCS) \ + AcsQueryVolumeCmd.cpp \ + AcsQueryVolumeCmdLine.cpp \ + AcsQueryVolumeMain.cpp +ACSQUERYVOLUMEBIN_OBJS = $(ACSQUERYVOLUMEBIN_SRCS:.cpp=.o) +COMPILECPP(AcsQueryVolumeCmd.cpp, -DLINUX -I/usr/include/CDK) +COMPILECPP(AcsQueryVolumeCmdLine.cpp, -DLINUX -I/usr/include/CDK) +COMPILECPP(AcsQueryVolumeMain.cpp, -DLINUX -I/usr/include/CDK) + +NormalProgramTarget(castor-tape-acs-queryvolume,$(ACSQUERYVOLUMEBIN_OBJS),,$(CDKLIB),755) +EXEMANPAGE(castor-tape-acs-queryvolume) diff --git a/castor/tape/rmc/castor-tape-acs-dismount.man b/castor/tape/rmc/castor-tape-acs-dismount.man new file mode 100644 index 0000000000000000000000000000000000000000..20b9561e72d3d0c80b63e3e327ebc7dd2baef82e --- /dev/null +++ b/castor/tape/rmc/castor-tape-acs-dismount.man @@ -0,0 +1,54 @@ +.\" 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. +.TH CASTOR-TAPE-ACS-DISMOUNT 1 "$Date: 2009/08/07 15:56:38 $" CASTOR "CASTOR" +.SH NAME +castor-tape-acs-dismount \- dismount a volume +.SH SYNOPSIS +.BI "castor-tape-acs-dismount [options] VID DRIVE" + +.SH DESCRIPTION +.B dismountacs +dismounts the volume with the specfied VID from the drive with the specified +DRIVE ID. The DRIVE ID format is ACS:LSM:panel:transport. + +.SH OPTIONS +.TP +\fB\-d, \-\-debug +Turns on the printing of debug information. +.TP +\fB\-f, \-\-force +Force the dismount. +.TP +\fB\-h, \-\-help +Prints the usage message. +.TP +\fB\-q, \-\-query SECONDS +Time wait between queries to ACLS for responses. +SECONDS must be an integer value greater than 0. +The default value of SECONDS is 10. +.TP +\fB\-t, \-\-timeout SECONDS +Time to wait for the dismount operation to conclude. +SECONDS must be an integer value greater than 0. +The default value of SECONDS is 600. + +.SH "RETURN CODES" +.TP +\fB 0 +Ok. +.TP +\fB 1 +Command failed. + +.SH AUTHOR +\fBCASTOR\fP Team <castor.support@cern.ch> diff --git a/castor/tape/rmc/castor-tape-acs-mount.man b/castor/tape/rmc/castor-tape-acs-mount.man new file mode 100644 index 0000000000000000000000000000000000000000..fd4c0de7b66cfb18b16772488c00b71fea69cf7f --- /dev/null +++ b/castor/tape/rmc/castor-tape-acs-mount.man @@ -0,0 +1,55 @@ +.\" 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. +.TH CASTOR-TAPE-ACS-MOUNT 1 "$Date: 2009/08/07 15:56:38 $" CASTOR "CASTOR" +.SH NAME +castor-tape-acs-mount \- mount a volume +.SH SYNOPSIS +.BI "castor-tape-acs-mount [options] VID DRIVE" + +.SH DESCRIPTION +.B castor-tape-acs-mount +mounts the volume with the specfied VID in an ACS compatible tape-library into +the drive with the specified DRIVE ID. The DRIVE ID format is +ACS:LSM:panel:transport. + +.SH OPTIONS +.TP +\fB\-d, \-\-debug +Turns on the printing of debug information. +.TP +\fB\-h, \-\-help +Prints the usage message. +.TP +\fB\-q, \-\-query SECONDS +Time wait between queries to ACLS for responses. +SECONDS must be an integer value greater than 0. +The default value of SECONDS is 10. +.TP +\fB\-r, \-\-readonly +Request the volume is mounted for read-only access. +.TP +\fB\-t, \-\-timeout SECONDS +Time to wait for the mount operation to conclude. +SECONDS must be an integer value greater than 0. +The default value of SECONDS is 600. + +.SH "RETURN CODES" +.TP +\fB 0 +Ok. +.TP +\fB 1 +Command failed. + +.SH AUTHOR +\fBCASTOR\fP Team <castor.support@cern.ch> diff --git a/castor/tape/rmc/castor-tape-acs-queryvolume.man b/castor/tape/rmc/castor-tape-acs-queryvolume.man new file mode 100644 index 0000000000000000000000000000000000000000..57b35654dcd6deaef62afc7c10063efe76f3d1c5 --- /dev/null +++ b/castor/tape/rmc/castor-tape-acs-queryvolume.man @@ -0,0 +1,50 @@ +.\" 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. +.TH MOUNTACS 1 "$Date: 2009/08/07 15:56:38 $" CASTOR "CASTOR" +.SH NAME +queryvolumeacs \- queries a volume +.SH SYNOPSIS +.BI "queryvolumeacs [options] VID" + +.SH DESCRIPTION +.B queryvolumeacs +quieries ACS for information about the volume with the specfied VID. + +.SH OPTIONS +.TP +\fB\-d, \-\-debug +Turns on the printing of debug information. +.TP +\fB\-h, \-\-help +Prints the usage message. +.TP +\fB\-q, \-\-query SECONDS +Time wait between queries to ACLS for responses. +SECONDS must be an integer value greater than 0. +The default values of SECONDS is 300. +.TP +\fB\-t, \-\-timeout SECONDS +Time to wait for the mount operation to conclude. +SECONDS must be an integer value greater than 0. +The default value of SECONDS is 10. + +.SH "RETURN CODES" +.TP +\fB 0 +Ok. +.TP +\fB 1 +Command failed. + +.SH AUTHOR +\fBCASTOR\fP Team <castor.support@cern.ch> diff --git a/debian/castor-devel.install.perm b/debian/castor-devel.install.perm index f55dfc2e5c2e61408b51662625e999a23d385c73..72148c4ab73139d892b9db0c4d32f5312cc7aedb 100644 --- a/debian/castor-devel.install.perm +++ b/debian/castor-devel.install.perm @@ -54,9 +54,6 @@ %attr(0644,root,root) usr/include/shift/rfio_constants.h %attr(0644,root,root) usr/include/shift/rfio_errno.h %attr(0644,root,root) usr/include/shift/rfio_lcastorfdt.h -%attr(0644,root,root) usr/include/shift/rmc.h -%attr(0644,root,root) usr/include/shift/rmc_api.h -%attr(0644,root,root) usr/include/shift/rmc_constants.h %attr(0644,root,root) usr/include/shift/rtcp.h %attr(0644,root,root) usr/include/shift/rtcp_api.h %attr(0644,root,root) usr/include/shift/rtcp_constants.h @@ -64,7 +61,6 @@ %attr(0644,root,root) usr/include/shift/sacct.h %attr(0644,root,root) usr/include/shift/scsictl.h %attr(0644,root,root) usr/include/shift/serrno.h -%attr(0644,root,root) usr/include/shift/smc.h %attr(0644,root,root) usr/include/shift/stage_api.h %attr(0644,root,root) usr/include/shift/stage_constants.h %attr(0644,root,root) usr/include/shift/stage_limits.h diff --git a/h/Imakefile b/h/Imakefile index dd419c63564bf72aba811d5f50bc5dc142c8482b..b94d030a230587f8f7354f4e62dadc273eb774ad 100644 --- a/h/Imakefile +++ b/h/Imakefile @@ -73,16 +73,12 @@ ClientInstallNonExecFile(rfio.h,$(DESTDIRCASTOR),644) ClientInstallNonExecFile(rfio_api.h,$(DESTDIRCASTOR),644) ClientInstallNonExecFile(rfio_constants.h,$(DESTDIRCASTOR),644) ClientInstallNonExecFile(rfio_errno.h,$(DESTDIRCASTOR),644) -ClientInstallNonExecFile(rmc.h,$(DESTDIRCASTOR),644) -ClientInstallNonExecFile(rmc_api.h,$(DESTDIRCASTOR),644) -ClientInstallNonExecFile(rmc_constants.h,$(DESTDIRCASTOR),644) ClientInstallNonExecFile(rtcp.h,$(DESTDIRCASTOR),644) ClientInstallNonExecFile(rtcp_api.h,$(DESTDIRCASTOR),644) ClientInstallNonExecFile(rtcp_constants.h,$(DESTDIRCASTOR),644) ClientInstallNonExecFile(rtcp_server.h,$(DESTDIRCASTOR),644) ClientInstallNonExecFile(scsictl.h,$(DESTDIRCASTOR),644) ClientInstallNonExecFile(serrno.h,$(DESTDIRCASTOR),644) -ClientInstallNonExecFile(smc.h,$(DESTDIRCASTOR),644) ClientInstallNonExecFile(stage_api.h,$(DESTDIRCASTOR),644) ClientInstallNonExecFile(stage_constants.h,$(DESTDIRCASTOR),644) ClientInstallNonExecFile(stage_limits.h,$(DESTDIRCASTOR),644) diff --git a/h/rmc.h b/h/rmc.h deleted file mode 100644 index a6a7be9fd29db065310b874ff503156cfb48b3ad..0000000000000000000000000000000000000000 --- a/h/rmc.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * $Id: rmc.h,v 1.2 2007/04/19 15:18:19 sponcec3 Exp $ - */ - -/* - * Copyright (C) 2001 by CERN/IT/PDP/DM - * All rights reserved - */ - -/* - */ - -#ifndef _RMC_H -#define _RMC_H - - /* SCSI media changer server constants */ - -#include "osdep.h" -#include "rmc_constants.h" -#include "smc.h" -#define CHECKI 5 /* max interval to check for work to be done */ -#define MAXRETRY 5 -#define RETRYI 60 -#define LOGBUFSZ 1024 -#define PRTBUFSZ 180 -#define REPBUFSZ 524288 /* must be >= max media changer server reply size */ -#define REQBUFSZ 256 /* must be >= max media changer server request size */ -#define RMC_MAGIC 0x120D0301 -#define RMC_TIMEOUT 5 /* netread timeout while receiving a request */ - -int rmclogit(char*, char*, ...); - -#define RETURN(x) \ - { \ - rmclogit (func, "returns %d\n", (x)); \ - return ((x)); \ - } - - /* Request types */ - -#define RMC_GETGEOM 1 /* Get robot geometry */ -#define RMC_FINDCART 2 /* Find cartridge(s) */ -#define RMC_READELEM 3 /* Read element status */ -#define RMC_MOUNT 4 /* Mount request */ -#define RMC_UNMOUNT 5 /* Unmount request */ -#define RMC_EXPORT 6 /* Export tape request */ -#define RMC_IMPORT 7 /* Import tape request */ - - /* SCSI media changer server reply types */ - -#define MSG_ERR 1 -#define MSG_DATA 2 -#define RMC_RC 3 - - /* SCSI media changer server messages */ - -#define RMC00 "RMC00 - SCSI media changer server not available on %s\n" -#define RMC01 "RMC01 - robot parameter is mandatory\n" -#define RMC02 "RMC02 - %s error : %s\n" -#define RMC03 "RMC03 - illegal function %d\n" -#define RMC04 "RMC04 - error getting request, netread = %d\n" -#define RMC05 "RMC05 - cannot allocate enough memory\n" -#define RMC06 "RMC06 - invalid value for %s\n" -#define RMC09 "RMC09 - fatal configuration error: %s %s\n" -#define RMC46 "RMC46 - request too large (max. %d)\n" -#define RMC92 "RMC92 - %s request by %d,%d from %s\n" -#define RMC98 "RMC98 - %s\n" - - /* SCSI media changer server structures */ - -struct extended_robot_info { - int smc_fd; - char smc_ldr[CA_MAXRBTNAMELEN+1]; - int smc_support_voltag; - struct robot_info robot_info; -}; -#endif diff --git a/h/rmc_api.h b/h/rmc_api.h index 489bf1e93bc1aad9e70973fc73fc7cdd4cdef477..462bd1e1f2a9077919d43277dfbfb6ffe894165a 100644 --- a/h/rmc_api.h +++ b/h/rmc_api.h @@ -12,7 +12,8 @@ #ifndef _RMC_API_H #define _RMC_API_H -#include "smc.h" + +#include "h/smc_struct.h" /* function prototypes */ diff --git a/h/rmc_constants.h b/h/rmc_constants.h index 159d807b12308ed60bb6797490640f9e3b9473af..02887bb496fc94e67293d4d1153635543180b8c6 100644 --- a/h/rmc_constants.h +++ b/h/rmc_constants.h @@ -14,6 +14,15 @@ #define _RMC_CONSTANTS_H #include "Castor_limits.h" +#define RMC_CHECKI 5 /* max interval to check for work to be done */ +#define RMC_PRTBUFSZ 180 +#define RMC_REPBUFSZ 524288 /* must be >= max media changer server reply size */ +#define RMC_REQBUFSZ 256 /* must be >= max media changer server request size */ +#define RMC_MAGIC 0x120D0301 +#define RMC_TIMEOUT 5 /* netread timeout while receiving a request */ +#define RMC_RETRYI 60 +#define RMC_LOGBUFSZ 1024 + #define RMC_PORT 5014 /* SCSI media changer utilities exit codes */ @@ -21,4 +30,37 @@ #define USERR 1 /* user error */ #define SYERR 2 /* system error */ #define CONFERR 4 /* configuration error */ + + /* Request types */ + +#define RMC_GETGEOM 1 /* Get robot geometry */ +#define RMC_FINDCART 2 /* Find cartridge(s) */ +#define RMC_READELEM 3 /* Read element status */ +#define RMC_MOUNT 4 /* Mount request */ +#define RMC_UNMOUNT 5 /* Unmount request */ +#define RMC_EXPORT 6 /* Export tape request */ +#define RMC_IMPORT 7 /* Import tape request */ +#define RMC_GENERICMOUNT 8 /* Generic (SCSI or ACS) mount request */ +#define RMC_GENERICUNMOUNT 9 /* Generic (SCSI or ACS) mount request */ + + /* SCSI media changer server reply types */ + +#define MSG_ERR 1 +#define MSG_DATA 2 +#define RMC_RC 3 + + /* SCSI media changer server messages */ + +#define RMC00 "RMC00 - SCSI media changer server not available on %s\n" +#define RMC01 "RMC01 - robot parameter is mandatory\n" +#define RMC02 "RMC02 - %s error : %s\n" +#define RMC03 "RMC03 - illegal function %d\n" +#define RMC04 "RMC04 - error getting request, netread = %d\n" +#define RMC05 "RMC05 - cannot allocate enough memory\n" +#define RMC06 "RMC06 - invalid value for %s\n" +#define RMC09 "RMC09 - fatal configuration error: %s %s\n" +#define RMC46 "RMC46 - request too large (max. %d)\n" +#define RMC92 "RMC92 - %s request by %d,%d from %s\n" +#define RMC98 "RMC98 - %s\n" + #endif diff --git a/h/rmc_logit.h b/h/rmc_logit.h new file mode 100644 index 0000000000000000000000000000000000000000..607abb6ce569c9fc610a0e4fe12f6b37d9a99a73 --- /dev/null +++ b/h/rmc_logit.h @@ -0,0 +1,11 @@ +/* + * Copyright (C) 2001 by CERN/IT/PDP/DM + * All rights reserved + */ + +#ifndef _RMC_LOGIT_H +#define _RMC_LOGIT_H 1 + +int rmc_logit(const char *const func, const char *const msg, ...); + +#endif diff --git a/h/rmc_logreq.h b/h/rmc_logreq.h new file mode 100644 index 0000000000000000000000000000000000000000..aa2437b153406a0fb1aec41fc3a7a0de33c0412d --- /dev/null +++ b/h/rmc_logreq.h @@ -0,0 +1,11 @@ +/* + * Copyright (C) 2001 by CERN/IT/PDP/DM + * All rights reserved + */ + +#ifndef _RMC_LOGREQ_H +#define _RMC_LOGREQ_H 1 + +void rmc_logreq(const char *const func, char *const logbuf); + +#endif diff --git a/h/rmc_marshall_element.h b/h/rmc_marshall_element.h new file mode 100644 index 0000000000000000000000000000000000000000..29c014adde578cdd76def5ae3354ec1a64fdbab6 --- /dev/null +++ b/h/rmc_marshall_element.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2001 by CERN/IT/PDP/DM + * All rights reserved + */ + +#ifndef _RMC_MARSHALL_ELEMENT_H +#define _RMC_MARSHALL_ELEMENT_H 1 + +#include "h/smc_struct.h" + +int rmc_marshall_element (char **const sbpp, const struct smc_element_info *const element_info); + +#endif diff --git a/h/rmc_procreq.h b/h/rmc_procreq.h new file mode 100644 index 0000000000000000000000000000000000000000..00c5e899726e3540e80413eeb8ed07a165e447a1 --- /dev/null +++ b/h/rmc_procreq.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * rmc_procreq.h + * + * 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 + *****************************************************************************/ + +#ifndef _RMC_PROCREQ_H +#define _RMC_PROCREQ_H 1 + +struct rmc_srv_rqst_context { + const char *localhost; + int rpfd; + char *req_data; + const char *clienthost; +}; + +int rmc_srv_export(struct rmc_srv_rqst_context *const rqst_context); +int rmc_srv_findcart(struct rmc_srv_rqst_context *const rqst_context); +int rmc_srv_getgeom(struct rmc_srv_rqst_context *const rqst_context); +int rmc_srv_import(struct rmc_srv_rqst_context *const rqst_context); +int rmc_srv_mount(struct rmc_srv_rqst_context *const rqst_context); +int rmc_srv_readelem(struct rmc_srv_rqst_context *const rqst_context); +int rmc_srv_unmount(struct rmc_srv_rqst_context *const rqst_context); +int rmc_srv_genericmount(struct rmc_srv_rqst_context *const rqst_context); +int rmc_srv_genericunmount(struct rmc_srv_rqst_context *const rqst_context); + +#endif diff --git a/h/rmc_send_scsi_cmd.h b/h/rmc_send_scsi_cmd.h new file mode 100644 index 0000000000000000000000000000000000000000..0112e93985aaef4a77abe8981a37a92334db7b0c --- /dev/null +++ b/h/rmc_send_scsi_cmd.h @@ -0,0 +1,44 @@ +/****************************************************************************** + * rmc_send_scsi_cmd.h + * + * 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 Sebastien Ponce + *****************************************************************************/ + +#ifndef H_RMC_SEND_SCSI_CMD_H +#define H_RMC_SEND_SCSI_CMD_H 1 + +int rmc_send_scsi_cmd ( + const int tapefd, + const char *const path, + const int do_not_open, + const unsigned char *const cdb, + const int cdblen, + unsigned char *const buffer, + const int buflen, + char *const sense, + const int senselen, + const int timeout, /* in milliseconds */ + const int flags, + int *const nb_sense_ret, + char **const msgaddr); + +#endif /* H_RMC_SEND_SCSI_CMD_H */ diff --git a/h/rmc_sendrep.h b/h/rmc_sendrep.h new file mode 100644 index 0000000000000000000000000000000000000000..f8c5b8453dd6539701463a5d6540f4adacfcaa4e --- /dev/null +++ b/h/rmc_sendrep.h @@ -0,0 +1,11 @@ +/* + * Copyright (C) 1998-2002 by CERN/IT/PDP/DM + * All rights reserved + */ + +#ifndef _RMC_SENDREP_H +#define _RMC_SENDREP_H 1 + +int rmc_sendrep(const int rpfd, const int rep_type, ...); + +#endif diff --git a/h/rmc_server_api.h b/h/rmc_server_api.h deleted file mode 100644 index 1366fceb2a7357eb89368e22ae3d890790e7395d..0000000000000000000000000000000000000000 --- a/h/rmc_server_api.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - */ - -#ifndef _RMC_SERVER_API_H -#define _RMC_SERVER_API_H - - /* function prototypes */ - -EXTERN_C int rmc_srv_export (char*, char*); -EXTERN_C int rmc_srv_findcart (char*, char*); -EXTERN_C int rmc_srv_getgeom (char*, char*); -EXTERN_C int rmc_srv_import (char*, char*); -EXTERN_C int rmc_srv_mount (char*, char*); -EXTERN_C int rmc_srv_readelem (char*, char*); -EXTERN_C int rmc_srv_unmount (char*, char*); - -#endif diff --git a/h/rmc_smcsubr.h b/h/rmc_smcsubr.h new file mode 100644 index 0000000000000000000000000000000000000000..a84ef69aaf62665be03659d5cb91258e99edc9fd --- /dev/null +++ b/h/rmc_smcsubr.h @@ -0,0 +1,72 @@ +/****************************************************************************** + * h/rmc_smcsubr.h + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#ifndef H_RMC_SMCSUBR_H +#define H_RMC_SMCSUBR_H 1 + +#include "h/smc_struct.h" + +int smc_get_geometry( + const int fd, + const char *const rbtdev, + struct robot_info *const robot_info); + +int smc_read_elem_status( + const int fd, + const char *const rbtdev, + const int type, + const int start, + const int nbelem, + struct smc_element_info element_info[]); + +int smc_find_cartridge2 ( + const int fd, + const char *const rbtdev, + const char *const template, + const int type, + const int start, + const int nbelem, + struct smc_element_info element_info[]); + +int smc_find_cartridge( + const int fd, + const char *const rbtdev, + const char *const template, + const int type, + const int start, + const int nbelem, + struct smc_element_info element_info[]); + +int smc_lasterror( + struct smc_status *const smc_stat, + char **const msgaddr); + +int smc_move_medium( + const int fd, + const char *const rbtdev, + const int from, + const int to, + const int invert); + +#endif /* H_RMC_SMCSUBR_H */ diff --git a/h/rmc_smcsubr2.h b/h/rmc_smcsubr2.h new file mode 100644 index 0000000000000000000000000000000000000000..448e488ac9258975ed23653e553dcc7812cae7dc --- /dev/null +++ b/h/rmc_smcsubr2.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 1998-2002 by CERN/IT/PDP/DM + * All rights reserved + */ + +#ifndef _RMC_SMCSUBR2_H +#define _RMC_SMCSUBR2_H 1 + +#include "h/smc_struct.h" + +int smc_dismount ( + const int rpfd, + const int fd, + const char *const loader, + struct robot_info *const robot_info, + const int drvord, + const char *const vid); + +int smc_export ( + const int rpfd, + const int fd, + const char *const loader, + struct robot_info *const robot_info, + const char *const vid); + +int smc_import ( + const int rpfd, + const int fd, + const char *const loader, + struct robot_info *const robot_info, + const char *const vid); + +int smc_mount ( + const int rpfd, + const int fd, + const char *const loader, + struct robot_info *const robot_info, + const int drvord, + const char *const vid, + const int invert); + +#endif diff --git a/h/sendscsicmd.h b/h/sendscsicmd.h index cdb05683d80c19ed76f753d524ce6c756859b9df..185f92c2e11d29ad8b6ddbea58da20c0593b7f49 100644 --- a/h/sendscsicmd.h +++ b/h/sendscsicmd.h @@ -26,7 +26,19 @@ #ifndef H_SENDSCSISMD_H #define H_SENDSCSISMD_H 1 -int send_scsi_cmd (int, char *, int, unsigned char *, int, unsigned char *, - int, char *, int, int, int, int *, char **); +int send_scsi_cmd ( + const int tapefd, + const char *const path, + const int do_not_open, + const unsigned char *const cdb, + const int cdblen, + unsigned char *const buffer, + const int buflen, + char *const sense, + const int senselen, + const int timeout, /* in milliseconds */ + const int flags, + int *const nb_sense_ret, + char **const msgaddr); #endif /* H_SENDSCSISMD_H */ diff --git a/h/smc.h b/h/smc.h deleted file mode 100644 index 4b9cdfa766651a2f033cd4377ed66cd5ca57064c..0000000000000000000000000000000000000000 --- a/h/smc.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * $Id: smc.h,v 1.10 2007/03/26 12:15:51 wiebalck Exp $ - */ - -/* - * Copyright (C) 1998-2002 by CERN/IT/PDP/DM - * All rights reserved - */ - -/* - */ - -#ifndef _SMC_H -#define _SMC_H - - /* error messages */ - -#define SR001 "SR001 - drive ordinal must be a non negative integer\n" -#define SR002 "SR002 - option -%c and -%c are mutually exclusive\n" -#define SR003 "SR003 - invalid query type %c\n" -#define SR004 "SR004 - vid %s must be at most 6 characters long\n" -#define SR005 "SR005 - loader must be specified\n" -#define SR006 "SR006 - drive ordinal is mandatory for demount operations\n" -#define SR007 "SR007 - drive ordinal and vid are mandatory for mount operations\n" -#define SR008 "SR008 - invalid device ordinal (must be < %d)\n" -#define SR009 "SR009 - vid mismatch: %s on request, %s on drive\n" -#define SR010 "SR010 - number of elements must be a positive integer\n" -#define SR011 "SR011 - vid is mandatory for export operations\n" -#define SR012 "SR012 - cannot allocate enough memory\n" -#define SR013 "SR013 - export slots are full\n" -#define SR014 "SR014 - slot ordinal must be a non negative integer\n" -#define SR015 "SR015 - storage cells are full\n" -#define SR016 "SR016 - invalid slot address (must be < %d)\n" -#define SR017 "SR017 - %s %s failed : %s\n" -#define SR018 "SR018 - %s of %s on drive %d failed : %s\n" -#define SR019 "SR019 - %s : %s error : %s\n" -#define SR020 "SR020 - %s failed : %s\n" -#define SR021 "SR021 - specify source slot and target slot\n" - - /* smc structures */ - -struct robot_info { - char inquiry[32]; - int transport_start; - int transport_count; - int slot_start; - int slot_count; - int port_start; - int port_count; - int device_start; - int device_count; -}; - -struct smc_element_info { - int element_address; - int element_type; - int state; - unsigned char asc; - unsigned char ascq; - int flags; - int source_address; - char name[9]; -}; - -struct smc_status { - unsigned char asc; - unsigned char ascq; - int save_errno; - int rc; /* return code from send_scsi_cmd */ - unsigned char sensekey; - int skvalid; /* sense key is valid */ -}; - -EXTERN_C int smc_get_geometry (int, char*, struct robot_info*); -EXTERN_C int smc_move_medium (int, char*, int, int, int); -EXTERN_C int smc_lasterror (struct smc_status *, char**); -EXTERN_C int smc_read_elem_status (int, char*, int, int, int, struct smc_element_info[]); -EXTERN_C int smc_find_cartridge (int, char*, char*, int, int, int, struct smc_element_info[]); -EXTERN_C int smc_find_cartridge2 (int, char*, char*, int, int, int, struct smc_element_info[]); - -EXTERN_C int smc_dismount (int, char*, struct robot_info*, int, char*); -EXTERN_C int smc_export (int, char*, struct robot_info*, char*); -EXTERN_C int smc_import (int, char*, struct robot_info*, char*); -EXTERN_C int smc_mount (int, char*, struct robot_info*, int, char*, int); - -#endif diff --git a/h/smc_constants.h b/h/smc_constants.h new file mode 100644 index 0000000000000000000000000000000000000000..e5eb67bef9161b69091dc568c878a8031056589c --- /dev/null +++ b/h/smc_constants.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 1998-2002 by CERN/IT/PDP/DM + * All rights reserved + */ + +#ifndef _SMC_CONSTANT_H +#define _SMC_CONSTANT_H 1 + + /* error messages */ + +#define SR001 "SR001 - drive ordinal must be a non negative integer\n" +#define SR002 "SR002 - option -%c and -%c are mutually exclusive\n" +#define SR003 "SR003 - invalid query type %c\n" +#define SR004 "SR004 - vid %s must be at most 6 characters long\n" +#define SR005 "SR005 - loader must be specified\n" +#define SR006 "SR006 - drive ordinal is mandatory for demount operations\n" +#define SR007 "SR007 - drive ordinal and vid are mandatory for mount operations\n" +#define SR008 "SR008 - invalid device ordinal (must be < %d)\n" +#define SR009 "SR009 - vid mismatch: %s on request, %s on drive\n" +#define SR010 "SR010 - number of elements must be a positive integer\n" +#define SR011 "SR011 - vid is mandatory for export operations\n" +#define SR012 "SR012 - cannot allocate enough memory\n" +#define SR013 "SR013 - export slots are full\n" +#define SR014 "SR014 - slot ordinal must be a non negative integer\n" +#define SR015 "SR015 - storage cells are full\n" +#define SR016 "SR016 - invalid slot address (must be < %d)\n" +#define SR017 "SR017 - %s %s failed : %s\n" +#define SR018 "SR018 - %s of %s on drive %d failed : %s\n" +#define SR019 "SR019 - %s : %s error : %s\n" +#define SR020 "SR020 - %s failed : %s\n" +#define SR021 "SR021 - specify source slot and target slot\n" + +#endif diff --git a/h/smc_struct.h b/h/smc_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..067e7e280a41b30091dd88468e796129f360c29f --- /dev/null +++ b/h/smc_struct.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 1998-2002 by CERN/IT/PDP/DM + * All rights reserved + */ + +#ifndef _SMC_STRUCT_H +#define _SMC_STRUCT_H 1 + +#include "h/Castor_limits.h" + +struct robot_info { + char inquiry[32]; + int transport_start; + int transport_count; + int slot_start; + int slot_count; + int port_start; + int port_count; + int device_start; + int device_count; +}; + +struct extended_robot_info { + int smc_fd; + char smc_ldr[CA_MAXRBTNAMELEN+1]; + int smc_support_voltag; + struct robot_info robot_info; +}; + +struct smc_element_info { + int element_address; + int element_type; + int state; + unsigned char asc; + unsigned char ascq; + int flags; + int source_address; + char name[9]; +}; + +struct smc_status { + unsigned char asc; + unsigned char ascq; + int save_errno; + int rc; /* return code from send_scsi_cmd */ + unsigned char sensekey; + int skvalid; /* sense key is valid */ +}; + +#endif diff --git a/rmc/Imakefile b/rmc/Imakefile index 26150ad14e9ec9faf33a5a838dc585c4efc26bb4..531e86271b0b8adbaa02a97c73840f1e23d01a88 100644 --- a/rmc/Imakefile +++ b/rmc/Imakefile @@ -11,7 +11,15 @@ include $(CASTOR_ROOT)/tape/Makefile RMCD_DEPLIBS = DepSharedLibraryTargetName(tape,castortape) RMCD_LIBS = $(RMCD_DEPLIBS) BuildRPathcastortape -RMCD_OBJS = rmc_serv.o rmc_procreq.o rmclogit.o sendrep.o usrmsg.o smcsubr.o smcsubr2.o +RMCD_OBJS = \ + rmc_serv.o \ + rmc_procreq.o \ + rmc_logit.o \ + rmc_logreq.o \ + rmc_marshall_element.o \ + rmc_sendrep.o \ + rmc_smcsubr.o \ + rmc_send_scsi_cmd.o TapeProgramTarget(rmcd,$(RMCD_OBJS),$(RMCD_DEPLIBS),$(RMCD_LIBS),755) ADMMANPAGE(rmcd) TapeMakeDir($(LOGPATH),0755) diff --git a/rmc/rmc_dismount.c b/rmc/rmc_dismount.c index 13ce8015766651aed0d591bf281383fa4656961e..6b4690177177747d55dc168dd8ca17e30ca156db 100644 --- a/rmc/rmc_dismount.c +++ b/rmc/rmc_dismount.c @@ -9,10 +9,10 @@ #include <sys/types.h> #include <unistd.h> #include <netinet/in.h> -#include "marshall.h" -#include "rmc.h" -#include "rmc_api.h" -#include "serrno.h" +#include "h/marshall.h" +#include "h/rmc_api.h" +#include "h/rmc_constants.h" +#include "h/serrno.h" int rmc_dismount( const char *const server, const char *const vid, @@ -25,7 +25,7 @@ int rmc_dismount( char *q; char repbuf[1]; char *sbp; - char sendbuf[REQBUFSZ]; + char sendbuf[RMC_REQBUFSZ]; uid_t uid; uid = getuid(); @@ -54,6 +54,6 @@ int rmc_dismount( while ((c = send2rmc (server, sendbuf, msglen, repbuf, sizeof(repbuf))) && serrno == ERMCNACT) - sleep (RETRYI); + sleep (RMC_RETRYI); return (c); } diff --git a/rmc/rmc_errmsg.c b/rmc/rmc_errmsg.c index d4f60c56599f8d47c174a846e2fcbc8822b9d06a..9c2342810bf738376b3961fe0a0f6851f59b7e12 100644 --- a/rmc/rmc_errmsg.c +++ b/rmc/rmc_errmsg.c @@ -8,7 +8,8 @@ #include <string.h> #include <stdarg.h> #include <sys/types.h> -#include "rmc.h" + +#include "h/rmc_constants.h" static char *errbufp = NULL; static int errbuflen; @@ -28,7 +29,7 @@ rmc_seterrbuf(char *buffer, int rmc_errmsg(char *func, char *msg, ...) { va_list args; - char prtbuf[PRTBUFSZ]; + char prtbuf[RMC_PRTBUFSZ]; int save_errno; save_errno = errno; diff --git a/rmc/rmc_export.c b/rmc/rmc_export.c index 38914793e10c1d2ead757b6c95f24b7d16314e0d..08bc1ccd03eae32eab5c8e4cdfc48ef761b80961 100644 --- a/rmc/rmc_export.c +++ b/rmc/rmc_export.c @@ -8,10 +8,10 @@ #include <sys/types.h> #include <unistd.h> #include <netinet/in.h> -#include "marshall.h" -#include "rmc.h" -#include "rmc_api.h" -#include "serrno.h" +#include "h/marshall.h" +#include "h/rmc_api.h" +#include "h/rmc_constants.h" +#include "h/serrno.h" int rmc_export(const char *const server, const char *const vid) { int c; @@ -20,7 +20,7 @@ int rmc_export(const char *const server, const char *const vid) char *q; char repbuf[1]; char *sbp; - char sendbuf[REQBUFSZ]; + char sendbuf[RMC_REQBUFSZ]; uid_t uid; uid = getuid(); @@ -47,6 +47,6 @@ int rmc_export(const char *const server, const char *const vid) while ((c = send2rmc (server, sendbuf, msglen, repbuf, sizeof(repbuf))) && serrno == ERMCNACT) - sleep (RETRYI); + sleep (RMC_RETRYI); return (c); } diff --git a/rmc/rmc_find_cartridge.c b/rmc/rmc_find_cartridge.c index 9497a1ac36379f3a4ba45a7995b58242200f58b5..8728ba2f4e1dd0285d06f85beaceb08896ddf12c 100644 --- a/rmc/rmc_find_cartridge.c +++ b/rmc/rmc_find_cartridge.c @@ -9,10 +9,10 @@ #include <sys/types.h> #include <unistd.h> #include <netinet/in.h> -#include "marshall.h" -#include "rmc.h" -#include "rmc_api.h" -#include "serrno.h" +#include "h/marshall.h" +#include "h/rmc_api.h" +#include "h/rmc_constants.h" +#include "h/serrno.h" int rmc_find_cartridge( const char *const server, const char *const pattern, @@ -28,9 +28,9 @@ int rmc_find_cartridge( int msglen; char *q; char *rbp; - char repbuf[REPBUFSZ]; + char repbuf[RMC_REPBUFSZ]; char *sbp; - char sendbuf[REQBUFSZ]; + char sendbuf[RMC_REQBUFSZ]; uid_t uid; uid = getuid(); @@ -60,7 +60,7 @@ int rmc_find_cartridge( while ((c = send2rmc (server, sendbuf, msglen, repbuf, sizeof(repbuf))) && serrno == ERMCNACT) - sleep (RETRYI); + sleep (RMC_RETRYI); if (c == 0) { rbp = repbuf; unmarshall_LONG (rbp, c); diff --git a/rmc/rmc_get_geometry.c b/rmc/rmc_get_geometry.c index cbf23df57920dbcd927127c5b61814b3448045c3..16f7e42f5c57ed7f94ae8636bcd92aac904593e4 100644 --- a/rmc/rmc_get_geometry.c +++ b/rmc/rmc_get_geometry.c @@ -9,10 +9,10 @@ #include <sys/types.h> #include <unistd.h> #include <netinet/in.h> -#include "marshall.h" -#include "rmc.h" -#include "rmc_api.h" -#include "serrno.h" +#include "h/marshall.h" +#include "h/rmc_api.h" +#include "h/rmc_constants.h" +#include "h/serrno.h" int rmc_get_geometry( const char *const server, struct robot_info *const robot_info) @@ -24,7 +24,7 @@ int rmc_get_geometry( char *rbp; char repbuf[64]; char *sbp; - char sendbuf[REQBUFSZ]; + char sendbuf[RMC_REQBUFSZ]; uid_t uid; uid = getuid(); @@ -50,7 +50,7 @@ int rmc_get_geometry( while ((c = send2rmc (server, sendbuf, msglen, repbuf, sizeof(repbuf))) && serrno == ERMCNACT) - sleep (RETRYI); + sleep (RMC_RETRYI); if (c == 0) { rbp = repbuf; unmarshall_STRING (rbp, robot_info->inquiry); diff --git a/rmc/rmc_import.c b/rmc/rmc_import.c index c198b2868ae50516273c8f292bb0c55dde07e8f8..bc0d20e3ab2ba984a4ad2c6f65f004105d86d379 100644 --- a/rmc/rmc_import.c +++ b/rmc/rmc_import.c @@ -9,10 +9,10 @@ #include <sys/types.h> #include <unistd.h> #include <netinet/in.h> -#include "marshall.h" -#include "rmc.h" -#include "rmc_api.h" -#include "serrno.h" +#include "h/marshall.h" +#include "h/rmc_api.h" +#include "h/rmc_constants.h" +#include "h/serrno.h" int rmc_import(const char *const server, const char *const vid) { int c; @@ -21,7 +21,7 @@ int rmc_import(const char *const server, const char *const vid) char *q; char repbuf[1]; char *sbp; - char sendbuf[REQBUFSZ]; + char sendbuf[RMC_REQBUFSZ]; uid_t uid; uid = getuid(); @@ -48,6 +48,6 @@ int rmc_import(const char *const server, const char *const vid) while ((c = send2rmc (server, sendbuf, msglen, repbuf, sizeof(repbuf))) && serrno == ERMCNACT) - sleep (RETRYI); + sleep (RMC_RETRYI); return (c); } diff --git a/rmc/rmclogit.c b/rmc/rmc_logit.c similarity index 85% rename from rmc/rmclogit.c rename to rmc/rmc_logit.c index dd93368c7fdb1a9beff550822eb90ab384c10481..76054ebbaa593bccc74ec6c1c7a20277fa2c92bd 100644 --- a/rmc/rmclogit.c +++ b/rmc/rmc_logit.c @@ -11,13 +11,14 @@ #include <time.h> #include <stdarg.h> #include <unistd.h> -#include "rmc.h" +#include "h/rmc_constants.h" +#include "h/rmc_logit.h" extern int jid; -int rmclogit(char *func, char *msg, ...) +int rmc_logit(const char *const func, const char *const msg, ...) { va_list args; - char prtbuf[PRTBUFSZ]; + char prtbuf[RMC_PRTBUFSZ]; int save_errno; struct tm *tm; time_t current_time; diff --git a/rmc/rmc_logreq.c b/rmc/rmc_logreq.c new file mode 100644 index 0000000000000000000000000000000000000000..6ee62b40d8f1afff89a104c86586be7bbfb17894 --- /dev/null +++ b/rmc/rmc_logreq.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2001-2002 by CERN/IT/PDP/DM + * All rights reserved + */ + +#include "h/rmc_constants.h" +#include "h/rmc_logit.h" +#include "h/rmc_logreq.h" +#include "h/tplogger_api.h" + +#include <string.h> + +/* rmc_logreq - log a request */ + +/* Split the message into lines so they don't exceed LOGBUFSZ-1 characters + * A backslash is appended to a line to be continued + * A continuation line is prefixed by '+ ' + */ +void rmc_logreq(const char *const func, char *const logbuf) { + int n1, n2; + char *p; + char savechrs1[2]; + char savechrs2[2]; + + n1 = RMC_LOGBUFSZ - strlen (func) - 36; + n2 = strlen (logbuf); + p = logbuf; + while (n2 > n1) { + savechrs1[0] = *(p + n1); + savechrs1[1] = *(p + n1 + 1); + *(p + n1) = '\\'; + *(p + n1 + 1) = '\0'; + rmc_logit (func, RMC98, p); + tl_rmcdaemon.tl_log( &tl_rmcdaemon, 98, 2, + "func" , TL_MSG_PARAM_STR, "rmc_logreq", + "Request", TL_MSG_PARAM_STR, p ); + if (p != logbuf) { + *p = savechrs2[0]; + *(p + 1) = savechrs2[1]; + } + p += n1 - 2; + savechrs2[0] = *p; + savechrs2[1] = *(p + 1); + *p = '+'; + *(p + 1) = ' '; + *(p + 2) = savechrs1[0]; + *(p + 3) = savechrs1[1]; + n2 -= n1; + } + rmc_logit (func, RMC98, p); + tl_rmcdaemon.tl_log( &tl_rmcdaemon, 98, 2, + "func" , TL_MSG_PARAM_STR, "rmc_logreq", + "Request", TL_MSG_PARAM_STR, p ); + if (p != logbuf) { + *p = savechrs2[0]; + *(p + 1) = savechrs2[1]; + } +} diff --git a/rmc/rmc_marshall_element.c b/rmc/rmc_marshall_element.c new file mode 100644 index 0000000000000000000000000000000000000000..f1607fcce2debc6e1546e534c2b5e011ffe04757 --- /dev/null +++ b/rmc/rmc_marshall_element.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2001-2002 by CERN/IT/PDP/DM + * All rights reserved + */ + +#include "h/marshall.h" +#include "h/rmc_marshall_element.h" + +int rmc_marshall_element ( + char **const sbpp, + const struct smc_element_info *const element_info) +{ + char *sbp = *sbpp; + + marshall_WORD (sbp, element_info->element_address); + marshall_BYTE (sbp, element_info->element_type); + marshall_BYTE (sbp, element_info->state); + marshall_BYTE (sbp, element_info->asc); + marshall_BYTE (sbp, element_info->ascq); + marshall_BYTE (sbp, element_info->flags); + marshall_WORD (sbp, element_info->source_address); + marshall_STRING (sbp, element_info->name); + *sbpp = sbp; + return (0); +} diff --git a/rmc/rmc_mount.c b/rmc/rmc_mount.c index f1dd077aac53725769ad4f5dde93cef4a31fadaa..aa72260c325419e5dac143eca669ec7383e84b87 100644 --- a/rmc/rmc_mount.c +++ b/rmc/rmc_mount.c @@ -9,10 +9,10 @@ #include <sys/types.h> #include <unistd.h> #include <netinet/in.h> -#include "marshall.h" -#include "rmc.h" -#include "rmc_api.h" -#include "serrno.h" +#include "h/marshall.h" +#include "h/rmc_api.h" +#include "h/rmc_constants.h" +#include "h/serrno.h" int rmc_mount( const char *const server, const char *const vid, @@ -25,7 +25,7 @@ int rmc_mount( char *q; char repbuf[1]; char *sbp; - char sendbuf[REQBUFSZ]; + char sendbuf[RMC_REQBUFSZ]; uid_t uid; uid = getuid(); @@ -54,6 +54,6 @@ int rmc_mount( while ((c = send2rmc (server, sendbuf, msglen, repbuf, sizeof(repbuf))) && serrno == ERMCNACT) - sleep (RETRYI); + sleep (RMC_RETRYI); return (c); } diff --git a/rmc/rmc_procreq.c b/rmc/rmc_procreq.c index 4cda2a7acb644fb10865988725868ec70e13f00e..5390ea0483832690247d6197cd0d830847818fa2 100644 --- a/rmc/rmc_procreq.c +++ b/rmc/rmc_procreq.c @@ -12,91 +12,25 @@ #include <time.h> #include <sys/types.h> #include <netinet/in.h> -#include "Cupv_api.h" -#include "marshall.h" -#include "rmc.h" -#include "serrno.h" -#include "tplogger_api.h" +#include "h/Cupv_api.h" +#include "h/marshall.h" +#include "h/serrno.h" +#include "h/rmc_constants.h" +#include "h/rmc_logit.h" +#include "h/rmc_logreq.h" +#include "h/rmc_marshall_element.h" +#include "h/rmc_procreq.h" +#include "h/rmc_smcsubr.h" +#include "h/rmc_smcsubr2.h" +#include "h/rmc_sendrep.h" +#include "h/tplogger_api.h" #include <string.h> #include <Ctape_api.h> -extern int being_shutdown; extern struct extended_robot_info extended_robot_info; -extern char localhost[CA_MAXHOSTNAMELEN+1]; -extern int rpfd; -void procreq(int, char*, char*); -/* rmc_logreq - log a request */ - -/* Split the message into lines so they don't exceed LOGBUFSZ-1 characters - * A backslash is appended to a line to be continued - * A continuation line is prefixed by '+ ' - */ -void -rmc_logreq(char *func, - char *logbuf) -{ - int n1, n2; - char *p; - char savechrs1[2]; - char savechrs2[2]; - - n1 = LOGBUFSZ - strlen (func) - 36; - n2 = strlen (logbuf); - p = logbuf; - while (n2 > n1) { - savechrs1[0] = *(p + n1); - savechrs1[1] = *(p + n1 + 1); - *(p + n1) = '\\'; - *(p + n1 + 1) = '\0'; - rmclogit (func, RMC98, p); - tl_rmcdaemon.tl_log( &tl_rmcdaemon, 98, 2, - "func" , TL_MSG_PARAM_STR, "rmc_logreq", - "Request", TL_MSG_PARAM_STR, p ); - if (p != logbuf) { - *p = savechrs2[0]; - *(p + 1) = savechrs2[1]; - } - p += n1 - 2; - savechrs2[0] = *p; - savechrs2[1] = *(p + 1); - *p = '+'; - *(p + 1) = ' '; - *(p + 2) = savechrs1[0]; - *(p + 3) = savechrs1[1]; - n2 -= n1; - } - rmclogit (func, RMC98, p); - tl_rmcdaemon.tl_log( &tl_rmcdaemon, 98, 2, - "func" , TL_MSG_PARAM_STR, "rmc_logreq", - "Request", TL_MSG_PARAM_STR, p ); - if (p != logbuf) { - *p = savechrs2[0]; - *(p + 1) = savechrs2[1]; - } -} - -int marshall_ELEMENT (char **sbpp, - struct smc_element_info *element_info) -{ - char *sbp = *sbpp; - - marshall_WORD (sbp, element_info->element_address); - marshall_BYTE (sbp, element_info->element_type); - marshall_BYTE (sbp, element_info->state); - marshall_BYTE (sbp, element_info->asc); - marshall_BYTE (sbp, element_info->ascq); - marshall_BYTE (sbp, element_info->flags); - marshall_WORD (sbp, element_info->source_address); - marshall_STRING (sbp, element_info->name); - *sbpp = sbp; - return (0); -} - /* rmc_srv_export - export/eject a cartridge from the robot */ -int rmc_srv_export(char *req_data, - char *clienthost) -{ +int rmc_srv_export(struct rmc_srv_rqst_context *const rqst_context) { int c; char func[16]; gid_t gid; @@ -106,46 +40,51 @@ int rmc_srv_export(char *req_data, char vid[CA_MAXVIDLEN+1]; strncpy (func, "rmc_srv_export", 16); - rbp = req_data; + rbp = rqst_context->req_data; unmarshall_LONG (rbp, uid); unmarshall_LONG (rbp, gid); - rmclogit (func, RMC92, "export", uid, gid, clienthost); + rmc_logit (func, RMC92, "export", uid, gid, rqst_context->clienthost); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 92, 5, - "func" , TL_MSG_PARAM_STR, "rmc_srv_export", - "Type" , TL_MSG_PARAM_STR, "export", - "UID" , TL_MSG_PARAM_UID, uid, - "GID" , TL_MSG_PARAM_GID, gid, - "ClientHost", TL_MSG_PARAM_STR, clienthost ); + "func" , TL_MSG_PARAM_STR, "rmc_srv_export", + "Type" , TL_MSG_PARAM_STR, "export", + "UID" , TL_MSG_PARAM_UID, uid, + "GID" , TL_MSG_PARAM_GID, gid, + "ClientHost", TL_MSG_PARAM_STR, rqst_context->clienthost ); /* Unmarshall and ignore the loader field as it is no longer used */ { char smc_ldr[CA_MAXRBTNAMELEN+1]; if (unmarshall_STRINGN (rbp, smc_ldr, CA_MAXRBTNAMELEN+1)) { - sendrep (rpfd, MSG_ERR, RMC06, "loader"); - RETURN (ERMCUNREC); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC06, + "loader"); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } } if (unmarshall_STRINGN (rbp, vid, CA_MAXVIDLEN+1)) { - sendrep (rpfd, MSG_ERR, RMC06, "vid"); - RETURN (ERMCUNREC); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC06, "vid"); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } snprintf (logbuf, CA_MAXVIDLEN+8, "export %s", vid); rmc_logreq (func, logbuf); - if (Cupv_check (uid, gid, clienthost, localhost, P_TAPE_OPERATOR)) { - sendrep (rpfd, MSG_ERR, "%s\n", sstrerror(serrno)); - RETURN (ERMCUNREC); + if (Cupv_check (uid, gid, rqst_context->clienthost, + rqst_context->localhost, P_TAPE_OPERATOR)) { + rmc_sendrep (rqst_context->rpfd, MSG_ERR, "%s\n", + sstrerror(serrno)); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } - c = smc_export (extended_robot_info.smc_fd, extended_robot_info.smc_ldr, - &extended_robot_info.robot_info, vid); + c = smc_export (rqst_context->rpfd, extended_robot_info.smc_fd, + extended_robot_info.smc_ldr, &extended_robot_info.robot_info, vid); if (c) c += ERMCRBTERR; - RETURN (c); + rmc_logit (func, "returns %d\n", c); + return c; } /* rmc_srv_findcart - find cartridge(s) */ -int rmc_srv_findcart(char *req_data, - char *clienthost) -{ +int rmc_srv_findcart(struct rmc_srv_rqst_context *const rqst_context) { int c; struct smc_element_info *element_info; struct smc_element_info *elemp; @@ -165,27 +104,31 @@ int rmc_srv_findcart(char *req_data, uid_t uid; strncpy (func, "rmc_srv_findcart", 17); - rbp = req_data; + rbp = rqst_context->req_data; unmarshall_LONG (rbp, uid); unmarshall_LONG (rbp, gid); - rmclogit (func, RMC92, "findcart", uid, gid, clienthost); + rmc_logit (func, RMC92, "findcart", uid, gid, rqst_context->clienthost); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 92, 5, - "func" , TL_MSG_PARAM_STR, "rmc_srv_findcart", - "Type" , TL_MSG_PARAM_STR, "findcart", - "UID" , TL_MSG_PARAM_UID, uid, - "GID" , TL_MSG_PARAM_GID, gid, - "ClientHost", TL_MSG_PARAM_STR, clienthost ); + "func" , TL_MSG_PARAM_STR, "rmc_srv_findcart", + "Type" , TL_MSG_PARAM_STR, "findcart", + "UID" , TL_MSG_PARAM_UID, uid, + "GID" , TL_MSG_PARAM_GID, gid, + "ClientHost", TL_MSG_PARAM_STR, + rqst_context->clienthost); /* Unmarshall and ignore the loader fiel as it is no longer used */ { char smc_ldr[CA_MAXRBTNAMELEN+1]; if (unmarshall_STRINGN (rbp, smc_ldr, CA_MAXRBTNAMELEN+1)) { - sendrep (rpfd, MSG_ERR, RMC06, "loader"); - RETURN (ERMCUNREC); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC06, + "loader"); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } } if (unmarshall_STRINGN (rbp, template, 40)) { - sendrep (rpfd, MSG_ERR, RMC06, "template"); - RETURN (ERMCUNREC); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC06, "template"); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } unmarshall_LONG (rbp, type); unmarshall_LONG (rbp, startaddr); @@ -194,12 +137,14 @@ int rmc_srv_findcart(char *req_data, rmc_logreq (func, logbuf); if (nbelem < 1) { - sendrep (rpfd, MSG_ERR, RMC06, "nbelem"); - RETURN (ERMCUNREC); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC06, "nbelem"); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } if ((element_info = malloc (nbelem * sizeof(struct smc_element_info))) == NULL) { - sendrep (rpfd, MSG_ERR, RMC05); - RETURN (ERMCUNREC); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC05); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } if (extended_robot_info.smc_support_voltag) c = smc_find_cartridge (extended_robot_info.smc_fd, @@ -212,30 +157,32 @@ int rmc_srv_findcart(char *req_data, if (c < 0) { c = smc_lasterror (&smc_status, &msgaddr); free (element_info); - sendrep (rpfd, MSG_ERR, RMC02, "smc_find_cartridge", msgaddr); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC02, + "smc_find_cartridge", msgaddr); c += ERMCRBTERR; - RETURN (c); + rmc_logit (func, "returns %d\n", c); + return c; } if ((repbuf = malloc (c * 18 + 4)) == NULL) { - sendrep (rpfd, MSG_ERR, RMC05); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC05); free (element_info); - RETURN (ERMCUNREC); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } sbp = repbuf; marshall_LONG (sbp, c); for (i = 0, elemp = element_info; i < c; i++, elemp++) - marshall_ELEMENT (&sbp, elemp); + rmc_marshall_element (&sbp, elemp); free (element_info); - sendrep (rpfd, MSG_DATA, sbp - repbuf, repbuf); + rmc_sendrep (rqst_context->rpfd, MSG_DATA, sbp - repbuf, repbuf); free (repbuf); - RETURN (0); + rmc_logit (func, "returns %d\n", 0); + return 0; } /* rmc_srv_getgeom - get the robot geometry */ -int rmc_srv_getgeom(char *req_data, - char *clienthost) -{ +int rmc_srv_getgeom(struct rmc_srv_rqst_context *const rqst_context) { char func[16]; gid_t gid; char logbuf[8]; @@ -245,22 +192,24 @@ int rmc_srv_getgeom(char *req_data, uid_t uid; strncpy (func, "rmc_srv_getgeom", 16); - rbp = req_data; + rbp = rqst_context->req_data; unmarshall_LONG (rbp, uid); unmarshall_LONG (rbp, gid); - rmclogit (func, RMC92, "getgeom", uid, gid, clienthost); + rmc_logit (func, RMC92, "getgeom", uid, gid, rqst_context->clienthost); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 92, 5, - "func" , TL_MSG_PARAM_STR, "rmc_srv_getgeom", - "Type" , TL_MSG_PARAM_STR, "getgeom", - "UID" , TL_MSG_PARAM_UID, uid, - "GID" , TL_MSG_PARAM_GID, gid, - "ClientHost", TL_MSG_PARAM_STR, clienthost ); + "func" , TL_MSG_PARAM_STR, "rmc_srv_getgeom", + "Type" , TL_MSG_PARAM_STR, "getgeom", + "UID" , TL_MSG_PARAM_UID, uid, + "GID" , TL_MSG_PARAM_GID, gid, + "ClientHost", TL_MSG_PARAM_STR, rqst_context->clienthost ); /* Unmarshall and ignore the loader field as it is no longer used */ { char smc_ldr[CA_MAXRBTNAMELEN+1]; if (unmarshall_STRINGN (rbp, smc_ldr, CA_MAXRBTNAMELEN+1)) { - sendrep (rpfd, MSG_ERR, RMC06, "loader"); - RETURN (ERMCUNREC); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC06, + "loader"); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } } snprintf (logbuf, 8, "getgeom"); @@ -276,15 +225,14 @@ int rmc_srv_getgeom(char *req_data, marshall_LONG (sbp, extended_robot_info.robot_info.port_count); marshall_LONG (sbp, extended_robot_info.robot_info.device_start); marshall_LONG (sbp, extended_robot_info.robot_info.device_count); - sendrep (rpfd, MSG_DATA, sbp - repbuf, repbuf); - RETURN (0); + rmc_sendrep (rqst_context->rpfd, MSG_DATA, sbp - repbuf, repbuf); + rmc_logit (func, "returns %d\n", 0); + return 0; } /* rmc_srv_import - import/inject a cartridge into the robot */ -int rmc_srv_import(char *req_data, - char *clienthost) -{ +int rmc_srv_import(struct rmc_srv_rqst_context *const rqst_context) { int c; char func[16]; gid_t gid; @@ -294,46 +242,51 @@ int rmc_srv_import(char *req_data, char vid[CA_MAXVIDLEN+1]; strncpy (func, "rmc_srv_import", 16); - rbp = req_data; + rbp = rqst_context->req_data; unmarshall_LONG (rbp, uid); unmarshall_LONG (rbp, gid); - rmclogit (func, RMC92, "import", uid, gid, clienthost); + rmc_logit (func, RMC92, "import", uid, gid, rqst_context->clienthost); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 92, 5, - "func" , TL_MSG_PARAM_STR, "rmc_srv_import", - "Type" , TL_MSG_PARAM_STR, "import", - "UID" , TL_MSG_PARAM_UID, uid, - "GID" , TL_MSG_PARAM_GID, gid, - "ClientHost", TL_MSG_PARAM_STR, clienthost ); + "func" , TL_MSG_PARAM_STR, "rmc_srv_import", + "Type" , TL_MSG_PARAM_STR, "import", + "UID" , TL_MSG_PARAM_UID, uid, + "GID" , TL_MSG_PARAM_GID, gid, + "ClientHost", TL_MSG_PARAM_STR, rqst_context->clienthost ); /* Unmarshall and ignore the loader field as it is no longer used */ { char smc_ldr[CA_MAXRBTNAMELEN+1]; if (unmarshall_STRINGN (rbp, smc_ldr, CA_MAXRBTNAMELEN+1)) { - sendrep (rpfd, MSG_ERR, RMC06, "loader"); - RETURN (ERMCUNREC); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC06, + "loader"); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } } if (unmarshall_STRINGN (rbp, vid, CA_MAXVIDLEN+1)) { - sendrep (rpfd, MSG_ERR, RMC06, "vid"); - RETURN (ERMCUNREC); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC06, "vid"); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } snprintf (logbuf, CA_MAXVIDLEN+8, "import %s", vid); rmc_logreq (func, logbuf); - if (Cupv_check (uid, gid, clienthost, localhost, P_TAPE_OPERATOR)) { - sendrep (rpfd, MSG_ERR, "%s\n", sstrerror(serrno)); - RETURN (ERMCUNREC); + if (Cupv_check (uid, gid, rqst_context->clienthost, + rqst_context->localhost, P_TAPE_OPERATOR)) { + rmc_sendrep (rqst_context->rpfd, MSG_ERR, "%s\n", + sstrerror(serrno)); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } - c = smc_import (extended_robot_info.smc_fd, extended_robot_info.smc_ldr, - &extended_robot_info.robot_info, vid); + c = smc_import (rqst_context->rpfd, extended_robot_info.smc_fd, + extended_robot_info.smc_ldr, &extended_robot_info.robot_info, vid); if (c) c += ERMCRBTERR; - RETURN (c); + rmc_logit (func, "returns %d\n", c); + return c; } /* rmc_srv_mount - mount a cartridge on a drive */ -int rmc_srv_mount(char *req_data, - char *clienthost) -{ +int rmc_srv_mount(struct rmc_srv_rqst_context *const rqst_context) { int c; int drvord; char func[16]; @@ -345,48 +298,54 @@ int rmc_srv_mount(char *req_data, char vid[CA_MAXVIDLEN+1]; strncpy (func, "rmc_srv_mount", 16); - rbp = req_data; + rbp = rqst_context->req_data; unmarshall_LONG (rbp, uid); unmarshall_LONG (rbp, gid); - rmclogit (func, RMC92, "mount", uid, gid, clienthost); + rmc_logit (func, RMC92, "mount", uid, gid, rqst_context->clienthost); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 92, 5, - "func" , TL_MSG_PARAM_STR, "rmc_srv_mount", - "Type" , TL_MSG_PARAM_STR, "mount", - "UID" , TL_MSG_PARAM_UID, uid, - "GID" , TL_MSG_PARAM_GID, gid, - "ClientHost", TL_MSG_PARAM_STR, clienthost ); + "func" , TL_MSG_PARAM_STR, "rmc_srv_mount", + "Type" , TL_MSG_PARAM_STR, "mount", + "UID" , TL_MSG_PARAM_UID, uid, + "GID" , TL_MSG_PARAM_GID, gid, + "ClientHost", TL_MSG_PARAM_STR, rqst_context->clienthost ); /* Unmarshall and ignore the loader field as it is no longer used */ { char smc_ldr[CA_MAXRBTNAMELEN+1]; if (unmarshall_STRINGN (rbp, smc_ldr, CA_MAXRBTNAMELEN+1)) { - sendrep (rpfd, MSG_ERR, RMC06, "loader"); - RETURN (ERMCUNREC); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC06, + "loader"); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } } if (unmarshall_STRINGN (rbp, vid, CA_MAXVIDLEN+1)) { - sendrep (rpfd, MSG_ERR, RMC06, "vid"); - RETURN (ERMCUNREC); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC06, "vid"); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } unmarshall_WORD (rbp, invert); unmarshall_WORD (rbp, drvord); snprintf (logbuf, CA_MAXVIDLEN+64, "mount %s/%d on drive %d", vid, invert, drvord); rmc_logreq (func, logbuf); - if (Cupv_check (uid, gid, clienthost, localhost, P_TAPE_SYSTEM)) { - sendrep (rpfd, MSG_ERR, "%s\n", sstrerror(serrno)); - RETURN (ERMCUNREC); + if (Cupv_check (uid, gid, rqst_context->clienthost, + rqst_context->localhost, P_TAPE_SYSTEM)) { + rmc_sendrep (rqst_context->rpfd, MSG_ERR, "%s\n", + sstrerror(serrno)); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } - c = smc_mount (extended_robot_info.smc_fd, extended_robot_info.smc_ldr, - &extended_robot_info.robot_info, drvord, vid, invert); + c = smc_mount (rqst_context->rpfd, extended_robot_info.smc_fd, + extended_robot_info.smc_ldr, &extended_robot_info.robot_info, drvord, + vid, invert); if (c) c += ERMCRBTERR; - RETURN (c); + rmc_logit (func, "returns %d\n", c); + return c; } /* rmc_srv_readelem - read element status */ -int rmc_srv_readelem(char *req_data, - char *clienthost) -{ +int rmc_srv_readelem(struct rmc_srv_rqst_context *const rqst_context) { int c; struct smc_element_info *element_info; struct smc_element_info *elemp; @@ -405,22 +364,24 @@ int rmc_srv_readelem(char *req_data, uid_t uid; strncpy (func, "rmc_srv_readelem", 17); - rbp = req_data; + rbp = rqst_context->req_data; unmarshall_LONG (rbp, uid); unmarshall_LONG (rbp, gid); - rmclogit (func, RMC92, "readelem", uid, gid, clienthost); + rmc_logit (func, RMC92, "readelem", uid, gid, rqst_context->clienthost); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 92, 5, - "func" , TL_MSG_PARAM_STR, "rmc_srv_readelem", - "Type" , TL_MSG_PARAM_STR, "readelem", - "UID" , TL_MSG_PARAM_UID, uid, - "GID" , TL_MSG_PARAM_GID, gid, - "ClientHost", TL_MSG_PARAM_STR, clienthost ); + "func" , TL_MSG_PARAM_STR, "rmc_srv_readelem", + "Type" , TL_MSG_PARAM_STR, "readelem", + "UID" , TL_MSG_PARAM_UID, uid, + "GID" , TL_MSG_PARAM_GID, gid, + "ClientHost", TL_MSG_PARAM_STR, rqst_context->clienthost ); /* Unmarshall and ignore the loader field as it is no longer used */ { char smc_ldr[CA_MAXRBTNAMELEN+1]; if (unmarshall_STRINGN (rbp, smc_ldr, CA_MAXRBTNAMELEN+1)) { - sendrep (rpfd, MSG_ERR, RMC06, "loader"); - RETURN (ERMCUNREC); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC06, + "loader"); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } } unmarshall_LONG (rbp, type); @@ -430,46 +391,51 @@ int rmc_srv_readelem(char *req_data, rmc_logreq (func, logbuf); if (type < 0 || type > 4) { - sendrep (rpfd, MSG_ERR, RMC06, "type"); - RETURN (ERMCUNREC); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC06, "type"); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } if (nbelem < 1) { - sendrep (rpfd, MSG_ERR, RMC06, "nbelem"); - RETURN (ERMCUNREC); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC06, "nbelem"); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } if ((element_info = malloc (nbelem * sizeof(struct smc_element_info))) == NULL) { - sendrep (rpfd, MSG_ERR, RMC05); - RETURN (ERMCUNREC); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC05); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } if ((c = smc_read_elem_status (extended_robot_info.smc_fd, extended_robot_info.smc_ldr, type, startaddr, nbelem, element_info)) < 0) { c = smc_lasterror (&smc_status, &msgaddr); free (element_info); - sendrep (rpfd, MSG_ERR, RMC02, "smc_read_elem_status", msgaddr); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC02, + "smc_read_elem_status", msgaddr); c += ERMCRBTERR; - RETURN (c); + rmc_logit (func, "returns %d\n", c); + return c; } if ((repbuf = malloc (c * 18 + 4)) == NULL) { - sendrep (rpfd, MSG_ERR, RMC05); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC05); free (element_info); - RETURN (ERMCUNREC); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } sbp = repbuf; marshall_LONG (sbp, c); for (i = 0, elemp = element_info; i < c; i++, elemp++) - marshall_ELEMENT (&sbp, elemp); + rmc_marshall_element (&sbp, elemp); free (element_info); - sendrep (rpfd, MSG_DATA, sbp - repbuf, repbuf); + rmc_sendrep (rqst_context->rpfd, MSG_DATA, sbp - repbuf, repbuf); free (repbuf); - RETURN (0); + rmc_logit (func, "returns %d\n", 0); + return 0; } /* rmc_srv_unmount - dismount a cartridge from a drive */ -int rmc_srv_unmount(char *req_data, - char *clienthost) -{ +int rmc_srv_unmount(struct rmc_srv_rqst_context *const rqst_context) { int c; int drvord; int force; @@ -481,39 +447,55 @@ int rmc_srv_unmount(char *req_data, char vid[CA_MAXVIDLEN+1]; strncpy (func, "rmc_srv_unmount", 16); - rbp = req_data; + rbp = rqst_context->req_data; unmarshall_LONG (rbp, uid); unmarshall_LONG (rbp, gid); - rmclogit (func, RMC92, "unmount", uid, gid, clienthost); + rmc_logit (func, RMC92, "unmount", uid, gid, rqst_context->clienthost); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 92, 5, - "func" , TL_MSG_PARAM_STR, "rmc_srv_unmount", - "Type" , TL_MSG_PARAM_STR, "unmount", - "UID" , TL_MSG_PARAM_UID, uid, - "GID" , TL_MSG_PARAM_GID, gid, - "ClientHost", TL_MSG_PARAM_STR, clienthost ); + "func" , TL_MSG_PARAM_STR, "rmc_srv_unmount", + "Type" , TL_MSG_PARAM_STR, "unmount", + "UID" , TL_MSG_PARAM_UID, uid, + "GID" , TL_MSG_PARAM_GID, gid, + "ClientHost", TL_MSG_PARAM_STR, rqst_context->clienthost ); /* Unmarshall and ignore the loader field as it is no longer used */ { char smc_ldr[CA_MAXRBTNAMELEN+1]; if (unmarshall_STRINGN (rbp, smc_ldr, CA_MAXRBTNAMELEN+1)) { - sendrep (rpfd, MSG_ERR, RMC06, "loader"); - RETURN (ERMCUNREC); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC06, + "loader"); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } } if (unmarshall_STRINGN (rbp, vid, CA_MAXVIDLEN+1)) { - sendrep (rpfd, MSG_ERR, RMC06, "vid"); - RETURN (ERMCUNREC); + rmc_sendrep (rqst_context->rpfd, MSG_ERR, RMC06, "vid"); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } unmarshall_WORD (rbp, drvord); unmarshall_WORD (rbp, force); snprintf (logbuf, CA_MAXVIDLEN+64, "unmount %s %d %d", vid, drvord, force); rmc_logreq (func, logbuf); - if (Cupv_check (uid, gid, clienthost, localhost, P_TAPE_SYSTEM)) { - sendrep (rpfd, MSG_ERR, "%s\n", sstrerror(serrno)); - RETURN (ERMCUNREC); + if (Cupv_check (uid, gid, rqst_context->clienthost, + rqst_context->localhost, P_TAPE_SYSTEM)) { + rmc_sendrep (rqst_context->rpfd, MSG_ERR, "%s\n", + sstrerror(serrno)); + rmc_logit (func, "returns %d\n", ERMCUNREC); + return ERMCUNREC; } - c = smc_dismount (extended_robot_info.smc_fd, extended_robot_info.smc_ldr, - &extended_robot_info.robot_info, drvord, force == 0 ? vid : ""); + c = smc_dismount (rqst_context->rpfd, extended_robot_info.smc_fd, + extended_robot_info.smc_ldr, &extended_robot_info.robot_info, drvord, + force == 0 ? vid : ""); if (c) c += ERMCRBTERR; - RETURN (c); + rmc_logit (func, "returns %d\n", c); + return c; +} + +int rmc_srv_genericmount(struct rmc_srv_rqst_context *const rqst_context) { + return 0; +} + +int rmc_srv_genericunmount(struct rmc_srv_rqst_context *const rqst_context) { + return 0; } diff --git a/rmc/rmc_read_elem_status.c b/rmc/rmc_read_elem_status.c index b8c92ef609e05ac985ecd312417b91d60b0f9966..551c256b827ba9b1edf7457ce1da495ae05bf0eb 100644 --- a/rmc/rmc_read_elem_status.c +++ b/rmc/rmc_read_elem_status.c @@ -9,10 +9,10 @@ #include <sys/types.h> #include <unistd.h> #include <netinet/in.h> -#include "marshall.h" -#include "rmc.h" -#include "rmc_api.h" -#include "serrno.h" +#include "h/marshall.h" +#include "h/rmc_api.h" +#include "h/rmc_constants.h" +#include "h/serrno.h" int rmc_read_elem_status( const char *const server, const int type, @@ -27,9 +27,9 @@ int rmc_read_elem_status( int msglen; char *q; char *rbp; - char repbuf[REPBUFSZ]; + char repbuf[RMC_REPBUFSZ]; char *sbp; - char sendbuf[REQBUFSZ]; + char sendbuf[RMC_REQBUFSZ]; uid_t uid; uid = getuid(); @@ -58,7 +58,7 @@ int rmc_read_elem_status( while ((c = send2rmc (server, sendbuf, msglen, repbuf, sizeof(repbuf))) && serrno == ERMCNACT) - sleep (RETRYI); + sleep (RMC_RETRYI); if (c == 0) { rbp = repbuf; unmarshall_LONG (rbp, c); diff --git a/rmc/rmc_send_scsi_cmd.c b/rmc/rmc_send_scsi_cmd.c new file mode 100644 index 0000000000000000000000000000000000000000..3fd4163043da0b127fd99d227318b4f225eccbb3 --- /dev/null +++ b/rmc/rmc_send_scsi_cmd.c @@ -0,0 +1,299 @@ +/* + * Copyright (C) 1996-2000 by CERN/IT/PDP/DM + * All rights reserved + */ + +/* rmc_send_scsi_cmd - Send a SCSI command to a device */ +/* return -5 if not supported on this platform (serrno = SEOPNOTSUP) + * -4 if SCSI error (serrno = EIO) + * -3 if CAM error (serrno = EIO) + * -2 if ioctl fails with errno (serrno = errno) + * -1 if open/stat fails with errno (message fully formatted) + * 0 if successful with no data transfer + * >0 number of bytes transferred + */ + +#include <unistd.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdlib.h> +#include <dirent.h> +#include <sys/stat.h> +#include <linux/version.h> +#include <sys/param.h> +/* Impossible unless very very old kernels: */ +#ifndef KERNEL_VERSION +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif +#include "/usr/include/scsi/sg.h" +#include <sys/stat.h> +#include "h/scsictl.h" +#include "h/serrno.h" +#include "h/rmc_send_scsi_cmd.h" +static char rmc_err_msgbuf[132]; +static char *sk_msg[] = { + "No sense", + "Recovered error", + "Not ready", + "Medium error", + "Hardware error", + "Illegal request", + "Unit attention", + "Data protect", + "Blank check", + "Vendor unique", + "Copy aborted", + "Aborted command", + "Equal", + "Volume overflow", + "Miscompare", + "Reserved", +}; + +static void find_sgpath(char *const sgpath, const int maj, const int min) { + + /* + Find the sg device for a pair of major and minor device IDs + of a tape device. The match is done by + + . identifying the tape's st device node + . getting the device's unique ID from sysfs + . searching the sg device with the same ID (in sysfs) + + If no match is found, the returned sg path will be an empty + string. + */ + + char systape[] = "/sys/class/scsi_tape"; + char sysgen[] = "/sys/class/scsi_generic"; + char syspath[256]; + + char tlink[256]; + char glink[256]; + + int match = 0; + DIR *dir_tape, *dir_gen; + struct dirent *dirent; + char st_dev[64]; + + struct stat sbuf; + + sgpath[0] = '\0'; + + /* find the st sysfs entry */ + if (!(dir_tape = opendir(systape))) return; + while ((dirent = readdir(dir_tape))) { + + if (0 == strcmp(".", dirent->d_name)) continue; + if (0 == strcmp("..", dirent->d_name)) continue; + + sprintf(st_dev, "/dev/%s", dirent->d_name); + stat(st_dev, &sbuf); + if (maj == (int)major(sbuf.st_rdev) && min == (int)minor(sbuf.st_rdev)) { + sprintf(syspath, "%s/%s/device", systape, dirent->d_name); + match = 1; + break; + } + } + closedir(dir_tape); + + if (0 == match) return; + + memset(tlink, 0, 256); + readlink(syspath, tlink, 256); + + /* find the corresponding sg sysfs entry */ + if (!(dir_gen = opendir(sysgen))) return; + while ((dirent = readdir(dir_gen))) { + + if (0 == strcmp(".", dirent->d_name)) continue; + if (0 == strcmp("..", dirent->d_name)) continue; + + sprintf(syspath, "%s/%s/device", sysgen, dirent->d_name); + + memset(glink, 0, 256); + readlink(syspath, glink, 256); + + if (0 == strcmp(glink, tlink)) { + sprintf(sgpath, "/dev/%s", dirent->d_name); + goto out; + } + } + out: + closedir(dir_gen); + return; +} + + +int rmc_send_scsi_cmd ( + const int tapefd, + const char *const path, + const int do_not_open, + const unsigned char *const cdb, + const int cdblen, + unsigned char *const buffer, + const int buflen, + char *const sense, + const int senselen, + const int timeout, /* in milliseconds */ + const int flags, + int *const nb_sense_ret, + char **const msgaddr) +{ + int fd; + FILE *fopen(); + int n; + int resid = 0; + struct stat sbuf; + struct stat sbufa; + static char *sg_buffer; + static int sg_bufsiz = 0; + struct sg_header *sg_hd; + char sgpath[80]; + int timeout_in_jiffies = 0; + int sg_big_buff_val = SG_BIG_BUFF; + int procfd, nbread; + char procbuf[80]; + + (void)senselen; + /* First the value in /proc of the max buffer size for the sg driver */ + procfd = open("/proc/scsi/sg/def_reserved_size", O_RDONLY); + if (procfd >= 0) { + memset(procbuf, 0, sizeof(procbuf)); + nbread = read(procfd, procbuf, sizeof(procbuf) - 1); + if (nbread > 0) { + long int tmp; + char *endptr = NULL; + tmp = strtol(procbuf, &endptr, 10); + if (endptr == NULL || *endptr == '\n') { + sg_big_buff_val = (int) tmp; + } + } + close(procfd); + } + + if ((int)sizeof(struct sg_header) + cdblen + buflen > sg_big_buff_val) { + sprintf (rmc_err_msgbuf, "blocksize too large (max %zd)\n", + sg_big_buff_val - sizeof(struct sg_header) - cdblen); + *msgaddr = rmc_err_msgbuf; + serrno = EINVAL; + return (-1); + } + if ((int)sizeof(struct sg_header)+cdblen+buflen > sg_bufsiz) { + if (sg_bufsiz > 0) free (sg_buffer); + if ((sg_buffer = malloc (sizeof(struct sg_header)+cdblen+buflen)) == NULL) { + serrno = errno; + sprintf (rmc_err_msgbuf, "cannot get memory"); + *msgaddr = rmc_err_msgbuf; + return (-1); + } + sg_bufsiz = sizeof(struct sg_header) + cdblen + buflen; + } + if (do_not_open) { + fd = tapefd; + strcpy (sgpath, path); + } else { + if (stat (path, &sbuf) < 0) { + serrno = errno; + snprintf (rmc_err_msgbuf, sizeof(rmc_err_msgbuf), "%s : stat error : %s\n", path, strerror(errno)); + rmc_err_msgbuf[sizeof(rmc_err_msgbuf) - 1] = '\0'; + *msgaddr = rmc_err_msgbuf; + return (-1); + } + + /* get the major device ID of the sg devices ... */ + if (stat ("/dev/sg0", &sbufa) < 0) { + serrno = errno; + snprintf (rmc_err_msgbuf, sizeof(rmc_err_msgbuf), "/dev/sg0 : stat error : %s\n", strerror(errno)); + rmc_err_msgbuf[sizeof(rmc_err_msgbuf) - 1] = '\0'; + *msgaddr = rmc_err_msgbuf; + return (-1); + } + /* ... to detect links and use the path directly! */ + if (major(sbuf.st_rdev) == major(sbufa.st_rdev)) { + strcpy (sgpath, path); + } else { + find_sgpath(sgpath, major(sbuf.st_rdev), minor(sbuf.st_rdev)); + } + + if ((fd = open (sgpath, O_RDWR)) < 0) { + serrno = errno; + snprintf (rmc_err_msgbuf, sizeof(rmc_err_msgbuf), "%s : open error : %s\n", sgpath, strerror(errno)); + rmc_err_msgbuf[sizeof(rmc_err_msgbuf) - 1] = '\0'; + *msgaddr = rmc_err_msgbuf; + return (-1); + } + } + + /* set the sg timeout (in jiffies) */ + timeout_in_jiffies = timeout * HZ / 1000; + ioctl (fd, SG_SET_TIMEOUT, &timeout_in_jiffies); + + memset (sg_buffer, 0, sizeof(struct sg_header)); + sg_hd = (struct sg_header *) sg_buffer; + sg_hd->reply_len = sizeof(struct sg_header) + ((flags & SCSI_IN) ? buflen : 0); + sg_hd->twelve_byte = cdblen == 12; + memcpy (sg_buffer+sizeof(struct sg_header), cdb, cdblen); + n = sizeof(struct sg_header) + cdblen; + if (buflen && (flags & SCSI_OUT)) { + memcpy (sg_buffer+n, buffer, buflen); + n+= buflen; + } + if (write (fd, sg_buffer, n) < 0) { + *msgaddr = (char *) strerror(errno); + serrno = errno; + snprintf (rmc_err_msgbuf, sizeof(rmc_err_msgbuf), "%s : write error : %s\n", sgpath, *msgaddr); + rmc_err_msgbuf[sizeof(rmc_err_msgbuf) - 1] = '\0'; + *msgaddr = rmc_err_msgbuf; + if (! do_not_open) close (fd); + return (-2); + } + if ((n = read (fd, sg_buffer, sizeof(struct sg_header) + + ((flags & SCSI_IN) ? buflen : 0))) < 0) { + *msgaddr = (char *) strerror(errno); + serrno = errno; + snprintf (rmc_err_msgbuf, sizeof(rmc_err_msgbuf), "%s : read error : %s\n", sgpath, *msgaddr); + rmc_err_msgbuf[sizeof(rmc_err_msgbuf) - 1] = '\0'; + *msgaddr = rmc_err_msgbuf; + if (! do_not_open) close (fd); + return (-2); + } + if (! do_not_open) close (fd); + if (sg_hd->sense_buffer[0]) { + memcpy (sense, sg_hd->sense_buffer, sizeof(sg_hd->sense_buffer)); + *nb_sense_ret = sizeof(sg_hd->sense_buffer); + } + if (sg_hd->sense_buffer[0] & 0x80) { /* valid */ + resid = sg_hd->sense_buffer[3] << 24 | sg_hd->sense_buffer[4] << 16 | + sg_hd->sense_buffer[5] << 8 | sg_hd->sense_buffer[6]; + } + if ((sg_hd->sense_buffer[0] & 0x70) && + ((sg_hd->sense_buffer[2] & 0xE0) == 0 || + (sg_hd->sense_buffer[2] & 0xF) != 0)) { + char tmp_msgbuf[132]; + snprintf (tmp_msgbuf, sizeof(tmp_msgbuf), "%s ASC=%X ASCQ=%X", + sk_msg[*(sense+2) & 0xF], *(sense+12), *(sense+13)); + tmp_msgbuf[sizeof(tmp_msgbuf) - 1] = '\0'; + serrno = EIO; + snprintf (rmc_err_msgbuf, sizeof(rmc_err_msgbuf), "%s : scsi error : %s\n", sgpath, tmp_msgbuf); + rmc_err_msgbuf[sizeof(rmc_err_msgbuf) - 1] = '\0'; + *msgaddr = rmc_err_msgbuf; + return (-4); + } else if (sg_hd->result) { + *msgaddr = (char *) strerror(sg_hd->result); + serrno = sg_hd->result; + snprintf (rmc_err_msgbuf, sizeof(rmc_err_msgbuf), "%s : read error : %s\n", sgpath, *msgaddr); + rmc_err_msgbuf[sizeof(rmc_err_msgbuf) - 1] = '\0'; + *msgaddr = rmc_err_msgbuf; + return (-2); + } + if (n) + n -= sizeof(struct sg_header) + resid; + if (n && (flags & SCSI_IN)) + memcpy (buffer, sg_buffer+sizeof(struct sg_header), n); + return ((flags & SCSI_IN) ? n : buflen - resid); +} diff --git a/rmc/sendrep.c b/rmc/rmc_sendrep.c similarity index 78% rename from rmc/sendrep.c rename to rmc/rmc_sendrep.c index 1cf84fa5b96cfc13747c0dbb64fe4c650a707b0d..eefee63be6fbeaa655565ed985c1dcd17fa6eee3 100644 --- a/rmc/sendrep.c +++ b/rmc/rmc_sendrep.c @@ -9,25 +9,28 @@ #include <string.h> #include <stdarg.h> #include <stdio.h> -#include "marshall.h" -#include "net.h" -#include "rmc.h" -#include "tplogger_api.h" +#include "h/marshall.h" +#include "h/net.h" +#include "h/rmc_constants.h" +#include "h/rmc_logit.h" +#include "h/rmc_sendrep.h" +#include "h/tplogger_api.h" #include <unistd.h> -int sendrep(int rpfd, int rep_type, ...) +int rmc_sendrep(const int rpfd, const int rep_type, ...) { va_list args; char func[16]; char *msg; int n; - char prtbuf[PRTBUFSZ]; + char prtbuf[RMC_PRTBUFSZ]; char *rbp; int rc; - char repbuf[REPBUFSZ]; + char repbuf[RMC_REPBUFSZ]; int repsize; - strncpy (func, "sendrep", 16); + strncpy (func, "rmc_sendrep", sizeof(func)); + func[sizeof(func) - 1] = '\0'; rbp = repbuf; marshall_LONG (rbp, RMC_MAGIC); va_start (args, rep_type); @@ -38,7 +41,7 @@ int sendrep(int rpfd, int rep_type, ...) vsprintf (prtbuf, msg, args); marshall_LONG (rbp, strlen (prtbuf) + 1); marshall_STRING (rbp, prtbuf); - rmclogit (func, "%s", prtbuf); + rmc_logit (func, "%s", prtbuf); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 103, 2, "func" , TL_MSG_PARAM_STR, func, "Message", TL_MSG_PARAM_STR, prtbuf ); @@ -58,7 +61,7 @@ int sendrep(int rpfd, int rep_type, ...) va_end (args); repsize = rbp - repbuf; if (netwrite (rpfd, repbuf, repsize) != repsize) { - rmclogit (func, RMC02, "send", neterror()); + rmc_logit (func, RMC02, "send", neterror()); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 2, 3, "func" , TL_MSG_PARAM_STR, func, "On" , TL_MSG_PARAM_STR, "send", diff --git a/rmc/rmc_serv.c b/rmc/rmc_serv.c index fef906b2bf86d9e4e1715eae56a7f41da6700506..d2cff293f36ea496490cf038509bc44af59be0b1 100644 --- a/rmc/rmc_serv.c +++ b/rmc/rmc_serv.c @@ -17,37 +17,39 @@ #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> -#include "Cinit.h" -#include "marshall.h" -#include "net.h" -#include "rmc.h" -#include "scsictl.h" -#include "serrno.h" -#include "rmc_server_api.h" -#include "Cdomainname.h" -#include "tplogger_api.h" +#include "h/Cinit.h" +#include "h/marshall.h" +#include "h/net.h" +#include "h/rmc_constants.h" +#include "h/rmc_logit.h" +#include "h/rmc_procreq.h" +#include "h/rmc_sendrep.h" +#include "h/rmc_smcsubr.h" +#include "h/scsictl.h" +#include "h/serrno.h" +#include "h/Cdomainname.h" +#include "h/tplogger_api.h" #include <sys/types.h> #include <sys/stat.h> #include <Ctape_api.h> -#include "sendscsicmd.h" +#include "h/sendscsicmd.h" /* Forward declaration */ -int getreq(int, int*, char*, char**); -void procreq(int, char*, char*); +static int getreq(const int s, int *const req_type, char *const req_data, + char **const clienthost); +static void procreq(const int rpfd, const int req_type, char *const req_data, + char *const clienthost); +static void rmc_doit(const int rpfd); -int being_shutdown; -char func[16]; int jid; char localhost[CA_MAXHOSTNAMELEN+1]; int maxfds; struct extended_robot_info extended_robot_info; -int rpfd; int rmc_main(struct main_args *main_args) { int c; unsigned char cdb[12]; - void doit(int); char domainname[CA_MAXHOSTNAMELEN+1]; struct sockaddr_in from; socklen_t fromlen = sizeof(from); @@ -55,11 +57,9 @@ int rmc_main(struct main_args *main_args) char *msgaddr; int nb_sense_ret; int on = 1; /* for REUSEADDR */ - char *p; char plist[40]; fd_set readfd, readmask; char *robot; - int rqfd; int s; int n=0; char sense[MAXSENSE]; @@ -67,22 +67,14 @@ int rmc_main(struct main_args *main_args) struct smc_status smc_status; struct servent *sp; struct timeval timeval; + char func[16]; + + strncpy (func, "rmc_serv", sizeof(func)); + func[sizeof(func) - 1] = '\0'; /* init the tplogger interface */ { - mode_t save_mask; - /* char *p; */ - - save_mask = umask(0); - - /* - p = getconfent ("TAPE", "TPLOGGER", 0); - if (p && (0 == strcasecmp(p, "SYSLOG"))) { - tl_init_handle( &tl_rtcpd, "syslog" ); - } else { - tl_init_handle( &tl_rmc, "dlf" ); - } - */ + const mode_t save_mask = umask(0); /* only syslog support */ tl_init_handle( &tl_rmcdaemon, "syslog" ); @@ -95,8 +87,7 @@ int rmc_main(struct main_args *main_args) } jid = getpid(); - strncpy (func, "rmc_serv", 16); - rmclogit (func, "started\n"); + rmc_logit (func, "started\n"); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 109, 2, "func" , TL_MSG_PARAM_STR, "rmc_main", "Message", TL_MSG_PARAM_STR, "Daemon started" ); @@ -104,7 +95,7 @@ int rmc_main(struct main_args *main_args) gethostname (localhost, CA_MAXHOSTNAMELEN+1); if (strchr (localhost, '.') == NULL) { if (Cdomainname (domainname, sizeof(domainname)) < 0) { - rmclogit (func, "Unable to get domainname\n"); + rmc_logit (func, "Unable to get domainname\n"); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 103, 2, "func" , TL_MSG_PARAM_STR, "rmc_main", "Message", TL_MSG_PARAM_STR, "Unable to get domainname" ); @@ -114,7 +105,7 @@ int rmc_main(struct main_args *main_args) } if (main_args->argc != 2) { - rmclogit (func, RMC01); + rmc_logit (func, RMC01); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 1, 1, "func", TL_MSG_PARAM_STR, "rmc_main" ); exit (USERR); @@ -122,7 +113,7 @@ int rmc_main(struct main_args *main_args) robot = main_args->argv[1]; if (*robot == '\0' || (strlen (robot) + (*robot == '/') ? 0 : 5) > CA_MAXRBTNAMELEN) { - rmclogit (func, RMC06, "robot"); + rmc_logit (func, RMC06, "robot"); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 6, 2, "func", TL_MSG_PARAM_STR, "rmc_main", "For" , TL_MSG_PARAM_STR, "robot" ); @@ -142,20 +133,20 @@ int rmc_main(struct main_args *main_args) extended_robot_info.smc_ldr, &extended_robot_info.robot_info))) { c = smc_lasterror (&smc_status, &msgaddr); - rmclogit (func, RMC02, "get_geometry", msgaddr); + rmc_logit (func, RMC02, "get_geometry", msgaddr); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 2, 4, "func" , TL_MSG_PARAM_STR, "rmc_main", "On" , TL_MSG_PARAM_STR, "get_geometry", "Message" , TL_MSG_PARAM_STR, msgaddr, "NextStep", TL_MSG_PARAM_STR, "Retry" ); - rmclogit (func,"trying again get_geometry\n"); + rmc_logit (func,"trying again get_geometry\n"); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 110, 2, "func" , TL_MSG_PARAM_STR, "rmc_main", "Message", TL_MSG_PARAM_STR, "trying again get_geometry" ); n++; if (n==2) { - rmclogit (func, RMC02, "get_geometry", msgaddr); + rmc_logit (func, RMC02, "get_geometry", msgaddr); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 2, 4, "func" , TL_MSG_PARAM_STR, "rmc_main", "On" , TL_MSG_PARAM_STR, "get_geometry", @@ -185,7 +176,7 @@ int rmc_main(struct main_args *main_args) sense[12] == 0x20) { extended_robot_info.smc_support_voltag = 0; } else { - rmclogit (func, RMC02, "find_cartridge", msgaddr); + rmc_logit (func, RMC02, "find_cartridge", msgaddr); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 2, 4, "func" , TL_MSG_PARAM_STR, "rmc_main", "On" , TL_MSG_PARAM_STR, "find_cartridge", @@ -202,7 +193,7 @@ int rmc_main(struct main_args *main_args) /* open request socket */ if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0) { - rmclogit (func, RMC02, "socket", neterror()); + rmc_logit (func, RMC02, "socket", neterror()); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 2, 4, "func" , TL_MSG_PARAM_STR, "rmc_main", "On" , TL_MSG_PARAM_STR, "socket", @@ -212,23 +203,26 @@ int rmc_main(struct main_args *main_args) } memset ((char *)&sin, 0, sizeof(struct sockaddr_in)) ; sin.sin_family = AF_INET ; - if ((p = getenv ("RMC_PORT")) || (p = getconfent ("RMC", "PORT", 0))) { - sin.sin_port = htons ((unsigned short)atoi (p)); - } else if ((sp = getservbyname ("rmc", "tcp"))) { - sin.sin_port = sp->s_port; - } else { - sin.sin_port = htons ((unsigned short)RMC_PORT); + { + const char *p; + if ((p = getenv ("RMC_PORT")) || (p = getconfent ("RMC", "PORT", 0))) { + sin.sin_port = htons ((unsigned short)atoi (p)); + } else if ((sp = getservbyname ("rmc", "tcp"))) { + sin.sin_port = sp->s_port; + } else { + sin.sin_port = htons ((unsigned short)RMC_PORT); + } } sin.sin_addr.s_addr = htonl(INADDR_ANY); if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) { - rmclogit (func, RMC02, "setsockopt", neterror()); + rmc_logit (func, RMC02, "setsockopt", neterror()); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 2, 3, "func" , TL_MSG_PARAM_STR, "rmc_main", "On" , TL_MSG_PARAM_STR, "setsockopt", "Message" , TL_MSG_PARAM_STR, msgaddr ); } if (bind (s, (struct sockaddr *) &sin, sizeof(sin)) < 0) { - rmclogit (func, RMC02, "bind", neterror()); + rmc_logit (func, RMC02, "bind", neterror()); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 2, 4, "func" , TL_MSG_PARAM_STR, "rmc_main", "On" , TL_MSG_PARAM_STR, "bind", @@ -245,12 +239,12 @@ int rmc_main(struct main_args *main_args) while (1) { if (FD_ISSET (s, &readfd)) { FD_CLR (s, &readfd); - rqfd = accept (s, (struct sockaddr *) &from, &fromlen); - rpfd = rqfd; - (void) doit (rqfd); + const int rpfd = + accept (s, (struct sockaddr *) &from, &fromlen); + (void) rmc_doit (rpfd); } memcpy (&readfd, &readmask, sizeof(readmask)); - timeval.tv_sec = CHECKI; + timeval.tv_sec = RMC_CHECKI; timeval.tv_usec = 0; if (select (maxfds, &readfd, (fd_set *)0, (fd_set *)0, &timeval) < 0) { FD_ZERO (&readfd); @@ -272,25 +266,26 @@ int main(int argc, exit (rmc_main (&main_args)); } -void doit(int rqfd) +static void rmc_doit(const int rpfd) { int c; char *clienthost; - char req_data[REQBUFSZ-3*LONGSIZE]; + char req_data[RMC_REQBUFSZ-3*LONGSIZE]; int req_type = 0; - if ((c = getreq (rqfd, &req_type, req_data, &clienthost)) == 0) - procreq (req_type, req_data, clienthost); + if ((c = getreq (rpfd, &req_type, req_data, &clienthost)) == 0) + procreq (rpfd, req_type, req_data, clienthost); else if (c > 0) - sendrep (rqfd, RMC_RC, c); + rmc_sendrep (rpfd, RMC_RC, c); else - close (rqfd); + close (rpfd); } -int getreq(int s, - int *req_type, - char *req_data, - char **clienthost) +static int getreq( + const int s, + int *const req_type, + char *const req_data, + char **const clienthost) { struct sockaddr_in from; socklen_t fromlen = sizeof(from); @@ -301,6 +296,10 @@ int getreq(int s, int n; char *rbp; char req_hdr[3*LONGSIZE]; + char func[16]; + + strncpy (func, "rmc_serv", sizeof(func)); + func[sizeof(func) - 1] = '\0'; l = netread_timeout (s, req_hdr, sizeof(req_hdr), RMC_TIMEOUT); if (l == sizeof(req_hdr)) { @@ -309,20 +308,17 @@ int getreq(int s, unmarshall_LONG (rbp, n); *req_type = n; unmarshall_LONG (rbp, msglen); - if (msglen > REQBUFSZ) { - rmclogit (func, RMC46, REQBUFSZ); + if (msglen > RMC_REQBUFSZ) { + rmc_logit (func, RMC46, RMC_REQBUFSZ); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 46, 2, "func" , TL_MSG_PARAM_STR, "getreq", - "MaxSize", TL_MSG_PARAM_INT, REQBUFSZ); + "MaxSize", TL_MSG_PARAM_INT, RMC_REQBUFSZ); return (-1); } l = msglen - sizeof(req_hdr); n = netread_timeout (s, req_data, l, RMC_TIMEOUT); - if (being_shutdown) { - return (ERMCNACT); - } if (getpeername (s, (struct sockaddr *) &from, &fromlen) < 0) { - rmclogit (func, RMC02, "getpeername", neterror()); + rmc_logit (func, RMC02, "getpeername", neterror()); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 2, 4, "func" , TL_MSG_PARAM_STR, "getreq", "On" , TL_MSG_PARAM_STR, "getpeername", @@ -339,13 +335,13 @@ int getreq(int s, return (0); } else { if (l > 0) { - rmclogit (func, RMC04, l); + rmc_logit (func, RMC04, l); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 4, 3, "func" , TL_MSG_PARAM_STR, "getreq", "netread", TL_MSG_PARAM_INT, l, "Return" , TL_MSG_PARAM_STR, "ERMCUNREC" ); } else if (l < 0) { - rmclogit (func, RMC02, "netread", strerror(errno)); + rmc_logit (func, RMC02, "netread", strerror(errno)); tl_rmcdaemon.tl_log( &tl_rmcdaemon, 2, 4, "func" , TL_MSG_PARAM_STR, "getreq", "On" , TL_MSG_PARAM_STR, "netread", @@ -356,37 +352,53 @@ int getreq(int s, } } -void procreq(int req_type, - char *req_data, - char *clienthost) +static void procreq( + const int rpfd, + const int req_type, + char *const req_data, + char *const clienthost) { - int c; + int c = 0; + struct rmc_srv_rqst_context rqst_context; + + rqst_context.localhost = localhost; + rqst_context.rpfd = rpfd; + rqst_context.req_data = req_data; + rqst_context.clienthost = clienthost; switch (req_type) { case RMC_MOUNT: - c = rmc_srv_mount (req_data, clienthost); + c = rmc_srv_mount (&rqst_context); break; case RMC_UNMOUNT: - c = rmc_srv_unmount (req_data, clienthost); + c = rmc_srv_unmount (&rqst_context); break; case RMC_EXPORT: - c = rmc_srv_export (req_data, clienthost); + c = rmc_srv_export (&rqst_context); break; case RMC_IMPORT: - c = rmc_srv_import (req_data, clienthost); + c = rmc_srv_import (&rqst_context); break; case RMC_GETGEOM: - c = rmc_srv_getgeom (req_data, clienthost); + c = rmc_srv_getgeom (&rqst_context); break; case RMC_READELEM: - c = rmc_srv_readelem (req_data, clienthost); + c = rmc_srv_readelem (&rqst_context); break; case RMC_FINDCART: - c = rmc_srv_findcart (req_data, clienthost); + c = rmc_srv_findcart (&rqst_context); + break; +/* + case RMC_GENERICMOUNT: + c = rmc_srv_genericmount (localhost, rpfd, req_data, clienthost); + break; + case RMC_GENERICUNMOUNT: + c = rmc_srv_genericunmount (localhost, rpfd, req_data, clienthost); break; +*/ default: - sendrep (rpfd, MSG_ERR, RMC03, req_type); + rmc_sendrep (rpfd, MSG_ERR, RMC03, req_type); c = ERMCUNREC; } - sendrep (rpfd, RMC_RC, c); + rmc_sendrep (rpfd, RMC_RC, c); } diff --git a/rmc/smcsubr.c b/rmc/rmc_smcsubr.c similarity index 56% rename from rmc/smcsubr.c rename to rmc/rmc_smcsubr.c index bf4f0e742302d44023897ccd4792e4a67309928c..d1954d2b6eeb1efdd1afc3b7e1000b817354e994 100644 --- a/rmc/smcsubr.c +++ b/rmc/rmc_smcsubr.c @@ -5,28 +5,33 @@ #include <errno.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> -#include "Ctape.h" -#include "scsictl.h" -#include "serrno.h" -#include "smc.h" -#include "sendscsicmd.h" -#include "getconfent.h" + +#include "h/Ctape.h" +#include "h/rmc_constants.h" +#include "h/rmc_sendrep.h" +#include "h/rmc_smcsubr.h" +#include "h/rmc_smcsubr2.h" +#include "h/scsictl.h" +#include "h/serrno.h" +#include "h/sendscsicmd.h" +#include "h/smc_constants.h" +#include "h/getconfent.h" #define RBT_XTRA_PROC 10 static struct smc_status smc_status; static char *smc_msgaddr; -static void -save_error(rc, nb_sense, sense, msgaddr) -int rc; -int nb_sense; -char *sense; -char *msgaddr; +static void save_error( + const int rc, + const int nb_sense, + const char *const sense, + char *const msgaddr) { smc_msgaddr = msgaddr; smc_status.rc = rc; @@ -44,11 +49,10 @@ char *msgaddr; } } -static int -vmatch (char *pattern, char *vid) +static int vmatch (const char *const pattern, const char *const vid) { - char *p; - char *v; + const char *p; + const char *v; for (p = pattern, v = vid; *p; p++, v++) { if (*v == 0 && *p != '*') @@ -72,10 +76,10 @@ vmatch (char *pattern, char *vid) return (*v != 0); } -static int -get_element_size(int fd, - char *rbtdev, - int type) +static int get_element_size( + const int fd, + const char *const rbtdev, + const int type) { unsigned char buf[128]; unsigned char cdb[12]; @@ -117,14 +121,14 @@ get_element_size(int fd, return (buf[10] * 256 + buf[11]); } -static int -get_element_info(char opcode, - int fd, - char *rbtdev, - int type, - int start, - int nbelem, - struct smc_element_info element_info[]) +static int get_element_info( + const char opcode, + const int fd, + const char *const rbtdev, + const int type, + const int start, + const int nbelem, + struct smc_element_info element_info[]) { int avail_elem; unsigned char cdb[12]; @@ -237,9 +241,10 @@ get_element_info(char opcode, return (avail_elem); } -int smc_get_geometry(int fd, - char *rbtdev, - struct robot_info *robot_info) +int smc_get_geometry( + const int fd, + const char *const rbtdev, + struct robot_info *const robot_info) { unsigned char buf[36]; unsigned char cdb[6]; @@ -321,12 +326,13 @@ int smc_get_geometry(int fd, return (0); } -int smc_read_elem_status(int fd, - char *rbtdev, - int type, - int start, - int nbelem, - struct smc_element_info element_info[]) +int smc_read_elem_status( + const int fd, + const char *const rbtdev, + const int type, + const int start, + const int nbelem, + struct smc_element_info element_info[]) { char func[16]; int rc; @@ -338,13 +344,14 @@ int smc_read_elem_status(int fd, return (rc); } -int smc_find_cartridge2 (int fd, - char *rbtdev, - char *template, - int type, - int start, - int nbelem, - struct smc_element_info element_info[]) +int smc_find_cartridge2 ( + const int fd, + const char *const rbtdev, + const char *const template, + const int type, + const int start, + const int nbelem, + struct smc_element_info element_info[]) { int c; static char err_msgbuf[132]; @@ -404,13 +411,14 @@ int smc_find_cartridge2 (int fd, } -int smc_find_cartridge(int fd, - char *rbtdev, - char *template, - int type, - int start, - int nbelem, - struct smc_element_info element_info[]) +int smc_find_cartridge( + const int fd, + const char *const rbtdev, + const char *const template, + const int type, + const int start, + const int nbelem, + struct smc_element_info element_info[]) { unsigned char cdb[12]; char func[16]; @@ -488,7 +496,7 @@ struct scsierr_codact { short action; char *txt; }; -struct scsierr_codact scsierr_acttbl[] = { +static struct scsierr_codact scsierr_acttbl[] = { {0x02, 0x04, 0x00, RBT_FAST_RETRY, "Logical Unit Not Ready, Cause Not Reportable"}, {0x02, 0x04, 0x01, RBT_FAST_RETRY, "Logical Unit Is In Process of Becoming Ready"}, {0x02, 0x04, 0x02, RBT_NORETRY, "Logical Unit Not Ready, initialization required"}, @@ -528,8 +536,9 @@ struct scsierr_codact scsierr_acttbl[] = { {0x02, 0x5A, 0x01, RBT_NORETRY, "Operator Medium Removal Request"} }; -int smc_lasterror(struct smc_status *smc_stat, - char **msgaddr) +int smc_lasterror( + struct smc_status *const smc_stat, + char **const msgaddr) { unsigned int i; @@ -555,11 +564,12 @@ int smc_lasterror(struct smc_status *smc_stat, return (RBT_NORETRY); } -int smc_move_medium(int fd, - char *rbtdev, - int from, - int to, - int invert) +int smc_move_medium( + const int fd, + const char *const rbtdev, + const int from, + const int to, + const int invert) { unsigned char cdb[12]; char func[16]; @@ -603,3 +613,341 @@ int smc_move_medium(int fd, } return (0); } + +static int rmc_usrmsg( + const int rpfd, + const char *func, + const char *const msg, + ...) +{ + va_list args; + char prtbuf[RMC_PRTBUFSZ]; + const int save_errno = errno; + + va_start (args, msg); + snprintf (prtbuf, sizeof(prtbuf), "%s: ", func); + prtbuf[sizeof(prtbuf) - 1] = '\0'; + { + const size_t nbBytesUsed = strlen (prtbuf); + + /* If there is still space in the print buffer */ + if(nbBytesUsed < (sizeof(prtbuf))) { + const size_t nbBytesRemaining = sizeof(prtbuf) - + nbBytesUsed; + char *const p = prtbuf + nbBytesUsed; + vsnprintf (p, nbBytesRemaining, msg, args); + prtbuf[sizeof(prtbuf) - 1] = '\0'; + } + } + rmc_sendrep (rpfd, MSG_ERR, "%s", prtbuf); + va_end (args); + errno = save_errno; + return (0); +} + +int smc_dismount ( + const int rpfd, + const int fd, + const char *const loader, + struct robot_info *const robot_info, + const int drvord, + const char *const vid) +{ + const unsigned int max_element_status_reads = 20; + const unsigned int dismount_status_read_delay = 1; /* In seconds */ + unsigned int nb_element_status_reads = 0; + int drive_not_unloaded = 1; + struct smc_element_info drive_element_info; + char func[16]; + char *msgaddr = 0; + struct smc_status smc_status; + + strncpy (func, "smc_dismount", sizeof(func)); + func[sizeof(func) - 1] = '\0'; + + memset(&smc_status, '\0', sizeof(smc_status)); + + /* IBM libraries sometimes disagree with the eject of their drives. */ + /* Sometimes the access bit of the result of Read Element Status */ + /* (XB8) indicates the gripper cannot access the tape even though */ + /* the eject was successful. Reading the element status at a later */ + /* point in time eventually indicates the tape is accessible. */ + while(drive_not_unloaded && nb_element_status_reads < max_element_status_reads) { + if (0 > smc_read_elem_status (fd, loader, 4, robot_info->device_start+drvord, + 1, &drive_element_info)) { + const int smc_error = smc_lasterror (&smc_status, &msgaddr); + rmc_usrmsg ( rpfd, func, SR020, "read_elem_status", msgaddr); + return (smc_error); + } + if (0 == (drive_element_info.state & 0x1)) { + rmc_usrmsg ( rpfd, func, SR018, "demount", vid, drvord, "Medium Not Present"); + return (RBT_OK); + } + + drive_not_unloaded = (0 == (drive_element_info.state & 0x8)); + if (drive_not_unloaded) { + rmc_usrmsg ( rpfd, func, "read_elem_status of %s on drive %d detected Drive Not Unloaded\n", vid, drvord); + } + + nb_element_status_reads++; + + if(nb_element_status_reads < max_element_status_reads) { + sleep(dismount_status_read_delay); + } + } + if(drive_not_unloaded) { + rmc_usrmsg ( rpfd, func, SR018, "demount", vid, drvord, "Drive Not Unloaded"); + return (RBT_UNLD_DMNT); + } + + if (*vid && strcmp (drive_element_info.name, vid)) { + rmc_usrmsg ( rpfd, func, SR009, vid, drive_element_info.name); + return (RBT_NORETRY); + } + if (0 > smc_move_medium (fd, loader, robot_info->device_start+drvord, + drive_element_info.source_address, (drive_element_info.flags & 0x40) ? 1 : 0)) { + const int smc_error = smc_lasterror (&smc_status, &msgaddr); + rmc_usrmsg ( rpfd, func, SR018, "demount", vid, drvord, msgaddr); + return (smc_error); + } + /* check that the vid is in a slot before returning */ + while (1) { + struct smc_element_info vol_element_info; + if (0 > smc_find_cartridge (fd, loader, drive_element_info.name, 0, 0, 1, &vol_element_info)) { + const int smc_error = smc_lasterror (&smc_status, &msgaddr); + rmc_usrmsg ( rpfd, func, SR017, "find_cartridge", drive_element_info.name, msgaddr); + return (smc_error); + } + + /* vid is in a storage slot */ + if (vol_element_info.element_type == 2) break; + /* give time for the tape enter the slot */ + sleep (2); + } + + return (0); +} + +int smc_export ( + const int rpfd, + const int fd, + const char *const loader, + struct robot_info *const robot_info, + const char *const vid) +{ + int c; + struct smc_element_info element_info; + char func[16]; + int i; + struct smc_element_info *impexp_info; + char *msgaddr; + int nbelem; + struct smc_status smc_status; + + strncpy (func, "smc_export", sizeof(func)); + func[sizeof(func) - 1] = '\0'; + + if ((c = smc_find_cartridge (fd, loader, vid, 0, 0, 1, &element_info)) < 0) { + c = smc_lasterror (&smc_status, &msgaddr); + rmc_usrmsg ( rpfd, func, SR017, "find_cartridge", vid, msgaddr); + return (c); + } + if (c == 0) { + rmc_usrmsg ( rpfd, func, SR017, "export", vid, "volume not in library"); + return (RBT_NORETRY); + } + if (element_info.element_type != 2) { + rmc_usrmsg ( rpfd, func, SR017, "export", vid, "volume in use"); + return (RBT_SLOW_RETRY); + } + /* look for a free export slot */ + + nbelem = robot_info->port_count; + if ((impexp_info = malloc (nbelem * sizeof(struct smc_element_info))) == NULL) { + rmc_usrmsg ( rpfd, func, SR012); + return (RBT_NORETRY); + } + + if ((c = smc_read_elem_status (fd, loader, 3, robot_info->port_start, + nbelem, impexp_info)) < 0) { + c = smc_lasterror (&smc_status, &msgaddr); + rmc_usrmsg ( rpfd, func, SR020, "read_elem_status", msgaddr); + free (impexp_info); + return (c); + } + for (i = 0; i < nbelem; i++) { + if (((impexp_info+i)->state & 0x1) == 0) /* element free */ + break; + } + if (i >= nbelem) { /* export slots are full */ + rmc_usrmsg ( rpfd, func, SR013); + free (impexp_info); + return (RBT_NORETRY); + } + + if ((c = smc_move_medium (fd, loader, element_info.element_address, + (impexp_info+i)->element_address, 0)) < 0) { + c = smc_lasterror (&smc_status, &msgaddr); + rmc_usrmsg ( rpfd, func, SR017, "export", vid, msgaddr); + free (impexp_info); + return (c); + } + free (impexp_info); + return (0); +} + +int smc_import ( + const int rpfd, + const int fd, + const char *const loader, + struct robot_info *const robot_info, + const char *const vid) +{ + int c; + int device_start; + struct smc_element_info *element_info; + char func[16]; + int i, j; + char *msgaddr; + int nbelem; + int port_start; + int slot_start; + struct smc_status smc_status; + + strncpy (func, "smc_import", sizeof(func)); + func[sizeof(func) - 1] = '\0'; + + nbelem = robot_info->transport_count + robot_info->slot_count + + robot_info->port_count + robot_info->device_count; + if ((element_info = malloc (nbelem * sizeof(struct smc_element_info))) == NULL) { + rmc_usrmsg ( rpfd, func, SR012); + return (RBT_NORETRY); + } + + /* get inventory */ + + if ((c = smc_read_elem_status (fd, loader, 0, 0, nbelem, element_info)) < 0) { + c = smc_lasterror (&smc_status, &msgaddr); + rmc_usrmsg ( rpfd, func, SR020, "read_elem_status", msgaddr); + free (element_info); + return (c); + } + for (i = 0; i < c; i++) + if ((element_info+i)->element_type == 2) break; + slot_start = i; + for (i = 0; i < c; i++) + if ((element_info+i)->element_type == 3) break; + port_start = i; + for (i = 0; i < c; i++) + if ((element_info+i)->element_type == 4) break; + device_start = i; + + /* mark home slots of cartridges currently on drives as non free */ + + for (i = device_start; i < device_start+robot_info->device_count; i++) { + if (((element_info+i)->state & 0x1) == 0) continue; + for (j = slot_start; j < slot_start+robot_info->slot_count; j++) + if ((element_info+i)->source_address == + (element_info+j)->element_address) break; + (element_info+j)->state |= 1; + } + + /* loop on all import slots */ + + for (i = port_start; i < port_start+robot_info->port_count; i++) { + if (*vid && strcmp (vid, (element_info+i)->name)) continue; + if (*vid || (*vid == '\0' && ((element_info+i)->state & 2))) { + + /* find a free storage slot */ + + for (j = slot_start; j < slot_start+robot_info->slot_count; j++) + if (((element_info+j)->state & 0x1) == 0) break; + if (j >= slot_start+robot_info->slot_count) { + rmc_usrmsg ( rpfd, func, SR015); + free (element_info); + return (RBT_NORETRY); + } + + if ((c = smc_move_medium (fd, loader, (element_info+i)->element_address, + (element_info+j)->element_address, 0)) < 0) { + c = smc_lasterror (&smc_status, &msgaddr); + rmc_usrmsg ( rpfd, func, SR017, "import", + (element_info+i)->name, msgaddr); + free (element_info); + return (c); + } + if (*vid || c) break; + (element_info+j)->state |= 1; /* dest slot is now full */ + } + } + free (element_info); + return (c); +} + +int smc_mount ( + const int rpfd, + const int fd, + const char *const loader, + struct robot_info *const robot_info, + const int drvord, + const char *const vid, + const int invert) +{ + int c; + struct smc_element_info element_info; + char func[16]; + char *msgaddr; + struct smc_status smc_status; + + strncpy (func, "smc_mount", sizeof(func)); + func[sizeof(func) - 1] = '\0'; + + if ((c = smc_find_cartridge (fd, loader, vid, 0, 0, 1, &element_info)) < 0) { + c = smc_lasterror (&smc_status, &msgaddr); + rmc_usrmsg ( rpfd, func, SR017, "find_cartridge", vid, msgaddr); + return (c); + } + if (c == 0) { + rmc_usrmsg ( rpfd, func, SR018, "mount", vid, drvord, "volume not in library"); + return (RBT_NORETRY); + } + if (element_info.element_type != 2) { + + /* compare requested and replied vid */ + rmc_usrmsg ( rpfd, func, "Asked for %s, got reply for %s\n", + vid, element_info.name ); + + /* detail on a tape's current location */ + switch (element_info.element_type) { + + case 1: + rmc_usrmsg ( rpfd, func, "Location: medium transport element (0x%x)\n", + element_info.element_type ); + break; + case 2: + /* normal case: in its home slot, not possible inside the if */ + break; + case 3: + rmc_usrmsg ( rpfd, func, "Location: import/export element (0x%x)\n", + element_info.element_type ); + break; + case 4: + rmc_usrmsg ( rpfd, func, "Location: data transfer element (0x%x)\n", + element_info.element_type ); + break; + default: + rmc_usrmsg ( rpfd, func, "Location: unknown (0x%x)\n", + element_info.element_type ); + } + + rmc_usrmsg ( rpfd, func, SR018, "mount", vid, drvord, "volume in use"); + return (RBT_SLOW_RETRY); + } + if ((c = smc_move_medium (fd, loader, element_info.element_address, + robot_info->device_start+drvord, invert)) < 0) { + c = smc_lasterror (&smc_status, &msgaddr); + rmc_usrmsg ( rpfd, func, SR018, "mount", vid, drvord, msgaddr); + return (c); + } + return (0); +} diff --git a/rmc/send2rmc.c b/rmc/send2rmc.c index 69b265204eacaddae841a01a36aaea37c088371c..c2464e25810771ba73ddd79bdbc4dbc3a39a693c 100644 --- a/rmc/send2rmc.c +++ b/rmc/send2rmc.c @@ -10,12 +10,12 @@ #include <unistd.h> #include <netinet/in.h> #include <sys/socket.h> -#include "Cnetdb.h" -#include "marshall.h" -#include "net.h" -#include "rmc.h" -#include "rmc_api.h" -#include "serrno.h" +#include "h/Cnetdb.h" +#include "h/marshall.h" +#include "h/net.h" +#include "h/rmc_api.h" +#include "h/rmc_constants.h" +#include "h/serrno.h" /* send2tpd - send a request to the SCSI media changer server and wait for the reply */ @@ -35,9 +35,9 @@ int send2rmc( int magic; int n; char *p; - char prtbuf[PRTBUFSZ]; + char prtbuf[RMC_PRTBUFSZ]; int rep_type; - char repbuf[REPBUFSZ]; + char repbuf[RMC_REPBUFSZ]; char rmchost[CA_MAXHOSTNAMELEN+1]; int s; struct sockaddr_in sin; /* internet socket */ diff --git a/rmc/smc.c b/rmc/smc.c index 1eb6b843957f9e5f2fcee41154e496678f37d123..7d5b1cf4ba9edd1671678d7688165efd102c184d 100644 --- a/rmc/smc.c +++ b/rmc/smc.c @@ -9,11 +9,11 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> -#include "Ctape.h" -#include "rmc_api.h" -#include "serrno.h" -#include "smc.h" -#include "getconfent.h" +#include "h/Ctape.h" +#include "h/rmc_api.h" +#include "h/serrno.h" +#include "h/smc_constants.h" +#include "h/getconfent.h" /* exit codes */ #define USERR 1 diff --git a/rmc/smcsubr2.c b/rmc/smcsubr2.c deleted file mode 100644 index 95d47c0b4ecefa66c4ed12ead7bce53b3a78e248..0000000000000000000000000000000000000000 --- a/rmc/smcsubr2.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright (C) 1998-2003 by CERN/IT/PDP/DM - * All rights reserved - */ - - -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/types.h> -#include "Ctape.h" -#include "Ctape_api.h" -#include "getconfent.h" -#include "serrno.h" -#include "smc.h" - -/* from smcsubr.c */ -extern int smc_read_elem_status(int, char *, int, int, int, struct smc_element_info[]); -extern int smc_lasterror(struct smc_status *, char **); -extern int smc_move_medium(int, char *, int, int, int); -extern int smc_find_cartridge(int, char *, char *, int, int, int, struct smc_element_info[] ); - -int smc_dismount (int fd, - char *loader, - struct robot_info *robot_info, - int drvord, - char *vid) -{ - const unsigned int max_element_status_reads = 20; - const unsigned int dismount_status_read_delay = 1; /* In seconds */ - unsigned int nb_element_status_reads = 0; - int drive_not_unloaded = 1; - struct smc_element_info drive_element_info; - char func[16]; - char *msgaddr = 0; - struct smc_status smc_status; - - strncpy (func, "smc_dismount", sizeof(func)); - func[sizeof(func) - 1] = '\0'; - - memset(&smc_status, '\0', sizeof(smc_status)); - - /* IBM libraries sometimes disagree with the eject of their drives. */ - /* Sometimes the access bit of the result of Read Element Status */ - /* (XB8) indicates the gripper cannot access the tape even though */ - /* the eject was successful. Reading the element status at a later */ - /* point in time eventually indicates the tape is accessible. */ - while(drive_not_unloaded && nb_element_status_reads < max_element_status_reads) { - if (0 > smc_read_elem_status (fd, loader, 4, robot_info->device_start+drvord, - 1, &drive_element_info)) { - const int smc_error = smc_lasterror (&smc_status, &msgaddr); - usrmsg (func, SR020, "read_elem_status", msgaddr); - return (smc_error); - } - if (0 == (drive_element_info.state & 0x1)) { - usrmsg (func, SR018, "demount", vid, drvord, "Medium Not Present"); - return (RBT_OK); - } - - drive_not_unloaded = (0 == (drive_element_info.state & 0x8)); - if (drive_not_unloaded) { - usrmsg (func, "read_elem_status of %s on drive %d detected Drive Not Unloaded\n", vid, drvord); - } - - nb_element_status_reads++; - - if(nb_element_status_reads < max_element_status_reads) { - sleep(dismount_status_read_delay); - } - } - if(drive_not_unloaded) { - usrmsg (func, SR018, "demount", vid, drvord, "Drive Not Unloaded"); - return (RBT_UNLD_DMNT); - } - - if (*vid && strcmp (drive_element_info.name, vid)) { - usrmsg (func, SR009, vid, drive_element_info.name); - return (RBT_NORETRY); - } - if (0 > smc_move_medium (fd, loader, robot_info->device_start+drvord, - drive_element_info.source_address, (drive_element_info.flags & 0x40) ? 1 : 0)) { - const int smc_error = smc_lasterror (&smc_status, &msgaddr); - usrmsg (func, SR018, "demount", vid, drvord, msgaddr); - return (smc_error); - } - /* check that the vid is in a slot before returning */ - while (1) { - struct smc_element_info vol_element_info; - if (0 > smc_find_cartridge (fd, loader, drive_element_info.name, 0, 0, 1, &vol_element_info)) { - const int smc_error = smc_lasterror (&smc_status, &msgaddr); - usrmsg (func, SR017, "find_cartridge", drive_element_info.name, msgaddr); - return (smc_error); - } - - /* vid is in a storage slot */ - if (vol_element_info.element_type == 2) break; - /* give time for the tape enter the slot */ - sleep (2); - } - - return (0); -} - -int smc_export (int fd, - char *loader, - struct robot_info *robot_info, - char *vid) -{ - int c; - struct smc_element_info element_info; - char func[16]; - int i; - struct smc_element_info *impexp_info; - char *msgaddr; - int nbelem; - struct smc_status smc_status; - - strncpy (func, "smc_export", sizeof(func)); - func[sizeof(func) - 1] = '\0'; - - if ((c = smc_find_cartridge (fd, loader, vid, 0, 0, 1, &element_info)) < 0) { - c = smc_lasterror (&smc_status, &msgaddr); - usrmsg (func, SR017, "find_cartridge", vid, msgaddr); - return (c); - } - if (c == 0) { - usrmsg (func, SR017, "export", vid, "volume not in library"); - return (RBT_NORETRY); - } - if (element_info.element_type != 2) { - usrmsg (func, SR017, "export", vid, "volume in use"); - return (RBT_SLOW_RETRY); - } - /* look for a free export slot */ - - nbelem = robot_info->port_count; - if ((impexp_info = malloc (nbelem * sizeof(struct smc_element_info))) == NULL) { - usrmsg (func, SR012); - return (RBT_NORETRY); - } - - if ((c = smc_read_elem_status (fd, loader, 3, robot_info->port_start, - nbelem, impexp_info)) < 0) { - c = smc_lasterror (&smc_status, &msgaddr); - usrmsg (func, SR020, "read_elem_status", msgaddr); - free (impexp_info); - return (c); - } - for (i = 0; i < nbelem; i++) { - if (((impexp_info+i)->state & 0x1) == 0) /* element free */ - break; - } - if (i >= nbelem) { /* export slots are full */ - usrmsg (func, SR013); - free (impexp_info); - return (RBT_NORETRY); - } - - if ((c = smc_move_medium (fd, loader, element_info.element_address, - (impexp_info+i)->element_address, 0)) < 0) { - c = smc_lasterror (&smc_status, &msgaddr); - usrmsg (func, SR017, "export", vid, msgaddr); - free (impexp_info); - return (c); - } - free (impexp_info); - return (0); -} - -int smc_import (int fd, - char *loader, - struct robot_info *robot_info, - char *vid) -{ - int c; - int device_start; - struct smc_element_info *element_info; - char func[16]; - int i, j; - char *msgaddr; - int nbelem; - int port_start; - int slot_start; - struct smc_status smc_status; - - strncpy (func, "smc_import", sizeof(func)); - func[sizeof(func) - 1] = '\0'; - - nbelem = robot_info->transport_count + robot_info->slot_count + - robot_info->port_count + robot_info->device_count; - if ((element_info = malloc (nbelem * sizeof(struct smc_element_info))) == NULL) { - usrmsg (func, SR012); - return (RBT_NORETRY); - } - - /* get inventory */ - - if ((c = smc_read_elem_status (fd, loader, 0, 0, nbelem, element_info)) < 0) { - c = smc_lasterror (&smc_status, &msgaddr); - usrmsg (func, SR020, "read_elem_status", msgaddr); - free (element_info); - return (c); - } - for (i = 0; i < c; i++) - if ((element_info+i)->element_type == 2) break; - slot_start = i; - for (i = 0; i < c; i++) - if ((element_info+i)->element_type == 3) break; - port_start = i; - for (i = 0; i < c; i++) - if ((element_info+i)->element_type == 4) break; - device_start = i; - - /* mark home slots of cartridges currently on drives as non free */ - - for (i = device_start; i < device_start+robot_info->device_count; i++) { - if (((element_info+i)->state & 0x1) == 0) continue; - for (j = slot_start; j < slot_start+robot_info->slot_count; j++) - if ((element_info+i)->source_address == - (element_info+j)->element_address) break; - (element_info+j)->state |= 1; - } - - /* loop on all import slots */ - - for (i = port_start; i < port_start+robot_info->port_count; i++) { - if (*vid && strcmp (vid, (element_info+i)->name)) continue; - if (*vid || (*vid == '\0' && ((element_info+i)->state & 2))) { - - /* find a free storage slot */ - - for (j = slot_start; j < slot_start+robot_info->slot_count; j++) - if (((element_info+j)->state & 0x1) == 0) break; - if (j >= slot_start+robot_info->slot_count) { - usrmsg (func, SR015); - free (element_info); - return (RBT_NORETRY); - } - - if ((c = smc_move_medium (fd, loader, (element_info+i)->element_address, - (element_info+j)->element_address, 0)) < 0) { - c = smc_lasterror (&smc_status, &msgaddr); - usrmsg (func, SR017, "import", - (element_info+i)->name, msgaddr); - free (element_info); - return (c); - } - if (*vid || c) break; - (element_info+j)->state |= 1; /* dest slot is now full */ - } - } - free (element_info); - return (c); -} - -int smc_mount (int fd, - char *loader, - struct robot_info *robot_info, - int drvord, - char *vid, - int invert) -{ - int c; - struct smc_element_info element_info; - char func[16]; - char *msgaddr; - struct smc_status smc_status; - - strncpy (func, "smc_mount", sizeof(func)); - func[sizeof(func) - 1] = '\0'; - - if ((c = smc_find_cartridge (fd, loader, vid, 0, 0, 1, &element_info)) < 0) { - c = smc_lasterror (&smc_status, &msgaddr); - usrmsg (func, SR017, "find_cartridge", vid, msgaddr); - return (c); - } - if (c == 0) { - usrmsg (func, SR018, "mount", vid, drvord, "volume not in library"); - return (RBT_NORETRY); - } - if (element_info.element_type != 2) { - - /* compare requested and replied vid */ - usrmsg( func, "Asked for %s, got reply for %s\n", - vid, element_info.name ); - - /* detail on a tape's current location */ - switch (element_info.element_type) { - - case 1: - usrmsg( func, "Location: medium transport element (0x%x)\n", - element_info.element_type ); - break; - case 2: - /* normal case: in its home slot, not possible inside the if */ - break; - case 3: - usrmsg( func, "Location: import/export element (0x%x)\n", - element_info.element_type ); - break; - case 4: - usrmsg( func, "Location: data transfer element (0x%x)\n", - element_info.element_type ); - break; - default: - usrmsg( func, "Location: unknown (0x%x)\n", - element_info.element_type ); - } - - usrmsg (func, SR018, "mount", vid, drvord, "volume in use"); - return (RBT_SLOW_RETRY); - } - if ((c = smc_move_medium (fd, loader, element_info.element_address, - robot_info->device_start+drvord, invert)) < 0) { - c = smc_lasterror (&smc_status, &msgaddr); - usrmsg (func, SR018, "mount", vid, drvord, msgaddr); - return (c); - } - return (0); -} diff --git a/rmc/usrmsg.c b/rmc/usrmsg.c deleted file mode 100644 index 6a1dc62074e9e20755ae2d58175af1dbf2ce1c3d..0000000000000000000000000000000000000000 --- a/rmc/usrmsg.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 1990-2002 by CERN/IT/PDP/DM - * All rights reserved - */ - -#include <stdio.h> -#include <errno.h> -#include <string.h> -#include <sys/types.h> -#include <stdarg.h> -#include "rmc.h" -#include <Ctape_api.h> - -int usrmsg(const char *func, const char *const msg, ...) -{ - va_list args; - char *p; - char prtbuf[PRTBUFSZ]; - extern int rpfd; - int save_errno; - - save_errno = errno; - va_start (args, msg); - sprintf (prtbuf, "%s: ", func); - p = prtbuf + strlen (prtbuf); - vsprintf (p, msg, args); - sendrep (rpfd, MSG_ERR, "%s", prtbuf); - va_end (args); - errno = save_errno; - return (0); -} diff --git a/tape/rbtsubr.c b/tape/rbtsubr.c index a7f1d610062c6d0cf17f72b2ba8a5bd447bb1514..e6a977c331cdbf6689cc36750909fc7c989d29f4 100644 --- a/tape/rbtsubr.c +++ b/tape/rbtsubr.c @@ -24,7 +24,6 @@ #include <arpa/inet.h> /* arpa internet routines */ #include "h/net.h" #include "h/rmc_api.h" -#include "h/smc.h" #include "h/Ctape.h" #include "h/Ctape_api.h" #include "h/tplogger_api.h" diff --git a/tape/sendscsicmd.c b/tape/sendscsicmd.c index 50851920c51ed1c4b89a9834cd219993a172bc57..c4803e8b618ba468d8453b412c266118ed7f2c0b 100644 --- a/tape/sendscsicmd.c +++ b/tape/sendscsicmd.c @@ -140,19 +140,20 @@ static void find_sgpath(char *sgpath, int maj, int min) { } -int send_scsi_cmd (int tapefd, - char *path, - int do_not_open, - unsigned char *cdb, - int cdblen, - unsigned char *buffer, - int buflen, - char *sense, - int senselen, - int timeout, /* in milliseconds */ - int flags, - int *nb_sense_ret, - char **msgaddr) +int send_scsi_cmd ( + const int tapefd, + const char *const path, + const int do_not_open, + const unsigned char *const cdb, + const int cdblen, + unsigned char *const buffer, + const int buflen, + char *const sense, + const int senselen, + const int timeout, /* in milliseconds */ + const int flags, + int *const nb_sense_ret, + char **const msgaddr) { int fd; FILE *fopen(); diff --git a/test/unittest/Makefile b/test/unittest/Makefile index 5b1843aaff558b3e45e76a31d81c6c760bc8bfc1..867683dd15dcbd9b377c7064facf91dffcd42f91 100644 --- a/test/unittest/Makefile +++ b/test/unittest/Makefile @@ -10,8 +10,10 @@ MACPORTS_CPPUNIT_INCLUDE_OP= MACPORTS_CPPUNIT_LIB_OP= endif +CDK_OPS=-DLINUX -I/usr/include/CDK +CDK_LIB_OPS = -L/usr/lib64/CDK -lapi -lcl -lipc -lutl ROOT_DIR=../.. -INCLUDE_OPS=-I$(ROOT_DIR) -I$(ROOT_DIR)/h $(MACPORTS_CPPUNIT_INCLUDE_OP) +INCLUDE_OPS=-I$(ROOT_DIR) -I$(ROOT_DIR)/h $(MACPORTS_CPPUNIT_INCLUDE_OP) $(CDK_OPS) LIB_DIR_OPS=$(MACPORTS_CPPUNIT_LIB_OP) EXECUTABLES=rununittests CSEC_MECHLIST=KRB5 GSI ID @@ -67,20 +69,26 @@ rununittests: \ dlf_Dlf.o \ dlf_Param.o \ dlf_dlf_lib.o \ - exception_Exception.o \ - exception_InvalidArgument.o \ exception_Communication.o \ + exception_DismountFailed.o \ + exception_Exception.o \ exception_Internal.o \ + exception_InvalidArgument.o \ exception_InvalidConfigEntry.o \ exception_InvalidConfiguration.o \ - exception_TimeOut.o \ - exception_TooBig.o \ + exception_Mismatch.o \ + exception_MissingOperand.o \ + exception_MountFailed.o \ + exception_NoEntry.o \ exception_NoPortInRange.o \ exception_NoValue.o \ - exception_TapeNetAcceptInterrupted.o \ - exception_PermissionDenied.o \ exception_OutOfMemory.o \ - exception_NoEntry.o \ + exception_PermissionDenied.o \ + exception_QueryVolumeFailed.o \ + exception_RequestFailed.o \ + exception_TapeNetAcceptInterrupted.o \ + exception_TimeOut.o \ + exception_TooBig.o \ io_AbstractSocket.o \ io_AbstractTCPSocket.o \ io_AuthClientSocket.o \ @@ -118,6 +126,15 @@ rununittests: \ metrics_InternalCounter.o \ metrics_MetricsCollector.o \ metrics_UpdateThread.o \ + mediachanger_Acs.o \ + mediachanger_AcsCmd.o \ + mediachanger_DebugBuf.o \ + mediachanger_DismountAcsCmdLine.o \ + mediachanger_DismountAcsCmd.o \ + mediachanger_MountAcsCmdLine.o \ + mediachanger_MountAcsCmd.o \ + mediachanger_QueryVolumeAcsCmdLine.o \ + mediachanger_QueryVolumeAcsCmd.o \ ns_Cns_selectsrvr.o \ ns_Cns_opendir.o \ ns_Cns_closedir.o \ @@ -310,13 +327,21 @@ rununittests: \ tapegateway_VolumeRequest.o \ test_exception.o \ unittest.o \ + unittest_AcsCmdTest.o \ + unittest_AcsTest.o \ unittest_CvtdenTest.o \ unittest_InitlabelTest.o \ unittest_Ctape_reserveTest.o \ + unittest_DismountAcsCmdLineTest.o \ + unittest_DismountAcsCmdTest.o \ unittest_RecvTapeBridgeFlushedToTapeAckTest.o \ unittest_MarshallTapeBridgeFlushedToTapeTest.o \ unittest_SendTapeBridgeFlushedToTapeTest.o \ unittest_MarshallTapeBridgeClientInfo2Test.o \ + unittest_MountAcsCmdLineTest.o \ + unittest_MountAcsCmdTest.o \ + unittest_QueryVolumeAcsCmdLineTest.o \ + unittest_QueryVolumeAcsCmdTest.o \ unittest_NetTest.o \ unittest_FileToRecallTest.o \ unittest_MigrationReportConnectionTest.o \ @@ -354,7 +379,7 @@ rununittests: \ vmgr_vmgr_querypool.o \ vmgr_send2vmgr.o \ vmgr_vmgr_querytape_byte_u64.o - g++ $(COMMON_OPS) $(LIB_DIR_OPS) -lpthread -ldl $(UUID_LIB) -lcppunit -lz -o $@ $^ + g++ $(COMMON_OPS) $(LIB_DIR_OPS) $(CDK_LIB_OPS) -lpthread -ldl $(UUID_LIB) -lcppunit -lz -o $@ $^ runUnitTestsMain.o: runUnitTestsMain.cpp g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ @@ -488,9 +513,21 @@ dlf_Param.o: $(ROOT_DIR)/castor/dlf/Param.cpp dlf_dlf_lib.o: $(ROOT_DIR)/dlf/dlf_lib.c gcc -g -pthread -c $(INCLUDE_OPS) -o $@ $^ +exception_DismountFailed.o: $(ROOT_DIR)/castor/exception/DismountFailed.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + exception_Exception.o: $(ROOT_DIR)/castor/exception/Exception.cpp g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ +exception_Mismatch.o: $(ROOT_DIR)/castor/exception/Mismatch.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +exception_MissingOperand.o: $(ROOT_DIR)/castor/exception/MissingOperand.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +exception_MountFailed.o: $(ROOT_DIR)/castor/exception/MountFailed.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + exception_NoEntry.o: $(ROOT_DIR)/castor/exception/NoEntry.cpp g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ @@ -511,6 +548,12 @@ exception_InvalidConfiguration.o: \ $(ROOT_DIR)/castor/exception/InvalidConfiguration.cpp g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ +exception_QueryVolumeFailed.o: $(ROOT_DIR)/castor/exception/QueryVolumeFailed.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +exception_RequestFailed.o: $(ROOT_DIR)/castor/exception/RequestFailed.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + exception_TimeOut.o: $(ROOT_DIR)/castor/exception/TimeOut.cpp g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ @@ -673,6 +716,33 @@ metrics_UpdateThread.o: \ $(ROOT_DIR)/castor/metrics/UpdateThread.cpp g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ +mediachanger_Acs.o: $(ROOT_DIR)/castor/tape/mediachanger/Acs.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +mediachanger_AcsCmd.o: $(ROOT_DIR)/castor/tape/mediachanger/AcsCmd.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +mediachanger_DebugBuf.o: $(ROOT_DIR)/castor/tape/mediachanger/DebugBuf.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +mediachanger_DismountAcsCmdLine.o: $(ROOT_DIR)/castor/tape/mediachanger/DismountAcsCmdLine.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +mediachanger_DismountAcsCmd.o: $(ROOT_DIR)/castor/tape/mediachanger/DismountAcsCmd.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +mediachanger_MountAcsCmdLine.o: $(ROOT_DIR)/castor/tape/mediachanger/MountAcsCmdLine.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +mediachanger_MountAcsCmd.o: $(ROOT_DIR)/castor/tape/mediachanger/MountAcsCmd.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +mediachanger_QueryVolumeAcsCmdLine.o: $(ROOT_DIR)/castor/tape/mediachanger/QueryVolumeAcsCmdLine.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +mediachanger_QueryVolumeAcsCmd.o: $(ROOT_DIR)/castor/tape/mediachanger/QueryVolumeAcsCmd.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + ns_Cns_selectsrvr.o: $(ROOT_DIR)/ns/Cns_selectsrvr.c gcc $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ @@ -1485,9 +1555,6 @@ unittest_SendTapeBridgeFlushedToTapeTest.o: $(ROOT_DIR)/test/unittest/tapebridge unittest_MarshallTapeBridgeClientInfo2Test.o: $(ROOT_DIR)/test/unittest/tapebridge/MarshallTapeBridgeClientInfo2Test.cpp g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ -unittest_NetTest.o: $(ROOT_DIR)/test/unittest/castor/tape/net/NetTest.cpp - g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ - unittest_FileToRecallTest.o: $(ROOT_DIR)/test/unittest/castor/tape/tapebridge/FileToRecallTest.cpp g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ @@ -1500,6 +1567,33 @@ unittest_SessionErrorTest.o: $(ROOT_DIR)/test/unittest/castor/tape/tapebridge/Se unittest_ClientAddressLocalTest.o: $(ROOT_DIR)/test/unittest/castor/tape/tapebridge/ClientAddressLocalTest.cpp g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ +unittest_AcsCmdTest.o: $(ROOT_DIR)/test/unittest/castor/tape/mediachanger/AcsCmdTest.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +unittest_AcsTest.o: $(ROOT_DIR)/test/unittest/castor/tape/mediachanger/AcsTest.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +unittest_DismountAcsCmdLineTest.o: $(ROOT_DIR)/test/unittest/castor/tape/mediachanger/DismountAcsCmdLineTest.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +unittest_DismountAcsCmdTest.o: $(ROOT_DIR)/test/unittest/castor/tape/mediachanger/DismountAcsCmdTest.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +unittest_NetTest.o: $(ROOT_DIR)/test/unittest/castor/tape/net/NetTest.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +unittest_MountAcsCmdLineTest.o: $(ROOT_DIR)/test/unittest/castor/tape/mediachanger/MountAcsCmdLineTest.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +unittest_MountAcsCmdTest.o: $(ROOT_DIR)/test/unittest/castor/tape/mediachanger/MountAcsCmdTest.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +unittest_QueryVolumeAcsCmdLineTest.o: $(ROOT_DIR)/test/unittest/castor/tape/mediachanger/QueryVolumeAcsCmdLineTest.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + +unittest_QueryVolumeAcsCmdTest.o: $(ROOT_DIR)/test/unittest/castor/tape/mediachanger/QueryVolumeAcsCmdTest.cpp + g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ + unittest_FileToMigrateTest.o: $(ROOT_DIR)/test/unittest/castor/tape/tapebridge/FileToMigrateTest.cpp g++ $(COMMON_OPS) -c $(INCLUDE_OPS) -o $@ $^ diff --git a/test/unittest/castor/tape/mediachanger/AcsCmdTest.cpp b/test/unittest/castor/tape/mediachanger/AcsCmdTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..075f80dd02cfd1185c529bc806b88680ac1f4d5f --- /dev/null +++ b/test/unittest/castor/tape/mediachanger/AcsCmdTest.cpp @@ -0,0 +1,53 @@ +/****************************************************************************** + * test/unittest/castor/tape/mountacs/AcsCmdTest.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "test/unittest/castor/tape/mediachanger/MockAcs.hpp" +#include "test/unittest/castor/tape/mediachanger/TestingAcsCmd.hpp" + +#include <cppunit/extensions/HelperMacros.h> +#include <sstream> +#include <string.h> + +namespace castor { +namespace tape { +namespace mediachanger { + +class AcsCmdTest: public CppUnit::TestFixture { +public: + + void setUp() { + } + + void tearDown() { + } + + CPPUNIT_TEST_SUITE(AcsCmdTest); + CPPUNIT_TEST_SUITE_END(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(AcsCmdTest); + +} // namespace mediachanger +} // namespace tape +} // namespace castor diff --git a/test/unittest/castor/tape/mediachanger/AcsTest.cpp b/test/unittest/castor/tape/mediachanger/AcsTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ae95325c1b852f196f7f811b832cde1aebd30db --- /dev/null +++ b/test/unittest/castor/tape/mediachanger/AcsTest.cpp @@ -0,0 +1,251 @@ +/****************************************************************************** + * test/unittest/castor/tape/dismountacs/AcsTest.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "test/unittest/castor/tape/mediachanger/MockAcs.hpp" + +#include <cppunit/extensions/HelperMacros.h> + +namespace castor { +namespace tape { +namespace mediachanger { + +class AcsTest: public CppUnit::TestFixture { +public: + + void setUp() { + } + + void tearDown() { + } + + void testStr2DriveIdWithValidDriveId() { + const std::string str = "111:112:113:114"; + DRIVEID driveId; + MockAcs acs; + CPPUNIT_ASSERT_NO_THROW_MESSAGE("Calling str2DriveId with valid drive ID", + driveId = acs.str2DriveId(str)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + (ACS)111, driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + (LSM)112, driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + (PANEL)113, driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + (DRIVE)114, driveId.drive); + } + + void testStr2DriveIdWithEmptyString() { + const std::string str = ""; + MockAcs acs; + CPPUNIT_ASSERT_THROW_MESSAGE("Calling str2DriveId with empty string", + acs.str2DriveId(str), + castor::exception::InvalidArgument); + } + + void testStr2DriveWithPrecedingZeros() { + const std::string str = "011:012:013:014"; + DRIVEID driveId; + MockAcs acs; + CPPUNIT_ASSERT_NO_THROW_MESSAGE("Calling str2DriveId with preceding zeros", + driveId = acs.str2DriveId(str)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + (ACS)11, driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + (LSM)12, driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + (PANEL)13, driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + (DRIVE)14, driveId.drive); + } + + void testStr2DriveIdWithTooManyColons() { + const std::string str = "111:112:113:114:115"; + MockAcs acs; + CPPUNIT_ASSERT_THROW_MESSAGE("Calling str2DriveId with too many colons", + acs.str2DriveId(str), castor::exception::InvalidArgument); + } + + void testDriveId2StrWithArbitrary3DigitValues() { + DRIVEID driveId; + driveId.panel_id.lsm_id.acs = (ACS)111; + driveId.panel_id.lsm_id.lsm = (LSM)112; + driveId.panel_id.panel = (PANEL)113; + driveId.drive = (DRIVE)114; + MockAcs acs; + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing str()", + std::string("111:112:113:114"), acs.driveId2Str(driveId)); + } + + void testDriveId2StrWithArbitrary1DigitValues() { + DRIVEID driveId; + driveId.panel_id.lsm_id.acs = (ACS)1; + driveId.panel_id.lsm_id.lsm = (LSM)2; + driveId.panel_id.panel = (PANEL)3; + driveId.drive = (DRIVE)4; + MockAcs acs; + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing str()", + std::string("001:002:003:004"), acs.driveId2Str(driveId)); + } + + void testStr2DriveIdWithTooLongAcs() { + const std::string str = "1111:112:113:114"; + MockAcs acs; + CPPUNIT_ASSERT_THROW_MESSAGE("Calling str2DriveId with too long ACS", + acs.str2DriveId(str), castor::exception::InvalidArgument); + } + + void testStr2DriveIdWithTooLongLsm() { + const std::string str = "111:1122:113:114"; + MockAcs acs; + CPPUNIT_ASSERT_THROW_MESSAGE("Calling str2DriveId with too long LSM", + acs.str2DriveId(str), castor::exception::InvalidArgument); + } + + void testStr2DriveIdWithTooLongPanel() { + const std::string str = "111:112:1133:114"; + MockAcs acs; + CPPUNIT_ASSERT_THROW_MESSAGE("Calling str2DriveId with too long panel", + acs.str2DriveId(str), castor::exception::InvalidArgument); + } + + void testStr2DriveIdWithTooLongTransport() { + const std::string str = "111:112:113:1144"; + MockAcs acs; + CPPUNIT_ASSERT_THROW_MESSAGE("Calling str2DriveId with too long drive", + acs.str2DriveId(str), castor::exception::InvalidArgument); + } + + void testStr2DriveIdWithNonNumericAcs() { + const std::string str = "acs:112:113:114"; + MockAcs acs; + CPPUNIT_ASSERT_THROW_MESSAGE("Calling str2DriveId with non-numeric ACS", + acs.str2DriveId(str), castor::exception::InvalidArgument); + } + + void testStr2DriveIdWithNonNumericLsm() { + const std::string str = "111:lsm:113:114"; + MockAcs acs; + CPPUNIT_ASSERT_THROW_MESSAGE("Calling str2DriveId with non-numeric LSM", + acs.str2DriveId(str), castor::exception::InvalidArgument); + } + + void testStr2DriveIdWithNonNumericPanel() { + const std::string str = "111:112:pan:114"; + MockAcs acs; + CPPUNIT_ASSERT_THROW_MESSAGE("Calling str2DriveId with non-numeric panel", + acs.str2DriveId(str), castor::exception::InvalidArgument); + } + + void testStr2DriveIdWithNonNumericTransport() { + const std::string str = "111:112:113:tra"; + MockAcs acs; + CPPUNIT_ASSERT_THROW_MESSAGE( + "Calling str2DriveId with non-numeric drive", + acs.str2DriveId(str), castor::exception::InvalidArgument); + } + + void testStr2DriveIdWithEmptyAcs() { + const std::string str = ":112:113:114"; + MockAcs acs; + CPPUNIT_ASSERT_THROW_MESSAGE("Calling str2DriveId with empty ACS", + acs.str2DriveId(str), castor::exception::InvalidArgument); + } + + void testStr2DriveIdWithEmptyLsm() { + const std::string str = "111::113:114"; + MockAcs acs; + CPPUNIT_ASSERT_THROW_MESSAGE("Calling str2DriveId with empty LSM", + acs.str2DriveId(str), castor::exception::InvalidArgument); + } + + void testStr2DriveIdWithEmptyPanel() { + const std::string str = "111:112::114"; + MockAcs acs; + CPPUNIT_ASSERT_THROW_MESSAGE("Calling str2DriveId with empty panel", + acs.str2DriveId(str), castor::exception::InvalidArgument); + } + + void testStr2DriveIdWithEmptyTransport() { + const std::string str = "111:112:113:"; + MockAcs acs; + CPPUNIT_ASSERT_THROW_MESSAGE("Calling str2DriveId with empty drive", + acs.str2DriveId(str), castor::exception::InvalidArgument); + } + + void testStr2VolidWithEmptyString() { + const std::string str = ""; + VOLID volId; + MockAcs acs; + CPPUNIT_ASSERT_NO_THROW_MESSAGE("Calling str2Volid with empty string", + volId = acs.str2Volid(str)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Checking external_label is an empty string", + '\0', volId.external_label[0]); + } + + void testStr2VolidWith6CharacterString() { + const std::string str = "123456"; + VOLID volId; + MockAcs acs; + CPPUNIT_ASSERT_NO_THROW_MESSAGE("Calling str2Volid with 6 character string", + volId = acs.str2Volid(str)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Checking external_label", + str, std::string(volId.external_label)); + } + + void testStr2VolidWith7CharacterString() { + const std::string str = "1234567"; + MockAcs acs; + CPPUNIT_ASSERT_THROW_MESSAGE("Calling str2Volid with 7 character string", + acs.str2Volid(str), castor::exception::InvalidArgument); + } + + CPPUNIT_TEST_SUITE(AcsTest); + CPPUNIT_TEST(testStr2DriveIdWithValidDriveId); + CPPUNIT_TEST(testStr2DriveIdWithEmptyString); + CPPUNIT_TEST(testStr2DriveWithPrecedingZeros); + CPPUNIT_TEST(testStr2DriveIdWithTooManyColons); + CPPUNIT_TEST(testStr2DriveIdWithTooLongAcs); + CPPUNIT_TEST(testStr2DriveIdWithTooLongLsm); + CPPUNIT_TEST(testStr2DriveIdWithTooLongPanel); + CPPUNIT_TEST(testStr2DriveIdWithTooLongTransport); + CPPUNIT_TEST(testStr2DriveIdWithNonNumericAcs); + CPPUNIT_TEST(testStr2DriveIdWithNonNumericLsm); + CPPUNIT_TEST(testStr2DriveIdWithNonNumericPanel); + CPPUNIT_TEST(testStr2DriveIdWithNonNumericTransport); + CPPUNIT_TEST(testStr2DriveIdWithEmptyAcs); + CPPUNIT_TEST(testStr2DriveIdWithEmptyLsm); + CPPUNIT_TEST(testStr2DriveIdWithEmptyPanel); + CPPUNIT_TEST(testStr2DriveIdWithEmptyTransport); + CPPUNIT_TEST(testDriveId2StrWithArbitrary3DigitValues); + CPPUNIT_TEST(testDriveId2StrWithArbitrary1DigitValues); + CPPUNIT_TEST(testStr2VolidWith6CharacterString); + CPPUNIT_TEST(testStr2VolidWith7CharacterString); + CPPUNIT_TEST_SUITE_END(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(AcsTest); + +} // namespace mediachanger +} // namespace tape +} // namespace castor diff --git a/test/unittest/castor/tape/mediachanger/DismountAcsCmdLineTest.cpp b/test/unittest/castor/tape/mediachanger/DismountAcsCmdLineTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1af3f6ebd578fda6ebd3b0eea54001f7ee1dec8b --- /dev/null +++ b/test/unittest/castor/tape/mediachanger/DismountAcsCmdLineTest.cpp @@ -0,0 +1,80 @@ +/****************************************************************************** + * test/unittest/castor/tape/dismountacs/DismountAcsCmdLineTest.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "castor/tape/mediachanger/DismountAcsCmdLine.hpp" + +#include <cppunit/extensions/HelperMacros.h> + +namespace castor { +namespace tape { +namespace mediachanger { + +class DismountAcsCmdLineTest: public CppUnit::TestFixture { +public: + + void setUp() { + } + + void tearDown() { + } + + void testConstructor() { + const DismountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing debug flag is initialised to FALSE", + false, cmdLine.debug); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing force flag is initialised to FALSE", + (BOOLEAN)FALSE, cmdLine.force); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing help flag is initialised to FALSE", + false, cmdLine.help); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing timeout option is initialised to 0", + 0, cmdLine.timeout); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing query option is initialised to 0", + 0, cmdLine.queryInterval); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing driveId.panel_id.lsm_id.acs is initialised to 0", + 0, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing driveId.panel_id.lsm_id.lsm is initialised to 0", + 0, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing driveId.panel_id.panel is initialised to 0", + 0, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing driveId.drive is initialised to 0", + 0, (int)cmdLine.driveId.drive); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing volId is initialised to an empty string", + '\0', cmdLine.volId.external_label[0]); + } + + CPPUNIT_TEST_SUITE(DismountAcsCmdLineTest); + CPPUNIT_TEST(testConstructor); + CPPUNIT_TEST_SUITE_END(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(DismountAcsCmdLineTest); + +} // namespace mediachanger +} // namespace tape +} // namespace castor diff --git a/test/unittest/castor/tape/mediachanger/DismountAcsCmdTest.cpp b/test/unittest/castor/tape/mediachanger/DismountAcsCmdTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2a2a06f1f6b3c27f44860fb7158893c03ec15013 --- /dev/null +++ b/test/unittest/castor/tape/mediachanger/DismountAcsCmdTest.cpp @@ -0,0 +1,578 @@ +/****************************************************************************** + * test/unittest/castor/tape/mediachanger/DismountAcsCmdTest.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "test/unittest/castor/tape/mediachanger/MockAcs.hpp" +#include "test/unittest/castor/tape/mediachanger/TestingDismountAcsCmd.hpp" + +#include <cppunit/extensions/HelperMacros.h> +#include <list> +#include <memory> +#include <sstream> +#include <string.h> + +namespace castor { +namespace tape { +namespace mediachanger { + +class DismountAcsCmdTest: public CppUnit::TestFixture { +private: + + 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); + duplicate[len] = '\0'; + return duplicate; + } + +public: + + void setUp() { + } + + 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; + } + } + + void testParceCmdLineWithNoArgs() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 1; + args->argv = new char *[2]; + args->argv[0] = dupString("dismountacs"); + args->argv[1] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingDismountAcsCmd cmd(inStream, outStream, errStream, acs); + CPPUNIT_ASSERT_THROW_MESSAGE("Calling parseCmdLine with no arguments", + cmd.parseCmdLine(args->argc, args->argv), + castor::exception::MissingOperand); + } + + void testParceCmdLineWithOnlyVolId() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 2; + args->argv = new char *[3]; + args->argv[0] = dupString("dismountacs"); + args->argv[1] = dupString("VIDVID"); + args->argv[2] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingDismountAcsCmd cmd(inStream, outStream, errStream, acs); + CPPUNIT_ASSERT_THROW_MESSAGE( + "Calling parseCmdLine with only volume identfier", + cmd.parseCmdLine(args->argc, args->argv), + castor::exception::MissingOperand); + } + + void testParceCmdLineWithShortForce() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 4; + args->argv = new char *[5]; + args->argv[0] = dupString("dismountacs"); + args->argv[1] = dupString("-f"); + args->argv[2] = dupString("VIDVID"); + args->argv[3] = dupString("111:112:113:114"); + args->argv[4] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingDismountAcsCmd cmd(inStream, outStream, errStream, acs); + DismountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing force is set after command line is parsed", + (BOOLEAN)TRUE, cmdLine.force); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + 111, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + 112, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + 113, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + 114, (int)cmdLine.driveId.drive); + } + + void testParceCmdLineWithLongForce() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 4; + args->argv = new char *[5]; + args->argv[0] = dupString("dismountacs"); + args->argv[1] = dupString("--force"); + args->argv[2] = dupString("VIDVID"); + args->argv[3] = dupString("111:112:113:114"); + args->argv[4] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingDismountAcsCmd cmd(inStream, outStream, errStream, acs); + DismountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing force is set after command line is parsed", + (BOOLEAN)TRUE, cmdLine.force); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + 111, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + 112, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + 113, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + 114, (int)cmdLine.driveId.drive); + } + + void testParceCmdLineWithShortHelp() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 2; + args->argv = new char *[3]; + args->argv[0] = dupString("dismountacs"); + args->argv[1] = dupString("-h"); + args->argv[2] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingDismountAcsCmd cmd(inStream, outStream, errStream, acs); + DismountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing help is set after command line is parsed", + true, cmdLine.help); + } + + void testParceCmdLineWithLongHelp() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 2; + args->argv = new char *[3]; + args->argv[0] = dupString("dismountacs"); + args->argv[1] = dupString("--help"); + args->argv[2] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingDismountAcsCmd cmd(inStream, outStream, errStream, acs); + DismountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing help is set after command line is parsed", + true, cmdLine.help); + } + + void testParceCmdLineWithVolIdAndDrive() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 3; + args->argv = new char *[4]; + args->argv[0] = dupString("dismountacs"); + args->argv[1] = dupString("VIDVID"); + args->argv[2] = dupString("111:112:113:114"); + args->argv[3] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingDismountAcsCmd cmd(inStream, outStream, errStream, acs); + DismountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW_MESSAGE("Testing valid volume identfier and drive", + cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing debug is not set", + false, cmdLine.debug); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing help is not set", + false, cmdLine.help); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing query is set to the default", + 10, cmdLine.queryInterval); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing timeout is set to the default", + 600, cmdLine.timeout); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + 111, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + 112, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + 113, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + 114, (int)cmdLine.driveId.drive); + } + + void testParceCmdLineWithShortDebug() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 4; + args->argv = new char *[5]; + args->argv[0] = dupString("dismountacs"); + args->argv[1] = dupString("-d"); + args->argv[2] = dupString("VIDVID"); + args->argv[3] = dupString("111:112:113:114"); + args->argv[4] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingDismountAcsCmd cmd(inStream, outStream, errStream, acs); + DismountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing debug is set after command line is parsed", + true, cmdLine.debug); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + 111, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + 112, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + 113, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + 114, (int)cmdLine.driveId.drive); + } + + void testParceCmdLineWithLongDebug() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 4; + args->argv = new char *[5]; + args->argv[0] = dupString("dismountacs"); + args->argv[1] = dupString("--debug"); + args->argv[2] = dupString("VIDVID"); + args->argv[3] = dupString("111:112:113:114"); + args->argv[4] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingDismountAcsCmd cmd(inStream, outStream, errStream, acs); + DismountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing debug is set after command line is parsed", + true, cmdLine.debug); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + 111, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + 112, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + 113, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + 114, (int)cmdLine.driveId.drive); + } + + void testParceCmdLineWithTooLongVolIdAndDrive() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 3; + args->argv = new char *[4]; + args->argv[0] = dupString("dismountacs"); + args->argv[1] = dupString("VIDVID7"); + args->argv[2] = dupString("111:112:113:114"); + args->argv[3] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingDismountAcsCmd cmd(inStream, outStream, errStream, acs); + CPPUNIT_ASSERT_THROW_MESSAGE("Testing volume identfier that is too long", + cmd.parseCmdLine(args->argc, args->argv), + castor::exception::InvalidArgument); + } + + void testParceCmdLineWithValidVolIdAndInvalidDrive() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 3; + args->argv = new char *[4]; + args->argv[0] = dupString("dismountacs"); + args->argv[1] = dupString("VIDVID"); + args->argv[2] = dupString("INVALID_DRIVE"); + args->argv[3] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingDismountAcsCmd cmd(inStream, outStream, errStream, acs); + CPPUNIT_ASSERT_THROW_MESSAGE( + "Testing valid volume identfier and invalid DRIVE", + cmd.parseCmdLine(args->argc, args->argv), + castor::exception::InvalidArgument); + } + + void testParceCmdLineWithShortTimeout() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 5; + args->argv = new char *[6]; + args->argv[0] = dupString("dismountacs"); + args->argv[1] = dupString("-t"); + args->argv[2] = dupString("2"); + args->argv[3] = dupString("VIDVID"); + args->argv[4] = dupString("111:112:113:114"); + args->argv[5] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingDismountAcsCmd cmd(inStream, outStream, errStream, acs); + DismountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing timeout is set after command line is parsed", + 2, cmdLine.timeout); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + 111, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + 112, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + 113, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + 114, (int)cmdLine.driveId.drive); + } + + void testParceCmdLineWithLongTimeout() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 5; + args->argv = new char *[6]; + args->argv[0] = dupString("dismountacs"); + args->argv[1] = dupString("--timeout"); + args->argv[2] = dupString("2"); + args->argv[3] = dupString("VIDVID"); + args->argv[4] = dupString("111:112:113:114"); + args->argv[5] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingDismountAcsCmd cmd(inStream, outStream, errStream, acs); + DismountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing timeout is set after command line is parsed", + 2, cmdLine.timeout); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + 111, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + 112, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + 113, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + 114, (int)cmdLine.driveId.drive); + } + + void testParceCmdLineWith0Timeout() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 5; + args->argv = new char *[6]; + args->argv[0] = dupString("dismountacs"); + args->argv[1] = dupString("--timeout"); + args->argv[2] = dupString("0"); + args->argv[3] = dupString("VIDVID"); + args->argv[4] = dupString("111:112:113:114"); + args->argv[5] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingDismountAcsCmd cmd(inStream, outStream, errStream, acs); + CPPUNIT_ASSERT_THROW_MESSAGE( + "Testing valid volume identfier and invalid DRIVE", + cmd.parseCmdLine(args->argc, args->argv), + castor::exception::InvalidArgument); + } + + void testParceCmdLineWithShortQuery() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 5; + args->argv = new char *[6]; + args->argv[0] = dupString("dismountacs"); + args->argv[1] = dupString("-q"); + args->argv[2] = dupString("1"); + args->argv[3] = dupString("VIDVID"); + args->argv[4] = dupString("111:112:113:114"); + args->argv[5] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingDismountAcsCmd cmd(inStream, outStream, errStream, acs); + DismountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing query is set after command line is parsed", + 1, cmdLine.queryInterval); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + 111, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + 112, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + 113, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + 114, (int)cmdLine.driveId.drive); + } + + void testParceCmdLineWithLongQuery() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 5; + args->argv = new char *[6]; + args->argv[0] = dupString("dismountacs"); + args->argv[1] = dupString("--query"); + args->argv[2] = dupString("1"); + args->argv[3] = dupString("VIDVID"); + args->argv[4] = dupString("111:112:113:114"); + args->argv[5] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingDismountAcsCmd cmd(inStream, outStream, errStream, acs); + DismountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing query is set after command line is parsed", + 1, cmdLine.queryInterval); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + 111, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + 112, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + 113, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + 114, (int)cmdLine.driveId.drive); + } + + void testParceCmdLineWith0Query() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 5; + args->argv = new char *[6]; + args->argv[0] = dupString("dismountacs"); + args->argv[1] = dupString("--query"); + args->argv[2] = dupString("0"); + args->argv[3] = dupString("VIDVID"); + args->argv[4] = dupString("111:112:113:114"); + args->argv[5] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingDismountAcsCmd cmd(inStream, outStream, errStream, acs); + CPPUNIT_ASSERT_THROW_MESSAGE( + "Testing valid volume identfier and invalid DRIVE", + cmd.parseCmdLine(args->argc, args->argv), + castor::exception::InvalidArgument); + } + + CPPUNIT_TEST_SUITE(DismountAcsCmdTest); + CPPUNIT_TEST(testParceCmdLineWithNoArgs); + CPPUNIT_TEST(testParceCmdLineWithOnlyVolId); + CPPUNIT_TEST(testParceCmdLineWithShortForce); + CPPUNIT_TEST(testParceCmdLineWithLongForce); + CPPUNIT_TEST(testParceCmdLineWithShortHelp); + CPPUNIT_TEST(testParceCmdLineWithLongHelp); + CPPUNIT_TEST(testParceCmdLineWithVolIdAndDrive); + CPPUNIT_TEST(testParceCmdLineWithShortDebug); + CPPUNIT_TEST(testParceCmdLineWithLongDebug); + CPPUNIT_TEST(testParceCmdLineWithTooLongVolIdAndDrive); + CPPUNIT_TEST(testParceCmdLineWithValidVolIdAndInvalidDrive); + CPPUNIT_TEST(testParceCmdLineWithShortTimeout); + CPPUNIT_TEST(testParceCmdLineWithLongTimeout); + CPPUNIT_TEST(testParceCmdLineWith0Timeout); + CPPUNIT_TEST(testParceCmdLineWithShortQuery); + CPPUNIT_TEST(testParceCmdLineWithLongQuery); + CPPUNIT_TEST(testParceCmdLineWith0Query); + CPPUNIT_TEST_SUITE_END(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(DismountAcsCmdTest); + +} // namespace mediachanger +} // namespace tape +} // namespace castor diff --git a/test/unittest/castor/tape/mediachanger/MockAcs.hpp b/test/unittest/castor/tape/mediachanger/MockAcs.hpp new file mode 100644 index 0000000000000000000000000000000000000000..743297a9ecc7beeefd32839f629e59e6e183b5c4 --- /dev/null +++ b/test/unittest/castor/tape/mediachanger/MockAcs.hpp @@ -0,0 +1,135 @@ +/****************************************************************************** + * test/unittest/castor/tape/mediachanger/MockAcs.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#ifndef TEST_UNITTEST_CASTOR_TAPE_MEDIACHANGER_MOCKACS_HPP +#define TEST_UNITTEST_CASTOR_TAPE_MEDIACHANGER_MOCKACS_HPP 1 + +#include "castor/tape/mediachanger/AcsCmd.hpp" + +namespace castor { +namespace tape { +namespace mediachanger { + +class MockAcs: public Acs { +public: + + /** + * Destructor. + */ + ~MockAcs() throw() { + } + + /** + * C++ wrapper around the acs_mount() function of the ACSLS C-API. + * + * @param seqNumber Client supplied sequence number. + * @param lockId Lock identifier or 0 meaning no lock. + * @param volId The identifier of the volume to be mounted. + * @param driveId The ID of the drive into which the volume is to be mounted. + * @param readOnly Set to true to request the volume be mounted for read-only + * access. + * @param bypass Set to true to override the ACSLS verification of + * compatibility between the drive and the media type of the volume. + * @return status value returned by acs_mount(). + */ + STATUS mount( + const SEQ_NO seqNumber, + const LOCKID lockId, + const VOLID &volId, + const DRIVEID &driveId, + const BOOLEAN readOnly, + const BOOLEAN bypass) + throw() { + return STATUS_SUCCESS; + } + + /** + * C++ wrapper around the acs_dismount() function of the ACSLS C-API. + * + * @param seqNumber Client supplied sequence number. + * @param lockId Lock identifier or 0 meaning no lock. + * @param volId The identifier of the volume to be mounted. + * @param driveId The ID of the drive into which the volume is to be mounted. + * @param force Set to true if the dismount should be forced. Forcing a + * dismount means dismounting the volume from the specified drive without + * checking the identifier of the volume. + * @return status value returned by acs_dismount(). + */ + STATUS dismount( + const SEQ_NO seqNumber, + const LOCKID lockId, + const VOLID &volId, + const DRIVEID &driveId, + const BOOLEAN force) + throw() { + return STATUS_SUCCESS; + } + + /** + * C++ wrapper around the acs_response() function of the ACSLS C-API. + * + * @param timeout Time in seconds to wait for a response. A value of -1 + * means block indefinitely and an a value of 0 means poll for the existence + * of a response. + * @param seqNumber Output parameter. If a response exists then seqNumber + * is set. + * @param reqId Output parameter. For an acknowledge response reqId is set + * to the request identifier of the original request. For an intermediate or + * final response reqId will be set to 0. + * @param rType Output parameter. Set to the type of the response. + * @param rBuf Output parameter. Set to the response information. + * @return status value returned by acs_response(). + */ + STATUS response( + const int timeout, + SEQ_NO &seqNumber, + REQ_ID &reqId, + ACS_RESPONSE_TYPE &rType, + ALIGNED_BYTES rBuf) throw() { + return STATUS_SUCCESS; + } + + /** + * C++ wrapper around the acs_query_volume() function of the ACSLS C-API. + * + * @param seqNumber Client supplied sequence number. + * @param volIds Array of the volume identifiers to be queried. + * @param count The number of volume identifiers contained iwthin the volId + * parameter. + * @return status value returned by acs_response(). + */ + STATUS queryVolume( + const SEQ_NO seqNumber, + VOLID (&volIds)[MAX_ID], + const unsigned short count) throw() { + return STATUS_SUCCESS; + } + +}; // class MockAcs + +} // namespace mediachanger +} // namespace tape +} // namespace castor + +#endif // TEST_UNITTEST_CASTOR_TAPE_MEDIACHANGER_MOCKACS_HPP diff --git a/test/unittest/castor/tape/mediachanger/MountAcsCmdLineTest.cpp b/test/unittest/castor/tape/mediachanger/MountAcsCmdLineTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a5ee1f06287f6ade7d351701cd922b572a5aa17 --- /dev/null +++ b/test/unittest/castor/tape/mediachanger/MountAcsCmdLineTest.cpp @@ -0,0 +1,81 @@ +/****************************************************************************** + * test/unittest/castor/tape/dismountacs/MountAcsCmdLineTest.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "castor/tape/mediachanger/MountAcsCmdLine.hpp" + +#include <cppunit/extensions/HelperMacros.h> + +namespace castor { +namespace tape { +namespace mediachanger { + +class MountAcsCmdLineTest: public CppUnit::TestFixture { +public: + + void setUp() { + } + + void tearDown() { + } + + void testConstructor() { + const MountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing debug flag is initialised to FALSE", + false, cmdLine.debug); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing help flag is initialised to FALSE", + false, cmdLine.help); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing readOnly flag is initialised to FALSE", + (BOOLEAN)FALSE, cmdLine.readOnly); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing timeout option is initialised to 0", + 0, cmdLine.timeout); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing query option is initialised to 0", + 0, cmdLine.queryInterval); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing driveId.panel_id.lsm_id.acs is initialised to 0", + 0, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing driveId.panel_id.lsm_id.lsm is initialised to 0", + 0, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing driveId.panel_id.panel is initialised to 0", + 0, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing driveId.drive is initialised to 0", + 0, (int)cmdLine.driveId.drive); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing volId is initialised to an empty string", + '\0', cmdLine.volId.external_label[0]); + } + + CPPUNIT_TEST_SUITE(MountAcsCmdLineTest); + CPPUNIT_TEST(testConstructor); + CPPUNIT_TEST_SUITE_END(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(MountAcsCmdLineTest); + +} // namespace mediachanger +} // namespace tape +} // namespace castor diff --git a/test/unittest/castor/tape/mediachanger/MountAcsCmdTest.cpp b/test/unittest/castor/tape/mediachanger/MountAcsCmdTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6d8573d265259704032846e48a66fdc9a119aa29 --- /dev/null +++ b/test/unittest/castor/tape/mediachanger/MountAcsCmdTest.cpp @@ -0,0 +1,578 @@ +/****************************************************************************** + * test/unittest/castor/tape/mediachanger/MountAcsCmdTest.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "test/unittest/castor/tape/mediachanger/MockAcs.hpp" +#include "test/unittest/castor/tape/mediachanger/TestingMountAcsCmd.hpp" + +#include <cppunit/extensions/HelperMacros.h> +#include <list> +#include <memory> +#include <sstream> +#include <string.h> + +namespace castor { +namespace tape { +namespace mediachanger { + +class MountAcsCmdTest: public CppUnit::TestFixture { +private: + + 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); + duplicate[len] = '\0'; + return duplicate; + } + +public: + + void setUp() { + } + + 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; + } + } + + void testParceCmdLineWithNoArgs() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 1; + args->argv = new char *[2]; + args->argv[0] = dupString("mountacs"); + args->argv[1] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingMountAcsCmd cmd(inStream, outStream, errStream, acs); + CPPUNIT_ASSERT_THROW_MESSAGE("Calling parseCmdLine with no arguments", + cmd.parseCmdLine(args->argc, args->argv), + castor::exception::MissingOperand); + } + + void testParceCmdLineWithOnlyVolId() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 2; + args->argv = new char *[3]; + args->argv[0] = dupString("mountacs"); + args->argv[1] = dupString("VIDVID"); + args->argv[2] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingMountAcsCmd cmd(inStream, outStream, errStream, acs); + CPPUNIT_ASSERT_THROW_MESSAGE( + "Calling parseCmdLine with only volume identfier", + cmd.parseCmdLine(args->argc, args->argv), + castor::exception::MissingOperand); + } + + void testParceCmdLineWithShortReadOnly() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 4; + args->argv = new char *[5]; + args->argv[0] = dupString("mountacs"); + args->argv[1] = dupString("-r"); + args->argv[2] = dupString("VIDVID"); + args->argv[3] = dupString("111:112:113:114"); + args->argv[4] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingMountAcsCmd cmd(inStream, outStream, errStream, acs); + MountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing readOnly is set after command line is parsed", + (BOOLEAN)TRUE, cmdLine.readOnly); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + 111, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + 112, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + 113, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + 114, (int)cmdLine.driveId.drive); + } + + void testParceCmdLineWithLongReadOnly() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 4; + args->argv = new char *[5]; + args->argv[0] = dupString("mountacs"); + args->argv[1] = dupString("--readonly"); + args->argv[2] = dupString("VIDVID"); + args->argv[3] = dupString("111:112:113:114"); + args->argv[4] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingMountAcsCmd cmd(inStream, outStream, errStream, acs); + MountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing readOnly is set after command line is parsed", + (BOOLEAN)TRUE, cmdLine.readOnly); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + 111, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + 112, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + 113, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + 114, (int)cmdLine.driveId.drive); + } + + void testParceCmdLineWithShortHelp() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 2; + args->argv = new char *[3]; + args->argv[0] = dupString("mountacs"); + args->argv[1] = dupString("-h"); + args->argv[2] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingMountAcsCmd cmd(inStream, outStream, errStream, acs); + MountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing help is set after command line is parsed", + true, cmdLine.help); + } + + void testParceCmdLineWithLongHelp() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 2; + args->argv = new char *[3]; + args->argv[0] = dupString("mountacs"); + args->argv[1] = dupString("--help"); + args->argv[2] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingMountAcsCmd cmd(inStream, outStream, errStream, acs); + MountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing help is set after command line is parsed", + true, cmdLine.help); + } + + void testParceCmdLineWithVolIdAndDrive() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 3; + args->argv = new char *[4]; + args->argv[0] = dupString("mountacs"); + args->argv[1] = dupString("VIDVID"); + args->argv[2] = dupString("111:112:113:114"); + args->argv[3] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingMountAcsCmd cmd(inStream, outStream, errStream, acs); + MountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW_MESSAGE("Testing valid volume identfier and drive", + cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing debug is not set", + false, cmdLine.debug); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing help is not set", + false, cmdLine.help); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing query is set to the default", + 10, cmdLine.queryInterval); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing timeout is set to the default", + 600, cmdLine.timeout); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + 111, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + 112, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + 113, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + 114, (int)cmdLine.driveId.drive); + } + + void testParceCmdLineWithShortDebug() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 4; + args->argv = new char *[5]; + args->argv[0] = dupString("mountacs"); + args->argv[1] = dupString("-d"); + args->argv[2] = dupString("VIDVID"); + args->argv[3] = dupString("111:112:113:114"); + args->argv[4] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingMountAcsCmd cmd(inStream, outStream, errStream, acs); + MountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing debug is set after command line is parsed", + true, cmdLine.debug); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + 111, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + 112, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + 113, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + 114, (int)cmdLine.driveId.drive); + } + + void testParceCmdLineWithLongDebug() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 4; + args->argv = new char *[5]; + args->argv[0] = dupString("mountacs"); + args->argv[1] = dupString("--debug"); + args->argv[2] = dupString("VIDVID"); + args->argv[3] = dupString("111:112:113:114"); + args->argv[4] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingMountAcsCmd cmd(inStream, outStream, errStream, acs); + MountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing debug is set after command line is parsed", + true, cmdLine.debug); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + 111, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + 112, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + 113, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + 114, (int)cmdLine.driveId.drive); + } + + void testParceCmdLineWithTooLongVolIdAndDrive() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 3; + args->argv = new char *[4]; + args->argv[0] = dupString("mountacs"); + args->argv[1] = dupString("VIDVID7"); + args->argv[2] = dupString("111:112:113:114"); + args->argv[3] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingMountAcsCmd cmd(inStream, outStream, errStream, acs); + CPPUNIT_ASSERT_THROW_MESSAGE("Testing volume identfier that is too long", + cmd.parseCmdLine(args->argc, args->argv), + castor::exception::InvalidArgument); + } + + void testParceCmdLineWithValidVolIdAndInvalidDrive() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 3; + args->argv = new char *[4]; + args->argv[0] = dupString("mountacs"); + args->argv[1] = dupString("VIDVID"); + args->argv[2] = dupString("INVALID_DRIVE"); + args->argv[3] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingMountAcsCmd cmd(inStream, outStream, errStream, acs); + CPPUNIT_ASSERT_THROW_MESSAGE( + "Testing valid volume identfier and invalid DRIVE", + cmd.parseCmdLine(args->argc, args->argv), + castor::exception::InvalidArgument); + } + + void testParceCmdLineWithShortTimeout() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 5; + args->argv = new char *[6]; + args->argv[0] = dupString("mountacs"); + args->argv[1] = dupString("-t"); + args->argv[2] = dupString("2"); + args->argv[3] = dupString("VIDVID"); + args->argv[4] = dupString("111:112:113:114"); + args->argv[5] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingMountAcsCmd cmd(inStream, outStream, errStream, acs); + MountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing timeout is set after command line is parsed", + 2, cmdLine.timeout); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + 111, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + 112, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + 113, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + 114, (int)cmdLine.driveId.drive); + } + + void testParceCmdLineWithLongTimeout() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 5; + args->argv = new char *[6]; + args->argv[0] = dupString("mountacs"); + args->argv[1] = dupString("--timeout"); + args->argv[2] = dupString("2"); + args->argv[3] = dupString("VIDVID"); + args->argv[4] = dupString("111:112:113:114"); + args->argv[5] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingMountAcsCmd cmd(inStream, outStream, errStream, acs); + MountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing timeout is set after command line is parsed", + 2, cmdLine.timeout); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + 111, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + 112, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + 113, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + 114, (int)cmdLine.driveId.drive); + } + + void testParceCmdLineWith0Timeout() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 5; + args->argv = new char *[6]; + args->argv[0] = dupString("mountacs"); + args->argv[1] = dupString("--timeout"); + args->argv[2] = dupString("0"); + args->argv[3] = dupString("VIDVID"); + args->argv[4] = dupString("111:112:113:114"); + args->argv[5] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingMountAcsCmd cmd(inStream, outStream, errStream, acs); + CPPUNIT_ASSERT_THROW_MESSAGE( + "Testing valid volume identfier and invalid DRIVE", + cmd.parseCmdLine(args->argc, args->argv), + castor::exception::InvalidArgument); + } + + void testParceCmdLineWithShortQuery() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 5; + args->argv = new char *[6]; + args->argv[0] = dupString("mountacs"); + args->argv[1] = dupString("-q"); + args->argv[2] = dupString("1"); + args->argv[3] = dupString("VIDVID"); + args->argv[4] = dupString("111:112:113:114"); + args->argv[5] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingMountAcsCmd cmd(inStream, outStream, errStream, acs); + MountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing query is set after command line is parsed", + 1, cmdLine.queryInterval); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + 111, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + 112, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + 113, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + 114, (int)cmdLine.driveId.drive); + } + + void testParceCmdLineWithLongQuery() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 5; + args->argv = new char *[6]; + args->argv[0] = dupString("mountacs"); + args->argv[1] = dupString("--query"); + args->argv[2] = dupString("1"); + args->argv[3] = dupString("VIDVID"); + args->argv[4] = dupString("111:112:113:114"); + args->argv[5] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingMountAcsCmd cmd(inStream, outStream, errStream, acs); + MountAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing query is set after command line is parsed", + 1, cmdLine.queryInterval); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing ACS number", + 111, (int)cmdLine.driveId.panel_id.lsm_id.acs); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing LSM number", + 112, (int)cmdLine.driveId.panel_id.lsm_id.lsm); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing panel number", + 113, (int)cmdLine.driveId.panel_id.panel); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing drive number", + 114, (int)cmdLine.driveId.drive); + } + + void testParceCmdLineWith0Query() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 5; + args->argv = new char *[6]; + args->argv[0] = dupString("mountacs"); + args->argv[1] = dupString("--query"); + args->argv[2] = dupString("0"); + args->argv[3] = dupString("VIDVID"); + args->argv[4] = dupString("111:112:113:114"); + args->argv[5] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingMountAcsCmd cmd(inStream, outStream, errStream, acs); + CPPUNIT_ASSERT_THROW_MESSAGE( + "Testing valid volume identfier and invalid DRIVE", + cmd.parseCmdLine(args->argc, args->argv), + castor::exception::InvalidArgument); + } + + CPPUNIT_TEST_SUITE(MountAcsCmdTest); + CPPUNIT_TEST(testParceCmdLineWithNoArgs); + CPPUNIT_TEST(testParceCmdLineWithOnlyVolId); + CPPUNIT_TEST(testParceCmdLineWithShortReadOnly); + CPPUNIT_TEST(testParceCmdLineWithLongReadOnly); + CPPUNIT_TEST(testParceCmdLineWithShortHelp); + CPPUNIT_TEST(testParceCmdLineWithLongHelp); + CPPUNIT_TEST(testParceCmdLineWithVolIdAndDrive); + CPPUNIT_TEST(testParceCmdLineWithShortDebug); + CPPUNIT_TEST(testParceCmdLineWithLongDebug); + CPPUNIT_TEST(testParceCmdLineWithTooLongVolIdAndDrive); + CPPUNIT_TEST(testParceCmdLineWithValidVolIdAndInvalidDrive); + CPPUNIT_TEST(testParceCmdLineWithShortTimeout); + CPPUNIT_TEST(testParceCmdLineWithLongTimeout); + CPPUNIT_TEST(testParceCmdLineWith0Timeout); + CPPUNIT_TEST(testParceCmdLineWithShortQuery); + CPPUNIT_TEST(testParceCmdLineWithLongQuery); + CPPUNIT_TEST(testParceCmdLineWith0Query); + CPPUNIT_TEST_SUITE_END(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(MountAcsCmdTest); + +} // namespace mediachanger +} // namespace tape +} // namespace castor diff --git a/test/unittest/castor/tape/mediachanger/QueryVolumeAcsCmdLineTest.cpp b/test/unittest/castor/tape/mediachanger/QueryVolumeAcsCmdLineTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1c1d1d6ca8057b54aca404df43968dc24cc81ae0 --- /dev/null +++ b/test/unittest/castor/tape/mediachanger/QueryVolumeAcsCmdLineTest.cpp @@ -0,0 +1,66 @@ +/****************************************************************************** + * test/unittest/castor/tape/dismountacs/QueryVolumeAcsCmdLineTest.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "castor/tape/mediachanger/QueryVolumeAcsCmdLine.hpp" + +#include <cppunit/extensions/HelperMacros.h> + +namespace castor { +namespace tape { +namespace mediachanger { + +class QueryVolumeAcsCmdLineTest: public CppUnit::TestFixture { +public: + + void setUp() { + } + + void tearDown() { + } + + void testConstructor() { + const QueryVolumeAcsCmdLine cmdLine; + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing debug flag is initialised to FALSE", + (BOOLEAN)FALSE, cmdLine.debug); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing help flag is initialised to FALSE", + (BOOLEAN)FALSE, cmdLine.help); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing timeout option is initialised to 0", + 0, cmdLine.timeout); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing query option is initialised to 0", + 0, cmdLine.queryInterval); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing volId is initialised to an empty string", + '\0', cmdLine.volId.external_label[0]); + } + + CPPUNIT_TEST_SUITE(QueryVolumeAcsCmdLineTest); + CPPUNIT_TEST(testConstructor); + CPPUNIT_TEST_SUITE_END(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(QueryVolumeAcsCmdLineTest); + +} // namespace mediachanger +} // namespace tape +} // namespace castor diff --git a/test/unittest/castor/tape/mediachanger/QueryVolumeAcsCmdTest.cpp b/test/unittest/castor/tape/mediachanger/QueryVolumeAcsCmdTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cb510c1947eefa4a10c0718f71e4ff5cf5fb0d36 --- /dev/null +++ b/test/unittest/castor/tape/mediachanger/QueryVolumeAcsCmdTest.cpp @@ -0,0 +1,402 @@ +/****************************************************************************** + * test/unittest/castor/tape/mediachanger/QueryVolumeAcsCmdTest.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#include "test/unittest/castor/tape/mediachanger/MockAcs.hpp" +#include "test/unittest/castor/tape/mediachanger/TestingQueryVolumeAcsCmd.hpp" + +#include <cppunit/extensions/HelperMacros.h> +#include <list> +#include <memory> +#include <sstream> +#include <string.h> + +namespace castor { +namespace tape { +namespace mediachanger { + +class QueryVolumeAcsCmdTest: public CppUnit::TestFixture { +private: + + 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); + duplicate[len] = '\0'; + return duplicate; + } + +public: + + void setUp() { + } + + 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; + } + } + + void testParceCmdLineWithNoArgs() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 1; + args->argv = new char *[2]; + args->argv[0] = dupString("queryvolume"); + args->argv[1] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingQueryVolumeAcsCmd cmd(inStream, outStream, errStream, acs); + CPPUNIT_ASSERT_THROW_MESSAGE("Calling parseCmdLine with no arguments", + cmd.parseCmdLine(args->argc, args->argv), + castor::exception::MissingOperand); + } + + void testParceCmdLineWithValidVolId() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 2; + args->argv = new char *[3]; + args->argv[0] = dupString("queryvolume"); + args->argv[1] = dupString("VIDVID"); + args->argv[2] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingQueryVolumeAcsCmd cmd(inStream, outStream, errStream, acs); + QueryVolumeAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW_MESSAGE( + "Calling parseCmdLine with valid volume-identfier", + cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing debug is not set", + (BOOLEAN)FALSE, cmdLine.debug); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing help is not set", + (BOOLEAN)FALSE, cmdLine.help); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing query is set to the default", + 1, cmdLine.queryInterval); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing timeout is set to the default", + 20, cmdLine.timeout); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + } + + void testParceCmdLineWithShortHelp() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 2; + args->argv = new char *[3]; + args->argv[0] = dupString("queryvolume"); + args->argv[1] = dupString("-h"); + args->argv[2] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingQueryVolumeAcsCmd cmd(inStream, outStream, errStream, acs); + QueryVolumeAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing help is set after command line is parsed", + (BOOLEAN)TRUE, cmdLine.help); + } + + void testParceCmdLineWithLongHelp() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 2; + args->argv = new char *[3]; + args->argv[0] = dupString("queryvolume"); + args->argv[1] = dupString("--help"); + args->argv[2] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingQueryVolumeAcsCmd cmd(inStream, outStream, errStream, acs); + QueryVolumeAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing help is set after command line is parsed", + (BOOLEAN)TRUE, cmdLine.help); + } + + void testParceCmdLineWithShortDebug() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 3; + args->argv = new char *[4]; + args->argv[0] = dupString("queryvolume"); + args->argv[1] = dupString("-d"); + args->argv[2] = dupString("VIDVID"); + args->argv[3] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingQueryVolumeAcsCmd cmd(inStream, outStream, errStream, acs); + QueryVolumeAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing debug is set after command line is parsed", + (BOOLEAN)TRUE, cmdLine.debug); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + } + + void testParceCmdLineWithLongDebug() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 3; + args->argv = new char *[4]; + args->argv[0] = dupString("queryvolume"); + args->argv[1] = dupString("--debug"); + args->argv[2] = dupString("VIDVID"); + args->argv[3] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingQueryVolumeAcsCmd cmd(inStream, outStream, errStream, acs); + QueryVolumeAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing debug is set after command line is parsed", + (BOOLEAN)TRUE, cmdLine.debug); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + } + + void testParceCmdLineWithTooLongVolId() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 2; + args->argv = new char *[3]; + args->argv[0] = dupString("queryvolume"); + args->argv[1] = dupString("VIDVID7"); + args->argv[2] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingQueryVolumeAcsCmd cmd(inStream, outStream, errStream, acs); + CPPUNIT_ASSERT_THROW_MESSAGE("Testing volume identfier that is too long", + cmd.parseCmdLine(args->argc, args->argv), + castor::exception::InvalidArgument); + } + + void testParceCmdLineWithShortTimeout() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 4; + args->argv = new char *[5]; + args->argv[0] = dupString("queryvolume"); + args->argv[1] = dupString("-t"); + args->argv[2] = dupString("2"); + args->argv[3] = dupString("VIDVID"); + args->argv[4] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingQueryVolumeAcsCmd cmd(inStream, outStream, errStream, acs); + QueryVolumeAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing timeout is set after command line is parsed", + 2, cmdLine.timeout); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + } + + void testParceCmdLineWithLongTimeout() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 4; + args->argv = new char *[5]; + args->argv[0] = dupString("queryvolume"); + args->argv[1] = dupString("--timeout"); + args->argv[2] = dupString("2"); + args->argv[3] = dupString("VIDVID"); + args->argv[4] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingQueryVolumeAcsCmd cmd(inStream, outStream, errStream, acs); + QueryVolumeAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing timeout is set after command line is parsed", + 2, cmdLine.timeout); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + } + + void testParceCmdLineWith0Timeout() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 4; + args->argv = new char *[5]; + args->argv[0] = dupString("queryvolume"); + args->argv[1] = dupString("--timeout"); + args->argv[2] = dupString("0"); + args->argv[3] = dupString("VIDVID"); + args->argv[4] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingQueryVolumeAcsCmd cmd(inStream, outStream, errStream, acs); + CPPUNIT_ASSERT_THROW_MESSAGE( + "Testing valid volume identfier and invalid DRIVE", + cmd.parseCmdLine(args->argc, args->argv), + castor::exception::InvalidArgument); + } + + void testParceCmdLineWithShortQuery() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 4; + args->argv = new char *[5]; + args->argv[0] = dupString("queryvolume"); + args->argv[1] = dupString("-q"); + args->argv[2] = dupString("1"); + args->argv[3] = dupString("VIDVID"); + args->argv[4] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingQueryVolumeAcsCmd cmd(inStream, outStream, errStream, acs); + QueryVolumeAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing query is set after command line is parsed", + 1, cmdLine.queryInterval); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + } + + void testParceCmdLineWithLongQuery() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 4; + args->argv = new char *[5]; + args->argv[0] = dupString("queryvolume"); + args->argv[1] = dupString("--query"); + args->argv[2] = dupString("1"); + args->argv[3] = dupString("VIDVID"); + args->argv[4] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingQueryVolumeAcsCmd cmd(inStream, outStream, errStream, acs); + QueryVolumeAcsCmdLine cmdLine; + CPPUNIT_ASSERT_NO_THROW(cmdLine = cmd.parseCmdLine(args->argc, args->argv)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Testing query is set after command line is parsed", + 1, cmdLine.queryInterval); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing volume identfier was parsed", + std::string("VIDVID"), std::string(cmdLine.volId.external_label)); + } + + void testParceCmdLineWith0Query() { + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 4; + args->argv = new char *[5]; + args->argv[0] = dupString("queryvolume"); + args->argv[1] = dupString("--query"); + args->argv[2] = dupString("0"); + args->argv[3] = dupString("VIDVID"); + args->argv[4] = NULL; + + std::istringstream inStream; + std::ostringstream outStream; + std::ostringstream errStream; + MockAcs acs; + TestingQueryVolumeAcsCmd cmd(inStream, outStream, errStream, acs); + CPPUNIT_ASSERT_THROW_MESSAGE( + "Testing valid volume identfier and invalid DRIVE", + cmd.parseCmdLine(args->argc, args->argv), + castor::exception::InvalidArgument); + } + + CPPUNIT_TEST_SUITE(QueryVolumeAcsCmdTest); + CPPUNIT_TEST(testParceCmdLineWithNoArgs); + CPPUNIT_TEST(testParceCmdLineWithValidVolId); + CPPUNIT_TEST(testParceCmdLineWithShortHelp); + CPPUNIT_TEST(testParceCmdLineWithLongHelp); + CPPUNIT_TEST(testParceCmdLineWithShortDebug); + CPPUNIT_TEST(testParceCmdLineWithLongDebug); + CPPUNIT_TEST(testParceCmdLineWithTooLongVolId); + CPPUNIT_TEST(testParceCmdLineWithShortTimeout); + CPPUNIT_TEST(testParceCmdLineWithLongTimeout); + CPPUNIT_TEST(testParceCmdLineWith0Timeout); + CPPUNIT_TEST(testParceCmdLineWithShortQuery); + CPPUNIT_TEST(testParceCmdLineWithLongQuery); + CPPUNIT_TEST(testParceCmdLineWith0Query); + CPPUNIT_TEST_SUITE_END(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(QueryVolumeAcsCmdTest); + +} // namespace mediachanger +} // namespace tape +} // namespace castor diff --git a/test/unittest/castor/tape/mediachanger/TestingAcs.hpp b/test/unittest/castor/tape/mediachanger/TestingAcs.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8496694f997cf292b83998c618f93146f34747c8 --- /dev/null +++ b/test/unittest/castor/tape/mediachanger/TestingAcs.hpp @@ -0,0 +1,92 @@ +/****************************************************************************** + * test/unittest/castor/tape/mediachanger/MockAcs.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#ifndef TEST_UNITTEST_CASTOR_TAPE_MEDIACHANGER_MOCKACS_HPP +#define TEST_UNITTEST_CASTOR_TAPE_MEDIACHANGER_MOCKACS_HPP 1 + +#include "castor/tape/mediachanger/AcsCmd.hpp" + +namespace castor { +namespace tape { +namespace mediachanger { + +class MockAcs: public Acs { +public: + + /** + * Destructor. + */ + ~MockAcs() throw() { + } + + /** + * C++ wrapper around the acs_mount function of the ACSLS C-API. + * + * @param seqNumber Client supplied sequence number. + * @param lockId Lock identifier or 0 meaning no lock. + * @param volId The volume ID of the tape to be mounted. + * @param driveId The ID of the drive into which the tape is to be mounted. + * @param readOnly Set to true to request the tape be mounted for read-only + * access. + * @param bypass Set to true to override the ACSLS verification of + * compatibility between the tape drive and the media type of the cartridge. + */ + void mount( + const SEQ_NO seqNumber, + const LOCKID lockId, + const std::string &volId, + const DRIVEID &driveId, + const bool readOnly, + const bool bypass) + throw(castor::exception::Internal, castor::exception::MountFailed); + + /** + * C++ wrapper around the acs_response function of the ACSLS C-API. + * + * @param timeout Time in seconds to wait for a response. A value of -1 + * means block indefinitely and an a value of 0 means poll for the existence + * of a response. + * @param seqNumber Output parameter. If a response exists then seqNumber + * is set. + * @param reqId Output parameter. For an acknowledge response reqId is set + * to the request identifier of the original request. For an intermediate or + * final response reqId will be set to 0. + * @param type Output parameter. Set to the type of the response. + * @param buffer Output parameter. Set to the response information. + * @return The status. + */ + STATUS response( + const int timeout, + SEQ_NO &seqNumber, + REQ_ID &reqId, + ACS_RESPONSE_TYPE &type, + ALIGNED_BYTES *buffer) + throw(); +}; // class MockAcs + +} // namespace mediachanger +} // namespace tape +} // namespace castor + +#endif // TEST_UNITTEST_CASTOR_TAPE_MEDIACHANGER_MOCKACS_HPP diff --git a/test/unittest/castor/tape/mediachanger/TestingAcsCmd.hpp b/test/unittest/castor/tape/mediachanger/TestingAcsCmd.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7ff0a2fa9a8e68abb22d3c3c948736b9cd137ef7 --- /dev/null +++ b/test/unittest/castor/tape/mediachanger/TestingAcsCmd.hpp @@ -0,0 +1,59 @@ +/****************************************************************************** + * test/unittest/castor/tape/mediachanger/TestingAcsCmd.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#ifndef TEST_UNITTEST_CASTOR_TAPE_MEDIACHANGER_TESTINGMOUNTACSCMD_HPP +#define TEST_UNITTEST_CASTOR_TAPE_MEDIACHANGER_TESTINGMOUNTACSCMD_HPP 1 + +#include "castor/tape/mediachanger/AcsCmd.hpp" + +namespace castor { +namespace tape { +namespace mediachanger { + +class TestingAcsCmd: public AcsCmd { +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. + */ + TestingAcsCmd(std::istream &inStream, std::ostream &outStream, + std::ostream &errStream, Acs &acs) throw(): + AcsCmd(inStream, outStream, errStream, acs) { + } + + ~TestingAcsCmd() throw() { + } + +}; // class TestingAcsCmd + +} // namespace mediachanger +} // namespace tape +} // namespace castor + +#endif // TEST_UNITTEST_CASTOR_TAPE_MEDIACHANGER_TESTINGMOUNTACSCMD_HPP diff --git a/test/unittest/castor/tape/mediachanger/TestingAcsImpl.hpp b/test/unittest/castor/tape/mediachanger/TestingAcsImpl.hpp new file mode 100644 index 0000000000000000000000000000000000000000..39dc01d959cb1711e9a97b21e26a1792c99292ad --- /dev/null +++ b/test/unittest/castor/tape/mediachanger/TestingAcsImpl.hpp @@ -0,0 +1,45 @@ +/****************************************************************************** + * test/unittest/castor/tape/mediachanger/TestingAcsImpl.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#ifndef TEST_UNITTEST_CASTOR_TAPE_MEDIACHANGER_TESTINGACSIMPL_HPP +#define TEST_UNITTEST_CASTOR_TAPE_MEDIACHANGER_TESTINGACSIMPL_HPP 1 + +#include "castor/tape/mediachanger/AcsImpl.hpp" + +namespace castor { +namespace tape { +namespace mediachanger { + +class TestingAcsImpl: public AcsImpl { +public: + + using AcsImpl::driveId2DRIVEID; + +}; // class TestingAcsImpl + +} // namespace mediachanger +} // namespace tape +} // namespace castor + +#endif // TEST_UNITTEST_CASTOR_TAPE_MEDIACHANGER_TESTINGACSIMPL_HPP diff --git a/test/unittest/castor/tape/mediachanger/TestingDismountAcsCmd.hpp b/test/unittest/castor/tape/mediachanger/TestingDismountAcsCmd.hpp new file mode 100644 index 0000000000000000000000000000000000000000..575cb7b0941fe12ac776e51e04410e198e5f0712 --- /dev/null +++ b/test/unittest/castor/tape/mediachanger/TestingDismountAcsCmd.hpp @@ -0,0 +1,58 @@ +/****************************************************************************** + * test/unittest/castor/tape/mediachanger/TestingDismountAcsCmd.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#ifndef TEST_UNITTEST_CASTOR_TAPE_DISMOUNTACS_TESTINGMOUNTACSCMD_HPP +#define TEST_UNITTEST_CASTOR_TAPE_DISMOUNTACS_TESTINGMOUNTACSCMD_HPP 1 + +#include "castor/tape/mediachanger/DismountAcsCmd.hpp" + +namespace castor { +namespace tape { +namespace mediachanger { + +class TestingDismountAcsCmd: public DismountAcsCmd { +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. + */ + TestingDismountAcsCmd(std::istream &inStream, std::ostream &outStream, + std::ostream &errStream, Acs &acs) throw(): + DismountAcsCmd(inStream, outStream, errStream, acs) { + } + + using DismountAcsCmd::parseCmdLine; + +}; // class TestingDismountAcsCmd + +} // namespace mediachanger +} // namespace tape +} // namespace castor + +#endif // TEST_UNITTEST_CASTOR_TAPE_DISMOUNTACS_TESTINGMOUNTACSCMD_HPP diff --git a/test/unittest/castor/tape/mediachanger/TestingMountAcsCmd.hpp b/test/unittest/castor/tape/mediachanger/TestingMountAcsCmd.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7ead17ef0f5715d94dbf152ebda9fb4b7026d337 --- /dev/null +++ b/test/unittest/castor/tape/mediachanger/TestingMountAcsCmd.hpp @@ -0,0 +1,57 @@ +/****************************************************************************** + * test/unittest/castor/tape/mediachanger/TestingMountAcsCmd.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#ifndef TEST_UNITTEST_CASTOR_TAPE_MEDIACHANGER_TESTINGMOUNTACSCMD_HPP +#define TEST_UNITTEST_CASTOR_TAPE_MEDIACHANGER_TESTINGMOUNTACSCMD_HPP 1 + +#include "castor/tape/mediachanger/MountAcsCmd.hpp" + +namespace castor { +namespace tape { +namespace mediachanger { + +class TestingMountAcsCmd: public MountAcsCmd { +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. + */ + TestingMountAcsCmd(std::istream &inStream, std::ostream &outStream, + std::ostream &errStream, Acs &acs) throw(): + MountAcsCmd(inStream, outStream, errStream, acs) { + } + + using MountAcsCmd::parseCmdLine; + +}; // class TestingMountAcsCmd + +} // namespace mediachanger +} // namespace tape +} // namespace castor + +#endif // TEST_UNITTEST_CASTOR_TAPE_MEDIACHANGER_TESTINGMOUNTACSCMD_HPP diff --git a/test/unittest/castor/tape/mediachanger/TestingQueryVolumeAcsCmd.hpp b/test/unittest/castor/tape/mediachanger/TestingQueryVolumeAcsCmd.hpp new file mode 100644 index 0000000000000000000000000000000000000000..68c53a8d062ba9519a57e3a420402b249bf0ab80 --- /dev/null +++ b/test/unittest/castor/tape/mediachanger/TestingQueryVolumeAcsCmd.hpp @@ -0,0 +1,57 @@ +/****************************************************************************** + * test/unittest/castor/tape/mediachanger/TestingQueryVolumeAcsCmd.hpp + * + * 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 Steven.Murray@cern.ch + *****************************************************************************/ + +#ifndef TEST_UNITTEST_CASTOR_TAPE_MEDIACHANGER_TESTINGQUERYVOLUMEACSCMD_HPP +#define TEST_UNITTEST_CASTOR_TAPE_MEDIACHANGER_TESTINGQUERYVOLUMEACSCMD_HPP 1 + +#include "castor/tape/mediachanger/QueryVolumeAcsCmd.hpp" + +namespace castor { +namespace tape { +namespace mediachanger { + +class TestingQueryVolumeAcsCmd: public QueryVolumeAcsCmd { +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. + */ + TestingQueryVolumeAcsCmd(std::istream &inStream, std::ostream &outStream, + std::ostream &errStream, Acs &acs) throw(): + QueryVolumeAcsCmd(inStream, outStream, errStream, acs) { + } + + using QueryVolumeAcsCmd::parseCmdLine; + +}; // class TestingQueryVolumeAcsCmd + +} // namespace mediachanger +} // namespace tape +} // namespace castor + +#endif // TEST_UNITTEST_CASTOR_TAPE_MEDIACHANGER_TESTINGQUERYVOLUMEACSCMD_HPP