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