14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1985-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.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 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 { 166*8462SApril.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 211*8462SApril.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 } 223*8462SApril.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