/* @(#)iodevr.c 17.1.1.1 (ESO-IPG) 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 iodevr .LANGUAGE C .AUTHOR IPG-ESO Garching .CATEGORY Host operating system interfaces. Remote tape management. .ENVIRONMENT UNIX .COMMENTS Remote tape management. The functions of this module provides remote connection with a server in a remote host which executes basic i/o on devices like magnetic tapes, optical disks on UNIX enviroments. This interface is called by "osu" when detecting that i/o device is not located in a local but in a remote host. It will try to establish connection with a tapeserver in the remote host. A new INET service is expected to be defined for both client and server in the system file /etc/services: mtape Port numbers for private services are typically in the range 1024-2048. .REMARKS The tapeserver must be running in the remote host before trying to stablish connection with remote devices. (See $MIDASHOME/$MIDVERS/system/tapeserv/inmtaped.doc file for more details) .VERSION 1.1 900124 Implementation C. Guirao .VERSION 2.1 910906 Full duplex socket connection. CG. .VERSION 2.2 920219 Acepting ':' as separator. CG. .VERSION 2.3 920820 Timout increased to 5hours. CG. .VERSION 3.1 940624 Using XDR interface (machine indepentent). CG. ------------------------------------------------------------*/ /* * Define _POSIX_SOURCE to indicate * that this is a POSIX program * Except for SUN & GNU-SUN & HP-UX & OSF & AIX & ULTRIX & SGI * because the POSIX definition * couses undefines (eg. u_long) in socket includes. */ /*JW Added !defined(__FreeBSD__) to the line below - Stops complaining about uint */ #if !defined(__hpux) && !defined(sun) && !defined(__sun) && !defined(__osf__) && !defined(_AIX) && !defined(ultrix) && !defined(__sgi) && !defined(__linux__) &&!defined(__FreeBSD__) #define _POSIX_SOURCE 1 #endif #define next_iodev iodevg /* Next iodev in chain: generic */ static char class_name[] = "remote"; #include #include /* ANSI-C prototyping */ #include #include #include /* XDR definitions */ #include #include #include #include #include #include #include #include #include #define NULL_PTR(x) (x *)0 #define RET_ERROR(a,b) {osxclose(skfd); oserror=(a); oserrmsg=(b); return(-1);} #define TAPE_SERVICE "mtape" /* must be defined in /etc/services */ #define ERR_SYNC msg0 #define ERR_XDR msg1 static char msg0[] = "Out of synchronism with tape server."; static char msg1[] = "XDR library error"; static char errmsg[MAX_MSG]; char *osmsg(); /* FILE *fdopen(); */ static int skfd; /* Socket file descriptor */ FILE *fp_in, *fp_out; struct info { struct osustat stat; int filenum; long blkno; }; /* * XDR routines */ static XDR xdrs_in, xdrs_out; bool_t xdr_command(xdrs, cmd) XDR *xdrs; struct command *cmd; { return(xdr_int(xdrs, &cmd->cmd) && xdr_int(xdrs, &cmd->param[0]) && xdr_int(xdrs, &cmd->param[1])); } bool_t xdr_osustat(xdrs, stat) XDR *xdrs; struct osustat *stat; { return(xdr_long(xdrs, &stat->usize) && xdr_int(xdrs, &stat->blocksize) && xdr_int(xdrs, &stat->density) && xdr_int(xdrs, &stat->isda) && xdr_int(xdrs, &stat->istm)); } bool_t xdr_result(xdrs, res) XDR *xdrs; struct result *res; { return(xdr_int(xdrs, &res->ret) && xdr_int(xdrs, &res->oserror) && xdr_int(xdrs, &res->nobyt)); } static int send_op(op) struct command *op; { oserror = 0; /* Send the command to the server */ if (!xdr_command(&xdrs_out, op)) RET_ERROR(-1,ERR_XDR); fflush(fp_out); return(0); } static int get_res(res) struct result *res; { char *msg; oserror = 0; msg = errmsg; /* Wait and get results from the server */ if (!xdr_result(&xdrs_in, res)) RET_ERROR(-1,ERR_XDR); /* If any error, then get error message */ oserror = res->oserror; if ( res->ret < 0 && res->nobyt > 0) if (!xdr_string(&xdrs_in, &msg,MAX_MSG)) RET_ERROR(-1,ERR_XDR); return(0); } static int ioctop(op) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Interface to remote ioctl routine. The structure command is already completed by the caller. .RETURNS 0 (OK) / -1 (error) ------------------------------------------------------------*/ struct command *op; /* IN: Command to be executed */ { struct result res; /* Send command and get results */ if (send_op(op) < 0) return(-1); if (get_res(&res) < 0) return(-1); /* Returns the remote-return-code */ 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 */ { struct command op; struct result res; /* Prepare command structure to tapeserver */ op.cmd = READ_INFO; op.param[0] = fd; op.param[1] = 0; /* Send the command to the server */ /* Send command and get results */ if (send_op(&op) < 0) return(-1); if (get_res(&res) < 0) return(-1); /* If no error, more data is expected from the server */ if ( res.ret == 0) { if (!xdr_osustat(&xdrs_in, s)) RET_ERROR(-1,ERR_XDR); if (!xdr_int(&xdrs_in, filenum)) RET_ERROR(-1,ERR_XDR); if (!xdr_long(&xdrs_in, blkno)) RET_ERROR(-1,ERR_XDR); } /* It returns the remote return code */ return(res.ret); } 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 */ { static char devname[MAX_DEVICE_NAME], remotehost[MAX_HOST_NAME]; static char *channame[2]; register char *p, *q; int uid; struct command op, xdr_op; struct result res, xdr_res; struct passwd *passwd; char null; char *pname, *puser; oserror = 0; /* Clear error from getdev */ /* Check that name comes in the format pw_name; /* Send devicename and username to server */ if (!xdr_string(&xdrs_out, &pname, MAX_HOST_NAME+MAX_DEVICE_NAME)) RET_ERROR(-1,ERR_XDR); if (!xdr_string(&xdrs_out, &puser, MAX_USER_NAME)) RET_ERROR(-1,ERR_XDR); fflush(fp_out); /* Read result of OPEN command from server */ if (get_res(&res) < 0) return(-1); /* Returns return_code from remote open */ return(res.ret); } static int ioclose(fd/*,option*/) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Close the opened device .RETURNS 0/-1 if error ------------------------------------------------------------*/ int fd; /* IN: Tape file descriptor */ /*int option;*/ /* IN: Option OPU_DISMOUNT */ { struct command op; struct result res; /* Prepare CLOSE command to be sent to server */ op.cmd = CLOSE_DEVICE; op.param[0] = fd; op.param[1] = 0; /* Send CLOSE command */ if (send_op(&op) < 0) return(-1); /* Wait for the server to return result */ if (get_res(&res) < 0) return(-1); /* Close socket */ if ( osxclose(skfd) < 0) return(-1); /* Close XDR streams */ xdr_destroy(&xdrs_in); xdr_destroy(&xdrs_out); /* Returns the return code from server */ 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 ret; struct command op; struct result res; /* Prepares READ command */ op.cmd = READ_DATA; op.param[0] = fd; op.param[1] = size; /* Send READ command to server */ if (send_op(&op) < 0) return(-1); /* Wait for results of READ command */ if (get_res(&res) < 0) return(-1); /* READ OK?, then get the data from the server */ if ( res.ret > 0 ) { if (!xdr_bytes(&xdrs_in, &buffer,(u_int *)&ret,(u_int)size)) RET_ERROR(-1,ERR_XDR); if ( ret != res.ret ) RET_ERROR(-1,ERR_SYNC); } /* Returns the return code from server */ 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 */ { struct result res; struct command op; /* Prepares WRITE command */ op.cmd = WRITE_DATA; op.param[0] = fd; op.param[1] = size; /* Send WRITE command to server */ if (send_op(&op) < 0 ) return(-1); /* Send data to be written in device */ if (!xdr_bytes(&xdrs_out, &buffer,(u_int *)&size,(u_int)size)) RET_ERROR(-1,ERR_XDR); fflush(fp_out); /* Wait for results of WRITE command */ if (get_res(&res) < 0) return(-1); /* Return code from server */ 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; /* Prepare WRITE TAPE MARK command */ op.cmd = WRITE_EOF; op.param[0] = fd; op.param[1] = ntm; /* Executes command in server and returns the remote-return-code */ 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; /* Prepare command */ op.cmd = SKIP_FSF; op.param[0] = fd; op.param[1] = ntm; /* Executes command in server and returns the remote-return-code */ 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; /* Prepare command */ op.cmd = SKIP_BSF; op.param[0] = fd; op.param[1] = ntm; /* Executes command in server and returns the remote-return-code */ return(ioctop(&op)); } static int iorew(fd) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Rewind tape .RETURNS 0 / -1 (error) ------------------------------------------------------------*/ int fd; /* IN: Tape device file descriptor */ { struct command op; /* Prepare command */ op.cmd = REWIND; op.param[0] = fd; op.param[1] = 0; /* Executes command in server and returns the remote-return-code */ return(ioctop(&op)); } 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; /* Prepare command */ op.cmd = SKIP_EOM; op.param[0] = fd; op.param[1] = 0; /* Executes command in server and returns the remote-return-code */ return(ioctop(&op)); } /*===================================================================== * Definition of the structure returned to osu *=====================================================================*/ #ifdef next_iodev struct iolist *next_iodev(); #else #define next_iodev (IODEV)0 #endif 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_EOM, ioeom} /* Move to EOMedia */ }; 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 }; struct iolist *iodevr() /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Get All definitions concerning this class of Devices .RETURNS The iolist .REMARKS Simply returns the local iolist address... ------------------------------------------------------------*/ { return(&this_dev); }