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