da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/***********************************************************************
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* This software is part of the ast package *
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner* Copyright (c) 1982-2010 AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* and is licensed under the *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Common Public License, Version 1.0 *
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin* by AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* A copy of the License is available at *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Information and Software Systems Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* AT&T Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Florham Park NJ *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* David Korn <dgk@research.att.com> *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin***********************************************************************/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Input/output file processing
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * David Korn
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * AT&T Labs
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# endif /* EAGAIN */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# endif /* !O_NONBLOCK */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* FNDELAY */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define RW_ALL (S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#if defined(_lib_socket) && defined(_sys_socket) && defined(_hdr_netinet_in)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# 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)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin# 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)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chingetaddrinfo(const char* node, const char* service, const struct addrinfo* hint, struct addrinfo **addr)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!(hp = gethostbyname(node)) || hp->h_addrtype!=AF_INET || hp->h_length>sizeof(struct in_addr))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ip_addr = (unsigned long)((struct in_addr*)hp->h_addr)->s_addr;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((n = strtol(service, &prot, 10)) > 0 && n <= USHRT_MAX && !*prot)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (!(ap = newof(0, struct addrinfo, 1, sizeof(struct sockaddr_in))))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * return <protocol>/<host>/<service> fd
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chininetopen(const char* path, int server, Inetintr_f onintr, void* handle)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* s;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char* t;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (path[0])
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (path[1]!='c' || path[2]!='t' || path[3]!='p' || path[4]!='/')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin s = "localhost";
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * some api's don't take the hint
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) >= 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (server && !bind(fd, p->ai_addr, p->ai_addrlen) && !listen(fd, 5) || !server && !connect(fd, p->ai_addr, p->ai_addrlen))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int eval_exceptf(Sfio_t*, int, void*, Sfdisc_t*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic ssize_t piperead(Sfio_t*, void*, size_t, Sfdisc_t*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic ssize_t slowread(Sfio_t*, void*, size_t, Sfdisc_t*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic ssize_t subread(Sfio_t*, void*, size_t, Sfdisc_t*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic ssize_t tee_write(Sfio_t*,const void*,size_t,Sfdisc_t*);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinstatic int io_heredoc(Shell_t*,register struct ionod*, const char*, int);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic const Sfdisc_t eval_disc = { NULL, NULL, NULL, eval_exceptf, NULL};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic Sfdisc_t tee_disc = {NULL,tee_write,NULL,NULL,NULL};
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinstatic Sfio_t *subopen(Shell_t *,Sfio_t*, off_t, long);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic const Sfdisc_t sub_disc = { subread, 0, 0, subexcept, 0 };
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic Sfdouble_t nget_cur_eof(register Namval_t* np, Namfun_t *fp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic const Namdisc_t EOF_disc = { sizeof(struct Eof), 0, 0, nget_cur_eof};
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* ======== input output and file copying ======== */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int n;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin filemap = (struct fdsave*)malloc(filemapsize*sizeof(struct fdsave));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_FASTPIPE */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin shp->fdstatus = (unsigned char*)malloc((unsigned)n);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin shp->sftable = (Sfio_t**)malloc(n*sizeof(Sfio_t*));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* all write steams are in the same pool and share outbuff */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin shp->outpool = sfopen(NIL(Sfio_t*),NIL(char*),"sw"); /* pool identifier */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin * Handle output stream exceptions
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinstatic int outexcept(register Sfio_t *iop,int type,void *data,Sfdisc_t *handle)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin else if(type==SF_WRITE && (*(ssize_t*)data)<0 && sffileno(iop)!=2)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin errormsg(SH_DICT,ERROR_system(1),e_badwrite,sffileno(iop));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * create or initialize a stream corresponding to descriptor <fd>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * a buffer with room for a sentinal is allocated for a read stream.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * A discipline is inserted when read stream is a tty or a pipe
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * For output streams, the buffer is set to sh.output and put into
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * the sh.outpool synchronization pool
7c2fbfb345896881c631598ee3852ce9ce33fb07April ChinSfio_t *sh_iostream(Shell_t *shp, register int fd)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_FASTPIPE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(!(iop=sfnew((fd<=2?iop:0),bp,IOBSIZE,fd,flags)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * preserve the file descriptor or stream by moving it
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinstatic void io_preserve(Shell_t* shp, register Sfio_t *sp, register int f2)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Given a file descriptor <f1>, move it to a file descriptor number <f2>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If <f2> is needed move it, otherwise it is closed first.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The original stream <f1> is closed.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The new file descriptor <f2> is returned;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinint sh_iorenumber(Shell_t *shp, register int f1,register int f2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* see whether file descriptor is in use */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(f2==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * close a file descriptor and update stream table and attributes
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int r = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(r);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Mimic open(2) with checks for pseudo /dev/ files.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (path[0]=='/' && path[1]=='d' && path[2]=='e' && path[3]=='v' && path[4]=='/')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((fd = inetopen(path+5, !!(flags & O_SERVICE), onintr, &sh)) < 0 && errno != ENOTDIR)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return -1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(mode&IOWRITE) && ((flags==O_WRONLY) || (flags==O_RDWR)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(mode&IOREAD) && ((flags==O_RDONLY) || (flags==O_RDWR)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz sfsprintf(buf, sizeof(buf), "%s%s", sh_regress_etc(path, __LINE__, __FILE__), path+4);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Open a file for reading
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * On failure, print message.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * move open file descriptor to a number > 2
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * create a pipe and print message on failure
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int pat_seek(void *handle, const char *str, size_t sz)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int pat_line(const regex_t* rp, const char *buff, register size_t n)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(n>0)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinstatic int io_patseek(Shell_t *shp, regex_t *rp, Sfio_t* sp, int flags)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin int r, fd=sffileno(sp), close_exec = shp->fdstatus[fd]&IOCLEX;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int was_share,s=(PIPE_BUF>SF_BUFSIZE?SF_BUFSIZE:PIPE_BUF);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while((cp=sfreserve(sp, -s, SF_LOCKR)) || (cp=sfreserve(sp,SF_UNBOUND, SF_LOCKR)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin r = regrexec(rp,cp,m,0,(regmatch_t*)0, 0, '\n', (void*)&match, pat_seek);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(r==2)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinstatic Sfoff_t file_offset(Shell_t *shp, int fn, char *fname)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * close a pipe
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinstatic char *io_usename(char *name, int *perm, int mode)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin *perm = statb.st_mode&(RW_ALL|(S_IXUSR|S_IXGRP|S_IXOTH));
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin tname = sp = (char*)stakalloc((len=strlen(name)) + 5);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * I/O redirection
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * flag = 0 if files are to be restored
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * flag = 2 if files are to be closed on exec
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * flag = 3 when called from $( < ...), just open file and return
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * flag = SH_SHOWME for trace only
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinint sh_redirect(Shell_t *shp,struct ionod *iop, int flag)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin char *tname=0, *after="", *trace = shp->st.trap[SH_DEBUGTRAP];
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz int isstring = shp->subshell?(sfset(sfstdout,0,0)&SF_STRING):0;
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if(fn==1 && shp->subshell && !shp->subshare && (flag==2 || isstring))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin struct argnod *ap = (struct argnod*)stakalloc(ARGVAL+strlen(iop->ioname));
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin fname=sh_macpat(shp,ap,(iof&IOARITH)?ARG_ARITH:ARG_EXP);
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz struct argnod *ap = (struct argnod*)stakalloc(ARGVAL+strlen(iop->ioname));
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin fname=sh_mactrim(shp,fname,(!sh_isoption(SH_NOGLOB)&&sh_isoption(SH_INTERACTIVE))?2:0);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin np = nv_open(iop->iovname,shp->var_tree,NV_NOASSIGN|NV_VARNAME);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np));
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if((iof&IOLSEEK) || ((iof&IOMOV) && *fname=='-'))
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if(shp->subshell && dupfd==1 && (sfset(sfstdout,0,0)&SF_STRING))
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin shp->fdstatus[fd] = (shp->fdstatus[dupfd]&~IOCLEX);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(toclose>=0)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin sh_iosave(shp,toclose,indx,(char*)0); /* save file descriptor */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin else if((iof&IOREWRITE) && (flag==0 || flag==1 || sh_subsavefd(fn)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_FS_3D */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if((fd=sh_open(tname?tname:fname,o_mode,RW_ALL)) <0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin errormsg(SH_DICT,ERROR_system(1),((o_mode&O_CREAT)?e_create:e_open),fname);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(sfstderr,"%s %s%s%c",io_op,fname,after,iop->ionxt?' ':'\n');
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin sh_debug(shp,trace,(char*)0,(char*)0,av,ARG_NOGLOB);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin extern const char e_notimp[];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(rp = regcache(fname, REG_SHELL|REG_NOSUB|REG_NEWLINE|REG_AUGMENTED|REG_FIRST|REG_LEFT|REG_RIGHT, &r)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* close stream but not fn */
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz sh_iosave(shp,fn,indx,tname?fname:(trunc?Empty:0));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* NOTREACHED */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Create a tmp file for the here-document
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinstatic int io_heredoc(Shell_t *shp,register struct ionod *iop, const char *name, int traceon)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(!(iop->iofile&IOSTRG) && (!shp->heredocs || iop->iosize==0))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* create an unnamed temporary file */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin infile = subopen(shp,shp->heredocs,iop->iooffset,iop->iosize);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* This is a quoted here-document, not expansion */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* close stream outfile, but save file descriptor */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This write discipline also writes the output on standard error
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This is used when tracing here-documents
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic ssize_t tee_write(Sfio_t *iop,const void *buff,size_t n,Sfdisc_t *unused)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * copy file <origfd> into a save place
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The saved file is set close-on-exec
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * if <origfd> < 0, then -origfd is saved, but not duped so that it
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * will be closed with sh_iorestore.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinvoid sh_iosave(Shell_t *shp, register int origfd, int oldtop, char *name)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin assume oldtop>=0 && oldtop<shp->lim.open_max;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* see if already saved, only save once */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* make sure table is large enough */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(filemap = (struct fdsave*)realloc(filemap,filemapsize*sizeof(struct fdsave))))
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin#endif /* SHOPT_FASTPIPE */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* SHOPT_DEVFD */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((savefd = sh_fcntl(origfd, F_DUPFD, 10)) < 0 && errno!=EBADF)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* make saved file close-on-exec */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin shp->fdptrs[savefd] = &filemap[shp->topfd-1].save_fd;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* copy standard stream to new stream */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * close all saved file descriptors
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * restore saved file descriptors from <last> on
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinvoid sh_iorestore(Shell_t *shp, int last, int jmpval)
34f9b3eef6fdadbda0a846aa4d68691ac40eace5Roland Mainz if(filemap[fd].tname == Empty && shp->exitval==0)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin io_usename(filemap[fd].tname,(int*)0,shp->exitval?2:1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* turn off close-on-exec if flag if necessary */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin sfswap(shp->sftable[savefd],shp->sftable[origfd]);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* keep file descriptors for subshell restore */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * returns access information on open file <fd>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * returns -1 for failure, 0 for success
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * <mode> is the same as for access()
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Handle interrupts for slow streams
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int slowexcept(register Sfio_t *iop,int type,void *data,Sfdisc_t *handle)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((sh.trapnote&(SH_SIGSET|SH_SIGTRAP)) && errno!=EIO && errno!=ENXIO)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# endif /* O_NDELAY */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* !FNDELAY */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* O_NONBLOCK */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * called when slowread times out
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic ssize_t piperead(Sfio_t *iop,void *buff,register size_t size,Sfdisc_t *handle)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(sh_isstate(SH_INTERACTIVE) && io_prompt(iop,sh.nextprompt)<0 && errno==EIO)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(sh.fdstatus[sffileno(iop)]&IOCLEX) && (sfset(iop,0,0)&SF_SHARE))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin size = ed_read(sh.ed_context, fd, (char*)buff, size,0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This is the read discipline that is applied to slow devices
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This routine takes care of prompting for input
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic ssize_t slowread(Sfio_t *iop,void *buff,register size_t size,Sfdisc_t *handle)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int (*readf)(void*, int, char*, int, int);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# endif /* SHOPT_ESH */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(sh_isoption(SH_VI) || ((SHOPT_RAWONLY-0) && mbwide()))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# endif /* SHOPT_VSH */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin timeout = (void*)sh_timeradd(sh_isstate(SH_GRACE)?1000L*TGRACE:1000L*sh.timeout,0,time_grace,NIL(void*));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rsize = (*readf)(sh.ed_context, sffileno(iop), (char*)buff, size, reedit);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(rsize && *(char*)buff != '\n' && sh.nextprompt==1 && sh_isoption(SH_HISTEXPAND))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((r & (HIST_EVENT|HIST_PRINT)) && !(r & HIST_ERROR) && xp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * check and return the attributes for a file descriptor
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* F_GETFL */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* /dev/null check is a workaround for select bug */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* S_ISSOCK */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* S_ISSOCK */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* The following is for sockets on the sgi */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (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) ||
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (S_ISCHR(statb.st_mode) && (statb.st_ino!=null_ino || statb.st_dev!=null_dev))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Display prompt PS<flag> on standard error
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(flag==2 && sfpkrd(sffileno(iop),buff,1,'\n',0,1) >= 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfflags = sfset(sfstderr,SF_SHARE|SF_PUBLIC|SF_READ,0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int c;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!sh_isoption(SH_VI) && !sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * re-enable output in case the user has
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * disabled it. Not needed with edit mode
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* TIOCLBIC */
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin cp = sh_mactry(shp,nv_getval(sh_scoped(shp,PS1NOD)));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* look at next character */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* print out line number if not !! */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(sfstderr,"%d", sh.hist_ptr?(int)sh.hist_ptr->histind:++cmdno);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*sh.prompt && (endprompt=(char*)sfreserve(sfstderr,0,0)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This discipline is inserted on write pipes to prevent SIGPIPE
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * from causing an infinite loop
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int pipeexcept(Sfio_t* iop, int mode, void *data, Sfdisc_t* handle)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(mode==SF_WRITE && errno==EINTR && sh.lastsig==SIGPIPE)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * keep track of each stream that is opened and closed
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinstatic void sftrack(Sfio_t* sp, int flag, void* data)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if(!shp->sftable[fd] && shp->fdstatus[fd]==IOCLOSE)
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if((pp=(struct checkpt*)shp->jmplist) && pp->mode==SH_JMPCMD)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * record open file descriptors so they can
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * be closed in case a longjmp prevents
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * built-ins from cleanup
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(flag==SF_CLOSING || (flag==SF_SETFD && newfd<=2))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Create a stream consisting of a space separated argv[] list
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This code gets called whenever an end of string is found with eval
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int eval_exceptf(Sfio_t *iop,int type, void *data, Sfdisc_t *handle)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* no more to do */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* get the length of this string */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* move to next string */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else /* insert space between arguments */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* insert the new string */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This routine returns a stream pointer to a segment of length <size> from
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * the stream <sp> starting at offset <offset>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The stream can be read with the normal stream operations
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chinstatic Sfio_t *subopen(Shell_t *shp,Sfio_t* sp, off_t offset, long size)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!(disp = (struct subfile*)malloc(sizeof(struct subfile)+IOBSIZE+1)))
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin sp = sfnew(NIL(Sfio_t*),(char*)(disp+1),IOBSIZE,shp->lim.open_max,SF_READ);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * read function for subfile discipline
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic ssize_t subread(Sfio_t* sp,void* buff,register size_t size,Sfdisc_t* handle)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register struct subfile *disp = (struct subfile*)handle;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * exception handler for subfile discipline
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int subexcept(Sfio_t* sp,register int mode, void *data, Sfdisc_t* handle)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register struct subfile *disp = (struct subfile*)handle;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define NROW 15 /* number of rows before going to multi-columns */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define LBLSIZ 3 /* size of label field and interfield spacing */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * print a list of arguments in columns
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int i,j;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin nrow = (cp?1+2*((int)strtol(cp, (char**)0, 10)/3):NROW);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for(i=0;i<nrow;i++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * shell version of read() for user added builtins
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * shell version of write() for user added builtins
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinssize_t sh_write(register int fd, const void* buff, size_t n)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * shell version of lseek() for user added builtins
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinoff_t sh_seek(register int fd, off_t offset, int whence)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((sp=sh.sftable[fd]) && (sfset(sp,0,0)&(SF_READ|SF_WRITE)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(umask(m));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * give file descriptor <fd> and <mode>, return an iostream pointer
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * <mode> must be SF_READ or SF_WRITE
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * <fd> must be a non-negative number ofr SH_IOCOPROCESS or SH_IOHISTFILE.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * returns NULL on failure and may set errno.