14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*10898Sroland.mainz@nrubsig.org * Copyright (c) 1982-2009 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 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 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 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 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 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 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 */ 408*10898Sroland.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 */ 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 */ 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 */ 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) 550*10898Sroland.mainz@nrubsig.org { 551*10898Sroland.mainz@nrubsig.org shp->toomany = 1; 552*10898Sroland.mainz@nrubsig.org ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT; 5534887Schin errormsg(SH_DICT,ERROR_system(1),e_toomany); 554*10898Sroland.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 */ 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 */ 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 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 */ 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 { 723*10898Sroland.mainz@nrubsig.org int nfd= -1; 724*10898Sroland.mainz@nrubsig.org if (flags & O_CREAT) 725*10898Sroland.mainz@nrubsig.org { 726*10898Sroland.mainz@nrubsig.org struct stat st; 727*10898Sroland.mainz@nrubsig.org if (stat(path,&st) >=0) 728*10898Sroland.mainz@nrubsig.org nfd = open(path,flags,st.st_mode); 729*10898Sroland.mainz@nrubsig.org } 730*10898Sroland.mainz@nrubsig.org else 731*10898Sroland.mainz@nrubsig.org nfd = open(path,flags); 732*10898Sroland.mainz@nrubsig.org if(nfd>=0) 733*10898Sroland.mainz@nrubsig.org { 734*10898Sroland.mainz@nrubsig.org fd = nfd; 735*10898Sroland.mainz@nrubsig.org goto ok; 736*10898Sroland.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 } 747*10898Sroland.mainz@nrubsig.org else 748*10898Sroland.mainz@nrubsig.org { 749*10898Sroland.mainz@nrubsig.org #if SHOPT_REGRESS 750*10898Sroland.mainz@nrubsig.org char buf[PATH_MAX]; 751*10898Sroland.mainz@nrubsig.org if(strncmp(path,"/etc/",5)==0) 752*10898Sroland.mainz@nrubsig.org { 753*10898Sroland.mainz@nrubsig.org sfsprintf(buf, sizeof(buf), "%s%s", sh_regress_etc(path, __LINE__, __FILE__), path+4); 754*10898Sroland.mainz@nrubsig.org path = buf; 755*10898Sroland.mainz@nrubsig.org } 756*10898Sroland.mainz@nrubsig.org #endif 757*10898Sroland.mainz@nrubsig.org while((fd = open(path, flags, mode)) < 0) 758*10898Sroland.mainz@nrubsig.org if(errno!=EINTR || sh.trapnote) 759*10898Sroland.mainz@nrubsig.org return(-1); 760*10898Sroland.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 */ 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 */ 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 */ 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 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 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 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 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 */ 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 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 */ 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 */ 968*10898Sroland.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; 972*10898Sroland.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); 981*10898Sroland.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 } 1008*10898Sroland.mainz@nrubsig.org else if(iof&IOPROCSUB) 1009*10898Sroland.mainz@nrubsig.org { 1010*10898Sroland.mainz@nrubsig.org struct argnod *ap = (struct argnod*)stakalloc(ARGVAL+strlen(iop->ioname)); 1011*10898Sroland.mainz@nrubsig.org memset(ap, 0, ARGVAL); 1012*10898Sroland.mainz@nrubsig.org if(iof&IOPUT) 1013*10898Sroland.mainz@nrubsig.org ap->argflag = ARG_RAW; 1014*10898Sroland.mainz@nrubsig.org ap->argchn.ap = (struct argnod*)fname; 1015*10898Sroland.mainz@nrubsig.org ap = sh_argprocsub(shp,ap); 1016*10898Sroland.mainz@nrubsig.org fname = ap->argval; 1017*10898Sroland.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 } 1073*10898Sroland.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; 1123*10898Sroland.mainz@nrubsig.org if(iof&IOREWRITE) 1124*10898Sroland.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) 1239*10898Sroland.mainz@nrubsig.org { 12408462SApril.Chin@Sun.COM off=sfseek(sp, off, SEEK_SET); 1241*10898Sroland.mainz@nrubsig.org sfsync(sp); 1242*10898Sroland.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 } 1290*10898Sroland.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 { 12978462SApril.Chin@Sun.COM if(sh_inuse(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 */ 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 */ 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 */ 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) 1467*10898Sroland.mainz@nrubsig.org { 1468*10898Sroland.mainz@nrubsig.org shp->toomany=1; 1469*10898Sroland.mainz@nrubsig.org ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT; 14704887Schin errormsg(SH_DICT,ERROR_system(1),e_toomany); 1471*10898Sroland.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 */ 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 */ 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; 1541*10898Sroland.mainz@nrubsig.org if(filemap[fd].tname == Empty && shp->exitval==0) 1542*10898Sroland.mainz@nrubsig.org ftruncate(origfd,lseek(origfd,0,SEEK_CUR)); 1543*10898Sroland.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 */ 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 */ 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 */ 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 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) 1689*10898Sroland.mainz@nrubsig.org { 1690*10898Sroland.mainz@nrubsig.org job_lock(); 1691*10898Sroland.mainz@nrubsig.org job_unlock(); 1692*10898Sroland.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 */ 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 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 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 */ 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 */ 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; 1996*10898Sroland.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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 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 23724887Schin Notify_f sh_fdnotify(Notify_f notify) 23734887Schin { 23744887Schin Notify_f old; 23754887Schin old = fdnotify; 23764887Schin fdnotify = notify; 23774887Schin return(old); 23784887Schin } 23794887Schin 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 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