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