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