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