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