diff --git a/mediachanger/castorrmc/rmc/Imakefile b/mediachanger/castorrmc/rmc/Imakefile index 56458a49c0dcabf721e3d14b633820e8e319e642..46555483090b6039fcddfbda62e3f267e702e252 100644 --- a/mediachanger/castorrmc/rmc/Imakefile +++ b/mediachanger/castorrmc/rmc/Imakefile @@ -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) diff --git a/mediachanger/castorrmc/rmc/smc.c b/mediachanger/castorrmc/rmc/smc.c new file mode 100644 index 0000000000000000000000000000000000000000..92053554a706744750d9bf49e8d013734a1fa67e --- /dev/null +++ b/mediachanger/castorrmc/rmc/smc.c @@ -0,0 +1,465 @@ +/* + * 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); +} diff --git a/mediachanger/castorrmc/rmc/smc.man b/mediachanger/castorrmc/rmc/smc.man new file mode 100644 index 0000000000000000000000000000000000000000..0703995836a4aebf016da436ab8feb597c5fc078 --- /dev/null +++ b/mediachanger/castorrmc/rmc/smc.man @@ -0,0 +1,291 @@ +.\" 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>