/* @(#)iodevg.c 17.1.1.1 (ES0-DMD) 01/25/02 17:35:07 */ /*=========================================================================== 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 iodevd .LANGUAGE C .AUTHOR IPG-ESO Garching .CATEGORY Host operating system interfaces. .COMMENTS Tape management. The functions of this module perform basic i/o to magnetic tapes on Unix enviroments .VERSION 1.0 08-Jan-1993 Implementation C. Guirao .ENVIRONMENT UNIX ------------------------------------------------------------*/ /* The IBM/6000 (AIX) does not support "mtio" interface. */ #if defined(_AIX) # define NO_MTIO #endif #define next_iodev iodev /* Next iodev in chain */ static char class_name[] = "generic"; /* Default Tape Class */ #include #ifndef NO_MTIO #include #include #include #include #include #include #include static struct mtget mt_stat; /* MagTape Status */ extern int errno; extern int oserror; extern char *oserrmsg; #define M_ST_MASK 077 /* Status code mask: ?? */ #else extern int oserror; extern char *oserrmsg; #endif /* On HPs there is MTEOD instead of MTEOM */ #if !defined(MTEOM) && defined(MTEOD) # define MTEOM MTEOD #endif /* On OSF/1 there is MTSEOD instead of MTEOM */ #if !defined(MTEOM) && defined(MTSEOD) # define MTEOM MTSEOD #endif #ifndef NO_MTIO static int iostat(fd) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Get status. .RETURNS None -----------------------------------------------------------*/ int fd; /* IN: Tape device file descriptor */ { oserror = 0; if (ioctl(fd,MTIOCGET,&mt_stat) == -1) { oserror = errno; return(-1); } #if DEBUG printf("type=0x%x\n",mt_stat.mt_type); printf("drive status=0%o\n",mt_stat.mt_dsreg); printf("error register=0%o\n",mt_stat.mt_erreg); printf("residual count=0x%x\n",mt_stat.mt_resid); #endif return(mt_stat.mt_erreg & M_ST_MASK); } static int ioctop(fd,op,count) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Interface to ioctl routine. .RETURNS 0 (OK) / -1 (error) ------------------------------------------------------------*/ int fd; /* IN: Tape device file descriptor */ int op; /* IN: Operation */ int count; /* IN: How many of them */ { struct mtop mtop; mtop.mt_op = op; mtop.mt_count = count; /* * First try to execute the command. * Even if fails, try to read the status */ if (ioctl(fd,MTIOCTOP,&mtop) == -1) { oserror = errno; return(-1); } return(0); } static int ioinfo(fd, s, fileno, 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 *fileno; /* OUT: Where we are */ long *blkno; /* OUT: Where we are */ { struct stat buf; oserror = 0; if ( fstat(fd,&buf) == -1) { oserror= errno; return(-1); } s->usize = 0; s->isda = 0; /* Not direct access */ s->istm = ((buf.st_mode & S_IFMT) == S_IFCHR); if (s->istm == 0) { oserror = -1; oserrmsg = "Device can't be a tape..."; return(-1); } /* Get current position ... */ if (fileno) { if( iostat(fd) == -1) return(-1); /* * Only sun and linux support mt_filenno and mt_blkno in the mtget struct, * hp9000s800 also defines these two variables, but they are always 0. */ #if defined(sun) || defined(__sun) || defined(__linux__) || defined(AUX) *fileno = mt_stat.mt_fileno; *blkno = mt_stat.mt_blkno; #else *fileno = -1; *blkno = -1; #endif } return(0); } /* ARGSUSED */ static int ioopen(name,mode,den) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Open a tape device .RETURNS File descriptor / -1 (error) ------------------------------------------------------------*/ char *name; /* IN: Physical name of tape device */ int mode; /* IN: Open mode */ int den; /* IN: Density. Not used */ { struct stat buf; int fd; int t; oserror = 0; switch(mode) { /* Open operations */ case READ: t = O_RDONLY; break; case WRITE: t = O_WRONLY; break; case READ_WRITE: t = O_RDWR; break; case APPEND: t = O_RDWR; break; default: oserror = EINVAL; return(-1); } if ( (fd = open(name,t)) == -1) { oserror= errno; if ( errno == EIO ) { oserror = -1; oserrmsg = "no tape loaded or drive offline"; } return(-1); } if ( fstat(fd,&buf) == -1) { oserror= errno; return(-1); } if ( (buf.st_mode & S_IFMT) != S_IFCHR) { oserror = -1; oserrmsg = "Osuopen: Not a character device"; return(-1); } return(fd); } /* ARGSUSED */ static int ioclose(fd, option) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Close the opened device .RETURNS 0 ------------------------------------------------------------*/ int fd; /* IN: Tape file descriptor */ int option; /* IN: not used. Option OPU_DISMOUNT */ { oserror=0; if (close(fd) == -1) { oserror = errno; return(-1); } /* * On linux, the close after writting data or FM, writes an extra FM. One * has to move bacwards 1FM to leave the tape ready to open it again, otherwise * there will be 2FM between files. */ #if defined(__linux__) ioopen(osuname(-1),osumode(-1)); ioctop(fd,MTBSF,1); close(fd); #endif return(0); } 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. ------------------------------------------------------------*/ int fd; /* IN: Tape device file descriptor */ char *buffer; /* IN: Buffer for reading */ int size; /* IN: Length of bytes to be read */ { int length; oserror = 0; if ((length = read(fd,buffer,size)) == -1) oserror = errno; #if DEBUG printf("ioread read %d to buffer of %d bytes\n", length, size); #endif return(length); } 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 length; length = 0; if ((length = write(fd,buffer,size)) == -1) oserror = errno; #if DEBUG printf("iowrite %d to buffer of %d bytes\n", length, size); #endif return(length); } static int ioweof(fd) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Write end-of-file record (tape_mark) on the tape. .RETURNS 0 / -1 (error) ------------------------------------------------------------*/ int fd; /* IN: Tape device file descriptor */ { oserror = 0; return(ioctop(fd,MTWEOF,1)); } static int iofsf(fd,ntm) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Skip forward space file on a tape. .RETURNS 0 (OK) / -1 (error) ------------------------------------------------------------*/ int fd; /* IN: Tape device file descriptor */ int ntm; /* IN: Number of tape marks */ { oserror = 0; return(ioctop(fd,MTFSF,ntm)); } static int iobsf(fd,ntm) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Skip backward space file on a tape. .RETURNS 0 (OK) / -1 (error) ------------------------------------------------------------*/ int fd; /* IN: Tape device file descriptor */ int ntm; /* IN: Number of tape marks */ { oserror = 0; return(ioctop(fd,MTBSF,ntm)); } static int iorew(fd) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Rewind tape .RETURNS 0 / -1 (error) ------------------------------------------------------------*/ int fd; /* IN: Tape device file descriptor */ { oserror = 0; return(ioctop(fd,MTREW,1)); } #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 */ { oserror = 0; /* * In linux, the ioeom() jumps after the 2FM and returns an error if trying * to write something afterwards. One has to move backwards 1FM to position * the tape between FMs. */ #if !defined(__linux__) return(ioctop(fd,MTEOM,1)); #else if (ioctop(fd,MTEOM,1)) return(-1); ioctop(fd,MTBSF,1); #endif } #endif #endif /*===================================================================== * Definition of the structure returned to osu *=====================================================================*/ #ifdef next_iodev struct iolist *next_iodev(); #else #define next_iodev (IODEV)0 #endif #ifdef NO_MTIO static struct iolist this_dev = { next_iodev, /* Next iodev in List */ class_name, /* How it's written in DEVCAPFILE */ 0, (OPITEM *)0 }; #else static OPITEM list_of_functions[] = { { U_INFO, ioinfo}, /* Get status info from device */ { U_OPEN, ioopen}, /* Open device */ { U_CLOSE, ioclose}, /* Close device */ { U_READ, ioread}, /* Read from device */ { U_WRITE, iowrite}, /* Write onto device */ { U_REWIND, iorew}, /* Rewind device */ { U_WEOF, ioweof}, /* Write End of File Mark */ { U_FMF, iofsf}, /* Forward File Skip forward */ { U_FMB, iobsf}, /* Backward File Skip */ #ifdef MTEOM { U_EOM, ioeom} /* Move to EOMedia */ #endif }; static struct iolist this_dev = { next_iodev, /* Next iodev in List */ class_name, /* How it's written in DEVCAPFILE */ sizeof(list_of_functions)/sizeof(list_of_functions[0]), list_of_functions }; #endif struct iolist *iodevg() /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Get All definitions concerning this class of Devices .RETURNS The iolist .REMARKS Simply returns the local iolist address... ------------------------------------------------------------*/ { return(&this_dev); }