1 /*-
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1997-2005
5  *	Herbert Xu <herbert@gondor.apana.org.au>.  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 <stdio.h>	/* defines BUFSIZ */
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <stdlib.h>
39 #include <string.h>
40 
41 #ifdef USE_LINENOISE
42 #include <linenoise/linenoise.h>
43 #endif
44 
45 /*
46  * This file implements the input routines used by the parser.
47  */
48 
49 #include "eval.h"
50 #include "shell.h"
51 #include "redir.h"
52 #include "syntax.h"
53 #include "input.h"
54 #include "output.h"
55 #include "options.h"
56 #include "memalloc.h"
57 #include "error.h"
58 #include "alias.h"
59 #include "parser.h"
60 #include "main.h"
61 
62 #define EOF_NLEFT -99		/* value of parsenleft when EOF pushed back */
63 #define IBUFSIZ (BUFSIZ + 1)
64 
65 
66 MKINIT struct parsefile basepf;	/* top level input file */
67 MKINIT char basebuf[IBUFSIZ];	/* buffer for top level input file */
68 struct parsefile *parsefile = &basepf;	/* current input file */
69 int whichprompt;		/* 1 == PS1, 2 == PS2 */
70 
71 #ifdef USE_LINENOISE
72 static char *pending_line;
73 static size_t pending_line_index;
74 static size_t pending_line_length;
75 #endif
76 
77 STATIC void pushfile(void);
78 static int preadfd(void);
79 static void setinputfd(int fd, int push);
80 static int preadbuffer(void);
81 
82 #ifdef mkinit
83 INCLUDE <stdio.h>
84 INCLUDE "input.h"
85 INCLUDE "error.h"
86 
87 INIT {
88 	basepf.nextc = basepf.buf = basebuf;
89 	basepf.linno = 1;
90 }
91 
92 RESET {
93 	/* clear input buffer */
94 	basepf.lleft = basepf.nleft = 0;
95 	popallfiles();
96 }
97 #endif
98 
99 
100 /*
101  * Read a character from the script, returning PEOF on end of file.
102  * Nul characters in the input are silently discarded.
103  */
104 
105 int
pgetc(void)106 pgetc(void)
107 {
108 	int c;
109 
110 	if (parsefile->unget)
111 		return parsefile->lastc[--parsefile->unget];
112 
113 	if (--parsefile->nleft >= 0)
114 		c = (signed char)*parsefile->nextc++;
115 	else
116 		c = preadbuffer();
117 
118 	parsefile->lastc[1] = parsefile->lastc[0];
119 	parsefile->lastc[0] = c;
120 
121 	return c;
122 }
123 
124 
125 /*
126  * Same as pgetc(), but ignores PEOA.
127  */
128 
129 int
pgetc2()130 pgetc2()
131 {
132 	int c;
133 	do {
134 		c = pgetc();
135 	} while (c == PEOA);
136 	return c;
137 }
138 
139 
140 static int
preadfd(void)141 preadfd(void)
142 {
143 	int nr;
144 	char *buf =  parsefile->buf;
145 	parsefile->nextc = buf;
146 	const char* prompt = NULL;
147 
148 retry:
149 #ifdef USE_LINENOISE
150 	if (parsefile->fd == 0 && iflag) {
151 		if (pending_line == NULL) {
152 			// linenoise stashs the prompt buffer away for
153 			// the duration of its edit cycle. Because
154 			// some edit functionality (in particular, tab
155 			// completion allocates the parts of PATH from
156 			// dash's stack-based allocator), we need to
157 			// properly save the string and then free it,
158 			// or it will be clobbered.
159 			prompt = savestr(getprompt(NULL));
160 			pending_line = linenoise(prompt);
161 			if (pending_line) {
162 				pending_line_index = 0u;
163 				pending_line_length = strlen(pending_line);
164 				pending_line[pending_line_length] = '\n';
165 				pending_line_length += 1;
166 			}
167 		}
168 		if (pending_line == NULL)
169 			nr = 0;
170 		else {
171 			nr = pending_line_length - pending_line_index;
172 			if (nr > IBUFSIZ - 1)
173 				nr = IBUFSIZ - 1;
174 			memcpy(buf, pending_line + pending_line_index, nr);
175 			pending_line_index += nr;
176 			if (pending_line_index == pending_line_length) {
177 				linenoiseFree(pending_line);
178 				free(prompt);
179 				pending_line = NULL;
180 				pending_line_index = 0u;
181 				pending_line_length = 0u;
182 			}
183 		}
184 	} else
185 #endif
186 		nr = read(parsefile->fd, buf, IBUFSIZ - 1);
187 
188 
189 	if (nr < 0) {
190 		if (errno == EINTR)
191 			goto retry;
192 		if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
193 			int flags = fcntl(0, F_GETFL, 0);
194 			if (flags >= 0 && flags & O_NONBLOCK) {
195 				flags &=~ O_NONBLOCK;
196 				if (fcntl(0, F_SETFL, flags) >= 0) {
197 					out2str("sh: turning off NDELAY mode\n");
198 					goto retry;
199 				}
200 			}
201 		}
202 	}
203 	return nr;
204 }
205 
addtohistory(const char * entry,size_t length)206 static void addtohistory(const char* entry, size_t length) {
207 	// TODO(abarth): If whichprompt != 1, we should append this value to an
208 	// existing history entry. However, linenoise doesn't support editing the
209 	// history entries, so we'll probably need to refactor the input system to
210 	// get this behavior right.
211 #ifdef USE_LINENOISE
212 	linenoiseHistoryAdd(entry);
213 #endif
214 }
215 
216 /*
217  * Refill the input buffer and return the next input character:
218  *
219  * 1) If a string was pushed back on the input, pop it;
220  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
221  *    from a string so we can't refill the buffer, return EOF.
222  * 3) If the is more stuff in this buffer, use it else call read to fill it.
223  * 4) Process input up to the next newline, deleting nul characters.
224  */
225 
preadbuffer(void)226 static int preadbuffer(void)
227 {
228 	char *q;
229 	int more;
230 #ifdef USE_LINENOISE
231 	int something;
232 #endif
233 	char savec;
234 
235 	if (unlikely(parsefile->strpush)) {
236 		if (
237 			parsefile->nleft == -1 &&
238 			parsefile->strpush->ap &&
239 			parsefile->nextc[-1] != ' ' &&
240 			parsefile->nextc[-1] != '\t'
241 		) {
242 			return PEOA;
243 		}
244 		popstring();
245 		return pgetc();
246 	}
247 	if (unlikely(parsefile->nleft == EOF_NLEFT ||
248 		     parsefile->buf == NULL))
249 		return PEOF;
250 	flushall();
251 
252 	more = parsefile->lleft;
253 	if (more <= 0) {
254 again:
255 		if ((more = preadfd()) <= 0) {
256 			parsefile->lleft = parsefile->nleft = EOF_NLEFT;
257 			return PEOF;
258 		}
259 	}
260 
261 	q = parsefile->nextc;
262 
263 	/* delete nul characters */
264 #ifdef USE_LINENOISE
265 	something = 0;
266 #endif
267 	for (;;) {
268 		int c;
269 
270 		more--;
271 		c = *q;
272 
273 		if (!c)
274 			memmove(q, q + 1, more);
275 		else {
276 			q++;
277 
278 			if (c == '\n') {
279 				parsefile->nleft = q - parsefile->nextc - 1;
280 				break;
281 			}
282 
283 #ifdef USE_LINENOISE
284 			switch (c) {
285 			default:
286 				something = 1;
287 				/* fall through */
288 			case '\t':
289 			case ' ':
290 				break;
291 			}
292 #endif
293 		}
294 
295 		if (more <= 0) {
296 			parsefile->nleft = q - parsefile->nextc - 1;
297 			if (parsefile->nleft < 0)
298 				goto again;
299 			break;
300 		}
301 	}
302 	parsefile->lleft = more;
303 
304 	savec = *q;
305 	*q = '\0';
306 
307 #ifdef USE_LINENOISE
308 	if (parsefile->fd == 0 && iflag && something) {
309 		// linenoise doesn't expect the command terminator at the end of the history
310 		// entry.
311 		char command_terminator = q[-1];
312 		q[-1] = '\0';
313 
314 		addtohistory(parsefile->nextc, strlen(parsefile->nextc));
315 
316 		// Restore the command terminator.
317 		q[-1] = command_terminator;
318 	}
319 #endif
320 
321 	if (vflag) {
322 		out2str(parsefile->nextc);
323 #ifdef FLUSHERR
324 		flushout(out2);
325 #endif
326 	}
327 
328 	*q = savec;
329 
330 	return (signed char)*parsefile->nextc++;
331 }
332 
333 /*
334  * Undo a call to pgetc.  Only two characters may be pushed back.
335  * PEOF may be pushed back.
336  */
337 
338 void
pungetc(void)339 pungetc(void)
340 {
341 	parsefile->unget++;
342 }
343 
344 /*
345  * Push a string back onto the input at this current parsefile level.
346  * We handle aliases this way.
347  */
348 void
pushstring(char * s,void * ap)349 pushstring(char *s, void *ap)
350 {
351 	struct strpush *sp;
352 	size_t len;
353 
354 	len = strlen(s);
355 	INTOFF;
356 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
357 	if (parsefile->strpush) {
358 		sp = ckmalloc(sizeof (struct strpush));
359 		sp->prev = parsefile->strpush;
360 		parsefile->strpush = sp;
361 	} else
362 		sp = parsefile->strpush = &(parsefile->basestrpush);
363 	sp->prevstring = parsefile->nextc;
364 	sp->prevnleft = parsefile->nleft;
365 	sp->unget = parsefile->unget;
366 	memcpy(sp->lastc, parsefile->lastc, sizeof(sp->lastc));
367 	sp->ap = (struct alias *)ap;
368 	if (ap) {
369 		((struct alias *)ap)->flag |= ALIASINUSE;
370 		sp->string = s;
371 	}
372 	parsefile->nextc = s;
373 	parsefile->nleft = len;
374 	parsefile->unget = 0;
375 	INTON;
376 }
377 
378 void
popstring(void)379 popstring(void)
380 {
381 	struct strpush *sp = parsefile->strpush;
382 
383 	INTOFF;
384 	if (sp->ap) {
385 		if (parsefile->nextc[-1] == ' ' ||
386 		    parsefile->nextc[-1] == '\t') {
387 			checkkwd |= CHKALIAS;
388 		}
389 		if (sp->string != sp->ap->val) {
390 			ckfree(sp->string);
391 		}
392 		sp->ap->flag &= ~ALIASINUSE;
393 		if (sp->ap->flag & ALIASDEAD) {
394 			unalias(sp->ap->name);
395 		}
396 	}
397 	parsefile->nextc = sp->prevstring;
398 	parsefile->nleft = sp->prevnleft;
399 	parsefile->unget = sp->unget;
400 	memcpy(parsefile->lastc, sp->lastc, sizeof(sp->lastc));
401 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
402 	parsefile->strpush = sp->prev;
403 	if (sp != &(parsefile->basestrpush))
404 		ckfree(sp);
405 	INTON;
406 }
407 
408 /*
409  * Set the input to take input from a file.  If push is set, push the
410  * old input onto the stack first.
411  */
412 
413 int
setinputfile(const char * fname,int flags)414 setinputfile(const char *fname, int flags)
415 {
416 	int fd;
417 
418 	INTOFF;
419 	if ((fd = open(fname, O_RDONLY)) < 0) {
420 		if (flags & INPUT_NOFILE_OK)
421 			goto out;
422 		exitstatus = 127;
423 		exerror(EXERROR, "Can't open %s", fname);
424 	}
425 	if (fd < 10)
426 		fd = savefd(fd, fd);
427 	setinputfd(fd, flags & INPUT_PUSH_FILE);
428 out:
429 	INTON;
430 	return fd;
431 }
432 
433 
434 /*
435  * Like setinputfile, but takes an open file descriptor.  Call this with
436  * interrupts off.
437  */
438 
439 static void
setinputfd(int fd,int push)440 setinputfd(int fd, int push)
441 {
442 	if (push) {
443 		pushfile();
444 		parsefile->buf = 0;
445 	}
446 	parsefile->fd = fd;
447 	if (parsefile->buf == NULL)
448 		parsefile->buf = ckmalloc(IBUFSIZ);
449 	parsefile->lleft = parsefile->nleft = 0;
450 	plinno = 1;
451 }
452 
453 
454 /*
455  * Like setinputfile, but takes input from a string.
456  */
457 
458 void
setinputstring(char * string)459 setinputstring(char *string)
460 {
461 	INTOFF;
462 	pushfile();
463 	parsefile->nextc = string;
464 	parsefile->nleft = strlen(string);
465 	parsefile->buf = NULL;
466 	plinno = 1;
467 	INTON;
468 }
469 
470 
471 
472 /*
473  * To handle the "." command, a stack of input files is used.  Pushfile
474  * adds a new entry to the stack and popfile restores the previous level.
475  */
476 
477 STATIC void
pushfile(void)478 pushfile(void)
479 {
480 	struct parsefile *pf;
481 
482 	pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
483 	pf->prev = parsefile;
484 	pf->fd = -1;
485 	pf->strpush = NULL;
486 	pf->basestrpush.prev = NULL;
487 	pf->unget = 0;
488 	parsefile = pf;
489 }
490 
491 
492 void
popfile(void)493 popfile(void)
494 {
495 	struct parsefile *pf = parsefile;
496 
497 	INTOFF;
498 	if (pf->fd >= 0)
499 		close(pf->fd);
500 	if (pf->buf)
501 		ckfree(pf->buf);
502 	while (pf->strpush)
503 		popstring();
504 	parsefile = pf->prev;
505 	ckfree(pf);
506 	INTON;
507 }
508 
509 
510 /*
511  * Return to top level.
512  */
513 
514 void
popallfiles(void)515 popallfiles(void)
516 {
517 	while (parsefile != &basepf)
518 		popfile();
519 }
520 
521 
522 
523 /*
524  * Close the file(s) that the shell is reading commands from.  Called
525  * after a fork is done.
526  */
527 
528 void
closescript(void)529 closescript(void)
530 {
531 	popallfiles();
532 	if (parsefile->fd > 0) {
533 		close(parsefile->fd);
534 		parsefile->fd = 0;
535 	}
536 }
537