/*-------------------------------------------------------------------*/ static int cardrdr_close_device ( DEVBLK *dev ) { /* Close the device file */ if (0 || ( dev->bs && dev->fd >= 0 && close_socket( dev->fd ) < 0 ) || ( !dev->bs && dev->fh != NULL && fclose( dev->fh ) != 0 ) ) { int errnum = dev->bs ? get_HSO_errno() : errno; WRMSG (HHC01200, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, "close_socket() or fclose()", strerror(errnum)); dev->fd = -1; dev->fh = NULL; return -1; } if (dev->bs && (dev->bs->clientip || dev->bs->clientname)) { WRMSG (HHC01206, "I", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->bs->clientname, dev->bs->clientip, dev->bs->spec); } dev->fd = -1; dev->fh = NULL; return 0; } /* end function cardrdr_close_device */
static int bufgetc(DEVBLK *dev, int blocking) { BYTE *bufp = dev->buf + dev->ctcpos, *bufend = bufp + dev->ctcrem; int n; if (bufp >= bufend) { if (blocking == 0) return -1; do { n = read(dev->fd, dev->buf, dev->bufsize); if (n <= 0) { if (n == 0) { /* VMnet died on us. */ WRMSG (HHC00976, "E", SSID_TO_LCSS(dev->ssid), dev->devnum); /* -2 will cause an error status to be set */ return -2; } if( n == EINTR ) return -3; WRMSG (HHC00900, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, "read()", strerror(errno)); SLEEP(2); } } while (n <= 0); dev->ctcrem = n; bufend = &dev->buf[n]; dev->ctclastpos = dev->ctclastrem = dev->ctcpos = 0; bufp = dev->buf; } dev->ctcpos++; dev->ctcrem--; return *bufp; }
/*-------------------------------------------------------------------*/ int read_omaheaders (DEVBLK *dev, OMATAPE_DESC *omadesc, BYTE *buf, BYTE *unitstat,BYTE code) { int rc; /* Return code */ long blkpos; /* Offset to block header */ S32 curblkl; /* Length of current block */ S32 prvhdro; /* Offset of previous header */ S32 nxthdro; /* Offset of next header */ /* Read the 16-byte block header */ blkpos = dev->nxtblkpos; rc = readhdr_omaheaders (dev, omadesc, blkpos, &curblkl, &prvhdro, &nxthdro, unitstat,code); if (rc < 0) return -1; /* Update the offsets of the next and previous blocks */ dev->nxtblkpos = nxthdro; dev->prvblkpos = blkpos; /* Increment file number and return zero if tapemark */ if (curblkl == -1) { close (dev->fd); dev->fd = -1; dev->curfilen++; dev->nxtblkpos = 0; dev->prvblkpos = -1; return 0; } /* Read data block from tape file */ rc = read (dev->fd, buf, curblkl); /* Handle read error condition */ if (rc < 0) { WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, omadesc->filename, "oma", "read()", (off_t)blkpos, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } /* Handle end of file within data block */ if (rc < curblkl) { WRMSG(HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, omadesc->filename, "oma", "read_omaheaders()", (off_t)blkpos, "unexpected end of file"); /* Set unit check with data check and partial record */ build_senseX(TAPE_BSENSE_BLOCKSHORT,dev,unitstat,code); return -1; } /* Return block length */ return curblkl; } /* end function read_omaheaders */
/*-------------------------------------------------------------------*/ int read_omafixed (DEVBLK *dev, OMATAPE_DESC *omadesc, BYTE *buf, BYTE *unitstat,BYTE code) { off_t rcoff; /* Return code from lseek() */ int blklen; /* Block length */ long blkpos; /* Offset of block in file */ /* Initialize current block position */ blkpos = dev->nxtblkpos; /* Seek to new current block position */ rcoff = lseek (dev->fd, blkpos, SEEK_SET); if (rcoff < 0) { /* Handle seek error condition */ WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, omadesc->filename, "oma", "lseek()", (off_t)blkpos, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); return -1; } /* Read fixed length block or short final block */ blklen = read (dev->fd, buf, omadesc->blklen); /* Handle read error condition */ if (blklen < 0) { WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, omadesc->filename, "oma", "read()", (off_t)blkpos, strerror(errno)); build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } /* At end of file return zero to indicate tapemark */ if (blklen == 0) { close (dev->fd); dev->fd = -1; dev->curfilen++; dev->nxtblkpos = 0; dev->prvblkpos = -1; return 0; } /* Calculate the offsets of the next and previous blocks */ dev->nxtblkpos = blkpos + blklen; dev->prvblkpos = blkpos; /* Return block length, or zero to indicate tapemark */ return blklen; } /* end function read_omafixed */
/*-------------------------------------------------------------------*/ int readhdr_awstape (DEVBLK *dev, off_t blkpos, AWSTAPE_BLKHDR *buf, BYTE *unitstat,BYTE code) { int rc; /* Return code */ off_t rcoff; /* Return code from lseek() */ /* Reposition file to the requested block header */ rcoff = lseek (dev->fd, blkpos, SEEK_SET); if (rcoff < 0) { /* Handle seek error condition */ WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "aws", "lseek()", blkpos, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); return -1; } /* Read the 6-byte block header */ rc = read (dev->fd, buf, sizeof(AWSTAPE_BLKHDR)); /* Handle read error condition */ if (rc < 0) { WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "aws", "read()", blkpos, strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } /* Handle end of file (uninitialized tape) condition */ if (rc == 0) { WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "aws", "readhdr_awstape()", blkpos, "end of file (uninitialized tape)"); /* Set unit exception with tape indicate (end of tape) */ build_senseX(TAPE_BSENSE_EMPTYTAPE,dev,unitstat,code); return -1; } /* Handle end of file within block header */ if (rc < (int)sizeof(AWSTAPE_BLKHDR)) { WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "aws", "readhdr_awstape()", blkpos, "unexpected end of file"); build_senseX(TAPE_BSENSE_BLOCKSHORT,dev,unitstat,code); return -1; } /* Successful return */ return 0; } /* end function readhdr_awstape */
/*-------------------------------------------------------------------*/ static int start_vmnet(DEVBLK *dev, DEVBLK *xdev, int argc, char *argv[]) { int sockfd[2]; int r, i; char *ipaddress; if (argc < 2) { WRMSG (HHC00915, "E", SSID_TO_LCSS(dev->ssid), dev->devnum); return -1; } ipaddress = argv[0]; argc--; argv++; if (socketpair (AF_UNIX, SOCK_STREAM, 0, sockfd) < 0) { WRMSG (HHC00900, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, "socketpair()", strerror(errno)); return -1; } r = fork (); if (r < 0) { WRMSG (HHC00900, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, "fork()", strerror(errno)); return -1; } else if (r == 0) { /* child */ close (0); close (1); dup (sockfd[1]); dup (sockfd[1]); r = (sockfd[0] > sockfd[1]) ? sockfd[0] : sockfd[1]; for (i = 3; i <= r; i++) { close (i); } /* the ugly cast is to silence a compiler warning due to const */ execv (argv[0], (EXECV_ARG2_ARGV_T)argv); exit (1); } close (sockfd[1]); dev->fd = sockfd[0]; xdev->fd = sockfd[0]; /* We just blindly copy these out in the hope vmnet will pick them * up correctly. I don't feel like implementing a complete login * scripting facility here... */ write(dev->fd, ipaddress, (u_int)strlen(ipaddress)); write(dev->fd, "\n", 1); return 0; }
static int VMNET_Write(DEVBLK *dev, BYTE *iobuf, U32 count, BYTE *unitstat) { U32 blklen = (iobuf[0]<<8) | iobuf[1]; U32 pktlen; BYTE *p = iobuf + 2; BYTE *buffer = dev->buf; U32 len = 0, rem; if (count < blklen) { WRMSG (HHC00975, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, "block", count, blklen); blklen = count; } while (p < iobuf + blklen) { pktlen = (p[0]<<8) | p[1]; rem = iobuf + blklen - p; if (rem < pktlen) { WRMSG (HHC00975, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, "packet", rem, pktlen); pktlen = rem; } if (pktlen < 6) { WRMSG (HHC00975, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, "packet", pktlen, 6); pktlen = 6; } pktlen -= 6; p += 6; while (pktlen--) { switch (*p) { case SLIP_END: buffer[len++] = SLIP_ESC; buffer[len++] = SLIP_ESC_END; break; case SLIP_ESC: buffer[len++] = SLIP_ESC; buffer[len++] = SLIP_ESC_ESC; break; default: buffer[len++] = *p; break; } p++; } buffer[len++] = SLIP_END; write(dev->fd, buffer, len); /* should check error conditions? */ len = 0; } *unitstat = CSW_CE | CSW_DE; return count; }
static int VMNET_Init(DEVBLK *dev, int argc, char *argv[]) { U16 xdevnum; /* Pair device devnum */ DEVBLK *xdev; /* Pair device */ int rc; U16 lcss; dev->devtype = 0x3088; dev->excps = 0; /* parameters for network CTC are: * devnum of the other CTC device of the pair * ipaddress * vmnet command line * * CTC adapters are used in pairs, one for READ, one for WRITE. * The vmnet is only initialised when both are initialised. */ if (argc < 3) { WRMSG(HHC00915, "E", SSID_TO_LCSS(dev->ssid), dev->devnum); return -1; } rc=parse_single_devnum(argv[0],&lcss,&xdevnum); if (rc<0) { WRMSG(HHC00916, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, "device number", argv[0]); return -1; } xdev = find_device_by_devnum(lcss,xdevnum); if (xdev != NULL) { if (start_vmnet(dev, xdev, argc - 1, &argv[1])) return -1; } strlcpy(dev->filename, "vmnet", sizeof(dev->filename) ); /* Set the control unit type */ /* Linux/390 currently only supports 3088 model 2 CTCA and ESCON */ dev->ctctype = CTC_VMNET; SetSIDInfo( dev, 0x3088, 0x08, 0x3088, 0x01 ); /* Initialize the device dependent fields */ dev->ctcpos = 0; dev->ctcrem = 0; /* Set length of buffer */ /* This size guarantees we can write a full iobuf of 65536 * as a SLIP packet in a single write. Probably overkill... */ dev->bufsize = 65536 * 2 + 1; return 0; }
/*-------------------------------------------------------------------*/ int bsf_het (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ /* Exit if already at BOT */ if (dev->curfilen==1 && dev->nxtblkpos == 0) { build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code); return -1; } rc = het_bsf (dev->hetb); if (rc < 0) { char msgbuf[128]; MSGBUF( msgbuf, "Het error '%s': '%s'", het_error(rc), strerror(errno)); WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het", "het_bsf()", (off_t)dev->hetb->cblk, msgbuf); build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); return -1; } /* Maintain position */ dev->blockid = rc; dev->curfilen--; /* Return success */ return 0; } /* end function bsf_het */
/*-------------------------------------------------------------------*/ int fsf_het (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ /* Forward space to start of next file */ rc = het_fsf (dev->hetb); if (rc < 0) { char msgbuf[128]; MSGBUF( msgbuf, "Het error '%s': '%s'", het_error(rc), strerror(errno)); WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het", "het_fsf()", (off_t)dev->hetb->cblk, msgbuf); if(rc==HETE_EOT) { build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); } else { build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); } return -1; } /* Maintain position */ dev->blockid = rc; dev->curfilen++; /* Return success */ return 0; } /* end function fsf_het */
/*-------------------------------------------------------------------*/ int write_hetmark( DEVBLK *dev, BYTE *unitstat, BYTE code ) { int rc; /* Return code */ if ( dev->hetb->writeprotect ) { build_senseX(TAPE_BSENSE_WRITEPROTECT,dev,unitstat,code); return -1; } /* Write the tape mark */ rc = het_tapemark (dev->hetb); if (rc < 0) { /* Handle error condition */ char msgbuf[128]; MSGBUF( msgbuf, "Het error '%s': '%s'", het_error(rc), strerror(errno)); WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het", "het_tapemark()", (off_t)dev->hetb->cblk, msgbuf); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); return -1; } /* Return normal status */ dev->blockid++; return 0; } /* end function write_hetmark */
/*-------------------------------------------------------------------*/ static void write_buffer (DEVBLK *dev, char *buf, int len, BYTE *unitstat) { int rc; /* Return code */ /* Write data to the printer file */ if (dev->bs) { /* (socket printer) */ rc = write_socket (dev->fd, buf, len); /* Check for socket error */ if (rc < len) { /* Close the connection */ if (dev->fd != -1) { int fd = dev->fd; dev->fd = -1; close_socket( fd ); WRMSG (HHC01100, "I", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->bs->clientname, dev->bs->clientip, dev->bs->spec); } /* Set unit check with intervention required */ dev->sense[0] = SENSE_IR; *unitstat = CSW_CE | CSW_DE | CSW_UC; } } else { /* Write data to the printer file */ rc = write (dev->fd, buf, len); /* Equipment check if error writing to printer file */ if (rc < len) { WRMSG (HHC01105, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, "write()", rc < 0 ? strerror(errno) : "incomplete record written"); dev->sense[0] = SENSE_EC; *unitstat = CSW_CE | CSW_DE | CSW_UC; } } } /* end function write_buffer */
/*-------------------------------------------------------------------*/ int fsb_omafixed (DEVBLK *dev, OMATAPE_DESC *omadesc, BYTE *unitstat,BYTE code) { off_t eofpos; /* Offset of end of file */ off_t blkpos; /* Offset of current block */ int curblkl; /* Length of current block */ /* Initialize current block position */ blkpos = dev->nxtblkpos; /* Seek to end of file to determine file size */ eofpos = lseek (dev->fd, 0, SEEK_END); if (eofpos < 0 || eofpos >= LONG_MAX) { /* Handle seek error condition */ if ( eofpos >= LONG_MAX) errno = EOVERFLOW; WRMSG (HHC00205, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, omadesc->filename, "oma", "lseek()", strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_LOCATEERR,dev,unitstat,code); return -1; } /* Check if already at end of file */ if (blkpos >= eofpos) { /* Close the current OMA file */ if (dev->fd >= 0) close (dev->fd); dev->fd = -1; dev->nxtblkpos = 0; dev->prvblkpos = -1; /* Increment the file number */ dev->curfilen++; /* Return zero to indicate tapemark */ return 0; } /* Calculate current block length */ curblkl = (int)(eofpos - blkpos); if (curblkl > omadesc->blklen) curblkl = omadesc->blklen; /* Update the offsets of the next and previous blocks */ dev->nxtblkpos = (long)(blkpos + curblkl); dev->prvblkpos = (long)(blkpos); /* Return block length */ return curblkl; } /* end function fsb_omafixed */
/*-------------------------------------------------------------------*/ void close_awstape (DEVBLK *dev) { if( dev->fd >= 0 ) { WRMSG (HHC00201, "I", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "aws"); close(dev->fd); } strlcpy(dev->filename, TAPE_UNLOADED, sizeof(dev->filename)); dev->fd=-1; dev->blockid = 0; dev->fenced = 0; return; }
/*-------------------------------------------------------------------*/ static int printer_close_device ( DEVBLK *dev ) { int fd = dev->fd; if (fd == -1) return 0; dev->fd = -1; dev->stopdev = FALSE; /* Close the device file */ if ( dev->ispiped ) { #if !defined( _MSVC_ ) close_pipe (fd); #else /* defined( _MSVC_ ) */ close (fd); /* Log end of child process */ WRMSG (HHC01107, "I", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->ptpcpid); #endif /* defined( _MSVC_ ) */ dev->ptpcpid = 0; } else { if (dev->bs) { /* Socket printer */ close_socket (fd); WRMSG (HHC01100, "I", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->bs->clientname, dev->bs->clientip, dev->bs->spec); } else { /* Regular printer */ close (fd); } } return 0; } /* end function printer_close_device */
/*-------------------------------------------------------------------*/ int read_het (DEVBLK *dev, BYTE *buf, BYTE *unitstat,BYTE code) { int rc; /* Return code */ rc = het_read (dev->hetb, buf); if (rc < 0) { /* Increment file number and return zero if tapemark was read */ if (rc == HETE_TAPEMARK) { dev->curfilen++; dev->blockid++; return 0; } /* Handle end of file (uninitialized tape) condition */ if (rc == HETE_EOT) { WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het", "het_read()", (off_t)dev->hetb->cblk, "end of file (uninitialized tape)"); /* Set unit exception with tape indicate (end of tape) */ build_senseX(TAPE_BSENSE_ENDOFTAPE,dev,unitstat,code); return -1; } { char msgbuf[128]; MSGBUF( msgbuf, "Het error '%s': '%s'", het_error(rc), strerror(errno)); WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het", "het_read()", (off_t)dev->hetb->cblk, msgbuf); } /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } dev->blockid++; /* Return block length */ return rc; } /* end function read_het */
int CTCX_Init( DEVBLK* pDEVBLK, int argc, char *argv[] ) { pDEVBLK->devtype = 0x3088; pDEVBLK->excps = 0; // The first argument is the device emulation type if( argc < 1 ) { WRMSG (HHC00915, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum ); return -1; } if((pDEVBLK->hnd = hdl_ghnd(argv[0]))) { if(pDEVBLK->hnd->init == &CTCX_Init) return -1; free(pDEVBLK->typname); pDEVBLK->typname = strdup(argv[0]); return (pDEVBLK->hnd->init)( pDEVBLK, --argc, ++argv ); } WRMSG (HHC00970, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, argv[0]); return -1; }
static void* CTCT_ListenThread( void* argp ) { int connfd; socklen_t servlen; char str[80]; CTCG_PARMBLK parm; // set up the parameters passed via create_thread parm = *((CTCG_PARMBLK*) argp); free( argp ); for( ; ; ) { servlen = sizeof(parm.addr); // await a connection connfd = accept( parm.listenfd, (struct sockaddr *)&parm.addr, &servlen ); MSGBUF( str, "%s:%d", inet_ntoa( parm.addr.sin_addr ), ntohs( parm.addr.sin_port ) ); if( strcmp( str, parm.dev->filename ) != 0 ) { WRMSG(HHC00974, "E", SSID_TO_LCSS(parm.dev->ssid), parm.dev->devnum, parm.dev->filename, str); close_socket( connfd ); } else { parm.dev->fd = connfd; } // Ok, so having done that we're going to loop back to the // accept(). This was meant to handle the connection failing // at the other end; this end will be ready to accept another // connection. Although this will happen, I'm sure you can // see the possibility for bad things to occur (eg if another // Hercules tries to connect). This will also be fixed RSN. } // UNREACHABLE }
/*--------------------------------------------------------------------*/ DLL_EXPORT void mpc_display_description( DEVBLK* pDEVBLK, char* pDesc ) { /* Display description, if one has been provided. */ if( pDesc ) { if( pDEVBLK ) { // HHC03983 "%1d:%04X %s: %s WRMSG(HHC03983, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->typname, pDesc ); } else { // HHC03984 "%s" WRMSG(HHC03984, "I", pDesc ); } } return; } /* End function mpc_display_description() */
/*-------------------------------------------------------------------*/ int rewind_het(DEVBLK *dev,BYTE *unitstat,BYTE code) { int rc; rc = het_rewind (dev->hetb); if (rc < 0) { /* Handle seek error condition */ char msgbuf[128]; MSGBUF( msgbuf, "Het error '%s': '%s'", het_error(rc), strerror(errno)); WRMSG (HHC00205, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het", "het_rewind()", msgbuf); build_senseX(TAPE_BSENSE_REWINDFAILED,dev,unitstat,code); return -1; } dev->nxtblkpos=0; dev->prvblkpos=-1; dev->curfilen=1; dev->blockid=0; dev->fenced = 0; return 0; }
/*-------------------------------------------------------------------*/ void build_attach_chrpt( DEVBLK *dev ) { U32 ssid, subchan, crwarray[8], crwcount=0; int devlock_obtained; /* Just return if shutting down */ if (sysblk.shutdown) return; /* Retrieve Source IDs */ devlock_obtained = (try_obtain_lock( &dev->lock ) == 0); { ssid = ((U32)SSID_TO_LCSS( dev->ssid )) & CRW_RSID_MASK; subchan = ((U32)dev->subchan) & CRW_RSID_MASK; } if (devlock_obtained) release_lock( &dev->lock ); /* Build Subchannel Alert Channel Report */ crwarray[crwcount++] = 0 | (sysblk.mss ? CRW_CHAIN : 0) | CRW_RSC_SUBCH | CRW_AR | CRW_ERC_ALERT | subchan ; if (sysblk.mss) crwarray[crwcount++] = 0 | CRW_RSC_SUBCH | CRW_AR | CRW_ERC_ALERT | (ssid << 8) ; /* Queue the Channel Report(s) */ VERIFY( queue_channel_report( crwarray, crwcount ) == 0 ); }
/*-------------------------------------------------------------------*/ int bsb_het (DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ /* Back space one block */ rc = het_bsb (dev->hetb); if (rc < 0) { /* Increment file number and return zero if tapemark was read */ if (rc == HETE_TAPEMARK) { dev->blockid--; dev->curfilen--; return 0; } /* Unit check if already at start of tape */ if (rc == HETE_BOT) { build_senseX(TAPE_BSENSE_LOADPTERR,dev,unitstat,code); return -1; } { char msgbuf[128]; MSGBUF( msgbuf, "Het error '%s': '%s'", het_error(rc), strerror(errno)); WRMSG (HHC00204, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het", "het_bsb()", (off_t)dev->hetb->cblk, msgbuf); } /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_READFAIL,dev,unitstat,code); return -1; } dev->blockid--; /* Return +1 to indicate back space successful */ return +1; } /* end function bsb_het */
/*-------------------------------------------------------------------*/ void close_het (DEVBLK *dev) { /* BHE 03/04/2010: This was the statement?? */ /* if(dev->hetb->fd >= 0) */ /* Caught it after a warning message */ if(dev->fd >= 0) { WRMSG (HHC00201, "I", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het"); } /* Close the HET file */ het_close (&dev->hetb); /* Reinitialize the DEV fields */ dev->fd = -1; dev->fh = NULL; strlcpy( dev->filename, TAPE_UNLOADED, sizeof(dev->filename) ); dev->blockid = 0; dev->fenced = 0; return; } /* end function close_het */
/*-------------------------------------------------------------------*/ int sync_het(DEVBLK *dev, BYTE *unitstat,BYTE code) { int rc; /* Return code */ /* Perform the flush */ rc = het_sync (dev->hetb); if (rc < 0) { /* Handle error condition */ if (HETE_PROTECTED == rc) build_senseX(TAPE_BSENSE_WRITEPROTECT,dev,unitstat,code); else { WRMSG (HHC00205, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "het", "het_sync()", strerror(errno)); build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); } return -1; } /* Return normal status */ return 0; } /* end function sync_het */
/*-------------------------------------------------------------------*/ int sync_awstape (DEVBLK *dev, BYTE *unitstat,BYTE code) { /* Unit check if tape is write-protected */ if (dev->readonly) { build_senseX(TAPE_BSENSE_WRITEPROTECT,dev,unitstat,code); return -1; } /* Perform sync. Return error on failure. */ if (fdatasync( dev->fd ) < 0) { /* Log the error */ WRMSG (HHC00205, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "aws", "fdatasync()", strerror(errno)); /* Set unit check with equipment check */ build_senseX(TAPE_BSENSE_WRITEFAIL,dev,unitstat,code); return -1; } /* Return normal status */ return 0; } /* end function sync_awstape */
/*-------------------------------------------------------------------*/ void close_omatape2(DEVBLK *dev) { if (dev->fd >= 0) { WRMSG (HHC00201, "I", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename, "oma"); close (dev->fd); } dev->fd=-1; if (dev->omadesc != NULL) { free (dev->omadesc); dev->omadesc = NULL; } /* Reset the device dependent fields */ dev->nxtblkpos=0; dev->prvblkpos=-1; dev->curfilen=1; dev->blockid=0; dev->fenced = 0; dev->omafiles = 0; return; }
/*-------------------------------------------------------------------*/ static void printer_execute_ccw (DEVBLK *dev, BYTE code, BYTE flags, BYTE chained, U16 count, BYTE prevcode, int ccwseq, BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual) { int rc = 0; /* Return code */ int i; /* Loop counter */ int num; /* Number of bytes to move */ char *eor; /* -> end of record string */ char *nls = "\n\n\n"; /* -> new lines */ BYTE c; /* Print character */ char hex[3]; /* for hex conversion */ char wbuf[150]; /* Reset flags at start of CCW chain */ if (chained == 0) { dev->diaggate = 0; } /* Open the device file if necessary */ if (dev->fd < 0 && !IS_CCW_SENSE(code)) rc = open_printer (dev); else { /* If printer stopped, return intervention required */ if (dev->stopdev && !IS_CCW_SENSE(code)) rc = -1; else rc = 0; } if (rc < 0) { /* Set unit check with intervention required */ dev->sense[0] = SENSE_IR; *unitstat = CSW_UC; return; } /* Process depending on CCW opcode */ switch (code) { case 0x01: /* Write No Space */ case 0x09: /* Write and Space 1 Line */ case 0x11: /* Write and Space 2 Lines */ case 0x19: /* Write and Space 3 Lines */ case 0x89: /* Write and Skip to Channel 1 */ case 0x91: /* Write and Skip to Channel 2 */ case 0x99: /* Write and Skip to Channel 3 */ case 0xA1: /* Write and Skip to Channel 4 */ case 0xA9: /* Write and Skip to Channel 5 */ case 0xB1: /* Write and Skip to Channel 6 */ case 0xB9: /* Write and Skip to Channel 7 */ case 0xC1: /* Write and Skip to Channel 8 */ case 0xC9: /* Write and Skip to Channel 9 */ case 0xD1: /* Write and Skip to Channel 10 */ case 0xD9: /* Write and Skip to Channel 11 */ case 0xE1: /* Write and Skip to Channel 12 */ if (dev->rawcc) { sprintf(hex,"%02x",code); write_buffer(dev, hex, 2, unitstat); if (*unitstat != 0) return; WRITE_LINE(); write_buffer(dev, "\n", 1, unitstat); if (*unitstat == 0) *unitstat = CSW_CE | CSW_DE; return; } if ( dev->browse && dev->ccpend && ((chained & CCW_FLAGS_CD) == 0) ) { dev->ccpend = 0; /* dev->currline++; */ write_buffer(dev, "\n", 1, unitstat); if (*unitstat != 0) return; } WRITE_LINE(); if ((flags & CCW_FLAGS_CD) == 0) { if ( code <= 0x80 ) /* line control */ { coun = code / 8; if ( coun == 0 ) { dev->chskip = 1; if ( dev->browse ) { dev->ccpend = 1; *unitstat = 0; } else write_buffer(dev, "\r", 1, unitstat); if (*unitstat == 0) *unitstat = CSW_CE | CSW_DE; return; } dev->ccpend = 0; dev->currline += coun; write_buffer(dev, nls, coun, unitstat); if (*unitstat == 0) *unitstat = CSW_CE | CSW_DE; return; } else /*code > 0x80*/ /* chan control */ { /* if ( dev->browse ) { dev->currline++; write_buffer(dev, "\n", 1, unitstat); if (*unitstat != 0) return; } */ chan = ( code - 128 ) / 8; if ( chan == 1 ) { write_buffer(dev, "\r", 1, unitstat); if (*unitstat != 0) return; } SKIP_TO_CHAN(); if (*unitstat == 0) *unitstat = CSW_CE | CSW_DE; return; } } *unitstat = CSW_CE | CSW_DE; return; case 0x03: /* No Operation */ *unitstat = CSW_CE | CSW_DE; break; case 0x0B: /* Space 1 Line */ case 0x13: /* Space 2 Lines */ case 0x1B: /* Space 3 Lines */ case 0x8B: /* Skip to Channel 1 */ case 0x93: /* Skip to Channel 2 */ case 0x9B: /* Skip to Channel 3 */ case 0xA3: /* Skip to Channel 4 */ case 0xAB: /* Skip to Channel 5 */ case 0xB3: /* Skip to Channel 6 */ case 0xBB: /* Skip to Channel 7 */ case 0xC3: /* Skip to Channel 8 */ case 0xCB: /* Skip to Channel 9 */ case 0xD3: /* Skip to Channel 10 */ case 0xDB: /* Skip to Channel 11 */ case 0xE3: /* Skip to Channel 12 */ if (dev->rawcc) { sprintf(hex,"%02x",code); write_buffer(dev, hex, 2, unitstat); if (*unitstat != 0) return; eor = (dev->crlf) ? "\r\n" : "\n"; write_buffer(dev, eor, (int)strlen(eor), unitstat); if (*unitstat == 0) *unitstat = CSW_CE | CSW_DE; return; } if ( code <= 0x80 ) /* line control */ { coun = code / 8; dev->ccpend = 0; dev->currline += coun; write_buffer(dev, nls, coun, unitstat); if (*unitstat == 0) *unitstat = CSW_CE | CSW_DE; return; } else /*code > 0x80*/ /* chan control */ { /* if ( dev->browse && dev->ccpend) { coun = 1; dev->ccpend = 0; dev->currline += coun; write_buffer(dev, nls, coun, unitstat); if (*unitstat != 0) return; } */ chan = ( code - 128 ) / 8; SKIP_TO_CHAN(); if (*unitstat == 0) *unitstat = CSW_CE | CSW_DE; return; } break; case 0x63: /*---------------------------------------------------------------*/ /* LOAD FORMS CONTROL BUFFER */ /*---------------------------------------------------------------*/ if (dev->rawcc) { sprintf(hex,"%02x",code); write_buffer(dev, hex, 2, unitstat); if (*unitstat != 0) return; for (i = 0; i < count; i++) { sprintf(hex,"%02x",iobuf[i]); dev->buf[i*2] = hex[0]; dev->buf[i*2+1] = hex[1]; } /* end for(i) */ write_buffer(dev, (char *)dev->buf, i*2, unitstat); if (*unitstat != 0) return; eor = (dev->crlf) ? "\r\n" : "\n"; write_buffer(dev, eor, (int)strlen(eor), unitstat); if (*unitstat != 0) return; } else { int i = 0; int j = 1; int more = 1; for (i = 0; i <= FCBSIZE; i++) dev->fcb[i] = 0; dev->lpi = 6; dev->index = 0; if (iobuf[0] & 0xc0) { /* First byte is a print position index */ if ((iobuf[0] & 0xc0) == 0x80) /* Indexing right */ dev->index = iobuf[0] & 0x1f; else /* Indexing left */ dev->index = - (iobuf[0] & 0x1f); i = 1; } for (; i < count && j <= FCBSIZE && more; i++, j++) { dev->fcb[i] = iobuf[i] & 0x0f; if (dev->fcb[j] > 12) { *residual = count - i; *unitstat = CSW_CE | CSW_DE | CSW_UC; dev->sense[0] = SENSE_CC; return; } if (iobuf[i] & 0x10) { /* Flag bit is on */ if (j == 1) /* Flag bit in first byte means eight lines per inch */ dev->lpi = 8; else more = 0; } } if (more) { /* No flag in last byte or too many bytes */ *residual = count - i; *unitstat = CSW_CE | CSW_DE | CSW_UC; dev->sense[0] = SENSE_CC; return; } *residual = count - i; dev->lpp = j - 1; fcb_dump(dev, wbuf, 150); WRMSG(HHC02210, "I", SSID_TO_LCSS(dev->ssid), dev->devnum, wbuf ); } /* Return normal status */ *residual = 0; *unitstat = CSW_CE | CSW_DE; break; case 0x06: /*---------------------------------------------------------------*/ /* DIAGNOSTIC CHECK READ */ /*---------------------------------------------------------------*/ /* If not 1403, reject if not preceded by DIAGNOSTIC GATE */ if (dev->devtype != 0x1403 && dev->diaggate == 0) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x07: /*---------------------------------------------------------------*/ /* DIAGNOSTIC GATE */ /*---------------------------------------------------------------*/ /* Command reject if 1403, or if chained to another CCW except a no-operation at the start of the CCW chain */ if (dev->devtype == 0x1403 || ccwseq > 1 || (chained && prevcode != 0x03)) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Set diagnostic gate flag */ dev->diaggate = 1; /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x0A: /*---------------------------------------------------------------*/ /* DIAGNOSTIC READ UCS BUFFER */ /*---------------------------------------------------------------*/ /* Reject if 1403 or not preceded by DIAGNOSTIC GATE */ if (dev->devtype == 0x1403 || dev->diaggate == 0) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x12: /*---------------------------------------------------------------*/ /* DIAGNOSTIC READ fcb */ /*---------------------------------------------------------------*/ /* Reject if 1403 or not preceded by DIAGNOSTIC GATE */ if (dev->devtype == 0x1403 || dev->diaggate == 0) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0x23: /*---------------------------------------------------------------*/ /* UNFOLD */ /*---------------------------------------------------------------*/ dev->fold = 0; *unitstat = CSW_CE | CSW_DE; break; case 0x43: /*---------------------------------------------------------------*/ /* FOLD */ /*---------------------------------------------------------------*/ dev->fold = 1; *unitstat = CSW_CE | CSW_DE; break; case 0x73: /*---------------------------------------------------------------*/ /* BLOCK DATA CHECK */ /*---------------------------------------------------------------*/ /* *residual = 0; */ *unitstat = CSW_CE | CSW_DE; break; case 0x7B: /*---------------------------------------------------------------*/ /* ALLOW DATA CHECK */ /*---------------------------------------------------------------*/ /* *residual = 0; */ *unitstat = CSW_CE | CSW_DE; break; case 0xEB: /*---------------------------------------------------------------*/ /* UCS GATE LOAD */ /*---------------------------------------------------------------*/ /* Command reject if not first command in chain */ if (chained != 0) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Return normal status */ *unitstat = CSW_CE | CSW_DE; break; case 0xF3: /*---------------------------------------------------------------*/ /* LOAD UCS BUFFER AND FOLD */ /*---------------------------------------------------------------*/ /* For 1403, command reject if not chained to UCS GATE */ /* Also allow ALLOW DATA CHECK to get TSS/370 working */ /* -- JRM 11/28/2007 */ if (dev->devtype == 0x1403 && ((prevcode != 0xEB) && (prevcode != 0x7B))) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Set fold indicator and return normal status */ dev->fold = 1; dev->chskip = 1; /* *residual = 0; */ *unitstat = CSW_CE | CSW_DE; break; case 0xFB: /*---------------------------------------------------------------*/ /* LOAD UCS BUFFER (NO FOLD) */ /*---------------------------------------------------------------*/ /* For 1403, command reject if not chained to UCS GATE */ if (dev->devtype == 0x1403 && prevcode != 0xEB) { dev->sense[0] = SENSE_CR; *unitstat = CSW_CE | CSW_DE | CSW_UC; break; } /* Reset fold indicator and return normal status */ dev->fold = 0; dev->chskip = 1; /* *residual = 0; */ *unitstat = CSW_CE | CSW_DE; break; case 0x04: /*---------------------------------------------------------------*/ /* SENSE */ /*---------------------------------------------------------------*/ /* Calculate residual byte count */ num = (count < dev->numsense) ? count : dev->numsense; *residual = count - num; if (count < dev->numsense) *more = 1; /* Copy device sense bytes to channel I/O buffer */ memcpy (iobuf, dev->sense, num); /* Clear the device sense bytes */ memset (dev->sense, 0, sizeof(dev->sense)); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; case 0xE4: /*---------------------------------------------------------------*/ /* SENSE ID */ /*---------------------------------------------------------------*/ /* SENSE ID is only supported if LEGACYSENSEID is ON; * otherwise, fall through to invalid operation. */ if (sysblk.legacysenseid) { /* Calculate residual byte count */ num = (count < dev->numdevid) ? count : dev->numdevid; *residual = count - num; if (count < dev->numdevid) *more = 1; /* Copy device identifier bytes to channel I/O buffer */ memcpy (iobuf, dev->devid, num); /* Return unit status */ *unitstat = CSW_CE | CSW_DE; break; } default: /*---------------------------------------------------------------*/ /* INVALID OPERATION */ /*---------------------------------------------------------------*/ /* Set command reject sense byte, and unit check status */ dev->sense[0] = SENSE_CR; *unitstat = CSW_UC; } /* end switch(code) */ } /* end function printer_execute_ccw */
/*-------------------------------------------------------------------*/ static int open_printer (DEVBLK *dev) { pid_t pid; /* Child process identifier */ int open_flags; /* File open flags */ #if !defined( _MSVC_ ) int pipefd[2]; /* Pipe descriptors */ int rc; /* Return code */ #endif /* Regular open if 1st char of filename is not vertical bar */ if (!dev->ispiped) { int fd; /* Socket printer? */ if (dev->bs) return (dev->fd < 0 ? -1 : 0); /* Normal printer */ open_flags = O_BINARY | O_WRONLY | O_CREAT /* | O_SYNC */; if (dev->notrunc != 1) { open_flags |= O_TRUNC; } fd = HOPEN (dev->filename, open_flags, S_IRUSR | S_IWUSR | S_IRGRP); if (fd < 0) { WRMSG (HHC01105, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, "open()", strerror(errno)); return -1; } /* Save file descriptor in device block and return */ dev->fd = fd; return 0; } /* Filename is in format |xxx, set up pipe to program xxx */ #if defined( _MSVC_ ) /* "Poor man's" fork... */ pid = w32_poor_mans_fork ( dev->filename+1, &dev->fd ); if (pid < 0) { WRMSG (HHC01105, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, "fork()", strerror(errno)); return -1; } /* Log start of child process */ WRMSG (HHC01106, "I", SSID_TO_LCSS(dev->ssid), dev->devnum, pid); dev->ptpcpid = pid; #else /* !defined( _MSVC_ ) */ /* Create a pipe */ rc = create_pipe (pipefd); if (rc < 0) { WRMSG (HHC01105, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, "create_pipe()", strerror(errno)); return -1; } /* Fork a child process to receive the pipe data */ pid = fork(); if (pid < 0) { WRMSG (HHC01005, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, "fork()", strerror(errno)); close_pipe ( pipefd[0] ); close_pipe ( pipefd[1] ); return -1; } /* The child process executes the pipe receiver program... */ if (pid == 0) { /* Log start of child process */ WRMSG (HHC01106, "I", SSID_TO_LCSS(dev->ssid), dev->devnum, getpid()); /* Close the write end of the pipe */ close_pipe ( pipefd[1] ); /* Duplicate the read end of the pipe onto STDIN */ if (pipefd[0] != STDIN_FILENO) { rc = dup2 (pipefd[0], STDIN_FILENO); if (rc != STDIN_FILENO) { WRMSG (HHC01105, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, "dup2()", strerror(errno)); close_pipe ( pipefd[0] ); _exit(127); } } /* end if(pipefd[0] != STDIN_FILENO) */ /* Close the original descriptor now duplicated to STDIN */ close_pipe ( pipefd[0] ); /* Redirect stderr (screen) to hercules log task */ dup2(STDOUT_FILENO, STDERR_FILENO); /* Relinquish any ROOT authority before calling shell */ SETMODE(TERM); /* Execute the specified pipe receiver program */ rc = system (dev->filename+1); if (rc == 0) { /* Log end of child process */ WRMSG (HHC01107, "I", SSID_TO_LCSS(dev->ssid), dev->devnum, getpid()); } else { /* Log error */ WRMSG (HHC01108, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->filename+1, strerror(errno)); } /* The child process terminates using _exit instead of exit to avoid invoking the panel atexit cleanup routine */ _exit(rc); } /* end if(pid==0) */ /* The parent process continues as the pipe sender */ /* Close the read end of the pipe */ close_pipe ( pipefd[0] ); /* Save pipe write descriptor in the device block */ dev->fd = pipefd[1]; dev->ptpcpid = pid; #endif /* defined( _MSVC_ ) */ return 0; } /* end function open_printer */
/*-------------------------------------------------------------------*/ static int printer_init_handler (DEVBLK *dev, int argc, char *argv[]) { int iarg,i,j; /* some Array subscripts */ char *ptr; char *nxt; int sockdev = 0; /* 1 == is socket device */ /* For re-initialisation, close the existing file, if any, and raise attention */ if (dev->fd >= 0) { (dev->hnd->close)(dev); release_lock (&dev->lock); device_attention (dev, CSW_DE); obtain_lock (&dev->lock); } dev->excps = 0; /* Forcibly disconnect anyone already currently connected */ if (dev->bs && !unbind_device_ex(dev,1)) return -1; // (error msg already issued) /* The first argument is the file name */ if (argc == 0 || strlen(argv[0]) >= sizeof(dev->filename)) { WRMSG (HHC01101, "E", SSID_TO_LCSS(dev->ssid), dev->devnum); return -1; } /* Save the file name in the device block */ hostpath(dev->filename, argv[0], sizeof(dev->filename)); if(!sscanf(dev->typname,"%hx",&(dev->devtype))) dev->devtype = 0x3211; /* Initialize device dependent fields */ dev->fd = -1; dev->diaggate = 0; dev->fold = 0; dev->crlf = 0; dev->stopdev = FALSE; dev->notrunc = 0; dev->ispiped = (dev->filename[0] == '|'); /* initialize the new fields for FCB+ support */ dev->fcbsupp = 1; dev->cc = 0; dev->rawcc = 0; dev->fcbcheck = 1; dev->nofcbcheck = 0; dev->ccpend = 0; dev->chskip = 0; dev->prevline = 1; dev->currline = 1; dev->destline = 1; dev->print = 1; dev->browse = 0; dev->lpi = 6; dev->index = 0; dev->ffchan = 1; for (i = 0; i < FCBSIZE; i++) dev->fcb[i] = 0; for (i = 1; i <= 12; i++ ) { if ( FCBMASK[i] != 0 ) dev->fcb[FCBMASK[i]] = i; } dev->lpp = FCBMASK[0]; dev->fcbisdef = 0; /* Process the driver arguments */ for (iarg = 1; iarg < argc; iarg++) { if (strcasecmp(argv[iarg], "crlf") == 0) { dev->crlf = 1; continue; } /* sockdev means the device file is actually a connected socket instead of a disk file. The file name is the socket_spec (host:port) to listen for connections on. */ if (!dev->ispiped && strcasecmp(argv[iarg], "sockdev") == 0) { sockdev = 1; continue; } if (strcasecmp(argv[iarg], "noclear") == 0) { dev->notrunc = 1; continue; } if (strcasecmp(argv[iarg], "cc") == 0) { dev->cc = 1; dev->rawcc = 0; continue; } if (strcasecmp(argv[iarg], "rawcc") == 0) { dev->cc = 0; dev->rawcc = 1; continue; } if (strcasecmp(argv[iarg], "nofcbcheck") == 0) { dev->fcbcheck = 0; dev->nofcbcheck = 1; continue; } if (strcasecmp(argv[iarg], "fcbcheck") == 0) { dev->fcbcheck = 1; dev->nofcbcheck = 0; continue; } if ( (strcasecmp(argv[iarg], "browse") == 0) || (strcasecmp(argv[iarg], "optbrowse") == 0 ) ) { dev->print = 0; dev->browse = 1; continue; } if ( (strcasecmp(argv[iarg], "print") == 0 ) || (strcasecmp(argv[iarg], "optprint") == 0) ) { dev->print = 1; dev->browse = 0; continue; } if (strncasecmp("lpi=", argv[iarg], 4) == 0) { ptr = argv[iarg]+4; errno = 0; dev->lpi = (int) strtoul(ptr,&nxt,10); if (errno != 0 || nxt == ptr || *nxt != 0 || ( dev->lpi != 6 && dev->lpi != 8 ) ) { j = ptr - argv[iarg]; WRMSG (HHC01103, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, iarg + 1, argv[iarg], j); return -1; } continue; } if (strncasecmp("index=", argv[iarg], 6) == 0) { if (dev->devtype != 0x3211 ) { WRMSG (HHC01103, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, iarg + 1, argv[iarg], 1); return -1; } ptr = argv[iarg]+6; errno = 0; dev->index = (int) strtoul(ptr,&nxt,10); if (errno != 0 || nxt == ptr || *nxt != 0 || ( dev->index < 0 || dev->index > 15) ) { j = ptr - argv[iarg]; WRMSG (HHC01103, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, iarg + 1, argv[iarg], j); return -1; } continue; } if (strncasecmp("lpp=", argv[iarg], 4) == 0) { ptr = argv[iarg]+4; errno = 0; dev->lpp = (int) strtoul(ptr,&nxt,10); if (errno != 0 || nxt == ptr || *nxt != 0 ||dev->lpp > FCBSIZE) { j = ptr - argv[iarg]; WRMSG (HHC01103, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, iarg + 1, argv[iarg], j); return -1; } continue; } #if 0 if (strncasecmp("ffchan=", argv[iarg], 7) == 0) { ptr = argv[iarg]+7; errno = 0; dev->ffchan = (int) strtoul(ptr,&nxt,10); if (errno != 0 || nxt == ptr || *nxt != 0 || dev->ffchan < 1 || dev->ffchan > 12) { j = ptr - argv[iarg]; WRMSG (HHC01103, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, iarg + 1, argv[iarg], j); return -1; } continue; } #endif if (strncasecmp("fcb=", argv[iarg], 4) == 0) { for (line = 0; line <= FCBSIZE; line++) dev->fcb[line] = 0; /* check for simple mode */ if ( strstr(argv[iarg],":") ) { /* ':" found ==> new mode */ ptr = argv[iarg]+4; while (*ptr) { errno = 0; line = (int) strtoul(ptr,&nxt,10); if (errno != 0 || *nxt != ':' || nxt == ptr || line > dev->lpp || dev->fcb[line] != 0 ) { j = ptr - argv[iarg]; WRMSG (HHC01103, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, iarg + 1, argv[iarg], j); return -1; } ptr = nxt + 1; errno = 0; chan = (int) strtoul(ptr,&nxt,10); if (errno != 0 || (*nxt != ',' && *nxt != 0) || nxt == ptr || chan < 1 || chan > 12 ) { j = ptr - argv[iarg]; WRMSG (HHC01103, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, iarg + 1, argv[iarg], j); return -1; } dev->fcb[line] = chan; if ( *nxt == 0 ) break; ptr = nxt + 1; } } else { /* ':" NOT found ==> old mode */ ptr = argv[iarg]+4; chan = 0; while (*ptr) { errno = 0; line = (int) strtoul(ptr,&nxt,10); if (errno != 0 || (*nxt != ',' && *nxt != 0) || nxt == ptr || line > dev->lpp || dev->fcb[line] != 0 ) { j = ptr - argv[iarg]; WRMSG (HHC01103, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, iarg + 1, argv[iarg], j); return -1; } chan += 1; if ( chan > 12 ) { j = ptr - argv[iarg]; WRMSG (HHC01103, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, iarg + 1, argv[iarg], j); return -1; } dev->fcb[line] = chan; if ( *nxt == 0 ) break; ptr = nxt + 1; } if ( chan != 12 ) { j = 5; WRMSG (HHC01103, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, iarg + 1, argv[iarg], j); return -1; } } continue; } WRMSG (HHC01102, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, iarg + 1, argv[iarg]); return -1; } /* Check for incompatible options */ if (dev->rawcc && dev->browse) { WRMSG (HHC01104, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, "rawcc/browse"); return -1; } if (sockdev && dev->crlf) { WRMSG (HHC01104, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, "sockdev/crlf"); return -1; } if (sockdev && dev->notrunc) { WRMSG (HHC01104, "E", SSID_TO_LCSS(dev->ssid), dev->devnum, "sockdev/noclear"); return -1; } /* If socket device, create a listening socket to accept connections on. */ if (sockdev && !bind_device_ex( dev, dev->filename, onconnect_callback, dev )) { return -1; // (error msg already issued) } /* Set length of print buffer */ // dev->bufsize = LINE_LENGTH + 8; dev->bufsize = BUFF_SIZE + BUFF_OVFL; dev->bufres = BUFF_SIZE; dev->bufoff = 0; /* Set number of sense bytes */ dev->numsense = 1; /* Initialize the device identifier bytes */ dev->devid[0] = 0xFF; dev->devid[1] = 0x28; /* Control unit type is 2821-1 */ dev->devid[2] = 0x21; dev->devid[3] = 0x01; dev->devid[4] = dev->devtype >> 8; dev->devid[5] = dev->devtype & 0xFF; dev->devid[6] = 0x01; dev->numdevid = 7; /* Activate I/O tracing */ // dev->ccwtrace = 1; return 0; } /* end function printer_init_handler */
/*-------------------------------------------------------------------*/ static void* spthread (void* arg) { DEVBLK* dev = (DEVBLK*) arg; BYTE byte; fd_set readset, errorset; struct timeval tv; int rc, fd = dev->fd; // (save original fd) /* Fix thread name */ { char thread_name[32]; thread_name[sizeof(thread_name)-1] = 0; snprintf( thread_name, sizeof(thread_name)-1, "spthread %1d:%04X", SSID_TO_LCSS(dev->ssid), dev->devnum ); SET_THREAD_NAME( thread_name ); } // Looooop... until shutdown or disconnect... // PROGRAMMING NOTE: we do our select specifying an immediate // timeout to prevent our select from holding up (slowing down) // the device thread (which does the actual writing of data to // the client). The only purpose for our thread even existing // is to detect a severed connection (i.e. to detect when the // client disconnects)... while ( !sysblk.shutdown && dev->fd == fd ) { if (dev->busy) { SLEEP(3); continue; } FD_ZERO( &readset ); FD_ZERO( &errorset ); FD_SET( fd, &readset ); FD_SET( fd, &errorset ); tv.tv_sec = 0; tv.tv_usec = 0; rc = select( fd+1, &readset, NULL, &errorset, &tv ); if (rc < 0) break; if (rc == 0) { SLEEP(3); continue; } if (FD_ISSET( fd, &errorset )) break; // Read and ignore any data they send us... // Note: recv should complete immediately // as we know data is waiting to be read. ASSERT( FD_ISSET( fd, &readset ) ); rc = recv( fd, &byte, sizeof(byte), 0 ); if (rc <= 0) break; } obtain_lock( &dev->lock ); // PROGRAMMING NOTE: the following tells us whether we detected // the error or if the device thread already did. If the device // thread detected it while we were sleeping (and subsequently // closed the connection) then we don't need to do anything at // all; just exit. If we were the ones that detected the error // however, then we need to close the connection so the device // thread can learn of it... if (dev->fd == fd) { dev->fd = -1; close_socket( fd ); WRMSG (HHC01100, "I", SSID_TO_LCSS(dev->ssid), dev->devnum, dev->bs->clientname, dev->bs->clientip, dev->bs->spec); } release_lock( &dev->lock ); return NULL; } /* end function spthread */