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