xref: /netbsd-src/bin/sh/input.c (revision 470d6e5e934dd64941c5ca4a159fc018b25193ec)
1*470d6e5eSkre /*	$NetBSD: input.c,v 1.76 2024/10/14 08:15:43 kre Exp $	*/
249f0ad86Scgd 
361f28255Scgd /*-
437ed7877Sjtc  * Copyright (c) 1991, 1993
537ed7877Sjtc  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * This code is derived from software contributed to Berkeley by
861f28255Scgd  * Kenneth Almquist.
961f28255Scgd  *
1061f28255Scgd  * Redistribution and use in source and binary forms, with or without
1161f28255Scgd  * modification, are permitted provided that the following conditions
1261f28255Scgd  * are met:
1361f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1461f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1561f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1661f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1761f28255Scgd  *    documentation and/or other materials provided with the distribution.
18b5b29542Sagc  * 3. Neither the name of the University nor the names of its contributors
1961f28255Scgd  *    may be used to endorse or promote products derived from this software
2061f28255Scgd  *    without specific prior written permission.
2161f28255Scgd  *
2261f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2361f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2461f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2561f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2661f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2761f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2861f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2961f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3061f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3161f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3261f28255Scgd  * SUCH DAMAGE.
3361f28255Scgd  */
3461f28255Scgd 
35cd799663Schristos #include <sys/cdefs.h>
3661f28255Scgd #ifndef lint
3749f0ad86Scgd #if 0
38a45947b2Schristos static char sccsid[] = "@(#)input.c	8.3 (Berkeley) 6/9/95";
3949f0ad86Scgd #else
40*470d6e5eSkre __RCSID("$NetBSD: input.c,v 1.76 2024/10/14 08:15:43 kre Exp $");
4149f0ad86Scgd #endif
4261f28255Scgd #endif /* not lint */
4361f28255Scgd 
4407bae7edSchristos #include <stdio.h>	/* defines BUFSIZ */
4507bae7edSchristos #include <fcntl.h>
4607bae7edSchristos #include <errno.h>
4707bae7edSchristos #include <unistd.h>
48a080d612Schristos #include <limits.h>
4907bae7edSchristos #include <stdlib.h>
50dcb82cbdScgd #include <string.h>
5109ccb201Skre #include <sys/stat.h>
5207bae7edSchristos 
5361f28255Scgd /*
5461f28255Scgd  * This file implements the input routines used by the parser.
5561f28255Scgd  */
5661f28255Scgd 
57a81e4124Sjtc #include "shell.h"
5807bae7edSchristos #include "redir.h"
5961f28255Scgd #include "syntax.h"
6061f28255Scgd #include "input.h"
6161f28255Scgd #include "output.h"
6237ed7877Sjtc #include "options.h"
6361f28255Scgd #include "memalloc.h"
6461f28255Scgd #include "error.h"
6537ed7877Sjtc #include "alias.h"
6637ed7877Sjtc #include "parser.h"
6737ed7877Sjtc #include "myhistedit.h"
68727a69dcSkre #include "show.h"
6961f28255Scgd 
7061f28255Scgd #define EOF_NLEFT -99		/* value of parsenleft when EOF pushed back */
7161f28255Scgd 
7237ed7877Sjtc MKINIT
7337ed7877Sjtc struct strpush {
7437ed7877Sjtc 	struct strpush *prev;	/* preceding string on stack */
75eaa91315Skre 	const char *prevstring;
7637ed7877Sjtc 	int prevnleft;
77c1b02d9bSchristos 	int prevlleft;
7837ed7877Sjtc 	struct alias *ap;	/* if push was associated with an alias */
7937ed7877Sjtc };
8061f28255Scgd 
8161f28255Scgd /*
8261f28255Scgd  * The parsefile structure pointed to by the global variable parsefile
8361f28255Scgd  * contains information about the current file being read.
8461f28255Scgd  */
8561f28255Scgd 
8661f28255Scgd MKINIT
8761f28255Scgd struct parsefile {
8837ed7877Sjtc 	struct parsefile *prev;	/* preceding file on stack */
8961f28255Scgd 	int linno;		/* current line */
9061f28255Scgd 	int fd;			/* file descriptor (or -1 if string) */
91c1b02d9bSchristos 	int nleft;		/* number of chars left in this line */
92c1b02d9bSchristos 	int lleft;		/* number of chars left in this buffer */
9300668d1eSkre 	int nskip;		/* number of \0's dropped in previous line */
94eaa91315Skre 	const char *nextc;	/* next char in buffer */
9561f28255Scgd 	char *buf;		/* input buffer */
9637ed7877Sjtc 	struct strpush *strpush; /* for pushing strings at this level */
9737ed7877Sjtc 	struct strpush basestrpush; /* so pushing one is fast */
9861f28255Scgd };
9961f28255Scgd 
10061f28255Scgd 
10161f28255Scgd int plinno = 1;			/* input line number */
10233809804Schristos int parsenleft;			/* copy of parsefile->nleft */
103c1b02d9bSchristos MKINIT int parselleft;		/* copy of parsefile->lleft */
104eaa91315Skre const char *parsenextc;		/* copy of parsefile->nextc */
10561f28255Scgd MKINIT struct parsefile basepf;	/* top level input file */
10633809804Schristos MKINIT char basebuf[BUFSIZ];	/* buffer for top level input file */
10761f28255Scgd struct parsefile *parsefile = &basepf;	/* current input file */
10837ed7877Sjtc int init_editline = 0;		/* editline library initialized? */
10937ed7877Sjtc int whichprompt;		/* 1 == PS1, 2 == PS2 */
11037ed7877Sjtc 
111c02b3bbdSchristos STATIC void pushfile(void);
112c02b3bbdSchristos static int preadfd(void);
11361f28255Scgd 
11461f28255Scgd #ifdef mkinit
11533809804Schristos INCLUDE <stdio.h>
11661f28255Scgd INCLUDE "input.h"
11761f28255Scgd INCLUDE "error.h"
11861f28255Scgd 
11961f28255Scgd INIT {
12061f28255Scgd 	basepf.nextc = basepf.buf = basebuf;
12161f28255Scgd }
12261f28255Scgd 
12361f28255Scgd RESET {
12461f28255Scgd 	if (exception != EXSHELLPROC)
125c1b02d9bSchristos 		parselleft = parsenleft = 0;	/* clear input buffer */
12661f28255Scgd 	popallfiles();
12761f28255Scgd }
12861f28255Scgd 
12961f28255Scgd SHELLPROC {
13061f28255Scgd 	popallfiles();
13161f28255Scgd }
13261f28255Scgd #endif
13361f28255Scgd 
13461f28255Scgd 
135ae375f01Skre #if 0		/* this is unused */
13661f28255Scgd /*
13761f28255Scgd  * Read a line from the script.
13861f28255Scgd  */
13961f28255Scgd 
14061f28255Scgd char *
141c02b3bbdSchristos pfgets(char *line, int len)
14261f28255Scgd {
14348250187Stls 	char *p = line;
14461f28255Scgd 	int nleft = len;
14561f28255Scgd 	int c;
14661f28255Scgd 
14761f28255Scgd 	while (--nleft > 0) {
14861f28255Scgd 		c = pgetc_macro();
1491a9b5ae6Skre 		if (c == PFAKE)		/* consecutive PFAKEs is impossible */
1501a9b5ae6Skre 			c = pgetc_macro();
15161f28255Scgd 		if (c == PEOF) {
15261f28255Scgd 			if (p == line)
15361f28255Scgd 				return NULL;
15461f28255Scgd 			break;
15561f28255Scgd 		}
15661f28255Scgd 		*p++ = c;
1571a9b5ae6Skre 		if (c == '\n') {
1581a9b5ae6Skre 			plinno++;
15961f28255Scgd 			break;
16061f28255Scgd 		}
1611a9b5ae6Skre 	}
16261f28255Scgd 	*p = '\0';
16361f28255Scgd 	return line;
16461f28255Scgd }
165ae375f01Skre #endif
16661f28255Scgd 
16761f28255Scgd 
16861f28255Scgd /*
16961f28255Scgd  * Read a character from the script, returning PEOF on end of file.
17061f28255Scgd  * Nul characters in the input are silently discarded.
17161f28255Scgd  */
17261f28255Scgd 
17361f28255Scgd int
174c02b3bbdSchristos pgetc(void)
175c1b02d9bSchristos {
176021ba509Skre 	int c;
177021ba509Skre 
178021ba509Skre 	c = pgetc_macro();
179021ba509Skre 	if (c == PFAKE)
180021ba509Skre 		c = pgetc_macro();
181021ba509Skre 	return c;
18261f28255Scgd }
18361f28255Scgd 
18461f28255Scgd 
185c1b02d9bSchristos static int
186c02b3bbdSchristos preadfd(void)
187c1b02d9bSchristos {
188c1b02d9bSchristos 	int nr;
1893d424690Schristos 	char *buf =  parsefile->buf;
1903d424690Schristos 	parsenextc = buf;
19161f28255Scgd 
19261f28255Scgd  retry:
1937accaec4Schristos #ifndef SMALL
19437ed7877Sjtc 	if (parsefile->fd == 0 && el) {
195c02b3bbdSchristos 		static const char *rl_cp;
196c02b3bbdSchristos 		static int el_len;
19737ed7877Sjtc 
198c02b3bbdSchristos 		if (rl_cp == NULL)
199c02b3bbdSchristos 			rl_cp = el_gets(el, &el_len);
200c1b02d9bSchristos 		if (rl_cp == NULL)
2019fa1d120Sroy 			nr = el_len == 0 ? 0 : -1;
202c1b02d9bSchristos 		else {
203c02b3bbdSchristos 			nr = el_len;
204c02b3bbdSchristos 			if (nr > BUFSIZ - 8)
205c02b3bbdSchristos 				nr = BUFSIZ - 8;
206c02b3bbdSchristos 			memcpy(buf, rl_cp, nr);
207c02b3bbdSchristos 			if (nr != el_len) {
208c02b3bbdSchristos 				el_len -= nr;
209c02b3bbdSchristos 				rl_cp += nr;
210c02b3bbdSchristos 			} else
211c02b3bbdSchristos 				rl_cp = 0;
21237ed7877Sjtc 		}
213c02b3bbdSchristos 
2146042831bSchristos 	} else
2156042831bSchristos #endif
216c02b3bbdSchristos 		nr = read(parsefile->fd, buf, BUFSIZ - 8);
2176042831bSchristos 
218c1b02d9bSchristos 
219c1b02d9bSchristos 	if (nr <= 0) {
220c1b02d9bSchristos 		if (nr < 0) {
22161f28255Scgd 			if (errno == EINTR)
22261f28255Scgd 				goto retry;
22361f28255Scgd 			if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
22461f28255Scgd 				int flags = fcntl(0, F_GETFL, 0);
225ae375f01Skre 
22661f28255Scgd 				if (flags >= 0 && flags & O_NONBLOCK) {
22761f28255Scgd 					flags &=~ O_NONBLOCK;
22861f28255Scgd 					if (fcntl(0, F_SETFL, flags) >= 0) {
22961f28255Scgd 						out2str("sh: turning off NDELAY mode\n");
23061f28255Scgd 						goto retry;
23161f28255Scgd 					}
23261f28255Scgd 				}
23361f28255Scgd 			}
23461f28255Scgd 		}
235c1b02d9bSchristos 		nr = -1;
236c1b02d9bSchristos 	}
237c1b02d9bSchristos 	return nr;
238c1b02d9bSchristos }
239c1b02d9bSchristos 
240c1b02d9bSchristos /*
241c1b02d9bSchristos  * Refill the input buffer and return the next input character:
242c1b02d9bSchristos  *
243c1b02d9bSchristos  * 1) If a string was pushed back on the input, pop it;
244c1b02d9bSchristos  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
245c1b02d9bSchristos  *    from a string so we can't refill the buffer, return EOF.
24639225745Skre  * 3) If there is more stuff in this buffer, use it else call read to fill it.
247c1b02d9bSchristos  * 4) Process input up to the next newline, deleting nul characters.
248c1b02d9bSchristos  */
249c1b02d9bSchristos 
250c1b02d9bSchristos int
251c02b3bbdSchristos preadbuffer(void)
252c1b02d9bSchristos {
253c1b02d9bSchristos 	char *p, *q;
254c1b02d9bSchristos 	int more;
2555a3d1851Smrg #ifndef SMALL
256c1b02d9bSchristos 	int something;
2575a3d1851Smrg #endif
258c1b02d9bSchristos 	char savec;
259c1b02d9bSchristos 
26070d8efb3Skre 	while (parsefile->strpush) {
261021ba509Skre 		if (parsenleft == -1 && parsefile->strpush->ap != NULL)
262021ba509Skre 			return PFAKE;
263c1b02d9bSchristos 		popstring();
264c1b02d9bSchristos 		if (--parsenleft >= 0)
265c1b02d9bSchristos 			return (*parsenextc++);
266c1b02d9bSchristos 	}
267c1b02d9bSchristos 	if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
268c1b02d9bSchristos 		return PEOF;
269c1b02d9bSchristos 	flushout(&output);
270c1b02d9bSchristos 	flushout(&errout);
271c1b02d9bSchristos 
272c1b02d9bSchristos  again:
273c1b02d9bSchristos 	if (parselleft <= 0) {
274f726a3c4Schristos 		if ((parselleft = preadfd()) == -1) {
275c1b02d9bSchristos 			parselleft = parsenleft = EOF_NLEFT;
27661f28255Scgd 			return PEOF;
27761f28255Scgd 		}
27800668d1eSkre 		parsefile->nskip = 0;
279c1b02d9bSchristos 	}
280c1b02d9bSchristos 
28100668d1eSkre 		/* jump over slots for any \0 chars that were dropped */
28200668d1eSkre 	parsenextc += parsefile->nskip;
28300668d1eSkre 	parsefile->nskip = 0;
28400668d1eSkre 
285eaa91315Skre 		/* p = (not const char *)parsenextc; */
286eaa91315Skre 	p = parsefile->buf + (parsenextc - parsefile->buf);
287eaa91315Skre 	q = p;
28861f28255Scgd 
28961f28255Scgd 	/* delete nul characters */
2905a3d1851Smrg #ifndef SMALL
29137ed7877Sjtc 	something = 0;
2925a3d1851Smrg #endif
293c1b02d9bSchristos 	for (more = 1; more;) {
294c1b02d9bSchristos 		switch (*p) {
295c1b02d9bSchristos 		case '\0':
296472691bdSkre #ifdef REJECT_NULS
297472691bdSkre 			parsenleft = parselleft = 0;
298472691bdSkre 			error("nul ('\\0') in shell input");
299472691bdSkre 			/* NOTREACHED */
300472691bdSkre #else
301c1b02d9bSchristos 			p++;	/* Skip nul */
30200668d1eSkre 			parsefile->nskip++;
303c1b02d9bSchristos 			goto check;
304472691bdSkre #endif
30537ed7877Sjtc 
306c1b02d9bSchristos 		case '\t':
307c1b02d9bSchristos 		case ' ':
308c1b02d9bSchristos 			break;
309c1b02d9bSchristos 
310c1b02d9bSchristos 		case '\n':
311c1b02d9bSchristos 			parsenleft = q - parsenextc;
312c1b02d9bSchristos 			more = 0; /* Stop processing here */
313c1b02d9bSchristos 			break;
314c1b02d9bSchristos 
315c1b02d9bSchristos 		default:
3165a3d1851Smrg #ifndef SMALL
317c1b02d9bSchristos 			something = 1;
3185a3d1851Smrg #endif
319c1b02d9bSchristos 			break;
320c1b02d9bSchristos 		}
321c1b02d9bSchristos 
32200668d1eSkre 		if (parsefile->nskip)
323c1b02d9bSchristos 			*q++ = *p++;
32400668d1eSkre 		else
32500668d1eSkre 			q = ++p;
32600668d1eSkre 
327472691bdSkre #ifndef REJECT_NULS
328472691bdSkre  check:;
329472691bdSkre #endif
330c1b02d9bSchristos 		if (--parselleft <= 0) {
331c1b02d9bSchristos 			parsenleft = q - parsenextc - 1;
332c1b02d9bSchristos 			if (parsenleft < 0)
333c1b02d9bSchristos 				goto again;
334c1b02d9bSchristos 			*q = '\0';
335c1b02d9bSchristos 			more = 0;
336c1b02d9bSchristos 		}
337c1b02d9bSchristos 	}
338c1b02d9bSchristos 
339c1b02d9bSchristos 	savec = *q;
340c1b02d9bSchristos 	*q = '\0';
341c1b02d9bSchristos 
3427accaec4Schristos #ifndef SMALL
34370a37837Skre 	if (parsefile->fd == 0 && hist && (something || whichprompt == 2)) {
34494604909Schristos 		HistEvent he;
34570a37837Skre 
34637ed7877Sjtc 		INTOFF;
34770a37837Skre 		history(hist, &he, whichprompt != 2 ? H_ENTER : H_APPEND,
348efee3927Schristos 		    parsenextc);
349c591669fSkre 		if (whichprompt != 2 && HistFP != NULL) {
350c591669fSkre 			history(hist, &he, H_NSAVE_FP, (size_t)0, HistFP);
351c591669fSkre 			fflush(HistFP);
352c591669fSkre 		}
35337ed7877Sjtc 		INTON;
35437ed7877Sjtc 	}
355893ade3fSchristos #endif
356c1b02d9bSchristos 
35737ed7877Sjtc 	if (vflag) {
358c1b02d9bSchristos 		out2str(parsenextc);
35937ed7877Sjtc 		flushout(out2);
36037ed7877Sjtc 	}
361c1b02d9bSchristos 
362c1b02d9bSchristos 	*q = savec;
363c1b02d9bSchristos 
36461f28255Scgd 	return *parsenextc++;
36561f28255Scgd }
36661f28255Scgd 
36761f28255Scgd /*
3688a9a9619Skre  * Test whether we have reached EOF on input stream.
3698a9a9619Skre  * Return true only if certain (without attempting a read).
3708a9a9619Skre  *
3718a9a9619Skre  * Note the similarity to the opening section of preadbuffer()
3728a9a9619Skre  */
3738a9a9619Skre int
3748a9a9619Skre at_eof(void)
3758a9a9619Skre {
3768a9a9619Skre 	struct strpush *sp = parsefile->strpush;
3778a9a9619Skre 
3788a9a9619Skre 	if (parsenleft > 0)	/* more chars are in the buffer */
3798a9a9619Skre 		return 0;
3808a9a9619Skre 
3818a9a9619Skre 	while (sp != NULL) {
3828a9a9619Skre 		/*
3838a9a9619Skre 		 * If any pushed string has any remaining data,
3848a9a9619Skre 		 * then we are not at EOF  (simulating popstring())
3858a9a9619Skre 		 */
3868a9a9619Skre 		if (sp->prevnleft > 0)
3878a9a9619Skre 			return 0;
3888a9a9619Skre 		sp = sp->prev;
3898a9a9619Skre 	}
3908a9a9619Skre 
3918a9a9619Skre 	/*
3928a9a9619Skre 	 * If we reached real EOF and pushed it back,
3938a9a9619Skre 	 * or if we are just processing a string (not reading a file)
3948a9a9619Skre 	 * then there is no more.   Note that if a file pushes a
3958a9a9619Skre 	 * string, the file's ->buf remains present.
3968a9a9619Skre 	 */
3978a9a9619Skre 	if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
3988a9a9619Skre 		return 1;
3998a9a9619Skre 
4008a9a9619Skre 	/*
4018a9a9619Skre 	 * In other cases, there might be more
4028a9a9619Skre 	 */
4038a9a9619Skre 	return 0;
4048a9a9619Skre }
4058a9a9619Skre 
4068a9a9619Skre /*
40761f28255Scgd  * Undo the last call to pgetc.  Only one character may be pushed back.
40861f28255Scgd  * PEOF may be pushed back.
40961f28255Scgd  */
41061f28255Scgd 
41161f28255Scgd void
412c02b3bbdSchristos pungetc(void)
413c02b3bbdSchristos {
41461f28255Scgd 	parsenleft++;
41561f28255Scgd 	parsenextc--;
41661f28255Scgd }
41761f28255Scgd 
41861f28255Scgd /*
41937ed7877Sjtc  * Push a string back onto the input at this current parsefile level.
42037ed7877Sjtc  * We handle aliases this way.
42161f28255Scgd  */
42261f28255Scgd void
423eaa91315Skre pushstring(const char *s, int len, struct alias *ap)
42461f28255Scgd {
42537ed7877Sjtc 	struct strpush *sp;
42637ed7877Sjtc 
427ae375f01Skre 	VTRACE(DBG_INPUT,
428ae375f01Skre 	    ("pushstring(\"%.*s\", %d)%s%s%s had: nl=%d ll=%d \"%.*s\"\n",
429ae375f01Skre 	    len, s, len, ap ? " for alias:'" : "",
430ae375f01Skre 	    ap ? ap->name : "", ap ? "'" : "",
431ae375f01Skre 	    parsenleft, parselleft, parsenleft, parsenextc));
432ae375f01Skre 
43337ed7877Sjtc 	INTOFF;
43437ed7877Sjtc 	if (parsefile->strpush) {
43537ed7877Sjtc 		sp = ckmalloc(sizeof (struct strpush));
43637ed7877Sjtc 		sp->prev = parsefile->strpush;
43737ed7877Sjtc 		parsefile->strpush = sp;
43837ed7877Sjtc 	} else
43937ed7877Sjtc 		sp = parsefile->strpush = &(parsefile->basestrpush);
440ae375f01Skre 
44137ed7877Sjtc 	sp->prevstring = parsenextc;
44237ed7877Sjtc 	sp->prevnleft = parsenleft;
443c1b02d9bSchristos 	sp->prevlleft = parselleft;
444323e8358Skre 	sp->ap = ap;
44537ed7877Sjtc 	if (ap)
446323e8358Skre 		ap->flag |= ALIASINUSE;
44737ed7877Sjtc 	parsenextc = s;
44837ed7877Sjtc 	parsenleft = len;
44937ed7877Sjtc 	INTON;
45061f28255Scgd }
45161f28255Scgd 
4525dad1439Scgd void
453c02b3bbdSchristos popstring(void)
45437ed7877Sjtc {
45537ed7877Sjtc 	struct strpush *sp = parsefile->strpush;
45661f28255Scgd 
45737ed7877Sjtc 	INTOFF;
458021ba509Skre 	if (sp->ap) {
459ed405f1dSkre 		int alen;
460ed405f1dSkre 
46120c0839aSkre 		if ((alen = strlen(sp->ap->val)) > 0 &&
462ed405f1dSkre 		    (sp->ap->val[alen - 1] == ' ' ||
463ed405f1dSkre 		     sp->ap->val[alen - 1] == '\t'))
464021ba509Skre 			checkkwd |= CHKALIAS;
465021ba509Skre 		sp->ap->flag &= ~ALIASINUSE;
466021ba509Skre 	}
46737ed7877Sjtc 	parsenextc = sp->prevstring;
46837ed7877Sjtc 	parsenleft = sp->prevnleft;
469c1b02d9bSchristos 	parselleft = sp->prevlleft;
470ae375f01Skre 
471ae375f01Skre 	VTRACE(DBG_INPUT, ("popstring()%s%s%s nl=%d ll=%d \"%.*s\"\n",
472ae375f01Skre 	    sp->ap ? " from alias:'" : "", sp->ap ? sp->ap->name : "",
473ae375f01Skre 	    sp->ap ? "'" : "", parsenleft, parselleft, parsenleft, parsenextc));
474ae375f01Skre 
47537ed7877Sjtc 	parsefile->strpush = sp->prev;
47637ed7877Sjtc 	if (sp != &(parsefile->basestrpush))
47737ed7877Sjtc 		ckfree(sp);
47837ed7877Sjtc 	INTON;
47937ed7877Sjtc }
48061f28255Scgd 
48161f28255Scgd /*
48261f28255Scgd  * Set the input to take input from a file.  If push is set, push the
48361f28255Scgd  * old input onto the stack first.
48461f28255Scgd  */
48561f28255Scgd 
48661f28255Scgd void
487c02b3bbdSchristos setinputfile(const char *fname, int push)
48861f28255Scgd {
4899da5e43fSrillig 	unsigned char magic[4];
49061f28255Scgd 	int fd;
49161f28255Scgd 	int fd2;
49209ccb201Skre 	struct stat sb;
49361f28255Scgd 
494ae375f01Skre 	CTRACE(DBG_INPUT,("setinputfile(\"%s\", %spush)\n",fname,push?"":"no"));
495ae375f01Skre 
49661f28255Scgd 	INTOFF;
49761f28255Scgd 	if ((fd = open(fname, O_RDONLY)) < 0)
49861f28255Scgd 		error("Can't open %s", fname);
4999da5e43fSrillig 
5009da5e43fSrillig 	/* Since the message "Syntax error: "(" unexpected" is not very
5019da5e43fSrillig 	 * helpful, we check if the file starts with the ELF magic to
5029da5e43fSrillig 	 * avoid that message. The first lseek tries to make sure that
5039da5e43fSrillig 	 * we can later rewind the file.
5049da5e43fSrillig 	 */
50509ccb201Skre 	if (fstat(fd, &sb) == 0 && S_ISREG(sb.st_mode) &&
50609ccb201Skre 	    lseek(fd, 0, SEEK_SET) == 0) {
5079da5e43fSrillig 		if (read(fd, magic, 4) == 4) {
5083eee1474Skre 			if (memcmp(magic, "\177ELF", 4) == 0) {
5093eee1474Skre 				(void)close(fd);
5109da5e43fSrillig 				error("Cannot execute ELF binary %s", fname);
5119da5e43fSrillig 			}
5123eee1474Skre 		}
5133eee1474Skre 		if (lseek(fd, 0, SEEK_SET) != 0) {
5143eee1474Skre 			(void)close(fd);
5159da5e43fSrillig 			error("Cannot rewind the file %s", fname);
5169da5e43fSrillig 		}
5173eee1474Skre 	}
5189da5e43fSrillig 
5191fad4bb6Schristos 	fd2 = to_upper_fd(fd);	/* closes fd, returns higher equiv */
5201fad4bb6Schristos 	if (fd2 == fd) {
5211fad4bb6Schristos 		(void) close(fd);
52261f28255Scgd 		error("Out of file descriptors");
52361f28255Scgd 	}
5241fad4bb6Schristos 
5251fad4bb6Schristos 	setinputfd(fd2, push);
52661f28255Scgd 	INTON;
52761f28255Scgd }
52861f28255Scgd 
52951c4dfe4Skre /*
53051c4dfe4Skre  * When a shell fd needs to be altered (when the user wants to use
53151c4dfe4Skre  * the same fd - rare, but happens - we need to locate the ref to
53251c4dfe4Skre  * the fd, and update it.  This happens via a callback.
53351c4dfe4Skre  * This is the callback func for fd's used for shell input
53451c4dfe4Skre  */
53551c4dfe4Skre static void
53651c4dfe4Skre input_fd_swap(int from, int to)
53751c4dfe4Skre {
53851c4dfe4Skre 	struct parsefile *pf;
53951c4dfe4Skre 
54051c4dfe4Skre 	pf = parsefile;
54151c4dfe4Skre 	while (pf != NULL) {		/* don't need to stop at basepf */
54251c4dfe4Skre 		if (pf->fd == from)
54351c4dfe4Skre 			pf->fd = to;
54451c4dfe4Skre 		pf = pf->prev;
54551c4dfe4Skre 	}
54651c4dfe4Skre }
54761f28255Scgd 
54861f28255Scgd /*
54961f28255Scgd  * Like setinputfile, but takes an open file descriptor.  Call this with
55061f28255Scgd  * interrupts off.
55161f28255Scgd  */
55261f28255Scgd 
55361f28255Scgd void
554c02b3bbdSchristos setinputfd(int fd, int push)
5555dad1439Scgd {
556ae375f01Skre 	VTRACE(DBG_INPUT, ("setinputfd(%d, %spush)\n", fd, push?"":"no"));
557ae375f01Skre 
558e8999de4Skre 	INTOFF;
55951c4dfe4Skre 	register_sh_fd(fd, input_fd_swap);
5603a59e5e8Smycroft 	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
561ae375f01Skre 	if (push)
56261f28255Scgd 		pushfile();
56361f28255Scgd 	if (parsefile->fd > 0)
56451c4dfe4Skre 		sh_close(parsefile->fd);
56561f28255Scgd 	parsefile->fd = fd;
56661f28255Scgd 	if (parsefile->buf == NULL)
56761f28255Scgd 		parsefile->buf = ckmalloc(BUFSIZ);
568c1b02d9bSchristos 	parselleft = parsenleft = 0;
56961f28255Scgd 	plinno = 1;
570e8999de4Skre 	INTON;
571ae375f01Skre 
572ae375f01Skre 	CTRACE(DBG_INPUT, ("setinputfd(%d, %spush) done; plinno=1\n", fd,
573ae375f01Skre 	    push ? "" : "no"));
57461f28255Scgd }
57561f28255Scgd 
57661f28255Scgd 
57761f28255Scgd /*
57861f28255Scgd  * Like setinputfile, but takes input from a string.
57961f28255Scgd  */
58061f28255Scgd 
58161f28255Scgd void
58250a5715bSkre setinputstring(const char *string, int push, int line1)
58361f28255Scgd {
584ca12a0b8Schristos 
58561f28255Scgd 	INTOFF;
586727a69dcSkre 	if (push)		/* XXX: always, as it happens */
58761f28255Scgd 		pushfile();
58861f28255Scgd 	parsenextc = string;
589c1b02d9bSchristos 	parselleft = parsenleft = strlen(string);
590fd38bbe2Skre 	plinno = line1;
591e8999de4Skre 	INTON;
592ae375f01Skre 
593ae375f01Skre 	CTRACE(DBG_INPUT,
594a9e6fc0bSkre 	    ("setinputstring(\"%.20s%s\" (%d), %spush, @ %d)\n", string,
595ae375f01Skre 	    (parsenleft > 20 ? "..." : ""), parsenleft, push?"":"no", line1));
59661f28255Scgd }
59761f28255Scgd 
59861f28255Scgd 
59961f28255Scgd 
60061f28255Scgd /*
60161f28255Scgd  * To handle the "." command, a stack of input files is used.  Pushfile
60261f28255Scgd  * adds a new entry to the stack and popfile restores the previous level.
60361f28255Scgd  */
60461f28255Scgd 
60561f28255Scgd STATIC void
606c02b3bbdSchristos pushfile(void)
607c02b3bbdSchristos {
60861f28255Scgd 	struct parsefile *pf;
60961f28255Scgd 
610ae375f01Skre 	VTRACE(DBG_INPUT,
611ae375f01Skre 	    ("pushfile(): fd=%d buf=%p nl=%d ll=%d \"%.*s\" plinno=%d\n",
612ae375f01Skre 	    parsefile->fd, parsefile->buf, parsenleft, parselleft,
6131fca9bbfSkre 	    parsenleft, parsenextc, plinno));
6141fca9bbfSkre 
61561f28255Scgd 	parsefile->nleft = parsenleft;
616c1b02d9bSchristos 	parsefile->lleft = parselleft;
61761f28255Scgd 	parsefile->nextc = parsenextc;
61861f28255Scgd 	parsefile->linno = plinno;
61961f28255Scgd 	pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
62061f28255Scgd 	pf->prev = parsefile;
62161f28255Scgd 	pf->fd = -1;
62237ed7877Sjtc 	pf->strpush = NULL;
62337ed7877Sjtc 	pf->basestrpush.prev = NULL;
624ae375f01Skre 	pf->buf = NULL;
62561f28255Scgd 	parsefile = pf;
62661f28255Scgd }
62761f28255Scgd 
62861f28255Scgd 
62961f28255Scgd void
630c02b3bbdSchristos popfile(void)
631c02b3bbdSchristos {
63261f28255Scgd 	struct parsefile *pf = parsefile;
63361f28255Scgd 
63461f28255Scgd 	INTOFF;
63561f28255Scgd 	if (pf->fd >= 0)
63651c4dfe4Skre 		sh_close(pf->fd);
63761f28255Scgd 	if (pf->buf)
63861f28255Scgd 		ckfree(pf->buf);
63937ed7877Sjtc 	while (pf->strpush)
64037ed7877Sjtc 		popstring();
64161f28255Scgd 	parsefile = pf->prev;
64261f28255Scgd 	ckfree(pf);
64361f28255Scgd 	parsenleft = parsefile->nleft;
644c1b02d9bSchristos 	parselleft = parsefile->lleft;
64561f28255Scgd 	parsenextc = parsefile->nextc;
646ae375f01Skre 
6471fca9bbfSkre 	VTRACE(DBG_INPUT,
648ae375f01Skre 	    ("popfile(): fd=%d buf=%p nl=%d ll=%d \"%.*s\" plinno:%d->%d\n",
649ae375f01Skre 	    parsefile->fd, parsefile->buf, parsenleft, parselleft,
6501fca9bbfSkre 	    parsenleft, parsenextc, plinno, parsefile->linno));
651ae375f01Skre 
65261f28255Scgd 	plinno = parsefile->linno;
65361f28255Scgd 	INTON;
65461f28255Scgd }
65561f28255Scgd 
6561fca9bbfSkre /*
6571fca9bbfSkre  * Return current file (to go back to it later using popfilesupto()).
6581fca9bbfSkre  */
6591fca9bbfSkre 
6601fca9bbfSkre struct parsefile *
6611fca9bbfSkre getcurrentfile(void)
6621fca9bbfSkre {
6631fca9bbfSkre 	return parsefile;
6641fca9bbfSkre }
6651fca9bbfSkre 
6661fca9bbfSkre 
6671fca9bbfSkre /*
6681fca9bbfSkre  * Pop files until the given file is on top again. Useful for regular
6691fca9bbfSkre  * builtins that read shell commands from files or strings.
6701fca9bbfSkre  * If the given file is not an active file, an error is raised.
6711fca9bbfSkre  */
6721fca9bbfSkre 
6731fca9bbfSkre void
6741fca9bbfSkre popfilesupto(struct parsefile *file)
6751fca9bbfSkre {
6761fca9bbfSkre 	while (parsefile != file && parsefile != &basepf)
6771fca9bbfSkre 		popfile();
6781fca9bbfSkre 	if (parsefile != file)
6791fca9bbfSkre 		error("popfilesupto() misused");
6801fca9bbfSkre }
6811fca9bbfSkre 
68261f28255Scgd 
68361f28255Scgd /*
68461f28255Scgd  * Return to top level.
68561f28255Scgd  */
68661f28255Scgd 
68761f28255Scgd void
688c02b3bbdSchristos popallfiles(void)
689c02b3bbdSchristos {
69061f28255Scgd 	while (parsefile != &basepf)
69161f28255Scgd 		popfile();
69261f28255Scgd }
69361f28255Scgd 
69461f28255Scgd 
69561f28255Scgd 
69661f28255Scgd /*
69761f28255Scgd  * Close the file(s) that the shell is reading commands from.  Called
69861f28255Scgd  * after a fork is done.
699edcb4544Schristos  *
700edcb4544Schristos  * Takes one arg, vfork, which tells it to not modify its global vars
701edcb4544Schristos  * as it is still running in the parent.
702a9fc176eSdsl  *
703a9fc176eSdsl  * This code is (probably) unnecessary as the 'close on exec' flag is
704a9fc176eSdsl  * set and should be enough.  In the vfork case it is definitely wrong
705a9fc176eSdsl  * to close the fds as another fork() may be done later to feed data
706a9fc176eSdsl  * from a 'here' document into a pipe and we don't want to close the
707a9fc176eSdsl  * pipe!
70861f28255Scgd  */
70961f28255Scgd 
71061f28255Scgd void
711c02b3bbdSchristos closescript(int vforked)
712c02b3bbdSchristos {
713a9fc176eSdsl 	if (vforked)
714edcb4544Schristos 		return;
71561f28255Scgd 	popallfiles();
71661f28255Scgd 	if (parsefile->fd > 0) {
71751c4dfe4Skre 		sh_close(parsefile->fd);
71861f28255Scgd 		parsefile->fd = 0;
71961f28255Scgd 	}
72061f28255Scgd }
721