14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1982-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * David Korn <dgk@research.att.com> *
184887Schin * *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin
224887Schin /*
234887Schin * Input/output file processing
244887Schin *
254887Schin * David Korn
264887Schin * AT&T Labs
274887Schin *
284887Schin */
294887Schin
304887Schin #include "defs.h"
314887Schin #include <fcin.h>
324887Schin #include <ls.h>
334887Schin #include <stdarg.h>
344887Schin #include <regex.h>
354887Schin #include "variables.h"
364887Schin #include "path.h"
374887Schin #include "io.h"
384887Schin #include "jobs.h"
394887Schin #include "shnodes.h"
404887Schin #include "history.h"
414887Schin #include "edit.h"
424887Schin #include "timeout.h"
434887Schin #include "FEATURE/externs"
444887Schin #include "FEATURE/dynamic"
454887Schin #include "FEATURE/poll"
464887Schin
474887Schin #ifdef FNDELAY
484887Schin # ifdef EAGAIN
494887Schin # if EAGAIN!=EWOULDBLOCK
504887Schin # undef EAGAIN
514887Schin # define EAGAIN EWOULDBLOCK
524887Schin # endif
534887Schin # else
544887Schin # define EAGAIN EWOULDBLOCK
554887Schin # endif /* EAGAIN */
564887Schin # ifndef O_NONBLOCK
574887Schin # define O_NONBLOCK FNDELAY
584887Schin # endif /* !O_NONBLOCK */
594887Schin #endif /* FNDELAY */
604887Schin
614887Schin #ifndef O_SERVICE
624887Schin # define O_SERVICE O_NOCTTY
634887Schin #endif
644887Schin
654887Schin #define RW_ALL (S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH)
664887Schin
674887Schin static void *timeout;
684887Schin static int (*fdnotify)(int,int);
694887Schin
704887Schin #if defined(_lib_socket) && defined(_sys_socket) && defined(_hdr_netinet_in)
714887Schin # include <sys/socket.h>
724887Schin # include <netdb.h>
734887Schin # include <netinet/in.h>
744887Schin # if !defined(htons) && !_lib_htons
754887Schin # define htons(x) (x)
764887Schin # endif
774887Schin # if !defined(htonl) && !_lib_htonl
784887Schin # define htonl(x) (x)
794887Schin # endif
804887Schin # if _pipe_socketpair
818462SApril.Chin@Sun.COM # ifndef SHUT_RD
828462SApril.Chin@Sun.COM # define SHUT_RD 0
838462SApril.Chin@Sun.COM # endif
848462SApril.Chin@Sun.COM # ifndef SHUT_WR
858462SApril.Chin@Sun.COM # define SHUT_WR 1
868462SApril.Chin@Sun.COM # endif
874887Schin # if _socketpair_shutdown_mode
888462SApril.Chin@Sun.COM # define pipe(v) ((socketpair(AF_UNIX,SOCK_STREAM,0,v)<0||shutdown((v)[1],SHUT_RD)<0||fchmod((v)[1],S_IWUSR)<0||shutdown((v)[0],SHUT_WR)<0||fchmod((v)[0],S_IRUSR)<0)?(-1):0)
894887Schin # else
908462SApril.Chin@Sun.COM # define pipe(v) ((socketpair(AF_UNIX,SOCK_STREAM,0,v)<0||shutdown((v)[1],SHUT_RD)<0||shutdown((v)[0],SHUT_WR)<0)?(-1):0)
914887Schin # endif
924887Schin # endif
934887Schin
944887Schin #if !_lib_getaddrinfo
954887Schin
964887Schin #undef EAI_SYSTEM
974887Schin
984887Schin #define EAI_SYSTEM 1
994887Schin
1004887Schin #undef addrinfo
1014887Schin #undef getaddrinfo
1024887Schin #undef freeaddrinfo
1034887Schin
1044887Schin #define addrinfo local_addrinfo
1054887Schin #define getaddrinfo local_getaddrinfo
1064887Schin #define freeaddrinfo local_freeaddrinfo
1074887Schin
1084887Schin struct addrinfo
1094887Schin {
1104887Schin int ai_flags;
1114887Schin int ai_family;
1124887Schin int ai_socktype;
1134887Schin int ai_protocol;
1144887Schin socklen_t ai_addrlen;
1154887Schin struct sockaddr* ai_addr;
1164887Schin struct addrinfo* ai_next;
1174887Schin };
1184887Schin
1194887Schin static int
getaddrinfo(const char * node,const char * service,const struct addrinfo * hint,struct addrinfo ** addr)1204887Schin getaddrinfo(const char* node, const char* service, const struct addrinfo* hint, struct addrinfo **addr)
1214887Schin {
1224887Schin unsigned long ip_addr = 0;
1234887Schin unsigned short ip_port = 0;
1244887Schin struct addrinfo* ap;
1254887Schin struct hostent* hp;
1264887Schin struct sockaddr_in* ip;
1274887Schin char* prot;
1284887Schin long n;
1294887Schin
1304887Schin if (!(hp = gethostbyname(node)) || hp->h_addrtype!=AF_INET || hp->h_length>sizeof(struct in_addr))
1314887Schin {
1324887Schin errno = EADDRNOTAVAIL;
1334887Schin return EAI_SYSTEM;
1344887Schin }
1354887Schin ip_addr = (unsigned long)((struct in_addr*)hp->h_addr)->s_addr;
1364887Schin if ((n = strtol(service, &prot, 10)) > 0 && n <= USHRT_MAX && !*prot)
1374887Schin ip_port = htons((unsigned short)n);
1384887Schin else
1394887Schin {
1404887Schin struct servent* sp;
1414887Schin const char* protocol = 0;
1424887Schin
1434887Schin if (hint)
1444887Schin switch (hint->ai_socktype)
1454887Schin {
1464887Schin case SOCK_STREAM:
1474887Schin switch (hint->ai_protocol)
1484887Schin {
1494887Schin case 0:
1504887Schin protocol = "tcp";
1514887Schin break;
1524887Schin #ifdef IPPROTO_SCTP
1534887Schin case IPPROTO_SCTP:
1544887Schin protocol = "sctp";
1554887Schin break;
1564887Schin #endif
1574887Schin }
1584887Schin break;
1594887Schin case SOCK_DGRAM:
1604887Schin protocol = "udp";
1614887Schin break;
1624887Schin }
1634887Schin if (!protocol)
1644887Schin {
1654887Schin errno = EPROTONOSUPPORT;
1664887Schin return 1;
1674887Schin }
1684887Schin if (sp = getservbyname(service, protocol))
1694887Schin ip_port = sp->s_port;
1704887Schin }
1714887Schin if (!ip_port)
1724887Schin {
1734887Schin errno = EADDRNOTAVAIL;
1744887Schin return EAI_SYSTEM;
1754887Schin }
1764887Schin if (!(ap = newof(0, struct addrinfo, 1, sizeof(struct sockaddr_in))))
1774887Schin return EAI_SYSTEM;
1784887Schin if (hint)
1794887Schin *ap = *hint;
1804887Schin ap->ai_family = hp->h_addrtype;
1814887Schin ap->ai_addrlen = sizeof(struct sockaddr_in);
1824887Schin ap->ai_addr = (struct sockaddr *)(ap+1);
1834887Schin ip = (struct sockaddr_in *)ap->ai_addr;
1844887Schin ip->sin_family = AF_INET;
1854887Schin ip->sin_port = ip_port;
1864887Schin ip->sin_addr.s_addr = ip_addr;
1874887Schin *addr = ap;
1884887Schin return 0;
1894887Schin }
1904887Schin
1914887Schin static void
freeaddrinfo(struct addrinfo * ap)1924887Schin freeaddrinfo(struct addrinfo* ap)
1934887Schin {
1944887Schin if (ap)
1954887Schin free(ap);
1964887Schin }
1974887Schin
1984887Schin #endif
1994887Schin
2004887Schin /*
2014887Schin * return <protocol>/<host>/<service> fd
2024887Schin */
2034887Schin
2044887Schin typedef int (*Inetintr_f)(struct addrinfo*, void*);
2054887Schin
2064887Schin static int
inetopen(const char * path,int server,Inetintr_f onintr,void * handle)2074887Schin inetopen(const char* path, int server, Inetintr_f onintr, void* handle)
2084887Schin {
2094887Schin register char* s;
2104887Schin register char* t;
2114887Schin int fd;
2124887Schin int oerrno;
2134887Schin struct addrinfo hint;
2144887Schin struct addrinfo* addr;
2154887Schin struct addrinfo* p;
2164887Schin
2174887Schin memset(&hint, 0, sizeof(hint));
2184887Schin hint.ai_family = PF_UNSPEC;
2194887Schin switch (path[0])
2204887Schin {
2214887Schin #ifdef IPPROTO_SCTP
2224887Schin case 's':
2234887Schin if (path[1]!='c' || path[2]!='t' || path[3]!='p' || path[4]!='/')
2244887Schin {
2254887Schin errno = ENOTDIR;
2264887Schin return -1;
2274887Schin }
2284887Schin hint.ai_socktype = SOCK_STREAM;
2294887Schin hint.ai_protocol = IPPROTO_SCTP;
2304887Schin path += 5;
2314887Schin break;
2324887Schin #endif
2334887Schin case 't':
2344887Schin if (path[1]!='c' || path[2]!='p' || path[3]!='/')
2354887Schin {
2364887Schin errno = ENOTDIR;
2374887Schin return -1;
2384887Schin }
2394887Schin hint.ai_socktype = SOCK_STREAM;
2404887Schin path += 4;
2414887Schin break;
2424887Schin case 'u':
2434887Schin if (path[1]!='d' || path[2]!='p' || path[3]!='/')
2444887Schin {
2454887Schin errno = ENOTDIR;
2464887Schin return -1;
2474887Schin }
2484887Schin hint.ai_socktype = SOCK_DGRAM;
2494887Schin path += 4;
2504887Schin break;
2514887Schin default:
2524887Schin errno = ENOTDIR;
2534887Schin return -1;
2544887Schin }
2554887Schin if (!(s = strdup(path)))
2564887Schin return -1;
2574887Schin if (t = strchr(s, '/'))
2584887Schin {
2594887Schin *t++ = 0;
2604887Schin if (streq(s, "local"))
2614887Schin s = "localhost";
2624887Schin fd = getaddrinfo(s, t, &hint, &addr);
2634887Schin }
2644887Schin else
2654887Schin fd = -1;
2664887Schin free(s);
2674887Schin if (fd)
2684887Schin {
2694887Schin if (fd != EAI_SYSTEM)
2704887Schin errno = ENOTDIR;
2714887Schin return -1;
2724887Schin }
2734887Schin oerrno = errno;
2744887Schin errno = 0;
2754887Schin fd = -1;
2764887Schin for (p = addr; p; p = p->ai_next)
2774887Schin {
2784887Schin /*
2794887Schin * some api's don't take the hint
2804887Schin */
2814887Schin
2824887Schin if (!p->ai_protocol)
2834887Schin p->ai_protocol = hint.ai_protocol;
2844887Schin if (!p->ai_socktype)
2854887Schin p->ai_socktype = hint.ai_socktype;
2864887Schin while ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) >= 0)
2874887Schin {
2884887Schin if (server && !bind(fd, p->ai_addr, p->ai_addrlen) && !listen(fd, 5) || !server && !connect(fd, p->ai_addr, p->ai_addrlen))
2894887Schin goto done;
2904887Schin close(fd);
2914887Schin fd = -1;
2924887Schin if (errno != EINTR || !onintr)
2934887Schin break;
2944887Schin if ((*onintr)(addr, handle))
2954887Schin return -1;
2964887Schin }
2974887Schin }
2984887Schin done:
2994887Schin freeaddrinfo(addr);
3004887Schin if (fd >= 0)
3014887Schin errno = oerrno;
3024887Schin return fd;
3034887Schin }
3044887Schin
3054887Schin #else
3064887Schin
3074887Schin #undef O_SERVICE
3084887Schin
3094887Schin #endif
3104887Schin
3114887Schin struct fdsave
3124887Schin {
3134887Schin int orig_fd; /* original file descriptor */
3144887Schin int save_fd; /* saved file descriptor */
3154887Schin int subshell; /* saved for subshell */
3168462SApril.Chin@Sun.COM char *tname; /* name used with >; */
3174887Schin };
3184887Schin
3194887Schin static int subexcept(Sfio_t*, int, void*, Sfdisc_t*);
3204887Schin static int eval_exceptf(Sfio_t*, int, void*, Sfdisc_t*);
3214887Schin static int slowexcept(Sfio_t*, int, void*, Sfdisc_t*);
3224887Schin static int pipeexcept(Sfio_t*, int, void*, Sfdisc_t*);
3234887Schin static ssize_t piperead(Sfio_t*, void*, size_t, Sfdisc_t*);
3244887Schin static ssize_t slowread(Sfio_t*, void*, size_t, Sfdisc_t*);
3254887Schin static ssize_t subread(Sfio_t*, void*, size_t, Sfdisc_t*);
3264887Schin static ssize_t tee_write(Sfio_t*,const void*,size_t,Sfdisc_t*);
3274887Schin static int io_prompt(Sfio_t*,int);
3288462SApril.Chin@Sun.COM static int io_heredoc(Shell_t*,register struct ionod*, const char*, int);
3298462SApril.Chin@Sun.COM static void sftrack(Sfio_t*,int,void*);
3304887Schin static const Sfdisc_t eval_disc = { NULL, NULL, NULL, eval_exceptf, NULL};
3314887Schin static Sfdisc_t tee_disc = {NULL,tee_write,NULL,NULL,NULL};
3328462SApril.Chin@Sun.COM static Sfio_t *subopen(Shell_t *,Sfio_t*, off_t, long);
3334887Schin static const Sfdisc_t sub_disc = { subread, 0, 0, subexcept, 0 };
3344887Schin
3354887Schin struct subfile
3364887Schin {
3374887Schin Sfdisc_t disc;
3384887Schin Sfio_t *oldsp;
3394887Schin off_t offset;
3404887Schin long size;
3414887Schin long left;
3424887Schin };
3434887Schin
3444887Schin struct Eof
3454887Schin {
3464887Schin Namfun_t hdr;
3474887Schin int fd;
3484887Schin };
3494887Schin
nget_cur_eof(register Namval_t * np,Namfun_t * fp)3504887Schin static Sfdouble_t nget_cur_eof(register Namval_t* np, Namfun_t *fp)
3514887Schin {
3524887Schin struct Eof *ep = (struct Eof*)fp;
3534887Schin Sfoff_t end, cur =lseek(ep->fd, (Sfoff_t)0, SEEK_CUR);
3544887Schin if(*np->nvname=='C')
3554887Schin return((Sfdouble_t)cur);
3564887Schin if(cur<0)
3574887Schin return((Sfdouble_t)-1);
3584887Schin end =lseek(ep->fd, (Sfoff_t)0, SEEK_END);
3594887Schin lseek(ep->fd, (Sfoff_t)0, SEEK_CUR);
3604887Schin return((Sfdouble_t)end);
3614887Schin }
3624887Schin
3634887Schin static const Namdisc_t EOF_disc = { sizeof(struct Eof), 0, 0, nget_cur_eof};
3644887Schin
3654887Schin #define MATCH_BUFF (64*1024)
3664887Schin struct Match
3674887Schin {
3684887Schin Sfoff_t offset;
3694887Schin char *base;
3704887Schin };
3714887Schin
matchf(void * handle,char * ptr,size_t size)3724887Schin static int matchf(void *handle, char *ptr, size_t size)
3734887Schin {
3744887Schin struct Match *mp = (struct Match*)handle;
3754887Schin mp->offset += (ptr-mp->base);
3764887Schin return(1);
3774887Schin }
3784887Schin
3794887Schin
3804887Schin static struct fdsave *filemap;
3814887Schin static short filemapsize;
3824887Schin
3834887Schin /* ======== input output and file copying ======== */
3844887Schin
sh_ioinit(Shell_t * shp)3858462SApril.Chin@Sun.COM void sh_ioinit(Shell_t *shp)
3864887Schin {
3874887Schin register int n;
3884887Schin filemapsize = 8;
3898462SApril.Chin@Sun.COM filemap = (struct fdsave*)malloc(filemapsize*sizeof(struct fdsave));
3904887Schin #if SHOPT_FASTPIPE
3918462SApril.Chin@Sun.COM n = shp->lim.open_max+2;
3924887Schin #else
3938462SApril.Chin@Sun.COM n = shp->lim.open_max;
3944887Schin #endif /* SHOPT_FASTPIPE */
3958462SApril.Chin@Sun.COM shp->fdstatus = (unsigned char*)malloc((unsigned)n);
3968462SApril.Chin@Sun.COM memset((char*)shp->fdstatus,0,n);
3978462SApril.Chin@Sun.COM shp->fdptrs = (int**)malloc(n*sizeof(int*));
3988462SApril.Chin@Sun.COM memset((char*)shp->fdptrs,0,n*sizeof(int*));
3998462SApril.Chin@Sun.COM shp->sftable = (Sfio_t**)malloc(n*sizeof(Sfio_t*));
4008462SApril.Chin@Sun.COM memset((char*)shp->sftable,0,n*sizeof(Sfio_t*));
4018462SApril.Chin@Sun.COM shp->sftable[0] = sfstdin;
4028462SApril.Chin@Sun.COM shp->sftable[1] = sfstdout;
4038462SApril.Chin@Sun.COM shp->sftable[2] = sfstderr;
4044887Schin sfnotify(sftrack);
4058462SApril.Chin@Sun.COM sh_iostream(shp,0);
4064887Schin /* all write steams are in the same pool and share outbuff */
4078462SApril.Chin@Sun.COM shp->outpool = sfopen(NIL(Sfio_t*),NIL(char*),"sw"); /* pool identifier */
40810898Sroland.mainz@nrubsig.org shp->outbuff = (char*)malloc(IOBSIZE+4);
4098462SApril.Chin@Sun.COM shp->errbuff = (char*)malloc(IOBSIZE/4);
4108462SApril.Chin@Sun.COM sfsetbuf(sfstderr,shp->errbuff,IOBSIZE/4);
4118462SApril.Chin@Sun.COM sfsetbuf(sfstdout,shp->outbuff,IOBSIZE);
4128462SApril.Chin@Sun.COM sfpool(sfstdout,shp->outpool,SF_WRITE);
4138462SApril.Chin@Sun.COM sfpool(sfstderr,shp->outpool,SF_WRITE);
4144887Schin sfset(sfstdout,SF_LINE,0);
4158462SApril.Chin@Sun.COM sfset(sfstderr,SF_LINE,0);
4168462SApril.Chin@Sun.COM sfset(sfstdin,SF_SHARE|SF_PUBLIC,1);
4178462SApril.Chin@Sun.COM }
4188462SApril.Chin@Sun.COM
4198462SApril.Chin@Sun.COM /*
4208462SApril.Chin@Sun.COM * Handle output stream exceptions
4218462SApril.Chin@Sun.COM */
outexcept(register Sfio_t * iop,int type,void * data,Sfdisc_t * handle)4228462SApril.Chin@Sun.COM static int outexcept(register Sfio_t *iop,int type,void *data,Sfdisc_t *handle)
4238462SApril.Chin@Sun.COM {
4248462SApril.Chin@Sun.COM static int active = 0;
4258462SApril.Chin@Sun.COM
4268462SApril.Chin@Sun.COM NOT_USED(handle);
4278462SApril.Chin@Sun.COM if(type==SF_DPOP || type==SF_FINAL)
4288462SApril.Chin@Sun.COM free((void*)handle);
4298462SApril.Chin@Sun.COM else if(type==SF_WRITE && (*(ssize_t*)data)<0 && sffileno(iop)!=2)
4308462SApril.Chin@Sun.COM switch (errno)
4318462SApril.Chin@Sun.COM {
4328462SApril.Chin@Sun.COM case EINTR:
4338462SApril.Chin@Sun.COM case EPIPE:
4348462SApril.Chin@Sun.COM #ifdef ECONNRESET
4358462SApril.Chin@Sun.COM case ECONNRESET:
4368462SApril.Chin@Sun.COM #endif
4378462SApril.Chin@Sun.COM #ifdef ESHUTDOWN
4388462SApril.Chin@Sun.COM case ESHUTDOWN:
4398462SApril.Chin@Sun.COM #endif
4408462SApril.Chin@Sun.COM break;
4418462SApril.Chin@Sun.COM default:
4428462SApril.Chin@Sun.COM if(!active)
4438462SApril.Chin@Sun.COM {
4448462SApril.Chin@Sun.COM int mode = ((struct checkpt*)sh.jmplist)->mode;
4458462SApril.Chin@Sun.COM int save = errno;
4468462SApril.Chin@Sun.COM active = 1;
4478462SApril.Chin@Sun.COM ((struct checkpt*)sh.jmplist)->mode = 0;
4488462SApril.Chin@Sun.COM sfpurge(iop);
4498462SApril.Chin@Sun.COM sfpool(iop,NIL(Sfio_t*),SF_WRITE);
4508462SApril.Chin@Sun.COM errno = save;
4518462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_system(1),e_badwrite,sffileno(iop));
4528462SApril.Chin@Sun.COM active = 0;
4538462SApril.Chin@Sun.COM ((struct checkpt*)sh.jmplist)->mode = mode;
4548462SApril.Chin@Sun.COM sh_exit(1);
4558462SApril.Chin@Sun.COM }
4568462SApril.Chin@Sun.COM return(-1);
4578462SApril.Chin@Sun.COM }
4588462SApril.Chin@Sun.COM return(0);
4594887Schin }
4604887Schin
4614887Schin /*
4624887Schin * create or initialize a stream corresponding to descriptor <fd>
4634887Schin * a buffer with room for a sentinal is allocated for a read stream.
4644887Schin * A discipline is inserted when read stream is a tty or a pipe
4654887Schin * For output streams, the buffer is set to sh.output and put into
4664887Schin * the sh.outpool synchronization pool
4674887Schin */
sh_iostream(Shell_t * shp,register int fd)4688462SApril.Chin@Sun.COM Sfio_t *sh_iostream(Shell_t *shp, register int fd)
4694887Schin {
4704887Schin register Sfio_t *iop;
4718462SApril.Chin@Sun.COM register int status = sh_iocheckfd(shp,fd);
4724887Schin register int flags = SF_WRITE;
4734887Schin char *bp;
4748462SApril.Chin@Sun.COM Sfdisc_t *dp;
4754887Schin #if SHOPT_FASTPIPE
4768462SApril.Chin@Sun.COM if(fd>=shp->lim.open_max)
4778462SApril.Chin@Sun.COM return(shp->sftable[fd]);
4784887Schin #endif /* SHOPT_FASTPIPE */
4794887Schin if(status==IOCLOSE)
4804887Schin {
4814887Schin switch(fd)
4824887Schin {
4834887Schin case 0:
4844887Schin return(sfstdin);
4854887Schin case 1:
4864887Schin return(sfstdout);
4874887Schin case 2:
4884887Schin return(sfstderr);
4894887Schin }
4904887Schin return(NIL(Sfio_t*));
4914887Schin }
4924887Schin if(status&IOREAD)
4934887Schin {
4944887Schin if(!(bp = (char *)malloc(IOBSIZE+1)))
4954887Schin return(NIL(Sfio_t*));
4964887Schin flags |= SF_READ;
4974887Schin if(!(status&IOWRITE))
4984887Schin flags &= ~SF_WRITE;
4994887Schin }
5004887Schin else
5018462SApril.Chin@Sun.COM bp = shp->outbuff;
5024887Schin if(status&IODUP)
5034887Schin flags |= SF_SHARE|SF_PUBLIC;
5048462SApril.Chin@Sun.COM if((iop = shp->sftable[fd]) && sffileno(iop)>=0)
5054887Schin sfsetbuf(iop, bp, IOBSIZE);
5064887Schin else if(!(iop=sfnew((fd<=2?iop:0),bp,IOBSIZE,fd,flags)))
5074887Schin return(NIL(Sfio_t*));
5088462SApril.Chin@Sun.COM dp = newof(0,Sfdisc_t,1,0);
5094887Schin if(status&IOREAD)
5104887Schin {
5114887Schin sfset(iop,SF_MALLOC,1);
5128462SApril.Chin@Sun.COM if(!(status&IOWRITE))
5138462SApril.Chin@Sun.COM sfset(iop,SF_IOCHECK,1);
5148462SApril.Chin@Sun.COM dp->exceptf = slowexcept;
5158462SApril.Chin@Sun.COM if(status&IOTTY)
5168462SApril.Chin@Sun.COM dp->readf = slowread;
5178462SApril.Chin@Sun.COM else if(status&IONOSEEK)
5184887Schin {
5198462SApril.Chin@Sun.COM dp->readf = piperead;
5208462SApril.Chin@Sun.COM sfset(iop, SF_IOINTR,1);
5214887Schin }
5228462SApril.Chin@Sun.COM else
5238462SApril.Chin@Sun.COM dp->readf = 0;
5248462SApril.Chin@Sun.COM dp->seekf = 0;
5258462SApril.Chin@Sun.COM dp->writef = 0;
5264887Schin }
5274887Schin else
5288462SApril.Chin@Sun.COM {
5298462SApril.Chin@Sun.COM dp->exceptf = outexcept;
5308462SApril.Chin@Sun.COM sfpool(iop,shp->outpool,SF_WRITE);
5318462SApril.Chin@Sun.COM }
5328462SApril.Chin@Sun.COM sfdisc(iop,dp);
5338462SApril.Chin@Sun.COM shp->sftable[fd] = iop;
5344887Schin return(iop);
5354887Schin }
5364887Schin
5374887Schin /*
5384887Schin * preserve the file descriptor or stream by moving it
5394887Schin */
io_preserve(Shell_t * shp,register Sfio_t * sp,register int f2)5408462SApril.Chin@Sun.COM static void io_preserve(Shell_t* shp, register Sfio_t *sp, register int f2)
5414887Schin {
5424887Schin register int fd;
5434887Schin if(sp)
5444887Schin fd = sfsetfd(sp,10);
5454887Schin else
5464887Schin fd = sh_fcntl(f2,F_DUPFD,10);
5478462SApril.Chin@Sun.COM if(f2==shp->infd)
5488462SApril.Chin@Sun.COM shp->infd = fd;
5494887Schin if(fd<0)
55010898Sroland.mainz@nrubsig.org {
55110898Sroland.mainz@nrubsig.org shp->toomany = 1;
55210898Sroland.mainz@nrubsig.org ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT;
5534887Schin errormsg(SH_DICT,ERROR_system(1),e_toomany);
55410898Sroland.mainz@nrubsig.org }
5558462SApril.Chin@Sun.COM if(shp->fdptrs[fd]=shp->fdptrs[f2])
5564887Schin {
5574887Schin if(f2==job.fd)
5584887Schin job.fd=fd;
5598462SApril.Chin@Sun.COM *shp->fdptrs[fd] = fd;
5608462SApril.Chin@Sun.COM shp->fdptrs[f2] = 0;
5614887Schin }
5628462SApril.Chin@Sun.COM shp->sftable[fd] = sp;
5638462SApril.Chin@Sun.COM shp->fdstatus[fd] = shp->fdstatus[f2];
5644887Schin if(fcntl(f2,F_GETFD,0)&1)
5654887Schin {
5664887Schin fcntl(fd,F_SETFD,FD_CLOEXEC);
5678462SApril.Chin@Sun.COM shp->fdstatus[fd] |= IOCLEX;
5684887Schin }
5698462SApril.Chin@Sun.COM shp->sftable[f2] = 0;
5704887Schin }
5714887Schin
5724887Schin /*
5734887Schin * Given a file descriptor <f1>, move it to a file descriptor number <f2>
5744887Schin * If <f2> is needed move it, otherwise it is closed first.
5754887Schin * The original stream <f1> is closed.
5764887Schin * The new file descriptor <f2> is returned;
5774887Schin */
sh_iorenumber(Shell_t * shp,register int f1,register int f2)5788462SApril.Chin@Sun.COM int sh_iorenumber(Shell_t *shp, register int f1,register int f2)
5794887Schin {
5808462SApril.Chin@Sun.COM register Sfio_t *sp = shp->sftable[f2];
5814887Schin if(f1!=f2)
5824887Schin {
5834887Schin /* see whether file descriptor is in use */
5844887Schin if(sh_inuse(f2) || (f2>2 && sp))
5854887Schin {
5868462SApril.Chin@Sun.COM if(!(shp->inuse_bits&(1<<f2)))
5878462SApril.Chin@Sun.COM io_preserve(shp,sp,f2);
5884887Schin sp = 0;
5894887Schin }
5904887Schin else if(f2==0)
5918462SApril.Chin@Sun.COM shp->st.ioset = 1;
5924887Schin sh_close(f2);
5934887Schin if(f2<=2 && sp)
5944887Schin {
5958462SApril.Chin@Sun.COM register Sfio_t *spnew = sh_iostream(shp,f1);
5968462SApril.Chin@Sun.COM shp->fdstatus[f2] = (shp->fdstatus[f1]&~IOCLEX);
5974887Schin sfsetfd(spnew,f2);
5984887Schin sfswap(spnew,sp);
5994887Schin sfset(sp,SF_SHARE|SF_PUBLIC,1);
6004887Schin }
6014887Schin else
6024887Schin {
6038462SApril.Chin@Sun.COM shp->fdstatus[f2] = (shp->fdstatus[f1]&~IOCLEX);
6044887Schin if((f2 = sh_fcntl(f1,F_DUPFD, f2)) < 0)
6054887Schin errormsg(SH_DICT,ERROR_system(1),e_file+4);
6064887Schin else if(f2 <= 2)
6078462SApril.Chin@Sun.COM sh_iostream(shp,f2);
6084887Schin }
6094887Schin if(sp)
6108462SApril.Chin@Sun.COM shp->sftable[f1] = 0;
6114887Schin sh_close(f1);
6124887Schin }
6134887Schin return(f2);
6144887Schin }
6154887Schin
6164887Schin /*
6174887Schin * close a file descriptor and update stream table and attributes
6184887Schin */
sh_close(register int fd)6194887Schin int sh_close(register int fd)
6204887Schin {
6214887Schin register Sfio_t *sp;
6224887Schin register int r = 0;
6234887Schin if(fd<0)
6244887Schin return(-1);
6254887Schin if(!(sp=sh.sftable[fd]) || sfclose(sp) < 0)
6264887Schin {
6274887Schin if(fdnotify)
6284887Schin (*fdnotify)(fd,SH_FDCLOSE);
6294887Schin r=close(fd);
6304887Schin }
6314887Schin if(fd>2)
6324887Schin sh.sftable[fd] = 0;
6334887Schin sh.fdstatus[fd] = IOCLOSE;
6344887Schin if(sh.fdptrs[fd])
6354887Schin *sh.fdptrs[fd] = -1;
6364887Schin sh.fdptrs[fd] = 0;
6374887Schin if(fd < 10)
6384887Schin sh.inuse_bits &= ~(1<<fd);
6394887Schin return(r);
6404887Schin }
6414887Schin
6428462SApril.Chin@Sun.COM #ifdef O_SERVICE
6438462SApril.Chin@Sun.COM
6444887Schin static int
onintr(struct addrinfo * addr,void * handle)6454887Schin onintr(struct addrinfo* addr, void* handle)
6464887Schin {
6474887Schin Shell_t* sh = (Shell_t*)handle;
6484887Schin
6494887Schin if (sh->trapnote&SH_SIGSET)
6504887Schin {
6514887Schin freeaddrinfo(addr);
6524887Schin sh_exit(SH_EXITSIG);
6534887Schin return -1;
6544887Schin }
6554887Schin if (sh->trapnote)
6564887Schin sh_chktrap();
6574887Schin return 0;
6584887Schin }
6594887Schin
6608462SApril.Chin@Sun.COM #endif
6618462SApril.Chin@Sun.COM
6624887Schin /*
6634887Schin * Mimic open(2) with checks for pseudo /dev/ files.
6644887Schin */
sh_open(register const char * path,int flags,...)6654887Schin int sh_open(register const char *path, int flags, ...)
6664887Schin {
6678462SApril.Chin@Sun.COM Shell_t *shp = &sh;
6684887Schin register int fd = -1;
6694887Schin mode_t mode;
6704887Schin char *e;
6714887Schin va_list ap;
6724887Schin va_start(ap, flags);
6734887Schin mode = (flags & O_CREAT) ? va_arg(ap, int) : 0;
6744887Schin va_end(ap);
6754887Schin errno = 0;
6764887Schin if(*path==0)
6774887Schin {
6784887Schin errno = ENOENT;
6794887Schin return(-1);
6804887Schin }
6814887Schin if (path[0]=='/' && path[1]=='d' && path[2]=='e' && path[3]=='v' && path[4]=='/')
6824887Schin {
6834887Schin switch (path[5])
6844887Schin {
6854887Schin case 'f':
6864887Schin if (path[6]=='d' && path[7]=='/')
6874887Schin {
6884887Schin fd = (int)strtol(path+8, &e, 10);
6894887Schin if (*e)
6904887Schin fd = -1;
6914887Schin }
6924887Schin break;
6934887Schin case 's':
6944887Schin if (path[6]=='t' && path[7]=='d')
6954887Schin switch (path[8])
6964887Schin {
6974887Schin case 'e':
6984887Schin if (path[9]=='r' && path[10]=='r' && !path[11])
6994887Schin fd = 2;
7004887Schin break;
7014887Schin case 'i':
7024887Schin if (path[9]=='n' && !path[10])
7034887Schin fd = 0;
7044887Schin break;
7054887Schin case 'o':
7064887Schin if (path[9]=='u' && path[10]=='t' && !path[11])
7074887Schin fd = 1;
7084887Schin break;
7094887Schin }
7104887Schin }
7114887Schin #ifdef O_SERVICE
7124887Schin if (fd < 0)
7134887Schin {
7144887Schin if ((fd = inetopen(path+5, !!(flags & O_SERVICE), onintr, &sh)) < 0 && errno != ENOTDIR)
7154887Schin return -1;
7164887Schin if (fd >= 0)
7174887Schin goto ok;
7184887Schin }
7194887Schin #endif
7204887Schin }
7214887Schin if (fd >= 0)
7224887Schin {
72310898Sroland.mainz@nrubsig.org int nfd= -1;
72410898Sroland.mainz@nrubsig.org if (flags & O_CREAT)
72510898Sroland.mainz@nrubsig.org {
72610898Sroland.mainz@nrubsig.org struct stat st;
72710898Sroland.mainz@nrubsig.org if (stat(path,&st) >=0)
72810898Sroland.mainz@nrubsig.org nfd = open(path,flags,st.st_mode);
72910898Sroland.mainz@nrubsig.org }
73010898Sroland.mainz@nrubsig.org else
73110898Sroland.mainz@nrubsig.org nfd = open(path,flags);
73210898Sroland.mainz@nrubsig.org if(nfd>=0)
73310898Sroland.mainz@nrubsig.org {
73410898Sroland.mainz@nrubsig.org fd = nfd;
73510898Sroland.mainz@nrubsig.org goto ok;
73610898Sroland.mainz@nrubsig.org }
7378462SApril.Chin@Sun.COM if((mode=sh_iocheckfd(shp,fd))==IOCLOSE)
7384887Schin return(-1);
7394887Schin flags &= O_ACCMODE;
7404887Schin if(!(mode&IOWRITE) && ((flags==O_WRONLY) || (flags==O_RDWR)))
7414887Schin return(-1);
7424887Schin if(!(mode&IOREAD) && ((flags==O_RDONLY) || (flags==O_RDWR)))
7434887Schin return(-1);
7444887Schin if((fd=dup(fd))<0)
7454887Schin return(-1);
7464887Schin }
74710898Sroland.mainz@nrubsig.org else
74810898Sroland.mainz@nrubsig.org {
74910898Sroland.mainz@nrubsig.org #if SHOPT_REGRESS
75010898Sroland.mainz@nrubsig.org char buf[PATH_MAX];
75110898Sroland.mainz@nrubsig.org if(strncmp(path,"/etc/",5)==0)
75210898Sroland.mainz@nrubsig.org {
75310898Sroland.mainz@nrubsig.org sfsprintf(buf, sizeof(buf), "%s%s", sh_regress_etc(path, __LINE__, __FILE__), path+4);
75410898Sroland.mainz@nrubsig.org path = buf;
75510898Sroland.mainz@nrubsig.org }
75610898Sroland.mainz@nrubsig.org #endif
75710898Sroland.mainz@nrubsig.org while((fd = open(path, flags, mode)) < 0)
75810898Sroland.mainz@nrubsig.org if(errno!=EINTR || sh.trapnote)
75910898Sroland.mainz@nrubsig.org return(-1);
76010898Sroland.mainz@nrubsig.org }
7614887Schin ok:
7624887Schin flags &= O_ACCMODE;
7634887Schin if(flags==O_WRONLY)
7644887Schin mode = IOWRITE;
7654887Schin else if(flags==O_RDWR)
7664887Schin mode = (IOREAD|IOWRITE);
7674887Schin else
7684887Schin mode = IOREAD;
7694887Schin sh.fdstatus[fd] = mode;
7704887Schin return(fd);
7714887Schin }
7724887Schin
7734887Schin /*
7744887Schin * Open a file for reading
7754887Schin * On failure, print message.
7764887Schin */
sh_chkopen(register const char * name)7774887Schin int sh_chkopen(register const char *name)
7784887Schin {
7794887Schin register int fd = sh_open(name,O_RDONLY,0);
7804887Schin if(fd < 0)
7814887Schin errormsg(SH_DICT,ERROR_system(1),e_open,name);
7824887Schin return(fd);
7834887Schin }
7844887Schin
7854887Schin /*
7864887Schin * move open file descriptor to a number > 2
7874887Schin */
sh_iomovefd(register int fdold)7884887Schin int sh_iomovefd(register int fdold)
7894887Schin {
7904887Schin register int fdnew;
7914887Schin if(fdold<0 || fdold>2)
7924887Schin return(fdold);
7934887Schin fdnew = sh_iomovefd(dup(fdold));
7944887Schin sh.fdstatus[fdnew] = (sh.fdstatus[fdold]&~IOCLEX);
7954887Schin close(fdold);
7964887Schin sh.fdstatus[fdold] = IOCLOSE;
7974887Schin return(fdnew);
7984887Schin }
7994887Schin
8004887Schin /*
8014887Schin * create a pipe and print message on failure
8024887Schin */
sh_pipe(register int pv[])8034887Schin int sh_pipe(register int pv[])
8044887Schin {
8054887Schin int fd[2];
8064887Schin if(pipe(fd)<0 || (pv[0]=fd[0])<0 || (pv[1]=fd[1])<0)
8074887Schin errormsg(SH_DICT,ERROR_system(1),e_pipe);
8084887Schin pv[0] = sh_iomovefd(pv[0]);
8094887Schin pv[1] = sh_iomovefd(pv[1]);
8104887Schin sh.fdstatus[pv[0]] = IONOSEEK|IOREAD;
8114887Schin sh.fdstatus[pv[1]] = IONOSEEK|IOWRITE;
8124887Schin sh_subsavefd(pv[0]);
8134887Schin sh_subsavefd(pv[1]);
8144887Schin return(0);
8154887Schin }
8164887Schin
pat_seek(void * handle,const char * str,size_t sz)8174887Schin static int pat_seek(void *handle, const char *str, size_t sz)
8184887Schin {
8194887Schin char **bp = (char**)handle;
8204887Schin *bp = (char*)str;
8214887Schin return(-1);
8224887Schin }
8234887Schin
pat_line(const regex_t * rp,const char * buff,register size_t n)8244887Schin static int pat_line(const regex_t* rp, const char *buff, register size_t n)
8254887Schin {
8264887Schin register const char *cp=buff, *sp;
8274887Schin while(n>0)
8284887Schin {
8294887Schin for(sp=cp; n-->0 && *cp++ != '\n';);
8304887Schin if(regnexec(rp,sp,cp-sp, 0, (regmatch_t*)0, 0)==0)
8314887Schin return(sp-buff);
8324887Schin }
8334887Schin return(cp-buff);
8344887Schin }
8354887Schin
io_patseek(Shell_t * shp,regex_t * rp,Sfio_t * sp,int flags)8368462SApril.Chin@Sun.COM static int io_patseek(Shell_t *shp, regex_t *rp, Sfio_t* sp, int flags)
8374887Schin {
8384887Schin char *cp, *match;
8398462SApril.Chin@Sun.COM int r, fd=sffileno(sp), close_exec = shp->fdstatus[fd]&IOCLEX;
8404887Schin int was_share,s=(PIPE_BUF>SF_BUFSIZE?SF_BUFSIZE:PIPE_BUF);
8414887Schin size_t n,m;
8428462SApril.Chin@Sun.COM shp->fdstatus[sffileno(sp)] |= IOCLEX;
8434887Schin if(fd==0)
8444887Schin was_share = sfset(sp,SF_SHARE,1);
8454887Schin while((cp=sfreserve(sp, -s, SF_LOCKR)) || (cp=sfreserve(sp,SF_UNBOUND, SF_LOCKR)))
8464887Schin {
8474887Schin m = n = sfvalue(sp);
8484887Schin while(n>0 && cp[n-1]!='\n')
8494887Schin n--;
8504887Schin if(n)
8514887Schin m = n;
8524887Schin r = regrexec(rp,cp,m,0,(regmatch_t*)0, 0, '\n', (void*)&match, pat_seek);
8534887Schin if(r<0)
8544887Schin m = match-cp;
8554887Schin else if(r==2)
8564887Schin {
8574887Schin if((m = pat_line(rp,cp,m)) < n)
8584887Schin r = -1;
8594887Schin }
8604887Schin if(m && (flags&IOCOPY))
8614887Schin sfwrite(sfstdout,cp,m);
8624887Schin sfread(sp,cp,m);
8634887Schin if(r<0)
8644887Schin break;
8654887Schin }
8664887Schin if(!close_exec)
8678462SApril.Chin@Sun.COM shp->fdstatus[sffileno(sp)] &= ~IOCLEX;
8684887Schin if(fd==0 && !(was_share&SF_SHARE))
8694887Schin sfset(sp, SF_SHARE,0);
8704887Schin return(0);
8714887Schin }
8724887Schin
file_offset(Shell_t * shp,int fn,char * fname)8738462SApril.Chin@Sun.COM static Sfoff_t file_offset(Shell_t *shp, int fn, char *fname)
8744887Schin {
8758462SApril.Chin@Sun.COM Sfio_t *sp = shp->sftable[fn];
8764887Schin char *cp;
8774887Schin Sfoff_t off;
8784887Schin struct Eof endf;
8798462SApril.Chin@Sun.COM Namval_t *mp = nv_open("EOF",shp->var_tree,0);
8808462SApril.Chin@Sun.COM Namval_t *pp = nv_open("CUR",shp->var_tree,0);
8814887Schin memset(&endf,0,sizeof(struct Eof));
8824887Schin endf.fd = fn;
8834887Schin endf.hdr.disc = &EOF_disc;
8844887Schin endf.hdr.nofree = 1;
8854887Schin if(mp)
8864887Schin nv_stack(mp, &endf.hdr);
8874887Schin if(pp)
8884887Schin nv_stack(pp, &endf.hdr);
8894887Schin if(sp)
8904887Schin sfsync(sp);
8914887Schin off = sh_strnum(fname, &cp, 0);
8924887Schin if(mp)
8934887Schin nv_stack(mp, NiL);
8944887Schin if(pp)
8954887Schin nv_stack(pp, NiL);
8964887Schin return(*cp?(Sfoff_t)-1:off);
8974887Schin }
8984887Schin
8994887Schin /*
9004887Schin * close a pipe
9014887Schin */
sh_pclose(register int pv[])9024887Schin void sh_pclose(register int pv[])
9034887Schin {
9044887Schin if(pv[0]>=2)
9054887Schin sh_close(pv[0]);
9064887Schin if(pv[1]>=2)
9074887Schin sh_close(pv[1]);
9084887Schin pv[0] = pv[1] = -1;
9094887Schin }
9104887Schin
io_usename(char * name,int * perm,int mode)9118462SApril.Chin@Sun.COM static char *io_usename(char *name, int *perm, int mode)
9128462SApril.Chin@Sun.COM {
9138462SApril.Chin@Sun.COM struct stat statb;
9148462SApril.Chin@Sun.COM char *tname, *sp, *ep;
9158462SApril.Chin@Sun.COM int fd,len,n=0;
9168462SApril.Chin@Sun.COM if(mode==0)
9178462SApril.Chin@Sun.COM {
9188462SApril.Chin@Sun.COM if((fd = sh_open(name,O_RDONLY,0)) > 0)
9198462SApril.Chin@Sun.COM {
9208462SApril.Chin@Sun.COM if(fstat(fd,&statb) < 0)
9218462SApril.Chin@Sun.COM return(0);
9228462SApril.Chin@Sun.COM if(!S_ISREG(statb.st_mode))
9238462SApril.Chin@Sun.COM return(0);
9248462SApril.Chin@Sun.COM *perm = statb.st_mode&(RW_ALL|(S_IXUSR|S_IXGRP|S_IXOTH));
9258462SApril.Chin@Sun.COM }
9268462SApril.Chin@Sun.COM else if(fd < 0 && errno!=ENOENT)
9278462SApril.Chin@Sun.COM return(0);
9288462SApril.Chin@Sun.COM }
9298462SApril.Chin@Sun.COM tname = sp = (char*)stakalloc((len=strlen(name)) + 5);
9308462SApril.Chin@Sun.COM if(ep = strrchr(name,'/'))
9318462SApril.Chin@Sun.COM {
9328462SApril.Chin@Sun.COM memcpy(sp,name,n=++ep-name);
9338462SApril.Chin@Sun.COM len -=n;
9348462SApril.Chin@Sun.COM sp += n;
9358462SApril.Chin@Sun.COM }
9368462SApril.Chin@Sun.COM else
9378462SApril.Chin@Sun.COM ep = name;
9388462SApril.Chin@Sun.COM *sp++ = '.';
9398462SApril.Chin@Sun.COM memcpy(sp,ep,len);
9408462SApril.Chin@Sun.COM strcpy(sp+len,".tmp");
9418462SApril.Chin@Sun.COM switch(mode)
9428462SApril.Chin@Sun.COM {
9438462SApril.Chin@Sun.COM case 1:
9448462SApril.Chin@Sun.COM rename(tname,name);
9458462SApril.Chin@Sun.COM break;
9468462SApril.Chin@Sun.COM case 2:
9478462SApril.Chin@Sun.COM unlink(tname);
9488462SApril.Chin@Sun.COM break;
9498462SApril.Chin@Sun.COM }
9508462SApril.Chin@Sun.COM return(tname);
9518462SApril.Chin@Sun.COM }
9528462SApril.Chin@Sun.COM
9534887Schin /*
9544887Schin * I/O redirection
9554887Schin * flag = 0 if files are to be restored
9564887Schin * flag = 2 if files are to be closed on exec
9574887Schin * flag = 3 when called from $( < ...), just open file and return
9584887Schin * flag = SH_SHOWME for trace only
9594887Schin */
sh_redirect(Shell_t * shp,struct ionod * iop,int flag)9608462SApril.Chin@Sun.COM int sh_redirect(Shell_t *shp,struct ionod *iop, int flag)
9614887Schin {
9624887Schin Sfoff_t off;
9634887Schin register char *fname;
9644887Schin register int fd, iof;
9654887Schin const char *message = e_open;
9664887Schin int o_mode; /* mode flag for open */
9674887Schin static char io_op[7]; /* used for -x trace info */
96810898Sroland.mainz@nrubsig.org int trunc=0, clexec=0, fn, traceon;
9698462SApril.Chin@Sun.COM int r, indx = shp->topfd, perm= -1;
9708462SApril.Chin@Sun.COM char *tname=0, *after="", *trace = shp->st.trap[SH_DEBUGTRAP];
9714887Schin Namval_t *np=0;
97210898Sroland.mainz@nrubsig.org int isstring = shp->subshell?(sfset(sfstdout,0,0)&SF_STRING):0;
9734887Schin if(flag==2)
9744887Schin clexec = 1;
9754887Schin if(iop)
9764887Schin traceon = sh_trace(NIL(char**),0);
9774887Schin for(;iop;iop=iop->ionxt)
9784887Schin {
9794887Schin iof=iop->iofile;
9804887Schin fn = (iof&IOUFD);
98110898Sroland.mainz@nrubsig.org if(fn==1 && shp->subshell && !shp->subshare && (flag==2 || isstring))
9828462SApril.Chin@Sun.COM sh_subfork();
9834887Schin io_op[0] = '0'+(iof&IOUFD);
9844887Schin if(iof&IOPUT)
9854887Schin {
9864887Schin io_op[1] = '>';
9874887Schin o_mode = O_WRONLY|O_CREAT;
9884887Schin }
9894887Schin else
9904887Schin {
9914887Schin io_op[1] = '<';
9924887Schin o_mode = O_RDONLY|O_NONBLOCK;
9934887Schin }
9944887Schin io_op[2] = 0;
9954887Schin io_op[3] = 0;
9964887Schin io_op[4] = 0;
9974887Schin fname = iop->ioname;
9984887Schin if(!(iof&IORAW))
9994887Schin {
10004887Schin if(iof&IOLSEEK)
10014887Schin {
10024887Schin struct argnod *ap = (struct argnod*)stakalloc(ARGVAL+strlen(iop->ioname));
10034887Schin memset(ap, 0, ARGVAL);
10044887Schin ap->argflag = ARG_MAC;
10054887Schin strcpy(ap->argval,iop->ioname);
10068462SApril.Chin@Sun.COM fname=sh_macpat(shp,ap,(iof&IOARITH)?ARG_ARITH:ARG_EXP);
10074887Schin }
100810898Sroland.mainz@nrubsig.org else if(iof&IOPROCSUB)
100910898Sroland.mainz@nrubsig.org {
101010898Sroland.mainz@nrubsig.org struct argnod *ap = (struct argnod*)stakalloc(ARGVAL+strlen(iop->ioname));
101110898Sroland.mainz@nrubsig.org memset(ap, 0, ARGVAL);
101210898Sroland.mainz@nrubsig.org if(iof&IOPUT)
101310898Sroland.mainz@nrubsig.org ap->argflag = ARG_RAW;
101410898Sroland.mainz@nrubsig.org ap->argchn.ap = (struct argnod*)fname;
101510898Sroland.mainz@nrubsig.org ap = sh_argprocsub(shp,ap);
101610898Sroland.mainz@nrubsig.org fname = ap->argval;
101710898Sroland.mainz@nrubsig.org }
10184887Schin else
10198462SApril.Chin@Sun.COM fname=sh_mactrim(shp,fname,(!sh_isoption(SH_NOGLOB)&&sh_isoption(SH_INTERACTIVE))?2:0);
10204887Schin }
10214887Schin errno=0;
10228462SApril.Chin@Sun.COM np = 0;
10234887Schin if(iop->iovname)
10244887Schin {
10258462SApril.Chin@Sun.COM np = nv_open(iop->iovname,shp->var_tree,NV_NOASSIGN|NV_VARNAME);
10264887Schin if(nv_isattr(np,NV_RDONLY))
10274887Schin errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np));
10284887Schin io_op[0] = '}';
10298462SApril.Chin@Sun.COM if((iof&IOLSEEK) || ((iof&IOMOV) && *fname=='-'))
10304887Schin fn = nv_getnum(np);
10314887Schin }
10324887Schin if(iof&IOLSEEK)
10334887Schin {
10344887Schin io_op[2] = '#';
10354887Schin if(iof&IOARITH)
10364887Schin {
10374887Schin strcpy(&io_op[3]," ((");
10384887Schin after = "))";
10394887Schin }
10404887Schin else if(iof&IOCOPY)
10414887Schin io_op[3] = '#';
10424887Schin goto traceit;
10434887Schin }
10444887Schin if(*fname)
10454887Schin {
10464887Schin if(iof&IODOC)
10474887Schin {
10484887Schin if(traceon)
10494887Schin sfputr(sfstderr,io_op,'<');
10508462SApril.Chin@Sun.COM fd = io_heredoc(shp,iop,fname,traceon);
10514887Schin if(traceon && (flag==SH_SHOWME))
10524887Schin sh_close(fd);
10534887Schin fname = 0;
10544887Schin }
10554887Schin else if(iof&IOMOV)
10564887Schin {
10574887Schin int dupfd,toclose= -1;
10584887Schin io_op[2] = '&';
10594887Schin if((fd=fname[0])>='0' && fd<='9')
10604887Schin {
10614887Schin char *number = fname;
10624887Schin dupfd = strtol(fname,&number,10);
10634887Schin if(*number=='-')
10644887Schin {
10654887Schin toclose = dupfd;
10664887Schin number++;
10674887Schin }
10684887Schin if(*number || dupfd > IOUFD)
10694887Schin {
10704887Schin message = e_file;
10714887Schin goto fail;
10724887Schin }
107310898Sroland.mainz@nrubsig.org if(shp->subshell && dupfd==1 && (sfset(sfstdout,0,0)&SF_STRING))
10744887Schin {
10758462SApril.Chin@Sun.COM sh_subtmpfile(0);
10764887Schin dupfd = sffileno(sfstdout);
10774887Schin }
10788462SApril.Chin@Sun.COM else if(shp->sftable[dupfd])
10798462SApril.Chin@Sun.COM sfsync(shp->sftable[dupfd]);
10804887Schin }
10814887Schin else if(fd=='-' && fname[1]==0)
10824887Schin {
10834887Schin fd= -1;
10844887Schin goto traceit;
10854887Schin }
10864887Schin else if(fd=='p' && fname[1]==0)
10874887Schin {
10884887Schin if(iof&IOPUT)
10898462SApril.Chin@Sun.COM dupfd = shp->coutpipe;
10904887Schin else
10918462SApril.Chin@Sun.COM dupfd = shp->cpipe[0];
10924887Schin if(flag)
10934887Schin toclose = dupfd;
10944887Schin }
10954887Schin else
10964887Schin {
10974887Schin message = e_file;
10984887Schin goto fail;
10994887Schin }
11004887Schin if(flag==SH_SHOWME)
11014887Schin goto traceit;
11024887Schin if((fd=sh_fcntl(dupfd,F_DUPFD,3))<0)
11034887Schin goto fail;
11048462SApril.Chin@Sun.COM sh_iocheckfd(shp,dupfd);
11058462SApril.Chin@Sun.COM shp->fdstatus[fd] = (shp->fdstatus[dupfd]&~IOCLEX);
11068462SApril.Chin@Sun.COM if(toclose<0 && shp->fdstatus[fd]&IOREAD)
11078462SApril.Chin@Sun.COM shp->fdstatus[fd] |= IODUP;
11088462SApril.Chin@Sun.COM else if(dupfd==shp->cpipe[0])
11098462SApril.Chin@Sun.COM sh_pclose(shp->cpipe);
11104887Schin else if(toclose>=0)
11114887Schin {
11124887Schin if(flag==0)
11138462SApril.Chin@Sun.COM sh_iosave(shp,toclose,indx,(char*)0); /* save file descriptor */
11144887Schin sh_close(toclose);
11154887Schin }
11164887Schin }
11174887Schin else if(iof&IORDW)
11184887Schin {
11194887Schin if(sh_isoption(SH_RESTRICTED))
11204887Schin errormsg(SH_DICT,ERROR_exit(1),e_restricted,fname);
11214887Schin io_op[2] = '>';
11224887Schin o_mode = O_RDWR|O_CREAT;
112310898Sroland.mainz@nrubsig.org if(iof&IOREWRITE)
112410898Sroland.mainz@nrubsig.org trunc = io_op[2] = ';';
11254887Schin goto openit;
11264887Schin }
11274887Schin else if(!(iof&IOPUT))
11284887Schin {
11294887Schin if(flag==SH_SHOWME)
11304887Schin goto traceit;
11314887Schin fd=sh_chkopen(fname);
11324887Schin }
11334887Schin else if(sh_isoption(SH_RESTRICTED))
11344887Schin errormsg(SH_DICT,ERROR_exit(1),e_restricted,fname);
11354887Schin else
11364887Schin {
11374887Schin if(iof&IOAPP)
11384887Schin {
11394887Schin io_op[2] = '>';
11404887Schin o_mode |= O_APPEND;
11414887Schin }
11428462SApril.Chin@Sun.COM else if((iof&IOREWRITE) && (flag==0 || flag==1 || sh_subsavefd(fn)))
11438462SApril.Chin@Sun.COM {
11448462SApril.Chin@Sun.COM io_op[2] = ';';
11458462SApril.Chin@Sun.COM o_mode |= O_TRUNC;
11468462SApril.Chin@Sun.COM tname = io_usename(fname,&perm,0);
11478462SApril.Chin@Sun.COM }
11484887Schin else
11494887Schin {
11504887Schin o_mode |= O_TRUNC;
11514887Schin if(iof&IOCLOB)
11524887Schin io_op[2] = '|';
11534887Schin else if(sh_isoption(SH_NOCLOBBER))
11544887Schin {
11554887Schin struct stat sb;
11564887Schin if(stat(fname,&sb)>=0)
11574887Schin {
11584887Schin #if SHOPT_FS_3D
11594887Schin if(S_ISREG(sb.st_mode)&&
11608462SApril.Chin@Sun.COM (!shp->lim.fs3d || iview(&sb)==0))
11614887Schin #else
11624887Schin if(S_ISREG(sb.st_mode))
11634887Schin #endif /* SHOPT_FS_3D */
11644887Schin {
11654887Schin errno = EEXIST;
11664887Schin errormsg(SH_DICT,ERROR_system(1),e_exists,fname);
11674887Schin }
11684887Schin }
11694887Schin else
11704887Schin o_mode |= O_EXCL;
11714887Schin }
11724887Schin }
11734887Schin openit:
11744887Schin if(flag!=SH_SHOWME)
11754887Schin {
11768462SApril.Chin@Sun.COM if((fd=sh_open(tname?tname:fname,o_mode,RW_ALL)) <0)
11774887Schin errormsg(SH_DICT,ERROR_system(1),((o_mode&O_CREAT)?e_create:e_open),fname);
11788462SApril.Chin@Sun.COM if(perm>0)
11798462SApril.Chin@Sun.COM #if _lib_fchmod
11808462SApril.Chin@Sun.COM fchmod(fd,perm);
11818462SApril.Chin@Sun.COM #else
11828462SApril.Chin@Sun.COM chmod(tname,perm);
11838462SApril.Chin@Sun.COM #endif
11844887Schin }
11854887Schin }
11864887Schin traceit:
11874887Schin if(traceon && fname)
11884887Schin {
11894887Schin if(np)
11904887Schin sfprintf(sfstderr,"{%s",nv_name(np));
11914887Schin sfprintf(sfstderr,"%s %s%s%c",io_op,fname,after,iop->ionxt?' ':'\n');
11924887Schin }
11934887Schin if(flag==SH_SHOWME)
11944887Schin return(indx);
11954887Schin if(trace && fname)
11964887Schin {
11974887Schin char *argv[7], **av=argv;
11984887Schin av[3] = io_op;
11994887Schin av[4] = fname;
12004887Schin av[5] = 0;
12014887Schin av[6] = 0;
12024887Schin if(iof&IOARITH)
12034887Schin av[5] = after;
12044887Schin if(np)
12054887Schin {
12064887Schin av[0] = "{";
12074887Schin av[1] = nv_name(np);
12084887Schin av[2] = "}";
12094887Schin }
12104887Schin else
12114887Schin av +=3;
12128462SApril.Chin@Sun.COM sh_debug(shp,trace,(char*)0,(char*)0,av,ARG_NOGLOB);
12134887Schin }
12144887Schin if(iof&IOLSEEK)
12154887Schin {
12168462SApril.Chin@Sun.COM Sfio_t *sp = shp->sftable[fn];
12178462SApril.Chin@Sun.COM r = shp->fdstatus[fn];
12184887Schin if(!(r&(IOSEEK|IONOSEEK)))
12198462SApril.Chin@Sun.COM r = sh_iocheckfd(shp,fn);
12204887Schin sfsprintf(io_op,sizeof(io_op),"%d\0",fn);
12214887Schin if(r==IOCLOSE)
12224887Schin {
12234887Schin fname = io_op;
12244887Schin message = e_file;
12254887Schin goto fail;
12264887Schin }
12274887Schin if(iof&IOARITH)
12284887Schin {
12294887Schin if(r&IONOSEEK)
12304887Schin {
12314887Schin fname = io_op;
12324887Schin message = e_notseek;
12334887Schin goto fail;
12344887Schin }
12354887Schin message = e_badseek;
12368462SApril.Chin@Sun.COM if((off = file_offset(shp,fn,fname))<0)
12374887Schin goto fail;
12384887Schin if(sp)
123910898Sroland.mainz@nrubsig.org {
12408462SApril.Chin@Sun.COM off=sfseek(sp, off, SEEK_SET);
124110898Sroland.mainz@nrubsig.org sfsync(sp);
124210898Sroland.mainz@nrubsig.org }
12434887Schin else
12448462SApril.Chin@Sun.COM off=lseek(fn, off, SEEK_SET);
12458462SApril.Chin@Sun.COM if(off<0)
12468462SApril.Chin@Sun.COM r = -1;
12474887Schin }
12484887Schin else
12494887Schin {
12504887Schin regex_t *rp;
12514887Schin extern const char e_notimp[];
12524887Schin if(!(r&IOREAD))
12534887Schin {
12544887Schin message = e_noread;
12554887Schin goto fail;
12564887Schin }
12574887Schin if(!(rp = regcache(fname, REG_SHELL|REG_NOSUB|REG_NEWLINE|REG_AUGMENTED|REG_FIRST|REG_LEFT|REG_RIGHT, &r)))
12584887Schin {
12594887Schin message = e_badpattern;
12604887Schin goto fail;
12614887Schin }
12624887Schin if(!sp)
12638462SApril.Chin@Sun.COM sp = sh_iostream(shp,fn);
12648462SApril.Chin@Sun.COM r=io_patseek(shp,rp,sp,iof);
12654887Schin if(sp && flag==3)
12664887Schin {
12674887Schin /* close stream but not fn */
12684887Schin sfsetfd(sp,-1);
12694887Schin sfclose(sp);
12704887Schin }
12714887Schin }
12724887Schin if(r<0)
12734887Schin goto fail;
12744887Schin if(flag==3)
12754887Schin return(fn);
12764887Schin continue;
12774887Schin }
12784887Schin if(!np)
12794887Schin {
12808462SApril.Chin@Sun.COM if(flag==0 || tname)
12814887Schin {
12824887Schin if(fd==fn)
12834887Schin {
12844887Schin if((r=sh_fcntl(fd,F_DUPFD,10)) > 0)
12854887Schin {
12864887Schin fd = r;
12874887Schin sh_close(fn);
12884887Schin }
12894887Schin }
129010898Sroland.mainz@nrubsig.org sh_iosave(shp,fn,indx,tname?fname:(trunc?Empty:0));
12914887Schin }
12924887Schin else if(sh_subsavefd(fn))
12938462SApril.Chin@Sun.COM sh_iosave(shp,fn,indx|IOSUBSHELL,tname?fname:0);
12944887Schin }
12954887Schin if(fd<0)
12964887Schin {
1297*12068SRoger.Faulkner@Oracle.COM if(sh_inuse(fn) || (fn && fn==shp->infd))
12984887Schin {
12998462SApril.Chin@Sun.COM if(fn>9 || !(shp->inuse_bits&(1<<fn)))
13008462SApril.Chin@Sun.COM io_preserve(shp,shp->sftable[fn],fn);
13014887Schin }
13024887Schin sh_close(fn);
13034887Schin }
13044887Schin if(flag==3)
13054887Schin return(fd);
13064887Schin if(fd>=0)
13074887Schin {
13084887Schin if(np)
13094887Schin {
13104887Schin int32_t v;
13114887Schin fn = fd;
13124887Schin if(fd<10)
13134887Schin {
13144887Schin if((fn=fcntl(fd,F_DUPFD,10)) < 0)
13154887Schin goto fail;
13168462SApril.Chin@Sun.COM shp->fdstatus[fn] = shp->fdstatus[fd];
13174887Schin sh_close(fd);
13184887Schin fd = fn;
13194887Schin }
13204887Schin nv_unset(np);
13214887Schin nv_onattr(np,NV_INT32);
13224887Schin v = fn;
13234887Schin nv_putval(np,(char*)&v, NV_INT32);
13248462SApril.Chin@Sun.COM sh_iocheckfd(shp,fd);
13254887Schin }
13264887Schin else
13274887Schin {
13288462SApril.Chin@Sun.COM fd = sh_iorenumber(shp,sh_iomovefd(fd),fn);
13294887Schin if(fn>2 && fn<10)
13308462SApril.Chin@Sun.COM shp->inuse_bits |= (1<<fn);
13314887Schin }
13324887Schin }
13334887Schin if(fd >2 && clexec)
13344887Schin {
13354887Schin fcntl(fd,F_SETFD,FD_CLOEXEC);
13368462SApril.Chin@Sun.COM shp->fdstatus[fd] |= IOCLEX;
13374887Schin }
13384887Schin }
13394887Schin else
13404887Schin goto fail;
13414887Schin }
13424887Schin return(indx);
13434887Schin fail:
13444887Schin errormsg(SH_DICT,ERROR_system(1),message,fname);
13454887Schin /* NOTREACHED */
13464887Schin return(0);
13474887Schin }
13484887Schin /*
13494887Schin * Create a tmp file for the here-document
13504887Schin */
io_heredoc(Shell_t * shp,register struct ionod * iop,const char * name,int traceon)13518462SApril.Chin@Sun.COM static int io_heredoc(Shell_t *shp,register struct ionod *iop, const char *name, int traceon)
13524887Schin {
13534887Schin register Sfio_t *infile = 0, *outfile;
13544887Schin register int fd;
13558462SApril.Chin@Sun.COM if(!(iop->iofile&IOSTRG) && (!shp->heredocs || iop->iosize==0))
13564887Schin return(sh_open(e_devnull,O_RDONLY));
13574887Schin /* create an unnamed temporary file */
13584887Schin if(!(outfile=sftmp(0)))
13594887Schin errormsg(SH_DICT,ERROR_system(1),e_tmpcreate);
13604887Schin if(iop->iofile&IOSTRG)
13614887Schin {
13624887Schin if(traceon)
13634887Schin sfprintf(sfstderr,"< %s\n",name);
13644887Schin sfputr(outfile,name,'\n');
13654887Schin }
13664887Schin else
13674887Schin {
13688462SApril.Chin@Sun.COM infile = subopen(shp,shp->heredocs,iop->iooffset,iop->iosize);
13694887Schin if(traceon)
13704887Schin {
13714887Schin char *cp = sh_fmtq(iop->iodelim);
13724887Schin fd = (*cp=='$' || *cp=='\'')?' ':'\\';
13734887Schin sfprintf(sfstderr," %c%s\n",fd,cp);
13744887Schin sfdisc(outfile,&tee_disc);
13754887Schin }
13764887Schin if(iop->iofile&IOQUOTE)
13774887Schin {
13784887Schin /* This is a quoted here-document, not expansion */
13794887Schin sfmove(infile,outfile,SF_UNBOUND,-1);
13804887Schin sfclose(infile);
13814887Schin }
13824887Schin else
13834887Schin {
13848462SApril.Chin@Sun.COM char *lastpath = shp->lastpath;
13858462SApril.Chin@Sun.COM sh_machere(shp,infile,outfile,iop->ioname);
13868462SApril.Chin@Sun.COM shp->lastpath = lastpath;
13874887Schin if(infile)
13884887Schin sfclose(infile);
13894887Schin }
13904887Schin }
13914887Schin /* close stream outfile, but save file descriptor */
13924887Schin fd = sffileno(outfile);
13934887Schin sfsetfd(outfile,-1);
13944887Schin sfclose(outfile);
13954887Schin if(traceon && !(iop->iofile&IOSTRG))
13964887Schin sfputr(sfstderr,iop->ioname,'\n');
13974887Schin lseek(fd,(off_t)0,SEEK_SET);
13988462SApril.Chin@Sun.COM shp->fdstatus[fd] = IOREAD;
13994887Schin return(fd);
14004887Schin }
14014887Schin
14024887Schin /*
14034887Schin * This write discipline also writes the output on standard error
14044887Schin * This is used when tracing here-documents
14054887Schin */
tee_write(Sfio_t * iop,const void * buff,size_t n,Sfdisc_t * unused)14064887Schin static ssize_t tee_write(Sfio_t *iop,const void *buff,size_t n,Sfdisc_t *unused)
14074887Schin {
14084887Schin NOT_USED(unused);
14094887Schin sfwrite(sfstderr,buff,n);
14104887Schin return(write(sffileno(iop),buff,n));
14114887Schin }
14124887Schin
14134887Schin /*
14144887Schin * copy file <origfd> into a save place
14154887Schin * The saved file is set close-on-exec
14164887Schin * if <origfd> < 0, then -origfd is saved, but not duped so that it
14174887Schin * will be closed with sh_iorestore.
14184887Schin */
sh_iosave(Shell_t * shp,register int origfd,int oldtop,char * name)14198462SApril.Chin@Sun.COM void sh_iosave(Shell_t *shp, register int origfd, int oldtop, char *name)
14204887Schin {
14214887Schin /*@
14228462SApril.Chin@Sun.COM assume oldtop>=0 && oldtop<shp->lim.open_max;
14234887Schin @*/
14244887Schin
14254887Schin register int savefd;
14264887Schin int flag = (oldtop&IOSUBSHELL);
14274887Schin oldtop &= ~IOSUBSHELL;
14284887Schin /* see if already saved, only save once */
14298462SApril.Chin@Sun.COM for(savefd=shp->topfd; --savefd>=oldtop; )
14304887Schin {
14314887Schin if(filemap[savefd].orig_fd == origfd)
14324887Schin return;
14334887Schin }
14344887Schin /* make sure table is large enough */
14358462SApril.Chin@Sun.COM if(shp->topfd >= filemapsize)
14364887Schin {
14378462SApril.Chin@Sun.COM char *cp, *oldptr = (char*)filemap;
14388462SApril.Chin@Sun.COM char *oldend = (char*)&filemap[filemapsize];
14398462SApril.Chin@Sun.COM long moved;
14404887Schin filemapsize += 8;
14414887Schin if(!(filemap = (struct fdsave*)realloc(filemap,filemapsize*sizeof(struct fdsave))))
14424887Schin errormsg(SH_DICT,ERROR_exit(4),e_nospace);
14438462SApril.Chin@Sun.COM if(moved = (char*)filemap - oldptr)
14448462SApril.Chin@Sun.COM {
14458462SApril.Chin@Sun.COM #if SHOPT_FASTPIPE
14468462SApril.Chin@Sun.COM for(savefd=shp->lim.open_max+2; --savefd>=0; )
14478462SApril.Chin@Sun.COM #else
14488462SApril.Chin@Sun.COM for(savefd=shp->lim.open_max; --savefd>=0; )
14498462SApril.Chin@Sun.COM #endif /* SHOPT_FASTPIPE */
14508462SApril.Chin@Sun.COM {
14518462SApril.Chin@Sun.COM cp = (char*)shp->fdptrs[savefd];
14528462SApril.Chin@Sun.COM if(cp >= oldptr && cp < oldend)
14538462SApril.Chin@Sun.COM shp->fdptrs[savefd] = (int*)(oldptr+moved);
14548462SApril.Chin@Sun.COM }
14558462SApril.Chin@Sun.COM }
14564887Schin }
14574887Schin #if SHOPT_DEVFD
14584887Schin if(origfd <0)
14594887Schin {
14604887Schin savefd = origfd;
14614887Schin origfd = -origfd;
14624887Schin }
14634887Schin else
14644887Schin #endif /* SHOPT_DEVFD */
14654887Schin {
14664887Schin if((savefd = sh_fcntl(origfd, F_DUPFD, 10)) < 0 && errno!=EBADF)
146710898Sroland.mainz@nrubsig.org {
146810898Sroland.mainz@nrubsig.org shp->toomany=1;
146910898Sroland.mainz@nrubsig.org ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT;
14704887Schin errormsg(SH_DICT,ERROR_system(1),e_toomany);
147110898Sroland.mainz@nrubsig.org }
14724887Schin }
14738462SApril.Chin@Sun.COM filemap[shp->topfd].tname = name;
14748462SApril.Chin@Sun.COM filemap[shp->topfd].subshell = flag;
14758462SApril.Chin@Sun.COM filemap[shp->topfd].orig_fd = origfd;
14768462SApril.Chin@Sun.COM filemap[shp->topfd++].save_fd = savefd;
14774887Schin if(savefd >=0)
14784887Schin {
14798462SApril.Chin@Sun.COM register Sfio_t* sp = shp->sftable[origfd];
14804887Schin /* make saved file close-on-exec */
14814887Schin sh_fcntl(savefd,F_SETFD,FD_CLOEXEC);
14824887Schin if(origfd==job.fd)
14834887Schin job.fd = savefd;
14848462SApril.Chin@Sun.COM shp->fdstatus[savefd] = shp->fdstatus[origfd];
14858462SApril.Chin@Sun.COM shp->fdptrs[savefd] = &filemap[shp->topfd-1].save_fd;
14868462SApril.Chin@Sun.COM if(!(shp->sftable[savefd]=sp))
14874887Schin return;
14884887Schin sfsync(sp);
14894887Schin if(origfd <=2)
14904887Schin {
14914887Schin /* copy standard stream to new stream */
14924887Schin sp = sfswap(sp,NIL(Sfio_t*));
14938462SApril.Chin@Sun.COM shp->sftable[savefd] = sp;
14944887Schin }
14954887Schin else
14968462SApril.Chin@Sun.COM shp->sftable[origfd] = 0;
14974887Schin }
14984887Schin }
14994887Schin
15004887Schin /*
15014887Schin * close all saved file descriptors
15024887Schin */
sh_iounsave(Shell_t * shp)15038462SApril.Chin@Sun.COM void sh_iounsave(Shell_t* shp)
15044887Schin {
15054887Schin register int fd, savefd, newfd;
15068462SApril.Chin@Sun.COM for(newfd=fd=0; fd < shp->topfd; fd++)
15074887Schin {
15084887Schin if((savefd = filemap[fd].save_fd)< 0)
15094887Schin filemap[newfd++] = filemap[fd];
15104887Schin else
15114887Schin {
15128462SApril.Chin@Sun.COM shp->sftable[savefd] = 0;
15134887Schin sh_close(savefd);
15144887Schin }
15154887Schin }
15168462SApril.Chin@Sun.COM shp->topfd = newfd;
15174887Schin }
15184887Schin
15194887Schin /*
15204887Schin * restore saved file descriptors from <last> on
15214887Schin */
sh_iorestore(Shell_t * shp,int last,int jmpval)15228462SApril.Chin@Sun.COM void sh_iorestore(Shell_t *shp, int last, int jmpval)
15234887Schin {
15244887Schin register int origfd, savefd, fd;
15254887Schin int flag = (last&IOSUBSHELL);
15264887Schin last &= ~IOSUBSHELL;
15278462SApril.Chin@Sun.COM for (fd = shp->topfd - 1; fd >= last; fd--)
15284887Schin {
15294887Schin if(!flag && filemap[fd].subshell)
15304887Schin continue;
15314887Schin if(jmpval==SH_JMPSCRIPT)
15324887Schin {
15334887Schin if ((savefd = filemap[fd].save_fd) >= 0)
15344887Schin {
15358462SApril.Chin@Sun.COM shp->sftable[savefd] = 0;
15364887Schin sh_close(savefd);
15374887Schin }
15384887Schin continue;
15394887Schin }
15404887Schin origfd = filemap[fd].orig_fd;
154110898Sroland.mainz@nrubsig.org if(filemap[fd].tname == Empty && shp->exitval==0)
154210898Sroland.mainz@nrubsig.org ftruncate(origfd,lseek(origfd,0,SEEK_CUR));
154310898Sroland.mainz@nrubsig.org else if(filemap[fd].tname)
15448462SApril.Chin@Sun.COM io_usename(filemap[fd].tname,(int*)0,shp->exitval?2:1);
15454887Schin sh_close(origfd);
15464887Schin if ((savefd = filemap[fd].save_fd) >= 0)
15474887Schin {
15484887Schin sh_fcntl(savefd, F_DUPFD, origfd);
15494887Schin if(savefd==job.fd)
15504887Schin job.fd=origfd;
15518462SApril.Chin@Sun.COM shp->fdstatus[origfd] = shp->fdstatus[savefd];
15524887Schin /* turn off close-on-exec if flag if necessary */
15538462SApril.Chin@Sun.COM if(shp->fdstatus[origfd]&IOCLEX)
15544887Schin fcntl(origfd,F_SETFD,FD_CLOEXEC);
15554887Schin if(origfd<=2)
15564887Schin {
15578462SApril.Chin@Sun.COM sfswap(shp->sftable[savefd],shp->sftable[origfd]);
15584887Schin if(origfd==0)
15598462SApril.Chin@Sun.COM shp->st.ioset = 0;
15604887Schin }
15614887Schin else
15628462SApril.Chin@Sun.COM shp->sftable[origfd] = shp->sftable[savefd];
15638462SApril.Chin@Sun.COM shp->sftable[savefd] = 0;
15644887Schin sh_close(savefd);
15654887Schin }
15664887Schin else
15678462SApril.Chin@Sun.COM shp->fdstatus[origfd] = IOCLOSE;
15684887Schin }
15694887Schin if(!flag)
15704887Schin {
15714887Schin /* keep file descriptors for subshell restore */
15728462SApril.Chin@Sun.COM for (fd = last ; fd < shp->topfd; fd++)
15734887Schin {
15744887Schin if(filemap[fd].subshell)
15754887Schin filemap[last++] = filemap[fd];
15764887Schin }
15774887Schin }
15788462SApril.Chin@Sun.COM if(last < shp->topfd)
15798462SApril.Chin@Sun.COM shp->topfd = last;
15804887Schin }
15814887Schin
15824887Schin /*
15834887Schin * returns access information on open file <fd>
15844887Schin * returns -1 for failure, 0 for success
15854887Schin * <mode> is the same as for access()
15864887Schin */
sh_ioaccess(int fd,register int mode)15874887Schin int sh_ioaccess(int fd,register int mode)
15884887Schin {
15898462SApril.Chin@Sun.COM Shell_t *shp = &sh;
15904887Schin register int flags;
15914887Schin if(mode==X_OK)
15924887Schin return(-1);
15938462SApril.Chin@Sun.COM if((flags=sh_iocheckfd(shp,fd))!=IOCLOSE)
15944887Schin {
15954887Schin if(mode==F_OK)
15964887Schin return(0);
15974887Schin if(mode==R_OK && (flags&IOREAD))
15984887Schin return(0);
15994887Schin if(mode==W_OK && (flags&IOWRITE))
16004887Schin return(0);
16014887Schin }
16024887Schin return(-1);
16034887Schin }
16044887Schin
16054887Schin /*
16064887Schin * Handle interrupts for slow streams
16074887Schin */
slowexcept(register Sfio_t * iop,int type,void * data,Sfdisc_t * handle)16084887Schin static int slowexcept(register Sfio_t *iop,int type,void *data,Sfdisc_t *handle)
16094887Schin {
16104887Schin register int n,fno;
16114887Schin NOT_USED(handle);
16124887Schin if(type==SF_DPOP || type==SF_FINAL)
16134887Schin free((void*)handle);
16144887Schin if(type!=SF_READ)
16154887Schin return(0);
16164887Schin if((sh.trapnote&(SH_SIGSET|SH_SIGTRAP)) && errno!=EIO && errno!=ENXIO)
16174887Schin errno = EINTR;
16184887Schin fno = sffileno(iop);
16194887Schin if((n=sfvalue(iop))<=0)
16204887Schin {
16214887Schin #ifndef FNDELAY
16224887Schin # ifdef O_NDELAY
16234887Schin if(errno==0 && (n=fcntl(fno,F_GETFL,0))&O_NDELAY)
16244887Schin {
16254887Schin n &= ~O_NDELAY;
16264887Schin fcntl(fno, F_SETFL, n);
16274887Schin return(1);
16284887Schin }
16294887Schin # endif /* O_NDELAY */
16304887Schin #endif /* !FNDELAY */
16314887Schin #ifdef O_NONBLOCK
16324887Schin if(errno==EAGAIN)
16334887Schin {
16344887Schin n = fcntl(fno,F_GETFL,0);
16354887Schin n &= ~O_NONBLOCK;
16364887Schin fcntl(fno, F_SETFL, n);
16374887Schin return(1);
16384887Schin }
16394887Schin #endif /* O_NONBLOCK */
16404887Schin if(errno!=EINTR)
16414887Schin return(0);
16424887Schin n=1;
16438462SApril.Chin@Sun.COM sh_onstate(SH_TTYWAIT);
16444887Schin }
16458462SApril.Chin@Sun.COM else
16468462SApril.Chin@Sun.COM n = 0;
16478462SApril.Chin@Sun.COM if(sh.bltinfun && sh.bltindata.sigset)
16488462SApril.Chin@Sun.COM return(-1);
16494887Schin errno = 0;
16504887Schin if(sh.trapnote&SH_SIGSET)
16514887Schin {
16524887Schin if(isatty(fno))
16534887Schin sfputc(sfstderr,'\n');
16544887Schin sh_exit(SH_EXITSIG);
16554887Schin }
16564887Schin if(sh.trapnote&SH_SIGTRAP)
16574887Schin sh_chktrap();
16584887Schin return(n);
16594887Schin }
16604887Schin
16614887Schin /*
16624887Schin * called when slowread times out
16634887Schin */
time_grace(void * handle)16644887Schin static void time_grace(void *handle)
16654887Schin {
16664887Schin NOT_USED(handle);
16674887Schin timeout = 0;
16684887Schin if(sh_isstate(SH_GRACE))
16694887Schin {
16704887Schin sh_offstate(SH_GRACE);
16714887Schin if(!sh_isstate(SH_INTERACTIVE))
16724887Schin return;
16734887Schin ((struct checkpt*)sh.jmplist)->mode = SH_JMPEXIT;
16744887Schin errormsg(SH_DICT,2,e_timeout);
16754887Schin sh.trapnote |= SH_SIGSET;
16764887Schin return;
16774887Schin }
16784887Schin errormsg(SH_DICT,0,e_timewarn);
16794887Schin sh_onstate(SH_GRACE);
16804887Schin sigrelease(SIGALRM);
16814887Schin sh.trapnote |= SH_SIGTRAP;
16824887Schin }
16834887Schin
piperead(Sfio_t * iop,void * buff,register size_t size,Sfdisc_t * handle)16844887Schin static ssize_t piperead(Sfio_t *iop,void *buff,register size_t size,Sfdisc_t *handle)
16854887Schin {
16864887Schin int fd = sffileno(iop);
16874887Schin NOT_USED(handle);
16888462SApril.Chin@Sun.COM if(job.waitsafe && job.savesig)
168910898Sroland.mainz@nrubsig.org {
169010898Sroland.mainz@nrubsig.org job_lock();
169110898Sroland.mainz@nrubsig.org job_unlock();
169210898Sroland.mainz@nrubsig.org }
16934887Schin if(sh.trapnote)
16944887Schin {
16954887Schin errno = EINTR;
16964887Schin return(-1);
16974887Schin }
16984887Schin if(sh_isstate(SH_INTERACTIVE) && io_prompt(iop,sh.nextprompt)<0 && errno==EIO)
16994887Schin return(0);
17008462SApril.Chin@Sun.COM sh_onstate(SH_TTYWAIT);
17014887Schin if(!(sh.fdstatus[sffileno(iop)]&IOCLEX) && (sfset(iop,0,0)&SF_SHARE))
17024887Schin size = ed_read(sh.ed_context, fd, (char*)buff, size,0);
17034887Schin else
17044887Schin size = sfrd(iop,buff,size,handle);
17058462SApril.Chin@Sun.COM sh_offstate(SH_TTYWAIT);
17064887Schin return(size);
17074887Schin }
17084887Schin /*
17094887Schin * This is the read discipline that is applied to slow devices
17104887Schin * This routine takes care of prompting for input
17114887Schin */
slowread(Sfio_t * iop,void * buff,register size_t size,Sfdisc_t * handle)17124887Schin static ssize_t slowread(Sfio_t *iop,void *buff,register size_t size,Sfdisc_t *handle)
17134887Schin {
17144887Schin int (*readf)(void*, int, char*, int, int);
17154887Schin int reedit=0, rsize;
17164887Schin #if SHOPT_HISTEXPAND
17174887Schin char *xp=0;
17184887Schin #endif
17194887Schin NOT_USED(handle);
17204887Schin # if SHOPT_ESH
17214887Schin if(sh_isoption(SH_EMACS) || sh_isoption(SH_GMACS))
17224887Schin readf = ed_emacsread;
17234887Schin else
17244887Schin # endif /* SHOPT_ESH */
17254887Schin # if SHOPT_VSH
17264887Schin # if SHOPT_RAWONLY
17274887Schin if(sh_isoption(SH_VI) || ((SHOPT_RAWONLY-0) && mbwide()))
17284887Schin # else
17294887Schin if(sh_isoption(SH_VI))
17304887Schin # endif
17314887Schin readf = ed_viread;
17324887Schin else
17334887Schin # endif /* SHOPT_VSH */
17344887Schin readf = ed_read;
17354887Schin if(sh.trapnote)
17364887Schin {
17374887Schin errno = EINTR;
17384887Schin return(-1);
17394887Schin }
17404887Schin while(1)
17414887Schin {
17424887Schin if(io_prompt(iop,sh.nextprompt)<0 && errno==EIO)
17434887Schin return(0);
17444887Schin if(sh.timeout)
17454887Schin timeout = (void*)sh_timeradd(sh_isstate(SH_GRACE)?1000L*TGRACE:1000L*sh.timeout,0,time_grace,NIL(void*));
17464887Schin rsize = (*readf)(sh.ed_context, sffileno(iop), (char*)buff, size, reedit);
17474887Schin if(timeout)
17484887Schin timerdel(timeout);
17494887Schin timeout=0;
17504887Schin #if SHOPT_HISTEXPAND
17514887Schin if(rsize && *(char*)buff != '\n' && sh.nextprompt==1 && sh_isoption(SH_HISTEXPAND))
17524887Schin {
17534887Schin int r;
17544887Schin ((char*)buff)[rsize] = '\0';
17554887Schin if(xp)
17564887Schin {
17574887Schin free(xp);
17584887Schin xp = 0;
17594887Schin }
17604887Schin r = hist_expand(buff, &xp);
17614887Schin if((r & (HIST_EVENT|HIST_PRINT)) && !(r & HIST_ERROR) && xp)
17624887Schin {
17634887Schin strlcpy(buff, xp, size);
17644887Schin rsize = strlen(buff);
17654887Schin if(!sh_isoption(SH_HISTVERIFY) || readf==ed_read)
17664887Schin {
17674887Schin sfputr(sfstderr, xp, -1);
17684887Schin break;
17694887Schin }
17704887Schin reedit = rsize - 1;
17714887Schin continue;
17724887Schin }
17734887Schin if((r & HIST_ERROR) && sh_isoption(SH_HISTREEDIT))
17744887Schin {
17754887Schin reedit = rsize - 1;
17764887Schin continue;
17774887Schin }
17784887Schin if(r & (HIST_ERROR|HIST_PRINT))
17794887Schin {
17804887Schin *(char*)buff = '\n';
17814887Schin rsize = 1;
17824887Schin }
17834887Schin }
17844887Schin #endif
17854887Schin break;
17864887Schin }
17874887Schin return(rsize);
17884887Schin }
17894887Schin
17904887Schin /*
17914887Schin * check and return the attributes for a file descriptor
17924887Schin */
17934887Schin
sh_iocheckfd(Shell_t * shp,register int fd)17948462SApril.Chin@Sun.COM int sh_iocheckfd(Shell_t *shp, register int fd)
17954887Schin {
17964887Schin register int flags, n;
17974887Schin if((n=sh.fdstatus[fd])&IOCLOSE)
17984887Schin return(n);
17994887Schin if(!(n&(IOREAD|IOWRITE)))
18004887Schin {
18014887Schin #ifdef F_GETFL
18024887Schin if((flags=fcntl(fd,F_GETFL,0)) < 0)
18034887Schin return(sh.fdstatus[fd]=IOCLOSE);
18044887Schin if((flags&O_ACCMODE)!=O_WRONLY)
18054887Schin n |= IOREAD;
18064887Schin if((flags&O_ACCMODE)!=O_RDONLY)
18074887Schin n |= IOWRITE;
18084887Schin #else
18094887Schin struct stat statb;
18104887Schin if((flags = fstat(fd,&statb))< 0)
18114887Schin return(sh.fdstatus[fd]=IOCLOSE);
18124887Schin n |= (IOREAD|IOWRITE);
18134887Schin if(read(fd,"",0) < 0)
18144887Schin n &= ~IOREAD;
18154887Schin #endif /* F_GETFL */
18164887Schin }
18174887Schin if(!(n&(IOSEEK|IONOSEEK)))
18184887Schin {
18194887Schin struct stat statb;
18204887Schin /* /dev/null check is a workaround for select bug */
18214887Schin static ino_t null_ino;
18224887Schin static dev_t null_dev;
18234887Schin if(null_ino==0 && stat(e_devnull,&statb) >=0)
18244887Schin {
18254887Schin null_ino = statb.st_ino;
18264887Schin null_dev = statb.st_dev;
18274887Schin }
18284887Schin if(tty_check(fd))
18294887Schin n |= IOTTY;
18304887Schin if(lseek(fd,NIL(off_t),SEEK_CUR)<0)
18314887Schin {
18324887Schin n |= IONOSEEK;
18334887Schin #ifdef S_ISSOCK
18344887Schin if((fstat(fd,&statb)>=0) && S_ISSOCK(statb.st_mode))
18354887Schin n |= IOREAD|IOWRITE;
18364887Schin #endif /* S_ISSOCK */
18374887Schin }
18384887Schin else if((fstat(fd,&statb)>=0) && (
18394887Schin S_ISFIFO(statb.st_mode) ||
18404887Schin #ifdef S_ISSOCK
18414887Schin S_ISSOCK(statb.st_mode) ||
18424887Schin #endif /* S_ISSOCK */
18434887Schin /* The following is for sockets on the sgi */
18444887Schin (statb.st_ino==0 && (statb.st_mode & ~(S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH|S_IXUSR|S_IXGRP|S_IXOTH|S_ISUID|S_ISGID))==0) ||
18454887Schin (S_ISCHR(statb.st_mode) && (statb.st_ino!=null_ino || statb.st_dev!=null_dev))
18464887Schin ))
18474887Schin n |= IONOSEEK;
18484887Schin else
18494887Schin n |= IOSEEK;
18504887Schin }
18514887Schin sh.fdstatus[fd] = n;
18524887Schin return(n);
18534887Schin }
18544887Schin
18554887Schin /*
18564887Schin * Display prompt PS<flag> on standard error
18574887Schin */
18584887Schin
io_prompt(Sfio_t * iop,register int flag)18594887Schin static int io_prompt(Sfio_t *iop,register int flag)
18604887Schin {
18618462SApril.Chin@Sun.COM Shell_t *shp = &sh;
18624887Schin register char *cp;
18634887Schin char buff[1];
18644887Schin char *endprompt;
18654887Schin static short cmdno;
18664887Schin int sfflags;
18674887Schin if(flag<3 && !sh_isstate(SH_INTERACTIVE))
18684887Schin flag = 0;
18694887Schin if(flag==2 && sfpkrd(sffileno(iop),buff,1,'\n',0,1) >= 0)
18704887Schin flag = 0;
18714887Schin if(flag==0)
18724887Schin return(sfsync(sfstderr));
18734887Schin sfflags = sfset(sfstderr,SF_SHARE|SF_PUBLIC|SF_READ,0);
18744887Schin if(!(sh.prompt=(char*)sfreserve(sfstderr,0,0)))
18754887Schin sh.prompt = "";
18764887Schin switch(flag)
18774887Schin {
18784887Schin case 1:
18794887Schin {
18804887Schin register int c;
18814887Schin #if defined(TIOCLBIC) && defined(LFLUSHO)
18824887Schin if(!sh_isoption(SH_VI) && !sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS))
18834887Schin {
18844887Schin /*
18854887Schin * re-enable output in case the user has
18864887Schin * disabled it. Not needed with edit mode
18874887Schin */
18884887Schin int mode = LFLUSHO;
18894887Schin ioctl(sffileno(sfstderr),TIOCLBIC,&mode);
18904887Schin }
18914887Schin #endif /* TIOCLBIC */
18928462SApril.Chin@Sun.COM cp = sh_mactry(shp,nv_getval(sh_scoped(shp,PS1NOD)));
18934887Schin for(;c= *cp;cp++)
18944887Schin {
18954887Schin if(c==HIST_CHAR)
18964887Schin {
18974887Schin /* look at next character */
18984887Schin c = *++cp;
18994887Schin /* print out line number if not !! */
19004887Schin if(c!= HIST_CHAR)
19014887Schin {
19024887Schin sfprintf(sfstderr,"%d", sh.hist_ptr?(int)sh.hist_ptr->histind:++cmdno);
19034887Schin }
19044887Schin if(c==0)
19054887Schin goto done;
19064887Schin }
19074887Schin sfputc(sfstderr,c);
19084887Schin }
19094887Schin goto done;
19104887Schin }
19114887Schin case 2:
19128462SApril.Chin@Sun.COM cp = nv_getval(sh_scoped(shp,PS2NOD));
19134887Schin break;
19144887Schin case 3:
19158462SApril.Chin@Sun.COM cp = nv_getval(sh_scoped(shp,PS3NOD));
19164887Schin break;
19174887Schin default:
19184887Schin goto done;
19194887Schin }
19204887Schin if(cp)
19214887Schin sfputr(sfstderr,cp,-1);
19224887Schin done:
19234887Schin if(*sh.prompt && (endprompt=(char*)sfreserve(sfstderr,0,0)))
19244887Schin *endprompt = 0;
19254887Schin sfset(sfstderr,sfflags&SF_READ|SF_SHARE|SF_PUBLIC,1);
19264887Schin return(sfsync(sfstderr));
19274887Schin }
19284887Schin
19294887Schin /*
19304887Schin * This discipline is inserted on write pipes to prevent SIGPIPE
19314887Schin * from causing an infinite loop
19324887Schin */
pipeexcept(Sfio_t * iop,int mode,void * data,Sfdisc_t * handle)19334887Schin static int pipeexcept(Sfio_t* iop, int mode, void *data, Sfdisc_t* handle)
19344887Schin {
19354887Schin NOT_USED(iop);
19364887Schin if(mode==SF_DPOP || mode==SF_FINAL)
19374887Schin free((void*)handle);
19384887Schin else if(mode==SF_WRITE && errno==EINTR && sh.lastsig==SIGPIPE)
19394887Schin return(-1);
19404887Schin return(0);
19414887Schin }
19424887Schin
19434887Schin /*
19444887Schin * keep track of each stream that is opened and closed
19454887Schin */
sftrack(Sfio_t * sp,int flag,void * data)19468462SApril.Chin@Sun.COM static void sftrack(Sfio_t* sp, int flag, void* data)
19474887Schin {
19488462SApril.Chin@Sun.COM Shell_t *shp = &sh;
19494887Schin register int fd = sffileno(sp);
19504887Schin register struct checkpt *pp;
19514887Schin register int mode;
19528462SApril.Chin@Sun.COM int newfd = integralof(data);
19534887Schin if(flag==SF_SETFD || flag==SF_CLOSING)
19544887Schin {
19554887Schin if(newfd<0)
19564887Schin flag = SF_CLOSING;
19574887Schin if(fdnotify)
19584887Schin (*fdnotify)(sffileno(sp),flag==SF_CLOSING?-1:newfd);
19594887Schin }
19604887Schin #ifdef DEBUG
19614887Schin if(flag==SF_READ || flag==SF_WRITE)
19624887Schin {
19634887Schin char *z = fmtbase((long)getpid(),0,0);
19644887Schin write(ERRIO,z,strlen(z));
19654887Schin write(ERRIO,": ",2);
19664887Schin write(ERRIO,"attempt to ",11);
19674887Schin if(flag==SF_READ)
19684887Schin write(ERRIO,"read from",9);
19694887Schin else
19704887Schin write(ERRIO,"write to",8);
19714887Schin write(ERRIO," locked stream\n",15);
19724887Schin return;
19734887Schin }
19744887Schin #endif
19758462SApril.Chin@Sun.COM if((unsigned)fd >= shp->lim.open_max)
19764887Schin return;
19774887Schin if(sh_isstate(SH_NOTRACK))
19784887Schin return;
19794887Schin mode = sfset(sp,0,0);
19808462SApril.Chin@Sun.COM if(sp==shp->heredocs && fd < 10 && flag==SF_NEW)
19814887Schin {
19824887Schin fd = sfsetfd(sp,10);
19834887Schin fcntl(fd,F_SETFD,FD_CLOEXEC);
19844887Schin }
19854887Schin if(fd < 3)
19864887Schin return;
19874887Schin if(flag==SF_NEW)
19884887Schin {
19898462SApril.Chin@Sun.COM if(!shp->sftable[fd] && shp->fdstatus[fd]==IOCLOSE)
19904887Schin {
19918462SApril.Chin@Sun.COM shp->sftable[fd] = sp;
19924887Schin flag = (mode&SF_WRITE)?IOWRITE:0;
19934887Schin if(mode&SF_READ)
19944887Schin flag |= IOREAD;
19958462SApril.Chin@Sun.COM shp->fdstatus[fd] = flag;
199610898Sroland.mainz@nrubsig.org sh_iostream(shp,fd);
19974887Schin }
19988462SApril.Chin@Sun.COM if((pp=(struct checkpt*)shp->jmplist) && pp->mode==SH_JMPCMD)
19994887Schin {
20004887Schin struct openlist *item;
20014887Schin /*
20024887Schin * record open file descriptors so they can
20034887Schin * be closed in case a longjmp prevents
20044887Schin * built-ins from cleanup
20054887Schin */
20064887Schin item = new_of(struct openlist, 0);
20074887Schin item->strm = sp;
20084887Schin item->next = pp->olist;
20094887Schin pp->olist = item;
20104887Schin }
20114887Schin if(fdnotify)
20124887Schin (*fdnotify)(-1,sffileno(sp));
20134887Schin }
20144887Schin else if(flag==SF_CLOSING || (flag==SF_SETFD && newfd<=2))
20154887Schin {
20168462SApril.Chin@Sun.COM shp->sftable[fd] = 0;
20178462SApril.Chin@Sun.COM shp->fdstatus[fd]=IOCLOSE;
20188462SApril.Chin@Sun.COM if(pp=(struct checkpt*)shp->jmplist)
20194887Schin {
20204887Schin struct openlist *item;
20214887Schin for(item=pp->olist; item; item=item->next)
20224887Schin {
20234887Schin if(item->strm == sp)
20244887Schin {
20254887Schin item->strm = 0;
20264887Schin break;
20274887Schin }
20284887Schin }
20294887Schin }
20304887Schin }
20314887Schin }
20324887Schin
20334887Schin struct eval
20344887Schin {
20354887Schin Sfdisc_t disc;
20364887Schin char **argv;
20374887Schin short slen;
20384887Schin char addspace;
20394887Schin };
20404887Schin
20414887Schin /*
20424887Schin * Create a stream consisting of a space separated argv[] list
20434887Schin */
20444887Schin
sh_sfeval(register char * argv[])20454887Schin Sfio_t *sh_sfeval(register char *argv[])
20464887Schin {
20474887Schin register Sfio_t *iop;
20484887Schin register char *cp;
20494887Schin if(argv[1])
20504887Schin cp = "";
20514887Schin else
20524887Schin cp = argv[0];
20534887Schin iop = sfopen(NIL(Sfio_t*),(char*)cp,"s");
20544887Schin if(argv[1])
20554887Schin {
20564887Schin register struct eval *ep;
20574887Schin if(!(ep = new_of(struct eval,0)))
20584887Schin return(NIL(Sfio_t*));
20594887Schin ep->disc = eval_disc;
20604887Schin ep->argv = argv;
20614887Schin ep->slen = -1;
20624887Schin ep->addspace = 0;
20634887Schin sfdisc(iop,&ep->disc);
20644887Schin }
20654887Schin return(iop);
20664887Schin }
20674887Schin
20684887Schin /*
20694887Schin * This code gets called whenever an end of string is found with eval
20704887Schin */
20714887Schin
eval_exceptf(Sfio_t * iop,int type,void * data,Sfdisc_t * handle)20724887Schin static int eval_exceptf(Sfio_t *iop,int type, void *data, Sfdisc_t *handle)
20734887Schin {
20744887Schin register struct eval *ep = (struct eval*)handle;
20754887Schin register char *cp;
20764887Schin register int len;
20774887Schin
20784887Schin /* no more to do */
20794887Schin if(type!=SF_READ || !(cp = ep->argv[0]))
20804887Schin {
20814887Schin if(type==SF_CLOSING)
20824887Schin sfdisc(iop,SF_POPDISC);
20834887Schin else if(ep && (type==SF_DPOP || type==SF_FINAL))
20844887Schin free((void*)ep);
20854887Schin return(0);
20864887Schin }
20874887Schin
20884887Schin if(!ep->addspace)
20894887Schin {
20904887Schin /* get the length of this string */
20914887Schin ep->slen = len = strlen(cp);
20924887Schin /* move to next string */
20934887Schin ep->argv++;
20944887Schin }
20954887Schin else /* insert space between arguments */
20964887Schin {
20974887Schin len = 1;
20984887Schin cp = " ";
20994887Schin }
21004887Schin /* insert the new string */
21014887Schin sfsetbuf(iop,cp,len);
21024887Schin ep->addspace = !ep->addspace;
21034887Schin return(1);
21044887Schin }
21054887Schin
21064887Schin /*
21074887Schin * This routine returns a stream pointer to a segment of length <size> from
21084887Schin * the stream <sp> starting at offset <offset>
21094887Schin * The stream can be read with the normal stream operations
21104887Schin */
21114887Schin
subopen(Shell_t * shp,Sfio_t * sp,off_t offset,long size)21128462SApril.Chin@Sun.COM static Sfio_t *subopen(Shell_t *shp,Sfio_t* sp, off_t offset, long size)
21134887Schin {
21144887Schin register struct subfile *disp;
21154887Schin if(sfseek(sp,offset,SEEK_SET) <0)
21164887Schin return(NIL(Sfio_t*));
21174887Schin if(!(disp = (struct subfile*)malloc(sizeof(struct subfile)+IOBSIZE+1)))
21184887Schin return(NIL(Sfio_t*));
21194887Schin disp->disc = sub_disc;
21204887Schin disp->oldsp = sp;
21214887Schin disp->offset = offset;
21224887Schin disp->size = disp->left = size;
21238462SApril.Chin@Sun.COM sp = sfnew(NIL(Sfio_t*),(char*)(disp+1),IOBSIZE,shp->lim.open_max,SF_READ);
21244887Schin sfdisc(sp,&disp->disc);
21254887Schin return(sp);
21264887Schin }
21274887Schin
21284887Schin /*
21294887Schin * read function for subfile discipline
21304887Schin */
subread(Sfio_t * sp,void * buff,register size_t size,Sfdisc_t * handle)21314887Schin static ssize_t subread(Sfio_t* sp,void* buff,register size_t size,Sfdisc_t* handle)
21324887Schin {
21334887Schin register struct subfile *disp = (struct subfile*)handle;
21344887Schin NOT_USED(sp);
21354887Schin if(disp->left == 0)
21364887Schin return(0);
21374887Schin if(size > disp->left)
21384887Schin size = disp->left;
21394887Schin disp->left -= size;
21404887Schin return(sfread(disp->oldsp,buff,size));
21414887Schin }
21424887Schin
21434887Schin /*
21444887Schin * exception handler for subfile discipline
21454887Schin */
subexcept(Sfio_t * sp,register int mode,void * data,Sfdisc_t * handle)21464887Schin static int subexcept(Sfio_t* sp,register int mode, void *data, Sfdisc_t* handle)
21474887Schin {
21484887Schin register struct subfile *disp = (struct subfile*)handle;
21494887Schin if(mode==SF_CLOSING)
21504887Schin {
21514887Schin sfdisc(sp,SF_POPDISC);
21524887Schin return(0);
21534887Schin }
21544887Schin else if(disp && (mode==SF_DPOP || mode==SF_FINAL))
21554887Schin {
21564887Schin free((void*)disp);
21574887Schin return(0);
21584887Schin }
21594887Schin #ifdef SF_ATEXIT
21604887Schin else if (mode==SF_ATEXIT)
21614887Schin {
21624887Schin sfdisc(sp, SF_POPDISC);
21634887Schin return(0);
21644887Schin }
21654887Schin #endif
21664887Schin else if(mode==SF_READ)
21674887Schin return(0);
21684887Schin return(-1);
21694887Schin }
21704887Schin
21714887Schin #define NROW 15 /* number of rows before going to multi-columns */
21724887Schin #define LBLSIZ 3 /* size of label field and interfield spacing */
21734887Schin /*
21744887Schin * print a list of arguments in columns
21754887Schin */
sh_menu(Sfio_t * outfile,int argn,char * argv[])21764887Schin void sh_menu(Sfio_t *outfile,int argn,char *argv[])
21774887Schin {
21788462SApril.Chin@Sun.COM Shell_t *shp = &sh;
21794887Schin register int i,j;
21804887Schin register char **arg;
21814887Schin int nrow, ncol=1, ndigits=1;
21824887Schin int fldsize, wsize = ed_window();
21838462SApril.Chin@Sun.COM char *cp = nv_getval(sh_scoped(shp,LINES));
21844887Schin nrow = (cp?1+2*((int)strtol(cp, (char**)0, 10)/3):NROW);
21854887Schin for(i=argn;i >= 10;i /= 10)
21864887Schin ndigits++;
21874887Schin if(argn < nrow)
21884887Schin {
21894887Schin nrow = argn;
21904887Schin goto skip;
21914887Schin }
21924887Schin i = 0;
21934887Schin for(arg=argv; *arg;arg++)
21944887Schin {
21954887Schin if((j=strlen(*arg)) > i)
21964887Schin i = j;
21974887Schin }
21984887Schin i += (ndigits+LBLSIZ);
21994887Schin if(i < wsize)
22004887Schin ncol = wsize/i;
22014887Schin if(argn > nrow*ncol)
22024887Schin {
22034887Schin nrow = 1 + (argn-1)/ncol;
22044887Schin }
22054887Schin else
22064887Schin {
22074887Schin ncol = 1 + (argn-1)/nrow;
22084887Schin nrow = 1 + (argn-1)/ncol;
22094887Schin }
22104887Schin skip:
22114887Schin fldsize = (wsize/ncol)-(ndigits+LBLSIZ);
22124887Schin for(i=0;i<nrow;i++)
22134887Schin {
22144887Schin if(sh.trapnote&SH_SIGSET)
22154887Schin return;
22164887Schin j = i;
22174887Schin while(1)
22184887Schin {
22194887Schin arg = argv+j;
22204887Schin sfprintf(outfile,"%*d) %s",ndigits,j+1,*arg);
22214887Schin j += nrow;
22224887Schin if(j >= argn)
22234887Schin break;
22244887Schin sfnputc(outfile,' ',fldsize-strlen(*arg));
22254887Schin }
22264887Schin sfputc(outfile,'\n');
22274887Schin }
22284887Schin }
22294887Schin
22304887Schin #undef read
22314887Schin /*
22324887Schin * shell version of read() for user added builtins
22334887Schin */
sh_read(register int fd,void * buff,size_t n)22344887Schin ssize_t sh_read(register int fd, void* buff, size_t n)
22354887Schin {
22364887Schin register Sfio_t *sp;
22374887Schin if(sp=sh.sftable[fd])
22384887Schin return(sfread(sp,buff,n));
22394887Schin else
22404887Schin return(read(fd,buff,n));
22414887Schin }
22424887Schin
22434887Schin #undef write
22444887Schin /*
22454887Schin * shell version of write() for user added builtins
22464887Schin */
sh_write(register int fd,const void * buff,size_t n)22474887Schin ssize_t sh_write(register int fd, const void* buff, size_t n)
22484887Schin {
22494887Schin register Sfio_t *sp;
22504887Schin if(sp=sh.sftable[fd])
22514887Schin return(sfwrite(sp,buff,n));
22524887Schin else
22534887Schin return(write(fd,buff,n));
22544887Schin }
22554887Schin
22564887Schin #undef lseek
22574887Schin /*
22584887Schin * shell version of lseek() for user added builtins
22594887Schin */
sh_seek(register int fd,off_t offset,int whence)22604887Schin off_t sh_seek(register int fd, off_t offset, int whence)
22614887Schin {
22624887Schin register Sfio_t *sp;
22634887Schin if((sp=sh.sftable[fd]) && (sfset(sp,0,0)&(SF_READ|SF_WRITE)))
22644887Schin return(sfseek(sp,offset,whence));
22654887Schin else
22664887Schin return(lseek(fd,offset,whence));
22674887Schin }
22684887Schin
22694887Schin #undef dup
sh_dup(register int old)22704887Schin int sh_dup(register int old)
22714887Schin {
22724887Schin register int fd = dup(old);
22734887Schin if(fd>=0)
22744887Schin {
22754887Schin if(sh.fdstatus[old] == IOCLOSE)
22764887Schin sh.fdstatus[old] = 0;
22774887Schin sh.fdstatus[fd] = (sh.fdstatus[old]&~IOCLEX);
22784887Schin if(fdnotify)
22794887Schin (*fdnotify)(old,fd);
22804887Schin }
22814887Schin return(fd);
22824887Schin }
22834887Schin
22844887Schin #undef fcntl
sh_fcntl(register int fd,int op,...)22854887Schin int sh_fcntl(register int fd, int op, ...)
22864887Schin {
22874887Schin int newfd, arg;
22884887Schin va_list ap;
22894887Schin va_start(ap, op);
22904887Schin arg = va_arg(ap, int) ;
22914887Schin va_end(ap);
22924887Schin newfd = fcntl(fd,op,arg);
22934887Schin if(newfd>=0) switch(op)
22944887Schin {
22954887Schin case F_DUPFD:
22964887Schin if(sh.fdstatus[fd] == IOCLOSE)
22974887Schin sh.fdstatus[fd] = 0;
22984887Schin sh.fdstatus[newfd] = (sh.fdstatus[fd]&~IOCLEX);
22994887Schin if(fdnotify)
23004887Schin (*fdnotify)(fd,newfd);
23014887Schin break;
23024887Schin case F_SETFD:
23034887Schin if(sh.fdstatus[fd] == IOCLOSE)
23044887Schin sh.fdstatus[fd] = 0;
23054887Schin if(arg&FD_CLOEXEC)
23064887Schin sh.fdstatus[fd] |= IOCLEX;
23074887Schin else
23084887Schin sh.fdstatus[fd] &= ~IOCLEX;
23094887Schin }
23104887Schin return(newfd);
23114887Schin }
23124887Schin
23134887Schin #undef umask
sh_umask(mode_t m)23144887Schin mode_t sh_umask(mode_t m)
23154887Schin {
23164887Schin sh.mask = m;
23174887Schin return(umask(m));
23184887Schin }
23194887Schin
23204887Schin /*
23214887Schin * give file descriptor <fd> and <mode>, return an iostream pointer
23224887Schin * <mode> must be SF_READ or SF_WRITE
23234887Schin * <fd> must be a non-negative number ofr SH_IOCOPROCESS or SH_IOHISTFILE.
23244887Schin * returns NULL on failure and may set errno.
23254887Schin */
23264887Schin
sh_iogetiop(int fd,int mode)23274887Schin Sfio_t *sh_iogetiop(int fd, int mode)
23284887Schin {
23298462SApril.Chin@Sun.COM Shell_t *shp = &sh;
23304887Schin int n;
23314887Schin Sfio_t *iop=0;
23324887Schin if(mode!=SF_READ && mode!=SF_WRITE)
23334887Schin {
23344887Schin errno = EINVAL;
23354887Schin return(iop);
23364887Schin }
23374887Schin switch(fd)
23384887Schin {
23394887Schin case SH_IOHISTFILE:
23408462SApril.Chin@Sun.COM if(!sh_histinit((void*)shp))
23414887Schin return(iop);
23428462SApril.Chin@Sun.COM fd = sffileno(shp->hist_ptr->histfp);
23434887Schin break;
23444887Schin case SH_IOCOPROCESS:
23454887Schin if(mode==SF_WRITE)
23468462SApril.Chin@Sun.COM fd = shp->coutpipe;
23474887Schin else
23488462SApril.Chin@Sun.COM fd = shp->cpipe[0];
23494887Schin break;
23504887Schin default:
23518462SApril.Chin@Sun.COM if(fd<0 || fd >= shp->lim.open_max)
23524887Schin fd = -1;
23534887Schin }
23544887Schin if(fd<0)
23554887Schin {
23564887Schin errno = EBADF;
23574887Schin return(iop);
23584887Schin }
23598462SApril.Chin@Sun.COM if(!(n=shp->fdstatus[fd]))
23608462SApril.Chin@Sun.COM n = sh_iocheckfd(shp,fd);
23614887Schin if(mode==SF_WRITE && !(n&IOWRITE))
23624887Schin return(iop);
23634887Schin if(mode==SF_READ && !(n&IOREAD))
23644887Schin return(iop);
23658462SApril.Chin@Sun.COM if(!(iop = shp->sftable[fd]))
23668462SApril.Chin@Sun.COM iop=sh_iostream(shp,fd);
23674887Schin return(iop);
23684887Schin }
23694887Schin
23704887Schin typedef int (*Notify_f)(int,int);
23714887Schin
sh_fdnotify(Notify_f notify)23724887Schin Notify_f sh_fdnotify(Notify_f notify)
23734887Schin {
23744887Schin Notify_f old;
23754887Schin old = fdnotify;
23764887Schin fdnotify = notify;
23774887Schin return(old);
23784887Schin }
23794887Schin
sh_fd2sfio(int fd)23804887Schin Sfio_t *sh_fd2sfio(int fd)
23814887Schin {
23828462SApril.Chin@Sun.COM Shell_t *shp = &sh;
23834887Schin register int status;
23844887Schin Sfio_t *sp = sh.sftable[fd];
23858462SApril.Chin@Sun.COM if(!sp && (status = sh_iocheckfd(shp,fd))!=IOCLOSE)
23864887Schin {
23874887Schin register int flags=0;
23884887Schin if(status&IOREAD)
23894887Schin flags |= SF_READ;
23904887Schin if(status&IOWRITE)
23914887Schin flags |= SF_WRITE;
23924887Schin sp = sfnew(NULL, NULL, -1, fd,flags);
23934887Schin sh.sftable[fd] = sp;
23944887Schin }
23954887Schin return(sp);
23964887Schin }
23974887Schin
sh_pathopen(const char * cp)23984887Schin Sfio_t *sh_pathopen(const char *cp)
23994887Schin {
24008462SApril.Chin@Sun.COM Shell_t *shp = &sh;
24014887Schin int n;
24024887Schin #ifdef PATH_BFPATH
24034887Schin if((n=path_open(cp,path_get(cp))) < 0)
24044887Schin n = path_open(cp,(Pathcomp_t*)0);
24054887Schin #else
24064887Schin if((n=path_open(cp,path_get(cp))) < 0)
24074887Schin n = path_open(cp,"");
24084887Schin #endif
24094887Schin if(n < 0)
24104887Schin errormsg(SH_DICT,ERROR_system(1),e_open,cp);
24118462SApril.Chin@Sun.COM return(sh_iostream(shp,n));
24124887Schin }
2413