/* * The CERN Tape Archive(CTA) project * Copyright(C) 2015 CERN * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or *(at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "common/utils/utils.hpp" #include "common/SmartFd.hpp" #include "mediachanger/CommonMarshal.hpp" #include "mediachanger/io.hpp" #include "mediachanger/RmcMarshal.hpp" #include "mediachanger/RmcProxy.hpp" #include "mediachanger/ScsiLibrarySlot.hpp" namespace cta { namespace mediachanger { //------------------------------------------------------------------------------ // constructor //------------------------------------------------------------------------------ RmcProxy::RmcProxy( const unsigned short rmcPort, const int netTimeout, const unsigned int maxRqstAttempts) throw(): m_rmcPort(rmcPort), m_netTimeout(netTimeout), m_maxRqstAttempts(maxRqstAttempts) { } //------------------------------------------------------------------------------ // destructor //------------------------------------------------------------------------------ RmcProxy::~RmcProxy() throw() { } //------------------------------------------------------------------------------ // mountTapeReadOnly //------------------------------------------------------------------------------ void RmcProxy::mountTapeReadOnly(const std::string &vid, const LibrarySlot &librarySlot) { // SCSI libraries do not support read-only mounts mountTapeReadWrite(vid, librarySlot); } //------------------------------------------------------------------------------ // mountTapeReadWrite //------------------------------------------------------------------------------ void RmcProxy::mountTapeReadWrite(const std::string &vid, const LibrarySlot &librarySlot) { try { RmcMountMsgBody rqstBody; rqstBody.uid = geteuid(); rqstBody.gid = getegid(); utils::copyString(rqstBody.vid, vid); const ScsiLibrarySlot &scsiLibrarySlot = dynamic_cast<const ScsiLibrarySlot&>(librarySlot); rqstBody.drvOrd = scsiLibrarySlot.getDrvOrd(); rmcSendRecvNbAttempts(m_maxRqstAttempts, rqstBody); } catch(cta::exception::Exception &ne) { cta::exception::Exception ex; ex.getMessage() << "Failed to mount tape in SCSI tape-library for read/write access" ": vid=" << vid << " librarySlot=" << librarySlot.str() << ": " << ne.getMessage().str(); throw ex; } } //------------------------------------------------------------------------------ // dismountTape //------------------------------------------------------------------------------ void RmcProxy::dismountTape(const std::string &vid, const LibrarySlot &librarySlot) { try { RmcUnmountMsgBody rqstBody; rqstBody.uid = geteuid(); rqstBody.gid = getegid(); utils::copyString(rqstBody.vid, vid); const ScsiLibrarySlot &scsiLibrarySlot = dynamic_cast<const ScsiLibrarySlot&>(librarySlot); rqstBody.drvOrd = scsiLibrarySlot.getDrvOrd(); rqstBody.force = 0; rmcSendRecvNbAttempts(m_maxRqstAttempts, rqstBody); } catch(cta::exception::Exception &ne) { cta::exception::Exception ex; ex.getMessage() << "Failed to dismount tape in SCSI tape-library" ": vid=" << vid << " librarySlot=" << librarySlot.str() << ": " << ne.getMessage().str(); throw ex; } } //------------------------------------------------------------------------------ // forceDismountTape //------------------------------------------------------------------------------ void RmcProxy::forceDismountTape(const std::string &vid, const LibrarySlot &librarySlot) { // SCSI libraries do not support forced dismounts dismountTape(vid, librarySlot); } //----------------------------------------------------------------------------- // connectToRmc //----------------------------------------------------------------------------- int RmcProxy::connectToRmc() const { const std::string rmcHost = "localhost"; cta::SmartFd smartConnectSock; try { smartConnectSock.reset(connectWithTimeout(rmcHost, m_rmcPort, m_netTimeout)); } catch(cta::exception::Exception &ne) { cta::exception::Exception ex; ex.getMessage() << "Failed to connect to rmcd: rmcHost=" << rmcHost << " rmcPort=" << RMC_PORT << ": " << ne.getMessage().str(); throw ex; } return smartConnectSock.release(); } //----------------------------------------------------------------------------- // writeRmcMountMsg //----------------------------------------------------------------------------- void RmcProxy::writeRmcMountMsg(const int fd, const RmcMountMsgBody &body) { char buf[RMC_MSGBUFSIZ]; const size_t len = marshal(buf, body); try { writeBytes(fd, m_netTimeout, len, buf); } catch(cta::exception::Exception &ne) { cta::exception::Exception ex; ex.getMessage() << "Failed to write RMC_SCSI_MOUNT message: " << ne.getMessage().str(); throw ex; } } //----------------------------------------------------------------------------- // readRmcMsgHeader //----------------------------------------------------------------------------- MessageHeader RmcProxy::readRmcMsgHeader(const int fd) { char buf[12]; // Magic + type + len MessageHeader header; try { readBytes(fd, m_netTimeout, sizeof(buf), buf); } catch(cta::exception::Exception &ne) { cta::exception::Exception ex; ex.getMessage() << "Failed to read message header: " << ne.getMessage().str(); throw ex; } const char *bufPtr = buf; size_t bufLen = sizeof(buf); unmarshal(bufPtr, bufLen, header); if(RMC_MAGIC != header.magic) { cta::exception::Exception ex; ex.getMessage() << "Failed to read message header: " " Header contains an invalid magic number: expected=0x" << std::hex << RMC_MAGIC << " actual=0x" << header.magic; throw ex; } return header; } //----------------------------------------------------------------------------- // writeRmcUnmountMsg //----------------------------------------------------------------------------- void RmcProxy::writeRmcUnmountMsg(const int fd, const RmcUnmountMsgBody &body) { char buf[RMC_MSGBUFSIZ]; const size_t len = marshal(buf, body); try { writeBytes(fd, m_netTimeout, len, buf); } catch(cta::exception::Exception &ne) { cta::exception::Exception ex; ex.getMessage() << "Failed to write RMC_SCSI_UNMOUNT message: " << ne.getMessage().str(); throw ex; } } //----------------------------------------------------------------------------- // rmcReplyTypeToStr //----------------------------------------------------------------------------- std::string RmcProxy::rmcReplyTypeToStr(const int replyType) { std::ostringstream oss; switch(replyType) { case RMC_RC: oss << "RMC_RC"; break; case MSG_ERR: oss << "MSG_ERR"; break; default: oss << "UNKNOWN(0x" << std::hex << replyType << ")"; } return oss.str(); } //----------------------------------------------------------------------------- // handleMSG_ERR //----------------------------------------------------------------------------- std::string RmcProxy::handleMSG_ERR(const MessageHeader &header, const int fd) { char errorBuf[1024]; const int nbBytesToRead = header.lenOrStatus > sizeof(errorBuf) ? sizeof(errorBuf) : header.lenOrStatus; readBytes(fd, m_netTimeout, nbBytesToRead, errorBuf); errorBuf[sizeof(errorBuf) - 1] = '\0'; return errorBuf; } } // namespace mediachanger } // namespace cta