1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
26 #include <sys/ioctl.h>
31 /* Read/Peek a record from an unseekable device
33 ** Written by Kiem-Phong Vo.
36 #define STREAM_PEEK 001
37 #define SOCKET_PEEK 002
40 ssize_t
sfpkrd(int fd
, Void_t
* argbuf
, size_t n
, int rc
, long tm
, int action
)
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
56 reg
char *buf
= (char*)argbuf
, *endbuf
;
58 if(rc
< 0 && tm
< 0 && action
<= 0)
59 return sysreadf(fd
,buf
,n
);
61 t
= (action
> 0 || rc
>= 0) ? (STREAM_PEEK
|SOCKET_PEEK
) : 0;
69 for(ntry
= 0; ntry
< 2; ++ntry
)
73 if((t
&STREAM_PEEK
) && (ntry
== 1 || tm
< 0) )
77 pbuf
.ctlbuf
.maxlen
= -1;
79 pbuf
.ctlbuf
.buf
= NIL(char*);
80 pbuf
.databuf
.maxlen
= n
;
81 pbuf
.databuf
.buf
= buf
;
84 if((r
= ioctl(fd
,I_PEEK
,&pbuf
)) < 0)
91 if(r
> 0 && (r
= pbuf
.databuf
.len
) <= 0)
92 { if(action
<= 0) /* read past eof */
93 r
= sysreadf(fd
,buf
,1);
102 #endif /* stream_peek */
107 /* poll or select to see if data is present. */
108 while(tm
>= 0 || action
> 0 ||
109 /* block until there is data before peeking again */
110 ((t
&STREAM_PEEK
) && rc
>= 0) ||
111 /* let select be interrupted instead of recv which autoresumes */
122 if((r
= SFPOLL(&po
,1,tm
)) < 0)
125 else if(errno
== EAGAIN
)
131 else r
= (po
.revents
&POLLIN
) ? 1 : -1;
137 #if _hpux_threads && vt_threaded
141 struct timeval tmb
, *tmp
;
145 tmp
= NIL(struct timeval
*);
148 tmb
.tv_sec
= tm
/SECOND
;
149 tmb
.tv_usec
= (tm
%SECOND
)*SECOND
;
151 r
= select(fd
+1,&rd
,NIL(fd_set
*),NIL(fd_set
*),tmp
);
155 else if(errno
== EAGAIN
)
161 else r
= FD_ISSET(fd
,&rd
) ? 1 : -1;
163 #endif /*_lib_select*/
166 #if !_lib_poll && !_lib_select /* both poll and select can't be used */
167 #ifdef FIONREAD /* quick and dirty check for availability */
168 long nsec
= tm
< 0 ? 0 : (tm
+999)/1000;
169 while(nsec
> 0 && r
< 0)
171 if((r
= ioctl(fd
,FIONREAD
,&avail
)) < 0)
174 else if(errno
== EAGAIN
)
178 else /* ioctl failed completely */
183 else r
= avail
<= 0 ? -1 : (ssize_t
)avail
;
185 if(r
< 0 && nsec
-- > 0)
192 if(r
> 0) /* there is data now */
193 { if(action
<= 0 && rc
< 0)
194 return sysreadf(fd
,buf
,n
);
197 else if(tm
>= 0) /* timeout exceeded */
206 #if __MACH__ && __APPLE__
208 * work around macos 10.4 recv(MSG_PEEK) bug that consumes pipe() data
212 static int recv_peek_ok
;
219 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;
223 if (recv_peek_ok
< 0 && !fstat(fd
, &st
) && !S_ISSOCK(st
.st_mode
))
230 while((r
= recv(fd
,(char*)buf
,n
,MSG_PEEK
)) < 0)
233 else if(errno
== EAGAIN
)
244 else /* read past eof */
246 r
= sysreadf(fd
,buf
,1);
255 { if(tm
>= 0 || action
> 0)
257 else /* get here means: tm < 0 && action <= 0 && rc >= 0 */
258 { /* number of records read at a time */
259 if((action
= action
? -action
: 1) > (int)n
)
262 while((t
= sysreadf(fd
,buf
,action
)) > 0)
264 for(endbuf
= buf
+t
; buf
< endbuf
;)
267 if(action
== 0 || (int)(n
-r
) < action
)
270 return r
== 0 ? t
: r
;
274 /* successful peek, find the record end */
278 t
= action
== 0 ? 1 : action
< 0 ? -action
: action
;
279 for(endbuf
= (sp
= buf
)+r
; sp
< endbuf
; )
288 r
= sysreadf(fd
,buf
,r
);