1/* vi: set sw=4 ts=4: */ 2/* 3 * ash shell port for busybox 4 * 5 * Copyright (c) 1989, 1991, 1993, 1994 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au> 9 * was re-ported from NetBSD and debianized. 10 * 11 * 12 * This code is derived from software contributed to Berkeley by 13 * Kenneth Almquist. 14 * 15 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. 16 * 17 * Original BSD copyright notice is retained at the end of this file. 18 */ 19 20/* 21 * rewrite arith.y to micro stack based cryptic algorithm by 22 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> 23 * 24 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support 25 * dynamic variables. 26 * 27 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2005 to be 28 * used in busybox and size optimizations, 29 * rewrote arith (see notes to this), added locale support, 30 * rewrote dynamic variables. 31 * 32 */ 33 34/* 35 * The follow should be set to reflect the type of system you have: 36 * JOBS -> 1 if you have Berkeley job control, 0 otherwise. 37 * define SYSV if you are running under System V. 38 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on) 39 * define DEBUG=2 to compile in and turn on debugging. 40 * 41 * When debugging is on, debugging info will be written to ./trace and 42 * a quit signal will generate a core dump. 43 */ 44#define DEBUG 0 45#define IFS_BROKEN 46#define PROFILE 0 47#if ENABLE_ASH_JOB_CONTROL 48#define JOBS 1 49#else 50#define JOBS 0 51#endif 52 53#if DEBUG 54#define _GNU_SOURCE 55#endif 56#include "busybox.h" /* for struct bb_applet */ 57#include <paths.h> 58#include <setjmp.h> 59#include <fnmatch.h> 60#if JOBS || ENABLE_ASH_READ_NCHARS 61#include <termios.h> 62#endif 63extern char **environ; 64 65#if defined(__uClinux__) 66#error "Do not even bother, ash will not run on uClinux" 67#endif 68 69 70/* ============ Misc helpers */ 71 72#define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0) 73 74/* C99 say: "char" declaration may be signed or unsigned default */ 75#define signed_char2int(sc) ((int)((signed char)sc)) 76 77 78/* ============ Shell options */ 79 80static const char *const optletters_optnames[] = { 81 "e" "errexit", 82 "f" "noglob", 83 "I" "ignoreeof", 84 "i" "interactive", 85 "m" "monitor", 86 "n" "noexec", 87 "s" "stdin", 88 "x" "xtrace", 89 "v" "verbose", 90 "C" "noclobber", 91 "a" "allexport", 92 "b" "notify", 93 "u" "nounset", 94 "\0" "vi" 95#if DEBUG 96 ,"\0" "nolog" 97 ,"\0" "debug" 98#endif 99}; 100 101#define optletters(n) optletters_optnames[(n)][0] 102#define optnames(n) (&optletters_optnames[(n)][1]) 103 104enum { NOPTS = ARRAY_SIZE(optletters_optnames) }; 105 106static char optlist[NOPTS] ALIGN1; 107 108#define eflag optlist[0] 109#define fflag optlist[1] 110#define Iflag optlist[2] 111#define iflag optlist[3] 112#define mflag optlist[4] 113#define nflag optlist[5] 114#define sflag optlist[6] 115#define xflag optlist[7] 116#define vflag optlist[8] 117#define Cflag optlist[9] 118#define aflag optlist[10] 119#define bflag optlist[11] 120#define uflag optlist[12] 121#define viflag optlist[13] 122#if DEBUG 123#define nolog optlist[14] 124#define debug optlist[15] 125#endif 126 127 128/* ============ Misc data */ 129 130static char nullstr[1] ALIGN1; /* zero length string */ 131static const char homestr[] ALIGN1 = "HOME"; 132static const char snlfmt[] ALIGN1 = "%s\n"; 133static const char illnum[] ALIGN1 = "Illegal number: %s"; 134 135static char *minusc; /* argument to -c option */ 136 137/* pid of main shell */ 138static int rootpid; 139/* shell level: 0 for the main shell, 1 for its children, and so on */ 140static int shlvl; 141#define rootshell (!shlvl) 142/* trap handler commands */ 143static char *trap[NSIG]; 144static smallint isloginsh; 145/* current value of signal */ 146static char sigmode[NSIG - 1]; 147/* indicates specified signal received */ 148static char gotsig[NSIG - 1]; 149static char *arg0; /* value of $0 */ 150 151 152/* ============ Interrupts / exceptions */ 153 154/* 155 * We enclose jmp_buf in a structure so that we can declare pointers to 156 * jump locations. The global variable handler contains the location to 157 * jump to when an exception occurs, and the global variable exception 158 * contains a code identifying the exception. To implement nested 159 * exception handlers, the user should save the value of handler on entry 160 * to an inner scope, set handler to point to a jmploc structure for the 161 * inner scope, and restore handler on exit from the scope. 162 */ 163struct jmploc { 164 jmp_buf loc; 165}; 166static struct jmploc *exception_handler; 167static int exception; 168/* exceptions */ 169#define EXINT 0 /* SIGINT received */ 170#define EXERROR 1 /* a generic error */ 171#define EXSHELLPROC 2 /* execute a shell procedure */ 172#define EXEXEC 3 /* command execution failed */ 173#define EXEXIT 4 /* exit the shell */ 174#define EXSIG 5 /* trapped signal in wait(1) */ 175static volatile int suppressint; 176static volatile sig_atomic_t intpending; 177/* do we generate EXSIG events */ 178static int exsig; 179/* last pending signal */ 180static volatile sig_atomic_t pendingsig; 181 182/* 183 * Sigmode records the current value of the signal handlers for the various 184 * modes. A value of zero means that the current handler is not known. 185 * S_HARD_IGN indicates that the signal was ignored on entry to the shell, 186 */ 187 188#define S_DFL 1 /* default signal handling (SIG_DFL) */ 189#define S_CATCH 2 /* signal is caught */ 190#define S_IGN 3 /* signal is ignored (SIG_IGN) */ 191#define S_HARD_IGN 4 /* signal is ignored permenantly */ 192#define S_RESET 5 /* temporary - to reset a hard ignored sig */ 193 194/* 195 * These macros allow the user to suspend the handling of interrupt signals 196 * over a period of time. This is similar to SIGHOLD to or sigblock, but 197 * much more efficient and portable. (But hacking the kernel is so much 198 * more fun than worrying about efficiency and portability. :-)) 199 */ 200#define INT_OFF \ 201 do { \ 202 suppressint++; \ 203 xbarrier(); \ 204 } while (0) 205 206/* 207 * Called to raise an exception. Since C doesn't include exceptions, we 208 * just do a longjmp to the exception handler. The type of exception is 209 * stored in the global variable "exception". 210 */ 211static void raise_exception(int) ATTRIBUTE_NORETURN; 212static void 213raise_exception(int e) 214{ 215#if DEBUG 216 if (exception_handler == NULL) 217 abort(); 218#endif 219 INT_OFF; 220 exception = e; 221 longjmp(exception_handler->loc, 1); 222} 223 224/* 225 * Called from trap.c when a SIGINT is received. (If the user specifies 226 * that SIGINT is to be trapped or ignored using the trap builtin, then 227 * this routine is not called.) Suppressint is nonzero when interrupts 228 * are held using the INT_OFF macro. (The test for iflag is just 229 * defensive programming.) 230 */ 231static void raise_interrupt(void) ATTRIBUTE_NORETURN; 232static void 233raise_interrupt(void) 234{ 235 int i; 236 sigset_t mask; 237 238 intpending = 0; 239 /* Signal is not automatically re-enabled after it is raised, 240 * do it ourself */ 241 sigemptyset(&mask); 242 sigprocmask(SIG_SETMASK, &mask, 0); 243 /* pendingsig = 0; - now done in onsig() */ 244 245 i = EXSIG; 246 if (gotsig[SIGINT - 1] && !trap[SIGINT]) { 247 if (!(rootshell && iflag)) { 248 signal(SIGINT, SIG_DFL); 249 raise(SIGINT); 250 } 251 i = EXINT; 252 } 253 raise_exception(i); 254 /* NOTREACHED */ 255} 256 257#if ENABLE_ASH_OPTIMIZE_FOR_SIZE 258static void 259int_on(void) 260{ 261 if (--suppressint == 0 && intpending) { 262 raise_interrupt(); 263 } 264} 265#define INT_ON int_on() 266static void 267force_int_on(void) 268{ 269 suppressint = 0; 270 if (intpending) 271 raise_interrupt(); 272} 273#define FORCE_INT_ON force_int_on() 274#else 275#define INT_ON \ 276 do { \ 277 xbarrier(); \ 278 if (--suppressint == 0 && intpending) \ 279 raise_interrupt(); \ 280 } while (0) 281#define FORCE_INT_ON \ 282 do { \ 283 xbarrier(); \ 284 suppressint = 0; \ 285 if (intpending) \ 286 raise_interrupt(); \ 287 } while (0) 288#endif /* ASH_OPTIMIZE_FOR_SIZE */ 289 290#define SAVE_INT(v) ((v) = suppressint) 291 292#define RESTORE_INT(v) \ 293 do { \ 294 xbarrier(); \ 295 suppressint = (v); \ 296 if (suppressint == 0 && intpending) \ 297 raise_interrupt(); \ 298 } while (0) 299 300#define EXSIGON \ 301 do { \ 302 exsig++; \ 303 xbarrier(); \ 304 if (pendingsig) \ 305 raise_exception(EXSIG); \ 306 } while (0) 307/* EXSIG is turned off by evalbltin(). */ 308 309/* 310 * Ignore a signal. Only one usage site - in forkchild() 311 */ 312static void 313ignoresig(int signo) 314{ 315 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { 316 signal(signo, SIG_IGN); 317 } 318 sigmode[signo - 1] = S_HARD_IGN; 319} 320 321/* 322 * Signal handler. Only one usage site - in setsignal() 323 */ 324static void 325onsig(int signo) 326{ 327 gotsig[signo - 1] = 1; 328 pendingsig = signo; 329 330 if (exsig || (signo == SIGINT && !trap[SIGINT])) { 331 if (!suppressint) { 332 pendingsig = 0; 333 raise_interrupt(); 334 } 335 intpending = 1; 336 } 337} 338 339 340/* ============ Stdout/stderr output */ 341 342static void 343outstr(const char *p, FILE *file) 344{ 345 INT_OFF; 346 fputs(p, file); 347 INT_ON; 348} 349 350static void 351flush_stdout_stderr(void) 352{ 353 INT_OFF; 354 fflush(stdout); 355 fflush(stderr); 356 INT_ON; 357} 358 359static void 360flush_stderr(void) 361{ 362 INT_OFF; 363 fflush(stderr); 364 INT_ON; 365} 366 367static void 368outcslow(int c, FILE *dest) 369{ 370 INT_OFF; 371 putc(c, dest); 372 fflush(dest); 373 INT_ON; 374} 375 376static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2))); 377static int 378out1fmt(const char *fmt, ...) 379{ 380 va_list ap; 381 int r; 382 383 INT_OFF; 384 va_start(ap, fmt); 385 r = vprintf(fmt, ap); 386 va_end(ap); 387 INT_ON; 388 return r; 389} 390 391static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4))); 392static int 393fmtstr(char *outbuf, size_t length, const char *fmt, ...) 394{ 395 va_list ap; 396 int ret; 397 398 va_start(ap, fmt); 399 INT_OFF; 400 ret = vsnprintf(outbuf, length, fmt, ap); 401 va_end(ap); 402 INT_ON; 403 return ret; 404} 405 406static void 407out1str(const char *p) 408{ 409 outstr(p, stdout); 410} 411 412static void 413out2str(const char *p) 414{ 415 outstr(p, stderr); 416 flush_stderr(); 417} 418 419 420/* ============ Parser structures */ 421 422/* control characters in argument strings */ 423#define CTLESC '\201' /* escape next character */ 424#define CTLVAR '\202' /* variable defn */ 425#define CTLENDVAR '\203' 426#define CTLBACKQ '\204' 427#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ 428/* CTLBACKQ | CTLQUOTE == '\205' */ 429#define CTLARI '\206' /* arithmetic expression */ 430#define CTLENDARI '\207' 431#define CTLQUOTEMARK '\210' 432 433/* variable substitution byte (follows CTLVAR) */ 434#define VSTYPE 0x0f /* type of variable substitution */ 435#define VSNUL 0x10 /* colon--treat the empty string as unset */ 436#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ 437 438/* values of VSTYPE field */ 439#define VSNORMAL 0x1 /* normal variable: $var or ${var} */ 440#define VSMINUS 0x2 /* ${var-text} */ 441#define VSPLUS 0x3 /* ${var+text} */ 442#define VSQUESTION 0x4 /* ${var?message} */ 443#define VSASSIGN 0x5 /* ${var=text} */ 444#define VSTRIMRIGHT 0x6 /* ${var%pattern} */ 445#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */ 446#define VSTRIMLEFT 0x8 /* ${var#pattern} */ 447#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */ 448#define VSLENGTH 0xa /* ${#var} */ 449 450static const char dolatstr[] ALIGN1 = { 451 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' 452}; 453 454#define NCMD 0 455#define NPIPE 1 456#define NREDIR 2 457#define NBACKGND 3 458#define NSUBSHELL 4 459#define NAND 5 460#define NOR 6 461#define NSEMI 7 462#define NIF 8 463#define NWHILE 9 464#define NUNTIL 10 465#define NFOR 11 466#define NCASE 12 467#define NCLIST 13 468#define NDEFUN 14 469#define NARG 15 470#define NTO 16 471#define NCLOBBER 17 472#define NFROM 18 473#define NFROMTO 19 474#define NAPPEND 20 475#define NTOFD 21 476#define NFROMFD 22 477#define NHERE 23 478#define NXHERE 24 479#define NNOT 25 480 481union node; 482 483struct ncmd { 484 int type; 485 union node *assign; 486 union node *args; 487 union node *redirect; 488}; 489 490struct npipe { 491 int type; 492 int backgnd; 493 struct nodelist *cmdlist; 494}; 495 496struct nredir { 497 int type; 498 union node *n; 499 union node *redirect; 500}; 501 502struct nbinary { 503 int type; 504 union node *ch1; 505 union node *ch2; 506}; 507 508struct nif { 509 int type; 510 union node *test; 511 union node *ifpart; 512 union node *elsepart; 513}; 514 515struct nfor { 516 int type; 517 union node *args; 518 union node *body; 519 char *var; 520}; 521 522struct ncase { 523 int type; 524 union node *expr; 525 union node *cases; 526}; 527 528struct nclist { 529 int type; 530 union node *next; 531 union node *pattern; 532 union node *body; 533}; 534 535struct narg { 536 int type; 537 union node *next; 538 char *text; 539 struct nodelist *backquote; 540}; 541 542struct nfile { 543 int type; 544 union node *next; 545 int fd; 546 union node *fname; 547 char *expfname; 548}; 549 550struct ndup { 551 int type; 552 union node *next; 553 int fd; 554 int dupfd; 555 union node *vname; 556}; 557 558struct nhere { 559 int type; 560 union node *next; 561 int fd; 562 union node *doc; 563}; 564 565struct nnot { 566 int type; 567 union node *com; 568}; 569 570union node { 571 int type; 572 struct ncmd ncmd; 573 struct npipe npipe; 574 struct nredir nredir; 575 struct nbinary nbinary; 576 struct nif nif; 577 struct nfor nfor; 578 struct ncase ncase; 579 struct nclist nclist; 580 struct narg narg; 581 struct nfile nfile; 582 struct ndup ndup; 583 struct nhere nhere; 584 struct nnot nnot; 585}; 586 587struct nodelist { 588 struct nodelist *next; 589 union node *n; 590}; 591 592struct funcnode { 593 int count; 594 union node n; 595}; 596 597/* 598 * Free a parse tree. 599 */ 600static void 601freefunc(struct funcnode *f) 602{ 603 if (f && --f->count < 0) 604 free(f); 605} 606 607 608/* ============ Debugging output */ 609 610#if DEBUG 611 612static FILE *tracefile; 613 614static void 615trace_printf(const char *fmt, ...) 616{ 617 va_list va; 618 619 if (debug != 1) 620 return; 621 va_start(va, fmt); 622 vfprintf(tracefile, fmt, va); 623 va_end(va); 624} 625 626static void 627trace_vprintf(const char *fmt, va_list va) 628{ 629 if (debug != 1) 630 return; 631 vfprintf(tracefile, fmt, va); 632} 633 634static void 635trace_puts(const char *s) 636{ 637 if (debug != 1) 638 return; 639 fputs(s, tracefile); 640} 641 642static void 643trace_puts_quoted(char *s) 644{ 645 char *p; 646 char c; 647 648 if (debug != 1) 649 return; 650 putc('"', tracefile); 651 for (p = s; *p; p++) { 652 switch (*p) { 653 case '\n': c = 'n'; goto backslash; 654 case '\t': c = 't'; goto backslash; 655 case '\r': c = 'r'; goto backslash; 656 case '"': c = '"'; goto backslash; 657 case '\\': c = '\\'; goto backslash; 658 case CTLESC: c = 'e'; goto backslash; 659 case CTLVAR: c = 'v'; goto backslash; 660 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; 661 case CTLBACKQ: c = 'q'; goto backslash; 662 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; 663 backslash: 664 putc('\\', tracefile); 665 putc(c, tracefile); 666 break; 667 default: 668 if (*p >= ' ' && *p <= '~') 669 putc(*p, tracefile); 670 else { 671 putc('\\', tracefile); 672 putc(*p >> 6 & 03, tracefile); 673 putc(*p >> 3 & 07, tracefile); 674 putc(*p & 07, tracefile); 675 } 676 break; 677 } 678 } 679 putc('"', tracefile); 680} 681 682static void 683trace_puts_args(char **ap) 684{ 685 if (debug != 1) 686 return; 687 if (!*ap) 688 return; 689 while (1) { 690 trace_puts_quoted(*ap); 691 if (!*++ap) { 692 putc('\n', tracefile); 693 break; 694 } 695 putc(' ', tracefile); 696 } 697} 698 699static void 700opentrace(void) 701{ 702 char s[100]; 703#ifdef O_APPEND 704 int flags; 705#endif 706 707 if (debug != 1) { 708 if (tracefile) 709 fflush(tracefile); 710 /* leave open because libedit might be using it */ 711 return; 712 } 713 strcpy(s, "./trace"); 714 if (tracefile) { 715 if (!freopen(s, "a", tracefile)) { 716 fprintf(stderr, "Can't re-open %s\n", s); 717 debug = 0; 718 return; 719 } 720 } else { 721 tracefile = fopen(s, "a"); 722 if (tracefile == NULL) { 723 fprintf(stderr, "Can't open %s\n", s); 724 debug = 0; 725 return; 726 } 727 } 728#ifdef O_APPEND 729 flags = fcntl(fileno(tracefile), F_GETFL); 730 if (flags >= 0) 731 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); 732#endif 733 setlinebuf(tracefile); 734 fputs("\nTracing started.\n", tracefile); 735} 736 737static void 738indent(int amount, char *pfx, FILE *fp) 739{ 740 int i; 741 742 for (i = 0; i < amount; i++) { 743 if (pfx && i == amount - 1) 744 fputs(pfx, fp); 745 putc('\t', fp); 746 } 747} 748 749/* little circular references here... */ 750static void shtree(union node *n, int ind, char *pfx, FILE *fp); 751 752static void 753sharg(union node *arg, FILE *fp) 754{ 755 char *p; 756 struct nodelist *bqlist; 757 int subtype; 758 759 if (arg->type != NARG) { 760 out1fmt("<node type %d>\n", arg->type); 761 abort(); 762 } 763 bqlist = arg->narg.backquote; 764 for (p = arg->narg.text; *p; p++) { 765 switch (*p) { 766 case CTLESC: 767 putc(*++p, fp); 768 break; 769 case CTLVAR: 770 putc('$', fp); 771 putc('{', fp); 772 subtype = *++p; 773 if (subtype == VSLENGTH) 774 putc('#', fp); 775 776 while (*p != '=') 777 putc(*p++, fp); 778 779 if (subtype & VSNUL) 780 putc(':', fp); 781 782 switch (subtype & VSTYPE) { 783 case VSNORMAL: 784 putc('}', fp); 785 break; 786 case VSMINUS: 787 putc('-', fp); 788 break; 789 case VSPLUS: 790 putc('+', fp); 791 break; 792 case VSQUESTION: 793 putc('?', fp); 794 break; 795 case VSASSIGN: 796 putc('=', fp); 797 break; 798 case VSTRIMLEFT: 799 putc('#', fp); 800 break; 801 case VSTRIMLEFTMAX: 802 putc('#', fp); 803 putc('#', fp); 804 break; 805 case VSTRIMRIGHT: 806 putc('%', fp); 807 break; 808 case VSTRIMRIGHTMAX: 809 putc('%', fp); 810 putc('%', fp); 811 break; 812 case VSLENGTH: 813 break; 814 default: 815 out1fmt("<subtype %d>", subtype); 816 } 817 break; 818 case CTLENDVAR: 819 putc('}', fp); 820 break; 821 case CTLBACKQ: 822 case CTLBACKQ|CTLQUOTE: 823 putc('$', fp); 824 putc('(', fp); 825 shtree(bqlist->n, -1, NULL, fp); 826 putc(')', fp); 827 break; 828 default: 829 putc(*p, fp); 830 break; 831 } 832 } 833} 834 835static void 836shcmd(union node *cmd, FILE *fp) 837{ 838 union node *np; 839 int first; 840 const char *s; 841 int dftfd; 842 843 first = 1; 844 for (np = cmd->ncmd.args; np; np = np->narg.next) { 845 if (!first) 846 putc(' ', fp); 847 sharg(np, fp); 848 first = 0; 849 } 850 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) { 851 if (!first) 852 putc(' ', fp); 853 dftfd = 0; 854 switch (np->nfile.type) { 855 case NTO: s = ">>"+1; dftfd = 1; break; 856 case NCLOBBER: s = ">|"; dftfd = 1; break; 857 case NAPPEND: s = ">>"; dftfd = 1; break; 858 case NTOFD: s = ">&"; dftfd = 1; break; 859 case NFROM: s = "<"; break; 860 case NFROMFD: s = "<&"; break; 861 case NFROMTO: s = "<>"; break; 862 default: s = "*error*"; break; 863 } 864 if (np->nfile.fd != dftfd) 865 fprintf(fp, "%d", np->nfile.fd); 866 fputs(s, fp); 867 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) { 868 fprintf(fp, "%d", np->ndup.dupfd); 869 } else { 870 sharg(np->nfile.fname, fp); 871 } 872 first = 0; 873 } 874} 875 876static void 877shtree(union node *n, int ind, char *pfx, FILE *fp) 878{ 879 struct nodelist *lp; 880 const char *s; 881 882 if (n == NULL) 883 return; 884 885 indent(ind, pfx, fp); 886 switch (n->type) { 887 case NSEMI: 888 s = "; "; 889 goto binop; 890 case NAND: 891 s = " && "; 892 goto binop; 893 case NOR: 894 s = " || "; 895 binop: 896 shtree(n->nbinary.ch1, ind, NULL, fp); 897 /* if (ind < 0) */ 898 fputs(s, fp); 899 shtree(n->nbinary.ch2, ind, NULL, fp); 900 break; 901 case NCMD: 902 shcmd(n, fp); 903 if (ind >= 0) 904 putc('\n', fp); 905 break; 906 case NPIPE: 907 for (lp = n->npipe.cmdlist; lp; lp = lp->next) { 908 shcmd(lp->n, fp); 909 if (lp->next) 910 fputs(" | ", fp); 911 } 912 if (n->npipe.backgnd) 913 fputs(" &", fp); 914 if (ind >= 0) 915 putc('\n', fp); 916 break; 917 default: 918 fprintf(fp, "<node type %d>", n->type); 919 if (ind >= 0) 920 putc('\n', fp); 921 break; 922 } 923} 924 925static void 926showtree(union node *n) 927{ 928 trace_puts("showtree called\n"); 929 shtree(n, 1, NULL, stdout); 930} 931 932#define TRACE(param) trace_printf param 933#define TRACEV(param) trace_vprintf param 934 935#else 936 937#define TRACE(param) 938#define TRACEV(param) 939 940#endif /* DEBUG */ 941 942 943/* ============ Parser data */ 944 945/* 946 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up. 947 */ 948struct strlist { 949 struct strlist *next; 950 char *text; 951}; 952 953#if ENABLE_ASH_ALIAS 954struct alias; 955#endif 956 957struct strpush { 958 struct strpush *prev; /* preceding string on stack */ 959 char *prevstring; 960 int prevnleft; 961#if ENABLE_ASH_ALIAS 962 struct alias *ap; /* if push was associated with an alias */ 963#endif 964 char *string; /* remember the string since it may change */ 965}; 966 967struct parsefile { 968 struct parsefile *prev; /* preceding file on stack */ 969 int linno; /* current line */ 970 int fd; /* file descriptor (or -1 if string) */ 971 int nleft; /* number of chars left in this line */ 972 int lleft; /* number of chars left in this buffer */ 973 char *nextc; /* next char in buffer */ 974 char *buf; /* input buffer */ 975 struct strpush *strpush; /* for pushing strings at this level */ 976 struct strpush basestrpush; /* so pushing one is fast */ 977}; 978 979static struct parsefile basepf; /* top level input file */ 980static struct parsefile *parsefile = &basepf; /* current input file */ 981static int startlinno; /* line # where last token started */ 982static char *commandname; /* currently executing command */ 983static struct strlist *cmdenviron; /* environment for builtin command */ 984static int exitstatus; /* exit status of last command */ 985 986 987/* ============ Message printing */ 988 989static void 990ash_vmsg(const char *msg, va_list ap) 991{ 992 fprintf(stderr, "%s: ", arg0); 993 if (commandname) { 994 if (strcmp(arg0, commandname)) 995 fprintf(stderr, "%s: ", commandname); 996 if (!iflag || parsefile->fd) 997 fprintf(stderr, "line %d: ", startlinno); 998 } 999 vfprintf(stderr, msg, ap); 1000 outcslow('\n', stderr); 1001} 1002 1003/* 1004 * Exverror is called to raise the error exception. If the second argument 1005 * is not NULL then error prints an error message using printf style 1006 * formatting. It then raises the error exception. 1007 */ 1008static void ash_vmsg_and_raise(int, const char *, va_list) ATTRIBUTE_NORETURN; 1009static void 1010ash_vmsg_and_raise(int cond, const char *msg, va_list ap) 1011{ 1012#if DEBUG 1013 if (msg) { 1014 TRACE(("ash_vmsg_and_raise(%d, \"", cond)); 1015 TRACEV((msg, ap)); 1016 TRACE(("\") pid=%d\n", getpid())); 1017 } else 1018 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid())); 1019 if (msg) 1020#endif 1021 ash_vmsg(msg, ap); 1022 1023 flush_stdout_stderr(); 1024 raise_exception(cond); 1025 /* NOTREACHED */ 1026} 1027 1028static void ash_msg_and_raise_error(const char *, ...) ATTRIBUTE_NORETURN; 1029static void 1030ash_msg_and_raise_error(const char *msg, ...) 1031{ 1032 va_list ap; 1033 1034 va_start(ap, msg); 1035 ash_vmsg_and_raise(EXERROR, msg, ap); 1036 /* NOTREACHED */ 1037 va_end(ap); 1038} 1039 1040static void ash_msg_and_raise(int, const char *, ...) ATTRIBUTE_NORETURN; 1041static void 1042ash_msg_and_raise(int cond, const char *msg, ...) 1043{ 1044 va_list ap; 1045 1046 va_start(ap, msg); 1047 ash_vmsg_and_raise(cond, msg, ap); 1048 /* NOTREACHED */ 1049 va_end(ap); 1050} 1051 1052/* 1053 * error/warning routines for external builtins 1054 */ 1055static void 1056ash_msg(const char *fmt, ...) 1057{ 1058 va_list ap; 1059 1060 va_start(ap, fmt); 1061 ash_vmsg(fmt, ap); 1062 va_end(ap); 1063} 1064 1065/* 1066 * Return a string describing an error. The returned string may be a 1067 * pointer to a static buffer that will be overwritten on the next call. 1068 * Action describes the operation that got the error. 1069 */ 1070static const char * 1071errmsg(int e, const char *em) 1072{ 1073 if (e == ENOENT || e == ENOTDIR) { 1074 return em; 1075 } 1076 return strerror(e); 1077} 1078 1079 1080/* ============ Memory allocation */ 1081 1082/* 1083 * It appears that grabstackstr() will barf with such alignments 1084 * because stalloc() will return a string allocated in a new stackblock. 1085 */ 1086#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE) 1087enum { 1088 /* Most machines require the value returned from malloc to be aligned 1089 * in some way. The following macro will get this right 1090 * on many machines. */ 1091 SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1, 1092 /* Minimum size of a block */ 1093 MINSIZE = SHELL_ALIGN(504), 1094}; 1095 1096struct stack_block { 1097 struct stack_block *prev; 1098 char space[MINSIZE]; 1099}; 1100 1101struct stackmark { 1102 struct stack_block *stackp; 1103 char *stacknxt; 1104 size_t stacknleft; 1105 struct stackmark *marknext; 1106}; 1107 1108static struct stack_block stackbase; 1109static struct stack_block *stackp = &stackbase; 1110static struct stackmark *markp; 1111static char *stacknxt = stackbase.space; 1112static size_t stacknleft = MINSIZE; 1113static char *sstrend = stackbase.space + MINSIZE; 1114static int herefd = -1; 1115 1116#define stackblock() ((void *)stacknxt) 1117#define stackblocksize() stacknleft 1118 1119static void * 1120ckrealloc(void * p, size_t nbytes) 1121{ 1122 p = realloc(p, nbytes); 1123 if (!p) 1124 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1125 return p; 1126} 1127 1128static void * 1129ckmalloc(size_t nbytes) 1130{ 1131 return ckrealloc(NULL, nbytes); 1132} 1133 1134/* 1135 * Make a copy of a string in safe storage. 1136 */ 1137static char * 1138ckstrdup(const char *s) 1139{ 1140 char *p = strdup(s); 1141 if (!p) 1142 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1143 return p; 1144} 1145 1146/* 1147 * Parse trees for commands are allocated in lifo order, so we use a stack 1148 * to make this more efficient, and also to avoid all sorts of exception 1149 * handling code to handle interrupts in the middle of a parse. 1150 * 1151 * The size 504 was chosen because the Ultrix malloc handles that size 1152 * well. 1153 */ 1154static void * 1155stalloc(size_t nbytes) 1156{ 1157 char *p; 1158 size_t aligned; 1159 1160 aligned = SHELL_ALIGN(nbytes); 1161 if (aligned > stacknleft) { 1162 size_t len; 1163 size_t blocksize; 1164 struct stack_block *sp; 1165 1166 blocksize = aligned; 1167 if (blocksize < MINSIZE) 1168 blocksize = MINSIZE; 1169 len = sizeof(struct stack_block) - MINSIZE + blocksize; 1170 if (len < blocksize) 1171 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1172 INT_OFF; 1173 sp = ckmalloc(len); 1174 sp->prev = stackp; 1175 stacknxt = sp->space; 1176 stacknleft = blocksize; 1177 sstrend = stacknxt + blocksize; 1178 stackp = sp; 1179 INT_ON; 1180 } 1181 p = stacknxt; 1182 stacknxt += aligned; 1183 stacknleft -= aligned; 1184 return p; 1185} 1186 1187static void 1188stunalloc(void *p) 1189{ 1190#if DEBUG 1191 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) { 1192 write(2, "stunalloc\n", 10); 1193 abort(); 1194 } 1195#endif 1196 stacknleft += stacknxt - (char *)p; 1197 stacknxt = p; 1198} 1199 1200/* 1201 * Like strdup but works with the ash stack. 1202 */ 1203static char * 1204ststrdup(const char *p) 1205{ 1206 size_t len = strlen(p) + 1; 1207 return memcpy(stalloc(len), p, len); 1208} 1209 1210static void 1211setstackmark(struct stackmark *mark) 1212{ 1213 mark->stackp = stackp; 1214 mark->stacknxt = stacknxt; 1215 mark->stacknleft = stacknleft; 1216 mark->marknext = markp; 1217 markp = mark; 1218} 1219 1220static void 1221popstackmark(struct stackmark *mark) 1222{ 1223 struct stack_block *sp; 1224 1225 if (!mark->stackp) 1226 return; 1227 1228 INT_OFF; 1229 markp = mark->marknext; 1230 while (stackp != mark->stackp) { 1231 sp = stackp; 1232 stackp = sp->prev; 1233 free(sp); 1234 } 1235 stacknxt = mark->stacknxt; 1236 stacknleft = mark->stacknleft; 1237 sstrend = mark->stacknxt + mark->stacknleft; 1238 INT_ON; 1239} 1240 1241/* 1242 * When the parser reads in a string, it wants to stick the string on the 1243 * stack and only adjust the stack pointer when it knows how big the 1244 * string is. Stackblock (defined in stack.h) returns a pointer to a block 1245 * of space on top of the stack and stackblocklen returns the length of 1246 * this block. Growstackblock will grow this space by at least one byte, 1247 * possibly moving it (like realloc). Grabstackblock actually allocates the 1248 * part of the block that has been used. 1249 */ 1250static void 1251growstackblock(void) 1252{ 1253 size_t newlen; 1254 1255 newlen = stacknleft * 2; 1256 if (newlen < stacknleft) 1257 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1258 if (newlen < 128) 1259 newlen += 128; 1260 1261 if (stacknxt == stackp->space && stackp != &stackbase) { 1262 struct stack_block *oldstackp; 1263 struct stackmark *xmark; 1264 struct stack_block *sp; 1265 struct stack_block *prevstackp; 1266 size_t grosslen; 1267 1268 INT_OFF; 1269 oldstackp = stackp; 1270 sp = stackp; 1271 prevstackp = sp->prev; 1272 grosslen = newlen + sizeof(struct stack_block) - MINSIZE; 1273 sp = ckrealloc(sp, grosslen); 1274 sp->prev = prevstackp; 1275 stackp = sp; 1276 stacknxt = sp->space; 1277 stacknleft = newlen; 1278 sstrend = sp->space + newlen; 1279 1280 /* 1281 * Stack marks pointing to the start of the old block 1282 * must be relocated to point to the new block 1283 */ 1284 xmark = markp; 1285 while (xmark != NULL && xmark->stackp == oldstackp) { 1286 xmark->stackp = stackp; 1287 xmark->stacknxt = stacknxt; 1288 xmark->stacknleft = stacknleft; 1289 xmark = xmark->marknext; 1290 } 1291 INT_ON; 1292 } else { 1293 char *oldspace = stacknxt; 1294 int oldlen = stacknleft; 1295 char *p = stalloc(newlen); 1296 1297 /* free the space we just allocated */ 1298 stacknxt = memcpy(p, oldspace, oldlen); 1299 stacknleft += newlen; 1300 } 1301} 1302 1303static void 1304grabstackblock(size_t len) 1305{ 1306 len = SHELL_ALIGN(len); 1307 stacknxt += len; 1308 stacknleft -= len; 1309} 1310 1311/* 1312 * The following routines are somewhat easier to use than the above. 1313 * The user declares a variable of type STACKSTR, which may be declared 1314 * to be a register. The macro STARTSTACKSTR initializes things. Then 1315 * the user uses the macro STPUTC to add characters to the string. In 1316 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is 1317 * grown as necessary. When the user is done, she can just leave the 1318 * string there and refer to it using stackblock(). Or she can allocate 1319 * the space for it using grabstackstr(). If it is necessary to allow 1320 * someone else to use the stack temporarily and then continue to grow 1321 * the string, the user should use grabstack to allocate the space, and 1322 * then call ungrabstr(p) to return to the previous mode of operation. 1323 * 1324 * USTPUTC is like STPUTC except that it doesn't check for overflow. 1325 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there 1326 * is space for at least one character. 1327 */ 1328static void * 1329growstackstr(void) 1330{ 1331 size_t len = stackblocksize(); 1332 if (herefd >= 0 && len >= 1024) { 1333 full_write(herefd, stackblock(), len); 1334 return stackblock(); 1335 } 1336 growstackblock(); 1337 return stackblock() + len; 1338} 1339 1340/* 1341 * Called from CHECKSTRSPACE. 1342 */ 1343static char * 1344makestrspace(size_t newlen, char *p) 1345{ 1346 size_t len = p - stacknxt; 1347 size_t size = stackblocksize(); 1348 1349 for (;;) { 1350 size_t nleft; 1351 1352 size = stackblocksize(); 1353 nleft = size - len; 1354 if (nleft >= newlen) 1355 break; 1356 growstackblock(); 1357 } 1358 return stackblock() + len; 1359} 1360 1361static char * 1362stack_nputstr(const char *s, size_t n, char *p) 1363{ 1364 p = makestrspace(n, p); 1365 p = memcpy(p, s, n) + n; 1366 return p; 1367} 1368 1369static char * 1370stack_putstr(const char *s, char *p) 1371{ 1372 return stack_nputstr(s, strlen(s), p); 1373} 1374 1375static char * 1376_STPUTC(int c, char *p) 1377{ 1378 if (p == sstrend) 1379 p = growstackstr(); 1380 *p++ = c; 1381 return p; 1382} 1383 1384#define STARTSTACKSTR(p) ((p) = stackblock()) 1385#define STPUTC(c, p) ((p) = _STPUTC((c), (p))) 1386#define CHECKSTRSPACE(n, p) \ 1387 do { \ 1388 char *q = (p); \ 1389 size_t l = (n); \ 1390 size_t m = sstrend - q; \ 1391 if (l > m) \ 1392 (p) = makestrspace(l, q); \ 1393 } while (0) 1394#define USTPUTC(c, p) (*p++ = (c)) 1395#define STACKSTRNUL(p) \ 1396 do { \ 1397 if ((p) == sstrend) \ 1398 p = growstackstr(); \ 1399 *p = '\0'; \ 1400 } while (0) 1401#define STUNPUTC(p) (--p) 1402#define STTOPC(p) (p[-1]) 1403#define STADJUST(amount, p) (p += (amount)) 1404 1405#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock()) 1406#define ungrabstackstr(s, p) stunalloc((s)) 1407#define stackstrend() ((void *)sstrend) 1408 1409 1410/* ============ String helpers */ 1411 1412/* 1413 * prefix -- see if pfx is a prefix of string. 1414 */ 1415static char * 1416prefix(const char *string, const char *pfx) 1417{ 1418 while (*pfx) { 1419 if (*pfx++ != *string++) 1420 return 0; 1421 } 1422 return (char *) string; 1423} 1424 1425/* 1426 * Check for a valid number. This should be elsewhere. 1427 */ 1428static int 1429is_number(const char *p) 1430{ 1431 do { 1432 if (!isdigit(*p)) 1433 return 0; 1434 } while (*++p != '\0'); 1435 return 1; 1436} 1437 1438/* 1439 * Convert a string of digits to an integer, printing an error message on 1440 * failure. 1441 */ 1442static int 1443number(const char *s) 1444{ 1445 if (!is_number(s)) 1446 ash_msg_and_raise_error(illnum, s); 1447 return atoi(s); 1448} 1449 1450/* 1451 * Produce a possibly single quoted string suitable as input to the shell. 1452 * The return string is allocated on the stack. 1453 */ 1454static char * 1455single_quote(const char *s) 1456{ 1457 char *p; 1458 1459 STARTSTACKSTR(p); 1460 1461 do { 1462 char *q; 1463 size_t len; 1464 1465 len = strchrnul(s, '\'') - s; 1466 1467 q = p = makestrspace(len + 3, p); 1468 1469 *q++ = '\''; 1470 q = memcpy(q, s, len) + len; 1471 *q++ = '\''; 1472 s += len; 1473 1474 STADJUST(q - p, p); 1475 1476 len = strspn(s, "'"); 1477 if (!len) 1478 break; 1479 1480 q = p = makestrspace(len + 3, p); 1481 1482 *q++ = '"'; 1483 q = memcpy(q, s, len) + len; 1484 *q++ = '"'; 1485 s += len; 1486 1487 STADJUST(q - p, p); 1488 } while (*s); 1489 1490 USTPUTC(0, p); 1491 1492 return stackblock(); 1493} 1494 1495 1496/* ============ nextopt */ 1497 1498static char **argptr; /* argument list for builtin commands */ 1499static char *optionarg; /* set by nextopt (like getopt) */ 1500static char *optptr; /* used by nextopt */ 1501 1502static int 1503nextopt(const char *optstring) 1504{ 1505 char *p; 1506 const char *q; 1507 char c; 1508 1509 p = optptr; 1510 if (p == NULL || *p == '\0') { 1511 p = *argptr; 1512 if (p == NULL || *p != '-' || *++p == '\0') 1513 return '\0'; 1514 argptr++; 1515 if (LONE_DASH(p)) /* check for "--" */ 1516 return '\0'; 1517 } 1518 c = *p++; 1519 for (q = optstring; *q != c; ) { 1520 if (*q == '\0') 1521 ash_msg_and_raise_error("illegal option -%c", c); 1522 if (*++q == ':') 1523 q++; 1524 } 1525 if (*++q == ':') { 1526 if (*p == '\0' && (p = *argptr++) == NULL) 1527 ash_msg_and_raise_error("no arg for -%c option", c); 1528 optionarg = p; 1529 p = NULL; 1530 } 1531 optptr = p; 1532 return c; 1533} 1534 1535 1536/* ============ Math support definitions */ 1537 1538#if ENABLE_ASH_MATH_SUPPORT_64 1539typedef int64_t arith_t; 1540#define arith_t_type long long 1541#else 1542typedef long arith_t; 1543#define arith_t_type long 1544#endif 1545 1546#if ENABLE_ASH_MATH_SUPPORT 1547static arith_t dash_arith(const char *); 1548static arith_t arith(const char *expr, int *perrcode); 1549#endif 1550 1551#if ENABLE_ASH_RANDOM_SUPPORT 1552static unsigned long rseed; 1553#ifndef DYNAMIC_VAR 1554#define DYNAMIC_VAR 1555#endif 1556#endif 1557 1558 1559/* ============ Shell variables */ 1560 1561/* flags */ 1562#define VEXPORT 0x01 /* variable is exported */ 1563#define VREADONLY 0x02 /* variable cannot be modified */ 1564#define VSTRFIXED 0x04 /* variable struct is statically allocated */ 1565#define VTEXTFIXED 0x08 /* text is statically allocated */ 1566#define VSTACK 0x10 /* text is allocated on the stack */ 1567#define VUNSET 0x20 /* the variable is not set */ 1568#define VNOFUNC 0x40 /* don't call the callback function */ 1569#define VNOSET 0x80 /* do not set variable - just readonly test */ 1570#define VNOSAVE 0x100 /* when text is on the heap before setvareq */ 1571#ifdef DYNAMIC_VAR 1572# define VDYNAMIC 0x200 /* dynamic variable */ 1573#else 1574# define VDYNAMIC 0 1575#endif 1576 1577#ifdef IFS_BROKEN 1578static const char defifsvar[] ALIGN1 = "IFS= \t\n"; 1579#define defifs (defifsvar + 4) 1580#else 1581static const char defifs[] ALIGN1 = " \t\n"; 1582#endif 1583 1584struct shparam { 1585 int nparam; /* # of positional parameters (without $0) */ 1586 unsigned char malloc; /* if parameter list dynamically allocated */ 1587 char **p; /* parameter list */ 1588#if ENABLE_ASH_GETOPTS 1589 int optind; /* next parameter to be processed by getopts */ 1590 int optoff; /* used by getopts */ 1591#endif 1592}; 1593 1594static struct shparam shellparam; /* $@ current positional parameters */ 1595 1596/* 1597 * Free the list of positional parameters. 1598 */ 1599static void 1600freeparam(volatile struct shparam *param) 1601{ 1602 char **ap; 1603 1604 if (param->malloc) { 1605 for (ap = param->p; *ap; ap++) 1606 free(*ap); 1607 free(param->p); 1608 } 1609} 1610 1611#if ENABLE_ASH_GETOPTS 1612static void 1613getoptsreset(const char *value) 1614{ 1615 shellparam.optind = number(value); 1616 shellparam.optoff = -1; 1617} 1618#endif 1619 1620struct var { 1621 struct var *next; /* next entry in hash list */ 1622 int flags; /* flags are defined above */ 1623 const char *text; /* name=value */ 1624 void (*func)(const char *); /* function to be called when */ 1625 /* the variable gets set/unset */ 1626}; 1627 1628struct localvar { 1629 struct localvar *next; /* next local variable in list */ 1630 struct var *vp; /* the variable that was made local */ 1631 int flags; /* saved flags */ 1632 const char *text; /* saved text */ 1633}; 1634 1635/* Forward decls for varinit[] */ 1636#if ENABLE_LOCALE_SUPPORT 1637static void 1638change_lc_all(const char *value) 1639{ 1640 if (value && *value != '\0') 1641 setlocale(LC_ALL, value); 1642} 1643static void 1644change_lc_ctype(const char *value) 1645{ 1646 if (value && *value != '\0') 1647 setlocale(LC_CTYPE, value); 1648} 1649#endif 1650#if ENABLE_ASH_MAIL 1651static void chkmail(void); 1652static void changemail(const char *); 1653#endif 1654static void changepath(const char *); 1655#if ENABLE_ASH_RANDOM_SUPPORT 1656static void change_random(const char *); 1657#endif 1658 1659static struct var varinit[] = { 1660#ifdef IFS_BROKEN 1661 { NULL, VSTRFIXED|VTEXTFIXED, defifsvar, NULL }, 1662#else 1663 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", NULL }, 1664#endif 1665#if ENABLE_ASH_MAIL 1666 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail }, 1667 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail }, 1668#endif 1669 { NULL, VSTRFIXED|VTEXTFIXED, bb_PATH_root_path, changepath }, 1670 { NULL, VSTRFIXED|VTEXTFIXED, "PS1=$ ", NULL }, 1671 { NULL, VSTRFIXED|VTEXTFIXED, "PS2=> ", NULL }, 1672 { NULL, VSTRFIXED|VTEXTFIXED, "PS4=+ ", NULL }, 1673#if ENABLE_ASH_GETOPTS 1674 { NULL, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset }, 1675#endif 1676#if ENABLE_ASH_RANDOM_SUPPORT 1677 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random }, 1678#endif 1679#if ENABLE_LOCALE_SUPPORT 1680 { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all }, 1681 { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype }, 1682#endif 1683#if ENABLE_FEATURE_EDITING_SAVEHISTORY 1684 { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL }, 1685#endif 1686}; 1687 1688#define vifs varinit[0] 1689#if ENABLE_ASH_MAIL 1690#define vmail (&vifs)[1] 1691#define vmpath (&vmail)[1] 1692#else 1693#define vmpath vifs 1694#endif 1695#define vpath (&vmpath)[1] 1696#define vps1 (&vpath)[1] 1697#define vps2 (&vps1)[1] 1698#define vps4 (&vps2)[1] 1699#define voptind (&vps4)[1] 1700#if ENABLE_ASH_GETOPTS 1701#define vrandom (&voptind)[1] 1702#else 1703#define vrandom (&vps4)[1] 1704#endif 1705 1706/* 1707 * The following macros access the values of the above variables. 1708 * They have to skip over the name. They return the null string 1709 * for unset variables. 1710 */ 1711#define ifsval() (vifs.text + 4) 1712#define ifsset() ((vifs.flags & VUNSET) == 0) 1713#define mailval() (vmail.text + 5) 1714#define mpathval() (vmpath.text + 9) 1715#define pathval() (vpath.text + 5) 1716#define ps1val() (vps1.text + 4) 1717#define ps2val() (vps2.text + 4) 1718#define ps4val() (vps4.text + 4) 1719#define optindval() (voptind.text + 7) 1720 1721#define mpathset() ((vmpath.flags & VUNSET) == 0) 1722 1723/* 1724 * The parsefile structure pointed to by the global variable parsefile 1725 * contains information about the current file being read. 1726 */ 1727struct redirtab { 1728 struct redirtab *next; 1729 int renamed[10]; 1730 int nullredirs; 1731}; 1732 1733static struct redirtab *redirlist; 1734static int nullredirs; 1735static int preverrout_fd; /* save fd2 before print debug if xflag is set. */ 1736 1737#define VTABSIZE 39 1738 1739static struct var *vartab[VTABSIZE]; 1740 1741#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) 1742#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) 1743 1744/* 1745 * Return of a legal variable name (a letter or underscore followed by zero or 1746 * more letters, underscores, and digits). 1747 */ 1748static char * 1749endofname(const char *name) 1750{ 1751 char *p; 1752 1753 p = (char *) name; 1754 if (!is_name(*p)) 1755 return p; 1756 while (*++p) { 1757 if (!is_in_name(*p)) 1758 break; 1759 } 1760 return p; 1761} 1762 1763/* 1764 * Compares two strings up to the first = or '\0'. The first 1765 * string must be terminated by '='; the second may be terminated by 1766 * either '=' or '\0'. 1767 */ 1768static int 1769varcmp(const char *p, const char *q) 1770{ 1771 int c, d; 1772 1773 while ((c = *p) == (d = *q)) { 1774 if (!c || c == '=') 1775 goto out; 1776 p++; 1777 q++; 1778 } 1779 if (c == '=') 1780 c = '\0'; 1781 if (d == '=') 1782 d = '\0'; 1783 out: 1784 return c - d; 1785} 1786 1787static int 1788varequal(const char *a, const char *b) 1789{ 1790 return !varcmp(a, b); 1791} 1792 1793/* 1794 * Find the appropriate entry in the hash table from the name. 1795 */ 1796static struct var ** 1797hashvar(const char *p) 1798{ 1799 unsigned hashval; 1800 1801 hashval = ((unsigned char) *p) << 4; 1802 while (*p && *p != '=') 1803 hashval += (unsigned char) *p++; 1804 return &vartab[hashval % VTABSIZE]; 1805} 1806 1807static int 1808vpcmp(const void *a, const void *b) 1809{ 1810 return varcmp(*(const char **)a, *(const char **)b); 1811} 1812 1813/* 1814 * This routine initializes the builtin variables. 1815 */ 1816static void 1817initvar(void) 1818{ 1819 struct var *vp; 1820 struct var *end; 1821 struct var **vpp; 1822 1823 /* 1824 * PS1 depends on uid 1825 */ 1826#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT 1827 vps1.text = "PS1=\\w \\$ "; 1828#else 1829 if (!geteuid()) 1830 vps1.text = "PS1=# "; 1831#endif 1832 vp = varinit; 1833 end = vp + ARRAY_SIZE(varinit); 1834 do { 1835 vpp = hashvar(vp->text); 1836 vp->next = *vpp; 1837 *vpp = vp; 1838 } while (++vp < end); 1839} 1840 1841static struct var ** 1842findvar(struct var **vpp, const char *name) 1843{ 1844 for (; *vpp; vpp = &(*vpp)->next) { 1845 if (varequal((*vpp)->text, name)) { 1846 break; 1847 } 1848 } 1849 return vpp; 1850} 1851 1852/* 1853 * Find the value of a variable. Returns NULL if not set. 1854 */ 1855static char * 1856lookupvar(const char *name) 1857{ 1858 struct var *v; 1859 1860 v = *findvar(hashvar(name), name); 1861 if (v) { 1862#ifdef DYNAMIC_VAR 1863 /* 1864 * Dynamic variables are implemented roughly the same way they are 1865 * in bash. Namely, they're "special" so long as they aren't unset. 1866 * As soon as they're unset, they're no longer dynamic, and dynamic 1867 * lookup will no longer happen at that point. -- PFM. 1868 */ 1869 if ((v->flags & VDYNAMIC)) 1870 (*v->func)(NULL); 1871#endif 1872 if (!(v->flags & VUNSET)) 1873 return strchrnul(v->text, '=') + 1; 1874 } 1875 return NULL; 1876} 1877 1878/* 1879 * Search the environment of a builtin command. 1880 */ 1881static char * 1882bltinlookup(const char *name) 1883{ 1884 struct strlist *sp; 1885 1886 for (sp = cmdenviron; sp; sp = sp->next) { 1887 if (varequal(sp->text, name)) 1888 return strchrnul(sp->text, '=') + 1; 1889 } 1890 return lookupvar(name); 1891} 1892 1893/* 1894 * Same as setvar except that the variable and value are passed in 1895 * the first argument as name=value. Since the first argument will 1896 * be actually stored in the table, it should not be a string that 1897 * will go away. 1898 * Called with interrupts off. 1899 */ 1900static void 1901setvareq(char *s, int flags) 1902{ 1903 struct var *vp, **vpp; 1904 1905 vpp = hashvar(s); 1906 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); 1907 vp = *findvar(vpp, s); 1908 if (vp) { 1909 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) { 1910 const char *n; 1911 1912 if (flags & VNOSAVE) 1913 free(s); 1914 n = vp->text; 1915 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n); 1916 } 1917 1918 if (flags & VNOSET) 1919 return; 1920 1921 if (vp->func && (flags & VNOFUNC) == 0) 1922 (*vp->func)(strchrnul(s, '=') + 1); 1923 1924 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) 1925 free((char*)vp->text); 1926 1927 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET); 1928 } else { 1929 if (flags & VNOSET) 1930 return; 1931 /* not found */ 1932 vp = ckmalloc(sizeof(*vp)); 1933 vp->next = *vpp; 1934 vp->func = NULL; 1935 *vpp = vp; 1936 } 1937 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE))) 1938 s = ckstrdup(s); 1939 vp->text = s; 1940 vp->flags = flags; 1941} 1942 1943/* 1944 * Set the value of a variable. The flags argument is ored with the 1945 * flags of the variable. If val is NULL, the variable is unset. 1946 */ 1947static void 1948setvar(const char *name, const char *val, int flags) 1949{ 1950 char *p, *q; 1951 size_t namelen; 1952 char *nameeq; 1953 size_t vallen; 1954 1955 q = endofname(name); 1956 p = strchrnul(q, '='); 1957 namelen = p - name; 1958 if (!namelen || p != q) 1959 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name); 1960 vallen = 0; 1961 if (val == NULL) { 1962 flags |= VUNSET; 1963 } else { 1964 vallen = strlen(val); 1965 } 1966 INT_OFF; 1967 nameeq = ckmalloc(namelen + vallen + 2); 1968 p = memcpy(nameeq, name, namelen) + namelen; 1969 if (val) { 1970 *p++ = '='; 1971 p = memcpy(p, val, vallen) + vallen; 1972 } 1973 *p = '\0'; 1974 setvareq(nameeq, flags | VNOSAVE); 1975 INT_ON; 1976} 1977 1978#if ENABLE_ASH_GETOPTS 1979/* 1980 * Safe version of setvar, returns 1 on success 0 on failure. 1981 */ 1982static int 1983setvarsafe(const char *name, const char *val, int flags) 1984{ 1985 int err; 1986 volatile int saveint; 1987 struct jmploc *volatile savehandler = exception_handler; 1988 struct jmploc jmploc; 1989 1990 SAVE_INT(saveint); 1991 if (setjmp(jmploc.loc)) 1992 err = 1; 1993 else { 1994 exception_handler = &jmploc; 1995 setvar(name, val, flags); 1996 err = 0; 1997 } 1998 exception_handler = savehandler; 1999 RESTORE_INT(saveint); 2000 return err; 2001} 2002#endif 2003 2004/* 2005 * Unset the specified variable. 2006 */ 2007static int 2008unsetvar(const char *s) 2009{ 2010 struct var **vpp; 2011 struct var *vp; 2012 int retval; 2013 2014 vpp = findvar(hashvar(s), s); 2015 vp = *vpp; 2016 retval = 2; 2017 if (vp) { 2018 int flags = vp->flags; 2019 2020 retval = 1; 2021 if (flags & VREADONLY) 2022 goto out; 2023#ifdef DYNAMIC_VAR 2024 vp->flags &= ~VDYNAMIC; 2025#endif 2026 if (flags & VUNSET) 2027 goto ok; 2028 if ((flags & VSTRFIXED) == 0) { 2029 INT_OFF; 2030 if ((flags & (VTEXTFIXED|VSTACK)) == 0) 2031 free((char*)vp->text); 2032 *vpp = vp->next; 2033 free(vp); 2034 INT_ON; 2035 } else { 2036 setvar(s, 0, 0); 2037 vp->flags &= ~VEXPORT; 2038 } 2039 ok: 2040 retval = 0; 2041 } 2042 out: 2043 return retval; 2044} 2045 2046/* 2047 * Process a linked list of variable assignments. 2048 */ 2049static void 2050listsetvar(struct strlist *list_set_var, int flags) 2051{ 2052 struct strlist *lp = list_set_var; 2053 2054 if (!lp) 2055 return; 2056 INT_OFF; 2057 do { 2058 setvareq(lp->text, flags); 2059 lp = lp->next; 2060 } while (lp); 2061 INT_ON; 2062} 2063 2064/* 2065 * Generate a list of variables satisfying the given conditions. 2066 */ 2067static char ** 2068listvars(int on, int off, char ***end) 2069{ 2070 struct var **vpp; 2071 struct var *vp; 2072 char **ep; 2073 int mask; 2074 2075 STARTSTACKSTR(ep); 2076 vpp = vartab; 2077 mask = on | off; 2078 do { 2079 for (vp = *vpp; vp; vp = vp->next) { 2080 if ((vp->flags & mask) == on) { 2081 if (ep == stackstrend()) 2082 ep = growstackstr(); 2083 *ep++ = (char *) vp->text; 2084 } 2085 } 2086 } while (++vpp < vartab + VTABSIZE); 2087 if (ep == stackstrend()) 2088 ep = growstackstr(); 2089 if (end) 2090 *end = ep; 2091 *ep++ = NULL; 2092 return grabstackstr(ep); 2093} 2094 2095 2096/* ============ Path search helper 2097 * 2098 * The variable path (passed by reference) should be set to the start 2099 * of the path before the first call; padvance will update 2100 * this value as it proceeds. Successive calls to padvance will return 2101 * the possible path expansions in sequence. If an option (indicated by 2102 * a percent sign) appears in the path entry then the global variable 2103 * pathopt will be set to point to it; otherwise pathopt will be set to 2104 * NULL. 2105 */ 2106static const char *pathopt; /* set by padvance */ 2107 2108static char * 2109padvance(const char **path, const char *name) 2110{ 2111 const char *p; 2112 char *q; 2113 const char *start; 2114 size_t len; 2115 2116 if (*path == NULL) 2117 return NULL; 2118 start = *path; 2119 for (p = start; *p && *p != ':' && *p != '%'; p++); 2120 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 2121 while (stackblocksize() < len) 2122 growstackblock(); 2123 q = stackblock(); 2124 if (p != start) { 2125 memcpy(q, start, p - start); 2126 q += p - start; 2127 *q++ = '/'; 2128 } 2129 strcpy(q, name); 2130 pathopt = NULL; 2131 if (*p == '%') { 2132 pathopt = ++p; 2133 while (*p && *p != ':') p++; 2134 } 2135 if (*p == ':') 2136 *path = p + 1; 2137 else 2138 *path = NULL; 2139 return stalloc(len); 2140} 2141 2142 2143/* ============ Prompt */ 2144 2145static int doprompt; /* if set, prompt the user */ 2146static int needprompt; /* true if interactive and at start of line */ 2147 2148#if ENABLE_FEATURE_EDITING 2149static line_input_t *line_input_state; 2150static const char *cmdedit_prompt; 2151static void 2152putprompt(const char *s) 2153{ 2154 if (ENABLE_ASH_EXPAND_PRMT) { 2155 free((char*)cmdedit_prompt); 2156 cmdedit_prompt = ckstrdup(s); 2157 return; 2158 } 2159 cmdedit_prompt = s; 2160} 2161#else 2162static void 2163putprompt(const char *s) 2164{ 2165 out2str(s); 2166} 2167#endif 2168 2169#if ENABLE_ASH_EXPAND_PRMT 2170/* expandstr() needs parsing machinery, so it is far away ahead... */ 2171static const char *expandstr(const char *ps); 2172#else 2173#define expandstr(s) s 2174#endif 2175 2176static void 2177setprompt(int whichprompt) 2178{ 2179 const char *prompt; 2180#if ENABLE_ASH_EXPAND_PRMT 2181 struct stackmark smark; 2182#endif 2183 2184 needprompt = 0; 2185 2186 switch (whichprompt) { 2187 case 1: 2188 prompt = ps1val(); 2189 break; 2190 case 2: 2191 prompt = ps2val(); 2192 break; 2193 default: /* 0 */ 2194 prompt = nullstr; 2195 } 2196#if ENABLE_ASH_EXPAND_PRMT 2197 setstackmark(&smark); 2198 stalloc(stackblocksize()); 2199#endif 2200 putprompt(expandstr(prompt)); 2201#if ENABLE_ASH_EXPAND_PRMT 2202 popstackmark(&smark); 2203#endif 2204} 2205 2206 2207/* ============ The cd and pwd commands */ 2208 2209#define CD_PHYSICAL 1 2210#define CD_PRINT 2 2211 2212static int docd(const char *, int); 2213 2214static char *curdir = nullstr; /* current working directory */ 2215static char *physdir = nullstr; /* physical working directory */ 2216 2217static int 2218cdopt(void) 2219{ 2220 int flags = 0; 2221 int i, j; 2222 2223 j = 'L'; 2224 while ((i = nextopt("LP"))) { 2225 if (i != j) { 2226 flags ^= CD_PHYSICAL; 2227 j = i; 2228 } 2229 } 2230 2231 return flags; 2232} 2233 2234/* 2235 * Update curdir (the name of the current directory) in response to a 2236 * cd command. 2237 */ 2238static const char * 2239updatepwd(const char *dir) 2240{ 2241 char *new; 2242 char *p; 2243 char *cdcomppath; 2244 const char *lim; 2245 2246 cdcomppath = ststrdup(dir); 2247 STARTSTACKSTR(new); 2248 if (*dir != '/') { 2249 if (curdir == nullstr) 2250 return 0; 2251 new = stack_putstr(curdir, new); 2252 } 2253 new = makestrspace(strlen(dir) + 2, new); 2254 lim = stackblock() + 1; 2255 if (*dir != '/') { 2256 if (new[-1] != '/') 2257 USTPUTC('/', new); 2258 if (new > lim && *lim == '/') 2259 lim++; 2260 } else { 2261 USTPUTC('/', new); 2262 cdcomppath++; 2263 if (dir[1] == '/' && dir[2] != '/') { 2264 USTPUTC('/', new); 2265 cdcomppath++; 2266 lim++; 2267 } 2268 } 2269 p = strtok(cdcomppath, "/"); 2270 while (p) { 2271 switch (*p) { 2272 case '.': 2273 if (p[1] == '.' && p[2] == '\0') { 2274 while (new > lim) { 2275 STUNPUTC(new); 2276 if (new[-1] == '/') 2277 break; 2278 } 2279 break; 2280 } 2281 if (p[1] == '\0') 2282 break; 2283 /* fall through */ 2284 default: 2285 new = stack_putstr(p, new); 2286 USTPUTC('/', new); 2287 } 2288 p = strtok(0, "/"); 2289 } 2290 if (new > lim) 2291 STUNPUTC(new); 2292 *new = 0; 2293 return stackblock(); 2294} 2295 2296/* 2297 * Find out what the current directory is. If we already know the current 2298 * directory, this routine returns immediately. 2299 */ 2300static char * 2301getpwd(void) 2302{ 2303 char *dir = getcwd(0, 0); 2304 return dir ? dir : nullstr; 2305} 2306 2307static void 2308setpwd(const char *val, int setold) 2309{ 2310 char *oldcur, *dir; 2311 2312 oldcur = dir = curdir; 2313 2314 if (setold) { 2315 setvar("OLDPWD", oldcur, VEXPORT); 2316 } 2317 INT_OFF; 2318 if (physdir != nullstr) { 2319 if (physdir != oldcur) 2320 free(physdir); 2321 physdir = nullstr; 2322 } 2323 if (oldcur == val || !val) { 2324 char *s = getpwd(); 2325 physdir = s; 2326 if (!val) 2327 dir = s; 2328 } else 2329 dir = ckstrdup(val); 2330 if (oldcur != dir && oldcur != nullstr) { 2331 free(oldcur); 2332 } 2333 curdir = dir; 2334 INT_ON; 2335 setvar("PWD", dir, VEXPORT); 2336} 2337 2338static void hashcd(void); 2339 2340/* 2341 * Actually do the chdir. We also call hashcd to let the routines in exec.c 2342 * know that the current directory has changed. 2343 */ 2344static int 2345docd(const char *dest, int flags) 2346{ 2347 const char *dir = 0; 2348 int err; 2349 2350 TRACE(("docd(\"%s\", %d) called\n", dest, flags)); 2351 2352 INT_OFF; 2353 if (!(flags & CD_PHYSICAL)) { 2354 dir = updatepwd(dest); 2355 if (dir) 2356 dest = dir; 2357 } 2358 err = chdir(dest); 2359 if (err) 2360 goto out; 2361 setpwd(dir, 1); 2362 hashcd(); 2363 out: 2364 INT_ON; 2365 return err; 2366} 2367 2368static int 2369cdcmd(int argc, char **argv) 2370{ 2371 const char *dest; 2372 const char *path; 2373 const char *p; 2374 char c; 2375 struct stat statb; 2376 int flags; 2377 2378 flags = cdopt(); 2379 dest = *argptr; 2380 if (!dest) 2381 dest = bltinlookup(homestr); 2382 else if (LONE_DASH(dest)) { 2383 dest = bltinlookup("OLDPWD"); 2384 flags |= CD_PRINT; 2385 } 2386 if (!dest) 2387 dest = nullstr; 2388 if (*dest == '/') 2389 goto step7; 2390 if (*dest == '.') { 2391 c = dest[1]; 2392 dotdot: 2393 switch (c) { 2394 case '\0': 2395 case '/': 2396 goto step6; 2397 case '.': 2398 c = dest[2]; 2399 if (c != '.') 2400 goto dotdot; 2401 } 2402 } 2403 if (!*dest) 2404 dest = "."; 2405 path = bltinlookup("CDPATH"); 2406 if (!path) { 2407 step6: 2408 step7: 2409 p = dest; 2410 goto docd; 2411 } 2412 do { 2413 c = *path; 2414 p = padvance(&path, dest); 2415 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { 2416 if (c && c != ':') 2417 flags |= CD_PRINT; 2418 docd: 2419 if (!docd(p, flags)) 2420 goto out; 2421 break; 2422 } 2423 } while (path); 2424 ash_msg_and_raise_error("can't cd to %s", dest); 2425 /* NOTREACHED */ 2426 out: 2427 if (flags & CD_PRINT) 2428 out1fmt(snlfmt, curdir); 2429 return 0; 2430} 2431 2432static int 2433pwdcmd(int argc, char **argv) 2434{ 2435 int flags; 2436 const char *dir = curdir; 2437 2438 flags = cdopt(); 2439 if (flags) { 2440 if (physdir == nullstr) 2441 setpwd(dir, 0); 2442 dir = physdir; 2443 } 2444 out1fmt(snlfmt, dir); 2445 return 0; 2446} 2447 2448 2449/* ============ ... */ 2450 2451#define IBUFSIZ (BUFSIZ + 1) 2452#define basebuf bb_common_bufsiz1 /* buffer for top level input file */ 2453 2454/* Syntax classes */ 2455#define CWORD 0 /* character is nothing special */ 2456#define CNL 1 /* newline character */ 2457#define CBACK 2 /* a backslash character */ 2458#define CSQUOTE 3 /* single quote */ 2459#define CDQUOTE 4 /* double quote */ 2460#define CENDQUOTE 5 /* a terminating quote */ 2461#define CBQUOTE 6 /* backwards single quote */ 2462#define CVAR 7 /* a dollar sign */ 2463#define CENDVAR 8 /* a '}' character */ 2464#define CLP 9 /* a left paren in arithmetic */ 2465#define CRP 10 /* a right paren in arithmetic */ 2466#define CENDFILE 11 /* end of file */ 2467#define CCTL 12 /* like CWORD, except it must be escaped */ 2468#define CSPCL 13 /* these terminate a word */ 2469#define CIGN 14 /* character should be ignored */ 2470 2471#if ENABLE_ASH_ALIAS 2472#define SYNBASE 130 2473#define PEOF -130 2474#define PEOA -129 2475#define PEOA_OR_PEOF PEOA 2476#else 2477#define SYNBASE 129 2478#define PEOF -129 2479#define PEOA_OR_PEOF PEOF 2480#endif 2481 2482/* number syntax index */ 2483#define BASESYNTAX 0 /* not in quotes */ 2484#define DQSYNTAX 1 /* in double quotes */ 2485#define SQSYNTAX 2 /* in single quotes */ 2486#define ARISYNTAX 3 /* in arithmetic */ 2487 2488#if ENABLE_ASH_OPTIMIZE_FOR_SIZE 2489#define USE_SIT_FUNCTION 2490#endif 2491 2492#if ENABLE_ASH_MATH_SUPPORT 2493static const char S_I_T[][4] = { 2494#if ENABLE_ASH_ALIAS 2495 { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */ 2496#endif 2497 { CSPCL, CWORD, CWORD, CWORD }, /* 1, ' ' */ 2498 { CNL, CNL, CNL, CNL }, /* 2, \n */ 2499 { CWORD, CCTL, CCTL, CWORD }, /* 3, !*-/:=?[]~ */ 2500 { CDQUOTE, CENDQUOTE, CWORD, CWORD }, /* 4, '"' */ 2501 { CVAR, CVAR, CWORD, CVAR }, /* 5, $ */ 2502 { CSQUOTE, CWORD, CENDQUOTE, CWORD }, /* 6, "'" */ 2503 { CSPCL, CWORD, CWORD, CLP }, /* 7, ( */ 2504 { CSPCL, CWORD, CWORD, CRP }, /* 8, ) */ 2505 { CBACK, CBACK, CCTL, CBACK }, /* 9, \ */ 2506 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* 10, ` */ 2507 { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* 11, } */ 2508#ifndef USE_SIT_FUNCTION 2509 { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */ 2510 { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */ 2511 { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */ 2512#endif 2513}; 2514#else 2515static const char S_I_T[][3] = { 2516#if ENABLE_ASH_ALIAS 2517 { CSPCL, CIGN, CIGN }, /* 0, PEOA */ 2518#endif 2519 { CSPCL, CWORD, CWORD }, /* 1, ' ' */ 2520 { CNL, CNL, CNL }, /* 2, \n */ 2521 { CWORD, CCTL, CCTL }, /* 3, !*-/:=?[]~ */ 2522 { CDQUOTE, CENDQUOTE, CWORD }, /* 4, '"' */ 2523 { CVAR, CVAR, CWORD }, /* 5, $ */ 2524 { CSQUOTE, CWORD, CENDQUOTE }, /* 6, "'" */ 2525 { CSPCL, CWORD, CWORD }, /* 7, ( */ 2526 { CSPCL, CWORD, CWORD }, /* 8, ) */ 2527 { CBACK, CBACK, CCTL }, /* 9, \ */ 2528 { CBQUOTE, CBQUOTE, CWORD }, /* 10, ` */ 2529 { CENDVAR, CENDVAR, CWORD }, /* 11, } */ 2530#ifndef USE_SIT_FUNCTION 2531 { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */ 2532 { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */ 2533 { CCTL, CCTL, CCTL } /* 14, CTLESC ... */ 2534#endif 2535}; 2536#endif /* ASH_MATH_SUPPORT */ 2537 2538#ifdef USE_SIT_FUNCTION 2539 2540static int 2541SIT(int c, int syntax) 2542{ 2543 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~"; 2544#if ENABLE_ASH_ALIAS 2545 static const char syntax_index_table[] ALIGN1 = { 2546 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */ 2547 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */ 2548 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */ 2549 11, 3 /* "}~" */ 2550 }; 2551#else 2552 static const char syntax_index_table[] ALIGN1 = { 2553 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */ 2554 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */ 2555 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */ 2556 10, 2 /* "}~" */ 2557 }; 2558#endif 2559 const char *s; 2560 int indx; 2561 2562 if (c == PEOF) /* 2^8+2 */ 2563 return CENDFILE; 2564#if ENABLE_ASH_ALIAS 2565 if (c == PEOA) /* 2^8+1 */ 2566 indx = 0; 2567 else 2568#endif 2569#define U_C(c) ((unsigned char)(c)) 2570 2571 if ((unsigned char)c >= (unsigned char)(CTLESC) 2572 && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK) 2573 ) { 2574 return CCTL; 2575 } else { 2576 s = strchr(spec_symbls, c); 2577 if (s == NULL || *s == '\0') 2578 return CWORD; 2579 indx = syntax_index_table[(s - spec_symbls)]; 2580 } 2581 return S_I_T[indx][syntax]; 2582} 2583 2584#else /* !USE_SIT_FUNCTION */ 2585 2586#if ENABLE_ASH_ALIAS 2587#define CSPCL_CIGN_CIGN_CIGN 0 2588#define CSPCL_CWORD_CWORD_CWORD 1 2589#define CNL_CNL_CNL_CNL 2 2590#define CWORD_CCTL_CCTL_CWORD 3 2591#define CDQUOTE_CENDQUOTE_CWORD_CWORD 4 2592#define CVAR_CVAR_CWORD_CVAR 5 2593#define CSQUOTE_CWORD_CENDQUOTE_CWORD 6 2594#define CSPCL_CWORD_CWORD_CLP 7 2595#define CSPCL_CWORD_CWORD_CRP 8 2596#define CBACK_CBACK_CCTL_CBACK 9 2597#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10 2598#define CENDVAR_CENDVAR_CWORD_CENDVAR 11 2599#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12 2600#define CWORD_CWORD_CWORD_CWORD 13 2601#define CCTL_CCTL_CCTL_CCTL 14 2602#else 2603#define CSPCL_CWORD_CWORD_CWORD 0 2604#define CNL_CNL_CNL_CNL 1 2605#define CWORD_CCTL_CCTL_CWORD 2 2606#define CDQUOTE_CENDQUOTE_CWORD_CWORD 3 2607#define CVAR_CVAR_CWORD_CVAR 4 2608#define CSQUOTE_CWORD_CENDQUOTE_CWORD 5 2609#define CSPCL_CWORD_CWORD_CLP 6 2610#define CSPCL_CWORD_CWORD_CRP 7 2611#define CBACK_CBACK_CCTL_CBACK 8 2612#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9 2613#define CENDVAR_CENDVAR_CWORD_CENDVAR 10 2614#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11 2615#define CWORD_CWORD_CWORD_CWORD 12 2616#define CCTL_CCTL_CCTL_CCTL 13 2617#endif 2618 2619static const char syntax_index_table[258] = { 2620 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */ 2621 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE, 2622#if ENABLE_ASH_ALIAS 2623 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN, 2624#endif 2625 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD, 2626 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL, 2627 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL, 2628 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL, 2629 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL, 2630 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL, 2631 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL, 2632 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL, 2633 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL, 2634 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD, 2635 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD, 2636 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD, 2637 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD, 2638 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD, 2639 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD, 2640 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD, 2641 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD, 2642 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD, 2643 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD, 2644 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD, 2645 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD, 2646 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD, 2647 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD, 2648 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD, 2649 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD, 2650 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD, 2651 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD, 2652 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD, 2653 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD, 2654 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD, 2655 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD, 2656 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD, 2657 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD, 2658 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD, 2659 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD, 2660 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD, 2661 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD, 2662 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD, 2663 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD, 2664 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD, 2665 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD, 2666 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD, 2667 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD, 2668 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD, 2669 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD, 2670 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD, 2671 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD, 2672 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD, 2673 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD, 2674 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD, 2675 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD, 2676 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD, 2677 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD, 2678 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD, 2679 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD, 2680 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD, 2681 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD, 2682 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD, 2683 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD, 2684 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD, 2685 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD, 2686 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD, 2687 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD, 2688 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD, 2689 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD, 2690 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD, 2691 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD, 2692 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD, 2693 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD, 2694 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD, 2695 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD, 2696 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD, 2697 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD, 2698 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD, 2699 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD, 2700 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD, 2701 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD, 2702 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD, 2703 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD, 2704 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD, 2705 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD, 2706 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD, 2707 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD, 2708 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD, 2709 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD, 2710 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD, 2711 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD, 2712 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD, 2713 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD, 2714 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD, 2715 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD, 2716 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD, 2717 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD, 2718 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD, 2719 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD, 2720 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD, 2721 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD, 2722 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD, 2723 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD, 2724 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD, 2725 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD, 2726 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD, 2727 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD, 2728 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD, 2729 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD, 2730 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD, 2731 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD, 2732 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD, 2733 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD, 2734 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD, 2735 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD, 2736 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD, 2737 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD, 2738 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD, 2739 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD, 2740 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD, 2741 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD, 2742 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD, 2743 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD, 2744 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD, 2745 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD, 2746 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD, 2747 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD, 2748 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD, 2749 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD, 2750 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD, 2751 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD, 2752 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD, 2753 /* 130 0 */ CWORD_CWORD_CWORD_CWORD, 2754 /* 131 1 */ CWORD_CWORD_CWORD_CWORD, 2755 /* 132 2 */ CWORD_CWORD_CWORD_CWORD, 2756 /* 133 3 */ CWORD_CWORD_CWORD_CWORD, 2757 /* 134 4 */ CWORD_CWORD_CWORD_CWORD, 2758 /* 135 5 */ CWORD_CWORD_CWORD_CWORD, 2759 /* 136 6 */ CWORD_CWORD_CWORD_CWORD, 2760 /* 137 7 */ CWORD_CWORD_CWORD_CWORD, 2761 /* 138 8 */ CWORD_CWORD_CWORD_CWORD, 2762 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD, 2763 /* 140 10 "\n" */ CNL_CNL_CNL_CNL, 2764 /* 141 11 */ CWORD_CWORD_CWORD_CWORD, 2765 /* 142 12 */ CWORD_CWORD_CWORD_CWORD, 2766 /* 143 13 */ CWORD_CWORD_CWORD_CWORD, 2767 /* 144 14 */ CWORD_CWORD_CWORD_CWORD, 2768 /* 145 15 */ CWORD_CWORD_CWORD_CWORD, 2769 /* 146 16 */ CWORD_CWORD_CWORD_CWORD, 2770 /* 147 17 */ CWORD_CWORD_CWORD_CWORD, 2771 /* 148 18 */ CWORD_CWORD_CWORD_CWORD, 2772 /* 149 19 */ CWORD_CWORD_CWORD_CWORD, 2773 /* 150 20 */ CWORD_CWORD_CWORD_CWORD, 2774 /* 151 21 */ CWORD_CWORD_CWORD_CWORD, 2775 /* 152 22 */ CWORD_CWORD_CWORD_CWORD, 2776 /* 153 23 */ CWORD_CWORD_CWORD_CWORD, 2777 /* 154 24 */ CWORD_CWORD_CWORD_CWORD, 2778 /* 155 25 */ CWORD_CWORD_CWORD_CWORD, 2779 /* 156 26 */ CWORD_CWORD_CWORD_CWORD, 2780 /* 157 27 */ CWORD_CWORD_CWORD_CWORD, 2781 /* 158 28 */ CWORD_CWORD_CWORD_CWORD, 2782 /* 159 29 */ CWORD_CWORD_CWORD_CWORD, 2783 /* 160 30 */ CWORD_CWORD_CWORD_CWORD, 2784 /* 161 31 */ CWORD_CWORD_CWORD_CWORD, 2785 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD, 2786 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD, 2787 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD, 2788 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD, 2789 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR, 2790 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD, 2791 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD, 2792 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD, 2793 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP, 2794 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP, 2795 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD, 2796 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD, 2797 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD, 2798 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD, 2799 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD, 2800 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD, 2801 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD, 2802 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD, 2803 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD, 2804 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD, 2805 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD, 2806 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD, 2807 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD, 2808 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD, 2809 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD, 2810 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD, 2811 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD, 2812 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD, 2813 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD, 2814 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD, 2815 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD, 2816 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD, 2817 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD, 2818 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD, 2819 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD, 2820 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD, 2821 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD, 2822 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD, 2823 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD, 2824 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD, 2825 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD, 2826 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD, 2827 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD, 2828 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD, 2829 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD, 2830 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD, 2831 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD, 2832 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD, 2833 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD, 2834 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD, 2835 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD, 2836 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD, 2837 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD, 2838 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD, 2839 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD, 2840 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD, 2841 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD, 2842 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD, 2843 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD, 2844 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD, 2845 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK, 2846 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD, 2847 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD, 2848 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD, 2849 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE, 2850 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD, 2851 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD, 2852 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD, 2853 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD, 2854 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD, 2855 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD, 2856 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD, 2857 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD, 2858 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD, 2859 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD, 2860 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD, 2861 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD, 2862 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD, 2863 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD, 2864 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD, 2865 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD, 2866 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD, 2867 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD, 2868 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD, 2869 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD, 2870 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD, 2871 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD, 2872 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD, 2873 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD, 2874 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD, 2875 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD, 2876 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD, 2877 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD, 2878 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR, 2879 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD, 2880 /* 257 127 */ CWORD_CWORD_CWORD_CWORD, 2881}; 2882 2883#define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]) 2884 2885#endif /* USE_SIT_FUNCTION */ 2886 2887 2888/* ============ Alias handling */ 2889 2890#if ENABLE_ASH_ALIAS 2891 2892#define ALIASINUSE 1 2893#define ALIASDEAD 2 2894 2895#define ATABSIZE 39 2896 2897struct alias { 2898 struct alias *next; 2899 char *name; 2900 char *val; 2901 int flag; 2902}; 2903 2904static struct alias *atab[ATABSIZE]; 2905 2906static struct alias ** 2907__lookupalias(const char *name) { 2908 unsigned int hashval; 2909 struct alias **app; 2910 const char *p; 2911 unsigned int ch; 2912 2913 p = name; 2914 2915 ch = (unsigned char)*p; 2916 hashval = ch << 4; 2917 while (ch) { 2918 hashval += ch; 2919 ch = (unsigned char)*++p; 2920 } 2921 app = &atab[hashval % ATABSIZE]; 2922 2923 for (; *app; app = &(*app)->next) { 2924 if (strcmp(name, (*app)->name) == 0) { 2925 break; 2926 } 2927 } 2928 2929 return app; 2930} 2931 2932static struct alias * 2933lookupalias(const char *name, int check) 2934{ 2935 struct alias *ap = *__lookupalias(name); 2936 2937 if (check && ap && (ap->flag & ALIASINUSE)) 2938 return NULL; 2939 return ap; 2940} 2941 2942static struct alias * 2943freealias(struct alias *ap) 2944{ 2945 struct alias *next; 2946 2947 if (ap->flag & ALIASINUSE) { 2948 ap->flag |= ALIASDEAD; 2949 return ap; 2950 } 2951 2952 next = ap->next; 2953 free(ap->name); 2954 free(ap->val); 2955 free(ap); 2956 return next; 2957} 2958 2959static void 2960setalias(const char *name, const char *val) 2961{ 2962 struct alias *ap, **app; 2963 2964 app = __lookupalias(name); 2965 ap = *app; 2966 INT_OFF; 2967 if (ap) { 2968 if (!(ap->flag & ALIASINUSE)) { 2969 free(ap->val); 2970 } 2971 ap->val = ckstrdup(val); 2972 ap->flag &= ~ALIASDEAD; 2973 } else { 2974 /* not found */ 2975 ap = ckmalloc(sizeof(struct alias)); 2976 ap->name = ckstrdup(name); 2977 ap->val = ckstrdup(val); 2978 ap->flag = 0; 2979 ap->next = 0; 2980 *app = ap; 2981 } 2982 INT_ON; 2983} 2984 2985static int 2986unalias(const char *name) 2987{ 2988 struct alias **app; 2989 2990 app = __lookupalias(name); 2991 2992 if (*app) { 2993 INT_OFF; 2994 *app = freealias(*app); 2995 INT_ON; 2996 return 0; 2997 } 2998 2999 return 1; 3000} 3001 3002static void 3003rmaliases(void) 3004{ 3005 struct alias *ap, **app; 3006 int i; 3007 3008 INT_OFF; 3009 for (i = 0; i < ATABSIZE; i++) { 3010 app = &atab[i]; 3011 for (ap = *app; ap; ap = *app) { 3012 *app = freealias(*app); 3013 if (ap == *app) { 3014 app = &ap->next; 3015 } 3016 } 3017 } 3018 INT_ON; 3019} 3020 3021static void 3022printalias(const struct alias *ap) 3023{ 3024 out1fmt("%s=%s\n", ap->name, single_quote(ap->val)); 3025} 3026 3027/* 3028 * TODO - sort output 3029 */ 3030static int 3031aliascmd(int argc, char **argv) 3032{ 3033 char *n, *v; 3034 int ret = 0; 3035 struct alias *ap; 3036 3037 if (argc == 1) { 3038 int i; 3039 3040 for (i = 0; i < ATABSIZE; i++) 3041 for (ap = atab[i]; ap; ap = ap->next) { 3042 printalias(ap); 3043 } 3044 return 0; 3045 } 3046 while ((n = *++argv) != NULL) { 3047 v = strchr(n+1, '='); 3048 if (v == NULL) { /* n+1: funny ksh stuff */ 3049 ap = *__lookupalias(n); 3050 if (ap == NULL) { 3051 fprintf(stderr, "%s: %s not found\n", "alias", n); 3052 ret = 1; 3053 } else 3054 printalias(ap); 3055 } else { 3056 *v++ = '\0'; 3057 setalias(n, v); 3058 } 3059 } 3060 3061 return ret; 3062} 3063 3064static int 3065unaliascmd(int argc, char **argv) 3066{ 3067 int i; 3068 3069 while ((i = nextopt("a")) != '\0') { 3070 if (i == 'a') { 3071 rmaliases(); 3072 return 0; 3073 } 3074 } 3075 for (i = 0; *argptr; argptr++) { 3076 if (unalias(*argptr)) { 3077 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr); 3078 i = 1; 3079 } 3080 } 3081 3082 return i; 3083} 3084 3085#endif /* ASH_ALIAS */ 3086 3087 3088/* ============ jobs.c */ 3089 3090/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ 3091#define FORK_FG 0 3092#define FORK_BG 1 3093#define FORK_NOJOB 2 3094 3095/* mode flags for showjob(s) */ 3096#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */ 3097#define SHOW_PID 0x04 /* include process pid */ 3098#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */ 3099 3100/* 3101 * A job structure contains information about a job. A job is either a 3102 * single process or a set of processes contained in a pipeline. In the 3103 * latter case, pidlist will be non-NULL, and will point to a -1 terminated 3104 * array of pids. 3105 */ 3106 3107struct procstat { 3108 pid_t pid; /* process id */ 3109 int status; /* last process status from wait() */ 3110 char *cmd; /* text of command being run */ 3111}; 3112 3113struct job { 3114 struct procstat ps0; /* status of process */ 3115 struct procstat *ps; /* status or processes when more than one */ 3116#if JOBS 3117 int stopstatus; /* status of a stopped job */ 3118#endif 3119 uint32_t 3120 nprocs: 16, /* number of processes */ 3121 state: 8, 3122#define JOBRUNNING 0 /* at least one proc running */ 3123#define JOBSTOPPED 1 /* all procs are stopped */ 3124#define JOBDONE 2 /* all procs are completed */ 3125#if JOBS 3126 sigint: 1, /* job was killed by SIGINT */ 3127 jobctl: 1, /* job running under job control */ 3128#endif 3129 waited: 1, /* true if this entry has been waited for */ 3130 used: 1, /* true if this entry is in used */ 3131 changed: 1; /* true if status has changed */ 3132 struct job *prev_job; /* previous job */ 3133}; 3134 3135static pid_t backgndpid; /* pid of last background process */ 3136static smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ 3137 3138static struct job *makejob(union node *, int); 3139static int forkshell(struct job *, union node *, int); 3140static int waitforjob(struct job *); 3141 3142#if !JOBS 3143enum { jobctl = 0 }; 3144#define setjobctl(on) do {} while (0) 3145#else 3146static smallint jobctl; /* true if doing job control */ 3147static void setjobctl(int); 3148#endif 3149 3150/* 3151 * Set the signal handler for the specified signal. The routine figures 3152 * out what it should be set to. 3153 */ 3154static void 3155setsignal(int signo) 3156{ 3157 int action; 3158 char *t, tsig; 3159 struct sigaction act; 3160 3161 t = trap[signo]; 3162 if (t == NULL) 3163 action = S_DFL; 3164 else if (*t != '\0') 3165 action = S_CATCH; 3166 else 3167 action = S_IGN; 3168 if (rootshell && action == S_DFL) { 3169 switch (signo) { 3170 case SIGINT: 3171 if (iflag || minusc || sflag == 0) 3172 action = S_CATCH; 3173 break; 3174 case SIGQUIT: 3175#if DEBUG 3176 if (debug) 3177 break; 3178#endif 3179 /* FALLTHROUGH */ 3180 case SIGTERM: 3181 if (iflag) 3182 action = S_IGN; 3183 break; 3184#if JOBS 3185 case SIGTSTP: 3186 case SIGTTOU: 3187 if (mflag) 3188 action = S_IGN; 3189 break; 3190#endif 3191 } 3192 } 3193 3194 t = &sigmode[signo - 1]; 3195 tsig = *t; 3196 if (tsig == 0) { 3197 /* 3198 * current setting unknown 3199 */ 3200 if (sigaction(signo, 0, &act) == -1) { 3201 /* 3202 * Pretend it worked; maybe we should give a warning 3203 * here, but other shells don't. We don't alter 3204 * sigmode, so that we retry every time. 3205 */ 3206 return; 3207 } 3208 if (act.sa_handler == SIG_IGN) { 3209 if (mflag 3210 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU) 3211 ) { 3212 tsig = S_IGN; /* don't hard ignore these */ 3213 } else 3214 tsig = S_HARD_IGN; 3215 } else { 3216 tsig = S_RESET; /* force to be set */ 3217 } 3218 } 3219 if (tsig == S_HARD_IGN || tsig == action) 3220 return; 3221 switch (action) { 3222 case S_CATCH: 3223 act.sa_handler = onsig; 3224 break; 3225 case S_IGN: 3226 act.sa_handler = SIG_IGN; 3227 break; 3228 default: 3229 act.sa_handler = SIG_DFL; 3230 } 3231 *t = action; 3232 act.sa_flags = 0; 3233 sigfillset(&act.sa_mask); 3234 sigaction(signo, &act, 0); 3235} 3236 3237/* mode flags for set_curjob */ 3238#define CUR_DELETE 2 3239#define CUR_RUNNING 1 3240#define CUR_STOPPED 0 3241 3242/* mode flags for dowait */ 3243#define DOWAIT_NORMAL 0 3244#define DOWAIT_BLOCK 1 3245 3246#if JOBS 3247/* pgrp of shell on invocation */ 3248static int initialpgrp; 3249static int ttyfd = -1; 3250#endif 3251/* array of jobs */ 3252static struct job *jobtab; 3253/* size of array */ 3254static unsigned njobs; 3255/* current job */ 3256static struct job *curjob; 3257/* number of presumed living untracked jobs */ 3258static int jobless; 3259 3260static void 3261set_curjob(struct job *jp, unsigned mode) 3262{ 3263 struct job *jp1; 3264 struct job **jpp, **curp; 3265 3266 /* first remove from list */ 3267 jpp = curp = &curjob; 3268 do { 3269 jp1 = *jpp; 3270 if (jp1 == jp) 3271 break; 3272 jpp = &jp1->prev_job; 3273 } while (1); 3274 *jpp = jp1->prev_job; 3275 3276 /* Then re-insert in correct position */ 3277 jpp = curp; 3278 switch (mode) { 3279 default: 3280#if DEBUG 3281 abort(); 3282#endif 3283 case CUR_DELETE: 3284 /* job being deleted */ 3285 break; 3286 case CUR_RUNNING: 3287 /* newly created job or backgrounded job, 3288 put after all stopped jobs. */ 3289 do { 3290 jp1 = *jpp; 3291#if JOBS 3292 if (!jp1 || jp1->state != JOBSTOPPED) 3293#endif 3294 break; 3295 jpp = &jp1->prev_job; 3296 } while (1); 3297 /* FALLTHROUGH */ 3298#if JOBS 3299 case CUR_STOPPED: 3300#endif 3301 /* newly stopped job - becomes curjob */ 3302 jp->prev_job = *jpp; 3303 *jpp = jp; 3304 break; 3305 } 3306} 3307 3308#if JOBS || DEBUG 3309static int 3310jobno(const struct job *jp) 3311{ 3312 return jp - jobtab + 1; 3313} 3314#endif 3315 3316/* 3317 * Convert a job name to a job structure. 3318 */ 3319static struct job * 3320getjob(const char *name, int getctl) 3321{ 3322 struct job *jp; 3323 struct job *found; 3324 const char *err_msg = "No such job: %s"; 3325 unsigned num; 3326 int c; 3327 const char *p; 3328 char *(*match)(const char *, const char *); 3329 3330 jp = curjob; 3331 p = name; 3332 if (!p) 3333 goto currentjob; 3334 3335 if (*p != '%') 3336 goto err; 3337 3338 c = *++p; 3339 if (!c) 3340 goto currentjob; 3341 3342 if (!p[1]) { 3343 if (c == '+' || c == '%') { 3344 currentjob: 3345 err_msg = "No current job"; 3346 goto check; 3347 } 3348 if (c == '-') { 3349 if (jp) 3350 jp = jp->prev_job; 3351 err_msg = "No previous job"; 3352 check: 3353 if (!jp) 3354 goto err; 3355 goto gotit; 3356 } 3357 } 3358 3359 if (is_number(p)) { 3360 num = atoi(p); 3361 if (num < njobs) { 3362 jp = jobtab + num - 1; 3363 if (jp->used) 3364 goto gotit; 3365 goto err; 3366 } 3367 } 3368 3369 match = prefix; 3370 if (*p == '?') { 3371 match = strstr; 3372 p++; 3373 } 3374 3375 found = 0; 3376 while (1) { 3377 if (!jp) 3378 goto err; 3379 if (match(jp->ps[0].cmd, p)) { 3380 if (found) 3381 goto err; 3382 found = jp; 3383 err_msg = "%s: ambiguous"; 3384 } 3385 jp = jp->prev_job; 3386 } 3387 3388 gotit: 3389#if JOBS 3390 err_msg = "job %s not created under job control"; 3391 if (getctl && jp->jobctl == 0) 3392 goto err; 3393#endif 3394 return jp; 3395 err: 3396 ash_msg_and_raise_error(err_msg, name); 3397} 3398 3399/* 3400 * Mark a job structure as unused. 3401 */ 3402static void 3403freejob(struct job *jp) 3404{ 3405 struct procstat *ps; 3406 int i; 3407 3408 INT_OFF; 3409 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { 3410 if (ps->cmd != nullstr) 3411 free(ps->cmd); 3412 } 3413 if (jp->ps != &jp->ps0) 3414 free(jp->ps); 3415 jp->used = 0; 3416 set_curjob(jp, CUR_DELETE); 3417 INT_ON; 3418} 3419 3420#if JOBS 3421static void 3422xtcsetpgrp(int fd, pid_t pgrp) 3423{ 3424 if (tcsetpgrp(fd, pgrp)) 3425 ash_msg_and_raise_error("cannot set tty process group (%m)"); 3426} 3427 3428/* 3429 * Turn job control on and off. 3430 * 3431 * Note: This code assumes that the third arg to ioctl is a character 3432 * pointer, which is true on Berkeley systems but not System V. Since 3433 * System V doesn't have job control yet, this isn't a problem now. 3434 * 3435 * Called with interrupts off. 3436 */ 3437static void 3438setjobctl(int on) 3439{ 3440 int fd; 3441 int pgrp; 3442 3443 if (on == jobctl || rootshell == 0) 3444 return; 3445 if (on) { 3446 int ofd; 3447 ofd = fd = open(_PATH_TTY, O_RDWR); 3448 if (fd < 0) { 3449 fd += 3; 3450 while (!isatty(fd) && --fd >= 0) 3451 ; 3452 } 3453 fd = fcntl(fd, F_DUPFD, 10); 3454 close(ofd); 3455 if (fd < 0) 3456 goto out; 3457 fcntl(fd, F_SETFD, FD_CLOEXEC); 3458 do { /* while we are in the background */ 3459 pgrp = tcgetpgrp(fd); 3460 if (pgrp < 0) { 3461 out: 3462 ash_msg("can't access tty; job control turned off"); 3463 mflag = on = 0; 3464 goto close; 3465 } 3466 if (pgrp == getpgrp()) 3467 break; 3468 killpg(0, SIGTTIN); 3469 } while (1); 3470 initialpgrp = pgrp; 3471 3472 setsignal(SIGTSTP); 3473 setsignal(SIGTTOU); 3474 setsignal(SIGTTIN); 3475 pgrp = rootpid; 3476 setpgid(0, pgrp); 3477 xtcsetpgrp(fd, pgrp); 3478 } else { 3479 /* turning job control off */ 3480 fd = ttyfd; 3481 pgrp = initialpgrp; 3482 /* was xtcsetpgrp, but this can make exiting ash 3483 * with pty already deleted loop forever */ 3484 tcsetpgrp(fd, pgrp); 3485 setpgid(0, pgrp); 3486 setsignal(SIGTSTP); 3487 setsignal(SIGTTOU); 3488 setsignal(SIGTTIN); 3489 close: 3490 close(fd); 3491 fd = -1; 3492 } 3493 ttyfd = fd; 3494 jobctl = on; 3495} 3496 3497static int 3498killcmd(int argc, char **argv) 3499{ 3500 if (argv[1] && strcmp(argv[1], "-l") != 0) { 3501 int i = 1; 3502 do { 3503 if (argv[i][0] == '%') { 3504 struct job *jp = getjob(argv[i], 0); 3505 unsigned pid = jp->ps[0].pid; 3506 /* Enough space for ' -NNN<nul>' */ 3507 argv[i] = alloca(sizeof(int)*3 + 3); 3508 /* kill_main has matching code to expect 3509 * leading space. Needed to not confuse 3510 * negative pids with "kill -SIGNAL_NO" syntax */ 3511 sprintf(argv[i], " -%u", pid); 3512 } 3513 } while (argv[++i]); 3514 } 3515 return kill_main(argc, argv); 3516} 3517 3518static void 3519showpipe(struct job *jp, FILE *out) 3520{ 3521 struct procstat *sp; 3522 struct procstat *spend; 3523 3524 spend = jp->ps + jp->nprocs; 3525 for (sp = jp->ps + 1; sp < spend; sp++) 3526 fprintf(out, " | %s", sp->cmd); 3527 outcslow('\n', out); 3528 flush_stdout_stderr(); 3529} 3530 3531 3532static int 3533restartjob(struct job *jp, int mode) 3534{ 3535 struct procstat *ps; 3536 int i; 3537 int status; 3538 pid_t pgid; 3539 3540 INT_OFF; 3541 if (jp->state == JOBDONE) 3542 goto out; 3543 jp->state = JOBRUNNING; 3544 pgid = jp->ps->pid; 3545 if (mode == FORK_FG) 3546 xtcsetpgrp(ttyfd, pgid); 3547 killpg(pgid, SIGCONT); 3548 ps = jp->ps; 3549 i = jp->nprocs; 3550 do { 3551 if (WIFSTOPPED(ps->status)) { 3552 ps->status = -1; 3553 } 3554 ps++; 3555 } while (--i); 3556 out: 3557 status = (mode == FORK_FG) ? waitforjob(jp) : 0; 3558 INT_ON; 3559 return status; 3560} 3561 3562static int 3563fg_bgcmd(int argc, char **argv) 3564{ 3565 struct job *jp; 3566 FILE *out; 3567 int mode; 3568 int retval; 3569 3570 mode = (**argv == 'f') ? FORK_FG : FORK_BG; 3571 nextopt(nullstr); 3572 argv = argptr; 3573 out = stdout; 3574 do { 3575 jp = getjob(*argv, 1); 3576 if (mode == FORK_BG) { 3577 set_curjob(jp, CUR_RUNNING); 3578 fprintf(out, "[%d] ", jobno(jp)); 3579 } 3580 outstr(jp->ps->cmd, out); 3581 showpipe(jp, out); 3582 retval = restartjob(jp, mode); 3583 } while (*argv && *++argv); 3584 return retval; 3585} 3586#endif 3587 3588static int 3589sprint_status(char *s, int status, int sigonly) 3590{ 3591 int col; 3592 int st; 3593 3594 col = 0; 3595 if (!WIFEXITED(status)) { 3596#if JOBS 3597 if (WIFSTOPPED(status)) 3598 st = WSTOPSIG(status); 3599 else 3600#endif 3601 st = WTERMSIG(status); 3602 if (sigonly) { 3603 if (st == SIGINT || st == SIGPIPE) 3604 goto out; 3605#if JOBS 3606 if (WIFSTOPPED(status)) 3607 goto out; 3608#endif 3609 } 3610 st &= 0x7f; 3611 col = fmtstr(s, 32, strsignal(st)); 3612 if (WCOREDUMP(status)) { 3613 col += fmtstr(s + col, 16, " (core dumped)"); 3614 } 3615 } else if (!sigonly) { 3616 st = WEXITSTATUS(status); 3617 if (st) 3618 col = fmtstr(s, 16, "Done(%d)", st); 3619 else 3620 col = fmtstr(s, 16, "Done"); 3621 } 3622 out: 3623 return col; 3624} 3625 3626/* 3627 * Do a wait system call. If job control is compiled in, we accept 3628 * stopped processes. If block is zero, we return a value of zero 3629 * rather than blocking. 3630 * 3631 * System V doesn't have a non-blocking wait system call. It does 3632 * have a SIGCLD signal that is sent to a process when one of it's 3633 * children dies. The obvious way to use SIGCLD would be to install 3634 * a handler for SIGCLD which simply bumped a counter when a SIGCLD 3635 * was received, and have waitproc bump another counter when it got 3636 * the status of a process. Waitproc would then know that a wait 3637 * system call would not block if the two counters were different. 3638 * This approach doesn't work because if a process has children that 3639 * have not been waited for, System V will send it a SIGCLD when it 3640 * installs a signal handler for SIGCLD. What this means is that when 3641 * a child exits, the shell will be sent SIGCLD signals continuously 3642 * until is runs out of stack space, unless it does a wait call before 3643 * restoring the signal handler. The code below takes advantage of 3644 * this (mis)feature by installing a signal handler for SIGCLD and 3645 * then checking to see whether it was called. If there are any 3646 * children to be waited for, it will be. 3647 * 3648 * If neither SYSV nor BSD is defined, we don't implement nonblocking 3649 * waits at all. In this case, the user will not be informed when 3650 * a background process until the next time she runs a real program 3651 * (as opposed to running a builtin command or just typing return), 3652 * and the jobs command may give out of date information. 3653 */ 3654static int 3655waitproc(int block, int *status) 3656{ 3657 int flags = 0; 3658 3659#if JOBS 3660 if (jobctl) 3661 flags |= WUNTRACED; 3662#endif 3663 if (block == 0) 3664 flags |= WNOHANG; 3665 return wait3(status, flags, (struct rusage *)NULL); 3666} 3667 3668/* 3669 * Wait for a process to terminate. 3670 */ 3671static int 3672dowait(int block, struct job *job) 3673{ 3674 int pid; 3675 int status; 3676 struct job *jp; 3677 struct job *thisjob; 3678 int state; 3679 3680 TRACE(("dowait(%d) called\n", block)); 3681 pid = waitproc(block, &status); 3682 TRACE(("wait returns pid %d, status=%d\n", pid, status)); 3683 if (pid <= 0) 3684 return pid; 3685 INT_OFF; 3686 thisjob = NULL; 3687 for (jp = curjob; jp; jp = jp->prev_job) { 3688 struct procstat *sp; 3689 struct procstat *spend; 3690 if (jp->state == JOBDONE) 3691 continue; 3692 state = JOBDONE; 3693 spend = jp->ps + jp->nprocs; 3694 sp = jp->ps; 3695 do { 3696 if (sp->pid == pid) { 3697 TRACE(("Job %d: changing status of proc %d " 3698 "from 0x%x to 0x%x\n", 3699 jobno(jp), pid, sp->status, status)); 3700 sp->status = status; 3701 thisjob = jp; 3702 } 3703 if (sp->status == -1) 3704 state = JOBRUNNING; 3705#if JOBS 3706 if (state == JOBRUNNING) 3707 continue; 3708 if (WIFSTOPPED(sp->status)) { 3709 jp->stopstatus = sp->status; 3710 state = JOBSTOPPED; 3711 } 3712#endif 3713 } while (++sp < spend); 3714 if (thisjob) 3715 goto gotjob; 3716 } 3717#if JOBS 3718 if (!WIFSTOPPED(status)) 3719#endif 3720 3721 jobless--; 3722 goto out; 3723 3724 gotjob: 3725 if (state != JOBRUNNING) { 3726 thisjob->changed = 1; 3727 3728 if (thisjob->state != state) { 3729 TRACE(("Job %d: changing state from %d to %d\n", 3730 jobno(thisjob), thisjob->state, state)); 3731 thisjob->state = state; 3732#if JOBS 3733 if (state == JOBSTOPPED) { 3734 set_curjob(thisjob, CUR_STOPPED); 3735 } 3736#endif 3737 } 3738 } 3739 3740 out: 3741 INT_ON; 3742 3743 if (thisjob && thisjob == job) { 3744 char s[48 + 1]; 3745 int len; 3746 3747 len = sprint_status(s, status, 1); 3748 if (len) { 3749 s[len] = '\n'; 3750 s[len + 1] = 0; 3751 out2str(s); 3752 } 3753 } 3754 return pid; 3755} 3756 3757#if JOBS 3758static void 3759showjob(FILE *out, struct job *jp, int mode) 3760{ 3761 struct procstat *ps; 3762 struct procstat *psend; 3763 int col; 3764 int indent_col; 3765 char s[80]; 3766 3767 ps = jp->ps; 3768 3769 if (mode & SHOW_PGID) { 3770 /* just output process (group) id of pipeline */ 3771 fprintf(out, "%d\n", ps->pid); 3772 return; 3773 } 3774 3775 col = fmtstr(s, 16, "[%d] ", jobno(jp)); 3776 indent_col = col; 3777 3778 if (jp == curjob) 3779 s[col - 2] = '+'; 3780 else if (curjob && jp == curjob->prev_job) 3781 s[col - 2] = '-'; 3782 3783 if (mode & SHOW_PID) 3784 col += fmtstr(s + col, 16, "%d ", ps->pid); 3785 3786 psend = ps + jp->nprocs; 3787 3788 if (jp->state == JOBRUNNING) { 3789 strcpy(s + col, "Running"); 3790 col += sizeof("Running") - 1; 3791 } else { 3792 int status = psend[-1].status; 3793 if (jp->state == JOBSTOPPED) 3794 status = jp->stopstatus; 3795 col += sprint_status(s + col, status, 0); 3796 } 3797 3798 goto start; 3799 3800 do { 3801 /* for each process */ 3802 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3; 3803 start: 3804 fprintf(out, "%s%*c%s", 3805 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd 3806 ); 3807 if (!(mode & SHOW_PID)) { 3808 showpipe(jp, out); 3809 break; 3810 } 3811 if (++ps == psend) { 3812 outcslow('\n', out); 3813 break; 3814 } 3815 } while (1); 3816 3817 jp->changed = 0; 3818 3819 if (jp->state == JOBDONE) { 3820 TRACE(("showjob: freeing job %d\n", jobno(jp))); 3821 freejob(jp); 3822 } 3823} 3824 3825/* 3826 * Print a list of jobs. If "change" is nonzero, only print jobs whose 3827 * statuses have changed since the last call to showjobs. 3828 */ 3829static void 3830showjobs(FILE *out, int mode) 3831{ 3832 struct job *jp; 3833 3834 TRACE(("showjobs(%x) called\n", mode)); 3835 3836 /* If not even one one job changed, there is nothing to do */ 3837 while (dowait(DOWAIT_NORMAL, NULL) > 0) 3838 continue; 3839 3840 for (jp = curjob; jp; jp = jp->prev_job) { 3841 if (!(mode & SHOW_CHANGED) || jp->changed) { 3842 showjob(out, jp, mode); 3843 } 3844 } 3845} 3846 3847static int 3848jobscmd(int argc, char **argv) 3849{ 3850 int mode, m; 3851 3852 mode = 0; 3853 while ((m = nextopt("lp"))) { 3854 if (m == 'l') 3855 mode = SHOW_PID; 3856 else 3857 mode = SHOW_PGID; 3858 } 3859 3860 argv = argptr; 3861 if (*argv) { 3862 do 3863 showjob(stdout, getjob(*argv,0), mode); 3864 while (*++argv); 3865 } else 3866 showjobs(stdout, mode); 3867 3868 return 0; 3869} 3870#endif /* JOBS */ 3871 3872static int 3873getstatus(struct job *job) 3874{ 3875 int status; 3876 int retval; 3877 3878 status = job->ps[job->nprocs - 1].status; 3879 retval = WEXITSTATUS(status); 3880 if (!WIFEXITED(status)) { 3881#if JOBS 3882 retval = WSTOPSIG(status); 3883 if (!WIFSTOPPED(status)) 3884#endif 3885 { 3886 retval = WTERMSIG(status); 3887#if JOBS 3888 if (retval == SIGINT) 3889 job->sigint = 1; 3890#endif 3891 } 3892 retval += 128; 3893 } 3894 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n", 3895 jobno(job), job->nprocs, status, retval)); 3896 return retval; 3897} 3898 3899static int 3900waitcmd(int argc, char **argv) 3901{ 3902 struct job *job; 3903 int retval; 3904 struct job *jp; 3905 3906 EXSIGON; 3907 3908 nextopt(nullstr); 3909 retval = 0; 3910 3911 argv = argptr; 3912 if (!*argv) { 3913 /* wait for all jobs */ 3914 for (;;) { 3915 jp = curjob; 3916 while (1) { 3917 if (!jp) { 3918 /* no running procs */ 3919 goto out; 3920 } 3921 if (jp->state == JOBRUNNING) 3922 break; 3923 jp->waited = 1; 3924 jp = jp->prev_job; 3925 } 3926 dowait(DOWAIT_BLOCK, 0); 3927 } 3928 } 3929 3930 retval = 127; 3931 do { 3932 if (**argv != '%') { 3933 pid_t pid = number(*argv); 3934 job = curjob; 3935 goto start; 3936 do { 3937 if (job->ps[job->nprocs - 1].pid == pid) 3938 break; 3939 job = job->prev_job; 3940 start: 3941 if (!job) 3942 goto repeat; 3943 } while (1); 3944 } else 3945 job = getjob(*argv, 0); 3946 /* loop until process terminated or stopped */ 3947 while (job->state == JOBRUNNING) 3948 dowait(DOWAIT_BLOCK, 0); 3949 job->waited = 1; 3950 retval = getstatus(job); 3951 repeat: 3952 ; 3953 } while (*++argv); 3954 3955 out: 3956 return retval; 3957} 3958 3959static struct job * 3960growjobtab(void) 3961{ 3962 size_t len; 3963 ptrdiff_t offset; 3964 struct job *jp, *jq; 3965 3966 len = njobs * sizeof(*jp); 3967 jq = jobtab; 3968 jp = ckrealloc(jq, len + 4 * sizeof(*jp)); 3969 3970 offset = (char *)jp - (char *)jq; 3971 if (offset) { 3972 /* Relocate pointers */ 3973 size_t l = len; 3974 3975 jq = (struct job *)((char *)jq + l); 3976 while (l) { 3977 l -= sizeof(*jp); 3978 jq--; 3979#define joff(p) ((struct job *)((char *)(p) + l)) 3980#define jmove(p) (p) = (void *)((char *)(p) + offset) 3981 if (joff(jp)->ps == &jq->ps0) 3982 jmove(joff(jp)->ps); 3983 if (joff(jp)->prev_job) 3984 jmove(joff(jp)->prev_job); 3985 } 3986 if (curjob) 3987 jmove(curjob); 3988#undef joff 3989#undef jmove 3990 } 3991 3992 njobs += 4; 3993 jobtab = jp; 3994 jp = (struct job *)((char *)jp + len); 3995 jq = jp + 3; 3996 do { 3997 jq->used = 0; 3998 } while (--jq >= jp); 3999 return jp; 4000} 4001 4002/* 4003 * Return a new job structure. 4004 * Called with interrupts off. 4005 */ 4006static struct job * 4007makejob(union node *node, int nprocs) 4008{ 4009 int i; 4010 struct job *jp; 4011 4012 for (i = njobs, jp = jobtab; ; jp++) { 4013 if (--i < 0) { 4014 jp = growjobtab(); 4015 break; 4016 } 4017 if (jp->used == 0) 4018 break; 4019 if (jp->state != JOBDONE || !jp->waited) 4020 continue; 4021#if JOBS 4022 if (jobctl) 4023 continue; 4024#endif 4025 freejob(jp); 4026 break; 4027 } 4028 memset(jp, 0, sizeof(*jp)); 4029#if JOBS 4030 /* jp->jobctl is a bitfield. 4031 * "jp->jobctl |= jobctl" likely to give awful code */ 4032 if (jobctl) 4033 jp->jobctl = 1; 4034#endif 4035 jp->prev_job = curjob; 4036 curjob = jp; 4037 jp->used = 1; 4038 jp->ps = &jp->ps0; 4039 if (nprocs > 1) { 4040 jp->ps = ckmalloc(nprocs * sizeof(struct procstat)); 4041 } 4042 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs, 4043 jobno(jp))); 4044 return jp; 4045} 4046 4047#if JOBS 4048/* 4049 * Return a string identifying a command (to be printed by the 4050 * jobs command). 4051 */ 4052static char *cmdnextc; 4053 4054static void 4055cmdputs(const char *s) 4056{ 4057 const char *p, *str; 4058 char c, cc[2] = " "; 4059 char *nextc; 4060 int subtype = 0; 4061 int quoted = 0; 4062 static const char vstype[VSTYPE + 1][4] = { 4063 "", "}", "-", "+", "?", "=", 4064 "%", "%%", "#", "##" 4065 }; 4066 4067 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc); 4068 p = s; 4069 while ((c = *p++) != 0) { 4070 str = 0; 4071 switch (c) { 4072 case CTLESC: 4073 c = *p++; 4074 break; 4075 case CTLVAR: 4076 subtype = *p++; 4077 if ((subtype & VSTYPE) == VSLENGTH) 4078 str = "${#"; 4079 else 4080 str = "${"; 4081 if (!(subtype & VSQUOTE) == !(quoted & 1)) 4082 goto dostr; 4083 quoted ^= 1; 4084 c = '"'; 4085 break; 4086 case CTLENDVAR: 4087 str = "\"}" + !(quoted & 1); 4088 quoted >>= 1; 4089 subtype = 0; 4090 goto dostr; 4091 case CTLBACKQ: 4092 str = "$(...)"; 4093 goto dostr; 4094 case CTLBACKQ+CTLQUOTE: 4095 str = "\"$(...)\""; 4096 goto dostr; 4097#if ENABLE_ASH_MATH_SUPPORT 4098 case CTLARI: 4099 str = "$(("; 4100 goto dostr; 4101 case CTLENDARI: 4102 str = "))"; 4103 goto dostr; 4104#endif 4105 case CTLQUOTEMARK: 4106 quoted ^= 1; 4107 c = '"'; 4108 break; 4109 case '=': 4110 if (subtype == 0) 4111 break; 4112 if ((subtype & VSTYPE) != VSNORMAL) 4113 quoted <<= 1; 4114 str = vstype[subtype & VSTYPE]; 4115 if (subtype & VSNUL) 4116 c = ':'; 4117 else 4118 goto checkstr; 4119 break; 4120 case '\'': 4121 case '\\': 4122 case '"': 4123 case '$': 4124 /* These can only happen inside quotes */ 4125 cc[0] = c; 4126 str = cc; 4127 c = '\\'; 4128 break; 4129 default: 4130 break; 4131 } 4132 USTPUTC(c, nextc); 4133 checkstr: 4134 if (!str) 4135 continue; 4136 dostr: 4137 while ((c = *str++)) { 4138 USTPUTC(c, nextc); 4139 } 4140 } 4141 if (quoted & 1) { 4142 USTPUTC('"', nextc); 4143 } 4144 *nextc = 0; 4145 cmdnextc = nextc; 4146} 4147 4148/* cmdtxt() and cmdlist() call each other */ 4149static void cmdtxt(union node *n); 4150 4151static void 4152cmdlist(union node *np, int sep) 4153{ 4154 for (; np; np = np->narg.next) { 4155 if (!sep) 4156 cmdputs(" "); 4157 cmdtxt(np); 4158 if (sep && np->narg.next) 4159 cmdputs(" "); 4160 } 4161} 4162 4163static void 4164cmdtxt(union node *n) 4165{ 4166 union node *np; 4167 struct nodelist *lp; 4168 const char *p; 4169 char s[2]; 4170 4171 if (!n) 4172 return; 4173 switch (n->type) { 4174 default: 4175#if DEBUG 4176 abort(); 4177#endif 4178 case NPIPE: 4179 lp = n->npipe.cmdlist; 4180 for (;;) { 4181 cmdtxt(lp->n); 4182 lp = lp->next; 4183 if (!lp) 4184 break; 4185 cmdputs(" | "); 4186 } 4187 break; 4188 case NSEMI: 4189 p = "; "; 4190 goto binop; 4191 case NAND: 4192 p = " && "; 4193 goto binop; 4194 case NOR: 4195 p = " || "; 4196 binop: 4197 cmdtxt(n->nbinary.ch1); 4198 cmdputs(p); 4199 n = n->nbinary.ch2; 4200 goto donode; 4201 case NREDIR: 4202 case NBACKGND: 4203 n = n->nredir.n; 4204 goto donode; 4205 case NNOT: 4206 cmdputs("!"); 4207 n = n->nnot.com; 4208 donode: 4209 cmdtxt(n); 4210 break; 4211 case NIF: 4212 cmdputs("if "); 4213 cmdtxt(n->nif.test); 4214 cmdputs("; then "); 4215 n = n->nif.ifpart; 4216 if (n->nif.elsepart) { 4217 cmdtxt(n); 4218 cmdputs("; else "); 4219 n = n->nif.elsepart; 4220 } 4221 p = "; fi"; 4222 goto dotail; 4223 case NSUBSHELL: 4224 cmdputs("("); 4225 n = n->nredir.n; 4226 p = ")"; 4227 goto dotail; 4228 case NWHILE: 4229 p = "while "; 4230 goto until; 4231 case NUNTIL: 4232 p = "until "; 4233 until: 4234 cmdputs(p); 4235 cmdtxt(n->nbinary.ch1); 4236 n = n->nbinary.ch2; 4237 p = "; done"; 4238 dodo: 4239 cmdputs("; do "); 4240 dotail: 4241 cmdtxt(n); 4242 goto dotail2; 4243 case NFOR: 4244 cmdputs("for "); 4245 cmdputs(n->nfor.var); 4246 cmdputs(" in "); 4247 cmdlist(n->nfor.args, 1); 4248 n = n->nfor.body; 4249 p = "; done"; 4250 goto dodo; 4251 case NDEFUN: 4252 cmdputs(n->narg.text); 4253 p = "() { ... }"; 4254 goto dotail2; 4255 case NCMD: 4256 cmdlist(n->ncmd.args, 1); 4257 cmdlist(n->ncmd.redirect, 0); 4258 break; 4259 case NARG: 4260 p = n->narg.text; 4261 dotail2: 4262 cmdputs(p); 4263 break; 4264 case NHERE: 4265 case NXHERE: 4266 p = "<<..."; 4267 goto dotail2; 4268 case NCASE: 4269 cmdputs("case "); 4270 cmdputs(n->ncase.expr->narg.text); 4271 cmdputs(" in "); 4272 for (np = n->ncase.cases; np; np = np->nclist.next) { 4273 cmdtxt(np->nclist.pattern); 4274 cmdputs(") "); 4275 cmdtxt(np->nclist.body); 4276 cmdputs(";; "); 4277 } 4278 p = "esac"; 4279 goto dotail2; 4280 case NTO: 4281 p = ">"; 4282 goto redir; 4283 case NCLOBBER: 4284 p = ">|"; 4285 goto redir; 4286 case NAPPEND: 4287 p = ">>"; 4288 goto redir; 4289 case NTOFD: 4290 p = ">&"; 4291 goto redir; 4292 case NFROM: 4293 p = "<"; 4294 goto redir; 4295 case NFROMFD: 4296 p = "<&"; 4297 goto redir; 4298 case NFROMTO: 4299 p = "<>"; 4300 redir: 4301 s[0] = n->nfile.fd + '0'; 4302 s[1] = '\0'; 4303 cmdputs(s); 4304 cmdputs(p); 4305 if (n->type == NTOFD || n->type == NFROMFD) { 4306 s[0] = n->ndup.dupfd + '0'; 4307 p = s; 4308 goto dotail2; 4309 } 4310 n = n->nfile.fname; 4311 goto donode; 4312 } 4313} 4314 4315static char * 4316commandtext(union node *n) 4317{ 4318 char *name; 4319 4320 STARTSTACKSTR(cmdnextc); 4321 cmdtxt(n); 4322 name = stackblock(); 4323 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n", 4324 name, cmdnextc, cmdnextc)); 4325 return ckstrdup(name); 4326} 4327#endif /* JOBS */ 4328 4329/* 4330 * Fork off a subshell. If we are doing job control, give the subshell its 4331 * own process group. Jp is a job structure that the job is to be added to. 4332 * N is the command that will be evaluated by the child. Both jp and n may 4333 * be NULL. The mode parameter can be one of the following: 4334 * FORK_FG - Fork off a foreground process. 4335 * FORK_BG - Fork off a background process. 4336 * FORK_NOJOB - Like FORK_FG, but don't give the process its own 4337 * process group even if job control is on. 4338 * 4339 * When job control is turned off, background processes have their standard 4340 * input redirected to /dev/null (except for the second and later processes 4341 * in a pipeline). 4342 * 4343 * Called with interrupts off. 4344 */ 4345/* 4346 * Clear traps on a fork. 4347 */ 4348static void 4349clear_traps(void) 4350{ 4351 char **tp; 4352 4353 for (tp = trap; tp < &trap[NSIG]; tp++) { 4354 if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 4355 INT_OFF; 4356 free(*tp); 4357 *tp = NULL; 4358 if (tp != &trap[0]) 4359 setsignal(tp - trap); 4360 INT_ON; 4361 } 4362 } 4363} 4364 4365/* Lives far away from here, needed for forkchild */ 4366static void closescript(void); 4367/* Called after fork(), in child */ 4368static void 4369forkchild(struct job *jp, union node *n, int mode) 4370{ 4371 int oldlvl; 4372 4373 TRACE(("Child shell %d\n", getpid())); 4374 oldlvl = shlvl; 4375 shlvl++; 4376 4377 closescript(); 4378 clear_traps(); 4379#if JOBS 4380 /* do job control only in root shell */ 4381 jobctl = 0; 4382 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) { 4383 pid_t pgrp; 4384 4385 if (jp->nprocs == 0) 4386 pgrp = getpid(); 4387 else 4388 pgrp = jp->ps[0].pid; 4389 /* This can fail because we are doing it in the parent also */ 4390 (void)setpgid(0, pgrp); 4391 if (mode == FORK_FG) 4392 xtcsetpgrp(ttyfd, pgrp); 4393 setsignal(SIGTSTP); 4394 setsignal(SIGTTOU); 4395 } else 4396#endif 4397 if (mode == FORK_BG) { 4398 ignoresig(SIGINT); 4399 ignoresig(SIGQUIT); 4400 if (jp->nprocs == 0) { 4401 close(0); 4402 if (open(bb_dev_null, O_RDONLY) != 0) 4403 ash_msg_and_raise_error("can't open %s", bb_dev_null); 4404 } 4405 } 4406 if (!oldlvl && iflag) { 4407 setsignal(SIGINT); 4408 setsignal(SIGQUIT); 4409 setsignal(SIGTERM); 4410 } 4411#if JOBS 4412 /* For "jobs | cat" to work like in bash, we must retain list of jobs 4413 * in child, but we do need to remove ourself */ 4414 if (jp) 4415 freejob(jp); 4416#else 4417 for (jp = curjob; jp; jp = jp->prev_job) 4418 freejob(jp); 4419#endif 4420 jobless = 0; 4421} 4422 4423/* Called after fork(), in parent */ 4424static void 4425forkparent(struct job *jp, union node *n, int mode, pid_t pid) 4426{ 4427 TRACE(("In parent shell: child = %d\n", pid)); 4428 if (!jp) { 4429 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0); 4430 jobless++; 4431 return; 4432 } 4433#if JOBS 4434 if (mode != FORK_NOJOB && jp->jobctl) { 4435 int pgrp; 4436 4437 if (jp->nprocs == 0) 4438 pgrp = pid; 4439 else 4440 pgrp = jp->ps[0].pid; 4441 /* This can fail because we are doing it in the child also */ 4442 setpgid(pid, pgrp); 4443 } 4444#endif 4445 if (mode == FORK_BG) { 4446 backgndpid = pid; /* set $! */ 4447 set_curjob(jp, CUR_RUNNING); 4448 } 4449 if (jp) { 4450 struct procstat *ps = &jp->ps[jp->nprocs++]; 4451 ps->pid = pid; 4452 ps->status = -1; 4453 ps->cmd = nullstr; 4454#if JOBS 4455 if (jobctl && n) 4456 ps->cmd = commandtext(n); 4457#endif 4458 } 4459} 4460 4461static int 4462forkshell(struct job *jp, union node *n, int mode) 4463{ 4464 int pid; 4465 4466 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); 4467 pid = fork(); 4468 if (pid < 0) { 4469 TRACE(("Fork failed, errno=%d", errno)); 4470 if (jp) 4471 freejob(jp); 4472 ash_msg_and_raise_error("cannot fork"); 4473 } 4474 if (pid == 0) 4475 forkchild(jp, n, mode); 4476 else 4477 forkparent(jp, n, mode, pid); 4478 return pid; 4479} 4480 4481/* 4482 * Wait for job to finish. 4483 * 4484 * Under job control we have the problem that while a child process is 4485 * running interrupts generated by the user are sent to the child but not 4486 * to the shell. This means that an infinite loop started by an inter- 4487 * active user may be hard to kill. With job control turned off, an 4488 * interactive user may place an interactive program inside a loop. If 4489 * the interactive program catches interrupts, the user doesn't want 4490 * these interrupts to also abort the loop. The approach we take here 4491 * is to have the shell ignore interrupt signals while waiting for a 4492 * foreground process to terminate, and then send itself an interrupt 4493 * signal if the child process was terminated by an interrupt signal. 4494 * Unfortunately, some programs want to do a bit of cleanup and then 4495 * exit on interrupt; unless these processes terminate themselves by 4496 * sending a signal to themselves (instead of calling exit) they will 4497 * confuse this approach. 4498 * 4499 * Called with interrupts off. 4500 */ 4501static int 4502waitforjob(struct job *jp) 4503{ 4504 int st; 4505 4506 TRACE(("waitforjob(%%%d) called\n", jobno(jp))); 4507 while (jp->state == JOBRUNNING) { 4508 dowait(DOWAIT_BLOCK, jp); 4509 } 4510 st = getstatus(jp); 4511#if JOBS 4512 if (jp->jobctl) { 4513 xtcsetpgrp(ttyfd, rootpid); 4514 /* 4515 * This is truly gross. 4516 * If we're doing job control, then we did a TIOCSPGRP which 4517 * caused us (the shell) to no longer be in the controlling 4518 * session -- so we wouldn't have seen any ^C/SIGINT. So, we 4519 * intuit from the subprocess exit status whether a SIGINT 4520 * occurred, and if so interrupt ourselves. Yuck. - mycroft 4521 */ 4522 if (jp->sigint) 4523 raise(SIGINT); 4524 } 4525 if (jp->state == JOBDONE) 4526#endif 4527 freejob(jp); 4528 return st; 4529} 4530 4531/* 4532 * return 1 if there are stopped jobs, otherwise 0 4533 */ 4534static int 4535stoppedjobs(void) 4536{ 4537 struct job *jp; 4538 int retval; 4539 4540 retval = 0; 4541 if (job_warning) 4542 goto out; 4543 jp = curjob; 4544 if (jp && jp->state == JOBSTOPPED) { 4545 out2str("You have stopped jobs.\n"); 4546 job_warning = 2; 4547 retval++; 4548 } 4549 out: 4550 return retval; 4551} 4552 4553 4554/* ============ redir.c 4555 * 4556 * Code for dealing with input/output redirection. 4557 */ 4558 4559#define EMPTY -2 /* marks an unused slot in redirtab */ 4560#ifndef PIPE_BUF 4561# define PIPESIZE 4096 /* amount of buffering in a pipe */ 4562#else 4563# define PIPESIZE PIPE_BUF 4564#endif 4565 4566/* 4567 * Open a file in noclobber mode. 4568 * The code was copied from bash. 4569 */ 4570static int 4571noclobberopen(const char *fname) 4572{ 4573 int r, fd; 4574 struct stat finfo, finfo2; 4575 4576 /* 4577 * If the file exists and is a regular file, return an error 4578 * immediately. 4579 */ 4580 r = stat(fname, &finfo); 4581 if (r == 0 && S_ISREG(finfo.st_mode)) { 4582 errno = EEXIST; 4583 return -1; 4584 } 4585 4586 /* 4587 * If the file was not present (r != 0), make sure we open it 4588 * exclusively so that if it is created before we open it, our open 4589 * will fail. Make sure that we do not truncate an existing file. 4590 * Note that we don't turn on O_EXCL unless the stat failed -- if the 4591 * file was not a regular file, we leave O_EXCL off. 4592 */ 4593 if (r != 0) 4594 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666); 4595 fd = open(fname, O_WRONLY|O_CREAT, 0666); 4596 4597 /* If the open failed, return the file descriptor right away. */ 4598 if (fd < 0) 4599 return fd; 4600 4601 /* 4602 * OK, the open succeeded, but the file may have been changed from a 4603 * non-regular file to a regular file between the stat and the open. 4604 * We are assuming that the O_EXCL open handles the case where FILENAME 4605 * did not exist and is symlinked to an existing file between the stat 4606 * and open. 4607 */ 4608 4609 /* 4610 * If we can open it and fstat the file descriptor, and neither check 4611 * revealed that it was a regular file, and the file has not been 4612 * replaced, return the file descriptor. 4613 */ 4614 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) 4615 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino) 4616 return fd; 4617 4618 /* The file has been replaced. badness. */ 4619 close(fd); 4620 errno = EEXIST; 4621 return -1; 4622} 4623 4624/* 4625 * Handle here documents. Normally we fork off a process to write the 4626 * data to a pipe. If the document is short, we can stuff the data in 4627 * the pipe without forking. 4628 */ 4629/* openhere needs this forward reference */ 4630static void expandhere(union node *arg, int fd); 4631static int 4632openhere(union node *redir) 4633{ 4634 int pip[2]; 4635 size_t len = 0; 4636 4637 if (pipe(pip) < 0) 4638 ash_msg_and_raise_error("pipe call failed"); 4639 if (redir->type == NHERE) { 4640 len = strlen(redir->nhere.doc->narg.text); 4641 if (len <= PIPESIZE) { 4642 full_write(pip[1], redir->nhere.doc->narg.text, len); 4643 goto out; 4644 } 4645 } 4646 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 4647 close(pip[0]); 4648 signal(SIGINT, SIG_IGN); 4649 signal(SIGQUIT, SIG_IGN); 4650 signal(SIGHUP, SIG_IGN); 4651#ifdef SIGTSTP 4652 signal(SIGTSTP, SIG_IGN); 4653#endif 4654 signal(SIGPIPE, SIG_DFL); 4655 if (redir->type == NHERE) 4656 full_write(pip[1], redir->nhere.doc->narg.text, len); 4657 else 4658 expandhere(redir->nhere.doc, pip[1]); 4659 _exit(0); 4660 } 4661 out: 4662 close(pip[1]); 4663 return pip[0]; 4664} 4665 4666static int 4667openredirect(union node *redir) 4668{ 4669 char *fname; 4670 int f; 4671 4672 switch (redir->nfile.type) { 4673 case NFROM: 4674 fname = redir->nfile.expfname; 4675 f = open(fname, O_RDONLY); 4676 if (f < 0) 4677 goto eopen; 4678 break; 4679 case NFROMTO: 4680 fname = redir->nfile.expfname; 4681 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666); 4682 if (f < 0) 4683 goto ecreate; 4684 break; 4685 case NTO: 4686 /* Take care of noclobber mode. */ 4687 if (Cflag) { 4688 fname = redir->nfile.expfname; 4689 f = noclobberopen(fname); 4690 if (f < 0) 4691 goto ecreate; 4692 break; 4693 } 4694 /* FALLTHROUGH */ 4695 case NCLOBBER: 4696 fname = redir->nfile.expfname; 4697 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666); 4698 if (f < 0) 4699 goto ecreate; 4700 break; 4701 case NAPPEND: 4702 fname = redir->nfile.expfname; 4703 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); 4704 if (f < 0) 4705 goto ecreate; 4706 break; 4707 default: 4708#if DEBUG 4709 abort(); 4710#endif 4711 /* Fall through to eliminate warning. */ 4712 case NTOFD: 4713 case NFROMFD: 4714 f = -1; 4715 break; 4716 case NHERE: 4717 case NXHERE: 4718 f = openhere(redir); 4719 break; 4720 } 4721 4722 return f; 4723 ecreate: 4724 ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "nonexistent directory")); 4725 eopen: 4726 ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "no such file")); 4727} 4728 4729/* 4730 * Copy a file descriptor to be >= to. Returns -1 4731 * if the source file descriptor is closed, EMPTY if there are no unused 4732 * file descriptors left. 4733 */ 4734static int 4735copyfd(int from, int to) 4736{ 4737 int newfd; 4738 4739 newfd = fcntl(from, F_DUPFD, to); 4740 if (newfd < 0) { 4741 if (errno == EMFILE) 4742 return EMPTY; 4743 ash_msg_and_raise_error("%d: %m", from); 4744 } 4745 return newfd; 4746} 4747 4748static void 4749dupredirect(union node *redir, int f) 4750{ 4751 int fd = redir->nfile.fd; 4752 4753 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { 4754 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ 4755 copyfd(redir->ndup.dupfd, fd); 4756 } 4757 return; 4758 } 4759 4760 if (f != fd) { 4761 copyfd(f, fd); 4762 close(f); 4763 } 4764} 4765 4766/* 4767 * Process a list of redirection commands. If the REDIR_PUSH flag is set, 4768 * old file descriptors are stashed away so that the redirection can be 4769 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the 4770 * standard output, and the standard error if it becomes a duplicate of 4771 * stdout, is saved in memory. 4772 */ 4773/* flags passed to redirect */ 4774#define REDIR_PUSH 01 /* save previous values of file descriptors */ 4775#define REDIR_SAVEFD2 03 /* set preverrout */ 4776static void 4777redirect(union node *redir, int flags) 4778{ 4779 union node *n; 4780 struct redirtab *sv; 4781 int i; 4782 int fd; 4783 int newfd; 4784 int *p; 4785 nullredirs++; 4786 if (!redir) { 4787 return; 4788 } 4789 sv = NULL; 4790 INT_OFF; 4791 if (flags & REDIR_PUSH) { 4792 struct redirtab *q; 4793 q = ckmalloc(sizeof(struct redirtab)); 4794 q->next = redirlist; 4795 redirlist = q; 4796 q->nullredirs = nullredirs - 1; 4797 for (i = 0; i < 10; i++) 4798 q->renamed[i] = EMPTY; 4799 nullredirs = 0; 4800 sv = q; 4801 } 4802 n = redir; 4803 do { 4804 fd = n->nfile.fd; 4805 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) 4806 && n->ndup.dupfd == fd) 4807 continue; /* redirect from/to same file descriptor */ 4808 4809 newfd = openredirect(n); 4810 if (fd == newfd) 4811 continue; 4812 if (sv && *(p = &sv->renamed[fd]) == EMPTY) { 4813 i = fcntl(fd, F_DUPFD, 10); 4814 4815 if (i == -1) { 4816 i = errno; 4817 if (i != EBADF) { 4818 close(newfd); 4819 errno = i; 4820 ash_msg_and_raise_error("%d: %m", fd); 4821 /* NOTREACHED */ 4822 } 4823 } else { 4824 *p = i; 4825 close(fd); 4826 } 4827 } else { 4828 close(fd); 4829 } 4830 dupredirect(n, newfd); 4831 } while ((n = n->nfile.next)); 4832 INT_ON; 4833 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0) 4834 preverrout_fd = sv->renamed[2]; 4835} 4836 4837/* 4838 * Undo the effects of the last redirection. 4839 */ 4840static void 4841popredir(int drop) 4842{ 4843 struct redirtab *rp; 4844 int i; 4845 4846 if (--nullredirs >= 0) 4847 return; 4848 INT_OFF; 4849 rp = redirlist; 4850 for (i = 0; i < 10; i++) { 4851 if (rp->renamed[i] != EMPTY) { 4852 if (!drop) { 4853 close(i); 4854 copyfd(rp->renamed[i], i); 4855 } 4856 close(rp->renamed[i]); 4857 } 4858 } 4859 redirlist = rp->next; 4860 nullredirs = rp->nullredirs; 4861 free(rp); 4862 INT_ON; 4863} 4864 4865/* 4866 * Undo all redirections. Called on error or interrupt. 4867 */ 4868 4869/* 4870 * Discard all saved file descriptors. 4871 */ 4872static void 4873clearredir(int drop) 4874{ 4875 for (;;) { 4876 nullredirs = 0; 4877 if (!redirlist) 4878 break; 4879 popredir(drop); 4880 } 4881} 4882 4883static int 4884redirectsafe(union node *redir, int flags) 4885{ 4886 int err; 4887 volatile int saveint; 4888 struct jmploc *volatile savehandler = exception_handler; 4889 struct jmploc jmploc; 4890 4891 SAVE_INT(saveint); 4892 err = setjmp(jmploc.loc) * 2; 4893 if (!err) { 4894 exception_handler = &jmploc; 4895 redirect(redir, flags); 4896 } 4897 exception_handler = savehandler; 4898 if (err && exception != EXERROR) 4899 longjmp(exception_handler->loc, 1); 4900 RESTORE_INT(saveint); 4901 return err; 4902} 4903 4904 4905/* ============ Routines to expand arguments to commands 4906 * 4907 * We have to deal with backquotes, shell variables, and file metacharacters. 4908 */ 4909 4910/* 4911 * expandarg flags 4912 */ 4913#define EXP_FULL 0x1 /* perform word splitting & file globbing */ 4914#define EXP_TILDE 0x2 /* do normal tilde expansion */ 4915#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ 4916#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ 4917#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ 4918#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */ 4919#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ 4920#define EXP_WORD 0x80 /* expand word in parameter expansion */ 4921#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */ 4922/* 4923 * _rmescape() flags 4924 */ 4925#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ 4926#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ 4927#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */ 4928#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ 4929#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ 4930 4931/* 4932 * Structure specifying which parts of the string should be searched 4933 * for IFS characters. 4934 */ 4935struct ifsregion { 4936 struct ifsregion *next; /* next region in list */ 4937 int begoff; /* offset of start of region */ 4938 int endoff; /* offset of end of region */ 4939 int nulonly; /* search for nul bytes only */ 4940}; 4941 4942struct arglist { 4943 struct strlist *list; 4944 struct strlist **lastp; 4945}; 4946 4947/* output of current string */ 4948static char *expdest; 4949/* list of back quote expressions */ 4950static struct nodelist *argbackq; 4951/* first struct in list of ifs regions */ 4952static struct ifsregion ifsfirst; 4953/* last struct in list */ 4954static struct ifsregion *ifslastp; 4955/* holds expanded arg list */ 4956static struct arglist exparg; 4957 4958/* 4959 * Our own itoa(). 4960 */ 4961static int 4962cvtnum(arith_t num) 4963{ 4964 int len; 4965 4966 expdest = makestrspace(32, expdest); 4967#if ENABLE_ASH_MATH_SUPPORT_64 4968 len = fmtstr(expdest, 32, "%lld", (long long) num); 4969#else 4970 len = fmtstr(expdest, 32, "%ld", num); 4971#endif 4972 STADJUST(len, expdest); 4973 return len; 4974} 4975 4976static size_t 4977esclen(const char *start, const char *p) 4978{ 4979 size_t esc = 0; 4980 4981 while (p > start && *--p == CTLESC) { 4982 esc++; 4983 } 4984 return esc; 4985} 4986 4987/* 4988 * Remove any CTLESC characters from a string. 4989 */ 4990static char * 4991_rmescapes(char *str, int flag) 4992{ 4993 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' }; 4994 4995 char *p, *q, *r; 4996 unsigned inquotes; 4997 int notescaped; 4998 int globbing; 4999 5000 p = strpbrk(str, qchars); 5001 if (!p) { 5002 return str; 5003 } 5004 q = p; 5005 r = str; 5006 if (flag & RMESCAPE_ALLOC) { 5007 size_t len = p - str; 5008 size_t fulllen = len + strlen(p) + 1; 5009 5010 if (flag & RMESCAPE_GROW) { 5011 r = makestrspace(fulllen, expdest); 5012 } else if (flag & RMESCAPE_HEAP) { 5013 r = ckmalloc(fulllen); 5014 } else { 5015 r = stalloc(fulllen); 5016 } 5017 q = r; 5018 if (len > 0) { 5019 q = memcpy(q, str, len) + len; 5020 } 5021 } 5022 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; 5023 globbing = flag & RMESCAPE_GLOB; 5024 notescaped = globbing; 5025 while (*p) { 5026 if (*p == CTLQUOTEMARK) { 5027 inquotes = ~inquotes; 5028 p++; 5029 notescaped = globbing; 5030 continue; 5031 } 5032 if (*p == '\\') { 5033 /* naked back slash */ 5034 notescaped = 0; 5035 goto copy; 5036 } 5037 if (*p == CTLESC) { 5038 p++; 5039 if (notescaped && inquotes && *p != '/') { 5040 *q++ = '\\'; 5041 } 5042 } 5043 notescaped = globbing; 5044 copy: 5045 *q++ = *p++; 5046 } 5047 *q = '\0'; 5048 if (flag & RMESCAPE_GROW) { 5049 expdest = r; 5050 STADJUST(q - r + 1, expdest); 5051 } 5052 return r; 5053} 5054#define rmescapes(p) _rmescapes((p), 0) 5055 5056#define pmatch(a, b) !fnmatch((a), (b), 0) 5057 5058/* 5059 * Prepare a pattern for a expmeta (internal glob(3)) call. 5060 * 5061 * Returns an stalloced string. 5062 */ 5063static char * 5064preglob(const char *pattern, int quoted, int flag) 5065{ 5066 flag |= RMESCAPE_GLOB; 5067 if (quoted) { 5068 flag |= RMESCAPE_QUOTED; 5069 } 5070 return _rmescapes((char *)pattern, flag); 5071} 5072 5073/* 5074 * Put a string on the stack. 5075 */ 5076static void 5077memtodest(const char *p, size_t len, int syntax, int quotes) 5078{ 5079 char *q = expdest; 5080 5081 q = makestrspace(len * 2, q); 5082 5083 while (len--) { 5084 int c = signed_char2int(*p++); 5085 if (!c) 5086 continue; 5087 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK)) 5088 USTPUTC(CTLESC, q); 5089 USTPUTC(c, q); 5090 } 5091 5092 expdest = q; 5093} 5094 5095static void 5096strtodest(const char *p, int syntax, int quotes) 5097{ 5098 memtodest(p, strlen(p), syntax, quotes); 5099} 5100 5101/* 5102 * Record the fact that we have to scan this region of the 5103 * string for IFS characters. 5104 */ 5105static void 5106recordregion(int start, int end, int nulonly) 5107{ 5108 struct ifsregion *ifsp; 5109 5110 if (ifslastp == NULL) { 5111 ifsp = &ifsfirst; 5112 } else { 5113 INT_OFF; 5114 ifsp = ckmalloc(sizeof(*ifsp)); 5115 ifsp->next = NULL; 5116 ifslastp->next = ifsp; 5117 INT_ON; 5118 } 5119 ifslastp = ifsp; 5120 ifslastp->begoff = start; 5121 ifslastp->endoff = end; 5122 ifslastp->nulonly = nulonly; 5123} 5124 5125static void 5126removerecordregions(int endoff) 5127{ 5128 if (ifslastp == NULL) 5129 return; 5130 5131 if (ifsfirst.endoff > endoff) { 5132 while (ifsfirst.next != NULL) { 5133 struct ifsregion *ifsp; 5134 INT_OFF; 5135 ifsp = ifsfirst.next->next; 5136 free(ifsfirst.next); 5137 ifsfirst.next = ifsp; 5138 INT_ON; 5139 } 5140 if (ifsfirst.begoff > endoff) 5141 ifslastp = NULL; 5142 else { 5143 ifslastp = &ifsfirst; 5144 ifsfirst.endoff = endoff; 5145 } 5146 return; 5147 } 5148 5149 ifslastp = &ifsfirst; 5150 while (ifslastp->next && ifslastp->next->begoff < endoff) 5151 ifslastp=ifslastp->next; 5152 while (ifslastp->next != NULL) { 5153 struct ifsregion *ifsp; 5154 INT_OFF; 5155 ifsp = ifslastp->next->next; 5156 free(ifslastp->next); 5157 ifslastp->next = ifsp; 5158 INT_ON; 5159 } 5160 if (ifslastp->endoff > endoff) 5161 ifslastp->endoff = endoff; 5162} 5163 5164static char * 5165exptilde(char *startp, char *p, int flag) 5166{ 5167 char c; 5168 char *name; 5169 struct passwd *pw; 5170 const char *home; 5171 int quotes = flag & (EXP_FULL | EXP_CASE); 5172 int startloc; 5173 5174 name = p + 1; 5175 5176 while ((c = *++p) != '\0') { 5177 switch (c) { 5178 case CTLESC: 5179 return startp; 5180 case CTLQUOTEMARK: 5181 return startp; 5182 case ':': 5183 if (flag & EXP_VARTILDE) 5184 goto done; 5185 break; 5186 case '/': 5187 case CTLENDVAR: 5188 goto done; 5189 } 5190 } 5191 done: 5192 *p = '\0'; 5193 if (*name == '\0') { 5194 home = lookupvar(homestr); 5195 } else { 5196 pw = getpwnam(name); 5197 if (pw == NULL) 5198 goto lose; 5199 home = pw->pw_dir; 5200 } 5201 if (!home || !*home) 5202 goto lose; 5203 *p = c; 5204 startloc = expdest - (char *)stackblock(); 5205 strtodest(home, SQSYNTAX, quotes); 5206 recordregion(startloc, expdest - (char *)stackblock(), 0); 5207 return p; 5208 lose: 5209 *p = c; 5210 return startp; 5211} 5212 5213/* 5214 * Execute a command inside back quotes. If it's a builtin command, we 5215 * want to save its output in a block obtained from malloc. Otherwise 5216 * we fork off a subprocess and get the output of the command via a pipe. 5217 * Should be called with interrupts off. 5218 */ 5219struct backcmd { /* result of evalbackcmd */ 5220 int fd; /* file descriptor to read from */ 5221 char *buf; /* buffer */ 5222 int nleft; /* number of chars in buffer */ 5223 struct job *jp; /* job structure for command */ 5224}; 5225 5226/* These forward decls are needed to use "eval" code for backticks handling: */ 5227static int back_exitstatus; /* exit status of backquoted command */ 5228#define EV_EXIT 01 /* exit after evaluating tree */ 5229static void evaltree(union node *, int); 5230 5231static void 5232evalbackcmd(union node *n, struct backcmd *result) 5233{ 5234 int saveherefd; 5235 5236 result->fd = -1; 5237 result->buf = NULL; 5238 result->nleft = 0; 5239 result->jp = NULL; 5240 if (n == NULL) { 5241 goto out; 5242 } 5243 5244 saveherefd = herefd; 5245 herefd = -1; 5246 5247 { 5248 int pip[2]; 5249 struct job *jp; 5250 5251 if (pipe(pip) < 0) 5252 ash_msg_and_raise_error("pipe call failed"); 5253 jp = makejob(n, 1); 5254 if (forkshell(jp, n, FORK_NOJOB) == 0) { 5255 FORCE_INT_ON; 5256 close(pip[0]); 5257 if (pip[1] != 1) { 5258 close(1); 5259 copyfd(pip[1], 1); 5260 close(pip[1]); 5261 } 5262 eflag = 0; 5263 evaltree(n, EV_EXIT); /* actually evaltreenr... */ 5264 /* NOTREACHED */ 5265 } 5266 close(pip[1]); 5267 result->fd = pip[0]; 5268 result->jp = jp; 5269 } 5270 herefd = saveherefd; 5271 out: 5272 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 5273 result->fd, result->buf, result->nleft, result->jp)); 5274} 5275 5276/* 5277 * Expand stuff in backwards quotes. 5278 */ 5279static void 5280expbackq(union node *cmd, int quoted, int quotes) 5281{ 5282 struct backcmd in; 5283 int i; 5284 char buf[128]; 5285 char *p; 5286 char *dest; 5287 int startloc; 5288 int syntax = quoted? DQSYNTAX : BASESYNTAX; 5289 struct stackmark smark; 5290 5291 INT_OFF; 5292 setstackmark(&smark); 5293 dest = expdest; 5294 startloc = dest - (char *)stackblock(); 5295 grabstackstr(dest); 5296 evalbackcmd(cmd, &in); 5297 popstackmark(&smark); 5298 5299 p = in.buf; 5300 i = in.nleft; 5301 if (i == 0) 5302 goto read; 5303 for (;;) { 5304 memtodest(p, i, syntax, quotes); 5305 read: 5306 if (in.fd < 0) 5307 break; 5308 i = safe_read(in.fd, buf, sizeof(buf)); 5309 TRACE(("expbackq: read returns %d\n", i)); 5310 if (i <= 0) 5311 break; 5312 p = buf; 5313 } 5314 5315 if (in.buf) 5316 free(in.buf); 5317 if (in.fd >= 0) { 5318 close(in.fd); 5319 back_exitstatus = waitforjob(in.jp); 5320 } 5321 INT_ON; 5322 5323 /* Eat all trailing newlines */ 5324 dest = expdest; 5325 for (; dest > (char *)stackblock() && dest[-1] == '\n';) 5326 STUNPUTC(dest); 5327 expdest = dest; 5328 5329 if (quoted == 0) 5330 recordregion(startloc, dest - (char *)stackblock(), 0); 5331 TRACE(("evalbackq: size=%d: \"%.*s\"\n", 5332 (dest - (char *)stackblock()) - startloc, 5333 (dest - (char *)stackblock()) - startloc, 5334 stackblock() + startloc)); 5335} 5336 5337#if ENABLE_ASH_MATH_SUPPORT 5338/* 5339 * Expand arithmetic expression. Backup to start of expression, 5340 * evaluate, place result in (backed up) result, adjust string position. 5341 */ 5342static void 5343expari(int quotes) 5344{ 5345 char *p, *start; 5346 int begoff; 5347 int flag; 5348 int len; 5349 5350 /* ifsfree(); */ 5351 5352 /* 5353 * This routine is slightly over-complicated for 5354 * efficiency. Next we scan backwards looking for the 5355 * start of arithmetic. 5356 */ 5357 start = stackblock(); 5358 p = expdest - 1; 5359 *p = '\0'; 5360 p--; 5361 do { 5362 int esc; 5363 5364 while (*p != CTLARI) { 5365 p--; 5366#if DEBUG 5367 if (p < start) { 5368 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)"); 5369 } 5370#endif 5371 } 5372 5373 esc = esclen(start, p); 5374 if (!(esc % 2)) { 5375 break; 5376 } 5377 5378 p -= esc + 1; 5379 } while (1); 5380 5381 begoff = p - start; 5382 5383 removerecordregions(begoff); 5384 5385 flag = p[1]; 5386 5387 expdest = p; 5388 5389 if (quotes) 5390 rmescapes(p + 2); 5391 5392 len = cvtnum(dash_arith(p + 2)); 5393 5394 if (flag != '"') 5395 recordregion(begoff, begoff + len, 0); 5396} 5397#endif 5398 5399/* argstr needs it */ 5400static char *evalvar(char *p, int flag); 5401 5402/* 5403 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC 5404 * characters to allow for further processing. Otherwise treat 5405 * $@ like $* since no splitting will be performed. 5406 */ 5407static void 5408argstr(char *p, int flag) 5409{ 5410 static const char spclchars[] ALIGN1 = { 5411 '=', 5412 ':', 5413 CTLQUOTEMARK, 5414 CTLENDVAR, 5415 CTLESC, 5416 CTLVAR, 5417 CTLBACKQ, 5418 CTLBACKQ | CTLQUOTE, 5419#if ENABLE_ASH_MATH_SUPPORT 5420 CTLENDARI, 5421#endif 5422 0 5423 }; 5424 const char *reject = spclchars; 5425 int c; 5426 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ 5427 int breakall = flag & EXP_WORD; 5428 int inquotes; 5429 size_t length; 5430 int startloc; 5431 5432 if (!(flag & EXP_VARTILDE)) { 5433 reject += 2; 5434 } else if (flag & EXP_VARTILDE2) { 5435 reject++; 5436 } 5437 inquotes = 0; 5438 length = 0; 5439 if (flag & EXP_TILDE) { 5440 char *q; 5441 5442 flag &= ~EXP_TILDE; 5443 tilde: 5444 q = p; 5445 if (*q == CTLESC && (flag & EXP_QWORD)) 5446 q++; 5447 if (*q == '~') 5448 p = exptilde(p, q, flag); 5449 } 5450 start: 5451 startloc = expdest - (char *)stackblock(); 5452 for (;;) { 5453 length += strcspn(p + length, reject); 5454 c = p[length]; 5455 if (c && (!(c & 0x80) 5456#if ENABLE_ASH_MATH_SUPPORT 5457 || c == CTLENDARI 5458#endif 5459 )) { 5460 /* c == '=' || c == ':' || c == CTLENDARI */ 5461 length++; 5462 } 5463 if (length > 0) { 5464 int newloc; 5465 expdest = stack_nputstr(p, length, expdest); 5466 newloc = expdest - (char *)stackblock(); 5467 if (breakall && !inquotes && newloc > startloc) { 5468 recordregion(startloc, newloc, 0); 5469 } 5470 startloc = newloc; 5471 } 5472 p += length + 1; 5473 length = 0; 5474 5475 switch (c) { 5476 case '\0': 5477 goto breakloop; 5478 case '=': 5479 if (flag & EXP_VARTILDE2) { 5480 p--; 5481 continue; 5482 } 5483 flag |= EXP_VARTILDE2; 5484 reject++; 5485 /* fall through */ 5486 case ':': 5487 /* 5488 * sort of a hack - expand tildes in variable 5489 * assignments (after the first '=' and after ':'s). 5490 */ 5491 if (*--p == '~') { 5492 goto tilde; 5493 } 5494 continue; 5495 } 5496 5497 switch (c) { 5498 case CTLENDVAR: /* ??? */ 5499 goto breakloop; 5500 case CTLQUOTEMARK: 5501 /* "$@" syntax adherence hack */ 5502 if ( 5503 !inquotes && 5504 !memcmp(p, dolatstr, 4) && 5505 (p[4] == CTLQUOTEMARK || ( 5506 p[4] == CTLENDVAR && 5507 p[5] == CTLQUOTEMARK 5508 )) 5509 ) { 5510 p = evalvar(p + 1, flag) + 1; 5511 goto start; 5512 } 5513 inquotes = !inquotes; 5514 addquote: 5515 if (quotes) { 5516 p--; 5517 length++; 5518 startloc++; 5519 } 5520 break; 5521 case CTLESC: 5522 startloc++; 5523 length++; 5524 goto addquote; 5525 case CTLVAR: 5526 p = evalvar(p, flag); 5527 goto start; 5528 case CTLBACKQ: 5529 c = 0; 5530 case CTLBACKQ|CTLQUOTE: 5531 expbackq(argbackq->n, c, quotes); 5532 argbackq = argbackq->next; 5533 goto start; 5534#if ENABLE_ASH_MATH_SUPPORT 5535 case CTLENDARI: 5536 p--; 5537 expari(quotes); 5538 goto start; 5539#endif 5540 } 5541 } 5542 breakloop: 5543 ; 5544} 5545 5546static char * 5547scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes, 5548 int zero) 5549{ 5550 char *loc; 5551 char *loc2; 5552 char c; 5553 5554 loc = startp; 5555 loc2 = rmesc; 5556 do { 5557 int match; 5558 const char *s = loc2; 5559 c = *loc2; 5560 if (zero) { 5561 *loc2 = '\0'; 5562 s = rmesc; 5563 } 5564 match = pmatch(str, s); 5565 *loc2 = c; 5566 if (match) 5567 return loc; 5568 if (quotes && *loc == CTLESC) 5569 loc++; 5570 loc++; 5571 loc2++; 5572 } while (c); 5573 return 0; 5574} 5575 5576static char * 5577scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes, 5578 int zero) 5579{ 5580 int esc = 0; 5581 char *loc; 5582 char *loc2; 5583 5584 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) { 5585 int match; 5586 char c = *loc2; 5587 const char *s = loc2; 5588 if (zero) { 5589 *loc2 = '\0'; 5590 s = rmesc; 5591 } 5592 match = pmatch(str, s); 5593 *loc2 = c; 5594 if (match) 5595 return loc; 5596 loc--; 5597 if (quotes) { 5598 if (--esc < 0) { 5599 esc = esclen(startp, loc); 5600 } 5601 if (esc % 2) { 5602 esc--; 5603 loc--; 5604 } 5605 } 5606 } 5607 return 0; 5608} 5609 5610static void varunset(const char *, const char *, const char *, int) ATTRIBUTE_NORETURN; 5611static void 5612varunset(const char *end, const char *var, const char *umsg, int varflags) 5613{ 5614 const char *msg; 5615 const char *tail; 5616 5617 tail = nullstr; 5618 msg = "parameter not set"; 5619 if (umsg) { 5620 if (*end == CTLENDVAR) { 5621 if (varflags & VSNUL) 5622 tail = " or null"; 5623 } else 5624 msg = umsg; 5625 } 5626 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail); 5627} 5628 5629static const char * 5630subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes) 5631{ 5632 char *startp; 5633 char *loc; 5634 int saveherefd = herefd; 5635 struct nodelist *saveargbackq = argbackq; 5636 int amount; 5637 char *rmesc, *rmescend; 5638 int zero; 5639 char *(*scan)(char *, char *, char *, char *, int , int); 5640 5641 herefd = -1; 5642 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0); 5643 STPUTC('\0', expdest); 5644 herefd = saveherefd; 5645 argbackq = saveargbackq; 5646 startp = stackblock() + startloc; 5647 5648 switch (subtype) { 5649 case VSASSIGN: 5650 setvar(str, startp, 0); 5651 amount = startp - expdest; 5652 STADJUST(amount, expdest); 5653 return startp; 5654 5655 case VSQUESTION: 5656 varunset(p, str, startp, varflags); 5657 /* NOTREACHED */ 5658 } 5659 5660 subtype -= VSTRIMRIGHT; 5661#if DEBUG 5662 if (subtype < 0 || subtype > 3) 5663 abort(); 5664#endif 5665 5666 rmesc = startp; 5667 rmescend = stackblock() + strloc; 5668 if (quotes) { 5669 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW); 5670 if (rmesc != startp) { 5671 rmescend = expdest; 5672 startp = stackblock() + startloc; 5673 } 5674 } 5675 rmescend--; 5676 str = stackblock() + strloc; 5677 preglob(str, varflags & VSQUOTE, 0); 5678 5679 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */ 5680 zero = subtype >> 1; 5681 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */ 5682 scan = (subtype & 1) ^ zero ? scanleft : scanright; 5683 5684 loc = scan(startp, rmesc, rmescend, str, quotes, zero); 5685 if (loc) { 5686 if (zero) { 5687 memmove(startp, loc, str - loc); 5688 loc = startp + (str - loc) - 1; 5689 } 5690 *loc = '\0'; 5691 amount = loc - expdest; 5692 STADJUST(amount, expdest); 5693 } 5694 return loc; 5695} 5696 5697/* 5698 * Add the value of a specialized variable to the stack string. 5699 */ 5700static ssize_t 5701varvalue(char *name, int varflags, int flags) 5702{ 5703 int num; 5704 char *p; 5705 int i; 5706 int sep = 0; 5707 int sepq = 0; 5708 ssize_t len = 0; 5709 char **ap; 5710 int syntax; 5711 int quoted = varflags & VSQUOTE; 5712 int subtype = varflags & VSTYPE; 5713 int quotes = flags & (EXP_FULL | EXP_CASE); 5714 5715 if (quoted && (flags & EXP_FULL)) 5716 sep = 1 << CHAR_BIT; 5717 5718 syntax = quoted ? DQSYNTAX : BASESYNTAX; 5719 switch (*name) { 5720 case '$': 5721 num = rootpid; 5722 goto numvar; 5723 case '?': 5724 num = exitstatus; 5725 goto numvar; 5726 case '#': 5727 num = shellparam.nparam; 5728 goto numvar; 5729 case '!': 5730 num = backgndpid; 5731 if (num == 0) 5732 return -1; 5733 numvar: 5734 len = cvtnum(num); 5735 break; 5736 case '-': 5737 p = makestrspace(NOPTS, expdest); 5738 for (i = NOPTS - 1; i >= 0; i--) { 5739 if (optlist[i]) { 5740 USTPUTC(optletters(i), p); 5741 len++; 5742 } 5743 } 5744 expdest = p; 5745 break; 5746 case '@': 5747 if (sep) 5748 goto param; 5749 /* fall through */ 5750 case '*': 5751 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' '; 5752 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK)) 5753 sepq = 1; 5754 param: 5755 ap = shellparam.p; 5756 if (!ap) 5757 return -1; 5758 while ((p = *ap++)) { 5759 size_t partlen; 5760 5761 partlen = strlen(p); 5762 len += partlen; 5763 5764 if (!(subtype == VSPLUS || subtype == VSLENGTH)) 5765 memtodest(p, partlen, syntax, quotes); 5766 5767 if (*ap && sep) { 5768 char *q; 5769 5770 len++; 5771 if (subtype == VSPLUS || subtype == VSLENGTH) { 5772 continue; 5773 } 5774 q = expdest; 5775 if (sepq) 5776 STPUTC(CTLESC, q); 5777 STPUTC(sep, q); 5778 expdest = q; 5779 } 5780 } 5781 return len; 5782 case '0': 5783 case '1': 5784 case '2': 5785 case '3': 5786 case '4': 5787 case '5': 5788 case '6': 5789 case '7': 5790 case '8': 5791 case '9': 5792 num = atoi(name); 5793 if (num < 0 || num > shellparam.nparam) 5794 return -1; 5795 p = num ? shellparam.p[num - 1] : arg0; 5796 goto value; 5797 default: 5798 p = lookupvar(name); 5799 value: 5800 if (!p) 5801 return -1; 5802 5803 len = strlen(p); 5804 if (!(subtype == VSPLUS || subtype == VSLENGTH)) 5805 memtodest(p, len, syntax, quotes); 5806 return len; 5807 } 5808 5809 if (subtype == VSPLUS || subtype == VSLENGTH) 5810 STADJUST(-len, expdest); 5811 return len; 5812} 5813 5814/* 5815 * Expand a variable, and return a pointer to the next character in the 5816 * input string. 5817 */ 5818static char * 5819evalvar(char *p, int flag) 5820{ 5821 int subtype; 5822 int varflags; 5823 char *var; 5824 int patloc; 5825 int c; 5826 int startloc; 5827 ssize_t varlen; 5828 int easy; 5829 int quotes; 5830 int quoted; 5831 5832 quotes = flag & (EXP_FULL | EXP_CASE); 5833 varflags = *p++; 5834 subtype = varflags & VSTYPE; 5835 quoted = varflags & VSQUOTE; 5836 var = p; 5837 easy = (!quoted || (*var == '@' && shellparam.nparam)); 5838 startloc = expdest - (char *)stackblock(); 5839 p = strchr(p, '=') + 1; 5840 5841 again: 5842 varlen = varvalue(var, varflags, flag); 5843 if (varflags & VSNUL) 5844 varlen--; 5845 5846 if (subtype == VSPLUS) { 5847 varlen = -1 - varlen; 5848 goto vsplus; 5849 } 5850 5851 if (subtype == VSMINUS) { 5852 vsplus: 5853 if (varlen < 0) { 5854 argstr( 5855 p, flag | EXP_TILDE | 5856 (quoted ? EXP_QWORD : EXP_WORD) 5857 ); 5858 goto end; 5859 } 5860 if (easy) 5861 goto record; 5862 goto end; 5863 } 5864 5865 if (subtype == VSASSIGN || subtype == VSQUESTION) { 5866 if (varlen < 0) { 5867 if (subevalvar(p, var, 0, subtype, startloc, varflags, 0)) { 5868 varflags &= ~VSNUL; 5869 /* 5870 * Remove any recorded regions beyond 5871 * start of variable 5872 */ 5873 removerecordregions(startloc); 5874 goto again; 5875 } 5876 goto end; 5877 } 5878 if (easy) 5879 goto record; 5880 goto end; 5881 } 5882 5883 if (varlen < 0 && uflag) 5884 varunset(p, var, 0, 0); 5885 5886 if (subtype == VSLENGTH) { 5887 cvtnum(varlen > 0 ? varlen : 0); 5888 goto record; 5889 } 5890 5891 if (subtype == VSNORMAL) { 5892 if (!easy) 5893 goto end; 5894 record: 5895 recordregion(startloc, expdest - (char *)stackblock(), quoted); 5896 goto end; 5897 } 5898 5899#if DEBUG 5900 switch (subtype) { 5901 case VSTRIMLEFT: 5902 case VSTRIMLEFTMAX: 5903 case VSTRIMRIGHT: 5904 case VSTRIMRIGHTMAX: 5905 break; 5906 default: 5907 abort(); 5908 } 5909#endif 5910 5911 if (varlen >= 0) { 5912 /* 5913 * Terminate the string and start recording the pattern 5914 * right after it 5915 */ 5916 STPUTC('\0', expdest); 5917 patloc = expdest - (char *)stackblock(); 5918 if (subevalvar(p, NULL, patloc, subtype, 5919 startloc, varflags, quotes) == 0) { 5920 int amount = expdest - ( 5921 (char *)stackblock() + patloc - 1 5922 ); 5923 STADJUST(-amount, expdest); 5924 } 5925 /* Remove any recorded regions beyond start of variable */ 5926 removerecordregions(startloc); 5927 goto record; 5928 } 5929 5930 end: 5931 if (subtype != VSNORMAL) { /* skip to end of alternative */ 5932 int nesting = 1; 5933 for (;;) { 5934 c = *p++; 5935 if (c == CTLESC) 5936 p++; 5937 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { 5938 if (varlen >= 0) 5939 argbackq = argbackq->next; 5940 } else if (c == CTLVAR) { 5941 if ((*p++ & VSTYPE) != VSNORMAL) 5942 nesting++; 5943 } else if (c == CTLENDVAR) { 5944 if (--nesting == 0) 5945 break; 5946 } 5947 } 5948 } 5949 return p; 5950} 5951 5952/* 5953 * Break the argument string into pieces based upon IFS and add the 5954 * strings to the argument list. The regions of the string to be 5955 * searched for IFS characters have been stored by recordregion. 5956 */ 5957static void 5958ifsbreakup(char *string, struct arglist *arglist) 5959{ 5960 struct ifsregion *ifsp; 5961 struct strlist *sp; 5962 char *start; 5963 char *p; 5964 char *q; 5965 const char *ifs, *realifs; 5966 int ifsspc; 5967 int nulonly; 5968 5969 start = string; 5970 if (ifslastp != NULL) { 5971 ifsspc = 0; 5972 nulonly = 0; 5973 realifs = ifsset() ? ifsval() : defifs; 5974 ifsp = &ifsfirst; 5975 do { 5976 p = string + ifsp->begoff; 5977 nulonly = ifsp->nulonly; 5978 ifs = nulonly ? nullstr : realifs; 5979 ifsspc = 0; 5980 while (p < string + ifsp->endoff) { 5981 q = p; 5982 if (*p == CTLESC) 5983 p++; 5984 if (!strchr(ifs, *p)) { 5985 p++; 5986 continue; 5987 } 5988 if (!nulonly) 5989 ifsspc = (strchr(defifs, *p) != NULL); 5990 /* Ignore IFS whitespace at start */ 5991 if (q == start && ifsspc) { 5992 p++; 5993 start = p; 5994 continue; 5995 } 5996 *q = '\0'; 5997 sp = stalloc(sizeof(*sp)); 5998 sp->text = start; 5999 *arglist->lastp = sp; 6000 arglist->lastp = &sp->next; 6001 p++; 6002 if (!nulonly) { 6003 for (;;) { 6004 if (p >= string + ifsp->endoff) { 6005 break; 6006 } 6007 q = p; 6008 if (*p == CTLESC) 6009 p++; 6010 if (strchr(ifs, *p) == NULL ) { 6011 p = q; 6012 break; 6013 } else if (strchr(defifs, *p) == NULL) { 6014 if (ifsspc) { 6015 p++; 6016 ifsspc = 0; 6017 } else { 6018 p = q; 6019 break; 6020 } 6021 } else 6022 p++; 6023 } 6024 } 6025 start = p; 6026 } /* while */ 6027 ifsp = ifsp->next; 6028 } while (ifsp != NULL); 6029 if (nulonly) 6030 goto add; 6031 } 6032 6033 if (!*start) 6034 return; 6035 6036 add: 6037 sp = stalloc(sizeof(*sp)); 6038 sp->text = start; 6039 *arglist->lastp = sp; 6040 arglist->lastp = &sp->next; 6041} 6042 6043static void 6044ifsfree(void) 6045{ 6046 struct ifsregion *p; 6047 6048 INT_OFF; 6049 p = ifsfirst.next; 6050 do { 6051 struct ifsregion *ifsp; 6052 ifsp = p->next; 6053 free(p); 6054 p = ifsp; 6055 } while (p); 6056 ifslastp = NULL; 6057 ifsfirst.next = NULL; 6058 INT_ON; 6059} 6060 6061/* 6062 * Add a file name to the list. 6063 */ 6064static void 6065addfname(const char *name) 6066{ 6067 struct strlist *sp; 6068 6069 sp = stalloc(sizeof(*sp)); 6070 sp->text = ststrdup(name); 6071 *exparg.lastp = sp; 6072 exparg.lastp = &sp->next; 6073} 6074 6075static char *expdir; 6076 6077/* 6078 * Do metacharacter (i.e. *, ?, [...]) expansion. 6079 */ 6080static void 6081expmeta(char *enddir, char *name) 6082{ 6083 char *p; 6084 const char *cp; 6085 char *start; 6086 char *endname; 6087 int metaflag; 6088 struct stat statb; 6089 DIR *dirp; 6090 struct dirent *dp; 6091 int atend; 6092 int matchdot; 6093 6094 metaflag = 0; 6095 start = name; 6096 for (p = name; *p; p++) { 6097 if (*p == '*' || *p == '?') 6098 metaflag = 1; 6099 else if (*p == '[') { 6100 char *q = p + 1; 6101 if (*q == '!') 6102 q++; 6103 for (;;) { 6104 if (*q == '\\') 6105 q++; 6106 if (*q == '/' || *q == '\0') 6107 break; 6108 if (*++q == ']') { 6109 metaflag = 1; 6110 break; 6111 } 6112 } 6113 } else if (*p == '\\') 6114 p++; 6115 else if (*p == '/') { 6116 if (metaflag) 6117 goto out; 6118 start = p + 1; 6119 } 6120 } 6121 out: 6122 if (metaflag == 0) { /* we've reached the end of the file name */ 6123 if (enddir != expdir) 6124 metaflag++; 6125 p = name; 6126 do { 6127 if (*p == '\\') 6128 p++; 6129 *enddir++ = *p; 6130 } while (*p++); 6131 if (metaflag == 0 || lstat(expdir, &statb) >= 0) 6132 addfname(expdir); 6133 return; 6134 } 6135 endname = p; 6136 if (name < start) { 6137 p = name; 6138 do { 6139 if (*p == '\\') 6140 p++; 6141 *enddir++ = *p++; 6142 } while (p < start); 6143 } 6144 if (enddir == expdir) { 6145 cp = "."; 6146 } else if (enddir == expdir + 1 && *expdir == '/') { 6147 cp = "/"; 6148 } else { 6149 cp = expdir; 6150 enddir[-1] = '\0'; 6151 } 6152 dirp = opendir(cp); 6153 if (dirp == NULL) 6154 return; 6155 if (enddir != expdir) 6156 enddir[-1] = '/'; 6157 if (*endname == 0) { 6158 atend = 1; 6159 } else { 6160 atend = 0; 6161 *endname++ = '\0'; 6162 } 6163 matchdot = 0; 6164 p = start; 6165 if (*p == '\\') 6166 p++; 6167 if (*p == '.') 6168 matchdot++; 6169 while (! intpending && (dp = readdir(dirp)) != NULL) { 6170 if (dp->d_name[0] == '.' && ! matchdot) 6171 continue; 6172 if (pmatch(start, dp->d_name)) { 6173 if (atend) { 6174 strcpy(enddir, dp->d_name); 6175 addfname(expdir); 6176 } else { 6177 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';) 6178 continue; 6179 p[-1] = '/'; 6180 expmeta(p, endname); 6181 } 6182 } 6183 } 6184 closedir(dirp); 6185 if (! atend) 6186 endname[-1] = '/'; 6187} 6188 6189static struct strlist * 6190msort(struct strlist *list, int len) 6191{ 6192 struct strlist *p, *q = NULL; 6193 struct strlist **lpp; 6194 int half; 6195 int n; 6196 6197 if (len <= 1) 6198 return list; 6199 half = len >> 1; 6200 p = list; 6201 for (n = half; --n >= 0; ) { 6202 q = p; 6203 p = p->next; 6204 } 6205 q->next = NULL; /* terminate first half of list */ 6206 q = msort(list, half); /* sort first half of list */ 6207 p = msort(p, len - half); /* sort second half */ 6208 lpp = &list; 6209 for (;;) { 6210#if ENABLE_LOCALE_SUPPORT 6211 if (strcoll(p->text, q->text) < 0) 6212#else 6213 if (strcmp(p->text, q->text) < 0) 6214#endif 6215 { 6216 *lpp = p; 6217 lpp = &p->next; 6218 p = *lpp; 6219 if (p == NULL) { 6220 *lpp = q; 6221 break; 6222 } 6223 } else { 6224 *lpp = q; 6225 lpp = &q->next; 6226 q = *lpp; 6227 if (q == NULL) { 6228 *lpp = p; 6229 break; 6230 } 6231 } 6232 } 6233 return list; 6234} 6235 6236/* 6237 * Sort the results of file name expansion. It calculates the number of 6238 * strings to sort and then calls msort (short for merge sort) to do the 6239 * work. 6240 */ 6241static struct strlist * 6242expsort(struct strlist *str) 6243{ 6244 int len; 6245 struct strlist *sp; 6246 6247 len = 0; 6248 for (sp = str; sp; sp = sp->next) 6249 len++; 6250 return msort(str, len); 6251} 6252 6253static void 6254expandmeta(struct strlist *str, int flag) 6255{ 6256 static const char metachars[] ALIGN1 = { 6257 '*', '?', '[', 0 6258 }; 6259 /* TODO - EXP_REDIR */ 6260 6261 while (str) { 6262 struct strlist **savelastp; 6263 struct strlist *sp; 6264 char *p; 6265 6266 if (fflag) 6267 goto nometa; 6268 if (!strpbrk(str->text, metachars)) 6269 goto nometa; 6270 savelastp = exparg.lastp; 6271 6272 INT_OFF; 6273 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); 6274 { 6275 int i = strlen(str->text); 6276 expdir = ckmalloc(i < 2048 ? 2048 : i); 6277 } 6278 6279 expmeta(expdir, p); 6280 free(expdir); 6281 if (p != str->text) 6282 free(p); 6283 INT_ON; 6284 if (exparg.lastp == savelastp) { 6285 /* 6286 * no matches 6287 */ 6288 nometa: 6289 *exparg.lastp = str; 6290 rmescapes(str->text); 6291 exparg.lastp = &str->next; 6292 } else { 6293 *exparg.lastp = NULL; 6294 *savelastp = sp = expsort(*savelastp); 6295 while (sp->next != NULL) 6296 sp = sp->next; 6297 exparg.lastp = &sp->next; 6298 } 6299 str = str->next; 6300 } 6301} 6302 6303/* 6304 * Perform variable substitution and command substitution on an argument, 6305 * placing the resulting list of arguments in arglist. If EXP_FULL is true, 6306 * perform splitting and file name expansion. When arglist is NULL, perform 6307 * here document expansion. 6308 */ 6309static void 6310expandarg(union node *arg, struct arglist *arglist, int flag) 6311{ 6312 struct strlist *sp; 6313 char *p; 6314 6315 argbackq = arg->narg.backquote; 6316 STARTSTACKSTR(expdest); 6317 ifsfirst.next = NULL; 6318 ifslastp = NULL; 6319 argstr(arg->narg.text, flag); 6320 p = _STPUTC('\0', expdest); 6321 expdest = p - 1; 6322 if (arglist == NULL) { 6323 return; /* here document expanded */ 6324 } 6325 p = grabstackstr(p); 6326 exparg.lastp = &exparg.list; 6327 /* 6328 * TODO - EXP_REDIR 6329 */ 6330 if (flag & EXP_FULL) { 6331 ifsbreakup(p, &exparg); 6332 *exparg.lastp = NULL; 6333 exparg.lastp = &exparg.list; 6334 expandmeta(exparg.list, flag); 6335 } else { 6336 if (flag & EXP_REDIR) 6337 rmescapes(p); 6338 sp = stalloc(sizeof(*sp)); 6339 sp->text = p; 6340 *exparg.lastp = sp; 6341 exparg.lastp = &sp->next; 6342 } 6343 if (ifsfirst.next) 6344 ifsfree(); 6345 *exparg.lastp = NULL; 6346 if (exparg.list) { 6347 *arglist->lastp = exparg.list; 6348 arglist->lastp = exparg.lastp; 6349 } 6350} 6351 6352/* 6353 * Expand shell variables and backquotes inside a here document. 6354 */ 6355static void 6356expandhere(union node *arg, int fd) 6357{ 6358 herefd = fd; 6359 expandarg(arg, (struct arglist *)NULL, 0); 6360 full_write(fd, stackblock(), expdest - (char *)stackblock()); 6361} 6362 6363/* 6364 * Returns true if the pattern matches the string. 6365 */ 6366static int 6367patmatch(char *pattern, const char *string) 6368{ 6369 return pmatch(preglob(pattern, 0, 0), string); 6370} 6371 6372/* 6373 * See if a pattern matches in a case statement. 6374 */ 6375static int 6376casematch(union node *pattern, char *val) 6377{ 6378 struct stackmark smark; 6379 int result; 6380 6381 setstackmark(&smark); 6382 argbackq = pattern->narg.backquote; 6383 STARTSTACKSTR(expdest); 6384 ifslastp = NULL; 6385 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); 6386 STACKSTRNUL(expdest); 6387 result = patmatch(stackblock(), val); 6388 popstackmark(&smark); 6389 return result; 6390} 6391 6392 6393/* ============ find_command */ 6394 6395struct builtincmd { 6396 const char *name; 6397 int (*builtin)(int, char **); 6398 /* unsigned flags; */ 6399}; 6400#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1) 6401#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2) 6402#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4) 6403 6404struct cmdentry { 6405 int cmdtype; 6406 union param { 6407 int index; 6408 const struct builtincmd *cmd; 6409 struct funcnode *func; 6410 } u; 6411}; 6412/* values of cmdtype */ 6413#define CMDUNKNOWN -1 /* no entry in table for command */ 6414#define CMDNORMAL 0 /* command is an executable program */ 6415#define CMDFUNCTION 1 /* command is a shell function */ 6416#define CMDBUILTIN 2 /* command is a shell builtin */ 6417 6418/* action to find_command() */ 6419#define DO_ERR 0x01 /* prints errors */ 6420#define DO_ABS 0x02 /* checks absolute paths */ 6421#define DO_NOFUNC 0x04 /* don't return shell functions, for command */ 6422#define DO_ALTPATH 0x08 /* using alternate path */ 6423#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */ 6424 6425static void find_command(char *, struct cmdentry *, int, const char *); 6426 6427 6428/* ============ Hashing commands */ 6429 6430/* 6431 * When commands are first encountered, they are entered in a hash table. 6432 * This ensures that a full path search will not have to be done for them 6433 * on each invocation. 6434 * 6435 * We should investigate converting to a linear search, even though that 6436 * would make the command name "hash" a misnomer. 6437 */ 6438 6439#define CMDTABLESIZE 31 /* should be prime */ 6440#define ARB 1 /* actual size determined at run time */ 6441 6442struct tblentry { 6443 struct tblentry *next; /* next entry in hash chain */ 6444 union param param; /* definition of builtin function */ 6445 short cmdtype; /* index identifying command */ 6446 char rehash; /* if set, cd done since entry created */ 6447 char cmdname[ARB]; /* name of command */ 6448}; 6449 6450static struct tblentry *cmdtable[CMDTABLESIZE]; 6451static int builtinloc = -1; /* index in path of %builtin, or -1 */ 6452 6453static void 6454tryexec(char *cmd, char **argv, char **envp) 6455{ 6456 int repeated = 0; 6457 6458#if ENABLE_FEATURE_SH_STANDALONE 6459 if (strchr(cmd, '/') == NULL) { 6460 const struct bb_applet *a; 6461 6462 a = find_applet_by_name(cmd); 6463 if (a) { 6464 if (a->noexec) { 6465 current_applet = a; 6466 run_current_applet_and_exit(argv); 6467 } 6468 /* re-exec ourselves with the new arguments */ 6469 execve(bb_busybox_exec_path, argv, envp); 6470 /* If they called chroot or otherwise made the binary no longer 6471 * executable, fall through */ 6472 } 6473 } 6474#endif 6475 6476 repeat: 6477#ifdef SYSV 6478 do { 6479 execve(cmd, argv, envp); 6480 } while (errno == EINTR); 6481#else 6482 execve(cmd, argv, envp); 6483#endif 6484 if (repeated++) { 6485 free(argv); 6486 } else if (errno == ENOEXEC) { 6487 char **ap; 6488 char **new; 6489 6490 for (ap = argv; *ap; ap++) 6491 ; 6492 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *)); 6493 ap[1] = cmd; 6494 ap[0] = cmd = (char *)DEFAULT_SHELL; 6495 ap += 2; 6496 argv++; 6497 while ((*ap++ = *argv++)) 6498 ; 6499 argv = new; 6500 goto repeat; 6501 } 6502} 6503 6504/* 6505 * Exec a program. Never returns. If you change this routine, you may 6506 * have to change the find_command routine as well. 6507 */ 6508#define environment() listvars(VEXPORT, VUNSET, 0) 6509static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN; 6510static void 6511shellexec(char **argv, const char *path, int idx) 6512{ 6513 char *cmdname; 6514 int e; 6515 char **envp; 6516 int exerrno; 6517 6518 clearredir(1); 6519 envp = environment(); 6520 if (strchr(argv[0], '/') 6521#if ENABLE_FEATURE_SH_STANDALONE 6522 || find_applet_by_name(argv[0]) 6523#endif 6524 ) { 6525 tryexec(argv[0], argv, envp); 6526 e = errno; 6527 } else { 6528 e = ENOENT; 6529 while ((cmdname = padvance(&path, argv[0])) != NULL) { 6530 if (--idx < 0 && pathopt == NULL) { 6531 tryexec(cmdname, argv, envp); 6532 if (errno != ENOENT && errno != ENOTDIR) 6533 e = errno; 6534 } 6535 stunalloc(cmdname); 6536 } 6537 } 6538 6539 /* Map to POSIX errors */ 6540 switch (e) { 6541 case EACCES: 6542 exerrno = 126; 6543 break; 6544 case ENOENT: 6545 exerrno = 127; 6546 break; 6547 default: 6548 exerrno = 2; 6549 break; 6550 } 6551 exitstatus = exerrno; 6552 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n", 6553 argv[0], e, suppressint )); 6554 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found")); 6555 /* NOTREACHED */ 6556} 6557 6558static void 6559printentry(struct tblentry *cmdp) 6560{ 6561 int idx; 6562 const char *path; 6563 char *name; 6564 6565 idx = cmdp->param.index; 6566 path = pathval(); 6567 do { 6568 name = padvance(&path, cmdp->cmdname); 6569 stunalloc(name); 6570 } while (--idx >= 0); 6571 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); 6572} 6573 6574/* 6575 * Clear out command entries. The argument specifies the first entry in 6576 * PATH which has changed. 6577 */ 6578static void 6579clearcmdentry(int firstchange) 6580{ 6581 struct tblentry **tblp; 6582 struct tblentry **pp; 6583 struct tblentry *cmdp; 6584 6585 INT_OFF; 6586 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) { 6587 pp = tblp; 6588 while ((cmdp = *pp) != NULL) { 6589 if ((cmdp->cmdtype == CMDNORMAL && 6590 cmdp->param.index >= firstchange) 6591 || (cmdp->cmdtype == CMDBUILTIN && 6592 builtinloc >= firstchange) 6593 ) { 6594 *pp = cmdp->next; 6595 free(cmdp); 6596 } else { 6597 pp = &cmdp->next; 6598 } 6599 } 6600 } 6601 INT_ON; 6602} 6603 6604/* 6605 * Locate a command in the command hash table. If "add" is nonzero, 6606 * add the command to the table if it is not already present. The 6607 * variable "lastcmdentry" is set to point to the address of the link 6608 * pointing to the entry, so that delete_cmd_entry can delete the 6609 * entry. 6610 * 6611 * Interrupts must be off if called with add != 0. 6612 */ 6613static struct tblentry **lastcmdentry; 6614 6615static struct tblentry * 6616cmdlookup(const char *name, int add) 6617{ 6618 unsigned int hashval; 6619 const char *p; 6620 struct tblentry *cmdp; 6621 struct tblentry **pp; 6622 6623 p = name; 6624 hashval = (unsigned char)*p << 4; 6625 while (*p) 6626 hashval += (unsigned char)*p++; 6627 hashval &= 0x7FFF; 6628 pp = &cmdtable[hashval % CMDTABLESIZE]; 6629 for (cmdp = *pp; cmdp; cmdp = cmdp->next) { 6630 if (strcmp(cmdp->cmdname, name) == 0) 6631 break; 6632 pp = &cmdp->next; 6633 } 6634 if (add && cmdp == NULL) { 6635 cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB 6636 + strlen(name) + 1); 6637 cmdp->next = NULL; 6638 cmdp->cmdtype = CMDUNKNOWN; 6639 strcpy(cmdp->cmdname, name); 6640 } 6641 lastcmdentry = pp; 6642 return cmdp; 6643} 6644 6645/* 6646 * Delete the command entry returned on the last lookup. 6647 */ 6648static void 6649delete_cmd_entry(void) 6650{ 6651 struct tblentry *cmdp; 6652 6653 INT_OFF; 6654 cmdp = *lastcmdentry; 6655 *lastcmdentry = cmdp->next; 6656 if (cmdp->cmdtype == CMDFUNCTION) 6657 freefunc(cmdp->param.func); 6658 free(cmdp); 6659 INT_ON; 6660} 6661 6662/* 6663 * Add a new command entry, replacing any existing command entry for 6664 * the same name - except special builtins. 6665 */ 6666static void 6667addcmdentry(char *name, struct cmdentry *entry) 6668{ 6669 struct tblentry *cmdp; 6670 6671 cmdp = cmdlookup(name, 1); 6672 if (cmdp->cmdtype == CMDFUNCTION) { 6673 freefunc(cmdp->param.func); 6674 } 6675 cmdp->cmdtype = entry->cmdtype; 6676 cmdp->param = entry->u; 6677 cmdp->rehash = 0; 6678} 6679 6680static int 6681hashcmd(int argc, char **argv) 6682{ 6683 struct tblentry **pp; 6684 struct tblentry *cmdp; 6685 int c; 6686 struct cmdentry entry; 6687 char *name; 6688 6689 while ((c = nextopt("r")) != '\0') { 6690 clearcmdentry(0); 6691 return 0; 6692 } 6693 if (*argptr == NULL) { 6694 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) { 6695 for (cmdp = *pp; cmdp; cmdp = cmdp->next) { 6696 if (cmdp->cmdtype == CMDNORMAL) 6697 printentry(cmdp); 6698 } 6699 } 6700 return 0; 6701 } 6702 c = 0; 6703 while ((name = *argptr) != NULL) { 6704 cmdp = cmdlookup(name, 0); 6705 if (cmdp != NULL 6706 && (cmdp->cmdtype == CMDNORMAL 6707 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) 6708 delete_cmd_entry(); 6709 find_command(name, &entry, DO_ERR, pathval()); 6710 if (entry.cmdtype == CMDUNKNOWN) 6711 c = 1; 6712 argptr++; 6713 } 6714 return c; 6715} 6716 6717/* 6718 * Called when a cd is done. Marks all commands so the next time they 6719 * are executed they will be rehashed. 6720 */ 6721static void 6722hashcd(void) 6723{ 6724 struct tblentry **pp; 6725 struct tblentry *cmdp; 6726 6727 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) { 6728 for (cmdp = *pp; cmdp; cmdp = cmdp->next) { 6729 if (cmdp->cmdtype == CMDNORMAL || ( 6730 cmdp->cmdtype == CMDBUILTIN && 6731 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) && 6732 builtinloc > 0 6733 )) 6734 cmdp->rehash = 1; 6735 } 6736 } 6737} 6738 6739/* 6740 * Fix command hash table when PATH changed. 6741 * Called before PATH is changed. The argument is the new value of PATH; 6742 * pathval() still returns the old value at this point. 6743 * Called with interrupts off. 6744 */ 6745static void 6746changepath(const char *newval) 6747{ 6748 const char *old, *new; 6749 int idx; 6750 int firstchange; 6751 int idx_bltin; 6752 6753 old = pathval(); 6754 new = newval; 6755 firstchange = 9999; /* assume no change */ 6756 idx = 0; 6757 idx_bltin = -1; 6758 for (;;) { 6759 if (*old != *new) { 6760 firstchange = idx; 6761 if ((*old == '\0' && *new == ':') 6762 || (*old == ':' && *new == '\0')) 6763 firstchange++; 6764 old = new; /* ignore subsequent differences */ 6765 } 6766 if (*new == '\0') 6767 break; 6768 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin")) 6769 idx_bltin = idx; 6770 if (*new == ':') { 6771 idx++; 6772 } 6773 new++, old++; 6774 } 6775 if (builtinloc < 0 && idx_bltin >= 0) 6776 builtinloc = idx_bltin; /* zap builtins */ 6777 if (builtinloc >= 0 && idx_bltin < 0) 6778 firstchange = 0; 6779 clearcmdentry(firstchange); 6780 builtinloc = idx_bltin; 6781} 6782 6783#define TEOF 0 6784#define TNL 1 6785#define TREDIR 2 6786#define TWORD 3 6787#define TSEMI 4 6788#define TBACKGND 5 6789#define TAND 6 6790#define TOR 7 6791#define TPIPE 8 6792#define TLP 9 6793#define TRP 10 6794#define TENDCASE 11 6795#define TENDBQUOTE 12 6796#define TNOT 13 6797#define TCASE 14 6798#define TDO 15 6799#define TDONE 16 6800#define TELIF 17 6801#define TELSE 18 6802#define TESAC 19 6803#define TFI 20 6804#define TFOR 21 6805#define TIF 22 6806#define TIN 23 6807#define TTHEN 24 6808#define TUNTIL 25 6809#define TWHILE 26 6810#define TBEGIN 27 6811#define TEND 28 6812 6813/* first char is indicating which tokens mark the end of a list */ 6814static const char *const tokname_array[] = { 6815 "\1end of file", 6816 "\0newline", 6817 "\0redirection", 6818 "\0word", 6819 "\0;", 6820 "\0&", 6821 "\0&&", 6822 "\0||", 6823 "\0|", 6824 "\0(", 6825 "\1)", 6826 "\1;;", 6827 "\1`", 6828#define KWDOFFSET 13 6829 /* the following are keywords */ 6830 "\0!", 6831 "\0case", 6832 "\1do", 6833 "\1done", 6834 "\1elif", 6835 "\1else", 6836 "\1esac", 6837 "\1fi", 6838 "\0for", 6839 "\0if", 6840 "\0in", 6841 "\1then", 6842 "\0until", 6843 "\0while", 6844 "\0{", 6845 "\1}", 6846}; 6847 6848static const char * 6849tokname(int tok) 6850{ 6851 static char buf[16]; 6852 6853//try this: 6854//if (tok < TSEMI) return tokname_array[tok] + 1; 6855//sprintf(buf, "\"%s\"", tokname_array[tok] + 1); 6856//return buf; 6857 6858 if (tok >= TSEMI) 6859 buf[0] = '"'; 6860 sprintf(buf + (tok >= TSEMI), "%s%c", 6861 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0)); 6862 return buf; 6863} 6864 6865/* Wrapper around strcmp for qsort/bsearch/... */ 6866static int 6867pstrcmp(const void *a, const void *b) 6868{ 6869 return strcmp((char*) a, (*(char**) b) + 1); 6870} 6871 6872static const char *const * 6873findkwd(const char *s) 6874{ 6875 return bsearch(s, tokname_array + KWDOFFSET, 6876 ARRAY_SIZE(tokname_array) - KWDOFFSET, 6877 sizeof(tokname_array[0]), pstrcmp); 6878} 6879 6880/* 6881 * Locate and print what a word is... 6882 */ 6883static int 6884describe_command(char *command, int describe_command_verbose) 6885{ 6886 struct cmdentry entry; 6887 struct tblentry *cmdp; 6888#if ENABLE_ASH_ALIAS 6889 const struct alias *ap; 6890#endif 6891 const char *path = pathval(); 6892 6893 if (describe_command_verbose) { 6894 out1str(command); 6895 } 6896 6897 /* First look at the keywords */ 6898 if (findkwd(command)) { 6899 out1str(describe_command_verbose ? " is a shell keyword" : command); 6900 goto out; 6901 } 6902 6903#if ENABLE_ASH_ALIAS 6904 /* Then look at the aliases */ 6905 ap = lookupalias(command, 0); 6906 if (ap != NULL) { 6907 if (!describe_command_verbose) { 6908 out1str("alias "); 6909 printalias(ap); 6910 return 0; 6911 } 6912 out1fmt(" is an alias for %s", ap->val); 6913 goto out; 6914 } 6915#endif 6916 /* Then check if it is a tracked alias */ 6917 cmdp = cmdlookup(command, 0); 6918 if (cmdp != NULL) { 6919 entry.cmdtype = cmdp->cmdtype; 6920 entry.u = cmdp->param; 6921 } else { 6922 /* Finally use brute force */ 6923 find_command(command, &entry, DO_ABS, path); 6924 } 6925 6926 switch (entry.cmdtype) { 6927 case CMDNORMAL: { 6928 int j = entry.u.index; 6929 char *p; 6930 if (j == -1) { 6931 p = command; 6932 } else { 6933 do { 6934 p = padvance(&path, command); 6935 stunalloc(p); 6936 } while (--j >= 0); 6937 } 6938 if (describe_command_verbose) { 6939 out1fmt(" is%s %s", 6940 (cmdp ? " a tracked alias for" : nullstr), p 6941 ); 6942 } else { 6943 out1str(p); 6944 } 6945 break; 6946 } 6947 6948 case CMDFUNCTION: 6949 if (describe_command_verbose) { 6950 out1str(" is a shell function"); 6951 } else { 6952 out1str(command); 6953 } 6954 break; 6955 6956 case CMDBUILTIN: 6957 if (describe_command_verbose) { 6958 out1fmt(" is a %sshell builtin", 6959 IS_BUILTIN_SPECIAL(entry.u.cmd) ? 6960 "special " : nullstr 6961 ); 6962 } else { 6963 out1str(command); 6964 } 6965 break; 6966 6967 default: 6968 if (describe_command_verbose) { 6969 out1str(": not found\n"); 6970 } 6971 return 127; 6972 } 6973 out: 6974 outstr("\n", stdout); 6975 return 0; 6976} 6977 6978static int 6979typecmd(int argc, char **argv) 6980{ 6981 int i = 1; 6982 int err = 0; 6983 int verbose = 1; 6984 6985 /* type -p ... ? (we don't bother checking for 'p') */ 6986 if (argv[1] && argv[1][0] == '-') { 6987 i++; 6988 verbose = 0; 6989 } 6990 while (i < argc) { 6991 err |= describe_command(argv[i++], verbose); 6992 } 6993 return err; 6994} 6995 6996#if ENABLE_ASH_CMDCMD 6997static int 6998commandcmd(int argc, char **argv) 6999{ 7000 int c; 7001 enum { 7002 VERIFY_BRIEF = 1, 7003 VERIFY_VERBOSE = 2, 7004 } verify = 0; 7005 7006 while ((c = nextopt("pvV")) != '\0') 7007 if (c == 'V') 7008 verify |= VERIFY_VERBOSE; 7009 else if (c == 'v') 7010 verify |= VERIFY_BRIEF; 7011#if DEBUG 7012 else if (c != 'p') 7013 abort(); 7014#endif 7015 if (verify) 7016 return describe_command(*argptr, verify - VERIFY_BRIEF); 7017 7018 return 0; 7019} 7020#endif 7021 7022 7023/* ============ eval.c */ 7024 7025static int funcblocksize; /* size of structures in function */ 7026static int funcstringsize; /* size of strings in node */ 7027static void *funcblock; /* block to allocate function from */ 7028static char *funcstring; /* block to allocate strings from */ 7029 7030/* flags in argument to evaltree */ 7031#define EV_EXIT 01 /* exit after evaluating tree */ 7032#define EV_TESTED 02 /* exit status is checked; ignore -e flag */ 7033#define EV_BACKCMD 04 /* command executing within back quotes */ 7034 7035static const short nodesize[26] = { 7036 SHELL_ALIGN(sizeof(struct ncmd)), 7037 SHELL_ALIGN(sizeof(struct npipe)), 7038 SHELL_ALIGN(sizeof(struct nredir)), 7039 SHELL_ALIGN(sizeof(struct nredir)), 7040 SHELL_ALIGN(sizeof(struct nredir)), 7041 SHELL_ALIGN(sizeof(struct nbinary)), 7042 SHELL_ALIGN(sizeof(struct nbinary)), 7043 SHELL_ALIGN(sizeof(struct nbinary)), 7044 SHELL_ALIGN(sizeof(struct nif)), 7045 SHELL_ALIGN(sizeof(struct nbinary)), 7046 SHELL_ALIGN(sizeof(struct nbinary)), 7047 SHELL_ALIGN(sizeof(struct nfor)), 7048 SHELL_ALIGN(sizeof(struct ncase)), 7049 SHELL_ALIGN(sizeof(struct nclist)), 7050 SHELL_ALIGN(sizeof(struct narg)), 7051 SHELL_ALIGN(sizeof(struct narg)), 7052 SHELL_ALIGN(sizeof(struct nfile)), 7053 SHELL_ALIGN(sizeof(struct nfile)), 7054 SHELL_ALIGN(sizeof(struct nfile)), 7055 SHELL_ALIGN(sizeof(struct nfile)), 7056 SHELL_ALIGN(sizeof(struct nfile)), 7057 SHELL_ALIGN(sizeof(struct ndup)), 7058 SHELL_ALIGN(sizeof(struct ndup)), 7059 SHELL_ALIGN(sizeof(struct nhere)), 7060 SHELL_ALIGN(sizeof(struct nhere)), 7061 SHELL_ALIGN(sizeof(struct nnot)), 7062}; 7063 7064static void calcsize(union node *n); 7065 7066static void 7067sizenodelist(struct nodelist *lp) 7068{ 7069 while (lp) { 7070 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); 7071 calcsize(lp->n); 7072 lp = lp->next; 7073 } 7074} 7075 7076static void 7077calcsize(union node *n) 7078{ 7079 if (n == NULL) 7080 return; 7081 funcblocksize += nodesize[n->type]; 7082 switch (n->type) { 7083 case NCMD: 7084 calcsize(n->ncmd.redirect); 7085 calcsize(n->ncmd.args); 7086 calcsize(n->ncmd.assign); 7087 break; 7088 case NPIPE: 7089 sizenodelist(n->npipe.cmdlist); 7090 break; 7091 case NREDIR: 7092 case NBACKGND: 7093 case NSUBSHELL: 7094 calcsize(n->nredir.redirect); 7095 calcsize(n->nredir.n); 7096 break; 7097 case NAND: 7098 case NOR: 7099 case NSEMI: 7100 case NWHILE: 7101 case NUNTIL: 7102 calcsize(n->nbinary.ch2); 7103 calcsize(n->nbinary.ch1); 7104 break; 7105 case NIF: 7106 calcsize(n->nif.elsepart); 7107 calcsize(n->nif.ifpart); 7108 calcsize(n->nif.test); 7109 break; 7110 case NFOR: 7111 funcstringsize += strlen(n->nfor.var) + 1; 7112 calcsize(n->nfor.body); 7113 calcsize(n->nfor.args); 7114 break; 7115 case NCASE: 7116 calcsize(n->ncase.cases); 7117 calcsize(n->ncase.expr); 7118 break; 7119 case NCLIST: 7120 calcsize(n->nclist.body); 7121 calcsize(n->nclist.pattern); 7122 calcsize(n->nclist.next); 7123 break; 7124 case NDEFUN: 7125 case NARG: 7126 sizenodelist(n->narg.backquote); 7127 funcstringsize += strlen(n->narg.text) + 1; 7128 calcsize(n->narg.next); 7129 break; 7130 case NTO: 7131 case NCLOBBER: 7132 case NFROM: 7133 case NFROMTO: 7134 case NAPPEND: 7135 calcsize(n->nfile.fname); 7136 calcsize(n->nfile.next); 7137 break; 7138 case NTOFD: 7139 case NFROMFD: 7140 calcsize(n->ndup.vname); 7141 calcsize(n->ndup.next); 7142 break; 7143 case NHERE: 7144 case NXHERE: 7145 calcsize(n->nhere.doc); 7146 calcsize(n->nhere.next); 7147 break; 7148 case NNOT: 7149 calcsize(n->nnot.com); 7150 break; 7151 }; 7152} 7153 7154static char * 7155nodeckstrdup(char *s) 7156{ 7157 char *rtn = funcstring; 7158 7159 strcpy(funcstring, s); 7160 funcstring += strlen(s) + 1; 7161 return rtn; 7162} 7163 7164static union node *copynode(union node *); 7165 7166static struct nodelist * 7167copynodelist(struct nodelist *lp) 7168{ 7169 struct nodelist *start; 7170 struct nodelist **lpp; 7171 7172 lpp = &start; 7173 while (lp) { 7174 *lpp = funcblock; 7175 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); 7176 (*lpp)->n = copynode(lp->n); 7177 lp = lp->next; 7178 lpp = &(*lpp)->next; 7179 } 7180 *lpp = NULL; 7181 return start; 7182} 7183 7184static union node * 7185copynode(union node *n) 7186{ 7187 union node *new; 7188 7189 if (n == NULL) 7190 return NULL; 7191 new = funcblock; 7192 funcblock = (char *) funcblock + nodesize[n->type]; 7193 7194 switch (n->type) { 7195 case NCMD: 7196 new->ncmd.redirect = copynode(n->ncmd.redirect); 7197 new->ncmd.args = copynode(n->ncmd.args); 7198 new->ncmd.assign = copynode(n->ncmd.assign); 7199 break; 7200 case NPIPE: 7201 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 7202 new->npipe.backgnd = n->npipe.backgnd; 7203 break; 7204 case NREDIR: 7205 case NBACKGND: 7206 case NSUBSHELL: 7207 new->nredir.redirect = copynode(n->nredir.redirect); 7208 new->nredir.n = copynode(n->nredir.n); 7209 break; 7210 case NAND: 7211 case NOR: 7212 case NSEMI: 7213 case NWHILE: 7214 case NUNTIL: 7215 new->nbinary.ch2 = copynode(n->nbinary.ch2); 7216 new->nbinary.ch1 = copynode(n->nbinary.ch1); 7217 break; 7218 case NIF: 7219 new->nif.elsepart = copynode(n->nif.elsepart); 7220 new->nif.ifpart = copynode(n->nif.ifpart); 7221 new->nif.test = copynode(n->nif.test); 7222 break; 7223 case NFOR: 7224 new->nfor.var = nodeckstrdup(n->nfor.var); 7225 new->nfor.body = copynode(n->nfor.body); 7226 new->nfor.args = copynode(n->nfor.args); 7227 break; 7228 case NCASE: 7229 new->ncase.cases = copynode(n->ncase.cases); 7230 new->ncase.expr = copynode(n->ncase.expr); 7231 break; 7232 case NCLIST: 7233 new->nclist.body = copynode(n->nclist.body); 7234 new->nclist.pattern = copynode(n->nclist.pattern); 7235 new->nclist.next = copynode(n->nclist.next); 7236 break; 7237 case NDEFUN: 7238 case NARG: 7239 new->narg.backquote = copynodelist(n->narg.backquote); 7240 new->narg.text = nodeckstrdup(n->narg.text); 7241 new->narg.next = copynode(n->narg.next); 7242 break; 7243 case NTO: 7244 case NCLOBBER: 7245 case NFROM: 7246 case NFROMTO: 7247 case NAPPEND: 7248 new->nfile.fname = copynode(n->nfile.fname); 7249 new->nfile.fd = n->nfile.fd; 7250 new->nfile.next = copynode(n->nfile.next); 7251 break; 7252 case NTOFD: 7253 case NFROMFD: 7254 new->ndup.vname = copynode(n->ndup.vname); 7255 new->ndup.dupfd = n->ndup.dupfd; 7256 new->ndup.fd = n->ndup.fd; 7257 new->ndup.next = copynode(n->ndup.next); 7258 break; 7259 case NHERE: 7260 case NXHERE: 7261 new->nhere.doc = copynode(n->nhere.doc); 7262 new->nhere.fd = n->nhere.fd; 7263 new->nhere.next = copynode(n->nhere.next); 7264 break; 7265 case NNOT: 7266 new->nnot.com = copynode(n->nnot.com); 7267 break; 7268 }; 7269 new->type = n->type; 7270 return new; 7271} 7272 7273/* 7274 * Make a copy of a parse tree. 7275 */ 7276static struct funcnode * 7277copyfunc(union node *n) 7278{ 7279 struct funcnode *f; 7280 size_t blocksize; 7281 7282 funcblocksize = offsetof(struct funcnode, n); 7283 funcstringsize = 0; 7284 calcsize(n); 7285 blocksize = funcblocksize; 7286 f = ckmalloc(blocksize + funcstringsize); 7287 funcblock = (char *) f + offsetof(struct funcnode, n); 7288 funcstring = (char *) f + blocksize; 7289 copynode(n); 7290 f->count = 0; 7291 return f; 7292} 7293 7294/* 7295 * Define a shell function. 7296 */ 7297static void 7298defun(char *name, union node *func) 7299{ 7300 struct cmdentry entry; 7301 7302 INT_OFF; 7303 entry.cmdtype = CMDFUNCTION; 7304 entry.u.func = copyfunc(func); 7305 addcmdentry(name, &entry); 7306 INT_ON; 7307} 7308 7309static int evalskip; /* set if we are skipping commands */ 7310/* reasons for skipping commands (see comment on breakcmd routine) */ 7311#define SKIPBREAK (1 << 0) 7312#define SKIPCONT (1 << 1) 7313#define SKIPFUNC (1 << 2) 7314#define SKIPFILE (1 << 3) 7315#define SKIPEVAL (1 << 4) 7316static int skipcount; /* number of levels to skip */ 7317static int funcnest; /* depth of function calls */ 7318 7319/* forward decl way out to parsing code - dotrap needs it */ 7320static int evalstring(char *s, int mask); 7321 7322/* 7323 * Called to execute a trap. Perhaps we should avoid entering new trap 7324 * handlers while we are executing a trap handler. 7325 */ 7326static int 7327dotrap(void) 7328{ 7329 char *p; 7330 char *q; 7331 int i; 7332 int savestatus; 7333 int skip = 0; 7334 7335 savestatus = exitstatus; 7336 pendingsig = 0; 7337 xbarrier(); 7338 7339 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) { 7340 if (!*q) 7341 continue; 7342 *q = '\0'; 7343 7344 p = trap[i + 1]; 7345 if (!p) 7346 continue; 7347 skip = evalstring(p, SKIPEVAL); 7348 exitstatus = savestatus; 7349 if (skip) 7350 break; 7351 } 7352 7353 return skip; 7354} 7355 7356/* forward declarations - evaluation is fairly recursive business... */ 7357static void evalloop(union node *, int); 7358static void evalfor(union node *, int); 7359static void evalcase(union node *, int); 7360static void evalsubshell(union node *, int); 7361static void expredir(union node *); 7362static void evalpipe(union node *, int); 7363static void evalcommand(union node *, int); 7364static int evalbltin(const struct builtincmd *, int, char **); 7365static void prehash(union node *); 7366 7367/* 7368 * Evaluate a parse tree. The value is left in the global variable 7369 * exitstatus. 7370 */ 7371static void 7372evaltree(union node *n, int flags) 7373{ 7374 int checkexit = 0; 7375 void (*evalfn)(union node *, int); 7376 unsigned isor; 7377 int status; 7378 if (n == NULL) { 7379 TRACE(("evaltree(NULL) called\n")); 7380 goto out; 7381 } 7382 TRACE(("pid %d, evaltree(%p: %d, %d) called\n", 7383 getpid(), n, n->type, flags)); 7384 switch (n->type) { 7385 default: 7386#if DEBUG 7387 out1fmt("Node type = %d\n", n->type); 7388 fflush(stdout); 7389 break; 7390#endif 7391 case NNOT: 7392 evaltree(n->nnot.com, EV_TESTED); 7393 status = !exitstatus; 7394 goto setstatus; 7395 case NREDIR: 7396 expredir(n->nredir.redirect); 7397 status = redirectsafe(n->nredir.redirect, REDIR_PUSH); 7398 if (!status) { 7399 evaltree(n->nredir.n, flags & EV_TESTED); 7400 status = exitstatus; 7401 } 7402 popredir(0); 7403 goto setstatus; 7404 case NCMD: 7405 evalfn = evalcommand; 7406 checkexit: 7407 if (eflag && !(flags & EV_TESTED)) 7408 checkexit = ~0; 7409 goto calleval; 7410 case NFOR: 7411 evalfn = evalfor; 7412 goto calleval; 7413 case NWHILE: 7414 case NUNTIL: 7415 evalfn = evalloop; 7416 goto calleval; 7417 case NSUBSHELL: 7418 case NBACKGND: 7419 evalfn = evalsubshell; 7420 goto calleval; 7421 case NPIPE: 7422 evalfn = evalpipe; 7423 goto checkexit; 7424 case NCASE: 7425 evalfn = evalcase; 7426 goto calleval; 7427 case NAND: 7428 case NOR: 7429 case NSEMI: 7430#if NAND + 1 != NOR 7431#error NAND + 1 != NOR 7432#endif 7433#if NOR + 1 != NSEMI 7434#error NOR + 1 != NSEMI 7435#endif 7436 isor = n->type - NAND; 7437 evaltree( 7438 n->nbinary.ch1, 7439 (flags | ((isor >> 1) - 1)) & EV_TESTED 7440 ); 7441 if (!exitstatus == isor) 7442 break; 7443 if (!evalskip) { 7444 n = n->nbinary.ch2; 7445 evaln: 7446 evalfn = evaltree; 7447 calleval: 7448 evalfn(n, flags); 7449 break; 7450 } 7451 break; 7452 case NIF: 7453 evaltree(n->nif.test, EV_TESTED); 7454 if (evalskip) 7455 break; 7456 if (exitstatus == 0) { 7457 n = n->nif.ifpart; 7458 goto evaln; 7459 } else if (n->nif.elsepart) { 7460 n = n->nif.elsepart; 7461 goto evaln; 7462 } 7463 goto success; 7464 case NDEFUN: 7465 defun(n->narg.text, n->narg.next); 7466 success: 7467 status = 0; 7468 setstatus: 7469 exitstatus = status; 7470 break; 7471 } 7472 out: 7473 if ((checkexit & exitstatus)) 7474 evalskip |= SKIPEVAL; 7475 else if (pendingsig && dotrap()) 7476 goto exexit; 7477 7478 if (flags & EV_EXIT) { 7479 exexit: 7480 raise_exception(EXEXIT); 7481 } 7482} 7483 7484#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3) 7485static 7486#endif 7487void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__)); 7488 7489static int loopnest; /* current loop nesting level */ 7490 7491static void 7492evalloop(union node *n, int flags) 7493{ 7494 int status; 7495 7496 loopnest++; 7497 status = 0; 7498 flags &= EV_TESTED; 7499 for (;;) { 7500 int i; 7501 7502 evaltree(n->nbinary.ch1, EV_TESTED); 7503 if (evalskip) { 7504 skipping: 7505 if (evalskip == SKIPCONT && --skipcount <= 0) { 7506 evalskip = 0; 7507 continue; 7508 } 7509 if (evalskip == SKIPBREAK && --skipcount <= 0) 7510 evalskip = 0; 7511 break; 7512 } 7513 i = exitstatus; 7514 if (n->type != NWHILE) 7515 i = !i; 7516 if (i != 0) 7517 break; 7518 evaltree(n->nbinary.ch2, flags); 7519 status = exitstatus; 7520 if (evalskip) 7521 goto skipping; 7522 } 7523 loopnest--; 7524 exitstatus = status; 7525} 7526 7527static void 7528evalfor(union node *n, int flags) 7529{ 7530 struct arglist arglist; 7531 union node *argp; 7532 struct strlist *sp; 7533 struct stackmark smark; 7534 7535 setstackmark(&smark); 7536 arglist.lastp = &arglist.list; 7537 for (argp = n->nfor.args; argp; argp = argp->narg.next) { 7538 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD); 7539 if (evalskip) 7540 goto out; 7541 } 7542 *arglist.lastp = NULL; 7543 7544 exitstatus = 0; 7545 loopnest++; 7546 flags &= EV_TESTED; 7547 for (sp = arglist.list; sp; sp = sp->next) { 7548 setvar(n->nfor.var, sp->text, 0); 7549 evaltree(n->nfor.body, flags); 7550 if (evalskip) { 7551 if (evalskip == SKIPCONT && --skipcount <= 0) { 7552 evalskip = 0; 7553 continue; 7554 } 7555 if (evalskip == SKIPBREAK && --skipcount <= 0) 7556 evalskip = 0; 7557 break; 7558 } 7559 } 7560 loopnest--; 7561 out: 7562 popstackmark(&smark); 7563} 7564 7565static void 7566evalcase(union node *n, int flags) 7567{ 7568 union node *cp; 7569 union node *patp; 7570 struct arglist arglist; 7571 struct stackmark smark; 7572 7573 setstackmark(&smark); 7574 arglist.lastp = &arglist.list; 7575 expandarg(n->ncase.expr, &arglist, EXP_TILDE); 7576 exitstatus = 0; 7577 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) { 7578 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) { 7579 if (casematch(patp, arglist.list->text)) { 7580 if (evalskip == 0) { 7581 evaltree(cp->nclist.body, flags); 7582 } 7583 goto out; 7584 } 7585 } 7586 } 7587 out: 7588 popstackmark(&smark); 7589} 7590 7591/* 7592 * Kick off a subshell to evaluate a tree. 7593 */ 7594static void 7595evalsubshell(union node *n, int flags) 7596{ 7597 struct job *jp; 7598 int backgnd = (n->type == NBACKGND); 7599 int status; 7600 7601 expredir(n->nredir.redirect); 7602 if (!backgnd && flags & EV_EXIT && !trap[0]) 7603 goto nofork; 7604 INT_OFF; 7605 jp = makejob(n, 1); 7606 if (forkshell(jp, n, backgnd) == 0) { 7607 INT_ON; 7608 flags |= EV_EXIT; 7609 if (backgnd) 7610 flags &=~ EV_TESTED; 7611 nofork: 7612 redirect(n->nredir.redirect, 0); 7613 evaltreenr(n->nredir.n, flags); 7614 /* never returns */ 7615 } 7616 status = 0; 7617 if (! backgnd) 7618 status = waitforjob(jp); 7619 exitstatus = status; 7620 INT_ON; 7621} 7622 7623/* 7624 * Compute the names of the files in a redirection list. 7625 */ 7626static void fixredir(union node *, const char *, int); 7627static void 7628expredir(union node *n) 7629{ 7630 union node *redir; 7631 7632 for (redir = n; redir; redir = redir->nfile.next) { 7633 struct arglist fn; 7634 7635 memset(&fn, 0, sizeof(fn)); 7636 fn.lastp = &fn.list; 7637 switch (redir->type) { 7638 case NFROMTO: 7639 case NFROM: 7640 case NTO: 7641 case NCLOBBER: 7642 case NAPPEND: 7643 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 7644 redir->nfile.expfname = fn.list->text; 7645 break; 7646 case NFROMFD: 7647 case NTOFD: 7648 if (redir->ndup.vname) { 7649 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); 7650 if (fn.list == NULL) 7651 ash_msg_and_raise_error("redir error"); 7652 fixredir(redir, fn.list->text, 1); 7653 } 7654 break; 7655 } 7656 } 7657} 7658 7659/* 7660 * Evaluate a pipeline. All the processes in the pipeline are children 7661 * of the process creating the pipeline. (This differs from some versions 7662 * of the shell, which make the last process in a pipeline the parent 7663 * of all the rest.) 7664 */ 7665static void 7666evalpipe(union node *n, int flags) 7667{ 7668 struct job *jp; 7669 struct nodelist *lp; 7670 int pipelen; 7671 int prevfd; 7672 int pip[2]; 7673 7674 TRACE(("evalpipe(0x%lx) called\n", (long)n)); 7675 pipelen = 0; 7676 for (lp = n->npipe.cmdlist; lp; lp = lp->next) 7677 pipelen++; 7678 flags |= EV_EXIT; 7679 INT_OFF; 7680 jp = makejob(n, pipelen); 7681 prevfd = -1; 7682 for (lp = n->npipe.cmdlist; lp; lp = lp->next) { 7683 prehash(lp->n); 7684 pip[1] = -1; 7685 if (lp->next) { 7686 if (pipe(pip) < 0) { 7687 close(prevfd); 7688 ash_msg_and_raise_error("pipe call failed"); 7689 } 7690 } 7691 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 7692 INT_ON; 7693 if (pip[1] >= 0) { 7694 close(pip[0]); 7695 } 7696 if (prevfd > 0) { 7697 dup2(prevfd, 0); 7698 close(prevfd); 7699 } 7700 if (pip[1] > 1) { 7701 dup2(pip[1], 1); 7702 close(pip[1]); 7703 } 7704 evaltreenr(lp->n, flags); 7705 /* never returns */ 7706 } 7707 if (prevfd >= 0) 7708 close(prevfd); 7709 prevfd = pip[0]; 7710 close(pip[1]); 7711 } 7712 if (n->npipe.backgnd == 0) { 7713 exitstatus = waitforjob(jp); 7714 TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 7715 } 7716 INT_ON; 7717} 7718 7719/* 7720 * Controls whether the shell is interactive or not. 7721 */ 7722static void 7723setinteractive(int on) 7724{ 7725 static int is_interactive; 7726 7727 if (++on == is_interactive) 7728 return; 7729 is_interactive = on; 7730 setsignal(SIGINT); 7731 setsignal(SIGQUIT); 7732 setsignal(SIGTERM); 7733#if !ENABLE_FEATURE_SH_EXTRA_QUIET 7734 if (is_interactive > 1) { 7735 /* Looks like they want an interactive shell */ 7736 static smallint did_banner; 7737 7738 if (!did_banner) { 7739 out1fmt( 7740 "\n\n" 7741 "%s built-in shell (ash)\n" 7742 "Enter 'help' for a list of built-in commands." 7743 "\n\n", 7744 bb_banner); 7745 did_banner = 1; 7746 } 7747 } 7748#endif 7749} 7750 7751#if ENABLE_FEATURE_EDITING_VI 7752#define setvimode(on) do { \ 7753 if (on) line_input_state->flags |= VI_MODE; \ 7754 else line_input_state->flags &= ~VI_MODE; \ 7755} while (0) 7756#else 7757#define setvimode(on) viflag = 0 /* forcibly keep the option off */ 7758#endif 7759 7760static void 7761optschanged(void) 7762{ 7763#if DEBUG 7764 opentrace(); 7765#endif 7766 setinteractive(iflag); 7767 setjobctl(mflag); 7768 setvimode(viflag); 7769} 7770 7771static struct localvar *localvars; 7772 7773/* 7774 * Called after a function returns. 7775 * Interrupts must be off. 7776 */ 7777static void 7778poplocalvars(void) 7779{ 7780 struct localvar *lvp; 7781 struct var *vp; 7782 7783 while ((lvp = localvars) != NULL) { 7784 localvars = lvp->next; 7785 vp = lvp->vp; 7786 TRACE(("poplocalvar %s", vp ? vp->text : "-")); 7787 if (vp == NULL) { /* $- saved */ 7788 memcpy(optlist, lvp->text, sizeof(optlist)); 7789 free((char*)lvp->text); 7790 optschanged(); 7791 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { 7792 unsetvar(vp->text); 7793 } else { 7794 if (vp->func) 7795 (*vp->func)(strchrnul(lvp->text, '=') + 1); 7796 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) 7797 free((char*)vp->text); 7798 vp->flags = lvp->flags; 7799 vp->text = lvp->text; 7800 } 7801 free(lvp); 7802 } 7803} 7804 7805static int 7806evalfun(struct funcnode *func, int argc, char **argv, int flags) 7807{ 7808 volatile struct shparam saveparam; 7809 struct localvar *volatile savelocalvars; 7810 struct jmploc *volatile savehandler; 7811 struct jmploc jmploc; 7812 int e; 7813 7814 saveparam = shellparam; 7815 savelocalvars = localvars; 7816 e = setjmp(jmploc.loc); 7817 if (e) { 7818 goto funcdone; 7819 } 7820 INT_OFF; 7821 savehandler = exception_handler; 7822 exception_handler = &jmploc; 7823 localvars = NULL; 7824 shellparam.malloc = 0; 7825 func->count++; 7826 funcnest++; 7827 INT_ON; 7828 shellparam.nparam = argc - 1; 7829 shellparam.p = argv + 1; 7830#if ENABLE_ASH_GETOPTS 7831 shellparam.optind = 1; 7832 shellparam.optoff = -1; 7833#endif 7834 evaltree(&func->n, flags & EV_TESTED); 7835funcdone: 7836 INT_OFF; 7837 funcnest--; 7838 freefunc(func); 7839 poplocalvars(); 7840 localvars = savelocalvars; 7841 freeparam(&shellparam); 7842 shellparam = saveparam; 7843 exception_handler = savehandler; 7844 INT_ON; 7845 evalskip &= ~SKIPFUNC; 7846 return e; 7847} 7848 7849#if ENABLE_ASH_CMDCMD 7850static char ** 7851parse_command_args(char **argv, const char **path) 7852{ 7853 char *cp, c; 7854 7855 for (;;) { 7856 cp = *++argv; 7857 if (!cp) 7858 return 0; 7859 if (*cp++ != '-') 7860 break; 7861 c = *cp++; 7862 if (!c) 7863 break; 7864 if (c == '-' && !*cp) { 7865 argv++; 7866 break; 7867 } 7868 do { 7869 switch (c) { 7870 case 'p': 7871 *path = bb_default_path; 7872 break; 7873 default: 7874 /* run 'typecmd' for other options */ 7875 return 0; 7876 } 7877 c = *cp++; 7878 } while (c); 7879 } 7880 return argv; 7881} 7882#endif 7883 7884/* 7885 * Make a variable a local variable. When a variable is made local, it's 7886 * value and flags are saved in a localvar structure. The saved values 7887 * will be restored when the shell function returns. We handle the name 7888 * "-" as a special case. 7889 */ 7890static void 7891mklocal(char *name) 7892{ 7893 struct localvar *lvp; 7894 struct var **vpp; 7895 struct var *vp; 7896 7897 INT_OFF; 7898 lvp = ckmalloc(sizeof(struct localvar)); 7899 if (LONE_DASH(name)) { 7900 char *p; 7901 p = ckmalloc(sizeof(optlist)); 7902 lvp->text = memcpy(p, optlist, sizeof(optlist)); 7903 vp = NULL; 7904 } else { 7905 char *eq; 7906 7907 vpp = hashvar(name); 7908 vp = *findvar(vpp, name); 7909 eq = strchr(name, '='); 7910 if (vp == NULL) { 7911 if (eq) 7912 setvareq(name, VSTRFIXED); 7913 else 7914 setvar(name, NULL, VSTRFIXED); 7915 vp = *vpp; /* the new variable */ 7916 lvp->flags = VUNSET; 7917 } else { 7918 lvp->text = vp->text; 7919 lvp->flags = vp->flags; 7920 vp->flags |= VSTRFIXED|VTEXTFIXED; 7921 if (eq) 7922 setvareq(name, 0); 7923 } 7924 } 7925 lvp->vp = vp; 7926 lvp->next = localvars; 7927 localvars = lvp; 7928 INT_ON; 7929} 7930 7931/* 7932 * The "local" command. 7933 */ 7934static int 7935localcmd(int argc, char **argv) 7936{ 7937 char *name; 7938 7939 argv = argptr; 7940 while ((name = *argv++) != NULL) { 7941 mklocal(name); 7942 } 7943 return 0; 7944} 7945 7946static int 7947falsecmd(int argc, char **argv) 7948{ 7949 return 1; 7950} 7951 7952static int 7953truecmd(int argc, char **argv) 7954{ 7955 return 0; 7956} 7957 7958static int 7959execcmd(int argc, char **argv) 7960{ 7961 if (argc > 1) { 7962 iflag = 0; /* exit on error */ 7963 mflag = 0; 7964 optschanged(); 7965 shellexec(argv + 1, pathval(), 0); 7966 } 7967 return 0; 7968} 7969 7970/* 7971 * The return command. 7972 */ 7973static int 7974returncmd(int argc, char **argv) 7975{ 7976 /* 7977 * If called outside a function, do what ksh does; 7978 * skip the rest of the file. 7979 */ 7980 evalskip = funcnest ? SKIPFUNC : SKIPFILE; 7981 return argv[1] ? number(argv[1]) : exitstatus; 7982} 7983 7984/* Forward declarations for builtintab[] */ 7985static int breakcmd(int, char **); 7986static int dotcmd(int, char **); 7987static int evalcmd(int, char **); 7988#if ENABLE_ASH_BUILTIN_ECHO 7989static int echocmd(int, char **); 7990#endif 7991#if ENABLE_ASH_BUILTIN_TEST 7992static int testcmd(int, char **); 7993#endif 7994static int exitcmd(int, char **); 7995static int exportcmd(int, char **); 7996#if ENABLE_ASH_GETOPTS 7997static int getoptscmd(int, char **); 7998#endif 7999#if !ENABLE_FEATURE_SH_EXTRA_QUIET 8000static int helpcmd(int argc, char **argv); 8001#endif 8002#if ENABLE_ASH_MATH_SUPPORT 8003static int letcmd(int, char **); 8004#endif 8005static int readcmd(int, char **); 8006static int setcmd(int, char **); 8007static int shiftcmd(int, char **); 8008static int timescmd(int, char **); 8009static int trapcmd(int, char **); 8010static int umaskcmd(int, char **); 8011static int unsetcmd(int, char **); 8012static int ulimitcmd(int, char **); 8013 8014#define BUILTIN_NOSPEC "0" 8015#define BUILTIN_SPECIAL "1" 8016#define BUILTIN_REGULAR "2" 8017#define BUILTIN_SPEC_REG "3" 8018#define BUILTIN_ASSIGN "4" 8019#define BUILTIN_SPEC_ASSG "5" 8020#define BUILTIN_REG_ASSG "6" 8021#define BUILTIN_SPEC_REG_ASSG "7" 8022 8023/* make sure to keep these in proper order since it is searched via bsearch() */ 8024static const struct builtincmd builtintab[] = { 8025 { BUILTIN_SPEC_REG ".", dotcmd }, 8026 { BUILTIN_SPEC_REG ":", truecmd }, 8027#if ENABLE_ASH_BUILTIN_TEST 8028 { BUILTIN_REGULAR "[", testcmd }, 8029 { BUILTIN_REGULAR "[[", testcmd }, 8030#endif 8031#if ENABLE_ASH_ALIAS 8032 { BUILTIN_REG_ASSG "alias", aliascmd }, 8033#endif 8034#if JOBS 8035 { BUILTIN_REGULAR "bg", fg_bgcmd }, 8036#endif 8037 { BUILTIN_SPEC_REG "break", breakcmd }, 8038 { BUILTIN_REGULAR "cd", cdcmd }, 8039 { BUILTIN_NOSPEC "chdir", cdcmd }, 8040#if ENABLE_ASH_CMDCMD 8041 { BUILTIN_REGULAR "command", commandcmd }, 8042#endif 8043 { BUILTIN_SPEC_REG "continue", breakcmd }, 8044#if ENABLE_ASH_BUILTIN_ECHO 8045 { BUILTIN_REGULAR "echo", echocmd }, 8046#endif 8047 { BUILTIN_SPEC_REG "eval", evalcmd }, 8048 { BUILTIN_SPEC_REG "exec", execcmd }, 8049 { BUILTIN_SPEC_REG "exit", exitcmd }, 8050 { BUILTIN_SPEC_REG_ASSG "export", exportcmd }, 8051 { BUILTIN_REGULAR "false", falsecmd }, 8052#if JOBS 8053 { BUILTIN_REGULAR "fg", fg_bgcmd }, 8054#endif 8055#if ENABLE_ASH_GETOPTS 8056 { BUILTIN_REGULAR "getopts", getoptscmd }, 8057#endif 8058 { BUILTIN_NOSPEC "hash", hashcmd }, 8059#if !ENABLE_FEATURE_SH_EXTRA_QUIET 8060 { BUILTIN_NOSPEC "help", helpcmd }, 8061#endif 8062#if JOBS 8063 { BUILTIN_REGULAR "jobs", jobscmd }, 8064 { BUILTIN_REGULAR "kill", killcmd }, 8065#endif 8066#if ENABLE_ASH_MATH_SUPPORT 8067 { BUILTIN_NOSPEC "let", letcmd }, 8068#endif 8069 { BUILTIN_ASSIGN "local", localcmd }, 8070 { BUILTIN_NOSPEC "pwd", pwdcmd }, 8071 { BUILTIN_REGULAR "read", readcmd }, 8072 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd }, 8073 { BUILTIN_SPEC_REG "return", returncmd }, 8074 { BUILTIN_SPEC_REG "set", setcmd }, 8075 { BUILTIN_SPEC_REG "shift", shiftcmd }, 8076 { BUILTIN_SPEC_REG "source", dotcmd }, 8077#if ENABLE_ASH_BUILTIN_TEST 8078 { BUILTIN_REGULAR "test", testcmd }, 8079#endif 8080 { BUILTIN_SPEC_REG "times", timescmd }, 8081 { BUILTIN_SPEC_REG "trap", trapcmd }, 8082 { BUILTIN_REGULAR "true", truecmd }, 8083 { BUILTIN_NOSPEC "type", typecmd }, 8084 { BUILTIN_NOSPEC "ulimit", ulimitcmd }, 8085 { BUILTIN_REGULAR "umask", umaskcmd }, 8086#if ENABLE_ASH_ALIAS 8087 { BUILTIN_REGULAR "unalias", unaliascmd }, 8088#endif 8089 { BUILTIN_SPEC_REG "unset", unsetcmd }, 8090 { BUILTIN_REGULAR "wait", waitcmd }, 8091}; 8092 8093 8094#define COMMANDCMD (builtintab + 5 + \ 8095 2 * ENABLE_ASH_BUILTIN_TEST + \ 8096 ENABLE_ASH_ALIAS + \ 8097 ENABLE_ASH_JOB_CONTROL) 8098#define EXECCMD (builtintab + 7 + \ 8099 2 * ENABLE_ASH_BUILTIN_TEST + \ 8100 ENABLE_ASH_ALIAS + \ 8101 ENABLE_ASH_JOB_CONTROL + \ 8102 ENABLE_ASH_CMDCMD + \ 8103 ENABLE_ASH_BUILTIN_ECHO) 8104 8105/* 8106 * Search the table of builtin commands. 8107 */ 8108static struct builtincmd * 8109find_builtin(const char *name) 8110{ 8111 struct builtincmd *bp; 8112 8113 bp = bsearch( 8114 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]), 8115 pstrcmp 8116 ); 8117 return bp; 8118} 8119 8120/* 8121 * Execute a simple command. 8122 */ 8123static int back_exitstatus; /* exit status of backquoted command */ 8124static int 8125isassignment(const char *p) 8126{ 8127 const char *q = endofname(p); 8128 if (p == q) 8129 return 0; 8130 return *q == '='; 8131} 8132static int 8133bltincmd(int argc, char **argv) 8134{ 8135 /* Preserve exitstatus of a previous possible redirection 8136 * as POSIX mandates */ 8137 return back_exitstatus; 8138} 8139static void 8140evalcommand(union node *cmd, int flags) 8141{ 8142 static const struct builtincmd bltin = { 8143 "\0\0", bltincmd 8144 }; 8145 struct stackmark smark; 8146 union node *argp; 8147 struct arglist arglist; 8148 struct arglist varlist; 8149 char **argv; 8150 int argc; 8151 const struct strlist *sp; 8152 struct cmdentry cmdentry; 8153 struct job *jp; 8154 char *lastarg; 8155 const char *path; 8156 int spclbltin; 8157 int cmd_is_exec; 8158 int status; 8159 char **nargv; 8160 struct builtincmd *bcmd; 8161 int pseudovarflag = 0; 8162 8163 /* First expand the arguments. */ 8164 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 8165 setstackmark(&smark); 8166 back_exitstatus = 0; 8167 8168 cmdentry.cmdtype = CMDBUILTIN; 8169 cmdentry.u.cmd = &bltin; 8170 varlist.lastp = &varlist.list; 8171 *varlist.lastp = NULL; 8172 arglist.lastp = &arglist.list; 8173 *arglist.lastp = NULL; 8174 8175 argc = 0; 8176 if (cmd->ncmd.args) { 8177 bcmd = find_builtin(cmd->ncmd.args->narg.text); 8178 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd); 8179 } 8180 8181 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) { 8182 struct strlist **spp; 8183 8184 spp = arglist.lastp; 8185 if (pseudovarflag && isassignment(argp->narg.text)) 8186 expandarg(argp, &arglist, EXP_VARTILDE); 8187 else 8188 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 8189 8190 for (sp = *spp; sp; sp = sp->next) 8191 argc++; 8192 } 8193 8194 argv = nargv = stalloc(sizeof(char *) * (argc + 1)); 8195 for (sp = arglist.list; sp; sp = sp->next) { 8196 TRACE(("evalcommand arg: %s\n", sp->text)); 8197 *nargv++ = sp->text; 8198 } 8199 *nargv = NULL; 8200 8201 lastarg = NULL; 8202 if (iflag && funcnest == 0 && argc > 0) 8203 lastarg = nargv[-1]; 8204 8205 preverrout_fd = 2; 8206 expredir(cmd->ncmd.redirect); 8207 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); 8208 8209 path = vpath.text; 8210 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { 8211 struct strlist **spp; 8212 char *p; 8213 8214 spp = varlist.lastp; 8215 expandarg(argp, &varlist, EXP_VARTILDE); 8216 8217 /* 8218 * Modify the command lookup path, if a PATH= assignment 8219 * is present 8220 */ 8221 p = (*spp)->text; 8222 if (varequal(p, path)) 8223 path = p; 8224 } 8225 8226 /* Print the command if xflag is set. */ 8227 if (xflag) { 8228 int n; 8229 const char *p = " %s"; 8230 8231 p++; 8232 dprintf(preverrout_fd, p, expandstr(ps4val())); 8233 8234 sp = varlist.list; 8235 for (n = 0; n < 2; n++) { 8236 while (sp) { 8237 dprintf(preverrout_fd, p, sp->text); 8238 sp = sp->next; 8239 if (*p == '%') { 8240 p--; 8241 } 8242 } 8243 sp = arglist.list; 8244 } 8245 full_write(preverrout_fd, "\n", 1); 8246 } 8247 8248 cmd_is_exec = 0; 8249 spclbltin = -1; 8250 8251 /* Now locate the command. */ 8252 if (argc) { 8253 const char *oldpath; 8254 int cmd_flag = DO_ERR; 8255 8256 path += 5; 8257 oldpath = path; 8258 for (;;) { 8259 find_command(argv[0], &cmdentry, cmd_flag, path); 8260 if (cmdentry.cmdtype == CMDUNKNOWN) { 8261 status = 127; 8262 flush_stderr(); 8263 goto bail; 8264 } 8265 8266 /* implement bltin and command here */ 8267 if (cmdentry.cmdtype != CMDBUILTIN) 8268 break; 8269 if (spclbltin < 0) 8270 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd); 8271 if (cmdentry.u.cmd == EXECCMD) 8272 cmd_is_exec++; 8273#if ENABLE_ASH_CMDCMD 8274 if (cmdentry.u.cmd == COMMANDCMD) { 8275 path = oldpath; 8276 nargv = parse_command_args(argv, &path); 8277 if (!nargv) 8278 break; 8279 argc -= nargv - argv; 8280 argv = nargv; 8281 cmd_flag |= DO_NOFUNC; 8282 } else 8283#endif 8284 break; 8285 } 8286 } 8287 8288 if (status) { 8289 /* We have a redirection error. */ 8290 if (spclbltin > 0) 8291 raise_exception(EXERROR); 8292 bail: 8293 exitstatus = status; 8294 goto out; 8295 } 8296 8297 /* Execute the command. */ 8298 switch (cmdentry.cmdtype) { 8299 default: 8300 /* Fork off a child process if necessary. */ 8301 if (!(flags & EV_EXIT) || trap[0]) { 8302 INT_OFF; 8303 jp = makejob(cmd, 1); 8304 if (forkshell(jp, cmd, FORK_FG) != 0) { 8305 exitstatus = waitforjob(jp); 8306 INT_ON; 8307 break; 8308 } 8309 FORCE_INT_ON; 8310 } 8311 listsetvar(varlist.list, VEXPORT|VSTACK); 8312 shellexec(argv, path, cmdentry.u.index); 8313 /* NOTREACHED */ 8314 8315 case CMDBUILTIN: 8316 cmdenviron = varlist.list; 8317 if (cmdenviron) { 8318 struct strlist *list = cmdenviron; 8319 int i = VNOSET; 8320 if (spclbltin > 0 || argc == 0) { 8321 i = 0; 8322 if (cmd_is_exec && argc > 1) 8323 i = VEXPORT; 8324 } 8325 listsetvar(list, i); 8326 } 8327 if (evalbltin(cmdentry.u.cmd, argc, argv)) { 8328 int exit_status; 8329 int i, j; 8330 8331 i = exception; 8332 if (i == EXEXIT) 8333 goto raise; 8334 8335 exit_status = 2; 8336 j = 0; 8337 if (i == EXINT) 8338 j = SIGINT; 8339 if (i == EXSIG) 8340 j = pendingsig; 8341 if (j) 8342 exit_status = j + 128; 8343 exitstatus = exit_status; 8344 8345 if (i == EXINT || spclbltin > 0) { 8346 raise: 8347 longjmp(exception_handler->loc, 1); 8348 } 8349 FORCE_INT_ON; 8350 } 8351 break; 8352 8353 case CMDFUNCTION: 8354 listsetvar(varlist.list, 0); 8355 if (evalfun(cmdentry.u.func, argc, argv, flags)) 8356 goto raise; 8357 break; 8358 } 8359 8360 out: 8361 popredir(cmd_is_exec); 8362 if (lastarg) 8363 /* dsl: I think this is intended to be used to support 8364 * '_' in 'vi' command mode during line editing... 8365 * However I implemented that within libedit itself. 8366 */ 8367 setvar("_", lastarg, 0); 8368 popstackmark(&smark); 8369} 8370 8371static int 8372evalbltin(const struct builtincmd *cmd, int argc, char **argv) 8373{ 8374 char *volatile savecmdname; 8375 struct jmploc *volatile savehandler; 8376 struct jmploc jmploc; 8377 int i; 8378 8379 savecmdname = commandname; 8380 i = setjmp(jmploc.loc); 8381 if (i) 8382 goto cmddone; 8383 savehandler = exception_handler; 8384 exception_handler = &jmploc; 8385 commandname = argv[0]; 8386 argptr = argv + 1; 8387 optptr = NULL; /* initialize nextopt */ 8388 exitstatus = (*cmd->builtin)(argc, argv); 8389 flush_stdout_stderr(); 8390 cmddone: 8391 exitstatus |= ferror(stdout); 8392 clearerr(stdout); 8393 commandname = savecmdname; 8394 exsig = 0; 8395 exception_handler = savehandler; 8396 8397 return i; 8398} 8399 8400static int 8401goodname(const char *p) 8402{ 8403 return !*endofname(p); 8404} 8405 8406 8407/* 8408 * Search for a command. This is called before we fork so that the 8409 * location of the command will be available in the parent as well as 8410 * the child. The check for "goodname" is an overly conservative 8411 * check that the name will not be subject to expansion. 8412 */ 8413static void 8414prehash(union node *n) 8415{ 8416 struct cmdentry entry; 8417 8418 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text)) 8419 find_command(n->ncmd.args->narg.text, &entry, 0, pathval()); 8420} 8421 8422 8423/* ============ Builtin commands 8424 * 8425 * Builtin commands whose functions are closely tied to evaluation 8426 * are implemented here. 8427 */ 8428 8429/* 8430 * Handle break and continue commands. Break, continue, and return are 8431 * all handled by setting the evalskip flag. The evaluation routines 8432 * above all check this flag, and if it is set they start skipping 8433 * commands rather than executing them. The variable skipcount is 8434 * the number of loops to break/continue, or the number of function 8435 * levels to return. (The latter is always 1.) It should probably 8436 * be an error to break out of more loops than exist, but it isn't 8437 * in the standard shell so we don't make it one here. 8438 */ 8439static int 8440breakcmd(int argc, char **argv) 8441{ 8442 int n = argc > 1 ? number(argv[1]) : 1; 8443 8444 if (n <= 0) 8445 ash_msg_and_raise_error(illnum, argv[1]); 8446 if (n > loopnest) 8447 n = loopnest; 8448 if (n > 0) { 8449 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK; 8450 skipcount = n; 8451 } 8452 return 0; 8453} 8454 8455 8456/* ============ input.c 8457 * 8458 * This implements the input routines used by the parser. 8459 */ 8460 8461#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ 8462 8463enum { 8464 INPUT_PUSH_FILE = 1, 8465 INPUT_NOFILE_OK = 2, 8466}; 8467 8468/* 8469 * NEOF is returned by parsecmd when it encounters an end of file. It 8470 * must be distinct from NULL, so we use the address of a variable that 8471 * happens to be handy. 8472 */ 8473static int plinno = 1; /* input line number */ 8474/* number of characters left in input buffer */ 8475static int parsenleft; /* copy of parsefile->nleft */ 8476static int parselleft; /* copy of parsefile->lleft */ 8477/* next character in input buffer */ 8478static char *parsenextc; /* copy of parsefile->nextc */ 8479 8480static int checkkwd; 8481/* values of checkkwd variable */ 8482#define CHKALIAS 0x1 8483#define CHKKWD 0x2 8484#define CHKNL 0x4 8485 8486static void 8487popstring(void) 8488{ 8489 struct strpush *sp = parsefile->strpush; 8490 8491 INT_OFF; 8492#if ENABLE_ASH_ALIAS 8493 if (sp->ap) { 8494 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') { 8495 checkkwd |= CHKALIAS; 8496 } 8497 if (sp->string != sp->ap->val) { 8498 free(sp->string); 8499 } 8500 sp->ap->flag &= ~ALIASINUSE; 8501 if (sp->ap->flag & ALIASDEAD) { 8502 unalias(sp->ap->name); 8503 } 8504 } 8505#endif 8506 parsenextc = sp->prevstring; 8507 parsenleft = sp->prevnleft; 8508/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ 8509 parsefile->strpush = sp->prev; 8510 if (sp != &(parsefile->basestrpush)) 8511 free(sp); 8512 INT_ON; 8513} 8514 8515static int 8516preadfd(void) 8517{ 8518 int nr; 8519 char *buf = parsefile->buf; 8520 parsenextc = buf; 8521 8522 retry: 8523#if ENABLE_FEATURE_EDITING 8524 if (!iflag || parsefile->fd) 8525 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 8526 else { 8527#if ENABLE_FEATURE_TAB_COMPLETION 8528 line_input_state->path_lookup = pathval(); 8529#endif 8530 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state); 8531 if (nr == 0) { 8532 /* Ctrl+C pressed */ 8533 if (trap[SIGINT]) { 8534 buf[0] = '\n'; 8535 buf[1] = '\0'; 8536 raise(SIGINT); 8537 return 1; 8538 } 8539 goto retry; 8540 } 8541 if (nr < 0 && errno == 0) { 8542 /* Ctrl+D presend */ 8543 nr = 0; 8544 } 8545 } 8546#else 8547 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 8548#endif 8549 8550 if (nr < 0) { 8551 if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 8552 int flags = fcntl(0, F_GETFL); 8553 if (flags >= 0 && flags & O_NONBLOCK) { 8554 flags &=~ O_NONBLOCK; 8555 if (fcntl(0, F_SETFL, flags) >= 0) { 8556 out2str("sh: turning off NDELAY mode\n"); 8557 goto retry; 8558 } 8559 } 8560 } 8561 } 8562 return nr; 8563} 8564 8565/* 8566 * Refill the input buffer and return the next input character: 8567 * 8568 * 1) If a string was pushed back on the input, pop it; 8569 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading 8570 * from a string so we can't refill the buffer, return EOF. 8571 * 3) If the is more stuff in this buffer, use it else call read to fill it. 8572 * 4) Process input up to the next newline, deleting nul characters. 8573 */ 8574static int 8575preadbuffer(void) 8576{ 8577 char *q; 8578 int more; 8579 char savec; 8580 8581 while (parsefile->strpush) { 8582#if ENABLE_ASH_ALIAS 8583 if (parsenleft == -1 && parsefile->strpush->ap && 8584 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') { 8585 return PEOA; 8586 } 8587#endif 8588 popstring(); 8589 if (--parsenleft >= 0) 8590 return signed_char2int(*parsenextc++); 8591 } 8592 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) 8593 return PEOF; 8594 flush_stdout_stderr(); 8595 8596 more = parselleft; 8597 if (more <= 0) { 8598 again: 8599 more = preadfd(); 8600 if (more <= 0) { 8601 parselleft = parsenleft = EOF_NLEFT; 8602 return PEOF; 8603 } 8604 } 8605 8606 q = parsenextc; 8607 8608 /* delete nul characters */ 8609 for (;;) { 8610 int c; 8611 8612 more--; 8613 c = *q; 8614 8615 if (!c) 8616 memmove(q, q + 1, more); 8617 else { 8618 q++; 8619 if (c == '\n') { 8620 parsenleft = q - parsenextc - 1; 8621 break; 8622 } 8623 } 8624 8625 if (more <= 0) { 8626 parsenleft = q - parsenextc - 1; 8627 if (parsenleft < 0) 8628 goto again; 8629 break; 8630 } 8631 } 8632 parselleft = more; 8633 8634 savec = *q; 8635 *q = '\0'; 8636 8637 if (vflag) { 8638 out2str(parsenextc); 8639 } 8640 8641 *q = savec; 8642 8643 return signed_char2int(*parsenextc++); 8644} 8645 8646#define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer()) 8647static int 8648pgetc(void) 8649{ 8650 return pgetc_as_macro(); 8651} 8652 8653#if ENABLE_ASH_OPTIMIZE_FOR_SIZE 8654#define pgetc_macro() pgetc() 8655#else 8656#define pgetc_macro() pgetc_as_macro() 8657#endif 8658 8659/* 8660 * Same as pgetc(), but ignores PEOA. 8661 */ 8662#if ENABLE_ASH_ALIAS 8663static int 8664pgetc2(void) 8665{ 8666 int c; 8667 8668 do { 8669 c = pgetc_macro(); 8670 } while (c == PEOA); 8671 return c; 8672} 8673#else 8674static int 8675pgetc2(void) 8676{ 8677 return pgetc_macro(); 8678} 8679#endif 8680 8681/* 8682 * Read a line from the script. 8683 */ 8684static char * 8685pfgets(char *line, int len) 8686{ 8687 char *p = line; 8688 int nleft = len; 8689 int c; 8690 8691 while (--nleft > 0) { 8692 c = pgetc2(); 8693 if (c == PEOF) { 8694 if (p == line) 8695 return NULL; 8696 break; 8697 } 8698 *p++ = c; 8699 if (c == '\n') 8700 break; 8701 } 8702 *p = '\0'; 8703 return line; 8704} 8705 8706/* 8707 * Undo the last call to pgetc. Only one character may be pushed back. 8708 * PEOF may be pushed back. 8709 */ 8710static void 8711pungetc(void) 8712{ 8713 parsenleft++; 8714 parsenextc--; 8715} 8716 8717/* 8718 * Push a string back onto the input at this current parsefile level. 8719 * We handle aliases this way. 8720 */ 8721static void 8722pushstring(char *s, void *ap) 8723{ 8724 struct strpush *sp; 8725 size_t len; 8726 8727 len = strlen(s); 8728 INT_OFF; 8729/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ 8730 if (parsefile->strpush) { 8731 sp = ckmalloc(sizeof(struct strpush)); 8732 sp->prev = parsefile->strpush; 8733 parsefile->strpush = sp; 8734 } else 8735 sp = parsefile->strpush = &(parsefile->basestrpush); 8736 sp->prevstring = parsenextc; 8737 sp->prevnleft = parsenleft; 8738#if ENABLE_ASH_ALIAS 8739 sp->ap = (struct alias *)ap; 8740 if (ap) { 8741 ((struct alias *)ap)->flag |= ALIASINUSE; 8742 sp->string = s; 8743 } 8744#endif 8745 parsenextc = s; 8746 parsenleft = len; 8747 INT_ON; 8748} 8749 8750/* 8751 * To handle the "." command, a stack of input files is used. Pushfile 8752 * adds a new entry to the stack and popfile restores the previous level. 8753 */ 8754static void 8755pushfile(void) 8756{ 8757 struct parsefile *pf; 8758 8759 parsefile->nleft = parsenleft; 8760 parsefile->lleft = parselleft; 8761 parsefile->nextc = parsenextc; 8762 parsefile->linno = plinno; 8763 pf = ckmalloc(sizeof(*pf)); 8764 pf->prev = parsefile; 8765 pf->fd = -1; 8766 pf->strpush = NULL; 8767 pf->basestrpush.prev = NULL; 8768 parsefile = pf; 8769} 8770 8771static void 8772popfile(void) 8773{ 8774 struct parsefile *pf = parsefile; 8775 8776 INT_OFF; 8777 if (pf->fd >= 0) 8778 close(pf->fd); 8779 if (pf->buf) 8780 free(pf->buf); 8781 while (pf->strpush) 8782 popstring(); 8783 parsefile = pf->prev; 8784 free(pf); 8785 parsenleft = parsefile->nleft; 8786 parselleft = parsefile->lleft; 8787 parsenextc = parsefile->nextc; 8788 plinno = parsefile->linno; 8789 INT_ON; 8790} 8791 8792/* 8793 * Return to top level. 8794 */ 8795static void 8796popallfiles(void) 8797{ 8798 while (parsefile != &basepf) 8799 popfile(); 8800} 8801 8802/* 8803 * Close the file(s) that the shell is reading commands from. Called 8804 * after a fork is done. 8805 */ 8806static void 8807closescript(void) 8808{ 8809 popallfiles(); 8810 if (parsefile->fd > 0) { 8811 close(parsefile->fd); 8812 parsefile->fd = 0; 8813 } 8814} 8815 8816/* 8817 * Like setinputfile, but takes an open file descriptor. Call this with 8818 * interrupts off. 8819 */ 8820static void 8821setinputfd(int fd, int push) 8822{ 8823 fcntl(fd, F_SETFD, FD_CLOEXEC); 8824 if (push) { 8825 pushfile(); 8826 parsefile->buf = 0; 8827 } 8828 parsefile->fd = fd; 8829 if (parsefile->buf == NULL) 8830 parsefile->buf = ckmalloc(IBUFSIZ); 8831 parselleft = parsenleft = 0; 8832 plinno = 1; 8833} 8834 8835/* 8836 * Set the input to take input from a file. If push is set, push the 8837 * old input onto the stack first. 8838 */ 8839static int 8840setinputfile(const char *fname, int flags) 8841{ 8842 int fd; 8843 int fd2; 8844 8845 INT_OFF; 8846 fd = open(fname, O_RDONLY); 8847 if (fd < 0) { 8848 if (flags & INPUT_NOFILE_OK) 8849 goto out; 8850 ash_msg_and_raise_error("can't open %s", fname); 8851 } 8852 if (fd < 10) { 8853 fd2 = copyfd(fd, 10); 8854 close(fd); 8855 if (fd2 < 0) 8856 ash_msg_and_raise_error("out of file descriptors"); 8857 fd = fd2; 8858 } 8859 setinputfd(fd, flags & INPUT_PUSH_FILE); 8860 out: 8861 INT_ON; 8862 return fd; 8863} 8864 8865/* 8866 * Like setinputfile, but takes input from a string. 8867 */ 8868static void 8869setinputstring(char *string) 8870{ 8871 INT_OFF; 8872 pushfile(); 8873 parsenextc = string; 8874 parsenleft = strlen(string); 8875 parsefile->buf = NULL; 8876 plinno = 1; 8877 INT_ON; 8878} 8879 8880 8881/* ============ mail.c 8882 * 8883 * Routines to check for mail. 8884 */ 8885 8886#if ENABLE_ASH_MAIL 8887 8888#define MAXMBOXES 10 8889 8890/* times of mailboxes */ 8891static time_t mailtime[MAXMBOXES]; 8892/* Set if MAIL or MAILPATH is changed. */ 8893static int mail_var_path_changed; 8894 8895/* 8896 * Print appropriate message(s) if mail has arrived. 8897 * If mail_var_path_changed is set, 8898 * then the value of MAIL has mail_var_path_changed, 8899 * so we just update the values. 8900 */ 8901static void 8902chkmail(void) 8903{ 8904 const char *mpath; 8905 char *p; 8906 char *q; 8907 time_t *mtp; 8908 struct stackmark smark; 8909 struct stat statb; 8910 8911 setstackmark(&smark); 8912 mpath = mpathset() ? mpathval() : mailval(); 8913 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) { 8914 p = padvance(&mpath, nullstr); 8915 if (p == NULL) 8916 break; 8917 if (*p == '\0') 8918 continue; 8919 for (q = p; *q; q++); 8920#if DEBUG 8921 if (q[-1] != '/') 8922 abort(); 8923#endif 8924 q[-1] = '\0'; /* delete trailing '/' */ 8925 if (stat(p, &statb) < 0) { 8926 *mtp = 0; 8927 continue; 8928 } 8929 if (!mail_var_path_changed && statb.st_mtime != *mtp) { 8930 fprintf( 8931 stderr, snlfmt, 8932 pathopt ? pathopt : "you have mail" 8933 ); 8934 } 8935 *mtp = statb.st_mtime; 8936 } 8937 mail_var_path_changed = 0; 8938 popstackmark(&smark); 8939} 8940 8941static void 8942changemail(const char *val) 8943{ 8944 mail_var_path_changed++; 8945} 8946 8947#endif /* ASH_MAIL */ 8948 8949 8950/* ============ ??? */ 8951 8952/* 8953 * Set the shell parameters. 8954 */ 8955static void 8956setparam(char **argv) 8957{ 8958 char **newparam; 8959 char **ap; 8960 int nparam; 8961 8962 for (nparam = 0; argv[nparam]; nparam++); 8963 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap)); 8964 while (*argv) { 8965 *ap++ = ckstrdup(*argv++); 8966 } 8967 *ap = NULL; 8968 freeparam(&shellparam); 8969 shellparam.malloc = 1; 8970 shellparam.nparam = nparam; 8971 shellparam.p = newparam; 8972#if ENABLE_ASH_GETOPTS 8973 shellparam.optind = 1; 8974 shellparam.optoff = -1; 8975#endif 8976} 8977 8978/* 8979 * Process shell options. The global variable argptr contains a pointer 8980 * to the argument list; we advance it past the options. 8981 */ 8982static void 8983minus_o(char *name, int val) 8984{ 8985 int i; 8986 8987 if (name) { 8988 for (i = 0; i < NOPTS; i++) { 8989 if (strcmp(name, optnames(i)) == 0) { 8990 optlist[i] = val; 8991 return; 8992 } 8993 } 8994 ash_msg_and_raise_error("illegal option -o %s", name); 8995 } 8996 out1str("Current option settings\n"); 8997 for (i = 0; i < NOPTS; i++) 8998 out1fmt("%-16s%s\n", optnames(i), 8999 optlist[i] ? "on" : "off"); 9000} 9001static void 9002setoption(int flag, int val) 9003{ 9004 int i; 9005 9006 for (i = 0; i < NOPTS; i++) { 9007 if (optletters(i) == flag) { 9008 optlist[i] = val; 9009 return; 9010 } 9011 } 9012 ash_msg_and_raise_error("illegal option -%c", flag); 9013 /* NOTREACHED */ 9014} 9015static void 9016options(int cmdline) 9017{ 9018 char *p; 9019 int val; 9020 int c; 9021 9022 if (cmdline) 9023 minusc = NULL; 9024 while ((p = *argptr) != NULL) { 9025 c = *p++; 9026 if (c != '-' && c != '+') 9027 break; 9028 argptr++; 9029 val = 0; /* val = 0 if c == '+' */ 9030 if (c == '-') { 9031 val = 1; 9032 if (p[0] == '\0' || LONE_DASH(p)) { 9033 if (!cmdline) { 9034 /* "-" means turn off -x and -v */ 9035 if (p[0] == '\0') 9036 xflag = vflag = 0; 9037 /* "--" means reset params */ 9038 else if (*argptr == NULL) 9039 setparam(argptr); 9040 } 9041 break; /* "-" or "--" terminates options */ 9042 } 9043 } 9044 /* first char was + or - */ 9045 while ((c = *p++) != '\0') { 9046 /* bash 3.2 indeed handles -c CMD and +c CMD the same */ 9047 if (c == 'c' && cmdline) { 9048 minusc = p; /* command is after shell args */ 9049 } else if (c == 'o') { 9050 minus_o(*argptr, val); 9051 if (*argptr) 9052 argptr++; 9053 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */ 9054 isloginsh = 1; 9055 /* bash does not accept +-login, we also won't */ 9056 } else if (cmdline && val && (c == '-')) { /* long options */ 9057 if (strcmp(p, "login") == 0) 9058 isloginsh = 1; 9059 break; 9060 } else { 9061 setoption(c, val); 9062 } 9063 } 9064 } 9065} 9066 9067/* 9068 * The shift builtin command. 9069 */ 9070static int 9071shiftcmd(int argc, char **argv) 9072{ 9073 int n; 9074 char **ap1, **ap2; 9075 9076 n = 1; 9077 if (argc > 1) 9078 n = number(argv[1]); 9079 if (n > shellparam.nparam) 9080 ash_msg_and_raise_error("can't shift that many"); 9081 INT_OFF; 9082 shellparam.nparam -= n; 9083 for (ap1 = shellparam.p; --n >= 0; ap1++) { 9084 if (shellparam.malloc) 9085 free(*ap1); 9086 } 9087 ap2 = shellparam.p; 9088 while ((*ap2++ = *ap1++) != NULL); 9089#if ENABLE_ASH_GETOPTS 9090 shellparam.optind = 1; 9091 shellparam.optoff = -1; 9092#endif 9093 INT_ON; 9094 return 0; 9095} 9096 9097/* 9098 * POSIX requires that 'set' (but not export or readonly) output the 9099 * variables in lexicographic order - by the locale's collating order (sigh). 9100 * Maybe we could keep them in an ordered balanced binary tree 9101 * instead of hashed lists. 9102 * For now just roll 'em through qsort for printing... 9103 */ 9104static int 9105showvars(const char *sep_prefix, int on, int off) 9106{ 9107 const char *sep; 9108 char **ep, **epend; 9109 9110 ep = listvars(on, off, &epend); 9111 qsort(ep, epend - ep, sizeof(char *), vpcmp); 9112 9113 sep = *sep_prefix ? " " : sep_prefix; 9114 9115 for (; ep < epend; ep++) { 9116 const char *p; 9117 const char *q; 9118 9119 p = strchrnul(*ep, '='); 9120 q = nullstr; 9121 if (*p) 9122 q = single_quote(++p); 9123 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q); 9124 } 9125 return 0; 9126} 9127 9128/* 9129 * The set command builtin. 9130 */ 9131static int 9132setcmd(int argc, char **argv) 9133{ 9134 if (argc == 1) 9135 return showvars(nullstr, 0, VUNSET); 9136 INT_OFF; 9137 options(0); 9138 optschanged(); 9139 if (*argptr != NULL) { 9140 setparam(argptr); 9141 } 9142 INT_ON; 9143 return 0; 9144} 9145 9146#if ENABLE_ASH_RANDOM_SUPPORT 9147/* Roughly copied from bash.. */ 9148static void 9149change_random(const char *value) 9150{ 9151 if (value == NULL) { 9152 /* "get", generate */ 9153 char buf[16]; 9154 9155 rseed = rseed * 1103515245 + 12345; 9156 sprintf(buf, "%d", (unsigned int)((rseed & 32767))); 9157 /* set without recursion */ 9158 setvar(vrandom.text, buf, VNOFUNC); 9159 vrandom.flags &= ~VNOFUNC; 9160 } else { 9161 /* set/reset */ 9162 rseed = strtoul(value, (char **)NULL, 10); 9163 } 9164} 9165#endif 9166 9167#if ENABLE_ASH_GETOPTS 9168static int 9169getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff) 9170{ 9171 char *p, *q; 9172 char c = '?'; 9173 int done = 0; 9174 int err = 0; 9175 char s[12]; 9176 char **optnext; 9177 9178 if (*param_optind < 1) 9179 return 1; 9180 optnext = optfirst + *param_optind - 1; 9181 9182 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff) 9183 p = NULL; 9184 else 9185 p = optnext[-1] + *optoff; 9186 if (p == NULL || *p == '\0') { 9187 /* Current word is done, advance */ 9188 p = *optnext; 9189 if (p == NULL || *p != '-' || *++p == '\0') { 9190 atend: 9191 p = NULL; 9192 done = 1; 9193 goto out; 9194 } 9195 optnext++; 9196 if (LONE_DASH(p)) /* check for "--" */ 9197 goto atend; 9198 } 9199 9200 c = *p++; 9201 for (q = optstr; *q != c; ) { 9202 if (*q == '\0') { 9203 if (optstr[0] == ':') { 9204 s[0] = c; 9205 s[1] = '\0'; 9206 err |= setvarsafe("OPTARG", s, 0); 9207 } else { 9208 fprintf(stderr, "Illegal option -%c\n", c); 9209 unsetvar("OPTARG"); 9210 } 9211 c = '?'; 9212 goto out; 9213 } 9214 if (*++q == ':') 9215 q++; 9216 } 9217 9218 if (*++q == ':') { 9219 if (*p == '\0' && (p = *optnext) == NULL) { 9220 if (optstr[0] == ':') { 9221 s[0] = c; 9222 s[1] = '\0'; 9223 err |= setvarsafe("OPTARG", s, 0); 9224 c = ':'; 9225 } else { 9226 fprintf(stderr, "No arg for -%c option\n", c); 9227 unsetvar("OPTARG"); 9228 c = '?'; 9229 } 9230 goto out; 9231 } 9232 9233 if (p == *optnext) 9234 optnext++; 9235 err |= setvarsafe("OPTARG", p, 0); 9236 p = NULL; 9237 } else 9238 err |= setvarsafe("OPTARG", nullstr, 0); 9239 out: 9240 *optoff = p ? p - *(optnext - 1) : -1; 9241 *param_optind = optnext - optfirst + 1; 9242 fmtstr(s, sizeof(s), "%d", *param_optind); 9243 err |= setvarsafe("OPTIND", s, VNOFUNC); 9244 s[0] = c; 9245 s[1] = '\0'; 9246 err |= setvarsafe(optvar, s, 0); 9247 if (err) { 9248 *param_optind = 1; 9249 *optoff = -1; 9250 flush_stdout_stderr(); 9251 raise_exception(EXERROR); 9252 } 9253 return done; 9254} 9255 9256/* 9257 * The getopts builtin. Shellparam.optnext points to the next argument 9258 * to be processed. Shellparam.optptr points to the next character to 9259 * be processed in the current argument. If shellparam.optnext is NULL, 9260 * then it's the first time getopts has been called. 9261 */ 9262static int 9263getoptscmd(int argc, char **argv) 9264{ 9265 char **optbase; 9266 9267 if (argc < 3) 9268 ash_msg_and_raise_error("usage: getopts optstring var [arg]"); 9269 if (argc == 3) { 9270 optbase = shellparam.p; 9271 if (shellparam.optind > shellparam.nparam + 1) { 9272 shellparam.optind = 1; 9273 shellparam.optoff = -1; 9274 } 9275 } else { 9276 optbase = &argv[3]; 9277 if (shellparam.optind > argc - 2) { 9278 shellparam.optind = 1; 9279 shellparam.optoff = -1; 9280 } 9281 } 9282 9283 return getopts(argv[1], argv[2], optbase, &shellparam.optind, 9284 &shellparam.optoff); 9285} 9286#endif /* ASH_GETOPTS */ 9287 9288 9289/* ============ Shell parser */ 9290 9291static int tokpushback; /* last token pushed back */ 9292#define NEOF ((union node *)&tokpushback) 9293static int parsebackquote; /* nonzero if we are inside backquotes */ 9294static int lasttoken; /* last token read */ 9295static char *wordtext; /* text of last word returned by readtoken */ 9296static struct nodelist *backquotelist; 9297static union node *redirnode; 9298static struct heredoc *heredoc; 9299static int quoteflag; /* set if (part of) last token was quoted */ 9300 9301static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN; 9302static void 9303raise_error_syntax(const char *msg) 9304{ 9305 ash_msg_and_raise_error("syntax error: %s", msg); 9306 /* NOTREACHED */ 9307} 9308 9309/* 9310 * Called when an unexpected token is read during the parse. The argument 9311 * is the token that is expected, or -1 if more than one type of token can 9312 * occur at this point. 9313 */ 9314static void raise_error_unexpected_syntax(int) ATTRIBUTE_NORETURN; 9315static void 9316raise_error_unexpected_syntax(int token) 9317{ 9318 char msg[64]; 9319 int l; 9320 9321 l = sprintf(msg, "%s unexpected", tokname(lasttoken)); 9322 if (token >= 0) 9323 sprintf(msg + l, " (expecting %s)", tokname(token)); 9324 raise_error_syntax(msg); 9325 /* NOTREACHED */ 9326} 9327 9328#define EOFMARKLEN 79 9329 9330struct heredoc { 9331 struct heredoc *next; /* next here document in list */ 9332 union node *here; /* redirection node */ 9333 char *eofmark; /* string indicating end of input */ 9334 int striptabs; /* if set, strip leading tabs */ 9335}; 9336 9337static struct heredoc *heredoclist; /* list of here documents to read */ 9338 9339/* parsing is heavily cross-recursive, need these forward decls */ 9340static union node *andor(void); 9341static union node *pipeline(void); 9342static union node *parse_command(void); 9343static void parseheredoc(void); 9344static char peektoken(void); 9345static int readtoken(void); 9346 9347static union node * 9348list(int nlflag) 9349{ 9350 union node *n1, *n2, *n3; 9351 int tok; 9352 9353 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9354 if (nlflag == 2 && peektoken()) 9355 return NULL; 9356 n1 = NULL; 9357 for (;;) { 9358 n2 = andor(); 9359 tok = readtoken(); 9360 if (tok == TBACKGND) { 9361 if (n2->type == NPIPE) { 9362 n2->npipe.backgnd = 1; 9363 } else { 9364 if (n2->type != NREDIR) { 9365 n3 = stalloc(sizeof(struct nredir)); 9366 n3->nredir.n = n2; 9367 n3->nredir.redirect = NULL; 9368 n2 = n3; 9369 } 9370 n2->type = NBACKGND; 9371 } 9372 } 9373 if (n1 == NULL) { 9374 n1 = n2; 9375 } else { 9376 n3 = stalloc(sizeof(struct nbinary)); 9377 n3->type = NSEMI; 9378 n3->nbinary.ch1 = n1; 9379 n3->nbinary.ch2 = n2; 9380 n1 = n3; 9381 } 9382 switch (tok) { 9383 case TBACKGND: 9384 case TSEMI: 9385 tok = readtoken(); 9386 /* fall through */ 9387 case TNL: 9388 if (tok == TNL) { 9389 parseheredoc(); 9390 if (nlflag == 1) 9391 return n1; 9392 } else { 9393 tokpushback++; 9394 } 9395 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9396 if (peektoken()) 9397 return n1; 9398 break; 9399 case TEOF: 9400 if (heredoclist) 9401 parseheredoc(); 9402 else 9403 pungetc(); /* push back EOF on input */ 9404 return n1; 9405 default: 9406 if (nlflag == 1) 9407 raise_error_unexpected_syntax(-1); 9408 tokpushback++; 9409 return n1; 9410 } 9411 } 9412} 9413 9414static union node * 9415andor(void) 9416{ 9417 union node *n1, *n2, *n3; 9418 int t; 9419 9420 n1 = pipeline(); 9421 for (;;) { 9422 t = readtoken(); 9423 if (t == TAND) { 9424 t = NAND; 9425 } else if (t == TOR) { 9426 t = NOR; 9427 } else { 9428 tokpushback++; 9429 return n1; 9430 } 9431 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9432 n2 = pipeline(); 9433 n3 = stalloc(sizeof(struct nbinary)); 9434 n3->type = t; 9435 n3->nbinary.ch1 = n1; 9436 n3->nbinary.ch2 = n2; 9437 n1 = n3; 9438 } 9439} 9440 9441static union node * 9442pipeline(void) 9443{ 9444 union node *n1, *n2, *pipenode; 9445 struct nodelist *lp, *prev; 9446 int negate; 9447 9448 negate = 0; 9449 TRACE(("pipeline: entered\n")); 9450 if (readtoken() == TNOT) { 9451 negate = !negate; 9452 checkkwd = CHKKWD | CHKALIAS; 9453 } else 9454 tokpushback++; 9455 n1 = parse_command(); 9456 if (readtoken() == TPIPE) { 9457 pipenode = stalloc(sizeof(struct npipe)); 9458 pipenode->type = NPIPE; 9459 pipenode->npipe.backgnd = 0; 9460 lp = stalloc(sizeof(struct nodelist)); 9461 pipenode->npipe.cmdlist = lp; 9462 lp->n = n1; 9463 do { 9464 prev = lp; 9465 lp = stalloc(sizeof(struct nodelist)); 9466 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9467 lp->n = parse_command(); 9468 prev->next = lp; 9469 } while (readtoken() == TPIPE); 9470 lp->next = NULL; 9471 n1 = pipenode; 9472 } 9473 tokpushback++; 9474 if (negate) { 9475 n2 = stalloc(sizeof(struct nnot)); 9476 n2->type = NNOT; 9477 n2->nnot.com = n1; 9478 return n2; 9479 } 9480 return n1; 9481} 9482 9483static union node * 9484makename(void) 9485{ 9486 union node *n; 9487 9488 n = stalloc(sizeof(struct narg)); 9489 n->type = NARG; 9490 n->narg.next = NULL; 9491 n->narg.text = wordtext; 9492 n->narg.backquote = backquotelist; 9493 return n; 9494} 9495 9496static void 9497fixredir(union node *n, const char *text, int err) 9498{ 9499 TRACE(("Fix redir %s %d\n", text, err)); 9500 if (!err) 9501 n->ndup.vname = NULL; 9502 9503 if (isdigit(text[0]) && text[1] == '\0') 9504 n->ndup.dupfd = text[0] - '0'; 9505 else if (LONE_DASH(text)) 9506 n->ndup.dupfd = -1; 9507 else { 9508 if (err) 9509 raise_error_syntax("Bad fd number"); 9510 n->ndup.vname = makename(); 9511 } 9512} 9513 9514/* 9515 * Returns true if the text contains nothing to expand (no dollar signs 9516 * or backquotes). 9517 */ 9518static int 9519noexpand(char *text) 9520{ 9521 char *p; 9522 char c; 9523 9524 p = text; 9525 while ((c = *p++) != '\0') { 9526 if (c == CTLQUOTEMARK) 9527 continue; 9528 if (c == CTLESC) 9529 p++; 9530 else if (SIT(c, BASESYNTAX) == CCTL) 9531 return 0; 9532 } 9533 return 1; 9534} 9535 9536static void 9537parsefname(void) 9538{ 9539 union node *n = redirnode; 9540 9541 if (readtoken() != TWORD) 9542 raise_error_unexpected_syntax(-1); 9543 if (n->type == NHERE) { 9544 struct heredoc *here = heredoc; 9545 struct heredoc *p; 9546 int i; 9547 9548 if (quoteflag == 0) 9549 n->type = NXHERE; 9550 TRACE(("Here document %d\n", n->type)); 9551 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 9552 raise_error_syntax("Illegal eof marker for << redirection"); 9553 rmescapes(wordtext); 9554 here->eofmark = wordtext; 9555 here->next = NULL; 9556 if (heredoclist == NULL) 9557 heredoclist = here; 9558 else { 9559 for (p = heredoclist; p->next; p = p->next); 9560 p->next = here; 9561 } 9562 } else if (n->type == NTOFD || n->type == NFROMFD) { 9563 fixredir(n, wordtext, 0); 9564 } else { 9565 n->nfile.fname = makename(); 9566 } 9567} 9568 9569static union node * 9570simplecmd(void) 9571{ 9572 union node *args, **app; 9573 union node *n = NULL; 9574 union node *vars, **vpp; 9575 union node **rpp, *redir; 9576 int savecheckkwd; 9577 9578 args = NULL; 9579 app = &args; 9580 vars = NULL; 9581 vpp = &vars; 9582 redir = NULL; 9583 rpp = &redir; 9584 9585 savecheckkwd = CHKALIAS; 9586 for (;;) { 9587 checkkwd = savecheckkwd; 9588 switch (readtoken()) { 9589 case TWORD: 9590 n = stalloc(sizeof(struct narg)); 9591 n->type = NARG; 9592 n->narg.text = wordtext; 9593 n->narg.backquote = backquotelist; 9594 if (savecheckkwd && isassignment(wordtext)) { 9595 *vpp = n; 9596 vpp = &n->narg.next; 9597 } else { 9598 *app = n; 9599 app = &n->narg.next; 9600 savecheckkwd = 0; 9601 } 9602 break; 9603 case TREDIR: 9604 *rpp = n = redirnode; 9605 rpp = &n->nfile.next; 9606 parsefname(); /* read name of redirection file */ 9607 break; 9608 case TLP: 9609 if (args && app == &args->narg.next 9610 && !vars && !redir 9611 ) { 9612 struct builtincmd *bcmd; 9613 const char *name; 9614 9615 /* We have a function */ 9616 if (readtoken() != TRP) 9617 raise_error_unexpected_syntax(TRP); 9618 name = n->narg.text; 9619 if (!goodname(name) 9620 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd)) 9621 ) { 9622 raise_error_syntax("Bad function name"); 9623 } 9624 n->type = NDEFUN; 9625 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9626 n->narg.next = parse_command(); 9627 return n; 9628 } 9629 /* fall through */ 9630 default: 9631 tokpushback++; 9632 goto out; 9633 } 9634 } 9635 out: 9636 *app = NULL; 9637 *vpp = NULL; 9638 *rpp = NULL; 9639 n = stalloc(sizeof(struct ncmd)); 9640 n->type = NCMD; 9641 n->ncmd.args = args; 9642 n->ncmd.assign = vars; 9643 n->ncmd.redirect = redir; 9644 return n; 9645} 9646 9647static union node * 9648parse_command(void) 9649{ 9650 union node *n1, *n2; 9651 union node *ap, **app; 9652 union node *cp, **cpp; 9653 union node *redir, **rpp; 9654 union node **rpp2; 9655 int t; 9656 9657 redir = NULL; 9658 rpp2 = &redir; 9659 9660 switch (readtoken()) { 9661 default: 9662 raise_error_unexpected_syntax(-1); 9663 /* NOTREACHED */ 9664 case TIF: 9665 n1 = stalloc(sizeof(struct nif)); 9666 n1->type = NIF; 9667 n1->nif.test = list(0); 9668 if (readtoken() != TTHEN) 9669 raise_error_unexpected_syntax(TTHEN); 9670 n1->nif.ifpart = list(0); 9671 n2 = n1; 9672 while (readtoken() == TELIF) { 9673 n2->nif.elsepart = stalloc(sizeof(struct nif)); 9674 n2 = n2->nif.elsepart; 9675 n2->type = NIF; 9676 n2->nif.test = list(0); 9677 if (readtoken() != TTHEN) 9678 raise_error_unexpected_syntax(TTHEN); 9679 n2->nif.ifpart = list(0); 9680 } 9681 if (lasttoken == TELSE) 9682 n2->nif.elsepart = list(0); 9683 else { 9684 n2->nif.elsepart = NULL; 9685 tokpushback++; 9686 } 9687 t = TFI; 9688 break; 9689 case TWHILE: 9690 case TUNTIL: { 9691 int got; 9692 n1 = stalloc(sizeof(struct nbinary)); 9693 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL; 9694 n1->nbinary.ch1 = list(0); 9695 got = readtoken(); 9696 if (got != TDO) { 9697 TRACE(("expecting DO got %s %s\n", tokname(got), 9698 got == TWORD ? wordtext : "")); 9699 raise_error_unexpected_syntax(TDO); 9700 } 9701 n1->nbinary.ch2 = list(0); 9702 t = TDONE; 9703 break; 9704 } 9705 case TFOR: 9706 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 9707 raise_error_syntax("Bad for loop variable"); 9708 n1 = stalloc(sizeof(struct nfor)); 9709 n1->type = NFOR; 9710 n1->nfor.var = wordtext; 9711 checkkwd = CHKKWD | CHKALIAS; 9712 if (readtoken() == TIN) { 9713 app = ≈ 9714 while (readtoken() == TWORD) { 9715 n2 = stalloc(sizeof(struct narg)); 9716 n2->type = NARG; 9717 n2->narg.text = wordtext; 9718 n2->narg.backquote = backquotelist; 9719 *app = n2; 9720 app = &n2->narg.next; 9721 } 9722 *app = NULL; 9723 n1->nfor.args = ap; 9724 if (lasttoken != TNL && lasttoken != TSEMI) 9725 raise_error_unexpected_syntax(-1); 9726 } else { 9727 n2 = stalloc(sizeof(struct narg)); 9728 n2->type = NARG; 9729 n2->narg.text = (char *)dolatstr; 9730 n2->narg.backquote = NULL; 9731 n2->narg.next = NULL; 9732 n1->nfor.args = n2; 9733 /* 9734 * Newline or semicolon here is optional (but note 9735 * that the original Bourne shell only allowed NL). 9736 */ 9737 if (lasttoken != TNL && lasttoken != TSEMI) 9738 tokpushback++; 9739 } 9740 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9741 if (readtoken() != TDO) 9742 raise_error_unexpected_syntax(TDO); 9743 n1->nfor.body = list(0); 9744 t = TDONE; 9745 break; 9746 case TCASE: 9747 n1 = stalloc(sizeof(struct ncase)); 9748 n1->type = NCASE; 9749 if (readtoken() != TWORD) 9750 raise_error_unexpected_syntax(TWORD); 9751 n1->ncase.expr = n2 = stalloc(sizeof(struct narg)); 9752 n2->type = NARG; 9753 n2->narg.text = wordtext; 9754 n2->narg.backquote = backquotelist; 9755 n2->narg.next = NULL; 9756 do { 9757 checkkwd = CHKKWD | CHKALIAS; 9758 } while (readtoken() == TNL); 9759 if (lasttoken != TIN) 9760 raise_error_unexpected_syntax(TIN); 9761 cpp = &n1->ncase.cases; 9762 next_case: 9763 checkkwd = CHKNL | CHKKWD; 9764 t = readtoken(); 9765 while (t != TESAC) { 9766 if (lasttoken == TLP) 9767 readtoken(); 9768 *cpp = cp = stalloc(sizeof(struct nclist)); 9769 cp->type = NCLIST; 9770 app = &cp->nclist.pattern; 9771 for (;;) { 9772 *app = ap = stalloc(sizeof(struct narg)); 9773 ap->type = NARG; 9774 ap->narg.text = wordtext; 9775 ap->narg.backquote = backquotelist; 9776 if (readtoken() != TPIPE) 9777 break; 9778 app = &ap->narg.next; 9779 readtoken(); 9780 } 9781 ap->narg.next = NULL; 9782 if (lasttoken != TRP) 9783 raise_error_unexpected_syntax(TRP); 9784 cp->nclist.body = list(2); 9785 9786 cpp = &cp->nclist.next; 9787 9788 checkkwd = CHKNL | CHKKWD; 9789 t = readtoken(); 9790 if (t != TESAC) { 9791 if (t != TENDCASE) 9792 raise_error_unexpected_syntax(TENDCASE); 9793 goto next_case; 9794 } 9795 } 9796 *cpp = NULL; 9797 goto redir; 9798 case TLP: 9799 n1 = stalloc(sizeof(struct nredir)); 9800 n1->type = NSUBSHELL; 9801 n1->nredir.n = list(0); 9802 n1->nredir.redirect = NULL; 9803 t = TRP; 9804 break; 9805 case TBEGIN: 9806 n1 = list(0); 9807 t = TEND; 9808 break; 9809 case TWORD: 9810 case TREDIR: 9811 tokpushback++; 9812 return simplecmd(); 9813 } 9814 9815 if (readtoken() != t) 9816 raise_error_unexpected_syntax(t); 9817 9818 redir: 9819 /* Now check for redirection which may follow command */ 9820 checkkwd = CHKKWD | CHKALIAS; 9821 rpp = rpp2; 9822 while (readtoken() == TREDIR) { 9823 *rpp = n2 = redirnode; 9824 rpp = &n2->nfile.next; 9825 parsefname(); 9826 } 9827 tokpushback++; 9828 *rpp = NULL; 9829 if (redir) { 9830 if (n1->type != NSUBSHELL) { 9831 n2 = stalloc(sizeof(struct nredir)); 9832 n2->type = NREDIR; 9833 n2->nredir.n = n1; 9834 n1 = n2; 9835 } 9836 n1->nredir.redirect = redir; 9837 } 9838 return n1; 9839} 9840 9841/* 9842 * If eofmark is NULL, read a word or a redirection symbol. If eofmark 9843 * is not NULL, read a here document. In the latter case, eofmark is the 9844 * word which marks the end of the document and striptabs is true if 9845 * leading tabs should be stripped from the document. The argument firstc 9846 * is the first character of the input token or document. 9847 * 9848 * Because C does not have internal subroutines, I have simulated them 9849 * using goto's to implement the subroutine linkage. The following macros 9850 * will run code that appears at the end of readtoken1. 9851 */ 9852 9853static int parsebackquote; /* nonzero if we are inside backquotes */ 9854 9855#define CHECKEND() {goto checkend; checkend_return:;} 9856#define PARSEREDIR() {goto parseredir; parseredir_return:;} 9857#define PARSESUB() {goto parsesub; parsesub_return:;} 9858#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} 9859#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} 9860#define PARSEARITH() {goto parsearith; parsearith_return:;} 9861 9862static int 9863readtoken1(int firstc, int syntax, char *eofmark, int striptabs) 9864{ 9865 int c = firstc; 9866 char *out; 9867 int len; 9868 char line[EOFMARKLEN + 1]; 9869 struct nodelist *bqlist = 0; 9870 int quotef = 0; 9871 int dblquote = 0; 9872 int varnest = 0; /* levels of variables expansion */ 9873 int arinest = 0; /* levels of arithmetic expansion */ 9874 int parenlevel = 0; /* levels of parens in arithmetic */ 9875 int dqvarnest = 0; /* levels of variables expansion within double quotes */ 9876 int oldstyle = 0; 9877 int prevsyntax = 0; /* syntax before arithmetic */ 9878#if __GNUC__ 9879 /* Avoid longjmp clobbering */ 9880 (void) &out; 9881 (void) "ef; 9882 (void) &dblquote; 9883 (void) &varnest; 9884 (void) &arinest; 9885 (void) &parenlevel; 9886 (void) &dqvarnest; 9887 (void) &oldstyle; 9888 (void) &prevsyntax; 9889 (void) &syntax; 9890#endif 9891 9892 startlinno = plinno; 9893 dblquote = 0; 9894 if (syntax == DQSYNTAX) 9895 dblquote = 1; 9896 quotef = 0; 9897 bqlist = NULL; 9898 varnest = 0; 9899 arinest = 0; 9900 parenlevel = 0; 9901 dqvarnest = 0; 9902 9903 STARTSTACKSTR(out); 9904 loop: { /* for each line, until end of word */ 9905 CHECKEND(); /* set c to PEOF if at end of here document */ 9906 for (;;) { /* until end of line or end of word */ 9907 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ 9908 switch (SIT(c, syntax)) { 9909 case CNL: /* '\n' */ 9910 if (syntax == BASESYNTAX) 9911 goto endword; /* exit outer loop */ 9912 USTPUTC(c, out); 9913 plinno++; 9914 if (doprompt) 9915 setprompt(2); 9916 c = pgetc(); 9917 goto loop; /* continue outer loop */ 9918 case CWORD: 9919 USTPUTC(c, out); 9920 break; 9921 case CCTL: 9922 if (eofmark == NULL || dblquote) 9923 USTPUTC(CTLESC, out); 9924 USTPUTC(c, out); 9925 break; 9926 case CBACK: /* backslash */ 9927 c = pgetc2(); 9928 if (c == PEOF) { 9929 USTPUTC(CTLESC, out); 9930 USTPUTC('\\', out); 9931 pungetc(); 9932 } else if (c == '\n') { 9933 if (doprompt) 9934 setprompt(2); 9935 } else { 9936 if (dblquote && 9937 c != '\\' && c != '`' && 9938 c != '$' && ( 9939 c != '"' || 9940 eofmark != NULL) 9941 ) { 9942 USTPUTC(CTLESC, out); 9943 USTPUTC('\\', out); 9944 } 9945 if (SIT(c, SQSYNTAX) == CCTL) 9946 USTPUTC(CTLESC, out); 9947 USTPUTC(c, out); 9948 quotef++; 9949 } 9950 break; 9951 case CSQUOTE: 9952 syntax = SQSYNTAX; 9953 quotemark: 9954 if (eofmark == NULL) { 9955 USTPUTC(CTLQUOTEMARK, out); 9956 } 9957 break; 9958 case CDQUOTE: 9959 syntax = DQSYNTAX; 9960 dblquote = 1; 9961 goto quotemark; 9962 case CENDQUOTE: 9963 if (eofmark != NULL && arinest == 0 9964 && varnest == 0 9965 ) { 9966 USTPUTC(c, out); 9967 } else { 9968 if (dqvarnest == 0) { 9969 syntax = BASESYNTAX; 9970 dblquote = 0; 9971 } 9972 quotef++; 9973 goto quotemark; 9974 } 9975 break; 9976 case CVAR: /* '$' */ 9977 PARSESUB(); /* parse substitution */ 9978 break; 9979 case CENDVAR: /* '}' */ 9980 if (varnest > 0) { 9981 varnest--; 9982 if (dqvarnest > 0) { 9983 dqvarnest--; 9984 } 9985 USTPUTC(CTLENDVAR, out); 9986 } else { 9987 USTPUTC(c, out); 9988 } 9989 break; 9990#if ENABLE_ASH_MATH_SUPPORT 9991 case CLP: /* '(' in arithmetic */ 9992 parenlevel++; 9993 USTPUTC(c, out); 9994 break; 9995 case CRP: /* ')' in arithmetic */ 9996 if (parenlevel > 0) { 9997 USTPUTC(c, out); 9998 --parenlevel; 9999 } else { 10000 if (pgetc() == ')') { 10001 if (--arinest == 0) { 10002 USTPUTC(CTLENDARI, out); 10003 syntax = prevsyntax; 10004 if (syntax == DQSYNTAX) 10005 dblquote = 1; 10006 else 10007 dblquote = 0; 10008 } else 10009 USTPUTC(')', out); 10010 } else { 10011 /* 10012 * unbalanced parens 10013 * (don't 2nd guess - no error) 10014 */ 10015 pungetc(); 10016 USTPUTC(')', out); 10017 } 10018 } 10019 break; 10020#endif 10021 case CBQUOTE: /* '`' */ 10022 PARSEBACKQOLD(); 10023 break; 10024 case CENDFILE: 10025 goto endword; /* exit outer loop */ 10026 case CIGN: 10027 break; 10028 default: 10029 if (varnest == 0) 10030 goto endword; /* exit outer loop */ 10031#if ENABLE_ASH_ALIAS 10032 if (c != PEOA) 10033#endif 10034 USTPUTC(c, out); 10035 10036 } 10037 c = pgetc_macro(); 10038 } 10039 } 10040 endword: 10041#if ENABLE_ASH_MATH_SUPPORT 10042 if (syntax == ARISYNTAX) 10043 raise_error_syntax("Missing '))'"); 10044#endif 10045 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL) 10046 raise_error_syntax("Unterminated quoted string"); 10047 if (varnest != 0) { 10048 startlinno = plinno; 10049 /* { */ 10050 raise_error_syntax("Missing '}'"); 10051 } 10052 USTPUTC('\0', out); 10053 len = out - (char *)stackblock(); 10054 out = stackblock(); 10055 if (eofmark == NULL) { 10056 if ((c == '>' || c == '<') 10057 && quotef == 0 10058 && len <= 2 10059 && (*out == '\0' || isdigit(*out))) { 10060 PARSEREDIR(); 10061 return lasttoken = TREDIR; 10062 } else { 10063 pungetc(); 10064 } 10065 } 10066 quoteflag = quotef; 10067 backquotelist = bqlist; 10068 grabstackblock(len); 10069 wordtext = out; 10070 lasttoken = TWORD; 10071 return lasttoken; 10072/* end of readtoken routine */ 10073 10074/* 10075 * Check to see whether we are at the end of the here document. When this 10076 * is called, c is set to the first character of the next input line. If 10077 * we are at the end of the here document, this routine sets the c to PEOF. 10078 */ 10079checkend: { 10080 if (eofmark) { 10081#if ENABLE_ASH_ALIAS 10082 if (c == PEOA) { 10083 c = pgetc2(); 10084 } 10085#endif 10086 if (striptabs) { 10087 while (c == '\t') { 10088 c = pgetc2(); 10089 } 10090 } 10091 if (c == *eofmark) { 10092 if (pfgets(line, sizeof(line)) != NULL) { 10093 char *p, *q; 10094 10095 p = line; 10096 for (q = eofmark + 1; *q && *p == *q; p++, q++); 10097 if (*p == '\n' && *q == '\0') { 10098 c = PEOF; 10099 plinno++; 10100 needprompt = doprompt; 10101 } else { 10102 pushstring(line, NULL); 10103 } 10104 } 10105 } 10106 } 10107 goto checkend_return; 10108} 10109 10110/* 10111 * Parse a redirection operator. The variable "out" points to a string 10112 * specifying the fd to be redirected. The variable "c" contains the 10113 * first character of the redirection operator. 10114 */ 10115parseredir: { 10116 char fd = *out; 10117 union node *np; 10118 10119 np = stalloc(sizeof(struct nfile)); 10120 if (c == '>') { 10121 np->nfile.fd = 1; 10122 c = pgetc(); 10123 if (c == '>') 10124 np->type = NAPPEND; 10125 else if (c == '|') 10126 np->type = NCLOBBER; 10127 else if (c == '&') 10128 np->type = NTOFD; 10129 else { 10130 np->type = NTO; 10131 pungetc(); 10132 } 10133 } else { /* c == '<' */ 10134 np->nfile.fd = 0; 10135 c = pgetc(); 10136 switch (c) { 10137 case '<': 10138 if (sizeof(struct nfile) != sizeof(struct nhere)) { 10139 np = stalloc(sizeof(struct nhere)); 10140 np->nfile.fd = 0; 10141 } 10142 np->type = NHERE; 10143 heredoc = stalloc(sizeof(struct heredoc)); 10144 heredoc->here = np; 10145 c = pgetc(); 10146 if (c == '-') { 10147 heredoc->striptabs = 1; 10148 } else { 10149 heredoc->striptabs = 0; 10150 pungetc(); 10151 } 10152 break; 10153 10154 case '&': 10155 np->type = NFROMFD; 10156 break; 10157 10158 case '>': 10159 np->type = NFROMTO; 10160 break; 10161 10162 default: 10163 np->type = NFROM; 10164 pungetc(); 10165 break; 10166 } 10167 } 10168 if (fd != '\0') 10169 np->nfile.fd = fd - '0'; 10170 redirnode = np; 10171 goto parseredir_return; 10172} 10173 10174/* 10175 * Parse a substitution. At this point, we have read the dollar sign 10176 * and nothing else. 10177 */ 10178 10179/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise 10180 * (assuming ascii char codes, as the original implementation did) */ 10181#define is_special(c) \ 10182 ((((unsigned int)c) - 33 < 32) \ 10183 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1)) 10184parsesub: { 10185 int subtype; 10186 int typeloc; 10187 int flags; 10188 char *p; 10189 static const char types[] ALIGN1 = "}-+?="; 10190 10191 c = pgetc(); 10192 if ( 10193 c <= PEOA_OR_PEOF || 10194 (c != '(' && c != '{' && !is_name(c) && !is_special(c)) 10195 ) { 10196 USTPUTC('$', out); 10197 pungetc(); 10198 } else if (c == '(') { /* $(command) or $((arith)) */ 10199 if (pgetc() == '(') { 10200#if ENABLE_ASH_MATH_SUPPORT 10201 PARSEARITH(); 10202#else 10203 raise_error_syntax("We unsupport $((arith))"); 10204#endif 10205 } else { 10206 pungetc(); 10207 PARSEBACKQNEW(); 10208 } 10209 } else { 10210 USTPUTC(CTLVAR, out); 10211 typeloc = out - (char *)stackblock(); 10212 USTPUTC(VSNORMAL, out); 10213 subtype = VSNORMAL; 10214 if (c == '{') { 10215 c = pgetc(); 10216 if (c == '#') { 10217 c = pgetc(); 10218 if (c == '}') 10219 c = '#'; 10220 else 10221 subtype = VSLENGTH; 10222 } else 10223 subtype = 0; 10224 } 10225 if (c > PEOA_OR_PEOF && is_name(c)) { 10226 do { 10227 STPUTC(c, out); 10228 c = pgetc(); 10229 } while (c > PEOA_OR_PEOF && is_in_name(c)); 10230 } else if (isdigit(c)) { 10231 do { 10232 STPUTC(c, out); 10233 c = pgetc(); 10234 } while (isdigit(c)); 10235 } else if (is_special(c)) { 10236 USTPUTC(c, out); 10237 c = pgetc(); 10238 } else 10239 badsub: raise_error_syntax("Bad substitution"); 10240 10241 STPUTC('=', out); 10242 flags = 0; 10243 if (subtype == 0) { 10244 switch (c) { 10245 case ':': 10246 flags = VSNUL; 10247 c = pgetc(); 10248 /*FALLTHROUGH*/ 10249 default: 10250 p = strchr(types, c); 10251 if (p == NULL) 10252 goto badsub; 10253 subtype = p - types + VSNORMAL; 10254 break; 10255 case '%': 10256 case '#': 10257 { 10258 int cc = c; 10259 subtype = c == '#' ? VSTRIMLEFT : 10260 VSTRIMRIGHT; 10261 c = pgetc(); 10262 if (c == cc) 10263 subtype++; 10264 else 10265 pungetc(); 10266 break; 10267 } 10268 } 10269 } else { 10270 pungetc(); 10271 } 10272 if (dblquote || arinest) 10273 flags |= VSQUOTE; 10274 *((char *)stackblock() + typeloc) = subtype | flags; 10275 if (subtype != VSNORMAL) { 10276 varnest++; 10277 if (dblquote || arinest) { 10278 dqvarnest++; 10279 } 10280 } 10281 } 10282 goto parsesub_return; 10283} 10284 10285/* 10286 * Called to parse command substitutions. Newstyle is set if the command 10287 * is enclosed inside $(...); nlpp is a pointer to the head of the linked 10288 * list of commands (passed by reference), and savelen is the number of 10289 * characters on the top of the stack which must be preserved. 10290 */ 10291parsebackq: { 10292 struct nodelist **nlpp; 10293 int savepbq; 10294 union node *n; 10295 char *volatile str; 10296 struct jmploc jmploc; 10297 struct jmploc *volatile savehandler; 10298 size_t savelen; 10299 int saveprompt = 0; 10300#ifdef __GNUC__ 10301 (void) &saveprompt; 10302#endif 10303 10304 savepbq = parsebackquote; 10305 if (setjmp(jmploc.loc)) { 10306 if (str) 10307 free(str); 10308 parsebackquote = 0; 10309 exception_handler = savehandler; 10310 longjmp(exception_handler->loc, 1); 10311 } 10312 INT_OFF; 10313 str = NULL; 10314 savelen = out - (char *)stackblock(); 10315 if (savelen > 0) { 10316 str = ckmalloc(savelen); 10317 memcpy(str, stackblock(), savelen); 10318 } 10319 savehandler = exception_handler; 10320 exception_handler = &jmploc; 10321 INT_ON; 10322 if (oldstyle) { 10323 /* We must read until the closing backquote, giving special 10324 treatment to some slashes, and then push the string and 10325 reread it as input, interpreting it normally. */ 10326 char *pout; 10327 int pc; 10328 size_t psavelen; 10329 char *pstr; 10330 10331 10332 STARTSTACKSTR(pout); 10333 for (;;) { 10334 if (needprompt) { 10335 setprompt(2); 10336 } 10337 pc = pgetc(); 10338 switch (pc) { 10339 case '`': 10340 goto done; 10341 10342 case '\\': 10343 pc = pgetc(); 10344 if (pc == '\n') { 10345 plinno++; 10346 if (doprompt) 10347 setprompt(2); 10348 /* 10349 * If eating a newline, avoid putting 10350 * the newline into the new character 10351 * stream (via the STPUTC after the 10352 * switch). 10353 */ 10354 continue; 10355 } 10356 if (pc != '\\' && pc != '`' && pc != '$' 10357 && (!dblquote || pc != '"')) 10358 STPUTC('\\', pout); 10359 if (pc > PEOA_OR_PEOF) { 10360 break; 10361 } 10362 /* fall through */ 10363 10364 case PEOF: 10365#if ENABLE_ASH_ALIAS 10366 case PEOA: 10367#endif 10368 startlinno = plinno; 10369 raise_error_syntax("EOF in backquote substitution"); 10370 10371 case '\n': 10372 plinno++; 10373 needprompt = doprompt; 10374 break; 10375 10376 default: 10377 break; 10378 } 10379 STPUTC(pc, pout); 10380 } 10381 done: 10382 STPUTC('\0', pout); 10383 psavelen = pout - (char *)stackblock(); 10384 if (psavelen > 0) { 10385 pstr = grabstackstr(pout); 10386 setinputstring(pstr); 10387 } 10388 } 10389 nlpp = &bqlist; 10390 while (*nlpp) 10391 nlpp = &(*nlpp)->next; 10392 *nlpp = stalloc(sizeof(**nlpp)); 10393 (*nlpp)->next = NULL; 10394 parsebackquote = oldstyle; 10395 10396 if (oldstyle) { 10397 saveprompt = doprompt; 10398 doprompt = 0; 10399 } 10400 10401 n = list(2); 10402 10403 if (oldstyle) 10404 doprompt = saveprompt; 10405 else if (readtoken() != TRP) 10406 raise_error_unexpected_syntax(TRP); 10407 10408 (*nlpp)->n = n; 10409 if (oldstyle) { 10410 /* 10411 * Start reading from old file again, ignoring any pushed back 10412 * tokens left from the backquote parsing 10413 */ 10414 popfile(); 10415 tokpushback = 0; 10416 } 10417 while (stackblocksize() <= savelen) 10418 growstackblock(); 10419 STARTSTACKSTR(out); 10420 if (str) { 10421 memcpy(out, str, savelen); 10422 STADJUST(savelen, out); 10423 INT_OFF; 10424 free(str); 10425 str = NULL; 10426 INT_ON; 10427 } 10428 parsebackquote = savepbq; 10429 exception_handler = savehandler; 10430 if (arinest || dblquote) 10431 USTPUTC(CTLBACKQ | CTLQUOTE, out); 10432 else 10433 USTPUTC(CTLBACKQ, out); 10434 if (oldstyle) 10435 goto parsebackq_oldreturn; 10436 goto parsebackq_newreturn; 10437} 10438 10439#if ENABLE_ASH_MATH_SUPPORT 10440/* 10441 * Parse an arithmetic expansion (indicate start of one and set state) 10442 */ 10443parsearith: { 10444 if (++arinest == 1) { 10445 prevsyntax = syntax; 10446 syntax = ARISYNTAX; 10447 USTPUTC(CTLARI, out); 10448 if (dblquote) 10449 USTPUTC('"', out); 10450 else 10451 USTPUTC(' ', out); 10452 } else { 10453 /* 10454 * we collapse embedded arithmetic expansion to 10455 * parenthesis, which should be equivalent 10456 */ 10457 USTPUTC('(', out); 10458 } 10459 goto parsearith_return; 10460} 10461#endif 10462 10463} /* end of readtoken */ 10464 10465/* 10466 * Read the next input token. 10467 * If the token is a word, we set backquotelist to the list of cmds in 10468 * backquotes. We set quoteflag to true if any part of the word was 10469 * quoted. 10470 * If the token is TREDIR, then we set redirnode to a structure containing 10471 * the redirection. 10472 * In all cases, the variable startlinno is set to the number of the line 10473 * on which the token starts. 10474 * 10475 * [Change comment: here documents and internal procedures] 10476 * [Readtoken shouldn't have any arguments. Perhaps we should make the 10477 * word parsing code into a separate routine. In this case, readtoken 10478 * doesn't need to have any internal procedures, but parseword does. 10479 * We could also make parseoperator in essence the main routine, and 10480 * have parseword (readtoken1?) handle both words and redirection.] 10481 */ 10482#define NEW_xxreadtoken 10483#ifdef NEW_xxreadtoken 10484/* singles must be first! */ 10485static const char xxreadtoken_chars[7] ALIGN1 = { 10486 '\n', '(', ')', '&', '|', ';', 0 10487}; 10488 10489static const char xxreadtoken_tokens[] ALIGN1 = { 10490 TNL, TLP, TRP, /* only single occurrence allowed */ 10491 TBACKGND, TPIPE, TSEMI, /* if single occurrence */ 10492 TEOF, /* corresponds to trailing nul */ 10493 TAND, TOR, TENDCASE /* if double occurrence */ 10494}; 10495 10496#define xxreadtoken_doubles \ 10497 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars)) 10498#define xxreadtoken_singles \ 10499 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1) 10500 10501static int 10502xxreadtoken(void) 10503{ 10504 int c; 10505 10506 if (tokpushback) { 10507 tokpushback = 0; 10508 return lasttoken; 10509 } 10510 if (needprompt) { 10511 setprompt(2); 10512 } 10513 startlinno = plinno; 10514 for (;;) { /* until token or start of word found */ 10515 c = pgetc_macro(); 10516 10517 if ((c != ' ') && (c != '\t') 10518#if ENABLE_ASH_ALIAS 10519 && (c != PEOA) 10520#endif 10521 ) { 10522 if (c == '#') { 10523 while ((c = pgetc()) != '\n' && c != PEOF); 10524 pungetc(); 10525 } else if (c == '\\') { 10526 if (pgetc() != '\n') { 10527 pungetc(); 10528 goto READTOKEN1; 10529 } 10530 startlinno = ++plinno; 10531 if (doprompt) 10532 setprompt(2); 10533 } else { 10534 const char *p 10535 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1; 10536 10537 if (c != PEOF) { 10538 if (c == '\n') { 10539 plinno++; 10540 needprompt = doprompt; 10541 } 10542 10543 p = strchr(xxreadtoken_chars, c); 10544 if (p == NULL) { 10545 READTOKEN1: 10546 return readtoken1(c, BASESYNTAX, (char *) NULL, 0); 10547 } 10548 10549 if (p - xxreadtoken_chars >= xxreadtoken_singles) { 10550 if (pgetc() == *p) { /* double occurrence? */ 10551 p += xxreadtoken_doubles + 1; 10552 } else { 10553 pungetc(); 10554 } 10555 } 10556 } 10557 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars]; 10558 } 10559 } 10560 } /* for */ 10561} 10562#else 10563#define RETURN(token) return lasttoken = token 10564static int 10565xxreadtoken(void) 10566{ 10567 int c; 10568 10569 if (tokpushback) { 10570 tokpushback = 0; 10571 return lasttoken; 10572 } 10573 if (needprompt) { 10574 setprompt(2); 10575 } 10576 startlinno = plinno; 10577 for (;;) { /* until token or start of word found */ 10578 c = pgetc_macro(); 10579 switch (c) { 10580 case ' ': case '\t': 10581#if ENABLE_ASH_ALIAS 10582 case PEOA: 10583#endif 10584 continue; 10585 case '#': 10586 while ((c = pgetc()) != '\n' && c != PEOF); 10587 pungetc(); 10588 continue; 10589 case '\\': 10590 if (pgetc() == '\n') { 10591 startlinno = ++plinno; 10592 if (doprompt) 10593 setprompt(2); 10594 continue; 10595 } 10596 pungetc(); 10597 goto breakloop; 10598 case '\n': 10599 plinno++; 10600 needprompt = doprompt; 10601 RETURN(TNL); 10602 case PEOF: 10603 RETURN(TEOF); 10604 case '&': 10605 if (pgetc() == '&') 10606 RETURN(TAND); 10607 pungetc(); 10608 RETURN(TBACKGND); 10609 case '|': 10610 if (pgetc() == '|') 10611 RETURN(TOR); 10612 pungetc(); 10613 RETURN(TPIPE); 10614 case ';': 10615 if (pgetc() == ';') 10616 RETURN(TENDCASE); 10617 pungetc(); 10618 RETURN(TSEMI); 10619 case '(': 10620 RETURN(TLP); 10621 case ')': 10622 RETURN(TRP); 10623 default: 10624 goto breakloop; 10625 } 10626 } 10627 breakloop: 10628 return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 10629#undef RETURN 10630} 10631#endif /* NEW_xxreadtoken */ 10632 10633static int 10634readtoken(void) 10635{ 10636 int t; 10637#if DEBUG 10638 int alreadyseen = tokpushback; 10639#endif 10640 10641#if ENABLE_ASH_ALIAS 10642 top: 10643#endif 10644 10645 t = xxreadtoken(); 10646 10647 /* 10648 * eat newlines 10649 */ 10650 if (checkkwd & CHKNL) { 10651 while (t == TNL) { 10652 parseheredoc(); 10653 t = xxreadtoken(); 10654 } 10655 } 10656 10657 if (t != TWORD || quoteflag) { 10658 goto out; 10659 } 10660 10661 /* 10662 * check for keywords 10663 */ 10664 if (checkkwd & CHKKWD) { 10665 const char *const *pp; 10666 10667 pp = findkwd(wordtext); 10668 if (pp) { 10669 lasttoken = t = pp - tokname_array; 10670 TRACE(("keyword %s recognized\n", tokname(t))); 10671 goto out; 10672 } 10673 } 10674 10675 if (checkkwd & CHKALIAS) { 10676#if ENABLE_ASH_ALIAS 10677 struct alias *ap; 10678 ap = lookupalias(wordtext, 1); 10679 if (ap != NULL) { 10680 if (*ap->val) { 10681 pushstring(ap->val, ap); 10682 } 10683 goto top; 10684 } 10685#endif 10686 } 10687 out: 10688 checkkwd = 0; 10689#if DEBUG 10690 if (!alreadyseen) 10691 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : "")); 10692 else 10693 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : "")); 10694#endif 10695 return t; 10696} 10697 10698static char 10699peektoken(void) 10700{ 10701 int t; 10702 10703 t = readtoken(); 10704 tokpushback++; 10705 return tokname_array[t][0]; 10706} 10707 10708/* 10709 * Read and parse a command. Returns NEOF on end of file. (NULL is a 10710 * valid parse tree indicating a blank line.) 10711 */ 10712static union node * 10713parsecmd(int interact) 10714{ 10715 int t; 10716 10717 tokpushback = 0; 10718 doprompt = interact; 10719 if (doprompt) 10720 setprompt(doprompt); 10721 needprompt = 0; 10722 t = readtoken(); 10723 if (t == TEOF) 10724 return NEOF; 10725 if (t == TNL) 10726 return NULL; 10727 tokpushback++; 10728 return list(1); 10729} 10730 10731/* 10732 * Input any here documents. 10733 */ 10734static void 10735parseheredoc(void) 10736{ 10737 struct heredoc *here; 10738 union node *n; 10739 10740 here = heredoclist; 10741 heredoclist = 0; 10742 10743 while (here) { 10744 if (needprompt) { 10745 setprompt(2); 10746 } 10747 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 10748 here->eofmark, here->striptabs); 10749 n = stalloc(sizeof(struct narg)); 10750 n->narg.type = NARG; 10751 n->narg.next = NULL; 10752 n->narg.text = wordtext; 10753 n->narg.backquote = backquotelist; 10754 here->here->nhere.doc = n; 10755 here = here->next; 10756 } 10757} 10758 10759 10760/* 10761 * called by editline -- any expansions to the prompt should be added here. 10762 */ 10763#if ENABLE_ASH_EXPAND_PRMT 10764static const char * 10765expandstr(const char *ps) 10766{ 10767 union node n; 10768 10769 setinputstring((char *)ps); 10770 readtoken1(pgetc(), DQSYNTAX, nullstr, 0); 10771 popfile(); 10772 10773 n.narg.type = NARG; 10774 n.narg.next = NULL; 10775 n.narg.text = wordtext; 10776 n.narg.backquote = backquotelist; 10777 10778 expandarg(&n, NULL, 0); 10779 return stackblock(); 10780} 10781#endif 10782 10783/* 10784 * Execute a command or commands contained in a string. 10785 */ 10786static int 10787evalstring(char *s, int mask) 10788{ 10789 union node *n; 10790 struct stackmark smark; 10791 int skip; 10792 10793 setinputstring(s); 10794 setstackmark(&smark); 10795 10796 skip = 0; 10797 while ((n = parsecmd(0)) != NEOF) { 10798 evaltree(n, 0); 10799 popstackmark(&smark); 10800 skip = evalskip; 10801 if (skip) 10802 break; 10803 } 10804 popfile(); 10805 10806 skip &= mask; 10807 evalskip = skip; 10808 return skip; 10809} 10810 10811/* 10812 * The eval command. 10813 */ 10814static int 10815evalcmd(int argc, char **argv) 10816{ 10817 char *p; 10818 char *concat; 10819 char **ap; 10820 10821 if (argc > 1) { 10822 p = argv[1]; 10823 if (argc > 2) { 10824 STARTSTACKSTR(concat); 10825 ap = argv + 2; 10826 for (;;) { 10827 concat = stack_putstr(p, concat); 10828 p = *ap++; 10829 if (p == NULL) 10830 break; 10831 STPUTC(' ', concat); 10832 } 10833 STPUTC('\0', concat); 10834 p = grabstackstr(concat); 10835 } 10836 evalstring(p, ~SKIPEVAL); 10837 10838 } 10839 return exitstatus; 10840} 10841 10842/* 10843 * Read and execute commands. "Top" is nonzero for the top level command 10844 * loop; it turns on prompting if the shell is interactive. 10845 */ 10846static int 10847cmdloop(int top) 10848{ 10849 union node *n; 10850 struct stackmark smark; 10851 int inter; 10852 int numeof = 0; 10853 10854 TRACE(("cmdloop(%d) called\n", top)); 10855 for (;;) { 10856 int skip; 10857 10858 setstackmark(&smark); 10859#if JOBS 10860 if (jobctl) 10861 showjobs(stderr, SHOW_CHANGED); 10862#endif 10863 inter = 0; 10864 if (iflag && top) { 10865 inter++; 10866#if ENABLE_ASH_MAIL 10867 chkmail(); 10868#endif 10869 } 10870 n = parsecmd(inter); 10871 /* showtree(n); DEBUG */ 10872 if (n == NEOF) { 10873 if (!top || numeof >= 50) 10874 break; 10875 if (!stoppedjobs()) { 10876 if (!Iflag) 10877 break; 10878 out2str("\nUse \"exit\" to leave shell.\n"); 10879 } 10880 numeof++; 10881 } else if (nflag == 0) { 10882 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */ 10883 job_warning >>= 1; 10884 numeof = 0; 10885 evaltree(n, 0); 10886 } 10887 popstackmark(&smark); 10888 skip = evalskip; 10889 10890 if (skip) { 10891 evalskip = 0; 10892 return skip & SKIPEVAL; 10893 } 10894 } 10895 return 0; 10896} 10897 10898/* 10899 * Take commands from a file. To be compatible we should do a path 10900 * search for the file, which is necessary to find sub-commands. 10901 */ 10902static char * 10903find_dot_file(char *name) 10904{ 10905 char *fullname; 10906 const char *path = pathval(); 10907 struct stat statb; 10908 10909 /* don't try this for absolute or relative paths */ 10910 if (strchr(name, '/')) 10911 return name; 10912 10913 while ((fullname = padvance(&path, name)) != NULL) { 10914 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { 10915 /* 10916 * Don't bother freeing here, since it will 10917 * be freed by the caller. 10918 */ 10919 return fullname; 10920 } 10921 stunalloc(fullname); 10922 } 10923 10924 /* not found in the PATH */ 10925 ash_msg_and_raise_error("%s: not found", name); 10926 /* NOTREACHED */ 10927} 10928 10929static int 10930dotcmd(int argc, char **argv) 10931{ 10932 struct strlist *sp; 10933 volatile struct shparam saveparam; 10934 int status = 0; 10935 10936 for (sp = cmdenviron; sp; sp = sp->next) 10937 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED); 10938 10939 if (argc >= 2) { /* That's what SVR2 does */ 10940 char *fullname; 10941 10942 fullname = find_dot_file(argv[1]); 10943 10944 if (argc > 2) { 10945 saveparam = shellparam; 10946 shellparam.malloc = 0; 10947 shellparam.nparam = argc - 2; 10948 shellparam.p = argv + 2; 10949 }; 10950 10951 setinputfile(fullname, INPUT_PUSH_FILE); 10952 commandname = fullname; 10953 cmdloop(0); 10954 popfile(); 10955 10956 if (argc > 2) { 10957 freeparam(&shellparam); 10958 shellparam = saveparam; 10959 }; 10960 status = exitstatus; 10961 } 10962 return status; 10963} 10964 10965static int 10966exitcmd(int argc, char **argv) 10967{ 10968 if (stoppedjobs()) 10969 return 0; 10970 if (argc > 1) 10971 exitstatus = number(argv[1]); 10972 raise_exception(EXEXIT); 10973 /* NOTREACHED */ 10974} 10975 10976#if ENABLE_ASH_BUILTIN_ECHO 10977static int 10978echocmd(int argc, char **argv) 10979{ 10980 return bb_echo(argv); 10981} 10982#endif 10983 10984#if ENABLE_ASH_BUILTIN_TEST 10985static int 10986testcmd(int argc, char **argv) 10987{ 10988 return test_main(argc, argv); 10989} 10990#endif 10991 10992/* 10993 * Read a file containing shell functions. 10994 */ 10995static void 10996readcmdfile(char *name) 10997{ 10998 setinputfile(name, INPUT_PUSH_FILE); 10999 cmdloop(0); 11000 popfile(); 11001} 11002 11003 11004/* ============ find_command inplementation */ 11005 11006/* 11007 * Resolve a command name. If you change this routine, you may have to 11008 * change the shellexec routine as well. 11009 */ 11010static void 11011find_command(char *name, struct cmdentry *entry, int act, const char *path) 11012{ 11013 struct tblentry *cmdp; 11014 int idx; 11015 int prev; 11016 char *fullname; 11017 struct stat statb; 11018 int e; 11019 int updatetbl; 11020 struct builtincmd *bcmd; 11021 11022 /* If name contains a slash, don't use PATH or hash table */ 11023 if (strchr(name, '/') != NULL) { 11024 entry->u.index = -1; 11025 if (act & DO_ABS) { 11026 while (stat(name, &statb) < 0) { 11027#ifdef SYSV 11028 if (errno == EINTR) 11029 continue; 11030#endif 11031 entry->cmdtype = CMDUNKNOWN; 11032 return; 11033 } 11034 } 11035 entry->cmdtype = CMDNORMAL; 11036 return; 11037 } 11038 11039/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ 11040 11041 updatetbl = (path == pathval()); 11042 if (!updatetbl) { 11043 act |= DO_ALTPATH; 11044 if (strstr(path, "%builtin") != NULL) 11045 act |= DO_ALTBLTIN; 11046 } 11047 11048 /* If name is in the table, check answer will be ok */ 11049 cmdp = cmdlookup(name, 0); 11050 if (cmdp != NULL) { 11051 int bit; 11052 11053 switch (cmdp->cmdtype) { 11054 default: 11055#if DEBUG 11056 abort(); 11057#endif 11058 case CMDNORMAL: 11059 bit = DO_ALTPATH; 11060 break; 11061 case CMDFUNCTION: 11062 bit = DO_NOFUNC; 11063 break; 11064 case CMDBUILTIN: 11065 bit = DO_ALTBLTIN; 11066 break; 11067 } 11068 if (act & bit) { 11069 updatetbl = 0; 11070 cmdp = NULL; 11071 } else if (cmdp->rehash == 0) 11072 /* if not invalidated by cd, we're done */ 11073 goto success; 11074 } 11075 11076 /* If %builtin not in path, check for builtin next */ 11077 bcmd = find_builtin(name); 11078 if (bcmd) { 11079 if (IS_BUILTIN_REGULAR(bcmd)) 11080 goto builtin_success; 11081 if (act & DO_ALTPATH) { 11082 if (!(act & DO_ALTBLTIN)) 11083 goto builtin_success; 11084 } else if (builtinloc <= 0) { 11085 goto builtin_success; 11086 } 11087 } 11088 11089#if ENABLE_FEATURE_SH_STANDALONE 11090 if (find_applet_by_name(name)) { 11091 entry->cmdtype = CMDNORMAL; 11092 entry->u.index = -1; 11093 return; 11094 } 11095#endif 11096 11097 /* We have to search path. */ 11098 prev = -1; /* where to start */ 11099 if (cmdp && cmdp->rehash) { /* doing a rehash */ 11100 if (cmdp->cmdtype == CMDBUILTIN) 11101 prev = builtinloc; 11102 else 11103 prev = cmdp->param.index; 11104 } 11105 11106 e = ENOENT; 11107 idx = -1; 11108 loop: 11109 while ((fullname = padvance(&path, name)) != NULL) { 11110 stunalloc(fullname); 11111 /* NB: code below will still use fullname 11112 * despite it being "unallocated" */ 11113 idx++; 11114 if (pathopt) { 11115 if (prefix(pathopt, "builtin")) { 11116 if (bcmd) 11117 goto builtin_success; 11118 continue; 11119 } else if (!(act & DO_NOFUNC) 11120 && prefix(pathopt, "func")) { 11121 /* handled below */ 11122 } else { 11123 /* ignore unimplemented options */ 11124 continue; 11125 } 11126 } 11127 /* if rehash, don't redo absolute path names */ 11128 if (fullname[0] == '/' && idx <= prev) { 11129 if (idx < prev) 11130 continue; 11131 TRACE(("searchexec \"%s\": no change\n", name)); 11132 goto success; 11133 } 11134 while (stat(fullname, &statb) < 0) { 11135#ifdef SYSV 11136 if (errno == EINTR) 11137 continue; 11138#endif 11139 if (errno != ENOENT && errno != ENOTDIR) 11140 e = errno; 11141 goto loop; 11142 } 11143 e = EACCES; /* if we fail, this will be the error */ 11144 if (!S_ISREG(statb.st_mode)) 11145 continue; 11146 if (pathopt) { /* this is a %func directory */ 11147 stalloc(strlen(fullname) + 1); 11148 /* NB: stalloc will return space pointed by fullname 11149 * (because we don't have any intervening allocations 11150 * between stunalloc above and this stalloc) */ 11151 readcmdfile(fullname); 11152 cmdp = cmdlookup(name, 0); 11153 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION) 11154 ash_msg_and_raise_error("%s not defined in %s", name, fullname); 11155 stunalloc(fullname); 11156 goto success; 11157 } 11158 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); 11159 if (!updatetbl) { 11160 entry->cmdtype = CMDNORMAL; 11161 entry->u.index = idx; 11162 return; 11163 } 11164 INT_OFF; 11165 cmdp = cmdlookup(name, 1); 11166 cmdp->cmdtype = CMDNORMAL; 11167 cmdp->param.index = idx; 11168 INT_ON; 11169 goto success; 11170 } 11171 11172 /* We failed. If there was an entry for this command, delete it */ 11173 if (cmdp && updatetbl) 11174 delete_cmd_entry(); 11175 if (act & DO_ERR) 11176 ash_msg("%s: %s", name, errmsg(e, "not found")); 11177 entry->cmdtype = CMDUNKNOWN; 11178 return; 11179 11180 builtin_success: 11181 if (!updatetbl) { 11182 entry->cmdtype = CMDBUILTIN; 11183 entry->u.cmd = bcmd; 11184 return; 11185 } 11186 INT_OFF; 11187 cmdp = cmdlookup(name, 1); 11188 cmdp->cmdtype = CMDBUILTIN; 11189 cmdp->param.cmd = bcmd; 11190 INT_ON; 11191 success: 11192 cmdp->rehash = 0; 11193 entry->cmdtype = cmdp->cmdtype; 11194 entry->u = cmdp->param; 11195} 11196 11197 11198/* ============ trap.c */ 11199 11200/* 11201 * The trap builtin. 11202 */ 11203static int 11204trapcmd(int argc, char **argv) 11205{ 11206 char *action; 11207 char **ap; 11208 int signo; 11209 11210 nextopt(nullstr); 11211 ap = argptr; 11212 if (!*ap) { 11213 for (signo = 0; signo < NSIG; signo++) { 11214 if (trap[signo] != NULL) { 11215 const char *sn; 11216 11217 sn = get_signame(signo); 11218 out1fmt("trap -- %s %s\n", 11219 single_quote(trap[signo]), sn); 11220 } 11221 } 11222 return 0; 11223 } 11224 if (!ap[1]) 11225 action = NULL; 11226 else 11227 action = *ap++; 11228 while (*ap) { 11229 signo = get_signum(*ap); 11230 if (signo < 0) 11231 ash_msg_and_raise_error("%s: bad trap", *ap); 11232 INT_OFF; 11233 if (action) { 11234 if (LONE_DASH(action)) 11235 action = NULL; 11236 else 11237 action = ckstrdup(action); 11238 } 11239 if (trap[signo]) 11240 free(trap[signo]); 11241 trap[signo] = action; 11242 if (signo != 0) 11243 setsignal(signo); 11244 INT_ON; 11245 ap++; 11246 } 11247 return 0; 11248} 11249 11250 11251/* ============ Builtins */ 11252 11253#if !ENABLE_FEATURE_SH_EXTRA_QUIET 11254/* 11255 * Lists available builtins 11256 */ 11257static int 11258helpcmd(int argc, char **argv) 11259{ 11260 int col, i; 11261 11262 out1fmt("\nBuilt-in commands:\n-------------------\n"); 11263 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) { 11264 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), 11265 builtintab[i].name + 1); 11266 if (col > 60) { 11267 out1fmt("\n"); 11268 col = 0; 11269 } 11270 } 11271#if ENABLE_FEATURE_SH_STANDALONE 11272 for (i = 0; i < NUM_APPLETS; i++) { 11273 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name); 11274 if (col > 60) { 11275 out1fmt("\n"); 11276 col = 0; 11277 } 11278 } 11279#endif 11280 out1fmt("\n\n"); 11281 return EXIT_SUCCESS; 11282} 11283#endif /* FEATURE_SH_EXTRA_QUIET */ 11284 11285/* 11286 * The export and readonly commands. 11287 */ 11288static int 11289exportcmd(int argc, char **argv) 11290{ 11291 struct var *vp; 11292 char *name; 11293 const char *p; 11294 char **aptr; 11295 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; 11296 11297 if (nextopt("p") != 'p') { 11298 aptr = argptr; 11299 name = *aptr; 11300 if (name) { 11301 do { 11302 p = strchr(name, '='); 11303 if (p != NULL) { 11304 p++; 11305 } else { 11306 vp = *findvar(hashvar(name), name); 11307 if (vp) { 11308 vp->flags |= flag; 11309 continue; 11310 } 11311 } 11312 setvar(name, p, flag); 11313 } while ((name = *++aptr) != NULL); 11314 return 0; 11315 } 11316 } 11317 showvars(argv[0], flag, 0); 11318 return 0; 11319} 11320 11321/* 11322 * Delete a function if it exists. 11323 */ 11324static void 11325unsetfunc(const char *name) 11326{ 11327 struct tblentry *cmdp; 11328 11329 cmdp = cmdlookup(name, 0); 11330 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION) 11331 delete_cmd_entry(); 11332} 11333 11334/* 11335 * The unset builtin command. We unset the function before we unset the 11336 * variable to allow a function to be unset when there is a readonly variable 11337 * with the same name. 11338 */ 11339static int 11340unsetcmd(int argc, char **argv) 11341{ 11342 char **ap; 11343 int i; 11344 int flag = 0; 11345 int ret = 0; 11346 11347 while ((i = nextopt("vf")) != '\0') { 11348 flag = i; 11349 } 11350 11351 for (ap = argptr; *ap; ap++) { 11352 if (flag != 'f') { 11353 i = unsetvar(*ap); 11354 ret |= i; 11355 if (!(i & 2)) 11356 continue; 11357 } 11358 if (flag != 'v') 11359 unsetfunc(*ap); 11360 } 11361 return ret & 1; 11362} 11363 11364 11365/* setmode.c */ 11366 11367#include <sys/times.h> 11368 11369static const unsigned char timescmd_str[] ALIGN1 = { 11370 ' ', offsetof(struct tms, tms_utime), 11371 '\n', offsetof(struct tms, tms_stime), 11372 ' ', offsetof(struct tms, tms_cutime), 11373 '\n', offsetof(struct tms, tms_cstime), 11374 0 11375}; 11376 11377static int 11378timescmd(int ac, char **av) 11379{ 11380 long clk_tck, s, t; 11381 const unsigned char *p; 11382 struct tms buf; 11383 11384 clk_tck = sysconf(_SC_CLK_TCK); 11385 times(&buf); 11386 11387 p = timescmd_str; 11388 do { 11389 t = *(clock_t *)(((char *) &buf) + p[1]); 11390 s = t / clk_tck; 11391 out1fmt("%ldm%ld.%.3lds%c", 11392 s/60, s%60, 11393 ((t - s * clk_tck) * 1000) / clk_tck, 11394 p[0]); 11395 } while (*(p += 2)); 11396 11397 return 0; 11398} 11399 11400#if ENABLE_ASH_MATH_SUPPORT 11401static arith_t 11402dash_arith(const char *s) 11403{ 11404 arith_t result; 11405 int errcode = 0; 11406 11407 INT_OFF; 11408 result = arith(s, &errcode); 11409 if (errcode < 0) { 11410 if (errcode == -3) 11411 ash_msg_and_raise_error("exponent less than 0"); 11412 if (errcode == -2) 11413 ash_msg_and_raise_error("divide by zero"); 11414 if (errcode == -5) 11415 ash_msg_and_raise_error("expression recursion loop detected"); 11416 raise_error_syntax(s); 11417 } 11418 INT_ON; 11419 11420 return result; 11421} 11422 11423/* 11424 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell. 11425 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. 11426 * 11427 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> 11428 */ 11429static int 11430letcmd(int argc, char **argv) 11431{ 11432 char **ap; 11433 arith_t i = 0; 11434 11435 ap = argv + 1; 11436 if (!*ap) 11437 ash_msg_and_raise_error("expression expected"); 11438 for (ap = argv + 1; *ap; ap++) { 11439 i = dash_arith(*ap); 11440 } 11441 11442 return !i; 11443} 11444#endif /* ASH_MATH_SUPPORT */ 11445 11446 11447/* ============ miscbltin.c 11448 * 11449 * Miscellaneous builtins. 11450 */ 11451 11452#undef rflag 11453 11454#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 11455typedef enum __rlimit_resource rlim_t; 11456#endif 11457 11458/* 11459 * The read builtin. The -e option causes backslashes to escape the 11460 * following character. 11461 * 11462 * This uses unbuffered input, which may be avoidable in some cases. 11463 */ 11464static int 11465readcmd(int argc, char **argv) 11466{ 11467 char **ap; 11468 int backslash; 11469 char c; 11470 int rflag; 11471 char *prompt; 11472 const char *ifs; 11473 char *p; 11474 int startword; 11475 int status; 11476 int i; 11477#if ENABLE_ASH_READ_NCHARS 11478 int nch_flag = 0; 11479 int nchars = 0; 11480 int silent = 0; 11481 struct termios tty, old_tty; 11482#endif 11483#if ENABLE_ASH_READ_TIMEOUT 11484 fd_set set; 11485 struct timeval ts; 11486 11487 ts.tv_sec = ts.tv_usec = 0; 11488#endif 11489 11490 rflag = 0; 11491 prompt = NULL; 11492#if ENABLE_ASH_READ_NCHARS && ENABLE_ASH_READ_TIMEOUT 11493 while ((i = nextopt("p:rt:n:s")) != '\0') 11494#elif ENABLE_ASH_READ_NCHARS 11495 while ((i = nextopt("p:rn:s")) != '\0') 11496#elif ENABLE_ASH_READ_TIMEOUT 11497 while ((i = nextopt("p:rt:")) != '\0') 11498#else 11499 while ((i = nextopt("p:r")) != '\0') 11500#endif 11501 { 11502 switch (i) { 11503 case 'p': 11504 prompt = optionarg; 11505 break; 11506#if ENABLE_ASH_READ_NCHARS 11507 case 'n': 11508 nchars = strtol(optionarg, &p, 10); 11509 if (*p) 11510 ash_msg_and_raise_error("invalid count"); 11511 nch_flag = (nchars > 0); 11512 break; 11513 case 's': 11514 silent = 1; 11515 break; 11516#endif 11517#if ENABLE_ASH_READ_TIMEOUT 11518 case 't': 11519 ts.tv_sec = strtol(optionarg, &p, 10); 11520 ts.tv_usec = 0; 11521 if (*p == '.') { 11522 char *p2; 11523 if (*++p) { 11524 int scale; 11525 ts.tv_usec = strtol(p, &p2, 10); 11526 if (*p2) 11527 ash_msg_and_raise_error("invalid timeout"); 11528 scale = p2 - p; 11529 /* normalize to usec */ 11530 if (scale > 6) 11531 ash_msg_and_raise_error("invalid timeout"); 11532 while (scale++ < 6) 11533 ts.tv_usec *= 10; 11534 } 11535 } else if (*p) { 11536 ash_msg_and_raise_error("invalid timeout"); 11537 } 11538 if ( ! ts.tv_sec && ! ts.tv_usec) 11539 ash_msg_and_raise_error("invalid timeout"); 11540 break; 11541#endif 11542 case 'r': 11543 rflag = 1; 11544 break; 11545 default: 11546 break; 11547 } 11548 } 11549 if (prompt && isatty(0)) { 11550 out2str(prompt); 11551 } 11552 ap = argptr; 11553 if (*ap == NULL) 11554 ash_msg_and_raise_error("arg count"); 11555 ifs = bltinlookup("IFS"); 11556 if (ifs == NULL) 11557 ifs = defifs; 11558#if ENABLE_ASH_READ_NCHARS 11559 if (nch_flag || silent) { 11560 tcgetattr(0, &tty); 11561 old_tty = tty; 11562 if (nch_flag) { 11563 tty.c_lflag &= ~ICANON; 11564 tty.c_cc[VMIN] = nchars; 11565 } 11566 if (silent) { 11567 tty.c_lflag &= ~(ECHO|ECHOK|ECHONL); 11568 11569 } 11570 tcsetattr(0, TCSANOW, &tty); 11571 } 11572#endif 11573#if ENABLE_ASH_READ_TIMEOUT 11574 if (ts.tv_sec || ts.tv_usec) { 11575 FD_ZERO(&set); 11576 FD_SET(0, &set); 11577 11578 i = select(FD_SETSIZE, &set, NULL, NULL, &ts); 11579 if (!i) { 11580#if ENABLE_ASH_READ_NCHARS 11581 if (nch_flag) 11582 tcsetattr(0, TCSANOW, &old_tty); 11583#endif 11584 return 1; 11585 } 11586 } 11587#endif 11588 status = 0; 11589 startword = 1; 11590 backslash = 0; 11591 STARTSTACKSTR(p); 11592#if ENABLE_ASH_READ_NCHARS 11593 while (!nch_flag || nchars--) 11594#else 11595 for (;;) 11596#endif 11597 { 11598 if (read(0, &c, 1) != 1) { 11599 status = 1; 11600 break; 11601 } 11602 if (c == '\0') 11603 continue; 11604 if (backslash) { 11605 backslash = 0; 11606 if (c != '\n') 11607 goto put; 11608 continue; 11609 } 11610 if (!rflag && c == '\\') { 11611 backslash++; 11612 continue; 11613 } 11614 if (c == '\n') 11615 break; 11616 if (startword && *ifs == ' ' && strchr(ifs, c)) { 11617 continue; 11618 } 11619 startword = 0; 11620 if (ap[1] != NULL && strchr(ifs, c) != NULL) { 11621 STACKSTRNUL(p); 11622 setvar(*ap, stackblock(), 0); 11623 ap++; 11624 startword = 1; 11625 STARTSTACKSTR(p); 11626 } else { 11627 put: 11628 STPUTC(c, p); 11629 } 11630 } 11631#if ENABLE_ASH_READ_NCHARS 11632 if (nch_flag || silent) 11633 tcsetattr(0, TCSANOW, &old_tty); 11634#endif 11635 11636 STACKSTRNUL(p); 11637 /* Remove trailing blanks */ 11638 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL) 11639 *p = '\0'; 11640 setvar(*ap, stackblock(), 0); 11641 while (*++ap != NULL) 11642 setvar(*ap, nullstr, 0); 11643 return status; 11644} 11645 11646static int 11647umaskcmd(int argc, char **argv) 11648{ 11649 static const char permuser[3] ALIGN1 = "ugo"; 11650 static const char permmode[3] ALIGN1 = "rwx"; 11651 static const short permmask[] ALIGN2 = { 11652 S_IRUSR, S_IWUSR, S_IXUSR, 11653 S_IRGRP, S_IWGRP, S_IXGRP, 11654 S_IROTH, S_IWOTH, S_IXOTH 11655 }; 11656 11657 char *ap; 11658 mode_t mask; 11659 int i; 11660 int symbolic_mode = 0; 11661 11662 while (nextopt("S") != '\0') { 11663 symbolic_mode = 1; 11664 } 11665 11666 INT_OFF; 11667 mask = umask(0); 11668 umask(mask); 11669 INT_ON; 11670 11671 ap = *argptr; 11672 if (ap == NULL) { 11673 if (symbolic_mode) { 11674 char buf[18]; 11675 char *p = buf; 11676 11677 for (i = 0; i < 3; i++) { 11678 int j; 11679 11680 *p++ = permuser[i]; 11681 *p++ = '='; 11682 for (j = 0; j < 3; j++) { 11683 if ((mask & permmask[3 * i + j]) == 0) { 11684 *p++ = permmode[j]; 11685 } 11686 } 11687 *p++ = ','; 11688 } 11689 *--p = 0; 11690 puts(buf); 11691 } else { 11692 out1fmt("%.4o\n", mask); 11693 } 11694 } else { 11695 if (isdigit((unsigned char) *ap)) { 11696 mask = 0; 11697 do { 11698 if (*ap >= '8' || *ap < '0') 11699 ash_msg_and_raise_error(illnum, argv[1]); 11700 mask = (mask << 3) + (*ap - '0'); 11701 } while (*++ap != '\0'); 11702 umask(mask); 11703 } else { 11704 mask = ~mask & 0777; 11705 if (!bb_parse_mode(ap, &mask)) { 11706 ash_msg_and_raise_error("illegal mode: %s", ap); 11707 } 11708 umask(~mask & 0777); 11709 } 11710 } 11711 return 0; 11712} 11713 11714/* 11715 * ulimit builtin 11716 * 11717 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and 11718 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with 11719 * ash by J.T. Conklin. 11720 * 11721 * Public domain. 11722 */ 11723 11724struct limits { 11725 const char *name; 11726 int cmd; 11727 int factor; /* multiply by to get rlim_{cur,max} values */ 11728 char option; 11729}; 11730 11731static const struct limits limits[] = { 11732#ifdef RLIMIT_CPU 11733 { "time(seconds)", RLIMIT_CPU, 1, 't' }, 11734#endif 11735#ifdef RLIMIT_FSIZE 11736 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' }, 11737#endif 11738#ifdef RLIMIT_DATA 11739 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' }, 11740#endif 11741#ifdef RLIMIT_STACK 11742 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' }, 11743#endif 11744#ifdef RLIMIT_CORE 11745 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' }, 11746#endif 11747#ifdef RLIMIT_RSS 11748 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' }, 11749#endif 11750#ifdef RLIMIT_MEMLOCK 11751 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' }, 11752#endif 11753#ifdef RLIMIT_NPROC 11754 { "process", RLIMIT_NPROC, 1, 'p' }, 11755#endif 11756#ifdef RLIMIT_NOFILE 11757 { "nofiles", RLIMIT_NOFILE, 1, 'n' }, 11758#endif 11759#ifdef RLIMIT_AS 11760 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' }, 11761#endif 11762#ifdef RLIMIT_LOCKS 11763 { "locks", RLIMIT_LOCKS, 1, 'w' }, 11764#endif 11765 { NULL, 0, 0, '\0' } 11766}; 11767 11768enum limtype { SOFT = 0x1, HARD = 0x2 }; 11769 11770static void 11771printlim(enum limtype how, const struct rlimit *limit, 11772 const struct limits *l) 11773{ 11774 rlim_t val; 11775 11776 val = limit->rlim_max; 11777 if (how & SOFT) 11778 val = limit->rlim_cur; 11779 11780 if (val == RLIM_INFINITY) 11781 out1fmt("unlimited\n"); 11782 else { 11783 val /= l->factor; 11784 out1fmt("%lld\n", (long long) val); 11785 } 11786} 11787 11788static int 11789ulimitcmd(int argc, char **argv) 11790{ 11791 int c; 11792 rlim_t val = 0; 11793 enum limtype how = SOFT | HARD; 11794 const struct limits *l; 11795 int set, all = 0; 11796 int optc, what; 11797 struct rlimit limit; 11798 11799 what = 'f'; 11800 while ((optc = nextopt("HSa" 11801#ifdef RLIMIT_CPU 11802 "t" 11803#endif 11804#ifdef RLIMIT_FSIZE 11805 "f" 11806#endif 11807#ifdef RLIMIT_DATA 11808 "d" 11809#endif 11810#ifdef RLIMIT_STACK 11811 "s" 11812#endif 11813#ifdef RLIMIT_CORE 11814 "c" 11815#endif 11816#ifdef RLIMIT_RSS 11817 "m" 11818#endif 11819#ifdef RLIMIT_MEMLOCK 11820 "l" 11821#endif 11822#ifdef RLIMIT_NPROC 11823 "p" 11824#endif 11825#ifdef RLIMIT_NOFILE 11826 "n" 11827#endif 11828#ifdef RLIMIT_AS 11829 "v" 11830#endif 11831#ifdef RLIMIT_LOCKS 11832 "w" 11833#endif 11834 )) != '\0') 11835 switch (optc) { 11836 case 'H': 11837 how = HARD; 11838 break; 11839 case 'S': 11840 how = SOFT; 11841 break; 11842 case 'a': 11843 all = 1; 11844 break; 11845 default: 11846 what = optc; 11847 } 11848 11849 for (l = limits; l->option != what; l++) 11850 ; 11851 11852 set = *argptr ? 1 : 0; 11853 if (set) { 11854 char *p = *argptr; 11855 11856 if (all || argptr[1]) 11857 ash_msg_and_raise_error("too many arguments"); 11858 if (strncmp(p, "unlimited\n", 9) == 0) 11859 val = RLIM_INFINITY; 11860 else { 11861 val = (rlim_t) 0; 11862 11863 while ((c = *p++) >= '0' && c <= '9') { 11864 val = (val * 10) + (long)(c - '0'); 11865 if (val < (rlim_t) 0) 11866 break; 11867 } 11868 if (c) 11869 ash_msg_and_raise_error("bad number"); 11870 val *= l->factor; 11871 } 11872 } 11873 if (all) { 11874 for (l = limits; l->name; l++) { 11875 getrlimit(l->cmd, &limit); 11876 out1fmt("%-20s ", l->name); 11877 printlim(how, &limit, l); 11878 } 11879 return 0; 11880 } 11881 11882 getrlimit(l->cmd, &limit); 11883 if (set) { 11884 if (how & HARD) 11885 limit.rlim_max = val; 11886 if (how & SOFT) 11887 limit.rlim_cur = val; 11888 if (setrlimit(l->cmd, &limit) < 0) 11889 ash_msg_and_raise_error("error setting limit (%m)"); 11890 } else { 11891 printlim(how, &limit, l); 11892 } 11893 return 0; 11894} 11895 11896 11897/* ============ Math support */ 11898 11899#if ENABLE_ASH_MATH_SUPPORT 11900 11901/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> 11902 11903 Permission is hereby granted, free of charge, to any person obtaining 11904 a copy of this software and associated documentation files (the 11905 "Software"), to deal in the Software without restriction, including 11906 without limitation the rights to use, copy, modify, merge, publish, 11907 distribute, sublicense, and/or sell copies of the Software, and to 11908 permit persons to whom the Software is furnished to do so, subject to 11909 the following conditions: 11910 11911 The above copyright notice and this permission notice shall be 11912 included in all copies or substantial portions of the Software. 11913 11914 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 11915 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 11916 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 11917 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 11918 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 11919 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 11920 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11921*/ 11922 11923/* This is my infix parser/evaluator. It is optimized for size, intended 11924 * as a replacement for yacc-based parsers. However, it may well be faster 11925 * than a comparable parser written in yacc. The supported operators are 11926 * listed in #defines below. Parens, order of operations, and error handling 11927 * are supported. This code is thread safe. The exact expression format should 11928 * be that which POSIX specifies for shells. */ 11929 11930/* The code uses a simple two-stack algorithm. See 11931 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html 11932 * for a detailed explanation of the infix-to-postfix algorithm on which 11933 * this is based (this code differs in that it applies operators immediately 11934 * to the stack instead of adding them to a queue to end up with an 11935 * expression). */ 11936 11937/* To use the routine, call it with an expression string and error return 11938 * pointer */ 11939 11940/* 11941 * Aug 24, 2001 Manuel Novoa III 11942 * 11943 * Reduced the generated code size by about 30% (i386) and fixed several bugs. 11944 * 11945 * 1) In arith_apply(): 11946 * a) Cached values of *numptr and &(numptr[-1]). 11947 * b) Removed redundant test for zero denominator. 11948 * 11949 * 2) In arith(): 11950 * a) Eliminated redundant code for processing operator tokens by moving 11951 * to a table-based implementation. Also folded handling of parens 11952 * into the table. 11953 * b) Combined all 3 loops which called arith_apply to reduce generated 11954 * code size at the cost of speed. 11955 * 11956 * 3) The following expressions were treated as valid by the original code: 11957 * 1() , 0! , 1 ( *3 ) . 11958 * These bugs have been fixed by internally enclosing the expression in 11959 * parens and then checking that all binary ops and right parens are 11960 * preceded by a valid expression (NUM_TOKEN). 11961 * 11962 * Note: It may be desirable to replace Aaron's test for whitespace with 11963 * ctype's isspace() if it is used by another busybox applet or if additional 11964 * whitespace chars should be considered. Look below the "#include"s for a 11965 * precompiler test. 11966 */ 11967 11968/* 11969 * Aug 26, 2001 Manuel Novoa III 11970 * 11971 * Return 0 for null expressions. Pointed out by Vladimir Oleynik. 11972 * 11973 * Merge in Aaron's comments previously posted to the busybox list, 11974 * modified slightly to take account of my changes to the code. 11975 * 11976 */ 11977 11978/* 11979 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> 11980 * 11981 * - allow access to variable, 11982 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6) 11983 * - realize assign syntax (VAR=expr, +=, *= etc) 11984 * - realize exponentiation (** operator) 11985 * - realize comma separated - expr, expr 11986 * - realise ++expr --expr expr++ expr-- 11987 * - realise expr ? expr : expr (but, second expr calculate always) 11988 * - allow hexadecimal and octal numbers 11989 * - was restored loses XOR operator 11990 * - remove one goto label, added three ;-) 11991 * - protect $((num num)) as true zero expr (Manuel`s error) 11992 * - always use special isspace(), see comment from bash ;-) 11993 */ 11994 11995#define arith_isspace(arithval) \ 11996 (arithval == ' ' || arithval == '\n' || arithval == '\t') 11997 11998typedef unsigned char operator; 11999 12000/* An operator's token id is a bit of a bitfield. The lower 5 bits are the 12001 * precedence, and 3 high bits are an ID unique across operators of that 12002 * precedence. The ID portion is so that multiple operators can have the 12003 * same precedence, ensuring that the leftmost one is evaluated first. 12004 * Consider * and /. */ 12005 12006#define tok_decl(prec,id) (((id)<<5)|(prec)) 12007#define PREC(op) ((op) & 0x1F) 12008 12009#define TOK_LPAREN tok_decl(0,0) 12010 12011#define TOK_COMMA tok_decl(1,0) 12012 12013#define TOK_ASSIGN tok_decl(2,0) 12014#define TOK_AND_ASSIGN tok_decl(2,1) 12015#define TOK_OR_ASSIGN tok_decl(2,2) 12016#define TOK_XOR_ASSIGN tok_decl(2,3) 12017#define TOK_PLUS_ASSIGN tok_decl(2,4) 12018#define TOK_MINUS_ASSIGN tok_decl(2,5) 12019#define TOK_LSHIFT_ASSIGN tok_decl(2,6) 12020#define TOK_RSHIFT_ASSIGN tok_decl(2,7) 12021 12022#define TOK_MUL_ASSIGN tok_decl(3,0) 12023#define TOK_DIV_ASSIGN tok_decl(3,1) 12024#define TOK_REM_ASSIGN tok_decl(3,2) 12025 12026/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */ 12027#define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0) 12028 12029/* conditional is right associativity too */ 12030#define TOK_CONDITIONAL tok_decl(4,0) 12031#define TOK_CONDITIONAL_SEP tok_decl(4,1) 12032 12033#define TOK_OR tok_decl(5,0) 12034 12035#define TOK_AND tok_decl(6,0) 12036 12037#define TOK_BOR tok_decl(7,0) 12038 12039#define TOK_BXOR tok_decl(8,0) 12040 12041#define TOK_BAND tok_decl(9,0) 12042 12043#define TOK_EQ tok_decl(10,0) 12044#define TOK_NE tok_decl(10,1) 12045 12046#define TOK_LT tok_decl(11,0) 12047#define TOK_GT tok_decl(11,1) 12048#define TOK_GE tok_decl(11,2) 12049#define TOK_LE tok_decl(11,3) 12050 12051#define TOK_LSHIFT tok_decl(12,0) 12052#define TOK_RSHIFT tok_decl(12,1) 12053 12054#define TOK_ADD tok_decl(13,0) 12055#define TOK_SUB tok_decl(13,1) 12056 12057#define TOK_MUL tok_decl(14,0) 12058#define TOK_DIV tok_decl(14,1) 12059#define TOK_REM tok_decl(14,2) 12060 12061/* exponent is right associativity */ 12062#define TOK_EXPONENT tok_decl(15,1) 12063 12064/* For now unary operators. */ 12065#define UNARYPREC 16 12066#define TOK_BNOT tok_decl(UNARYPREC,0) 12067#define TOK_NOT tok_decl(UNARYPREC,1) 12068 12069#define TOK_UMINUS tok_decl(UNARYPREC+1,0) 12070#define TOK_UPLUS tok_decl(UNARYPREC+1,1) 12071 12072#define PREC_PRE (UNARYPREC+2) 12073 12074#define TOK_PRE_INC tok_decl(PREC_PRE, 0) 12075#define TOK_PRE_DEC tok_decl(PREC_PRE, 1) 12076 12077#define PREC_POST (UNARYPREC+3) 12078 12079#define TOK_POST_INC tok_decl(PREC_POST, 0) 12080#define TOK_POST_DEC tok_decl(PREC_POST, 1) 12081 12082#define SPEC_PREC (UNARYPREC+4) 12083 12084#define TOK_NUM tok_decl(SPEC_PREC, 0) 12085#define TOK_RPAREN tok_decl(SPEC_PREC, 1) 12086 12087#define NUMPTR (*numstackptr) 12088 12089static int 12090tok_have_assign(operator op) 12091{ 12092 operator prec = PREC(op); 12093 12094 convert_prec_is_assing(prec); 12095 return (prec == PREC(TOK_ASSIGN) || 12096 prec == PREC_PRE || prec == PREC_POST); 12097} 12098 12099static int 12100is_right_associativity(operator prec) 12101{ 12102 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) 12103 || prec == PREC(TOK_CONDITIONAL)); 12104} 12105 12106typedef struct ARITCH_VAR_NUM { 12107 arith_t val; 12108 arith_t contidional_second_val; 12109 char contidional_second_val_initialized; 12110 char *var; /* if NULL then is regular number, 12111 else is variable name */ 12112} v_n_t; 12113 12114typedef struct CHK_VAR_RECURSIVE_LOOPED { 12115 const char *var; 12116 struct CHK_VAR_RECURSIVE_LOOPED *next; 12117} chk_var_recursive_looped_t; 12118 12119static chk_var_recursive_looped_t *prev_chk_var_recursive; 12120 12121static int 12122arith_lookup_val(v_n_t *t) 12123{ 12124 if (t->var) { 12125 const char * p = lookupvar(t->var); 12126 12127 if (p) { 12128 int errcode; 12129 12130 /* recursive try as expression */ 12131 chk_var_recursive_looped_t *cur; 12132 chk_var_recursive_looped_t cur_save; 12133 12134 for (cur = prev_chk_var_recursive; cur; cur = cur->next) { 12135 if (strcmp(cur->var, t->var) == 0) { 12136 /* expression recursion loop detected */ 12137 return -5; 12138 } 12139 } 12140 /* save current lookuped var name */ 12141 cur = prev_chk_var_recursive; 12142 cur_save.var = t->var; 12143 cur_save.next = cur; 12144 prev_chk_var_recursive = &cur_save; 12145 12146 t->val = arith (p, &errcode); 12147 /* restore previous ptr after recursiving */ 12148 prev_chk_var_recursive = cur; 12149 return errcode; 12150 } 12151 /* allow undefined var as 0 */ 12152 t->val = 0; 12153 } 12154 return 0; 12155} 12156 12157/* "applying" a token means performing it on the top elements on the integer 12158 * stack. For a unary operator it will only change the top element, but a 12159 * binary operator will pop two arguments and push a result */ 12160static int 12161arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) 12162{ 12163 v_n_t *numptr_m1; 12164 arith_t numptr_val, rez; 12165 int ret_arith_lookup_val; 12166 12167 /* There is no operator that can work without arguments */ 12168 if (NUMPTR == numstack) goto err; 12169 numptr_m1 = NUMPTR - 1; 12170 12171 /* check operand is var with noninteger value */ 12172 ret_arith_lookup_val = arith_lookup_val(numptr_m1); 12173 if (ret_arith_lookup_val) 12174 return ret_arith_lookup_val; 12175 12176 rez = numptr_m1->val; 12177 if (op == TOK_UMINUS) 12178 rez *= -1; 12179 else if (op == TOK_NOT) 12180 rez = !rez; 12181 else if (op == TOK_BNOT) 12182 rez = ~rez; 12183 else if (op == TOK_POST_INC || op == TOK_PRE_INC) 12184 rez++; 12185 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC) 12186 rez--; 12187 else if (op != TOK_UPLUS) { 12188 /* Binary operators */ 12189 12190 /* check and binary operators need two arguments */ 12191 if (numptr_m1 == numstack) goto err; 12192 12193 /* ... and they pop one */ 12194 --NUMPTR; 12195 numptr_val = rez; 12196 if (op == TOK_CONDITIONAL) { 12197 if (! numptr_m1->contidional_second_val_initialized) { 12198 /* protect $((expr1 ? expr2)) without ": expr" */ 12199 goto err; 12200 } 12201 rez = numptr_m1->contidional_second_val; 12202 } else if (numptr_m1->contidional_second_val_initialized) { 12203 /* protect $((expr1 : expr2)) without "expr ? " */ 12204 goto err; 12205 } 12206 numptr_m1 = NUMPTR - 1; 12207 if (op != TOK_ASSIGN) { 12208 /* check operand is var with noninteger value for not '=' */ 12209 ret_arith_lookup_val = arith_lookup_val(numptr_m1); 12210 if (ret_arith_lookup_val) 12211 return ret_arith_lookup_val; 12212 } 12213 if (op == TOK_CONDITIONAL) { 12214 numptr_m1->contidional_second_val = rez; 12215 } 12216 rez = numptr_m1->val; 12217 if (op == TOK_BOR || op == TOK_OR_ASSIGN) 12218 rez |= numptr_val; 12219 else if (op == TOK_OR) 12220 rez = numptr_val || rez; 12221 else if (op == TOK_BAND || op == TOK_AND_ASSIGN) 12222 rez &= numptr_val; 12223 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN) 12224 rez ^= numptr_val; 12225 else if (op == TOK_AND) 12226 rez = rez && numptr_val; 12227 else if (op == TOK_EQ) 12228 rez = (rez == numptr_val); 12229 else if (op == TOK_NE) 12230 rez = (rez != numptr_val); 12231 else if (op == TOK_GE) 12232 rez = (rez >= numptr_val); 12233 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN) 12234 rez >>= numptr_val; 12235 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN) 12236 rez <<= numptr_val; 12237 else if (op == TOK_GT) 12238 rez = (rez > numptr_val); 12239 else if (op == TOK_LT) 12240 rez = (rez < numptr_val); 12241 else if (op == TOK_LE) 12242 rez = (rez <= numptr_val); 12243 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN) 12244 rez *= numptr_val; 12245 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN) 12246 rez += numptr_val; 12247 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN) 12248 rez -= numptr_val; 12249 else if (op == TOK_ASSIGN || op == TOK_COMMA) 12250 rez = numptr_val; 12251 else if (op == TOK_CONDITIONAL_SEP) { 12252 if (numptr_m1 == numstack) { 12253 /* protect $((expr : expr)) without "expr ? " */ 12254 goto err; 12255 } 12256 numptr_m1->contidional_second_val_initialized = op; 12257 numptr_m1->contidional_second_val = numptr_val; 12258 } else if (op == TOK_CONDITIONAL) { 12259 rez = rez ? 12260 numptr_val : numptr_m1->contidional_second_val; 12261 } else if (op == TOK_EXPONENT) { 12262 if (numptr_val < 0) 12263 return -3; /* exponent less than 0 */ 12264 else { 12265 arith_t c = 1; 12266 12267 if (numptr_val) 12268 while (numptr_val--) 12269 c *= rez; 12270 rez = c; 12271 } 12272 } else if (numptr_val==0) /* zero divisor check */ 12273 return -2; 12274 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) 12275 rez /= numptr_val; 12276 else if (op == TOK_REM || op == TOK_REM_ASSIGN) 12277 rez %= numptr_val; 12278 } 12279 if (tok_have_assign(op)) { 12280 char buf[sizeof(arith_t_type)*3 + 2]; 12281 12282 if (numptr_m1->var == NULL) { 12283 /* Hmm, 1=2 ? */ 12284 goto err; 12285 } 12286 /* save to shell variable */ 12287#if ENABLE_ASH_MATH_SUPPORT_64 12288 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez); 12289#else 12290 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez); 12291#endif 12292 setvar(numptr_m1->var, buf, 0); 12293 /* after saving, make previous value for v++ or v-- */ 12294 if (op == TOK_POST_INC) 12295 rez--; 12296 else if (op == TOK_POST_DEC) 12297 rez++; 12298 } 12299 numptr_m1->val = rez; 12300 /* protect geting var value, is number now */ 12301 numptr_m1->var = NULL; 12302 return 0; 12303 err: 12304 return -1; 12305} 12306 12307/* longest must be first */ 12308static const char op_tokens[] ALIGN1 = { 12309 '<','<','=',0, TOK_LSHIFT_ASSIGN, 12310 '>','>','=',0, TOK_RSHIFT_ASSIGN, 12311 '<','<', 0, TOK_LSHIFT, 12312 '>','>', 0, TOK_RSHIFT, 12313 '|','|', 0, TOK_OR, 12314 '&','&', 0, TOK_AND, 12315 '!','=', 0, TOK_NE, 12316 '<','=', 0, TOK_LE, 12317 '>','=', 0, TOK_GE, 12318 '=','=', 0, TOK_EQ, 12319 '|','=', 0, TOK_OR_ASSIGN, 12320 '&','=', 0, TOK_AND_ASSIGN, 12321 '*','=', 0, TOK_MUL_ASSIGN, 12322 '/','=', 0, TOK_DIV_ASSIGN, 12323 '%','=', 0, TOK_REM_ASSIGN, 12324 '+','=', 0, TOK_PLUS_ASSIGN, 12325 '-','=', 0, TOK_MINUS_ASSIGN, 12326 '-','-', 0, TOK_POST_DEC, 12327 '^','=', 0, TOK_XOR_ASSIGN, 12328 '+','+', 0, TOK_POST_INC, 12329 '*','*', 0, TOK_EXPONENT, 12330 '!', 0, TOK_NOT, 12331 '<', 0, TOK_LT, 12332 '>', 0, TOK_GT, 12333 '=', 0, TOK_ASSIGN, 12334 '|', 0, TOK_BOR, 12335 '&', 0, TOK_BAND, 12336 '*', 0, TOK_MUL, 12337 '/', 0, TOK_DIV, 12338 '%', 0, TOK_REM, 12339 '+', 0, TOK_ADD, 12340 '-', 0, TOK_SUB, 12341 '^', 0, TOK_BXOR, 12342 /* uniq */ 12343 '~', 0, TOK_BNOT, 12344 ',', 0, TOK_COMMA, 12345 '?', 0, TOK_CONDITIONAL, 12346 ':', 0, TOK_CONDITIONAL_SEP, 12347 ')', 0, TOK_RPAREN, 12348 '(', 0, TOK_LPAREN, 12349 0 12350}; 12351/* ptr to ")" */ 12352#define endexpression &op_tokens[sizeof(op_tokens)-7] 12353 12354static arith_t 12355arith(const char *expr, int *perrcode) 12356{ 12357 char arithval; /* Current character under analysis */ 12358 operator lasttok, op; 12359 operator prec; 12360 12361 const char *p = endexpression; 12362 int errcode; 12363 12364 size_t datasizes = strlen(expr) + 2; 12365 12366 /* Stack of integers */ 12367 /* The proof that there can be no more than strlen(startbuf)/2+1 integers 12368 * in any given correct or incorrect expression is left as an exercise to 12369 * the reader. */ 12370 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)), 12371 *numstackptr = numstack; 12372 /* Stack of operator tokens */ 12373 operator *stack = alloca((datasizes) * sizeof(operator)), 12374 *stackptr = stack; 12375 12376 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ 12377 *perrcode = errcode = 0; 12378 12379 while (1) { 12380 arithval = *expr; 12381 if (arithval == 0) { 12382 if (p == endexpression) { 12383 /* Null expression. */ 12384 return 0; 12385 } 12386 12387 /* This is only reached after all tokens have been extracted from the 12388 * input stream. If there are still tokens on the operator stack, they 12389 * are to be applied in order. At the end, there should be a final 12390 * result on the integer stack */ 12391 12392 if (expr != endexpression + 1) { 12393 /* If we haven't done so already, */ 12394 /* append a closing right paren */ 12395 expr = endexpression; 12396 /* and let the loop process it. */ 12397 continue; 12398 } 12399 /* At this point, we're done with the expression. */ 12400 if (numstackptr != numstack+1) { 12401 /* ... but if there isn't, it's bad */ 12402 err: 12403 return (*perrcode = -1); 12404 } 12405 if (numstack->var) { 12406 /* expression is $((var)) only, lookup now */ 12407 errcode = arith_lookup_val(numstack); 12408 } 12409 ret: 12410 *perrcode = errcode; 12411 return numstack->val; 12412 } 12413 12414 /* Continue processing the expression. */ 12415 if (arith_isspace(arithval)) { 12416 /* Skip whitespace */ 12417 goto prologue; 12418 } 12419 p = endofname(expr); 12420 if (p != expr) { 12421 size_t var_name_size = (p-expr) + 1; /* trailing zero */ 12422 12423 numstackptr->var = alloca(var_name_size); 12424 safe_strncpy(numstackptr->var, expr, var_name_size); 12425 expr = p; 12426 num: 12427 numstackptr->contidional_second_val_initialized = 0; 12428 numstackptr++; 12429 lasttok = TOK_NUM; 12430 continue; 12431 } 12432 if (isdigit(arithval)) { 12433 numstackptr->var = NULL; 12434#if ENABLE_ASH_MATH_SUPPORT_64 12435 numstackptr->val = strtoll(expr, (char **) &expr, 0); 12436#else 12437 numstackptr->val = strtol(expr, (char **) &expr, 0); 12438#endif 12439 goto num; 12440 } 12441 for (p = op_tokens; ; p++) { 12442 const char *o; 12443 12444 if (*p == 0) { 12445 /* strange operator not found */ 12446 goto err; 12447 } 12448 for (o = expr; *p && *o == *p; p++) 12449 o++; 12450 if (! *p) { 12451 /* found */ 12452 expr = o - 1; 12453 break; 12454 } 12455 /* skip tail uncompared token */ 12456 while (*p) 12457 p++; 12458 /* skip zero delim */ 12459 p++; 12460 } 12461 op = p[1]; 12462 12463 /* post grammar: a++ reduce to num */ 12464 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC) 12465 lasttok = TOK_NUM; 12466 12467 /* Plus and minus are binary (not unary) _only_ if the last 12468 * token was as number, or a right paren (which pretends to be 12469 * a number, since it evaluates to one). Think about it. 12470 * It makes sense. */ 12471 if (lasttok != TOK_NUM) { 12472 switch (op) { 12473 case TOK_ADD: 12474 op = TOK_UPLUS; 12475 break; 12476 case TOK_SUB: 12477 op = TOK_UMINUS; 12478 break; 12479 case TOK_POST_INC: 12480 op = TOK_PRE_INC; 12481 break; 12482 case TOK_POST_DEC: 12483 op = TOK_PRE_DEC; 12484 break; 12485 } 12486 } 12487 /* We don't want a unary operator to cause recursive descent on the 12488 * stack, because there can be many in a row and it could cause an 12489 * operator to be evaluated before its argument is pushed onto the 12490 * integer stack. */ 12491 /* But for binary operators, "apply" everything on the operator 12492 * stack until we find an operator with a lesser priority than the 12493 * one we have just extracted. */ 12494 /* Left paren is given the lowest priority so it will never be 12495 * "applied" in this way. 12496 * if associativity is right and priority eq, applied also skip 12497 */ 12498 prec = PREC(op); 12499 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) { 12500 /* not left paren or unary */ 12501 if (lasttok != TOK_NUM) { 12502 /* binary op must be preceded by a num */ 12503 goto err; 12504 } 12505 while (stackptr != stack) { 12506 if (op == TOK_RPAREN) { 12507 /* The algorithm employed here is simple: while we don't 12508 * hit an open paren nor the bottom of the stack, pop 12509 * tokens and apply them */ 12510 if (stackptr[-1] == TOK_LPAREN) { 12511 --stackptr; 12512 /* Any operator directly after a */ 12513 lasttok = TOK_NUM; 12514 /* close paren should consider itself binary */ 12515 goto prologue; 12516 } 12517 } else { 12518 operator prev_prec = PREC(stackptr[-1]); 12519 12520 convert_prec_is_assing(prec); 12521 convert_prec_is_assing(prev_prec); 12522 if (prev_prec < prec) 12523 break; 12524 /* check right assoc */ 12525 if (prev_prec == prec && is_right_associativity(prec)) 12526 break; 12527 } 12528 errcode = arith_apply(*--stackptr, numstack, &numstackptr); 12529 if (errcode) goto ret; 12530 } 12531 if (op == TOK_RPAREN) { 12532 goto err; 12533 } 12534 } 12535 12536 /* Push this operator to the stack and remember it. */ 12537 *stackptr++ = lasttok = op; 12538 prologue: 12539 ++expr; 12540 } /* while */ 12541} 12542#endif /* ASH_MATH_SUPPORT */ 12543 12544 12545/* ============ main() and helpers */ 12546 12547/* 12548 * Called to exit the shell. 12549 */ 12550static void exitshell(void) ATTRIBUTE_NORETURN; 12551static void 12552exitshell(void) 12553{ 12554 struct jmploc loc; 12555 char *p; 12556 int status; 12557 12558 status = exitstatus; 12559 TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); 12560 if (setjmp(loc.loc)) { 12561 if (exception == EXEXIT) 12562/* dash bug: it just does _exit(exitstatus) here 12563 * but we have to do setjobctl(0) first! 12564 * (bug is still not fixed in dash-0.5.3 - if you run dash 12565 * under Midnight Commander, on exit from dash MC is backgrounded) */ 12566 status = exitstatus; 12567 goto out; 12568 } 12569 exception_handler = &loc; 12570 p = trap[0]; 12571 if (p) { 12572 trap[0] = NULL; 12573 evalstring(p, 0); 12574 } 12575 flush_stdout_stderr(); 12576 out: 12577 setjobctl(0); 12578 _exit(status); 12579 /* NOTREACHED */ 12580} 12581 12582static void 12583init(void) 12584{ 12585 /* from input.c: */ 12586 basepf.nextc = basepf.buf = basebuf; 12587 12588 /* from trap.c: */ 12589 signal(SIGCHLD, SIG_DFL); 12590 12591 /* from var.c: */ 12592 { 12593 char **envp; 12594 char ppid[sizeof(int)*3 + 1]; 12595 const char *p; 12596 struct stat st1, st2; 12597 12598 initvar(); 12599 for (envp = environ; envp && *envp; envp++) { 12600 if (strchr(*envp, '=')) { 12601 setvareq(*envp, VEXPORT|VTEXTFIXED); 12602 } 12603 } 12604 12605 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid()); 12606 setvar("PPID", ppid, 0); 12607 12608 p = lookupvar("PWD"); 12609 if (p) 12610 if (*p != '/' || stat(p, &st1) || stat(".", &st2) 12611 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) 12612 p = '\0'; 12613 setpwd(p, 0); 12614 } 12615} 12616 12617/* 12618 * Process the shell command line arguments. 12619 */ 12620static void 12621procargs(int argc, char **argv) 12622{ 12623 int i; 12624 const char *xminusc; 12625 char **xargv; 12626 12627 xargv = argv; 12628 arg0 = xargv[0]; 12629 if (argc > 0) 12630 xargv++; 12631 for (i = 0; i < NOPTS; i++) 12632 optlist[i] = 2; 12633 argptr = xargv; 12634 options(1); 12635 xargv = argptr; 12636 xminusc = minusc; 12637 if (*xargv == NULL) { 12638 if (xminusc) 12639 ash_msg_and_raise_error(bb_msg_requires_arg, "-c"); 12640 sflag = 1; 12641 } 12642 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) 12643 iflag = 1; 12644 if (mflag == 2) 12645 mflag = iflag; 12646 for (i = 0; i < NOPTS; i++) 12647 if (optlist[i] == 2) 12648 optlist[i] = 0; 12649#if DEBUG == 2 12650 debug = 1; 12651#endif 12652 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ 12653 if (xminusc) { 12654 minusc = *xargv++; 12655 if (*xargv) 12656 goto setarg0; 12657 } else if (!sflag) { 12658 setinputfile(*xargv, 0); 12659 setarg0: 12660 arg0 = *xargv++; 12661 commandname = arg0; 12662 } 12663 12664 shellparam.p = xargv; 12665#if ENABLE_ASH_GETOPTS 12666 shellparam.optind = 1; 12667 shellparam.optoff = -1; 12668#endif 12669 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 12670 while (*xargv) { 12671 shellparam.nparam++; 12672 xargv++; 12673 } 12674 optschanged(); 12675} 12676 12677/* 12678 * Read /etc/profile or .profile. 12679 */ 12680static void 12681read_profile(const char *name) 12682{ 12683 int skip; 12684 12685 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0) 12686 return; 12687 skip = cmdloop(0); 12688 popfile(); 12689 if (skip) 12690 exitshell(); 12691} 12692 12693/* 12694 * This routine is called when an error or an interrupt occurs in an 12695 * interactive shell and control is returned to the main command loop. 12696 */ 12697static void 12698reset(void) 12699{ 12700 /* from eval.c: */ 12701 evalskip = 0; 12702 loopnest = 0; 12703 /* from input.c: */ 12704 parselleft = parsenleft = 0; /* clear input buffer */ 12705 popallfiles(); 12706 /* from parser.c: */ 12707 tokpushback = 0; 12708 checkkwd = 0; 12709 /* from redir.c: */ 12710 clearredir(0); 12711} 12712 12713#if PROFILE 12714static short profile_buf[16384]; 12715extern int etext(); 12716#endif 12717 12718/* 12719 * Main routine. We initialize things, parse the arguments, execute 12720 * profiles if we're a login shell, and then call cmdloop to execute 12721 * commands. The setjmp call sets up the location to jump to when an 12722 * exception occurs. When an exception occurs the variable "state" 12723 * is used to figure out how far we had gotten. 12724 */ 12725int ash_main(int argc, char **argv); 12726int ash_main(int argc, char **argv) 12727{ 12728 char *shinit; 12729 volatile int state; 12730 struct jmploc jmploc; 12731 struct stackmark smark; 12732 12733#if PROFILE 12734 monitor(4, etext, profile_buf, sizeof(profile_buf), 50); 12735#endif 12736 12737#if ENABLE_FEATURE_EDITING 12738 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); 12739#endif 12740 state = 0; 12741 if (setjmp(jmploc.loc)) { 12742 int e; 12743 int s; 12744 12745 reset(); 12746 12747 e = exception; 12748 if (e == EXERROR) 12749 exitstatus = 2; 12750 s = state; 12751 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) 12752 exitshell(); 12753 12754 if (e == EXINT) { 12755 outcslow('\n', stderr); 12756 } 12757 popstackmark(&smark); 12758 FORCE_INT_ON; /* enable interrupts */ 12759 if (s == 1) 12760 goto state1; 12761 if (s == 2) 12762 goto state2; 12763 if (s == 3) 12764 goto state3; 12765 goto state4; 12766 } 12767 exception_handler = &jmploc; 12768#if DEBUG 12769 opentrace(); 12770 trace_puts("Shell args: "); 12771 trace_puts_args(argv); 12772#endif 12773 rootpid = getpid(); 12774 12775#if ENABLE_ASH_RANDOM_SUPPORT 12776 rseed = rootpid + time(NULL); 12777#endif 12778 init(); 12779 setstackmark(&smark); 12780 procargs(argc, argv); 12781#if ENABLE_FEATURE_EDITING_SAVEHISTORY 12782 if (iflag) { 12783 const char *hp = lookupvar("HISTFILE"); 12784 12785 if (hp == NULL) { 12786 hp = lookupvar("HOME"); 12787 if (hp != NULL) { 12788 char *defhp = concat_path_file(hp, ".ash_history"); 12789 setvar("HISTFILE", defhp, 0); 12790 free(defhp); 12791 } 12792 } 12793 } 12794#endif 12795 if (argv[0] && argv[0][0] == '-') 12796 isloginsh = 1; 12797 if (isloginsh) { 12798 state = 1; 12799 read_profile("/etc/profile"); 12800 state1: 12801 state = 2; 12802 read_profile(".profile"); 12803 } 12804 state2: 12805 state = 3; 12806 if ( 12807#ifndef linux 12808 getuid() == geteuid() && getgid() == getegid() && 12809#endif 12810 iflag 12811 ) { 12812 shinit = lookupvar("ENV"); 12813 if (shinit != NULL && *shinit != '\0') { 12814 read_profile(shinit); 12815 } 12816 } 12817 state3: 12818 state = 4; 12819 if (minusc) 12820 evalstring(minusc, 0); 12821 12822 if (sflag || minusc == NULL) { 12823#if ENABLE_FEATURE_EDITING_SAVEHISTORY 12824 if ( iflag ) { 12825 const char *hp = lookupvar("HISTFILE"); 12826 12827 if (hp != NULL) 12828 line_input_state->hist_file = hp; 12829 } 12830#endif 12831 state4: 12832 cmdloop(1); 12833 } 12834#if PROFILE 12835 monitor(0); 12836#endif 12837#ifdef GPROF 12838 { 12839 extern void _mcleanup(void); 12840 _mcleanup(); 12841 } 12842#endif 12843 exitshell(); 12844 /* NOTREACHED */ 12845} 12846 12847#if DEBUG 12848const char *applet_name = "debug stuff usage"; 12849int main(int argc, char **argv) 12850{ 12851 return ash_main(argc, argv); 12852} 12853#endif 12854 12855 12856/*- 12857 * Copyright (c) 1989, 1991, 1993, 1994 12858 * The Regents of the University of California. All rights reserved. 12859 * 12860 * This code is derived from software contributed to Berkeley by 12861 * Kenneth Almquist. 12862 * 12863 * Redistribution and use in source and binary forms, with or without 12864 * modification, are permitted provided that the following conditions 12865 * are met: 12866 * 1. Redistributions of source code must retain the above copyright 12867 * notice, this list of conditions and the following disclaimer. 12868 * 2. Redistributions in binary form must reproduce the above copyright 12869 * notice, this list of conditions and the following disclaimer in the 12870 * documentation and/or other materials provided with the distribution. 12871 * 3. Neither the name of the University nor the names of its contributors 12872 * may be used to endorse or promote products derived from this software 12873 * without specific prior written permission. 12874 * 12875 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 12876 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 12877 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 12878 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 12879 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 12880 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 12881 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 12882 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 12883 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 12884 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 12885 * SUCH DAMAGE. 12886 */ 12887