1da2e3ebchin/***********************************************************************
2da2e3ebchin*                                                                      *
3da2e3ebchin*               This software is part of the ast package               *
43e14f97Roger A. Faulkner*          Copyright (c) 1982-2010 AT&T Intellectual Property          *
5da2e3ebchin*                      and is licensed under the                       *
6da2e3ebchin*                  Common Public License, Version 1.0                  *
77c2fbfbApril Chin*                    by AT&T Intellectual Property                     *
8da2e3ebchin*                                                                      *
9da2e3ebchin*                A copy of the License is available at                 *
10da2e3ebchin*            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebchin*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebchin*                                                                      *
13da2e3ebchin*              Information and Software Systems Research               *
14da2e3ebchin*                            AT&T Research                             *
15da2e3ebchin*                           Florham Park NJ                            *
16da2e3ebchin*                                                                      *
17da2e3ebchin*                  David Korn <dgk@research.att.com>                   *
18da2e3ebchin*                                                                      *
19da2e3ebchin***********************************************************************/
20da2e3ebchin#pragma prototyped
21da2e3ebchin
22da2e3ebchin/*
23da2e3ebchin * Input/output file processing
24da2e3ebchin *
25da2e3ebchin *   David Korn
26da2e3ebchin *   AT&T Labs
27da2e3ebchin *
28da2e3ebchin */
29da2e3ebchin
30da2e3ebchin#include	"defs.h"
31da2e3ebchin#include	<fcin.h>
32da2e3ebchin#include	<ls.h>
33da2e3ebchin#include	<stdarg.h>
34da2e3ebchin#include	<regex.h>
35da2e3ebchin#include	"variables.h"
36da2e3ebchin#include	"path.h"
37da2e3ebchin#include	"io.h"
38da2e3ebchin#include	"jobs.h"
39da2e3ebchin#include	"shnodes.h"
40da2e3ebchin#include	"history.h"
41da2e3ebchin#include	"edit.h"
42da2e3ebchin#include	"timeout.h"
43da2e3ebchin#include	"FEATURE/externs"
44da2e3ebchin#include	"FEATURE/dynamic"
45da2e3ebchin#include	"FEATURE/poll"
46da2e3ebchin
47da2e3ebchin#ifdef	FNDELAY
48da2e3ebchin#   ifdef EAGAIN
49da2e3ebchin#	if EAGAIN!=EWOULDBLOCK
50da2e3ebchin#	    undef EAGAIN
51da2e3ebchin#	    define EAGAIN       EWOULDBLOCK
52da2e3ebchin#	endif
53da2e3ebchin#   else
54da2e3ebchin#	define EAGAIN   EWOULDBLOCK
55da2e3ebchin#   endif /* EAGAIN */
56da2e3ebchin#   ifndef O_NONBLOCK
57da2e3ebchin#	define O_NONBLOCK	FNDELAY
58da2e3ebchin#   endif /* !O_NONBLOCK */
59da2e3ebchin#endif	/* FNDELAY */
60da2e3ebchin
61da2e3ebchin#ifndef O_SERVICE
62da2e3ebchin#   define O_SERVICE	O_NOCTTY
63da2e3ebchin#endif
64da2e3ebchin
65da2e3ebchin#define RW_ALL	(S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH)
66da2e3ebchin
67da2e3ebchinstatic void	*timeout;
68da2e3ebchinstatic int	(*fdnotify)(int,int);
69da2e3ebchin
70da2e3ebchin#if defined(_lib_socket) && defined(_sys_socket) && defined(_hdr_netinet_in)
71da2e3ebchin#   include <sys/socket.h>
72da2e3ebchin#   include <netdb.h>
73da2e3ebchin#   include <netinet/in.h>
74da2e3ebchin#   if !defined(htons) && !_lib_htons
75da2e3ebchin#      define htons(x)	(x)
76da2e3ebchin#   endif
77da2e3ebchin#   if !defined(htonl) && !_lib_htonl
78da2e3ebchin#      define htonl(x)	(x)
79da2e3ebchin#   endif
80da2e3ebchin#   if _pipe_socketpair
817c2fbfbApril Chin#      ifndef SHUT_RD
827c2fbfbApril Chin#         define SHUT_RD         0
837c2fbfbApril Chin#      endif
847c2fbfbApril Chin#      ifndef SHUT_WR
857c2fbfbApril Chin#         define SHUT_WR         1
867c2fbfbApril Chin#      endif
87da2e3ebchin#      if _socketpair_shutdown_mode
887c2fbfbApril 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)
89da2e3ebchin#      else
907c2fbfbApril 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)
91da2e3ebchin#      endif
92da2e3ebchin#   endif
93da2e3ebchin
94da2e3ebchin#if !_lib_getaddrinfo
95da2e3ebchin
96da2e3ebchin#undef	EAI_SYSTEM
97da2e3ebchin
98da2e3ebchin#define EAI_SYSTEM		1
99da2e3ebchin
100da2e3ebchin#undef	addrinfo
101da2e3ebchin#undef	getaddrinfo
102da2e3ebchin#undef	freeaddrinfo
103da2e3ebchin
104da2e3ebchin#define addrinfo		local_addrinfo
105da2e3ebchin#define getaddrinfo		local_getaddrinfo
106da2e3ebchin#define freeaddrinfo		local_freeaddrinfo
107da2e3ebchin
108da2e3ebchinstruct addrinfo
109da2e3ebchin{
110da2e3ebchin        int			ai_flags;
111da2e3ebchin        int			ai_family;
112da2e3ebchin        int			ai_socktype;
113da2e3ebchin        int			ai_protocol;
114da2e3ebchin        socklen_t		ai_addrlen;
115da2e3ebchin        struct sockaddr*	ai_addr;
116da2e3ebchin        struct addrinfo*	ai_next;
117da2e3ebchin};
118da2e3ebchin
119da2e3ebchinstatic int
120da2e3ebchingetaddrinfo(const char* node, const char* service, const struct addrinfo* hint, struct addrinfo **addr)
121da2e3ebchin{
122da2e3ebchin	unsigned long	    	ip_addr = 0;
123da2e3ebchin	unsigned short	    	ip_port = 0;
124da2e3ebchin	struct addrinfo*	ap;
125da2e3ebchin	struct hostent*		hp;
126da2e3ebchin	struct sockaddr_in*	ip;
127da2e3ebchin	char*			prot;
128da2e3ebchin	long			n;
129da2e3ebchin
130da2e3ebchin	if (!(hp = gethostbyname(node)) || hp->h_addrtype!=AF_INET || hp->h_length>sizeof(struct in_addr))
131da2e3ebchin	{
132da2e3ebchin		errno = EADDRNOTAVAIL;
133da2e3ebchin		return EAI_SYSTEM;
134da2e3ebchin	}
135da2e3ebchin	ip_addr = (unsigned long)((struct in_addr*)hp->h_addr)->s_addr;
136da2e3ebchin	if ((n = strtol(service, &prot, 10)) > 0 && n <= USHRT_MAX && !*prot)
137da2e3ebchin		ip_port = htons((unsigned short)n);
138da2e3ebchin	else
139da2e3ebchin	{
140da2e3ebchin		struct servent*	sp;
141da2e3ebchin		const char*	protocol = 0;
142da2e3ebchin
143da2e3ebchin		if (hint)
144da2e3ebchin			switch (hint->ai_socktype)
145da2e3ebchin			{
146da2e3ebchin			case SOCK_STREAM:
147da2e3ebchin				switch (hint->ai_protocol)
148da2e3ebchin				{
149da2e3ebchin				case 0:
150da2e3ebchin					protocol = "tcp";
151da2e3ebchin					break;
152da2e3ebchin#ifdef IPPROTO_SCTP
153da2e3ebchin				case IPPROTO_SCTP:
154da2e3ebchin					protocol = "sctp";
155da2e3ebchin					break;
156da2e3ebchin#endif
157da2e3ebchin				}
158da2e3ebchin				break;
159da2e3ebchin			case SOCK_DGRAM:
160da2e3ebchin				protocol = "udp";
161da2e3ebchin				break;
162da2e3ebchin			}
163da2e3ebchin		if (!protocol)
164da2e3ebchin		{
165da2e3ebchin			errno =  EPROTONOSUPPORT;
166da2e3ebchin			return 1;
167da2e3ebchin		}
168da2e3ebchin		if (sp = getservbyname(service, protocol))
169da2e3ebchin			ip_port = sp->s_port;
170da2e3ebchin	}
171da2e3ebchin	if (!ip_port)
172da2e3ebchin	{
173da2e3ebchin		errno = EADDRNOTAVAIL;
174da2e3ebchin		return EAI_SYSTEM;
175da2e3ebchin	}
176da2e3ebchin	if (!(ap = newof(0, struct addrinfo, 1, sizeof(struct sockaddr_in))))
177da2e3ebchin		return EAI_SYSTEM;
178da2e3ebchin	if (hint)
179da2e3ebchin		*ap = *hint;
180da2e3ebchin	ap->ai_family = hp->h_addrtype;
181da2e3ebchin	ap->ai_addrlen 	= sizeof(struct sockaddr_in);
182da2e3ebchin	ap->ai_addr = (struct sockaddr *)(ap+1);
183da2e3ebchin	ip = (struct sockaddr_in *)ap->ai_addr;
184da2e3ebchin	ip->sin_family = AF_INET;
185da2e3ebchin	ip->sin_port = ip_port;
186da2e3ebchin	ip->sin_addr.s_addr = ip_addr;
187da2e3ebchin	*addr = ap;
188da2e3ebchin	return 0;
189da2e3ebchin}
190da2e3ebchin
191da2e3ebchinstatic void
192da2e3ebchinfreeaddrinfo(struct addrinfo* ap)
193da2e3ebchin{
194da2e3ebchin	if (ap)
195da2e3ebchin		free(ap);
196da2e3ebchin}
197da2e3ebchin
198da2e3ebchin#endif
199da2e3ebchin
200da2e3ebchin/*
201da2e3ebchin * return <protocol>/<host>/<service> fd
202da2e3ebchin */
203da2e3ebchin
204da2e3ebchintypedef int (*Inetintr_f)(struct addrinfo*, void*);
205da2e3ebchin
206da2e3ebchinstatic int
207da2e3ebchininetopen(const char* path, int server, Inetintr_f onintr, void* handle)
208da2e3ebchin{
209da2e3ebchin	register char*		s;
210da2e3ebchin	register char*		t;
211da2e3ebchin	int			fd;
212da2e3ebchin	int			oerrno;
213da2e3ebchin	struct addrinfo		hint;
214da2e3ebchin	struct addrinfo*	addr;
215da2e3ebchin	struct addrinfo*	p;
216da2e3ebchin
217da2e3ebchin	memset(&hint, 0, sizeof(hint));
218da2e3ebchin	hint.ai_family = PF_UNSPEC;
219da2e3ebchin	switch (path[0])
220da2e3ebchin	{
221da2e3ebchin#ifdef IPPROTO_SCTP
222da2e3ebchin	case 's':
223da2e3ebchin		if (path[1]!='c' || path[2]!='t' || path[3]!='p' || path[4]!='/')
224da2e3ebchin		{
225da2e3ebchin			errno = ENOTDIR;
226da2e3ebchin			return -1;
227da2e3ebchin		}
228da2e3ebchin		hint.ai_socktype = SOCK_STREAM;
229da2e3ebchin		hint.ai_protocol = IPPROTO_SCTP;
230da2e3ebchin		path += 5;
231da2e3ebchin		break;
232da2e3ebchin#endif
233da2e3ebchin	case 't':
234da2e3ebchin		if (path[1]!='c' || path[2]!='p' || path[3]!='/')
235da2e3ebchin		{
236da2e3ebchin			errno = ENOTDIR;
237da2e3ebchin			return -1;
238da2e3ebchin		}
239da2e3ebchin		hint.ai_socktype = SOCK_STREAM;
240da2e3ebchin		path += 4;
241da2e3ebchin		break;
242da2e3ebchin	case 'u':
243da2e3ebchin		if (path[1]!='d' || path[2]!='p' || path[3]!='/')
244da2e3ebchin		{
245da2e3ebchin			errno = ENOTDIR;
246da2e3ebchin			return -1;
247da2e3ebchin		}
248da2e3ebchin		hint.ai_socktype = SOCK_DGRAM;
249da2e3ebchin		path += 4;
250da2e3ebchin		break;
251da2e3ebchin	default:
252da2e3ebchin		errno = ENOTDIR;
253da2e3ebchin		return -1;
254da2e3ebchin	}
255da2e3ebchin	if (!(s = strdup(path)))
256da2e3ebchin		return -1;
257da2e3ebchin	if (t = strchr(s, '/'))
258da2e3ebchin	{
259da2e3ebchin		*t++ = 0;
260da2e3ebchin		if (streq(s, "local"))
261da2e3ebchin			s = "localhost";
262da2e3ebchin		fd = getaddrinfo(s, t, &hint, &addr);
263da2e3ebchin	}
264da2e3ebchin	else
265da2e3ebchin		fd = -1;
266da2e3ebchin	free(s);
267da2e3ebchin	if (fd)
268da2e3ebchin	{
269da2e3ebchin		if (fd != EAI_SYSTEM)
270da2e3ebchin			errno = ENOTDIR;
271da2e3ebchin		return -1;
272da2e3ebchin	}
273da2e3ebchin	oerrno = errno;
274da2e3ebchin	errno = 0;
275da2e3ebchin	fd = -1;
276da2e3ebchin	for (p = addr; p; p = p->ai_next)
277da2e3ebchin	{
278da2e3ebchin		/*
279da2e3ebchin		 * some api's don't take the hint
280da2e3ebchin		 */
281da2e3ebchin
282da2e3ebchin		if (!p->ai_protocol)
283da2e3ebchin			p->ai_protocol = hint.ai_protocol;
284da2e3ebchin		if (!p->ai_socktype)
285da2e3ebchin			p->ai_socktype = hint.ai_socktype;
286da2e3ebchin		while ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) >= 0)
287da2e3ebchin		{
288da2e3ebchin			if (server && !bind(fd, p->ai_addr, p->ai_addrlen) && !listen(fd, 5) || !server && !connect(fd, p->ai_addr, p->ai_addrlen))
289da2e3ebchin				goto done;
290da2e3ebchin			close(fd);
291da2e3ebchin			fd = -1;
292da2e3ebchin			if (errno != EINTR || !onintr)
293da2e3ebchin				break;
294da2e3ebchin			if ((*onintr)(addr, handle))
295da2e3ebchin				return -1;
296da2e3ebchin		}
297da2e3ebchin	}
298da2e3ebchin done:
299da2e3ebchin	freeaddrinfo(addr);
300da2e3ebchin	if (fd >= 0)
301da2e3ebchin		errno = oerrno;
302da2e3ebchin	return fd;
303da2e3ebchin}
304da2e3ebchin
305da2e3ebchin#else
306da2e3ebchin
307da2e3ebchin#undef	O_SERVICE
308da2e3ebchin
309da2e3ebchin#endif
310da2e3ebchin
311da2e3ebchinstruct fdsave
312da2e3ebchin{
313da2e3ebchin	int	orig_fd;	/* original file descriptor */
314da2e3ebchin	int	save_fd;	/* saved file descriptor */
315da2e3ebchin	int	subshell;	/* saved for subshell */
3167c2fbfbApril Chin	char	*tname;		/* name used with >; */
317da2e3ebchin};
318da2e3ebchin
319da2e3ebchinstatic int  	subexcept(Sfio_t*, int, void*, Sfdisc_t*);
320da2e3ebchinstatic int  	eval_exceptf(Sfio_t*, int, void*, Sfdisc_t*);
321da2e3ebchinstatic int  	slowexcept(Sfio_t*, int, void*, Sfdisc_t*);
322da2e3ebchinstatic int	pipeexcept(Sfio_t*, int, void*, Sfdisc_t*);
323da2e3ebchinstatic ssize_t	piperead(Sfio_t*, void*, size_t, Sfdisc_t*);
324da2e3ebchinstatic ssize_t	slowread(Sfio_t*, void*, size_t, Sfdisc_t*);
325da2e3ebchinstatic ssize_t	subread(Sfio_t*, void*, size_t, Sfdisc_t*);
326da2e3ebchinstatic ssize_t	tee_write(Sfio_t*,const void*,size_t,Sfdisc_t*);
327da2e3ebchinstatic int	io_prompt(Sfio_t*,int);
3287c2fbfbApril Chinstatic int	io_heredoc(Shell_t*,register struct ionod*, const char*, int);
3297c2fbfbApril Chinstatic void	sftrack(Sfio_t*,int,void*);
330da2e3ebchinstatic const Sfdisc_t eval_disc = { NULL, NULL, NULL, eval_exceptf, NULL};
331da2e3ebchinstatic Sfdisc_t tee_disc = {NULL,tee_write,NULL,NULL,NULL};
3327c2fbfbApril Chinstatic Sfio_t *subopen(Shell_t *,Sfio_t*, off_t, long);
333da2e3ebchinstatic const Sfdisc_t sub_disc = { subread, 0, 0, subexcept, 0 };
334da2e3ebchin
335da2e3ebchinstruct subfile
336da2e3ebchin{
337da2e3ebchin	Sfdisc_t	disc;
338da2e3ebchin	Sfio_t		*oldsp;
339da2e3ebchin	off_t		offset;
340da2e3ebchin	long		size;
341da2e3ebchin	long		left;
342da2e3ebchin};
343da2e3ebchin
344da2e3ebchinstruct Eof
345da2e3ebchin{
346da2e3ebchin	Namfun_t	hdr;
347da2e3ebchin	int		fd;
348da2e3ebchin};
349da2e3ebchin
350da2e3ebchinstatic Sfdouble_t nget_cur_eof(register Namval_t* np, Namfun_t *fp)
351da2e3ebchin{
352da2e3ebchin	struct Eof *ep = (struct Eof*)fp;
353da2e3ebchin	Sfoff_t end, cur =lseek(ep->fd, (Sfoff_t)0, SEEK_CUR);
354da2e3ebchin	if(*np->nvname=='C')
355da2e3ebchin	        return((Sfdouble_t)cur);
356da2e3ebchin	if(cur<0)
357da2e3ebchin		return((Sfdouble_t)-1);
358da2e3ebchin	end =lseek(ep->fd, (Sfoff_t)0, SEEK_END);
359da2e3ebchin	lseek(ep->fd, (Sfoff_t)0, SEEK_CUR);
360da2e3ebchin        return((Sfdouble_t)end);
361da2e3ebchin}
362da2e3ebchin
363da2e3ebchinstatic const Namdisc_t EOF_disc	= { sizeof(struct Eof), 0, 0, nget_cur_eof};
364da2e3ebchin
365da2e3ebchin#define	MATCH_BUFF	(64*1024)
366da2e3ebchinstruct Match
367da2e3ebchin{
368da2e3ebchin	Sfoff_t	offset;
369da2e3ebchin	char	*base;
370da2e3ebchin};
371da2e3ebchin
372da2e3ebchinstatic int matchf(void *handle, char *ptr, size_t size)
373da2e3ebchin{
374da2e3ebchin	struct Match *mp = (struct Match*)handle;
375da2e3ebchin	mp->offset += (ptr-mp->base);
376da2e3ebchin	return(1);
377da2e3ebchin}
378da2e3ebchin
379da2e3ebchin
380da2e3ebchinstatic struct fdsave	*filemap;
381da2e3ebchinstatic short		filemapsize;
382da2e3ebchin
383da2e3ebchin/* ======== input output and file copying ======== */
384da2e3ebchin
3857c2fbfbApril Chinvoid sh_ioinit(Shell_t *shp)
386da2e3ebchin{
387da2e3ebchin	register int n;
388da2e3ebchin	filemapsize = 8;
3897c2fbfbApril Chin	filemap = (struct fdsave*)malloc(filemapsize*sizeof(struct fdsave));
390da2e3ebchin#if SHOPT_FASTPIPE
3917c2fbfbApril Chin	n = shp->lim.open_max+2;
392da2e3ebchin#else
3937c2fbfbApril Chin	n = shp->lim.open_max;
394da2e3ebchin#endif /* SHOPT_FASTPIPE */
3957c2fbfbApril Chin	shp->fdstatus = (unsigned char*)malloc((unsigned)n);
3967c2fbfbApril Chin	memset((char*)shp->fdstatus,0,n);
3977c2fbfbApril Chin	shp->fdptrs = (int**)malloc(n*sizeof(int*));
3987c2fbfbApril Chin	memset((char*)shp->fdptrs,0,n*sizeof(int*));
3997c2fbfbApril Chin	shp->sftable = (Sfio_t**)malloc(n*sizeof(Sfio_t*));
4007c2fbfbApril Chin	memset((char*)shp->sftable,0,n*sizeof(Sfio_t*));
4017c2fbfbApril Chin	shp->sftable[0] = sfstdin;
4027c2fbfbApril Chin	shp->sftable[1] = sfstdout;
4037c2fbfbApril Chin	shp->sftable[2] = sfstderr;
404da2e3ebchin	sfnotify(sftrack);
4057c2fbfbApril Chin	sh_iostream(shp,0);
406da2e3ebchin	/* all write steams are in the same pool and share outbuff */
4077c2fbfbApril Chin	shp->outpool = sfopen(NIL(Sfio_t*),NIL(char*),"sw");  /* pool identifier */
40834f9b3eRoland Mainz	shp->outbuff = (char*)malloc(IOBSIZE+4);
4097c2fbfbApril Chin	shp->errbuff = (char*)malloc(IOBSIZE/4);
4107c2fbfbApril Chin	sfsetbuf(sfstderr,shp->errbuff,IOBSIZE/4);
4117c2fbfbApril Chin	sfsetbuf(sfstdout,shp->outbuff,IOBSIZE);
4127c2fbfbApril Chin	sfpool(sfstdout,shp->outpool,SF_WRITE);
4137c2fbfbApril Chin	sfpool(sfstderr,shp->outpool,SF_WRITE);
414da2e3ebchin	sfset(sfstdout,SF_LINE,0);
4157c2fbfbApril Chin	sfset(sfstderr,SF_LINE,0);
4167c2fbfbApril Chin	sfset(sfstdin,SF_SHARE|SF_PUBLIC,1);
4177c2fbfbApril Chin}
4187c2fbfbApril Chin
4197c2fbfbApril Chin/*
4207c2fbfbApril Chin *  Handle output stream exceptions
4217c2fbfbApril Chin */
4227c2fbfbApril Chinstatic int outexcept(register Sfio_t *iop,int type,void *data,Sfdisc_t *handle)
4237c2fbfbApril Chin{
4247c2fbfbApril Chin	static int	active = 0;
4257c2fbfbApril Chin
4267c2fbfbApril Chin	NOT_USED(handle);
4277c2fbfbApril Chin	if(type==SF_DPOP || type==SF_FINAL)
4287c2fbfbApril Chin		free((void*)handle);
4297c2fbfbApril Chin	else if(type==SF_WRITE && (*(ssize_t*)data)<0 && sffileno(iop)!=2)
4307c2fbfbApril Chin		switch (errno)
4317c2fbfbApril Chin		{
4327c2fbfbApril Chin		case EINTR:
4337c2fbfbApril Chin		case EPIPE:
4347c2fbfbApril Chin#ifdef ECONNRESET
4357c2fbfbApril Chin		case ECONNRESET:
4367c2fbfbApril Chin#endif
4377c2fbfbApril Chin#ifdef ESHUTDOWN
4387c2fbfbApril Chin		case ESHUTDOWN:
4397c2fbfbApril Chin#endif
4407c2fbfbApril Chin			break;
4417c2fbfbApril Chin		default:
4427c2fbfbApril Chin			if(!active)
4437c2fbfbApril Chin			{
4447c2fbfbApril Chin				int mode = ((struct checkpt*)sh.jmplist)->mode;
4457c2fbfbApril Chin				int save = errno;
4467c2fbfbApril Chin				active = 1;
4477c2fbfbApril Chin				((struct checkpt*)sh.jmplist)->mode = 0;
4487c2fbfbApril Chin				sfpurge(iop);
4497c2fbfbApril Chin				sfpool(iop,NIL(Sfio_t*),SF_WRITE);
4507c2fbfbApril Chin				errno = save;
4517c2fbfbApril Chin				errormsg(SH_DICT,ERROR_system(1),e_badwrite,sffileno(iop));
4527c2fbfbApril Chin				active = 0;
4537c2fbfbApril Chin				((struct checkpt*)sh.jmplist)->mode = mode;
4547c2fbfbApril Chin				sh_exit(1);
4557c2fbfbApril Chin			}
4567c2fbfbApril Chin			return(-1);
4577c2fbfbApril Chin		}
4587c2fbfbApril Chin	return(0);
459da2e3ebchin}
460da2e3ebchin
461da2e3ebchin/*
462da2e3ebchin * create or initialize a stream corresponding to descriptor <fd>
463da2e3ebchin * a buffer with room for a sentinal is allocated for a read stream.
464da2e3ebchin * A discipline is inserted when read stream is a tty or a pipe
465da2e3ebchin * For output streams, the buffer is set to sh.output and put into
466da2e3ebchin * the sh.outpool synchronization pool
467da2e3ebchin */
4687c2fbfbApril ChinSfio_t *sh_iostream(Shell_t *shp, register int fd)
469da2e3ebchin{
470da2e3ebchin	register Sfio_t *iop;
4717c2fbfbApril Chin	register int status = sh_iocheckfd(shp,fd);
472da2e3ebchin	register int flags = SF_WRITE;
473da2e3ebchin	char *bp;
4747c2fbfbApril Chin	Sfdisc_t *dp;
475da2e3ebchin#if SHOPT_FASTPIPE
4767c2fbfbApril Chin	if(fd>=shp->lim.open_max)
4777c2fbfbApril Chin		return(shp->sftable[fd]);
478da2e3ebchin#endif /* SHOPT_FASTPIPE */
479da2e3ebchin	if(status==IOCLOSE)
480da2e3ebchin	{
481da2e3ebchin		switch(fd)
482da2e3ebchin		{
483da2e3ebchin		    case 0:
484da2e3ebchin			return(sfstdin);
485da2e3ebchin		    case 1:
486da2e3ebchin			return(sfstdout);
487da2e3ebchin		    case 2:
488da2e3ebchin			return(sfstderr);
489da2e3ebchin		}
490da2e3ebchin		return(NIL(Sfio_t*));
491da2e3ebchin	}
492da2e3ebchin	if(status&IOREAD)
493da2e3ebchin	{
494da2e3ebchin		if(!(bp = (char *)malloc(IOBSIZE+1)))
495da2e3ebchin			return(NIL(Sfio_t*));
496da2e3ebchin		flags |= SF_READ;
497da2e3ebchin		if(!(status&IOWRITE))
498da2e3ebchin			flags &= ~SF_WRITE;
499da2e3ebchin	}
500da2e3ebchin	else
5017c2fbfbApril Chin		bp = shp->outbuff;
502da2e3ebchin	if(status&IODUP)
503da2e3ebchin		flags |= SF_SHARE|SF_PUBLIC;
5047c2fbfbApril Chin	if((iop = shp->sftable[fd]) && sffileno(iop)>=0)
505da2e3ebchin		sfsetbuf(iop, bp, IOBSIZE);
506da2e3ebchin	else if(!(iop=sfnew((fd<=2?iop:0),bp,IOBSIZE,fd,flags)))
507da2e3ebchin		return(NIL(Sfio_t*));
508