mtx.c

来自「通用SCSI设备备份/读写程序」· C语言 代码 · 共 779 行 · 第 1/2 页

C
779
字号
/*  MTX -- SCSI Tape Attached Medium Changer Control Program  $Date: 2001/11/06 21:20:40 $  $Revision: 1.2.2.1 $  Copyright 1997-1998 by Leonard N. Zubkoff <lnz@dandelion.com>  Now maintained by Eric Lee Green <eric@estinc.com>  This program is free software; you may redistribute and/or modify it under  the terms of the GNU General Public License Version 2 as published by the  Free Software Foundation.  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 complete details.  The author respectfully requests that any modifications to this software be  sent directly to him for evaluation and testing.  Thanks to Philip A. Prindeville <philipp@enteka.com> of Enteka Enterprise  Technology Service for porting MTX to Solaris/SPARC.  Thanks to Carsten Koch <Carsten.Koch@icem.de> for porting MTX to SGI IRIX.  Thanks to TECSys Development, Inc. for porting MTX to Digital Unix and  OpenVMS.  Changes Feb 2000 Eric Lee Green <eric@estinc.com> to add support for  multi-drive tape changers, extract out library stuff into mtxl.c,  and otherwise bring things up to date for dealing with LARGE tape jukeboxes  and other such enterprise-class storage subsystems. */char *argv0;#include "mtx.h"   /* various defines for bit order etc. */#include "mtxl.h"/* A table for printing out the peripheral device type as ASCII. */ static char *PeripheralDeviceType[32] = {  "Disk Drive",  /* 0 */  "Tape Drive",   /* 1 */  "Printer",   /* 2 */  "Processor",   /* 3 */  "Write-once",   /* 4 */  "CD-ROM",       /* 5 */  "Scanner",      /* 6 */  "Optical",      /* 7 */   "Medium Changer",  /* 8 */  "Communications",  /* 9 */  "ASC IT8",           /* a */   "ASC IT8",            /* b */  "RAID Array",         /* c */  "Enclosure Services",  /* d */  "RBC Simplified Disk", /* e */  "OCR/W",           /* f */  "Bridging Expander", /* 0x10 */  "Reserved",  /* 0x11 */  "Reserved", /* 0x12 */  "Reserved",  /* 0x13 */  "Reserved",  /* 0x14 */  "Reserved",  /* 0x15 */  "Reserved",  /* 0x16 */  "Reserved",  /* 0x17 */  "Reserved",  /* 0x18 */  "Reserved",  /* 0x19 */  "Reserved",  /* 0x1a */  "Reserved",  /* 0x1b */  "Reserved",  /* 0x1c */  "Reserved",  /* 0x1d */  "Reserved",  /* 0x1e */  "Unknown"    /* 0x1f */};  static int argc;static char **argv;static char *device=NULL; /* the device name passed as argument *//* Unfortunately this must be true for SGI, because SGI does not   use an int :-(. */static DEVICE_TYPE MediumChangerFD = (DEVICE_TYPE) 0;static int device_opened = 0;  /* okay, replace check here. *//* was: static int MediumChangerFD=-1; *//* open filehandle to that device */static int arg1=-1;       /* first arg to command */static int arg2=-1;       /* second arg to command */static SCSI_Flags_T SCSI_Flags = { 0, 0, 0,0 };  /* static int invert_bit=0;*/  /* we by default do not invert... *//* static int eepos=0;     */  /* the extend thingy for import/export. */static Inquiry_T *inquiry_info;  /* needed by MoveMedium etc... */static ElementStatus_T *ElementStatus = NULL;/* pre-defined commands: */static void ReportInquiry(void);static void Status(void);static void Load(void);static void Unload(void);static void First(void);static void Last(void);static void Next(void);/* static void Previous(void); */static void InvertCommand(void);static void Transfer(void);static void Eepos(void);static void NoAttach(void);static void Version(void);static void do_Inventory(void); static void do_Unload(void);static void do_Erase(void);static void NoBarCode(void);struct command_table_struct {  int num_args;  char *name;  void (*command)(void);  int need_device;  int need_status;} command_table[] = {  { 0, "inquiry",ReportInquiry, 1,0},  { 0, "status", Status, 1,1 },  { 0, "invert", InvertCommand, 0,0},  { 0, "noattach",NoAttach,0,0},  { 1, "eepos", Eepos, 0,0},  { 2, "load", Load, 1,1 },  { 2, "unload", Unload, 1,1 },  { 2, "transfer", Transfer, 1,1 },  { 1, "first", First, 1,1 },  { 1, "last", Last, 1,1 },  { 1, "next", Next, 1,1 },  { 0, "--version", Version, 0,0 },  { 0, "inventory", do_Inventory, 1,0},  { 0, "eject", do_Unload, 1, 0},  { 0, "erase", do_Erase, 1, 0},  { 0, "nobarcode", NoBarCode, 0,0},  { 0, NULL, NULL }};static void Usage(){  fprintf(stderr, "Usage:\n\  mtx --version\n\  mtx [ -f <loader-dev> ] noattach <more commands>\n\  mtx [ -f <loader-dev> ] inquiry | inventory \n\  mtx [ -f <loader-dev> ] [nobarcode] status\n\  mtx [ -f <loader-dev> ] first [<drive#>]\n\  mtx [ -f <loader-dev> ] last [<drive#>]\n\  mtx [ -f <loader-dev> ] next [<drive#>]\n\  mtx [ -f <loader-dev> ] previous [<drive#>]\n\  mtx [ -f <loader-dev> ] [invert] load <storage-element-number> [<drive#>]\n\  mtx [ -f <loader-dev> ] [invert] unload [<storage-element-number>][<drive#>]\n\  mtx [ -f <loader-dev> ] [eepos eepos-number] transfer <storage-element-number> <storage-element-number>\n\  mtx [ -f <device> ] eject\n");#ifndef VMS  exit(1);#else  sys$exit(VMS_ExitCode);#endif}static void Version(void) {  fprintf(stderr,"mtx version %s\n\n",VERSION);  Usage(); }static void NoAttach(void) {  SCSI_Flags.no_attached=1;}static void InvertCommand(void) {  SCSI_Flags.invert=1;  /* invert_bit=1;*/}static void NoBarCode(void) {  SCSI_Flags.no_barcodes=1;  /* don't request barcodes, sigh! */} /* First and Last are easy. Next is the bitch. */static void First(void){  int driveno;  /* okay, first see if we have a drive#: */  if (arg1 >= 0 && arg1 < ElementStatus->DataTransferElementCount) {    driveno=arg1;  } else {    driveno = 0;  }  /* now see if there's anything *IN* that drive: */  if (ElementStatus->DataTransferElementFull[driveno]) {    /* if so, then unload it... */    arg1=ElementStatus->DataTransferElementSourceStorageElementNumber[driveno]+1;    if (arg1==1) {      printf("loading...done.\n");  /* it already has tape #1 in it! */       return;    }    arg2=driveno;    Unload();  }  /* and now to actually do the Load(): */  arg2=driveno;  arg1=1; /* first! */  Load(); /* and voila! */  }static void Last(void) {  int driveno;  /* okay, first see if we have a drive#: */  if (arg1 >= 0 && arg1 < ElementStatus->DataTransferElementCount) {    driveno=arg1;  } else {    driveno = 0;  }  /* now see if there's anything *IN* that drive: */  if (ElementStatus->DataTransferElementFull[driveno]) {    /* if so, then unload it... */    arg1=ElementStatus->DataTransferElementSourceStorageElementNumber[driveno]+1;    if (arg1==ElementStatus->StorageElementCount) {      printf("loading...done.\n");  /* it already has last tape in it! */       return;    }    arg2=driveno;    Unload();  }  arg1 = ElementStatus->StorageElementCount; /* the last slot... */  arg2=driveno;  Load(); /* and load it, sigh! */}static void Next(void) {  int driveno;  int current=0;   /* okay, first see if we have a drive#: */  if (arg1 >= 0 && arg1 < ElementStatus->DataTransferElementCount) {    driveno=arg1;  } else {    driveno = 0;  }  /* Now to see if there's anything in that drive! */  if (ElementStatus->DataTransferElementFull[driveno]) {    /* if so, unload it! */    arg1=ElementStatus->DataTransferElementSourceStorageElementNumber[driveno]+1;    current=arg1;    arg2=driveno;    Unload();  }    /* okay, now to load, if we can... */  current++;  if (current > ElementStatus->StorageElementCount) { /* the last slot... */    FatalError("No More Tapes\n");  }  arg1=current;  arg2=driveno;  Load();}static void do_Inventory(void) {  int i;  i=Inventory(MediumChangerFD);  if (i < 0) {    fprintf(stderr,"mtx:inventory failed\n");    fflush(stderr);    exit(1); /*  exit with an error status. */  }  return;  /* if it failed, well, sigh.... */}/* For Linux, this allows us to do a short erase on a tape (sigh!). * Note that you'll need to do a 'mt status' on the tape afterwards in * order to get the tape driver in sync with the tape drive again. Also * note that on other OS's, this might do other evil things to the tape * driver. Note that to do an erase, you must first rewind using the OS's * native tools! */static void do_Erase(void) {  RequestSense_T *RequestSense;  RequestSense=Erase(MediumChangerFD);  if (RequestSense) {    PrintRequestSense(RequestSense);    exit(1);  /* exit with an error status. */  }  return;}  /* This should eject a tape or magazine, depending upon the device sent * to. */static void do_Unload(void){  int i;  i=Eject(MediumChangerFD);  if (i<0) {    fprintf(stderr,"mtx:eject failed\n");    fflush(stderr);  }  return;  /* if it failed, well, sigh.... */}static void ReportInquiry(void){  RequestSense_T RequestSense;  Inquiry_T *Inquiry;  int i;  Inquiry = RequestInquiry(MediumChangerFD,&RequestSense);  if (Inquiry == NULL)     {      PrintRequestSense(&RequestSense);      FatalError("INQUIRY Command Failed\n");    }    printf("Product Type: %s\n",PeripheralDeviceType[Inquiry->PeripheralDeviceType]);  printf("Vendor ID: '");  for (i = 0; i < sizeof(Inquiry->VendorIdentification); i++)    printf("%c", Inquiry->VendorIdentification[i]);  printf("'\nProduct ID: '");  for (i = 0; i < sizeof(Inquiry->ProductIdentification); i++)    printf("%c", Inquiry->ProductIdentification[i]);  printf("'\nRevision: '");  for (i = 0; i < sizeof(Inquiry->ProductRevisionLevel); i++)    printf("%c", Inquiry->ProductRevisionLevel[i]);  printf("'\n");\  if (Inquiry->MChngr) {  /* check the attached-media-changer bit... */    printf("Attached Changer: Yes\n");  } else {    printf("Attached Changer: No\n");  }  free(Inquiry);  /* well, we're about to exit, but ... */}static void Status(void){  int StorageElementNumber;  int TransferElementNumber;  printf("  Storage Changer %s:%d Drives, %d Slots ( %d Import/Export )\n",	 device,	 ElementStatus->DataTransferElementCount,	 ElementStatus->StorageElementCount,	 ElementStatus->ImportExportCount);  for (TransferElementNumber=0;TransferElementNumber <	 ElementStatus->DataTransferElementCount;TransferElementNumber++) {        printf("Data Transfer Element %d:",TransferElementNumber);    if (ElementStatus->DataTransferElementFull[TransferElementNumber])      {	if (ElementStatus->DataTransferElementSourceStorageElementNumber[TransferElementNumber] > -1) 	  printf("Full (Storage Element %d Loaded)",		 ElementStatus->DataTransferElementSourceStorageElementNumber[TransferElementNumber]+1);	else printf("Full (Unknown Storage Element Loaded)");	if	  (ElementStatus->DataTransferPrimaryVolumeTag[TransferElementNumber][0])	  printf(":VolumeTag = %s",ElementStatus->DataTransferPrimaryVolumeTag[TransferElementNumber]);	if	  (ElementStatus->DataTransferAlternateVolumeTag[TransferElementNumber][0])	  	  printf(":AlternateVolumeTag = %s",ElementStatus->DataTransferAlternateVolumeTag[TransferElementNumber]); 	putchar('\n');      }    else printf("Empty\n");  }  for (StorageElementNumber = 0;       StorageElementNumber < ElementStatus->StorageElementCount;       StorageElementNumber++) {    printf("      Storage Element %d%s:%s", StorageElementNumber+1, 	   (ElementStatus->StorageElementIsImportExport[StorageElementNumber]) ? " IMPORT/EXPORT" : "",

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?