1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1982-2010 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                  David Korn <dgk@research.att.com>                   *
18*                                                                      *
19***********************************************************************/
20#pragma prototyped
21
22/*
23 * Input/output file processing
24 *
25 *   David Korn
26 *   AT&T Labs
27 *
28 */
29
30#include	"defs.h"
31#include	<fcin.h>
32#include	<ls.h>
33#include	<stdarg.h>
34#include	<regex.h>
35#include	"variables.h"
36#include	"path.h"
37#include	"io.h"
38#include	"jobs.h"
39#include	"shnodes.h"
40#include	"history.h"
41#include	"edit.h"
42#include	"timeout.h"
43#include	"FEATURE/externs"
44#include	"FEATURE/dynamic"
45#include	"FEATURE/poll"
46
47#ifdef	FNDELAY
48#   ifdef EAGAIN
49#	if EAGAIN!=EWOULDBLOCK
50#	    undef EAGAIN
51#	    define EAGAIN       EWOULDBLOCK
52#	endif
53#   else
54#	define EAGAIN   EWOULDBLOCK
55#   endif /* EAGAIN */
56#   ifndef O_NONBLOCK
57#	define O_NONBLOCK	FNDELAY
58#   endif /* !O_NONBLOCK */
59#endif	/* FNDELAY */
60
61#ifndef O_SERVICE
62#   define O_SERVICE	O_NOCTTY
63#endif
64
65#define RW_ALL	(S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH)
66
67static void	*timeout;
68static int	(*fdnotify)(int,int);
69
70#if defined(_lib_socket) && defined(_sys_socket) && defined(_hdr_netinet_in)
71#   include <sys/socket.h>
72#   include <netdb.h>
73#   include <netinet/in.h>
74#   if !defined(htons) && !_lib_htons
75#      define htons(x)	(x)
76#   endif
77#   if !defined(htonl) && !_lib_htonl
78#      define htonl(x)	(x)
79#   endif
80#   if _pipe_socketpair
81#      ifndef SHUT_RD
82#         define SHUT_RD         0
83#      endif
84#      ifndef SHUT_WR
85#         define SHUT_WR         1
86#      endif
87#      if _socketpair_shutdown_mode
88#         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)
89#      else
90#         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)
91#      endif
92#   endif
93
94#if !_lib_getaddrinfo
95
96#undef	EAI_SYSTEM
97
98#define EAI_SYSTEM		1
99
100#undef	addrinfo
101#undef	getaddrinfo
102#undef	freeaddrinfo
103
104#define addrinfo		local_addrinfo
105#define getaddrinfo		local_getaddrinfo
106#define freeaddrinfo		local_freeaddrinfo
107
108struct addrinfo
109{
110        int			ai_flags;
111        int			ai_family;
112        int			ai_socktype;
113        int			ai_protocol;
114        socklen_t		ai_addrlen;
115        struct sockaddr*	ai_addr;
116        struct addrinfo*	ai_next;
117};
118
119static int
120getaddrinfo(const char* node, const char* service, const struct addrinfo* hint, struct addrinfo **addr)
121{
122	unsigned long	    	ip_addr = 0;
123	unsigned short	    	ip_port = 0;
124	struct addrinfo*	ap;
125	struct hostent*		hp;
126	struct sockaddr_in*	ip;
127	char*			prot;
128	long			n;
129
130	if (!(hp = gethostbyname(node)) || hp->h_addrtype!=AF_INET || hp->h_length>sizeof(struct in_addr))
131	{
132		errno = EADDRNOTAVAIL;
133		return EAI_SYSTEM;
134	}
135	ip_addr = (unsigned long)((struct in_addr*)hp->h_addr)->s_addr;
136	if ((n = strtol(service, &prot, 10)) > 0 && n <= USHRT_MAX && !*prot)
137		ip_port = htons((unsigned short)n);
138	else
139	{
140		struct servent*	sp;
141		const char*	protocol = 0;
142
143		if (hint)
144			switch (hint->ai_socktype)
145			{
146			case SOCK_STREAM:
147				switch (hint->ai_protocol)
148				{
149				case 0:
150					protocol = "tcp";
151					break;
152#ifdef IPPROTO_SCTP
153				case IPPROTO_SCTP:
154					protocol = "sctp";
155					break;
156#endif
157				}
158				break;
159			case SOCK_DGRAM:
160				protocol = "udp";
161				break;
162			}
163		if (!protocol)
164		{
165			errno =  EPROTONOSUPPORT;
166			return 1;
167		}
168		if (sp = getservbyname(service, protocol))
169			ip_port = sp->s_port;
170	}
171	if (!ip_port)
172	{
173		errno = EADDRNOTAVAIL;
174		return EAI_SYSTEM;
175	}
176	if (!(ap = newof(0, struct addrinfo, 1, sizeof(struct sockaddr_in))))
177		return EAI_SYSTEM;
178	if (hint)
179		*ap = *hint;
180	ap->ai_family = hp->h_addrtype;
181	ap->ai_addrlen 	= sizeof(struct sockaddr_in);
182	ap->ai_addr = (struct sockaddr *)(ap+1);
183	ip = (struct sockaddr_in *)ap->ai_addr;
184	ip->sin_family = AF_INET;
185	ip->sin_port = ip_port;
186	ip->sin_addr.s_addr = ip_addr;
187	*addr = ap;
188	return 0;
189}
190
191static void
192freeaddrinfo(struct addrinfo* ap)
193{
194	if (ap)
195		free(ap);
196}
197
198#endif
199
200/*
201 * return <protocol>/<host>/<service> fd
202 */
203
204typedef int (*Inetintr_f)(struct addrinfo*, void*);
205
206static int
207inetopen(const char* path, int server, Inetintr_f onintr, void* handle)
208{
209	register char*		s;
210	register char*		t;
211	int			fd;
212	int			oerrno;
213	struct addrinfo		hint;
214	struct addrinfo*	addr;
215	struct addrinfo*	p;
216
217	memset(&hint, 0, sizeof(hint));
218	hint.ai_family = PF_UNSPEC;
219	switch (path[0])
220	{
221#ifdef IPPROTO_SCTP
222	case 's':
223		if (path[1]!='c' || path[2]!='t' || path[3]!='p' || path[4]!='/')
224		{
225			errno = ENOTDIR;
226			return -1;
227		}
228		hint.ai_socktype = SOCK_STREAM;
229		hint.ai_protocol = IPPROTO_SCTP;
230		path += 5;
231		break;
232#endif
233	case 't':
234		if (path[1]!='c' || path[2]!='p' || path[3]!='/')
235		{
236			errno = ENOTDIR;
237			return -1;
238		}
239		hint.ai_socktype = SOCK_STREAM;
240		path += 4;
241		break;
242	case 'u':
243		if (path[1]!='d' || path[2]!='p' || path[3]!='/')
244		{
245			errno = ENOTDIR;
246			return -1;
247		}
248		hint.ai_socktype = SOCK_DGRAM;
249		path += 4;
250		break;
251	default:
252		errno = ENOTDIR;
253		return -1;
254	}
255	if (!(s = strdup(path)))
256		return -1;
257	if (t = strchr(s, '/'))
258	{
259		*t++ = 0;
260		if (streq(s, "local"))
261			s = "localhost";
262		fd = getaddrinfo(s, t, &hint, &addr);
263	}
264	else
265		fd = -1;
266	free(s);
267	if (fd)
268	{
269		if (fd != EAI_SYSTEM)
270			errno = ENOTDIR;
271		return -1;
272	}
273	oerrno = errno;
274	errno = 0;
275	fd = -1;
276	for (p = addr; p; p = p->ai_next)
277	{
278		/*
279		 * some api's don't take the hint
280		 */
281
282		if (!p->ai_protocol)
283			p->ai_protocol = hint.ai_protocol;
284		if (!p->ai_socktype)
285			p->ai_socktype = hint.ai_socktype;
286		while ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) >= 0)
287		{
288			if (server && !bind(fd, p->ai_addr, p->ai_addrlen) && !listen(fd, 5) || !server && !connect(fd, p->ai_addr, p->ai_addrlen))
289				goto done;
290			close(fd);
291			fd = -1;
292			if (errno != EINTR || !onintr)
293				break;
294			if ((*onintr)(addr, handle))
295				return -1;
296		}
297	}
298 done:
299	freeaddrinfo(addr);
300	if (fd >= 0)
301		errno = oerrno;
302	return fd;
303}
304
305#else
306
307#undef	O_SERVICE
308
309#endif
310
311struct fdsave
312{
313	int	orig_fd;	/* original file descriptor */
314	int	save_fd;	/* saved file descriptor */
315	int	subshell;	/* saved for subshell */
316	char	*tname;		/* name used with >; */
317};
318
319static int  	subexcept(Sfio_t*, int, void*, Sfdisc_t*);
320static int  	eval_exceptf(Sfio_t*, int, void*, Sfdisc_t*);
321static int  	slowexcept(Sfio_t*, int, void*, Sfdisc_t*);
322static int	pipeexcept(Sfio_t*, int, void*, Sfdisc_t*);
323static ssize_t	piperead(Sfio_t*, void*, size_t, Sfdisc_t*);
324static ssize_t	slowread(Sfio_t*, void*, size_t, Sfdisc_t*);
325static ssize_t	subread(Sfio_t*, void*, size_t, Sfdisc_t*);
326static ssize_t	tee_write(Sfio_t*,const void*,size_t,Sfdisc_t*);
327static int	io_prompt(Sfio_t*,int);
328static int	io_heredoc(Shell_t*,register struct ionod*, const char*, int);
329static void	sftrack(Sfio_t*,int,void*);
330static const Sfdisc_t eval_disc = { NULL, NULL, NULL, eval_exceptf, NULL};
331static Sfdisc_t tee_disc = {NULL,tee_write,NULL,NULL,NULL};
332static Sfio_t *subopen(Shell_t *,Sfio_t*, off_t, long);
333static const Sfdisc_t sub_disc = { subread, 0, 0, subexcept, 0 };
334
335struct subfile
336{
337	Sfdisc_t	disc;
338	Sfio_t		*oldsp;
339	off_t		offset;
340	long		size;
341	long		left;
342};
343
344struct Eof
345{
346	Namfun_t	hdr;
347	int		fd;
348};
349
350static Sfdouble_t nget_cur_eof(register Namval_t* np, Namfun_t *fp)
351{
352	struct Eof *ep = (struct Eof*)fp;
353	Sfoff_t end, cur =lseek(ep->fd, (Sfoff_t)0, SEEK_CUR);
354	if(*np->nvname=='C')
355	        return((Sfdouble_t)cur);
356	if(cur<0)
357		return((Sfdouble_t)-1);
358	end =lseek(ep->fd, (Sfoff_t)0, SEEK_END);
359	lseek(ep->fd, (Sfoff_t)0, SEEK_CUR);
360        return((Sfdouble_t)end);
361}
362
363static const Namdisc_t EOF_disc	= { sizeof(struct Eof), 0, 0, nget_cur_eof};
364
365#define	MATCH_BUFF	(64*1024)
366struct Match
367{
368	Sfoff_t	offset;
369	char	*base;
370};
371
372static int matchf(void *handle, char *ptr, size_t size)
373{
374	struct Match *mp = (struct Match*)handle;
375	mp->offset += (ptr-mp->base);
376	return(1);
377}
378
379
380static struct fdsave	*filemap;
381static short		filemapsize;
382
383/* ======== input output and file copying ======== */
384
385void sh_ioinit(Shell_t *shp)
386{
387	register int n;
388	filemapsize = 8;
389	filemap = (struct fdsave*)malloc(filemapsize*sizeof(struct fdsave));
390#if SHOPT_FASTPIPE
391	n = shp->lim.open_max+2;
392#else
393	n = shp->lim.open_max;
394#endif /* SHOPT_FASTPIPE */
395	shp->fdstatus = (unsigned char*)malloc((unsigned)n);
396	memset((char*)shp->fdstatus,0,n);
397	shp->fdptrs = (int**)malloc(n*sizeof(int*));
398	memset((char*)shp->fdptrs,0,n*sizeof(int*));
399	shp->sftable = (Sfio_t**)malloc(n*sizeof(Sfio_t*));
400	memset((char*)shp->sftable,0,n*sizeof(Sfio_t*));
401	shp->sftable[0] = sfstdin;
402	shp->sftable[1] = sfstdout;
403	shp->sftable[2] = sfstderr;
404	sfnotify(sftrack);
405	sh_iostream(shp,0);
406	/* all write steams are in the same pool and share outbuff */
407	shp->outpool = sfopen(NIL(Sfio_t*),NIL(char*),"sw");  /* pool identifier */
408	shp->outbuff = (char*)malloc(IOBSIZE+4);
409	shp->errbuff = (char*)malloc(IOBSIZE/4);
410	sfsetbuf(sfstderr,shp->errbuff,IOBSIZE/4);
411	sfsetbuf(sfstdout,shp->outbuff,IOBSIZE);
412	sfpool(sfstdout,shp->outpool,SF_WRITE);
413	sfpool(sfstderr,shp->outpool,SF_WRITE);
414	sfset(sfstdout,SF_LINE,0);
415	sfset(sfstderr,SF_LINE,0);
416	sfset(sfstdin,SF_SHARE|SF_PUBLIC,1);
417}
418
419/*
420 *  Handle output stream exceptions
421 */
422static int outexcept(register Sfio_t *iop,int type,void *data,Sfdisc_t *handle)
423{
424	static int	active = 0;
425
426	NOT_USED(handle);
427	if(type==SF_DPOP || type==SF_FINAL)
428		free((void*)handle);
429	else if(type==SF_WRITE && (*(ssize_t*)data)<0 && sffileno(iop)!=2)
430		switch (errno)
431		{
432		case EINTR:
433		case EPIPE:
434#ifdef ECONNRESET
435		case ECONNRESET:
436#endif
437#ifdef ESHUTDOWN
438		case ESHUTDOWN:
439#endif
440			break;
441		default:
442			if(!active)
443			{
444				int mode = ((struct checkpt*)sh.jmplist)->mode;
445				int save = errno;
446				active = 1;
447				((struct checkpt*)sh.jmplist)->mode = 0;
448				sfpurge(iop);
449				sfpool(iop,NIL(Sfio_t*),SF_WRITE);
450				errno = save;
451				errormsg(SH_DICT,ERROR_system(1),e_badwrite,sffileno(iop));
452				active = 0;
453				((struct checkpt*)sh.jmplist)->mode = mode;
454				sh_exit(1);
455			}
456			return(-1);
457		}
458	return(0);
459}
460
461/*
462 * create or initialize a stream corresponding to descriptor <fd>
463 * a buffer with room for a sentinal is allocated for a read stream.
464 * A discipline is inserted when read stream is a tty or a pipe
465 * For output streams, the buffer is set to sh.output and put into
466 * the sh.outpool synchronization pool
467 */
468Sfio_t *sh_iostream(Shell_t *shp, register int fd)
469{
470	register Sfio_t *iop;
471	register int status = sh_iocheckfd(shp,fd);
472	register int flags = SF_WRITE;
473	char *bp;
474	Sfdisc_t *dp;
475#if SHOPT_FASTPIPE
476	if(fd>=shp->lim.open_max)
477		return(shp->sftable[fd]);
478#endif /* SHOPT_FASTPIPE */
479	if(status==IOCLOSE)
480	{
481		switch(fd)
482		{
483		    case 0:
484			return(sfstdin);
485		    case 1:
486			return(sfstdout);
487		    case 2:
488			return(sfstderr);
489		}
490		return(NIL(Sfio_t*));
491	}
492	if(status&IOREAD)
493	{
494		if(!(bp = (char *)malloc(IOBSIZE+1)))
495			return(NIL(Sfio_t*));
496		flags |= SF_READ;
497		if(!(status&IOWRITE))
498			flags &= ~SF_WRITE;
499	}
500	else
501		bp = shp->outbuff;
502	if(status&IODUP)
503		flags |= SF_SHARE|SF_PUBLIC;
504	if((iop = shp->sftable[fd]) && sffileno(iop)>=0)
505		sfsetbuf(iop, bp, IOBSIZE);
506	else if(!(iop=sfnew((fd<=2?iop:0),bp,IOBSIZE,fd,flags)))
507		return(NIL(Sfio_t*));
508	dp = newof(0,Sfdisc_t,1,0);
509	if(status&IOREAD)
510	{
511		sfset(iop,SF_MALLOC,1);
512		if(!(status&IOWRITE))
513			sfset(iop,SF_IOCHECK,1);
514		dp->exceptf = slowexcept;
515		if(status&IOTTY)
516			dp->readf = slowread;
517		else if(status&IONOSEEK)
518		{
519			dp->readf = piperead;
520			sfset(iop, SF_IOINTR,1);
521		}
522		else
523			dp->readf = 0;
524		dp->seekf = 0;
525		dp->writef = 0;
526	}
527	else
528	{
529		dp->exceptf = outexcept;
530		sfpool(iop,shp->outpool,SF_WRITE);
531	}
532	sfdisc(iop,dp);
533	shp->sftable[fd] = iop;
534	return(iop);
535}
536
537/*
538 * preserve the file descriptor or stream by moving it
539 */
540static void io_preserve(Shell_t* shp, register Sfio_t *sp, register int f2)
541{
542	register int fd;
543	if(sp)
544		fd = sfsetfd(sp,10);
545	else
546		fd = sh_fcntl(f2,F_DUPFD,10);
547	if(f2==shp->infd)
548		shp->infd = fd;
549	if(fd<0)
550	{
551		shp->toomany = 1;
552		((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT;
553		errormsg(SH_DICT,ERROR_system(1),e_toomany);
554	}
555	if(shp->fdptrs[fd]=shp->fdptrs[f2])
556	{
557		if(f2==job.fd)
558			job.fd=fd;
559		*shp->fdptrs[fd] = fd;
560		shp->fdptrs[f2] = 0;
561	}
562	shp->sftable[fd] = sp;
563	shp->fdstatus[fd] = shp->fdstatus[f2];
564	if(fcntl(f2,F_GETFD,0)&1)
565	{
566		fcntl(fd,F_SETFD,FD_CLOEXEC);
567		shp->fdstatus[fd] |= IOCLEX;
568	}
569	shp->sftable[f2] = 0;
570}
571
572/*
573 * Given a file descriptor <f1>, move it to a file descriptor number <f2>
574 * If <f2> is needed move it, otherwise it is closed first.
575 * The original stream <f1> is closed.
576 *  The new file descriptor <f2> is returned;
577 */
578int sh_iorenumber(Shell_t *shp, register int f1,register int f2)
579{
580	register Sfio_t *sp = shp->sftable[f2];
581	if(f1!=f2)
582	{
583		/* see whether file descriptor is in use */
584		if(sh_inuse(f2) || (f2>2 && sp))
585		{
586			if(!(shp->inuse_bits&(1<<f2)))
587				io_preserve(shp,sp,f2);
588			sp = 0;
589		}
590		else if(f2==0)
591			shp->st.ioset = 1;
592		sh_close(f2);
593		if(f2<=2 && sp)
594		{
595			register Sfio_t *spnew = sh_iostream(shp,f1);
596			shp->fdstatus[f2] = (shp->fdstatus[f1]&~IOCLEX);
597			sfsetfd(spnew,f2);
598			sfswap(spnew,sp);
599			sfset(sp,SF_SHARE|SF_PUBLIC,1);
600		}
601		else
602		{
603			shp->fdstatus[f2] = (shp->fdstatus[f1]&~IOCLEX);
604			if((f2 = sh_fcntl(f1,F_DUPFD, f2)) < 0)
605				errormsg(SH_DICT,ERROR_system(1),e_file+4);
606			else if(f2 <= 2)
607				sh_iostream(shp,f2);
608		}
609		if(sp)
610			shp->sftable[f1] = 0;
611		sh_close(f1);
612	}
613	return(f2);
614}
615
616/*
617 * close a file descriptor and update stream table and attributes
618 */
619int sh_close(register int fd)
620{
621	register Sfio_t *sp;
622	register int r = 0;
623	if(fd<0)
624		return(-1);
625	if(!(sp=sh.sftable[fd]) || sfclose(sp) < 0)
626	{
627		if(fdnotify)
628			(*fdnotify)(fd,SH_FDCLOSE);
629		r=close(fd);
630	}
631	if(fd>2)
632		sh.sftable[fd] = 0;
633	sh.fdstatus[fd] = IOCLOSE;
634	if(sh.fdptrs[fd])
635		*sh.fdptrs[fd] = -1;
636	sh.fdptrs[fd] = 0;
637	if(fd < 10)
638		sh.inuse_bits &= ~(1<<fd);
639	return(r);
640}
641
642#ifdef O_SERVICE
643
644static int
645onintr(struct addrinfo* addr, void* handle)
646{
647	Shell_t*	sh = (Shell_t*)handle;
648
649	if (sh->trapnote&SH_SIGSET)
650	{
651		freeaddrinfo(addr);
652		sh_exit(SH_EXITSIG);
653		return -1;
654	}
655	if (sh->trapnote)
656		sh_chktrap();
657	return 0;
658}
659
660#endif
661
662/*
663 * Mimic open(2) with checks for pseudo /dev/ files.
664 */
665int sh_open(register const char *path, int flags, ...)
666{
667	Shell_t			*shp = &sh;
668	register int		fd = -1;
669	mode_t			mode;
670	char			*e;
671	va_list			ap;
672	va_start(ap, flags);
673	mode = (flags & O_CREAT) ? va_arg(ap, int) : 0;
674	va_end(ap);
675	errno = 0;
676	if(*path==0)
677	{
678		errno = ENOENT;
679		return(-1);
680	}
681	if (path[0]=='/' && path[1]=='d' && path[2]=='e' && path[3]=='v' && path[4]=='/')
682	{
683		switch (path[5])
684		{
685		case 'f':
686			if (path[6]=='d' && path[7]=='/')
687			{
688				fd = (int)strtol(path+8, &e, 10);
689				if (*e)
690					fd = -1;
691			}
692			break;
693		case 's':
694			if (path[6]=='t' && path[7]=='d')
695				switch (path[8])
696				{
697				case 'e':
698					if (path[9]=='r' && path[10]=='r' && !path[11])
699						fd = 2;
700					break;
701				case 'i':
702					if (path[9]=='n' && !path[10])
703						fd = 0;
704					break;
705				case 'o':
706					if (path[9]=='u' && path[10]=='t' && !path[11])
707						fd = 1;
708					break;
709				}
710		}
711#ifdef O_SERVICE
712		if (fd < 0)
713		{
714			if ((fd = inetopen(path+5, !!(flags & O_SERVICE), onintr, &sh)) < 0 && errno != ENOTDIR)
715				return -1;
716			if (fd >= 0)
717				goto ok;
718		}
719#endif
720	}
721	if (fd >= 0)
722	{
723		int nfd= -1;
724		if (flags & O_CREAT)
725		{
726			struct stat st;
727			if (stat(path,&st) >=0)
728				nfd = open(path,flags,st.st_mode);
729		}
730		else
731			nfd = open(path,flags);
732		if(nfd>=0)
733		{
734			fd = nfd;
735			goto ok;
736		}
737		if((mode=sh_iocheckfd(shp,fd))==IOCLOSE)
738			return(-1);
739		flags &= O_ACCMODE;
740		if(!(mode&IOWRITE) && ((flags==O_WRONLY) || (flags==O_RDWR)))
741			return(-1);
742		if(!(mode&IOREAD) && ((flags==O_RDONLY) || (flags==O_RDWR)))
743			return(-1);
744		if((fd=dup(fd))<0)
745			return(-1);
746	}
747	else
748	{
749#if SHOPT_REGRESS
750		char	buf[PATH_MAX];
751		if(strncmp(path,"/etc/",5)==0)
752		{
753			sfsprintf(buf, sizeof(buf), "%s%s", sh_regress_etc(path, __LINE__, __FILE__), path+4);
754			path = buf;
755		}
756#endif
757		while((fd = open(path, flags, mode)) < 0)
758			if(errno!=EINTR || sh.trapnote)
759				return(-1);
760 	}
761 ok:
762	flags &= O_ACCMODE;
763	if(flags==O_WRONLY)
764		mode = IOWRITE;
765	else if(flags==O_RDWR)
766		mode = (IOREAD|IOWRITE);
767	else
768		mode = IOREAD;
769	sh.fdstatus[fd] = mode;
770	return(fd);
771}
772
773/*
774 * Open a file for reading
775 * On failure, print message.
776 */
777int sh_chkopen(register const char *name)
778{
779	register int fd = sh_open(name,O_RDONLY,0);
780	if(fd < 0)
781		errormsg(SH_DICT,ERROR_system(1),e_open,name);
782	return(fd);
783}
784
785/*
786 * move open file descriptor to a number > 2
787 */
788int sh_iomovefd(register int fdold)
789{
790	register int fdnew;
791	if(fdold<0 || fdold>2)
792		return(fdold);
793	fdnew = sh_iomovefd(dup(fdold));
794	sh.fdstatus[fdnew] = (sh.fdstatus[fdold]&~IOCLEX);
795	close(fdold);
796	sh.fdstatus[fdold] = IOCLOSE;
797	return(fdnew);
798}
799
800/*
801 * create a pipe and print message on failure
802 */
803int	sh_pipe(register int pv[])
804{
805	int fd[2];
806	if(pipe(fd)<0 || (pv[0]=fd[0])<0 || (pv[1]=fd[1])<0)
807		errormsg(SH_DICT,ERROR_system(1),e_pipe);
808	pv[0] = sh_iomovefd(pv[0]);
809	pv[1] = sh_iomovefd(pv[1]);
810	sh.fdstatus[pv[0]] = IONOSEEK|IOREAD;
811	sh.fdstatus[pv[1]] = IONOSEEK|IOWRITE;
812	sh_subsavefd(pv[0]);
813	sh_subsavefd(pv[1]);
814	return(0);
815}
816
817static int pat_seek(void *handle, const char *str, size_t sz)
818{
819	char **bp = (char**)handle;
820	*bp = (char*)str;
821	return(-1);
822}
823
824static int pat_line(const regex_t* rp, const char *buff, register size_t n)
825{
826	register const char *cp=buff, *sp;
827	while(n>0)
828	{
829		for(sp=cp; n-->0 && *cp++ != '\n';);
830		if(regnexec(rp,sp,cp-sp, 0, (regmatch_t*)0, 0)==0)
831			return(sp-buff);
832	}
833	return(cp-buff);
834}
835
836static int io_patseek(Shell_t *shp, regex_t *rp, Sfio_t* sp, int flags)
837{
838	char	*cp, *match;
839	int	r, fd=sffileno(sp), close_exec = shp->fdstatus[fd]&IOCLEX;
840	int	was_share,s=(PIPE_BUF>SF_BUFSIZE?SF_BUFSIZE:PIPE_BUF);
841	size_t	n,m;
842	shp->fdstatus[sffileno(sp)] |= IOCLEX;
843	if(fd==0)
844		was_share = sfset(sp,SF_SHARE,1);
845	while((cp=sfreserve(sp, -s, SF_LOCKR)) || (cp=sfreserve(sp,SF_UNBOUND, SF_LOCKR)))
846	{
847		m = n = sfvalue(sp);
848		while(n>0 && cp[n-1]!='\n')
849			n--;
850		if(n)
851			m = n;
852		r = regrexec(rp,cp,m,0,(regmatch_t*)0, 0, '\n', (void*)&match, pat_seek);
853		if(r<0)
854			m = match-cp;
855		else if(r==2)
856		{
857			if((m = pat_line(rp,cp,m)) < n)
858				r = -1;
859		}
860		if(m && (flags&IOCOPY))
861			sfwrite(sfstdout,cp,m);
862		sfread(sp,cp,m);
863		if(r<0)
864			break;
865	}
866	if(!close_exec)
867		shp->fdstatus[sffileno(sp)] &= ~IOCLEX;
868	if(fd==0 && !(was_share&SF_SHARE))
869		sfset(sp, SF_SHARE,0);
870	return(0);
871}
872
873static Sfoff_t	file_offset(Shell_t *shp, int fn, char *fname)
874{
875	Sfio_t		*sp = shp->sftable[fn];
876	char		*cp;
877	Sfoff_t		off;
878	struct Eof	endf;
879	Namval_t	*mp = nv_open("EOF",shp->var_tree,0);
880	Namval_t	*pp = nv_open("CUR",shp->var_tree,0);
881	memset(&endf,0,sizeof(struct Eof));
882	endf.fd = fn;
883	endf.hdr.disc = &EOF_disc;
884	endf.hdr.nofree = 1;
885	if(mp)
886		nv_stack(mp, &endf.hdr);
887	if(pp)
888		nv_stack(pp, &endf.hdr);
889	if(sp)
890		sfsync(sp);
891	off = sh_strnum(fname, &cp, 0);
892	if(mp)
893		nv_stack(mp, NiL);
894	if(pp)
895		nv_stack(pp, NiL);
896	return(*cp?(Sfoff_t)-1:off);
897}
898
899/*
900 * close a pipe
901 */
902void sh_pclose(register int pv[])
903{
904	if(pv[0]>=2)
905		sh_close(pv[0]);
906	if(pv[1]>=2)
907		sh_close(pv[1]);
908	pv[0] = pv[1] = -1;
909}
910
911static char *io_usename(char *name, int *perm, int mode)
912{
913	struct stat	statb;
914	char		*tname, *sp, *ep;
915	int		fd,len,n=0;
916	if(mode==0)
917	{
918		if((fd = sh_open(name,O_RDONLY,0)) > 0)
919		{
920			if(fstat(fd,&statb) < 0)
921				return(0);
922			if(!S_ISREG(statb.st_mode))
923				return(0);
924		 	*perm = statb.st_mode&(RW_ALL|(S_IXUSR|S_IXGRP|S_IXOTH));
925		}
926		else if(fd < 0  && errno!=ENOENT)
927			return(0);
928	}
929	tname = sp = (char*)stakalloc((len=strlen(name)) + 5);
930	if(ep = strrchr(name,'/'))
931	{
932		memcpy(sp,name,n=++ep-name);
933		len -=n;
934		sp += n;
935	}
936	else
937		ep = name;
938	*sp++ = '.';
939	memcpy(sp,ep,len);
940	strcpy(sp+len,".tmp");
941	switch(mode)
942	{
943	    case 1:
944		rename(tname,name);
945		break;
946	    case 2:
947		unlink(tname);
948		break;
949	}
950	return(tname);
951}
952
953/*
954 * I/O redirection
955 * flag = 0 if files are to be restored
956 * flag = 2 if files are to be closed on exec
957 * flag = 3 when called from $( < ...), just open file and return
958 * flag = SH_SHOWME for trace only
959 */
960int	sh_redirect(Shell_t *shp,struct ionod *iop, int flag)
961{
962	Sfoff_t off;
963	register char *fname;
964	register int 	fd, iof;
965	const char *message = e_open;
966	int o_mode;		/* mode flag for open */
967	static char io_op[7];	/* used for -x trace info */
968	int trunc=0, clexec=0, fn, traceon;
969	int r, indx = shp->topfd, perm= -1;
970	char *tname=0, *after="", *trace = shp->st.trap[SH_DEBUGTRAP];
971	Namval_t *np=0;
972	int isstring = shp->subshell?(sfset(sfstdout,0,0)&SF_STRING):0;
973	if(flag==2)
974		clexec = 1;
975	if(iop)
976		traceon = sh_trace(NIL(char**),0);
977	for(;iop;iop=iop->ionxt)
978	{
979		iof=iop->iofile;
980		fn = (iof&IOUFD);
981		if(fn==1 && shp->subshell && !shp->subshare && (flag==2 || isstring))
982			sh_subfork();
983		io_op[0] = '0'+(iof&IOUFD);
984		if(iof&IOPUT)
985		{
986			io_op[1] = '>';
987			o_mode = O_WRONLY|O_CREAT;
988		}
989		else
990		{
991			io_op[1] = '<';
992			o_mode = O_RDONLY|O_NONBLOCK;
993		}
994		io_op[2] = 0;
995		io_op[3] = 0;
996		io_op[4] = 0;
997		fname = iop->ioname;
998		if(!(iof&IORAW))
999		{
1000			if(iof&IOLSEEK)
1001			{
1002				struct argnod *ap = (struct argnod*)stakalloc(ARGVAL+strlen(iop->ioname));
1003				memset(ap, 0, ARGVAL);
1004				ap->argflag = ARG_MAC;
1005				strcpy(ap->argval,iop->ioname);
1006				fname=sh_macpat(shp,ap,(iof&IOARITH)?ARG_ARITH:ARG_EXP);
1007			}
1008			else if(iof&IOPROCSUB)
1009			{
1010				struct argnod *ap = (struct argnod*)stakalloc(ARGVAL+strlen(iop->ioname));
1011				memset(ap, 0, ARGVAL);
1012				if(iof&IOPUT)
1013					ap->argflag = ARG_RAW;
1014				ap->argchn.ap = (struct argnod*)fname;
1015				ap = sh_argprocsub(shp,ap);
1016				fname = ap->argval;
1017			}
1018			else
1019				fname=sh_mactrim(shp,fname,(!sh_isoption(SH_NOGLOB)&&sh_isoption(SH_INTERACTIVE))?2:0);
1020		}
1021		errno=0;
1022		np = 0;
1023		if(iop->iovname)
1024		{
1025			np = nv_open(iop->iovname,shp->var_tree,NV_NOASSIGN|NV_VARNAME);
1026			if(nv_isattr(np,NV_RDONLY))
1027				errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np));
1028			io_op[0] = '}';
1029			if((iof&IOLSEEK) || ((iof&IOMOV) && *fname=='-'))
1030				fn = nv_getnum(np);
1031		}
1032		if(iof&IOLSEEK)
1033		{
1034			io_op[2] = '#';
1035			if(iof&IOARITH)
1036			{
1037				strcpy(&io_op[3]," ((");
1038				after = "))";
1039			}
1040			else if(iof&IOCOPY)
1041				io_op[3] = '#';
1042			goto traceit;
1043		}
1044		if(*fname)
1045		{
1046			if(iof&IODOC)
1047			{
1048				if(traceon)
1049					sfputr(sfstderr,io_op,'<');
1050				fd = io_heredoc(shp,iop,fname,traceon);
1051				if(traceon && (flag==SH_SHOWME))
1052					sh_close(fd);
1053				fname = 0;
1054			}
1055			else if(iof&IOMOV)
1056			{
1057				int dupfd,toclose= -1;
1058				io_op[2] = '&';
1059				if((fd=fname[0])>='0' && fd<='9')
1060				{
1061					char *number = fname;
1062					dupfd = strtol(fname,&number,10);
1063					if(*number=='-')
1064					{
1065						toclose = dupfd;
1066						number++;
1067					}
1068					if(*number || dupfd > IOUFD)
1069					{
1070						message = e_file;
1071						goto fail;
1072					}
1073					if(shp->subshell && dupfd==1 && (sfset(sfstdout,0,0)&SF_STRING))
1074					{
1075						sh_subtmpfile(0);
1076						dupfd = sffileno(sfstdout);
1077					}
1078					else if(shp->sftable[dupfd])
1079						sfsync(shp->sftable[dupfd]);
1080				}
1081				else if(fd=='-' && fname[1]==0)
1082				{
1083					fd= -1;
1084					goto traceit;
1085				}
1086				else if(fd=='p' && fname[1]==0)
1087				{
1088					if(iof&IOPUT)
1089						dupfd = shp->coutpipe;
1090					else
1091						dupfd = shp->cpipe[0];
1092					if(flag)
1093						toclose = dupfd;
1094				}
1095				else
1096				{
1097					message = e_file;
1098					goto fail;
1099				}
1100				if(flag==SH_SHOWME)
1101					goto traceit;
1102				if((fd=sh_fcntl(dupfd,F_DUPFD,3))<0)
1103					goto fail;
1104				sh_iocheckfd(shp,dupfd);
1105				shp->fdstatus[fd] = (shp->fdstatus[dupfd]&~IOCLEX);
1106				if(toclose<0 && shp->fdstatus[fd]&IOREAD)
1107					shp->fdstatus[fd] |= IODUP;
1108				else if(dupfd==shp->cpipe[0])
1109					sh_pclose(shp->cpipe);
1110				else if(toclose>=0)
1111				{
1112					if(flag==0)
1113						sh_iosave(shp,toclose,indx,(char*)0); /* save file descriptor */
1114					sh_close(toclose);
1115				}
1116			}
1117			else if(iof&IORDW)
1118			{
1119				if(sh_isoption(SH_RESTRICTED))
1120					errormsg(SH_DICT,ERROR_exit(1),e_restricted,fname);
1121				io_op[2] = '>';
1122				o_mode = O_RDWR|O_CREAT;
1123				if(iof&IOREWRITE)
1124					trunc = io_op[2] = ';';
1125				goto openit;
1126			}
1127			else if(!(iof&IOPUT))
1128			{
1129				if(flag==SH_SHOWME)
1130					goto traceit;
1131				fd=sh_chkopen(fname);
1132			}
1133			else if(sh_isoption(SH_RESTRICTED))
1134				errormsg(SH_DICT,ERROR_exit(1),e_restricted,fname);
1135			else
1136			{
1137				if(iof&IOAPP)
1138				{
1139					io_op[2] = '>';
1140					o_mode |= O_APPEND;
1141				}
1142				else if((iof&IOREWRITE) && (flag==0 || flag==1 || sh_subsavefd(fn)))
1143				{
1144					io_op[2] = ';';
1145					o_mode |= O_TRUNC;
1146					tname = io_usename(fname,&perm,0);
1147				}
1148				else
1149				{
1150					o_mode |= O_TRUNC;
1151					if(iof&IOCLOB)
1152						io_op[2] = '|';
1153					else if(sh_isoption(SH_NOCLOBBER))
1154					{
1155						struct stat sb;
1156						if(stat(fname,&sb)>=0)
1157						{
1158#if SHOPT_FS_3D
1159							if(S_ISREG(sb.st_mode)&&
1160						                (!shp->lim.fs3d || iview(&sb)==0))
1161#else
1162							if(S_ISREG(sb.st_mode))
1163#endif /* SHOPT_FS_3D */
1164							{
1165								errno = EEXIST;
1166								errormsg(SH_DICT,ERROR_system(1),e_exists,fname);
1167							}
1168						}
1169						else
1170							o_mode |= O_EXCL;
1171					}
1172				}
1173			openit:
1174				if(flag!=SH_SHOWME)
1175				{
1176					if((fd=sh_open(tname?tname:fname,o_mode,RW_ALL)) <0)
1177						errormsg(SH_DICT,ERROR_system(1),((o_mode&O_CREAT)?e_create:e_open),fname);
1178					if(perm>0)
1179#if _lib_fchmod
1180						fchmod(fd,perm);
1181#else
1182						chmod(tname,perm);
1183#endif
1184				}
1185			}
1186		traceit:
1187			if(traceon && fname)
1188			{
1189				if(np)
1190					sfprintf(sfstderr,"{%s",nv_name(np));
1191				sfprintf(sfstderr,"%s %s%s%c",io_op,fname,after,iop->ionxt?' ':'\n');
1192			}
1193			if(flag==SH_SHOWME)
1194				return(indx);
1195			if(trace && fname)
1196			{
1197				char *argv[7], **av=argv;
1198				av[3] = io_op;
1199				av[4] = fname;
1200				av[5] = 0;
1201				av[6] = 0;
1202				if(iof&IOARITH)
1203					av[5] = after;
1204				if(np)
1205				{
1206					av[0] = "{";
1207					av[1] = nv_name(np);
1208					av[2] = "}";
1209				}
1210				else
1211					av +=3;
1212				sh_debug(shp,trace,(char*)0,(char*)0,av,ARG_NOGLOB);
1213			}
1214			if(iof&IOLSEEK)
1215			{
1216				Sfio_t *sp = shp->sftable[fn];
1217				r = shp->fdstatus[fn];
1218				if(!(r&(IOSEEK|IONOSEEK)))
1219					r = sh_iocheckfd(shp,fn);
1220				sfsprintf(io_op,sizeof(io_op),"%d\0",fn);
1221				if(r==IOCLOSE)
1222				{
1223					fname = io_op;
1224					message = e_file;
1225					goto fail;
1226				}
1227				if(iof&IOARITH)
1228				{
1229					if(r&IONOSEEK)
1230					{
1231						fname = io_op;
1232						message = e_notseek;
1233						goto fail;
1234					}
1235					message = e_badseek;
1236					if((off = file_offset(shp,fn,fname))<0)
1237						goto fail;
1238					if(sp)
1239					{
1240						off=sfseek(sp, off, SEEK_SET);
1241						sfsync(sp);
1242					}
1243					else
1244						off=lseek(fn, off, SEEK_SET);
1245					if(off<0)
1246						r = -1;
1247				}
1248				else
1249				{
1250					regex_t *rp;
1251					extern const char e_notimp[];
1252					if(!(r&IOREAD))
1253					{
1254						message = e_noread;
1255						goto fail;
1256					}
1257					if(!(rp = regcache(fname, REG_SHELL|REG_NOSUB|REG_NEWLINE|REG_AUGMENTED|REG_FIRST|REG_LEFT|REG_RIGHT, &r)))
1258					{
1259						message = e_badpattern;
1260						goto fail;
1261					}
1262					if(!sp)
1263						sp = sh_iostream(shp,fn);
1264					r=io_patseek(shp,rp,sp,iof);
1265					if(sp && flag==3)
1266					{
1267						/* close stream but not fn */
1268						sfsetfd(sp,-1);
1269						sfclose(sp);
1270					}
1271				}
1272				if(r<0)
1273					goto fail;
1274				if(flag==3)
1275					return(fn);
1276				continue;
1277			}
1278			if(!np)
1279			{
1280				if(flag==0 || tname)
1281				{
1282					if(fd==fn)
1283					{
1284						if((r=sh_fcntl(fd,F_DUPFD,10)) > 0)
1285						{
1286							fd = r;
1287							sh_close(fn);
1288						}
1289					}
1290					sh_iosave(shp,fn,indx,tname?fname:(trunc?Empty:0));
1291				}
1292				else if(sh_subsavefd(fn))
1293					sh_iosave(shp,fn,indx|IOSUBSHELL,tname?fname:0);
1294			}
1295			if(fd<0)
1296			{
1297				if(sh_inuse(fn) || (fn && fn==shp->infd))
1298				{
1299					if(fn>9 || !(shp->inuse_bits&(1<<fn)))
1300						io_preserve(shp,shp->sftable[fn],fn);
1301				}
1302				sh_close(fn);
1303			}
1304			if(flag==3)
1305				return(fd);
1306			if(fd>=0)
1307			{
1308				if(np)
1309				{
1310					int32_t v;
1311					fn = fd;
1312					if(fd<10)
1313					{
1314						if((fn=fcntl(fd,F_DUPFD,10)) < 0)
1315							goto fail;
1316						shp->fdstatus[fn] = shp->fdstatus[fd];
1317						sh_close(fd);
1318						fd = fn;
1319					}
1320					nv_unset(np);
1321					nv_onattr(np,NV_INT32);
1322					v = fn;
1323					nv_putval(np,(char*)&v, NV_INT32);
1324					sh_iocheckfd(shp,fd);
1325				}
1326				else
1327				{
1328					fd = sh_iorenumber(shp,sh_iomovefd(fd),fn);
1329					if(fn>2 && fn<10)
1330						shp->inuse_bits |= (1<<fn);
1331				}
1332			}
1333			if(fd >2 && clexec)
1334			{
1335				fcntl(fd,F_SETFD,FD_CLOEXEC);
1336				shp->fdstatus[fd] |= IOCLEX;
1337			}
1338		}
1339		else
1340			goto fail;
1341	}
1342	return(indx);
1343fail:
1344	errormsg(SH_DICT,ERROR_system(1),message,fname);
1345	/* NOTREACHED */
1346	return(0);
1347}
1348/*
1349 * Create a tmp file for the here-document
1350 */
1351static int io_heredoc(Shell_t *shp,register struct ionod *iop, const char *name, int traceon)
1352{
1353	register Sfio_t	*infile = 0, *outfile;
1354	register int		fd;
1355	if(!(iop->iofile&IOSTRG) && (!shp->heredocs || iop->iosize==0))
1356		return(sh_open(e_devnull,O_RDONLY));
1357	/* create an unnamed temporary file */
1358	if(!(outfile=sftmp(0)))
1359		errormsg(SH_DICT,ERROR_system(1),e_tmpcreate);
1360	if(iop->iofile&IOSTRG)
1361	{
1362		if(traceon)
1363			sfprintf(sfstderr,"< %s\n",name);
1364		sfputr(outfile,name,'\n');
1365	}
1366	else
1367	{
1368		infile = subopen(shp,shp->heredocs,iop->iooffset,iop->iosize);
1369		if(traceon)
1370		{
1371			char *cp = sh_fmtq(iop->iodelim);
1372			fd = (*cp=='$' || *cp=='\'')?' ':'\\';
1373			sfprintf(sfstderr," %c%s\n",fd,cp);
1374			sfdisc(outfile,&tee_disc);
1375		}
1376		if(iop->iofile&IOQUOTE)
1377		{
1378			/* This is a quoted here-document, not expansion */
1379			sfmove(infile,outfile,SF_UNBOUND,-1);
1380			sfclose(infile);
1381		}
1382		else
1383		{
1384			char *lastpath = shp->lastpath;
1385			sh_machere(shp,infile,outfile,iop->ioname);
1386			shp->lastpath = lastpath;
1387			if(infile)
1388				sfclose(infile);
1389		}
1390	}
1391	/* close stream outfile, but save file descriptor */
1392	fd = sffileno(outfile);
1393	sfsetfd(outfile,-1);
1394	sfclose(outfile);
1395	if(traceon && !(iop->iofile&IOSTRG))
1396		sfputr(sfstderr,iop->ioname,'\n');
1397	lseek(fd,(off_t)0,SEEK_SET);
1398	shp->fdstatus[fd] = IOREAD;
1399	return(fd);
1400}
1401
1402/*
1403 * This write discipline also writes the output on standard error
1404 * This is used when tracing here-documents
1405 */
1406static ssize_t tee_write(Sfio_t *iop,const void *buff,size_t n,Sfdisc_t *unused)
1407{
1408	NOT_USED(unused);
1409	sfwrite(sfstderr,buff,n);
1410	return(write(sffileno(iop),buff,n));
1411}
1412
1413/*
1414 * copy file <origfd> into a save place
1415 * The saved file is set close-on-exec
1416 * if <origfd> < 0, then -origfd is saved, but not duped so that it
1417 *   will be closed with sh_iorestore.
1418 */
1419void sh_iosave(Shell_t *shp, register int origfd, int oldtop, char *name)
1420{
1421/*@
1422	assume oldtop>=0 && oldtop<shp->lim.open_max;
1423@*/
1424
1425	register int	savefd;
1426	int flag = (oldtop&IOSUBSHELL);
1427	oldtop &= ~IOSUBSHELL;
1428	/* see if already saved, only save once */
1429	for(savefd=shp->topfd; --savefd>=oldtop; )
1430	{
1431		if(filemap[savefd].orig_fd == origfd)
1432			return;
1433	}
1434	/* make sure table is large enough */
1435	if(shp->topfd >= filemapsize)
1436	{
1437		char 	*cp, *oldptr = (char*)filemap;
1438		char 	*oldend = (char*)&filemap[filemapsize];
1439		long	moved;
1440		filemapsize += 8;
1441		if(!(filemap = (struct fdsave*)realloc(filemap,filemapsize*sizeof(struct fdsave))))
1442			errormsg(SH_DICT,ERROR_exit(4),e_nospace);
1443		if(moved = (char*)filemap - oldptr)
1444		{
1445#if SHOPT_FASTPIPE
1446			for(savefd=shp->lim.open_max+2; --savefd>=0; )
1447#else
1448			for(savefd=shp->lim.open_max; --savefd>=0; )
1449#endif /* SHOPT_FASTPIPE */
1450			{
1451				cp = (char*)shp->fdptrs[savefd];
1452				if(cp >= oldptr && cp < oldend)
1453					shp->fdptrs[savefd] = (int*)(oldptr+moved);
1454			}
1455		}
1456	}
1457#if SHOPT_DEVFD
1458	if(origfd <0)
1459	{
1460		savefd = origfd;
1461		origfd = -origfd;
1462	}
1463	else
1464#endif /* SHOPT_DEVFD */
1465	{
1466		if((savefd = sh_fcntl(origfd, F_DUPFD, 10)) < 0 && errno!=EBADF)
1467		{
1468			shp->toomany=1;
1469			((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT;
1470			errormsg(SH_DICT,ERROR_system(1),e_toomany);
1471		}
1472	}
1473	filemap[shp->topfd].tname = name;
1474	filemap[shp->topfd].subshell = flag;
1475	filemap[shp->topfd].orig_fd = origfd;
1476	filemap[shp->topfd++].save_fd = savefd;
1477	if(savefd >=0)
1478	{
1479		register Sfio_t* sp = shp->sftable[origfd];
1480		/* make saved file close-on-exec */
1481		sh_fcntl(savefd,F_SETFD,FD_CLOEXEC);
1482		if(origfd==job.fd)
1483			job.fd = savefd;
1484		shp->fdstatus[savefd] = shp->fdstatus[origfd];
1485		shp->fdptrs[savefd] = &filemap[shp->topfd-1].save_fd;
1486		if(!(shp->sftable[savefd]=sp))
1487			return;
1488		sfsync(sp);
1489		if(origfd <=2)
1490		{
1491			/* copy standard stream to new stream */
1492			sp = sfswap(sp,NIL(Sfio_t*));
1493			shp->sftable[savefd] = sp;
1494		}
1495		else
1496			shp->sftable[origfd] = 0;
1497	}
1498}
1499
1500/*
1501 *  close all saved file descriptors
1502 */
1503void	sh_iounsave(Shell_t* shp)
1504{
1505	register int fd, savefd, newfd;
1506	for(newfd=fd=0; fd < shp->topfd; fd++)
1507	{
1508		if((savefd = filemap[fd].save_fd)< 0)
1509			filemap[newfd++] = filemap[fd];
1510		else
1511		{
1512			shp->sftable[savefd] = 0;
1513			sh_close(savefd);
1514		}
1515	}
1516	shp->topfd = newfd;
1517}
1518
1519/*
1520 *  restore saved file descriptors from <last> on
1521 */
1522void	sh_iorestore(Shell_t *shp, int last, int jmpval)
1523{
1524	register int 	origfd, savefd, fd;
1525	int flag = (last&IOSUBSHELL);
1526	last &= ~IOSUBSHELL;
1527	for (fd = shp->topfd - 1; fd >= last; fd--)
1528	{
1529		if(!flag && filemap[fd].subshell)
1530			continue;
1531		if(jmpval==SH_JMPSCRIPT)
1532		{
1533			if ((savefd = filemap[fd].save_fd) >= 0)
1534			{
1535				shp->sftable[savefd] = 0;
1536				sh_close(savefd);
1537			}
1538			continue;
1539		}
1540		origfd = filemap[fd].orig_fd;
1541		if(filemap[fd].tname == Empty && shp->exitval==0)
1542			ftruncate(origfd,lseek(origfd,0,SEEK_CUR));
1543		else if(filemap[fd].tname)
1544			io_usename(filemap[fd].tname,(int*)0,shp->exitval?2:1);
1545		sh_close(origfd);
1546		if ((savefd = filemap[fd].save_fd) >= 0)
1547		{
1548			sh_fcntl(savefd, F_DUPFD, origfd);
1549			if(savefd==job.fd)
1550				job.fd=origfd;
1551			shp->fdstatus[origfd] = shp->fdstatus[savefd];
1552			/* turn off close-on-exec if flag if necessary */
1553			if(shp->fdstatus[origfd]&IOCLEX)
1554				fcntl(origfd,F_SETFD,FD_CLOEXEC);
1555			if(origfd<=2)
1556			{
1557				sfswap(shp->sftable[savefd],shp->sftable[origfd]);
1558				if(origfd==0)
1559					shp->st.ioset = 0;
1560			}
1561			else
1562				shp->sftable[origfd] = shp->sftable[savefd];
1563			shp->sftable[savefd] = 0;
1564			sh_close(savefd);
1565		}
1566		else
1567			shp->fdstatus[origfd] = IOCLOSE;
1568	}
1569	if(!flag)
1570	{
1571		/* keep file descriptors for subshell restore */
1572		for (fd = last ; fd < shp->topfd; fd++)
1573		{
1574			if(filemap[fd].subshell)
1575				filemap[last++] = filemap[fd];
1576		}
1577	}
1578	if(last < shp->topfd)
1579		shp->topfd = last;
1580}
1581
1582/*
1583 * returns access information on open file <fd>
1584 * returns -1 for failure, 0 for success
1585 * <mode> is the same as for access()
1586 */
1587int sh_ioaccess(int fd,register int mode)
1588{
1589	Shell_t	*shp = &sh;
1590	register int flags;
1591	if(mode==X_OK)
1592		return(-1);
1593	if((flags=sh_iocheckfd(shp,fd))!=IOCLOSE)
1594	{
1595		if(mode==F_OK)
1596			return(0);
1597		if(mode==R_OK && (flags&IOREAD))
1598			return(0);
1599		if(mode==W_OK && (flags&IOWRITE))
1600			return(0);
1601	}
1602	return(-1);
1603}
1604
1605/*
1606 *  Handle interrupts for slow streams
1607 */
1608static int slowexcept(register Sfio_t *iop,int type,void *data,Sfdisc_t *handle)
1609{
1610	register int	n,fno;
1611	NOT_USED(handle);
1612	if(type==SF_DPOP || type==SF_FINAL)
1613		free((void*)handle);
1614	if(type!=SF_READ)
1615		return(0);
1616	if((sh.trapnote&(SH_SIGSET|SH_SIGTRAP)) && errno!=EIO && errno!=ENXIO)
1617		errno = EINTR;
1618	fno = sffileno(iop);
1619	if((n=sfvalue(iop))<=0)
1620	{
1621#ifndef FNDELAY
1622#   ifdef O_NDELAY
1623		if(errno==0 && (n=fcntl(fno,F_GETFL,0))&O_NDELAY)
1624		{
1625			n &= ~O_NDELAY;
1626			fcntl(fno, F_SETFL, n);
1627			return(1);
1628		}
1629#   endif /* O_NDELAY */
1630#endif /* !FNDELAY */
1631#ifdef O_NONBLOCK
1632		if(errno==EAGAIN)
1633		{
1634			n = fcntl(fno,F_GETFL,0);
1635			n &= ~O_NONBLOCK;
1636			fcntl(fno, F_SETFL, n);
1637			return(1);
1638		}
1639#endif /* O_NONBLOCK */
1640		if(errno!=EINTR)
1641			return(0);
1642		n=1;
1643		sh_onstate(SH_TTYWAIT);
1644	}
1645	else
1646		n = 0;
1647	if(sh.bltinfun && sh.bltindata.sigset)
1648		return(-1);
1649	errno = 0;
1650	if(sh.trapnote&SH_SIGSET)
1651	{
1652		if(isatty(fno))
1653			sfputc(sfstderr,'\n');
1654		sh_exit(SH_EXITSIG);
1655	}
1656	if(sh.trapnote&SH_SIGTRAP)
1657		sh_chktrap();
1658	return(n);
1659}
1660
1661/*
1662 * called when slowread times out
1663 */
1664static void time_grace(void *handle)
1665{
1666	NOT_USED(handle);
1667	timeout = 0;
1668	if(sh_isstate(SH_GRACE))
1669	{
1670		sh_offstate(SH_GRACE);
1671		if(!sh_isstate(SH_INTERACTIVE))
1672			return;
1673		((struct checkpt*)sh.jmplist)->mode = SH_JMPEXIT;
1674		errormsg(SH_DICT,2,e_timeout);
1675		sh.trapnote |= SH_SIGSET;
1676		return;
1677	}
1678	errormsg(SH_DICT,0,e_timewarn);
1679	sh_onstate(SH_GRACE);
1680	sigrelease(SIGALRM);
1681	sh.trapnote |= SH_SIGTRAP;
1682}
1683
1684static ssize_t piperead(Sfio_t *iop,void *buff,register size_t size,Sfdisc_t *handle)
1685{
1686	int fd = sffileno(iop);
1687	NOT_USED(handle);
1688	if(job.waitsafe && job.savesig)
1689	{
1690		job_lock();
1691		job_unlock();
1692	}
1693	if(sh.trapnote)
1694	{
1695		errno = EINTR;
1696		return(-1);
1697	}
1698	if(sh_isstate(SH_INTERACTIVE) && io_prompt(iop,sh.nextprompt)<0 && errno==EIO)
1699		return(0);
1700	sh_onstate(SH_TTYWAIT);
1701	if(!(sh.fdstatus[sffileno(iop)]&IOCLEX) && (sfset(iop,0,0)&SF_SHARE))
1702		size = ed_read(sh.ed_context, fd, (char*)buff, size,0);
1703	else
1704		size = sfrd(iop,buff,size,handle);
1705	sh_offstate(SH_TTYWAIT);
1706	return(size);
1707}
1708/*
1709 * This is the read discipline that is applied to slow devices
1710 * This routine takes care of prompting for input
1711 */
1712static ssize_t slowread(Sfio_t *iop,void *buff,register size_t size,Sfdisc_t *handle)
1713{
1714	int	(*readf)(void*, int, char*, int, int);
1715	int	reedit=0, rsize;
1716#if SHOPT_HISTEXPAND
1717	char    *xp=0;
1718#endif
1719	NOT_USED(handle);
1720#   if SHOPT_ESH
1721	if(sh_isoption(SH_EMACS) || sh_isoption(SH_GMACS))
1722		readf = ed_emacsread;
1723	else
1724#   endif	/* SHOPT_ESH */
1725#   if SHOPT_VSH
1726#	if SHOPT_RAWONLY
1727	    if(sh_isoption(SH_VI) || ((SHOPT_RAWONLY-0) && mbwide()))
1728#	else
1729	    if(sh_isoption(SH_VI))
1730#	endif
1731		readf = ed_viread;
1732	else
1733#   endif	/* SHOPT_VSH */
1734		readf = ed_read;
1735	if(sh.trapnote)
1736	{
1737		errno = EINTR;
1738		return(-1);
1739	}
1740	while(1)
1741	{
1742		if(io_prompt(iop,sh.nextprompt)<0 && errno==EIO)
1743			return(0);
1744		if(sh.timeout)
1745			timeout = (void*)sh_timeradd(sh_isstate(SH_GRACE)?1000L*TGRACE:1000L*sh.timeout,0,time_grace,NIL(void*));
1746		rsize = (*readf)(sh.ed_context, sffileno(iop), (char*)buff, size, reedit);
1747		if(timeout)
1748			timerdel(timeout);
1749		timeout=0;
1750#if SHOPT_HISTEXPAND
1751		if(rsize && *(char*)buff != '\n' && sh.nextprompt==1 && sh_isoption(SH_HISTEXPAND))
1752		{
1753			int r;
1754			((char*)buff)[rsize] = '\0';
1755			if(xp)
1756			{
1757				free(xp);
1758				xp = 0;
1759			}
1760			r = hist_expand(buff, &xp);
1761			if((r & (HIST_EVENT|HIST_PRINT)) && !(r & HIST_ERROR) && xp)
1762			{
1763				strlcpy(buff, xp, size);
1764				rsize = strlen(buff);
1765				if(!sh_isoption(SH_HISTVERIFY) || readf==ed_read)
1766				{
1767					sfputr(sfstderr, xp, -1);
1768					break;
1769				}
1770				reedit = rsize - 1;
1771				continue;
1772			}
1773			if((r & HIST_ERROR) && sh_isoption(SH_HISTREEDIT))
1774			{
1775				reedit  = rsize - 1;
1776				continue;
1777			}
1778			if(r & (HIST_ERROR|HIST_PRINT))
1779			{
1780				*(char*)buff = '\n';
1781				rsize = 1;
1782			}
1783		}
1784#endif
1785		break;
1786	}
1787	return(rsize);
1788}
1789
1790/*
1791 * check and return the attributes for a file descriptor
1792 */
1793
1794int sh_iocheckfd(Shell_t *shp, register int fd)
1795{
1796	register int flags, n;
1797	if((n=sh.fdstatus[fd])&IOCLOSE)
1798		return(n);
1799	if(!(n&(IOREAD|IOWRITE)))
1800	{
1801#ifdef F_GETFL
1802		if((flags=fcntl(fd,F_GETFL,0)) < 0)
1803			return(sh.fdstatus[fd]=IOCLOSE);
1804		if((flags&O_ACCMODE)!=O_WRONLY)
1805			n |= IOREAD;
1806		if((flags&O_ACCMODE)!=O_RDONLY)
1807			n |= IOWRITE;
1808#else
1809		struct stat statb;
1810		if((flags = fstat(fd,&statb))< 0)
1811			return(sh.fdstatus[fd]=IOCLOSE);
1812		n |= (IOREAD|IOWRITE);
1813		if(read(fd,"",0) < 0)
1814			n &= ~IOREAD;
1815#endif /* F_GETFL */
1816	}
1817	if(!(n&(IOSEEK|IONOSEEK)))
1818	{
1819		struct stat statb;
1820		/* /dev/null check is a workaround for select bug */
1821		static ino_t null_ino;
1822		static dev_t null_dev;
1823		if(null_ino==0 && stat(e_devnull,&statb) >=0)
1824		{
1825			null_ino = statb.st_ino;
1826			null_dev = statb.st_dev;
1827		}
1828		if(tty_check(fd))
1829			n |= IOTTY;
1830		if(lseek(fd,NIL(off_t),SEEK_CUR)<0)
1831		{
1832			n |= IONOSEEK;
1833#ifdef S_ISSOCK
1834			if((fstat(fd,&statb)>=0) && S_ISSOCK(statb.st_mode))
1835				n |= IOREAD|IOWRITE;
1836#endif /* S_ISSOCK */
1837		}
1838		else if((fstat(fd,&statb)>=0) && (
1839			S_ISFIFO(statb.st_mode) ||
1840#ifdef S_ISSOCK
1841			S_ISSOCK(statb.st_mode) ||
1842#endif /* S_ISSOCK */
1843			/* The following is for sockets on the sgi */
1844			(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) ||
1845			(S_ISCHR(statb.st_mode) && (statb.st_ino!=null_ino || statb.st_dev!=null_dev))
1846		))
1847			n |= IONOSEEK;
1848		else
1849			n |= IOSEEK;
1850	}
1851	sh.fdstatus[fd] = n;
1852	return(n);
1853}
1854
1855/*
1856 * Display prompt PS<flag> on standard error
1857 */
1858
1859static int	io_prompt(Sfio_t *iop,register int flag)
1860{
1861	Shell_t	*shp = &sh;
1862	register char *cp;
1863	char buff[1];
1864	char *endprompt;
1865	static short cmdno;
1866	int sfflags;
1867	if(flag<3 && !sh_isstate(SH_INTERACTIVE))
1868		flag = 0;
1869	if(flag==2 && sfpkrd(sffileno(iop),buff,1,'\n',0,1) >= 0)
1870		flag = 0;
1871	if(flag==0)
1872		return(sfsync(sfstderr));
1873	sfflags = sfset(sfstderr,SF_SHARE|SF_PUBLIC|SF_READ,0);
1874	if(!(sh.prompt=(char*)sfreserve(sfstderr,0,0)))
1875		sh.prompt = "";
1876	switch(flag)
1877	{
1878		case 1:
1879		{
1880			register int c;
1881#if defined(TIOCLBIC) && defined(LFLUSHO)
1882			if(!sh_isoption(SH_VI) && !sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS))
1883			{
1884				/*
1885				 * re-enable output in case the user has
1886				 * disabled it.  Not needed with edit mode
1887				 */
1888				int mode = LFLUSHO;
1889				ioctl(sffileno(sfstderr),TIOCLBIC,&mode);
1890			}
1891#endif	/* TIOCLBIC */
1892			cp = sh_mactry(shp,nv_getval(sh_scoped(shp,PS1NOD)));
1893			for(;c= *cp;cp++)
1894			{
1895				if(c==HIST_CHAR)
1896				{
1897					/* look at next character */
1898					c = *++cp;
1899					/* print out line number if not !! */
1900					if(c!= HIST_CHAR)
1901					{
1902						sfprintf(sfstderr,"%d", sh.hist_ptr?(int)sh.hist_ptr->histind:++cmdno);
1903					}
1904					if(c==0)
1905						goto done;
1906				}
1907				sfputc(sfstderr,c);
1908			}
1909			goto done;
1910		}
1911		case 2:
1912			cp = nv_getval(sh_scoped(shp,PS2NOD));
1913			break;
1914		case 3:
1915			cp = nv_getval(sh_scoped(shp,PS3NOD));
1916			break;
1917		default:
1918			goto done;
1919	}
1920	if(cp)
1921		sfputr(sfstderr,cp,-1);
1922done:
1923	if(*sh.prompt && (endprompt=(char*)sfreserve(sfstderr,0,0)))
1924		*endprompt = 0;
1925	sfset(sfstderr,sfflags&SF_READ|SF_SHARE|SF_PUBLIC,1);
1926	return(sfsync(sfstderr));
1927}
1928
1929/*
1930 * This discipline is inserted on write pipes to prevent SIGPIPE
1931 * from causing an infinite loop
1932 */
1933static int pipeexcept(Sfio_t* iop, int mode, void *data, Sfdisc_t* handle)
1934{
1935	NOT_USED(iop);
1936	if(mode==SF_DPOP || mode==SF_FINAL)
1937		free((void*)handle);
1938	else if(mode==SF_WRITE && errno==EINTR && sh.lastsig==SIGPIPE)
1939		return(-1);
1940	return(0);
1941}
1942
1943/*
1944 * keep track of each stream that is opened and closed
1945 */
1946static void	sftrack(Sfio_t* sp, int flag, void* data)
1947{
1948	Shell_t *shp = &sh;
1949	register int fd = sffileno(sp);
1950	register struct checkpt *pp;
1951	register int mode;
1952	int newfd = integralof(data);
1953	if(flag==SF_SETFD || flag==SF_CLOSING)
1954	{
1955		if(newfd<0)
1956			flag = SF_CLOSING;
1957		if(fdnotify)
1958			(*fdnotify)(sffileno(sp),flag==SF_CLOSING?-1:newfd);
1959	}
1960#ifdef DEBUG
1961	if(flag==SF_READ || flag==SF_WRITE)
1962	{
1963		char *z = fmtbase((long)getpid(),0,0);
1964		write(ERRIO,z,strlen(z));
1965		write(ERRIO,": ",2);
1966		write(ERRIO,"attempt to ",11);
1967		if(flag==SF_READ)
1968			write(ERRIO,"read from",9);
1969		else
1970			write(ERRIO,"write to",8);
1971		write(ERRIO," locked stream\n",15);
1972		return;
1973	}
1974#endif
1975	if((unsigned)fd >= shp->lim.open_max)
1976		return;
1977	if(sh_isstate(SH_NOTRACK))
1978		return;
1979	mode = sfset(sp,0,0);
1980	if(sp==shp->heredocs && fd < 10 && flag==SF_NEW)
1981	{
1982		fd = sfsetfd(sp,10);
1983		fcntl(fd,F_SETFD,FD_CLOEXEC);
1984	}
1985	if(fd < 3)
1986		return;
1987	if(flag==SF_NEW)
1988	{
1989		if(!shp->sftable[fd] && shp->fdstatus[fd]==IOCLOSE)
1990		{
1991			shp->sftable[fd] = sp;
1992			flag = (mode&SF_WRITE)?IOWRITE:0;
1993			if(mode&SF_READ)
1994				flag |= IOREAD;
1995			shp->fdstatus[fd] = flag;
1996			sh_iostream(shp,fd);
1997		}
1998		if((pp=(struct checkpt*)shp->jmplist) && pp->mode==SH_JMPCMD)
1999		{
2000			struct openlist *item;
2001			/*
2002			 * record open file descriptors so they can
2003			 * be closed in case a longjmp prevents
2004			 * built-ins from cleanup
2005			 */
2006			item = new_of(struct openlist, 0);
2007			item->strm = sp;
2008			item->next = pp->olist;
2009			pp->olist = item;
2010		}
2011		if(fdnotify)
2012			(*fdnotify)(-1,sffileno(sp));
2013	}
2014	else if(flag==SF_CLOSING || (flag==SF_SETFD  && newfd<=2))
2015	{
2016		shp->sftable[fd] = 0;
2017		shp->fdstatus[fd]=IOCLOSE;
2018		if(pp=(struct checkpt*)shp->jmplist)
2019		{
2020			struct openlist *item;
2021			for(item=pp->olist; item; item=item->next)
2022			{
2023				if(item->strm == sp)
2024				{
2025					item->strm = 0;
2026					break;
2027				}
2028			}
2029		}
2030	}
2031}
2032
2033struct eval
2034{
2035	Sfdisc_t	disc;
2036	char		**argv;
2037	short		slen;
2038	char		addspace;
2039};
2040
2041/*
2042 * Create a stream consisting of a space separated argv[] list
2043 */
2044
2045Sfio_t *sh_sfeval(register char *argv[])
2046{
2047	register Sfio_t *iop;
2048	register char *cp;
2049	if(argv[1])
2050		cp = "";
2051	else
2052		cp = argv[0];
2053	iop = sfopen(NIL(Sfio_t*),(char*)cp,"s");
2054	if(argv[1])
2055	{
2056		register struct eval *ep;
2057		if(!(ep = new_of(struct eval,0)))
2058			return(NIL(Sfio_t*));
2059		ep->disc = eval_disc;
2060		ep->argv = argv;
2061		ep->slen  = -1;
2062		ep->addspace  = 0;
2063		sfdisc(iop,&ep->disc);
2064	}
2065	return(iop);
2066}
2067
2068/*
2069 * This code gets called whenever an end of string is found with eval
2070 */
2071
2072static int eval_exceptf(Sfio_t *iop,int type, void *data, Sfdisc_t *handle)
2073{
2074	register struct eval *ep = (struct eval*)handle;
2075	register char	*cp;
2076	register int	len;
2077
2078	/* no more to do */
2079	if(type!=SF_READ || !(cp = ep->argv[0]))
2080	{
2081		if(type==SF_CLOSING)
2082			sfdisc(iop,SF_POPDISC);
2083		else if(ep && (type==SF_DPOP || type==SF_FINAL))
2084			free((void*)ep);
2085		return(0);
2086	}
2087
2088	if(!ep->addspace)
2089	{
2090		/* get the length of this string */
2091		ep->slen = len = strlen(cp);
2092		/* move to next string */
2093		ep->argv++;
2094	}
2095	else /* insert space between arguments */
2096	{
2097		len = 1;
2098		cp = " ";
2099	}
2100	/* insert the new string */
2101	sfsetbuf(iop,cp,len);
2102	ep->addspace = !ep->addspace;
2103	return(1);
2104}
2105
2106/*
2107 * This routine returns a stream pointer to a segment of length <size> from
2108 * the stream <sp> starting at offset <offset>
2109 * The stream can be read with the normal stream operations
2110 */
2111
2112static Sfio_t *subopen(Shell_t *shp,Sfio_t* sp, off_t offset, long size)
2113{
2114	register struct subfile *disp;
2115	if(sfseek(sp,offset,SEEK_SET) <0)
2116		return(NIL(Sfio_t*));
2117	if(!(disp = (struct subfile*)malloc(sizeof(struct subfile)+IOBSIZE+1)))
2118		return(NIL(Sfio_t*));
2119	disp->disc = sub_disc;
2120	disp->oldsp = sp;
2121	disp->offset = offset;
2122	disp->size = disp->left = size;
2123	sp = sfnew(NIL(Sfio_t*),(char*)(disp+1),IOBSIZE,shp->lim.open_max,SF_READ);
2124	sfdisc(sp,&disp->disc);
2125	return(sp);
2126}
2127
2128/*
2129 * read function for subfile discipline
2130 */
2131static ssize_t subread(Sfio_t* sp,void* buff,register size_t size,Sfdisc_t* handle)
2132{
2133	register struct subfile *disp = (struct subfile*)handle;
2134	NOT_USED(sp);
2135	if(disp->left == 0)
2136		return(0);
2137	if(size > disp->left)
2138		size = disp->left;
2139	disp->left -= size;
2140	return(sfread(disp->oldsp,buff,size));
2141}
2142
2143/*
2144 * exception handler for subfile discipline
2145 */
2146static int subexcept(Sfio_t* sp,register int mode, void *data, Sfdisc_t* handle)
2147{
2148	register struct subfile *disp = (struct subfile*)handle;
2149	if(mode==SF_CLOSING)
2150	{
2151		sfdisc(sp,SF_POPDISC);
2152		return(0);
2153	}
2154	else if(disp && (mode==SF_DPOP || mode==SF_FINAL))
2155	{
2156		free((void*)disp);
2157		return(0);
2158	}
2159#ifdef SF_ATEXIT
2160	else if (mode==SF_ATEXIT)
2161	{
2162		sfdisc(sp, SF_POPDISC);
2163		return(0);
2164	}
2165#endif
2166	else if(mode==SF_READ)
2167		return(0);
2168	return(-1);
2169}
2170
2171#define NROW    15      /* number of rows before going to multi-columns */
2172#define LBLSIZ	3	/* size of label field and interfield spacing */
2173/*
2174 * print a list of arguments in columns
2175 */
2176void	sh_menu(Sfio_t *outfile,int argn,char *argv[])
2177{
2178	Shell_t *shp = &sh;
2179	register int i,j;
2180	register char **arg;
2181	int nrow, ncol=1, ndigits=1;
2182	int fldsize, wsize = ed_window();
2183	char *cp = nv_getval(sh_scoped(shp,LINES));
2184	nrow = (cp?1+2*((int)strtol(cp, (char**)0, 10)/3):NROW);
2185	for(i=argn;i >= 10;i /= 10)
2186		ndigits++;
2187	if(argn < nrow)
2188	{
2189		nrow = argn;
2190		goto skip;
2191	}
2192	i = 0;
2193	for(arg=argv; *arg;arg++)
2194	{
2195		if((j=strlen(*arg)) > i)
2196			i = j;
2197	}
2198	i += (ndigits+LBLSIZ);
2199	if(i < wsize)
2200		ncol = wsize/i;
2201	if(argn > nrow*ncol)
2202	{
2203		nrow = 1 + (argn-1)/ncol;
2204	}
2205	else
2206	{
2207		ncol = 1 + (argn-1)/nrow;
2208		nrow = 1 + (argn-1)/ncol;
2209	}
2210skip:
2211	fldsize = (wsize/ncol)-(ndigits+LBLSIZ);
2212	for(i=0;i<nrow;i++)
2213	{
2214		if(sh.trapnote&SH_SIGSET)
2215			return;
2216		j = i;
2217		while(1)
2218		{
2219			arg = argv+j;
2220			sfprintf(outfile,"%*d) %s",ndigits,j+1,*arg);
2221			j += nrow;
2222			if(j >= argn)
2223				break;
2224			sfnputc(outfile,' ',fldsize-strlen(*arg));
2225		}
2226		sfputc(outfile,'\n');
2227	}
2228}
2229
2230#undef read
2231/*
2232 * shell version of read() for user added builtins
2233 */
2234ssize_t sh_read(register int fd, void* buff, size_t n)
2235{
2236	register Sfio_t *sp;
2237	if(sp=sh.sftable[fd])
2238		return(sfread(sp,buff,n));
2239	else
2240		return(read(fd,buff,n));
2241}
2242
2243#undef write
2244/*
2245 * shell version of write() for user added builtins
2246 */
2247ssize_t sh_write(register int fd, const void* buff, size_t n)
2248{
2249	register Sfio_t *sp;
2250	if(sp=sh.sftable[fd])
2251		return(sfwrite(sp,buff,n));
2252	else
2253		return(write(fd,buff,n));
2254}
2255
2256#undef lseek
2257/*
2258 * shell version of lseek() for user added builtins
2259 */
2260off_t sh_seek(register int fd, off_t offset, int whence)
2261{
2262	register Sfio_t *sp;
2263	if((sp=sh.sftable[fd]) && (sfset(sp,0,0)&(SF_READ|SF_WRITE)))
2264		return(sfseek(sp,offset,whence));
2265	else
2266		return(lseek(fd,offset,whence));
2267}
2268
2269#undef dup
2270int sh_dup(register int old)
2271{
2272	register int fd = dup(old);
2273	if(fd>=0)
2274	{
2275		if(sh.fdstatus[old] == IOCLOSE)
2276			sh.fdstatus[old] = 0;
2277		sh.fdstatus[fd] = (sh.fdstatus[old]&~IOCLEX);
2278		if(fdnotify)
2279			(*fdnotify)(old,fd);
2280	}
2281	return(fd);
2282}
2283
2284#undef fcntl
2285int sh_fcntl(register int fd, int op, ...)
2286{
2287	int newfd, arg;
2288	va_list		ap;
2289	va_start(ap, op);
2290	arg =  va_arg(ap, int) ;
2291	va_end(ap);
2292	newfd = fcntl(fd,op,arg);
2293	if(newfd>=0) switch(op)
2294	{
2295	    case F_DUPFD:
2296		if(sh.fdstatus[fd] == IOCLOSE)
2297			sh.fdstatus[fd] = 0;
2298		sh.fdstatus[newfd] = (sh.fdstatus[fd]&~IOCLEX);
2299		if(fdnotify)
2300			(*fdnotify)(fd,newfd);
2301		break;
2302	    case F_SETFD:
2303		if(sh.fdstatus[fd] == IOCLOSE)
2304			sh.fdstatus[fd] = 0;
2305		if(arg&FD_CLOEXEC)
2306			sh.fdstatus[fd] |= IOCLEX;
2307		else
2308			sh.fdstatus[fd] &= ~IOCLEX;
2309	}
2310	return(newfd);
2311}
2312
2313#undef umask
2314mode_t	sh_umask(mode_t m)
2315{
2316	sh.mask = m;
2317	return(umask(m));
2318}
2319
2320/*
2321 * give file descriptor <fd> and <mode>, return an iostream pointer
2322 * <mode> must be SF_READ or SF_WRITE
2323 * <fd> must be a non-negative number ofr SH_IOCOPROCESS or SH_IOHISTFILE.
2324 * returns NULL on failure and may set errno.
2325 */
2326
2327Sfio_t *sh_iogetiop(int fd, int mode)
2328{
2329	Shell_t	*shp = &sh;
2330	int n;
2331	Sfio_t *iop=0;
2332	if(mode!=SF_READ && mode!=SF_WRITE)
2333	{
2334		errno = EINVAL;
2335		return(iop);
2336	}
2337	switch(fd)
2338	{
2339	    case SH_IOHISTFILE:
2340		if(!sh_histinit((void*)shp))
2341			return(iop);
2342		fd = sffileno(shp->hist_ptr->histfp);
2343		break;
2344	    case SH_IOCOPROCESS:
2345		if(mode==SF_WRITE)
2346			fd = shp->coutpipe;
2347		else
2348			fd = shp->cpipe[0];
2349		break;
2350	    default:
2351		if(fd<0 || fd >= shp->lim.open_max)
2352			fd = -1;
2353	}
2354	if(fd<0)
2355	{
2356		errno = EBADF;
2357		return(iop);
2358	}
2359	if(!(n=shp->fdstatus[fd]))
2360		n = sh_iocheckfd(shp,fd);
2361	if(mode==SF_WRITE && !(n&IOWRITE))
2362		return(iop);
2363	if(mode==SF_READ && !(n&IOREAD))
2364		return(iop);
2365	if(!(iop = shp->sftable[fd]))
2366		iop=sh_iostream(shp,fd);
2367	return(iop);
2368}
2369
2370typedef int (*Notify_f)(int,int);
2371
2372Notify_f    sh_fdnotify(Notify_f notify)
2373{
2374	Notify_f old;
2375        old = fdnotify;
2376        fdnotify = notify;
2377        return(old);
2378}
2379
2380Sfio_t	*sh_fd2sfio(int fd)
2381{
2382	Shell_t	*shp = &sh;
2383	register int status;
2384	Sfio_t *sp = sh.sftable[fd];
2385	if(!sp  && (status = sh_iocheckfd(shp,fd))!=IOCLOSE)
2386	{
2387		register int flags=0;
2388		if(status&IOREAD)
2389			flags |= SF_READ;
2390		if(status&IOWRITE)
2391			flags |= SF_WRITE;
2392		sp = sfnew(NULL, NULL, -1, fd,flags);
2393		sh.sftable[fd] = sp;
2394	}
2395	return(sp);
2396}
2397
2398Sfio_t *sh_pathopen(const char *cp)
2399{
2400	Shell_t *shp = &sh;
2401	int n;
2402#ifdef PATH_BFPATH
2403	if((n=path_open(cp,path_get(cp))) < 0)
2404		n = path_open(cp,(Pathcomp_t*)0);
2405#else
2406	if((n=path_open(cp,path_get(cp))) < 0)
2407		n = path_open(cp,"");
2408#endif
2409	if(n < 0)
2410		errormsg(SH_DICT,ERROR_system(1),e_open,cp);
2411	return(sh_iostream(shp,n));
2412}
2413