mtx.c

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

C
779
字号
	   (ElementStatus->StorageElementFull[StorageElementNumber] ? "Full " : "Empty"));    if (ElementStatus->PrimaryVolumeTag[StorageElementNumber][0]) {      printf(":VolumeTag=%s",ElementStatus->PrimaryVolumeTag[StorageElementNumber]);    }    if (ElementStatus->AlternateVolumeTag[StorageElementNumber][0]) {            printf(":AlternateVolumeTag=%s",ElementStatus->AlternateVolumeTag[StorageElementNumber]);    }    putchar('\n');  }  #ifdef VMS  VMS_DefineStatusSymbols();#endif}void Move(int src, int dest) {  RequestSense_T *result; /* from MoveMedium */    result=MoveMedium(MediumChangerFD,src,dest,ElementStatus,inquiry_info,&SCSI_Flags);  if (result)   /* we have an error! */     {      if (result->AdditionalSenseCode == 0x3B &&	  result->AdditionalSenseCodeQualifier == 0x0E)	FatalError("source Element Address %d is Empty\n", src);      if (result->AdditionalSenseCode == 0x3B &&	  result->AdditionalSenseCodeQualifier == 0x0D)	FatalError("destination Element Address %d is Already Full\n",		   dest);      if (result->AdditionalSenseCode == 0x30 &&	  result->AdditionalSenseCodeQualifier == 0x03)	FatalError("Cleaning Cartridge Installed and Ejected\n");      PrintRequestSense(result);      FatalError("MOVE MEDIUM from Element Address %d to %d Failed\n",		 src,dest);    }}   /* okay, now for the Load, Unload, etc. logic: */static void Load(void) {  int src, dest;  /* okay, check src, dest: arg1=src, arg2=dest */  if (arg1 < 1) {    FatalError("No source specified\n");  }  if (arg2 < 0) {    arg2 = 0; /* default to 1st drive :-( */  }  arg1--;  /* we use zero-based arrays, sigh, not 1 base like some lusers */  /* check for filehandle: */  if (!device_opened) {    FatalError("No Media Changer Device Specified\n");  }   /* okay, we should be there: */  if (arg1 < 0 || arg1 >= ElementStatus->StorageElementCount) {    	FatalError(	  "illegal <storage-element-number> argument '%s' to 'load' command\n",	  arg1+1);  }  if (arg2 < 0 || arg2 >= ElementStatus->DataTransferElementCount) {    FatalError(	       "illegal <drive-number> argument '%s' to 'load' command\n",	       arg2);  }  if (ElementStatus->DataTransferElementFull[arg2])  {    FatalError("Drive %d Full (Storage Element %d loaded)\n",arg2,	       ElementStatus->DataTransferElementSourceStorageElementNumber[arg2]+1);  }  /* Now look up the actual devices: */  dest=ElementStatus->DataTransferElementAddress[arg2];  src=ElementStatus->StorageElementAddress[arg1];  Move(src,dest);  /* load it into the particular slot, if possible! */  /* now set the status for further command son this line... */  ElementStatus->StorageElementFull[arg1] = false;  ElementStatus->DataTransferElementFull[arg2] = true;  return; /* and done! */}static void Transfer(void) {  int src,dest;  if (arg1 < 1 ) {    FatalError("No source specified\n");  }   if (arg2 < 1) {    FatalError("No destination specified\n");  }  if (arg1 > ElementStatus->StorageElementCount) {    FatalError("Invalid source\n");  }  if (arg2 > ElementStatus->StorageElementCount) {    FatalError("Invalid destination\n");  }  /* okay, that's done... */  src=ElementStatus->StorageElementAddress[arg1-1];  dest=ElementStatus->StorageElementAddress[arg2-1];  Move(src,dest);}static void Eepos(void) {  if (arg1 < 0 || arg1 > 3) {    FatalError("eepos equires argument between 0 and 3.\n");  }  SCSI_Flags.eepos=arg1;}static void Unload(void) {  int src,dest;  /* the actual SCSI-level numbers */  if (arg2 < 0) {    arg2 = 0; /* default to 1st drive :-( */  }  /* check for filehandle: */  if (!device_opened) {    FatalError("No Media Changer Device Specified\n");  }   /* okay, we should be there: */  if (arg1 < 0) {    arg1 = ElementStatus->DataTransferElementSourceStorageElementNumber[arg2];    if (arg1 < 0) {      FatalError("No Source for tape in drive %d!\n");    }  } else {    arg1--; /* go from bogus 1-base to zero-base */  }  if (arg1 >= ElementStatus->StorageElementCount) {    	FatalError(	  "illegal <storage-element-number> argument '%s' to 'unload' command\n",	  arg1+1);  }      if (arg2 < 0 || arg2 >= ElementStatus->DataTransferElementCount) {    FatalError(	       "illegal <drive-number> argument '%s' to 'unload' command\n",	       arg2);  }  if (ElementStatus->DataTransferElementFull[arg2] < 0 ) {    FatalError("Data Transfer Element %d is Empty\n", arg2);  }      /* Now see if something already lives where  we wanna go... */  if (ElementStatus->StorageElementFull[arg1]) {    FatalError("Storage Element %d is Already Full\n", arg1+1);  }  /* okay, now to get src, dest: */  src=ElementStatus->DataTransferElementAddress[arg2];  if (arg1 >=0) {    dest=ElementStatus->StorageElementAddress[arg1];  } else {    dest=ElementStatus->DataTransferElementSourceStorageElementNumber[arg2];  }  if (dest < 0) { /* we STILL don't know, sigh... */    FatalError("Do not know which slot to unload tape into!\n");  }  fprintf(stderr, "Unloading Data Transfer Element into Storage Element %d...", arg1+1);  fflush(stderr); /* make it real-time :-( */   Move(src,dest);  fprintf(stderr, "done\n");  ElementStatus->StorageElementFull[arg1] = true;  ElementStatus->DataTransferElementFull[arg2] = false;}/***************************************************************** ** ARGUMENT PARSING SUBROUTINES: Parse arguments, dispatch.  *****************************************************************//* *** * int get_arg(idx): * * If we have an actual argument at the index position indicated (i.e. we * have not gone off the edge of the world), we return * its number. If we don't, or it's not a numeric argument,  * we return -1. Note that 'get_arg' is kind of misleading, we only accept  * numeric arguments, not any other kind.  */int get_arg(int idx) {  char *arg;  int retval=-1;  if (idx >= argc) return -1;  /* sorry! */  arg=argv[idx];  if (*arg < '0' || *arg > '9') {    return -1;  /* sorry! */  }  retval=atoi(arg);  return retval;}/* open_device() -- set the 'fh' variable.... */void open_device(void) {  if (device_opened) {    SCSI_CloseDevice("Unknown",MediumChangerFD);  /* close it, sigh...  new device now! */  }  MediumChangerFD = SCSI_OpenDevice(device);  device_opened=1; /* SCSI_OpenDevice does an exit() if not. */}  /* we see if we've got a file open. If not, we open one :-(. Then * we execute the actual command. Or not :-(.  */ void execute_command(struct command_table_struct *command) {  RequestSense_T RequestSense;  if ((device==NULL) && command->need_device) {   /* try to get it from TAPE environment variable... */    device=getenv("CHANGER");    if (device==NULL) {      device=getenv("TAPE");      if (device==NULL) {	device="/dev/changer"; /* Usage(); */      }    }    open_device();  }  if (!ElementStatus && command->need_status) {    inquiry_info=RequestInquiry(MediumChangerFD,&RequestSense);    if (!inquiry_info) {      PrintRequestSense(&RequestSense);      FatalError("INQUIRY command Failed\n");    }    ElementStatus = ReadElementStatus(MediumChangerFD,&RequestSense,inquiry_info,&SCSI_Flags);    if (!ElementStatus) {      PrintRequestSense(&RequestSense);                         FatalError("READ ELEMENT STATUS Command Failed\n");     }  }  /* okay, now to execute the command... */  command->command();}/* parse_args(): *   Basically, we are parsing argv/argc. We can have multiple commands * on a line now, such as "unload 3 0 load 4 0" to unload one tape and * load in another tape into drive 0, and we execute these commands one * at a time as we come to them. If we don't have a -f at the start, we * barf. If we leave out a drive #, we default to drive 0 (the first drive * in the cabinet).  */ int parse_args(void) {  int i,cmd_tbl_idx;  struct command_table_struct *command;  i=1;  while (i<argc) {    if (strcmp(argv[i],"-f") == 0) {      i++;      if (i>=argc) {	Usage();      }      device=argv[i++];      open_device(); /* open the device and do a status scan on it... */    } else {      cmd_tbl_idx=0;      command=&command_table[0]; /* default to the first command... */      command=&command_table[cmd_tbl_idx];      while (command->name) {	if (!strcmp(command->name,argv[i])) {	  /* we have a match... */	  break;	}	/* otherwise we don't have a match... */	cmd_tbl_idx++;	command=&command_table[cmd_tbl_idx];      }      /* if it's not a command, exit.... */      if (!command->name) {	Usage();      }      i++;  /* go to the next argument, if possible... */      /* see if we need to gather arguments, though! */      if (command->num_args == 0) {	execute_command(command);  /* execute_command handles 'stuff' */      }      else {	arg1=get_arg(i);  /* checks i... */	if (arg1 != -1) {	  i++;  /* next! */	}	if (command->num_args==2 && arg1 != -1) {	  arg2=get_arg(i); 	  if (arg2 != -1) {	    i++;	  }	}	execute_command(command);      }      arg1=-1;      arg2=-1;    }  }  return 0; /* should never get here. */}int main(int ArgCount,	 char *ArgVector[],	 char *Environment[]){#ifdef VMS  RequestSense_T RequestSense;#endif    /* save these where we can get at them elsewhere... */  argc=ArgCount;  argv=ArgVector;  argv0=argv[0];     parse_args();  /* also executes them as it sees them, sigh. */#ifndef VMS  if (device)     SCSI_CloseDevice(device, MediumChangerFD);  return 0;#else  if (device) {    ElementStatus = ReadElementStatus(MediumChangerFD,&RequestSense);    if (!ElementStatus) {      PrintRequestSense(&RequestSense);                         FatalError("READ ELEMENT STATUS Command Failed\n");     }    VMS_DefineStatusSymbols();    SCSI_CloseDevice(device, MediumChangerFD);  }  return SS$_NORMAL;#endif}/* *$Log: mtx.c,v $ *Revision 1.2.2.1  2001/11/06 21:20:40  elgreen *Hopefully a fix to the problem with the 0 return for open in crontabs * *Revision 1.2  2001/06/09 17:26:26  elgreen *Added 'nobarcode' command to mtx (to skip the initial request asking for *barcodes for mtx status purposes). * *Revision 1.1.1.1  2001/06/05 17:10:22  elgreen *Initial import into SourceForge * *Revision 1.15  2001/04/18 16:32:59  eric *Cleaned up all -Wall messages. * *Revision 1.14  2001/04/18 16:08:08  eric *after re-arranging & fixing bugs * *Revision 1.13  2001/03/06 01:37:05  eric *Solaris changes * *Revision 1.12  2001/01/24 22:04:08  eric *added /dev/changer as default file name. * *Revision 1.11  2001/01/15 22:21:06  eric *added autoconf stuff. * *Revision 1.10  2000/11/30 20:37:17  eric *Added quicky 'erase' command because I needed blank tapes and Linux *only does long erases. (Not documented on purpose, because of rather *bizarre interactions with the native tape driver if you don't know *what you are doing). * *Revision 1.9  2000/11/28 01:10:50  eric *Fixed syntax error in mtx.c... * *Revision 1.8  2000/10/28 00:10:35  eric *Fixed stupid typo * *Revision 1.7  2000/10/27 23:36:57  eric *make mtx inventory return an error code if the inventory fails, so that *we can wait for inventory to be completed at system startup * * */

⌨️ 快捷键说明

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