14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1982-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.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 <ctype.h> 354887Schin #include <regex.h> 364887Schin #include "variables.h" 374887Schin #include "path.h" 384887Schin #include "io.h" 394887Schin #include "jobs.h" 404887Schin #include "shnodes.h" 414887Schin #include "history.h" 424887Schin #include "edit.h" 434887Schin #include "timeout.h" 444887Schin #include "FEATURE/externs" 454887Schin #include "FEATURE/dynamic" 464887Schin #include "FEATURE/poll" 474887Schin 484887Schin #ifdef FNDELAY 494887Schin # ifdef EAGAIN 504887Schin # if EAGAIN!=EWOULDBLOCK 514887Schin # undef EAGAIN 524887Schin # define EAGAIN EWOULDBLOCK 534887Schin # endif 544887Schin # else 554887Schin # define EAGAIN EWOULDBLOCK 564887Schin # endif /* EAGAIN */ 574887Schin # ifndef O_NONBLOCK 584887Schin # define O_NONBLOCK FNDELAY 594887Schin # endif /* !O_NONBLOCK */ 604887Schin #endif /* FNDELAY */ 614887Schin 624887Schin #ifndef O_SERVICE 634887Schin # define O_SERVICE O_NOCTTY 644887Schin #endif 654887Schin 664887Schin #define RW_ALL (S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH) 674887Schin 684887Schin static void *timeout; 694887Schin static int (*fdnotify)(int,int); 704887Schin 714887Schin #if defined(_lib_socket) && defined(_sys_socket) && defined(_hdr_netinet_in) 724887Schin # include <sys/socket.h> 734887Schin # include <netdb.h> 744887Schin # include <netinet/in.h> 754887Schin # if !defined(htons) && !_lib_htons 764887Schin # define htons(x) (x) 774887Schin # endif 784887Schin # if !defined(htonl) && !_lib_htonl 794887Schin # define htonl(x) (x) 804887Schin # endif 814887Schin # if _pipe_socketpair 82*8462SApril.Chin@Sun.COM # ifndef SHUT_RD 83*8462SApril.Chin@Sun.COM # define SHUT_RD 0 84*8462SApril.Chin@Sun.COM # endif 85*8462SApril.Chin@Sun.COM # ifndef SHUT_WR 86*8462SApril.Chin@Sun.COM # define SHUT_WR 1 87*8462SApril.Chin@Sun.COM # endif 884887Schin # if _socketpair_shutdown_mode 89*8462SApril.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) 904887Schin # else 91*8462SApril.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) 924887Schin # endif 934887Schin # endif 944887Schin 954887Schin #if !_lib_getaddrinfo 964887Schin 974887Schin #undef EAI_SYSTEM 984887Schin 994887Schin #define EAI_SYSTEM 1 1004887Schin 1014887Schin #undef addrinfo 1024887Schin #undef getaddrinfo 1034887Schin #undef freeaddrinfo 1044887Schin 1054887Schin #define addrinfo local_addrinfo 1064887Schin #define getaddrinfo local_getaddrinfo 1074887Schin #define freeaddrinfo local_freeaddrinfo 1084887Schin 1094887Schin struct addrinfo 1104887Schin { 1114887Schin int ai_flags; 1124887Schin int ai_family; 1134887Schin int ai_socktype; 1144887Schin int ai_protocol; 1154887Schin socklen_t ai_addrlen; 1164887Schin struct sockaddr* ai_addr; 1174887Schin struct addrinfo* ai_next; 1184887Schin }; 1194887Schin 1204887Schin static int 1214887Schin getaddrinfo(const char* node, const char* service, const struct addrinfo* hint, struct addrinfo **addr) 1224887Schin { 1234887Schin unsigned long ip_addr = 0; 1244887Schin unsigned short ip_port = 0; 1254887Schin struct addrinfo* ap; 1264887Schin struct hostent* hp; 1274887Schin struct sockaddr_in* ip; 1284887Schin char* prot; 1294887Schin long n; 1304887Schin 1314887Schin if (!(hp = gethostbyname(node)) || hp->h_addrtype!=AF_INET || hp->h_length>sizeof(struct in_addr)) 1324887Schin { 1334887Schin errno = EADDRNOTAVAIL; 1344887Schin return EAI_SYSTEM; 1354887Schin } 1364887Schin ip_addr = (unsigned long)((struct in_addr*)hp->h_addr)->s_addr; 1374887Schin if ((n = strtol(service, &prot, 10)) > 0 && n <= USHRT_MAX && !*prot) 1384887Schin ip_port = htons((unsigned short)n); 1394887Schin else 1404887Schin { 1414887Schin struct servent* sp; 1424887Schin const char* protocol = 0; 1434887Schin 1444887Schin if (hint) 1454887Schin switch (hint->ai_socktype) 1464887Schin { 1474887Schin case SOCK_STREAM: 1484887Schin switch (hint->ai_protocol) 1494887Schin { 1504887Schin case 0: 1514887Schin protocol = "tcp"; 1524887Schin break; 1534887Schin #ifdef IPPROTO_SCTP 1544887Schin case IPPROTO_SCTP: 1554887Schin protocol = "sctp"; 1564887Schin break; 1574887Schin #endif 1584887Schin } 1594887Schin break; 1604887Schin case SOCK_DGRAM: 1614887Schin protocol = "udp"; 1624887Schin break; 1634887Schin } 1644887Schin if (!protocol) 1654887Schin { 1664887Schin errno = EPROTONOSUPPORT; 1674887Schin return 1; 1684887Schin } 1694887Schin if (sp = getservbyname(service, protocol)) 1704887Schin ip_port = sp->s_port; 1714887Schin } 1724887Schin if (!ip_port) 1734887Schin { 1744887Schin errno = EADDRNOTAVAIL; 1754887Schin return EAI_SYSTEM; 1764887Schin } 1774887Schin if (!(ap = newof(0, struct addrinfo, 1, sizeof(struct sockaddr_in)))) 1784887Schin return EAI_SYSTEM; 1794887Schin if (hint) 1804887Schin *ap = *hint; 1814887Schin ap->ai_family = hp->h_addrtype; 1824887Schin ap->ai_addrlen = sizeof(struct sockaddr_in); 1834887Schin ap->ai_addr = (struct sockaddr *)(ap+1); 1844887Schin ip = (struct sockaddr_in *)ap->ai_addr; 1854887Schin ip->sin_family = AF_INET; 1864887Schin ip->sin_port = ip_port; 1874887Schin ip->sin_addr.s_addr = ip_addr; 1884887Schin *addr = ap; 1894887Schin return 0; 1904887Schin } 1914887Schin 1924887Schin static void 1934887Schin freeaddrinfo(struct addrinfo* ap) 1944887Schin { 1954887Schin if (ap) 1964887Schin free(ap); 1974887Schin } 1984887Schin 1994887Schin #endif 2004887Schin 2014887Schin /* 2024887Schin * return <protocol>/<host>/<service> fd 2034887Schin */ 2044887Schin 2054887Schin typedef int (*Inetintr_f)(struct addrinfo*, void*); 2064887Schin 2074887Schin static int 2084887Schin inetopen(const char* path, int server, Inetintr_f onintr, void* handle) 2094887Schin { 2104887Schin register char* s; 2114887Schin register char* t; 2124887Schin int fd; 2134887Schin int oerrno; 2144887Schin struct addrinfo hint; 2154887Schin struct addrinfo* addr; 2164887Schin struct addrinfo* p; 2174887Schin 2184887Schin memset(&hint, 0, sizeof(hint)); 2194887Schin hint.ai_family = PF_UNSPEC; 2204887Schin switch (path[0]) 2214887Schin { 2224887Schin #ifdef IPPROTO_SCTP 2234887Schin case 's': 2244887Schin if (path[1]!='c' || path[2]!='t' || path[3]!='p' || path[4]!='/') 2254887Schin { 2264887Schin errno = ENOTDIR; 2274887Schin return -1; 2284887Schin } 2294887Schin hint.ai_socktype = SOCK_STREAM; 2304887Schin hint.ai_protocol = IPPROTO_SCTP; 2314887Schin path += 5; 2324887Schin break; 2334887Schin #endif 2344887Schin case 't': 2354887Schin if (path[1]!='c' || path[2]!='p' || path[3]!='/') 2364887Schin { 2374887Schin errno = ENOTDIR; 2384887Schin return -1; 2394887Schin } 2404887Schin hint.ai_socktype = SOCK_STREAM; 2414887Schin path += 4; 2424887Schin break; 2434887Schin case 'u': 2444887Schin if (path[1]!='d' || path[2]!='p' || path[3]!='/') 2454887Schin { 2464887Schin errno = ENOTDIR; 2474887Schin return -1; 2484887Schin } 2494887Schin hint.ai_socktype = SOCK_DGRAM; 2504887Schin path += 4; 2514887Schin break; 2524887Schin default: 2534887Schin errno = ENOTDIR; 2544887Schin return -1; 2554887Schin } 2564887Schin if (!(s = strdup(path))) 2574887Schin return -1; 2584887Schin if (t = strchr(s, '/')) 2594887Schin { 2604887Schin *t++ = 0; 2614887Schin if (streq(s, "local")) 2624887Schin s = "localhost"; 2634887Schin fd = getaddrinfo(s, t, &hint, &addr); 2644887Schin } 2654887Schin else 2664887Schin fd = -1; 2674887Schin free(s); 2684887Schin if (fd) 2694887Schin { 2704887Schin if (fd != EAI_SYSTEM) 2714887Schin errno = ENOTDIR; 2724887Schin return -1; 2734887Schin } 2744887Schin oerrno = errno; 2754887Schin errno = 0; 2764887Schin fd = -1; 2774887Schin for (p = addr; p; p = p->ai_next) 2784887Schin { 2794887Schin /* 2804887Schin * some api's don't take the hint 2814887Schin */ 2824887Schin 2834887Schin if (!p->ai_protocol) 2844887Schin p->ai_protocol = hint.ai_protocol; 2854887Schin if (!p->ai_socktype) 2864887Schin p->ai_socktype = hint.ai_socktype; 2874887Schin while ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) >= 0) 2884887Schin { 2894887Schin if (server && !bind(fd, p->ai_addr, p->ai_addrlen) && !listen(fd, 5) || !server && !connect(fd, p->ai_addr, p->ai_addrlen)) 2904887Schin goto done; 2914887Schin close(fd); 2924887Schin fd = -1; 2934887Schin if (errno != EINTR || !onintr) 2944887Schin break; 2954887Schin if ((*onintr)(addr, handle)) 2964887Schin return -1; 2974887Schin } 2984887Schin } 2994887Schin done: 3004887Schin freeaddrinfo(addr); 3014887Schin if (fd >= 0) 3024887Schin errno = oerrno; 3034887Schin return fd; 3044887Schin } 3054887Schin 3064887Schin #else 3074887Schin 3084887Schin #undef O_SERVICE 3094887Schin 3104887Schin #endif 3114887Schin 3124887Schin struct fdsave 3134887Schin { 3144887Schin int orig_fd; /* original file descriptor */ 3154887Schin int save_fd; /* saved file descriptor */ 3164887Schin int subshell; /* saved for subshell */ 317*8462SApril.Chin@Sun.COM char *tname; /* name used with >; */ 3184887Schin }; 3194887Schin 3204887Schin static int subexcept(Sfio_t*, int, void*, Sfdisc_t*); 3214887Schin static int eval_exceptf(Sfio_t*, int, void*, Sfdisc_t*); 3224887Schin static int slowexcept(Sfio_t*, int, void*, Sfdisc_t*); 3234887Schin static int pipeexcept(Sfio_t*, int, void*, Sfdisc_t*); 3244887Schin static ssize_t piperead(Sfio_t*, void*, size_t, Sfdisc_t*); 3254887Schin static ssize_t slowread(Sfio_t*, void*, size_t, Sfdisc_t*); 3264887Schin static ssize_t subread(Sfio_t*, void*, size_t, Sfdisc_t*); 3274887Schin static ssize_t tee_write(Sfio_t*,const void*,size_t,Sfdisc_t*); 3284887Schin static int io_prompt(Sfio_t*,int); 329*8462SApril.Chin@Sun.COM static int io_heredoc(Shell_t*,register struct ionod*, const char*, int); 330*8462SApril.Chin@Sun.COM static void sftrack(Sfio_t*,int,void*); 3314887Schin static const Sfdisc_t eval_disc = { NULL, NULL, NULL, eval_exceptf, NULL}; 3324887Schin static Sfdisc_t tee_disc = {NULL,tee_write,NULL,NULL,NULL}; 333*8462SApril.Chin@Sun.COM static Sfio_t *subopen(Shell_t *,Sfio_t*, off_t, long); 3344887Schin static const Sfdisc_t sub_disc = { subread, 0, 0, subexcept, 0 }; 3354887Schin 3364887Schin struct subfile 3374887Schin { 3384887Schin Sfdisc_t disc; 3394887Schin Sfio_t *oldsp; 3404887Schin off_t offset; 3414887Schin long size; 3424887Schin long left; 3434887Schin }; 3444887Schin 3454887Schin struct Eof 3464887Schin { 3474887Schin Namfun_t hdr; 3484887Schin int fd; 3494887Schin }; 3504887Schin 3514887Schin static Sfdouble_t nget_cur_eof(register Namval_t* np, Namfun_t *fp) 3524887Schin { 3534887Schin struct Eof *ep = (struct Eof*)fp; 3544887Schin Sfoff_t end, cur =lseek(ep->fd, (Sfoff_t)0, SEEK_CUR); 3554887Schin if(*np->nvname=='C') 3564887Schin return((Sfdouble_t)cur); 3574887Schin if(cur<0) 3584887Schin return((Sfdouble_t)-1); 3594887Schin end =lseek(ep->fd, (Sfoff_t)0, SEEK_END); 3604887Schin lseek(ep->fd, (Sfoff_t)0, SEEK_CUR); 3614887Schin return((Sfdouble_t)end); 3624887Schin } 3634887Schin 3644887Schin static const Namdisc_t EOF_disc = { sizeof(struct Eof), 0, 0, nget_cur_eof}; 3654887Schin 3664887Schin #define MATCH_BUFF (64*1024) 3674887Schin struct Match 3684887Schin { 3694887Schin Sfoff_t offset; 3704887Schin char *base; 3714887Schin }; 3724887Schin 3734887Schin static int matchf(void *handle, char *ptr, size_t size) 3744887Schin { 3754887Schin struct Match *mp = (struct Match*)handle; 3764887Schin mp->offset += (ptr-mp->base); 3774887Schin return(1); 3784887Schin } 3794887Schin 3804887Schin 3814887Schin static struct fdsave *filemap; 3824887Schin static short filemapsize; 3834887Schin 3844887Schin /* ======== input output and file copying ======== */ 3854887Schin 386*8462SApril.Chin@Sun.COM void sh_ioinit(Shell_t *shp) 3874887Schin { 3884887Schin register int n; 3894887Schin filemapsize = 8; 390*8462SApril.Chin@Sun.COM filemap = (struct fdsave*)malloc(filemapsize*sizeof(struct fdsave)); 3914887Schin #if SHOPT_FASTPIPE 392*8462SApril.Chin@Sun.COM n = shp->lim.open_max+2; 3934887Schin #else 394*8462SApril.Chin@Sun.COM n = shp->lim.open_max; 3954887Schin #endif /* SHOPT_FASTPIPE */ 396*8462SApril.Chin@Sun.COM shp->fdstatus = (unsigned char*)malloc((unsigned)n); 397*8462SApril.Chin@Sun.COM memset((char*)shp->fdstatus,0,n); 398*8462SApril.Chin@Sun.COM shp->fdptrs = (int**)malloc(n*sizeof(int*)); 399*8462SApril.Chin@Sun.COM memset((char*)shp->fdptrs,0,n*sizeof(int*)); 400*8462SApril.Chin@Sun.COM shp->sftable = (Sfio_t**)malloc(n*sizeof(Sfio_t*)); 401*8462SApril.Chin@Sun.COM memset((char*)shp->sftable,0,n*sizeof(Sfio_t*)); 402*8462SApril.Chin@Sun.COM shp->sftable[0] = sfstdin; 403*8462SApril.Chin@Sun.COM shp->sftable[1] = sfstdout; 404*8462SApril.Chin@Sun.COM shp->sftable[2] = sfstderr; 4054887Schin sfnotify(sftrack); 406*8462SApril.Chin@Sun.COM sh_iostream(shp,0); 4074887Schin /* all write steams are in the same pool and share outbuff */ 408*8462SApril.Chin@Sun.COM shp->outpool = sfopen(NIL(Sfio_t*),NIL(char*),"sw"); /* pool identifier */ 409*8462SApril.Chin@Sun.COM shp->outbuff = (char*)malloc(IOBSIZE); 410*8462SApril.Chin@Sun.COM shp->errbuff = (char*)malloc(IOBSIZE/4); 411*8462SApril.Chin@Sun.COM sfsetbuf(sfstderr,shp->errbuff,IOBSIZE/4); 412*8462SApril.Chin@Sun.COM sfsetbuf(sfstdout,shp->outbuff,IOBSIZE); 413*8462SApril.Chin@Sun.COM sfpool(sfstdout,shp->outpool,SF_WRITE); 414*8462SApril.Chin@Sun.COM sfpool(sfstderr,shp->outpool,SF_WRITE); 4154887Schin sfset(sfstdout,SF_LINE,0); 416*8462SApril.Chin@Sun.COM sfset(sfstderr,SF_LINE,0); 417*8462SApril.Chin@Sun.COM sfset(sfstdin,SF_SHARE|SF_PUBLIC,1); 418*8462SApril.Chin@Sun.COM } 419*8462SApril.Chin@Sun.COM 420*8462SApril.Chin@Sun.COM /* 421*8462SApril.Chin@Sun.COM * Handle output stream exceptions 422*8462SApril.Chin@Sun.COM */ 423*8462SApril.Chin@Sun.COM static int outexcept(register Sfio_t *iop,int type,void *data,Sfdisc_t *handle) 424*8462SApril.Chin@Sun.COM { 425*8462SApril.Chin@Sun.COM static int active = 0; 426*8462SApril.Chin@Sun.COM 427*8462SApril.Chin@Sun.COM NOT_USED(handle); 428*8462SApril.Chin@Sun.COM if(type==SF_DPOP || type==SF_FINAL) 429*8462SApril.Chin@Sun.COM free((void*)handle); 430*8462SApril.Chin@Sun.COM else if(type==SF_WRITE && (*(ssize_t*)data)<0 && sffileno(iop)!=2) 431*8462SApril.Chin@Sun.COM switch (errno) 432*8462SApril.Chin@Sun.COM { 433*8462SApril.Chin@Sun.COM case EINTR: 434*8462SApril.Chin@Sun.COM case EPIPE: 435*8462SApril.Chin@Sun.COM #ifdef ECONNRESET 436*8462SApril.Chin@Sun.COM case ECONNRESET: 437*8462SApril.Chin@Sun.COM #endif 438*8462SApril.Chin@Sun.COM #ifdef ESHUTDOWN 439*8462SApril.Chin@Sun.COM case ESHUTDOWN: 440*8462SApril.Chin@Sun.COM #endif 441*8462SApril.Chin@Sun.COM break; 442*8462SApril.Chin@Sun.COM default: 443*8462SApril.Chin@Sun.COM if(!active) 444*8462SApril.Chin@Sun.COM { 445*8462SApril.Chin@Sun.COM int mode = ((struct checkpt*)sh.jmplist)->mode; 446*8462SApril.Chin@Sun.COM int save = errno; 447*8462SApril.Chin@Sun.COM active = 1; 448*8462SApril.Chin@Sun.COM ((struct checkpt*)sh.jmplist)->mode = 0; 449*8462SApril.Chin@Sun.COM sfpurge(iop); 450*8462SApril.Chin@Sun.COM sfpool(iop,NIL(Sfio_t*),SF_WRITE); 451*8462SApril.Chin@Sun.COM errno = save; 452*8462SApril.Chin@Sun.COM errormsg(SH_DICT,ERROR_system(1),e_badwrite,sffileno(iop)); 453*8462SApril.Chin@Sun.COM active = 0; 454*8462SApril.Chin@Sun.COM ((struct checkpt*)sh.jmplist)->mode = mode; 455*8462SApril.Chin@Sun.COM sh_exit(1); 456*8462SApril.Chin@Sun.COM } 457*8462SApril.Chin@Sun.COM return(-1); 458*8462SApril.Chin@Sun.COM } 459*8462SApril.Chin@Sun.COM return(0); 4604887Schin } 4614887Schin 4624887Schin /* 4634887Schin * create or initialize a stream corresponding to descriptor <fd> 4644887Schin * a buffer with room for a sentinal is allocated for a read stream. 4654887Schin * A discipline is inserted when read stream is a tty or a pipe 4664887Schin * For output streams, the buffer is set to sh.output and put into 4674887Schin * the sh.outpool synchronization pool 4684887Schin */ 469*8462SApril.Chin@Sun.COM Sfio_t *sh_iostream(Shell_t *shp, register int fd) 4704887Schin { 4714887Schin register Sfio_t *iop; 472*8462SApril.Chin@Sun.COM register int status = sh_iocheckfd(shp,fd); 4734887Schin register int flags = SF_WRITE; 4744887Schin char *bp; 475*8462SApril.Chin@Sun.COM Sfdisc_t *dp; 4764887Schin #if SHOPT_FASTPIPE 477*8462SApril.Chin@Sun.COM if(fd>=shp->lim.open_max) 478*8462SApril.Chin@Sun.COM return(shp->sftable[fd]); 4794887Schin #endif /* SHOPT_FASTPIPE */ 4804887Schin if(status==IOCLOSE) 4814887Schin { 4824887Schin switch(fd) 4834887Schin { 4844887Schin case 0: 4854887Schin return(sfstdin); 4864887Schin case 1: 4874887Schin return(sfstdout); 4884887Schin case 2: 4894887Schin return(sfstderr); 4904887Schin } 4914887Schin return(NIL(Sfio_t*)); 4924887Schin } 4934887Schin if(status&IOREAD) 4944887Schin { 4954887Schin if(!(bp = (char *)malloc(IOBSIZE+1))) 4964887Schin return(NIL(Sfio_t*)); 4974887Schin flags |= SF_READ; 4984887Schin if(!(status&IOWRITE)) 4994887Schin flags &= ~SF_WRITE; 5004887Schin } 5014887Schin else 502*8462SApril.Chin@Sun.COM bp = shp->outbuff; 5034887Schin if(status&IODUP) 5044887Schin flags |= SF_SHARE|SF_PUBLIC; 505*8462SApril.Chin@Sun.COM if((iop = shp->sftable[fd]) && sffileno(iop)>=0) 5064887Schin sfsetbuf(iop, bp, IOBSIZE); 5074887Schin else if(!(iop=sfnew((fd<=2?iop:0),bp,IOBSIZE,fd,flags))) 5084887Schin return(NIL(Sfio_t*)); 509*8462SApril.Chin@Sun.COM dp = newof(0,Sfdisc_t,1,0); 5104887Schin if(status&IOREAD) 5114887Schin { 5124887Schin sfset(iop,SF_MALLOC,1); 513*8462SApril.Chin@Sun.COM if(!(status&IOWRITE)) 514*8462SApril.Chin@Sun.COM sfset(iop,SF_IOCHECK,1); 515*8462SApril.Chin@Sun.COM dp->exceptf = slowexcept; 516*8462SApril.Chin@Sun.COM if(status&IOTTY) 517*8462SApril.Chin@Sun.COM dp->readf = slowread; 518*8462SApril.Chin@Sun.COM else if(status&IONOSEEK) 5194887Schin { 520*8462SApril.Chin@Sun.COM dp->readf = piperead; 521*8462SApril.Chin@Sun.COM sfset(iop, SF_IOINTR,1); 5224887Schin } 523*8462SApril.Chin@Sun.COM else 524*8462SApril.Chin@Sun.COM dp->readf = 0; 525*8462SApril.Chin@Sun.COM dp->seekf = 0; 526*8462SApril.Chin@Sun.COM dp->writef = 0; 5274887Schin } 5284887Schin else 529*8462SApril.Chin@Sun.COM { 530*8462SApril.Chin@Sun.COM dp->exceptf = outexcept; 531*8462SApril.Chin@Sun.COM sfpool(iop,shp->outpool,SF_WRITE); 532*8462SApril.Chin@Sun.COM } 533*8462SApril.Chin@Sun.COM sfdisc(iop,dp); 534*8462SApril.Chin@Sun.COM shp->sftable[fd] = iop; 5354887Schin return(iop); 5364887Schin } 5374887Schin 5384887Schin /* 5394887Schin * preserve the file descriptor or stream by moving it 5404887Schin */ 541*8462SApril.Chin@Sun.COM static void io_preserve(Shell_t* shp, register Sfio_t *sp, register int f2) 5424887Schin { 5434887Schin register int fd; 5444887Schin if(sp) 5454887Schin fd = sfsetfd(sp,10); 5464887Schin else 5474887Schin fd = sh_fcntl(f2,F_DUPFD,10); 548*8462SApril.Chin@Sun.COM if(f2==shp->infd) 549*8462SApril.Chin@Sun.COM shp->infd = fd; 5504887Schin if(fd<0) 5514887Schin errormsg(SH_DICT,ERROR_system(1),e_toomany); 552*8462SApril.Chin@Sun.COM if(shp->fdptrs[fd]=shp->fdptrs[f2]) 5534887Schin { 5544887Schin if(f2==job.fd) 5554887Schin job.fd=fd; 556*8462SApril.Chin@Sun.COM *shp->fdptrs[fd] = fd; 557*8462SApril.Chin@Sun.COM shp->fdptrs[f2] = 0; 5584887Schin } 559*8462SApril.Chin@Sun.COM shp->sftable[fd] = sp; 560*8462SApril.Chin@Sun.COM shp->fdstatus[fd] = shp->fdstatus[f2]; 5614887Schin if(fcntl(f2,F_GETFD,0)&1) 5624887Schin { 5634887Schin fcntl(fd,F_SETFD,FD_CLOEXEC); 564*8462SApril.Chin@Sun.COM shp->fdstatus[fd] |= IOCLEX; 5654887Schin } 566*8462SApril.Chin@Sun.COM shp->sftable[f2] = 0; 5674887Schin } 5684887Schin 5694887Schin /* 5704887Schin * Given a file descriptor <f1>, move it to a file descriptor number <f2> 5714887Schin * If <f2> is needed move it, otherwise it is closed first. 5724887Schin * The original stream <f1> is closed. 5734887Schin * The new file descriptor <f2> is returned; 5744887Schin */ 575*8462SApril.Chin@Sun.COM int sh_iorenumber(Shell_t *shp, register int f1,register int f2) 5764887Schin { 577*8462SApril.Chin@Sun.COM register Sfio_t *sp = shp->sftable[f2]; 5784887Schin if(f1!=f2) 5794887Schin { 5804887Schin /* see whether file descriptor is in use */ 5814887Schin if(sh_inuse(f2) || (f2>2 && sp)) 5824887Schin { 583*8462SApril.Chin@Sun.COM if(!(shp->inuse_bits&(1<<f2))) 584*8462SApril.Chin@Sun.COM io_preserve(shp,sp,f2); 5854887Schin sp = 0; 5864887Schin } 5874887Schin else if(f2==0) 588*8462SApril.Chin@Sun.COM shp->st.ioset = 1; 5894887Schin sh_close(f2); 5904887Schin if(f2<=2 && sp) 5914887Schin { 592*8462SApril.Chin@Sun.COM register Sfio_t *spnew = sh_iostream(shp,f1); 593*8462SApril.Chin@Sun.COM shp->fdstatus[f2] = (shp->fdstatus[f1]&~IOCLEX); 5944887Schin sfsetfd(spnew,f2); 5954887Schin sfswap(spnew,sp); 5964887Schin sfset(sp,SF_SHARE|SF_PUBLIC,1); 5974887Schin } 5984887Schin else 5994887Schin { 600*8462SApril.Chin@Sun.COM shp->fdstatus[f2] = (shp->fdstatus[f1]&~IOCLEX); 6014887Schin if((f2 = sh_fcntl(f1,F_DUPFD, f2)) < 0) 6024887Schin errormsg(SH_DICT,ERROR_system(1),e_file+4); 6034887Schin else if(f2 <= 2) 604*8462SApril.Chin@Sun.COM sh_iostream(shp,f2); 6054887Schin } 6064887Schin if(sp) 607*8462SApril.Chin@Sun.COM shp->sftable[f1] = 0; 6084887Schin sh_close(f1); 6094887Schin } 6104887Schin return(f2); 6114887Schin } 6124887Schin 6134887Schin /* 6144887Schin * close a file descriptor and update stream table and attributes 6154887Schin */ 6164887Schin int sh_close(register int fd) 6174887Schin { 6184887Schin register Sfio_t *sp; 6194887Schin register int r = 0; 6204887Schin if(fd<0) 6214887Schin return(-1); 6224887Schin if(!(sp=sh.sftable[fd]) || sfclose(sp) < 0) 6234887Schin { 6244887Schin if(fdnotify) 6254887Schin (*fdnotify)(fd,SH_FDCLOSE); 6264887Schin r=close(fd); 6274887Schin } 6284887Schin if(fd>2) 6294887Schin sh.sftable[fd] = 0; 6304887Schin sh.fdstatus[fd] = IOCLOSE; 6314887Schin if(sh.fdptrs[fd]) 6324887Schin *sh.fdptrs[fd] = -1; 6334887Schin sh.fdptrs[fd] = 0; 6344887Schin if(fd < 10) 6354887Schin sh.inuse_bits &= ~(1<<fd); 6364887Schin return(r); 6374887Schin } 6384887Schin 639*8462SApril.Chin@Sun.COM #ifdef O_SERVICE 640*8462SApril.Chin@Sun.COM 6414887Schin static int 6424887Schin onintr(struct addrinfo* addr, void* handle) 6434887Schin { 6444887Schin Shell_t* sh = (Shell_t*)handle; 6454887Schin 6464887Schin if (sh->trapnote&SH_SIGSET) 6474887Schin { 6484887Schin freeaddrinfo(addr); 6494887Schin sh_exit(SH_EXITSIG); 6504887Schin return -1; 6514887Schin } 6524887Schin if (sh->trapnote) 6534887Schin sh_chktrap(); 6544887Schin return 0; 6554887Schin } 6564887Schin 657*8462SApril.Chin@Sun.COM #endif 658*8462SApril.Chin@Sun.COM 6594887Schin /* 6604887Schin * Mimic open(2) with checks for pseudo /dev/ files. 6614887Schin */ 6624887Schin int sh_open(register const char *path, int flags, ...) 6634887Schin { 664*8462SApril.Chin@Sun.COM Shell_t *shp = &sh; 6654887Schin register int fd = -1; 6664887Schin mode_t mode; 6674887Schin char *e; 6684887Schin va_list ap; 6694887Schin va_start(ap, flags); 6704887Schin mode = (flags & O_CREAT) ? va_arg(ap, int) : 0; 6714887Schin va_end(ap); 6724887Schin errno = 0; 6734887Schin if(*path==0) 6744887Schin { 6754887Schin errno = ENOENT; 6764887Schin return(-1); 6774887Schin } 6784887Schin if (path[0]=='/' && path[1]=='d' && path[2]=='e' && path[3]=='v' && path[4]=='/') 6794887Schin { 6804887Schin switch (path[5]) 6814887Schin { 6824887Schin case 'f': 6834887Schin if (path[6]=='d' && path[7]=='/') 6844887Schin { 6854887Schin fd = (int)strtol(path+8, &e, 10); 6864887Schin if (*e) 6874887Schin fd = -1; 6884887Schin } 6894887Schin break; 6904887Schin case 's': 6914887Schin if (path[6]=='t' && path[7]=='d') 6924887Schin switch (path[8]) 6934887Schin { 6944887Schin case 'e': 6954887Schin if (path[9]=='r' && path[10]=='r' && !path[11]) 6964887Schin fd = 2; 6974887Schin break; 6984887Schin case 'i': 6994887Schin if (path[9]=='n' && !path[10]) 7004887Schin fd = 0; 7014887Schin break; 7024887Schin case 'o': 7034887Schin if (path[9]=='u' && path[10]=='t' && !path[11]) 7044887Schin fd = 1; 7054887Schin break; 7064887Schin } 7074887Schin } 7084887Schin #ifdef O_SERVICE 7094887Schin if (fd < 0) 7104887Schin { 7114887Schin if ((fd = inetopen(path+5, !!(flags & O_SERVICE), onintr, &sh)) < 0 && errno != ENOTDIR) 7124887Schin return -1; 7134887Schin if (fd >= 0) 7144887Schin goto ok; 7154887Schin } 7164887Schin #endif 7174887Schin } 7184887Schin if (fd >= 0) 7194887Schin { 720*8462SApril.Chin@Sun.COM if((mode=sh_iocheckfd(shp,fd))==IOCLOSE) 7214887Schin return(-1); 7224887Schin flags &= O_ACCMODE; 7234887Schin if(!(mode&IOWRITE) && ((flags==O_WRONLY) || (flags==O_RDWR))) 7244887Schin return(-1); 7254887Schin if(!(mode&IOREAD) && ((flags==O_RDONLY) || (flags==O_RDWR))) 7264887Schin return(-1); 7274887Schin if((fd=dup(fd))<0) 7284887Schin return(-1); 7294887Schin } 7304887Schin else while((fd = open(path, flags, mode)) < 0) 7314887Schin if(errno!=EINTR || sh.trapnote) 7324887Schin return(-1); 7334887Schin #ifdef O_SERVICE 7344887Schin ok: 7354887Schin #endif 7364887Schin flags &= O_ACCMODE; 7374887Schin if(flags==O_WRONLY) 7384887Schin mode = IOWRITE; 7394887Schin else if(flags==O_RDWR) 7404887Schin mode = (IOREAD|IOWRITE); 7414887Schin else 7424887Schin mode = IOREAD; 7434887Schin sh.fdstatus[fd] = mode; 7444887Schin return(fd); 7454887Schin } 7464887Schin 7474887Schin /* 7484887Schin * Open a file for reading 7494887Schin * On failure, print message. 7504887Schin */ 7514887Schin int sh_chkopen(register const char *name) 7524887Schin { 7534887Schin register int fd = sh_open(name,O_RDONLY,0); 7544887Schin if(fd < 0) 7554887Schin errormsg(SH_DICT,ERROR_system(1),e_open,name); 7564887Schin return(fd); 7574887Schin } 7584887Schin 7594887Schin /* 7604887Schin * move open file descriptor to a number > 2 7614887Schin */ 7624887Schin int sh_iomovefd(register int fdold) 7634887Schin { 7644887Schin register int fdnew; 7654887Schin if(fdold<0 || fdold>2) 7664887Schin return(fdold); 7674887Schin fdnew = sh_iomovefd(dup(fdold)); 7684887Schin sh.fdstatus[fdnew] = (sh.fdstatus[fdold]&~IOCLEX); 7694887Schin close(fdold); 7704887Schin sh.fdstatus[fdold] = IOCLOSE; 7714887Schin return(fdnew); 7724887Schin } 7734887Schin 7744887Schin /* 7754887Schin * create a pipe and print message on failure 7764887Schin */ 7774887Schin int sh_pipe(register int pv[]) 7784887Schin { 7794887Schin int fd[2]; 7804887Schin if(pipe(fd)<0 || (pv[0]=fd[0])<0 || (pv[1]=fd[1])<0) 7814887Schin errormsg(SH_DICT,ERROR_system(1),e_pipe); 7824887Schin pv[0] = sh_iomovefd(pv[0]); 7834887Schin pv[1] = sh_iomovefd(pv[1]); 7844887Schin sh.fdstatus[pv[0]] = IONOSEEK|IOREAD; 7854887Schin sh.fdstatus[pv[1]] = IONOSEEK|IOWRITE; 7864887Schin sh_subsavefd(pv[0]); 7874887Schin sh_subsavefd(pv[1]); 7884887Schin return(0); 7894887Schin } 7904887Schin 7914887Schin static int pat_seek(void *handle, const char *str, size_t sz) 7924887Schin { 7934887Schin char **bp = (char**)handle; 7944887Schin *bp = (char*)str; 7954887Schin return(-1); 7964887Schin } 7974887Schin 7984887Schin static int pat_line(const regex_t* rp, const char *buff, register size_t n) 7994887Schin { 8004887Schin register const char *cp=buff, *sp; 8014887Schin while(n>0) 8024887Schin { 8034887Schin for(sp=cp; n-->0 && *cp++ != '\n';); 8044887Schin if(regnexec(rp,sp,cp-sp, 0, (regmatch_t*)0, 0)==0) 8054887Schin return(sp-buff); 8064887Schin } 8074887Schin return(cp-buff); 8084887Schin } 8094887Schin 810*8462SApril.Chin@Sun.COM static int io_patseek(Shell_t *shp, regex_t *rp, Sfio_t* sp, int flags) 8114887Schin { 8124887Schin char *cp, *match; 813*8462SApril.Chin@Sun.COM int r, fd=sffileno(sp), close_exec = shp->fdstatus[fd]&IOCLEX; 8144887Schin int was_share,s=(PIPE_BUF>SF_BUFSIZE?SF_BUFSIZE:PIPE_BUF); 8154887Schin size_t n,m; 816*8462SApril.Chin@Sun.COM shp->fdstatus[sffileno(sp)] |= IOCLEX; 8174887Schin if(fd==0) 8184887Schin was_share = sfset(sp,SF_SHARE,1); 8194887Schin while((cp=sfreserve(sp, -s, SF_LOCKR)) || (cp=sfreserve(sp,SF_UNBOUND, SF_LOCKR))) 8204887Schin { 8214887Schin m = n = sfvalue(sp); 8224887Schin while(n>0 && cp[n-1]!='\n') 8234887Schin n--; 8244887Schin if(n) 8254887Schin m = n; 8264887Schin r = regrexec(rp,cp,m,0,(regmatch_t*)0, 0, '\n', (void*)&match, pat_seek); 8274887Schin if(r<0) 8284887Schin m = match-cp; 8294887Schin else if(r==2) 8304887Schin { 8314887Schin if((m = pat_line(rp,cp,m)) < n) 8324887Schin r = -1; 8334887Schin } 8344887Schin if(m && (flags&IOCOPY)) 8354887Schin sfwrite(sfstdout,cp,m); 8364887Schin sfread(sp,cp,m); 8374887Schin if(r<0) 8384887Schin break; 8394887Schin } 8404887Schin if(!close_exec) 841*8462SApril.Chin@Sun.COM shp->fdstatus[sffileno(sp)] &= ~IOCLEX; 8424887Schin if(fd==0 && !(was_share&SF_SHARE)) 8434887Schin sfset(sp, SF_SHARE,0); 8444887Schin return(0); 8454887Schin } 8464887Schin 847*8462SApril.Chin@Sun.COM static Sfoff_t file_offset(Shell_t *shp, int fn, char *fname) 8484887Schin { 849*8462SApril.Chin@Sun.COM Sfio_t *sp = shp->sftable[fn]; 8504887Schin char *cp; 8514887Schin Sfoff_t off; 8524887Schin struct Eof endf; 853*8462SApril.Chin@Sun.COM Namval_t *mp = nv_open("EOF",shp->var_tree,0); 854*8462SApril.Chin@Sun.COM Namval_t *pp = nv_open("CUR",shp->var_tree,0); 8554887Schin memset(&endf,0,sizeof(struct Eof)); 8564887Schin endf.fd = fn; 8574887Schin endf.hdr.disc = &EOF_disc; 8584887Schin endf.hdr.nofree = 1; 8594887Schin if(mp) 8604887Schin nv_stack(mp, &endf.hdr); 8614887Schin if(pp) 8624887Schin nv_stack(pp, &endf.hdr); 8634887Schin if(sp) 8644887Schin sfsync(sp); 8654887Schin off = sh_strnum(fname, &cp, 0); 8664887Schin if(mp) 8674887Schin nv_stack(mp, NiL); 8684887Schin if(pp) 8694887Schin nv_stack(pp, NiL); 8704887Schin return(*cp?(Sfoff_t)-1:off); 8714887Schin } 8724887Schin 8734887Schin /* 8744887Schin * close a pipe 8754887Schin */ 8764887Schin void sh_pclose(register int pv[]) 8774887Schin { 8784887Schin if(pv[0]>=2) 8794887Schin sh_close(pv[0]); 8804887Schin if(pv[1]>=2) 8814887Schin sh_close(pv[1]); 8824887Schin pv[0] = pv[1] = -1; 8834887Schin } 8844887Schin 885*8462SApril.Chin@Sun.COM static char *io_usename(char *name, int *perm, int mode) 886*8462SApril.Chin@Sun.COM { 887*8462SApril.Chin@Sun.COM struct stat statb; 888*8462SApril.Chin@Sun.COM char *tname, *sp, *ep; 889*8462SApril.Chin@Sun.COM int fd,len,n=0; 890*8462SApril.Chin@Sun.COM if(mode==0) 891*8462SApril.Chin@Sun.COM { 892*8462SApril.Chin@Sun.COM if((fd = sh_open(name,O_RDONLY,0)) > 0) 893*8462SApril.Chin@Sun.COM { 894*8462SApril.Chin@Sun.COM if(fstat(fd,&statb) < 0) 895*8462SApril.Chin@Sun.COM return(0); 896*8462SApril.Chin@Sun.COM if(!S_ISREG(statb.st_mode)) 897*8462SApril.Chin@Sun.COM return(0); 898*8462SApril.Chin@Sun.COM *perm = statb.st_mode&(RW_ALL|(S_IXUSR|S_IXGRP|S_IXOTH)); 899*8462SApril.Chin@Sun.COM } 900*8462SApril.Chin@Sun.COM else if(fd < 0 && errno!=ENOENT) 901*8462SApril.Chin@Sun.COM return(0); 902*8462SApril.Chin@Sun.COM } 903*8462SApril.Chin@Sun.COM tname = sp = (char*)stakalloc((len=strlen(name)) + 5); 904*8462SApril.Chin@Sun.COM if(ep = strrchr(name,'/')) 905*8462SApril.Chin@Sun.COM { 906*8462SApril.Chin@Sun.COM memcpy(sp,name,n=++ep-name); 907*8462SApril.Chin@Sun.COM len -=n; 908*8462SApril.Chin@Sun.COM sp += n; 909*8462SApril.Chin@Sun.COM } 910*8462SApril.Chin@Sun.COM else 911*8462SApril.Chin@Sun.COM ep = name; 912*8462SApril.Chin@Sun.COM *sp++ = '.'; 913*8462SApril.Chin@Sun.COM memcpy(sp,ep,len); 914*8462SApril.Chin@Sun.COM strcpy(sp+len,".tmp"); 915*8462SApril.Chin@Sun.COM switch(mode) 916*8462SApril.Chin@Sun.COM { 917*8462SApril.Chin@Sun.COM case 1: 918*8462SApril.Chin@Sun.COM rename(tname,name); 919*8462SApril.Chin@Sun.COM break; 920*8462SApril.Chin@Sun.COM case 2: 921*8462SApril.Chin@Sun.COM unlink(tname); 922*8462SApril.Chin@Sun.COM break; 923*8462SApril.Chin@Sun.COM } 924*8462SApril.Chin@Sun.COM return(tname); 925*8462SApril.Chin@Sun.COM } 926*8462SApril.Chin@Sun.COM 9274887Schin /* 9284887Schin * I/O redirection 9294887Schin * flag = 0 if files are to be restored 9304887Schin * flag = 2 if files are to be closed on exec 9314887Schin * flag = 3 when called from $( < ...), just open file and return 9324887Schin * flag = SH_SHOWME for trace only 9334887Schin */ 934*8462SApril.Chin@Sun.COM int sh_redirect(Shell_t *shp,struct ionod *iop, int flag) 9354887Schin { 9364887Schin Sfoff_t off; 9374887Schin register char *fname; 9384887Schin register int fd, iof; 9394887Schin const char *message = e_open; 9404887Schin int o_mode; /* mode flag for open */ 9414887Schin static char io_op[7]; /* used for -x trace info */ 9424887Schin int clexec=0, fn, traceon; 943*8462SApril.Chin@Sun.COM int r, indx = shp->topfd, perm= -1; 944*8462SApril.Chin@Sun.COM char *tname=0, *after="", *trace = shp->st.trap[SH_DEBUGTRAP]; 9454887Schin Namval_t *np=0; 9464887Schin if(flag==2) 9474887Schin clexec = 1; 9484887Schin if(iop) 9494887Schin traceon = sh_trace(NIL(char**),0); 9504887Schin for(;iop;iop=iop->ionxt) 9514887Schin { 9524887Schin iof=iop->iofile; 9534887Schin fn = (iof&IOUFD); 954*8462SApril.Chin@Sun.COM if(fn==1 && shp->subshell && (flag==2 || (sfset(sfstdout,0,0)&SF_STRING))) 955*8462SApril.Chin@Sun.COM sh_subfork(); 9564887Schin io_op[0] = '0'+(iof&IOUFD); 9574887Schin if(iof&IOPUT) 9584887Schin { 9594887Schin io_op[1] = '>'; 9604887Schin o_mode = O_WRONLY|O_CREAT; 9614887Schin } 9624887Schin else 9634887Schin { 9644887Schin io_op[1] = '<'; 9654887Schin o_mode = O_RDONLY|O_NONBLOCK; 9664887Schin } 9674887Schin io_op[2] = 0; 9684887Schin io_op[3] = 0; 9694887Schin io_op[4] = 0; 9704887Schin fname = iop->ioname; 9714887Schin if(!(iof&IORAW)) 9724887Schin { 9734887Schin if(iof&IOLSEEK) 9744887Schin { 9754887Schin struct argnod *ap = (struct argnod*)stakalloc(ARGVAL+strlen(iop->ioname)); 9764887Schin memset(ap, 0, ARGVAL); 9774887Schin ap->argflag = ARG_MAC; 9784887Schin strcpy(ap->argval,iop->ioname); 979*8462SApril.Chin@Sun.COM fname=sh_macpat(shp,ap,(iof&IOARITH)?ARG_ARITH:ARG_EXP); 9804887Schin } 9814887Schin else 982*8462SApril.Chin@Sun.COM fname=sh_mactrim(shp,fname,(!sh_isoption(SH_NOGLOB)&&sh_isoption(SH_INTERACTIVE))?2:0); 9834887Schin } 9844887Schin errno=0; 985*8462SApril.Chin@Sun.COM np = 0; 9864887Schin if(iop->iovname) 9874887Schin { 988*8462SApril.Chin@Sun.COM np = nv_open(iop->iovname,shp->var_tree,NV_NOASSIGN|NV_VARNAME); 9894887Schin if(nv_isattr(np,NV_RDONLY)) 9904887Schin errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np)); 9914887Schin io_op[0] = '}'; 992*8462SApril.Chin@Sun.COM if((iof&IOLSEEK) || ((iof&IOMOV) && *fname=='-')) 9934887Schin fn = nv_getnum(np); 9944887Schin } 9954887Schin if(iof&IOLSEEK) 9964887Schin { 9974887Schin io_op[2] = '#'; 9984887Schin if(iof&IOARITH) 9994887Schin { 10004887Schin strcpy(&io_op[3]," (("); 10014887Schin after = "))"; 10024887Schin } 10034887Schin else if(iof&IOCOPY) 10044887Schin io_op[3] = '#'; 10054887Schin goto traceit; 10064887Schin } 10074887Schin if(*fname) 10084887Schin { 10094887Schin if(iof&IODOC) 10104887Schin { 10114887Schin if(traceon) 10124887Schin sfputr(sfstderr,io_op,'<'); 1013*8462SApril.Chin@Sun.COM fd = io_heredoc(shp,iop,fname,traceon); 10144887Schin if(traceon && (flag==SH_SHOWME)) 10154887Schin sh_close(fd); 10164887Schin fname = 0; 10174887Schin } 10184887Schin else if(iof&IOMOV) 10194887Schin { 10204887Schin int dupfd,toclose= -1; 10214887Schin io_op[2] = '&'; 10224887Schin if((fd=fname[0])>='0' && fd<='9') 10234887Schin { 10244887Schin char *number = fname; 10254887Schin dupfd = strtol(fname,&number,10); 10264887Schin if(*number=='-') 10274887Schin { 10284887Schin toclose = dupfd; 10294887Schin number++; 10304887Schin } 10314887Schin if(*number || dupfd > IOUFD) 10324887Schin { 10334887Schin message = e_file; 10344887Schin goto fail; 10354887Schin } 1036*8462SApril.Chin@Sun.COM if(shp->subshell && dupfd==1) 10374887Schin { 1038*8462SApril.Chin@Sun.COM sh_subtmpfile(0); 10394887Schin dupfd = sffileno(sfstdout); 10404887Schin } 1041*8462SApril.Chin@Sun.COM else if(shp->sftable[dupfd]) 1042*8462SApril.Chin@Sun.COM sfsync(shp->sftable[dupfd]); 10434887Schin } 10444887Schin else if(fd=='-' && fname[1]==0) 10454887Schin { 10464887Schin fd= -1; 10474887Schin goto traceit; 10484887Schin } 10494887Schin else if(fd=='p' && fname[1]==0) 10504887Schin { 10514887Schin if(iof&IOPUT) 1052*8462SApril.Chin@Sun.COM dupfd = shp->coutpipe; 10534887Schin else 1054*8462SApril.Chin@Sun.COM dupfd = shp->cpipe[0]; 10554887Schin if(flag) 10564887Schin toclose = dupfd; 10574887Schin } 10584887Schin else 10594887Schin { 10604887Schin message = e_file; 10614887Schin goto fail; 10624887Schin } 10634887Schin if(flag==SH_SHOWME) 10644887Schin goto traceit; 10654887Schin if((fd=sh_fcntl(dupfd,F_DUPFD,3))<0) 10664887Schin goto fail; 1067*8462SApril.Chin@Sun.COM sh_iocheckfd(shp,dupfd); 1068*8462SApril.Chin@Sun.COM shp->fdstatus[fd] = (shp->fdstatus[dupfd]&~IOCLEX); 1069*8462SApril.Chin@Sun.COM if(toclose<0 && shp->fdstatus[fd]&IOREAD) 1070*8462SApril.Chin@Sun.COM shp->fdstatus[fd] |= IODUP; 1071*8462SApril.Chin@Sun.COM else if(dupfd==shp->cpipe[0]) 1072*8462SApril.Chin@Sun.COM sh_pclose(shp->cpipe); 10734887Schin else if(toclose>=0) 10744887Schin { 10754887Schin if(flag==0) 1076*8462SApril.Chin@Sun.COM sh_iosave(shp,toclose,indx,(char*)0); /* save file descriptor */ 10774887Schin sh_close(toclose); 10784887Schin } 10794887Schin } 10804887Schin else if(iof&IORDW) 10814887Schin { 10824887Schin if(sh_isoption(SH_RESTRICTED)) 10834887Schin errormsg(SH_DICT,ERROR_exit(1),e_restricted,fname); 10844887Schin io_op[2] = '>'; 10854887Schin o_mode = O_RDWR|O_CREAT; 10864887Schin goto openit; 10874887Schin } 10884887Schin else if(!(iof&IOPUT)) 10894887Schin { 10904887Schin if(flag==SH_SHOWME) 10914887Schin goto traceit; 10924887Schin fd=sh_chkopen(fname); 10934887Schin } 10944887Schin else if(sh_isoption(SH_RESTRICTED)) 10954887Schin errormsg(SH_DICT,ERROR_exit(1),e_restricted,fname); 10964887Schin else 10974887Schin { 10984887Schin if(iof&IOAPP) 10994887Schin { 11004887Schin io_op[2] = '>'; 11014887Schin o_mode |= O_APPEND; 11024887Schin } 1103*8462SApril.Chin@Sun.COM else if((iof&IOREWRITE) && (flag==0 || flag==1 || sh_subsavefd(fn))) 1104*8462SApril.Chin@Sun.COM { 1105*8462SApril.Chin@Sun.COM io_op[2] = ';'; 1106*8462SApril.Chin@Sun.COM o_mode |= O_TRUNC; 1107*8462SApril.Chin@Sun.COM tname = io_usename(fname,&perm,0); 1108*8462SApril.Chin@Sun.COM } 11094887Schin else 11104887Schin { 11114887Schin o_mode |= O_TRUNC; 11124887Schin if(iof&IOCLOB) 11134887Schin io_op[2] = '|'; 11144887Schin else if(sh_isoption(SH_NOCLOBBER)) 11154887Schin { 11164887Schin struct stat sb; 11174887Schin if(stat(fname,&sb)>=0) 11184887Schin { 11194887Schin #if SHOPT_FS_3D 11204887Schin if(S_ISREG(sb.st_mode)&& 1121*8462SApril.Chin@Sun.COM (!shp->lim.fs3d || iview(&sb)==0)) 11224887Schin #else 11234887Schin if(S_ISREG(sb.st_mode)) 11244887Schin #endif /* SHOPT_FS_3D */ 11254887Schin { 11264887Schin errno = EEXIST; 11274887Schin errormsg(SH_DICT,ERROR_system(1),e_exists,fname); 11284887Schin } 11294887Schin } 11304887Schin else 11314887Schin o_mode |= O_EXCL; 11324887Schin } 11334887Schin } 11344887Schin openit: 11354887Schin if(flag!=SH_SHOWME) 11364887Schin { 1137*8462SApril.Chin@Sun.COM if((fd=sh_open(tname?tname:fname,o_mode,RW_ALL)) <0) 11384887Schin errormsg(SH_DICT,ERROR_system(1),((o_mode&O_CREAT)?e_create:e_open),fname); 1139*8462SApril.Chin@Sun.COM if(perm>0) 1140*8462SApril.Chin@Sun.COM #if _lib_fchmod 1141*8462SApril.Chin@Sun.COM fchmod(fd,perm); 1142*8462SApril.Chin@Sun.COM #else 1143*8462SApril.Chin@Sun.COM chmod(tname,perm); 1144*8462SApril.Chin@Sun.COM #endif 11454887Schin } 11464887Schin } 11474887Schin traceit: 11484887Schin if(traceon && fname) 11494887Schin { 11504887Schin if(np) 11514887Schin sfprintf(sfstderr,"{%s",nv_name(np)); 11524887Schin sfprintf(sfstderr,"%s %s%s%c",io_op,fname,after,iop->ionxt?' ':'\n'); 11534887Schin } 11544887Schin if(flag==SH_SHOWME) 11554887Schin return(indx); 11564887Schin if(trace && fname) 11574887Schin { 11584887Schin char *argv[7], **av=argv; 11594887Schin av[3] = io_op; 11604887Schin av[4] = fname; 11614887Schin av[5] = 0; 11624887Schin av[6] = 0; 11634887Schin if(iof&IOARITH) 11644887Schin av[5] = after; 11654887Schin if(np) 11664887Schin { 11674887Schin av[0] = "{"; 11684887Schin av[1] = nv_name(np); 11694887Schin av[2] = "}"; 11704887Schin } 11714887Schin else 11724887Schin av +=3; 1173*8462SApril.Chin@Sun.COM sh_debug(shp,trace,(char*)0,(char*)0,av,ARG_NOGLOB); 11744887Schin } 11754887Schin if(iof&IOLSEEK) 11764887Schin { 1177*8462SApril.Chin@Sun.COM Sfio_t *sp = shp->sftable[fn]; 1178*8462SApril.Chin@Sun.COM r = shp->fdstatus[fn]; 11794887Schin if(!(r&(IOSEEK|IONOSEEK))) 1180*8462SApril.Chin@Sun.COM r = sh_iocheckfd(shp,fn); 11814887Schin sfsprintf(io_op,sizeof(io_op),"%d\0",fn); 11824887Schin if(r==IOCLOSE) 11834887Schin { 11844887Schin fname = io_op; 11854887Schin message = e_file; 11864887Schin goto fail; 11874887Schin } 11884887Schin if(iof&IOARITH) 11894887Schin { 11904887Schin if(r&IONOSEEK) 11914887Schin { 11924887Schin fname = io_op; 11934887Schin message = e_notseek; 11944887Schin goto fail; 11954887Schin } 11964887Schin message = e_badseek; 1197*8462SApril.Chin@Sun.COM if((off = file_offset(shp,fn,fname))<0) 11984887Schin goto fail; 11994887Schin if(sp) 1200*8462SApril.Chin@Sun.COM off=sfseek(sp, off, SEEK_SET); 12014887Schin else 1202*8462SApril.Chin@Sun.COM off=lseek(fn, off, SEEK_SET); 1203*8462SApril.Chin@Sun.COM if(off<0) 1204*8462SApril.Chin@Sun.COM r = -1; 12054887Schin } 12064887Schin else 12074887Schin { 12084887Schin regex_t *rp; 12094887Schin extern const char e_notimp[]; 12104887Schin if(!(r&IOREAD)) 12114887Schin { 12124887Schin message = e_noread; 12134887Schin goto fail; 12144887Schin } 12154887Schin if(!(rp = regcache(fname, REG_SHELL|REG_NOSUB|REG_NEWLINE|REG_AUGMENTED|REG_FIRST|REG_LEFT|REG_RIGHT, &r))) 12164887Schin { 12174887Schin message = e_badpattern; 12184887Schin goto fail; 12194887Schin } 12204887Schin if(!sp) 1221*8462SApril.Chin@Sun.COM sp = sh_iostream(shp,fn); 1222*8462SApril.Chin@Sun.COM r=io_patseek(shp,rp,sp,iof); 12234887Schin if(sp && flag==3) 12244887Schin { 12254887Schin /* close stream but not fn */ 12264887Schin sfsetfd(sp,-1); 12274887Schin sfclose(sp); 12284887Schin } 12294887Schin } 12304887Schin if(r<0) 12314887Schin goto fail; 12324887Schin if(flag==3) 12334887Schin return(fn); 12344887Schin continue; 12354887Schin } 12364887Schin if(!np) 12374887Schin { 1238*8462SApril.Chin@Sun.COM if(flag==0 || tname) 12394887Schin { 12404887Schin if(fd==fn) 12414887Schin { 12424887Schin if((r=sh_fcntl(fd,F_DUPFD,10)) > 0) 12434887Schin { 12444887Schin fd = r; 12454887Schin sh_close(fn); 12464887Schin } 12474887Schin } 1248*8462SApril.Chin@Sun.COM sh_iosave(shp,fn,indx,tname?fname:0); 12494887Schin } 12504887Schin else if(sh_subsavefd(fn)) 1251*8462SApril.Chin@Sun.COM sh_iosave(shp,fn,indx|IOSUBSHELL,tname?fname:0); 12524887Schin } 12534887Schin if(fd<0) 12544887Schin { 1255*8462SApril.Chin@Sun.COM if(sh_inuse(fn) || fn==shp->infd) 12564887Schin { 1257*8462SApril.Chin@Sun.COM if(fn>9 || !(shp->inuse_bits&(1<<fn))) 1258*8462SApril.Chin@Sun.COM io_preserve(shp,shp->sftable[fn],fn); 12594887Schin } 12604887Schin sh_close(fn); 12614887Schin } 12624887Schin if(flag==3) 12634887Schin return(fd); 12644887Schin if(fd>=0) 12654887Schin { 12664887Schin if(np) 12674887Schin { 12684887Schin int32_t v; 12694887Schin fn = fd; 12704887Schin if(fd<10) 12714887Schin { 12724887Schin if((fn=fcntl(fd,F_DUPFD,10)) < 0) 12734887Schin goto fail; 1274*8462SApril.Chin@Sun.COM shp->fdstatus[fn] = shp->fdstatus[fd]; 12754887Schin sh_close(fd); 12764887Schin fd = fn; 12774887Schin } 12784887Schin nv_unset(np); 12794887Schin nv_onattr(np,NV_INT32); 12804887Schin v = fn; 12814887Schin nv_putval(np,(char*)&v, NV_INT32); 1282*8462SApril.Chin@Sun.COM sh_iocheckfd(shp,fd); 12834887Schin } 12844887Schin else 12854887Schin { 1286*8462SApril.Chin@Sun.COM fd = sh_iorenumber(shp,sh_iomovefd(fd),fn); 12874887Schin if(fn>2 && fn<10) 1288*8462SApril.Chin@Sun.COM shp->inuse_bits |= (1<<fn); 12894887Schin } 12904887Schin } 12914887Schin if(fd >2 && clexec) 12924887Schin { 12934887Schin fcntl(fd,F_SETFD,FD_CLOEXEC); 1294*8462SApril.Chin@Sun.COM shp->fdstatus[fd] |= IOCLEX; 12954887Schin } 12964887Schin } 12974887Schin else 12984887Schin goto fail; 12994887Schin } 13004887Schin return(indx); 13014887Schin fail: 13024887Schin errormsg(SH_DICT,ERROR_system(1),message,fname); 13034887Schin /* NOTREACHED */ 13044887Schin return(0); 13054887Schin } 13064887Schin /* 13074887Schin * Create a tmp file for the here-document 13084887Schin */ 1309*8462SApril.Chin@Sun.COM static int io_heredoc(Shell_t *shp,register struct ionod *iop, const char *name, int traceon) 13104887Schin { 13114887Schin register Sfio_t *infile = 0, *outfile; 13124887Schin register int fd; 1313*8462SApril.Chin@Sun.COM if(!(iop->iofile&IOSTRG) && (!shp->heredocs || iop->iosize==0)) 13144887Schin return(sh_open(e_devnull,O_RDONLY)); 13154887Schin /* create an unnamed temporary file */ 13164887Schin if(!(outfile=sftmp(0))) 13174887Schin errormsg(SH_DICT,ERROR_system(1),e_tmpcreate); 13184887Schin if(iop->iofile&IOSTRG) 13194887Schin { 13204887Schin if(traceon) 13214887Schin sfprintf(sfstderr,"< %s\n",name); 13224887Schin sfputr(outfile,name,'\n'); 13234887Schin } 13244887Schin else 13254887Schin { 1326*8462SApril.Chin@Sun.COM infile = subopen(shp,shp->heredocs,iop->iooffset,iop->iosize); 13274887Schin if(traceon) 13284887Schin { 13294887Schin char *cp = sh_fmtq(iop->iodelim); 13304887Schin fd = (*cp=='$' || *cp=='\'')?' ':'\\'; 13314887Schin sfprintf(sfstderr," %c%s\n",fd,cp); 13324887Schin sfdisc(outfile,&tee_disc); 13334887Schin } 13344887Schin if(iop->iofile&IOQUOTE) 13354887Schin { 13364887Schin /* This is a quoted here-document, not expansion */ 13374887Schin sfmove(infile,outfile,SF_UNBOUND,-1); 13384887Schin sfclose(infile); 13394887Schin } 13404887Schin else 13414887Schin { 1342*8462SApril.Chin@Sun.COM char *lastpath = shp->lastpath; 1343*8462SApril.Chin@Sun.COM sh_machere(shp,infile,outfile,iop->ioname); 1344*8462SApril.Chin@Sun.COM shp->lastpath = lastpath; 13454887Schin if(infile) 13464887Schin sfclose(infile); 13474887Schin } 13484887Schin } 13494887Schin /* close stream outfile, but save file descriptor */ 13504887Schin fd = sffileno(outfile); 13514887Schin sfsetfd(outfile,-1); 13524887Schin sfclose(outfile); 13534887Schin if(traceon && !(iop->iofile&IOSTRG)) 13544887Schin sfputr(sfstderr,iop->ioname,'\n'); 13554887Schin lseek(fd,(off_t)0,SEEK_SET); 1356*8462SApril.Chin@Sun.COM shp->fdstatus[fd] = IOREAD; 13574887Schin return(fd); 13584887Schin } 13594887Schin 13604887Schin /* 13614887Schin * This write discipline also writes the output on standard error 13624887Schin * This is used when tracing here-documents 13634887Schin */ 13644887Schin static ssize_t tee_write(Sfio_t *iop,const void *buff,size_t n,Sfdisc_t *unused) 13654887Schin { 13664887Schin NOT_USED(unused); 13674887Schin sfwrite(sfstderr,buff,n); 13684887Schin return(write(sffileno(iop),buff,n)); 13694887Schin } 13704887Schin 13714887Schin /* 13724887Schin * copy file <origfd> into a save place 13734887Schin * The saved file is set close-on-exec 13744887Schin * if <origfd> < 0, then -origfd is saved, but not duped so that it 13754887Schin * will be closed with sh_iorestore. 13764887Schin */ 1377*8462SApril.Chin@Sun.COM void sh_iosave(Shell_t *shp, register int origfd, int oldtop, char *name) 13784887Schin { 13794887Schin /*@ 1380*8462SApril.Chin@Sun.COM assume oldtop>=0 && oldtop<shp->lim.open_max; 13814887Schin @*/ 13824887Schin 13834887Schin register int savefd; 13844887Schin int flag = (oldtop&IOSUBSHELL); 13854887Schin oldtop &= ~IOSUBSHELL; 13864887Schin /* see if already saved, only save once */ 1387*8462SApril.Chin@Sun.COM for(savefd=shp->topfd; --savefd>=oldtop; ) 13884887Schin { 13894887Schin if(filemap[savefd].orig_fd == origfd) 13904887Schin return; 13914887Schin } 13924887Schin /* make sure table is large enough */ 1393*8462SApril.Chin@Sun.COM if(shp->topfd >= filemapsize) 13944887Schin { 1395*8462SApril.Chin@Sun.COM char *cp, *oldptr = (char*)filemap; 1396*8462SApril.Chin@Sun.COM char *oldend = (char*)&filemap[filemapsize]; 1397*8462SApril.Chin@Sun.COM long moved; 13984887Schin filemapsize += 8; 13994887Schin if(!(filemap = (struct fdsave*)realloc(filemap,filemapsize*sizeof(struct fdsave)))) 14004887Schin errormsg(SH_DICT,ERROR_exit(4),e_nospace); 1401*8462SApril.Chin@Sun.COM if(moved = (char*)filemap - oldptr) 1402*8462SApril.Chin@Sun.COM { 1403*8462SApril.Chin@Sun.COM #if SHOPT_FASTPIPE 1404*8462SApril.Chin@Sun.COM for(savefd=shp->lim.open_max+2; --savefd>=0; ) 1405*8462SApril.Chin@Sun.COM #else 1406*8462SApril.Chin@Sun.COM for(savefd=shp->lim.open_max; --savefd>=0; ) 1407*8462SApril.Chin@Sun.COM #endif /* SHOPT_FASTPIPE */ 1408*8462SApril.Chin@Sun.COM { 1409*8462SApril.Chin@Sun.COM cp = (char*)shp->fdptrs[savefd]; 1410*8462SApril.Chin@Sun.COM if(cp >= oldptr && cp < oldend) 1411*8462SApril.Chin@Sun.COM shp->fdptrs[savefd] = (int*)(oldptr+moved); 1412*8462SApril.Chin@Sun.COM } 1413*8462SApril.Chin@Sun.COM } 14144887Schin } 14154887Schin #if SHOPT_DEVFD 14164887Schin if(origfd <0) 14174887Schin { 14184887Schin savefd = origfd; 14194887Schin origfd = -origfd; 14204887Schin } 14214887Schin else 14224887Schin #endif /* SHOPT_DEVFD */ 14234887Schin { 14244887Schin if((savefd = sh_fcntl(origfd, F_DUPFD, 10)) < 0 && errno!=EBADF) 14254887Schin errormsg(SH_DICT,ERROR_system(1),e_toomany); 14264887Schin } 1427*8462SApril.Chin@Sun.COM filemap[shp->topfd].tname = name; 1428*8462SApril.Chin@Sun.COM filemap[shp->topfd].subshell = flag; 1429*8462SApril.Chin@Sun.COM filemap[shp->topfd].orig_fd = origfd; 1430*8462SApril.Chin@Sun.COM filemap[shp->topfd++].save_fd = savefd; 14314887Schin if(savefd >=0) 14324887Schin { 1433*8462SApril.Chin@Sun.COM register Sfio_t* sp = shp->sftable[origfd]; 14344887Schin /* make saved file close-on-exec */ 14354887Schin sh_fcntl(savefd,F_SETFD,FD_CLOEXEC); 14364887Schin if(origfd==job.fd) 14374887Schin job.fd = savefd; 1438*8462SApril.Chin@Sun.COM shp->fdstatus[savefd] = shp->fdstatus[origfd]; 1439*8462SApril.Chin@Sun.COM shp->fdptrs[savefd] = &filemap[shp->topfd-1].save_fd; 1440*8462SApril.Chin@Sun.COM if(!(shp->sftable[savefd]=sp)) 14414887Schin return; 14424887Schin sfsync(sp); 14434887Schin if(origfd <=2) 14444887Schin { 14454887Schin /* copy standard stream to new stream */ 14464887Schin sp = sfswap(sp,NIL(Sfio_t*)); 1447*8462SApril.Chin@Sun.COM shp->sftable[savefd] = sp; 14484887Schin } 14494887Schin else 1450*8462SApril.Chin@Sun.COM shp->sftable[origfd] = 0; 14514887Schin } 14524887Schin } 14534887Schin 14544887Schin /* 14554887Schin * close all saved file descriptors 14564887Schin */ 1457*8462SApril.Chin@Sun.COM void sh_iounsave(Shell_t* shp) 14584887Schin { 14594887Schin register int fd, savefd, newfd; 1460*8462SApril.Chin@Sun.COM for(newfd=fd=0; fd < shp->topfd; fd++) 14614887Schin { 14624887Schin if((savefd = filemap[fd].save_fd)< 0) 14634887Schin filemap[newfd++] = filemap[fd]; 14644887Schin else 14654887Schin { 1466*8462SApril.Chin@Sun.COM shp->sftable[savefd] = 0; 14674887Schin sh_close(savefd); 14684887Schin } 14694887Schin } 1470*8462SApril.Chin@Sun.COM shp->topfd = newfd; 14714887Schin } 14724887Schin 14734887Schin /* 14744887Schin * restore saved file descriptors from <last> on 14754887Schin */ 1476*8462SApril.Chin@Sun.COM void sh_iorestore(Shell_t *shp, int last, int jmpval) 14774887Schin { 14784887Schin register int origfd, savefd, fd; 14794887Schin int flag = (last&IOSUBSHELL); 14804887Schin last &= ~IOSUBSHELL; 1481*8462SApril.Chin@Sun.COM for (fd = shp->topfd - 1; fd >= last; fd--) 14824887Schin { 14834887Schin if(!flag && filemap[fd].subshell) 14844887Schin continue; 14854887Schin if(jmpval==SH_JMPSCRIPT) 14864887Schin { 14874887Schin if ((savefd = filemap[fd].save_fd) >= 0) 14884887Schin { 1489*8462SApril.Chin@Sun.COM shp->sftable[savefd] = 0; 14904887Schin sh_close(savefd); 14914887Schin } 14924887Schin continue; 14934887Schin } 14944887Schin origfd = filemap[fd].orig_fd; 1495*8462SApril.Chin@Sun.COM if(filemap[fd].tname) 1496*8462SApril.Chin@Sun.COM io_usename(filemap[fd].tname,(int*)0,shp->exitval?2:1); 14974887Schin sh_close(origfd); 14984887Schin if ((savefd = filemap[fd].save_fd) >= 0) 14994887Schin { 15004887Schin sh_fcntl(savefd, F_DUPFD, origfd); 15014887Schin if(savefd==job.fd) 15024887Schin job.fd=origfd; 1503*8462SApril.Chin@Sun.COM shp->fdstatus[origfd] = shp->fdstatus[savefd]; 15044887Schin /* turn off close-on-exec if flag if necessary */ 1505*8462SApril.Chin@Sun.COM if(shp->fdstatus[origfd]&IOCLEX) 15064887Schin fcntl(origfd,F_SETFD,FD_CLOEXEC); 15074887Schin if(origfd<=2) 15084887Schin { 1509*8462SApril.Chin@Sun.COM sfswap(shp->sftable[savefd],shp->sftable[origfd]); 15104887Schin if(origfd==0) 1511*8462SApril.Chin@Sun.COM shp->st.ioset = 0; 15124887Schin } 15134887Schin else 1514*8462SApril.Chin@Sun.COM shp->sftable[origfd] = shp->sftable[savefd]; 1515*8462SApril.Chin@Sun.COM shp->sftable[savefd] = 0; 15164887Schin sh_close(savefd); 15174887Schin } 15184887Schin else 1519*8462SApril.Chin@Sun.COM shp->fdstatus[origfd] = IOCLOSE; 15204887Schin } 15214887Schin if(!flag) 15224887Schin { 15234887Schin /* keep file descriptors for subshell restore */ 1524*8462SApril.Chin@Sun.COM for (fd = last ; fd < shp->topfd; fd++) 15254887Schin { 15264887Schin if(filemap[fd].subshell) 15274887Schin filemap[last++] = filemap[fd]; 15284887Schin } 15294887Schin } 1530*8462SApril.Chin@Sun.COM if(last < shp->topfd) 1531*8462SApril.Chin@Sun.COM shp->topfd = last; 15324887Schin } 15334887Schin 15344887Schin /* 15354887Schin * returns access information on open file <fd> 15364887Schin * returns -1 for failure, 0 for success 15374887Schin * <mode> is the same as for access() 15384887Schin */ 15394887Schin int sh_ioaccess(int fd,register int mode) 15404887Schin { 1541*8462SApril.Chin@Sun.COM Shell_t *shp = &sh; 15424887Schin register int flags; 15434887Schin if(mode==X_OK) 15444887Schin return(-1); 1545*8462SApril.Chin@Sun.COM if((flags=sh_iocheckfd(shp,fd))!=IOCLOSE) 15464887Schin { 15474887Schin if(mode==F_OK) 15484887Schin return(0); 15494887Schin if(mode==R_OK && (flags&IOREAD)) 15504887Schin return(0); 15514887Schin if(mode==W_OK && (flags&IOWRITE)) 15524887Schin return(0); 15534887Schin } 15544887Schin return(-1); 15554887Schin } 15564887Schin 15574887Schin /* 15584887Schin * Handle interrupts for slow streams 15594887Schin */ 15604887Schin static int slowexcept(register Sfio_t *iop,int type,void *data,Sfdisc_t *handle) 15614887Schin { 15624887Schin register int n,fno; 15634887Schin NOT_USED(handle); 15644887Schin if(type==SF_DPOP || type==SF_FINAL) 15654887Schin free((void*)handle); 15664887Schin if(type!=SF_READ) 15674887Schin return(0); 15684887Schin if((sh.trapnote&(SH_SIGSET|SH_SIGTRAP)) && errno!=EIO && errno!=ENXIO) 15694887Schin errno = EINTR; 15704887Schin fno = sffileno(iop); 15714887Schin if((n=sfvalue(iop))<=0) 15724887Schin { 15734887Schin #ifndef FNDELAY 15744887Schin # ifdef O_NDELAY 15754887Schin if(errno==0 && (n=fcntl(fno,F_GETFL,0))&O_NDELAY) 15764887Schin { 15774887Schin n &= ~O_NDELAY; 15784887Schin fcntl(fno, F_SETFL, n); 15794887Schin return(1); 15804887Schin } 15814887Schin # endif /* O_NDELAY */ 15824887Schin #endif /* !FNDELAY */ 15834887Schin #ifdef O_NONBLOCK 15844887Schin if(errno==EAGAIN) 15854887Schin { 15864887Schin n = fcntl(fno,F_GETFL,0); 15874887Schin n &= ~O_NONBLOCK; 15884887Schin fcntl(fno, F_SETFL, n); 15894887Schin return(1); 15904887Schin } 15914887Schin #endif /* O_NONBLOCK */ 15924887Schin if(errno!=EINTR) 15934887Schin return(0); 15944887Schin n=1; 1595*8462SApril.Chin@Sun.COM sh_onstate(SH_TTYWAIT); 15964887Schin } 1597*8462SApril.Chin@Sun.COM else 1598*8462SApril.Chin@Sun.COM n = 0; 1599*8462SApril.Chin@Sun.COM if(sh.bltinfun && sh.bltindata.sigset) 1600*8462SApril.Chin@Sun.COM return(-1); 16014887Schin errno = 0; 16024887Schin if(sh.trapnote&SH_SIGSET) 16034887Schin { 16044887Schin if(isatty(fno)) 16054887Schin sfputc(sfstderr,'\n'); 16064887Schin sh_exit(SH_EXITSIG); 16074887Schin } 16084887Schin if(sh.trapnote&SH_SIGTRAP) 16094887Schin sh_chktrap(); 16104887Schin return(n); 16114887Schin } 16124887Schin 16134887Schin /* 16144887Schin * called when slowread times out 16154887Schin */ 16164887Schin static void time_grace(void *handle) 16174887Schin { 16184887Schin NOT_USED(handle); 16194887Schin timeout = 0; 16204887Schin if(sh_isstate(SH_GRACE)) 16214887Schin { 16224887Schin sh_offstate(SH_GRACE); 16234887Schin if(!sh_isstate(SH_INTERACTIVE)) 16244887Schin return; 16254887Schin ((struct checkpt*)sh.jmplist)->mode = SH_JMPEXIT; 16264887Schin errormsg(SH_DICT,2,e_timeout); 16274887Schin sh.trapnote |= SH_SIGSET; 16284887Schin return; 16294887Schin } 16304887Schin errormsg(SH_DICT,0,e_timewarn); 16314887Schin sh_onstate(SH_GRACE); 16324887Schin sigrelease(SIGALRM); 16334887Schin sh.trapnote |= SH_SIGTRAP; 16344887Schin } 16354887Schin 16364887Schin static ssize_t piperead(Sfio_t *iop,void *buff,register size_t size,Sfdisc_t *handle) 16374887Schin { 16384887Schin int fd = sffileno(iop); 16394887Schin NOT_USED(handle); 1640*8462SApril.Chin@Sun.COM if(job.waitsafe && job.savesig) 1641*8462SApril.Chin@Sun.COM job_reap(job.savesig); 16424887Schin if(sh.trapnote) 16434887Schin { 16444887Schin errno = EINTR; 16454887Schin return(-1); 16464887Schin } 16474887Schin if(sh_isstate(SH_INTERACTIVE) && io_prompt(iop,sh.nextprompt)<0 && errno==EIO) 16484887Schin return(0); 1649*8462SApril.Chin@Sun.COM sh_onstate(SH_TTYWAIT); 16504887Schin if(!(sh.fdstatus[sffileno(iop)]&IOCLEX) && (sfset(iop,0,0)&SF_SHARE)) 16514887Schin size = ed_read(sh.ed_context, fd, (char*)buff, size,0); 16524887Schin else 16534887Schin size = sfrd(iop,buff,size,handle); 1654*8462SApril.Chin@Sun.COM sh_offstate(SH_TTYWAIT); 16554887Schin return(size); 16564887Schin } 16574887Schin /* 16584887Schin * This is the read discipline that is applied to slow devices 16594887Schin * This routine takes care of prompting for input 16604887Schin */ 16614887Schin static ssize_t slowread(Sfio_t *iop,void *buff,register size_t size,Sfdisc_t *handle) 16624887Schin { 16634887Schin int (*readf)(void*, int, char*, int, int); 16644887Schin int reedit=0, rsize; 16654887Schin #if SHOPT_HISTEXPAND 16664887Schin char *xp=0; 16674887Schin #endif 16684887Schin NOT_USED(handle); 16694887Schin # if SHOPT_ESH 16704887Schin if(sh_isoption(SH_EMACS) || sh_isoption(SH_GMACS)) 16714887Schin readf = ed_emacsread; 16724887Schin else 16734887Schin # endif /* SHOPT_ESH */ 16744887Schin # if SHOPT_VSH 16754887Schin # if SHOPT_RAWONLY 16764887Schin if(sh_isoption(SH_VI) || ((SHOPT_RAWONLY-0) && mbwide())) 16774887Schin # else 16784887Schin if(sh_isoption(SH_VI)) 16794887Schin # endif 16804887Schin readf = ed_viread; 16814887Schin else 16824887Schin # endif /* SHOPT_VSH */ 16834887Schin readf = ed_read; 16844887Schin if(sh.trapnote) 16854887Schin { 16864887Schin errno = EINTR; 16874887Schin return(-1); 16884887Schin } 16894887Schin while(1) 16904887Schin { 16914887Schin if(io_prompt(iop,sh.nextprompt)<0 && errno==EIO) 16924887Schin return(0); 16934887Schin if(sh.timeout) 16944887Schin timeout = (void*)sh_timeradd(sh_isstate(SH_GRACE)?1000L*TGRACE:1000L*sh.timeout,0,time_grace,NIL(void*)); 16954887Schin rsize = (*readf)(sh.ed_context, sffileno(iop), (char*)buff, size, reedit); 16964887Schin if(timeout) 16974887Schin timerdel(timeout); 16984887Schin timeout=0; 16994887Schin #if SHOPT_HISTEXPAND 17004887Schin if(rsize && *(char*)buff != '\n' && sh.nextprompt==1 && sh_isoption(SH_HISTEXPAND)) 17014887Schin { 17024887Schin int r; 17034887Schin ((char*)buff)[rsize] = '\0'; 17044887Schin if(xp) 17054887Schin { 17064887Schin free(xp); 17074887Schin xp = 0; 17084887Schin } 17094887Schin r = hist_expand(buff, &xp); 17104887Schin if((r & (HIST_EVENT|HIST_PRINT)) && !(r & HIST_ERROR) && xp) 17114887Schin { 17124887Schin strlcpy(buff, xp, size); 17134887Schin rsize = strlen(buff); 17144887Schin if(!sh_isoption(SH_HISTVERIFY) || readf==ed_read) 17154887Schin { 17164887Schin sfputr(sfstderr, xp, -1); 17174887Schin break; 17184887Schin } 17194887Schin reedit = rsize - 1; 17204887Schin continue; 17214887Schin } 17224887Schin if((r & HIST_ERROR) && sh_isoption(SH_HISTREEDIT)) 17234887Schin { 17244887Schin reedit = rsize - 1; 17254887Schin continue; 17264887Schin } 17274887Schin if(r & (HIST_ERROR|HIST_PRINT)) 17284887Schin { 17294887Schin *(char*)buff = '\n'; 17304887Schin rsize = 1; 17314887Schin } 17324887Schin } 17334887Schin #endif 17344887Schin break; 17354887Schin } 17364887Schin return(rsize); 17374887Schin } 17384887Schin 17394887Schin /* 17404887Schin * check and return the attributes for a file descriptor 17414887Schin */ 17424887Schin 1743*8462SApril.Chin@Sun.COM int sh_iocheckfd(Shell_t *shp, register int fd) 17444887Schin { 17454887Schin register int flags, n; 17464887Schin if((n=sh.fdstatus[fd])&IOCLOSE) 17474887Schin return(n); 17484887Schin if(!(n&(IOREAD|IOWRITE))) 17494887Schin { 17504887Schin #ifdef F_GETFL 17514887Schin if((flags=fcntl(fd,F_GETFL,0)) < 0) 17524887Schin return(sh.fdstatus[fd]=IOCLOSE); 17534887Schin if((flags&O_ACCMODE)!=O_WRONLY) 17544887Schin n |= IOREAD; 17554887Schin if((flags&O_ACCMODE)!=O_RDONLY) 17564887Schin n |= IOWRITE; 17574887Schin #else 17584887Schin struct stat statb; 17594887Schin if((flags = fstat(fd,&statb))< 0) 17604887Schin return(sh.fdstatus[fd]=IOCLOSE); 17614887Schin n |= (IOREAD|IOWRITE); 17624887Schin if(read(fd,"",0) < 0) 17634887Schin n &= ~IOREAD; 17644887Schin #endif /* F_GETFL */ 17654887Schin } 17664887Schin if(!(n&(IOSEEK|IONOSEEK))) 17674887Schin { 17684887Schin struct stat statb; 17694887Schin /* /dev/null check is a workaround for select bug */ 17704887Schin static ino_t null_ino; 17714887Schin static dev_t null_dev; 17724887Schin if(null_ino==0 && stat(e_devnull,&statb) >=0) 17734887Schin { 17744887Schin null_ino = statb.st_ino; 17754887Schin null_dev = statb.st_dev; 17764887Schin } 17774887Schin if(tty_check(fd)) 17784887Schin n |= IOTTY; 17794887Schin if(lseek(fd,NIL(off_t),SEEK_CUR)<0) 17804887Schin { 17814887Schin n |= IONOSEEK; 17824887Schin #ifdef S_ISSOCK 17834887Schin if((fstat(fd,&statb)>=0) && S_ISSOCK(statb.st_mode)) 17844887Schin n |= IOREAD|IOWRITE; 17854887Schin #endif /* S_ISSOCK */ 17864887Schin } 17874887Schin else if((fstat(fd,&statb)>=0) && ( 17884887Schin S_ISFIFO(statb.st_mode) || 17894887Schin #ifdef S_ISSOCK 17904887Schin S_ISSOCK(statb.st_mode) || 17914887Schin #endif /* S_ISSOCK */ 17924887Schin /* The following is for sockets on the sgi */ 17934887Schin (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) || 17944887Schin (S_ISCHR(statb.st_mode) && (statb.st_ino!=null_ino || statb.st_dev!=null_dev)) 17954887Schin )) 17964887Schin n |= IONOSEEK; 17974887Schin else 17984887Schin n |= IOSEEK; 17994887Schin } 18004887Schin sh.fdstatus[fd] = n; 18014887Schin return(n); 18024887Schin } 18034887Schin 18044887Schin /* 18054887Schin * Display prompt PS<flag> on standard error 18064887Schin */ 18074887Schin 18084887Schin static int io_prompt(Sfio_t *iop,register int flag) 18094887Schin { 1810*8462SApril.Chin@Sun.COM Shell_t *shp = &sh; 18114887Schin register char *cp; 18124887Schin char buff[1]; 18134887Schin char *endprompt; 18144887Schin static short cmdno; 18154887Schin int sfflags; 18164887Schin if(flag<3 && !sh_isstate(SH_INTERACTIVE)) 18174887Schin flag = 0; 18184887Schin if(flag==2 && sfpkrd(sffileno(iop),buff,1,'\n',0,1) >= 0) 18194887Schin flag = 0; 18204887Schin if(flag==0) 18214887Schin return(sfsync(sfstderr)); 18224887Schin sfflags = sfset(sfstderr,SF_SHARE|SF_PUBLIC|SF_READ,0); 18234887Schin if(!(sh.prompt=(char*)sfreserve(sfstderr,0,0))) 18244887Schin sh.prompt = ""; 18254887Schin switch(flag) 18264887Schin { 18274887Schin case 1: 18284887Schin { 18294887Schin register int c; 18304887Schin #if defined(TIOCLBIC) && defined(LFLUSHO) 18314887Schin if(!sh_isoption(SH_VI) && !sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS)) 18324887Schin { 18334887Schin /* 18344887Schin * re-enable output in case the user has 18354887Schin * disabled it. Not needed with edit mode 18364887Schin */ 18374887Schin int mode = LFLUSHO; 18384887Schin ioctl(sffileno(sfstderr),TIOCLBIC,&mode); 18394887Schin } 18404887Schin #endif /* TIOCLBIC */ 1841*8462SApril.Chin@Sun.COM cp = sh_mactry(shp,nv_getval(sh_scoped(shp,PS1NOD))); 18424887Schin for(;c= *cp;cp++) 18434887Schin { 18444887Schin if(c==HIST_CHAR) 18454887Schin { 18464887Schin /* look at next character */ 18474887Schin c = *++cp; 18484887Schin /* print out line number if not !! */ 18494887Schin if(c!= HIST_CHAR) 18504887Schin { 18514887Schin sfprintf(sfstderr,"%d", sh.hist_ptr?(int)sh.hist_ptr->histind:++cmdno); 18524887Schin } 18534887Schin if(c==0) 18544887Schin goto done; 18554887Schin } 18564887Schin sfputc(sfstderr,c); 18574887Schin } 18584887Schin goto done; 18594887Schin } 18604887Schin case 2: 1861*8462SApril.Chin@Sun.COM cp = nv_getval(sh_scoped(shp,PS2NOD)); 18624887Schin break; 18634887Schin case 3: 1864*8462SApril.Chin@Sun.COM cp = nv_getval(sh_scoped(shp,PS3NOD)); 18654887Schin break; 18664887Schin default: 18674887Schin goto done; 18684887Schin } 18694887Schin if(cp) 18704887Schin sfputr(sfstderr,cp,-1); 18714887Schin done: 18724887Schin if(*sh.prompt && (endprompt=(char*)sfreserve(sfstderr,0,0))) 18734887Schin *endprompt = 0; 18744887Schin sfset(sfstderr,sfflags&SF_READ|SF_SHARE|SF_PUBLIC,1); 18754887Schin return(sfsync(sfstderr)); 18764887Schin } 18774887Schin 18784887Schin /* 18794887Schin * This discipline is inserted on write pipes to prevent SIGPIPE 18804887Schin * from causing an infinite loop 18814887Schin */ 18824887Schin static int pipeexcept(Sfio_t* iop, int mode, void *data, Sfdisc_t* handle) 18834887Schin { 18844887Schin NOT_USED(iop); 18854887Schin if(mode==SF_DPOP || mode==SF_FINAL) 18864887Schin free((void*)handle); 18874887Schin else if(mode==SF_WRITE && errno==EINTR && sh.lastsig==SIGPIPE) 18884887Schin return(-1); 18894887Schin return(0); 18904887Schin } 18914887Schin 18924887Schin /* 18934887Schin * keep track of each stream that is opened and closed 18944887Schin */ 1895*8462SApril.Chin@Sun.COM static void sftrack(Sfio_t* sp, int flag, void* data) 18964887Schin { 1897*8462SApril.Chin@Sun.COM Shell_t *shp = &sh; 18984887Schin register int fd = sffileno(sp); 18994887Schin register struct checkpt *pp; 19004887Schin register int mode; 1901*8462SApril.Chin@Sun.COM int newfd = integralof(data); 19024887Schin if(flag==SF_SETFD || flag==SF_CLOSING) 19034887Schin { 19044887Schin if(newfd<0) 19054887Schin flag = SF_CLOSING; 19064887Schin if(fdnotify) 19074887Schin (*fdnotify)(sffileno(sp),flag==SF_CLOSING?-1:newfd); 19084887Schin } 19094887Schin #ifdef DEBUG 19104887Schin if(flag==SF_READ || flag==SF_WRITE) 19114887Schin { 19124887Schin char *z = fmtbase((long)getpid(),0,0); 19134887Schin write(ERRIO,z,strlen(z)); 19144887Schin write(ERRIO,": ",2); 19154887Schin write(ERRIO,"attempt to ",11); 19164887Schin if(flag==SF_READ) 19174887Schin write(ERRIO,"read from",9); 19184887Schin else 19194887Schin write(ERRIO,"write to",8); 19204887Schin write(ERRIO," locked stream\n",15); 19214887Schin return; 19224887Schin } 19234887Schin #endif 1924*8462SApril.Chin@Sun.COM if((unsigned)fd >= shp->lim.open_max) 19254887Schin return; 19264887Schin if(sh_isstate(SH_NOTRACK)) 19274887Schin return; 19284887Schin mode = sfset(sp,0,0); 1929*8462SApril.Chin@Sun.COM if(sp==shp->heredocs && fd < 10 && flag==SF_NEW) 19304887Schin { 19314887Schin fd = sfsetfd(sp,10); 19324887Schin fcntl(fd,F_SETFD,FD_CLOEXEC); 19334887Schin } 19344887Schin if(fd < 3) 19354887Schin return; 19364887Schin if(flag==SF_NEW) 19374887Schin { 1938*8462SApril.Chin@Sun.COM if(!shp->sftable[fd] && shp->fdstatus[fd]==IOCLOSE) 19394887Schin { 1940*8462SApril.Chin@Sun.COM shp->sftable[fd] = sp; 19414887Schin flag = (mode&SF_WRITE)?IOWRITE:0; 19424887Schin if(mode&SF_READ) 19434887Schin flag |= IOREAD; 1944*8462SApril.Chin@Sun.COM shp->fdstatus[fd] = flag; 19454887Schin #if 0 19464887Schin if(flag==IOWRITE) 1947*8462SApril.Chin@Sun.COM sfpool(sp,shp->outpool,SF_WRITE); 19484887Schin else 19494887Schin #else 19504887Schin if(flag!=IOWRITE) 19514887Schin #endif 1952*8462SApril.Chin@Sun.COM sh_iostream(shp,fd); 19534887Schin } 1954*8462SApril.Chin@Sun.COM if((pp=(struct checkpt*)shp->jmplist) && pp->mode==SH_JMPCMD) 19554887Schin { 19564887Schin struct openlist *item; 19574887Schin /* 19584887Schin * record open file descriptors so they can 19594887Schin * be closed in case a longjmp prevents 19604887Schin * built-ins from cleanup 19614887Schin */ 19624887Schin item = new_of(struct openlist, 0); 19634887Schin item->strm = sp; 19644887Schin item->next = pp->olist; 19654887Schin pp->olist = item; 19664887Schin } 19674887Schin if(fdnotify) 19684887Schin (*fdnotify)(-1,sffileno(sp)); 19694887Schin } 19704887Schin else if(flag==SF_CLOSING || (flag==SF_SETFD && newfd<=2)) 19714887Schin { 1972*8462SApril.Chin@Sun.COM shp->sftable[fd] = 0; 1973*8462SApril.Chin@Sun.COM shp->fdstatus[fd]=IOCLOSE; 1974*8462SApril.Chin@Sun.COM if(pp=(struct checkpt*)shp->jmplist) 19754887Schin { 19764887Schin struct openlist *item; 19774887Schin for(item=pp->olist; item; item=item->next) 19784887Schin { 19794887Schin if(item->strm == sp) 19804887Schin { 19814887Schin item->strm = 0; 19824887Schin break; 19834887Schin } 19844887Schin } 19854887Schin } 19864887Schin } 19874887Schin } 19884887Schin 19894887Schin struct eval 19904887Schin { 19914887Schin Sfdisc_t disc; 19924887Schin char **argv; 19934887Schin short slen; 19944887Schin char addspace; 19954887Schin }; 19964887Schin 19974887Schin /* 19984887Schin * Create a stream consisting of a space separated argv[] list 19994887Schin */ 20004887Schin 20014887Schin Sfio_t *sh_sfeval(register char *argv[]) 20024887Schin { 20034887Schin register Sfio_t *iop; 20044887Schin register char *cp; 20054887Schin if(argv[1]) 20064887Schin cp = ""; 20074887Schin else 20084887Schin cp = argv[0]; 20094887Schin iop = sfopen(NIL(Sfio_t*),(char*)cp,"s"); 20104887Schin if(argv[1]) 20114887Schin { 20124887Schin register struct eval *ep; 20134887Schin if(!(ep = new_of(struct eval,0))) 20144887Schin return(NIL(Sfio_t*)); 20154887Schin ep->disc = eval_disc; 20164887Schin ep->argv = argv; 20174887Schin ep->slen = -1; 20184887Schin ep->addspace = 0; 20194887Schin sfdisc(iop,&ep->disc); 20204887Schin } 20214887Schin return(iop); 20224887Schin } 20234887Schin 20244887Schin /* 20254887Schin * This code gets called whenever an end of string is found with eval 20264887Schin */ 20274887Schin 20284887Schin static int eval_exceptf(Sfio_t *iop,int type, void *data, Sfdisc_t *handle) 20294887Schin { 20304887Schin register struct eval *ep = (struct eval*)handle; 20314887Schin register char *cp; 20324887Schin register int len; 20334887Schin 20344887Schin /* no more to do */ 20354887Schin if(type!=SF_READ || !(cp = ep->argv[0])) 20364887Schin { 20374887Schin if(type==SF_CLOSING) 20384887Schin sfdisc(iop,SF_POPDISC); 20394887Schin else if(ep && (type==SF_DPOP || type==SF_FINAL)) 20404887Schin free((void*)ep); 20414887Schin return(0); 20424887Schin } 20434887Schin 20444887Schin if(!ep->addspace) 20454887Schin { 20464887Schin /* get the length of this string */ 20474887Schin ep->slen = len = strlen(cp); 20484887Schin /* move to next string */ 20494887Schin ep->argv++; 20504887Schin } 20514887Schin else /* insert space between arguments */ 20524887Schin { 20534887Schin len = 1; 20544887Schin cp = " "; 20554887Schin } 20564887Schin /* insert the new string */ 20574887Schin sfsetbuf(iop,cp,len); 20584887Schin ep->addspace = !ep->addspace; 20594887Schin return(1); 20604887Schin } 20614887Schin 20624887Schin /* 20634887Schin * This routine returns a stream pointer to a segment of length <size> from 20644887Schin * the stream <sp> starting at offset <offset> 20654887Schin * The stream can be read with the normal stream operations 20664887Schin */ 20674887Schin 2068*8462SApril.Chin@Sun.COM static Sfio_t *subopen(Shell_t *shp,Sfio_t* sp, off_t offset, long size) 20694887Schin { 20704887Schin register struct subfile *disp; 20714887Schin if(sfseek(sp,offset,SEEK_SET) <0) 20724887Schin return(NIL(Sfio_t*)); 20734887Schin if(!(disp = (struct subfile*)malloc(sizeof(struct subfile)+IOBSIZE+1))) 20744887Schin return(NIL(Sfio_t*)); 20754887Schin disp->disc = sub_disc; 20764887Schin disp->oldsp = sp; 20774887Schin disp->offset = offset; 20784887Schin disp->size = disp->left = size; 2079*8462SApril.Chin@Sun.COM sp = sfnew(NIL(Sfio_t*),(char*)(disp+1),IOBSIZE,shp->lim.open_max,SF_READ); 20804887Schin sfdisc(sp,&disp->disc); 20814887Schin return(sp); 20824887Schin } 20834887Schin 20844887Schin /* 20854887Schin * read function for subfile discipline 20864887Schin */ 20874887Schin static ssize_t subread(Sfio_t* sp,void* buff,register size_t size,Sfdisc_t* handle) 20884887Schin { 20894887Schin register struct subfile *disp = (struct subfile*)handle; 20904887Schin NOT_USED(sp); 20914887Schin if(disp->left == 0) 20924887Schin return(0); 20934887Schin if(size > disp->left) 20944887Schin size = disp->left; 20954887Schin disp->left -= size; 20964887Schin return(sfread(disp->oldsp,buff,size)); 20974887Schin } 20984887Schin 20994887Schin /* 21004887Schin * exception handler for subfile discipline 21014887Schin */ 21024887Schin static int subexcept(Sfio_t* sp,register int mode, void *data, Sfdisc_t* handle) 21034887Schin { 21044887Schin register struct subfile *disp = (struct subfile*)handle; 21054887Schin if(mode==SF_CLOSING) 21064887Schin { 21074887Schin sfdisc(sp,SF_POPDISC); 21084887Schin return(0); 21094887Schin } 21104887Schin else if(disp && (mode==SF_DPOP || mode==SF_FINAL)) 21114887Schin { 21124887Schin free((void*)disp); 21134887Schin return(0); 21144887Schin } 21154887Schin #ifdef SF_ATEXIT 21164887Schin else if (mode==SF_ATEXIT) 21174887Schin { 21184887Schin sfdisc(sp, SF_POPDISC); 21194887Schin return(0); 21204887Schin } 21214887Schin #endif 21224887Schin else if(mode==SF_READ) 21234887Schin return(0); 21244887Schin return(-1); 21254887Schin } 21264887Schin 21274887Schin #define NROW 15 /* number of rows before going to multi-columns */ 21284887Schin #define LBLSIZ 3 /* size of label field and interfield spacing */ 21294887Schin /* 21304887Schin * print a list of arguments in columns 21314887Schin */ 21324887Schin void sh_menu(Sfio_t *outfile,int argn,char *argv[]) 21334887Schin { 2134*8462SApril.Chin@Sun.COM Shell_t *shp = &sh; 21354887Schin register int i,j; 21364887Schin register char **arg; 21374887Schin int nrow, ncol=1, ndigits=1; 21384887Schin int fldsize, wsize = ed_window(); 2139*8462SApril.Chin@Sun.COM char *cp = nv_getval(sh_scoped(shp,LINES)); 21404887Schin nrow = (cp?1+2*((int)strtol(cp, (char**)0, 10)/3):NROW); 21414887Schin for(i=argn;i >= 10;i /= 10) 21424887Schin ndigits++; 21434887Schin if(argn < nrow) 21444887Schin { 21454887Schin nrow = argn; 21464887Schin goto skip; 21474887Schin } 21484887Schin i = 0; 21494887Schin for(arg=argv; *arg;arg++) 21504887Schin { 21514887Schin if((j=strlen(*arg)) > i) 21524887Schin i = j; 21534887Schin } 21544887Schin i += (ndigits+LBLSIZ); 21554887Schin if(i < wsize) 21564887Schin ncol = wsize/i; 21574887Schin if(argn > nrow*ncol) 21584887Schin { 21594887Schin nrow = 1 + (argn-1)/ncol; 21604887Schin } 21614887Schin else 21624887Schin { 21634887Schin ncol = 1 + (argn-1)/nrow; 21644887Schin nrow = 1 + (argn-1)/ncol; 21654887Schin } 21664887Schin skip: 21674887Schin fldsize = (wsize/ncol)-(ndigits+LBLSIZ); 21684887Schin for(i=0;i<nrow;i++) 21694887Schin { 21704887Schin if(sh.trapnote&SH_SIGSET) 21714887Schin return; 21724887Schin j = i; 21734887Schin while(1) 21744887Schin { 21754887Schin arg = argv+j; 21764887Schin sfprintf(outfile,"%*d) %s",ndigits,j+1,*arg); 21774887Schin j += nrow; 21784887Schin if(j >= argn) 21794887Schin break; 21804887Schin sfnputc(outfile,' ',fldsize-strlen(*arg)); 21814887Schin } 21824887Schin sfputc(outfile,'\n'); 21834887Schin } 21844887Schin } 21854887Schin 21864887Schin #undef read 21874887Schin /* 21884887Schin * shell version of read() for user added builtins 21894887Schin */ 21904887Schin ssize_t sh_read(register int fd, void* buff, size_t n) 21914887Schin { 21924887Schin register Sfio_t *sp; 21934887Schin if(sp=sh.sftable[fd]) 21944887Schin return(sfread(sp,buff,n)); 21954887Schin else 21964887Schin return(read(fd,buff,n)); 21974887Schin } 21984887Schin 21994887Schin #undef write 22004887Schin /* 22014887Schin * shell version of write() for user added builtins 22024887Schin */ 22034887Schin ssize_t sh_write(register int fd, const void* buff, size_t n) 22044887Schin { 22054887Schin register Sfio_t *sp; 22064887Schin if(sp=sh.sftable[fd]) 22074887Schin return(sfwrite(sp,buff,n)); 22084887Schin else 22094887Schin return(write(fd,buff,n)); 22104887Schin } 22114887Schin 22124887Schin #undef lseek 22134887Schin /* 22144887Schin * shell version of lseek() for user added builtins 22154887Schin */ 22164887Schin off_t sh_seek(register int fd, off_t offset, int whence) 22174887Schin { 22184887Schin register Sfio_t *sp; 22194887Schin if((sp=sh.sftable[fd]) && (sfset(sp,0,0)&(SF_READ|SF_WRITE))) 22204887Schin return(sfseek(sp,offset,whence)); 22214887Schin else 22224887Schin return(lseek(fd,offset,whence)); 22234887Schin } 22244887Schin 22254887Schin #undef dup 22264887Schin int sh_dup(register int old) 22274887Schin { 22284887Schin register int fd = dup(old); 22294887Schin if(fd>=0) 22304887Schin { 22314887Schin if(sh.fdstatus[old] == IOCLOSE) 22324887Schin sh.fdstatus[old] = 0; 22334887Schin sh.fdstatus[fd] = (sh.fdstatus[old]&~IOCLEX); 22344887Schin if(fdnotify) 22354887Schin (*fdnotify)(old,fd); 22364887Schin } 22374887Schin return(fd); 22384887Schin } 22394887Schin 22404887Schin #undef fcntl 22414887Schin int sh_fcntl(register int fd, int op, ...) 22424887Schin { 22434887Schin int newfd, arg; 22444887Schin va_list ap; 22454887Schin va_start(ap, op); 22464887Schin arg = va_arg(ap, int) ; 22474887Schin va_end(ap); 22484887Schin newfd = fcntl(fd,op,arg); 22494887Schin if(newfd>=0) switch(op) 22504887Schin { 22514887Schin case F_DUPFD: 22524887Schin if(sh.fdstatus[fd] == IOCLOSE) 22534887Schin sh.fdstatus[fd] = 0; 22544887Schin sh.fdstatus[newfd] = (sh.fdstatus[fd]&~IOCLEX); 22554887Schin if(fdnotify) 22564887Schin (*fdnotify)(fd,newfd); 22574887Schin break; 22584887Schin case F_SETFD: 22594887Schin if(sh.fdstatus[fd] == IOCLOSE) 22604887Schin sh.fdstatus[fd] = 0; 22614887Schin if(arg&FD_CLOEXEC) 22624887Schin sh.fdstatus[fd] |= IOCLEX; 22634887Schin else 22644887Schin sh.fdstatus[fd] &= ~IOCLEX; 22654887Schin } 22664887Schin return(newfd); 22674887Schin } 22684887Schin 22694887Schin #undef umask 22704887Schin mode_t sh_umask(mode_t m) 22714887Schin { 22724887Schin sh.mask = m; 22734887Schin return(umask(m)); 22744887Schin } 22754887Schin 22764887Schin /* 22774887Schin * give file descriptor <fd> and <mode>, return an iostream pointer 22784887Schin * <mode> must be SF_READ or SF_WRITE 22794887Schin * <fd> must be a non-negative number ofr SH_IOCOPROCESS or SH_IOHISTFILE. 22804887Schin * returns NULL on failure and may set errno. 22814887Schin */ 22824887Schin 22834887Schin Sfio_t *sh_iogetiop(int fd, int mode) 22844887Schin { 2285*8462SApril.Chin@Sun.COM Shell_t *shp = &sh; 22864887Schin int n; 22874887Schin Sfio_t *iop=0; 22884887Schin if(mode!=SF_READ && mode!=SF_WRITE) 22894887Schin { 22904887Schin errno = EINVAL; 22914887Schin return(iop); 22924887Schin } 22934887Schin switch(fd) 22944887Schin { 22954887Schin case SH_IOHISTFILE: 2296*8462SApril.Chin@Sun.COM if(!sh_histinit((void*)shp)) 22974887Schin return(iop); 2298*8462SApril.Chin@Sun.COM fd = sffileno(shp->hist_ptr->histfp); 22994887Schin break; 23004887Schin case SH_IOCOPROCESS: 23014887Schin if(mode==SF_WRITE) 2302*8462SApril.Chin@Sun.COM fd = shp->coutpipe; 23034887Schin else 2304*8462SApril.Chin@Sun.COM fd = shp->cpipe[0]; 23054887Schin break; 23064887Schin default: 2307*8462SApril.Chin@Sun.COM if(fd<0 || fd >= shp->lim.open_max) 23084887Schin fd = -1; 23094887Schin } 23104887Schin if(fd<0) 23114887Schin { 23124887Schin errno = EBADF; 23134887Schin return(iop); 23144887Schin } 2315*8462SApril.Chin@Sun.COM if(!(n=shp->fdstatus[fd])) 2316*8462SApril.Chin@Sun.COM n = sh_iocheckfd(shp,fd); 23174887Schin if(mode==SF_WRITE && !(n&IOWRITE)) 23184887Schin return(iop); 23194887Schin if(mode==SF_READ && !(n&IOREAD)) 23204887Schin return(iop); 2321*8462SApril.Chin@Sun.COM if(!(iop = shp->sftable[fd])) 2322*8462SApril.Chin@Sun.COM iop=sh_iostream(shp,fd); 23234887Schin return(iop); 23244887Schin } 23254887Schin 23264887Schin typedef int (*Notify_f)(int,int); 23274887Schin 23284887Schin Notify_f sh_fdnotify(Notify_f notify) 23294887Schin { 23304887Schin Notify_f old; 23314887Schin old = fdnotify; 23324887Schin fdnotify = notify; 23334887Schin return(old); 23344887Schin } 23354887Schin 23364887Schin Sfio_t *sh_fd2sfio(int fd) 23374887Schin { 2338*8462SApril.Chin@Sun.COM Shell_t *shp = &sh; 23394887Schin register int status; 23404887Schin Sfio_t *sp = sh.sftable[fd]; 2341*8462SApril.Chin@Sun.COM if(!sp && (status = sh_iocheckfd(shp,fd))!=IOCLOSE) 23424887Schin { 23434887Schin register int flags=0; 23444887Schin if(status&IOREAD) 23454887Schin flags |= SF_READ; 23464887Schin if(status&IOWRITE) 23474887Schin flags |= SF_WRITE; 23484887Schin sp = sfnew(NULL, NULL, -1, fd,flags); 23494887Schin sh.sftable[fd] = sp; 23504887Schin } 23514887Schin return(sp); 23524887Schin } 23534887Schin 23544887Schin Sfio_t *sh_pathopen(const char *cp) 23554887Schin { 2356*8462SApril.Chin@Sun.COM Shell_t *shp = &sh; 23574887Schin int n; 23584887Schin #ifdef PATH_BFPATH 23594887Schin if((n=path_open(cp,path_get(cp))) < 0) 23604887Schin n = path_open(cp,(Pathcomp_t*)0); 23614887Schin #else 23624887Schin if((n=path_open(cp,path_get(cp))) < 0) 23634887Schin n = path_open(cp,""); 23644887Schin #endif 23654887Schin if(n < 0) 23664887Schin errormsg(SH_DICT,ERROR_system(1),e_open,cp); 2367*8462SApril.Chin@Sun.COM return(sh_iostream(shp,n)); 23684887Schin } 2369