xref: /illumos-gate/usr/src/cmd/lp/lib/msgs/read_fifo.c (revision 2a8bcb4e)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23f928ce67Sceastha  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
287c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /* LINTLIBRARY */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate # include	<errno.h>
337c478bd9Sstevel@tonic-gate # include	<string.h>
347c478bd9Sstevel@tonic-gate #include <syslog.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate # include	"lp.h"
377c478bd9Sstevel@tonic-gate # include	"msgs.h"
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate extern char	Resync[];
407c478bd9Sstevel@tonic-gate extern char	Endsync[];
417c478bd9Sstevel@tonic-gate static int	Had_Full_Buffer = 1;
427c478bd9Sstevel@tonic-gate int		Garbage_Bytes	= 0;
437c478bd9Sstevel@tonic-gate int		Garbage_Messages= 0;
447c478bd9Sstevel@tonic-gate 
45f928ce67Sceastha static int _buffer(int);
46f928ce67Sceastha 
477c478bd9Sstevel@tonic-gate /*
487c478bd9Sstevel@tonic-gate ** A real message is written in one piece, and the write
497c478bd9Sstevel@tonic-gate ** is atomic. Thus, even if the O_NDELAY flag is set,
507c478bd9Sstevel@tonic-gate ** if we read part of the real message, we can continue
517c478bd9Sstevel@tonic-gate ** to read the rest of it in as many steps as we want
527c478bd9Sstevel@tonic-gate ** (up to the size of the message, of course!) without
537c478bd9Sstevel@tonic-gate ** UNIX returning 0 because no data is available.
547c478bd9Sstevel@tonic-gate ** So, a real message doesn't have to be read in one piece,
557c478bd9Sstevel@tonic-gate ** which is good since we don't know how much to read!
567c478bd9Sstevel@tonic-gate **
577c478bd9Sstevel@tonic-gate ** Fake messages, or improperly written messages, don't
587c478bd9Sstevel@tonic-gate ** have this nice property.
597c478bd9Sstevel@tonic-gate **
607c478bd9Sstevel@tonic-gate ** INTERRUPTED READS:
617c478bd9Sstevel@tonic-gate **
627c478bd9Sstevel@tonic-gate ** If a signal occurs during an attempted read, we can exit.
637c478bd9Sstevel@tonic-gate ** The caller can retry the read and we will correctly restart
647c478bd9Sstevel@tonic-gate ** it. The correctness of this assertion can be seen by noticing
657c478bd9Sstevel@tonic-gate ** that at the beginning of each READ below, we can go back
667c478bd9Sstevel@tonic-gate ** to the first statement executed (the first READ below)
677c478bd9Sstevel@tonic-gate ** and correctly reexecute the code.
687c478bd9Sstevel@tonic-gate **
697c478bd9Sstevel@tonic-gate ** If the last writer closed the fifo, we'll read 0 bytes
707c478bd9Sstevel@tonic-gate ** (at least on the subsequent read). If we were in the
717c478bd9Sstevel@tonic-gate ** middle of reading a message, we were reading a bogus
727c478bd9Sstevel@tonic-gate ** message (but see below).
737c478bd9Sstevel@tonic-gate **
747c478bd9Sstevel@tonic-gate ** If we read less than we expect, it's because we were
757c478bd9Sstevel@tonic-gate ** reading a fake message (but see below).
767c478bd9Sstevel@tonic-gate **
777c478bd9Sstevel@tonic-gate ** HOWEVER: In the last two cases, we may have ONE OR MORE
787c478bd9Sstevel@tonic-gate ** REAL MESSAGES snuggled in amongst the trash!
797c478bd9Sstevel@tonic-gate **
807c478bd9Sstevel@tonic-gate ** All this verbal rambling is preface to let you understand why we
817c478bd9Sstevel@tonic-gate ** buffer the data (which is a shame, but necessary).
827c478bd9Sstevel@tonic-gate */
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate ** As long as we get real messages, we can avoid needless function calls.
867c478bd9Sstevel@tonic-gate ** The SYNC argument in this macro should be set if the resynch. bytes
877c478bd9Sstevel@tonic-gate ** have been read--i.e. if the rest of the message is trying to be read.
887c478bd9Sstevel@tonic-gate ** In this case, if we had not read a full buffer last time, then we
897c478bd9Sstevel@tonic-gate ** must be in the middle of a bogus message.
907c478bd9Sstevel@tonic-gate */
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate #define UNSYNCHED_READ(N) \
937c478bd9Sstevel@tonic-gate     if (fbp->psave_end - fbp->psave < N || fbp->psave >= fbp->psave_end) \
947c478bd9Sstevel@tonic-gate     { \
957c478bd9Sstevel@tonic-gate 	switch (_buffer(fifo)) \
967c478bd9Sstevel@tonic-gate 	{ \
977c478bd9Sstevel@tonic-gate 	    case -1: \
987c478bd9Sstevel@tonic-gate 		return (-1); \
997c478bd9Sstevel@tonic-gate 	    case 0: \
1007c478bd9Sstevel@tonic-gate 		if (fbp->psave_end > fbp->psave) \
1017c478bd9Sstevel@tonic-gate 		    goto SyncUp; \
1027c478bd9Sstevel@tonic-gate 		return (0); \
1037c478bd9Sstevel@tonic-gate 	} \
1047c478bd9Sstevel@tonic-gate     }
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate #define SYNCHED_READ(N) \
1077c478bd9Sstevel@tonic-gate     if (fbp->psave_end - fbp->psave < N || fbp->psave >= fbp->psave_end) \
1087c478bd9Sstevel@tonic-gate     { \
1097c478bd9Sstevel@tonic-gate 	switch (_buffer(fifo)) \
1107c478bd9Sstevel@tonic-gate 	{ \
1117c478bd9Sstevel@tonic-gate 	    case -1: \
1127c478bd9Sstevel@tonic-gate 		return (-1); \
1137c478bd9Sstevel@tonic-gate 	    case 0: \
1147c478bd9Sstevel@tonic-gate 		if (fbp->psave_end > fbp->psave) \
1157c478bd9Sstevel@tonic-gate 		    goto SyncUp; \
1167c478bd9Sstevel@tonic-gate 		return (0); \
1177c478bd9Sstevel@tonic-gate 	} \
1187c478bd9Sstevel@tonic-gate 	if (!Had_Full_Buffer) \
1197c478bd9Sstevel@tonic-gate 	    goto SyncUp; \
1207c478bd9Sstevel@tonic-gate     }
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate /*
1237c478bd9Sstevel@tonic-gate ** read_fifo() - READ A BUFFER WITH HEADER AND CHECKSUM
1247c478bd9Sstevel@tonic-gate */
1257c478bd9Sstevel@tonic-gate int
read_fifo(fifo,buf,size)1267c478bd9Sstevel@tonic-gate read_fifo (fifo, buf, size)
1277c478bd9Sstevel@tonic-gate int		fifo;
1287c478bd9Sstevel@tonic-gate char		*buf;
1297c478bd9Sstevel@tonic-gate unsigned int	size;
1307c478bd9Sstevel@tonic-gate {
1317c478bd9Sstevel@tonic-gate     register fifobuffer_t *fbp;
1327c478bd9Sstevel@tonic-gate     register unsigned int real_chksum,
1337c478bd9Sstevel@tonic-gate 			  chksum,
1347c478bd9Sstevel@tonic-gate 			  real_size;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate     /*
1377c478bd9Sstevel@tonic-gate     ** Make sure we start on a message boundary. The first
1387c478bd9Sstevel@tonic-gate     ** line of defense is to look for the resync. bytes.
1397c478bd9Sstevel@tonic-gate     **
1407c478bd9Sstevel@tonic-gate     ** The "SyncUp" label is global to this routine (below this point)
1417c478bd9Sstevel@tonic-gate     ** and is called whenever we determine that we're out
1427c478bd9Sstevel@tonic-gate     ** of sync. with the incoming bytes.
1437c478bd9Sstevel@tonic-gate     */
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate     if (!(fbp=GetFifoBuffer (fifo)))
1467c478bd9Sstevel@tonic-gate 	return	-1;
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate     UNSYNCHED_READ (HEAD_RESYNC_LEN);
1497c478bd9Sstevel@tonic-gate     while (*fbp->psave != Resync[0] || *(fbp->psave + 1) != Resync[1])
1507c478bd9Sstevel@tonic-gate     {
1517c478bd9Sstevel@tonic-gate SyncUp:
1527c478bd9Sstevel@tonic-gate #if	defined(TRACE_MESSAGES)
1537c478bd9Sstevel@tonic-gate 	if (trace_messages)
1547c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG, "DISCARD %c\n", *fbp->psave);
1557c478bd9Sstevel@tonic-gate #endif
1567c478bd9Sstevel@tonic-gate 	fbp->psave++;
1577c478bd9Sstevel@tonic-gate 	Garbage_Bytes++;
1587c478bd9Sstevel@tonic-gate 	UNSYNCHED_READ (HEAD_RESYNC_LEN);
1597c478bd9Sstevel@tonic-gate     }
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate     /*
1637c478bd9Sstevel@tonic-gate     ** We're sync'd, so read the full header.
1647c478bd9Sstevel@tonic-gate     */
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate     SYNCHED_READ (HEAD_LEN);
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate     /*
1707c478bd9Sstevel@tonic-gate     ** If the header size is smaller than the minimum size for a header,
1717c478bd9Sstevel@tonic-gate     ** or larger than allowed, we must assume that we really aren't
1727c478bd9Sstevel@tonic-gate     ** synchronized.
1737c478bd9Sstevel@tonic-gate     */
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate     real_size = stoh(fbp->psave + HEAD_SIZE);
1767c478bd9Sstevel@tonic-gate     if (real_size < CONTROL_LEN || MSGMAX < real_size)
1777c478bd9Sstevel@tonic-gate     {
1787c478bd9Sstevel@tonic-gate #if	defined(TRACE_MESSAGES)
1797c478bd9Sstevel@tonic-gate 	if (trace_messages)
1807c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG, "BAD SIZE\n");
1817c478bd9Sstevel@tonic-gate #endif
1827c478bd9Sstevel@tonic-gate 	goto SyncUp;
1837c478bd9Sstevel@tonic-gate     }
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate     /*
1867c478bd9Sstevel@tonic-gate     ** We have the header. Now we can finally read the rest of the
1877c478bd9Sstevel@tonic-gate     ** message...
1887c478bd9Sstevel@tonic-gate     */
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate     SYNCHED_READ (real_size);
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate     /*
1947c478bd9Sstevel@tonic-gate     ** ...but did we read a real message?...
1957c478bd9Sstevel@tonic-gate     */
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate     if
1987c478bd9Sstevel@tonic-gate     (
199*2a8bcb4eSToomas Soome 	   *(fbp->psave + TAIL_ENDSYNC(real_size)) != Endsync[0]
200*2a8bcb4eSToomas Soome 	|| *(fbp->psave + TAIL_ENDSYNC(real_size) + 1) != Endsync[1]
2017c478bd9Sstevel@tonic-gate     )
2027c478bd9Sstevel@tonic-gate     {
2037c478bd9Sstevel@tonic-gate #if	defined(TRACE_MESSAGES)
2047c478bd9Sstevel@tonic-gate 	if (trace_messages)
2057c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG, "BAD ENDSYNC\n");
2067c478bd9Sstevel@tonic-gate #endif
2077c478bd9Sstevel@tonic-gate 	Garbage_Messages++;
2087c478bd9Sstevel@tonic-gate 	goto SyncUp;
2097c478bd9Sstevel@tonic-gate     }
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate     chksum = stoh(fbp->psave + TAIL_CHKSUM(real_size));
2127c478bd9Sstevel@tonic-gate     CALC_CHKSUM (fbp->psave, real_size, real_chksum);
2137c478bd9Sstevel@tonic-gate     if (real_chksum != chksum)
2147c478bd9Sstevel@tonic-gate     {
2157c478bd9Sstevel@tonic-gate #if	defined(TRACE_MESSAGES)
2167c478bd9Sstevel@tonic-gate 	if (trace_messages)
2177c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG, "BAD CHKSUM\n");
2187c478bd9Sstevel@tonic-gate #endif
2197c478bd9Sstevel@tonic-gate 	Garbage_Messages++;
2207c478bd9Sstevel@tonic-gate 	goto SyncUp;
2217c478bd9Sstevel@tonic-gate     }
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate     /*
2247c478bd9Sstevel@tonic-gate     ** ...yes!...but can the caller handle the message?
2257c478bd9Sstevel@tonic-gate     */
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate     if (size < real_size)
2287c478bd9Sstevel@tonic-gate     {
2297c478bd9Sstevel@tonic-gate 	errno = E2BIG;
2307c478bd9Sstevel@tonic-gate 	return (-1);
2317c478bd9Sstevel@tonic-gate     }
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate     /*
2357c478bd9Sstevel@tonic-gate     ** Yes!! We can finally copy the message into the caller's buffer
2367c478bd9Sstevel@tonic-gate     ** and remove it from our buffer. That wasn't so bad, was it?
2377c478bd9Sstevel@tonic-gate     */
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate #if	defined(TRACE_MESSAGES)
2407c478bd9Sstevel@tonic-gate     if (trace_messages)
2417c478bd9Sstevel@tonic-gate 	syslog(LOG_DEBUG, "MESSAGE: %-.*s", real_size, fbp->psave);
2427c478bd9Sstevel@tonic-gate #endif
2437c478bd9Sstevel@tonic-gate     (void)memcpy (buf, fbp->psave, real_size);
2447c478bd9Sstevel@tonic-gate     fbp->psave += real_size;
2457c478bd9Sstevel@tonic-gate     return (real_size);
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate int
peek3_2(fifo)2497c478bd9Sstevel@tonic-gate peek3_2 (fifo)
2507c478bd9Sstevel@tonic-gate int		fifo;
2517c478bd9Sstevel@tonic-gate {
2527c478bd9Sstevel@tonic-gate     register fifobuffer_t	*fbp;
2537c478bd9Sstevel@tonic-gate     register unsigned int	real_size;
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate     /*
2567c478bd9Sstevel@tonic-gate     ** Make sure we start on a message boundary. The first
2577c478bd9Sstevel@tonic-gate     ** line of defense is to look for the resync. bytes.
2587c478bd9Sstevel@tonic-gate     **
2597c478bd9Sstevel@tonic-gate     ** The "SyncUp" label is global to this routine (below this point)
2607c478bd9Sstevel@tonic-gate     ** and is called whenever we determine that we're out
2617c478bd9Sstevel@tonic-gate     ** of sync. with the incoming bytes.
2627c478bd9Sstevel@tonic-gate     */
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate     if (!(fbp=GetFifoBuffer (fifo)))
2657c478bd9Sstevel@tonic-gate 	return	-1;
2667c478bd9Sstevel@tonic-gate     UNSYNCHED_READ (HEAD_RESYNC_LEN);
2677c478bd9Sstevel@tonic-gate     while (*fbp->psave != Resync[0] || *(fbp->psave + 1) != Resync[1])
2687c478bd9Sstevel@tonic-gate     {
2697c478bd9Sstevel@tonic-gate SyncUp:
2707c478bd9Sstevel@tonic-gate 	fbp->psave++;
2717c478bd9Sstevel@tonic-gate 	Garbage_Bytes++;
2727c478bd9Sstevel@tonic-gate 	UNSYNCHED_READ (HEAD_RESYNC_LEN);
2737c478bd9Sstevel@tonic-gate     }
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate     /*
2777c478bd9Sstevel@tonic-gate     ** We're sync'd, so read the full header.
2787c478bd9Sstevel@tonic-gate     */
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate     SYNCHED_READ (HEAD_LEN);
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate     /*
2847c478bd9Sstevel@tonic-gate     ** If the header size is smaller than the minimum size for a header,
2857c478bd9Sstevel@tonic-gate     ** or larger than allowed, we must assume that we really aren't
2867c478bd9Sstevel@tonic-gate     ** synchronized.
2877c478bd9Sstevel@tonic-gate     */
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate     real_size = stoh(fbp->psave + HEAD_SIZE);
2907c478bd9Sstevel@tonic-gate     if (real_size < CONTROL_LEN || MSGMAX < real_size)
2917c478bd9Sstevel@tonic-gate     {
2927c478bd9Sstevel@tonic-gate 	goto SyncUp;
2937c478bd9Sstevel@tonic-gate     }
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate     return(real_size);
2967c478bd9Sstevel@tonic-gate }
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate static int
_buffer(int fifo)299f928ce67Sceastha _buffer(int fifo)
3007c478bd9Sstevel@tonic-gate {
3017c478bd9Sstevel@tonic-gate 	     int	   n, nbytes, count = 0;
3027c478bd9Sstevel@tonic-gate     register fifobuffer_t  *fbp;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate     /*
3057c478bd9Sstevel@tonic-gate     ** As long as we get real messages, and if we chose
3067c478bd9Sstevel@tonic-gate     ** SAVE_SIZE well, we shouldn't have to move the data
3077c478bd9Sstevel@tonic-gate     ** in the "else" branch below: Each time we call "read"
3087c478bd9Sstevel@tonic-gate     ** we aren't likely to get as many bytes as we ask for,
3097c478bd9Sstevel@tonic-gate     ** just as many as are in the fifo, AND THIS SHOULD
3107c478bd9Sstevel@tonic-gate     ** REPRESENT AN INTEGRAL NUMBER OF MESSAGES. Since
3117c478bd9Sstevel@tonic-gate     ** the "read_fifo" routine reads complete messages,
3127c478bd9Sstevel@tonic-gate     ** it will end its read at the end of the message,
3137c478bd9Sstevel@tonic-gate     ** which (eventually) will make "psave_end" == "psave".
3147c478bd9Sstevel@tonic-gate     */
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate     /*
3177c478bd9Sstevel@tonic-gate     ** If the buffer is empty, there's nothing to move.
3187c478bd9Sstevel@tonic-gate     */
3197c478bd9Sstevel@tonic-gate     if (!(fbp = GetFifoBuffer (fifo)))
3207c478bd9Sstevel@tonic-gate 	return	-1;
3217c478bd9Sstevel@tonic-gate     if (fbp->psave_end == fbp->psave)
3227c478bd9Sstevel@tonic-gate 	fbp->psave = fbp->psave_end = fbp->save;	/* sane pointers! */
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate     /*
3257c478bd9Sstevel@tonic-gate     ** If the buffer has data at the high end, move it down.
3267c478bd9Sstevel@tonic-gate     */
3277c478bd9Sstevel@tonic-gate     else
3287c478bd9Sstevel@tonic-gate     if (fbp->psave != fbp->save)		/* sane pointers! */
3297c478bd9Sstevel@tonic-gate     {
3307c478bd9Sstevel@tonic-gate 	/*
3317c478bd9Sstevel@tonic-gate 	** Move the data still left in the buffer to the
3327c478bd9Sstevel@tonic-gate 	** front, so we can read as much as possible into
3337c478bd9Sstevel@tonic-gate 	** buffer after it.
3347c478bd9Sstevel@tonic-gate 	*/
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	memmove(fbp->save, fbp->psave, fbp->psave_end - fbp->psave);
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	fbp->psave_end = fbp->save + (fbp->psave_end - fbp->psave);
3397c478bd9Sstevel@tonic-gate 	fbp->psave = fbp->save;	/* sane	pointers! */
3407c478bd9Sstevel@tonic-gate     }
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate     /*
3437c478bd9Sstevel@tonic-gate     ** The "fbp->psave" and "fbp->psave_end" pointers must be in a sane
3447c478bd9Sstevel@tonic-gate     ** state when we get here, in case the "read()" gets interrupted.
3457c478bd9Sstevel@tonic-gate     ** When that happens, we return to the caller who may try
3467c478bd9Sstevel@tonic-gate     ** to restart us! Sane: fbp->psave == fbp->save (HERE!)
3477c478bd9Sstevel@tonic-gate     */
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate     nbytes = MSGMAX - (fbp->psave_end - fbp->save);
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate     while ((n = read(fifo, fbp->psave_end, nbytes)) == 0 && count < 60)
3527c478bd9Sstevel@tonic-gate     {
3537c478bd9Sstevel@tonic-gate 	(void)	sleep ((unsigned) 1);
3547c478bd9Sstevel@tonic-gate 	count++;
3557c478bd9Sstevel@tonic-gate     }
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate     if (n > 0)
3587c478bd9Sstevel@tonic-gate 	fbp->psave_end += n;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate     Had_Full_Buffer = fbp->full;
3617c478bd9Sstevel@tonic-gate     fbp->full = (nbytes == n);
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate     return (n);
3647c478bd9Sstevel@tonic-gate }
365