xref: /onnv-gate/usr/src/lib/libast/common/sfio/sfpkrd.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #include	"sfhdr.h"
234887Schin #if !_PACKAGE_ast
244887Schin #ifndef FIONREAD
254887Schin #if _sys_ioctl
264887Schin #include	<sys/ioctl.h>
274887Schin #endif
284887Schin #endif
294887Schin #endif
304887Schin 
314887Schin /*	Read/Peek a record from an unseekable device
324887Schin **
334887Schin **	Written by Kiem-Phong Vo.
344887Schin */
354887Schin 
364887Schin #define STREAM_PEEK	001
374887Schin #define SOCKET_PEEK	002
384887Schin 
394887Schin #if __STD_C
sfpkrd(int fd,Void_t * argbuf,size_t n,int rc,long tm,int action)404887Schin ssize_t sfpkrd(int fd, Void_t* argbuf, size_t n, int rc, long tm, int action)
414887Schin #else
424887Schin ssize_t sfpkrd(fd, argbuf, n, rc, tm, action)
434887Schin int	fd;	/* file descriptor */
444887Schin Void_t*	argbuf;	/* buffer to read data */
454887Schin size_t	n;	/* buffer size */
464887Schin int	rc;	/* record character */
474887Schin long	tm;	/* time-out */
484887Schin int	action;	/* >0: peeking, if rc>=0, get action records,
494887Schin 		   <0: no peeking, if rc>=0, get -action records,
504887Schin 		   =0: no peeking, if rc>=0, must get a single record
514887Schin 		*/
524887Schin #endif
534887Schin {
544887Schin 	reg ssize_t	r;
554887Schin 	reg int		ntry, t;
564887Schin 	reg char	*buf = (char*)argbuf, *endbuf;
574887Schin 
584887Schin 	if(rc < 0 && tm < 0 && action <= 0)
594887Schin 		return sysreadf(fd,buf,n);
604887Schin 
614887Schin 	t = (action > 0 || rc >= 0) ? (STREAM_PEEK|SOCKET_PEEK) : 0;
624887Schin #if !_stream_peek
634887Schin 	t &= ~STREAM_PEEK;
644887Schin #endif
654887Schin #if !_socket_peek
664887Schin 	t &= ~SOCKET_PEEK;
674887Schin #endif
684887Schin 
694887Schin 	for(ntry = 0; ntry < 2; ++ntry)
704887Schin 	{
714887Schin 		r = -1;
724887Schin #if _stream_peek
734887Schin 		if((t&STREAM_PEEK) && (ntry == 1 || tm < 0) )
744887Schin 		{
754887Schin 			struct strpeek	pbuf;
764887Schin 			pbuf.flags = 0;
774887Schin 			pbuf.ctlbuf.maxlen = -1;
784887Schin 			pbuf.ctlbuf.len = 0;
794887Schin 			pbuf.ctlbuf.buf = NIL(char*);
804887Schin 			pbuf.databuf.maxlen = n;
814887Schin 			pbuf.databuf.buf = buf;
824887Schin 			pbuf.databuf.len = 0;
834887Schin 
844887Schin 			if((r = ioctl(fd,I_PEEK,&pbuf)) < 0)
854887Schin 			{	if(errno == EINTR)
864887Schin 					return -1;
874887Schin 				t &= ~STREAM_PEEK;
884887Schin 			}
894887Schin 			else
904887Schin 			{	t &= ~SOCKET_PEEK;
914887Schin 				if(r > 0 && (r = pbuf.databuf.len) <= 0)
924887Schin 				{	if(action <= 0)	/* read past eof */
934887Schin 						r = sysreadf(fd,buf,1);
944887Schin 					return r;
954887Schin 				}
964887Schin 				if(r == 0)
974887Schin 					r = -1;
984887Schin 				else if(r > 0)
994887Schin 					break;
1004887Schin 			}
1014887Schin 		}
1024887Schin #endif /* stream_peek */
1034887Schin 
1044887Schin 		if(ntry == 1)
1054887Schin 			break;
1064887Schin 
1074887Schin 		/* poll or select to see if data is present.  */
1084887Schin 		while(tm >= 0 || action > 0 ||
1094887Schin 			/* block until there is data before peeking again */
1104887Schin 			((t&STREAM_PEEK) && rc >= 0) ||
1114887Schin 			/* let select be interrupted instead of recv which autoresumes */
1124887Schin 			(t&SOCKET_PEEK) )
1134887Schin 		{	r = -2;
1144887Schin #if _lib_poll
1154887Schin 			if(r == -2)
1164887Schin 			{
1174887Schin 				struct pollfd	po;
1184887Schin 				po.fd = fd;
1194887Schin 				po.events = POLLIN;
1204887Schin 				po.revents = 0;
1214887Schin 
1224887Schin 				if((r = SFPOLL(&po,1,tm)) < 0)
1234887Schin 				{	if(errno == EINTR)
1244887Schin 						return -1;
1254887Schin 					else if(errno == EAGAIN)
1264887Schin 					{	errno = 0;
1274887Schin 						continue;
1284887Schin 					}
1294887Schin 					else	r = -2;
1304887Schin 				}
1314887Schin 				else	r = (po.revents&POLLIN) ? 1 : -1;
1324887Schin 			}
1334887Schin #endif /*_lib_poll*/
1344887Schin #if _lib_select
1354887Schin 			if(r == -2)
1364887Schin 			{
1374887Schin #if _hpux_threads && vt_threaded
1384887Schin #define fd_set	int
1394887Schin #endif
1404887Schin 				fd_set		rd;
1414887Schin 				struct timeval	tmb, *tmp;
1424887Schin 				FD_ZERO(&rd);
1434887Schin 				FD_SET(fd,&rd);
1444887Schin 				if(tm < 0)
1454887Schin 					tmp = NIL(struct timeval*);
1464887Schin 				else
1474887Schin 				{	tmp = &tmb;
1484887Schin 					tmb.tv_sec = tm/SECOND;
1494887Schin 					tmb.tv_usec = (tm%SECOND)*SECOND;
1504887Schin 				}
1514887Schin 				r = select(fd+1,&rd,NIL(fd_set*),NIL(fd_set*),tmp);
1524887Schin 				if(r < 0)
1534887Schin 				{	if(errno == EINTR)
1544887Schin 						return -1;
1554887Schin 					else if(errno == EAGAIN)
1564887Schin 					{	errno = 0;
1574887Schin 						continue;
1584887Schin 					}
1594887Schin 					else	r = -2;
1604887Schin 				}
1614887Schin 				else	r = FD_ISSET(fd,&rd) ? 1 : -1;
1624887Schin 			}
1634887Schin #endif /*_lib_select*/
1644887Schin 			if(r == -2)
1654887Schin 			{
1668462SApril.Chin@Sun.COM #if !_lib_poll && !_lib_select	/* both poll and select can't be used */
1674887Schin #ifdef FIONREAD			/* quick and dirty check for availability */
1684887Schin 				long	nsec = tm < 0 ? 0 : (tm+999)/1000;
1694887Schin 				while(nsec > 0 && r < 0)
1704887Schin 				{	long	avail = -1;
1714887Schin 					if((r = ioctl(fd,FIONREAD,&avail)) < 0)
1724887Schin 					{	if(errno == EINTR)
1734887Schin 							return -1;
1744887Schin 						else if(errno == EAGAIN)
1754887Schin 						{	errno = 0;
1764887Schin 							continue;
1774887Schin 						}
1784887Schin 						else	/* ioctl failed completely */
1794887Schin 						{	r = -2;
1804887Schin 							break;
1814887Schin 						}
1824887Schin 					}
1834887Schin 					else	r = avail <= 0 ? -1 : (ssize_t)avail;
1844887Schin 
1854887Schin 					if(r < 0 && nsec-- > 0)
1864887Schin 						sleep(1);
1874887Schin 				}
1884887Schin #endif
1894887Schin #endif
1904887Schin 			}
1914887Schin 
1924887Schin 			if(r > 0)		/* there is data now */
1934887Schin 			{	if(action <= 0 && rc < 0)
1944887Schin 					return sysreadf(fd,buf,n);
1954887Schin 				else	r = -1;
1964887Schin 			}
1974887Schin 			else if(tm >= 0)	/* timeout exceeded */
1984887Schin 				return -1;
1994887Schin 			else	r = -1;
2004887Schin 			break;
2014887Schin 		}
2024887Schin 
2034887Schin #if _socket_peek
2044887Schin 		if(t&SOCKET_PEEK)
2054887Schin 		{
2064887Schin #if __MACH__ && __APPLE__
2074887Schin 			/*
2084887Schin 			 * work around macos 10.4 recv(MSG_PEEK) bug that consumes pipe() data
2094887Schin 			 */
2104887Schin 
2118462SApril.Chin@Sun.COM 			struct stat	st;
2124887Schin 			static int	recv_peek_ok;
2134887Schin 			if (!recv_peek_ok)
2144887Schin 			{
2154887Schin 				int	fds[2];
2164887Schin 				char	tst[2];
2174887Schin 				tst[0] = 'a';
2184887Schin 				tst[1] = 'z';
2194887Schin 				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;
2204887Schin 				close(fds[0]);
2214887Schin 				close(fds[1]);
2224887Schin 			}
2238462SApril.Chin@Sun.COM 			if (recv_peek_ok < 0 && !fstat(fd, &st) && !S_ISSOCK(st.st_mode))
2244887Schin 			{
2254887Schin 				r = -1;
2264887Schin 				t &= ~SOCKET_PEEK;
2274887Schin 			}
2284887Schin 			else
2294887Schin #endif
2304887Schin 			while((r = recv(fd,(char*)buf,n,MSG_PEEK)) < 0)
2314887Schin 			{	if(errno == EINTR)
2324887Schin 					return -1;
2334887Schin 				else if(errno == EAGAIN)
2344887Schin 				{	errno = 0;
2354887Schin 					continue;
2364887Schin 				}
2374887Schin 				t &= ~SOCKET_PEEK;
2384887Schin 				break;
2394887Schin 			}
2404887Schin 			if(r >= 0)
2414887Schin 			{	t &= ~STREAM_PEEK;
2424887Schin 				if(r > 0)
2434887Schin 					break;
2444887Schin 				else	/* read past eof */
2454887Schin 				{	if(action <= 0)
2464887Schin 						r = sysreadf(fd,buf,1);
2474887Schin 					return r;
2484887Schin 				}
2494887Schin 			}
2504887Schin 		}
2514887Schin #endif
2524887Schin 	}
2534887Schin 
2544887Schin 	if(r < 0)
2554887Schin 	{	if(tm >= 0 || action > 0)
2564887Schin 			return -1;
2574887Schin 		else /* get here means: tm < 0 && action <= 0 && rc >= 0 */
2584887Schin 		{	/* number of records read at a time */
2594887Schin 			if((action = action ? -action : 1) > (int)n)
2604887Schin 				action = n;
2614887Schin 			r = 0;
2624887Schin 			while((t = sysreadf(fd,buf,action)) > 0)
2634887Schin 			{	r += t;
2644887Schin 				for(endbuf = buf+t; buf < endbuf;)
2654887Schin 					if(*buf++ == rc)
2664887Schin 						action -= 1;
2674887Schin 				if(action == 0 || (int)(n-r) < action)
2684887Schin 					break;
2694887Schin 			}
2704887Schin 			return r == 0 ? t : r;
2714887Schin 		}
2724887Schin 	}
2734887Schin 
2744887Schin 	/* successful peek, find the record end */
2754887Schin 	if(rc >= 0)
2764887Schin 	{	reg char*	sp;
2774887Schin 
2784887Schin 		t = action == 0 ? 1 : action < 0 ? -action : action;
2794887Schin 		for(endbuf = (sp = buf)+r; sp < endbuf; )
2804887Schin 			if(*sp++ == rc)
2814887Schin 				if((t -= 1) == 0)
2824887Schin 					break;
2834887Schin 		r = sp - buf;
2844887Schin 	}
2854887Schin 
2864887Schin 	/* advance */
2874887Schin 	if(action <= 0)
2884887Schin 		r = sysreadf(fd,buf,r);
2894887Schin 
2904887Schin 	return r;
2914887Schin }
292