xref: /onnv-gate/usr/src/cmd/bnu/fio.c (revision 728:fc30a8886345)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*728Sceastha  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  *
310Sstevel@tonic-gate  * flow control protocol.
320Sstevel@tonic-gate  *
330Sstevel@tonic-gate  * This protocol relies on flow control of the data stream.
340Sstevel@tonic-gate  * It is meant for working over links that can (almost) be
350Sstevel@tonic-gate  * guaranteed to be errorfree, specifically X.25/PAD links.
360Sstevel@tonic-gate  * A sumcheck is carried out over a whole file only. If a
370Sstevel@tonic-gate  * transport fails the receiver can request retransmission(s).
380Sstevel@tonic-gate  * This protocol uses a 7-bit datapath only, so it can be
390Sstevel@tonic-gate  * used on links that are not 8-bit transparent.
400Sstevel@tonic-gate  *
410Sstevel@tonic-gate  * When using this protocol with an X.25 PAD:
420Sstevel@tonic-gate  * Although this protocol uses no control chars except CR,
430Sstevel@tonic-gate  * control chars NULL and ^P are used before this protocol
440Sstevel@tonic-gate  * is started; since ^P is the default char for accessing
450Sstevel@tonic-gate  * PAD X.28 command mode, be sure to disable that access
460Sstevel@tonic-gate  * (PAD par 1). Also make sure both flow control pars
470Sstevel@tonic-gate  * (5 and 12) are set. The CR used in this proto is meant
480Sstevel@tonic-gate  * to trigger packet transmission, hence par 3 should be
490Sstevel@tonic-gate  * set to 2; a good value for the Idle Timer (par 4) is 10.
500Sstevel@tonic-gate  * All other pars should be set to 0.
510Sstevel@tonic-gate  *
520Sstevel@tonic-gate  * Normally a calling site will take care of setting the
530Sstevel@tonic-gate  * local PAD pars via an X.28 command and those of the remote
540Sstevel@tonic-gate  * PAD via an X.29 command, unless the remote site has a
550Sstevel@tonic-gate  * special channel assigned for this protocol with the proper
560Sstevel@tonic-gate  * par settings.
570Sstevel@tonic-gate  *
580Sstevel@tonic-gate  * Additional comments for hosts with direct X.25 access:
590Sstevel@tonic-gate  * - the global variable IsTcpIp, when set, excludes the ioctl's,
600Sstevel@tonic-gate  *   so the same binary can run on X.25 and non-X.25 hosts;
610Sstevel@tonic-gate  * - reads are done in small chunks, which can be smaller than
620Sstevel@tonic-gate  *   the packet size; your X.25 driver must support that.
630Sstevel@tonic-gate  *
640Sstevel@tonic-gate  *
650Sstevel@tonic-gate  * Author:
660Sstevel@tonic-gate  *	Piet Beertema, CWI, Amsterdam, Sep 1984
670Sstevel@tonic-gate  * Modified for X.25 hosts:
680Sstevel@tonic-gate  *	Robert Elz, Melbourne Univ, Mar 1985
690Sstevel@tonic-gate  */
700Sstevel@tonic-gate 
710Sstevel@tonic-gate #include "uucp.h"
720Sstevel@tonic-gate #ifdef F_PROTOCOL
730Sstevel@tonic-gate 
740Sstevel@tonic-gate extern unsigned msgtime;
750Sstevel@tonic-gate 
760Sstevel@tonic-gate /* privates */
770Sstevel@tonic-gate static int frdblk(), fwrblk();
780Sstevel@tonic-gate 
790Sstevel@tonic-gate #define FIBUFSIZ	4096	/* for X.25 interfaces: set equal to packet size,
800Sstevel@tonic-gate 				 * but see comment above
810Sstevel@tonic-gate 				 */
820Sstevel@tonic-gate 
830Sstevel@tonic-gate #define FOBUFSIZ	4096	/* for X.25 interfaces: set equal to packet size;
840Sstevel@tonic-gate 				 * otherwise make as large as feasible to reduce
850Sstevel@tonic-gate 				 * number of write system calls
860Sstevel@tonic-gate 				 */
870Sstevel@tonic-gate 
880Sstevel@tonic-gate #ifndef MAXMSGLEN
890Sstevel@tonic-gate #define MAXMSGLEN	BUFSIZ
90*728Sceastha #endif	/* MAXMSGLEN */
910Sstevel@tonic-gate 
920Sstevel@tonic-gate static int fchksum;
930Sstevel@tonic-gate static jmp_buf Ffailbuf;
940Sstevel@tonic-gate 
950Sstevel@tonic-gate /* ARGSUSED */
960Sstevel@tonic-gate static void
falarm(sig)970Sstevel@tonic-gate falarm(sig)
980Sstevel@tonic-gate 	int sig;
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate 	signal(SIGALRM, falarm);
1010Sstevel@tonic-gate 	longjmp(Ffailbuf, 1);
1020Sstevel@tonic-gate }
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate static void (*fsig)();
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate static int ioctlok;
1070Sstevel@tonic-gate #ifdef ATTSVTTY
1080Sstevel@tonic-gate static struct termio ttbuf;
1090Sstevel@tonic-gate #else
1100Sstevel@tonic-gate static struct sgttyb ttbuf;
1110Sstevel@tonic-gate #endif
1120Sstevel@tonic-gate 
113*728Sceastha int
fturnon(void)114*728Sceastha fturnon(void)
1150Sstevel@tonic-gate {
1160Sstevel@tonic-gate 	int ret;
1170Sstevel@tonic-gate #ifdef ATTSVTTY
1180Sstevel@tonic-gate 	struct termio save_ttbuf;
1190Sstevel@tonic-gate #else
1200Sstevel@tonic-gate 	struct sgttyb save_ttbuf;
1210Sstevel@tonic-gate #endif
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate #ifdef ATTSVTTY
1240Sstevel@tonic-gate 	if (ioctl(Ifn, TCGETA, &ttbuf) >= 0) {
1250Sstevel@tonic-gate 		ioctlok = 1;
1260Sstevel@tonic-gate 		save_ttbuf = ttbuf;
1270Sstevel@tonic-gate 		ioctl(Ifn, TCGETA, &ttbuf);
1280Sstevel@tonic-gate 		ttbuf.c_iflag = IXOFF|IXON|ISTRIP;
1290Sstevel@tonic-gate 		ttbuf.c_cc[VMIN] = FIBUFSIZ > 64 ? 64 : FIBUFSIZ;
1300Sstevel@tonic-gate 		ttbuf.c_cc[VTIME] = 5;
1310Sstevel@tonic-gate 		ret = ioctl(Ifn, TCSETA, &ttbuf);
1320Sstevel@tonic-gate 		ASSERT(ret >= 0, "STTY FAILED", "", ret);
1330Sstevel@tonic-gate 		ttbuf = save_ttbuf;
1340Sstevel@tonic-gate 	}
1350Sstevel@tonic-gate #else /* !ATTSVTTY */
1360Sstevel@tonic-gate 	if (ioctl(Ifn, TIOCGETP, &ttbuf) >= 0) {
1370Sstevel@tonic-gate 		ioctlok = 1;
1380Sstevel@tonic-gate 		save_ttbuf = ttbuf;
1390Sstevel@tonic-gate 		ttbuf.sg_flags = ANYP|CBREAK|TANDEM;
1400Sstevel@tonic-gate 		ret = ioctl(Ifn, TIOCSETP, &ttbuf);
1410Sstevel@tonic-gate 		ASSERT(ret >= 0, "STTY FAILED", "", ret);
1420Sstevel@tonic-gate 		ttbuf = save_ttbuf;
1430Sstevel@tonic-gate 	}
1440Sstevel@tonic-gate #endif /* ATTSVTTY */
1450Sstevel@tonic-gate 	fsig = signal(SIGALRM, falarm);
1460Sstevel@tonic-gate 	/* give the other side time to perform its ioctl;
1470Sstevel@tonic-gate 	 * otherwise it may flush out the first data this
1480Sstevel@tonic-gate 	 * side is about to send.
1490Sstevel@tonic-gate 	 */
1500Sstevel@tonic-gate 	sleep(2);
1510Sstevel@tonic-gate 	return SUCCESS;
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate 
154*728Sceastha int
fturnoff(void)155*728Sceastha fturnoff(void)
1560Sstevel@tonic-gate {
1570Sstevel@tonic-gate 	if (ioctlok) {
1580Sstevel@tonic-gate #ifdef ATTSVTTY
1590Sstevel@tonic-gate 		(void) ioctl(Ifn, TCSETA, &ttbuf);
1600Sstevel@tonic-gate #else
1610Sstevel@tonic-gate 		(void) ioctl(Ifn, TIOCSETP, &ttbuf);
1620Sstevel@tonic-gate #endif
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 	(void) signal(SIGALRM, fsig);
1650Sstevel@tonic-gate 	sleep(2);
1660Sstevel@tonic-gate 	return SUCCESS;
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate 
169*728Sceastha int
fwrmsg(type,str,fn)1700Sstevel@tonic-gate fwrmsg(type, str, fn)
171*728Sceastha char *str;
1720Sstevel@tonic-gate int fn;
1730Sstevel@tonic-gate char type;
1740Sstevel@tonic-gate {
175*728Sceastha 	char *s;
1760Sstevel@tonic-gate 	char bufr[MAXMSGLEN];
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	s = bufr;
1790Sstevel@tonic-gate 	*s++ = type;
1800Sstevel@tonic-gate 	while (*str)
1810Sstevel@tonic-gate 		*s++ = *str++;
1820Sstevel@tonic-gate 	if (*(s-1) == '\n')
1830Sstevel@tonic-gate 		s--;
1840Sstevel@tonic-gate 	*s++ = '\r';
1850Sstevel@tonic-gate 	*s = 0;
1860Sstevel@tonic-gate 	(void) write(fn, bufr, s - bufr);
1870Sstevel@tonic-gate 	return SUCCESS;
1880Sstevel@tonic-gate }
1890Sstevel@tonic-gate 
190*728Sceastha int
frdmsg(str,fn)1910Sstevel@tonic-gate frdmsg(str, fn)
192*728Sceastha char *str;
193*728Sceastha int fn;
1940Sstevel@tonic-gate {
195*728Sceastha 	char *smax;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	if (setjmp(Ffailbuf))
1980Sstevel@tonic-gate 		return FAIL;
1990Sstevel@tonic-gate 	smax = str + MAXMSGLEN - 1;
2000Sstevel@tonic-gate 	(void) alarm(msgtime);
2010Sstevel@tonic-gate 	for (;;) {
2020Sstevel@tonic-gate 		if (read(fn, str, 1) <= 0)
2030Sstevel@tonic-gate 			goto msgerr;
2040Sstevel@tonic-gate 		*str &= 0177;
2050Sstevel@tonic-gate 		if (*str == '\r')
2060Sstevel@tonic-gate 			break;
2070Sstevel@tonic-gate 		if (*str < ' ') {
2080Sstevel@tonic-gate 			continue;
2090Sstevel@tonic-gate 		}
2100Sstevel@tonic-gate 		if (str++ >= smax)
2110Sstevel@tonic-gate 			goto msgerr;
2120Sstevel@tonic-gate 	}
2130Sstevel@tonic-gate 	*str = '\0';
2140Sstevel@tonic-gate 	(void) alarm(0);
2150Sstevel@tonic-gate 	return SUCCESS;
2160Sstevel@tonic-gate msgerr:
2170Sstevel@tonic-gate 	(void) alarm(0);
2180Sstevel@tonic-gate 	return FAIL;
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate 
221*728Sceastha int
fwrdata(fp1,fn)2220Sstevel@tonic-gate fwrdata(fp1, fn)
2230Sstevel@tonic-gate FILE *fp1;
2240Sstevel@tonic-gate int fn;
2250Sstevel@tonic-gate {
226*728Sceastha 	int alen, ret;
2270Sstevel@tonic-gate 	char ack, ibuf[MAXMSGLEN];
2280Sstevel@tonic-gate 	int flen, retries = 0;
2290Sstevel@tonic-gate 	long fbytes;
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	ret = FAIL;
2320Sstevel@tonic-gate retry:
2330Sstevel@tonic-gate 	fchksum = 0xffff;
2340Sstevel@tonic-gate 	fbytes = 0L;
2350Sstevel@tonic-gate 	ack = '\0';
2360Sstevel@tonic-gate 	do {
2370Sstevel@tonic-gate 		alen = fwrblk(fn, fp1, &flen);
2380Sstevel@tonic-gate 		fbytes += flen;
2390Sstevel@tonic-gate 		if (alen <= 0) {
2400Sstevel@tonic-gate 			goto acct;
2410Sstevel@tonic-gate 		}
2420Sstevel@tonic-gate 	} while (!feof(fp1) && !ferror(fp1));
2430Sstevel@tonic-gate 	DEBUG(8, "\nchecksum: %04x\n", fchksum);
2440Sstevel@tonic-gate 	if (frdmsg(ibuf, fn) != FAIL) {
2450Sstevel@tonic-gate 		if ((ack = ibuf[0]) == 'G')
2460Sstevel@tonic-gate 			ret = SUCCESS;
2470Sstevel@tonic-gate 		DEBUG(4, "ack - '%c'\n", ack);
2480Sstevel@tonic-gate 	}
2490Sstevel@tonic-gate acct:
2500Sstevel@tonic-gate 	DEBUG(7, "%d retries\n", retries);
2510Sstevel@tonic-gate 	if (ack == 'R') {
2520Sstevel@tonic-gate 		DEBUG(4, "RETRY:\n", 0);
2530Sstevel@tonic-gate 		fseek(fp1, 0L, 0);
2540Sstevel@tonic-gate 		retries++;
2550Sstevel@tonic-gate 		goto retry;
2560Sstevel@tonic-gate 	}
2570Sstevel@tonic-gate 	return ret;
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate /* max. attempts to retransmit a file: */
2610Sstevel@tonic-gate #define MAXRETRIES	(fbytes < 10000L ? 2 : 1)
2620Sstevel@tonic-gate 
263*728Sceastha int
frddata(fn,fp2)2640Sstevel@tonic-gate frddata(fn, fp2)
265*728Sceastha int fn;
266*728Sceastha FILE *fp2;
2670Sstevel@tonic-gate {
268*728Sceastha 	int flen;
269*728Sceastha 	char eof;
2700Sstevel@tonic-gate 	char ibuf[FIBUFSIZ];
2710Sstevel@tonic-gate 	int ret, retries = 0;
2720Sstevel@tonic-gate 	long alen, fbytes;
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	ret = FAIL;
2750Sstevel@tonic-gate retry:
2760Sstevel@tonic-gate 	fchksum = 0xffff;
2770Sstevel@tonic-gate 	fbytes = 0L;
2780Sstevel@tonic-gate 	do {
2790Sstevel@tonic-gate 		flen = frdblk(ibuf, fn, &alen);
2800Sstevel@tonic-gate 		if (flen < 0)
2810Sstevel@tonic-gate 			goto acct;
2820Sstevel@tonic-gate 		if (eof = flen > FIBUFSIZ)
2830Sstevel@tonic-gate 			flen -= FIBUFSIZ + 1;
2840Sstevel@tonic-gate 		fbytes += flen;
2850Sstevel@tonic-gate 		if (fwrite(ibuf, sizeof (char), flen, fp2) != flen)
2860Sstevel@tonic-gate 			goto acct;
2870Sstevel@tonic-gate 	} while (!eof);
2880Sstevel@tonic-gate 	ret = SUCCESS;
2890Sstevel@tonic-gate acct:
2900Sstevel@tonic-gate 	DEBUG(7, "%d retries\n", retries);
2910Sstevel@tonic-gate 	if (ret == FAIL) {
2920Sstevel@tonic-gate 		if (retries++ < MAXRETRIES) {
2930Sstevel@tonic-gate 			DEBUG(8, "send ack: 'R'\n", 0);
2940Sstevel@tonic-gate 			fwrmsg('R', "", fn);
2950Sstevel@tonic-gate 			fseek(fp2, 0L, 0);
2960Sstevel@tonic-gate 			DEBUG(4, "RETRY:\n", 0);
2970Sstevel@tonic-gate 			goto retry;
2980Sstevel@tonic-gate 		}
2990Sstevel@tonic-gate 		DEBUG(8, "send ack: 'Q'\n", 0);
3000Sstevel@tonic-gate 		fwrmsg('Q', "", fn);
3010Sstevel@tonic-gate 	}
3020Sstevel@tonic-gate 	else {
3030Sstevel@tonic-gate 		DEBUG(8, "send ack: 'G'\n", 0);
3040Sstevel@tonic-gate 		fwrmsg('G', "", fn);
3050Sstevel@tonic-gate 	}
3060Sstevel@tonic-gate 	return ret;
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate 
309*728Sceastha static int
frdbuf(blk,len,fn)3100Sstevel@tonic-gate frdbuf(blk, len, fn)
311*728Sceastha char *blk;
312*728Sceastha int len;
313*728Sceastha int fn;
3140Sstevel@tonic-gate {
3150Sstevel@tonic-gate 	static int ret = FIBUFSIZ / 2;
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	if (setjmp(Ffailbuf))
3180Sstevel@tonic-gate 		return FAIL;
3190Sstevel@tonic-gate 	(void) alarm(msgtime);
3200Sstevel@tonic-gate 	ret = read(fn, blk, len);
3210Sstevel@tonic-gate 	alarm(0);
3220Sstevel@tonic-gate 	return ret <= 0 ? FAIL : ret;
3230Sstevel@tonic-gate }
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate #if !defined(ATTSVKILL)
3260Sstevel@tonic-gate /* call ultouch every TC calls to either frdblk or fwrblk  */
3270Sstevel@tonic-gate #define TC	20
3280Sstevel@tonic-gate static int tc = TC;
329*728Sceastha #endif	/* !defined(ATTSVKILL) */
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate /* Byte conversion:
3320Sstevel@tonic-gate  *
3330Sstevel@tonic-gate  *   from	 pre	   to
3340Sstevel@tonic-gate  * 000-037	 172	 100-137
3350Sstevel@tonic-gate  * 040-171		 040-171
3360Sstevel@tonic-gate  * 172-177	 173	 072-077
3370Sstevel@tonic-gate  * 200-237	 174	 100-137
3380Sstevel@tonic-gate  * 240-371	 175	 040-171
3390Sstevel@tonic-gate  * 372-377	 176	 072-077
3400Sstevel@tonic-gate  */
3410Sstevel@tonic-gate 
342*728Sceastha static int
fwrblk(fn,fp,lenp)3430Sstevel@tonic-gate fwrblk(fn, fp, lenp)
3440Sstevel@tonic-gate int fn;
345*728Sceastha FILE *fp;
3460Sstevel@tonic-gate int *lenp;
3470Sstevel@tonic-gate {
348*728Sceastha 	char *op;
349*728Sceastha 	int c, sum, nl, len;
3500Sstevel@tonic-gate 	char obuf[FOBUFSIZ + 8];
3510Sstevel@tonic-gate 	int ret;
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate #if !defined(ATTSVKILL)
3540Sstevel@tonic-gate 	/* call ultouch occasionally */
3550Sstevel@tonic-gate 	if (--tc < 0) {
3560Sstevel@tonic-gate 		tc = TC;
3570Sstevel@tonic-gate 		ultouch();
3580Sstevel@tonic-gate 	}
3590Sstevel@tonic-gate #endif /*!defined(ATTSVKILL)*/
3600Sstevel@tonic-gate 	op = obuf;
3610Sstevel@tonic-gate 	nl = 0;
3620Sstevel@tonic-gate 	len = 0;
3630Sstevel@tonic-gate 	sum = fchksum;
3640Sstevel@tonic-gate 	while ((c = getc(fp)) != EOF) {
3650Sstevel@tonic-gate 		len++;
3660Sstevel@tonic-gate 		if (sum & 0x8000) {
3670Sstevel@tonic-gate 			sum <<= 1;
3680Sstevel@tonic-gate 			sum++;
3690Sstevel@tonic-gate 		} else
3700Sstevel@tonic-gate 			sum <<= 1;
3710Sstevel@tonic-gate 		sum += c;
3720Sstevel@tonic-gate 		sum &= 0xffff;
3730Sstevel@tonic-gate 		if (c & 0200) {
3740Sstevel@tonic-gate 			c &= 0177;
3750Sstevel@tonic-gate 			if (c < 040) {
3760Sstevel@tonic-gate 				*op++ = '\174';
3770Sstevel@tonic-gate 				*op++ = c + 0100;
3780Sstevel@tonic-gate 			} else
3790Sstevel@tonic-gate 			if (c <= 0171) {
3800Sstevel@tonic-gate 				*op++ = '\175';
3810Sstevel@tonic-gate 				*op++ = c;
3820Sstevel@tonic-gate 			}
3830Sstevel@tonic-gate 			else {
3840Sstevel@tonic-gate 				*op++ = '\176';
3850Sstevel@tonic-gate 				*op++ = c - 0100;
3860Sstevel@tonic-gate 			}
3870Sstevel@tonic-gate 			nl += 2;
3880Sstevel@tonic-gate 		} else {
3890Sstevel@tonic-gate 			if (c < 040) {
3900Sstevel@tonic-gate 				*op++ = '\172';
3910Sstevel@tonic-gate 				*op++ = c + 0100;
3920Sstevel@tonic-gate 				nl += 2;
3930Sstevel@tonic-gate 			} else
3940Sstevel@tonic-gate 			if (c <= 0171) {
3950Sstevel@tonic-gate 				*op++ = c;
3960Sstevel@tonic-gate 				nl++;
3970Sstevel@tonic-gate 			} else {
3980Sstevel@tonic-gate 				*op++ = '\173';
3990Sstevel@tonic-gate 				*op++ = c - 0100;
4000Sstevel@tonic-gate 				nl += 2;
4010Sstevel@tonic-gate 			}
4020Sstevel@tonic-gate 		}
4030Sstevel@tonic-gate 		if (nl >= FOBUFSIZ - 1) {
4040Sstevel@tonic-gate 			/*
4050Sstevel@tonic-gate 			 * peek at next char, see if it will fit
4060Sstevel@tonic-gate 			 */
4070Sstevel@tonic-gate 			c = getc(fp);
4080Sstevel@tonic-gate 			if (c == EOF)
4090Sstevel@tonic-gate 				break;
4100Sstevel@tonic-gate 			(void) ungetc(c, fp);
4110Sstevel@tonic-gate 			if (nl >= FOBUFSIZ || c < 040 || c > 0171)
4120Sstevel@tonic-gate 				goto writeit;
4130Sstevel@tonic-gate 		}
4140Sstevel@tonic-gate 	}
4150Sstevel@tonic-gate 	/*
4160Sstevel@tonic-gate 	 * At EOF - append checksum, there is space for it...
4170Sstevel@tonic-gate 	 */
4180Sstevel@tonic-gate 	sprintf(op, "\176\176%04x\r", sum);
4190Sstevel@tonic-gate 	nl += strlen(op);
4200Sstevel@tonic-gate writeit:
4210Sstevel@tonic-gate 	*lenp = len;
4220Sstevel@tonic-gate 	fchksum = sum;
4230Sstevel@tonic-gate 	DEBUG(8, "%d/", len);
4240Sstevel@tonic-gate 	DEBUG(8, "%d,", nl);
4250Sstevel@tonic-gate 	ret = write(fn, obuf, nl);
4260Sstevel@tonic-gate 	return ret == nl ? nl : ret < 0 ? 0 : -ret;
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate 
429*728Sceastha static int
frdblk(ip,fn,rlen)4300Sstevel@tonic-gate frdblk(ip, fn, rlen)
431*728Sceastha char *ip;
4320Sstevel@tonic-gate int fn;
4330Sstevel@tonic-gate long *rlen;
4340Sstevel@tonic-gate {
435*728Sceastha 	char *op, c;
436*728Sceastha 	int sum, len, nl;
4370Sstevel@tonic-gate 	char buf[5], *erbp = ip;
4380Sstevel@tonic-gate 	int i;
4390Sstevel@tonic-gate 	static char special = 0;
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate #if !defined(ATTSVKILL)
4420Sstevel@tonic-gate 	/* call ultouch occasionally */
4430Sstevel@tonic-gate 	if (--tc < 0) {
4440Sstevel@tonic-gate 		tc = TC;
4450Sstevel@tonic-gate 		ultouch();
4460Sstevel@tonic-gate 	}
4470Sstevel@tonic-gate #endif /*!defined(ATTSVKILL)*/
4480Sstevel@tonic-gate 	if ((len = frdbuf(ip, FIBUFSIZ, fn)) == FAIL) {
4490Sstevel@tonic-gate 		*rlen = 0;
4500Sstevel@tonic-gate 		goto dcorr;
4510Sstevel@tonic-gate 	}
4520Sstevel@tonic-gate 	*rlen = len;
4530Sstevel@tonic-gate 	DEBUG(8, "%d/", len);
4540Sstevel@tonic-gate 	op = ip;
4550Sstevel@tonic-gate 	nl = 0;
4560Sstevel@tonic-gate 	sum = fchksum;
4570Sstevel@tonic-gate 	do {
4580Sstevel@tonic-gate 		if ((*ip &= 0177) >= '\172') {
4590Sstevel@tonic-gate 			if (special) {
4600Sstevel@tonic-gate 				DEBUG(8, "%d", nl);
4610Sstevel@tonic-gate 				special = 0;
4620Sstevel@tonic-gate 				op = buf;
4630Sstevel@tonic-gate 				if (*ip++ != '\176' || (i = --len) > 5)
4640Sstevel@tonic-gate 					goto dcorr;
4650Sstevel@tonic-gate 				while (i--)
4660Sstevel@tonic-gate 					*op++ = *ip++ & 0177;
4670Sstevel@tonic-gate 				while (len < 5) {
4680Sstevel@tonic-gate 					i = frdbuf(&buf[len], 5 - len, fn);
4690Sstevel@tonic-gate 					if (i == FAIL) {
4700Sstevel@tonic-gate 						len = FAIL;
4710Sstevel@tonic-gate 						goto dcorr;
4720Sstevel@tonic-gate 					}
4730Sstevel@tonic-gate 					DEBUG(8, ",%d", i);
4740Sstevel@tonic-gate 					len += i;
4750Sstevel@tonic-gate 					*rlen += i;
4760Sstevel@tonic-gate 					while (i--)
4770Sstevel@tonic-gate 						*op++ &= 0177;
4780Sstevel@tonic-gate 				}
4790Sstevel@tonic-gate 				if (buf[4] != '\r')
4800Sstevel@tonic-gate 					goto dcorr;
4810Sstevel@tonic-gate 				sscanf(buf, "%4x", &fchksum);
4820Sstevel@tonic-gate 				DEBUG(8, "\nchecksum: %04x\n", sum);
4830Sstevel@tonic-gate 				if (fchksum == sum)
4840Sstevel@tonic-gate 					return FIBUFSIZ + 1 + nl;
4850Sstevel@tonic-gate 				else {
4860Sstevel@tonic-gate 					DEBUG(8, "\n", 0);
4870Sstevel@tonic-gate 					DEBUG(4, "Bad checksum\n", 0);
4880Sstevel@tonic-gate 					return FAIL;
4890Sstevel@tonic-gate 				}
4900Sstevel@tonic-gate 			}
4910Sstevel@tonic-gate 			special = *ip++;
4920Sstevel@tonic-gate 		} else {
4930Sstevel@tonic-gate 			if (*ip < '\040') {
4940Sstevel@tonic-gate 				/* error: shouldn't get control chars */
4950Sstevel@tonic-gate 				goto dcorr;
4960Sstevel@tonic-gate 			}
4970Sstevel@tonic-gate 			switch (special) {
4980Sstevel@tonic-gate 			case 0:
4990Sstevel@tonic-gate 				c = *ip++;
5000Sstevel@tonic-gate 				break;
5010Sstevel@tonic-gate 			case '\172':
5020Sstevel@tonic-gate 				c = *ip++ - 0100;
5030Sstevel@tonic-gate 				break;
5040Sstevel@tonic-gate 			case '\173':
5050Sstevel@tonic-gate 				c = *ip++ + 0100;
5060Sstevel@tonic-gate 				break;
5070Sstevel@tonic-gate 			case '\174':
5080Sstevel@tonic-gate 				c = *ip++ + 0100;
5090Sstevel@tonic-gate 				break;
5100Sstevel@tonic-gate 			case '\175':
5110Sstevel@tonic-gate 				c = *ip++ + 0200;
5120Sstevel@tonic-gate 				break;
5130Sstevel@tonic-gate 			case '\176':
5140Sstevel@tonic-gate 				c = *ip++ + 0300;
5150Sstevel@tonic-gate 				break;
5160Sstevel@tonic-gate 			}
5170Sstevel@tonic-gate 			*op++ = c;
5180Sstevel@tonic-gate 			if (sum & 0x8000) {
5190Sstevel@tonic-gate 				sum <<= 1;
5200Sstevel@tonic-gate 				sum++;
5210Sstevel@tonic-gate 			} else
5220Sstevel@tonic-gate 				sum <<= 1;
5230Sstevel@tonic-gate 			sum += c & 0377;
5240Sstevel@tonic-gate 			sum &= 0xffff;
5250Sstevel@tonic-gate 			special = 0;
5260Sstevel@tonic-gate 			nl++;
5270Sstevel@tonic-gate 		}
5280Sstevel@tonic-gate 	} while (--len);
5290Sstevel@tonic-gate 	fchksum = sum;
5300Sstevel@tonic-gate 	DEBUG(8, "%d,", nl);
5310Sstevel@tonic-gate 	return nl;
5320Sstevel@tonic-gate dcorr:
5330Sstevel@tonic-gate 	DEBUG(8, "\n", 0);
5340Sstevel@tonic-gate 	DEBUG(4, "Data corrupted\n", 0);
5350Sstevel@tonic-gate 	while (len != FAIL) {
5360Sstevel@tonic-gate 		if ((len = frdbuf(erbp, FIBUFSIZ, fn)) != FAIL)
5370Sstevel@tonic-gate 			*rlen += len;
5380Sstevel@tonic-gate 	}
5390Sstevel@tonic-gate 	return FAIL;
5400Sstevel@tonic-gate }
5410Sstevel@tonic-gate #endif /* F_PROTOCOL */
542