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