Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libast/sfio/sfpkrd.c
1810 views
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 <[email protected]> *
18
* David Korn <[email protected]> *
19
* Phong Vo <[email protected]> *
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
327