ftp.nice.ch/pub/next/tools/tape/ArchiveViper150Tool.N.bs.tar.gz#/tape.c

This is tape.c in view mode; [Download] [Up]

/*
*
*    This program is a tool to access a tape like "Archive Viper 150" from
*    a NeXT computer. (compiled under NS2.1)
*
*    tape [-f device] [fsf|fsr|bsf|bsr|rew|end] [count]
*
*    tape -f device        : set device, default is /dev/nrst0 (not rewinding!)
*    tape fsf              : Forward space 1 (count) EOF marks
*    tape fsr              : Forward space 1 (count) records
*    tape bsf              : Back space 1 (count) EOF marks
*    tape bsr              : Back space 1 (count) records
*    tape rew              : rewind tape
*    tape end              : space to EOF (behind last EOF mark)
*
*    tape < file           : write file to tape
*    tape > file           : read file from tape
*
*    examples:
*    tar cvf - files | tape     : write files on the tape using tar    
*    tape | tar xvf - files     : read files from the tape using tar
*
*
*    written by Max Boehm (boehm@cs.uni-duesseldorf.de)
*
*/


#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <nextdev/scsireg.h>


#define BLK_SIZE 512
#define COUNT 128
#define BUF_SIZE (COUNT*BLK_SIZE)

#define TIMEOUT (60*30)		/* 30 Minuten Timeout */


void error_message (struct scsi_req *sr)
{
    static char *io_status_tab[18] = {
    "successful","selection timeout","check status, sr_esense valid",
    "check status, sr_esense not valid",
    "target attempted to move more than sr_dma_max bytes",
    "sr_ioto exceeded","SCSI Bus violation","command reject (by driver)",
    "memory allocation failure","memory fault","not super user",
    "device not open","target aborted command",
    "bad SCSI status byte  (other than check status)",
    "internal driver error","unexpected byte count seen on SCSI bus",
    "desired volume not available","Media Write Protected" };
    static char *sensekey_tab[16] = {
    "NO SENSE","RECOVERED ERROR","NOT READY","MEDIUM ERROR",
    "HARDWARE ERROR","ILLEGAL REQUEST","UNIT ATTENTION","DATA PROTECT",
    "BLANK CHECK","VENDOR UNIQUE","?","ABORTED COMMAND",
    "?","VOLUME OVERFLOW","?","?" };
    static char *scsi_status_tab[16] = {
    "GOOD STATUS","CHECK CONDITION","?","?","BUSY","?","?","?",
    "INTERMEDIATE STATUS","?","?","?","RESERVATION CONFLICT","?","?","?" };
    
    if(sr->sr_io_status) {
	fprintf(stderr,"sr_io_status  = %02XH : %s\n",sr->sr_io_status,
	(unsigned)sr->sr_io_status<18?io_status_tab[sr->sr_io_status]:"?");
	if(sr->sr_io_status == SR_IOST_CHKSV) {
	    fprintf(stderr,"   sense key  = %02XH : %s\n",
		sr->sr_esense.er_sensekey,
		sensekey_tab[sr->sr_esense.er_sensekey&15]);
	    fprintf(stderr,"   sense code = %02XH\n",
		sr->sr_esense.er_addsensecode);
	}
	fprintf(stderr,"SCSI status   = %02XH : %s\n",sr->sr_scsi_status,
	scsi_status_tab[(sr->sr_scsi_status&15)>>1]);
	fprintf(stderr,"sr_dma_xfr    = %-5d actual number of bytes transferred\n",
	sr->sr_dma_xfr);
    }
}



int do_ioc (int fd, struct scsi_req *sr)
{
    if (ioctl(fd,MTIOCSRQ,sr) < 0) {
	fprintf(stderr,"..Error executing ioctl\n");
	fprintf(stderr,"errno = %d\n",errno);
	perror("ioctl(MTIOCSRQ)");
	return -1;
    }
    if (sr->sr_io_status) {
	error_message(sr);
	return -1;
    }
    return 0;
}


void cdb_clr (union cdb *cdbp)
{
    int i;
    char *p;
    
    p = (char *)cdbp;
    for(i=0; i<sizeof(union cdb); i++)
	*p++ = 0;
}


