⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mtxl.c

📁 通用SCSI设备备份/读写程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/*  MTX -- SCSI Tape Attached Medium Changer Control Program  Copyright 1997-1998 by Leonard N. Zubkoff <lnz@dandelion.com>$Date: 2002/09/27 17:23:28 $$Revision: 1.8.2.7 $  This file created Feb 2000 by Eric Lee Green <eric@badtux.org> from pieces  extracted from mtx.c, plus some additional routines.   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.*//* FatalError: changed Feb. 2000 elg@estinc.com to eliminate a buffer   overflow :-(. That could be important if mtxl is SUID for some reason. */#include "mtx.h"#include "mtxl.h"/* #define DEBUG_MODE_SENSE 1 *//* #define DEBUG *//* #define DEBUG_SCSI *//* zap the following define when we finally add real import/export support */#define IMPORT_EXPORT_HACK 1 /* for the moment, import/export == storage *//* First, do some SCSI routines: *//* the camlib is used on FreeBSD. */#if HAVE_CAMLIB_H#  include "scsi_freebsd.c"#endif/* the scsi_ctl interface is used on HP/UX. */#if HAVE_SYS_SCSI_CTL_H#  include "scsi_hpux.c"#endif/* the 'sg' interface is used on Linux. */#if HAVE_SCSI_SG_H#  include "scsi_linux.c"#endif/* The 'uscsi' interface is used on Solaris. */#if HAVE_SYS_SCSI_IMPL_USCSI_H#  include "scsi_sun.c"#endif/* The 'tm_buf' interface, as used on AIX. */#ifdef HAVE_SYS_SCSI_H#  include "scsi_aix.c"#endif/* The 'dslib' interface is used on SGI. */#if HAVE_DSLIB_H#  include "scsi_sgi.c"#endif/* Hmm, dunno what to do about Digital Unix at the moment. */#ifdef DIGITAL_UNIX#include "du/scsi.c"#endif#ifdef VMS#include "[.vms]scsi.c"#endifextern char *argv0; /* something to let us do good error messages. *//* Now for some low-level SCSI stuff: */Inquiry_T *RequestInquiry(DEVICE_TYPE fd, RequestSense_T *RequestSense) {  Inquiry_T *Inquiry;  CDB_T CDB;  Inquiry = (Inquiry_T *) xmalloc(sizeof(Inquiry_T));      CDB[0] = 0x12;		/* INQUIRY */  CDB[1] = 0;			/* EVPD = 0 */  CDB[2] = 0;			/* Page Code */  CDB[3] = 0;			/* Reserved */  CDB[4] = sizeof(Inquiry_T);	/* Allocation Length */  CDB[5] = 0;			/* Control */  /* set us a very short timeout, sigh... */  SCSI_Set_Timeout(30); /* 30 seconds, sigh! */  if (SCSI_ExecuteCommand(fd, Input, &CDB, 6,			  Inquiry, sizeof(Inquiry_T), RequestSense) != 0)    {      free(Inquiry);      return NULL;  /* sorry! */    }  return Inquiry;}int BigEndian16(unsigned char *BigEndianData){  return (BigEndianData[0] << 8) + BigEndianData[1];}int BigEndian24(unsigned char *BigEndianData){  return (BigEndianData[0] << 16) + (BigEndianData[1] << 8) + BigEndianData[2];}void FatalError(char *ErrorMessage, ...){#define FORMAT_BUF_LEN 1024  char FormatBuffer[FORMAT_BUF_LEN];  char *SourcePointer;  char *TargetPointer = FormatBuffer;  int Character, LastCharacter = '\0';  int numchars = 0;  va_list ArgumentPointer;  va_start(ArgumentPointer, ErrorMessage);  /*  SourcePointer = "mtx: "; */  sprintf(TargetPointer,"%s: ",argv0);  numchars=strlen(TargetPointer);    /* while ((Character = *SourcePointer++) != '\0') { */  /*  *TargetPointer++ = Character;                   */  /*  numchars++;                                     */  /*   }                                              */     while ((Character = *ErrorMessage++) != '\0')    if (LastCharacter == '%')      {	if (Character == 'm')	  {	    SourcePointer = strerror(errno);	    while ((Character = *SourcePointer++) != '\0') {	      *TargetPointer++ = Character;	      numchars++;	      if (numchars==FORMAT_BUF_LEN-1) break;  	    }	    if (numchars==FORMAT_BUF_LEN-1) break;  /* break outer loop... */	  }	else	  {	    *TargetPointer++ = '%';	    *TargetPointer++ = Character;	    numchars++;	    if (numchars==FORMAT_BUF_LEN-1) break;	  }	LastCharacter = '\0';      }    else      {	if (Character != '%') {	  *TargetPointer++ = Character;	  numchars++;	  if (numchars==FORMAT_BUF_LEN-1) break;	}	LastCharacter = Character;      }  *TargetPointer = '\0';  /* works even if we had to break from above... */  vfprintf(stderr, FormatBuffer, ArgumentPointer);  va_end(ArgumentPointer);#ifndef VMS  exit(1);#else  sys$exit(VMS_ExitCode);#endif}/* This is a really slow and stupid 'bzero' implementation'... */void slow_bzero(char *buffer, int numchars) {  while (numchars--) *buffer++ = 0;}/* malloc some memory while checking for out-of-memory conditions. */void *xmalloc(size_t Size){  void *Result = (void *) malloc(Size);  if (Result == NULL)    FatalError("cannot allocate %d bytes of memory\n", Size);  return Result;}/* malloc some memory, zeroing it too: */void *xzmalloc(size_t Size){  void *Result=(void *)xmalloc(Size);    slow_bzero(Result,Size);  return Result;}int min(int x, int y){  return (x < y ? x : y);}int max(int x, int y){  return (x > y ? x : y);}/* Routine to inventory the library. Needed by, e.g., some Breece Hill * loaders. Sends an INITIALIZE_ELEMENT_STATUS command. This command * has no parameters, such as a range to scan :-(.  */int Inventory(DEVICE_TYPE MediumChangerFD) {  CDB_T CDB;  RequestSense_T RequestSense;   /* okay, now for the command: */  CDB[0]=0x07;   CDB[1]=CDB[2]=CDB[3]=CDB[4]=CDB[5]=0;  /* set us a very long timeout, sigh... */  SCSI_Set_Timeout(30*60); /* 30 minutes, sigh! */    if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,NULL,0,&RequestSense) != 0) {    return -1;  /* could not do! */  }  return 0; /* did do! */}/* Routine to send an UNLOAD from the SSC spec to a device. This can be * used either to eject a tape (when sent to a tape drive), or to eject * a magzine (on some Seagate changers, when sent to LUN 1 ).  */int Eject(DEVICE_TYPE fd) {  CDB_T CDB;  RequestSense_T RequestSense;  /* okay, now for the command: */    CDB[0]=0x1b;  CDB[1]=CDB[2]=CDB[3]=CDB[4]=CDB[5]=0;    if (SCSI_ExecuteCommand(fd,Input,&CDB,6,NULL,0,&RequestSense) != 0) {    return -1;  /* could not do! */  }  return 0; /* did do! */}  /* Routine to read the Mode Sense Element Address Assignment Page *//* We try to read the page. If we can't read the page, we return NULL. * Our caller really isn't too worried about why we could not read the * page, it will simply default to some kind of default values.  */ ElementModeSense_T *ReadAssignmentPage(DEVICE_TYPE MediumChangerFD) {  CDB_T CDB;  ElementModeSense_T *retval;  /* processed SCSI. */  unsigned char input_buffer[136];  ElementModeSensePage_T *sense_page; /* raw SCSI. */  RequestSense_T RequestSense;       /* see what retval of raw SCSI was... */    /* okay, now for the command: */  CDB[0]=0x1a; /* Mode Sense(6) */  CDB[1]=0;   CDB[2]=0x1d; /* Mode Sense Element Address Assignment Page */  CDB[3]=0;  CDB[4]=136; /* allocation_length... */  CDB[5]=0;  /* clear the data buffer: */  slow_bzero((char *)&RequestSense,sizeof(RequestSense_T));  slow_bzero((char *)input_buffer,sizeof(input_buffer));  if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,			  &input_buffer,sizeof(input_buffer),&RequestSense) != 0) {#ifdef DEBUG_MODE_SENSE    fprintf(stderr,"Could not execute mode sense...\n");    fflush(stderr);#endif    return NULL; /* sorry, couldn't do it. */  }  /* Could do it, now build return value: */#ifdef DEBUG_MODE_SENSE  {    int i;    for (i=0;i<30;i+=3) {      fprintf(stderr,"ib[%d]=%d ib[%d]=%d ib[%d]=%d\n",	      i,input_buffer[i],i+1,input_buffer[i+1],	      i+2,input_buffer[i+2]);      /*  fprintf(stderr,"input_buffer[0]=%d input_buffer[3]=%d\n",       *	  input_buffer[0], input_buffer[3]);       */    }    fflush(stderr);  }#endif  /* first, skip past: mode data header, and block descriptor header if any */  sense_page=(ElementModeSensePage_T *)(input_buffer+4+input_buffer[3]);#ifdef DEBUG_MODE_SENSE  fprintf(stderr,"*sense_page=%x  %x\n",*((unsigned char *)sense_page),sense_page->PageCode);  fflush(stderr);#endif    retval=(ElementModeSense_T *) xzmalloc(sizeof(ElementModeSense_T));  /* Remember that all SCSI values are big-endian: */  retval->MediumTransportStart=(((int)sense_page->MediumTransportStartHi)<<8) +    sense_page->MediumTransportStartLo;  retval->NumMediumTransport=(((int)(sense_page->NumMediumTransportHi))<<8) +    sense_page->NumMediumTransportLo;  /* HACK! Some HP autochangers don't report NumMediumTransport right! */  /* ARG! TAKE OUT THE %#@!# HACK! */#ifdef STUPID_DUMB_IDIOTIC_HP_LOADER_HACK  if (!retval->NumMediumTransport) {    retval->NumMediumTransport=1;  }#endif#ifdef DEBUG_MODE_SENSE  fprintf(stderr,"rawNumStorage= %d %d    rawNumImportExport= %d %d\n",	  sense_page->NumStorageHi,sense_page->NumStorageLo,	  sense_page->NumImportExportHi, sense_page->NumImportExportLo);  fprintf(stderr,"rawNumTransport=%d %d  rawNumDataTransfer=%d %d\n",	  sense_page->NumMediumTransportHi,sense_page->NumMediumTransportLo,	  sense_page->NumDataTransferHi,sense_page->NumDataTransferLo);  fflush(stderr);#endif  retval->StorageStart=(((int)(sense_page->StorageStartHi))<<8) +    sense_page->StorageStartLo;  retval->NumStorage=(((int)(sense_page->NumStorageHi))<<8) +     sense_page->NumStorageLo;  retval->ImportExportStart=(((int)(sense_page->ImportExportStartHi))<<8)+    sense_page->ImportExportStartLo;   retval->NumImportExport=(((int)(sense_page->NumImportExportHi))<<8)+    sense_page->NumImportExportLo;  retval->DataTransferStart=(((int)(sense_page->DataTransferStartHi))<<8)+    sense_page->DataTransferStartLo;  retval->NumDataTransfer=(((int)(sense_page->NumDataTransferHi))<<8)+    sense_page->NumDataTransferLo;  /* allocate a couple spares 'cause some HP autochangers and maybe others   * don't properly report the robotics arm(s) count here...    */  retval->NumElements=retval->NumStorage+retval->NumImportExport+    retval->NumDataTransfer+retval->NumMediumTransport;  retval->MaxReadElementStatusData=(sizeof(ElementStatusDataHeader_T) +				    4 * sizeof(ElementStatusPage_T) +				    (retval->NumElements) *				      sizeof(TransportElementDescriptor_T));#ifdef IMPORT_EXPORT_HACK  retval->NumStorage=retval->NumStorage+retval->NumImportExport;#endif#ifdef DEBUG_MODE_SENSE  fprintf(stderr,"NumMediumTransport=%d\n",retval->NumMediumTransport);  fprintf(stderr,"NumStorage=%d\n",retval->NumStorage);  fprintf(stderr,"NumImportExport=%d\n",retval->NumImportExport);  fprintf(stderr,"NumDataTransfer=%d\n",retval->NumDataTransfer);  fprintf(stderr,"MaxReadElementStatusData=%d\n",retval->MaxReadElementStatusData);  fprintf(stderr,"NumElements=%d\n",retval->NumElements);  fflush(stderr);#endif    return retval;}static void FreeElementData(ElementStatus_T *data){  free(data->DataTransferElementAddress);  free(data->DataTransferElementSourceStorageElementNumber);  free(data->DataTransferPrimaryVolumeTag);  free(data->DataTransferAlternateVolumeTag);  free(data->PrimaryVolumeTag);  free(data->AlternateVolumeTag);  free(data->StorageElementAddress);  free(data->StorageElementIsImportExport);  free(data->StorageElementFull);  free(data->DataTransferElementFull);}         /* allocate data  */static ElementStatus_T *AllocateElementData(ElementModeSense_T *mode_sense) {  ElementStatus_T *retval;  retval=(ElementStatus_T *) xzmalloc(sizeof(ElementStatus_T));  /* now for the invidual component arrays.... */  retval->DataTransferElementAddress = (int *) xzmalloc(sizeof(int)*                                    (mode_sense->NumDataTransfer + 1));  retval->DataTransferElementSourceStorageElementNumber =     (int *) xzmalloc(sizeof(int)*(mode_sense->NumDataTransfer+1));  retval->DataTransferPrimaryVolumeTag=    (barcode *)xzmalloc(sizeof(barcode)*(mode_sense->NumDataTransfer+1));  retval->DataTransferAlternateVolumeTag=    (barcode *)xzmalloc(sizeof(barcode)*(mode_sense->NumDataTransfer+1));  retval->PrimaryVolumeTag=    (barcode *)xzmalloc(sizeof(barcode)*(mode_sense->NumStorage+1));  retval->AlternateVolumeTag=    (barcode *)xzmalloc(sizeof(barcode)*(mode_sense->NumStorage+1));  retval->StorageElementAddress=    (int *)xzmalloc(sizeof(int)*(mode_sense->NumStorage+1));  retval->StorageElementIsImportExport=    (boolean *)xzmalloc(sizeof(boolean)*(mode_sense->NumStorage+1));      retval->StorageElementFull=    (boolean *)xzmalloc(sizeof(boolean)*(mode_sense->NumStorage+1));      retval->DataTransferElementFull=    (boolean *)xzmalloc(sizeof(boolean)*(mode_sense->NumDataTransfer+1));    return retval; /* sigh! */}void copy_barcode(unsigned char *src, unsigned char *dest) {  int i;    for (i=0; i < 36; i++) {    *dest=*src++;#ifdef __WEIRD_CHAR_SUPPRESS    if ((*dest < 32) || (*dest > 127))       *dest = '\0';

⌨️ 快捷键说明

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