v08i013: Updated servercomm
Brandon S. Allbery - comp.sources.misc
allbery at uunet.UU.NET
Thu Aug 24 09:51:54 AEST 1989
Posting-number: Volume 8, Issue 13
Submitted-by: dinah at krebs.bcm.tmc.edu (Dinah Anderson)
Archive-name: servercomm2
Here is an updated version of servercomm. I modified the make file
to not make the spool directories and modify the printcap since the
make file wanted to do this everytime you installed the software. I
also fixed the program to work correctly with the Sun pty's and a bridge
comm. terminal server. The previous version did not work with SunOS 4.0 and
postscript files properly.
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# Makefile
# README
# example
# hello.ps
# servercomm.8l
# servercomm.c
# This archive created: Wed Aug 23 12:04:23 1989
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Makefile'" '(4422 characters)'
if test -f 'Makefile'
then
echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^ X//' << \SHAR_EOF > 'Makefile'
X#
X# Wright State University Remote LaserWriter Kit
X# John Sloan <jsloan%SPOTS.Wright.EDU@@Relay.CS.NET>
X# $Revision: 1.3 $
X# $Date: 89/08/06 02:27:15 $
X#
X# Modified by Dinah Anderson <dinah at bcm.tmc.edu>
X# Baylor College of Medicine
X# 89/8/23
X#
X
X# C Compiler flags (if any)
XCFLAGS=-DBRIDGE
X
X# Printcap name of remote LaserWriter
XPRINTER=motc
X
X# Local LaserWriter spool directory (must differ from NEWSPOOLDIR)
XPSSPOOLDIR=/usr/spool/lpd/local
X
X# New remote LaserWriter spool directory (must differ from PSSPOOLDIR)
XNEWSPOOLDIR=/usr/spool/lpd/motc
X
X# Original Transcript software directory (must differ from NEWLIBDIR)
XPSLIBDIR=/usr/local/lib/ps
X
X# New remote Transcript filters directory (must differ from PSLIBDIR)
XNEWLIBDIR=/usr/motc
X
X# Network name of host computer handling spooling to communication server
X# This is the computer on which you are installing this software
XHOST="`hostname`"
X
X# Network name of host communications server
XSERVER=128.249.4.40
X
X# Port number for LaserWriter on host
XPORT=23
X
X# Master pseudo-terminal (typically /dev/ptyXX, where XX=[pqrs][0-f])
X# You may roll your own (as we do) with /etc/mknod
X# Owner should be daemon and mode should be 666
X# Device should not appear in /etc/ttys as login enabled (with getty)
XPTY=/dev/ptyr4
X
X# Slave pseudo-terminal (typically /dev/ttyXX)
X# You may roll your own (as we do) with /etc/mknod
X# Owner should be daemon and mode should be 666
X# Device should not appear in /etc/ttys as login enabled (with getty)
XTTY=/dev/ttyr4
X
X# Location of servercomm(8l) man page
XMANDIR=/usr/man/manl
X
X#########################################################################
X
Xall: servercomm filters printcap printcap.remote
X
Xinstall: all ${NEWLIBDIR}/servercomm ${MANDIR} servercomm.8l
X cp /dev/null ${NEWLIBDIR}/${PRINTER}
X cp servercomm.8l ${MANDIR}
X chmod 644 ${MANDIR}/servercomm.8l
X
Xclean:
X rm -if diffs printcap printcap.remote
X
Xbackout: clean
X rm -rif ${NEWSPOOLDIR} ${NEWLIBDIR}
X
Xservercomm: servercomm.c
X cc ${CFLAGS} -O -o servercomm servercomm.c
X
X${NEWLIBDIR}/servercomm: servercomm
X strip servercomm
X mv servercomm ${NEWLIBDIR}
X chmod 755 ${NEWLIBDIR}/servercomm
X
Xtest: debug hello.ps
X debug -v -x -h ${SERVER} -p ${PORT} -t ${PTY} ${TTY} -f ${NEWLIBDIR}/pscomm -P ${PRINTER} -p psif /dev/tty < hello.ps
X#debug -v -x -h ${SERVER} -p ${PORT} -t ${PTY} ${TTY} -f ${PSLIBDIR}/pscomm -P ${PRINTER} -p psif /dev/tty < hello.ps
X
Xdebug: servercomm.c
X cc ${CFLAGS} -g -DDEBUG -DDUMP -o debug servercomm.c
X
Xfilters: ${NEWLIBDIR} ${NEWLIBDIR}/psint.sh
X ln ${NEWLIBDIR}/psint.sh ${NEWLIBDIR}/psof
X ln ${NEWLIBDIR}/psint.sh ${NEWLIBDIR}/psif
X ln ${NEWLIBDIR}/psint.sh ${NEWLIBDIR}/psgf
X ln ${NEWLIBDIR}/psint.sh ${NEWLIBDIR}/psnf
X ln ${NEWLIBDIR}/psint.sh ${NEWLIBDIR}/pstf
X ln ${NEWLIBDIR}/psint.sh ${NEWLIBDIR}/psrf
X ln ${NEWLIBDIR}/psint.sh ${NEWLIBDIR}/psvf
X ln ${NEWLIBDIR}/psint.sh ${NEWLIBDIR}/pscf
X ln ${NEWLIBDIR}/psint.sh ${NEWLIBDIR}/psdf
X
X${NEWLIBDIR}/psint.sh: ${PSLIBDIR}/psint.sh ${NEWLIBDIR} diffs
X cp ${PSLIBDIR}/psint.sh ${NEWLIBDIR}
X chmod 755 ${NEWLIBDIR}/psint.sh
X patch ${NEWLIBDIR}/psint.sh diffs
X
X${NEWLIBDIR}:
X mkdir ${NEWLIBDIR}
X chmod 755 ${NEWLIBDIR}
X
Xdiffs:
X echo "67c67,68" > diffs
X echo "< comm=\"\$$PSCOMM -P \$$pname -p \$$prog -n \$$user -h \$$host \$$afile\"" >> diffs
X echo "---" >> diffs
X echo "> filter=\"\$$PSCOMM -P \$$pname -p \$$prog -n \$$user -h \$$host \$$afile\"" >> diffs
X echo "> comm=\"servercomm -h ${SERVER} -p ${PORT} -t ${PTY} ${TTY} -f \$$filter\"" >> diffs
X
Xprintcap:
X echo "${PRINTER}|LaserWriter on communication server ${SERVER} Port ${PORT}:\\" > printcap
X echo " :lp=${NEWLIBDIR}/${PRINTER}:sd=${NEWSPOOLDIR}:\\" >> printcap
X echo " :lf=${NEWSPOOLDIR}/lw-log:af=/usr/adm/lw.acct:\\" >> printcap
X echo " :mx#0:sf:sb:\\" >> printcap
X echo " :if=${NEWLIBDIR}/psif:\\" >> printcap
X echo " :of=${NEWLIBDIR}/psof:gf=${NEWLIBDIR}/psgf:\\" >> printcap
X echo " :nf=${NEWLIBDIR}/psnf:tf=${NEWLIBDIR}/pstf:\\" >> printcap
X echo " :rf=${NEWLIBDIR}/psrf:vf=${NEWLIBDIR}/psvf:\\" >> printcap
X echo " :cf=${NEWLIBDIR}/pscf:df=${NEWLIBDIR}/psdf:" >> printcap
X
X
Xprintcap.remote:
X echo "${PRINTER}|Remote LaserWriter on Host ${HOST} communication server ${SERVER} Port ${PORT}:\\" > printcap.remote
X echo " :lp=:rm=${HOST}:rp=${PRINTER}:sd=${NEWSPOOLDIR}:" >> printcap.remote
X
Xsharfile: README Makefile servercomm.8l servercomm.c hello.ps example
X shar README Makefile servercomm.8l servercomm.c hello.ps example > sharfile
SHAR_EOF
if test 4422 -ne "`wc -c < 'Makefile'`"
then
echo shar: error transmitting "'Makefile'" '(should have been 4422 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'README'" '(3390 characters)'
if test -f 'README'
then
echo shar: will not over-write existing file "'README'"
else
sed 's/^ X//' << \SHAR_EOF > 'README'
XManifest
X--------
X
XMakefile installation makefile
Xservercomm.8l manual page
Xservercomm.c source code
Xhello.ps Postscript "Hello, World" test file
Xexample Sample output from configuration of 3com Comm Server
XREADME This file
X
XTroubleshooting the connection to the server
X--------------------------------------------
X
X0) You may want to do this first, before doing the software installation.
X
X1) Kill the lpd daemon servicing your Laserwriter on the server, if
Xyou're troubleshooting after installing this kit.
X
X2) Provided you've already setup the port on the communications server
Xfor your Laserwriter, telnet to the port.
X
X3) If you get through the port to the Laserwriter, type the Postscript
Xcommand "executive" and see what the Laserwriter says. You should see a
X"PS>" prompt. If the Laserwriter responds, then the physical
Xconnection at least is good. Type "quit" to get out of executive mode
Xon the Laserwriter.
X
X4) As usual, check the modes and ownerships of the directories and
Xespecially the pseudo master and slave terminals in /dev.
X
X5) Edit the Makefile, setting the various variables to meaningful
Xvalues. Then, "make test", and the Makefile will compile a version of
Xservercomm in the current directory with the debugging code in, and then
Xrun the debug version in verbose mode. Watch the output carefully and
Xlook for complaints from servercomm. You do not have to have the spool
Xdirectory, new print filters, or printcap built to do this step. You DO
Xhave to have the variables in the Makefile set appropriately for your
Xsite.
X
XInstallation Steps for Bridge Server and TRANSCRIPT
X---------------------------------------------------
X0) Use the Makefile as a model of what to do. The easiest thing is to
Xset the Makefile variables to meaningful values, and then use the
XMakefile just to make some ancillary files that you will find useful in
Xa moment. "make printcap" and "make diffs" will not change
Xanything in your system, just make some files in the current
Xdirectory.
X
X1) Compile servercomm. (Type "make")
X
X2) Create a spool directory for the remote printer.
X
X3) Create a new directory to hold the modified Transcript filter.
XAlthough there appears to be several filters, they are in fact all hard
Xlinks to the same shell script. Copy the Transcript filter psint.sh into
Xthis directory, make the indicated changes in "diffs" (they are quite
Xsmall), and establish all the requisite hard links. Since the filters
Xare all in fact sybolic links to a single file, the overhead in maintaining
Xa separate directory for every such remote printer is not high. Copy servercomm
Xto this new directory. (Type "make filters")
X
X4) Make up a printcap entry for the remote printer and install it in
Xthe /etc/printcap file. Use "printcap", produced by the Makefile, as an
Xexample. The filters should point to your new modified filters. The
Xspool area should point to your new spool directory. The device should
Xpoint to a null file (and not a real device), since servercomm handles
Xall the I/O.
X
X5) Set up the Bridge server by assigning an IP address to a port and
Xsetting the port parameters to those in the "example" file.
X
X6) Hook your Laserwriter up to the Bridge server to the port you just
Xsetup.
X
X7) Try printing using the usual Berkeley lpr commands. Look in lw-log
Xin the spool directory for errors. Under SunOS 4.0, you may find these
Xerrors in /usr/adm/lpd-errors.
SHAR_EOF
if test 3390 -ne "`wc -c < 'README'`"
then
echo shar: error transmitting "'README'" '(should have been 3390 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'example'" '(1026 characters)'
if test -f 'example'
then
echo shar: will not over-write existing file "'example'"
else
sed 's/^ X//' << \SHAR_EOF > 'example'
X
Xcs/1t# sh (!63) dp
XDefaultParameters for PortId !63
X...................Port Transmission and VTP Characteristics...................
XAUToDisconnect = 60 AUtoLogoff = OFF BUffersize = 82
XDeVice = ( Host, Glass, DeFault ) PermanentVC = ""
X.........................Port Physical Characteristics.........................
XBAud = 9600 BSPad = None CRPad = None FFPad = None
XLFPad = None TabPad = None DataBits = 7 DUplex = Full
XLinePRotocol = ASynchronous PARIty = AutoParity StopBits = 1
XUseDCDout = ( AlwaysAssert, NoToggle ) UseDTRin = AsDTR (by DTE)
X.................Session Transmission and VTP Characteristics..................
XBReakAction = IGnore DIsconnectAction = None
XDataForward = None ECHOData = OFF
XECHOMask = ( AlphaNum, CR, Term, Punct ) NetAScii = UseLF
XFlowControlFrom = ( Xon_Xoff ) FlowControlTo = ( Xon_Xoff )
XIdleTimer = 2 LongBReakAction = IGnore XOFF = ^S
XXON = ^Q
Xcs/1t#
SHAR_EOF
if test 1026 -ne "`wc -c < 'example'`"
then
echo shar: error transmitting "'example'" '(should have been 1026 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'hello.ps'" '(4967 characters)'
if test -f 'hello.ps'
then
echo shar: will not over-write existing file "'hello.ps'"
else
sed 's/^ X//' << \SHAR_EOF > 'hello.ps'
X%!PS-Adobe-1.0
X%%Creator: odin:jsloan (John Sloan,407 Fawcett,2987,5134268082)
X%%Title: stdin
X%%CreationDate: Tue Jun 21 11:41:28 1988
X%%DocumentFonts: Times-Roman Times-Italic Times-Bold Symbol Times-Roman
X%%Pages: (atend)
X%%EndComments
X% lib/pscat.pro -- prolog for pscat (troff) files
X% Copyright (C) 1985 Adobe Systems, Inc.
X% Added defs for Manual Feed
Xsave /pscatsave exch def
X/$pscat 50 dict def
X$pscat begin
X/fm [1 0 0 1 0 0] def
X/xo 0 def /yo 0 def
X/M /moveto load def
X/R /show load def
X/S {exch currentpoint exch pop moveto show}def
X/T {exch currentpoint pop exch moveto show}def
X/U {3 1 roll moveto show}def
X/siz 0 def
X/font 0 def
X/Z {/siz exch def SF}def
X/F {/font exch def SF}def
X/SF{font 0 ne
X {catfonts font 1 sub get fm 0 siz put fm 3 siz neg put
X fm makefont setfont}if}def
X/BP{save/catsv exch def 0 792 translate 72 432 div dup neg scale
X xo yo translate 0 0 moveto}def
X/BPL{save/catsv exch def 72 8.25 mul 792 translate -90 rotate
X 72 432 div dup neg scale xo yo translate 0 0 moveto}def
X/EP{catsv restore showpage}def
X/SetStTime{statusdict /manualfeedtimeout 120 put} def
X/SetStatus{statusdict /manualfeed true put
X statusdict /product get (LaserWriter) eq
X {version (23.0) eq % Don't redefine EP if printer is not "Classic LW"
X {/EP {catsv restore
X {statusdict /printerstatus get exec 16#22000000 and 0 eq{exit}if}loop
X showpage}def}if }if}def
X% definitions for PPROC callback functions
X% each PPROC is called with the following number on the stack:
X% pointsize charcode railmag pswidth pschar x y wid
X/$pprocs 50 dict def
X/fractm [.65 0 0 .6 0 0] def
X% fractions
X/PS1{gsave $pprocs begin
X /wid exch def pop pop pop pop pop /ch exch def /size exch def
X /pair $pprocs ch get def /cf currentfont def
X cf fractm makefont setfont
X 0 .3 size mul 6 mul 2 copy neg rmoveto pair 0 get show rmoveto
X currentfont cf setfont (\244) show setfont
X pair 1 get show grestore wid .06 div 0 rmoveto end}def
X$pprocs begin
X8#34 [(1)(4)] def
X8#36 [(1)(2)] def
X8#46 [(3)(4)] def
Xend
X% boxes
X/PS2{gsave /wid exch def pop pop /char exch def pop pop pop /size exch def
X /len size 3.5 mul def % length of a side
X len 0 rlineto 0 len neg rlineto len neg 0 rlineto closepath
X char 3 eq {fill}{size 5 mul .07 mul setlinewidth stroke}ifelse
X grestore wid .06 div 0 rmoveto}def
X/PS3/PS2 load def % boxes are the same...
X% circle
X/PS4{gsave /wid exch def pop pop pop pop pop pop /size exch def
X wid .8333 mul size 2.5 mul neg rmoveto currentpoint % center
X newpath size 1.8 mul 0 360 arc size .2 mul setlinewidth stroke
X grestore wid .06 div 0 rmoveto}def
X/bb{$pprocs begin /wid exch def pop pop pop pop pop pop /size exch 6 mul def
X /s2 size 2 div def /s4 size 4 div def gsave
X currentpoint newpath transform round exch round exch itransform translate
X size 16 div setlinewidth 2 setlinejoin 0 setgray}def
X$pprocs begin
X/mrr{moveto rlineto rlineto}def
X/be{stroke grestore wid .06 div 0 rmoveto end}def
Xend
X% leftfloor
X/PS6 {bb s4 0 0 size s4 size -.8 mul mrr be}def
X% rightfloor
X/PS7 {bb s4 neg 0 0 size s4 size -.8 mul mrr be}def
X% leftceil
X/PS8 {bb s4 0 0 size neg s4 size .2 mul mrr be}def
X% rightceil
X/PS9 {bb s4 neg 0 0 size neg s4 size .2 mul mrr be}def
X% boldvert
X/PS5 {bb 0 0 0 size neg s4 size .2 mul mrr be}def
X% box rule
X/PS32 {bb /sw size 24 div def sw 2 div size 4.5 div moveto
X 0 size neg rlineto sw setlinewidth be}def
X% rule (roman, bold and italic)
X/PS16 {gsave $pprocs begin
X /wid exch def pop pop pop pop pop pop /size exch 6 mul def
X /sw size 14 div def currentpoint exch sw 2 div sub exch
X newpath transform round exch round exch itransform translate
X 0 0 moveto size 2 div 0 rlineto sw setlinewidth be}def
X% lefttopcurl
X/PS20 {bb s4 size .2 mul moveto 0 size -.55 mul rlineto currentpoint
X pop size -.8 mul 2 copy exch s4 add exch s4 arcto pop pop pop pop be}def
X% leftbotcurl
X/PS21 {bb s4 size -.8 mul moveto 0 size .55 mul rlineto currentpoint
X pop size .2 mul 2 copy exch s4 add exch s4 arcto pop pop pop pop be}def
X% righttopcurl
X/PS22 {bb s4 size .2 mul moveto 0 size -.55 mul rlineto currentpoint
X pop size -.8 mul 2 copy exch s4 sub exch s4 arcto pop pop pop pop be}def
X% rightbotcurl
X/PS23 {bb s4 size -.8 mul moveto 0 size .55 mul rlineto currentpoint
X pop size .2 mul 2 copy exch s4 sub exch s4 arcto pop pop pop pop be}def
X% rightmidcurl
X/PS25 {bb /s3 size -.3 mul def s4 size -.8 mul moveto s4 s3 s2 s3
X s4 arcto pop pop size add s4 s3 4 2 roll
X s4 arcto pop pop pop pop s4 size .2 mul lineto be}def
X% leftmidcurl
X/PS24 {bb /s3 size -.3 mul def s4 size -.8 mul moveto s4 s3 0 s3
X s4 arcto pop pop size add s4 s3 4 2 roll s4 arcto pop pop pop pop
X s4 size .2 mul lineto be}def
X/catfonts [
X /Times-Roman findfont
X /Times-Italic findfont
X /Times-Bold findfont
X /Symbol findfont
X /Times-Roman findfont
X ] def
X%%EndProlog
X%%Page: ? 1
XBP
X1 F
X60 Z
X432 165(Hello,)U
X601(World!)S
XEP
X%%Trailer
Xpscatsave end restore
X%%Pages: 1
SHAR_EOF
if test 4967 -ne "`wc -c < 'hello.ps'`"
then
echo shar: error transmitting "'hello.ps'" '(should have been 4967 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'servercomm.8l'" '(4271 characters)'
if test -f 'servercomm.8l'
then
echo shar: will not over-write existing file "'servercomm.8l'"
else
sed 's/^ X//' << \SHAR_EOF > 'servercomm.8l'
X.TH SERVERCOMM 8 "8 JULY 1989"
X\" $Header$
X.ds TS T\s-2RAN\s+2S\s-2CRIPT\s+2
X.SH NAME
Xservercomm \- spool to a printer on a terminal server
X.SH SYNOPSIS
X.B servercomm
X[ \fB\-v\fR ]
X[ \fB\-x\fR ]
X[ \fB\-d\fI device\fR ]
X[ \fB\-h\fI host\fR [ \fB\-p\fI port\fR ] ]
X[ \fB\-t\fI ptydevice ttydevice\fR ]
X[ \fB\-f\fI filter\fR ]
X.SH DESCRIPTION
X.I servercomm
Xis an program that provides an interface between a typical Berkeley
X.I lpd
Xfilter (such as those provided in the Adobe \*(TS package) and
Xa printer (such as a LaserWriter) connected to a serial port on a
Xterminal server manufactured by 3com (Bridge), cisco systems, or
XXylogics (Annex).
X.I Servercomm
Xmakes a TCP/IP TELNET connection to the specified serial port of the
Xspecified terminal server. It then forks and execs the normal filter
X(as specified).
XSince filters expect to talk to a physical device, a /dev/tty??, so
X.I servercomm
Xobliges by communicating with filters
Xthrough the master and slave portions of a network pseudo-terminal pair,
X/dev/pty?? and /dev/tty??.
X.I Servercomm
Xhandles the interchange of data between the pseudo-terminal and the
Xcommunications server.
X.I Lpd
Xand any filters behave as if they were communicating with a directly-attached
Xprinter.
X.SH OPTIONS
X.LP
X.IP "\fB\-v\fR"
XTurn on the debugging output to stderr, if the option was enabled at
Xcompile time through the use of the -DDEBUG cc switch.
X.IP "\fB\-x\fR"
XTurn on the dump output to stderr, if the option was enabled at compile
Xtime through the use of the -DDUMP cc switch.
X.IP "\fB\-d\fI device\fR"
XSpecify a device, such as /dev/lp, to use instead of the terminal server.
XThis is useful for debugging the filter with a hardwired printer. Omitted
Xif the \fB\-h\fR switch is used.
X.IP "\fB\-h\fI host\fR"
XSpecify the host name of the terminal server [or port on a terminal server]
Xthat the printer is attached to.
XOmitted if the \fB\-d\fR switch is used.
X.IP "\fB\-p\fI port\fR"
XSpecify the number of the serial port that the printer is attached
Xto. Omitted if the \fB\-d\fR switch is used. This switch is unneeded with
Xthe 3com or cisco terminal servers.
X.IP "\fB\-t\fI ptydevice ttydevice\fR"
XIndicate the master-slave pseudo-terminal pair to be used to communicate
Xwith the filter. The tty name could be intuited from the pty name, provided
Xthe standard names are used, but the user should be able to name the
Xpair something else, like /dev/plp and /dev/tlp.
X.IP "\fB\-f\fI filter\fR"
XProvide the complete command line for the filter to be invoked.
XTypically, this is
X.I pscomm
Xfrom the \*(TS package, but it could be something else.
X.SH "NOTES for \*(TS "
XBriefly, the Berkeley line printer daemon,
X.I lpd,
Xinvokes filters to handle communications with a printer attached to a
Xserial port on the host computer. If these filters are modified to start
X.I servercomm
Xinstead of calling the usual communications filter,
X.I pscomm,
Xthen
X.I servercomm
Xwill initialize the connection and start
X.I pscomm
Xto output the information.
X.br
XTo install
X.I servercomm,
Xcopy it in the the directory where
X.I pscomm
Xis located. Make a copy of the
X.I psint.sh
Xshell script and edit it to make the following changes.
X.br
XChange the line the begins
X.B comm=
Xto begin with
X.B filter=
Xand then add this line:
X.br
Xcomm=servercomm -h
X.B hostname
X-p
X.B portid
X-t
X.B tty-names
X-f $filter
X.br
X.sp
X.B hostname,
X.B portid,
Xand
X.B psudo-tty-name
Xare described above.
XIf you replace the
X.I psint.sh
Xscript with this modified one, then your changes are complete. However, if
Xyou have more than one printer, you will need a version of
X.I psint.sh
Xfor each one.
X.SH FILES
X.nf
X/etc/printcap printer capabilities data base
X/usr/lib/lpd* line printer daemons
X/usr/spool/* directories used for spooling
X.fi
X.SH "SEE ALSO"
Xprintcap(5),
Xlpc(8),
Xlpd(8),
Xpscomm(8),
Xpsif(8)
X.SH DIAGNOSTICS
XThere are many possible fatal diagnostic messages. Each indicates which
Xroutine in
X.I servercomm
Xhad the fatal error. In most cases,
X.I servercomm
Xreturns an LPD_ABORT code to
X.I lpd.
XIf the specified filter (typically
X.I pscomm
X) fails,
X.I servercomm
Xreturns the exit code of the filter to
X.I lpd.
X.SH NOTES
X\*(TS is a trademark of Adobe Systems Incorporated.
X.br
XAnnex is a trademark of Xylogics Incorporated.
X.br
XLaserWriter is a trademark of Apple Computer.
SHAR_EOF
if test 4271 -ne "`wc -c < 'servercomm.8l'`"
then
echo shar: error transmitting "'servercomm.8l'" '(should have been 4271 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'servercomm.c'" '(16356 characters)'
if test -f 'servercomm.c'
then
echo shar: will not over-write existing file "'servercomm.c'"
else
sed 's/^ X//' << \SHAR_EOF > 'servercomm.c'
X/*
X** S E R V E R C O M M
X**
X** Title: servercomm (formerly annexf)
X** Original Author: John Sloan (internet: jsloan at SPOTS.Wright.Edu)
X** System: SunOS
X** Language: C
X** Date: April 1988
X** Abstract
X**
X** Servercomm is a filter for the Berkeley spooler daemon that
X** establishes a bidirectional TCP/IP/TELNET connection to
X** a serial port on an terminal server made by popular makers
X** so that printouts can be spooled to a serial printer connected
X** to the server. It is intended to be used with an Apple
X** Laserwriter and the Adobe Transcript package, but could
X** be used for other things as well. It can also be configured
X** at run time to talk to a /dev device instead of the terminal server
X++
X++ Modified by Jim Warner to work with the service listener
X++ port on Bridge Communications terminal servers. The dialog
X++ in handshake() is unnecessary. The "port" number was the physical
X++ connector on the back of the annex. For Bridge (and Cisco, I bet)
X++ this is the tcp-port number to use instead of telnet=23. For
X++ Bridge, we're going to need an IP address per printer.
X++ Jan 2 1989
X==
X== Modified by Dinah Anderson <dinah at bcm.tmc.edu> to use the
X== sys/termios.h data structure instead of the sys/ioctl.h.
X== Also set the ptys characteristics explicitly since most postscript
X== files would not print. We tested this using a Bridge server.
X== 8/23/89.
X**
X** Disclaimer
X**
X** This software is supplied as is, and no warranty is expressed or
X** implied as to its correctness, functionality, or suitability
X** for any application, anywhere, at anytime, by anyone.
X**
X** Acknowledgements
X**
X** Much of this code was inspired by telnet.c from UCB and aprint.c
X** from Encore Computer. No code borrowed, but a lot of questions
X** were answered by perusing these examples. Also, many thanks to
X** Ken Yap <ken at cs.rochester.edu>, who suggested using a pty/tty
X** pair to communicate with pscomm. I was working on that when I
X** received his email, and it was encouraging to hear someone else
X** that thought it should work.
X**
X** Compile Time Flags
X**
X** DEBUG Compiles in debugging code to make
X** useful remarks on stderr. Use the
X** -v run time flag to activate.
X**
X** DUMP Compiles in code to dump data to stderr
X** as it's being processed. Very verbose,
X** but useful in debugging. Use the -x run
X** time flag to activate.
X**
X** BRIDGE Compiles in code to support CISCO or BRIDGE
X** communications servers.
X**
X*/
X/*
X** To do:
X** The pseudottys should not have to be specified. The program
X** should find the first available ones and use them.
X**
X*/
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/file.h>
X#include <sys/termios.h>
X#include <ctype.h>
X#include <errno.h>
X#include <fcntl.h>
X#include <setjmp.h>
X#include <signal.h>
X#include <netdb.h>
X#include <netinet/in.h>
X#define TELOPTS
X#include <arpa/telnet.h>
X#include <arpa/inet.h>
X#include <sys/socket.h>
X#include <sys/wait.h>
X#include <strings.h>
X
X#define LPD_OK 0 /* lpd filter exit codes */
X#define LPD_RETRY 1
X#define LPD_ABORT 2
X#define BUFFER 512 /* spooler buffer size in bytes */
X#define CR '\015'
X#define PROMPT ':'
X
X#ifdef DEBUG
X#define DPRINTF(s) if (debugon) fprintf s
X#else
X#define DPRINTF(s)
X#endif
X
X/*
X** Identification
X*/
Xstatic char id[]="$Header: /home/crick/vpit/sob/src/servercomm/RCS/servercomm.c,v 1.1 89/08/06 00:10:36 sob Exp Locker: sob $";
X
X/*
X** Must be static (used by network code).
X*/
Xstruct servent *srvc;
Xstruct hostent *host;
Xstruct sockaddr_in sock;
Xstruct sockaddr dev;
Xstruct termios ttycb;
Xjmp_buf context;
X
X/*
X** Must be global (used by interrupt service routines).
X*/
X#ifndef errno
Xextern int errno; /* warner: not needed for Sun OS */
X#endif
Xchar *pgmname;
Xint filterpid,prodpid,conspid;
Xint netfd,ptyfd,ttyfd;
Xint debugon,dumpon;
X
Xvoid setup(),cleanup(),handshake(),trigger(),rendezvous();
Xvoid spool(),transmit(),usage(),bailout(),fatal();
Xvoid lost(),interrupted(),finished();
X#ifdef DEBUG
Xvoid pargs();
X#endif
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X {
X int nargc,rc;
X char *host,*port,*device,*filter,*pty,*tty,**nargv;
X
X pgmname=rindex(argv[0],'/');
X pgmname=pgmname?pgmname+1:argv[0];
X setup(argc,argv,&debugon,&dumpon,&host,&port,&device,&pty,&tty,&filter,&nargc,&nargv);
X filterpid=0;
X prodpid=0;
X conspid=0;
X if (pty!=NULL)
X {
X ptyfd=acquire(pty);
X ttyfd=acquire(tty);
X if ((rc=ioctl(ttyfd,TCGETS,&ttycb))<0)
X fatal(rc,"main ioctl getp failed",LPD_ABORT);
X ttycb.c_cflag = (B9600 | CS7 | CREAD );
X ttycb.c_oflag = (OPOST | OCRNL );
X ttycb.c_iflag = (ISTRIP );
X ttycb.c_lflag = (0 );
X if ((rc=ioctl(ttyfd,TCSETS,&ttycb))<0)
X fatal(rc,"main ioctl setp failed",LPD_ABORT);
X }
X else
X ptyfd=0;
X if (host!=NULL)
X netfd=establish(host,port);
X else if (device!=NULL)
X netfd=acquire(device);
X else
X usage(0);
X if (rc=setjmp(context))
X bailout(rc);
X if (port!=NULL)
X handshake(netfd,port);
X if (filter!=NULL)
X {
X /*
X ** Fork off producer and consumer processes
X ** ahead of the filter so that they are ready
X ** to handle the filter's I/O immediately. This
X ** scheme is process intensive (makes several
X ** processes) but is simpler than using non-blocking
X ** I/O, which was the original implementation.
X */
X spool(netfd,ptyfd,&prodpid,&conspid);
X filterpid=attach(filter,nargc,nargv,ttyfd);
X /*
X ** Don't let children inherit our interrupt
X ** service routines. This naively assumes that
X ** nothing interesting will happen prior to now.
X */
X signal(SIGPIPE,lost);
X signal(SIGINT,interrupted);
X /*
X ** Wait for something interesting to happen.
X */
X rendezvous(filterpid,prodpid,conspid);
X DPRINTF((stderr,"%s: main complete\n",pgmname));
X exit(LPD_OK);
X }
X }
X
X/*
X** Setup: parses argument list.
X*/
Xvoid
Xsetup(argc,argv,dbgon,dmpon,host,port,device,pty,tty,filter,nargc,nargv)
Xint argc,*dbgon,*dmpon,*nargc;
Xchar *argv[],**host,**port,**device,**pty,**tty,**filter,***nargv;
X {
X
X *dbgon=0;
X *dmpon=0;
X *host=NULL;
X *port=NULL;
X *device=NULL;
X *pty=NULL;
X *tty=NULL;
X *filter=NULL;
X *nargc=0;
X *nargv=NULL;
X while (argc>0)
X {
X if (argv[0][0]=='-')
X {
X switch (argv[0][1])
X {
X case 'v':
X *dbgon=1;
X DPRINTF((stderr,"%s: debug on\n",pgmname));
X break;
X case 'x':
X *dmpon=1;
X DPRINTF((stderr,"%s: dump on\n",pgmname));
X break;
X case 'h':
X usage(--argc);
X *host=(*++argv);
X DPRINTF((stderr,"%s: setup host=%s\n",pgmname,*host));
X break;
X case 'p':
X usage(--argc);
X *port=(*++argv);
X DPRINTF((stderr,"%s: setup port=%s\n",pgmname,*port));
X break;
X case 'd':
X usage(--argc);
X *device=(*++argv);
X DPRINTF((stderr,"%s: setup device=%s\n",pgmname,*device));
X break;
X case 't':
X usage(--argc);
X *pty=(*++argv);
X usage(--argc);
X *tty=(*++argv);
X DPRINTF((stderr,"%s: setup pty=%s, tty=%s\n",pgmname,*pty,*tty));
X break;
X case 'f':
X usage(--argc);
X *filter=(*++argv);
X *nargv=argv;
X *nargc=argc;
X argc=0;
X DPRINTF((stderr,"%s: setup filter=%s, argc=%d\n",pgmname,*filter,*nargc));
X break;
X default:
X usage(0);
X }
X }
X argv++;
X argc--;
X }
X }
X
X/*
X** Cleanup: Shutdown child processes, close files, do anything else
X** necessary to gracefully complete in the event of an error.
X*/
Xvoid
Xcleanup()
X {
X /*
X ** Filter may not have been started up yet.
X */
X if (filterpid)
X {
X kill(filterpid,SIGTERM);
X DPRINTF((stderr,"%s: cleanup killed filter %d\n",pgmname,filterpid));
X }
X /*
X ** Producer may not have been started up yet.
X */
X if (prodpid)
X {
X kill(prodpid,SIGTERM);
X DPRINTF((stderr,"%s: cleanup killed spooler %d\n",pgmname,prodpid));
X }
X /*
X ** Consumer may not have been started up yet.
X */
X if (conspid)
X {
X kill(conspid,SIGTERM);
X DPRINTF((stderr,"%s: cleanup killed spooler %d\n",pgmname,conspid));
X }
X /*
X ** These may be already closed, in which case close returns an
X ** error we can safely ignore.
X */
X close(ptyfd);
X close(ttyfd);
X close(netfd);
X }
X
X/*
X** Establish: Given a host name or an IP address, establish a real
X** time TCP/IP/TELNET connection to the specified Annex.
X*/
Xint
Xestablish(hostname,port)
Xchar *hostname, *port;
X {
X char *name;
X int rc,netfd;
X
X if ((srvc=getservbyname("telnet","tcp"))==0)
X fatal(srvc,"establish getservbyname failed",LPD_ABORT);
X if (host=gethostbyname(hostname))
X {
X /*
X ** hostname is an alphanumeric name in /etc/hosts
X */
X DPRINTF((stderr,"%s: got hostname\n",pgmname));
X sock.sin_family=host->h_addrtype;
X bcopy(host->h_addr,(caddr_t)&sock.sin_addr,host->h_length);
X name=host->h_name;
X }
X else if ((sock.sin_addr.s_addr=inet_addr(hostname))!=-1)
X {
X /*
X ** hostname is a numeric IP address
X */
X DPRINTF((stderr,"%s: got IP address\n",pgmname));
X sock.sin_family=AF_INET;
X name=hostname;
X }
X else
X /*
X ** hostname is not anything useful
X */
X fatal(sock.sin_addr.s_addr,"establish hostname failed",LPD_ABORT);
X#ifndef BRIDGE
X sock.sin_port=srvc->s_port;
X#else
X sock.sin_port= htons ( atoi (port));
X DPRINTF ((stderr,"%s: tcp port %d\n",pgmname, atoi (port) ));
X#endif
X if ((netfd=socket(AF_INET,SOCK_STREAM,0,0))<0)
X fatal(netfd,"establish socket failed",LPD_ABORT);
X if ((rc=connect(netfd,(caddr_t)&sock,sizeof(sock),0))<0)
X fatal(rc,"establish connect failed",LPD_ABORT);
X DPRINTF((stderr,"%s: establish host=%s, socket=%d\n",pgmname,name,netfd));
X return(netfd);
X }
X
X/*
X** Handshake: Given a TCP/IP/TELNET connection to an Annex,
X** carry out handshaking necessary to connect to the specified
X** serial port. This is clearly kludgy, and should be replaced
X** with Encore's Annex R4.0.
X**
X*/
Xvoid
Xhandshake(netfd,port)
Xint netfd;
Xchar *port;
X {
X int rc;
X
X DPRINTF((stderr,"%s: handshake fd=%d, port=%s\n",pgmname,netfd,port));
X#ifndef BRIDGE
X transmit(netfd,"\r",1);
X trigger(netfd,':');
X trigger(netfd,':');
X transmit(netfd,port,strlen(port));
X transmit(netfd,"\r",1);
X trigger(netfd,'\n');
X trigger(netfd,'\n');
X#endif
X }
X
X/*
X** Trigger: Scan the data from a specified file descriptor until
X** the given trigger character is encountered. Hey, is this kludgey
X** or what? But it keeps handshake and the comm server synchronized
X** (providing no characters are lost), and keeps pscomm from seeing
X** any of the prompts from the annex. Both trigger and handshake
X** will be obsolesced by Encore's Annex R4.0, which has a better
X** reverse telnet mechanism.
X*/
Xvoid
Xtrigger(fd,ch)
Xint fd;
Xchar ch;
X {
X int count;
X char buf;
X
X do
X {
X if ((count=receive(fd,&buf,1))!=1)
X fatal(count,"trigger receive would block",LPD_ABORT);
X#ifdef DEBUG
X if (debugon) putc(buf,stderr);
X#endif
X }
X while (buf!=ch);
X }
X
X/*
X** Attach: Given a connection to a particular serial port on an
X** terminal server, invoke an appropriate printer filter to handle the
X** input/output.
X*/
Xint
Xattach(filter,argc,argv,prtfd)
Xint argc,prtfd;
Xchar *filter,**argv;
X {
X int rc,pid;
X
X if ((pid=fork())<0)
X fatal(pid,"attach fork failed",LPD_ABORT);
X else
X if (pid)
X {
X /*
X ** Child owns the prtfd now.
X */
X close(prtfd);
X DPRINTF((stderr,"%s: attach filter=%s, prtfd=%d, pid=%d\n",pgmname,filter,prtfd,pid));
X#ifdef DEBUG
X if (debugon) pargs(argc,argv);
X#endif
X return(pid);
X }
X else
X {
X /*
X ** stdout gets connected to the tty end of pty
X ** so pscomm sees a tty devices as its output.
X ** stdin remains connected to lpd output.
X */
X close(1);
X if ((rc=dup2(prtfd,1))==-1)
X fatal(rc,"attach dup2 failed",LPD_ABORT);
X if ((rc=execvp(filter,argv))==-1)
X fatal(rc,"attach execvp failed",LPD_ABORT);
X /*
X ** Never reached.
X */
X }
X }
X
X/*
X** Rendezvous: waits for the child process (the true printer
X** filter) to complete.
X*/
Xvoid
Xrendezvous(filterpid,prodpid,conspid)
Xint filterpid,prodpid,conspid;
X {
X int wpid,rc;
X union wait status;
X
X do
X wpid=wait(&status);
X while ((wpid!=filterpid)&&(wpid!=-1));
X if (wpid==-1)
X fatal(wpid,"rendezvous wait failed",LPD_ABORT);
X rc=status.w_retcode;
X if (rc!=LPD_OK)
X fatal(rc,"rendezvous filter failed",rc);
X DPRINTF((stderr,"%s: rendezvous wpid=%d, retcode=%d\n",pgmname,wpid,rc));
X /*
X ** These may have already returned, in which case the kill
X ** returns an error we can safely ignore.
X */
X kill(prodpid,SIGTERM);
X kill(conspid,SIGTERM);
X }
X
X/*
X** Acquire: open a device and return the file descriptor.
X*/
Xint
Xacquire(dev)
Xchar *dev;
X {
X int fd;
X
X if ((fd=open(dev,O_RDWR))==-1)
X fatal(fd,"acquire open failed",LPD_ABORT);
X DPRINTF((stderr,"%s: acquire dev=%s, fd=%d\n",pgmname,dev,fd));
X return(fd);
X }
X
X/*
X** Spool: set up the net and pty connections and fork off
X** children to do the actual work.
X*/
Xvoid
Xspool(netfd,ptyfd,prodpid,conspid)
Xint netfd,ptyfd,*prodpid,*conspid;
X {
X int rc;
X
X if ((*conspid=fork())<0)
X fatal(*conspid,"spool consumer fork failed",LPD_ABORT);
X if (!*conspid)
X {
X rc=process(netfd,ptyfd);
X /*
X ** Release fds now that consumer is complete.
X */
X close(netfd);
X close(ptyfd);
X exit(rc);
X }
X DPRINTF((stderr,"%s: spool %d->%d=%d\n",pgmname,netfd,ptyfd,*conspid));
X if ((*prodpid=fork())<0)
X fatal(*prodpid,"spool producer fork failed",LPD_ABORT);
X if (!*prodpid)
X {
X rc=process(ptyfd,netfd);
X /*
X ** Release fds now that producer is complete.
X */
X close(ptyfd);
X close(netfd);
X exit(rc);
X }
X /*
X ** Producer and consumer children own the fds now.
X */
X close(ptyfd);
X close(netfd);
X DPRINTF((stderr,"%s: spool %d->%d=%d\n",pgmname,ptyfd,netfd,*prodpid));
X }
X
X/*
X** Process: copy from input fd to output fd until end of file.
X*/
Xint
Xprocess(infd,outfd)
X {
X int len;
X char buf[BUFFER+1];
X
X do
X if ((len=receive(infd,buf,sizeof(buf)))>0)
X {
X transmit(outfd,buf,len);
X#ifdef DUMP
X if (dumpon)
X {
X buf[len]='\0';
X fputs(buf,stderr);
X }
X#endif
X }
X while (len>0);
X DPRINTF((stderr,"%s: process %d->%d=%d\n",pgmname,infd,outfd,len));
X return(len);
X }
X
X/*
X** Transmit: send a buffer of a given length to a
X** specified file descriptor.
X*/
Xvoid
Xtransmit(fd,buf,len)
Xint fd,len;
Xchar *buf;
X {
X int count;
X
X while (len>0)
X if ((count=write(fd,buf,len))<0)
X {
X if (errno!=EWOULDBLOCK)
X fatal(count,"transmit write failed",LPD_ABORT);
X }
X else
X {
X buf+=count;
X len-=count;
X }
X }
X
X/*
X** Receive: Receive a specified amount of data from a given
X** file descriptor and place it in the specied buffer.
X*/
Xint
Xreceive(fd,buf,len)
Xint fd,len;
Xchar *buf;
X {
X int count;
X
X if (len<=0)
X return(len);
X if ((count=read(fd,buf,len))<0)
X {
X if (errno!=EWOULDBLOCK)
X fatal(count,"receive read failed",LPD_ABORT);
X }
X else
X if (count>len)
X fatal(count,"receive read overflow",LPD_ABORT);
X return(count);
X }
X
X/*
X** Bailout: handle interrupts while attempting to exit
X** as gracefully and politely as possible.
X*/
Xvoid
Xbailout(rc)
Xint rc;
X {
X switch(rc)
X {
X case 1:
X signal(SIGPIPE,SIG_DFL);
X fatal(rc,"broken pipe",LPD_ABORT);
X break;
X case 2:
X signal(SIGINT,SIG_DFL);
X fatal(rc,"aborted",LPD_ABORT);
X break;
X default:
X fatal(rc,"unknown signal",LPD_ABORT);
X }
X }
X
X/*
X** Fatal: Prints the system error message, prints a user
X** error message, and exits with the specified code.
X*/
Xvoid
Xfatal(rc,msg,xit)
Xint rc,xit;
Xchar *msg;
X {
X /*
X ** Naively assume that if rc<=0, it's a system call
X ** return, and perror is valid; otherwise, perror is
X ** misleading.
X */
X if (rc<=0)
X perror("annexf");
X fprintf(stderr,"%s: %s (%d)\n",pgmname,msg,rc);
X cleanup();
X exit(xit);
X }
X
X/*
X** Usage: check argc, and report usage error.
X*/
Xvoid
Xusage(argc)
Xint argc;
X {
X if (argc <= 0)
X {
X fprintf(stderr,"usage: %s [-v] [-x] [[-h host [-p port]]|[-d device]] [-t pty tty] [-f filter [args]]\n",pgmname);
X cleanup();
X exit(LPD_ABORT);
X }
X }
X
X/*
X** Lost: Interrupt service routine which is invoked when
X** a pipe breaks and a connection is lost.
X*/
Xvoid
Xlost()
X {
X longjmp(context,1);
X }
X
X/*
X** Interrupted: Interrupt service routine which is invoked
X** when a interrupt signal is received from another process
X** (typically the line printer spooler daemon).
X*/
Xvoid
Xinterrupted()
X {
X longjmp(context,2);
X }
X
X/*
X** Finished: Interrupt service routine which is invoked
X** when the parent receives end of file and signals the
X** child process to terminate.
X*/
Xvoid
Xfinished()
X {
X longjmp(context,3);
X }
X
X#ifdef DEBUG
X/*
X** Pargs: prints argc and argv argument lists for debugging.
X*/
Xvoid
Xpargs(argc,argv)
Xint argc;
Xchar **argv;
X {
X int nargc;
X
X fprintf(stderr,"%s:",pgmname);
X for (nargc=0;argc>0;argc--,nargc++,argv++)
X {
X putc(' ',stderr);
X fputs(*argv,stderr);
X }
X putc('\n',stderr);
X }
X#endif
SHAR_EOF
if test 16356 -ne "`wc -c < 'servercomm.c'`"
then
echo shar: error transmitting "'servercomm.c'" '(should have been 16356 characters)'
fi
fi # end of overwriting check
# End of shell archive
exit 0
More information about the Comp.sources.misc
mailing list