int st_read (int fd, int block_count, char *bp)
/* read block_count blocks. Data goes to *bp.
   The actual number of bytes transferred is returned (-1 on error).
*/
{
    struct scsi_req sr;	
    struct cdb_6s *cdbp = &sr.sr_cdb.cdb_c6s;
    
    cdb_clr((union cdb*)cdbp);
    cdbp->c6s_opcode    = C6OP_READ;
    cdbp->c6s_lun       = 0;
    cdbp->c6s_opt       = C6OPT_FIXED;		/* fixed block size */
    cdbp->c6s_len	= block_count;
    cdbp->c6s_ctrl	= 0;
    sr.sr_dma_dir	= SR_DMA_RD;
    sr.sr_addr		= bp;
    sr.sr_dma_max	= block_count * BLK_SIZE;
    sr.sr_ioto		= TIMEOUT;
    if (do_ioc(fd,&sr)<0)
	return -1;
    return sr.sr_dma_xfr;		/* number of bytes transferred */
}


int st_write (int fd, int block_count, char *bp)
/* write block_count blocks. Data comes from *bp.
   The actual number of bytes transferred is returned (-1 on error).
*/
{
    struct scsi_req sr;	
    struct cdb_6s *cdbp = &sr.sr_cdb.cdb_c6s;
    
    cdb_clr((union cdb*)cdbp);
    cdbp->c6s_opcode    = C6OP_WRITE;
    cdbp->c6s_lun       = 0;
    cdbp->c6s_opt       = C6OPT_FIXED;		/* fixed block size */
    cdbp->c6s_len	= block_count;
    cdbp->c6s_ctrl	= 0;
    sr.sr_dma_dir	= SR_DMA_WR;
    sr.sr_addr		= bp;
    sr.sr_dma_max	= block_count * BLK_SIZE;
    sr.sr_ioto		= TIMEOUT;
    if (do_ioc(fd,&sr)<0)
	return -1;
    return sr.sr_dma_xfr;		/* number of bytes transferred */
}


int st_rewind (int fd)
/* Band zurueckspulen */
{
    struct scsi_req sr;	
    struct cdb_6s *cdbp = &sr.sr_cdb.cdb_c6s;
    
    cdb_clr((union cdb*)cdbp);
    cdbp->c6s_opcode    = C6OP_REWIND;
    cdbp->c6s_lun       = 0;
    cdbp->c6s_opt       = 0;
    cdbp->c6s_len	= 0;
    cdbp->c6s_ctrl	= 0;
    sr.sr_dma_dir	= SR_DMA_RD;
    sr.sr_addr		= NULL;
    sr.sr_dma_max	= 0;
    sr.sr_ioto		= TIMEOUT;
    return (do_ioc(fd,&sr));
}


int st_seek_block (int fd, int block)
/* scheinbar hat der erste Block auf dem Band die Nummer 2! */
{
    struct scsi_req sr;	
    struct cdb_6s *cdbp = &sr.sr_cdb.cdb_c6s;
    
    cdb_clr((union cdb*)cdbp);
    cdbp->c6s_opcode    = 0x0C;			/* SEEK BLOCK */
    cdbp->c6s_lun       = 0;
    cdbp->c6s_opt       = 0;
    cdbp->c6s_len	= block;
    cdbp->c6s_ctrl	= 0;
    sr.sr_dma_dir	= SR_DMA_RD;
    sr.sr_addr		= NULL;
    sr.sr_dma_max	= 0;
    sr.sr_ioto		= TIMEOUT;
    return (do_ioc(fd,&sr));
}


int st_space (int fd, int code, int count)
/*
code=C6OPT_SPACE_LB	space logical blocks
code=C6OPT_SPACE_FM	space filemarks
code=C6OPT_SPACE_SFM	space sequential filemarks
code=C6OPT_SPACE_PEOD	space to physical end of data
*/
{
    struct scsi_req sr;	
    struct cdb_6s *cdbp = &sr.sr_cdb.cdb_c6s;
    
    cdb_clr((union cdb*)cdbp);
    cdbp->c6s_opcode    = C6OP_SPACE;
    cdbp->c6s_lun       = 0;
    cdbp->c6s_opt       = code;
    cdbp->c6s_len	= count;
    cdbp->c6s_ctrl	= 0;
    sr.sr_dma_dir	= SR_DMA_RD;
    sr.sr_addr		= NULL;
    sr.sr_dma_max	= 0;
    sr.sr_ioto		= TIMEOUT;
    return (do_ioc(fd,&sr));
}


