Home | History | Annotate | Line # | Download | only in sh
input.c revision 1.52
      1 /*	$NetBSD: input.c,v 1.52 2017/04/29 15:14:28 kre 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.52 2017/04/29 15:14:28 kre 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 #include <sys/stat.h>
     52 
     53 /*
     54  * This file implements the input routines used by the parser.
     55  */
     56 
     57 #include "shell.h"
     58 #include "redir.h"
     59 #include "syntax.h"
     60 #include "input.h"
     61 #include "output.h"
     62 #include "options.h"
     63 #include "memalloc.h"
     64 #include "error.h"
     65 #include "alias.h"
     66 #include "parser.h"
     67 #include "myhistedit.h"
     68 
     69 #define EOF_NLEFT -99		/* value of parsenleft when EOF pushed back */
     70 
     71 MKINIT
     72 struct strpush {
     73 	struct strpush *prev;	/* preceding string on stack */
     74 	char *prevstring;
     75 	int prevnleft;
     76 	int prevlleft;
     77 	struct alias *ap;	/* if push was associated with an alias */
     78 };
     79 
     80 /*
     81  * The parsefile structure pointed to by the global variable parsefile
     82  * contains information about the current file being read.
     83  */
     84 
     85 MKINIT
     86 struct parsefile {
     87 	struct parsefile *prev;	/* preceding file on stack */
     88 	int linno;		/* current line */
     89 	int fd;			/* file descriptor (or -1 if string) */
     90 	int nleft;		/* number of chars left in this line */
     91 	int lleft;		/* number of chars left in this buffer */
     92 	char *nextc;		/* next char in buffer */
     93 	char *buf;		/* input buffer */
     94 	struct strpush *strpush; /* for pushing strings at this level */
     95 	struct strpush basestrpush; /* so pushing one is fast */
     96 };
     97 
     98 
     99 int plinno = 1;			/* input line number */
    100 int parsenleft;			/* copy of parsefile->nleft */
    101 MKINIT int parselleft;		/* copy of parsefile->lleft */
    102 char *parsenextc;		/* copy of parsefile->nextc */
    103 MKINIT struct parsefile basepf;	/* top level input file */
    104 MKINIT char basebuf[BUFSIZ];	/* buffer for top level input file */
    105 struct parsefile *parsefile = &basepf;	/* current input file */
    106 int init_editline = 0;		/* editline library initialized? */
    107 int whichprompt;		/* 1 == PS1, 2 == PS2 */
    108 
    109 STATIC void pushfile(void);
    110 static int preadfd(void);
    111 
    112 #ifdef mkinit
    113 INCLUDE <stdio.h>
    114 INCLUDE "input.h"
    115 INCLUDE "error.h"
    116 
    117 INIT {
    118 	basepf.nextc = basepf.buf = basebuf;
    119 }
    120 
    121 RESET {
    122 	if (exception != EXSHELLPROC)
    123 		parselleft = parsenleft = 0;	/* clear input buffer */
    124 	popallfiles();
    125 }
    126 
    127 SHELLPROC {
    128 	popallfiles();
    129 }
    130 #endif
    131 
    132 
    133 /*
    134  * Read a line from the script.
    135  */
    136 
    137 char *
    138 pfgets(char *line, int len)
    139 {
    140 	char *p = line;
    141 	int nleft = len;
    142 	int c;
    143 
    144 	while (--nleft > 0) {
    145 		c = pgetc_macro();
    146 		if (c == PEOF) {
    147 			if (p == line)
    148 				return NULL;
    149 			break;
    150 		}
    151 		*p++ = c;
    152 		if (c == '\n')
    153 			break;
    154 	}
    155 	*p = '\0';
    156 	return line;
    157 }
    158 
    159 
    160 
    161 /*
    162  * Read a character from the script, returning PEOF on end of file.
    163  * Nul characters in the input are silently discarded.
    164  */
    165 
    166 int
    167 pgetc(void)
    168 {
    169 	return pgetc_macro();
    170 }
    171 
    172 
    173 static int
    174 preadfd(void)
    175 {
    176 	int nr;
    177 	char *buf =  parsefile->buf;
    178 	parsenextc = buf;
    179 
    180 retry:
    181 #ifndef SMALL
    182 	if (parsefile->fd == 0 && el) {
    183 		static const char *rl_cp;
    184 		static int el_len;
    185 
    186 		if (rl_cp == NULL)
    187 			rl_cp = el_gets(el, &el_len);
    188 		if (rl_cp == NULL)
    189 			nr = el_len == 0 ? 0 : -1;
    190 		else {
    191 			nr = el_len;
    192 			if (nr > BUFSIZ - 8)
    193 				nr = BUFSIZ - 8;
    194 			memcpy(buf, rl_cp, nr);
    195 			if (nr != el_len) {
    196 				el_len -= nr;
    197 				rl_cp += nr;
    198 			} else
    199 				rl_cp = 0;
    200 		}
    201 
    202 	} else
    203 #endif
    204 		nr = read(parsefile->fd, buf, BUFSIZ - 8);
    205 
    206 
    207 	if (nr <= 0) {
    208                 if (nr < 0) {
    209                         if (errno == EINTR)
    210                                 goto retry;
    211                         if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
    212                                 int flags = fcntl(0, F_GETFL, 0);
    213                                 if (flags >= 0 && flags & O_NONBLOCK) {
    214                                         flags &=~ O_NONBLOCK;
    215                                         if (fcntl(0, F_SETFL, flags) >= 0) {
    216 						out2str("sh: turning off NDELAY mode\n");
    217                                                 goto retry;
    218                                         }
    219                                 }
    220                         }
    221                 }
    222                 nr = -1;
    223 	}
    224 	return nr;
    225 }
    226 
    227 /*
    228  * Refill the input buffer and return the next input character:
    229  *
    230  * 1) If a string was pushed back on the input, pop it;
    231  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
    232  *    from a string so we can't refill the buffer, return EOF.
    233  * 3) If the is more stuff in this buffer, use it else call read to fill it.
    234  * 4) Process input up to the next newline, deleting nul characters.
    235  */
    236 
    237 int
    238 preadbuffer(void)
    239 {
    240 	char *p, *q;
    241 	int more;
    242 #ifndef SMALL
    243 	int something;
    244 #endif
    245 	char savec;
    246 
    247 	if (parsefile->strpush) {
    248 		popstring();
    249 		if (--parsenleft >= 0)
    250 			return (*parsenextc++);
    251 	}
    252 	if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
    253 		return PEOF;
    254 	flushout(&output);
    255 	flushout(&errout);
    256 
    257 again:
    258 	if (parselleft <= 0) {
    259 		if ((parselleft = preadfd()) == -1) {
    260 			parselleft = parsenleft = EOF_NLEFT;
    261 			return PEOF;
    262 		}
    263 	}
    264 
    265 	q = p = parsenextc;
    266 
    267 	/* delete nul characters */
    268 #ifndef SMALL
    269 	something = 0;
    270 #endif
    271 	for (more = 1; more;) {
    272 		switch (*p) {
    273 		case '\0':
    274 			p++;	/* Skip nul */
    275 			goto check;
    276 
    277 		case '\t':
    278 		case ' ':
    279 			break;
    280 
    281 		case '\n':
    282 			parsenleft = q - parsenextc;
    283 			more = 0; /* Stop processing here */
    284 			break;
    285 
    286 		default:
    287 #ifndef SMALL
    288 			something = 1;
    289 #endif
    290 			break;
    291 		}
    292 
    293 		*q++ = *p++;
    294 check:
    295 		if (--parselleft <= 0) {
    296 			parsenleft = q - parsenextc - 1;
    297 			if (parsenleft < 0)
    298 				goto again;
    299 			*q = '\0';
    300 			more = 0;
    301 		}
    302 	}
    303 
    304 	savec = *q;
    305 	*q = '\0';
    306 
    307 #ifndef SMALL
    308 	if (parsefile->fd == 0 && hist && something) {
    309 		HistEvent he;
    310 		INTOFF;
    311 		history(hist, &he, whichprompt == 1? H_ENTER : H_APPEND,
    312 		    parsenextc);
    313 		INTON;
    314 	}
    315 #endif
    316 
    317 	if (vflag) {
    318 		out2str(parsenextc);
    319 		flushout(out2);
    320 	}
    321 
    322 	*q = savec;
    323 
    324 	return *parsenextc++;
    325 }
    326 
    327 /*
    328  * Undo the last call to pgetc.  Only one character may be pushed back.
    329  * PEOF may be pushed back.
    330  */
    331 
    332 void
    333 pungetc(void)
    334 {
    335 	parsenleft++;
    336 	parsenextc--;
    337 }
    338 
    339 /*
    340  * Push a string back onto the input at this current parsefile level.
    341  * We handle aliases this way.
    342  */
    343 void
    344 pushstring(char *s, int len, void *ap)
    345 {
    346 	struct strpush *sp;
    347 
    348 	INTOFF;
    349 /*debugprintf("*** calling pushstring: %s, %d\n", s, len);*/
    350 	if (parsefile->strpush) {
    351 		sp = ckmalloc(sizeof (struct strpush));
    352 		sp->prev = parsefile->strpush;
    353 		parsefile->strpush = sp;
    354 	} else
    355 		sp = parsefile->strpush = &(parsefile->basestrpush);
    356 	sp->prevstring = parsenextc;
    357 	sp->prevnleft = parsenleft;
    358 	sp->prevlleft = parselleft;
    359 	sp->ap = (struct alias *)ap;
    360 	if (ap)
    361 		((struct alias *)ap)->flag |= ALIASINUSE;
    362 	parsenextc = s;
    363 	parsenleft = len;
    364 	INTON;
    365 }
    366 
    367 void
    368 popstring(void)
    369 {
    370 	struct strpush *sp = parsefile->strpush;
    371 
    372 	INTOFF;
    373 	parsenextc = sp->prevstring;
    374 	parsenleft = sp->prevnleft;
    375 	parselleft = sp->prevlleft;
    376 /*debugprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
    377 	if (sp->ap)
    378 		sp->ap->flag &= ~ALIASINUSE;
    379 	parsefile->strpush = sp->prev;
    380 	if (sp != &(parsefile->basestrpush))
    381 		ckfree(sp);
    382 	INTON;
    383 }
    384 
    385 /*
    386  * Set the input to take input from a file.  If push is set, push the
    387  * old input onto the stack first.
    388  */
    389 
    390 void
    391 setinputfile(const char *fname, int push)
    392 {
    393 	unsigned char magic[4];
    394 	int fd;
    395 	int fd2;
    396 	struct stat sb;
    397 
    398 	INTOFF;
    399 	if ((fd = open(fname, O_RDONLY)) < 0)
    400 		error("Can't open %s", fname);
    401 
    402 	/* Since the message "Syntax error: "(" unexpected" is not very
    403 	 * helpful, we check if the file starts with the ELF magic to
    404 	 * avoid that message. The first lseek tries to make sure that
    405 	 * we can later rewind the file.
    406 	 */
    407 	if (fstat(fd, &sb) == 0 && S_ISREG(sb.st_mode) &&
    408 	    lseek(fd, 0, SEEK_SET) == 0) {
    409 		if (read(fd, magic, 4) == 4) {
    410 			if (memcmp(magic, "\177ELF", 4) == 0) {
    411 				(void)close(fd);
    412 				error("Cannot execute ELF binary %s", fname);
    413 			}
    414 		}
    415 		if (lseek(fd, 0, SEEK_SET) != 0) {
    416 			(void)close(fd);
    417 			error("Cannot rewind the file %s", fname);
    418 		}
    419 	}
    420 
    421 	fd2 = to_upper_fd(fd);	/* closes fd, returns higher equiv */
    422 	if (fd2 == fd) {
    423 		(void) close(fd);
    424 		error("Out of file descriptors");
    425 	}
    426 
    427 	setinputfd(fd2, push);
    428 	INTON;
    429 }
    430 
    431 /*
    432  * When a shell fd needs to be altered (when the user wants to use
    433  * the same fd - rare, but happens - we need to locate the ref to
    434  * the fd, and update it.  This happens via a callback.
    435  * This is the callback func for fd's used for shell input
    436  */
    437 static void
    438 input_fd_swap(int from, int to)
    439 {
    440 	struct parsefile *pf;
    441 
    442 	pf = parsefile;
    443 	while (pf != NULL) {		/* don't need to stop at basepf */
    444 		if (pf->fd == from)
    445 			pf->fd = to;
    446 		pf = pf->prev;
    447 	}
    448 }
    449 
    450 /*
    451  * Like setinputfile, but takes an open file descriptor.  Call this with
    452  * interrupts off.
    453  */
    454 
    455 void
    456 setinputfd(int fd, int push)
    457 {
    458 	register_sh_fd(fd, input_fd_swap);
    459 	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
    460 	if (push) {
    461 		pushfile();
    462 		parsefile->buf = ckmalloc(BUFSIZ);
    463 	}
    464 	if (parsefile->fd > 0)
    465 		sh_close(parsefile->fd);
    466 	parsefile->fd = fd;
    467 	if (parsefile->buf == NULL)
    468 		parsefile->buf = ckmalloc(BUFSIZ);
    469 	parselleft = parsenleft = 0;
    470 	plinno = 1;
    471 }
    472 
    473 
    474 /*
    475  * Like setinputfile, but takes input from a string.
    476  */
    477 
    478 void
    479 setinputstring(char *string, int push)
    480 {
    481 
    482 	INTOFF;
    483 	if (push)
    484 		pushfile();
    485 	parsenextc = string;
    486 	parselleft = parsenleft = strlen(string);
    487 	parsefile->buf = NULL;
    488 	plinno = 1;
    489 	INTON;
    490 }
    491 
    492 
    493 
    494 /*
    495  * To handle the "." command, a stack of input files is used.  Pushfile
    496  * adds a new entry to the stack and popfile restores the previous level.
    497  */
    498 
    499 STATIC void
    500 pushfile(void)
    501 {
    502 	struct parsefile *pf;
    503 
    504 	parsefile->nleft = parsenleft;
    505 	parsefile->lleft = parselleft;
    506 	parsefile->nextc = parsenextc;
    507 	parsefile->linno = plinno;
    508 	pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
    509 	pf->prev = parsefile;
    510 	pf->fd = -1;
    511 	pf->strpush = NULL;
    512 	pf->basestrpush.prev = NULL;
    513 	parsefile = pf;
    514 }
    515 
    516 
    517 void
    518 popfile(void)
    519 {
    520 	struct parsefile *pf = parsefile;
    521 
    522 	INTOFF;
    523 	if (pf->fd >= 0)
    524 		sh_close(pf->fd);
    525 	if (pf->buf)
    526 		ckfree(pf->buf);
    527 	while (pf->strpush)
    528 		popstring();
    529 	parsefile = pf->prev;
    530 	ckfree(pf);
    531 	parsenleft = parsefile->nleft;
    532 	parselleft = parsefile->lleft;
    533 	parsenextc = parsefile->nextc;
    534 	plinno = parsefile->linno;
    535 	INTON;
    536 }
    537 
    538 
    539 /*
    540  * Return to top level.
    541  */
    542 
    543 void
    544 popallfiles(void)
    545 {
    546 	while (parsefile != &basepf)
    547 		popfile();
    548 }
    549 
    550 
    551 
    552 /*
    553  * Close the file(s) that the shell is reading commands from.  Called
    554  * after a fork is done.
    555  *
    556  * Takes one arg, vfork, which tells it to not modify its global vars
    557  * as it is still running in the parent.
    558  *
    559  * This code is (probably) unnecessary as the 'close on exec' flag is
    560  * set and should be enough.  In the vfork case it is definitely wrong
    561  * to close the fds as another fork() may be done later to feed data
    562  * from a 'here' document into a pipe and we don't want to close the
    563  * pipe!
    564  */
    565 
    566 void
    567 closescript(int vforked)
    568 {
    569 	if (vforked)
    570 		return;
    571 	popallfiles();
    572 	if (parsefile->fd > 0) {
    573 		sh_close(parsefile->fd);
    574 		parsefile->fd = 0;
    575 	}
    576 }
    577