xref: /netbsd-src/bin/sh/input.c (revision b757af438b42b93f8c6571f026d8b8ef3eaf5fc9)
1 /*	$NetBSD: input.c,v 1.45 2012/03/28 20:11:25 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 1991, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Kenneth Almquist.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include <sys/cdefs.h>
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)input.c	8.3 (Berkeley) 6/9/95";
39 #else
40 __RCSID("$NetBSD: input.c,v 1.45 2012/03/28 20:11:25 christos Exp $");
41 #endif
42 #endif /* not lint */
43 
44 #include <stdio.h>	/* defines BUFSIZ */
45 #include <fcntl.h>
46 #include <errno.h>
47 #include <unistd.h>
48 #include <limits.h>
49 #include <stdlib.h>
50 #include <string.h>
51 
52 /*
53  * This file implements the input routines used by the parser.
54  */
55 
56 #include "shell.h"
57 #include "redir.h"
58 #include "syntax.h"
59 #include "input.h"
60 #include "output.h"
61 #include "options.h"
62 #include "memalloc.h"
63 #include "error.h"
64 #include "alias.h"
65 #include "parser.h"
66 #include "myhistedit.h"
67 
68 #define EOF_NLEFT -99		/* value of parsenleft when EOF pushed back */
69 
70 MKINIT
71 struct strpush {
72 	struct strpush *prev;	/* preceding string on stack */
73 	char *prevstring;
74 	int prevnleft;
75 	int prevlleft;
76 	struct alias *ap;	/* if push was associated with an alias */
77 };
78 
79 /*
80  * The parsefile structure pointed to by the global variable parsefile
81  * contains information about the current file being read.
82  */
83 
84 MKINIT
85 struct parsefile {
86 	struct parsefile *prev;	/* preceding file on stack */
87 	int linno;		/* current line */
88 	int fd;			/* file descriptor (or -1 if string) */
89 	int nleft;		/* number of chars left in this line */
90 	int lleft;		/* number of chars left in this buffer */
91 	char *nextc;		/* next char in buffer */
92 	char *buf;		/* input buffer */
93 	struct strpush *strpush; /* for pushing strings at this level */
94 	struct strpush basestrpush; /* so pushing one is fast */
95 };
96 
97 
98 int plinno = 1;			/* input line number */
99 int parsenleft;			/* copy of parsefile->nleft */
100 MKINIT int parselleft;		/* copy of parsefile->lleft */
101 char *parsenextc;		/* copy of parsefile->nextc */
102 MKINIT struct parsefile basepf;	/* top level input file */
103 MKINIT char basebuf[BUFSIZ];	/* buffer for top level input file */
104 struct parsefile *parsefile = &basepf;	/* current input file */
105 int init_editline = 0;		/* editline library initialized? */
106 int whichprompt;		/* 1 == PS1, 2 == PS2 */
107 
108 STATIC void pushfile(void);
109 static int preadfd(void);
110 
111 #ifdef mkinit
112 INCLUDE <stdio.h>
113 INCLUDE "input.h"
114 INCLUDE "error.h"
115 
116 INIT {
117 	basepf.nextc = basepf.buf = basebuf;
118 }
119 
120 RESET {
121 	if (exception != EXSHELLPROC)
122 		parselleft = parsenleft = 0;	/* clear input buffer */
123 	popallfiles();
124 }
125 
126 SHELLPROC {
127 	popallfiles();
128 }
129 #endif
130 
131 
132 /*
133  * Read a line from the script.
134  */
135 
136 char *
137 pfgets(char *line, int len)
138 {
139 	char *p = line;
140 	int nleft = len;
141 	int c;
142 
143 	while (--nleft > 0) {
144 		c = pgetc_macro();
145 		if (c == PEOF) {
146 			if (p == line)
147 				return NULL;
148 			break;
149 		}
150 		*p++ = c;
151 		if (c == '\n')
152 			break;
153 	}
154 	*p = '\0';
155 	return line;
156 }
157 
158 
159 
160 /*
161  * Read a character from the script, returning PEOF on end of file.
162  * Nul characters in the input are silently discarded.
163  */
164 
165 int
166 pgetc(void)
167 {
168 	return pgetc_macro();
169 }
170 
171 
172 static int
173 preadfd(void)
174 {
175 	int nr;
176 	char *buf =  parsefile->buf;
177 	parsenextc = buf;
178 
179 retry:
180 #ifndef SMALL
181 	if (parsefile->fd == 0 && el) {
182 		static const char *rl_cp;
183 		static int el_len;
184 
185 		if (rl_cp == NULL)
186 			rl_cp = el_gets(el, &el_len);
187 		if (rl_cp == NULL)
188 			nr = el_len == 0 ? 0 : -1;
189 		else {
190 			nr = el_len;
191 			if (nr > BUFSIZ - 8)
192 				nr = BUFSIZ - 8;
193 			memcpy(buf, rl_cp, nr);
194 			if (nr != el_len) {
195 				el_len -= nr;
196 				rl_cp += nr;
197 			} else
198 				rl_cp = 0;
199 		}
200 
201 	} else
202 #endif
203 		nr = read(parsefile->fd, buf, BUFSIZ - 8);
204 
205 
206 	if (nr <= 0) {
207                 if (nr < 0) {
208                         if (errno == EINTR)
209                                 goto retry;
210                         if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
211                                 int flags = fcntl(0, F_GETFL, 0);
212                                 if (flags >= 0 && flags & O_NONBLOCK) {
213                                         flags &=~ O_NONBLOCK;
214                                         if (fcntl(0, F_SETFL, flags) >= 0) {
215 						out2str("sh: turning off NDELAY mode\n");
216                                                 goto retry;
217                                         }
218                                 }
219                         }
220                 }
221                 nr = -1;
222 	}
223 	return nr;
224 }
225 
226 /*
227  * Refill the input buffer and return the next input character:
228  *
229  * 1) If a string was pushed back on the input, pop it;
230  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
231  *    from a string so we can't refill the buffer, return EOF.
232  * 3) If the is more stuff in this buffer, use it else call read to fill it.
233  * 4) Process input up to the next newline, deleting nul characters.
234  */
235 
236 int
237 preadbuffer(void)
238 {
239 	char *p, *q;
240 	int more;
241 	int something;
242 	char savec;
243 
244 	if (parsefile->strpush) {
245 		popstring();
246 		if (--parsenleft >= 0)
247 			return (*parsenextc++);
248 	}
249 	if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
250 		return PEOF;
251 	flushout(&output);
252 	flushout(&errout);
253 
254 again:
255 	if (parselleft <= 0) {
256 		if ((parselleft = preadfd()) == -1) {
257 			parselleft = parsenleft = EOF_NLEFT;
258 			return PEOF;
259 		}
260 	}
261 
262 	q = p = parsenextc;
263 
264 	/* delete nul characters */
265 	something = 0;
266 	for (more = 1; more;) {
267 		switch (*p) {
268 		case '\0':
269 			p++;	/* Skip nul */
270 			goto check;
271 
272 		case '\t':
273 		case ' ':
274 			break;
275 
276 		case '\n':
277 			parsenleft = q - parsenextc;
278 			more = 0; /* Stop processing here */
279 			break;
280 
281 		default:
282 			something = 1;
283 			break;
284 		}
285 
286 		*q++ = *p++;
287 check:
288 		if (--parselleft <= 0) {
289 			parsenleft = q - parsenextc - 1;
290 			if (parsenleft < 0)
291 				goto again;
292 			*q = '\0';
293 			more = 0;
294 		}
295 	}
296 
297 	savec = *q;
298 	*q = '\0';
299 
300 #ifndef SMALL
301 	if (parsefile->fd == 0 && hist && something) {
302 		HistEvent he;
303 		INTOFF;
304 		history(hist, &he, whichprompt == 1? H_ENTER : H_APPEND,
305 		    parsenextc);
306 		INTON;
307 	}
308 #endif
309 
310 	if (vflag) {
311 		out2str(parsenextc);
312 		flushout(out2);
313 	}
314 
315 	*q = savec;
316 
317 	return *parsenextc++;
318 }
319 
320 /*
321  * Undo the last call to pgetc.  Only one character may be pushed back.
322  * PEOF may be pushed back.
323  */
324 
325 void
326 pungetc(void)
327 {
328 	parsenleft++;
329 	parsenextc--;
330 }
331 
332 /*
333  * Push a string back onto the input at this current parsefile level.
334  * We handle aliases this way.
335  */
336 void
337 pushstring(char *s, int len, void *ap)
338 {
339 	struct strpush *sp;
340 
341 	INTOFF;
342 /*debugprintf("*** calling pushstring: %s, %d\n", s, len);*/
343 	if (parsefile->strpush) {
344 		sp = ckmalloc(sizeof (struct strpush));
345 		sp->prev = parsefile->strpush;
346 		parsefile->strpush = sp;
347 	} else
348 		sp = parsefile->strpush = &(parsefile->basestrpush);
349 	sp->prevstring = parsenextc;
350 	sp->prevnleft = parsenleft;
351 	sp->prevlleft = parselleft;
352 	sp->ap = (struct alias *)ap;
353 	if (ap)
354 		((struct alias *)ap)->flag |= ALIASINUSE;
355 	parsenextc = s;
356 	parsenleft = len;
357 	INTON;
358 }
359 
360 void
361 popstring(void)
362 {
363 	struct strpush *sp = parsefile->strpush;
364 
365 	INTOFF;
366 	parsenextc = sp->prevstring;
367 	parsenleft = sp->prevnleft;
368 	parselleft = sp->prevlleft;
369 /*debugprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
370 	if (sp->ap)
371 		sp->ap->flag &= ~ALIASINUSE;
372 	parsefile->strpush = sp->prev;
373 	if (sp != &(parsefile->basestrpush))
374 		ckfree(sp);
375 	INTON;
376 }
377 
378 /*
379  * Set the input to take input from a file.  If push is set, push the
380  * old input onto the stack first.
381  */
382 
383 void
384 setinputfile(const char *fname, int push)
385 {
386 	unsigned char magic[4];
387 	int fd;
388 	int fd2;
389 
390 	INTOFF;
391 	if ((fd = open(fname, O_RDONLY)) < 0)
392 		error("Can't open %s", fname);
393 
394 	/* Since the message "Syntax error: "(" unexpected" is not very
395 	 * helpful, we check if the file starts with the ELF magic to
396 	 * avoid that message. The first lseek tries to make sure that
397 	 * we can later rewind the file.
398 	 */
399 	if (lseek(fd, 0, SEEK_SET) == 0) {
400 		if (read(fd, magic, 4) == 4) {
401 			if (memcmp(magic, "\177ELF", 4) == 0)
402 				error("Cannot execute ELF binary %s", fname);
403 		}
404 		if (lseek(fd, 0, SEEK_SET) != 0)
405 			error("Cannot rewind the file %s", fname);
406 	}
407 
408 	if (fd < 10) {
409 		fd2 = copyfd(fd, 10, 0);
410 		close(fd);
411 		if (fd2 < 0)
412 			error("Out of file descriptors");
413 		fd = fd2;
414 	}
415 	setinputfd(fd, push);
416 	INTON;
417 }
418 
419 
420 /*
421  * Like setinputfile, but takes an open file descriptor.  Call this with
422  * interrupts off.
423  */
424 
425 void
426 setinputfd(int fd, int push)
427 {
428 	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
429 	if (push) {
430 		pushfile();
431 		parsefile->buf = ckmalloc(BUFSIZ);
432 	}
433 	if (parsefile->fd > 0)
434 		close(parsefile->fd);
435 	parsefile->fd = fd;
436 	if (parsefile->buf == NULL)
437 		parsefile->buf = ckmalloc(BUFSIZ);
438 	parselleft = parsenleft = 0;
439 	plinno = 1;
440 }
441 
442 
443 /*
444  * Like setinputfile, but takes input from a string.
445  */
446 
447 void
448 setinputstring(char *string, int push)
449 {
450 	INTOFF;
451 	if (push)
452 		pushfile();
453 	parsenextc = string;
454 	parselleft = parsenleft = strlen(string);
455 	parsefile->buf = NULL;
456 	plinno = 1;
457 	INTON;
458 }
459 
460 
461 
462 /*
463  * To handle the "." command, a stack of input files is used.  Pushfile
464  * adds a new entry to the stack and popfile restores the previous level.
465  */
466 
467 STATIC void
468 pushfile(void)
469 {
470 	struct parsefile *pf;
471 
472 	parsefile->nleft = parsenleft;
473 	parsefile->lleft = parselleft;
474 	parsefile->nextc = parsenextc;
475 	parsefile->linno = plinno;
476 	pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
477 	pf->prev = parsefile;
478 	pf->fd = -1;
479 	pf->strpush = NULL;
480 	pf->basestrpush.prev = NULL;
481 	parsefile = pf;
482 }
483 
484 
485 void
486 popfile(void)
487 {
488 	struct parsefile *pf = parsefile;
489 
490 	INTOFF;
491 	if (pf->fd >= 0)
492 		close(pf->fd);
493 	if (pf->buf)
494 		ckfree(pf->buf);
495 	while (pf->strpush)
496 		popstring();
497 	parsefile = pf->prev;
498 	ckfree(pf);
499 	parsenleft = parsefile->nleft;
500 	parselleft = parsefile->lleft;
501 	parsenextc = parsefile->nextc;
502 	plinno = parsefile->linno;
503 	INTON;
504 }
505 
506 
507 /*
508  * Return to top level.
509  */
510 
511 void
512 popallfiles(void)
513 {
514 	while (parsefile != &basepf)
515 		popfile();
516 }
517 
518 
519 
520 /*
521  * Close the file(s) that the shell is reading commands from.  Called
522  * after a fork is done.
523  *
524  * Takes one arg, vfork, which tells it to not modify its global vars
525  * as it is still running in the parent.
526  *
527  * This code is (probably) unnecessary as the 'close on exec' flag is
528  * set and should be enough.  In the vfork case it is definitely wrong
529  * to close the fds as another fork() may be done later to feed data
530  * from a 'here' document into a pipe and we don't want to close the
531  * pipe!
532  */
533 
534 void
535 closescript(int vforked)
536 {
537 	if (vforked)
538 		return;
539 	popallfiles();
540 	if (parsefile->fd > 0) {
541 		close(parsefile->fd);
542 		parsefile->fd = 0;
543 	}
544 }
545