/* @(#)riodev.c 17.1.1.1 (ES0-DMD) 01/25/02 17:58:06 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, MA 02139, USA. Corresponding concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .TYPE Module .NAME iodev .LANGUAGE C .AUTHOR IPG-ESO Garching .CATEGORY Host operating system interfaces. Tape management. .COMMENTS Remote tape management. The functions of this module perform basic i/o to magnetic tapes on UNIX enviroments .VERSION 1.1 24-Jan-1990 Implementation C. Guirao .ENVIRONMENT UNIX ------------------------------------------------------------*/ static char class_name[] = "remote"; /* MAgnetic Tape Class */ #define DEBUG 1 #include #include #include #include #include #include #include extern int errno; extern int oserror; extern char *oserrmsg; #ifdef SYSV_V2 #define BCOPY(a,b,c) memcpy((b),(a),(c)) #else /* BSD */ #define BCOPY(a,b,c) bcopy((a),(b),(c)) #endif #define OPEN_DEVICE 0 #define CLOSE_DEVICE 1 #define READ_DATA 2 #define WRITE_DATA 3 #define WRITE_EOF 4 #define SKIP_FSF 5 #define SKIP_BSF 6 #define REWIND 7 #define SKIP_FSR 8 #define SKIP_BSR 9 #define SKIP_EOM 10 #define READ_INFO 11 #define NULL 0 #define RET_ERROR(x) { oserror = (x); return(-1); } #define RET_OUT_SYNC { oserrmsg = msg0; oserror = -1; return(-1); } #define TAPE_SERVICE "tcp_tape" /* must be defined in /etc/services */ #define MAXMSG 160 /* Max. lenth for a error message */ static int fdr, fdw; /* Read and Write descriptors for sockets*/ static char *message; static char msg0[] = "Out of syncronism with tape server"; struct command { int cmd; int param[4]; int nobyt; }; struct result { int ret; int oserror; int nobyt; }; static char errmsg[MAXMSG]; char *malloc(); static int ioctop(op) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Interface to remote ioctl routine. .RETURNS 0 (OK) / -1 (error) ------------------------------------------------------------*/ struct command *op; { int nobyt, ret; struct result res; oserror=0; nobyt = sizeof(struct command); if ( (ret=osxwrite(fdw,(char *)op,nobyt,'c')) < 0) return(-1); if ( ret != nobyt) RET_OUT_SYNC; nobyt = sizeof(struct result); if ( (ret=osxread(fdr,(char *)&res,nobyt,'c')) < 0) return(-1); if ( ret != nobyt ) RET_OUT_SYNC; oserror=res.oserror; if ( res.ret < 0 && res.nobyt > 0) { if (( message = malloc((unsigned)res.nobyt)) == NULL) RET_ERROR(ENOMEM); if ( (ret=osxread(fdr,message,res.nobyt,'c')) < 0) return(-1); if ( ret != res.nobyt ) RET_OUT_SYNC; strncpy(errmsg,message,MIN(res.nobyt,MAXMSG)); oserrmsg=errmsg; free(message); } return(res.ret); } static int ioinfo(fd, s, filenum, blkno) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Retrieve Info concerning an opened device .RETURNS 0 (success) / -1 (error) ------------------------------------------------------------*/ int fd; /* IN: File Descriptor */ struct osustat *s; /* OUT: The filled components */ int *filenum; /* OUT: Where we are */ long *blkno; /* OUT: Where we are */ { int nobyt, ret; char *buffer; struct command op; struct result res; oserror=0; op.cmd = READ_INFO; op.param[0] = fd; op.param[1] = sizeof(struct osustat) + sizeof(int) + sizeof(long); nobyt = sizeof(struct command); if ( (ret=osxwrite(fdw,(char *)&op,nobyt,'c')) < 0) return(-1); if ( ret != nobyt ) RET_OUT_SYNC; nobyt = sizeof(struct result); if ( (ret=osxread(fdr,(char *)&res,nobyt,'c')) < 0) return(-1); if ( ret != nobyt ) RET_OUT_SYNC; if ((buffer = malloc((unsigned)op.param[1])) == NULL) RET_ERROR(ENOMEM); if (res.ret = 0) { if ( (ret=osxread(fdr,buffer,op.param[1],'c')) < 0) return(-1); if ( ret != op.param[1] ) RET_OUT_SYNC; } BCOPY(s,buffer,sizeof(struct osustat)); *filenum = (int) buffer[sizeof(struct osustat)]; *blkno = (long) buffer[sizeof(struct osustat)+sizeof(int)]; free(buffer); oserror=res.oserror; if ( res.ret < 0 && res.nobyt > 0) { if (( message = malloc((unsigned)res.nobyt)) == NULL) RET_ERROR(ENOMEM); if ( (ret=osxread(fdr,message,res.nobyt,'c')) < 0) return(-1); if ( ret != res.nobyt ) RET_OUT_SYNC; strncpy(errmsg,message,MIN(res.nobyt,MAXMSG)); oserrmsg=errmsg; free(message); } return(res.ret); } static int ioopen(name,class,mode,den) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Open a tape device .RETURNS File descriptor / -1 (error) ------------------------------------------------------------*/ char *name; /* IN: Physical name of tape device */ char *class; /* IN: Class name */ int mode; /* IN: Open mode */ int den; /* IN: Density. Not used */ { static char devname[80], remotehost[64]; static char *channame[2]; static char localhost[64]; register char *p, *q; char *buff; int nobyt, ret; struct command op; struct result res; oserror = 0; /* Clear error from getdev */ for (q = remotehost , p = name ; (*p) && (*p != '!'); p++) *q = *p ; *q = '\0'; if (*p == '!') p++; else { oserror = -1; oserrmsg = "Name not in format"; return(-1); } for (q = devname; *p; p++, q++) *q = *p; *q = '\0'; channame[0] = TAPE_SERVICE; channame[1] = remotehost; if ( (fdr=osxopen(channame,NETW|IPC_READ)) < 0 ) return(-1); if ( (fdw=osxopen(channame,NETW|IPC_WRITE)) < 0 ) return(-1); gethostname(localhost,64); op.cmd = OPEN_DEVICE; op.param[0] = mode; op.param[1] = den; op.param[2] = strlen(name); op.param[3] = strlen(class); op.nobyt = strlen(name) + strlen(class) + strlen(localhost); nobyt = sizeof(struct command); if ( (ret=osxwrite(fdw,(char *)&op,nobyt,'c')) < 0) return(-1); if ( ret != nobyt ) RET_OUT_SYNC; if (( buff = malloc((unsigned)op.nobyt)) == NULL) RET_ERROR(ENOMEM); strcpy(buff,name); strcat(buff,class); strcat(buff,localhost); if ( (ret=osxwrite(fdw,buff,op.nobyt,'c')) < 0) return(-1); if ( ret != op.nobyt ) RET_OUT_SYNC; free(buff); nobyt = sizeof(struct result); if ( (ret=osxread(fdr,(char *)&res,nobyt,'c')) < 0) return(-1); if ( ret != nobyt ) RET_OUT_SYNC; oserror=res.oserror; if ( res.ret < 0 && res.nobyt > 0) { if (( message = malloc((unsigned)res.nobyt)) == NULL) RET_ERROR(ENOMEM); if ( (ret=osxread(fdr,message,res.nobyt,'c')) < 0) return(-1); if ( ret != res.nobyt ) RET_OUT_SYNC; strncpy(errmsg,message,MIN(res.nobyt,MAXMSG)); oserrmsg=errmsg; free(message); } return(res.ret); } static int ioclose(fd) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Close the opened device .RETURNS 0 ------------------------------------------------------------*/ int fd; /* IN: Tape file descriptor */ { int nobyt, ret; struct command op; struct result res; oserror=0; op.cmd = CLOSE_DEVICE; op.param[0] = fd; op.nobyt = 0; nobyt = sizeof(struct command); if ( (ret=osxwrite(fdw,(char *)&op,nobyt,'c')) < 0) return(-1); if ( ret != nobyt ) RET_OUT_SYNC; nobyt = sizeof(struct result); if ( (ret=osxread(fdr,(char *)&res,nobyt,'c')) < 0) return(-1); if ( ret != nobyt ) RET_OUT_SYNC; oserror=res.oserror; if ( res.ret < 0 && res.nobyt > 0) { if (( message = malloc((unsigned)res.nobyt)) == NULL) RET_ERROR(ENOMEM); if ( (ret=osxread(fdr,message,res.nobyt,'c')) < 0) return(-1); if ( ret != res.nobyt ) RET_OUT_SYNC; strncpy(errmsg,message,MIN(res.nobyt,MAXMSG)); oserrmsg=errmsg; free(message); } if ( osxclose(fdr) < 0) return(-1); if ( osxclose(fdw) < 0) return(-1); return(res.ret); } static int ioread(fd,buffer,size) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Read a block from a magnetic tape. .RETURNS Bytes read / -1 if error .REMARKS 0 Bytes read, means a File Mark was detected. .REMARKS oserror set to -2 if buffer too small ------------------------------------------------------------*/ int fd; /* IN: Tape device file descriptor */ char *buffer; /* IN: Buffer for reading */ int size; /* IN: Length of bytes to be read */ { int nobyt, ret; struct command op; struct result res; oserror=0; op.cmd = READ_DATA; op.param[0] = fd; op.param[1] = size; op.nobyt = 0; nobyt = sizeof(struct command); if ( (ret=osxwrite(fdw,(char *)&op,nobyt,'c')) < 0) return(-1); if ( ret != nobyt ) RET_OUT_SYNC; nobyt = sizeof(struct result); if ( (ret=osxread(fdr,(char *)&res,nobyt,'c')) < 0) return(-1); if ( ret != nobyt ) RET_OUT_SYNC; if (res.ret > 0) { if ( (ret=osxread(fdr,buffer,res.ret,'c')) < 0) return(-1); if ( ret != res.ret ) RET_OUT_SYNC; } oserror=res.oserror; if ( res.ret < 0 && res.nobyt > 0) { if (( message = malloc((unsigned)res.nobyt)) == NULL) RET_ERROR(ENOMEM); if ( (ret=osxread(fdr,message,res.nobyt,'c')) < 0) return(-1); if ( ret != res.nobyt ) RET_OUT_SYNC; strncpy(errmsg,message,MIN(res.nobyt,MAXMSG)); oserrmsg=errmsg; free(message); } return(res.ret); } static int iowrite(fd,buffer,size) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Write a block on a magnetic tape. .RETURNS Bytes written / -1 (error) ------------------------------------------------------------*/ int fd; /* IN: Tape device file descriptor */ char *buffer; /* IN: Buffer for reading */ int size; /* IN: Length of bytes to be read */ { int nobyt, ret; struct command op; struct result res; oserror=0; op.cmd = WRITE_DATA; op.param[0] = fd; op.param[1] = size; op.nobyt = 0; nobyt = sizeof(struct command); if ( (ret=osxwrite(fdw,(char *)&op,nobyt,'c')) < 0) return(-1); if ( ret != nobyt) RET_OUT_SYNC; if ( (ret=osxwrite(fdr,buffer,size,'c')) < 0) return(-1); if ( ret != size ) RET_OUT_SYNC; nobyt = sizeof(struct result); if ( (ret=osxread(fdr,(char *)&res,nobyt,'c')) < 0) return(-1); if ( ret != nobyt ) RET_OUT_SYNC; oserror=res.oserror; if ( res.ret < 0 && res.nobyt > 0) { if (( message = malloc((unsigned)res.nobyt)) == NULL) RET_ERROR(ENOMEM); if ( (ret=osxread(fdr,message,res.nobyt,'c')) < 0) return(-1); if ( ret != res.nobyt ) RET_OUT_SYNC; strncpy(errmsg,message,MIN(res.nobyt,MAXMSG)); oserrmsg=errmsg; free(message); } return(res.ret); } static int ioweof(fd,ntm) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Write end-of-file record (tape_mark) on the tape. .RETURNS 0 / -1 (error) ------------------------------------------------------------*/ int fd; /* IN: Tape device file descriptor */ int ntm; /* IN: Number of tape marks */ { struct command op; op.cmd = WRITE_EOF; op.param[0] = fd; op.param[1] = ntm; op.nobyt = 0; return(ioctop(&op)); } static int iofsf(fd,ntm) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Skip forward space file on a tape. .RETURNS Tape marks skipped/ -1 (error) ------------------------------------------------------------*/ int fd; /* IN: Tape device file descriptor */ int ntm; /* IN: Number of tape marks */ { struct command op; op.cmd = SKIP_FSF; op.param[0] = fd; op.param[1] = ntm; op.nobyt = 0; return(ioctop(&op)); } static int iobsf(fd,ntm) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Skip backward space file on a tape. .RETURNS Tape marks skipped/ -1 (error) ------------------------------------------------------------*/ int fd; /* IN: Tape device file descriptor */ int ntm; /* IN: Number of tape marks */ { struct command op; op.cmd = SKIP_BSF; op.param[0] = fd; op.param[1] = ntm; op.nobyt = 0; return(ioctop(&op)); } static int iorew(fd) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Rewind tape .RETURNS 0 / -1 (error) ------------------------------------------------------------*/ int fd; /* IN: Tape device file descriptor */ { struct command op; op.cmd = REWIND; op.param[0] = fd; op.nobyt = 0; return(ioctop(&op)); } static int iofsr(fd,count) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Forward space record on tape .RETURNS records skipped/ -1 (error) ------------------------------------------------------------*/ int fd; /* IN: Tape device file descriptor */ int count; /* IN: Number of records */ { struct command op; op.cmd = SKIP_FSR; op.param[0] = fd; op.param[1] = count; op.nobyt = 0; return(ioctop(&op)); } static int iobsr(fd,count) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Backward space record on tape .RETURNS records skipped/ -1 (error) ------------------------------------------------------------*/ int fd; /* IN: Tape device file descriptor */ int count; /* IN: Number of records */ { struct command op; op.cmd = SKIP_BSR; op.param[0] = fd; op.param[1] = count; op.nobyt = 0; return(ioctop(&op)); } /* #ifdef MTEOM /* Does the driver know the End-Of-Media ? */ static int ioeom(fd) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Move to EOMedia .RETURNS 0 (OK) / -1 (not done, error) ------------------------------------------------------------*/ int fd; /* IN: Tape device file descriptor */ { struct command op; op.cmd = SKIP_EOM; op.param[0] = fd; op.nobyt = 0; return(ioctop(&op)); } /*#endif */ /*===================================================================== * Definition of the structure returned to osu *=====================================================================*/ struct iolist *dumb(); static OPITEM list_of_functions[] = { { U_INFO, ioinfo}, { U_OPEN, ioopen}, { U_CLOSE, ioclose}, { U_READ, ioread}, { U_WRITE, iowrite}, { U_REWIND, iorew}, { U_WEOF, ioweof}, { U_FMF, iofsf}, /* File Move Forward */ { U_FMB, iobsf}, /* File Move Backward */ { U_BMF, iofsr}, /* Block Move Forward */ { U_BMB, iobsr}, /* Block Move Backward */ #ifdef MTEOM { U_EOM, ioeom} /* Move to EOMedia */ #endif }; static struct iolist this_dev = { dumb, /* Next iodev in List */ class_name, /* How it's written in DEVCAPFILE */ sizeof(list_of_functions)/sizeof(list_of_functions[0]), list_of_functions }; struct iolist *iodev() /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Get All definitions concerning this class of Devices .RETURNS The iolist .REMARKS Simply returns the local iolist address... ------------------------------------------------------------*/ { return(&this_dev); }