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;
9