Skip to content
Snippets Groups Projects
Commit 4656ccb0 authored by Steven Murray's avatar Steven Murray Committed by Steven Murray
Browse files

bug #102374: RFE: Create a separate rmc client library called libcastorrmc.so

Fixed in the trunk.
parent 234f166d
No related branches found
No related tags found
No related merge requests found
......@@ -5,13 +5,14 @@ COMM
COMM Make SCSI media changer server programs.
TapeDependsOnLibrary(common,castorcommon)
TapeDependsOnLibrary(upv,castorupv)
TapeDependsOnLibrary(dlf,castordlf)
TapeDependsOnLibrary(tape,castortape)
COMM The rmcd daemon depends on libcastortape.so therefore include the rules to
COMM make it
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
TapeProgramTarget(rmcd,$(RMCD_OBJS),,,755)
TapeProgramTarget(rmcd,$(RMCD_OBJS),$(RMCD_DEPLIBS),$(RMCD_LIBS),755)
ADMMANPAGE(rmcd)
TapeMakeDir($(LOGPATH),0755)
LOGROTATE(castor-rmc-server,installtape)
......@@ -26,3 +27,17 @@ CLIENTLIBMANPAGE(rmc_import)
CLIENTLIBMANPAGE(rmc_mount)
CLIENTLIBMANPAGE(rmc_read_elem_status)
CLIENTLIBMANPAGE(rmc_seterrbuf)
COMM The rmc library depends on libcastorcommon.so therefore include the rules
COMM to make it
include $(CASTOR_ROOT)/common/Makefile
RMCLIB_DEPLIBS = DepSharedLibraryTargetName(common,castorcommon)
RMCLIB_LIBS = $(RMCLIB_DEPLIBS)
RMCLIB_OBJS = rmc_dismount.o rmc_errmsg.o rmc_export.o rmc_find_cartridge.o rmc_get_geometry.o rmc_import.o rmc_mount.o rmc_read_elem_status.o send2rmc.o
TapeSharedLibraryTarget(castorrmc,$(RMCLIB_OBJS),$(RMCLIB_DEPLIBS),$(RMCLIB_LIBS))
SMC_DEPLIBS = DepSharedLibraryTargetName(rmc,castorrmc)
SMC_LIBS = $(SMC_DEPLIBS) BuildRPathcastorrmc
TapeProgramTarget(smc,smc.o,$(SMC_DEPLIBS),$(SMC_LIBS),6755)
EXEMANPAGE(smc)
/*
* 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 "Ctape.h"
#include "rmc_api.h"
#include "serrno.h"
#include "smc.h"
#include "getconfent.h"
/* exit codes */
#define USERR 1
extern char *optarg;
static void usage(char *cmd)
{
fprintf (stderr, "usage: %s ", cmd);
fprintf (stderr,
"-d -D drive_ordinal -h rmcserver -l loader [-V vid] [-v]\n"
"\t-e -h rmcserver -l loader -V vid [-v]\n"
"\t-i -h rmcserver -l loader [-V vid] [-v]\n"
"\t-m -D drive_ordinal -h rmcserver [-I] -l loader -V vid [-v]\n"
"\t-q D [-D drive_ordinal] -h rmcserver -l loader [-v]\n"
"\t-q L -h rmcserver -l loader [-v]\n"
"\t-q S -h rmcserver -l loader [-N nbelem] [-S starting_slot] [-v]\n"
"\t-q V -h rmcserver -l loader [-N nbelem] [-V vid] [-v]\n");
}
static int smc_qdrive (char *rmchost,
int fd,
char *loader,
struct robot_info *robot_info,
int drvord,
int verbose)
{
int c;
struct smc_element_info *element_info;
int i;
int nbelem;
char *pstatus;
char *smcLibraryType;
char useSpectraLib;
if (drvord < 0) {
drvord = 0;
nbelem = robot_info->device_count;
} else {
nbelem = 1;
}
if ((element_info = malloc (nbelem * sizeof(struct smc_element_info))) == NULL) {
fprintf (stderr, SR012);
return (USERR);
}
if ((c = rmc_read_elem_status (rmchost, loader, 4,
robot_info->device_start+drvord, nbelem, element_info)) < 0) {
free (element_info);
return (c);
}
if (verbose)
printf ("Drive Ordinal\tElement Addr.\tStatus\t\tVid\n");
useSpectraLib=0;
smcLibraryType = getconfent("SMC","LIBRARY_TYPE",0);
if (NULL != smcLibraryType &&
0 == strcasecmp(smcLibraryType,"SPECTRA")) {
useSpectraLib = 1;
}
for (i = 0; i < c; i++) {
if (((element_info+i)->state & 0x1) == 0)
pstatus = "free";
else if ((element_info+i)->state & 0x4)
pstatus = "error";
else if ((element_info+i)->state & 0x8 && !useSpectraLib)
pstatus = "unloaded";
else
pstatus = "loaded";
printf (" %2d\t %d\t%s\t%s\n",
(element_info+i)->element_address-robot_info->device_start,
(element_info+i)->element_address, pstatus,
(element_info+i)->name);
}
free (element_info);
return (0);
}
static int smc_qlib (struct robot_info *robot_info)
{
printf ("Vendor/Product/Revision = <%s>\n", robot_info->inquiry);
printf ("Transport Count = %d, Start = %d\n",
robot_info->transport_count, robot_info->transport_start);
printf ("Slot Count = %d, Start = %d\n",
robot_info->slot_count, robot_info->slot_start);
printf ("Port Count = %d, Start = %d\n",
robot_info->port_count, robot_info->port_start);
printf ("Device Count = %d, Start = %d\n",
robot_info->device_count, robot_info->device_start);
return (0);
}
static int smc_qport (char *rmchost,
int fd,
char *loader,
struct robot_info *robot_info,
int verbose)
{
int c;
struct smc_element_info *element_info;
int i;
int nbelem;
char *pstatus;
nbelem = robot_info->port_count;
if ((element_info = malloc (nbelem * sizeof(struct smc_element_info))) == NULL) {
fprintf (stderr, SR012);
return (USERR);
}
if ((c = rmc_read_elem_status (rmchost, loader, 3,
robot_info->port_start, nbelem, element_info)) < 0) {
free (element_info);
return (serrno - ERMCRBTERR);
}
if (verbose)
printf ("Element Addr.\tVid\tImpExp\n");
for (i = 0; i < c; i++) {
if (((element_info+i)->state & 0x1) == 0)
pstatus = "";
else if (((element_info+i)->state & 0x2) == 0)
pstatus = "export";
else
pstatus = "import";
printf (" %4d\t%s\t%s\n",
(element_info+i)->element_address,
(element_info+i)->name, pstatus);
}
free (element_info);
return (0);
}
static int smc_qslot (char *rmchost,
int fd,
char *loader,
struct robot_info *robot_info,
int slotaddr,
int nbelem,
int verbose)
{
int c;
struct smc_element_info *element_info;
int i;
if (nbelem == 0) {
if (slotaddr < 0)
nbelem = robot_info->slot_count;
else
nbelem = 1;
}
if (slotaddr < 0)
slotaddr = 0;
if ((element_info = malloc (nbelem * sizeof(struct smc_element_info))) == NULL) {
fprintf (stderr, SR012);
return (USERR);
}
if ((c = rmc_read_elem_status (rmchost, loader, 2, slotaddr,
nbelem, element_info)) < 0) {
free (element_info);
return (serrno - ERMCRBTERR);
}
if (verbose)
printf ("Element Addr.\tVid\n");
for (i = 0; i < c; i++) {
printf (" %4d\t%s\n",
element_info[i].element_address, element_info[i].name);
}
free (element_info);
return (0);
}
static int smc_qvid (char *rmchost,
int fd,
char *loader,
struct robot_info *robot_info,
char *reqvid,
int nbelem,
int verbose)
{
int c;
struct smc_element_info *element_info;
int i;
char *ptype;
static char ptypes[5][6] = {"", "hand", "slot", "port", "drive"};
char *vid;
if (*reqvid)
vid = reqvid;
else
vid = "*";
if (nbelem == 0) {
if (strchr (vid, '*') || strchr (vid, '?')) /* pattern matching */
nbelem = robot_info->transport_count + robot_info->slot_count +
robot_info->port_count + robot_info->device_count;
else
nbelem = 1;
}
if ((element_info = malloc (nbelem * sizeof(struct smc_element_info))) == NULL) {
fprintf (stderr, SR012);
return (USERR);
}
if ((c = rmc_find_cartridge (rmchost, loader, vid, 0, 0, nbelem,
element_info)) < 0) {
free (element_info);
return (serrno - ERMCRBTERR);
}
if (verbose)
printf ("Vid\tElement Addr.\tElement Type\n");
for (i = 0; i < c; i++) {
ptype = ptypes[(element_info+i)->element_type];
if ((element_info+i)->element_type == 3) {
if (((element_info+i)->state & 0x2) == 0) {
ptype = "export";
} else {
ptype = "import";
}
}
printf ("%s\t %4d\t%s\n",
(element_info+i)->name, (element_info+i)->element_address,
ptype);
}
free (element_info);
return (0);
}
int main(int argc,
char **argv)
{
int c;
char *dp;
int drvord = -1;
int errflg = 0;
const int fd = -1;
int invert = 0;
char loader[32];
int n;
int nbelem = 0;
char qry_type = 0;
char req_type = 0;
struct robot_info robot_info;
char rmchost[CA_MAXHOSTNAMELEN+1];
int slotaddr = -1;
int targetslotaddr = -1;
int verbose = 0;
char vid[7];
/* parse and check command options */
memset(loader, '\0', sizeof(loader));
memset(rmchost, '\0', sizeof(rmchost));
memset (vid, '\0', sizeof(vid));
while ((c = getopt (argc, argv, "D:deh:Iil:mN:q:S:V:vT:")) != EOF) {
switch (c) {
case 'D': /* drive ordinal */
drvord = strtol (optarg, &dp, 10);
if (*dp != '\0' || drvord < 0) {
fprintf (stderr, SR001);
errflg++;
}
break;
case 'd': /* demount */
case 'e': /* export */
if (req_type) {
fprintf (stderr, SR002, req_type, c);
errflg++;
} else
req_type = c;
break;
case 'h': /* remote server */
if(strlen(optarg) > (sizeof(rmchost) - 1)) {
fprintf(stderr,
"rmcserver %s must be at most %d characters long\n",
optarg, (int)(sizeof(rmchost) - 1));
errflg++;
} else {
strncpy (rmchost, optarg, sizeof(rmchost) - 1);
}
break;
case 'i': /* import */
if (req_type) {
fprintf (stderr, SR002, req_type, c);
errflg++;
} else
req_type = c;
break;
case 'I': /* invert */
invert = 1;
break;
case 'l': /* loader */
if(strlen(optarg) > (sizeof(loader) - 1)) {
fprintf(stderr,
"loader %s must be at most %d characters long\n",
optarg, (int)(sizeof(loader) - 1));
errflg++;
} else {
strncpy (loader, optarg, sizeof(loader) - 1);
}
break;
case 'm': /* mount */
if (req_type) {
fprintf (stderr, SR002, req_type, c);
errflg++;
} else
req_type = c;
break;
case 'N': /* number of elements */
nbelem = strtol (optarg, &dp, 10);
if (*dp != '\0' || nbelem <= 0) {
fprintf (stderr, SR010);
errflg++;
}
break;
case 'q': /* query */
if (req_type) {
fprintf (stderr, SR002, req_type, c);
errflg++;
} else {
req_type = c;
qry_type = *optarg;
if (qry_type != 'D' && qry_type != 'L' &&
qry_type != 'P' && qry_type != 'S' &&
qry_type != 'V') {
fprintf (stderr, SR003, qry_type);
errflg++;
}
}
break;
case 'S': /* starting slot */
slotaddr = strtol (optarg, &dp, 10);
if (*dp != '\0' || slotaddr < 0) {
fprintf (stderr, SR001);
errflg++;
}
break;
case 'T': /* Target slot */
targetslotaddr = strtol (optarg, &dp, 10);
if (*dp != '\0' || targetslotaddr < 0) {
fprintf (stderr, SR001);
errflg++;
}
break;
case 'V': /* vid */
n = strlen (optarg);
if (n > 6) {
fprintf (stderr, SR004, optarg);
errflg++;
} else {
strcpy (vid, optarg);
UPPER (vid);
}
break;
case 'v':
verbose = 1;
break;
case '?':
errflg++;
break;
}
}
if (req_type && *loader == '\0') {
fprintf (stderr, SR005);
errflg++;
}
if (req_type && *rmchost == '\0') {
fprintf (stderr, "rmcserver must be specified\n");
errflg++;
}
if (req_type == 'd' && drvord < 0) {
fprintf (stderr, SR006);
errflg++;
}
if (req_type == 'e' && *vid =='\0') {
fprintf (stderr, SR011);
errflg++;
}
if (req_type == 'm' && (*vid =='\0' || drvord < 0)) {
fprintf (stderr, SR007);
errflg++;
}
if (errflg || req_type == 0) {
usage (argv[0]);
exit (USERR);
}
/* get robot geometry */
if (rmc_get_geometry (rmchost, loader, &robot_info)) {
exit (serrno);
}
if (drvord >= robot_info.device_count) {
fprintf (stderr, SR008, robot_info.device_count);
exit (USERR);
}
if (slotaddr > (robot_info.slot_count + robot_info.slot_start)) {
fprintf (stderr, SR016, robot_info.slot_count + robot_info.slot_start);
exit (USERR);
}
/* process request */
switch (req_type) {
case 'd':
if ((c = rmc_dismount (rmchost, loader, vid, drvord, 0)) < 0) {
c = (serrno == SECOMERR) ? RBT_FAST_RETRY : serrno - ERMCRBTERR;
}
break;
case 'e':
if ((c = rmc_export (rmchost, loader, vid)) < 0) {
c = (serrno == SECOMERR) ? RBT_FAST_RETRY : serrno - ERMCRBTERR;
}
break;
case 'i':
if ((c = rmc_import (rmchost, loader, vid)) < 0) {
c = (serrno == SECOMERR) ? RBT_FAST_RETRY : serrno - ERMCRBTERR;
}
break;
case 'm':
if ((c = rmc_mount (rmchost, loader, vid, invert, drvord)) < 0) {
c = (serrno == SECOMERR) ? RBT_FAST_RETRY : serrno - ERMCRBTERR;
}
break;
case 'q':
switch (qry_type) {
case 'D':
c = smc_qdrive (rmchost, fd, loader, &robot_info, drvord,
verbose);
break;
case 'L':
c = smc_qlib (&robot_info);
break;
case 'P':
c = smc_qport (rmchost, fd, loader, &robot_info, verbose);
break;
case 'S':
c = smc_qslot (rmchost, fd, loader, &robot_info, slotaddr,
nbelem, verbose);
break;
case 'V':
c = smc_qvid (rmchost, fd, loader, &robot_info, vid,
nbelem, verbose);
break;
}
break;
}
exit (c);
}
.\" Copyright (C) 1998-2002 by CERN/IT/PDP/DM
.\" All rights reserved
.\"
.TH SMC 1 "$Date: 2005/06/16 09:43:12 $" CASTOR "Ctape User Commands"
.SH NAME
smc \- command line interface to drive robotic devices through SCSI
.SH SYNOPSIS
.B smc
.BI -d
.BI -D " drive_ordinal"
.BI -h " rmcserver"
.BI -l " loader"
[
.BI -V " vid"
] [
.BI -v
]
.br
.B smc
.BI -e
.BI -h " rmcserver"
.BI -l " loader"
.BI -V " vid"
[
.BI -v
]
.br
.B smc
.BI -i
.BI -h " rmcserver"
.BI -l " loader"
[
.BI -V " vid"
] [
.BI -v
]
.br
.B smc
.BI -m
.BI -D " drive_ordinal"
.BI -h " rmcserver"
[
.BI -I
]
.BI -l " loader"
.BI -V " vid"
[
.BI -v
]
.br
.B smc
.BI -h " rmcserver"
.BI -l " loader"
.B -q D
[
.BI -D " drive_ordinal"
]
[
.BI -v
]
.br
.B smc
.BI -h " rmcserver"
.BI -l " loader"
.B -q L
[
.BI -v
]
.br
.B smc
.BI -h " rmcserver"
.BI -l " loader"
.B -q P
[
.BI -v
]
.br
.B smc
.BI -h " rmcserver"
.BI -l " loader"
.B -q S
[
.BI -N " nbelem"
] [
.BI -S " starting_slot"
] [
.BI -v
]
.br
.B smc
.BI -h " rmcserver"
.BI -l " loader"
.B -q V
[
.BI -N " nbelem"
] [
.BI -V " vid"
] [
.BI -v
]
.SH DESCRIPTION
.B smc
is a program allowing to mount, dismount, export volumes in a robotic
library through SCSI. It allows also to query various elements of the library.
.SH OPTIONS
.TP
.BI \-d
triggers a dismount operation. The drive must be already unloaded.
The drive must be specified while the vid of the cartridge is optional.
If
.B -V
is specified, the vid must match the vid on the cartridge to be dismounted.
.TP
.BI \-e
exports a volume. The cartridge must be in a storage slot (not a drive).
The vid must be specified.
.TP
.BI \-h " rmcserver"
specifies the hostname of the machine where the Remote SCSI Media Changer
daemon runs. This parameter is mandatory.
.TP
.BI \-I
flips media side.
.TP
.BI \-i
imports either a specific volume indicated by
.B -V
option or all volumes in state "import" in the import/export cells.
.TP
.BI \-l " loader"
specifies the picker SCSI device. This parameter is mandatory.
.TP
.BI \-m
triggers a mount operation. The drive must be free.
The drive and the vid must be specified.
.TP
.BI \-N " nbelem"
allows to specify the maximum number of entries to be reported.
.TP
.BI \-q " query_type"
queries the library and produce a report about the status of various elements
in the library.
.I query_type
may be one of the following:
.RS
.TP
.B D
produce a list of drives with their status and the vid of the mounted tape
if any. Unless a specific drive is also given with the option
.BR -D ,
the status of all drives is reported.
.TP
.B L
prints the result of the INQUIRY command (Vendor/Product/Revision).
It gives also the starting address and the number of slots, drives, ports
and transports (hands) in the library.
.TP
.B P
prints the status of import/export slots.
.TP
.B S
prints the status of slots. By default all slots are reported, but the
starting address may be specified with the option
.B -S
and the number of elements to be reported may be given by the option
.BR -N .
.TP
.B V
prints the status of volumes. A single vid or a pattern may also be specified
with the option
.BR -V .
.RE
.TP
.B \-S " starting_slot"
specifies the starting slot address for the query operation.
.TP
.B \-V " vid"
A full vid or a pattern may be specified. In the latter case wild card
characters '*' and '?' may be used but must be escaped because of the shell.
.TP
.B \-v
verbose mode. On query requests it prints headers on top of the columns.
.SH EXAMPLES
.LP
To mount the volume JK2005 on drive 1:
.br
.RS
.B "smc -l /dev/smc01 -m -D 1 -V JK2005"
.RE
.LP
To dismount the volume present on drive 1 after checking the vid:
.br
.RS
.B "smc -l /dev/smc01 -d -D 1 -V JK2005"
.RE
.LP
To query the main charateristics of the library:
.br
.RS
.B "smc -l /dev/smc01 -q L"
.sp
.nf
Vendor/Product/Revision = <STK 9714 1500>
Transport Count = 1, Start = 1000
Slot Count = 99, Start = 0
Port Count = 1, Start = 1010
Device Count = 2, Start = 1030
.fi
.RE
.LP
To query the status of all the drives:
.br
.RS
.B "smc -l /dev/smc01 -q D -v"
.sp
.nf
.cs R 20
Drive Ordinal Element Addr. Status Vid
0 1030 free
1 1031 unloaded JK2005
.cs R
.fi
.RE
.LP
To get the list of a few slots in the library:
.br
.RS
.B "smc -l /dev/smc01 -q S -S 20 -N 10 -v"
.sp
.nf
.cs R 20
Element Addr. Vid
20 JK2021
21 JK2022
22 JK2023
23 JK2024
24 JK2025
25 JK2026
26 JK2027
27 JK2028
28 JK2029
29 JK2030
.cs R
.fi
.RE
.LP
To get the status of volumes for which the vid starts with JK200
.br
.RS
.B "smc -l /dev/smc01 -q V -V 'JK200*' -v"
.sp
.nf
.cs R 20
Vid Element Addr. Element Type
JK2001 0 slot
JK2002 1 slot
JK2003 2 slot
JK2004 3 slot
JK2006 5 slot
JK2007 6 slot
JK2008 7 slot
JK2009 8 slot
JK2005 1031 drive
.cs R
.fi
.RE
.SH RETURN CODES
0 Ok.
.br
1 Parameter error or unrecoverable error (just log it).
.br
2 Should release drive & retry in 600 seconds.
.br
3 Should retry in 60 seconds.
.br
4 Should do first a demount force.
.br
5 Should configure the drive down.
.br
6 Should send a msg to operator and exit.
.br
7 Ops msg (nowait) + release drive + slow retry.
.br
8 Should send a msg to operator and wait.
.br
9 Should unload the tape and retry demount.
.br
16 Robot busy.
.SH AUTHOR
\fBCASTOR\fP Team <castor.support@cern.ch>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment