1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1982-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
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
65da2e3ebdSchin #define RW_ALL (S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH)
66da2e3ebdSchin
67da2e3ebdSchin static void *timeout;
68da2e3ebdSchin static int (*fdnotify)(int,int);
69da2e3ebdSchin
70da2e3ebdSchin #if defined(_lib_socket) && defined(_sys_socket) && defined(_hdr_netinet_in)
71da2e3ebdSchin # include <sys/socket.h>
72da2e3ebdSchin # include <netdb.h>
73da2e3ebdSchin # include <netinet/in.h>
74da2e3ebdSchin # if !defined(htons) && !_lib_htons
75da2e3ebdSchin # define htons(x) (x)
76da2e3ebdSchin # endif
77da2e3ebdSchin # if !defined(htonl) && !_lib_htonl
78da2e3ebdSchin # define htonl(x) (x)
79da2e3ebdSchin # endif
80da2e3ebdSchin # if _pipe_socketpair
817c2fbfb3SApril Chin # ifndef SHUT_RD
827c2fbfb3SApril Chin # define SHUT_RD 0
837c2fbfb3SApril Chin # endif
847c2fbfb3SApril Chin # ifndef SHUT_WR
857c2fbfb3SApril Chin # define SHUT_WR 1
867c2fbfb3SApril Chin # endif
87da2e3ebdSchin # if _socketpair_shutdown_mode
887c2fbfb3SApril 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)
89da2e3ebdSchin # else
907c2fbfb3SApril 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)
91da2e3ebdSchin # endif
92da2e3ebdSchin # endif
93da2e3ebdSchin
94da2e3ebdSchin #if !_lib_getaddrinfo
95da2e3ebdSchin
96da2e3ebdSchin #undef EAI_SYSTEM
97da2e3ebdSchin
98da2e3ebdSchin #define EAI_SYSTEM 1
99da2e3ebdSchin
100da2e3ebdSchin #undef addrinfo
101da2e3ebdSchin #undef getaddrinfo
102da2e3ebdSchin #undef freeaddrinfo
103da2e3ebdSchin
104da2e3ebdSchin #define addrinfo local_addrinfo
105da2e3ebdSchin #define getaddrinfo local_getaddrinfo
106da2e3ebdSchin #define freeaddrinfo local_freeaddrinfo
107da2e3ebdSchin
108da2e3ebdSchin struct addrinfo
109da2e3ebdSchin {
110da2e3ebdSchin int ai_flags;
111da2e3ebdSchin int ai_family;
112da2e3ebdSchin int ai_socktype;
113da2e3ebdSchin int ai_protocol;
114da2e3ebdSchin socklen_t ai_addrlen;
115da2e3ebdSchin struct sockaddr* ai_addr;
116da2e3ebdSchin struct addrinfo* ai_next;
117da2e3ebdSchin };
118da2e3ebdSchin
119da2e3ebdSchin static int
getaddrinfo(const char * node,const char * service,const struct addrinfo * hint,struct addrinfo ** addr)120da2e3ebdSchin getaddrinfo(const char* node, const char* service, const struct addrinfo* hint, struct addrinfo **addr)
121da2e3ebdSchin {
122da2e3ebdSchin unsigned long ip_addr = 0;
123da2e3ebdSchin unsigned short ip_port = 0;
124da2e3ebdSchin struct addrinfo* ap;
125da2e3ebdSchin struct hostent* hp;
126da2e3ebdSchin struct sockaddr_in* ip;
127da2e3ebdSchin char* prot;
128da2e3ebdSchin long n;
129da2e3ebdSchin
130da2e3ebdSchin if (!(hp = gethostbyname(node)) || hp->h_addrtype!=AF_INET || hp->h_length>sizeof(struct in_addr))
131da2e3ebdSchin {
132da2e3ebdSchin errno = EADDRNOTAVAIL;
133da2e3ebdSchin return EAI_SYSTEM;
134da2e3ebdSchin }
135da2e3ebdSchin ip_addr = (unsigned long)((struct in_addr*)hp->h_addr)->s_addr;
136da2e3ebdSchin if ((n = strtol(service, &prot, 10)) > 0 && n <= USHRT_MAX && !*prot)
137da2e3ebdSchin ip_port = htons((unsigned short)n);
138da2e3ebdSchin else
139da2e3ebdSchin {
140da2e3ebdSchin struct servent* sp;
141da2e3ebdSchin const char* protocol = 0;
142da2e3ebdSchin
143da2e3ebdSchin if (hint)
144da2e3ebdSchin switch (hint->ai_socktype)
145da2e3ebdSchin {
146da2e3ebdSchin case SOCK_STREAM:
147da2e3ebdSchin switch (hint->ai_protocol)
148da2e3ebdSchin {
149da2e3ebdSchin case 0:
150da2e3ebdSchin protocol = "tcp";
151da2e3ebdSchin break;
152da2e3ebdSchin #ifdef IPPROTO_SCTP
153da2e3ebdSchin case IPPROTO_SCTP:
154da2e3ebdSchin protocol = "sctp";
155da2e3ebdSchin break;
156da2e3ebdSchin #endif
157da2e3ebdSchin }
158da2e3ebdSchin break;
159da2e3ebdSchin case SOCK_DGRAM:
160da2e3ebdSchin protocol = "udp";
161da2e3ebdSchin break;
162da2e3ebdSchin }
163da2e3ebdSchin if (!protocol)
164da2e3ebdSchin {
165da2e3ebdSchin errno = EPROTONOSUPPORT;
166da2e3ebdSchin return 1;
167da2e3ebdSchin }
168da2e3ebdSchin if (sp = getservbyname(service, protocol))
169da2e3ebdSchin ip_port = sp->s_port;
170da2e3ebdSchin }
171da2e3ebdSchin if (!ip_port)
172da2e3ebdSchin {
173da2e3ebdSchin errno = EADDRNOTAVAIL;
174da2e3ebdSchin return EAI_SYSTEM;
175da2e3ebdSchin }
176da2e3ebdSchin if (!(ap = newof(0, struct addrinfo, 1, sizeof(struct sockaddr_in))))
177da2e3ebdSchin return EAI_SYSTEM;
178da2e3ebdSchin if (hint)
179da2e3ebdSchin *ap = *hint;
180da2e3ebdSchin ap->ai_family = hp->h_addrtype;
181da2e3ebdSchin ap->ai_addrlen = sizeof(struct sockaddr_in);
182da2e3ebdSchin ap->ai_addr = (struct sockaddr *)(ap+1);
183da2e3ebdSchin ip = (struct sockaddr_in *)ap->ai_addr;
184da2e3ebdSchin ip->sin_family = AF_INET;
185da2e3ebdSchin ip->sin_port = ip_port;
186da2e3ebdSchin ip->sin_addr.s_addr = ip_addr;
187da2e3ebdSchin *addr = ap;
188da2e3ebdSchin return 0;
189da2e3ebdSchin }
190da2e3ebdSchin
191da2e3ebdSchin static void
freeaddrinfo(struct addrinfo * ap)192da2e3ebdSchin freeaddrinfo(struct addrinfo* ap)
193da2e3ebdSchin {
194da2e3ebdSchin if (ap)
195da2e3ebdSchin free(ap);
196da2e3ebdSchin }
197da2e3ebdSchin
198da2e3ebdSchin #endif
199da2e3ebdSchin
200da2e3ebdSchin /*
201da2e3ebdSchin * return <protocol>/<host>/<service> fd
202da2e3ebdSchin */
203da2e3ebdSchin
204da2e3ebdSchin typedef int (*Inetintr_f)(struct addrinfo*, void*);
205da2e3ebdSchin
206da2e3ebdSchin static int
inetopen(const char * path,int server,Inetintr_f onintr,void * handle)207da2e3ebdSchin inetopen(const char* path, int server, Inetintr_f onintr, void* handle)
208da2e3ebdSchin {
209da2e3ebdSchin register char* s;
210da2e3ebdSchin register char* t;
211da2e3ebdSchin int fd;
212da2e3ebdSchin int oerrno;
213da2e3ebdSchin struct addrinfo hint;
214da2e3ebdSchin struct addrinfo* addr;
215da2e3ebdSchin struct addrinfo* p;
216da2e3ebdSchin
217da2e3ebdSchin memset(&hint, 0, sizeof(hint));
218da2e3ebdSchin hint.ai_family = PF_UNSPEC;
219da2e3ebdSchin switch (path[0])
220da2e3ebdSchin {
221da2e3ebdSchin #ifdef IPPROTO_SCTP
222da2e3ebdSchin case 's':
223da2e3ebdSchin if (path[1]!='c' || path[2]!='t' || path[3]!='p' || path[4]!='/')
224da2e3ebdSchin {
225da2e3ebdSchin errno = ENOTDIR;
226da2e3ebdSchin return -1;
227da2e3ebdSchin }
228da2e3ebdSchin hint.ai_socktype = SOCK_STREAM;
229da2e3ebdSchin hint.ai_protocol = IPPROTO_SCTP;
230da2e3ebdSchin path += 5;
231da2e3ebdSchin break;
232da2e3ebdSchin #endif
233da2e3ebdSchin case 't':
234da2e3ebdSchin if (path[1]!='c' || path[2]!='p' || path[3]!='/')
235da2e3ebdSchin {
236da2e3ebdSchin errno = ENOTDIR;
237da2e3ebdSchin return -1;
238da2e3ebdSchin }
239da2e3ebdSchin hint.ai_socktype = SOCK_STREAM;
240da2e3ebdSchin path += 4;
241da2e3ebdSchin break;
242da2e3ebdSchin case 'u':
243da2e3ebdSchin if (path[1]!='d' || path[2]!='p' || path[3]!='/')
244da2e3ebdSchin {
245da2e3ebdSchin errno = ENOTDIR;
246da2e3ebdSchin return -1;
247da2e3ebdSchin }
248da2e3ebdSchin hint.ai_socktype = SOCK_DGRAM;
249da2e3ebdSchin path += 4;
250da2e3ebdSchin break;
251da2e3ebdSchin default:
252da2e3ebdSchin errno = ENOTDIR;
253da2e3ebdSchin return -1;
254da2e3ebdSchin }
255da2e3ebdSchin if (!(s = strdup(path)))
256da2e3ebdSchin return -1;
257da2e3ebdSchin if (t = strchr(s, '/'))
258da2e3ebdSchin {
259da2e3ebdSchin *t++ = 0;
260da2e3ebdSchin if (streq(s, "local"))
261da2e3ebdSchin s = "localhost";
262da2e3ebdSchin fd = getaddrinfo(s, t, &hint, &addr);
263da2e3ebdSchin }
264da2e3ebdSchin else
265da2e3ebdSchin fd = -1;
266da2e3ebdSchin free(s);
267da2e3ebdSchin if (fd)
268da2e3ebdSchin {
269da2e3ebdSchin if (fd != EAI_SYSTEM)
270da2e3ebdSchin errno = ENOTDIR;
271da2e3ebdSchin return -1;
272da2e3ebdSchin }
273da2e3ebdSchin oerrno = errno;
274da2e3ebdSchin errno = 0;
275da2e3ebdSchin fd = -1;
276da2e3ebdSchin for (p = addr; p; p = p->ai_next)
277da2e3ebdSchin {
278da2e3ebdSchin /*
279da2e3ebdSchin * some api's don't take the hint
280da2e3ebdSchin */
281da2e3ebdSchin
282da2e3ebdSchin if (!p->ai_protocol)
283da2e3ebdSchin p->ai_protocol = hint.ai_protocol;
284da2e3ebdSchin if (!p->ai_socktype)
285da2e3ebdSchin p->ai_socktype = hint.ai_socktype;
286da2e3ebdSchin while ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) >= 0)
287da2e3ebdSchin {
288da2e3ebdSchin if (server && !bind(fd, p->ai_addr, p->ai_addrlen) && !listen(fd, 5) || !server && !connect(fd, p->ai_addr, p->ai_addrlen))
289da2e3ebdSchin goto done;
290da2e3ebdSchin close(fd);
291da2e3ebdSchin fd = -1;
292da2e3ebdSchin if (errno != EINTR || !onintr)
293da2e3ebdSchin break;
294da2e3ebdSchin if ((*onintr)(addr, handle))
295da2e3ebdSchin return -1;
296da2e3ebdSchin }
297da2e3ebdSchin }
298da2e3ebdSchin done:
299da2e3ebdSchin freeaddrinfo(addr);
300da2e3ebdSchin if (fd >= 0)
301da2e3ebdSchin errno = oerrno;
302da2e3ebdSchin return fd;
303da2e3ebdSchin }
304da2e3ebdSchin
305da2e3ebdSchin #else
306da2e3ebdSchin
307da2e3ebdSchin #undef O_SERVICE
308da2e3ebdSchin
309da2e3ebdSchin #endif
310da2e3ebdSchin
311da2e3ebdSchin struct fdsave
312da2e3ebdSchin {
313da2e3ebdSchin int orig_fd; /* original file descriptor */
314da2e3ebdSchin int save_fd; /* saved file descriptor */
315da2e3ebdSchin int subshell; /* saved for subshell */
3167c2fbfb3SApril Chin char *tname; /* name used with >; */
317da2e3ebdSchin };
318da2e3ebdSchin
319da2e3ebdSchin static int subexcept(Sfio_t*, int, void*, Sfdisc_t*);
320da2e3ebdSchin static int eval_exceptf(Sfio_t*, int, void*, Sfdisc_t*);
321da2e3ebdSchin static int slowexcept(Sfio_t*, int, void*, Sfdisc_t*);
322da2e3ebdSchin static int pipeexcept(Sfio_t*, int, void*, Sfdisc_t*);
323da2e3ebdSchin static ssize_t piperead(Sfio_t*, void*, size_t, Sfdisc_t*);
324da2e3ebdSchin static ssize_t slowread(Sfio_t*, void*, size_t, Sfdisc_t*);
325da2e3ebdSchin static ssize_t subread(Sfio_t*, void*, size_t, Sfdisc_t*);
326da2e3ebdSchin static ssize_t tee_write(Sfio_t*,const void*,size_t,Sfdisc_t*);
327da2e3ebdSchin static int io_prompt(Sfio_t*,int);
3287c2fbfb3SApril Chin static int io_heredoc(Shell_t*,register struct ionod*, const char*, int);
3297c2fbfb3SApril Chin static void sftrack(Sfio_t*,int,void*);
330da2e3ebdSchin static const Sfdisc_t eval_disc = { NULL, NULL, NULL, eval_exceptf, NULL};
331da2e3ebdSchin static Sfdisc_t tee_disc = {NULL,tee_write,NULL,NULL,NULL};
3327c2fbfb3SApril Chin static Sfio_t *subopen(Shell_t *,Sfio_t*, off_t, long);
333da2e3ebdSchin static const Sfdisc_t sub_disc = { subread, 0, 0, subexcept, 0 };
334da2e3ebdSchin
335da2e3ebdSchin struct subfile
336da2e3ebdSchin {
337da2e3ebdSchin Sfdisc_t disc;
338da2e3ebdSchin Sfio_t *oldsp;
339da2e3ebdSchin off_t offset;
340da2e3ebdSchin long size;
341da2e3ebdSchin long left;
342da2e3ebdSchin };
343da2e3ebdSchin
344da2e3ebdSchin struct Eof
345da2e3ebdSchin {
346da2e3ebdSchin Namfun_t hdr;
347da2e3ebdSchin int fd;
348da2e3ebdSchin };
349da2e3ebdSchin
nget_cur_eof(register Namval_t * np,Namfun_t * fp)350da2e3ebdSchin static Sfdouble_t nget_cur_eof(register Namval_t* np, Namfun_t *fp)
351da2e3ebdSchin {
352da2e3ebdSchin struct Eof *ep = (struct Eof*)fp;
353da2e3ebdSchin Sfoff_t end, cur =lseek(ep->fd, (Sfoff_t)0, SEEK_CUR);
354da2e3ebdSchin if(*np->nvname=='C')
355da2e3ebdSchin return((Sfdouble_t)cur);
356da2e3ebdSchin if(cur<0)
357da2e3ebdSchin return((Sfdouble_t)-1);
358da2e3ebdSchin end =lseek(ep->fd, (Sfoff_t)0, SEEK_END);
359da2e3ebdSchin lseek(ep->fd, (Sfoff_t)0, SEEK_CUR);
360da2e3ebdSchin return((Sfdouble_t)end);
361da2e3ebdSchin }
362da2e3ebdSchin
363da2e3ebdSchin static const Namdisc_t EOF_disc = { sizeof(struct Eof), 0, 0, nget_cur_eof};
364da2e3ebdSchin
365da2e3ebdSchin #define MATCH_BUFF (64*1024)
366da2e3ebdSchin struct Match
367da2e3ebdSchin {
368da2e3ebdSchin Sfoff_t offset;
369da2e3ebdSchin char *base;
370da2e3ebdSchin };
371da2e3ebdSchin
matchf(void * handle,char * ptr,size_t size)372da2e3ebdSchin static int matchf(void *handle, char *ptr, size_t size)
373da2e3ebdSchin {
374da2e3ebdSchin struct Match *mp = (struct Match*)handle;
375da2e3ebdSchin mp->offset += (ptr-mp->base);
376da2e3ebdSchin return(1);
377da2e3ebdSchin }
378da2e3ebdSchin
379da2e3ebdSchin
380da2e3ebdSchin static struct fdsave *filemap;
381da2e3ebdSchin static short filemapsize;
382da2e3ebdSchin
383da2e3ebdSchin /* ======== input output and file copying ======== */
384da2e3ebdSchin
sh_ioinit(Shell_t * shp)3857c2fbfb3SApril Chin void sh_ioinit(Shell_t *shp)
386da2e3ebdSchin {
387da2e3ebdSchin register int n;
388da2e3ebdSchin filemapsize = 8;
3897c2fbfb3SApril Chin filemap = (struct fdsave*)malloc(filemapsize*sizeof(struct fdsave));
390da2e3ebdSchin #if SHOPT_FASTPIPE
3917c2fbfb3SApril Chin n = shp->lim.open_max+2;
392da2e3ebdSchin #else
3937c2fbfb3SApril Chin n = shp->lim.open_max;
394da2e3ebdSchin #endif /* SHOPT_FASTPIPE */
3957c2fbfb3SApril Chin shp->fdstatus = (unsigned char*)malloc((unsigned)n);
3967c2fbfb3SApril Chin memset((char*)shp->fdstatus,0,n);
3977c2fbfb3SApril Chin shp->fdptrs = (int**)malloc(n*sizeof(int*));
3987c2fbfb3SApril Chin memset((char*)shp->fdptrs,0,n*sizeof(int*));
3997c2fbfb3SApril Chin shp->sftable = (Sfio_t**)malloc(n*sizeof(Sfio_t*));
4007c2fbfb3SApril Chin memset((char*)shp->sftable,0,n*sizeof(Sfio_t*));
4017c2fbfb3SApril Chin shp->sftable[0] = sfstdin;
4027c2fbfb3SApril Chin shp->sftable[1] = sfstdout;
4037c2fbfb3SApril Chin shp->sftable[2] = sfstderr;
404da2e3ebdSchin sfnotify(sftrack);
4057c2fbfb3SApril Chin sh_iostream(shp,0);
406da2e3ebdSchin /* all write steams are in the same pool and share outbuff */
4077c2fbfb3SApril Chin shp->outpool = sfopen(NIL(Sfio_t*),NIL(char*),"sw"); /* pool identifier */
40834f9b3eeSRoland Mainz shp->outbuff = (char*)malloc(IOBSIZE+4);
4097c2fbfb3SApril Chin shp->errbuff = (char*)malloc(IOBSIZE/4);
4107c2fbfb3SApril Chin sfsetbuf(sfstderr,shp->errbuff,IOBSIZE/4);
4117c2fbfb3SApril Chin sfsetbuf(sfstdout,shp->outbuff,IOBSIZE);
4127c2fbfb3SApril Chin sfpool(sfstdout,shp->outpool,SF_WRITE);
4137c2fbfb3SApril Chin sfpool(sfstderr,shp->outpool,SF_WRITE);
414da2e3ebdSchin sfset(sfstdout,SF_LINE,0);
4157c2fbfb3SApril Chin sfset(sfstderr,SF_LINE,0);
4167c2fbfb3SApril Chin sfset(sfstdin,SF_SHARE|SF_PUBLIC,1);
4177c2fbfb3SApril Chin }
4187c2fbfb3SApril Chin
4197c2fbfb3SApril Chin /*
4207c2fbfb3SApril Chin * Handle output stream exceptions
4217c2fbfb3SApril Chin */
outexcept(register Sfio_t * iop,int type,void * data,Sfdisc_t * handle)4227c2fbfb3SApril Chin static int outexcept(register Sfio_t *iop,int type,void *data,Sfdisc_t *handle)
4237c2fbfb3SApril Chin {
4247c2fbfb3SApril Chin static int active = 0;
4257c2fbfb3SApril Chin
4267c2fbfb3SApril Chin NOT_USED(handle);
4277c2fbfb3SApril Chin if(type==SF_DPOP || type==SF_FINAL)
4287c2fbfb3SApril Chin free((void*)handle);
4297c2fbfb3SApril Chin else if(type==SF_WRITE && (*(ssize_t*)data)<0 && sffileno(iop)!=2)
4307c2fbfb3SApril Chin switch (errno)
4317c2fbfb3SApril Chin {
4327c2fbfb3SApril Chin case EINTR:
4337c2fbfb3SApril Chin case EPIPE:
4347c2fbfb3SApril Chin #ifdef ECONNRESET
4357c2fbfb3SApril Chin case ECONNRESET:
4367c2fbfb3SApril Chin #endif
4377c2fbfb3SApril Chin #ifdef ESHUTDOWN
4387c2fbfb3SApril Chin case ESHUTDOWN:
4397c2fbfb3SApril Chin #endif
4407c2fbfb3SApril Chin break;
4417c2fbfb3SApril Chin default:
4427c2fbfb3SApril Chin if(!active)
4437c2fbfb3SApril Chin {
4447c2fbfb3SApril Chin int mode = ((struct checkpt*)sh.jmplist)->mode;
4457c2fbfb3SApril Chin int save = errno;
4467c2fbfb3SApril Chin active = 1;
4477c2fbfb3SApril Chin ((struct checkpt*)sh.jmplist)->mode = 0;
4487c2fbfb3SApril Chin sfpurge(iop);
4497c2fbfb3SApril Chin sfpool(iop,NIL(Sfio_t*),SF_WRITE);
4507c2fbfb3SApril Chin errno = save;
4517c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_system(1),e_badwrite,sffileno(iop));
4527c2fbfb3SApril Chin active = 0;
4537c2fbfb3SApril Chin ((struct checkpt*)sh.jmplist)->mode = mode;
4547c2fbfb3SApril Chin sh_exit(1);
4557c2fbfb3SApril Chin }
4567c2fbfb3SApril Chin return(-1);
4577c2fbfb3SApril Chin }
4587c2fbfb3SApril Chin return(0);
459da2e3ebdSchin }
460da2e3ebdSchin
461da2e3ebdSchin /*
462da2e3ebdSchin * create or initialize a stream corresponding to descriptor <fd>
463da2e3ebdSchin * a buffer with room for a sentinal is allocated for a read stream.
464da2e3ebdSchin * A discipline is inserted when read stream is a tty or a pipe
465da2e3ebdSchin * For output streams, the buffer is set to sh.output and put into
466da2e3ebdSchin * the sh.outpool synchronization pool
467da2e3ebdSchin */
sh_iostream(Shell_t * shp,register int fd)4687c2fbfb3SApril Chin Sfio_t *sh_iostream(Shell_t *shp, register int fd)
469da2e3ebdSchin {
470da2e3ebdSchin register Sfio_t *iop;
4717c2fbfb3SApril Chin register int status = sh_iocheckfd(shp,fd);
472da2e3ebdSchin register int flags = SF_WRITE;
473da2e3ebdSchin char *bp;
4747c2fbfb3SApril Chin Sfdisc_t *dp;
475da2e3ebdSchin #if SHOPT_FASTPIPE
4767c2fbfb3SApril Chin if(fd>=shp->lim.open_max)
4777c2fbfb3SApril Chin return(shp->sftable[fd]);
478da2e3ebdSchin #endif /* SHOPT_FASTPIPE */
479da2e3ebdSchin if(status==IOCLOSE)
480da2e3ebdSchin {
481da2e3ebdSchin switch(fd)
482da2e3ebdSchin {
483da2e3ebdSchin case 0:
484da2e3ebdSchin return(sfstdin);
485da2e3ebdSchin case 1:
486da2e3ebdSchin return(sfstdout);
487da2e3ebdSchin case 2:
488da2e3ebdSchin return(sfstderr);
489da2e3ebdSchin }
490da2e3ebdSchin return(NIL(Sfio_t*));
491da2e3ebdSchin }
492da2e3ebdSchin if(status&IOREAD)
493da2e3ebdSchin {
494da2e3ebdSchin if(!(bp = (char *)malloc(IOBSIZE+1)))
495da2e3ebdSchin return(NIL(Sfio_t*));
496da2e3ebdSchin flags |= SF_READ;
497da2e3ebdSchin if(!(status&IOWRITE))
498da2e3ebdSchin flags &= ~SF_WRITE;
499da2e3ebdSchin }
500da2e3ebdSchin else
5017c2fbfb3SApril Chin bp = shp->outbuff;
502da2e3ebdSchin if(status&IODUP)
503da2e3ebdSchin flags |= SF_SHARE|SF_PUBLIC;
5047c2fbfb3SApril Chin if((iop = shp->sftable[fd]) && sffileno(iop)>=0)
505da2e3ebdSchin sfsetbuf(iop, bp, IOBSIZE);
506da2e3ebdSchin else if(!(iop=sfnew((fd<=2?iop:0),bp,IOBSIZE,fd,flags)))
507da2e3ebdSchin return(NIL(Sfio_t*));
5087c2fbfb3SApril Chin dp = newof(0,Sfdisc_t,1,0);
509da2e3ebdSchin if(status&IOREAD)
510da2e3ebdSchin {
511da2e3ebdSchin sfset(iop,SF_MALLOC,1);
5127c2fbfb3SApril Chin if(!(status&IOWRITE))
5137c2fbfb3SApril Chin sfset(iop,SF_IOCHECK,1);
514da2e3ebdSchin dp->exceptf = slowexcept;
515da2e3ebdSchin if(status&IOTTY)
516da2e3ebdSchin dp->readf = slowread;
517da2e3ebdSchin else if(status&IONOSEEK)
518da2e3ebdSchin {
519da2e3ebdSchin dp->readf = piperead;
520da2e3ebdSchin sfset(iop, SF_IOINTR,1);
521da2e3ebdSchin }
522da2e3ebdSchin else
523da2e3ebdSchin dp->readf = 0;
524da2e3ebdSchin dp->seekf = 0;
525da2e3ebdSchin dp->writef = 0;
526da2e3ebdSchin }
527da2e3ebdSchin else
5287c2fbfb3SApril Chin {
5297c2fbfb3SApril Chin dp->exceptf = outexcept;
5307c2fbfb3SApril Chin sfpool(iop,shp->outpool,SF_WRITE);
5317c2fbfb3SApril Chin }
5327c2fbfb3SApril Chin sfdisc(iop,dp);
5337c2fbfb3SApril Chin shp->sftable[fd] = iop;
534da2e3ebdSchin return(iop);
535da2e3ebdSchin }
536da2e3ebdSchin
537da2e3ebdSchin /*
538da2e3ebdSchin * preserve the file descriptor or stream by moving it
539da2e3ebdSchin */
io_preserve(Shell_t * shp,register Sfio_t * sp,register int f2)5407c2fbfb3SApril Chin static void io_preserve(Shell_t* shp, register Sfio_t *sp, register int f2)
541da2e3ebdSchin {
542da2e3ebdSchin register int fd;
543da2e3ebdSchin if(sp)
544da2e3ebdSchin fd = sfsetfd(sp,10);
545da2e3ebdSchin else
546da2e3ebdSchin fd = sh_fcntl(f2,F_DUPFD,10);
5477c2fbfb3SApril Chin if(f2==shp->infd)
5487c2fbfb3SApril Chin shp->infd = fd;
549da2e3ebdSchin if(fd<0)
55034f9b3eeSRoland Mainz {
55134f9b3eeSRoland Mainz shp->toomany = 1;
55234f9b3eeSRoland Mainz ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT;
553da2e3ebdSchin errormsg(SH_DICT,ERROR_system(1),e_toomany);
55434f9b3eeSRoland Mainz }
5557c2fbfb3SApril Chin if(shp->fdptrs[fd]=shp->fdptrs[f2])
556da2e3ebdSchin {
557da2e3ebdSchin if(f2==job.fd)
558da2e3ebdSchin job.fd=fd;
5597c2fbfb3SApril Chin *shp->fdptrs[fd] = fd;
5607c2fbfb3SApril Chin shp->fdptrs[f2] = 0;
561da2e3ebdSchin }
5627c2fbfb3SApril Chin shp->sftable[fd] = sp;
5637c2fbfb3SApril Chin shp->fdstatus[fd] = shp->fdstatus[f2];
564da2e3ebdSchin if(fcntl(f2,F_GETFD,0)&1)
565da2e3ebdSchin {
566da2e3ebdSchin fcntl(fd,F_SETFD,FD_CLOEXEC);
5677c2fbfb3SApril Chin shp->fdstatus[fd] |= IOCLEX;
568da2e3ebdSchin }
5697c2fbfb3SApril Chin shp->sftable[f2] = 0;
570da2e3ebdSchin }
571da2e3ebdSchin
572da2e3ebdSchin /*
573da2e3ebdSchin * Given a file descriptor <f1>, move it to a file descriptor number <f2>
574da2e3ebdSchin * If <f2> is needed move it, otherwise it is closed first.
575da2e3ebdSchin * The original stream <f1> is closed.
576da2e3ebdSchin * The new file descriptor <f2> is returned;
577da2e3ebdSchin */
sh_iorenumber(Shell_t * shp,register int f1,register int f2)5787c2fbfb3SApril Chin int sh_iorenumber(Shell_t *shp, register int f1,register int f2)
579da2e3ebdSchin {
5807c2fbfb3SApril Chin register Sfio_t *sp = shp->sftable[f2];
581da2e3ebdSchin if(f1!=f2)
582da2e3ebdSchin {
583da2e3ebdSchin /* see whether file descriptor is in use */
584da2e3ebdSchin if(sh_inuse(f2) || (f2>2 && sp))
585da2e3ebdSchin {
5867c2fbfb3SApril Chin if(!(shp->inuse_bits&(1<<f2)))
5877c2fbfb3SApril Chin io_preserve(shp,sp,f2);
588da2e3ebdSchin sp = 0;
589da2e3ebdSchin }
590da2e3ebdSchin else if(f2==0)
5917c2fbfb3SApril Chin shp->st.ioset = 1;
592da2e3ebdSchin sh_close(f2);
593da2e3ebdSchin if(f2<=2 && sp)
594da2e3ebdSchin {
5957c2fbfb3SApril Chin register Sfio_t *spnew = sh_iostream(shp,f1);
5967c2fbfb3SApril Chin shp->fdstatus[f2] = (shp->fdstatus[f1]&~IOCLEX);
597da2e3ebdSchin sfsetfd(spnew,f2);
598da2e3ebdSchin sfswap(spnew,sp);
599da2e3ebdSchin sfset(sp,SF_SHARE|SF_PUBLIC,1);
600da2e3ebdSchin }
601da2e3ebdSchin else
602da2e3ebdSchin {
6037c2fbfb3SApril Chin shp->fdstatus[f2] = (shp->fdstatus[f1]&~IOCLEX);
604da2e3ebdSchin if((f2 = sh_fcntl(f1,F_DUPFD, f2)) < 0)
605da2e3ebdSchin errormsg(SH_DICT,ERROR_system(1),e_file+4);
606da2e3ebdSchin else if(f2 <= 2)
6077c2fbfb3SApril Chin sh_iostream(shp,f2);
608da2e3ebdSchin }
609da2e3ebdSchin if(sp)
6107c2fbfb3SApril Chin shp->sftable[f1] = 0;
611da2e3ebdSchin sh_close(f1);
612da2e3ebdSchin }
613da2e3ebdSchin return(f2);
614da2e3ebdSchin }
615da2e3ebdSchin
616da2e3ebdSchin /*
617da2e3ebdSchin * close a file descriptor and update stream table and attributes
618da2e3ebdSchin */
sh_close(register int fd)619da2e3ebdSchin int sh_close(register int fd)
620da2e3ebdSchin {
621da2e3ebdSchin register Sfio_t *sp;
622da2e3ebdSchin register int r = 0;
623da2e3ebdSchin if(fd<0)
624da2e3ebdSchin return(-1);
625da2e3ebdSchin if(!(sp=sh.sftable[fd]) || sfclose(sp) < 0)
626da2e3ebdSchin {
627da2e3ebdSchin if(fdnotify)
628da2e3ebdSchin (*fdnotify)(fd,SH_FDCLOSE);
629da2e3ebdSchin r=close(fd);
630da2e3ebdSchin }
631da2e3ebdSchin if(fd>2)
632da2e3ebdSchin sh.sftable[fd] = 0;
633da2e3ebdSchin sh.fdstatus[fd] = IOCLOSE;
634da2e3ebdSchin if(sh.fdptrs[fd])
635da2e3ebdSchin *sh.fdptrs[fd] = -1;
636da2e3ebdSchin sh.fdptrs[fd] = 0;
637da2e3ebdSchin if(fd < 10)
638da2e3ebdSchin sh.inuse_bits &= ~(1<<fd);
639da2e3ebdSchin return(r);
640da2e3ebdSchin }
641da2e3ebdSchin
6427c2fbfb3SApril Chin #ifdef O_SERVICE
6437c2fbfb3SApril Chin
644da2e3ebdSchin static int
onintr(struct addrinfo * addr,void * handle)645da2e3ebdSchin onintr(struct addrinfo* addr, void* handle)
646da2e3ebdSchin {
647da2e3ebdSchin Shell_t* sh = (Shell_t*)handle;
648da2e3ebdSchin
649da2e3ebdSchin if (sh->trapnote&SH_SIGSET)
650da2e3ebdSchin {
651da2e3ebdSchin freeaddrinfo(addr);
652da2e3ebdSchin sh_exit(SH_EXITSIG);
653da2e3ebdSchin return -1;
654da2e3ebdSchin }
655da2e3ebdSchin if (sh->trapnote)
656da2e3ebdSchin sh_chktrap();
657da2e3ebdSchin return 0;
658da2e3ebdSchin }
659da2e3ebdSchin
6607c2fbfb3SApril Chin #endif
6617c2fbfb3SApril Chin
662da2e3ebdSchin /*
663da2e3ebdSchin * Mimic open(2) with checks for pseudo /dev/ files.
664da2e3ebdSchin */
sh_open(register const char * path,int flags,...)665da2e3ebdSchin int sh_open(register const char *path, int flags, ...)
666da2e3ebdSchin {
6677c2fbfb3SApril Chin Shell_t *shp = &sh;
668da2e3ebdSchin register int fd = -1;
669da2e3ebdSchin mode_t mode;
670da2e3ebdSchin char *e;
671da2e3ebdSchin va_list ap;
672da2e3ebdSchin va_start(ap, flags);
673da2e3ebdSchin mode = (flags & O_CREAT) ? va_arg(ap, int) : 0;
674da2e3ebdSchin va_end(ap);
675da2e3ebdSchin errno = 0;
676da2e3ebdSchin if(*path==0)
677da2e3ebdSchin {
678da2e3ebdSchin errno = ENOENT;
679da2e3ebdSchin return(-1);
680da2e3ebdSchin }
681da2e3ebdSchin if (path[0]=='/' && path[1]=='d' && path[2]=='e' && path[3]=='v' && path[4]=='/')
682da2e3ebdSchin {
683da2e3ebdSchin switch (path[5])
684da2e3ebdSchin {
685da2e3ebdSchin case 'f':
686da2e3ebdSchin if (path[6]=='d' && path[7]=='/')
687da2e3ebdSchin {
688da2e3ebdSchin fd = (int)strtol(path+8, &e, 10);
689da2e3ebdSchin if (*e)
690da2e3ebdSchin fd = -1;
691da2e3ebdSchin }
692da2e3ebdSchin break;
693da2e3ebdSchin case 's':
694da2e3ebdSchin if (path[6]=='t' && path[7]=='d')
695da2e3ebdSchin switch (path[8])
696da2e3ebdSchin {
697da2e3ebdSchin case 'e':
698da2e3ebdSchin if (path[9]=='r' && path[10]=='r' && !path[11])
699da2e3ebdSchin fd = 2;
700da2e3ebdSchin break;
701da2e3ebdSchin case 'i':
702da2e3ebdSchin if (path[9]=='n' && !path[10])
703da2e3ebdSchin fd = 0;
704da2e3ebdSchin break;
705da2e3ebdSchin case 'o':
706da2e3ebdSchin if (path[9]=='u' && path[10]=='t' && !path[11])
707da2e3ebdSchin fd = 1;
708da2e3ebdSchin break;
709da2e3ebdSchin }
710da2e3ebdSchin }
711da2e3ebdSchin #ifdef O_SERVICE
712da2e3ebdSchin if (fd < 0)
713da2e3ebdSchin {
714da2e3ebdSchin if ((fd = inetopen(path+5, !!(flags & O_SERVICE), onintr, &sh)) < 0 && errno != ENOTDIR)
715da2e3ebdSchin return -1;
716da2e3ebdSchin if (fd >= 0)
717da2e3ebdSchin goto ok;
718da2e3ebdSchin }
719da2e3ebdSchin #endif
720da2e3ebdSchin }
721da2e3ebdSchin if (fd >= 0)
722da2e3ebdSchin {
72334f9b3eeSRoland Mainz int nfd= -1;
72434f9b3eeSRoland Mainz if (flags & O_CREAT)
72534f9b3eeSRoland Mainz {
72634f9b3eeSRoland Mainz struct stat st;
72734f9b3eeSRoland Mainz if (stat(path,&st) >=0)
72834f9b3eeSRoland Mainz nfd = open(path,flags,st.st_mode);
72934f9b3eeSRoland Mainz }
73034f9b3eeSRoland Mainz else
73134f9b3eeSRoland Mainz nfd = open(path,flags);
73234f9b3eeSRoland Mainz if(nfd>=0)
73334f9b3eeSRoland Mainz {
73434f9b3eeSRoland Mainz fd = nfd;
73534f9b3eeSRoland Mainz goto ok;
73634f9b3eeSRoland Mainz }
7377c2fbfb3SApril Chin if((mode=sh_iocheckfd(shp,fd))==IOCLOSE)
738da2e3ebdSchin return(-1);
739da2e3ebdSchin flags &= O_ACCMODE;
740da2e3ebdSchin if(!(mode&IOWRITE) && ((flags==O_WRONLY) || (flags==O_RDWR)))
741da2e3ebdSchin return(-1);
742da2e3ebdSchin if(!(mode&IOREAD) && ((flags==O_RDONLY) || (flags==O_RDWR)))
743da2e3ebdSchin return(-1);
744da2e3ebdSchin if((fd=dup(fd))<0)
745da2e3ebdSchin return(-1);
746da2e3ebdSchin }
74734f9b3eeSRoland Mainz else
74834f9b3eeSRoland Mainz {
74934f9b3eeSRoland Mainz #if SHOPT_REGRESS
75034f9b3eeSRoland Mainz char buf[PATH_MAX];
75134f9b3eeSRoland Mainz if(strncmp(path,"/etc/",5)==0)
75234f9b3eeSRoland Mainz {
75334f9b3eeSRoland Mainz sfsprintf(buf, sizeof(buf), "%s%s", sh_regress_etc(path, __LINE__, __FILE__), path+4);
75434f9b3eeSRoland Mainz path = buf;
75534f9b3eeSRoland Mainz }
75634f9b3eeSRoland Mainz #endif
75734f9b3eeSRoland Mainz while((fd = open(path, flags, mode)) < 0)
758da2e3ebdSchin if(errno!=EINTR || sh.trapnote)
759da2e3ebdSchin return(-1);
76034f9b3eeSRoland Mainz }
761da2e3ebdSchin ok:
762da2e3ebdSchin flags &= O_ACCMODE;
763da2e3ebdSchin if(flags==O_WRONLY)
764da2e3ebdSchin mode = IOWRITE;
765da2e3ebdSchin else if(flags==O_RDWR)
766da2e3ebdSchin mode = (IOREAD|IOWRITE);
767da2e3ebdSchin else
768da2e3ebdSchin mode = IOREAD;
769da2e3ebdSchin sh.fdstatus[fd] = mode;
770da2e3ebdSchin return(fd);
771da2e3ebdSchin }
772da2e3ebdSchin
773da2e3ebdSchin /*
774da2e3ebdSchin * Open a file for reading
775da2e3ebdSchin * On failure, print message.
776da2e3ebdSchin */
sh_chkopen(register const char * name)777da2e3ebdSchin int sh_chkopen(register const char *name)
778da2e3ebdSchin {
779da2e3ebdSchin register int fd = sh_open(name,O_RDONLY,0);
780da2e3ebdSchin if(fd < 0)
781da2e3ebdSchin errormsg(SH_DICT,ERROR_system(1),e_open,name);
782da2e3ebdSchin return(fd);
783da2e3ebdSchin }
784da2e3ebdSchin
785da2e3ebdSchin /*
786da2e3ebdSchin * move open file descriptor to a number > 2
787da2e3ebdSchin */
sh_iomovefd(register int fdold)788da2e3ebdSchin int sh_iomovefd(register int fdold)
789da2e3ebdSchin {
790da2e3ebdSchin register int fdnew;
791da2e3ebdSchin if(fdold<0 || fdold>2)
792da2e3ebdSchin return(fdold);
793da2e3ebdSchin fdnew = sh_iomovefd(dup(fdold));
794da2e3ebdSchin sh.fdstatus[fdnew] = (sh.fdstatus[fdold]&~IOCLEX);
795da2e3ebdSchin close(fdold);
796da2e3ebdSchin sh.fdstatus[fdold] = IOCLOSE;
797da2e3ebdSchin return(fdnew);
798da2e3ebdSchin }
799da2e3ebdSchin
800da2e3ebdSchin /*
801da2e3ebdSchin * create a pipe and print message on failure
802da2e3ebdSchin */
sh_pipe(register int pv[])803da2e3ebdSchin int sh_pipe(register int pv[])
804da2e3ebdSchin {
805da2e3ebdSchin int fd[2];
806da2e3ebdSchin if(pipe(fd)<0 || (pv[0]=fd[0])<0 || (pv[1]=fd[1])<0)
807da2e3ebdSchin errormsg(SH_DICT,ERROR_system(1),e_pipe);
808da2e3ebdSchin pv[0] = sh_iomovefd(pv[0]);
809da2e3ebdSchin pv[1] = sh_iomovefd(pv[1]);
810da2e3ebdSchin sh.fdstatus[pv[0]] = IONOSEEK|IOREAD;
811da2e3ebdSchin sh.fdstatus[pv[1]] = IONOSEEK|IOWRITE;
812da2e3ebdSchin sh_subsavefd(pv[0]);
813da2e3ebdSchin sh_subsavefd(pv[1]);
814da2e3ebdSchin return(0);
815da2e3ebdSchin }
816da2e3ebdSchin
pat_seek(void * handle,const char * str,size_t sz)817da2e3ebdSchin static int pat_seek(void *handle, const char *str, size_t sz)
818da2e3ebdSchin {
819da2e3ebdSchin char **bp = (char**)handle;
820da2e3ebdSchin *bp = (char*)str;
821da2e3ebdSchin return(-1);
822da2e3ebdSchin }
823da2e3ebdSchin
pat_line(const regex_t * rp,const char * buff,register size_t n)824da2e3ebdSchin static int pat_line(const regex_t* rp, const char *buff, register size_t n)
825da2e3ebdSchin {
826da2e3ebdSchin register const char *cp=buff, *sp;
827da2e3ebdSchin while(n>0)
828da2e3ebdSchin {
829da2e3ebdSchin for(sp=cp; n-->0 && *cp++ != '\n';);
830da2e3ebdSchin if(regnexec(rp,sp,cp-sp, 0, (regmatch_t*)0, 0)==0)
831da2e3ebdSchin return(sp-buff);
832da2e3ebdSchin }
833da2e3ebdSchin return(cp-buff);
834da2e3ebdSchin }
835da2e3ebdSchin
io_patseek(Shell_t * shp,regex_t * rp,Sfio_t * sp,int flags)8367c2fbfb3SApril Chin static int io_patseek(Shell_t *shp, regex_t *rp, Sfio_t* sp, int flags)
837da2e3ebdSchin {
838da2e3ebdSchin char *cp, *match;
8397c2fbfb3SApril Chin int r, fd=sffileno(sp), close_exec = shp->fdstatus[fd]&IOCLEX;
840da2e3ebdSchin int was_share,s=(PIPE_BUF>SF_BUFSIZE?SF_BUFSIZE:PIPE_BUF);
841da2e3ebdSchin size_t n,m;
8427c2fbfb3SApril Chin shp->fdstatus[sffileno(sp)] |= IOCLEX;
843da2e3ebdSchin if(fd==0)
844da2e3ebdSchin was_share = sfset(sp,SF_SHARE,1);
845da2e3ebdSchin while((cp=sfreserve(sp, -s, SF_LOCKR)) || (cp=sfreserve(sp,SF_UNBOUND, SF_LOCKR)))
846da2e3ebdSchin {
847da2e3ebdSchin m = n = sfvalue(sp);
848da2e3ebdSchin while(n>0 && cp[n-1]!='\n')
849da2e3ebdSchin n--;
850da2e3ebdSchin if(n)
851da2e3ebdSchin m = n;
852da2e3ebdSchin r = regrexec(rp,cp,m,0,(regmatch_t*)0, 0, '\n', (void*)&match, pat_seek);
853da2e3ebdSchin if(r<0)
854da2e3ebdSchin m = match-cp;
855da2e3ebdSchin else if(r==2)
856da2e3ebdSchin {
857da2e3ebdSchin if((m = pat_line(rp,cp,m)) < n)
858da2e3ebdSchin r = -1;
859da2e3ebdSchin }
860da2e3ebdSchin if(m && (flags&IOCOPY))
861da2e3ebdSchin sfwrite(sfstdout,cp,m);
862da2e3ebdSchin sfread(sp,cp,m);
863da2e3ebdSchin if(r<0)
864da2e3ebdSchin break;
865da2e3ebdSchin }
866da2e3ebdSchin if(!close_exec)
8677c2fbfb3SApril Chin shp->fdstatus[sffileno(sp)] &= ~IOCLEX;
868da2e3ebdSchin if(fd==0 && !(was_share&SF_SHARE))
869da2e3ebdSchin sfset(sp, SF_SHARE,0);
870da2e3ebdSchin return(0);
871da2e3ebdSchin }
872da2e3ebdSchin
file_offset(Shell_t * shp,int fn,char * fname)8737c2fbfb3SApril Chin static Sfoff_t file_offset(Shell_t *shp, int fn, char *fname)
874da2e3ebdSchin {
8757c2fbfb3SApril Chin Sfio_t *sp = shp->sftable[fn];
876da2e3ebdSchin char *cp;
877da2e3ebdSchin Sfoff_t off;
878da2e3ebdSchin struct Eof endf;
8797c2fbfb3SApril Chin Namval_t *mp = nv_open("EOF",shp->var_tree,0);
8807c2fbfb3SApril Chin Namval_t *pp = nv_open("CUR",shp->var_tree,0);
881da2e3ebdSchin memset(&endf,0,sizeof(struct Eof));
882da2e3ebdSchin endf.fd = fn;
883da2e3ebdSchin endf.hdr.disc = &EOF_disc;
884da2e3ebdSchin endf.hdr.nofree = 1;
885da2e3ebdSchin if(mp)
886da2e3ebdSchin nv_stack(mp, &endf.hdr);
887da2e3ebdSchin if(pp)
888da2e3ebdSchin nv_stack(pp, &endf.hdr);
889da2e3ebdSchin if(sp)
890da2e3ebdSchin sfsync(sp);
891da2e3ebdSchin off = sh_strnum(fname, &cp, 0);
892da2e3ebdSchin if(mp)
893da2e3ebdSchin nv_stack(mp, NiL);
894da2e3ebdSchin if(pp)
895da2e3ebdSchin nv_stack(pp, NiL);
896da2e3ebdSchin return(*cp?(Sfoff_t)-1:off);
897da2e3ebdSchin }
898da2e3ebdSchin
899da2e3ebdSchin /*
900da2e3ebdSchin * close a pipe
901da2e3ebdSchin */
sh_pclose(register int pv[])902da2e3ebdSchin void sh_pclose(register int pv[])
903da2e3ebdSchin {
904da2e3ebdSchin if(pv[0]>=2)
905da2e3ebdSchin sh_close(pv[0]);
906da2e3ebdSchin if(pv[1]>=2)
907da2e3ebdSchin sh_close(pv[1]);
908da2e3ebdSchin pv[0] = pv[1] = -1;
909da2e3ebdSchin }
910da2e3ebdSchin
io_usename(char * name,int * perm,int mode)9117c2fbfb3SApril Chin static char *io_usename(char *name, int *perm, int mode)
9127c2fbfb3SApril Chin {
9137c2fbfb3SApril Chin struct stat statb;
9147c2fbfb3SApril Chin char *tname, *sp, *ep;
9157c2fbfb3SApril Chin int fd,len,n=0;
9167c2fbfb3SApril Chin if(mode==0)
9177c2fbfb3SApril Chin {
9187c2fbfb3SApril Chin if((fd = sh_open(name,O_RDONLY,0)) > 0)
9197c2fbfb3SApril Chin {
9207c2fbfb3SApril Chin if(fstat(fd,&statb) < 0)
9217c2fbfb3SApril Chin return(0);
9227c2fbfb3SApril Chin if(!S_ISREG(statb.st_mode))
9237c2fbfb3SApril Chin return(0);
9247c2fbfb3SApril Chin *perm = statb.st_mode&(RW_ALL|(S_IXUSR|S_IXGRP|S_IXOTH));
9257c2fbfb3SApril Chin }
9267c2fbfb3SApril Chin else if(fd < 0 && errno!=ENOENT)
9277c2fbfb3SApril Chin return(0);
9287c2fbfb3SApril Chin }
9297c2fbfb3SApril Chin tname = sp = (char*)stakalloc((len=strlen(name)) + 5);
9307c2fbfb3SApril Chin if(ep = strrchr(name,'/'))
9317c2fbfb3SApril Chin {
9327c2fbfb3SApril Chin memcpy(sp,name,n=++ep-name);
9337c2fbfb3SApril Chin len -=n;
9347c2fbfb3SApril Chin sp += n;
9357c2fbfb3SApril Chin }
9367c2fbfb3SApril Chin else
9377c2fbfb3SApril Chin ep = name;
9387c2fbfb3SApril Chin *sp++ = '.';
9397c2fbfb3SApril Chin memcpy(sp,ep,len);
9407c2fbfb3SApril Chin strcpy(sp+len,".tmp");
9417c2fbfb3SApril Chin switch(mode)
9427c2fbfb3SApril Chin {
9437c2fbfb3SApril Chin case 1:
9447c2fbfb3SApril Chin rename(tname,name);
9457c2fbfb3SApril Chin break;
9467c2fbfb3SApril Chin case 2:
9477c2fbfb3SApril Chin unlink(tname);
9487c2fbfb3SApril Chin break;
9497c2fbfb3SApril Chin }
9507c2fbfb3SApril Chin return(tname);
9517c2fbfb3SApril Chin }
9527c2fbfb3SApril Chin
953da2e3ebdSchin /*
954da2e3ebdSchin * I/O redirection
955da2e3ebdSchin * flag = 0 if files are to be restored
956da2e3ebdSchin * flag = 2 if files are to be closed on exec
957da2e3ebdSchin * flag = 3 when called from $( < ...), just open file and return
958da2e3ebdSchin * flag = SH_SHOWME for trace only
959da2e3ebdSchin */
sh_redirect(Shell_t * shp,struct ionod * iop,int flag)9607c2fbfb3SApril Chin int sh_redirect(Shell_t *shp,struct ionod *iop, int flag)
961da2e3ebdSchin {
962da2e3ebdSchin Sfoff_t off;
963da2e3ebdSchin register char *fname;
964da2e3ebdSchin register int fd, iof;
965da2e3ebdSchin const char *message = e_open;
966da2e3ebdSchin int o_mode; /* mode flag for open */
967da2e3ebdSchin static char io_op[7]; /* used for -x trace info */
96834f9b3eeSRoland Mainz int trunc=0, clexec=0, fn, traceon;
9697c2fbfb3SApril Chin int r, indx = shp->topfd, perm= -1;
9707c2fbfb3SApril Chin char *tname=0, *after="", *trace = shp->st.trap[SH_DEBUGTRAP];
971da2e3ebdSchin Namval_t *np=0;
97234f9b3eeSRoland Mainz int isstring = shp->subshell?(sfset(sfstdout,0,0)&SF_STRING):0;
973da2e3ebdSchin if(flag==2)
974da2e3ebdSchin clexec = 1;
975da2e3ebdSchin if(iop)
976da2e3ebdSchin traceon = sh_trace(NIL(char**),0);
977da2e3ebdSchin for(;iop;iop=iop->ionxt)
978da2e3ebdSchin {
979da2e3ebdSchin iof=iop->iofile;
980da2e3ebdSchin fn = (iof&IOUFD);
98134f9b3eeSRoland Mainz if(fn==1 && shp->subshell && !shp->subshare && (flag==2 || isstring))
9827c2fbfb3SApril Chin sh_subfork();
983da2e3ebdSchin io_op[0] = '0'+(iof&IOUFD);
984da2e3ebdSchin if(iof&IOPUT)
985da2e3ebdSchin {
986da2e3ebdSchin io_op[1] = '>';
987da2e3ebdSchin o_mode = O_WRONLY|O_CREAT;
988da2e3ebdSchin }
989da2e3ebdSchin else
990da2e3ebdSchin {
991da2e3ebdSchin io_op[1] = '<';
992da2e3ebdSchin o_mode = O_RDONLY|O_NONBLOCK;
993da2e3ebdSchin }
994da2e3ebdSchin io_op[2] = 0;
995da2e3ebdSchin io_op[3] = 0;
996da2e3ebdSchin io_op[4] = 0;
997da2e3ebdSchin fname = iop->ioname;
998da2e3ebdSchin if(!(iof&IORAW))
999da2e3ebdSchin {
1000da2e3ebdSchin if(iof&IOLSEEK)
1001da2e3ebdSchin {
1002da2e3ebdSchin struct argnod *ap = (struct argnod*)stakalloc(ARGVAL+strlen(iop->ioname));
1003da2e3ebdSchin memset(ap, 0, ARGVAL);
1004da2e3ebdSchin ap->argflag = ARG_MAC;
1005da2e3ebdSchin strcpy(ap->argval,iop->ioname);
10067c2fbfb3SApril Chin fname=sh_macpat(shp,ap,(iof&IOARITH)?ARG_ARITH:ARG_EXP);
1007da2e3ebdSchin }
100834f9b3eeSRoland Mainz else if(iof&IOPROCSUB)
100934f9b3eeSRoland Mainz {
101034f9b3eeSRoland Mainz struct argnod *ap = (struct argnod*)stakalloc(ARGVAL+strlen(iop->ioname));
101134f9b3eeSRoland Mainz memset(ap, 0, ARGVAL);
101234f9b3eeSRoland Mainz if(iof&IOPUT)
101334f9b3eeSRoland Mainz ap->argflag = ARG_RAW;
101434f9b3eeSRoland Mainz ap->argchn.ap = (struct argnod*)fname;
101534f9b3eeSRoland Mainz ap = sh_argprocsub(shp,ap);
101634f9b3eeSRoland Mainz fname = ap->argval;
101734f9b3eeSRoland Mainz }
1018da2e3ebdSchin else
10197c2fbfb3SApril Chin fname=sh_mactrim(shp,fname,(!sh_isoption(SH_NOGLOB)&&sh_isoption(SH_INTERACTIVE))?2:0);
1020da2e3ebdSchin }
1021da2e3ebdSchin errno=0;
10227c2fbfb3SApril Chin np = 0;
1023da2e3ebdSchin if(iop->iovname)
1024da2e3ebdSchin {
10257c2fbfb3SApril Chin np = nv_open(iop->iovname,shp->var_tree,NV_NOASSIGN|NV_VARNAME);
1026da2e3ebdSchin if(nv_isattr(np,NV_RDONLY))
1027da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np));
1028da2e3ebdSchin io_op[0] = '}';
10297c2fbfb3SApril Chin if((iof&IOLSEEK) || ((iof&IOMOV) && *fname=='-'))
1030da2e3ebdSchin fn = nv_getnum(np);
1031da2e3ebdSchin }
1032da2e3ebdSchin if(iof&IOLSEEK)
1033da2e3ebdSchin {
1034da2e3ebdSchin io_op[2] = '#';
1035da2e3ebdSchin if(iof&IOARITH)
1036da2e3ebdSchin {
1037da2e3ebdSchin strcpy(&io_op[3]," ((");
1038da2e3ebdSchin after = "))";
1039da2e3ebdSchin }
1040da2e3ebdSchin else if(iof&IOCOPY)
1041da2e3ebdSchin io_op[3] = '#';
1042da2e3ebdSchin goto traceit;
1043da2e3ebdSchin }
1044da2e3ebdSchin if(*fname)
1045da2e3ebdSchin {
1046da2e3ebdSchin if(iof&IODOC)
1047da2e3ebdSchin {
1048da2e3ebdSchin if(traceon)
1049da2e3ebdSchin sfputr(sfstderr,io_op,'<');
10507c2fbfb3SApril Chin fd = io_heredoc(shp,iop,fname,traceon);
1051da2e3ebdSchin if(traceon && (flag==SH_SHOWME))
1052da2e3ebdSchin sh_close(fd);
1053da2e3ebdSchin fname = 0;
1054da2e3ebdSchin }
1055da2e3ebdSchin else if(iof&IOMOV)
1056da2e3ebdSchin {
1057da2e3ebdSchin int dupfd,toclose= -1;
1058da2e3ebdSchin io_op[2] = '&';
1059da2e3ebdSchin if((fd=fname[0])>='0' && fd<='9')
1060da2e3ebdSchin {
1061da2e3ebdSchin char *number = fname;
1062da2e3ebdSchin dupfd = strtol(fname,&number,10);
1063da2e3ebdSchin if(*number=='-')
1064da2e3ebdSchin {
1065da2e3ebdSchin toclose = dupfd;
1066da2e3ebdSchin number++;
1067da2e3ebdSchin }
1068da2e3ebdSchin if(*number || dupfd > IOUFD)
1069da2e3ebdSchin {
1070da2e3ebdSchin message = e_file;
1071da2e3ebdSchin goto fail;
1072da2e3ebdSchin }
107334f9b3eeSRoland Mainz if(shp->subshell && dupfd==1 && (sfset(sfstdout,0,0)&SF_STRING))
1074da2e3ebdSchin {
10757c2fbfb3SApril Chin sh_subtmpfile(0);
1076da2e3ebdSchin dupfd = sffileno(sfstdout);
1077da2e3ebdSchin }
10787c2fbfb3SApril Chin else if(shp->sftable[dupfd])
10797c2fbfb3SApril Chin sfsync(shp->sftable[dupfd]);
1080da2e3ebdSchin }
1081da2e3ebdSchin else if(fd=='-' && fname[1]==0)
1082da2e3ebdSchin {
1083da2e3ebdSchin fd= -1;
1084da2e3ebdSchin goto traceit;
1085da2e3ebdSchin }
1086da2e3ebdSchin else if(fd=='p' && fname[1]==0)
1087da2e3ebdSchin {
1088da2e3ebdSchin if(iof&IOPUT)
10897c2fbfb3SApril Chin dupfd = shp->coutpipe;
1090da2e3ebdSchin else
10917c2fbfb3SApril Chin dupfd = shp->cpipe[0];
1092da2e3ebdSchin if(flag)
1093da2e3ebdSchin toclose = dupfd;
1094da2e3ebdSchin }
1095da2e3ebdSchin else
1096da2e3ebdSchin {
1097da2e3ebdSchin message = e_file;
1098da2e3ebdSchin goto fail;
1099da2e3ebdSchin }
1100da2e3ebdSchin if(flag==SH_SHOWME)
1101da2e3ebdSchin goto traceit;
1102da2e3ebdSchin if((fd=sh_fcntl(dupfd,F_DUPFD,3))<0)
1103da2e3ebdSchin goto fail;
11047c2fbfb3SApril Chin sh_iocheckfd(shp,dupfd);
11057c2fbfb3SApril Chin shp->fdstatus[fd] = (shp->fdstatus[dupfd]&~IOCLEX);
11067c2fbfb3SApril Chin if(toclose<0 && shp->fdstatus[fd]&IOREAD)
11077c2fbfb3SApril Chin shp->fdstatus[fd] |= IODUP;
11087c2fbfb3SApril Chin else if(dupfd==shp->cpipe[0])
11097c2fbfb3SApril Chin sh_pclose(shp->cpipe);
1110da2e3ebdSchin else if(toclose>=0)
1111da2e3ebdSchin {
1112da2e3ebdSchin if(flag==0)
11137c2fbfb3SApril Chin sh_iosave(shp,toclose,indx,(char*)0); /* save file descriptor */
1114da2e3ebdSchin sh_close(toclose);
1115da2e3ebdSchin }
1116da2e3ebdSchin }
1117da2e3ebdSchin else if(iof&IORDW)
1118da2e3ebdSchin {
1119da2e3ebdSchin if(sh_isoption(SH_RESTRICTED))
1120da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_restricted,fname);
1121da2e3ebdSchin io_op[2] = '>';
1122da2e3ebdSchin o_mode = O_RDWR|O_CREAT;
112334f9b3eeSRoland Mainz if(iof&IOREWRITE)
112434f9b3eeSRoland Mainz trunc = io_op[2] = ';';
1125da2e3ebdSchin goto openit;
1126da2e3ebdSchin }
1127da2e3ebdSchin else if(!(iof&IOPUT))
1128da2e3ebdSchin {
1129da2e3ebdSchin if(flag==SH_SHOWME)
1130da2e3ebdSchin goto traceit;
1131da2e3ebdSchin fd=sh_chkopen(fname);
1132da2e3ebdSchin }
1133da2e3ebdSchin else if(sh_isoption(SH_RESTRICTED))
1134da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_restricted,fname);
1135da2e3ebdSchin else
1136da2e3ebdSchin {
1137da2e3ebdSchin if(iof&IOAPP)
1138da2e3ebdSchin {
1139da2e3ebdSchin io_op[2] = '>';
1140da2e3ebdSchin o_mode |= O_APPEND;
1141da2e3ebdSchin }
11427c2fbfb3SApril Chin else if((iof&IOREWRITE) && (flag==0 || flag==1 || sh_subsavefd(fn)))
11437c2fbfb3SApril Chin {
11447c2fbfb3SApril Chin io_op[2] = ';';
11457c2fbfb3SApril Chin o_mode |= O_TRUNC;
11467c2fbfb3SApril Chin tname = io_usename(fname,&perm,0);
11477c2fbfb3SApril Chin }
1148da2e3ebdSchin else
1149da2e3ebdSchin {
1150da2e3ebdSchin o_mode |= O_TRUNC;
1151da2e3ebdSchin if(iof&IOCLOB)
1152da2e3ebdSchin io_op[2] = '|';
1153da2e3ebdSchin else if(sh_isoption(SH_NOCLOBBER))
1154da2e3ebdSchin {
1155da2e3ebdSchin struct stat sb;
1156da2e3ebdSchin if(stat(fname,&sb)>=0)
1157da2e3ebdSchin {
1158da2e3ebdSchin #if SHOPT_FS_3D
1159da2e3ebdSchin if(S_ISREG(sb.st_mode)&&
11607c2fbfb3SApril Chin (!shp->lim.fs3d || iview(&sb)==0))
1161da2e3ebdSchin #else
1162da2e3ebdSchin if(S_ISREG(sb.st_mode))
1163da2e3ebdSchin #endif /* SHOPT_FS_3D */
1164da2e3ebdSchin {
1165da2e3ebdSchin errno = EEXIST;
1166da2e3ebdSchin errormsg(SH_DICT,ERROR_system(1),e_exists,fname);
1167da2e3ebdSchin }
1168da2e3ebdSchin }
1169da2e3ebdSchin else
1170da2e3ebdSchin o_mode |= O_EXCL;
1171da2e3ebdSchin }
1172da2e3ebdSchin }
1173da2e3ebdSchin openit:
1174da2e3ebdSchin if(flag!=SH_SHOWME)
1175da2e3ebdSchin {
11767c2fbfb3SApril Chin if((fd=sh_open(tname?tname:fname,o_mode,RW_ALL)) <0)
1177da2e3ebdSchin errormsg(SH_DICT,ERROR_system(1),((o_mode&O_CREAT)?e_create:e_open),fname);
11787c2fbfb3SApril Chin if(perm>0)
11797c2fbfb3SApril Chin #if _lib_fchmod
11807c2fbfb3SApril Chin fchmod(fd,perm);
11817c2fbfb3SApril Chin #else
11827c2fbfb3SApril Chin chmod(tname,perm);
11837c2fbfb3SApril Chin #endif
1184da2e3ebdSchin }
1185da2e3ebdSchin }
1186da2e3ebdSchin traceit:
1187da2e3ebdSchin if(traceon && fname)
1188da2e3ebdSchin {
1189da2e3ebdSchin if(np)
1190da2e3ebdSchin sfprintf(sfstderr,"{%s",nv_name(np));
1191da2e3ebdSchin sfprintf(sfstderr,"%s %s%s%c",io_op,fname,after,iop->ionxt?' ':'\n');
1192da2e3ebdSchin }
1193da2e3ebdSchin if(flag==SH_SHOWME)
1194da2e3ebdSchin return(indx);
1195da2e3ebdSchin if(trace && fname)
1196da2e3ebdSchin {
1197da2e3ebdSchin char *argv[7], **av=argv;
1198da2e3ebdSchin av[3] = io_op;
1199da2e3ebdSchin av[4] = fname;
1200da2e3ebdSchin av[5] = 0;
1201da2e3ebdSchin av[6] = 0;
1202da2e3ebdSchin if(iof&IOARITH)
1203da2e3ebdSchin av[5] = after;
1204da2e3ebdSchin if(np)
1205da2e3ebdSchin {
1206da2e3ebdSchin av[0] = "{";
1207da2e3ebdSchin av[1] = nv_name(np);
1208da2e3ebdSchin av[2] = "}";
1209da2e3ebdSchin }
1210da2e3ebdSchin else
1211da2e3ebdSchin av +=3;
12127c2fbfb3SApril Chin sh_debug(shp,trace,(char*)0,(char*)0,av,ARG_NOGLOB);
1213da2e3ebdSchin }
1214da2e3ebdSchin if(iof&IOLSEEK)
1215da2e3ebdSchin {
12167c2fbfb3SApril Chin Sfio_t *sp = shp->sftable[fn];
12177c2fbfb3SApril Chin r = shp->fdstatus[fn];
1218da2e3ebdSchin if(!(r&(IOSEEK|IONOSEEK)))
12197c2fbfb3SApril Chin r = sh_iocheckfd(shp,fn);
1220da2e3ebdSchin sfsprintf(io_op,sizeof(io_op),"%d\0",fn);
1221da2e3ebdSchin if(r==IOCLOSE)
1222da2e3ebdSchin {
1223da2e3ebdSchin fname = io_op;
1224da2e3ebdSchin message = e_file;
1225da2e3ebdSchin goto fail;
1226da2e3ebdSchin }
1227da2e3ebdSchin if(iof&IOARITH)
1228da2e3ebdSchin {
1229da2e3ebdSchin if(r&IONOSEEK)
1230da2e3ebdSchin {
1231da2e3ebdSchin fname = io_op;
1232da2e3ebdSchin message = e_notseek;
1233da2e3ebdSchin goto fail;
1234da2e3ebdSchin }
1235da2e3ebdSchin message = e_badseek;
12367c2fbfb3SApril Chin if((off = file_offset(shp,fn,fname))<0)
1237da2e3ebdSchin goto fail;
1238da2e3ebdSchin if(sp)
123934f9b3eeSRoland Mainz {
12407c2fbfb3SApril Chin off=sfseek(sp, off, SEEK_SET);
124134f9b3eeSRoland Mainz sfsync(sp);
124234f9b3eeSRoland Mainz }
1243da2e3ebdSchin else
12447c2fbfb3SApril Chin off=lseek(fn, off, SEEK_SET);
12457c2fbfb3SApril Chin if(off<0)
12467c2fbfb3SApril Chin r = -1;
1247da2e3ebdSchin }
1248da2e3ebdSchin else
1249da2e3ebdSchin {
1250da2e3ebdSchin regex_t *rp;
1251da2e3ebdSchin extern const char e_notimp[];
1252da2e3ebdSchin if(!(r&IOREAD))
1253da2e3ebdSchin {
1254da2e3ebdSchin message = e_noread;
1255da2e3ebdSchin goto fail;
1256da2e3ebdSchin }
1257da2e3ebdSchin if(!(rp = regcache(fname, REG_SHELL|REG_NOSUB|REG_NEWLINE|REG_AUGMENTED|REG_FIRST|REG_LEFT|REG_RIGHT, &r)))
1258da2e3ebdSchin {
1259da2e3ebdSchin message = e_badpattern;
1260da2e3ebdSchin goto fail;
1261da2e3ebdSchin }
1262da2e3ebdSchin if(!sp)
12637c2fbfb3SApril Chin sp = sh_iostream(shp,fn);
12647c2fbfb3SApril Chin r=io_patseek(shp,rp,sp,iof);
1265da2e3ebdSchin if(sp && flag==3)
1266da2e3ebdSchin {
1267da2e3ebdSchin /* close stream but not fn */
1268da2e3ebdSchin sfsetfd(sp,-1);
1269da2e3ebdSchin sfclose(sp);
1270da2e3ebdSchin }
1271da2e3ebdSchin }
1272da2e3ebdSchin if(r<0)
1273da2e3ebdSchin goto fail;
1274da2e3ebdSchin if(flag==3)
1275da2e3ebdSchin return(fn);
1276da2e3ebdSchin continue;
1277da2e3ebdSchin }
1278da2e3ebdSchin if(!np)
1279da2e3ebdSchin {
12807c2fbfb3SApril Chin if(flag==0 || tname)
1281da2e3ebdSchin {
1282da2e3ebdSchin if(fd==fn)
1283da2e3ebdSchin {
1284da2e3ebdSchin if((r=sh_fcntl(fd,F_DUPFD,10)) > 0)
1285da2e3ebdSchin {
1286da2e3ebdSchin fd = r;
1287da2e3ebdSchin sh_close(fn);
1288da2e3ebdSchin }
1289da2e3ebdSchin }
129034f9b3eeSRoland Mainz sh_iosave(shp,fn,indx,tname?fname:(trunc?Empty:0));
1291da2e3ebdSchin }
1292da2e3ebdSchin else if(sh_subsavefd(fn))
12937c2fbfb3SApril Chin sh_iosave(shp,fn,indx|IOSUBSHELL,tname?fname:0);
1294da2e3ebdSchin }
1295da2e3ebdSchin if(fd<0)
1296da2e3ebdSchin {
1297*3e14f97fSRoger A. Faulkner if(sh_inuse(fn) || (fn && fn==shp->infd))
1298da2e3ebdSchin {
12997c2fbfb3SApril Chin if(fn>9 || !(shp->inuse_bits&(1<<fn)))
13007c2fbfb3SApril Chin io_preserve(shp,shp->sftable[fn],fn);
1301da2e3ebdSchin }
1302da2e3ebdSchin sh_close(fn);
1303da2e3ebdSchin }
1304da2e3ebdSchin if(flag==3)
1305da2e3ebdSchin return(fd);
1306da2e3ebdSchin if(fd>=0)
1307da2e3ebdSchin {
1308da2e3ebdSchin if(np)
1309da2e3ebdSchin {
1310da2e3ebdSchin int32_t v;
1311da2e3ebdSchin fn = fd;
1312da2e3ebdSchin if(fd<10)
1313da2e3ebdSchin {
1314da2e3ebdSchin if((fn=fcntl(fd,F_DUPFD,10)) < 0)
1315da2e3ebdSchin goto fail;
13167c2fbfb3SApril Chin shp->fdstatus[fn] = shp->fdstatus[fd];
1317da2e3ebdSchin sh_close(fd);
1318da2e3ebdSchin fd = fn;
1319da2e3ebdSchin }
1320da2e3ebdSchin nv_unset(np);
1321da2e3ebdSchin nv_onattr(np,NV_INT32);
1322da2e3ebdSchin v = fn;
1323da2e3ebdSchin nv_putval(np,(char*)&v, NV_INT32);
13247c2fbfb3SApril Chin sh_iocheckfd(shp,fd);
1325da2e3ebdSchin }
1326da2e3ebdSchin else
1327da2e3ebdSchin {
13287c2fbfb3SApril Chin fd = sh_iorenumber(shp,sh_iomovefd(fd),fn);
1329da2e3ebdSchin if(fn>2 && fn<10)
13307c2fbfb3SApril Chin shp->inuse_bits |= (1<<fn);
1331da2e3ebdSchin }
1332da2e3ebdSchin }
1333da2e3ebdSchin if(fd >2 && clexec)
1334da2e3ebdSchin {
1335da2e3ebdSchin fcntl(fd,F_SETFD,FD_CLOEXEC);
13367c2fbfb3SApril Chin shp->fdstatus[fd] |= IOCLEX;
1337da2e3ebdSchin }
1338da2e3ebdSchin }
1339da2e3ebdSchin else
1340da2e3ebdSchin goto fail;
1341da2e3ebdSchin }
1342da2e3ebdSchin return(indx);
1343da2e3ebdSchin fail:
1344da2e3ebdSchin errormsg(SH_DICT,ERROR_system(1),message,fname);
1345da2e3ebdSchin /* NOTREACHED */
1346da2e3ebdSchin return(0);
1347da2e3ebdSchin }
1348da2e3ebdSchin /*
1349da2e3ebdSchin * Create a tmp file for the here-document
1350da2e3ebdSchin */
io_heredoc(Shell_t * shp,register struct ionod * iop,const char * name,int traceon)13517c2fbfb3SApril Chin static int io_heredoc(Shell_t *shp,register struct ionod *iop, const char *name, int traceon)
1352da2e3ebdSchin {
1353da2e3ebdSchin register Sfio_t *infile = 0, *outfile;
1354da2e3ebdSchin register int fd;
13557c2fbfb3SApril Chin if(!(iop->iofile&IOSTRG) && (!shp->heredocs || iop->iosize==0))
1356da2e3ebdSchin return(sh_open(e_devnull,O_RDONLY));
1357da2e3ebdSchin /* create an unnamed temporary file */
1358da2e3ebdSchin if(!(outfile=sftmp(0)))
1359da2e3ebdSchin errormsg(SH_DICT,ERROR_system(1),e_tmpcreate);
1360da2e3ebdSchin if(iop->iofile&IOSTRG)
1361da2e3ebdSchin {
1362da2e3ebdSchin if(traceon)
1363da2e3ebdSchin sfprintf(sfstderr,"< %s\n",name);
1364da2e3ebdSchin sfputr(outfile,name,'\n');
1365da2e3ebdSchin }
1366da2e3ebdSchin else
1367da2e3ebdSchin {
13687c2fbfb3SApril Chin infile = subopen(shp,shp->heredocs,iop->iooffset,iop->iosize);
1369da2e3ebdSchin if(traceon)
1370da2e3ebdSchin {
1371da2e3ebdSchin char *cp = sh_fmtq(iop->iodelim);
1372da2e3ebdSchin fd = (*cp=='$' || *cp=='\'')?' ':'\\';
1373da2e3ebdSchin sfprintf(sfstderr," %c%s\n",fd,cp);
1374da2e3ebdSchin sfdisc(outfile,&tee_disc);
1375da2e3ebdSchin }
1376da2e3ebdSchin if(iop->iofile&IOQUOTE)
1377da2e3ebdSchin {
1378da2e3ebdSchin /* This is a quoted here-document, not expansion */
1379da2e3ebdSchin sfmove(infile,outfile,SF_UNBOUND,-1);
1380da2e3ebdSchin sfclose(infile);
1381da2e3ebdSchin }
1382da2e3ebdSchin else
1383da2e3ebdSchin {
13847c2fbfb3SApril Chin char *lastpath = shp->lastpath;
13857c2fbfb3SApril Chin sh_machere(shp,infile,outfile,iop->ioname);
13867c2fbfb3SApril Chin shp->lastpath = lastpath;
1387da2e3ebdSchin if(infile)
1388da2e3ebdSchin sfclose(infile);
1389da2e3ebdSchin }
1390da2e3ebdSchin }
1391da2e3ebdSchin /* close stream outfile, but save file descriptor */
1392da2e3ebdSchin fd = sffileno(outfile);
1393da2e3ebdSchin sfsetfd(outfile,-1);
1394da2e3ebdSchin sfclose(outfile);
1395da2e3ebdSchin if(traceon && !(iop->iofile&IOSTRG))
1396da2e3ebdSchin sfputr(sfstderr,iop->ioname,'\n');
1397da2e3ebdSchin lseek(fd,(off_t)0,SEEK_SET);
13987c2fbfb3SApril Chin shp->fdstatus[fd] = IOREAD;
1399da2e3ebdSchin return(fd);
1400da2e3ebdSchin }
1401da2e3ebdSchin
1402da2e3ebdSchin /*
1403da2e3ebdSchin * This write discipline also writes the output on standard error
1404da2e3ebdSchin * This is used when tracing here-documents
1405da2e3ebdSchin */
tee_write(Sfio_t * iop,const void * buff,size_t n,Sfdisc_t * unused)1406da2e3ebdSchin static ssize_t tee_write(Sfio_t *iop,const void *buff,size_t n,Sfdisc_t *unused)
1407da2e3ebdSchin {
1408da2e3ebdSchin NOT_USED(unused);
1409da2e3ebdSchin sfwrite(sfstderr,buff,n);
1410da2e3ebdSchin return(write(sffileno(iop),buff,n));
1411da2e3ebdSchin }
1412da2e3ebdSchin
1413da2e3ebdSchin /*
1414da2e3ebdSchin * copy file <origfd> into a save place
1415da2e3ebdSchin * The saved file is set close-on-exec
1416da2e3ebdSchin * if <origfd> < 0, then -origfd is saved, but not duped so that it
1417da2e3ebdSchin * will be closed with sh_iorestore.
1418da2e3ebdSchin */
sh_iosave(Shell_t * shp,register int origfd,int oldtop,char * name)14197c2fbfb3SApril Chin void sh_iosave(Shell_t *shp, register int origfd, int oldtop, char *name)
1420da2e3ebdSchin {
1421da2e3ebdSchin /*@
14227c2fbfb3SApril Chin assume oldtop>=0 && oldtop<shp->lim.open_max;
1423da2e3ebdSchin @*/
1424da2e3ebdSchin
1425da2e3ebdSchin register int savefd;
1426da2e3ebdSchin int flag = (oldtop&IOSUBSHELL);
1427da2e3ebdSchin oldtop &= ~IOSUBSHELL;
1428da2e3ebdSchin /* see if already saved, only save once */
14297c2fbfb3SApril Chin for(savefd=shp->topfd; --savefd>=oldtop; )
1430da2e3ebdSchin {
1431da2e3ebdSchin if(filemap[savefd].orig_fd == origfd)
1432da2e3ebdSchin return;
1433da2e3ebdSchin }
1434da2e3ebdSchin /* make sure table is large enough */
14357c2fbfb3SApril Chin if(shp->topfd >= filemapsize)
1436da2e3ebdSchin {
14377c2fbfb3SApril Chin char *cp, *oldptr = (char*)filemap;
14387c2fbfb3SApril Chin char *oldend = (char*)&filemap[filemapsize];
14397c2fbfb3SApril Chin long moved;
1440da2e3ebdSchin filemapsize += 8;
1441da2e3ebdSchin if(!(filemap = (struct fdsave*)realloc(filemap,filemapsize*sizeof(struct fdsave))))
1442da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(4),e_nospace);
14437c2fbfb3SApril Chin if(moved = (char*)filemap - oldptr)
14447c2fbfb3SApril Chin {
14457c2fbfb3SApril Chin #if SHOPT_FASTPIPE
14467c2fbfb3SApril Chin for(savefd=shp->lim.open_max+2; --savefd>=0; )
14477c2fbfb3SApril Chin #else
14487c2fbfb3SApril Chin for(savefd=shp->lim.open_max; --savefd>=0; )
14497c2fbfb3SApril Chin #endif /* SHOPT_FASTPIPE */
14507c2fbfb3SApril Chin {
14517c2fbfb3SApril Chin cp = (char*)shp->fdptrs[savefd];
14527c2fbfb3SApril Chin if(cp >= oldptr && cp < oldend)
14537c2fbfb3SApril Chin shp->fdptrs[savefd] = (int*)(oldptr+moved);
14547c2fbfb3SApril Chin }
14557c2fbfb3SApril Chin }
1456da2e3ebdSchin }
1457da2e3ebdSchin #if SHOPT_DEVFD
1458da2e3ebdSchin if(origfd <0)
1459da2e3ebdSchin {
1460da2e3ebdSchin savefd = origfd;
1461da2e3ebdSchin origfd = -origfd;
1462da2e3ebdSchin }
1463da2e3ebdSchin else
1464da2e3ebdSchin #endif /* SHOPT_DEVFD */
1465da2e3ebdSchin {
1466da2e3ebdSchin if((savefd = sh_fcntl(origfd, F_DUPFD, 10)) < 0 && errno!=EBADF)
146734f9b3eeSRoland Mainz {
146834f9b3eeSRoland Mainz shp->toomany=1;
146934f9b3eeSRoland Mainz ((struct checkpt*)shp->jmplist)->mode = SH_JMPERREXIT;
1470da2e3ebdSchin errormsg(SH_DICT,ERROR_system(1),e_toomany);
1471da2e3ebdSchin }
147234f9b3eeSRoland Mainz }
14737c2fbfb3SApril Chin filemap[shp->topfd].tname = name;
14747c2fbfb3SApril Chin filemap[shp->topfd].subshell = flag;
14757c2fbfb3SApril Chin filemap[shp->topfd].orig_fd = origfd;
14767c2fbfb3SApril Chin filemap[shp->topfd++].save_fd = savefd;
1477da2e3ebdSchin if(savefd >=0)
1478da2e3ebdSchin {
14797c2fbfb3SApril Chin register Sfio_t* sp = shp->sftable[origfd];
1480da2e3ebdSchin /* make saved file close-on-exec */
1481da2e3ebdSchin sh_fcntl(savefd,F_SETFD,FD_CLOEXEC);
1482da2e3ebdSchin if(origfd==job.fd)
1483da2e3ebdSchin job.fd = savefd;
14847c2fbfb3SApril Chin shp->fdstatus[savefd] = shp->fdstatus[origfd];
14857c2fbfb3SApril Chin shp->fdptrs[savefd] = &filemap[shp->topfd-1].save_fd;
14867c2fbfb3SApril Chin if(!(shp->sftable[savefd]=sp))
1487da2e3ebdSchin return;
1488da2e3ebdSchin sfsync(sp);
1489da2e3ebdSchin if(origfd <=2)
1490da2e3ebdSchin {
1491da2e3ebdSchin /* copy standard stream to new stream */
1492da2e3ebdSchin sp = sfswap(sp,NIL(Sfio_t*));
14937c2fbfb3SApril Chin shp->sftable[savefd] = sp;
1494da2e3ebdSchin }
1495da2e3ebdSchin else
14967c2fbfb3SApril Chin shp->sftable[origfd] = 0;
1497da2e3ebdSchin }
1498da2e3ebdSchin }
1499da2e3ebdSchin
1500da2e3ebdSchin /*
1501da2e3ebdSchin * close all saved file descriptors
1502da2e3ebdSchin */
sh_iounsave(Shell_t * shp)15037c2fbfb3SApril Chin void sh_iounsave(Shell_t* shp)
1504da2e3ebdSchin {
1505da2e3ebdSchin register int fd, savefd, newfd;
15067c2fbfb3SApril Chin for(newfd=fd=0; fd < shp->topfd; fd++)
1507da2e3ebdSchin {
1508da2e3ebdSchin if((savefd = filemap[fd].save_fd)< 0)
1509da2e3ebdSchin filemap[newfd++] = filemap[fd];
1510da2e3ebdSchin else
1511da2e3ebdSchin {
15127c2fbfb3SApril Chin shp->sftable[savefd] = 0;
1513da2e3ebdSchin sh_close(savefd);
1514da2e3ebdSchin }
1515da2e3ebdSchin }
15167c2fbfb3SApril Chin shp->topfd = newfd;
1517da2e3ebdSchin }
1518da2e3ebdSchin
1519da2e3ebdSchin /*
1520da2e3ebdSchin * restore saved file descriptors from <last> on
1521da2e3ebdSchin */
sh_iorestore(Shell_t * shp,int last,int jmpval)15227c2fbfb3SApril Chin void sh_iorestore(Shell_t *shp, int last, int jmpval)
1523da2e3ebdSchin {
1524da2e3ebdSchin register int origfd, savefd, fd;
1525da2e3ebdSchin int flag = (last&IOSUBSHELL);
1526da2e3ebdSchin last &= ~IOSUBSHELL;
15277c2fbfb3SApril Chin for (fd = shp->topfd - 1; fd >= last; fd--)
1528da2e3ebdSchin {
1529da2e3ebdSchin if(!flag && filemap[fd].subshell)
1530da2e3ebdSchin continue;
1531da2e3ebdSchin if(jmpval==SH_JMPSCRIPT)
1532da2e3ebdSchin {
1533da2e3ebdSchin if ((savefd = filemap[fd].save_fd) >= 0)
1534da2e3ebdSchin {
15357c2fbfb3SApril Chin shp->sftable[savefd] = 0;
1536da2e3ebdSchin sh_close(savefd);
1537da2e3ebdSchin }
1538da2e3ebdSchin continue;
1539da2e3ebdSchin }
1540da2e3ebdSchin origfd = filemap[fd].orig_fd;
154134f9b3eeSRoland Mainz if(filemap[fd].tname == Empty && shp->exitval==0)
154234f9b3eeSRoland Mainz ftruncate(origfd,lseek(origfd,0,SEEK_CUR));
154334f9b3eeSRoland Mainz else if(filemap[fd].tname)
15447c2fbfb3SApril Chin io_usename(filemap[fd].tname,(int*)0,shp->exitval?2:1);
1545da2e3ebdSchin sh_close(origfd);
1546da2e3ebdSchin if ((savefd = filemap[fd].save_fd) >= 0)
1547da2e3ebdSchin {
1548da2e3ebdSchin sh_fcntl(savefd, F_DUPFD, origfd);
1549da2e3ebdSchin if(savefd==job.fd)
1550da2e3ebdSchin job.fd=origfd;
15517c2fbfb3SApril Chin shp->fdstatus[origfd] = shp->fdstatus[savefd];
1552da2e3ebdSchin /* turn off close-on-exec if flag if necessary */
15537c2fbfb3SApril Chin if(shp->fdstatus[origfd]&IOCLEX)
1554da2e3ebdSchin fcntl(origfd,F_SETFD,FD_CLOEXEC);
1555da2e3ebdSchin if(origfd<=2)
1556da2e3ebdSchin {
15577c2fbfb3SApril Chin sfswap(shp->sftable[savefd],shp->sftable[origfd]);
1558da2e3ebdSchin if(origfd==0)
15597c2fbfb3SApril Chin shp->st.ioset = 0;
1560da2e3ebdSchin }
1561da2e3ebdSchin else
15627c2fbfb3SApril Chin shp->sftable[origfd] = shp->sftable[savefd];
15637c2fbfb3SApril Chin shp->sftable[savefd] = 0;
1564da2e3ebdSchin sh_close(savefd);
1565da2e3ebdSchin }
1566da2e3ebdSchin else
15677c2fbfb3SApril Chin shp->fdstatus[origfd] = IOCLOSE;
1568da2e3ebdSchin }
1569da2e3ebdSchin if(!flag)
1570da2e3ebdSchin {
1571da2e3ebdSchin /* keep file descriptors for subshell restore */
15727c2fbfb3SApril Chin for (fd = last ; fd < shp->topfd; fd++)
1573da2e3ebdSchin {
1574da2e3ebdSchin if(filemap[fd].subshell)
1575da2e3ebdSchin filemap[last++] = filemap[fd];
1576da2e3ebdSchin }
1577da2e3ebdSchin }
15787c2fbfb3SApril Chin if(last < shp->topfd)
15797c2fbfb3SApril Chin shp->topfd = last;
1580da2e3ebdSchin }
1581da2e3ebdSchin
1582da2e3ebdSchin /*
1583da2e3ebdSchin * returns access information on open file <fd>
1584da2e3ebdSchin * returns -1 for failure, 0 for success
1585da2e3ebdSchin * <mode> is the same as for access()
1586da2e3ebdSchin */
sh_ioaccess(int fd,register int mode)1587da2e3ebdSchin int sh_ioaccess(int fd,register int mode)
1588da2e3ebdSchin {
15897c2fbfb3SApril Chin Shell_t *shp = &sh;
1590da2e3ebdSchin register int flags;
1591da2e3ebdSchin if(mode==X_OK)
1592da2e3ebdSchin return(-1);
15937c2fbfb3SApril Chin if((flags=sh_iocheckfd(shp,fd))!=IOCLOSE)
1594da2e3ebdSchin {
1595da2e3ebdSchin if(mode==F_OK)
1596da2e3ebdSchin return(0);
1597da2e3ebdSchin if(mode==R_OK && (flags&IOREAD))
1598da2e3ebdSchin return(0);
1599da2e3ebdSchin if(mode==W_OK && (flags&IOWRITE))
1600da2e3ebdSchin return(0);
1601da2e3ebdSchin }
1602da2e3ebdSchin return(-1);
1603da2e3ebdSchin }
1604da2e3ebdSchin
1605da2e3ebdSchin /*
1606da2e3ebdSchin * Handle interrupts for slow streams
1607da2e3ebdSchin */
slowexcept(register Sfio_t * iop,int type,void * data,Sfdisc_t * handle)1608da2e3ebdSchin static int slowexcept(register Sfio_t *iop,int type,void *data,Sfdisc_t *handle)
1609da2e3ebdSchin {
1610da2e3ebdSchin register int n,fno;
1611da2e3ebdSchin NOT_USED(handle);
1612da2e3ebdSchin if(type==SF_DPOP || type==SF_FINAL)
1613da2e3ebdSchin free((void*)handle);
1614da2e3ebdSchin if(type!=SF_READ)
1615da2e3ebdSchin return(0);
1616da2e3ebdSchin if((sh.trapnote&(SH_SIGSET|SH_SIGTRAP)) && errno!=EIO && errno!=ENXIO)
1617da2e3ebdSchin errno = EINTR;
1618da2e3ebdSchin fno = sffileno(iop);
1619da2e3ebdSchin if((n=sfvalue(iop))<=0)
1620da2e3ebdSchin {
1621da2e3ebdSchin #ifndef FNDELAY
1622da2e3ebdSchin # ifdef O_NDELAY
1623da2e3ebdSchin if(errno==0 && (n=fcntl(fno,F_GETFL,0))&O_NDELAY)
1624da2e3ebdSchin {
1625da2e3ebdSchin n &= ~O_NDELAY;
1626da2e3ebdSchin fcntl(fno, F_SETFL, n);
1627da2e3ebdSchin return(1);
1628da2e3ebdSchin }
1629da2e3ebdSchin # endif /* O_NDELAY */
1630da2e3ebdSchin #endif /* !FNDELAY */
1631da2e3ebdSchin #ifdef O_NONBLOCK
1632da2e3ebdSchin if(errno==EAGAIN)
1633da2e3ebdSchin {
1634da2e3ebdSchin n = fcntl(fno,F_GETFL,0);
1635da2e3ebdSchin n &= ~O_NONBLOCK;
1636da2e3ebdSchin fcntl(fno, F_SETFL, n);
1637da2e3ebdSchin return(1);
1638da2e3ebdSchin }
1639da2e3ebdSchin #endif /* O_NONBLOCK */
1640da2e3ebdSchin if(errno!=EINTR)
1641da2e3ebdSchin return(0);
1642da2e3ebdSchin n=1;
16437c2fbfb3SApril Chin sh_onstate(SH_TTYWAIT);
1644da2e3ebdSchin }
16457c2fbfb3SApril Chin else
16467c2fbfb3SApril Chin n = 0;
16477c2fbfb3SApril Chin if(sh.bltinfun && sh.bltindata.sigset)
16487c2fbfb3SApril Chin return(-1);
1649da2e3ebdSchin errno = 0;
1650da2e3ebdSchin if(sh.trapnote&SH_SIGSET)
1651da2e3ebdSchin {
1652da2e3ebdSchin if(isatty(fno))
1653da2e3ebdSchin sfputc(sfstderr,'\n');
1654da2e3ebdSchin sh_exit(SH_EXITSIG);
1655da2e3ebdSchin }
1656da2e3ebdSchin if(sh.trapnote&SH_SIGTRAP)
1657da2e3ebdSchin sh_chktrap();
1658da2e3ebdSchin return(n);
1659da2e3ebdSchin }
1660da2e3ebdSchin
1661da2e3ebdSchin /*
1662da2e3ebdSchin * called when slowread times out
1663da2e3ebdSchin */
time_grace(void * handle)1664da2e3ebdSchin static void time_grace(void *handle)
1665da2e3ebdSchin {
1666da2e3ebdSchin NOT_USED(handle);
1667da2e3ebdSchin timeout = 0;
1668da2e3ebdSchin if(sh_isstate(SH_GRACE))
1669da2e3ebdSchin {
1670da2e3ebdSchin sh_offstate(SH_GRACE);
1671da2e3ebdSchin if(!sh_isstate(SH_INTERACTIVE))
1672da2e3ebdSchin return;
1673da2e3ebdSchin ((struct checkpt*)sh.jmplist)->mode = SH_JMPEXIT;
1674da2e3ebdSchin errormsg(SH_DICT,2,e_timeout);
1675da2e3ebdSchin sh.trapnote |= SH_SIGSET;
1676da2e3ebdSchin return;
1677da2e3ebdSchin }
1678da2e3ebdSchin errormsg(SH_DICT,0,e_timewarn);
1679da2e3ebdSchin sh_onstate(SH_GRACE);
1680da2e3ebdSchin sigrelease(SIGALRM);
1681da2e3ebdSchin sh.trapnote |= SH_SIGTRAP;
1682da2e3ebdSchin }
1683da2e3ebdSchin
piperead(Sfio_t * iop,void * buff,register size_t size,Sfdisc_t * handle)1684da2e3ebdSchin static ssize_t piperead(Sfio_t *iop,void *buff,register size_t size,Sfdisc_t *handle)
1685da2e3ebdSchin {
1686da2e3ebdSchin int fd = sffileno(iop);
1687da2e3ebdSchin NOT_USED(handle);
16887c2fbfb3SApril Chin if(job.waitsafe && job.savesig)
168934f9b3eeSRoland Mainz {
169034f9b3eeSRoland Mainz job_lock();
169134f9b3eeSRoland Mainz job_unlock();
169234f9b3eeSRoland Mainz }
1693da2e3ebdSchin if(sh.trapnote)
1694da2e3ebdSchin {
1695da2e3ebdSchin errno = EINTR;
1696da2e3ebdSchin return(-1);
1697da2e3ebdSchin }
1698da2e3ebdSchin if(sh_isstate(SH_INTERACTIVE) && io_prompt(iop,sh.nextprompt)<0 && errno==EIO)
1699da2e3ebdSchin return(0);
17007c2fbfb3SApril Chin sh_onstate(SH_TTYWAIT);
1701da2e3ebdSchin if(!(sh.fdstatus[sffileno(iop)]&IOCLEX) && (sfset(iop,0,0)&SF_SHARE))
1702da2e3ebdSchin size = ed_read(sh.ed_context, fd, (char*)buff, size,0);
1703da2e3ebdSchin else
1704da2e3ebdSchin size = sfrd(iop,buff,size,handle);
17057c2fbfb3SApril Chin sh_offstate(SH_TTYWAIT);
1706da2e3ebdSchin return(size);
1707da2e3ebdSchin }
1708da2e3ebdSchin /*
1709da2e3ebdSchin * This is the read discipline that is applied to slow devices
1710da2e3ebdSchin * This routine takes care of prompting for input
1711da2e3ebdSchin */
slowread(Sfio_t * iop,void * buff,register size_t size,Sfdisc_t * handle)1712da2e3ebdSchin static ssize_t slowread(Sfio_t *iop,void *buff,register size_t size,Sfdisc_t *handle)
1713da2e3ebdSchin {
1714da2e3ebdSchin int (*readf)(void*, int, char*, int, int);
1715da2e3ebdSchin int reedit=0, rsize;
1716da2e3ebdSchin #if SHOPT_HISTEXPAND
1717da2e3ebdSchin char *xp=0;
1718da2e3ebdSchin #endif
1719da2e3ebdSchin NOT_USED(handle);
1720da2e3ebdSchin # if SHOPT_ESH
1721da2e3ebdSchin if(sh_isoption(SH_EMACS) || sh_isoption(SH_GMACS))
1722da2e3ebdSchin readf = ed_emacsread;
1723da2e3ebdSchin else
1724da2e3ebdSchin # endif /* SHOPT_ESH */
1725da2e3ebdSchin # if SHOPT_VSH
1726da2e3ebdSchin # if SHOPT_RAWONLY
1727da2e3ebdSchin if(sh_isoption(SH_VI) || ((SHOPT_RAWONLY-0) && mbwide()))
1728da2e3ebdSchin # else
1729da2e3ebdSchin if(sh_isoption(SH_VI))
1730da2e3ebdSchin # endif
1731da2e3ebdSchin readf = ed_viread;
1732da2e3ebdSchin else
1733da2e3ebdSchin # endif /* SHOPT_VSH */
1734da2e3ebdSchin readf = ed_read;
1735da2e3ebdSchin if(sh.trapnote)
1736da2e3ebdSchin {
1737da2e3ebdSchin errno = EINTR;
1738da2e3ebdSchin return(-1);
1739da2e3ebdSchin }
1740da2e3ebdSchin while(1)
1741da2e3ebdSchin {
1742da2e3ebdSchin if(io_prompt(iop,sh.nextprompt)<0 && errno==EIO)
1743da2e3ebdSchin return(0);
1744da2e3ebdSchin if(sh.timeout)
1745da2e3ebdSchin timeout = (void*)sh_timeradd(sh_isstate(SH_GRACE)?1000L*TGRACE:1000L*sh.timeout,0,time_grace,NIL(void*));
1746da2e3ebdSchin rsize = (*readf)(sh.ed_context, sffileno(iop), (char*)buff, size, reedit);
1747da2e3ebdSchin if(timeout)
1748da2e3ebdSchin timerdel(timeout);
1749da2e3ebdSchin timeout=0;
1750da2e3ebdSchin #if SHOPT_HISTEXPAND
1751da2e3ebdSchin if(rsize && *(char*)buff != '\n' && sh.nextprompt==1 && sh_isoption(SH_HISTEXPAND))
1752da2e3ebdSchin {
1753da2e3ebdSchin int r;
1754da2e3ebdSchin ((char*)buff)[rsize] = '\0';
1755da2e3ebdSchin if(xp)
1756da2e3ebdSchin {
1757da2e3ebdSchin free(xp);
1758da2e3ebdSchin xp = 0;
1759da2e3ebdSchin }
1760da2e3ebdSchin r = hist_expand(buff, &xp);
1761da2e3ebdSchin if((r & (HIST_EVENT|HIST_PRINT)) && !(r & HIST_ERROR) && xp)
1762da2e3ebdSchin {
1763da2e3ebdSchin strlcpy(buff, xp, size);
1764da2e3ebdSchin rsize = strlen(buff);
1765da2e3ebdSchin if(!sh_isoption(SH_HISTVERIFY) || readf==ed_read)
1766da2e3ebdSchin {
1767da2e3ebdSchin sfputr(sfstderr, xp, -1);
1768da2e3ebdSchin break;
1769da2e3ebdSchin }
1770da2e3ebdSchin reedit = rsize - 1;
1771da2e3ebdSchin continue;
1772da2e3ebdSchin }
1773da2e3ebdSchin if((r & HIST_ERROR) && sh_isoption(SH_HISTREEDIT))
1774da2e3ebdSchin {
1775da2e3ebdSchin reedit = rsize - 1;
1776da2e3ebdSchin continue;
1777da2e3ebdSchin }
1778da2e3ebdSchin if(r & (HIST_ERROR|HIST_PRINT))
1779da2e3ebdSchin {
1780da2e3ebdSchin *(char*)buff = '\n';
1781da2e3ebdSchin rsize = 1;
1782da2e3ebdSchin }
1783da2e3ebdSchin }
1784da2e3ebdSchin #endif
1785da2e3ebdSchin break;
1786da2e3ebdSchin }
1787da2e3ebdSchin return(rsize);
1788da2e3ebdSchin }
1789da2e3ebdSchin
1790da2e3ebdSchin /*
1791da2e3ebdSchin * check and return the attributes for a file descriptor
1792da2e3ebdSchin */
1793da2e3ebdSchin
sh_iocheckfd(Shell_t * shp,register int fd)17947c2fbfb3SApril Chin int sh_iocheckfd(Shell_t *shp, register int fd)
1795da2e3ebdSchin {
1796da2e3ebdSchin register int flags, n;
1797da2e3ebdSchin if((n=sh.fdstatus[fd])&IOCLOSE)
1798da2e3ebdSchin return(n);
1799da2e3ebdSchin if(!(n&(IOREAD|IOWRITE)))
1800da2e3ebdSchin {
1801da2e3ebdSchin #ifdef F_GETFL
1802da2e3ebdSchin if((flags=fcntl(fd,F_GETFL,0)) < 0)
1803da2e3ebdSchin return(sh.fdstatus[fd]=IOCLOSE);
1804da2e3ebdSchin if((flags&O_ACCMODE)!=O_WRONLY)
1805da2e3ebdSchin n |= IOREAD;
1806da2e3ebdSchin if((flags&O_ACCMODE)!=O_RDONLY)
1807da2e3ebdSchin n |= IOWRITE;
1808da2e3ebdSchin #else
1809da2e3ebdSchin struct stat statb;
1810da2e3ebdSchin if((flags = fstat(fd,&statb))< 0)
1811da2e3ebdSchin return(sh.fdstatus[fd]=IOCLOSE);
1812da2e3ebdSchin n |= (IOREAD|IOWRITE);
1813da2e3ebdSchin if(read(fd,"",0) < 0)
1814da2e3ebdSchin n &= ~IOREAD;
1815da2e3ebdSchin #endif /* F_GETFL */
1816da2e3ebdSchin }
1817da2e3ebdSchin if(!(n&(IOSEEK|IONOSEEK)))
1818da2e3ebdSchin {
1819da2e3ebdSchin struct stat statb;
1820da2e3ebdSchin /* /dev/null check is a workaround for select bug */
1821da2e3ebdSchin static ino_t null_ino;
1822da2e3ebdSchin static dev_t null_dev;
1823da2e3ebdSchin if(null_ino==0 && stat(e_devnull,&statb) >=0)
1824da2e3ebdSchin {
1825da2e3ebdSchin null_ino = statb.st_ino;
1826da2e3ebdSchin null_dev = statb.st_dev;
1827da2e3ebdSchin }
1828da2e3ebdSchin if(tty_check(fd))
1829da2e3ebdSchin n |= IOTTY;
1830da2e3ebdSchin if(lseek(fd,NIL(off_t),SEEK_CUR)<0)
1831da2e3ebdSchin {
1832da2e3ebdSchin n |= IONOSEEK;
1833da2e3ebdSchin #ifdef S_ISSOCK
1834da2e3ebdSchin if((fstat(fd,&statb)>=0) && S_ISSOCK(statb.st_mode))
1835da2e3ebdSchin n |= IOREAD|IOWRITE;
1836da2e3ebdSchin #endif /* S_ISSOCK */
1837da2e3ebdSchin }
1838da2e3ebdSchin else if((fstat(fd,&statb)>=0) && (
1839da2e3ebdSchin S_ISFIFO(statb.st_mode) ||
1840da2e3ebdSchin #ifdef S_ISSOCK
1841da2e3ebdSchin S_ISSOCK(statb.st_mode) ||
1842da2e3ebdSchin #endif /* S_ISSOCK */
1843da2e3ebdSchin /* The following is for sockets on the sgi */
1844da2e3ebdSchin (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) ||
1845da2e3ebdSchin (S_ISCHR(statb.st_mode) && (statb.st_ino!=null_ino || statb.st_dev!=null_dev))
1846da2e3ebdSchin ))
1847da2e3ebdSchin n |= IONOSEEK;
1848da2e3ebdSchin else
1849da2e3ebdSchin n |= IOSEEK;
1850da2e3ebdSchin }
1851da2e3ebdSchin sh.fdstatus[fd] = n;
1852da2e3ebdSchin return(n);
1853da2e3ebdSchin }
1854da2e3ebdSchin
1855da2e3ebdSchin /*
1856da2e3ebdSchin * Display prompt PS<flag> on standard error
1857da2e3ebdSchin */
1858da2e3ebdSchin
io_prompt(Sfio_t * iop,register int flag)1859da2e3ebdSchin static int io_prompt(Sfio_t *iop,register int flag)
1860da2e3ebdSchin {
18617c2fbfb3SApril Chin Shell_t *shp = &sh;
1862da2e3ebdSchin register char *cp;
1863da2e3ebdSchin char buff[1];
1864da2e3ebdSchin char *endprompt;
1865da2e3ebdSchin static short cmdno;
1866da2e3ebdSchin int sfflags;
1867da2e3ebdSchin if(flag<3 && !sh_isstate(SH_INTERACTIVE))
1868da2e3ebdSchin flag = 0;
1869da2e3ebdSchin if(flag==2 && sfpkrd(sffileno(iop),buff,1,'\n',0,1) >= 0)
1870da2e3ebdSchin flag = 0;
1871da2e3ebdSchin if(flag==0)
1872da2e3ebdSchin return(sfsync(sfstderr));
1873da2e3ebdSchin sfflags = sfset(sfstderr,SF_SHARE|SF_PUBLIC|SF_READ,0);
1874da2e3ebdSchin if(!(sh.prompt=(char*)sfreserve(sfstderr,0,0)))
1875da2e3ebdSchin sh.prompt = "";
1876da2e3ebdSchin switch(flag)
1877da2e3ebdSchin {
1878da2e3ebdSchin case 1:
1879da2e3ebdSchin {
1880da2e3ebdSchin register int c;
1881da2e3ebdSchin #if defined(TIOCLBIC) && defined(LFLUSHO)
1882da2e3ebdSchin if(!sh_isoption(SH_VI) && !sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS))
1883da2e3ebdSchin {
1884da2e3ebdSchin /*
1885da2e3ebdSchin * re-enable output in case the user has
1886da2e3ebdSchin * disabled it. Not needed with edit mode
1887da2e3ebdSchin */
1888da2e3ebdSchin int mode = LFLUSHO;
1889da2e3ebdSchin ioctl(sffileno(sfstderr),TIOCLBIC,&mode);
1890da2e3ebdSchin }
1891da2e3ebdSchin #endif /* TIOCLBIC */
18927c2fbfb3SApril Chin cp = sh_mactry(shp,nv_getval(sh_scoped(shp,PS1NOD)));
1893da2e3ebdSchin for(;c= *cp;cp++)
1894da2e3ebdSchin {
1895da2e3ebdSchin if(c==HIST_CHAR)
1896da2e3ebdSchin {
1897da2e3ebdSchin /* look at next character */
1898da2e3ebdSchin c = *++cp;
1899da2e3ebdSchin /* print out line number if not !! */
1900da2e3ebdSchin if(c!= HIST_CHAR)
1901da2e3ebdSchin {
1902da2e3ebdSchin sfprintf(sfstderr,"%d", sh.hist_ptr?(int)sh.hist_ptr->histind:++cmdno);
1903da2e3ebdSchin }
1904da2e3ebdSchin if(c==0)
1905da2e3ebdSchin goto done;
1906da2e3ebdSchin }
1907da2e3ebdSchin sfputc(sfstderr,c);
1908da2e3ebdSchin }
1909da2e3ebdSchin goto done;
1910da2e3ebdSchin }
1911da2e3ebdSchin case 2:
19127c2fbfb3SApril Chin cp = nv_getval(sh_scoped(shp,PS2NOD));
1913da2e3ebdSchin break;
1914da2e3ebdSchin case 3:
19157c2fbfb3SApril Chin cp = nv_getval(sh_scoped(shp,PS3NOD));
1916da2e3ebdSchin break;
1917da2e3ebdSchin default:
1918da2e3ebdSchin goto done;
1919da2e3ebdSchin }
1920da2e3ebdSchin if(cp)
1921da2e3ebdSchin sfputr(sfstderr,cp,-1);
1922da2e3ebdSchin done:
1923da2e3ebdSchin if(*sh.prompt && (endprompt=(char*)sfreserve(sfstderr,0,0)))
1924da2e3ebdSchin *endprompt = 0;
1925da2e3ebdSchin sfset(sfstderr,sfflags&SF_READ|SF_SHARE|SF_PUBLIC,1);
1926da2e3ebdSchin return(sfsync(sfstderr));
1927da2e3ebdSchin }
1928da2e3ebdSchin
1929da2e3ebdSchin /*
1930da2e3ebdSchin * This discipline is inserted on write pipes to prevent SIGPIPE
1931da2e3ebdSchin * from causing an infinite loop
1932da2e3ebdSchin */
pipeexcept(Sfio_t * iop,int mode,void * data,Sfdisc_t * handle)1933da2e3ebdSchin static int pipeexcept(Sfio_t* iop, int mode, void *data, Sfdisc_t* handle)
1934da2e3ebdSchin {
1935da2e3ebdSchin NOT_USED(iop);
1936da2e3ebdSchin if(mode==SF_DPOP || mode==SF_FINAL)
1937da2e3ebdSchin free((void*)handle);
1938da2e3ebdSchin else if(mode==SF_WRITE && errno==EINTR && sh.lastsig==SIGPIPE)
1939da2e3ebdSchin return(-1);
1940da2e3ebdSchin return(0);
1941da2e3ebdSchin }
1942da2e3ebdSchin
1943da2e3ebdSchin /*
1944da2e3ebdSchin * keep track of each stream that is opened and closed
1945da2e3ebdSchin */
sftrack(Sfio_t * sp,int flag,void * data)19467c2fbfb3SApril Chin static void sftrack(Sfio_t* sp, int flag, void* data)
1947da2e3ebdSchin {
19487c2fbfb3SApril Chin Shell_t *shp = &sh;
1949da2e3ebdSchin register int fd = sffileno(sp);
1950da2e3ebdSchin register struct checkpt *pp;
1951da2e3ebdSchin register int mode;
19527c2fbfb3SApril Chin int newfd = integralof(data);
1953da2e3ebdSchin if(flag==SF_SETFD || flag==SF_CLOSING)
1954da2e3ebdSchin {
1955da2e3ebdSchin if(newfd<0)
1956da2e3ebdSchin flag = SF_CLOSING;
1957da2e3ebdSchin if(fdnotify)
1958da2e3ebdSchin (*fdnotify)(sffileno(sp),flag==SF_CLOSING?-1:newfd);
1959da2e3ebdSchin }
1960da2e3ebdSchin #ifdef DEBUG
1961da2e3ebdSchin if(flag==SF_READ || flag==SF_WRITE)
1962da2e3ebdSchin {
1963da2e3ebdSchin char *z = fmtbase((long)getpid(),0,0);
1964da2e3ebdSchin write(ERRIO,z,strlen(z));
1965da2e3ebdSchin write(ERRIO,": ",2);
1966da2e3ebdSchin write(ERRIO,"attempt to ",11);
1967da2e3ebdSchin if(flag==SF_READ)
1968da2e3ebdSchin write(ERRIO,"read from",9);
1969da2e3ebdSchin else
1970da2e3ebdSchin write(ERRIO,"write to",8);
1971da2e3ebdSchin write(ERRIO," locked stream\n",15);
1972da2e3ebdSchin return;
1973da2e3ebdSchin }
1974da2e3ebdSchin #endif
19757c2fbfb3SApril Chin if((unsigned)fd >= shp->lim.open_max)
1976da2e3ebdSchin return;
1977da2e3ebdSchin if(sh_isstate(SH_NOTRACK))
1978da2e3ebdSchin return;
1979da2e3ebdSchin mode = sfset(sp,0,0);
19807c2fbfb3SApril Chin if(sp==shp->heredocs && fd < 10 && flag==SF_NEW)
1981da2e3ebdSchin {
1982da2e3ebdSchin fd = sfsetfd(sp,10);
1983da2e3ebdSchin fcntl(fd,F_SETFD,FD_CLOEXEC);
1984da2e3ebdSchin }
1985da2e3ebdSchin if(fd < 3)
1986da2e3ebdSchin return;
1987da2e3ebdSchin if(flag==SF_NEW)
1988da2e3ebdSchin {
19897c2fbfb3SApril Chin if(!shp->sftable[fd] && shp->fdstatus[fd]==IOCLOSE)
1990da2e3ebdSchin {
19917c2fbfb3SApril Chin shp->sftable[fd] = sp;
1992da2e3ebdSchin flag = (mode&SF_WRITE)?IOWRITE:0;
1993da2e3ebdSchin if(mode&SF_READ)
1994da2e3ebdSchin flag |= IOREAD;
19957c2fbfb3SApril Chin shp->fdstatus[fd] = flag;
19967c2fbfb3SApril Chin sh_iostream(shp,fd);
1997da2e3ebdSchin }
19987c2fbfb3SApril Chin if((pp=(struct checkpt*)shp->jmplist) && pp->mode==SH_JMPCMD)
1999da2e3ebdSchin {
2000da2e3ebdSchin struct openlist *item;
2001da2e3ebdSchin /*
2002da2e3ebdSchin * record open file descriptors so they can
2003da2e3ebdSchin * be closed in case a longjmp prevents
2004da2e3ebdSchin * built-ins from cleanup
2005da2e3ebdSchin */
2006da2e3ebdSchin item = new_of(struct openlist, 0);
2007da2e3ebdSchin item->strm = sp;
2008da2e3ebdSchin item->next = pp->olist;
2009da2e3ebdSchin pp->olist = item;
2010da2e3ebdSchin }
2011da2e3ebdSchin if(fdnotify)
2012da2e3ebdSchin (*fdnotify)(-1,sffileno(sp));
2013da2e3ebdSchin }
2014da2e3ebdSchin else if(flag==SF_CLOSING || (flag==SF_SETFD && newfd<=2))
2015da2e3ebdSchin {
20167c2fbfb3SApril Chin shp->sftable[fd] = 0;
20177c2fbfb3SApril Chin shp->fdstatus[fd]=IOCLOSE;
20187c2fbfb3SApril Chin if(pp=(struct checkpt*)shp->jmplist)
2019da2e3ebdSchin {
2020da2e3ebdSchin struct openlist *item;
2021da2e3ebdSchin for(item=pp->olist; item; item=item->next)
2022da2e3ebdSchin {
2023da2e3ebdSchin if(item->strm == sp)
2024da2e3ebdSchin {
2025da2e3ebdSchin item->strm = 0;
2026da2e3ebdSchin break;
2027da2e3ebdSchin }
2028da2e3ebdSchin }
2029da2e3ebdSchin }
2030da2e3ebdSchin }
2031da2e3ebdSchin }
2032da2e3ebdSchin
2033da2e3ebdSchin struct eval
2034da2e3ebdSchin {
2035da2e3ebdSchin Sfdisc_t disc;
2036da2e3ebdSchin char **argv;
2037da2e3ebdSchin short slen;
2038da2e3ebdSchin char addspace;
2039da2e3ebdSchin };
2040da2e3ebdSchin
2041da2e3ebdSchin /*
2042da2e3ebdSchin * Create a stream consisting of a space separated argv[] list
2043da2e3ebdSchin */
2044da2e3ebdSchin
sh_sfeval(register char * argv[])2045da2e3ebdSchin Sfio_t *sh_sfeval(register char *argv[])
2046da2e3ebdSchin {
2047da2e3ebdSchin register Sfio_t *iop;
2048da2e3ebdSchin register char *cp;
2049da2e3ebdSchin if(argv[1])
2050da2e3ebdSchin cp = "";
2051da2e3ebdSchin else
2052da2e3ebdSchin cp = argv[0];
2053da2e3ebdSchin iop = sfopen(NIL(Sfio_t*),(char*)cp,"s");
2054da2e3ebdSchin if(argv[1])
2055da2e3ebdSchin {
2056da2e3ebdSchin register struct eval *ep;
2057da2e3ebdSchin if(!(ep = new_of(struct eval,0)))
2058da2e3ebdSchin return(NIL(Sfio_t*));
2059da2e3ebdSchin ep->disc = eval_disc;
2060da2e3ebdSchin ep->argv = argv;
2061da2e3ebdSchin ep->slen = -1;
2062da2e3ebdSchin ep->addspace = 0;
2063da2e3ebdSchin sfdisc(iop,&ep->disc);
2064da2e3ebdSchin }
2065da2e3ebdSchin return(iop);
2066da2e3ebdSchin }
2067da2e3ebdSchin
2068da2e3ebdSchin /*
2069da2e3ebdSchin * This code gets called whenever an end of string is found with eval
2070da2e3ebdSchin */
2071da2e3ebdSchin
eval_exceptf(Sfio_t * iop,int type,void * data,Sfdisc_t * handle)2072da2e3ebdSchin static int eval_exceptf(Sfio_t *iop,int type, void *data, Sfdisc_t *handle)
2073da2e3ebdSchin {
2074da2e3ebdSchin register struct eval *ep = (struct eval*)handle;
2075da2e3ebdSchin register char *cp;
2076da2e3ebdSchin register int len;
2077da2e3ebdSchin
2078da2e3ebdSchin /* no more to do */
2079da2e3ebdSchin if(type!=SF_READ || !(cp = ep->argv[0]))
2080da2e3ebdSchin {
2081da2e3ebdSchin if(type==SF_CLOSING)
2082da2e3ebdSchin sfdisc(iop,SF_POPDISC);
2083da2e3ebdSchin else if(ep && (type==SF_DPOP || type==SF_FINAL))
2084da2e3ebdSchin free((void*)ep);
2085da2e3ebdSchin return(0);
2086da2e3ebdSchin }
2087da2e3ebdSchin
2088da2e3ebdSchin if(!ep->addspace)
2089da2e3ebdSchin {
2090da2e3ebdSchin /* get the length of this string */
2091da2e3ebdSchin ep->slen = len = strlen(cp);
2092da2e3ebdSchin /* move to next string */
2093da2e3ebdSchin ep->argv++;
2094da2e3ebdSchin }
2095da2e3ebdSchin else /* insert space between arguments */
2096da2e3ebdSchin {
2097da2e3ebdSchin len = 1;
2098da2e3ebdSchin cp = " ";
2099da2e3ebdSchin }
2100da2e3ebdSchin /* insert the new string */
2101da2e3ebdSchin sfsetbuf(iop,cp,len);
2102da2e3ebdSchin ep->addspace = !ep->addspace;
2103da2e3ebdSchin return(1);
2104da2e3ebdSchin }
2105da2e3ebdSchin
2106da2e3ebdSchin /*
2107da2e3ebdSchin * This routine returns a stream pointer to a segment of length <size> from
2108da2e3ebdSchin * the stream <sp> starting at offset <offset>
2109da2e3ebdSchin * The stream can be read with the normal stream operations
2110da2e3ebdSchin */
2111da2e3ebdSchin
subopen(Shell_t * shp,Sfio_t * sp,off_t offset,long size)21127c2fbfb3SApril Chin static Sfio_t *subopen(Shell_t *shp,Sfio_t* sp, off_t offset, long size)
2113da2e3ebdSchin {
2114da2e3ebdSchin register struct subfile *disp;
2115da2e3ebdSchin if(sfseek(sp,offset,SEEK_SET) <0)
2116da2e3ebdSchin return(NIL(Sfio_t*));
2117da2e3ebdSchin if(!(disp = (struct subfile*)malloc(sizeof(struct subfile)+IOBSIZE+1)))
2118da2e3ebdSchin return(NIL(Sfio_t*));
2119da2e3ebdSchin disp->disc = sub_disc;
2120da2e3ebdSchin disp->oldsp = sp;
2121da2e3ebdSchin disp->offset = offset;
2122da2e3ebdSchin disp->size = disp->left = size;
21237c2fbfb3SApril Chin sp = sfnew(NIL(Sfio_t*),(char*)(disp+1),IOBSIZE,shp->lim.open_max,SF_READ);
2124da2e3ebdSchin sfdisc(sp,&disp->disc);
2125da2e3ebdSchin return(sp);
2126da2e3ebdSchin }
2127da2e3ebdSchin
2128da2e3ebdSchin /*
2129da2e3ebdSchin * read function for subfile discipline
2130da2e3ebdSchin */
subread(Sfio_t * sp,void * buff,register size_t size,Sfdisc_t * handle)2131da2e3ebdSchin static ssize_t subread(Sfio_t* sp,void* buff,register size_t size,Sfdisc_t* handle)
2132da2e3ebdSchin {
2133da2e3ebdSchin register struct subfile *disp = (struct subfile*)handle;
2134da2e3ebdSchin NOT_USED(sp);
2135da2e3ebdSchin if(disp->left == 0)
2136da2e3ebdSchin return(0);
2137da2e3ebdSchin if(size > disp->left)
2138da2e3ebdSchin size = disp->left;
2139da2e3ebdSchin disp->left -= size;
2140da2e3ebdSchin return(sfread(disp->oldsp,buff,size));
2141da2e3ebdSchin }
2142da2e3ebdSchin
2143da2e3ebdSchin /*
2144da2e3ebdSchin * exception handler for subfile discipline
2145da2e3ebdSchin */
subexcept(Sfio_t * sp,register int mode,void * data,Sfdisc_t * handle)2146da2e3ebdSchin static int subexcept(Sfio_t* sp,register int mode, void *data, Sfdisc_t* handle)
2147da2e3ebdSchin {
2148da2e3ebdSchin register struct subfile *disp = (struct subfile*)handle;
2149da2e3ebdSchin if(mode==SF_CLOSING)
2150da2e3ebdSchin {
2151da2e3ebdSchin sfdisc(sp,SF_POPDISC);
2152da2e3ebdSchin return(0);
2153da2e3ebdSchin }
2154da2e3ebdSchin else if(disp && (mode==SF_DPOP || mode==SF_FINAL))
2155da2e3ebdSchin {
2156da2e3ebdSchin free((void*)disp);
2157da2e3ebdSchin return(0);
2158da2e3ebdSchin }
2159da2e3ebdSchin #ifdef SF_ATEXIT
2160da2e3ebdSchin else if (mode==SF_ATEXIT)
2161da2e3ebdSchin {
2162da2e3ebdSchin sfdisc(sp, SF_POPDISC);
2163da2e3ebdSchin return(0);
2164da2e3ebdSchin }
2165da2e3ebdSchin #endif
2166da2e3ebdSchin else if(mode==SF_READ)
2167da2e3ebdSchin return(0);
2168da2e3ebdSchin return(-1);
2169da2e3ebdSchin }
2170da2e3ebdSchin
2171da2e3ebdSchin #define NROW 15 /* number of rows before going to multi-columns */
2172da2e3ebdSchin #define LBLSIZ 3 /* size of label field and interfield spacing */
2173da2e3ebdSchin /*
2174da2e3ebdSchin * print a list of arguments in columns
2175da2e3ebdSchin */
sh_menu(Sfio_t * outfile,int argn,char * argv[])2176da2e3ebdSchin void sh_menu(Sfio_t *outfile,int argn,char *argv[])
2177da2e3ebdSchin {
21787c2fbfb3SApril Chin Shell_t *shp = &sh;
2179da2e3ebdSchin register int i,j;
2180da2e3ebdSchin register char **arg;
2181da2e3ebdSchin int nrow, ncol=1, ndigits=1;
2182da2e3ebdSchin int fldsize, wsize = ed_window();
21837c2fbfb3SApril Chin char *cp = nv_getval(sh_scoped(shp,LINES));
2184da2e3ebdSchin nrow = (cp?1+2*((int)strtol(cp, (char**)0, 10)/3):NROW);
2185da2e3ebdSchin for(i=argn;i >= 10;i /= 10)
2186da2e3ebdSchin ndigits++;
2187da2e3ebdSchin if(argn < nrow)
2188da2e3ebdSchin {
2189da2e3ebdSchin nrow = argn;
2190da2e3ebdSchin goto skip;
2191da2e3ebdSchin }
2192da2e3ebdSchin i = 0;
2193da2e3ebdSchin for(arg=argv; *arg;arg++)
2194da2e3ebdSchin {
2195da2e3ebdSchin if((j=strlen(*arg)) > i)
2196da2e3ebdSchin i = j;
2197da2e3ebdSchin }
2198da2e3ebdSchin i += (ndigits+LBLSIZ);
2199da2e3ebdSchin if(i < wsize)
2200da2e3ebdSchin ncol = wsize/i;
2201da2e3ebdSchin if(argn > nrow*ncol)
2202da2e3ebdSchin {
2203da2e3ebdSchin nrow = 1 + (argn-1)/ncol;
2204da2e3ebdSchin }
2205da2e3ebdSchin else
2206da2e3ebdSchin {
2207da2e3ebdSchin ncol = 1 + (argn-1)/nrow;
2208da2e3ebdSchin nrow = 1 + (argn-1)/ncol;
2209da2e3ebdSchin }
2210da2e3ebdSchin skip:
2211da2e3ebdSchin fldsize = (wsize/ncol)-(ndigits+LBLSIZ);
2212da2e3ebdSchin for(i=0;i<nrow;i++)
2213da2e3ebdSchin {
2214da2e3ebdSchin if(sh.trapnote&SH_SIGSET)
2215da2e3ebdSchin return;
2216da2e3ebdSchin j = i;
2217da2e3ebdSchin while(1)
2218da2e3ebdSchin {
2219da2e3ebdSchin arg = argv+j;
2220da2e3ebdSchin sfprintf(outfile,"%*d) %s",ndigits,j+1,*arg);
2221da2e3ebdSchin j += nrow;
2222da2e3ebdSchin if(j >= argn)
2223da2e3ebdSchin break;
2224da2e3ebdSchin sfnputc(outfile,' ',fldsize-strlen(*arg));
2225da2e3ebdSchin }
2226da2e3ebdSchin sfputc(outfile,'\n');
2227da2e3ebdSchin }
2228da2e3ebdSchin }
2229da2e3ebdSchin
2230da2e3ebdSchin #undef read
2231da2e3ebdSchin /*
2232da2e3ebdSchin * shell version of read() for user added builtins
2233da2e3ebdSchin */
sh_read(register int fd,void * buff,size_t n)2234da2e3ebdSchin ssize_t sh_read(register int fd, void* buff, size_t n)
2235da2e3ebdSchin {
2236da2e3ebdSchin register Sfio_t *sp;
2237da2e3ebdSchin if(sp=sh.sftable[fd])
2238da2e3ebdSchin return(sfread(sp,buff,n));
2239da2e3ebdSchin else
2240da2e3ebdSchin return(read(fd,buff,n));
2241da2e3ebdSchin }
2242da2e3ebdSchin
2243da2e3ebdSchin #undef write
2244da2e3ebdSchin /*
2245da2e3ebdSchin * shell version of write() for user added builtins
2246da2e3ebdSchin */
sh_write(register int fd,const void * buff,size_t n)2247da2e3ebdSchin ssize_t sh_write(register int fd, const void* buff, size_t n)
2248da2e3ebdSchin {
2249da2e3ebdSchin register Sfio_t *sp;
2250da2e3ebdSchin if(sp=sh.sftable[fd])
2251da2e3ebdSchin return(sfwrite(sp,buff,n));
2252da2e3ebdSchin else
2253da2e3ebdSchin return(write(fd,buff,n));
2254da2e3ebdSchin }
2255da2e3ebdSchin
2256da2e3ebdSchin #undef lseek
2257da2e3ebdSchin /*
2258da2e3ebdSchin * shell version of lseek() for user added builtins
2259da2e3ebdSchin */
sh_seek(register int fd,off_t offset,int whence)2260da2e3ebdSchin off_t sh_seek(register int fd, off_t offset, int whence)
2261da2e3ebdSchin {
2262da2e3ebdSchin register Sfio_t *sp;
2263da2e3ebdSchin if((sp=sh.sftable[fd]) && (sfset(sp,0,0)&(SF_READ|SF_WRITE)))
2264da2e3ebdSchin return(sfseek(sp,offset,whence));
2265da2e3ebdSchin else
2266da2e3ebdSchin return(lseek(fd,offset,whence));
2267da2e3ebdSchin }
2268da2e3ebdSchin
2269da2e3ebdSchin #undef dup
sh_dup(register int old)2270da2e3ebdSchin int sh_dup(register int old)
2271da2e3ebdSchin {
2272da2e3ebdSchin register int fd = dup(old);
2273da2e3ebdSchin if(fd>=0)
2274da2e3ebdSchin {
2275da2e3ebdSchin if(sh.fdstatus[old] == IOCLOSE)
2276da2e3ebdSchin sh.fdstatus[old] = 0;
2277da2e3ebdSchin sh.fdstatus[fd] = (sh.fdstatus[old]&~IOCLEX);
2278da2e3ebdSchin if(fdnotify)
2279da2e3ebdSchin (*fdnotify)(old,fd);
2280da2e3ebdSchin }
2281da2e3ebdSchin return(fd);
2282da2e3ebdSchin }
2283da2e3ebdSchin
2284da2e3ebdSchin #undef fcntl
sh_fcntl(register int fd,int op,...)2285da2e3ebdSchin int sh_fcntl(register int fd, int op, ...)
2286da2e3ebdSchin {
2287da2e3ebdSchin int newfd, arg;
2288da2e3ebdSchin va_list ap;
2289da2e3ebdSchin va_start(ap, op);
2290da2e3ebdSchin arg = va_arg(ap, int) ;
2291da2e3ebdSchin va_end(ap);
2292da2e3ebdSchin newfd = fcntl(fd,op,arg);
2293da2e3ebdSchin if(newfd>=0) switch(op)
2294da2e3ebdSchin {
2295da2e3ebdSchin case F_DUPFD:
2296da2e3ebdSchin if(sh.fdstatus[fd] == IOCLOSE)
2297da2e3ebdSchin sh.fdstatus[fd] = 0;
2298da2e3ebdSchin sh.fdstatus[newfd] = (sh.fdstatus[fd]&~IOCLEX);
2299da2e3ebdSchin if(fdnotify)
2300da2e3ebdSchin (*fdnotify)(fd,newfd);
2301da2e3ebdSchin break;
2302da2e3ebdSchin case F_SETFD:
2303da2e3ebdSchin if(sh.fdstatus[fd] == IOCLOSE)
2304da2e3ebdSchin sh.fdstatus[fd] = 0;
2305da2e3ebdSchin if(arg&FD_CLOEXEC)
2306da2e3ebdSchin sh.fdstatus[fd] |= IOCLEX;
2307da2e3ebdSchin else
2308da2e3ebdSchin sh.fdstatus[fd] &= ~IOCLEX;
2309da2e3ebdSchin }
2310da2e3ebdSchin return(newfd);
2311da2e3ebdSchin }
2312da2e3ebdSchin
2313da2e3ebdSchin #undef umask
sh_umask(mode_t m)2314da2e3ebdSchin mode_t sh_umask(mode_t m)
2315da2e3ebdSchin {
2316da2e3ebdSchin sh.mask = m;
2317da2e3ebdSchin return(umask(m));
2318da2e3ebdSchin }
2319da2e3ebdSchin
2320da2e3ebdSchin /*
2321da2e3ebdSchin * give file descriptor <fd> and <mode>, return an iostream pointer
2322da2e3ebdSchin * <mode> must be SF_READ or SF_WRITE
2323da2e3ebdSchin * <fd> must be a non-negative number ofr SH_IOCOPROCESS or SH_IOHISTFILE.
2324da2e3ebdSchin * returns NULL on failure and may set errno.
2325da2e3ebdSchin */
2326da2e3ebdSchin
sh_iogetiop(int fd,int mode)2327da2e3ebdSchin Sfio_t *sh_iogetiop(int fd, int mode)
2328da2e3ebdSchin {
23297c2fbfb3SApril Chin Shell_t *shp = &sh;
2330da2e3ebdSchin int n;
2331da2e3ebdSchin Sfio_t *iop=0;
2332da2e3ebdSchin if(mode!=SF_READ && mode!=SF_WRITE)
2333da2e3ebdSchin {
2334da2e3ebdSchin errno = EINVAL;
2335da2e3ebdSchin return(iop);
2336da2e3ebdSchin }
2337da2e3ebdSchin switch(fd)
2338da2e3ebdSchin {
2339da2e3ebdSchin case SH_IOHISTFILE:
23407c2fbfb3SApril Chin if(!sh_histinit((void*)shp))
2341da2e3ebdSchin return(iop);
23427c2fbfb3SApril Chin fd = sffileno(shp->hist_ptr->histfp);
2343da2e3ebdSchin break;
2344da2e3ebdSchin case SH_IOCOPROCESS:
2345da2e3ebdSchin if(mode==SF_WRITE)
23467c2fbfb3SApril Chin fd = shp->coutpipe;
2347da2e3ebdSchin else
23487c2fbfb3SApril Chin fd = shp->cpipe[0];
2349da2e3ebdSchin break;
2350da2e3ebdSchin default:
23517c2fbfb3SApril Chin if(fd<0 || fd >= shp->lim.open_max)
2352da2e3ebdSchin fd = -1;
2353da2e3ebdSchin }
2354da2e3ebdSchin if(fd<0)
2355da2e3ebdSchin {
2356da2e3ebdSchin errno = EBADF;
2357da2e3ebdSchin return(iop);
2358da2e3ebdSchin }
23597c2fbfb3SApril Chin if(!(n=shp->fdstatus[fd]))
23607c2fbfb3SApril Chin n = sh_iocheckfd(shp,fd);
2361da2e3ebdSchin if(mode==SF_WRITE && !(n&IOWRITE))
2362da2e3ebdSchin return(iop);
2363da2e3ebdSchin if(mode==SF_READ && !(n&IOREAD))
2364da2e3ebdSchin return(iop);
23657c2fbfb3SApril Chin if(!(iop = shp->sftable[fd]))
23667c2fbfb3SApril Chin iop=sh_iostream(shp,fd);
2367da2e3ebdSchin return(iop);
2368da2e3ebdSchin }
2369da2e3ebdSchin
2370da2e3ebdSchin typedef int (*Notify_f)(int,int);
2371da2e3ebdSchin
sh_fdnotify(Notify_f notify)2372da2e3ebdSchin Notify_f sh_fdnotify(Notify_f notify)
2373da2e3ebdSchin {
2374da2e3ebdSchin Notify_f old;
2375da2e3ebdSchin old = fdnotify;
2376da2e3ebdSchin fdnotify = notify;
2377da2e3ebdSchin return(old);
2378da2e3ebdSchin }
2379da2e3ebdSchin
sh_fd2sfio(int fd)2380da2e3ebdSchin Sfio_t *sh_fd2sfio(int fd)
2381da2e3ebdSchin {
23827c2fbfb3SApril Chin Shell_t *shp = &sh;
2383da2e3ebdSchin register int status;
2384da2e3ebdSchin Sfio_t *sp = sh.sftable[fd];
23857c2fbfb3SApril Chin if(!sp && (status = sh_iocheckfd(shp,fd))!=IOCLOSE)
2386da2e3ebdSchin {
2387da2e3ebdSchin register int flags=0;
2388da2e3ebdSchin if(status&IOREAD)
2389da2e3ebdSchin flags |= SF_READ;
2390da2e3ebdSchin if(status&IOWRITE)
2391da2e3ebdSchin flags |= SF_WRITE;
2392da2e3ebdSchin sp = sfnew(NULL, NULL, -1, fd,flags);
2393da2e3ebdSchin sh.sftable[fd] = sp;
2394da2e3ebdSchin }
2395da2e3ebdSchin return(sp);
2396da2e3ebdSchin }
2397da2e3ebdSchin
sh_pathopen(const char * cp)2398da2e3ebdSchin Sfio_t *sh_pathopen(const char *cp)
2399da2e3ebdSchin {
24007c2fbfb3SApril Chin Shell_t *shp = &sh;
2401da2e3ebdSchin int n;
2402da2e3ebdSchin #ifdef PATH_BFPATH
2403da2e3ebdSchin if((n=path_open(cp,path_get(cp))) < 0)
2404da2e3ebdSchin n = path_open(cp,(Pathcomp_t*)0);
2405da2e3ebdSchin #else
2406da2e3ebdSchin if((n=path_open(cp,path_get(cp))) < 0)
2407da2e3ebdSchin n = path_open(cp,"");
2408da2e3ebdSchin #endif
2409da2e3ebdSchin if(n < 0)
2410da2e3ebdSchin errormsg(SH_DICT,ERROR_system(1),e_open,cp);
24117c2fbfb3SApril Chin return(sh_iostream(shp,n));
2412da2e3ebdSchin }
2413