scsitape.c

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

C
852
字号
/* Copyright 2001 Enhanced Software Technologies Inc. *   Released under terms of the GNU General Public License as * required by the license on 'mtxl.c'. * $Date: 2001/06/05 17:10:27 $ * $Revision: 1.1.1.1 $ *//* This is a generic SCSI tape control program. It operates by * directly sending commands to the tape drive. If you are going * through your operating system's SCSI tape driver, do *NOT* use  * this program! If, on the other hand, you are using raw READ and WRITE * commands through your operating system's generic SCSI interface (or * through our built-in 'read' and 'write'), this is the place for you.  *//*#define DEBUG_PARTITION *//*#define DEBUG 1 *//*    Commands:         setblk <n> -- set the block size to <n>         fsf <n> -- go forward by <n> filemarks         bsf <n> -- go backward by <n> filemarks         eod  -- go to end of data         rewind -- rewind back to start of data         eject  -- rewind, then eject the tape. 	 erase  -- (short) erase the tape (we have no long erase)         mark <n> -- write <n> filemarks.         seek <n> -- seek to position <n>.	 write <blksize> <-- write blocks from stdin to the tape          read  [<blksize>] [<#blocks/#bytes>] -- read blocks from tape, write to stdout.    See the 'tapeinfo' program for status info about the tape drive. */#include <stdio.h>#include <string.h>#include "mtx.h"#include "mtxl.h"#include <unistd.h>#include <sys/types.h>#include <sys/ioctl.h>#include <sys/mtio.h> /* will try issuing some ioctls for Solaris, sigh. */void Usage(void) {  FatalError("Usage: scsitape -f <generic-device> <command> where <command> is:\n setblk <n> | fsf <n> | bsf <n> | eod | rewind | eject | mark <n> |\n  seek <n> | read [<blksize> [<numblocks]] | write [<blocksize>] \n");}#define arg1 (arg[0])  /* for backward compatibility, sigh */static int arg[4];  /* the argument for the command, sigh. *//* the device handle we're operating upon, sigh. */static unsigned char *device;  /* the text of the device thingy. */static DEVICE_TYPE MediumChangerFD = (DEVICE_TYPE) 0;static int S_setblk(void);static int S_fsf(void);static int S_bsf(void);static int S_eod(void);static int S_rewind(void);static int S_eject(void);static int S_mark(void);static int S_seek(void);static int S_reten(void);static int S_erase(void);static int S_read(void);static int S_write(void);struct command_table_struct {  int num_args;  char *name;  int (*command)(void);} command_table[] = {  { 1, "setblk", S_setblk },  { 1, "fsf", S_fsf },  { 1, "bsf", S_bsf },  { 0, "eod", S_eod },  { 0, "rewind", S_rewind },  { 0, "eject", S_eject },  { 0, "reten", S_reten },  { 0, "erase", S_erase },  { 1, "mark", S_mark },  { 1, "seek", S_seek },  { 2, "read", S_read },  { 2, "write",S_write }};char *argv0;/* A table for printing out the peripheral device type as ASCII. */ static char *PeripheralDeviceType[32] = {  "Disk Drive",  "Tape Drive",  "Printer",  "Processor",  "Write-once",  "CD-ROM",  "Scanner",  "Optical",  "Medium Changer",  "Communications",  "ASC IT8",  "ASC IT8",  "RAID Array",  "Enclosure Services",  "OCR/W",  "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 */};/* open_device() -- set the 'fh' variable.... */void open_device(void) {  if (MediumChangerFD) {    SCSI_CloseDevice("Unknown",MediumChangerFD);  /* close it, sigh...  new device now! */  }  MediumChangerFD = SCSI_OpenDevice(device);}static int get_arg(char *arg) {  int retval=-1;  if (*arg < '0' || *arg > '9') {    return -1;  /* sorry! */  }  retval=atoi(arg);  return retval;}/* we see if we've got a file open. If not, we open one :-(. Then * we execute the actual command. Or not :-(.  */ int execute_command(struct command_table_struct *command) {  /* if the device is not already open, then open it from the    * environment.   */  if (!MediumChangerFD) {    /* try to get it from STAPE or TAPE environment variable... */    device=getenv("STAPE");    if (device==NULL) {      device=getenv("TAPE");      if (device==NULL) {	Usage();      }    }    open_device();  }  /* okay, now to execute the command... */  return 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(int argc,char **argv) {  int i,cmd_tbl_idx,retval,arg_idx;  struct command_table_struct *command;  i=1;  arg_idx=0;  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! */      arg1=-1; /* default it to something */      for (arg_idx=0;arg_idx < command->num_args ; arg_idx++) {	if (i < argc) {	  arg[arg_idx]=get_arg(argv[i]);	  if (arg[arg_idx] !=  -1) {	    i++; /* increment i over the next cmd. */	  }	} else {	  arg[arg_idx]=0; /* default to 0 setmarks or whatever */	}       }      retval=execute_command(command);  /* execute_command handles 'stuff' */      exit(retval);    }  }  return 0; /* should never get here */}/* 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! */static int S_erase(void) {  int retval;  RequestSense_T *RequestSense;  retval=S_rewind();  if (retval) {    return retval;  /* we have an exit status :-(. */  }   RequestSense=Erase(MediumChangerFD);  if (RequestSense) {    PrintRequestSense(RequestSense);    exit(1);  /* exit with an error status. */  }  return 0;}/* This should eject a tape or magazine, depending upon the device sent * to. */static int S_eject(void){int i;  i=Eject(MediumChangerFD);  if (i<0) {    fprintf(stderr,"scsitape:eject failed\n");    fflush(stderr);  }  return i;  /* if it failed, well, sigh.... */}/* We write a filemarks of 0 before going to grab position, in order * to insure that data in the buffer is not a problem.  */static int S_mark(void) {  RequestSense_T RequestSense; /* for result of ReadElementStatus */  CDB_T CDB;  unsigned char buffer[6];  int count=arg1; /* voila! */  CDB[0]=0x10;  /* SET_MARK */  CDB[1]=0;  CDB[2]=(count >> 16) & 0xff;  CDB[3]=(count >>8) & 0xff;  CDB[4]=count & 0xff;  CDB[5]=0;   /* we really don't care if this command works or not, sigh.  */  slow_bzero((unsigned char *)&RequestSense,sizeof(RequestSense_T));  if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,buffer,0,&RequestSense)!=0){    PrintRequestSense(&RequestSense);    return 1;  }  return 0;}/* let's rewind to bod!  */static int S_rewind(void) {  RequestSense_T sense;  CDB_T CDB;  unsigned char buffer[6];  CDB[0]=0x01;  /* REWIND */  CDB[1]=0;  CDB[2]=0;  CDB[3]=0;  CDB[4]=0;  CDB[5]=0;   /* we really don't care if this command works or not, sigh.  */  slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T));  if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,buffer,0,&sense)!=0){    PrintRequestSense(&sense);    return 1;  }  return 0;}/* This is used for fsf and bsf. */static int Space(int count,int code){  RequestSense_T sense;  CDB_T CDB;  unsigned char buffer[6];  CDB[0]=0x11;  /* SET_MARK */  CDB[1]=code;  CDB[2]=(count >> 16) & 0xff;  CDB[3]=(count >>8) & 0xff;  CDB[4]=count & 0xff;  CDB[5]=0;   /* we really don't care if this command works or not, sigh.  */  slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T));  if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,buffer,0,&sense)!=0){    PrintRequestSense(&sense);    return 1;  }  return 0;  }/* Let's try a fsf: *//* We write a filemarks of 0 before going to grab position, in order * to insure that data in the buffer is not a problem.  */static int S_fsf(void) {  return Space(arg1,1); /* go forward! */}static int S_bsf(void) {  return Space(-arg1,1); /* go backward! */}static int S_eod(void) {  return Space(0,3); /* go to eod! */}/* sigh, abuse of the LOAD command... */static int S_reten(void) {  RequestSense_T sense;  CDB_T CDB;  unsigned char buffer[6];  CDB[0]=0x1b;  /* START_STOP */  CDB[1]=0; /* wait */  CDB[2]=0;  CDB[3]=0;  CDB[4]=3; /* reten. */   CDB[5]=0;   /* we really don't care if this command works or not, sigh.  */  slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T));  if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,buffer,0,&sense)!=0){    PrintRequestSense(&sense);    return 1;  }  return 0;}/* seek a position on the tape (sigh!) */static int S_seek(void){  RequestSense_T sense;  CDB_T CDB;  unsigned char buffer[6];  int count =  arg1;  /* printf("count=%d\n",arg1); */  CDB[0]=0x2b;  /* LOCATE */  CDB[1]=0;  /* Logical */  CDB[2]=0; /* padding */  CDB[3]=(count >> 24) & 0xff;  CDB[4]=(count >> 16) & 0xff;  CDB[5]=(count >>8) & 0xff;  CDB[6]=count & 0xff;  CDB[7]=0;   CDB[8]=0;   CDB[9]=0;   /* we really don't care if this command works or not, sigh.  */  slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T));  if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,10,buffer,0,&sense)!=0){    PrintRequestSense(&sense);

⌨️ 快捷键说明

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