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