1 1.76 kre /* $NetBSD: input.c,v 1.76 2024/10/14 08:15:43 kre Exp $ */ 2 1.13 cgd 3 1.1 cgd /*- 4 1.5 jtc * Copyright (c) 1991, 1993 5 1.5 jtc * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This code is derived from software contributed to Berkeley by 8 1.1 cgd * Kenneth Almquist. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.39 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd */ 34 1.1 cgd 35 1.27 christos #include <sys/cdefs.h> 36 1.1 cgd #ifndef lint 37 1.13 cgd #if 0 38 1.16 christos static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95"; 39 1.13 cgd #else 40 1.76 kre __RCSID("$NetBSD: input.c,v 1.76 2024/10/14 08:15:43 kre Exp $"); 41 1.13 cgd #endif 42 1.1 cgd #endif /* not lint */ 43 1.1 cgd 44 1.14 christos #include <stdio.h> /* defines BUFSIZ */ 45 1.14 christos #include <fcntl.h> 46 1.14 christos #include <errno.h> 47 1.14 christos #include <unistd.h> 48 1.45 christos #include <limits.h> 49 1.14 christos #include <stdlib.h> 50 1.15 cgd #include <string.h> 51 1.51 kre #include <sys/stat.h> 52 1.14 christos 53 1.1 cgd /* 54 1.1 cgd * This file implements the input routines used by the parser. 55 1.1 cgd */ 56 1.1 cgd 57 1.6 jtc #include "shell.h" 58 1.14 christos #include "redir.h" 59 1.1 cgd #include "syntax.h" 60 1.1 cgd #include "input.h" 61 1.1 cgd #include "output.h" 62 1.5 jtc #include "options.h" 63 1.1 cgd #include "memalloc.h" 64 1.1 cgd #include "error.h" 65 1.5 jtc #include "alias.h" 66 1.5 jtc #include "parser.h" 67 1.5 jtc #include "myhistedit.h" 68 1.58 kre #include "show.h" 69 1.1 cgd 70 1.1 cgd #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ 71 1.1 cgd 72 1.5 jtc MKINIT 73 1.5 jtc struct strpush { 74 1.5 jtc struct strpush *prev; /* preceding string on stack */ 75 1.55 kre const char *prevstring; 76 1.5 jtc int prevnleft; 77 1.17 christos int prevlleft; 78 1.5 jtc struct alias *ap; /* if push was associated with an alias */ 79 1.5 jtc }; 80 1.1 cgd 81 1.1 cgd /* 82 1.1 cgd * The parsefile structure pointed to by the global variable parsefile 83 1.1 cgd * contains information about the current file being read. 84 1.1 cgd */ 85 1.1 cgd 86 1.1 cgd MKINIT 87 1.1 cgd struct parsefile { 88 1.5 jtc struct parsefile *prev; /* preceding file on stack */ 89 1.1 cgd int linno; /* current line */ 90 1.1 cgd int fd; /* file descriptor (or -1 if string) */ 91 1.17 christos int nleft; /* number of chars left in this line */ 92 1.17 christos int lleft; /* number of chars left in this buffer */ 93 1.72 kre int nskip; /* number of \0's dropped in previous line */ 94 1.55 kre const char *nextc; /* next char in buffer */ 95 1.1 cgd char *buf; /* input buffer */ 96 1.5 jtc struct strpush *strpush; /* for pushing strings at this level */ 97 1.5 jtc struct strpush basestrpush; /* so pushing one is fast */ 98 1.1 cgd }; 99 1.1 cgd 100 1.1 cgd 101 1.1 cgd int plinno = 1; /* input line number */ 102 1.35 christos int parsenleft; /* copy of parsefile->nleft */ 103 1.17 christos MKINIT int parselleft; /* copy of parsefile->lleft */ 104 1.55 kre const char *parsenextc; /* copy of parsefile->nextc */ 105 1.1 cgd MKINIT struct parsefile basepf; /* top level input file */ 106 1.35 christos MKINIT char basebuf[BUFSIZ]; /* buffer for top level input file */ 107 1.1 cgd struct parsefile *parsefile = &basepf; /* current input file */ 108 1.5 jtc int init_editline = 0; /* editline library initialized? */ 109 1.5 jtc int whichprompt; /* 1 == PS1, 2 == PS2 */ 110 1.5 jtc 111 1.37 christos STATIC void pushfile(void); 112 1.37 christos static int preadfd(void); 113 1.1 cgd 114 1.1 cgd #ifdef mkinit 115 1.35 christos INCLUDE <stdio.h> 116 1.1 cgd INCLUDE "input.h" 117 1.1 cgd INCLUDE "error.h" 118 1.1 cgd 119 1.1 cgd INIT { 120 1.1 cgd basepf.nextc = basepf.buf = basebuf; 121 1.1 cgd } 122 1.1 cgd 123 1.1 cgd RESET { 124 1.1 cgd if (exception != EXSHELLPROC) 125 1.17 christos parselleft = parsenleft = 0; /* clear input buffer */ 126 1.1 cgd popallfiles(); 127 1.1 cgd } 128 1.1 cgd 129 1.1 cgd SHELLPROC { 130 1.1 cgd popallfiles(); 131 1.1 cgd } 132 1.1 cgd #endif 133 1.1 cgd 134 1.1 cgd 135 1.60 kre #if 0 /* this is unused */ 136 1.1 cgd /* 137 1.1 cgd * Read a line from the script. 138 1.1 cgd */ 139 1.1 cgd 140 1.1 cgd char * 141 1.37 christos pfgets(char *line, int len) 142 1.11 cgd { 143 1.22 tls char *p = line; 144 1.1 cgd int nleft = len; 145 1.1 cgd int c; 146 1.1 cgd 147 1.1 cgd while (--nleft > 0) { 148 1.1 cgd c = pgetc_macro(); 149 1.69 kre if (c == PFAKE) /* consecutive PFAKEs is impossible */ 150 1.69 kre c = pgetc_macro(); 151 1.1 cgd if (c == PEOF) { 152 1.1 cgd if (p == line) 153 1.1 cgd return NULL; 154 1.1 cgd break; 155 1.1 cgd } 156 1.1 cgd *p++ = c; 157 1.69 kre if (c == '\n') { 158 1.69 kre plinno++; 159 1.1 cgd break; 160 1.69 kre } 161 1.1 cgd } 162 1.1 cgd *p = '\0'; 163 1.1 cgd return line; 164 1.1 cgd } 165 1.60 kre #endif 166 1.1 cgd 167 1.1 cgd 168 1.1 cgd /* 169 1.1 cgd * Read a character from the script, returning PEOF on end of file. 170 1.1 cgd * Nul characters in the input are silently discarded. 171 1.1 cgd */ 172 1.1 cgd 173 1.1 cgd int 174 1.37 christos pgetc(void) 175 1.17 christos { 176 1.64 kre int c; 177 1.64 kre 178 1.64 kre c = pgetc_macro(); 179 1.64 kre if (c == PFAKE) 180 1.64 kre c = pgetc_macro(); 181 1.64 kre return c; 182 1.1 cgd } 183 1.1 cgd 184 1.1 cgd 185 1.17 christos static int 186 1.37 christos preadfd(void) 187 1.17 christos { 188 1.17 christos int nr; 189 1.32 christos char *buf = parsefile->buf; 190 1.32 christos parsenextc = buf; 191 1.17 christos 192 1.60 kre retry: 193 1.25 christos #ifndef SMALL 194 1.17 christos if (parsefile->fd == 0 && el) { 195 1.37 christos static const char *rl_cp; 196 1.37 christos static int el_len; 197 1.17 christos 198 1.37 christos if (rl_cp == NULL) 199 1.37 christos rl_cp = el_gets(el, &el_len); 200 1.17 christos if (rl_cp == NULL) 201 1.42 roy nr = el_len == 0 ? 0 : -1; 202 1.17 christos else { 203 1.37 christos nr = el_len; 204 1.37 christos if (nr > BUFSIZ - 8) 205 1.37 christos nr = BUFSIZ - 8; 206 1.37 christos memcpy(buf, rl_cp, nr); 207 1.37 christos if (nr != el_len) { 208 1.37 christos el_len -= nr; 209 1.37 christos rl_cp += nr; 210 1.37 christos } else 211 1.37 christos rl_cp = 0; 212 1.17 christos } 213 1.37 christos 214 1.24 christos } else 215 1.24 christos #endif 216 1.37 christos nr = read(parsefile->fd, buf, BUFSIZ - 8); 217 1.24 christos 218 1.17 christos 219 1.17 christos if (nr <= 0) { 220 1.71 kre if (nr < 0) { 221 1.71 kre if (errno == EINTR) 222 1.71 kre goto retry; 223 1.71 kre if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 224 1.71 kre int flags = fcntl(0, F_GETFL, 0); 225 1.71 kre 226 1.71 kre if (flags >= 0 && flags & O_NONBLOCK) { 227 1.71 kre flags &=~ O_NONBLOCK; 228 1.71 kre if (fcntl(0, F_SETFL, flags) >= 0) { 229 1.17 christos out2str("sh: turning off NDELAY mode\n"); 230 1.71 kre goto retry; 231 1.71 kre } 232 1.71 kre } 233 1.71 kre } 234 1.71 kre } 235 1.71 kre nr = -1; 236 1.17 christos } 237 1.17 christos return nr; 238 1.17 christos } 239 1.17 christos 240 1.1 cgd /* 241 1.1 cgd * Refill the input buffer and return the next input character: 242 1.1 cgd * 243 1.5 jtc * 1) If a string was pushed back on the input, pop it; 244 1.1 cgd * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading 245 1.1 cgd * from a string so we can't refill the buffer, return EOF. 246 1.67 kre * 3) If there is more stuff in this buffer, use it else call read to fill it. 247 1.17 christos * 4) Process input up to the next newline, deleting nul characters. 248 1.1 cgd */ 249 1.1 cgd 250 1.1 cgd int 251 1.37 christos preadbuffer(void) 252 1.17 christos { 253 1.17 christos char *p, *q; 254 1.17 christos int more; 255 1.46 mrg #ifndef SMALL 256 1.17 christos int something; 257 1.46 mrg #endif 258 1.17 christos char savec; 259 1.1 cgd 260 1.56 kre while (parsefile->strpush) { 261 1.64 kre if (parsenleft == -1 && parsefile->strpush->ap != NULL) 262 1.64 kre return PFAKE; 263 1.5 jtc popstring(); 264 1.1 cgd if (--parsenleft >= 0) 265 1.5 jtc return (*parsenextc++); 266 1.1 cgd } 267 1.1 cgd if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) 268 1.1 cgd return PEOF; 269 1.1 cgd flushout(&output); 270 1.1 cgd flushout(&errout); 271 1.5 jtc 272 1.60 kre again: 273 1.17 christos if (parselleft <= 0) { 274 1.26 christos if ((parselleft = preadfd()) == -1) { 275 1.17 christos parselleft = parsenleft = EOF_NLEFT; 276 1.17 christos return PEOF; 277 1.5 jtc } 278 1.72 kre parsefile->nskip = 0; 279 1.17 christos } 280 1.5 jtc 281 1.72 kre /* jump over slots for any \0 chars that were dropped */ 282 1.72 kre parsenextc += parsefile->nskip; 283 1.72 kre parsefile->nskip = 0; 284 1.72 kre 285 1.55 kre /* p = (not const char *)parsenextc; */ 286 1.55 kre p = parsefile->buf + (parsenextc - parsefile->buf); 287 1.55 kre q = p; 288 1.1 cgd 289 1.1 cgd /* delete nul characters */ 290 1.46 mrg #ifndef SMALL 291 1.5 jtc something = 0; 292 1.46 mrg #endif 293 1.17 christos for (more = 1; more;) { 294 1.17 christos switch (*p) { 295 1.17 christos case '\0': 296 1.75 kre #ifdef REJECT_NULS 297 1.75 kre parsenleft = parselleft = 0; 298 1.75 kre error("nul ('\\0') in shell input"); 299 1.75 kre /* NOTREACHED */ 300 1.75 kre #else 301 1.17 christos p++; /* Skip nul */ 302 1.72 kre parsefile->nskip++; 303 1.17 christos goto check; 304 1.75 kre #endif 305 1.20 christos 306 1.17 christos case '\t': 307 1.17 christos case ' ': 308 1.1 cgd break; 309 1.17 christos 310 1.17 christos case '\n': 311 1.17 christos parsenleft = q - parsenextc; 312 1.17 christos more = 0; /* Stop processing here */ 313 1.17 christos break; 314 1.17 christos 315 1.17 christos default: 316 1.46 mrg #ifndef SMALL 317 1.5 jtc something = 1; 318 1.46 mrg #endif 319 1.17 christos break; 320 1.17 christos } 321 1.17 christos 322 1.72 kre if (parsefile->nskip) 323 1.72 kre *q++ = *p++; 324 1.72 kre else 325 1.72 kre q = ++p; 326 1.72 kre 327 1.75 kre #ifndef REJECT_NULS 328 1.75 kre check:; 329 1.75 kre #endif 330 1.17 christos if (--parselleft <= 0) { 331 1.17 christos parsenleft = q - parsenextc - 1; 332 1.17 christos if (parsenleft < 0) 333 1.17 christos goto again; 334 1.17 christos *q = '\0'; 335 1.17 christos more = 0; 336 1.5 jtc } 337 1.1 cgd } 338 1.17 christos 339 1.17 christos savec = *q; 340 1.5 jtc *q = '\0'; 341 1.5 jtc 342 1.25 christos #ifndef SMALL 343 1.61 kre if (parsefile->fd == 0 && hist && (something || whichprompt == 2)) { 344 1.28 christos HistEvent he; 345 1.61 kre 346 1.5 jtc INTOFF; 347 1.61 kre history(hist, &he, whichprompt != 2 ? H_ENTER : H_APPEND, 348 1.31 christos parsenextc); 349 1.73 kre if (whichprompt != 2 && HistFP != NULL) { 350 1.73 kre history(hist, &he, H_NSAVE_FP, (size_t)0, HistFP); 351 1.73 kre fflush(HistFP); 352 1.73 kre } 353 1.5 jtc INTON; 354 1.5 jtc } 355 1.19 christos #endif 356 1.17 christos 357 1.5 jtc if (vflag) { 358 1.17 christos out2str(parsenextc); 359 1.5 jtc flushout(out2); 360 1.5 jtc } 361 1.17 christos 362 1.17 christos *q = savec; 363 1.17 christos 364 1.1 cgd return *parsenextc++; 365 1.1 cgd } 366 1.1 cgd 367 1.1 cgd /* 368 1.63 kre * Test whether we have reached EOF on input stream. 369 1.63 kre * Return true only if certain (without attempting a read). 370 1.63 kre * 371 1.63 kre * Note the similarity to the opening section of preadbuffer() 372 1.63 kre */ 373 1.63 kre int 374 1.63 kre at_eof(void) 375 1.63 kre { 376 1.63 kre struct strpush *sp = parsefile->strpush; 377 1.63 kre 378 1.63 kre if (parsenleft > 0) /* more chars are in the buffer */ 379 1.63 kre return 0; 380 1.63 kre 381 1.63 kre while (sp != NULL) { 382 1.63 kre /* 383 1.63 kre * If any pushed string has any remaining data, 384 1.63 kre * then we are not at EOF (simulating popstring()) 385 1.63 kre */ 386 1.63 kre if (sp->prevnleft > 0) 387 1.63 kre return 0; 388 1.63 kre sp = sp->prev; 389 1.63 kre } 390 1.63 kre 391 1.63 kre /* 392 1.63 kre * If we reached real EOF and pushed it back, 393 1.63 kre * or if we are just processing a string (not reading a file) 394 1.63 kre * then there is no more. Note that if a file pushes a 395 1.63 kre * string, the file's ->buf remains present. 396 1.63 kre */ 397 1.63 kre if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) 398 1.63 kre return 1; 399 1.63 kre 400 1.63 kre /* 401 1.63 kre * In other cases, there might be more 402 1.63 kre */ 403 1.63 kre return 0; 404 1.63 kre } 405 1.63 kre 406 1.63 kre /* 407 1.1 cgd * Undo the last call to pgetc. Only one character may be pushed back. 408 1.1 cgd * PEOF may be pushed back. 409 1.1 cgd */ 410 1.1 cgd 411 1.1 cgd void 412 1.37 christos pungetc(void) 413 1.37 christos { 414 1.1 cgd parsenleft++; 415 1.1 cgd parsenextc--; 416 1.1 cgd } 417 1.1 cgd 418 1.1 cgd /* 419 1.5 jtc * Push a string back onto the input at this current parsefile level. 420 1.5 jtc * We handle aliases this way. 421 1.1 cgd */ 422 1.1 cgd void 423 1.55 kre pushstring(const char *s, int len, struct alias *ap) 424 1.37 christos { 425 1.5 jtc struct strpush *sp; 426 1.5 jtc 427 1.60 kre VTRACE(DBG_INPUT, 428 1.60 kre ("pushstring(\"%.*s\", %d)%s%s%s had: nl=%d ll=%d \"%.*s\"\n", 429 1.60 kre len, s, len, ap ? " for alias:'" : "", 430 1.60 kre ap ? ap->name : "", ap ? "'" : "", 431 1.60 kre parsenleft, parselleft, parsenleft, parsenextc)); 432 1.60 kre 433 1.5 jtc INTOFF; 434 1.5 jtc if (parsefile->strpush) { 435 1.5 jtc sp = ckmalloc(sizeof (struct strpush)); 436 1.5 jtc sp->prev = parsefile->strpush; 437 1.5 jtc parsefile->strpush = sp; 438 1.5 jtc } else 439 1.5 jtc sp = parsefile->strpush = &(parsefile->basestrpush); 440 1.60 kre 441 1.5 jtc sp->prevstring = parsenextc; 442 1.5 jtc sp->prevnleft = parsenleft; 443 1.17 christos sp->prevlleft = parselleft; 444 1.53 kre sp->ap = ap; 445 1.5 jtc if (ap) 446 1.53 kre ap->flag |= ALIASINUSE; 447 1.5 jtc parsenextc = s; 448 1.5 jtc parsenleft = len; 449 1.5 jtc INTON; 450 1.1 cgd } 451 1.1 cgd 452 1.11 cgd void 453 1.37 christos popstring(void) 454 1.5 jtc { 455 1.5 jtc struct strpush *sp = parsefile->strpush; 456 1.1 cgd 457 1.5 jtc INTOFF; 458 1.64 kre if (sp->ap) { 459 1.66 kre int alen; 460 1.66 kre 461 1.68 kre if ((alen = strlen(sp->ap->val)) > 0 && 462 1.66 kre (sp->ap->val[alen - 1] == ' ' || 463 1.66 kre sp->ap->val[alen - 1] == '\t')) 464 1.64 kre checkkwd |= CHKALIAS; 465 1.64 kre sp->ap->flag &= ~ALIASINUSE; 466 1.64 kre } 467 1.5 jtc parsenextc = sp->prevstring; 468 1.5 jtc parsenleft = sp->prevnleft; 469 1.17 christos parselleft = sp->prevlleft; 470 1.60 kre 471 1.60 kre VTRACE(DBG_INPUT, ("popstring()%s%s%s nl=%d ll=%d \"%.*s\"\n", 472 1.60 kre sp->ap ? " from alias:'" : "", sp->ap ? sp->ap->name : "", 473 1.60 kre sp->ap ? "'" : "", parsenleft, parselleft, parsenleft, parsenextc)); 474 1.60 kre 475 1.5 jtc parsefile->strpush = sp->prev; 476 1.5 jtc if (sp != &(parsefile->basestrpush)) 477 1.5 jtc ckfree(sp); 478 1.5 jtc INTON; 479 1.5 jtc } 480 1.1 cgd 481 1.1 cgd /* 482 1.1 cgd * Set the input to take input from a file. If push is set, push the 483 1.1 cgd * old input onto the stack first. 484 1.1 cgd */ 485 1.1 cgd 486 1.1 cgd void 487 1.37 christos setinputfile(const char *fname, int push) 488 1.11 cgd { 489 1.40 rillig unsigned char magic[4]; 490 1.1 cgd int fd; 491 1.1 cgd int fd2; 492 1.51 kre struct stat sb; 493 1.1 cgd 494 1.60 kre CTRACE(DBG_INPUT,("setinputfile(\"%s\", %spush)\n",fname,push?"":"no")); 495 1.60 kre 496 1.1 cgd INTOFF; 497 1.1 cgd if ((fd = open(fname, O_RDONLY)) < 0) 498 1.1 cgd error("Can't open %s", fname); 499 1.40 rillig 500 1.40 rillig /* Since the message "Syntax error: "(" unexpected" is not very 501 1.40 rillig * helpful, we check if the file starts with the ELF magic to 502 1.40 rillig * avoid that message. The first lseek tries to make sure that 503 1.40 rillig * we can later rewind the file. 504 1.40 rillig */ 505 1.51 kre if (fstat(fd, &sb) == 0 && S_ISREG(sb.st_mode) && 506 1.51 kre lseek(fd, 0, SEEK_SET) == 0) { 507 1.40 rillig if (read(fd, magic, 4) == 4) { 508 1.50 kre if (memcmp(magic, "\177ELF", 4) == 0) { 509 1.50 kre (void)close(fd); 510 1.40 rillig error("Cannot execute ELF binary %s", fname); 511 1.50 kre } 512 1.40 rillig } 513 1.50 kre if (lseek(fd, 0, SEEK_SET) != 0) { 514 1.50 kre (void)close(fd); 515 1.40 rillig error("Cannot rewind the file %s", fname); 516 1.50 kre } 517 1.40 rillig } 518 1.40 rillig 519 1.49 christos fd2 = to_upper_fd(fd); /* closes fd, returns higher equiv */ 520 1.49 christos if (fd2 == fd) { 521 1.49 christos (void) close(fd); 522 1.49 christos error("Out of file descriptors"); 523 1.1 cgd } 524 1.49 christos 525 1.49 christos setinputfd(fd2, push); 526 1.1 cgd INTON; 527 1.1 cgd } 528 1.1 cgd 529 1.52 kre /* 530 1.52 kre * When a shell fd needs to be altered (when the user wants to use 531 1.52 kre * the same fd - rare, but happens - we need to locate the ref to 532 1.52 kre * the fd, and update it. This happens via a callback. 533 1.52 kre * This is the callback func for fd's used for shell input 534 1.52 kre */ 535 1.52 kre static void 536 1.52 kre input_fd_swap(int from, int to) 537 1.52 kre { 538 1.52 kre struct parsefile *pf; 539 1.52 kre 540 1.52 kre pf = parsefile; 541 1.52 kre while (pf != NULL) { /* don't need to stop at basepf */ 542 1.52 kre if (pf->fd == from) 543 1.52 kre pf->fd = to; 544 1.52 kre pf = pf->prev; 545 1.52 kre } 546 1.52 kre } 547 1.1 cgd 548 1.1 cgd /* 549 1.1 cgd * Like setinputfile, but takes an open file descriptor. Call this with 550 1.1 cgd * interrupts off. 551 1.1 cgd */ 552 1.1 cgd 553 1.1 cgd void 554 1.37 christos setinputfd(int fd, int push) 555 1.11 cgd { 556 1.60 kre VTRACE(DBG_INPUT, ("setinputfd(%d, %spush)\n", fd, push?"":"no")); 557 1.60 kre 558 1.70 kre INTOFF; 559 1.52 kre register_sh_fd(fd, input_fd_swap); 560 1.23 mycroft (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 561 1.60 kre if (push) 562 1.1 cgd pushfile(); 563 1.1 cgd if (parsefile->fd > 0) 564 1.52 kre sh_close(parsefile->fd); 565 1.1 cgd parsefile->fd = fd; 566 1.1 cgd if (parsefile->buf == NULL) 567 1.1 cgd parsefile->buf = ckmalloc(BUFSIZ); 568 1.17 christos parselleft = parsenleft = 0; 569 1.1 cgd plinno = 1; 570 1.70 kre INTON; 571 1.60 kre 572 1.60 kre CTRACE(DBG_INPUT, ("setinputfd(%d, %spush) done; plinno=1\n", fd, 573 1.60 kre push ? "" : "no")); 574 1.1 cgd } 575 1.1 cgd 576 1.1 cgd 577 1.1 cgd /* 578 1.1 cgd * Like setinputfile, but takes input from a string. 579 1.1 cgd */ 580 1.1 cgd 581 1.1 cgd void 582 1.74 kre setinputstring(const char *string, int push, int line1) 583 1.37 christos { 584 1.48 christos 585 1.1 cgd INTOFF; 586 1.58 kre if (push) /* XXX: always, as it happens */ 587 1.1 cgd pushfile(); 588 1.1 cgd parsenextc = string; 589 1.17 christos parselleft = parsenleft = strlen(string); 590 1.57 kre plinno = line1; 591 1.70 kre INTON; 592 1.60 kre 593 1.60 kre CTRACE(DBG_INPUT, 594 1.62 kre ("setinputstring(\"%.20s%s\" (%d), %spush, @ %d)\n", string, 595 1.60 kre (parsenleft > 20 ? "..." : ""), parsenleft, push?"":"no", line1)); 596 1.1 cgd } 597 1.1 cgd 598 1.1 cgd 599 1.1 cgd 600 1.1 cgd /* 601 1.1 cgd * To handle the "." command, a stack of input files is used. Pushfile 602 1.1 cgd * adds a new entry to the stack and popfile restores the previous level. 603 1.1 cgd */ 604 1.1 cgd 605 1.1 cgd STATIC void 606 1.37 christos pushfile(void) 607 1.37 christos { 608 1.1 cgd struct parsefile *pf; 609 1.1 cgd 610 1.60 kre VTRACE(DBG_INPUT, 611 1.60 kre ("pushfile(): fd=%d buf=%p nl=%d ll=%d \"%.*s\" plinno=%d\n", 612 1.60 kre parsefile->fd, parsefile->buf, parsenleft, parselleft, 613 1.59 kre parsenleft, parsenextc, plinno)); 614 1.59 kre 615 1.1 cgd parsefile->nleft = parsenleft; 616 1.17 christos parsefile->lleft = parselleft; 617 1.1 cgd parsefile->nextc = parsenextc; 618 1.1 cgd parsefile->linno = plinno; 619 1.1 cgd pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile)); 620 1.1 cgd pf->prev = parsefile; 621 1.1 cgd pf->fd = -1; 622 1.5 jtc pf->strpush = NULL; 623 1.5 jtc pf->basestrpush.prev = NULL; 624 1.60 kre pf->buf = NULL; 625 1.1 cgd parsefile = pf; 626 1.1 cgd } 627 1.1 cgd 628 1.1 cgd 629 1.1 cgd void 630 1.37 christos popfile(void) 631 1.37 christos { 632 1.1 cgd struct parsefile *pf = parsefile; 633 1.1 cgd 634 1.1 cgd INTOFF; 635 1.1 cgd if (pf->fd >= 0) 636 1.52 kre sh_close(pf->fd); 637 1.1 cgd if (pf->buf) 638 1.1 cgd ckfree(pf->buf); 639 1.5 jtc while (pf->strpush) 640 1.5 jtc popstring(); 641 1.1 cgd parsefile = pf->prev; 642 1.1 cgd ckfree(pf); 643 1.1 cgd parsenleft = parsefile->nleft; 644 1.17 christos parselleft = parsefile->lleft; 645 1.1 cgd parsenextc = parsefile->nextc; 646 1.60 kre 647 1.59 kre VTRACE(DBG_INPUT, 648 1.60 kre ("popfile(): fd=%d buf=%p nl=%d ll=%d \"%.*s\" plinno:%d->%d\n", 649 1.60 kre parsefile->fd, parsefile->buf, parsenleft, parselleft, 650 1.59 kre parsenleft, parsenextc, plinno, parsefile->linno)); 651 1.60 kre 652 1.1 cgd plinno = parsefile->linno; 653 1.1 cgd INTON; 654 1.1 cgd } 655 1.1 cgd 656 1.59 kre /* 657 1.59 kre * Return current file (to go back to it later using popfilesupto()). 658 1.59 kre */ 659 1.59 kre 660 1.59 kre struct parsefile * 661 1.59 kre getcurrentfile(void) 662 1.59 kre { 663 1.59 kre return parsefile; 664 1.59 kre } 665 1.59 kre 666 1.59 kre 667 1.59 kre /* 668 1.59 kre * Pop files until the given file is on top again. Useful for regular 669 1.59 kre * builtins that read shell commands from files or strings. 670 1.59 kre * If the given file is not an active file, an error is raised. 671 1.59 kre */ 672 1.59 kre 673 1.59 kre void 674 1.59 kre popfilesupto(struct parsefile *file) 675 1.59 kre { 676 1.59 kre while (parsefile != file && parsefile != &basepf) 677 1.59 kre popfile(); 678 1.59 kre if (parsefile != file) 679 1.59 kre error("popfilesupto() misused"); 680 1.59 kre } 681 1.59 kre 682 1.1 cgd 683 1.1 cgd /* 684 1.1 cgd * Return to top level. 685 1.1 cgd */ 686 1.1 cgd 687 1.1 cgd void 688 1.37 christos popallfiles(void) 689 1.37 christos { 690 1.1 cgd while (parsefile != &basepf) 691 1.1 cgd popfile(); 692 1.1 cgd } 693 1.1 cgd 694 1.1 cgd 695 1.1 cgd 696 1.1 cgd /* 697 1.1 cgd * Close the file(s) that the shell is reading commands from. Called 698 1.1 cgd * after a fork is done. 699 1.36 christos * 700 1.36 christos * Takes one arg, vfork, which tells it to not modify its global vars 701 1.36 christos * as it is still running in the parent. 702 1.38 dsl * 703 1.38 dsl * This code is (probably) unnecessary as the 'close on exec' flag is 704 1.38 dsl * set and should be enough. In the vfork case it is definitely wrong 705 1.38 dsl * to close the fds as another fork() may be done later to feed data 706 1.38 dsl * from a 'here' document into a pipe and we don't want to close the 707 1.38 dsl * pipe! 708 1.1 cgd */ 709 1.1 cgd 710 1.1 cgd void 711 1.37 christos closescript(int vforked) 712 1.37 christos { 713 1.38 dsl if (vforked) 714 1.36 christos return; 715 1.1 cgd popallfiles(); 716 1.1 cgd if (parsefile->fd > 0) { 717 1.52 kre sh_close(parsefile->fd); 718 1.1 cgd parsefile->fd = 0; 719 1.1 cgd } 720 1.1 cgd } 721