|
Packit |
992a25 |
/***********************************************************************
|
|
Packit |
992a25 |
* *
|
|
Packit |
992a25 |
* This software is part of the ast package *
|
|
Packit |
992a25 |
* Copyright (c) 1985-2012 AT&T Intellectual Property *
|
|
Packit |
992a25 |
* and is licensed under the *
|
|
Packit |
992a25 |
* Eclipse Public License, Version 1.0 *
|
|
Packit |
992a25 |
* by AT&T Intellectual Property *
|
|
Packit |
992a25 |
* *
|
|
Packit |
992a25 |
* A copy of the License is available at *
|
|
Packit |
992a25 |
* http://www.eclipse.org/org/documents/epl-v10.html *
|
|
Packit |
992a25 |
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
|
|
Packit |
992a25 |
* *
|
|
Packit |
992a25 |
* Information and Software Systems Research *
|
|
Packit |
992a25 |
* AT&T Research *
|
|
Packit |
992a25 |
* Florham Park NJ *
|
|
Packit |
992a25 |
* *
|
|
Packit |
992a25 |
* Glenn Fowler <gsf@research.att.com> *
|
|
Packit |
992a25 |
* David Korn <dgk@research.att.com> *
|
|
Packit |
992a25 |
* Phong Vo <kpv@research.att.com> *
|
|
Packit |
992a25 |
* *
|
|
Packit |
992a25 |
***********************************************************************/
|
|
Packit |
992a25 |
#include "sfhdr.h"
|
|
Packit |
992a25 |
#if !_PACKAGE_ast
|
|
Packit |
992a25 |
#ifndef FIONREAD
|
|
Packit |
992a25 |
#if _sys_ioctl
|
|
Packit |
992a25 |
#include <sys/ioctl.h>
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* Read/Peek a record from an unseekable device
|
|
Packit |
992a25 |
**
|
|
Packit |
992a25 |
** Written by Kiem-Phong Vo.
|
|
Packit |
992a25 |
*/
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
#define STREAM_PEEK 001
|
|
Packit |
992a25 |
#define SOCKET_PEEK 002
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
#if __STD_C
|
|
Packit |
992a25 |
ssize_t sfpkrd(int fd, Void_t* argbuf, size_t n, int rc, long tm, int action)
|
|
Packit |
992a25 |
#else
|
|
Packit |
992a25 |
ssize_t sfpkrd(fd, argbuf, n, rc, tm, action)
|
|
Packit |
992a25 |
int fd; /* file descriptor */
|
|
Packit |
992a25 |
Void_t* argbuf; /* buffer to read data */
|
|
Packit |
992a25 |
size_t n; /* buffer size */
|
|
Packit |
992a25 |
int rc; /* record character */
|
|
Packit |
992a25 |
long tm; /* time-out */
|
|
Packit |
992a25 |
int action; /* >0: peeking, if rc>=0, get action records,
|
|
Packit |
992a25 |
<0: no peeking, if rc>=0, get -action records,
|
|
Packit |
992a25 |
=0: no peeking, if rc>=0, must get a single record
|
|
Packit |
992a25 |
*/
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
reg ssize_t r;
|
|
Packit |
992a25 |
reg int ntry, t;
|
|
Packit |
992a25 |
reg char *buf = (char*)argbuf, *endbuf;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if(rc < 0 && tm < 0 && action <= 0)
|
|
Packit |
992a25 |
return sysreadf(fd,buf,n);
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
t = (action > 0 || rc >= 0) ? (STREAM_PEEK|SOCKET_PEEK) : 0;
|
|
Packit |
992a25 |
#if !_stream_peek
|
|
Packit |
992a25 |
t &= ~STREAM_PEEK;
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
#if !_socket_peek
|
|
Packit |
992a25 |
t &= ~SOCKET_PEEK;
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
for(ntry = 0; ntry < 2; ++ntry)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
r = -1;
|
|
Packit |
992a25 |
#if _stream_peek
|
|
Packit |
992a25 |
if((t&STREAM_PEEK) && (ntry == 1 || tm < 0) )
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
#ifdef __sun
|
|
Packit |
992a25 |
/*
|
|
Packit |
992a25 |
* I_PEEK on stdin can hang rsh+ksh on solaris
|
|
Packit |
992a25 |
* this kludge will have to do until sun^H^H^Horacle fixes I_PEEK/rsh
|
|
Packit |
992a25 |
*/
|
|
Packit |
992a25 |
static int stream_peek;
|
|
Packit |
992a25 |
if (stream_peek == 0) /* this will be done just once */
|
|
Packit |
992a25 |
{ char *e;
|
|
Packit |
992a25 |
stream_peek = (
|
|
Packit |
992a25 |
getenv("LOGNAME") == 0 &&
|
|
Packit |
992a25 |
getenv("MAIL") == 0 &&
|
|
Packit |
992a25 |
((e = getenv("LANG")) == 0 || strcmp(e, "C") == 0) &&
|
|
Packit |
992a25 |
((e = getenv("PATH")) == 0 || strncmp(e, "/usr/bin:", 9) == 0)
|
|
Packit |
992a25 |
) ? -1 : 1;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
if(stream_peek < 0)
|
|
Packit |
992a25 |
t &= ~STREAM_PEEK;
|
|
Packit |
992a25 |
else
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
{ struct strpeek pbuf;
|
|
Packit |
992a25 |
pbuf.flags = 0;
|
|
Packit |
992a25 |
pbuf.ctlbuf.maxlen = -1;
|
|
Packit |
992a25 |
pbuf.ctlbuf.len = 0;
|
|
Packit |
992a25 |
pbuf.ctlbuf.buf = NIL(char*);
|
|
Packit |
992a25 |
pbuf.databuf.maxlen = n;
|
|
Packit |
992a25 |
pbuf.databuf.buf = buf;
|
|
Packit |
992a25 |
pbuf.databuf.len = 0;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if((r = ioctl(fd,I_PEEK,&pbuf)) < 0)
|
|
Packit |
992a25 |
{ if(errno == EINTR)
|
|
Packit |
992a25 |
return -1;
|
|
Packit |
992a25 |
t &= ~STREAM_PEEK;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
else
|
|
Packit |
992a25 |
{ t &= ~SOCKET_PEEK;
|
|
Packit |
992a25 |
if(r > 0 && (r = pbuf.databuf.len) <= 0)
|
|
Packit |
992a25 |
{ if(action <= 0) /* read past eof */
|
|
Packit |
992a25 |
r = sysreadf(fd,buf,1);
|
|
Packit |
992a25 |
return r;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
if(r == 0)
|
|
Packit |
992a25 |
r = -1;
|
|
Packit |
992a25 |
else if(r > 0)
|
|
Packit |
992a25 |
break;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
#endif /* stream_peek */
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if(ntry == 1)
|
|
Packit |
992a25 |
break;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* poll or select to see if data is present. */
|
|
Packit |
992a25 |
while(tm >= 0 || action > 0 ||
|
|
Packit |
992a25 |
/* block until there is data before peeking again */
|
|
Packit |
992a25 |
((t&STREAM_PEEK) && rc >= 0) ||
|
|
Packit |
992a25 |
/* let select be interrupted instead of recv which autoresumes */
|
|
Packit |
992a25 |
(t&SOCKET_PEEK) )
|
|
Packit |
992a25 |
{ r = -2;
|
|
Packit |
992a25 |
#if _lib_poll
|
|
Packit |
992a25 |
if(r == -2)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
struct pollfd po;
|
|
Packit |
992a25 |
po.fd = fd;
|
|
Packit |
992a25 |
po.events = POLLIN;
|
|
Packit |
992a25 |
po.revents = 0;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if((r = SFPOLL(&po,1,tm)) < 0)
|
|
Packit |
992a25 |
{ if(errno == EINTR)
|
|
Packit |
992a25 |
return -1;
|
|
Packit |
992a25 |
else if(errno == EAGAIN)
|
|
Packit |
992a25 |
{ errno = 0;
|
|
Packit |
992a25 |
continue;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
else r = -2;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
else r = (po.revents&POLLIN) ? 1 : -1;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
#endif /*_lib_poll*/
|
|
Packit |
992a25 |
#if _lib_select
|
|
Packit |
992a25 |
if(r == -2)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
#if _hpux_threads && vt_threaded
|
|
Packit |
992a25 |
#define fd_set int
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
fd_set rd;
|
|
Packit |
992a25 |
struct timeval tmb, *tmp;
|
|
Packit |
992a25 |
FD_ZERO(&rd);
|
|
Packit |
992a25 |
FD_SET(fd,&rd);
|
|
Packit |
992a25 |
if(tm < 0)
|
|
Packit |
992a25 |
tmp = NIL(struct timeval*);
|
|
Packit |
992a25 |
else
|
|
Packit |
992a25 |
{ tmp = &tm;;
|
|
Packit |
992a25 |
tmb.tv_sec = tm/SECOND;
|
|
Packit |
992a25 |
tmb.tv_usec = (tm%SECOND)*SECOND;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
r = select(fd+1,&rd,NIL(fd_set*),NIL(fd_set*),tmp);
|
|
Packit |
992a25 |
if(r < 0)
|
|
Packit |
992a25 |
{ if(errno == EINTR)
|
|
Packit |
992a25 |
return -1;
|
|
Packit |
992a25 |
else if(errno == EAGAIN)
|
|
Packit |
992a25 |
{ errno = 0;
|
|
Packit |
992a25 |
continue;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
else r = -2;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
else r = FD_ISSET(fd,&rd) ? 1 : -1;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
#endif /*_lib_select*/
|
|
Packit |
992a25 |
if(r == -2)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
#if !_lib_poll && !_lib_select /* both poll and select can't be used */
|
|
Packit |
992a25 |
#ifdef FIONREAD /* quick and dirty check for availability */
|
|
Packit |
992a25 |
long nsec = tm < 0 ? 0 : (tm+999)/1000;
|
|
Packit |
992a25 |
while(nsec > 0 && r < 0)
|
|
Packit |
992a25 |
{ long avail = -1;
|
|
Packit |
992a25 |
if((r = ioctl(fd,FIONREAD,&avail)) < 0)
|
|
Packit |
992a25 |
{ if(errno == EINTR)
|
|
Packit |
992a25 |
return -1;
|
|
Packit |
992a25 |
else if(errno == EAGAIN)
|
|
Packit |
992a25 |
{ errno = 0;
|
|
Packit |
992a25 |
continue;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
else /* ioctl failed completely */
|
|
Packit |
992a25 |
{ r = -2;
|
|
Packit |
992a25 |
break;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
else r = avail <= 0 ? -1 : (ssize_t)avail;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if(r < 0 && nsec-- > 0)
|
|
Packit |
992a25 |
sleep(1);
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if(r > 0) /* there is data now */
|
|
Packit |
992a25 |
{ if(action <= 0 && rc < 0)
|
|
Packit |
992a25 |
return sysreadf(fd,buf,n);
|
|
Packit |
992a25 |
else r = -1;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
else if(tm >= 0) /* timeout exceeded */
|
|
Packit |
992a25 |
return -1;
|
|
Packit |
992a25 |
else r = -1;
|
|
Packit |
992a25 |
break;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
#if _socket_peek
|
|
Packit |
992a25 |
if(t&SOCKET_PEEK)
|
|
Packit |
992a25 |
{
|
|
Packit |
992a25 |
#if __MACH__ && __APPLE__ /* check 10.4 recv(MSG_PEEK) bug that consumes pipe data */
|
|
Packit |
992a25 |
static int recv_peek_pipe;
|
|
Packit |
992a25 |
if (recv_peek_pipe == 0) /* this will be done just once */
|
|
Packit |
992a25 |
{ int fds[2], r;
|
|
Packit |
992a25 |
char tst[2];
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
tst[0] = 'a'; tst[1] = 'z';
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* open a pipe and write to it */
|
|
Packit |
992a25 |
recv_peek_pipe = 1;
|
|
Packit |
992a25 |
if(recv_peek_pipe == 1 && pipe(fds) < 0)
|
|
Packit |
992a25 |
recv_peek_pipe = -1;
|
|
Packit |
992a25 |
if(recv_peek_pipe == 1 && write(fds[1], tst, 2) != 2)
|
|
Packit |
992a25 |
recv_peek_pipe = -1;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* try recv() to see if it gets anything */
|
|
Packit |
992a25 |
tst[0] = tst[1] = 0;
|
|
Packit |
992a25 |
if(recv_peek_pipe == 1 && (r = recv(fds[0], tst, 1, MSG_PEEK)) != 1)
|
|
Packit |
992a25 |
recv_peek_pipe = -1;
|
|
Packit |
992a25 |
if(recv_peek_pipe == 1 && tst[0] != 'a')
|
|
Packit |
992a25 |
recv_peek_pipe = -1;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* make sure that recv() did not consume data */
|
|
Packit |
992a25 |
tst[0] = tst[1] = 0;
|
|
Packit |
992a25 |
if(recv_peek_pipe == 1 && (r = recv(fds[0], tst, 2, MSG_PEEK)) != 2)
|
|
Packit |
992a25 |
recv_peek_pipe = -1;
|
|
Packit |
992a25 |
if(recv_peek_pipe == 1 && (tst[0] != 'a' || tst[1] != 'z') )
|
|
Packit |
992a25 |
recv_peek_pipe = -1;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
close(fds[0]);
|
|
Packit |
992a25 |
close(fds[1]);
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if(recv_peek_pipe < 0)
|
|
Packit |
992a25 |
{ struct stat st; /* recv should work on sockets */
|
|
Packit |
992a25 |
if(fstat(fd, &st) < 0 || !S_ISSOCK(st.st_mode) )
|
|
Packit |
992a25 |
{ r = -1;
|
|
Packit |
992a25 |
t &= ~SOCKET_PEEK;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
while((t&SOCKET_PEEK) && (r = recv(fd,(char*)buf,n,MSG_PEEK)) < 0)
|
|
Packit |
992a25 |
{ if(errno == EINTR)
|
|
Packit |
992a25 |
return -1;
|
|
Packit |
992a25 |
else if(errno == EAGAIN)
|
|
Packit |
992a25 |
errno = 0;
|
|
Packit |
992a25 |
else t &= ~SOCKET_PEEK;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
if(r >= 0)
|
|
Packit |
992a25 |
{ t &= ~STREAM_PEEK;
|
|
Packit |
992a25 |
if(r > 0)
|
|
Packit |
992a25 |
break;
|
|
Packit |
992a25 |
else /* read past eof */
|
|
Packit |
992a25 |
{ if(action <= 0)
|
|
Packit |
992a25 |
r = sysreadf(fd,buf,1);
|
|
Packit |
992a25 |
return r;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
#endif
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
if(r < 0)
|
|
Packit |
992a25 |
{ if(tm >= 0 || action > 0)
|
|
Packit |
992a25 |
return -1;
|
|
Packit |
992a25 |
else /* get here means: tm < 0 && action <= 0 && rc >= 0 */
|
|
Packit |
992a25 |
{ /* number of records read at a time */
|
|
Packit |
992a25 |
if((action = action ? -action : 1) > (int)n)
|
|
Packit |
992a25 |
action = n;
|
|
Packit |
992a25 |
r = 0;
|
|
Packit |
992a25 |
while((t = sysreadf(fd,buf,action)) > 0)
|
|
Packit |
992a25 |
{ r += t;
|
|
Packit |
992a25 |
for(endbuf = buf+t; buf < endbuf;)
|
|
Packit |
992a25 |
if(*buf++ == rc)
|
|
Packit |
992a25 |
action -= 1;
|
|
Packit |
992a25 |
if(action == 0 || (int)(n-r) < action)
|
|
Packit |
992a25 |
break;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
return r == 0 ? t : r;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* successful peek, find the record end */
|
|
Packit |
992a25 |
if(rc >= 0)
|
|
Packit |
992a25 |
{ reg char* sp;
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
t = action == 0 ? 1 : action < 0 ? -action : action;
|
|
Packit |
992a25 |
for(endbuf = (sp = buf)+r; sp < endbuf; )
|
|
Packit |
992a25 |
if(*sp++ == rc)
|
|
Packit |
992a25 |
if((t -= 1) == 0)
|
|
Packit |
992a25 |
break;
|
|
Packit |
992a25 |
r = sp - buf;
|
|
Packit |
992a25 |
}
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
/* advance */
|
|
Packit |
992a25 |
if(action <= 0)
|
|
Packit |
992a25 |
r = sysreadf(fd,buf,r);
|
|
Packit |
992a25 |
|
|
Packit |
992a25 |
return r;
|
|
Packit |
992a25 |
}
|