xref: /onnv-gate/usr/src/lib/libshell/common/sh/io.c (revision 8462)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1982-2008 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
7*8462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                  David Korn <dgk@research.att.com>                   *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin 
224887Schin /*
234887Schin  * Input/output file processing
244887Schin  *
254887Schin  *   David Korn
264887Schin  *   AT&T Labs
274887Schin  *
284887Schin  */
294887Schin 
304887Schin #include	"defs.h"
314887Schin #include	<fcin.h>
324887Schin #include	<ls.h>
334887Schin #include	<stdarg.h>
344887Schin #include	<ctype.h>
354887Schin #include	<regex.h>
364887Schin #include	"variables.h"
374887Schin #include	"path.h"
384887Schin #include	"io.h"
394887Schin #include	"jobs.h"
404887Schin #include	"shnodes.h"
414887Schin #include	"history.h"
424887Schin #include	"edit.h"
434887Schin #include	"timeout.h"
444887Schin #include	"FEATURE/externs"
454887Schin #include	"FEATURE/dynamic"
464887Schin #include	"FEATURE/poll"
474887Schin 
484887Schin #ifdef	FNDELAY
494887Schin #   ifdef EAGAIN
504887Schin #	if EAGAIN!=EWOULDBLOCK
514887Schin #	    undef EAGAIN
524887Schin #	    define EAGAIN       EWOULDBLOCK
534887Schin #	endif
544887Schin #   else
554887Schin #	define EAGAIN   EWOULDBLOCK
564887Schin #   endif /* EAGAIN */
574887Schin #   ifndef O_NONBLOCK
584887Schin #	define O_NONBLOCK	FNDELAY
594887Schin #   endif /* !O_NONBLOCK */
604887Schin #endif	/* FNDELAY */
614887Schin 
624887Schin #ifndef O_SERVICE
634887Schin #   define O_SERVICE	O_NOCTTY
644887Schin #endif
654887Schin 
664887Schin #define RW_ALL	(S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH)
674887Schin 
684887Schin static void	*timeout;
694887Schin static int	(*fdnotify)(int,int);
704887Schin 
714887Schin #if defined(_lib_socket) && defined(_sys_socket) && defined(_hdr_netinet_in)
724887Schin #   include <sys/socket.h>
734887Schin #   include <netdb.h>
744887Schin #   include <netinet/in.h>
754887Schin #   if !defined(htons) && !_lib_htons
764887Schin #      define htons(x)	(x)
774887Schin #   endif
784887Schin #   if !defined(htonl) && !_lib_htonl
794887Schin #      define htonl(x)	(x)
804887Schin #   endif
814887Schin #   if _pipe_socketpair
82*8462SApril.Chin@Sun.COM #      ifndef SHUT_RD
83*8462SApril.Chin@Sun.COM #         define SHUT_RD         0
84*8462SApril.Chin@Sun.COM #      endif
85*8462SApril.Chin@Sun.COM #      ifndef SHUT_WR
86*8462SApril.Chin@Sun.COM #         define SHUT_WR         1
87*8462SApril.Chin@Sun.COM #      endif
884887Schin #      if _socketpair_shutdown_mode
89*8462SApril.Chin@Sun.COM #         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)
904887Schin #      else
91*8462SApril.Chin@Sun.COM #         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)
924887Schin #      endif
934887Schin #   endif
944887Schin 
954887Schin #if !_lib_getaddrinfo
964887Schin 
974887Schin #undef	EAI_SYSTEM
984887Schin 
994887Schin #define EAI_SYSTEM		1
1004887Schin 
1014887Schin #undef	addrinfo
1024887Schin #undef	getaddrinfo
1034887Schin #undef	freeaddrinfo
1044887Schin 
1054887Schin #define addrinfo		local_addrinfo
1064887Schin #define getaddrinfo		local_getaddrinfo
1074887Schin #define freeaddrinfo		local_freeaddrinfo
1084887Schin 
1094887Schin struct addrinfo
1104887Schin {
1114887Schin         int			ai_flags;
1124887Schin         int			ai_family;
1134887Schin         int			ai_socktype;
1144887Schin         int			ai_protocol;
1154887Schin         socklen_t		ai_addrlen;
1164887Schin         struct sockaddr*	ai_addr;
1174887Schin         struct addrinfo*	ai_next;
1184887Schin };
1194887Schin 
1204887Schin static int
1214887Schin getaddrinfo(const char* node, const char* service, const struct addrinfo* hint, struct addrinfo **addr)
1224887Schin {
1234887Schin 	unsigned long	    	ip_addr = 0;
1244887Schin 	unsigned short	    	ip_port = 0;
1254887Schin 	struct addrinfo*	ap;
1264887Schin 	struct hostent*		hp;
1274887Schin 	struct sockaddr_in*	ip;
1284887Schin 	char*			prot;
1294887Schin 	long			n;
1304887Schin 
1314887Schin 	if (!(hp = gethostbyname(node)) || hp->h_addrtype!=AF_INET || hp->h_length>sizeof(struct in_addr))
1324887Schin 	{
1334887Schin 		errno = EADDRNOTAVAIL;
1344887Schin 		return EAI_SYSTEM;
1354887Schin 	}
1364887Schin 	ip_addr = (unsigned long)((struct in_addr*)hp->h_addr)->s_addr;
1374887Schin 	if ((n = strtol(service, &prot, 10)) > 0 && n <= USHRT_MAX && !*prot)
1384887Schin 		ip_port = htons((unsigned short)n);
1394887Schin 	else
1404887Schin 	{
1414887Schin 		struct servent*	sp;
1424887Schin 		const char*	protocol = 0;
1434887Schin 
1444887Schin 		if (hint)
1454887Schin 			switch (hint->ai_socktype)
1464887Schin 			{
1474887Schin 			case SOCK_STREAM:
1484887Schin 				switch (hint->ai_protocol)
1494887Schin 				{
1504887Schin 				case 0:
1514887Schin 					protocol = "tcp";
1524887Schin 					break;
1534887Schin #ifdef IPPROTO_SCTP
1544887Schin 				case IPPROTO_SCTP:
1554887Schin 					protocol = "sctp";
1564887Schin 					break;
1574887Schin #endif
1584887Schin 				}
1594887Schin 				break;
1604887Schin 			case SOCK_DGRAM:
1614887Schin 				protocol = "udp";
1624887Schin 				break;
1634887Schin 			}
1644887Schin 		if (!protocol)
1654887Schin 		{
1664887Schin 			errno =  EPROTONOSUPPORT;
1674887Schin 			return 1;
1684887Schin 		}
1694887Schin 		if (sp = getservbyname(service, protocol))
1704887Schin 			ip_port = sp->s_port;
1714887Schin 	}
1724887Schin 	if (!ip_port)
1734887Schin 	{
1744887Schin 		errno = EADDRNOTAVAIL;
1754887Schin 		return EAI_SYSTEM;
1764887Schin 	}
1774887Schin 	if (!(ap = newof(0, struct addrinfo, 1, sizeof(struct sockaddr_in))))
1784887Schin 		return EAI_SYSTEM;
1794887Schin 	if (hint)
1804887Schin 		*ap = *hint;
1814887Schin 	ap->ai_family = hp->h_addrtype;
1824887Schin 	ap->ai_addrlen 	= sizeof(struct sockaddr_in);
1834887Schin 	ap->ai_addr = (struct sockaddr *)(ap+1);
1844887Schin 	ip = (struct sockaddr_in *)ap->ai_addr;
1854887Schin 	ip->sin_family = AF_INET;
1864887Schin 	ip->sin_port = ip_port;
1874887Schin 	ip->sin_addr.s_addr = ip_addr;
1884887Schin 	*addr = ap;
1894887Schin 	return 0;
1904887Schin }
1914887Schin 
1924887Schin static void
1934887Schin freeaddrinfo(struct addrinfo* ap)
1944887Schin {
1954887Schin 	if (ap)
1964887Schin 		free(ap);
1974887Schin }
1984887Schin 
1994887Schin #endif
2004887Schin 
2014887Schin /*
2024887Schin  * return <protocol>/<host>/<service> fd
2034887Schin  */
2044887Schin 
2054887Schin typedef int (*Inetintr_f)(struct addrinfo*, void*);
2064887Schin 
2074887Schin static int
2084887Schin inetopen(const char* path, int server, Inetintr_f onintr, void* handle)
2094887Schin {
2104887Schin 	register char*		s;
2114887Schin 	register char*		t;
2124887Schin 	int			fd;
2134887Schin 	int			oerrno;
2144887Schin 	struct addrinfo		hint;
2154887Schin 	struct addrinfo*	addr;
2164887Schin 	struct addrinfo*	p;
2174887Schin 
2184887Schin 	memset(&hint, 0, sizeof(hint));
2194887Schin 	hint.ai_family = PF_UNSPEC;
2204887Schin 	switch (path[0])
2214887Schin 	{
2224887Schin #ifdef IPPROTO_SCTP
2234887Schin 	case 's':
2244887Schin 		if (path[1]!='c' || path[2]!='t' || path[3]!='p' || path[4]!='/')
2254887Schin 		{
2264887Schin 			errno = ENOTDIR;
2274887Schin 			return -1;
2284887Schin 		}
2294887Schin 		hint.ai_socktype = SOCK_STREAM;
2304887Schin 		hint.ai_protocol = IPPROTO_SCTP;
2314887Schin 		path += 5;
2324887Schin 		break;
2334887Schin #endif
2344887Schin 	case 't':
2354887Schin 		if (path[1]!='c' || path[2]!='p' || path[3]!='/')
2364887Schin 		{
2374887Schin 			errno = ENOTDIR;
2384887Schin 			return -1;
2394887Schin 		}
2404887Schin 		hint.ai_socktype = SOCK_STREAM;
2414887Schin 		path += 4;
2424887Schin 		break;
2434887Schin 	case 'u':
2444887Schin 		if (path[1]!='d' || path[2]!='p' || path[3]!='/')
2454887Schin 		{
2464887Schin 			errno = ENOTDIR;
2474887Schin 			return -1;
2484887Schin 		}
2494887Schin 		hint.ai_socktype = SOCK_DGRAM;
2504887Schin 		path += 4;
2514887Schin 		break;
2524887Schin 	default:
2534887Schin 		errno = ENOTDIR;
2544887Schin 		return -1;
2554887Schin 	}
2564887Schin 	if (!(s = strdup(path)))
2574887Schin 		return -1;
2584887Schin 	if (t = strchr(s, '/'))
2594887Schin 	{
2604887Schin 		*t++ = 0;
2614887Schin 		if (streq(s, "local"))
2624887Schin 			s = "localhost";
2634887Schin 		fd = getaddrinfo(s, t, &hint, &addr);
2644887Schin 	}
2654887Schin 	else
2664887Schin 		fd = -1;
2674887Schin 	free(s);
2684887Schin 	if (fd)
2694887Schin 	{
2704887Schin 		if (fd != EAI_SYSTEM)
2714887Schin 			errno = ENOTDIR;
2724887Schin 		return -1;
2734887Schin 	}
2744887Schin 	oerrno = errno;
2754887Schin 	errno = 0;
2764887Schin 	fd = -1;
2774887Schin 	for (p = addr; p; p = p->ai_next)
2784887Schin 	{
2794887Schin 		/*
2804887Schin 		 * some api's don't take the hint
2814887Schin 		 */
2824887Schin 
2834887Schin 		if (!p->ai_protocol)
2844887Schin 			p->ai_protocol = hint.ai_protocol;
2854887Schin 		if (!p->ai_socktype)
2864887Schin 			p->ai_socktype = hint.ai_socktype;
2874887Schin 		while ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) >= 0)
2884887Schin 		{
2894887Schin 			if (server && !bind(fd, p->ai_addr, p->ai_addrlen) && !listen(fd, 5) || !server && !connect(fd, p->ai_addr, p->ai_addrlen))
2904887Schin 				goto done;
2914887Schin 			close(fd);
2924887Schin 			fd = -1;
2934887Schin 			if (errno != EINTR || !onintr)
2944887Schin 				break;
2954887Schin 			if ((*onintr)(addr, handle))
2964887Schin 				return -1;
2974887Schin 		}
2984887Schin 	}
2994887Schin  done:
3004887Schin 	freeaddrinfo(addr);
3014887Schin 	if (fd >= 0)
3024887Schin 		errno = oerrno;
3034887Schin 	return fd;
3044887Schin }
3054887Schin 
3064887Schin #else
3074887Schin 
3084887Schin #undef	O_SERVICE
3094887Schin 
3104887Schin #endif
3114887Schin 
3124887Schin struct fdsave
3134887Schin {
3144887Schin 	int	orig_fd;	/* original file descriptor */
3154887Schin 	int	save_fd;	/* saved file descriptor */
3164887Schin 	int	subshell;	/* saved for subshell */
317*8462SApril.Chin@Sun.COM 	char	*tname;		/* name used with >; */
3184887Schin };
3194887Schin 
3204887Schin static int  	subexcept(Sfio_t*, int, void*, Sfdisc_t*);
3214887Schin static int  	eval_exceptf(Sfio_t*, int, void*, Sfdisc_t*);
3224887Schin static int  	slowexcept(Sfio_t*, int, void*, Sfdisc_t*);
3234887Schin static int	pipeexcept(Sfio_t*, int, void*, Sfdisc_t*);
3244887Schin static ssize_t	piperead(Sfio_t*, void*, size_t, Sfdisc_t*);
3254887Schin static ssize_t	slowread(Sfio_t*, void*, size_t, Sfdisc_t*);
3264887Schin static ssize_t	subread(Sfio_t*, void*, size_t, Sfdisc_t*);
3274887Schin static ssize_t	tee_write(Sfio_t*,const void*,size_t,Sfdisc_t*);
3284887Schin static int	io_prompt(Sfio_t*,int);
329*8462SApril.Chin@Sun.COM static int	io_heredoc(Shell_t*,register struct ionod*, const char*, int);
330*8462SApril.Chin@Sun.COM static void	sftrack(Sfio_t*,int,void*);
3314887Schin static const Sfdisc_t eval_disc = { NULL, NULL, NULL, eval_exceptf, NULL};
3324887Schin static Sfdisc_t tee_disc = {NULL,tee_write,NULL,NULL,NULL};
333*8462SApril.Chin@Sun.COM static Sfio_t *subopen(Shell_t *,Sfio_t*, off_t, long);
3344887Schin static const Sfdisc_t sub_disc = { subread, 0, 0, subexcept, 0 };
3354887Schin 
3364887Schin struct subfile
3374887Schin {
3384887Schin 	Sfdisc_t	disc;
3394887Schin 	Sfio_t		*oldsp;
3404887Schin 	off_t		offset;
3414887Schin 	long		size;
3424887Schin 	long		left;
3434887Schin };
3444887Schin 
3454887Schin struct Eof
3464887Schin {
3474887Schin 	Namfun_t	hdr;
3484887Schin 	int		fd;
3494887Schin };
3504887Schin 
3514887Schin static Sfdouble_t nget_cur_eof(register Namval_t* np, Namfun_t *fp)
3524887Schin {
3534887Schin 	struct Eof *ep = (struct Eof*)fp;
3544887Schin 	Sfoff_t end, cur =lseek(ep->fd, (Sfoff_t)0, SEEK_CUR);
3554887Schin 	if(*np->nvname=='C')
3564887Schin 	        return((Sfdouble_t)cur);
3574887Schin 	if(cur<0)
3584887Schin 		return((Sfdouble_t)-1);
3594887Schin 	end =lseek(ep->fd, (Sfoff_t)0, SEEK_END);
3604887Schin 	lseek(ep->fd, (Sfoff_t)0, SEEK_CUR);
3614887Schin         return((Sfdouble_t)end);
3624887Schin }
3634887Schin 
3644887Schin static const Namdisc_t EOF_disc	= { sizeof(struct Eof), 0, 0, nget_cur_eof};
3654887Schin 
3664887Schin #define	MATCH_BUFF	(64*1024)
3674887Schin struct Match
3684887Schin {
3694887Schin 	Sfoff_t	offset;
3704887Schin 	char	*base;
3714887Schin };
3724887Schin 
3734887Schin static int matchf(void *handle, char *ptr, size_t size)
3744887Schin {
3754887Schin 	struct Match *mp = (struct Match*)handle;
3764887Schin 	mp->offset += (ptr-mp->base);
3774887Schin 	return(1);
3784887Schin }
3794887Schin 
3804887Schin 
3814887Schin static struct fdsave	*filemap;
3824887Schin static short		filemapsize;
3834887Schin 
3844887Schin /* ======== input output and file copying ======== */
3854887Schin 
386*8462SApril.Chin@Sun.COM void sh_ioinit(Shell_t *shp)
3874887Schin {
3884887Schin 	register int n;
3894887Schin 	filemapsize = 8;
390*8462SApril.Chin@Sun.COM 	filemap = (struct fdsave*)malloc(filemapsize*sizeof(struct fdsave));
3914887Schin #if SHOPT_FASTPIPE
392*8462SApril.Chin@Sun.COM 	n = shp->lim.open_max+2;
3934887Schin #else
394*8462SApril.Chin@Sun.COM 	n = shp->lim.open_max;
3954887Schin #endif /* SHOPT_FASTPIPE */
396*8462SApril.Chin@Sun.COM 	shp->fdstatus = (unsigned char*)malloc((unsigned)n);
397*8462SApril.Chin@Sun.COM 	memset((char*)shp->fdstatus,0,n);
398*8462SApril.Chin@Sun.COM 	shp->fdptrs = (int**)malloc(n*sizeof(int*));
399*8462SApril.Chin@Sun.COM 	memset((char*)shp->fdptrs,0,n*sizeof(int*));
400*8462SApril.Chin@Sun.COM 	shp->sftable = (Sfio_t**)malloc(n*sizeof(Sfio_t*));
401*8462SApril.Chin@Sun.COM 	memset((char*)shp->sftable,0,n*sizeof(Sfio_t*));
402*8462SApril.Chin@Sun.COM 	shp->sftable[0] = sfstdin;
403*8462SApril.Chin@Sun.COM 	shp->sftable[1] = sfstdout;
404*8462SApril.Chin@Sun.COM 	shp->sftable[2] = sfstderr;
4054887Schin 	sfnotify(sftrack);
406*8462SApril.Chin@Sun.COM 	sh_iostream(shp,0);
4074887Schin 	/* all write steams are in the same pool and share outbuff */
408*8462SApril.Chin@Sun.COM 	shp->outpool = sfopen(NIL(Sfio_t*),NIL(char*),"sw");  /* pool identifier */
409*8462SApril.Chin@Sun.COM 	shp->outbuff = (char*)malloc(IOBSIZE);
410*8462SApril.Chin@Sun.COM 	shp->errbuff = (char*)malloc(IOBSIZE/4);
411*8462SApril.Chin@Sun.COM 	sfsetbuf(sfstderr,shp->errbuff,IOBSIZE/4);
412*8462SApril.Chin@Sun.COM 	sfsetbuf(sfstdout,shp->outbuff,IOBSIZE);
413*8462SApril.Chin@Sun.COM 	sfpool(sfstdout,shp->outpool,SF_WRITE);
414*8462SApril.Chin@Sun.COM 	sfpool(sfstderr,shp->outpool,SF_WRITE);
4154887Schin 	sfset(sfstdout,SF_LINE,0);
416*8462SApril.Chin@Sun.COM 	sfset(sfstderr,SF_LINE,0);
417*8462SApril.Chin@Sun.COM 	sfset(sfstdin,SF_SHARE|SF_PUBLIC,1);
418*8462SApril.Chin@Sun.COM }
419*8462SApril.Chin@Sun.COM 
420*8462SApril.Chin@Sun.COM /*
421*8462SApril.Chin@Sun.COM  *  Handle output stream exceptions
422*8462SApril.Chin@Sun.COM  */
423*8462SApril.Chin@Sun.COM static int outexcept(register Sfio_t *iop,int type,void *data,Sfdisc_t *handle)
424*8462SApril.Chin@Sun.COM {
425*8462SApril.Chin@Sun.COM 	static int	active = 0;
426*8462SApril.Chin@Sun.COM 
427*8462SApril.Chin@Sun.COM 	NOT_USED(handle);
428*8462SApril.Chin@Sun.COM 	if(type==SF_DPOP || type==SF_FINAL)
429*8462SApril.Chin@Sun.COM 		free((void*)handle);
430*8462SApril.Chin@Sun.COM 	else if(type==SF_WRITE && (*(ssize_t*)data)<0 && sffileno(iop)!=2)
431*8462SApril.Chin@Sun.COM 		switch (errno)
432*8462SApril.Chin@Sun.COM 		{
433*8462SApril.Chin@Sun.COM 		case EINTR:
434*8462SApril.Chin@Sun.COM 		case EPIPE:
435*8462SApril.Chin@Sun.COM #ifdef ECONNRESET
436*8462SApril.Chin@Sun.COM 		case ECONNRESET:
437*8462SApril.Chin@Sun.COM #endif
438*8462SApril.Chin@Sun.COM #ifdef ESHUTDOWN
439*8462SApril.Chin@Sun.COM 		case ESHUTDOWN:
440*8462SApril.Chin@Sun.COM #endif
441*8462SApril.Chin@Sun.COM 			break;
442*8462SApril.Chin@Sun.COM 		default:
443*8462SApril.Chin@Sun.COM 			if(!active)
444*8462SApril.Chin@Sun.COM 			{
445*8462SApril.Chin@Sun.COM 				int mode = ((struct checkpt*)sh.jmplist)->mode;
446*8462SApril.Chin@Sun.COM 				int save = errno;
447*8462SApril.Chin@Sun.COM 				active = 1;
448*8462SApril.Chin@Sun.COM 				((struct checkpt*)sh.jmplist)->mode = 0;
449*8462SApril.Chin@Sun.COM 				sfpurge(iop);
450*8462SApril.Chin@Sun.COM 				sfpool(iop,NIL(Sfio_t*),SF_WRITE);
451*8462SApril.Chin@Sun.COM 				errno = save;
452*8462SApril.Chin@Sun.COM 				errormsg(SH_DICT,ERROR_system(1),e_badwrite,sffileno(iop));
453*8462SApril.Chin@Sun.COM 				active = 0;
454*8462SApril.Chin@Sun.COM 				((struct checkpt*)sh.jmplist)->mode = mode;
455*8462SApril.Chin@Sun.COM 				sh_exit(1);
456*8462SApril.Chin@Sun.COM 			}
457*8462SApril.Chin@Sun.COM 			return(-1);
458*8462SApril.Chin@Sun.COM 		}
459*8462SApril.Chin@Sun.COM 	return(0);
4604887Schin }
4614887Schin 
4624887Schin /*
4634887Schin  * create or initialize a stream corresponding to descriptor <fd>
4644887Schin  * a buffer with room for a sentinal is allocated for a read stream.
4654887Schin  * A discipline is inserted when read stream is a tty or a pipe
4664887Schin  * For output streams, the buffer is set to sh.output and put into
4674887Schin  * the sh.outpool synchronization pool
4684887Schin  */
469*8462SApril.Chin@Sun.COM Sfio_t *sh_iostream(Shell_t *shp, register int fd)
4704887Schin {
4714887Schin 	register Sfio_t *iop;
472*8462SApril.Chin@Sun.COM 	register int status = sh_iocheckfd(shp,fd);
4734887Schin 	register int flags = SF_WRITE;
4744887Schin 	char *bp;
475*8462SApril.Chin@Sun.COM 	Sfdisc_t *dp;
4764887Schin #if SHOPT_FASTPIPE
477*8462SApril.Chin@Sun.COM 	if(fd>=shp->lim.open_max)
478*8462SApril.Chin@Sun.COM 		return(shp->sftable[fd]);
4794887Schin #endif /* SHOPT_FASTPIPE */
4804887Schin 	if(status==IOCLOSE)
4814887Schin 	{
4824887Schin 		switch(fd)
4834887Schin 		{
4844887Schin 		    case 0:
4854887Schin 			return(sfstdin);
4864887Schin 		    case 1:
4874887Schin 			return(sfstdout);
4884887Schin 		    case 2:
4894887Schin 			return(sfstderr);
4904887Schin 		}
4914887Schin 		return(NIL(Sfio_t*));
4924887Schin 	}
4934887Schin 	if(status&IOREAD)
4944887Schin 	{
4954887Schin 		if(!(bp = (char *)malloc(IOBSIZE+1)))
4964887Schin 			return(NIL(Sfio_t*));
4974887Schin 		flags |= SF_READ;
4984887Schin 		if(!(status&IOWRITE))
4994887Schin 			flags &= ~SF_WRITE;
5004887Schin 	}
5014887Schin 	else
502*8462SApril.Chin@Sun.COM 		bp = shp->outbuff;
5034887Schin 	if(status&IODUP)
5044887Schin 		flags |= SF_SHARE|SF_PUBLIC;
505*8462SApril.Chin@Sun.COM 	if((iop = shp->sftable[fd]) && sffileno(iop)>=0)
5064887Schin 		sfsetbuf(iop, bp, IOBSIZE);
5074887Schin 	else if(!(iop=sfnew((fd<=2?iop:0),bp,IOBSIZE,fd,flags)))
5084887Schin 		return(NIL(Sfio_t*));
509*8462SApril.Chin@Sun.COM 	dp = newof(0,Sfdisc_t,1,0);
5104887Schin 	if(status&IOREAD)
5114887Schin 	{
5124887Schin 		sfset(iop,SF_MALLOC,1);
513*8462SApril.Chin@Sun.COM 		if(!(status&IOWRITE))
514*8462SApril.Chin@Sun.COM 			sfset(iop,SF_IOCHECK,1);
515*8462SApril.Chin@Sun.COM 		dp->exceptf = slowexcept;
516*8462SApril.Chin@Sun.COM 		if(status&IOTTY)
517*8462SApril.Chin@Sun.COM 			dp->readf = slowread;
518*8462SApril.Chin@Sun.COM 		else if(status&IONOSEEK)
5194887Schin 		{
520*8462SApril.Chin@Sun.COM 			dp->readf = piperead;
521*8462SApril.Chin@Sun.COM 			sfset(iop, SF_IOINTR,1);
5224887Schin 		}
523*8462SApril.Chin@Sun.COM 		else
524*8462SApril.Chin@Sun.COM 			dp->readf = 0;
525*8462SApril.Chin@Sun.COM 		dp->seekf = 0;
526*8462SApril.Chin@Sun.COM 		dp->writef = 0;
5274887Schin 	}
5284887Schin 	else
529*8462SApril.Chin@Sun.COM 	{
530*8462SApril.Chin@Sun.COM 		dp->exceptf = outexcept;
531*8462SApril.Chin@Sun.COM 		sfpool(iop,shp->outpool,SF_WRITE);
532*8462SApril.Chin@Sun.COM 	}
533*8462SApril.Chin@Sun.COM 	sfdisc(iop,dp);
534*8462SApril.Chin@Sun.COM 	shp->sftable[fd] = iop;
5354887Schin 	return(iop);
5364887Schin }
5374887Schin 
5384887Schin /*
5394887Schin  * preserve the file descriptor or stream by moving it
5404887Schin  */
541*8462SApril.Chin@Sun.COM static void io_preserve(Shell_t* shp, register Sfio_t *sp, register int f2)
5424887Schin {
5434887Schin 	register int fd;
5444887Schin 	if(sp)
5454887Schin 		fd = sfsetfd(sp,10);
5464887Schin 	else
5474887Schin 		fd = sh_fcntl(f2,F_DUPFD,10);
548*8462SApril.Chin@Sun.COM 	if(f2==shp->infd)
549*8462SApril.Chin@Sun.COM 		shp->infd = fd;
5504887Schin 	if(fd<0)
5514887Schin 		errormsg(SH_DICT,ERROR_system(1),e_toomany);
552*8462SApril.Chin@Sun.COM 	if(shp->fdptrs[fd]=shp->fdptrs[f2])
5534887Schin 	{
5544887Schin 		if(f2==job.fd)
5554887Schin 			job.fd=fd;
556*8462SApril.Chin@Sun.COM 		*shp->fdptrs[fd] = fd;
557*8462SApril.Chin@Sun.COM 		shp->fdptrs[f2] = 0;
5584887Schin 	}
559*8462SApril.Chin@Sun.COM 	shp->sftable[fd] = sp;
560*8462SApril.Chin@Sun.COM 	shp->fdstatus[fd] = shp->fdstatus[f2];
5614887Schin 	if(fcntl(f2,F_GETFD,0)&1)
5624887Schin 	{
5634887Schin 		fcntl(fd,F_SETFD,FD_CLOEXEC);
564*8462SApril.Chin@Sun.COM 		shp->fdstatus[fd] |= IOCLEX;
5654887Schin 	}
566*8462SApril.Chin@Sun.COM 	shp->sftable[f2] = 0;
5674887Schin }
5684887Schin 
5694887Schin /*
5704887Schin  * Given a file descriptor <f1>, move it to a file descriptor number <f2>
5714887Schin  * If <f2> is needed move it, otherwise it is closed first.
5724887Schin  * The original stream <f1> is closed.
5734887Schin  *  The new file descriptor <f2> is returned;
5744887Schin  */
575*8462SApril.Chin@Sun.COM int sh_iorenumber(Shell_t *shp, register int f1,register int f2)
5764887Schin {
577*8462SApril.Chin@Sun.COM 	register Sfio_t *sp = shp->sftable[f2];
5784887Schin 	if(f1!=f2)
5794887Schin 	{
5804887Schin 		/* see whether file descriptor is in use */
5814887Schin 		if(sh_inuse(f2) || (f2>2 && sp))
5824887Schin 		{
583*8462SApril.Chin@Sun.COM 			if(!(shp->inuse_bits&(1<<f2)))
584*8462SApril.Chin@Sun.COM 				io_preserve(shp,sp,f2);
5854887Schin 			sp = 0;
5864887Schin 		}
5874887Schin 		else if(f2==0)
588*8462SApril.Chin@Sun.COM 			shp->st.ioset = 1;
5894887Schin 		sh_close(f2);
5904887Schin 		if(f2<=2 && sp)
5914887Schin 		{
592*8462SApril.Chin@Sun.COM 			register Sfio_t *spnew = sh_iostream(shp,f1);
593*8462SApril.Chin@Sun.COM 			shp->fdstatus[f2] = (shp->fdstatus[f1]&~IOCLEX);
5944887Schin 			sfsetfd(spnew,f2);
5954887Schin 			sfswap(spnew,sp);
5964887Schin 			sfset(sp,SF_SHARE|SF_PUBLIC,1);
5974887Schin 		}
5984887Schin 		else
5994887Schin 		{
600*8462SApril.Chin@Sun.COM 			shp->fdstatus[f2] = (shp->fdstatus[f1]&~IOCLEX);
6014887Schin 			if((f2 = sh_fcntl(f1,F_DUPFD, f2)) < 0)
6024887Schin 				errormsg(SH_DICT,ERROR_system(1),e_file+4);
6034887Schin 			else if(f2 <= 2)
604*8462SApril.Chin@Sun.COM 				sh_iostream(shp,f2);
6054887Schin 		}
6064887Schin 		if(sp)
607*8462SApril.Chin@Sun.COM 			shp->sftable[f1] = 0;
6084887Schin 		sh_close(f1);
6094887Schin 	}
6104887Schin 	return(f2);
6114887Schin }
6124887Schin 
6134887Schin /*
6144887Schin  * close a file descriptor and update stream table and attributes
6154887Schin  */
6164887Schin int sh_close(register int fd)
6174887Schin {
6184887Schin 	register Sfio_t *sp;
6194887Schin 	register int r = 0;
6204887Schin 	if(fd<0)
6214887Schin 		return(-1);
6224887Schin 	if(!(sp=sh.sftable[fd]) || sfclose(sp) < 0)
6234887Schin 	{
6244887Schin 		if(fdnotify)
6254887Schin 			(*fdnotify)(fd,SH_FDCLOSE);
6264887Schin 		r=close(fd);
6274887Schin 	}
6284887Schin 	if(fd>2)
6294887Schin 		sh.sftable[fd] = 0;
6304887Schin 	sh.fdstatus[fd] = IOCLOSE;
6314887Schin 	if(sh.fdptrs[fd])
6324887Schin 		*sh.fdptrs[fd] = -1;
6334887Schin 	sh.fdptrs[fd] = 0;
6344887Schin 	if(fd < 10)
6354887Schin 		sh.inuse_bits &= ~(1<<fd);
6364887Schin 	return(r);
6374887Schin }
6384887Schin 
639*8462SApril.Chin@Sun.COM #ifdef O_SERVICE
640*8462SApril.Chin@Sun.COM 
6414887Schin static int
6424887Schin onintr(struct addrinfo* addr, void* handle)
6434887Schin {
6444887Schin 	Shell_t*	sh = (Shell_t*)handle;
6454887Schin 
6464887Schin 	if (sh->trapnote&SH_SIGSET)
6474887Schin 	{
6484887Schin 		freeaddrinfo(addr);
6494887Schin 		sh_exit(SH_EXITSIG);
6504887Schin 		return -1;
6514887Schin 	}
6524887Schin 	if (sh->trapnote)
6534887Schin 		sh_chktrap();
6544887Schin 	return 0;
6554887Schin }
6564887Schin 
657*8462SApril.Chin@Sun.COM #endif
658*8462SApril.Chin@Sun.COM 
6594887Schin /*
6604887Schin  * Mimic open(2) with checks for pseudo /dev/ files.
6614887Schin  */
6624887Schin int sh_open(register const char *path, int flags, ...)
6634887Schin {
664*8462SApril.Chin@Sun.COM 	Shell_t			*shp = &sh;
6654887Schin 	register int		fd = -1;
6664887Schin 	mode_t			mode;
6674887Schin 	char			*e;
6684887Schin 	va_list			ap;
6694887Schin 	va_start(ap, flags);
6704887Schin 	mode = (flags & O_CREAT) ? va_arg(ap, int) : 0;
6714887Schin 	va_end(ap);
6724887Schin 	errno = 0;
6734887Schin 	if(*path==0)
6744887Schin 	{
6754887Schin 		errno = ENOENT;
6764887Schin 		return(-1);
6774887Schin 	}
6784887Schin 	if (path[0]=='/' && path[1]=='d' && path[2]=='e' && path[3]=='v' && path[4]=='/')
6794887Schin 	{
6804887Schin 		switch (path[5])
6814887Schin 		{
6824887Schin 		case 'f':
6834887Schin 			if (path[6]=='d' && path[7]=='/')
6844887Schin 			{
6854887Schin 				fd = (int)strtol(path+8, &e, 10);
6864887Schin 				if (*e)
6874887Schin 					fd = -1;
6884887Schin 			}
6894887Schin 			break;
6904887Schin 		case 's':
6914887Schin 			if (path[6]=='t' && path[7]=='d')
6924887Schin 				switch (path[8])
6934887Schin 				{
6944887Schin 				case 'e':
6954887Schin 					if (path[9]=='r' && path[10]=='r' && !path[11])
6964887Schin 						fd = 2;
6974887Schin 					break;
6984887Schin 				case 'i':
6994887Schin 					if (path[9]=='n' && !path[10])
7004887Schin 						fd = 0;
7014887Schin 					break;
7024887Schin 				case 'o':
7034887Schin 					if (path[9]=='u' && path[10]=='t' && !path[11])
7044887Schin 						fd = 1;
7054887Schin 					break;
7064887Schin 				}
7074887Schin 		}
7084887Schin #ifdef O_SERVICE
7094887Schin 		if (fd < 0)
7104887Schin 		{
7114887Schin 			if ((fd = inetopen(path+5, !!(flags & O_SERVICE), onintr, &sh)) < 0 && errno != ENOTDIR)
7124887Schin 				return -1;
7134887Schin 			if (fd >= 0)
7144887Schin 				goto ok;
7154887Schin 		}
7164887Schin #endif
7174887Schin 	}
7184887Schin 	if (fd >= 0)
7194887Schin 	{
720*8462SApril.Chin@Sun.COM 		if((mode=sh_iocheckfd(shp,fd))==IOCLOSE)
7214887Schin 			return(-1);
7224887Schin 		flags &= O_ACCMODE;
7234887Schin 		if(!(mode&IOWRITE) && ((flags==O_WRONLY) || (flags==O_RDWR)))
7244887Schin 			return(-1);
7254887Schin 		if(!(mode&IOREAD) && ((flags==O_RDONLY) || (flags==O_RDWR)))
7264887Schin 			return(-1);
7274887Schin 		if((fd=dup(fd))<0)
7284887Schin 			return(-1);
7294887Schin 	}
7304887Schin 	else while((fd = open(path, flags, mode)) < 0)
7314887Schin 		if(errno!=EINTR || sh.trapnote)
7324887Schin 			return(-1);
7334887Schin #ifdef O_SERVICE
7344887Schin  ok:
7354887Schin #endif
7364887Schin 	flags &= O_ACCMODE;
7374887Schin 	if(flags==O_WRONLY)
7384887Schin 		mode = IOWRITE;
7394887Schin 	else if(flags==O_RDWR)
7404887Schin 		mode = (IOREAD|IOWRITE);
7414887Schin 	else
7424887Schin 		mode = IOREAD;
7434887Schin 	sh.fdstatus[fd] = mode;
7444887Schin 	return(fd);
7454887Schin }
7464887Schin 
7474887Schin /*
7484887Schin  * Open a file for reading
7494887Schin  * On failure, print message.
7504887Schin  */
7514887Schin int sh_chkopen(register const char *name)
7524887Schin {
7534887Schin 	register int fd = sh_open(name,O_RDONLY,0);
7544887Schin 	if(fd < 0)
7554887Schin 		errormsg(SH_DICT,ERROR_system(1),e_open,name);
7564887Schin 	return(fd);
7574887Schin }
7584887Schin 
7594887Schin /*
7604887Schin  * move open file descriptor to a number > 2
7614887Schin  */
7624887Schin int sh_iomovefd(register int fdold)
7634887Schin {
7644887Schin 	register int fdnew;
7654887Schin 	if(fdold<0 || fdold>2)
7664887Schin 		return(fdold);
7674887Schin 	fdnew = sh_iomovefd(dup(fdold));
7684887Schin 	sh.fdstatus[fdnew] = (sh.fdstatus[fdold]&~IOCLEX);
7694887Schin 	close(fdold);
7704887Schin 	sh.fdstatus[fdold] = IOCLOSE;
7714887Schin 	return(fdnew);
7724887Schin }
7734887Schin 
7744887Schin /*
7754887Schin  * create a pipe and print message on failure
7764887Schin  */
7774887Schin int	sh_pipe(register int pv[])
7784887Schin {
7794887Schin 	int fd[2];
7804887Schin 	if(pipe(fd)<0 || (pv[0]=fd[0])<0 || (pv[1]=fd[1])<0)
7814887Schin 		errormsg(SH_DICT,ERROR_system(1),e_pipe);
7824887Schin 	pv[0] = sh_iomovefd(pv[0]);
7834887Schin 	pv[1] = sh_iomovefd(pv[1]);
7844887Schin 	sh.fdstatus[pv[0]] = IONOSEEK|IOREAD;
7854887Schin 	sh.fdstatus[pv[1]] = IONOSEEK|IOWRITE;
7864887Schin 	sh_subsavefd(pv[0]);
7874887Schin 	sh_subsavefd(pv[1]);
7884887Schin 	return(0);
7894887Schin }
7904887Schin 
7914887Schin static int pat_seek(void *handle, const char *str, size_t sz)
7924887Schin {
7934887Schin 	char **bp = (char**)handle;
7944887Schin 	*bp = (char*)str;
7954887Schin 	return(-1);
7964887Schin }
7974887Schin 
7984887Schin static int pat_line(const regex_t* rp, const char *buff, register size_t n)
7994887Schin {
8004887Schin 	register const char *cp=buff, *sp;
8014887Schin 	while(n>0)
8024887Schin 	{
8034887Schin 		for(sp=cp; n-->0 && *cp++ != '\n';);
8044887Schin 		if(regnexec(rp,sp,cp-sp, 0, (regmatch_t*)0, 0)==0)
8054887Schin 			return(sp-buff);
8064887Schin 	}
8074887Schin 	return(cp-buff);
8084887Schin }
8094887Schin 
810*8462SApril.Chin@Sun.COM static int io_patseek(Shell_t *shp, regex_t *rp, Sfio_t* sp, int flags)
8114887Schin {
8124887Schin 	char	*cp, *match;
813*8462SApril.Chin@Sun.COM 	int	r, fd=sffileno(sp), close_exec = shp->fdstatus[fd]&IOCLEX;
8144887Schin 	int	was_share,s=(PIPE_BUF>SF_BUFSIZE?SF_BUFSIZE:PIPE_BUF);
8154887Schin 	size_t	n,m;
816*8462SApril.Chin@Sun.COM 	shp->fdstatus[sffileno(sp)] |= IOCLEX;
8174887Schin 	if(fd==0)
8184887Schin 		was_share = sfset(sp,SF_SHARE,1);
8194887Schin 	while((cp=sfreserve(sp, -s, SF_LOCKR)) || (cp=sfreserve(sp,SF_UNBOUND, SF_LOCKR)))
8204887Schin 	{
8214887Schin 		m = n = sfvalue(sp);
8224887Schin 		while(n>0 && cp[n-1]!='\n')
8234887Schin 			n--;
8244887Schin 		if(n)
8254887Schin 			m = n;
8264887Schin 		r = regrexec(rp,cp,m,0,(regmatch_t*)0, 0, '\n', (void*)&match, pat_seek);
8274887Schin 		if(r<0)
8284887Schin 			m = match-cp;
8294887Schin 		else if(r==2)
8304887Schin 		{
8314887Schin 			if((m = pat_line(rp,cp,m)) < n)
8324887Schin 				r = -1;
8334887Schin 		}
8344887Schin 		if(m && (flags&IOCOPY))
8354887Schin 			sfwrite(sfstdout,cp,m);
8364887Schin 		sfread(sp,cp,m);
8374887Schin 		if(r<0)
8384887Schin 			break;
8394887Schin 	}
8404887Schin 	if(!close_exec)
841*8462SApril.Chin@Sun.COM 		shp->fdstatus[sffileno(sp)] &= ~IOCLEX;
8424887Schin 	if(fd==0 && !(was_share&SF_SHARE))
8434887Schin 		sfset(sp, SF_SHARE,0);
8444887Schin 	return(0);
8454887Schin }
8464887Schin 
847*8462SApril.Chin@Sun.COM static Sfoff_t	file_offset(Shell_t *shp, int fn, char *fname)
8484887Schin {
849*8462SApril.Chin@Sun.COM 	Sfio_t		*sp = shp->sftable[fn];
8504887Schin 	char		*cp;
8514887Schin 	Sfoff_t		off;
8524887Schin 	struct Eof	endf;
853*8462SApril.Chin@Sun.COM 	Namval_t	*mp = nv_open("EOF",shp->var_tree,0);
854*8462SApril.Chin@Sun.COM 	Namval_t	*pp = nv_open("CUR",shp->var_tree,0);
8554887Schin 	memset(&endf,0,sizeof(struct Eof));
8564887Schin 	endf.fd = fn;
8574887Schin 	endf.hdr.disc = &EOF_disc;
8584887Schin 	endf.hdr.nofree = 1;
8594887Schin 	if(mp)
8604887Schin 		nv_stack(mp, &endf.hdr);
8614887Schin 	if(pp)
8624887Schin 		nv_stack(pp, &endf.hdr);
8634887Schin 	if(sp)
8644887Schin 		sfsync(sp);
8654887Schin 	off = sh_strnum(fname, &cp, 0);
8664887Schin 	if(mp)
8674887Schin 		nv_stack(mp, NiL);
8684887Schin 	if(pp)
8694887Schin 		nv_stack(pp, NiL);
8704887Schin 	return(*cp?(Sfoff_t)-1:off);
8714887Schin }
8724887Schin 
8734887Schin /*
8744887Schin  * close a pipe
8754887Schin  */
8764887Schin void sh_pclose(register int pv[])
8774887Schin {
8784887Schin 	if(pv[0]>=2)
8794887Schin 		sh_close(pv[0]);
8804887Schin 	if(pv[1]>=2)
8814887Schin 		sh_close(pv[1]);
8824887Schin 	pv[0] = pv[1] = -1;
8834887Schin }
8844887Schin 
885*8462SApril.Chin@Sun.COM static char *io_usename(char *name, int *perm, int mode)
886*8462SApril.Chin@Sun.COM {
887*8462SApril.Chin@Sun.COM 	struct stat	statb;
888*8462SApril.Chin@Sun.COM 	char		*tname, *sp, *ep;
889*8462SApril.Chin@Sun.COM 	int		fd,len,n=0;
890*8462SApril.Chin@Sun.COM 	if(mode==0)
891*8462SApril.Chin@Sun.COM 	{
892*8462SApril.Chin@Sun.COM 		if((fd = sh_open(name,O_RDONLY,0)) > 0)
893*8462SApril.Chin@Sun.COM 		{
894*8462SApril.Chin@Sun.COM 			if(fstat(fd,&statb) < 0)
895*8462SApril.Chin@Sun.COM 				return(0);
896*8462SApril.Chin@Sun.COM 			if(!S_ISREG(statb.st_mode))
897*8462SApril.Chin@Sun.COM 				return(0);
898*8462SApril.Chin@Sun.COM 		 	*perm = statb.st_mode&(RW_ALL|(S_IXUSR|S_IXGRP|S_IXOTH));
899*8462SApril.Chin@Sun.COM 		}
900*8462SApril.Chin@Sun.COM 		else if(fd < 0  && errno!=ENOENT)
901*8462SApril.Chin@Sun.COM 			return(0);
902*8462SApril.Chin@Sun.COM 	}
903*8462SApril.Chin@Sun.COM 	tname = sp = (char*)stakalloc((len=strlen(name)) + 5);
904*8462SApril.Chin@Sun.COM 	if(ep = strrchr(name,'/'))
905*8462SApril.Chin@Sun.COM 	{
906*8462SApril.Chin@Sun.COM 		memcpy(sp,name,n=++ep-name);
907*8462SApril.Chin@Sun.COM 		len -=n;
908*8462SApril.Chin@Sun.COM 		sp += n;
909*8462SApril.Chin@Sun.COM 	}
910*8462SApril.Chin@Sun.COM 	else
911*8462SApril.Chin@Sun.COM 		ep = name;
912*8462SApril.Chin@Sun.COM 	*sp++ = '.';
913*8462SApril.Chin@Sun.COM 	memcpy(sp,ep,len);
914*8462SApril.Chin@Sun.COM 	strcpy(sp+len,".tmp");
915*8462SApril.Chin@Sun.COM 	switch(mode)
916*8462SApril.Chin@Sun.COM 	{
917*8462SApril.Chin@Sun.COM 	    case 1:
918*8462SApril.Chin@Sun.COM 		rename(tname,name);
919*8462SApril.Chin@Sun.COM 		break;
920*8462SApril.Chin@Sun.COM 	    case 2:
921*8462SApril.Chin@Sun.COM 		unlink(tname);
922*8462SApril.Chin@Sun.COM 		break;
923*8462SApril.Chin@Sun.COM 	}
924*8462SApril.Chin@Sun.COM 	return(tname);
925*8462SApril.Chin@Sun.COM }
926*8462SApril.Chin@Sun.COM 
9274887Schin /*
9284887Schin  * I/O redirection
9294887Schin  * flag = 0 if files are to be restored
9304887Schin  * flag = 2 if files are to be closed on exec
9314887Schin  * flag = 3 when called from $( < ...), just open file and return
9324887Schin  * flag = SH_SHOWME for trace only
9334887Schin  */
934*8462SApril.Chin@Sun.COM int	sh_redirect(Shell_t *shp,struct ionod *iop, int flag)
9354887Schin {
9364887Schin 	Sfoff_t off;
9374887Schin 	register char *fname;
9384887Schin 	register int 	fd, iof;
9394887Schin 	const char *message = e_open;
9404887Schin 	int o_mode;		/* mode flag for open */
9414887Schin 	static char io_op[7];	/* used for -x trace info */
9424887Schin 	int clexec=0, fn, traceon;
943*8462SApril.Chin@Sun.COM 	int r, indx = shp->topfd, perm= -1;
944*8462SApril.Chin@Sun.COM 	char *tname=0, *after="", *trace = shp->st.trap[SH_DEBUGTRAP];
9454887Schin 	Namval_t *np=0;
9464887Schin 	if(flag==2)
9474887Schin 		clexec = 1;
9484887Schin 	if(iop)
9494887Schin 		traceon = sh_trace(NIL(char**),0);
9504887Schin 	for(;iop;iop=iop->ionxt)
9514887Schin 	{
9524887Schin 		iof=iop->iofile;
9534887Schin 		fn = (iof&IOUFD);
954*8462SApril.Chin@Sun.COM 		if(fn==1 && shp->subshell && (flag==2 || (sfset(sfstdout,0,0)&SF_STRING)))
955*8462SApril.Chin@Sun.COM 			sh_subfork();
9564887Schin 		io_op[0] = '0'+(iof&IOUFD);
9574887Schin 		if(iof&IOPUT)
9584887Schin 		{
9594887Schin 			io_op[1] = '>';
9604887Schin 			o_mode = O_WRONLY|O_CREAT;
9614887Schin 		}
9624887Schin 		else
9634887Schin 		{
9644887Schin 			io_op[1] = '<';
9654887Schin 			o_mode = O_RDONLY|O_NONBLOCK;
9664887Schin 		}
9674887Schin 		io_op[2] = 0;
9684887Schin 		io_op[3] = 0;
9694887Schin 		io_op[4] = 0;
9704887Schin 		fname = iop->ioname;
9714887Schin 		if(!(iof&IORAW))
9724887Schin 		{
9734887Schin 			if(iof&IOLSEEK)
9744887Schin 			{
9754887Schin 				struct argnod *ap = (struct argnod*)stakalloc(ARGVAL+strlen(iop->ioname));
9764887Schin 				memset(ap, 0, ARGVAL);
9774887Schin 				ap->argflag = ARG_MAC;
9784887Schin 				strcpy(ap->argval,iop->ioname);
979*8462SApril.Chin@Sun.COM 				fname=sh_macpat(shp,ap,(iof&IOARITH)?ARG_ARITH:ARG_EXP);
9804887Schin 			}
9814887Schin 			else
982*8462SApril.Chin@Sun.COM 				fname=sh_mactrim(shp,fname,(!sh_isoption(SH_NOGLOB)&&sh_isoption(SH_INTERACTIVE))?2:0);
9834887Schin 		}
9844887Schin 		errno=0;
985*8462SApril.Chin@Sun.COM 		np = 0;
9864887Schin 		if(iop->iovname)
9874887Schin 		{
988*8462SApril.Chin@Sun.COM 			np = nv_open(iop->iovname,shp->var_tree,NV_NOASSIGN|NV_VARNAME);
9894887Schin 			if(nv_isattr(np,NV_RDONLY))
9904887Schin 				errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np));
9914887Schin 			io_op[0] = '}';
992*8462SApril.Chin@Sun.COM 			if((iof&IOLSEEK) || ((iof&IOMOV) && *fname=='-'))
9934887Schin 				fn = nv_getnum(np);
9944887Schin 		}
9954887Schin 		if(iof&IOLSEEK)
9964887Schin 		{
9974887Schin 			io_op[2] = '#';
9984887Schin 			if(iof&IOARITH)
9994887Schin 			{
10004887Schin 				strcpy(&io_op[3]," ((");
10014887Schin 				after = "))";
10024887Schin 			}
10034887Schin 			else if(iof&IOCOPY)
10044887Schin 				io_op[3] = '#';
10054887Schin 			goto traceit;
10064887Schin 		}
10074887Schin 		if(*fname)
10084887Schin 		{
10094887Schin 			if(iof&IODOC)
10104887Schin 			{
10114887Schin 				if(traceon)
10124887Schin 					sfputr(sfstderr,io_op,'<');
1013*8462SApril.Chin@Sun.COM 				fd = io_heredoc(shp,iop,fname,traceon);
10144887Schin 				if(traceon && (flag==SH_SHOWME))
10154887Schin 					sh_close(fd);
10164887Schin 				fname = 0;
10174887Schin 			}
10184887Schin 			else if(iof&IOMOV)
10194887Schin 			{
10204887Schin 				int dupfd,toclose= -1;
10214887Schin 				io_op[2] = '&';
10224887Schin 				if((fd=fname[0])>='0' && fd<='9')
10234887Schin 				{
10244887Schin 					char *number = fname;
10254887Schin 					dupfd = strtol(fname,&number,10);
10264887Schin 					if(*number=='-')
10274887Schin 					{
10284887Schin 						toclose = dupfd;
10294887Schin 						number++;
10304887Schin 					}
10314887Schin 					if(*number || dupfd > IOUFD)
10324887Schin 					{
10334887Schin 						message = e_file;
10344887Schin 						goto fail;
10354887Schin 					}
1036*8462SApril.Chin@Sun.COM 					if(shp->subshell && dupfd==1)
10374887Schin 					{
1038*8462SApril.Chin@Sun.COM 						sh_subtmpfile(0);
10394887Schin 						dupfd = sffileno(sfstdout);
10404887Schin 					}
1041*8462SApril.Chin@Sun.COM 					else if(shp->sftable[dupfd])
1042*8462SApril.Chin@Sun.COM 						sfsync(shp->sftable[dupfd]);
10434887Schin 				}
10444887Schin 				else if(fd=='-' && fname[1]==0)
10454887Schin 				{
10464887Schin 					fd= -1;
10474887Schin 					goto traceit;
10484887Schin 				}
10494887Schin 				else if(fd=='p' && fname[1]==0)
10504887Schin 				{
10514887Schin 					if(iof&IOPUT)
1052*8462SApril.Chin@Sun.COM 						dupfd = shp->coutpipe;
10534887Schin 					else
1054*8462SApril.Chin@Sun.COM 						dupfd = shp->cpipe[0];
10554887Schin 					if(flag)
10564887Schin 						toclose = dupfd;
10574887Schin 				}
10584887Schin 				else
10594887Schin 				{
10604887Schin 					message = e_file;
10614887Schin 					goto fail;
10624887Schin 				}
10634887Schin 				if(flag==SH_SHOWME)
10644887Schin 					goto traceit;
10654887Schin 				if((fd=sh_fcntl(dupfd,F_DUPFD,3))<0)
10664887Schin 					goto fail;
1067*8462SApril.Chin@Sun.COM 				sh_iocheckfd(shp,dupfd);
1068*8462SApril.Chin@Sun.COM 				shp->fdstatus[fd] = (shp->fdstatus[dupfd]&~IOCLEX);
1069*8462SApril.Chin@Sun.COM 				if(toclose<0 && shp->fdstatus[fd]&IOREAD)
1070*8462SApril.Chin@Sun.COM 					shp->fdstatus[fd] |= IODUP;
1071*8462SApril.Chin@Sun.COM 				else if(dupfd==shp->cpipe[0])
1072*8462SApril.Chin@Sun.COM 					sh_pclose(shp->cpipe);
10734887Schin 				else if(toclose>=0)
10744887Schin 				{
10754887Schin 					if(flag==0)
1076*8462SApril.Chin@Sun.COM 						sh_iosave(shp,toclose,indx,(char*)0); /* save file descriptor */
10774887Schin 					sh_close(toclose);
10784887Schin 				}
10794887Schin 			}
10804887Schin 			else if(iof&IORDW)
10814887Schin 			{
10824887Schin 				if(sh_isoption(SH_RESTRICTED))
10834887Schin 					errormsg(SH_DICT,ERROR_exit(1),e_restricted,fname);
10844887Schin 				io_op[2] = '>';
10854887Schin 				o_mode = O_RDWR|O_CREAT;
10864887Schin 				goto openit;
10874887Schin 			}
10884887Schin 			else if(!(iof&IOPUT))
10894887Schin 			{
10904887Schin 				if(flag==SH_SHOWME)
10914887Schin 					goto traceit;
10924887Schin 				fd=sh_chkopen(fname);
10934887Schin 			}
10944887Schin 			else if(sh_isoption(SH_RESTRICTED))
10954887Schin 				errormsg(SH_DICT,ERROR_exit(1),e_restricted,fname);
10964887Schin 			else
10974887Schin 			{
10984887Schin 				if(iof&IOAPP)
10994887Schin 				{
11004887Schin 					io_op[2] = '>';
11014887Schin 					o_mode |= O_APPEND;
11024887Schin 				}
1103*8462SApril.Chin@Sun.COM 				else if((iof&IOREWRITE) && (flag==0 || flag==1 || sh_subsavefd(fn)))
1104*8462SApril.Chin@Sun.COM 				{
1105*8462SApril.Chin@Sun.COM 					io_op[2] = ';';
1106*8462SApril.Chin@Sun.COM 					o_mode |= O_TRUNC;
1107*8462SApril.Chin@Sun.COM 					tname = io_usename(fname,&perm,0);
1108*8462SApril.Chin@Sun.COM 				}
11094887Schin 				else
11104887Schin 				{
11114887Schin 					o_mode |= O_TRUNC;
11124887Schin 					if(iof&IOCLOB)
11134887Schin 						io_op[2] = '|';
11144887Schin 					else if(sh_isoption(SH_NOCLOBBER))
11154887Schin 					{
11164887Schin 						struct stat sb;
11174887Schin 						if(stat(fname,&sb)>=0)
11184887Schin 						{
11194887Schin #if SHOPT_FS_3D
11204887Schin 							if(S_ISREG(sb.st_mode)&&
1121*8462SApril.Chin@Sun.COM 						                (!shp->lim.fs3d || iview(&sb)==0))
11224887Schin #else
11234887Schin 							if(S_ISREG(sb.st_mode))
11244887Schin #endif /* SHOPT_FS_3D */
11254887Schin 							{
11264887Schin 								errno = EEXIST;
11274887Schin 								errormsg(SH_DICT,ERROR_system(1),e_exists,fname);
11284887Schin 							}
11294887Schin 						}
11304887Schin 						else
11314887Schin 							o_mode |= O_EXCL;
11324887Schin 					}
11334887Schin 				}
11344887Schin 			openit:
11354887Schin 				if(flag!=SH_SHOWME)
11364887Schin 				{
1137*8462SApril.Chin@Sun.COM 					if((fd=sh_open(tname?tname:fname,o_mode,RW_ALL)) <0)
11384887Schin 						errormsg(SH_DICT,ERROR_system(1),((o_mode&O_CREAT)?e_create:e_open),fname);
1139*8462SApril.Chin@Sun.COM 					if(perm>0)
1140*8462SApril.Chin@Sun.COM #if _lib_fchmod
1141*8462SApril.Chin@Sun.COM 						fchmod(fd,perm);
1142*8462SApril.Chin@Sun.COM #else
1143*8462SApril.Chin@Sun.COM 						chmod(tname,perm);
1144*8462SApril.Chin@Sun.COM #endif
11454887Schin 				}
11464887Schin 			}
11474887Schin 		traceit:
11484887Schin 			if(traceon && fname)
11494887Schin 			{
11504887Schin 				if(np)
11514887Schin 					sfprintf(sfstderr,"{%s",nv_name(np));
11524887Schin 				sfprintf(sfstderr,"%s %s%s%c",io_op,fname,after,iop->ionxt?' ':'\n');
11534887Schin 			}
11544887Schin 			if(flag==SH_SHOWME)
11554887Schin 				return(indx);
11564887Schin 			if(trace && fname)
11574887Schin 			{
11584887Schin 				char *argv[7], **av=argv;
11594887Schin 				av[3] = io_op;
11604887Schin 				av[4] = fname;
11614887Schin 				av[5] = 0;
11624887Schin 				av[6] = 0;
11634887Schin 				if(iof&IOARITH)
11644887Schin 					av[5] = after;
11654887Schin 				if(np)
11664887Schin 				{
11674887Schin 					av[0] = "{";
11684887Schin 					av[1] = nv_name(np);
11694887Schin 					av[2] = "}";
11704887Schin 				}
11714887Schin 				else
11724887Schin 					av +=3;
1173*8462SApril.Chin@Sun.COM 				sh_debug(shp,trace,(char*)0,(char*)0,av,ARG_NOGLOB);
11744887Schin 			}
11754887Schin 			if(iof&IOLSEEK)
11764887Schin 			{
1177*8462SApril.Chin@Sun.COM 				Sfio_t *sp = shp->sftable[fn];
1178*8462SApril.Chin@Sun.COM 				r = shp->fdstatus[fn];
11794887Schin 				if(!(r&(IOSEEK|IONOSEEK)))
1180*8462SApril.Chin@Sun.COM 					r = sh_iocheckfd(shp,fn);
11814887Schin 				sfsprintf(io_op,sizeof(io_op),"%d\0",fn);
11824887Schin 				if(r==IOCLOSE)
11834887Schin 				{
11844887Schin 					fname = io_op;
11854887Schin 					message = e_file;
11864887Schin 					goto fail;
11874887Schin 				}
11884887Schin 				if(iof&IOARITH)
11894887Schin 				{
11904887Schin 					if(r&IONOSEEK)
11914887Schin 					{
11924887Schin 						fname = io_op;
11934887Schin 						message = e_notseek;
11944887Schin 						goto fail;
11954887Schin 					}
11964887Schin 					message = e_badseek;
1197*8462SApril.Chin@Sun.COM 					if((off = file_offset(shp,fn,fname))<0)
11984887Schin 						goto fail;
11994887Schin 					if(sp)
1200*8462SApril.Chin@Sun.COM 						off=sfseek(sp, off, SEEK_SET);
12014887Schin 					else
1202*8462SApril.Chin@Sun.COM 						off=lseek(fn, off, SEEK_SET);
1203*8462SApril.Chin@Sun.COM 					if(off<0)
1204*8462SApril.Chin@Sun.COM 						r = -1;
12054887Schin 				}
12064887Schin 				else
12074887Schin 				{
12084887Schin 					regex_t *rp;
12094887Schin 					extern const char e_notimp[];
12104887Schin 					if(!(r&IOREAD))
12114887Schin 					{
12124887Schin 						message = e_noread;
12134887Schin 						goto fail;
12144887Schin 					}
12154887Schin 					if(!(rp = regcache(fname, REG_SHELL|REG_NOSUB|REG_NEWLINE|REG_AUGMENTED|REG_FIRST|REG_LEFT|REG_RIGHT, &r)))
12164887Schin 					{
12174887Schin 						message = e_badpattern;
12184887Schin 						goto fail;
12194887Schin 					}
12204887Schin 					if(!sp)
1221*8462SApril.Chin@Sun.COM 						sp = sh_iostream(shp,fn);
1222*8462SApril.Chin@Sun.COM 					r=io_patseek(shp,rp,sp,iof);
12234887Schin 					if(sp && flag==3)
12244887Schin 					{
12254887Schin 						/* close stream but not fn */
12264887Schin 						sfsetfd(sp,-1);
12274887Schin 						sfclose(sp);
12284887Schin 					}
12294887Schin 				}
12304887Schin 				if(r<0)
12314887Schin 					goto fail;
12324887Schin 				if(flag==3)
12334887Schin 					return(fn);
12344887Schin 				continue;
12354887Schin 			}
12364887Schin 			if(!np)
12374887Schin 			{
1238*8462SApril.Chin@Sun.COM 				if(flag==0 || tname)
12394887Schin 				{
12404887Schin 					if(fd==fn)
12414887Schin 					{
12424887Schin 						if((r=sh_fcntl(fd,F_DUPFD,10)) > 0)
12434887Schin 						{
12444887Schin 							fd = r;
12454887Schin 							sh_close(fn);
12464887Schin 						}
12474887Schin 					}
1248*8462SApril.Chin@Sun.COM 					sh_iosave(shp,fn,indx,tname?fname:0);
12494887Schin 				}
12504887Schin 				else if(sh_subsavefd(fn))
1251*8462SApril.Chin@Sun.COM 					sh_iosave(shp,fn,indx|IOSUBSHELL,tname?fname:0);
12524887Schin 			}
12534887Schin 			if(fd<0)
12544887Schin 			{
1255*8462SApril.Chin@Sun.COM 				if(sh_inuse(fn) || fn==shp->infd)
12564887Schin 				{
1257*8462SApril.Chin@Sun.COM 					if(fn>9 || !(shp->inuse_bits&(1<<fn)))
1258*8462SApril.Chin@Sun.COM 						io_preserve(shp,shp->sftable[fn],fn);
12594887Schin 				}
12604887Schin 				sh_close(fn);
12614887Schin 			}
12624887Schin 			if(flag==3)
12634887Schin 				return(fd);
12644887Schin 			if(fd>=0)
12654887Schin 			{
12664887Schin 				if(np)
12674887Schin 				{
12684887Schin 					int32_t v;
12694887Schin 					fn = fd;
12704887Schin 					if(fd<10)
12714887Schin 					{
12724887Schin 						if((fn=fcntl(fd,F_DUPFD,10)) < 0)
12734887Schin 							goto fail;
1274*8462SApril.Chin@Sun.COM 						shp->fdstatus[fn] = shp->fdstatus[fd];
12754887Schin 						sh_close(fd);
12764887Schin 						fd = fn;
12774887Schin 					}
12784887Schin 					nv_unset(np);
12794887Schin 					nv_onattr(np,NV_INT32);
12804887Schin 					v = fn;
12814887Schin 					nv_putval(np,(char*)&v, NV_INT32);
1282*8462SApril.Chin@Sun.COM 					sh_iocheckfd(shp,fd);
12834887Schin 				}
12844887Schin 				else
12854887Schin 				{
1286*8462SApril.Chin@Sun.COM 					fd = sh_iorenumber(shp,sh_iomovefd(fd),fn);
12874887Schin 					if(fn>2 && fn<10)
1288*8462SApril.Chin@Sun.COM 						shp->inuse_bits |= (1<<fn);
12894887Schin 				}
12904887Schin 			}
12914887Schin 			if(fd >2 && clexec)
12924887Schin 			{
12934887Schin 				fcntl(fd,F_SETFD,FD_CLOEXEC);
1294*8462SApril.Chin@Sun.COM 				shp->fdstatus[fd] |= IOCLEX;
12954887Schin 			}
12964887Schin 		}
12974887Schin 		else
12984887Schin 			goto fail;
12994887Schin 	}
13004887Schin 	return(indx);
13014887Schin fail:
13024887Schin 	errormsg(SH_DICT,ERROR_system(1),message,fname);
13034887Schin 	/* NOTREACHED */
13044887Schin 	return(0);
13054887Schin }
13064887Schin /*
13074887Schin  * Create a tmp file for the here-document
13084887Schin  */
1309*8462SApril.Chin@Sun.COM static int io_heredoc(Shell_t *shp,register struct ionod *iop, const char *name, int traceon)
13104887Schin {
13114887Schin 	register Sfio_t	*infile = 0, *outfile;
13124887Schin 	register int		fd;
1313*8462SApril.Chin@Sun.COM 	if(!(iop->iofile&IOSTRG) && (!shp->heredocs || iop->iosize==0))
13144887Schin 		return(sh_open(e_devnull,O_RDONLY));
13154887Schin 	/* create an unnamed temporary file */
13164887Schin 	if(!(outfile=sftmp(0)))
13174887Schin 		errormsg(SH_DICT,ERROR_system(1),e_tmpcreate);
13184887Schin 	if(iop->iofile&IOSTRG)
13194887Schin 	{
13204887Schin 		if(traceon)
13214887Schin 			sfprintf(sfstderr,"< %s\n",name);
13224887Schin 		sfputr(outfile,name,'\n');
13234887Schin 	}
13244887Schin 	else
13254887Schin 	{
1326*8462SApril.Chin@Sun.COM 		infile = subopen(shp,shp->heredocs,iop->iooffset,iop->iosize);
13274887Schin 		if(traceon)
13284887Schin 		{
13294887Schin 			char *cp = sh_fmtq(iop->iodelim);
13304887Schin 			fd = (*cp=='$' || *cp=='\'')?' ':'\\';
13314887Schin 			sfprintf(sfstderr," %c%s\n",fd,cp);
13324887Schin 			sfdisc(outfile,&tee_disc);
13334887Schin 		}
13344887Schin 		if(iop->iofile&IOQUOTE)
13354887Schin 		{
13364887Schin 			/* This is a quoted here-document, not expansion */
13374887Schin 			sfmove(infile,outfile,SF_UNBOUND,-1);
13384887Schin 			sfclose(infile);
13394887Schin 		}
13404887Schin 		else
13414887Schin 		{
1342*8462SApril.Chin@Sun.COM 			char *lastpath = shp->lastpath;
1343*8462SApril.Chin@Sun.COM 			sh_machere(shp,infile,outfile,iop->ioname);
1344*8462SApril.Chin@Sun.COM 			shp->lastpath = lastpath;
13454887Schin 			if(infile)
13464887Schin 				sfclose(infile);
13474887Schin 		}
13484887Schin 	}
13494887Schin 	/* close stream outfile, but save file descriptor */
13504887Schin 	fd = sffileno(outfile);
13514887Schin 	sfsetfd(outfile,-1);
13524887Schin 	sfclose(outfile);
13534887Schin 	if(traceon && !(iop->iofile&IOSTRG))
13544887Schin 		sfputr(sfstderr,iop->ioname,'\n');
13554887Schin 	lseek(fd,(off_t)0,SEEK_SET);
1356*8462SApril.Chin@Sun.COM 	shp->fdstatus[fd] = IOREAD;
13574887Schin 	return(fd);
13584887Schin }
13594887Schin 
13604887Schin /*
13614887Schin  * This write discipline also writes the output on standard error
13624887Schin  * This is used when tracing here-documents
13634887Schin  */
13644887Schin static ssize_t tee_write(Sfio_t *iop,const void *buff,size_t n,Sfdisc_t *unused)
13654887Schin {
13664887Schin 	NOT_USED(unused);
13674887Schin 	sfwrite(sfstderr,buff,n);
13684887Schin 	return(write(sffileno(iop),buff,n));
13694887Schin }
13704887Schin 
13714887Schin /*
13724887Schin  * copy file <origfd> into a save place
13734887Schin  * The saved file is set close-on-exec
13744887Schin  * if <origfd> < 0, then -origfd is saved, but not duped so that it
13754887Schin  *   will be closed with sh_iorestore.
13764887Schin  */
1377*8462SApril.Chin@Sun.COM void sh_iosave(Shell_t *shp, register int origfd, int oldtop, char *name)
13784887Schin {
13794887Schin /*@
1380*8462SApril.Chin@Sun.COM 	assume oldtop>=0 && oldtop<shp->lim.open_max;
13814887Schin @*/
13824887Schin 
13834887Schin 	register int	savefd;
13844887Schin 	int flag = (oldtop&IOSUBSHELL);
13854887Schin 	oldtop &= ~IOSUBSHELL;
13864887Schin 	/* see if already saved, only save once */
1387*8462SApril.Chin@Sun.COM 	for(savefd=shp->topfd; --savefd>=oldtop; )
13884887Schin 	{
13894887Schin 		if(filemap[savefd].orig_fd == origfd)
13904887Schin 			return;
13914887Schin 	}
13924887Schin 	/* make sure table is large enough */
1393*8462SApril.Chin@Sun.COM 	if(shp->topfd >= filemapsize)
13944887Schin 	{
1395*8462SApril.Chin@Sun.COM 		char 	*cp, *oldptr = (char*)filemap;
1396*8462SApril.Chin@Sun.COM 		char 	*oldend = (char*)&filemap[filemapsize];
1397*8462SApril.Chin@Sun.COM 		long	moved;
13984887Schin 		filemapsize += 8;
13994887Schin 		if(!(filemap = (struct fdsave*)realloc(filemap,filemapsize*sizeof(struct fdsave))))
14004887Schin 			errormsg(SH_DICT,ERROR_exit(4),e_nospace);
1401*8462SApril.Chin@Sun.COM 		if(moved = (char*)filemap - oldptr)
1402*8462SApril.Chin@Sun.COM 		{
1403*8462SApril.Chin@Sun.COM #if SHOPT_FASTPIPE
1404*8462SApril.Chin@Sun.COM 			for(savefd=shp->lim.open_max+2; --savefd>=0; )
1405*8462SApril.Chin@Sun.COM #else
1406*8462SApril.Chin@Sun.COM 			for(savefd=shp->lim.open_max; --savefd>=0; )
1407*8462SApril.Chin@Sun.COM #endif /* SHOPT_FASTPIPE */
1408*8462SApril.Chin@Sun.COM 			{
1409*8462SApril.Chin@Sun.COM 				cp = (char*)shp->fdptrs[savefd];
1410*8462SApril.Chin@Sun.COM 				if(cp >= oldptr && cp < oldend)
1411*8462SApril.Chin@Sun.COM 					shp->fdptrs[savefd] = (int*)(oldptr+moved);
1412*8462SApril.Chin@Sun.COM 			}
1413*8462SApril.Chin@Sun.COM 		}
14144887Schin 	}
14154887Schin #if SHOPT_DEVFD
14164887Schin 	if(origfd <0)
14174887Schin 	{
14184887Schin 		savefd = origfd;
14194887Schin 		origfd = -origfd;
14204887Schin 	}
14214887Schin 	else
14224887Schin #endif /* SHOPT_DEVFD */
14234887Schin 	{
14244887Schin 		if((savefd = sh_fcntl(origfd, F_DUPFD, 10)) < 0 && errno!=EBADF)
14254887Schin 			errormsg(SH_DICT,ERROR_system(1),e_toomany);
14264887Schin 	}
1427*8462SApril.Chin@Sun.COM 	filemap[shp->topfd].tname = name;
1428*8462SApril.Chin@Sun.COM 	filemap[shp->topfd].subshell = flag;
1429*8462SApril.Chin@Sun.COM 	filemap[shp->topfd].orig_fd = origfd;
1430*8462SApril.Chin@Sun.COM 	filemap[shp->topfd++].save_fd = savefd;
14314887Schin 	if(savefd >=0)
14324887Schin 	{
1433*8462SApril.Chin@Sun.COM 		register Sfio_t* sp = shp->sftable[origfd];
14344887Schin 		/* make saved file close-on-exec */
14354887Schin 		sh_fcntl(savefd,F_SETFD,FD_CLOEXEC);
14364887Schin 		if(origfd==job.fd)
14374887Schin 			job.fd = savefd;
1438*8462SApril.Chin@Sun.COM 		shp->fdstatus[savefd] = shp->fdstatus[origfd];
1439*8462SApril.Chin@Sun.COM 		shp->fdptrs[savefd] = &filemap[shp->topfd-1].save_fd;
1440*8462SApril.Chin@Sun.COM 		if(!(shp->sftable[savefd]=sp))
14414887Schin 			return;
14424887Schin 		sfsync(sp);
14434887Schin 		if(origfd <=2)
14444887Schin 		{
14454887Schin 			/* copy standard stream to new stream */
14464887Schin 			sp = sfswap(sp,NIL(Sfio_t*));
1447*8462SApril.Chin@Sun.COM 			shp->sftable[savefd] = sp;
14484887Schin 		}
14494887Schin 		else
1450*8462SApril.Chin@Sun.COM 			shp->sftable[origfd] = 0;
14514887Schin 	}
14524887Schin }
14534887Schin 
14544887Schin /*
14554887Schin  *  close all saved file descriptors
14564887Schin  */
1457*8462SApril.Chin@Sun.COM void	sh_iounsave(Shell_t* shp)
14584887Schin {
14594887Schin 	register int fd, savefd, newfd;
1460*8462SApril.Chin@Sun.COM 	for(newfd=fd=0; fd < shp->topfd; fd++)
14614887Schin 	{
14624887Schin 		if((savefd = filemap[fd].save_fd)< 0)
14634887Schin 			filemap[newfd++] = filemap[fd];
14644887Schin 		else
14654887Schin 		{
1466*8462SApril.Chin@Sun.COM 			shp->sftable[savefd] = 0;
14674887Schin 			sh_close(savefd);
14684887Schin 		}
14694887Schin 	}
1470*8462SApril.Chin@Sun.COM 	shp->topfd = newfd;
14714887Schin }
14724887Schin 
14734887Schin /*
14744887Schin  *  restore saved file descriptors from <last> on
14754887Schin  */
1476*8462SApril.Chin@Sun.COM void	sh_iorestore(Shell_t *shp, int last, int jmpval)
14774887Schin {
14784887Schin 	register int 	origfd, savefd, fd;
14794887Schin 	int flag = (last&IOSUBSHELL);
14804887Schin 	last &= ~IOSUBSHELL;
1481*8462SApril.Chin@Sun.COM 	for (fd = shp->topfd - 1; fd >= last; fd--)
14824887Schin 	{
14834887Schin 		if(!flag && filemap[fd].subshell)
14844887Schin 			continue;
14854887Schin 		if(jmpval==SH_JMPSCRIPT)
14864887Schin 		{
14874887Schin 			if ((savefd = filemap[fd].save_fd) >= 0)
14884887Schin 			{
1489*8462SApril.Chin@Sun.COM 				shp->sftable[savefd] = 0;
14904887Schin 				sh_close(savefd);
14914887Schin 			}
14924887Schin 			continue;
14934887Schin 		}
14944887Schin 		origfd = filemap[fd].orig_fd;
1495*8462SApril.Chin@Sun.COM 		if(filemap[fd].tname)
1496*8462SApril.Chin@Sun.COM 			io_usename(filemap[fd].tname,(int*)0,shp->exitval?2:1);
14974887Schin 		sh_close(origfd);
14984887Schin 		if ((savefd = filemap[fd].save_fd) >= 0)
14994887Schin 		{
15004887Schin 			sh_fcntl(savefd, F_DUPFD, origfd);
15014887Schin 			if(savefd==job.fd)
15024887Schin 				job.fd=origfd;
1503*8462SApril.Chin@Sun.COM 			shp->fdstatus[origfd] = shp->fdstatus[savefd];
15044887Schin 			/* turn off close-on-exec if flag if necessary */
1505*8462SApril.Chin@Sun.COM 			if(shp->fdstatus[origfd]&IOCLEX)
15064887Schin 				fcntl(origfd,F_SETFD,FD_CLOEXEC);
15074887Schin 			if(origfd<=2)
15084887Schin 			{
1509*8462SApril.Chin@Sun.COM 				sfswap(shp->sftable[savefd],shp->sftable[origfd]);
15104887Schin 				if(origfd==0)
1511*8462SApril.Chin@Sun.COM 					shp->st.ioset = 0;
15124887Schin 			}
15134887Schin 			else
1514*8462SApril.Chin@Sun.COM 				shp->sftable[origfd] = shp->sftable[savefd];
1515*8462SApril.Chin@Sun.COM 			shp->sftable[savefd] = 0;
15164887Schin 			sh_close(savefd);
15174887Schin 		}
15184887Schin 		else
1519*8462SApril.Chin@Sun.COM 			shp->fdstatus[origfd] = IOCLOSE;
15204887Schin 	}
15214887Schin 	if(!flag)
15224887Schin 	{
15234887Schin 		/* keep file descriptors for subshell restore */
1524*8462SApril.Chin@Sun.COM 		for (fd = last ; fd < shp->topfd; fd++)
15254887Schin 		{
15264887Schin 			if(filemap[fd].subshell)
15274887Schin 				filemap[last++] = filemap[fd];
15284887Schin 		}
15294887Schin 	}
1530*8462SApril.Chin@Sun.COM 	if(last < shp->topfd)
1531*8462SApril.Chin@Sun.COM 		shp->topfd = last;
15324887Schin }
15334887Schin 
15344887Schin /*
15354887Schin  * returns access information on open file <fd>
15364887Schin  * returns -1 for failure, 0 for success
15374887Schin  * <mode> is the same as for access()
15384887Schin  */
15394887Schin int sh_ioaccess(int fd,register int mode)
15404887Schin {
1541*8462SApril.Chin@Sun.COM 	Shell_t	*shp = &sh;
15424887Schin 	register int flags;
15434887Schin 	if(mode==X_OK)
15444887Schin 		return(-1);
1545*8462SApril.Chin@Sun.COM 	if((flags=sh_iocheckfd(shp,fd))!=IOCLOSE)
15464887Schin 	{
15474887Schin 		if(mode==F_OK)
15484887Schin 			return(0);
15494887Schin 		if(mode==R_OK && (flags&IOREAD))
15504887Schin 			return(0);
15514887Schin 		if(mode==W_OK && (flags&IOWRITE))
15524887Schin 			return(0);
15534887Schin 	}
15544887Schin 	return(-1);
15554887Schin }
15564887Schin 
15574887Schin /*
15584887Schin  *  Handle interrupts for slow streams
15594887Schin  */
15604887Schin static int slowexcept(register Sfio_t *iop,int type,void *data,Sfdisc_t *handle)
15614887Schin {
15624887Schin 	register int	n,fno;
15634887Schin 	NOT_USED(handle);
15644887Schin 	if(type==SF_DPOP || type==SF_FINAL)
15654887Schin 		free((void*)handle);
15664887Schin 	if(type!=SF_READ)
15674887Schin 		return(0);
15684887Schin 	if((sh.trapnote&(SH_SIGSET|SH_SIGTRAP)) && errno!=EIO && errno!=ENXIO)
15694887Schin 		errno = EINTR;
15704887Schin 	fno = sffileno(iop);
15714887Schin 	if((n=sfvalue(iop))<=0)
15724887Schin 	{
15734887Schin #ifndef FNDELAY
15744887Schin #   ifdef O_NDELAY
15754887Schin 		if(errno==0 && (n=fcntl(fno,F_GETFL,0))&O_NDELAY)
15764887Schin 		{
15774887Schin 			n &= ~O_NDELAY;
15784887Schin 			fcntl(fno, F_SETFL, n);
15794887Schin 			return(1);
15804887Schin 		}
15814887Schin #   endif /* O_NDELAY */
15824887Schin #endif /* !FNDELAY */
15834887Schin #ifdef O_NONBLOCK
15844887Schin 		if(errno==EAGAIN)
15854887Schin 		{
15864887Schin 			n = fcntl(fno,F_GETFL,0);
15874887Schin 			n &= ~O_NONBLOCK;
15884887Schin 			fcntl(fno, F_SETFL, n);
15894887Schin 			return(1);
15904887Schin 		}
15914887Schin #endif /* O_NONBLOCK */
15924887Schin 		if(errno!=EINTR)
15934887Schin 			return(0);
15944887Schin 		n=1;
1595*8462SApril.Chin@Sun.COM 		sh_onstate(SH_TTYWAIT);
15964887Schin 	}
1597*8462SApril.Chin@Sun.COM 	else
1598*8462SApril.Chin@Sun.COM 		n = 0;
1599*8462SApril.Chin@Sun.COM 	if(sh.bltinfun && sh.bltindata.sigset)
1600*8462SApril.Chin@Sun.COM 		return(-1);
16014887Schin 	errno = 0;
16024887Schin 	if(sh.trapnote&SH_SIGSET)
16034887Schin 	{
16044887Schin 		if(isatty(fno))
16054887Schin 			sfputc(sfstderr,'\n');
16064887Schin 		sh_exit(SH_EXITSIG);
16074887Schin 	}
16084887Schin 	if(sh.trapnote&SH_SIGTRAP)
16094887Schin 		sh_chktrap();
16104887Schin 	return(n);
16114887Schin }
16124887Schin 
16134887Schin /*
16144887Schin  * called when slowread times out
16154887Schin  */
16164887Schin static void time_grace(void *handle)
16174887Schin {
16184887Schin 	NOT_USED(handle);
16194887Schin 	timeout = 0;
16204887Schin 	if(sh_isstate(SH_GRACE))
16214887Schin 	{
16224887Schin 		sh_offstate(SH_GRACE);
16234887Schin 		if(!sh_isstate(SH_INTERACTIVE))
16244887Schin 			return;
16254887Schin 		((struct checkpt*)sh.jmplist)->mode = SH_JMPEXIT;
16264887Schin 		errormsg(SH_DICT,2,e_timeout);
16274887Schin 		sh.trapnote |= SH_SIGSET;
16284887Schin 		return;
16294887Schin 	}
16304887Schin 	errormsg(SH_DICT,0,e_timewarn);
16314887Schin 	sh_onstate(SH_GRACE);
16324887Schin 	sigrelease(SIGALRM);
16334887Schin 	sh.trapnote |= SH_SIGTRAP;
16344887Schin }
16354887Schin 
16364887Schin static ssize_t piperead(Sfio_t *iop,void *buff,register size_t size,Sfdisc_t *handle)
16374887Schin {
16384887Schin 	int fd = sffileno(iop);
16394887Schin 	NOT_USED(handle);
1640*8462SApril.Chin@Sun.COM 	if(job.waitsafe && job.savesig)
1641*8462SApril.Chin@Sun.COM 		job_reap(job.savesig);
16424887Schin 	if(sh.trapnote)
16434887Schin 	{
16444887Schin 		errno = EINTR;
16454887Schin 		return(-1);
16464887Schin 	}
16474887Schin 	if(sh_isstate(SH_INTERACTIVE) && io_prompt(iop,sh.nextprompt)<0 && errno==EIO)
16484887Schin 		return(0);
1649*8462SApril.Chin@Sun.COM 	sh_onstate(SH_TTYWAIT);
16504887Schin 	if(!(sh.fdstatus[sffileno(iop)]&IOCLEX) && (sfset(iop,0,0)&SF_SHARE))
16514887Schin 		size = ed_read(sh.ed_context, fd, (char*)buff, size,0);
16524887Schin 	else
16534887Schin 		size = sfrd(iop,buff,size,handle);
1654*8462SApril.Chin@Sun.COM 	sh_offstate(SH_TTYWAIT);
16554887Schin 	return(size);
16564887Schin }
16574887Schin /*
16584887Schin  * This is the read discipline that is applied to slow devices
16594887Schin  * This routine takes care of prompting for input
16604887Schin  */
16614887Schin static ssize_t slowread(Sfio_t *iop,void *buff,register size_t size,Sfdisc_t *handle)
16624887Schin {
16634887Schin 	int	(*readf)(void*, int, char*, int, int);
16644887Schin 	int	reedit=0, rsize;
16654887Schin #if SHOPT_HISTEXPAND
16664887Schin 	char    *xp=0;
16674887Schin #endif
16684887Schin 	NOT_USED(handle);
16694887Schin #   if SHOPT_ESH
16704887Schin 	if(sh_isoption(SH_EMACS) || sh_isoption(SH_GMACS))
16714887Schin 		readf = ed_emacsread;
16724887Schin 	else
16734887Schin #   endif	/* SHOPT_ESH */
16744887Schin #   if SHOPT_VSH
16754887Schin #	if SHOPT_RAWONLY
16764887Schin 	    if(sh_isoption(SH_VI) || ((SHOPT_RAWONLY-0) && mbwide()))
16774887Schin #	else
16784887Schin 	    if(sh_isoption(SH_VI))
16794887Schin #	endif
16804887Schin 		readf = ed_viread;
16814887Schin 	else
16824887Schin #   endif	/* SHOPT_VSH */
16834887Schin 		readf = ed_read;
16844887Schin 	if(sh.trapnote)
16854887Schin 	{
16864887Schin 		errno = EINTR;
16874887Schin 		return(-1);
16884887Schin 	}
16894887Schin 	while(1)
16904887Schin 	{
16914887Schin 		if(io_prompt(iop,sh.nextprompt)<0 && errno==EIO)
16924887Schin 			return(0);
16934887Schin 		if(sh.timeout)
16944887Schin 			timeout = (void*)sh_timeradd(sh_isstate(SH_GRACE)?1000L*TGRACE:1000L*sh.timeout,0,time_grace,NIL(void*));
16954887Schin 		rsize = (*readf)(sh.ed_context, sffileno(iop), (char*)buff, size, reedit);
16964887Schin 		if(timeout)
16974887Schin 			timerdel(timeout);
16984887Schin 		timeout=0;
16994887Schin #if SHOPT_HISTEXPAND
17004887Schin 		if(rsize && *(char*)buff != '\n' && sh.nextprompt==1 && sh_isoption(SH_HISTEXPAND))
17014887Schin 		{
17024887Schin 			int r;
17034887Schin 			((char*)buff)[rsize] = '\0';
17044887Schin 			if(xp)
17054887Schin 			{
17064887Schin 				free(xp);
17074887Schin 				xp = 0;
17084887Schin 			}
17094887Schin 			r = hist_expand(buff, &xp);
17104887Schin 			if((r & (HIST_EVENT|HIST_PRINT)) && !(r & HIST_ERROR) && xp)
17114887Schin 			{
17124887Schin 				strlcpy(buff, xp, size);
17134887Schin 				rsize = strlen(buff);
17144887Schin 				if(!sh_isoption(SH_HISTVERIFY) || readf==ed_read)
17154887Schin 				{
17164887Schin 					sfputr(sfstderr, xp, -1);
17174887Schin 					break;
17184887Schin 				}
17194887Schin 				reedit = rsize - 1;
17204887Schin 				continue;
17214887Schin 			}
17224887Schin 			if((r & HIST_ERROR) && sh_isoption(SH_HISTREEDIT))
17234887Schin 			{
17244887Schin 				reedit  = rsize - 1;
17254887Schin 				continue;
17264887Schin 			}
17274887Schin 			if(r & (HIST_ERROR|HIST_PRINT))
17284887Schin 			{
17294887Schin 				*(char*)buff = '\n';
17304887Schin 				rsize = 1;
17314887Schin 			}
17324887Schin 		}
17334887Schin #endif
17344887Schin 		break;
17354887Schin 	}
17364887Schin 	return(rsize);
17374887Schin }
17384887Schin 
17394887Schin /*
17404887Schin  * check and return the attributes for a file descriptor
17414887Schin  */
17424887Schin 
1743*8462SApril.Chin@Sun.COM int sh_iocheckfd(Shell_t *shp, register int fd)
17444887Schin {
17454887Schin 	register int flags, n;
17464887Schin 	if((n=sh.fdstatus[fd])&IOCLOSE)
17474887Schin 		return(n);
17484887Schin 	if(!(n&(IOREAD|IOWRITE)))
17494887Schin 	{
17504887Schin #ifdef F_GETFL
17514887Schin 		if((flags=fcntl(fd,F_GETFL,0)) < 0)
17524887Schin 			return(sh.fdstatus[fd]=IOCLOSE);
17534887Schin 		if((flags&O_ACCMODE)!=O_WRONLY)
17544887Schin 			n |= IOREAD;
17554887Schin 		if((flags&O_ACCMODE)!=O_RDONLY)
17564887Schin 			n |= IOWRITE;
17574887Schin #else
17584887Schin 		struct stat statb;
17594887Schin 		if((flags = fstat(fd,&statb))< 0)
17604887Schin 			return(sh.fdstatus[fd]=IOCLOSE);
17614887Schin 		n |= (IOREAD|IOWRITE);
17624887Schin 		if(read(fd,"",0) < 0)
17634887Schin 			n &= ~IOREAD;
17644887Schin #endif /* F_GETFL */
17654887Schin 	}
17664887Schin 	if(!(n&(IOSEEK|IONOSEEK)))
17674887Schin 	{
17684887Schin 		struct stat statb;
17694887Schin 		/* /dev/null check is a workaround for select bug */
17704887Schin 		static ino_t null_ino;
17714887Schin 		static dev_t null_dev;
17724887Schin 		if(null_ino==0 && stat(e_devnull,&statb) >=0)
17734887Schin 		{
17744887Schin 			null_ino = statb.st_ino;
17754887Schin 			null_dev = statb.st_dev;
17764887Schin 		}
17774887Schin 		if(tty_check(fd))
17784887Schin 			n |= IOTTY;
17794887Schin 		if(lseek(fd,NIL(off_t),SEEK_CUR)<0)
17804887Schin 		{
17814887Schin 			n |= IONOSEEK;
17824887Schin #ifdef S_ISSOCK
17834887Schin 			if((fstat(fd,&statb)>=0) && S_ISSOCK(statb.st_mode))
17844887Schin 				n |= IOREAD|IOWRITE;
17854887Schin #endif /* S_ISSOCK */
17864887Schin 		}
17874887Schin 		else if((fstat(fd,&statb)>=0) && (
17884887Schin 			S_ISFIFO(statb.st_mode) ||
17894887Schin #ifdef S_ISSOCK
17904887Schin 			S_ISSOCK(statb.st_mode) ||
17914887Schin #endif /* S_ISSOCK */
17924887Schin 			/* The following is for sockets on the sgi */
17934887Schin 			(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) ||
17944887Schin 			(S_ISCHR(statb.st_mode) && (statb.st_ino!=null_ino || statb.st_dev!=null_dev))
17954887Schin 		))
17964887Schin 			n |= IONOSEEK;
17974887Schin 		else
17984887Schin 			n |= IOSEEK;
17994887Schin 	}
18004887Schin 	sh.fdstatus[fd] = n;
18014887Schin 	return(n);
18024887Schin }
18034887Schin 
18044887Schin /*
18054887Schin  * Display prompt PS<flag> on standard error
18064887Schin  */
18074887Schin 
18084887Schin static int	io_prompt(Sfio_t *iop,register int flag)
18094887Schin {
1810*8462SApril.Chin@Sun.COM 	Shell_t	*shp = &sh;
18114887Schin 	register char *cp;
18124887Schin 	char buff[1];
18134887Schin 	char *endprompt;
18144887Schin 	static short cmdno;
18154887Schin 	int sfflags;
18164887Schin 	if(flag<3 && !sh_isstate(SH_INTERACTIVE))
18174887Schin 		flag = 0;
18184887Schin 	if(flag==2 && sfpkrd(sffileno(iop),buff,1,'\n',0,1) >= 0)
18194887Schin 		flag = 0;
18204887Schin 	if(flag==0)
18214887Schin 		return(sfsync(sfstderr));
18224887Schin 	sfflags = sfset(sfstderr,SF_SHARE|SF_PUBLIC|SF_READ,0);
18234887Schin 	if(!(sh.prompt=(char*)sfreserve(sfstderr,0,0)))
18244887Schin 		sh.prompt = "";
18254887Schin 	switch(flag)
18264887Schin 	{
18274887Schin 		case 1:
18284887Schin 		{
18294887Schin 			register int c;
18304887Schin #if defined(TIOCLBIC) && defined(LFLUSHO)
18314887Schin 			if(!sh_isoption(SH_VI) && !sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS))
18324887Schin 			{
18334887Schin 				/*
18344887Schin 				 * re-enable output in case the user has
18354887Schin 				 * disabled it.  Not needed with edit mode
18364887Schin 				 */
18374887Schin 				int mode = LFLUSHO;
18384887Schin 				ioctl(sffileno(sfstderr),TIOCLBIC,&mode);
18394887Schin 			}
18404887Schin #endif	/* TIOCLBIC */
1841*8462SApril.Chin@Sun.COM 			cp = sh_mactry(shp,nv_getval(sh_scoped(shp,PS1NOD)));
18424887Schin 			for(;c= *cp;cp++)
18434887Schin 			{
18444887Schin 				if(c==HIST_CHAR)
18454887Schin 				{
18464887Schin 					/* look at next character */
18474887Schin 					c = *++cp;
18484887Schin 					/* print out line number if not !! */
18494887Schin 					if(c!= HIST_CHAR)
18504887Schin 					{
18514887Schin 						sfprintf(sfstderr,"%d", sh.hist_ptr?(int)sh.hist_ptr->histind:++cmdno);
18524887Schin 					}
18534887Schin 					if(c==0)
18544887Schin 						goto done;
18554887Schin 				}
18564887Schin 				sfputc(sfstderr,c);
18574887Schin 			}
18584887Schin 			goto done;
18594887Schin 		}
18604887Schin 		case 2:
1861*8462SApril.Chin@Sun.COM 			cp = nv_getval(sh_scoped(shp,PS2NOD));
18624887Schin 			break;
18634887Schin 		case 3:
1864*8462SApril.Chin@Sun.COM 			cp = nv_getval(sh_scoped(shp,PS3NOD));
18654887Schin 			break;
18664887Schin 		default:
18674887Schin 			goto done;
18684887Schin 	}
18694887Schin 	if(cp)
18704887Schin 		sfputr(sfstderr,cp,-1);
18714887Schin done:
18724887Schin 	if(*sh.prompt && (endprompt=(char*)sfreserve(sfstderr,0,0)))
18734887Schin 		*endprompt = 0;
18744887Schin 	sfset(sfstderr,sfflags&SF_READ|SF_SHARE|SF_PUBLIC,1);
18754887Schin 	return(sfsync(sfstderr));
18764887Schin }
18774887Schin 
18784887Schin /*
18794887Schin  * This discipline is inserted on write pipes to prevent SIGPIPE
18804887Schin  * from causing an infinite loop
18814887Schin  */
18824887Schin static int pipeexcept(Sfio_t* iop, int mode, void *data, Sfdisc_t* handle)
18834887Schin {
18844887Schin 	NOT_USED(iop);
18854887Schin 	if(mode==SF_DPOP || mode==SF_FINAL)
18864887Schin 		free((void*)handle);
18874887Schin 	else if(mode==SF_WRITE && errno==EINTR && sh.lastsig==SIGPIPE)
18884887Schin 		return(-1);
18894887Schin 	return(0);
18904887Schin }
18914887Schin 
18924887Schin /*
18934887Schin  * keep track of each stream that is opened and closed
18944887Schin  */
1895*8462SApril.Chin@Sun.COM static void	sftrack(Sfio_t* sp, int flag, void* data)
18964887Schin {
1897*8462SApril.Chin@Sun.COM 	Shell_t *shp = &sh;
18984887Schin 	register int fd = sffileno(sp);
18994887Schin 	register struct checkpt *pp;
19004887Schin 	register int mode;
1901*8462SApril.Chin@Sun.COM 	int newfd = integralof(data);
19024887Schin 	if(flag==SF_SETFD || flag==SF_CLOSING)
19034887Schin 	{
19044887Schin 		if(newfd<0)
19054887Schin 			flag = SF_CLOSING;
19064887Schin 		if(fdnotify)
19074887Schin 			(*fdnotify)(sffileno(sp),flag==SF_CLOSING?-1:newfd);
19084887Schin 	}
19094887Schin #ifdef DEBUG
19104887Schin 	if(flag==SF_READ || flag==SF_WRITE)
19114887Schin 	{
19124887Schin 		char *z = fmtbase((long)getpid(),0,0);
19134887Schin 		write(ERRIO,z,strlen(z));
19144887Schin 		write(ERRIO,": ",2);
19154887Schin 		write(ERRIO,"attempt to ",11);
19164887Schin 		if(flag==SF_READ)
19174887Schin 			write(ERRIO,"read from",9);
19184887Schin 		else
19194887Schin 			write(ERRIO,"write to",8);
19204887Schin 		write(ERRIO," locked stream\n",15);
19214887Schin 		return;
19224887Schin 	}
19234887Schin #endif
1924*8462SApril.Chin@Sun.COM 	if((unsigned)fd >= shp->lim.open_max)
19254887Schin 		return;
19264887Schin 	if(sh_isstate(SH_NOTRACK))
19274887Schin 		return;
19284887Schin 	mode = sfset(sp,0,0);
1929*8462SApril.Chin@Sun.COM 	if(sp==shp->heredocs && fd < 10 && flag==SF_NEW)
19304887Schin 	{
19314887Schin 		fd = sfsetfd(sp,10);
19324887Schin 		fcntl(fd,F_SETFD,FD_CLOEXEC);
19334887Schin 	}
19344887Schin 	if(fd < 3)
19354887Schin 		return;
19364887Schin 	if(flag==SF_NEW)
19374887Schin 	{
1938*8462SApril.Chin@Sun.COM 		if(!shp->sftable[fd] && shp->fdstatus[fd]==IOCLOSE)
19394887Schin 		{
1940*8462SApril.Chin@Sun.COM 			shp->sftable[fd] = sp;
19414887Schin 			flag = (mode&SF_WRITE)?IOWRITE:0;
19424887Schin 			if(mode&SF_READ)
19434887Schin 				flag |= IOREAD;
1944*8462SApril.Chin@Sun.COM 			shp->fdstatus[fd] = flag;
19454887Schin #if 0
19464887Schin 			if(flag==IOWRITE)
1947*8462SApril.Chin@Sun.COM 				sfpool(sp,shp->outpool,SF_WRITE);
19484887Schin 			else
19494887Schin #else
19504887Schin 			if(flag!=IOWRITE)
19514887Schin #endif
1952*8462SApril.Chin@Sun.COM 				sh_iostream(shp,fd);
19534887Schin 		}
1954*8462SApril.Chin@Sun.COM 		if((pp=(struct checkpt*)shp->jmplist) && pp->mode==SH_JMPCMD)
19554887Schin 		{
19564887Schin 			struct openlist *item;
19574887Schin 			/*
19584887Schin 			 * record open file descriptors so they can
19594887Schin 			 * be closed in case a longjmp prevents
19604887Schin 			 * built-ins from cleanup
19614887Schin 			 */
19624887Schin 			item = new_of(struct openlist, 0);
19634887Schin 			item->strm = sp;
19644887Schin 			item->next = pp->olist;
19654887Schin 			pp->olist = item;
19664887Schin 		}
19674887Schin 		if(fdnotify)
19684887Schin 			(*fdnotify)(-1,sffileno(sp));
19694887Schin 	}
19704887Schin 	else if(flag==SF_CLOSING || (flag==SF_SETFD  && newfd<=2))
19714887Schin 	{
1972*8462SApril.Chin@Sun.COM 		shp->sftable[fd] = 0;
1973*8462SApril.Chin@Sun.COM 		shp->fdstatus[fd]=IOCLOSE;
1974*8462SApril.Chin@Sun.COM 		if(pp=(struct checkpt*)shp->jmplist)
19754887Schin 		{
19764887Schin 			struct openlist *item;
19774887Schin 			for(item=pp->olist; item; item=item->next)
19784887Schin 			{
19794887Schin 				if(item->strm == sp)
19804887Schin 				{
19814887Schin 					item->strm = 0;
19824887Schin 					break;
19834887Schin 				}
19844887Schin 			}
19854887Schin 		}
19864887Schin 	}
19874887Schin }
19884887Schin 
19894887Schin struct eval
19904887Schin {
19914887Schin 	Sfdisc_t	disc;
19924887Schin 	char		**argv;
19934887Schin 	short		slen;
19944887Schin 	char		addspace;
19954887Schin };
19964887Schin 
19974887Schin /*
19984887Schin  * Create a stream consisting of a space separated argv[] list
19994887Schin  */
20004887Schin 
20014887Schin Sfio_t *sh_sfeval(register char *argv[])
20024887Schin {
20034887Schin 	register Sfio_t *iop;
20044887Schin 	register char *cp;
20054887Schin 	if(argv[1])
20064887Schin 		cp = "";
20074887Schin 	else
20084887Schin 		cp = argv[0];
20094887Schin 	iop = sfopen(NIL(Sfio_t*),(char*)cp,"s");
20104887Schin 	if(argv[1])
20114887Schin 	{
20124887Schin 		register struct eval *ep;
20134887Schin 		if(!(ep = new_of(struct eval,0)))
20144887Schin 			return(NIL(Sfio_t*));
20154887Schin 		ep->disc = eval_disc;
20164887Schin 		ep->argv = argv;
20174887Schin 		ep->slen  = -1;
20184887Schin 		ep->addspace  = 0;
20194887Schin 		sfdisc(iop,&ep->disc);
20204887Schin 	}
20214887Schin 	return(iop);
20224887Schin }
20234887Schin 
20244887Schin /*
20254887Schin  * This code gets called whenever an end of string is found with eval
20264887Schin  */
20274887Schin 
20284887Schin static int eval_exceptf(Sfio_t *iop,int type, void *data, Sfdisc_t *handle)
20294887Schin {
20304887Schin 	register struct eval *ep = (struct eval*)handle;
20314887Schin 	register char	*cp;
20324887Schin 	register int	len;
20334887Schin 
20344887Schin 	/* no more to do */
20354887Schin 	if(type!=SF_READ || !(cp = ep->argv[0]))
20364887Schin 	{
20374887Schin 		if(type==SF_CLOSING)
20384887Schin 			sfdisc(iop,SF_POPDISC);
20394887Schin 		else if(ep && (type==SF_DPOP || type==SF_FINAL))
20404887Schin 			free((void*)ep);
20414887Schin 		return(0);
20424887Schin 	}
20434887Schin 
20444887Schin 	if(!ep->addspace)
20454887Schin 	{
20464887Schin 		/* get the length of this string */
20474887Schin 		ep->slen = len = strlen(cp);
20484887Schin 		/* move to next string */
20494887Schin 		ep->argv++;
20504887Schin 	}
20514887Schin 	else /* insert space between arguments */
20524887Schin 	{
20534887Schin 		len = 1;
20544887Schin 		cp = " ";
20554887Schin 	}
20564887Schin 	/* insert the new string */
20574887Schin 	sfsetbuf(iop,cp,len);
20584887Schin 	ep->addspace = !ep->addspace;
20594887Schin 	return(1);
20604887Schin }
20614887Schin 
20624887Schin /*
20634887Schin  * This routine returns a stream pointer to a segment of length <size> from
20644887Schin  * the stream <sp> starting at offset <offset>
20654887Schin  * The stream can be read with the normal stream operations
20664887Schin  */
20674887Schin 
2068*8462SApril.Chin@Sun.COM static Sfio_t *subopen(Shell_t *shp,Sfio_t* sp, off_t offset, long size)
20694887Schin {
20704887Schin 	register struct subfile *disp;
20714887Schin 	if(sfseek(sp,offset,SEEK_SET) <0)
20724887Schin 		return(NIL(Sfio_t*));
20734887Schin 	if(!(disp = (struct subfile*)malloc(sizeof(struct subfile)+IOBSIZE+1)))
20744887Schin 		return(NIL(Sfio_t*));
20754887Schin 	disp->disc = sub_disc;
20764887Schin 	disp->oldsp = sp;
20774887Schin 	disp->offset = offset;
20784887Schin 	disp->size = disp->left = size;
2079*8462SApril.Chin@Sun.COM 	sp = sfnew(NIL(Sfio_t*),(char*)(disp+1),IOBSIZE,shp->lim.open_max,SF_READ);
20804887Schin 	sfdisc(sp,&disp->disc);
20814887Schin 	return(sp);
20824887Schin }
20834887Schin 
20844887Schin /*
20854887Schin  * read function for subfile discipline
20864887Schin  */
20874887Schin static ssize_t subread(Sfio_t* sp,void* buff,register size_t size,Sfdisc_t* handle)
20884887Schin {
20894887Schin 	register struct subfile *disp = (struct subfile*)handle;
20904887Schin 	NOT_USED(sp);
20914887Schin 	if(disp->left == 0)
20924887Schin 		return(0);
20934887Schin 	if(size > disp->left)
20944887Schin 		size = disp->left;
20954887Schin 	disp->left -= size;
20964887Schin 	return(sfread(disp->oldsp,buff,size));
20974887Schin }
20984887Schin 
20994887Schin /*
21004887Schin  * exception handler for subfile discipline
21014887Schin  */
21024887Schin static int subexcept(Sfio_t* sp,register int mode, void *data, Sfdisc_t* handle)
21034887Schin {
21044887Schin 	register struct subfile *disp = (struct subfile*)handle;
21054887Schin 	if(mode==SF_CLOSING)
21064887Schin 	{
21074887Schin 		sfdisc(sp,SF_POPDISC);
21084887Schin 		return(0);
21094887Schin 	}
21104887Schin 	else if(disp && (mode==SF_DPOP || mode==SF_FINAL))
21114887Schin 	{
21124887Schin 		free((void*)disp);
21134887Schin 		return(0);
21144887Schin 	}
21154887Schin #ifdef SF_ATEXIT
21164887Schin 	else if (mode==SF_ATEXIT)
21174887Schin 	{
21184887Schin 		sfdisc(sp, SF_POPDISC);
21194887Schin 		return(0);
21204887Schin 	}
21214887Schin #endif
21224887Schin 	else if(mode==SF_READ)
21234887Schin 		return(0);
21244887Schin 	return(-1);
21254887Schin }
21264887Schin 
21274887Schin #define NROW    15      /* number of rows before going to multi-columns */
21284887Schin #define LBLSIZ	3	/* size of label field and interfield spacing */
21294887Schin /*
21304887Schin  * print a list of arguments in columns
21314887Schin  */
21324887Schin void	sh_menu(Sfio_t *outfile,int argn,char *argv[])
21334887Schin {
2134*8462SApril.Chin@Sun.COM 	Shell_t *shp = &sh;
21354887Schin 	register int i,j;
21364887Schin 	register char **arg;
21374887Schin 	int nrow, ncol=1, ndigits=1;
21384887Schin 	int fldsize, wsize = ed_window();
2139*8462SApril.Chin@Sun.COM 	char *cp = nv_getval(sh_scoped(shp,LINES));
21404887Schin 	nrow = (cp?1+2*((int)strtol(cp, (char**)0, 10)/3):NROW);
21414887Schin 	for(i=argn;i >= 10;i /= 10)
21424887Schin 		ndigits++;
21434887Schin 	if(argn < nrow)
21444887Schin 	{
21454887Schin 		nrow = argn;
21464887Schin 		goto skip;
21474887Schin 	}
21484887Schin 	i = 0;
21494887Schin 	for(arg=argv; *arg;arg++)
21504887Schin 	{
21514887Schin 		if((j=strlen(*arg)) > i)
21524887Schin 			i = j;
21534887Schin 	}
21544887Schin 	i += (ndigits+LBLSIZ);
21554887Schin 	if(i < wsize)
21564887Schin 		ncol = wsize/i;
21574887Schin 	if(argn > nrow*ncol)
21584887Schin 	{
21594887Schin 		nrow = 1 + (argn-1)/ncol;
21604887Schin 	}
21614887Schin 	else
21624887Schin 	{
21634887Schin 		ncol = 1 + (argn-1)/nrow;
21644887Schin 		nrow = 1 + (argn-1)/ncol;
21654887Schin 	}
21664887Schin skip:
21674887Schin 	fldsize = (wsize/ncol)-(ndigits+LBLSIZ);
21684887Schin 	for(i=0;i<nrow;i++)
21694887Schin 	{
21704887Schin 		if(sh.trapnote&SH_SIGSET)
21714887Schin 			return;
21724887Schin 		j = i;
21734887Schin 		while(1)
21744887Schin 		{
21754887Schin 			arg = argv+j;
21764887Schin 			sfprintf(outfile,"%*d) %s",ndigits,j+1,*arg);
21774887Schin 			j += nrow;
21784887Schin 			if(j >= argn)
21794887Schin 				break;
21804887Schin 			sfnputc(outfile,' ',fldsize-strlen(*arg));
21814887Schin 		}
21824887Schin 		sfputc(outfile,'\n');
21834887Schin 	}
21844887Schin }
21854887Schin 
21864887Schin #undef read
21874887Schin /*
21884887Schin  * shell version of read() for user added builtins
21894887Schin  */
21904887Schin ssize_t sh_read(register int fd, void* buff, size_t n)
21914887Schin {
21924887Schin 	register Sfio_t *sp;
21934887Schin 	if(sp=sh.sftable[fd])
21944887Schin 		return(sfread(sp,buff,n));
21954887Schin 	else
21964887Schin 		return(read(fd,buff,n));
21974887Schin }
21984887Schin 
21994887Schin #undef write
22004887Schin /*
22014887Schin  * shell version of write() for user added builtins
22024887Schin  */
22034887Schin ssize_t sh_write(register int fd, const void* buff, size_t n)
22044887Schin {
22054887Schin 	register Sfio_t *sp;
22064887Schin 	if(sp=sh.sftable[fd])
22074887Schin 		return(sfwrite(sp,buff,n));
22084887Schin 	else
22094887Schin 		return(write(fd,buff,n));
22104887Schin }
22114887Schin 
22124887Schin #undef lseek
22134887Schin /*
22144887Schin  * shell version of lseek() for user added builtins
22154887Schin  */
22164887Schin off_t sh_seek(register int fd, off_t offset, int whence)
22174887Schin {
22184887Schin 	register Sfio_t *sp;
22194887Schin 	if((sp=sh.sftable[fd]) && (sfset(sp,0,0)&(SF_READ|SF_WRITE)))
22204887Schin 		return(sfseek(sp,offset,whence));
22214887Schin 	else
22224887Schin 		return(lseek(fd,offset,whence));
22234887Schin }
22244887Schin 
22254887Schin #undef dup
22264887Schin int sh_dup(register int old)
22274887Schin {
22284887Schin 	register int fd = dup(old);
22294887Schin 	if(fd>=0)
22304887Schin 	{
22314887Schin 		if(sh.fdstatus[old] == IOCLOSE)
22324887Schin 			sh.fdstatus[old] = 0;
22334887Schin 		sh.fdstatus[fd] = (sh.fdstatus[old]&~IOCLEX);
22344887Schin 		if(fdnotify)
22354887Schin 			(*fdnotify)(old,fd);
22364887Schin 	}
22374887Schin 	return(fd);
22384887Schin }
22394887Schin 
22404887Schin #undef fcntl
22414887Schin int sh_fcntl(register int fd, int op, ...)
22424887Schin {
22434887Schin 	int newfd, arg;
22444887Schin 	va_list		ap;
22454887Schin 	va_start(ap, op);
22464887Schin 	arg =  va_arg(ap, int) ;
22474887Schin 	va_end(ap);
22484887Schin 	newfd = fcntl(fd,op,arg);
22494887Schin 	if(newfd>=0) switch(op)
22504887Schin 	{
22514887Schin 	    case F_DUPFD:
22524887Schin 		if(sh.fdstatus[fd] == IOCLOSE)
22534887Schin 			sh.fdstatus[fd] = 0;
22544887Schin 		sh.fdstatus[newfd] = (sh.fdstatus[fd]&~IOCLEX);
22554887Schin 		if(fdnotify)
22564887Schin 			(*fdnotify)(fd,newfd);
22574887Schin 		break;
22584887Schin 	    case F_SETFD:
22594887Schin 		if(sh.fdstatus[fd] == IOCLOSE)
22604887Schin 			sh.fdstatus[fd] = 0;
22614887Schin 		if(arg&FD_CLOEXEC)
22624887Schin 			sh.fdstatus[fd] |= IOCLEX;
22634887Schin 		else
22644887Schin 			sh.fdstatus[fd] &= ~IOCLEX;
22654887Schin 	}
22664887Schin 	return(newfd);
22674887Schin }
22684887Schin 
22694887Schin #undef umask
22704887Schin mode_t	sh_umask(mode_t m)
22714887Schin {
22724887Schin 	sh.mask = m;
22734887Schin 	return(umask(m));
22744887Schin }
22754887Schin 
22764887Schin /*
22774887Schin  * give file descriptor <fd> and <mode>, return an iostream pointer
22784887Schin  * <mode> must be SF_READ or SF_WRITE
22794887Schin  * <fd> must be a non-negative number ofr SH_IOCOPROCESS or SH_IOHISTFILE.
22804887Schin  * returns NULL on failure and may set errno.
22814887Schin  */
22824887Schin 
22834887Schin Sfio_t *sh_iogetiop(int fd, int mode)
22844887Schin {
2285*8462SApril.Chin@Sun.COM 	Shell_t	*shp = &sh;
22864887Schin 	int n;
22874887Schin 	Sfio_t *iop=0;
22884887Schin 	if(mode!=SF_READ && mode!=SF_WRITE)
22894887Schin 	{
22904887Schin 		errno = EINVAL;
22914887Schin 		return(iop);
22924887Schin 	}
22934887Schin 	switch(fd)
22944887Schin 	{
22954887Schin 	    case SH_IOHISTFILE:
2296*8462SApril.Chin@Sun.COM 		if(!sh_histinit((void*)shp))
22974887Schin 			return(iop);
2298*8462SApril.Chin@Sun.COM 		fd = sffileno(shp->hist_ptr->histfp);
22994887Schin 		break;
23004887Schin 	    case SH_IOCOPROCESS:
23014887Schin 		if(mode==SF_WRITE)
2302*8462SApril.Chin@Sun.COM 			fd = shp->coutpipe;
23034887Schin 		else
2304*8462SApril.Chin@Sun.COM 			fd = shp->cpipe[0];
23054887Schin 		break;
23064887Schin 	    default:
2307*8462SApril.Chin@Sun.COM 		if(fd<0 || fd >= shp->lim.open_max)
23084887Schin 			fd = -1;
23094887Schin 	}
23104887Schin 	if(fd<0)
23114887Schin 	{
23124887Schin 		errno = EBADF;
23134887Schin 		return(iop);
23144887Schin 	}
2315*8462SApril.Chin@Sun.COM 	if(!(n=shp->fdstatus[fd]))
2316*8462SApril.Chin@Sun.COM 		n = sh_iocheckfd(shp,fd);
23174887Schin 	if(mode==SF_WRITE && !(n&IOWRITE))
23184887Schin 		return(iop);
23194887Schin 	if(mode==SF_READ && !(n&IOREAD))
23204887Schin 		return(iop);
2321*8462SApril.Chin@Sun.COM 	if(!(iop = shp->sftable[fd]))
2322*8462SApril.Chin@Sun.COM 		iop=sh_iostream(shp,fd);
23234887Schin 	return(iop);
23244887Schin }
23254887Schin 
23264887Schin typedef int (*Notify_f)(int,int);
23274887Schin 
23284887Schin Notify_f    sh_fdnotify(Notify_f notify)
23294887Schin {
23304887Schin 	Notify_f old;
23314887Schin         old = fdnotify;
23324887Schin         fdnotify = notify;
23334887Schin         return(old);
23344887Schin }
23354887Schin 
23364887Schin Sfio_t	*sh_fd2sfio(int fd)
23374887Schin {
2338*8462SApril.Chin@Sun.COM 	Shell_t	*shp = &sh;
23394887Schin 	register int status;
23404887Schin 	Sfio_t *sp = sh.sftable[fd];
2341*8462SApril.Chin@Sun.COM 	if(!sp  && (status = sh_iocheckfd(shp,fd))!=IOCLOSE)
23424887Schin 	{
23434887Schin 		register int flags=0;
23444887Schin 		if(status&IOREAD)
23454887Schin 			flags |= SF_READ;
23464887Schin 		if(status&IOWRITE)
23474887Schin 			flags |= SF_WRITE;
23484887Schin 		sp = sfnew(NULL, NULL, -1, fd,flags);
23494887Schin 		sh.sftable[fd] = sp;
23504887Schin 	}
23514887Schin 	return(sp);
23524887Schin }
23534887Schin 
23544887Schin Sfio_t *sh_pathopen(const char *cp)
23554887Schin {
2356*8462SApril.Chin@Sun.COM 	Shell_t *shp = &sh;
23574887Schin 	int n;
23584887Schin #ifdef PATH_BFPATH
23594887Schin 	if((n=path_open(cp,path_get(cp))) < 0)
23604887Schin 		n = path_open(cp,(Pathcomp_t*)0);
23614887Schin #else
23624887Schin 	if((n=path_open(cp,path_get(cp))) < 0)
23634887Schin 		n = path_open(cp,"");
23644887Schin #endif
23654887Schin 	if(n < 0)
23664887Schin 		errormsg(SH_DICT,ERROR_system(1),e_open,cp);
2367*8462SApril.Chin@Sun.COM 	return(sh_iostream(shp,n));
23684887Schin }
2369