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