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