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