xref: /onnv-gate/usr/src/lib/libast/common/sfio/sfpkrd.c (revision 4887:feebf9260c2e)
1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
18*4887Schin *                  David Korn <dgk@research.att.com>                   *
19*4887Schin *                   Phong Vo <kpv@research.att.com>                    *
20*4887Schin *                                                                      *
21*4887Schin ***********************************************************************/
22*4887Schin #include	"sfhdr.h"
23*4887Schin #if !_PACKAGE_ast
24*4887Schin #ifndef FIONREAD
25*4887Schin #if _sys_ioctl
26*4887Schin #include	<sys/ioctl.h>
27*4887Schin #endif
28*4887Schin #endif
29*4887Schin #endif
30*4887Schin 
31*4887Schin /*	Read/Peek a record from an unseekable device
32*4887Schin **
33*4887Schin **	Written by Kiem-Phong Vo.
34*4887Schin */
35*4887Schin 
36*4887Schin #define STREAM_PEEK	001
37*4887Schin #define SOCKET_PEEK	002
38*4887Schin 
39*4887Schin #if __STD_C
40*4887Schin ssize_t sfpkrd(int fd, Void_t* argbuf, size_t n, int rc, long tm, int action)
41*4887Schin #else
42*4887Schin ssize_t sfpkrd(fd, argbuf, n, rc, tm, action)
43*4887Schin int	fd;	/* file descriptor */
44*4887Schin Void_t*	argbuf;	/* buffer to read data */
45*4887Schin size_t	n;	/* buffer size */
46*4887Schin int	rc;	/* record character */
47*4887Schin long	tm;	/* time-out */
48*4887Schin int	action;	/* >0: peeking, if rc>=0, get action records,
49*4887Schin 		   <0: no peeking, if rc>=0, get -action records,
50*4887Schin 		   =0: no peeking, if rc>=0, must get a single record
51*4887Schin 		*/
52*4887Schin #endif
53*4887Schin {
54*4887Schin 	reg ssize_t	r;
55*4887Schin 	reg int		ntry, t;
56*4887Schin 	reg char	*buf = (char*)argbuf, *endbuf;
57*4887Schin 
58*4887Schin 	if(rc < 0 && tm < 0 && action <= 0)
59*4887Schin 		return sysreadf(fd,buf,n);
60*4887Schin 
61*4887Schin 	t = (action > 0 || rc >= 0) ? (STREAM_PEEK|SOCKET_PEEK) : 0;
62*4887Schin #if !_stream_peek
63*4887Schin 	t &= ~STREAM_PEEK;
64*4887Schin #endif
65*4887Schin #if !_socket_peek
66*4887Schin 	t &= ~SOCKET_PEEK;
67*4887Schin #endif
68*4887Schin 
69*4887Schin 	for(ntry = 0; ntry < 2; ++ntry)
70*4887Schin 	{
71*4887Schin 		r = -1;
72*4887Schin #if _stream_peek
73*4887Schin 		if((t&STREAM_PEEK) && (ntry == 1 || tm < 0) )
74*4887Schin 		{
75*4887Schin 			struct strpeek	pbuf;
76*4887Schin 			pbuf.flags = 0;
77*4887Schin 			pbuf.ctlbuf.maxlen = -1;
78*4887Schin 			pbuf.ctlbuf.len = 0;
79*4887Schin 			pbuf.ctlbuf.buf = NIL(char*);
80*4887Schin 			pbuf.databuf.maxlen = n;
81*4887Schin 			pbuf.databuf.buf = buf;
82*4887Schin 			pbuf.databuf.len = 0;
83*4887Schin 
84*4887Schin 			if((r = ioctl(fd,I_PEEK,&pbuf)) < 0)
85*4887Schin 			{	if(errno == EINTR)
86*4887Schin 					return -1;
87*4887Schin 				t &= ~STREAM_PEEK;
88*4887Schin 			}
89*4887Schin 			else
90*4887Schin 			{	t &= ~SOCKET_PEEK;
91*4887Schin 				if(r > 0 && (r = pbuf.databuf.len) <= 0)
92*4887Schin 				{	if(action <= 0)	/* read past eof */
93*4887Schin 						r = sysreadf(fd,buf,1);
94*4887Schin 					return r;
95*4887Schin 				}
96*4887Schin 				if(r == 0)
97*4887Schin 					r = -1;
98*4887Schin 				else if(r > 0)
99*4887Schin 					break;
100*4887Schin 			}
101*4887Schin 		}
102*4887Schin #endif /* stream_peek */
103*4887Schin 
104*4887Schin 		if(ntry == 1)
105*4887Schin 			break;
106*4887Schin 
107*4887Schin 		/* poll or select to see if data is present.  */
108*4887Schin 		while(tm >= 0 || action > 0 ||
109*4887Schin 			/* block until there is data before peeking again */
110*4887Schin 			((t&STREAM_PEEK) && rc >= 0) ||
111*4887Schin 			/* let select be interrupted instead of recv which autoresumes */
112*4887Schin 			(t&SOCKET_PEEK) )
113*4887Schin 		{	r = -2;
114*4887Schin #if _lib_poll
115*4887Schin 			if(r == -2)
116*4887Schin 			{
117*4887Schin 				struct pollfd	po;
118*4887Schin 				po.fd = fd;
119*4887Schin 				po.events = POLLIN;
120*4887Schin 				po.revents = 0;
121*4887Schin 
122*4887Schin 				if((r = SFPOLL(&po,1,tm)) < 0)
123*4887Schin 				{	if(errno == EINTR)
124*4887Schin 						return -1;
125*4887Schin 					else if(errno == EAGAIN)
126*4887Schin 					{	errno = 0;
127*4887Schin 						continue;
128*4887Schin 					}
129*4887Schin 					else	r = -2;
130*4887Schin 				}
131*4887Schin 				else	r = (po.revents&POLLIN) ? 1 : -1;
132*4887Schin 			}
133*4887Schin #endif /*_lib_poll*/
134*4887Schin #if _lib_select
135*4887Schin 			if(r == -2)
136*4887Schin 			{
137*4887Schin #if _hpux_threads && vt_threaded
138*4887Schin #define fd_set	int
139*4887Schin #endif
140*4887Schin 				fd_set		rd;
141*4887Schin 				struct timeval	tmb, *tmp;
142*4887Schin 				FD_ZERO(&rd);
143*4887Schin 				FD_SET(fd,&rd);
144*4887Schin 				if(tm < 0)
145*4887Schin 					tmp = NIL(struct timeval*);
146*4887Schin 				else
147*4887Schin 				{	tmp = &tmb;
148*4887Schin 					tmb.tv_sec = tm/SECOND;
149*4887Schin 					tmb.tv_usec = (tm%SECOND)*SECOND;
150*4887Schin 				}
151*4887Schin 				r = select(fd+1,&rd,NIL(fd_set*),NIL(fd_set*),tmp);
152*4887Schin 				if(r < 0)
153*4887Schin 				{	if(errno == EINTR)
154*4887Schin 						return -1;
155*4887Schin 					else if(errno == EAGAIN)
156*4887Schin 					{	errno = 0;
157*4887Schin 						continue;
158*4887Schin 					}
159*4887Schin 					else	r = -2;
160*4887Schin 				}
161*4887Schin 				else	r = FD_ISSET(fd,&rd) ? 1 : -1;
162*4887Schin 			}
163*4887Schin #endif /*_lib_select*/
164*4887Schin 			if(r == -2)
165*4887Schin 			{
166*4887Schin #if !_lib_poll && !_lib_select	/* both poll and select cann't be used */
167*4887Schin #ifdef FIONREAD			/* quick and dirty check for availability */
168*4887Schin 				long	nsec = tm < 0 ? 0 : (tm+999)/1000;
169*4887Schin 				while(nsec > 0 && r < 0)
170*4887Schin 				{	long	avail = -1;
171*4887Schin 					if((r = ioctl(fd,FIONREAD,&avail)) < 0)
172*4887Schin 					{	if(errno == EINTR)
173*4887Schin 							return -1;
174*4887Schin 						else if(errno == EAGAIN)
175*4887Schin 						{	errno = 0;
176*4887Schin 							continue;
177*4887Schin 						}
178*4887Schin 						else	/* ioctl failed completely */
179*4887Schin 						{	r = -2;
180*4887Schin 							break;
181*4887Schin 						}
182*4887Schin 					}
183*4887Schin 					else	r = avail <= 0 ? -1 : (ssize_t)avail;
184*4887Schin 
185*4887Schin 					if(r < 0 && nsec-- > 0)
186*4887Schin 						sleep(1);
187*4887Schin 				}
188*4887Schin #endif
189*4887Schin #endif
190*4887Schin 			}
191*4887Schin 
192*4887Schin 			if(r > 0)		/* there is data now */
193*4887Schin 			{	if(action <= 0 && rc < 0)
194*4887Schin 					return sysreadf(fd,buf,n);
195*4887Schin 				else	r = -1;
196*4887Schin 			}
197*4887Schin 			else if(tm >= 0)	/* timeout exceeded */
198*4887Schin 				return -1;
199*4887Schin 			else	r = -1;
200*4887Schin 			break;
201*4887Schin 		}
202*4887Schin 
203*4887Schin #if _socket_peek
204*4887Schin 		if(t&SOCKET_PEEK)
205*4887Schin 		{
206*4887Schin #if __MACH__ && __APPLE__
207*4887Schin 			/*
208*4887Schin 			 * work around macos 10.4 recv(MSG_PEEK) bug that consumes pipe() data
209*4887Schin 			 */
210*4887Schin 
211*4887Schin 			static int	recv_peek_ok;
212*4887Schin 			if (!recv_peek_ok)
213*4887Schin 			{
214*4887Schin 				int	fds[2];
215*4887Schin 				char	tst[2];
216*4887Schin 				tst[0] = 'a';
217*4887Schin 				tst[1] = 'z';
218*4887Schin 				recv_peek_ok = (!pipe(fds) && write(fds[1], tst, 2) && recv(fds[0], tst, 1, MSG_PEEK) == 1 && tst[0] == 'a' && recv(fds[0], tst, 1, MSG_PEEK) == 1 && tst[0] == 'a') ? 1 : -1;
219*4887Schin 				close(fds[0]);
220*4887Schin 				close(fds[1]);
221*4887Schin 			}
222*4887Schin 			if (recv_peek_ok < 0)
223*4887Schin 			{
224*4887Schin 				r = -1;
225*4887Schin 				t &= ~SOCKET_PEEK;
226*4887Schin 			}
227*4887Schin 			else
228*4887Schin #endif
229*4887Schin 			while((r = recv(fd,(char*)buf,n,MSG_PEEK)) < 0)
230*4887Schin 			{	if(errno == EINTR)
231*4887Schin 					return -1;
232*4887Schin 				else if(errno == EAGAIN)
233*4887Schin 				{	errno = 0;
234*4887Schin 					continue;
235*4887Schin 				}
236*4887Schin 				t &= ~SOCKET_PEEK;
237*4887Schin 				break;
238*4887Schin 			}
239*4887Schin 			if(r >= 0)
240*4887Schin 			{	t &= ~STREAM_PEEK;
241*4887Schin 				if(r > 0)
242*4887Schin 					break;
243*4887Schin 				else	/* read past eof */
244*4887Schin 				{	if(action <= 0)
245*4887Schin 						r = sysreadf(fd,buf,1);
246*4887Schin 					return r;
247*4887Schin 				}
248*4887Schin 			}
249*4887Schin 		}
250*4887Schin #endif
251*4887Schin 	}
252*4887Schin 
253*4887Schin 	if(r < 0)
254*4887Schin 	{	if(tm >= 0 || action > 0)
255*4887Schin 			return -1;
256*4887Schin 		else /* get here means: tm < 0 && action <= 0 && rc >= 0 */
257*4887Schin 		{	/* number of records read at a time */
258*4887Schin 			if((action = action ? -action : 1) > (int)n)
259*4887Schin 				action = n;
260*4887Schin 			r = 0;
261*4887Schin 			while((t = sysreadf(fd,buf,action)) > 0)
262*4887Schin 			{	r += t;
263*4887Schin 				for(endbuf = buf+t; buf < endbuf;)
264*4887Schin 					if(*buf++ == rc)
265*4887Schin 						action -= 1;
266*4887Schin 				if(action == 0 || (int)(n-r) < action)
267*4887Schin 					break;
268*4887Schin 			}
269*4887Schin 			return r == 0 ? t : r;
270*4887Schin 		}
271*4887Schin 	}
272*4887Schin 
273*4887Schin 	/* successful peek, find the record end */
274*4887Schin 	if(rc >= 0)
275*4887Schin 	{	reg char*	sp;
276*4887Schin 
277*4887Schin 		t = action == 0 ? 1 : action < 0 ? -action : action;
278*4887Schin 		for(endbuf = (sp = buf)+r; sp < endbuf; )
279*4887Schin 			if(*sp++ == rc)
280*4887Schin 				if((t -= 1) == 0)
281*4887Schin 					break;
282*4887Schin 		r = sp - buf;
283*4887Schin 	}
284*4887Schin 
285*4887Schin 	/* advance */
286*4887Schin 	if(action <= 0)
287*4887Schin 		r = sysreadf(fd,buf,r);
288*4887Schin 
289*4887Schin 	return r;
290*4887Schin }
291