From ae64ec8065a3a8cb1c4a4fd799bb436b04500b11 Mon Sep 17 00:00:00 2001 From: Steven Murray <murrayc3@cern.ch> Date: Tue, 1 Oct 2013 07:55:05 +0000 Subject: [PATCH] bug #102728: RFE: Develop Oracle ACS compatible executables for rmcd This commit does two things. Firstly it adds the first version of the source code for the executables to help the rmcd daemon to work with Oracle ACS compatible tape-libraries. Secondly it refactors and cleans up some of the rmcd daemon code. Please note that the source code of the binaries to help the rmcd work with Oracle ACS tape-libraries is neither compiled or packaged into rpms. Therefore there will be no affect on the current 2.1.14 release concerning these executables. --- .gitignore | 3 + castor/tape/Imakefile | 1 + castor/tape/rmc/Acs.cpp | 162 +++++ castor/tape/rmc/Acs.hpp | 177 ++++++ castor/tape/rmc/AcsCmd.cpp | 143 +++++ castor/tape/rmc/AcsCmd.hpp | 165 +++++ castor/tape/rmc/AcsDismountCmd.cpp | 305 +++++++++ castor/tape/rmc/AcsDismountCmd.hpp | 150 +++++ castor/tape/rmc/AcsDismountCmdLine.cpp | 41 ++ castor/tape/rmc/AcsDismountCmdLine.hpp | 96 +++ castor/tape/rmc/AcsDismountMain.cpp | 39 ++ castor/tape/rmc/AcsImpl.cpp | 84 +++ castor/tape/rmc/AcsImpl.hpp | 129 ++++ castor/tape/rmc/AcsMountCmd.cpp | 306 ++++++++++ castor/tape/rmc/AcsMountCmd.hpp | 144 +++++ castor/tape/rmc/AcsMountCmdLine.cpp | 41 ++ castor/tape/rmc/AcsMountCmdLine.hpp | 93 +++ castor/tape/rmc/AcsMountMain.cpp | 40 ++ castor/tape/rmc/AcsQueryVolumeCmd.cpp | 352 +++++++++++ castor/tape/rmc/AcsQueryVolumeCmd.hpp | 159 +++++ castor/tape/rmc/AcsQueryVolumeCmdLine.cpp | 37 ++ castor/tape/rmc/AcsQueryVolumeCmdLine.hpp | 83 +++ castor/tape/rmc/AcsQueryVolumeMain.cpp | 40 ++ castor/tape/rmc/DebugBuf.cpp | 75 +++ castor/tape/rmc/DebugBuf.hpp | 105 ++++ castor/tape/rmc/Imakefile | 100 +++ castor/tape/rmc/castor-tape-acs-dismount.man | 54 ++ castor/tape/rmc/castor-tape-acs-mount.man | 55 ++ .../tape/rmc/castor-tape-acs-queryvolume.man | 50 ++ debian/castor-devel.install.perm | 4 - h/Imakefile | 4 - h/rmc.h | 77 --- h/rmc_api.h | 3 +- h/rmc_constants.h | 42 ++ h/rmc_logit.h | 11 + h/rmc_logreq.h | 11 + h/rmc_marshall_element.h | 13 + h/rmc_procreq.h | 46 ++ h/rmc_send_scsi_cmd.h | 44 ++ h/rmc_sendrep.h | 11 + h/rmc_server_api.h | 17 - h/rmc_smcsubr.h | 72 +++ h/rmc_smcsubr2.h | 42 ++ h/sendscsicmd.h | 16 +- h/smc.h | 86 --- h/smc_constants.h | 33 + h/smc_struct.h | 50 ++ rmc/Imakefile | 10 +- rmc/rmc_dismount.c | 12 +- rmc/rmc_errmsg.c | 5 +- rmc/rmc_export.c | 12 +- rmc/rmc_find_cartridge.c | 14 +- rmc/rmc_get_geometry.c | 12 +- rmc/rmc_import.c | 12 +- rmc/{rmclogit.c => rmc_logit.c} | 7 +- rmc/rmc_logreq.c | 58 ++ rmc/rmc_marshall_element.c | 25 + rmc/rmc_mount.c | 12 +- rmc/rmc_procreq.c | 422 ++++++------- rmc/rmc_read_elem_status.c | 14 +- rmc/rmc_send_scsi_cmd.c | 299 +++++++++ rmc/{sendrep.c => rmc_sendrep.c} | 23 +- rmc/rmc_serv.c | 182 +++--- rmc/{smcsubr.c => rmc_smcsubr.c} | 466 ++++++++++++-- rmc/send2rmc.c | 16 +- rmc/smc.c | 10 +- rmc/smcsubr2.c | 323 ---------- rmc/usrmsg.c | 31 - tape/rbtsubr.c | 1 - tape/sendscsicmd.c | 27 +- test/unittest/Makefile | 118 +++- .../castor/tape/mediachanger/AcsCmdTest.cpp | 53 ++ .../castor/tape/mediachanger/AcsTest.cpp | 251 ++++++++ .../mediachanger/DismountAcsCmdLineTest.cpp | 80 +++ .../tape/mediachanger/DismountAcsCmdTest.cpp | 578 ++++++++++++++++++ .../castor/tape/mediachanger/MockAcs.hpp | 135 ++++ .../tape/mediachanger/MountAcsCmdLineTest.cpp | 81 +++ .../tape/mediachanger/MountAcsCmdTest.cpp | 578 ++++++++++++++++++ .../QueryVolumeAcsCmdLineTest.cpp | 66 ++ .../mediachanger/QueryVolumeAcsCmdTest.cpp | 402 ++++++++++++ .../castor/tape/mediachanger/TestingAcs.hpp | 92 +++ .../tape/mediachanger/TestingAcsCmd.hpp | 59 ++ .../tape/mediachanger/TestingAcsImpl.hpp | 45 ++ .../mediachanger/TestingDismountAcsCmd.hpp | 58 ++ .../tape/mediachanger/TestingMountAcsCmd.hpp | 57 ++ .../mediachanger/TestingQueryVolumeAcsCmd.hpp | 57 ++ 86 files changed, 7506 insertions(+), 1008 deletions(-) create mode 100644 castor/tape/rmc/Acs.cpp create mode 100644 castor/tape/rmc/Acs.hpp create mode 100644 castor/tape/rmc/AcsCmd.cpp create mode 100644 castor/tape/rmc/AcsCmd.hpp create mode 100644 castor/tape/rmc/AcsDismountCmd.cpp create mode 100644 castor/tape/rmc/AcsDismountCmd.hpp create mode 100644 castor/tape/rmc/AcsDismountCmdLine.cpp create mode 100644 castor/tape/rmc/AcsDismountCmdLine.hpp create mode 100644 castor/tape/rmc/AcsDismountMain.cpp create mode 100644 castor/tape/rmc/AcsImpl.cpp create mode 100644 castor/tape/rmc/AcsImpl.hpp create mode 100644 castor/tape/rmc/AcsMountCmd.cpp create mode 100644 castor/tape/rmc/AcsMountCmd.hpp create mode 100644 castor/tape/rmc/AcsMountCmdLine.cpp create mode 100644 castor/tape/rmc/AcsMountCmdLine.hpp create mode 100644 castor/tape/rmc/AcsMountMain.cpp create mode 100644 castor/tape/rmc/AcsQueryVolumeCmd.cpp create mode 100644 castor/tape/rmc/AcsQueryVolumeCmd.hpp create mode 100644 castor/tape/rmc/AcsQueryVolumeCmdLine.cpp create mode 100644 castor/tape/rmc/AcsQueryVolumeCmdLine.hpp create mode 100644 castor/tape/rmc/AcsQueryVolumeMain.cpp create mode 100644 castor/tape/rmc/DebugBuf.cpp create mode 100644 castor/tape/rmc/DebugBuf.hpp create mode 100644 castor/tape/rmc/Imakefile create mode 100644 castor/tape/rmc/castor-tape-acs-dismount.man create mode 100644 castor/tape/rmc/castor-tape-acs-mount.man create mode 100644 castor/tape/rmc/castor-tape-acs-queryvolume.man delete mode 100644 h/rmc.h create mode 100644 h/rmc_logit.h create mode 100644 h/rmc_logreq.h create mode 100644 h/rmc_marshall_element.h create mode 100644 h/rmc_procreq.h create mode 100644 h/rmc_send_scsi_cmd.h create mode 100644 h/rmc_sendrep.h delete mode 100644 h/rmc_server_api.h create mode 100644 h/rmc_smcsubr.h create mode 100644 h/rmc_smcsubr2.h delete mode 100644 h/smc.h create mode 100644 h/smc_constants.h create mode 100644 h/smc_struct.h rename rmc/{rmclogit.c => rmc_logit.c} (85%) create mode 100644 rmc/rmc_logreq.c create mode 100644 rmc/rmc_marshall_element.c create mode 100644 rmc/rmc_send_scsi_cmd.c rename rmc/{sendrep.c => rmc_sendrep.c} (78%) rename rmc/{smcsubr.c => rmc_smcsubr.c} (56%) delete mode 100644 rmc/smcsubr2.c delete mode 100644 rmc/usrmsg.c create mode 100644 test/unittest/castor/tape/mediachanger/AcsCmdTest.cpp create mode 100644 test/unittest/castor/tape/mediachanger/AcsTest.cpp create mode 100644 test/unittest/castor/tape/mediachanger/DismountAcsCmdLineTest.cpp create mode 100644 test/unittest/castor/tape/mediachanger/DismountAcsCmdTest.cpp create mode 100644 test/unittest/castor/tape/mediachanger/MockAcs.hpp create mode 100644 test/unittest/castor/tape/mediachanger/MountAcsCmdLineTest.cpp create mode 100644 test/unittest/castor/tape/mediachanger/MountAcsCmdTest.cpp create mode 100644 test/unittest/castor/tape/mediachanger/QueryVolumeAcsCmdLineTest.cpp create mode 100644 test/unittest/castor/tape/mediachanger/QueryVolumeAcsCmdTest.cpp create mode 100644 test/unittest/castor/tape/mediachanger/TestingAcs.hpp create mode 100644 test/unittest/castor/tape/mediachanger/TestingAcsCmd.hpp create mode 100644 test/unittest/castor/tape/mediachanger/TestingAcsImpl.hpp create mode 100644 test/unittest/castor/tape/mediachanger/TestingDismountAcsCmd.hpp create mode 100644 test/unittest/castor/tape/mediachanger/TestingMountAcsCmd.hpp create mode 100644 test/unittest/castor/tape/mediachanger/TestingQueryVolumeAcsCmd.hpp diff --git a/.gitignore b/.gitignore index aa35b98a52..77d49d817d 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 c7fa71a672..4365f3152f 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 0000000000..9e907143ca --- /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 0000000000..6579b88a95 --- /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 0000000000..c70d9f64aa --- /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 0000000000..0dfceeba22 --- /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 0000000000..07f7487c71 --- /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 0000000000..02cfe6dc2c --- /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 0000000000..9a5b6e30a4 --- /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 0000000000..4c1a581740 --- /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 0000000000..f93dfa9c8e --- /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 0000000000..73ff227865 --- /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 0000000000..0b2824669e --- /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 0000000000..62589bc05e --- /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 0000000000..1ac0f7e226 --- /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 0000000000..6e27e6dc28 --- /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 0000000000..ab140dd134 --- /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 0000000000..e3b7d16b88 --- /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 0000000000..019532e939 --- /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 0000000000..139650c015 --- /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 0000000000..870adc3d1f --- /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 0000000000..b9bda6e2a5 --- /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 0000000000..6cb852a1da --- /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 0000000000..fdcb37f13d --- /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 0000000000..11a98cb2cf --- /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 0000000000..cd015165cb --- /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 0000000000..20b9561e72 --- /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 0000000000..fd4c0de7b6 --- /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 0000000000..57b35654dc --- /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 f55dfc2e5c..72148c4ab7 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 dd419c6356..b94d030a23 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 a6a7be9fd2..0000000000 --- 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 489bf1e93b..462bd1e1f2 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 159d807b12..02887bb496 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 0000000000..607abb6ce5 --- /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 0000000000..aa2437b153 --- /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 0000000000..29c014adde --- /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 0000000000..00c5e89972 --- /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 0000000000..0112e93985 --- /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 0000000000..f8c5b8453d --- /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 1366fceb2a..0000000000 --- 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 0000000000..a84ef69aaf --- /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 0000000000..448e488ac9 --- /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 cdb05683d8..185f92c2e1 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 4b9cdfa766..0000000000 --- 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 0000000000..e5eb67bef9 --- /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 0000000000..067e7e280a --- /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 26150ad14e..531e86271b 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 13ce801576..6b46901771 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 d4f60c5659..9c2342810b 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 38914793e1..08bc1ccd03 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 9497a1ac36..8728ba2f4e 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 cbf23df579..16f7e42f5c 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 c198b2868a..bc0d20e3ab 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 dd93368c7f..76054ebbaa 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 0000000000..6ee62b40d8 --- /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 0000000000..f1607fcce2 --- /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 f1dd077aac..aa72260c32 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 4cda2a7acb..5390ea0483 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 b8c92ef609..551c256b82 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 0000000000..3fd4163043 --- /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 1cf84fa5b9..eefee63be6 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 fef906b2bf..d2cff293f3 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 bf4f0e7423..d1954d2b6e 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 69b265204e..c2464e2581 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 1eb6b84395..7d5b1cf4ba 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 95d47c0b4e..0000000000 --- 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 6a1dc62074..0000000000 --- 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 a7f1d61006..e6a977c331 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 50851920c5..c4803e8b61 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 5b1843aaff..867683dd15 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 0000000000..075f80dd02 --- /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 0000000000..4ae95325c1 --- /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 0000000000..1af3f6ebd5 --- /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 0000000000..2a2a06f1f6 --- /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 0000000000..743297a9ec --- /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 0000000000..4a5ee1f062 --- /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 0000000000..6d8573d265 --- /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 0000000000..1c1d1d6ca8 --- /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 0000000000..cb510c1947 --- /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 0000000000..8496694f99 --- /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 0000000000..7ff0a2fa9a --- /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 0000000000..39dc01d959 --- /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 0000000000..575cb7b094 --- /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 0000000000..7ead17ef0f --- /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 0000000000..68c53a8d06 --- /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 -- GitLab