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 + -
显示快捷键?