Commit c8408633 authored by Anastasia Karachaliou's avatar Anastasia Karachaliou
Browse files

acsd daemon working also with the new tool cta-tape-acs-querydrive

parent 6be4f031
......@@ -41,5 +41,5 @@ namespace cta { namespace exception {
}; // class QueryVolumeFailed
} } // namespace castor exception
} } // namespace cta exception
......@@ -376,6 +376,7 @@ castor (Cern Advanced STORage system)
%attr(0755,root,root) /usr/bin/cta-tape-acs-queryvolume
%attr(0755,root,root) /usr/bin/cta-tape-acs-dismount
%attr(0755,root,root) /usr/bin/cta-tape-acs-mount
%attr(0755,root,root) /usr/bin/cta-tape-acs-querydrive
%attr(0644,root,root) %doc /usr/share/man/man1/cta-tape-acs-queryvolume.1cta.gz
%attr(0644,root,root) %doc /usr/share/man/man1/cta-tape-acs-mount.1cta.gz
%attr(0644,root,root) %doc /usr/share/man/man1/cta-tape-acs-dismount.1cta.gz
/*
* 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 "AcsQueryDriveCmd.hpp"
#include "AcsQueryDriveCmdLine.hpp"
#include "common/exception/QueryVolumeFailed.hpp"
#include <getopt.h>
#include <iostream>
#include <string.h>
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
cta::mediachanger::acs::AcsQueryDriveCmd::AcsQueryDriveCmd(
std::istream &inStream, std::ostream &outStream, std::ostream &errStream,
Acs &acs) throw():
AcsCmd(inStream, outStream, errStream, acs) {
}
//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
cta::mediachanger::acs::AcsQueryDriveCmd::~AcsQueryDriveCmd() throw() {
// Do nothing
}
//------------------------------------------------------------------------------
// exceptionThrowingMain
//------------------------------------------------------------------------------
int cta::mediachanger::acs::AcsQueryDriveCmd::exceptionThrowingMain(const int argc,
char *const *const argv) {
try {
m_cmdLine = AcsQueryDriveCmdLine(argc, argv);
} catch(cta::exception::Exception &ex) {
m_err << ex.getMessage().str() << std::endl;
m_err << std::endl;
m_err << m_cmdLine.getUsage() << std::endl;
return 1;
}
// Display the usage message to standard out and exit with success if the
// user requested help
if(m_cmdLine.help) {
m_out << AcsQueryDriveCmdLine::getUsage();
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 << "DRIVE_SLOT = " << m_acs.driveId2Str(m_cmdLine.libraryDriveSlot);
syncQueryDrive();
return 0;
}
//------------------------------------------------------------------------------
// syncQueryDrive
//------------------------------------------------------------------------------
void cta::mediachanger::acs::AcsQueryDriveCmd::syncQueryDrive() {
const SEQ_NO requestSeqNumber = 1;
ALIGNED_BYTES buf[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)];
try {
sendQueryDriveRequest(requestSeqNumber);
requestResponsesUntilFinal(requestSeqNumber, buf, m_cmdLine.queryInterval,
m_cmdLine.timeout);
processQueryResponse(m_out, buf);
} catch(cta::exception::Exception &ex) {
cta::exception::QueryVolumeFailed qf;
qf.getMessage() << "Failed to query drive " <<
m_acs.driveId2Str(m_cmdLine.libraryDriveSlot) << ": " << ex.getMessage().str();
throw qf;
}
}
//------------------------------------------------------------------------------
// sendQueryDriveRequest
//------------------------------------------------------------------------------
void cta::mediachanger::acs::AcsQueryDriveCmd::sendQueryDriveRequest(
const SEQ_NO sequence) {
m_dbg << "Calling Acs::queryDrive()" << std::endl;
const STATUS s = acs_query_drive(sequence, &(m_cmdLine.libraryDriveSlot), 1);
m_dbg << "Acs::queryDrive() returned " << acs_status(s) << std::endl;
if(STATUS_SUCCESS != s) {
cta::exception::QueryVolumeFailed ex;
ex.getMessage() << "Failed to send query request for drive " <<
m_acs.driveId2Str(m_cmdLine.libraryDriveSlot)<< ": " << acs_status(s);
throw ex;
}
}
//------------------------------------------------------------------------------
// processQueryResponse
//------------------------------------------------------------------------------
void cta::mediachanger::acs::AcsQueryDriveCmd::processQueryResponse(
std::ostream &os,
ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) {
const ACS_QUERY_DRV_RESPONSE *const msg = (ACS_QUERY_DRV_RESPONSE *)buf;
if(STATUS_SUCCESS != msg->query_drv_status) {
cta::exception::QueryVolumeFailed ex;
ex.getMessage() << "Status of query response is not success: " <<
acs_status(msg->query_drv_status);
throw ex;
}
if((unsigned short)1 != msg->count) {
cta::exception::QueryVolumeFailed ex;
ex.getMessage() << "Query response does not contain a single drive: count="
<< msg->count;
throw ex;
}
// count is 1 so it is safe to make a reference to the single drive status
const QU_DRV_STATUS &drvStatus = msg->drv_status[0];
if(m_acs.driveId2Str(m_cmdLine.libraryDriveSlot)!= m_acs.driveId2Str(drvStatus.drive_id)) {
cta::exception::QueryVolumeFailed ex;
ex.getMessage() <<
"Drive identifier of query response does not match that of request"
" requestDriveID=" <<m_acs.driveId2Str(m_cmdLine.libraryDriveSlot) <<
" responseDriveID=" << m_acs.driveId2Str(drvStatus.drive_id);
throw ex;
}
writeDriveStatus(os, drvStatus);
}
//------------------------------------------------------------------------------
// writeDriveStatus
//------------------------------------------------------------------------------
void cta::mediachanger::acs::AcsQueryDriveCmd::writeDriveStatus(
std::ostream &os, const QU_DRV_STATUS &s) throw() {
os << "Drive identifier: " << m_acs.driveId2Str(s.drive_id) << std::endl;
os << "Drive type: " << acs_type((TYPE)s.drive_type) << std::endl;
os << "Drive state: " << acs_state(s.state) << std::endl;
os << "Drive status: " << acs_status(s.status) << std::endl;
os << "Volume identifier: " << s.vol_id.external_label << std::endl;
}
/*
* 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/>.
*/
#pragma once
#include "AcsCmd.hpp"
#include "AcsQueryDriveCmdLine.hpp"
#include "common/exception/InvalidArgument.hpp"
#include "common/exception/MissingOperand.hpp"
#include "mediachanger/CmdLineTool.hpp"
#include <stdint.h>
namespace cta {
namespace mediachanger {
namespace acs {
/**
* The class implementing the mount command.
*/
class AcsQueryDriveCmd: 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.
*/
AcsQueryDriveCmd(std::istream &inStream, std::ostream &outStream,
std::ostream &errStream, Acs &acs) throw();
/**
* Destructor.
*/
virtual ~AcsQueryDriveCmd() throw();
/**
* The entry function of the command.
*
* @param argc The number of command-line arguments.
* @param argv The command-line arguments.
* @return The exit value of the program.
*/
int exceptionThrowingMain(const int argc, char *const *const argv);
protected:
/**
* Queries ACS for information about the drive 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 drive status of the drive identifier specified on the
* command-line.
*/
void syncQueryDrive();
/**
* Sends the query drive request to ACSLS.
*
* @param seqNumber The sequence number to be used in the request.
*/
void sendQueryDriveRequest(const SEQ_NO seqNumber);
/**
* Extracts the drive 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)]);
/**
* Writes a human readable representation of the specified drive status to
* the specified output stream.
*
* @param os The output stream.
* @param s The drive status.
*/
void writeDriveStatus(std::ostream &os, const QU_DRV_STATUS &s) throw();
private:
/**
* The parsed command-line.
*
* The value of this member variable is set within the main() method of this
* class.
*/
AcsQueryDriveCmdLine m_cmdLine;
}; // class AcsQueryDriveCmd
} // namespace acs
} // namepsace mediachanger
} // namespace cta
/*
* 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 "Acs.hpp"
#include "AcsQueryDriveCmdLine.hpp"
#include "Constants.hpp"
#include "common/exception/InvalidArgument.hpp"
#include "common/exception/MissingOperand.hpp"
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
//-----------------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------------
cta::mediachanger::acs::AcsQueryDriveCmdLine::AcsQueryDriveCmdLine() throw():
debug(false),
help(false),
queryInterval(0),
timeout(0) {
libraryDriveSlot.panel_id.lsm_id.acs = (ACS)0;
libraryDriveSlot.panel_id.lsm_id.lsm = (LSM)0;
libraryDriveSlot.panel_id.panel = (PANEL)0;
libraryDriveSlot.drive = (DRIVE)0;
memset(volId.external_label, '\0', sizeof(volId.external_label));
}
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
cta::mediachanger::acs::AcsQueryDriveCmdLine::AcsQueryDriveCmdLine(const int argc,
char *const *const argv):
debug(false),
help(false),
queryInterval(ACS_QUERY_INTERVAL),
timeout(ACS_CMD_TIMEOUT) {
libraryDriveSlot.panel_id.lsm_id.acs = (ACS)0;
libraryDriveSlot.panel_id.lsm_id.lsm = (LSM)0;
libraryDriveSlot.panel_id.panel = (PANEL)0;
libraryDriveSlot.drive = (DRIVE)0;
memset(volId.external_label, '\0', sizeof(volId.external_label));
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}
};
// Prevent getopt() from printing an error message if it does not recognize
// an option character
opterr = 0;
int opt = 0;
while((opt = getopt_long(argc, argv, ":dhq:t:", longopts, NULL)) != -1) {
processOption(opt);
}
// There is no need to continue parsing when the help option is set
if(help) {
return;
}
// Check that DRIVE_SLOT has been specified
if(argc < 1) {
cta::exception::MissingOperand ex;
ex.getMessage() << "DRIVE_SLOT must be specified";
throw ex;
}
// Parse DRIVE_SLOT
libraryDriveSlot = Acs::str2DriveId(argv[1]);
}
//------------------------------------------------------------------------------
// processOption
//------------------------------------------------------------------------------
void cta::mediachanger::acs::AcsQueryDriveCmdLine::processOption(const int opt) {
switch(opt) {
case 'd':
debug = true;
break;
case 'h':
help = true;
break;
case 'q':
queryInterval = parseQueryInterval(optarg);
break;
case 't':
timeout = parseTimeout(optarg);
break;
case ':':
return handleMissingParameter(optopt);
case '?':
return handleUnknownOption(optopt);
default:
{
cta::exception::Exception ex;
ex.getMessage() <<
"getopt_long returned the following unknown value: 0x" <<
std::hex << (int)opt;
throw ex;
}
} // switch(opt)
}
//------------------------------------------------------------------------------
// getUsage
//------------------------------------------------------------------------------
std::string cta::mediachanger::acs::AcsQueryDriveCmdLine::getUsage() throw() {
std::ostringstream usage;
usage <<
"Usage:\n"
"\n"
<< getProgramName() << " [options] DRIVE_SLOT\n"
"\n"
"Where:\n"
"\n"
" DRIVE_SLOT The slot in the tape library where the drive is located.\n"
" DRIVE_SLOT must be in one of the following two forms:\n"
"\n"
" acsACS_NUMBER,LSM_NUMBER,PANEL_NUMBER,TRANSPORT_NUMBER\n"
" smcDRIVE_ORDINAL\n"
"\n"
"Options:\n"
"\n"
" -d|--debug Turn on the printing of debug information.\n"
"\n"
" -h|--help Print this help message and exit.\n"
"\n";
return usage.str();
}
//------------------------------------------------------------------------------
// getProgramName
//------------------------------------------------------------------------------
std::string cta::mediachanger::acs::AcsQueryDriveCmdLine::getProgramName() {
return "cta-tape-acs-querydrive";
}
/*
* 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/>.
*/
#pragma once
#include "AcsCmdLine.hpp"
#include "mediachanger/AcsLibrarySlot.hpp"
#include "mediachanger/LibrarySlotParser.hpp"
extern "C" {
#include "acssys.h"
#include "acsapi.h"
}
#include <string>
namespace cta {
namespace mediachanger {
namespace acs {
/**
* Data type used to store the results of parsing the command-line.
*/
struct AcsQueryDriveCmdLine: public AcsCmdLine {
/**
* 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;
/**
* Constructor.
*
* Initialises all BOOLEAN member-variables to FALSE, all integer
* member-variables to 0 and the volume identifier to an empty string.
*/
AcsQueryDriveCmdLine() throw();
/**
* Constructor.
*
* Parses the specified command-line arguments.
*
* @param argc Argument count from the executable's entry function: main().
* @param argv Argument vector from the executable's entry function: main().
*/
AcsQueryDriveCmdLine(const int argc, char *const *const argv);
/**
* Gets the usage message that describes the command line.
*
* @return The usage message.
*/
static std::string getUsage() throw();
/**
* Return sthe program name.
*
* @return sthe program name.
*/
static std::string getProgramName();
/**
* The slot in the tape library where the drive is located.
*/
DRIVEID libraryDriveSlot;
private:
/**
* Processes the specified option that was returned by getopt_long().
*
* @param opt The option that was returned by getopt_long().
*/
void processOption(const int opt);
}; // class AcsQueryDriveCmdLine
} // namespace acs
} // namespace mediachanger
} // namespace cta
/*
* 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 "AcsImpl.hpp"
#include "AcsQueryDriveCmd.hpp"
#include "AcsQueryDriveCmdLine.hpp"
#include <iostream>
/**
* An exception throwing version of main().
*
* @param argc The number of command-line arguments including the program name.
* @param argv The command-line arguments.
* @param The exit value of the program.
*/
static int exceptionThrowingMain(const int argc, char *const *const argv);
//------------------------------------------------------------------------------
// main
//------------------------------------------------------------------------------
int main(const int argc, char *const *const argv) {
using namespace cta;
std::string errorMessage;
try {