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