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