/*****************************************************************/


int read_tape (int fd, int out)
{
    static char buf[BUF_SIZE];
    int cnt;
    
    do {
	cnt=st_read(fd,COUNT,buf);
	if (cnt<0) {
	    perror("read");
	    return -1;
	}
	if (cnt==0)
	    break;
	if (write(out,buf,cnt)!=cnt) {
	    perror("write");
	    return -1;
	}
    }
    while (cnt==BUF_SIZE);
    
    return 0;
}


int write_tape (int fd, int in)
{
    static char buf[BUF_SIZE];
    int cnt;
    
    do {
	cnt=0;
	while (cnt<BUF_SIZE) {
	    int c=read(in,buf+cnt,BUF_SIZE-cnt);
	    if (c<0) {
		perror("read");
		return -1;
	    }
	    if (c==0)
		break;
	    cnt+=c;
	}
	if (cnt==0)
	    break;
	cnt=(cnt+BLK_SIZE-1)/BLK_SIZE;
	if (st_write(fd,cnt,buf)!=cnt*BLK_SIZE) {
	    perror("write");
	    return -1;
	}
    }
    while (1);
    
    return 0;
}


#define READ_TAPE  1
#define WRITE_TAPE 2


int main (int argc, char **argv)
{
    char *dev_name;
    int fd, count, err, flag;
    struct stat s;

    flag=0;
    if (fstat(fileno(stdout),&s))
	perror("fstat stdout");
    if ((s.st_mode&S_IFMT)!=S_IFCHR)
	flag=READ_TAPE;
    else {
	if (fstat(fileno(stdin),&s))
	    perror("fstat stdin");
	if ((s.st_mode&S_IFMT)!=S_IFCHR)
	    flag=WRITE_TAPE;
    }
    
    argc--;
    argv++;
    if (argc==0 && flag==0) {
	fprintf(stderr,
	"usage: tape [-f device] [fsf|fsr|bsf|bsr|rew|end] [count]\n");
	return 1;
    }
    
    if (argc>0 && strcmp(argv[0],"-f")==0) {
	argc--;
	argv++;
	if (argc==0) {
	    fprintf(stderr,"tapename expected!\n");
	    return 1;
	}
	dev_name=argv[0];
	argc--;
	argv++;
    }
    else
	dev_name="/dev/nrst0";
    
    fd=open(dev_name,O_RDWR,0);
    if (fd<0) {
	perror("open");
	return 1;
    }
    
    err=0;

    if (argc>0) {
	if (argc>1) {
	    if (sscanf(argv[1],"%d",&count)!=1) {
		fprintf(stderr,"count expected!\n");
		return 1;
	    }
	}
	else
	    count=1;
	
	if (strcmp(argv[0],"fsf")==0)
	    err=st_space(fd,C6OPT_SPACE_FM,count);
	else if (strcmp(argv[0],"fsr")==0)
	    err=st_space(fd,C6OPT_SPACE_LB,count);
	else if (strcmp(argv[0],"bsf")==0)
	    err=st_space(fd,C6OPT_SPACE_FM,-count);
	else if (strcmp(argv[0],"bsr")==0)
	    err=st_space(fd,C6OPT_SPACE_LB,-count);
	else if (strcmp(argv[0],"rew")==0)
	    err=st_rewind(fd);
	else if (strcmp(argv[0],"end")==0)
	    err=st_space(fd,C6OPT_SPACE_PEOD,0);
	
	if (err)
	    return 2;
    }

    if (flag==READ_TAPE) {		/* copy tape to stdout */
	fprintf(stderr,"tape %s -> stdout ...\n",dev_name);
	err=read_tape(fd,fileno(stdout));
    }
    else if (flag==WRITE_TAPE) {	/* copy stdin to tape */
	fprintf(stderr,"stdin -> tape %s ...\n",dev_name);
	err=write_tape(fd,fileno(stdin));
    }

    close(fd);
    
    return err?2:0;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.