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