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