Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/shell/ash.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/shell/ash.c
r821 r1770 32 32 */ 33 33 34 35 34 /* 36 35 * The follow should be set to reflect the type of system you have: … … 43 42 * a quit signal will generate a core dump. 44 43 */ 45 46 44 #define DEBUG 0 47 45 #define IFS_BROKEN 48 49 46 #define PROFILE 0 50 51 #include "busybox.h" 52 53 #ifdef DEBUG 47 #if ENABLE_ASH_JOB_CONTROL 48 #define JOBS 1 49 #else 50 #define JOBS 0 51 #endif 52 53 #if DEBUG 54 54 #define _GNU_SOURCE 55 55 #endif 56 57 #include <sys/types.h> 58 #include <sys/ioctl.h> 59 #include <sys/param.h> 60 #include <sys/resource.h> 61 #include <sys/stat.h> 62 #include <sys/wait.h> 63 64 #include <stdio.h> 65 #include <stdlib.h> 66 #include <string.h> 67 #include <unistd.h> 68 69 #include <stdarg.h> 70 #include <stddef.h> 71 #include <assert.h> 72 #include <ctype.h> 73 #include <dirent.h> 74 #include <errno.h> 75 #include <fcntl.h> 76 #include <limits.h> 56 #include "busybox.h" /* for struct bb_applet */ 77 57 #include <paths.h> 78 58 #include <setjmp.h> 79 #include <signal.h>80 /*#include <stdint.h>*/81 #include <time.h>82 59 #include <fnmatch.h> 83 84 #include "pwd_.h" 85 86 #ifdef CONFIG_ASH_JOB_CONTROL 87 #define JOBS 1 88 #else 89 #undef JOBS 90 #endif 91 92 #if JOBS || defined(CONFIG_ASH_READ_NCHARS) 60 #if JOBS || ENABLE_ASH_READ_NCHARS 93 61 #include <termios.h> 94 62 #endif 95 96 #include "cmdedit.h" 97 98 #ifdef __GLIBC__ 99 /* glibc sucks */ 100 static int *dash_errno; 101 #undef errno 102 #define errno (*dash_errno) 103 #endif 63 extern char **environ; 104 64 105 65 #if defined(__uClinux__) … … 107 67 #endif 108 68 109 #ifdef DEBUG 110 #define _DIAGASSERT(assert_expr) assert(assert_expr) 111 #else 112 #define _DIAGASSERT(assert_expr) 113 #endif 114 115 116 #ifdef CONFIG_ASH_ALIAS 117 /* alias.h */ 118 119 #define ALIASINUSE 1 120 #define ALIASDEAD 2 121 122 struct alias { 123 struct alias *next; 124 char *name; 125 char *val; 126 int flag; 69 70 /* ============ Misc helpers */ 71 72 #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0) 73 74 /* C99 say: "char" declaration may be signed or unsigned default */ 75 #define signed_char2int(sc) ((int)((signed char)sc)) 76 77 78 /* ============ Shell options */ 79 80 static const char *const optletters_optnames[] = { 81 "e" "errexit", 82 "f" "noglob", 83 "I" "ignoreeof", 84 "i" "interactive", 85 "m" "monitor", 86 "n" "noexec", 87 "s" "stdin", 88 "x" "xtrace", 89 "v" "verbose", 90 "C" "noclobber", 91 "a" "allexport", 92 "b" "notify", 93 "u" "nounset", 94 "\0" "vi" 95 #if DEBUG 96 ,"\0" "nolog" 97 ,"\0" "debug" 98 #endif 127 99 }; 128 100 129 static struct alias *lookupalias(const char *, int); 130 static int aliascmd(int, char **); 131 static int unaliascmd(int, char **); 132 static void rmaliases(void); 133 static int unalias(const char *); 134 static void printalias(const struct alias *); 135 #endif 136 137 /* cd.h */ 138 139 140 static void setpwd(const char *, int); 141 142 /* error.h */ 143 144 145 /* 146 * Types of operations (passed to the errmsg routine). 147 */ 148 149 150 static const char not_found_msg[] = "%s: not found"; 151 152 153 #define E_OPEN "No such file" /* opening a file */ 154 #define E_CREAT "Directory nonexistent" /* creating a file */ 155 #define E_EXEC not_found_msg+4 /* executing a program */ 101 #define optletters(n) optletters_optnames[(n)][0] 102 #define optnames(n) (&optletters_optnames[(n)][1]) 103 104 enum { NOPTS = ARRAY_SIZE(optletters_optnames) }; 105 106 static char optlist[NOPTS] ALIGN1; 107 108 #define eflag optlist[0] 109 #define fflag optlist[1] 110 #define Iflag optlist[2] 111 #define iflag optlist[3] 112 #define mflag optlist[4] 113 #define nflag optlist[5] 114 #define sflag optlist[6] 115 #define xflag optlist[7] 116 #define vflag optlist[8] 117 #define Cflag optlist[9] 118 #define aflag optlist[10] 119 #define bflag optlist[11] 120 #define uflag optlist[12] 121 #define viflag optlist[13] 122 #if DEBUG 123 #define nolog optlist[14] 124 #define debug optlist[15] 125 #endif 126 127 128 /* ============ Misc data */ 129 130 static char nullstr[1] ALIGN1; /* zero length string */ 131 static const char homestr[] ALIGN1 = "HOME"; 132 static const char snlfmt[] ALIGN1 = "%s\n"; 133 static const char illnum[] ALIGN1 = "Illegal number: %s"; 134 135 static char *minusc; /* argument to -c option */ 136 137 /* pid of main shell */ 138 static int rootpid; 139 /* shell level: 0 for the main shell, 1 for its children, and so on */ 140 static int shlvl; 141 #define rootshell (!shlvl) 142 /* trap handler commands */ 143 static char *trap[NSIG]; 144 static smallint isloginsh; 145 /* current value of signal */ 146 static char sigmode[NSIG - 1]; 147 /* indicates specified signal received */ 148 static char gotsig[NSIG - 1]; 149 static char *arg0; /* value of $0 */ 150 151 152 /* ============ Interrupts / exceptions */ 156 153 157 154 /* … … 164 161 * inner scope, and restore handler on exit from the scope. 165 162 */ 166 167 163 struct jmploc { 168 164 jmp_buf loc; 169 165 }; 170 171 static struct jmploc *handler; 166 static struct jmploc *exception_handler; 172 167 static int exception; 173 static volatile int suppressint;174 static volatile sig_atomic_t intpending;175 176 168 /* exceptions */ 177 169 #define EXINT 0 /* SIGINT received */ … … 181 173 #define EXEXIT 4 /* exit the shell */ 182 174 #define EXSIG 5 /* trapped signal in wait(1) */ 183 184 175 static volatile int suppressint; 176 static volatile sig_atomic_t intpending; 185 177 /* do we generate EXSIG events */ 186 178 static int exsig; 187 179 /* last pending signal */ 188 static volatile sig_atomic_t pendingsigs; 180 static volatile sig_atomic_t pendingsig; 181 182 /* 183 * Sigmode records the current value of the signal handlers for the various 184 * modes. A value of zero means that the current handler is not known. 185 * S_HARD_IGN indicates that the signal was ignored on entry to the shell, 186 */ 187 188 #define S_DFL 1 /* default signal handling (SIG_DFL) */ 189 #define S_CATCH 2 /* signal is caught */ 190 #define S_IGN 3 /* signal is ignored (SIG_IGN) */ 191 #define S_HARD_IGN 4 /* signal is ignored permenantly */ 192 #define S_RESET 5 /* temporary - to reset a hard ignored sig */ 189 193 190 194 /* … … 194 198 * more fun than worrying about efficiency and portability. :-)) 195 199 */ 196 197 #define xbarrier() ({ __asm__ __volatile__ ("": : :"memory"); }) 198 #define INTOFF \ 199 ({ \ 200 #define INT_OFF \ 201 do { \ 200 202 suppressint++; \ 201 203 xbarrier(); \ 202 0; \ 203 }) 204 #define SAVEINT(v) ((v) = suppressint) 205 #define RESTOREINT(v) \ 206 ({ \ 204 } while (0) 205 206 /* 207 * Called to raise an exception. Since C doesn't include exceptions, we 208 * just do a longjmp to the exception handler. The type of exception is 209 * stored in the global variable "exception". 210 */ 211 static void raise_exception(int) ATTRIBUTE_NORETURN; 212 static void 213 raise_exception(int e) 214 { 215 #if DEBUG 216 if (exception_handler == NULL) 217 abort(); 218 #endif 219 INT_OFF; 220 exception = e; 221 longjmp(exception_handler->loc, 1); 222 } 223 224 /* 225 * Called from trap.c when a SIGINT is received. (If the user specifies 226 * that SIGINT is to be trapped or ignored using the trap builtin, then 227 * this routine is not called.) Suppressint is nonzero when interrupts 228 * are held using the INT_OFF macro. (The test for iflag is just 229 * defensive programming.) 230 */ 231 static void raise_interrupt(void) ATTRIBUTE_NORETURN; 232 static void 233 raise_interrupt(void) 234 { 235 int i; 236 sigset_t mask; 237 238 intpending = 0; 239 /* Signal is not automatically re-enabled after it is raised, 240 * do it ourself */ 241 sigemptyset(&mask); 242 sigprocmask(SIG_SETMASK, &mask, 0); 243 /* pendingsig = 0; - now done in onsig() */ 244 245 i = EXSIG; 246 if (gotsig[SIGINT - 1] && !trap[SIGINT]) { 247 if (!(rootshell && iflag)) { 248 signal(SIGINT, SIG_DFL); 249 raise(SIGINT); 250 } 251 i = EXINT; 252 } 253 raise_exception(i); 254 /* NOTREACHED */ 255 } 256 257 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE 258 static void 259 int_on(void) 260 { 261 if (--suppressint == 0 && intpending) { 262 raise_interrupt(); 263 } 264 } 265 #define INT_ON int_on() 266 static void 267 force_int_on(void) 268 { 269 suppressint = 0; 270 if (intpending) 271 raise_interrupt(); 272 } 273 #define FORCE_INT_ON force_int_on() 274 #else 275 #define INT_ON \ 276 do { \ 207 277 xbarrier(); \ 208 if ((suppressint = (v)) == 0 && intpending) onint(); \ 209 0; \ 210 }) 211 #define EXSIGON() \ 212 ({ \ 278 if (--suppressint == 0 && intpending) \ 279 raise_interrupt(); \ 280 } while (0) 281 #define FORCE_INT_ON \ 282 do { \ 283 xbarrier(); \ 284 suppressint = 0; \ 285 if (intpending) \ 286 raise_interrupt(); \ 287 } while (0) 288 #endif /* ASH_OPTIMIZE_FOR_SIZE */ 289 290 #define SAVE_INT(v) ((v) = suppressint) 291 292 #define RESTORE_INT(v) \ 293 do { \ 294 xbarrier(); \ 295 suppressint = (v); \ 296 if (suppressint == 0 && intpending) \ 297 raise_interrupt(); \ 298 } while (0) 299 300 #define EXSIGON \ 301 do { \ 213 302 exsig++; \ 214 303 xbarrier(); \ 215 if (pendingsigs) \ 216 exraise(EXSIG); \ 217 0; \ 218 }) 304 if (pendingsig) \ 305 raise_exception(EXSIG); \ 306 } while (0) 219 307 /* EXSIG is turned off by evalbltin(). */ 220 308 221 222 static void exraise(int) ATTRIBUTE_NORETURN; 223 static void onint(void) ATTRIBUTE_NORETURN; 224 225 static void sh_error(const char *, ...) ATTRIBUTE_NORETURN; 226 static void exerror(int, const char *, ...) ATTRIBUTE_NORETURN; 227 228 static void sh_warnx(const char *, ...); 229 230 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE 231 static void 232 inton(void) { 233 if (--suppressint == 0 && intpending) { 234 onint(); 235 } 236 } 237 #define INTON inton() 238 static void forceinton(void) 239 { 240 suppressint = 0; 241 if (intpending) 242 onint(); 243 } 244 #define FORCEINTON forceinton() 245 #else 246 #define INTON \ 247 ({ \ 248 xbarrier(); \ 249 if (--suppressint == 0 && intpending) onint(); \ 250 0; \ 251 }) 252 #define FORCEINTON \ 253 ({ \ 254 xbarrier(); \ 255 suppressint = 0; \ 256 if (intpending) onint(); \ 257 0; \ 258 }) 259 #endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */ 260 261 /* expand.h */ 262 263 struct strlist { 264 struct strlist *next; 265 char *text; 309 /* 310 * Ignore a signal. Only one usage site - in forkchild() 311 */ 312 static void 313 ignoresig(int signo) 314 { 315 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { 316 signal(signo, SIG_IGN); 317 } 318 sigmode[signo - 1] = S_HARD_IGN; 319 } 320 321 /* 322 * Signal handler. Only one usage site - in setsignal() 323 */ 324 static void 325 onsig(int signo) 326 { 327 gotsig[signo - 1] = 1; 328 pendingsig = signo; 329 330 if (exsig || (signo == SIGINT && !trap[SIGINT])) { 331 if (!suppressint) { 332 pendingsig = 0; 333 raise_interrupt(); 334 } 335 intpending = 1; 336 } 337 } 338 339 340 /* ============ Stdout/stderr output */ 341 342 static void 343 outstr(const char *p, FILE *file) 344 { 345 INT_OFF; 346 fputs(p, file); 347 INT_ON; 348 } 349 350 static void 351 flush_stdout_stderr(void) 352 { 353 INT_OFF; 354 fflush(stdout); 355 fflush(stderr); 356 INT_ON; 357 } 358 359 static void 360 flush_stderr(void) 361 { 362 INT_OFF; 363 fflush(stderr); 364 INT_ON; 365 } 366 367 static void 368 outcslow(int c, FILE *dest) 369 { 370 INT_OFF; 371 putc(c, dest); 372 fflush(dest); 373 INT_ON; 374 } 375 376 static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2))); 377 static int 378 out1fmt(const char *fmt, ...) 379 { 380 va_list ap; 381 int r; 382 383 INT_OFF; 384 va_start(ap, fmt); 385 r = vprintf(fmt, ap); 386 va_end(ap); 387 INT_ON; 388 return r; 389 } 390 391 static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4))); 392 static int 393 fmtstr(char *outbuf, size_t length, const char *fmt, ...) 394 { 395 va_list ap; 396 int ret; 397 398 va_start(ap, fmt); 399 INT_OFF; 400 ret = vsnprintf(outbuf, length, fmt, ap); 401 va_end(ap); 402 INT_ON; 403 return ret; 404 } 405 406 static void 407 out1str(const char *p) 408 { 409 outstr(p, stdout); 410 } 411 412 static void 413 out2str(const char *p) 414 { 415 outstr(p, stderr); 416 flush_stderr(); 417 } 418 419 420 /* ============ Parser structures */ 421 422 /* control characters in argument strings */ 423 #define CTLESC '\201' /* escape next character */ 424 #define CTLVAR '\202' /* variable defn */ 425 #define CTLENDVAR '\203' 426 #define CTLBACKQ '\204' 427 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ 428 /* CTLBACKQ | CTLQUOTE == '\205' */ 429 #define CTLARI '\206' /* arithmetic expression */ 430 #define CTLENDARI '\207' 431 #define CTLQUOTEMARK '\210' 432 433 /* variable substitution byte (follows CTLVAR) */ 434 #define VSTYPE 0x0f /* type of variable substitution */ 435 #define VSNUL 0x10 /* colon--treat the empty string as unset */ 436 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ 437 438 /* values of VSTYPE field */ 439 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */ 440 #define VSMINUS 0x2 /* ${var-text} */ 441 #define VSPLUS 0x3 /* ${var+text} */ 442 #define VSQUESTION 0x4 /* ${var?message} */ 443 #define VSASSIGN 0x5 /* ${var=text} */ 444 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */ 445 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */ 446 #define VSTRIMLEFT 0x8 /* ${var#pattern} */ 447 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */ 448 #define VSLENGTH 0xa /* ${#var} */ 449 450 static const char dolatstr[] ALIGN1 = { 451 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' 266 452 }; 267 268 269 struct arglist {270 struct strlist *list;271 struct strlist **lastp;272 };273 274 /*275 * expandarg() flags276 */277 #define EXP_FULL 0x1 /* perform word splitting & file globbing */278 #define EXP_TILDE 0x2 /* do normal tilde expansion */279 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */280 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */281 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */282 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */283 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */284 #define EXP_WORD 0x80 /* expand word in parameter expansion */285 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */286 287 288 union node;289 static void expandarg(union node *, struct arglist *, int);290 #define rmescapes(p) _rmescapes((p), 0)291 static char *_rmescapes(char *, int);292 static int casematch(union node *, char *);293 294 #ifdef CONFIG_ASH_MATH_SUPPORT295 static void expari(int);296 #endif297 298 /* eval.h */299 300 static char *commandname; /* currently executing command */301 static struct strlist *cmdenviron; /* environment for builtin command */302 static int exitstatus; /* exit status of last command */303 static int back_exitstatus; /* exit status of backquoted command */304 305 306 struct backcmd { /* result of evalbackcmd */307 int fd; /* file descriptor to read from */308 char *buf; /* buffer */309 int nleft; /* number of chars in buffer */310 struct job *jp; /* job structure for command */311 };312 313 /*314 * This file was generated by the mknodes program.315 */316 453 317 454 #define NCMD 0 … … 342 479 #define NNOT 25 343 480 344 481 union node; 345 482 346 483 struct ncmd { 347 348 349 350 484 int type; 485 union node *assign; 486 union node *args; 487 union node *redirect; 351 488 }; 352 489 353 354 490 struct npipe { 355 356 357 491 int type; 492 int backgnd; 493 struct nodelist *cmdlist; 358 494 }; 359 495 360 361 496 struct nredir { 362 363 364 497 int type; 498 union node *n; 499 union node *redirect; 365 500 }; 366 501 367 368 502 struct nbinary { 369 370 371 503 int type; 504 union node *ch1; 505 union node *ch2; 372 506 }; 373 507 374 375 508 struct nif { 376 377 378 379 509 int type; 510 union node *test; 511 union node *ifpart; 512 union node *elsepart; 380 513 }; 381 514 382 383 515 struct nfor { 384 385 386 387 516 int type; 517 union node *args; 518 union node *body; 519 char *var; 388 520 }; 389 521 390 391 522 struct ncase { 392 393 394 523 int type; 524 union node *expr; 525 union node *cases; 395 526 }; 396 527 397 398 528 struct nclist { 399 400 401 402 529 int type; 530 union node *next; 531 union node *pattern; 532 union node *body; 403 533 }; 404 534 405 406 535 struct narg { 407 408 409 410 536 int type; 537 union node *next; 538 char *text; 539 struct nodelist *backquote; 411 540 }; 412 541 413 414 542 struct nfile { 415 416 417 418 419 543 int type; 544 union node *next; 545 int fd; 546 union node *fname; 547 char *expfname; 420 548 }; 421 549 422 423 550 struct ndup { 424 425 426 427 428 551 int type; 552 union node *next; 553 int fd; 554 int dupfd; 555 union node *vname; 429 556 }; 430 557 431 432 558 struct nhere { 433 434 435 436 559 int type; 560 union node *next; 561 int fd; 562 union node *doc; 437 563 }; 438 564 439 440 565 struct nnot { 441 442 566 int type; 567 union node *com; 443 568 }; 444 569 445 446 570 union node { 447 448 449 450 451 452 453 454 455 456 457 458 459 460 571 int type; 572 struct ncmd ncmd; 573 struct npipe npipe; 574 struct nredir nredir; 575 struct nbinary nbinary; 576 struct nif nif; 577 struct nfor nfor; 578 struct ncase ncase; 579 struct nclist nclist; 580 struct narg narg; 581 struct nfile nfile; 582 struct ndup ndup; 583 struct nhere nhere; 584 struct nnot nnot; 461 585 }; 462 463 586 464 587 struct nodelist { … … 467 590 }; 468 591 469 470 592 struct funcnode { 471 593 int count; … … 473 595 }; 474 596 475 476 static void freefunc(struct funcnode *); 477 /* parser.h */ 478 479 /* control characters in argument strings */ 480 #define CTL_FIRST '\201' /* first 'special' character */ 481 #define CTLESC '\201' /* escape next character */ 482 #define CTLVAR '\202' /* variable defn */ 483 #define CTLENDVAR '\203' 484 #define CTLBACKQ '\204' 485 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ 486 /* CTLBACKQ | CTLQUOTE == '\205' */ 487 #define CTLARI '\206' /* arithmetic expression */ 488 #define CTLENDARI '\207' 489 #define CTLQUOTEMARK '\210' 490 #define CTL_LAST '\210' /* last 'special' character */ 491 492 /* variable substitution byte (follows CTLVAR) */ 493 #define VSTYPE 0x0f /* type of variable substitution */ 494 #define VSNUL 0x10 /* colon--treat the empty string as unset */ 495 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ 496 497 /* values of VSTYPE field */ 498 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */ 499 #define VSMINUS 0x2 /* ${var-text} */ 500 #define VSPLUS 0x3 /* ${var+text} */ 501 #define VSQUESTION 0x4 /* ${var?message} */ 502 #define VSASSIGN 0x5 /* ${var=text} */ 503 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */ 504 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */ 505 #define VSTRIMLEFT 0x8 /* ${var#pattern} */ 506 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */ 507 #define VSLENGTH 0xa /* ${#var} */ 508 509 /* values of checkkwd variable */ 510 #define CHKALIAS 0x1 511 #define CHKKWD 0x2 512 #define CHKNL 0x4 513 514 #define IBUFSIZ (BUFSIZ + 1) 515 516 /* 517 * NEOF is returned by parsecmd when it encounters an end of file. It 518 * must be distinct from NULL, so we use the address of a variable that 519 * happens to be handy. 520 */ 521 static int plinno = 1; /* input line number */ 522 523 /* number of characters left in input buffer */ 524 static int parsenleft; /* copy of parsefile->nleft */ 525 static int parselleft; /* copy of parsefile->lleft */ 526 527 /* next character in input buffer */ 528 static char *parsenextc; /* copy of parsefile->nextc */ 597 /* 598 * Free a parse tree. 599 */ 600 static void 601 freefunc(struct funcnode *f) 602 { 603 if (f && --f->count < 0) 604 free(f); 605 } 606 607 608 /* ============ Debugging output */ 609 610 #if DEBUG 611 612 static FILE *tracefile; 613 614 static void 615 trace_printf(const char *fmt, ...) 616 { 617 va_list va; 618 619 if (debug != 1) 620 return; 621 va_start(va, fmt); 622 vfprintf(tracefile, fmt, va); 623 va_end(va); 624 } 625 626 static void 627 trace_vprintf(const char *fmt, va_list va) 628 { 629 if (debug != 1) 630 return; 631 vfprintf(tracefile, fmt, va); 632 } 633 634 static void 635 trace_puts(const char *s) 636 { 637 if (debug != 1) 638 return; 639 fputs(s, tracefile); 640 } 641 642 static void 643 trace_puts_quoted(char *s) 644 { 645 char *p; 646 char c; 647 648 if (debug != 1) 649 return; 650 putc('"', tracefile); 651 for (p = s; *p; p++) { 652 switch (*p) { 653 case '\n': c = 'n'; goto backslash; 654 case '\t': c = 't'; goto backslash; 655 case '\r': c = 'r'; goto backslash; 656 case '"': c = '"'; goto backslash; 657 case '\\': c = '\\'; goto backslash; 658 case CTLESC: c = 'e'; goto backslash; 659 case CTLVAR: c = 'v'; goto backslash; 660 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; 661 case CTLBACKQ: c = 'q'; goto backslash; 662 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; 663 backslash: 664 putc('\\', tracefile); 665 putc(c, tracefile); 666 break; 667 default: 668 if (*p >= ' ' && *p <= '~') 669 putc(*p, tracefile); 670 else { 671 putc('\\', tracefile); 672 putc(*p >> 6 & 03, tracefile); 673 putc(*p >> 3 & 07, tracefile); 674 putc(*p & 07, tracefile); 675 } 676 break; 677 } 678 } 679 putc('"', tracefile); 680 } 681 682 static void 683 trace_puts_args(char **ap) 684 { 685 if (debug != 1) 686 return; 687 if (!*ap) 688 return; 689 while (1) { 690 trace_puts_quoted(*ap); 691 if (!*++ap) { 692 putc('\n', tracefile); 693 break; 694 } 695 putc(' ', tracefile); 696 } 697 } 698 699 static void 700 opentrace(void) 701 { 702 char s[100]; 703 #ifdef O_APPEND 704 int flags; 705 #endif 706 707 if (debug != 1) { 708 if (tracefile) 709 fflush(tracefile); 710 /* leave open because libedit might be using it */ 711 return; 712 } 713 strcpy(s, "./trace"); 714 if (tracefile) { 715 if (!freopen(s, "a", tracefile)) { 716 fprintf(stderr, "Can't re-open %s\n", s); 717 debug = 0; 718 return; 719 } 720 } else { 721 tracefile = fopen(s, "a"); 722 if (tracefile == NULL) { 723 fprintf(stderr, "Can't open %s\n", s); 724 debug = 0; 725 return; 726 } 727 } 728 #ifdef O_APPEND 729 flags = fcntl(fileno(tracefile), F_GETFL); 730 if (flags >= 0) 731 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); 732 #endif 733 setlinebuf(tracefile); 734 fputs("\nTracing started.\n", tracefile); 735 } 736 737 static void 738 indent(int amount, char *pfx, FILE *fp) 739 { 740 int i; 741 742 for (i = 0; i < amount; i++) { 743 if (pfx && i == amount - 1) 744 fputs(pfx, fp); 745 putc('\t', fp); 746 } 747 } 748 749 /* little circular references here... */ 750 static void shtree(union node *n, int ind, char *pfx, FILE *fp); 751 752 static void 753 sharg(union node *arg, FILE *fp) 754 { 755 char *p; 756 struct nodelist *bqlist; 757 int subtype; 758 759 if (arg->type != NARG) { 760 out1fmt("<node type %d>\n", arg->type); 761 abort(); 762 } 763 bqlist = arg->narg.backquote; 764 for (p = arg->narg.text; *p; p++) { 765 switch (*p) { 766 case CTLESC: 767 putc(*++p, fp); 768 break; 769 case CTLVAR: 770 putc('$', fp); 771 putc('{', fp); 772 subtype = *++p; 773 if (subtype == VSLENGTH) 774 putc('#', fp); 775 776 while (*p != '=') 777 putc(*p++, fp); 778 779 if (subtype & VSNUL) 780 putc(':', fp); 781 782 switch (subtype & VSTYPE) { 783 case VSNORMAL: 784 putc('}', fp); 785 break; 786 case VSMINUS: 787 putc('-', fp); 788 break; 789 case VSPLUS: 790 putc('+', fp); 791 break; 792 case VSQUESTION: 793 putc('?', fp); 794 break; 795 case VSASSIGN: 796 putc('=', fp); 797 break; 798 case VSTRIMLEFT: 799 putc('#', fp); 800 break; 801 case VSTRIMLEFTMAX: 802 putc('#', fp); 803 putc('#', fp); 804 break; 805 case VSTRIMRIGHT: 806 putc('%', fp); 807 break; 808 case VSTRIMRIGHTMAX: 809 putc('%', fp); 810 putc('%', fp); 811 break; 812 case VSLENGTH: 813 break; 814 default: 815 out1fmt("<subtype %d>", subtype); 816 } 817 break; 818 case CTLENDVAR: 819 putc('}', fp); 820 break; 821 case CTLBACKQ: 822 case CTLBACKQ|CTLQUOTE: 823 putc('$', fp); 824 putc('(', fp); 825 shtree(bqlist->n, -1, NULL, fp); 826 putc(')', fp); 827 break; 828 default: 829 putc(*p, fp); 830 break; 831 } 832 } 833 } 834 835 static void 836 shcmd(union node *cmd, FILE *fp) 837 { 838 union node *np; 839 int first; 840 const char *s; 841 int dftfd; 842 843 first = 1; 844 for (np = cmd->ncmd.args; np; np = np->narg.next) { 845 if (!first) 846 putc(' ', fp); 847 sharg(np, fp); 848 first = 0; 849 } 850 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) { 851 if (!first) 852 putc(' ', fp); 853 dftfd = 0; 854 switch (np->nfile.type) { 855 case NTO: s = ">>"+1; dftfd = 1; break; 856 case NCLOBBER: s = ">|"; dftfd = 1; break; 857 case NAPPEND: s = ">>"; dftfd = 1; break; 858 case NTOFD: s = ">&"; dftfd = 1; break; 859 case NFROM: s = "<"; break; 860 case NFROMFD: s = "<&"; break; 861 case NFROMTO: s = "<>"; break; 862 default: s = "*error*"; break; 863 } 864 if (np->nfile.fd != dftfd) 865 fprintf(fp, "%d", np->nfile.fd); 866 fputs(s, fp); 867 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) { 868 fprintf(fp, "%d", np->ndup.dupfd); 869 } else { 870 sharg(np->nfile.fname, fp); 871 } 872 first = 0; 873 } 874 } 875 876 static void 877 shtree(union node *n, int ind, char *pfx, FILE *fp) 878 { 879 struct nodelist *lp; 880 const char *s; 881 882 if (n == NULL) 883 return; 884 885 indent(ind, pfx, fp); 886 switch (n->type) { 887 case NSEMI: 888 s = "; "; 889 goto binop; 890 case NAND: 891 s = " && "; 892 goto binop; 893 case NOR: 894 s = " || "; 895 binop: 896 shtree(n->nbinary.ch1, ind, NULL, fp); 897 /* if (ind < 0) */ 898 fputs(s, fp); 899 shtree(n->nbinary.ch2, ind, NULL, fp); 900 break; 901 case NCMD: 902 shcmd(n, fp); 903 if (ind >= 0) 904 putc('\n', fp); 905 break; 906 case NPIPE: 907 for (lp = n->npipe.cmdlist; lp; lp = lp->next) { 908 shcmd(lp->n, fp); 909 if (lp->next) 910 fputs(" | ", fp); 911 } 912 if (n->npipe.backgnd) 913 fputs(" &", fp); 914 if (ind >= 0) 915 putc('\n', fp); 916 break; 917 default: 918 fprintf(fp, "<node type %d>", n->type); 919 if (ind >= 0) 920 putc('\n', fp); 921 break; 922 } 923 } 924 925 static void 926 showtree(union node *n) 927 { 928 trace_puts("showtree called\n"); 929 shtree(n, 1, NULL, stdout); 930 } 931 932 #define TRACE(param) trace_printf param 933 #define TRACEV(param) trace_vprintf param 934 935 #else 936 937 #define TRACE(param) 938 #define TRACEV(param) 939 940 #endif /* DEBUG */ 941 942 943 /* ============ Parser data */ 944 945 /* 946 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up. 947 */ 948 struct strlist { 949 struct strlist *next; 950 char *text; 951 }; 952 953 #if ENABLE_ASH_ALIAS 954 struct alias; 955 #endif 529 956 530 957 struct strpush { … … 532 959 char *prevstring; 533 960 int prevnleft; 534 #if def CONFIG_ASH_ALIAS961 #if ENABLE_ASH_ALIAS 535 962 struct alias *ap; /* if push was associated with an alias */ 536 963 #endif … … 551 978 552 979 static struct parsefile basepf; /* top level input file */ 553 #define basebuf bb_common_bufsiz1 /* buffer for top level input file */554 980 static struct parsefile *parsefile = &basepf; /* current input file */ 555 556 557 static int tokpushback; /* last token pushed back */ 558 #define NEOF ((union node *)&tokpushback) 559 static int parsebackquote; /* nonzero if we are inside backquotes */ 981 static int startlinno; /* line # where last token started */ 982 static char *commandname; /* currently executing command */ 983 static struct strlist *cmdenviron; /* environment for builtin command */ 984 static int exitstatus; /* exit status of last command */ 985 986 987 /* ============ Message printing */ 988 989 static void 990 ash_vmsg(const char *msg, va_list ap) 991 { 992 fprintf(stderr, "%s: ", arg0); 993 if (commandname) { 994 if (strcmp(arg0, commandname)) 995 fprintf(stderr, "%s: ", commandname); 996 if (!iflag || parsefile->fd) 997 fprintf(stderr, "line %d: ", startlinno); 998 } 999 vfprintf(stderr, msg, ap); 1000 outcslow('\n', stderr); 1001 } 1002 1003 /* 1004 * Exverror is called to raise the error exception. If the second argument 1005 * is not NULL then error prints an error message using printf style 1006 * formatting. It then raises the error exception. 1007 */ 1008 static void ash_vmsg_and_raise(int, const char *, va_list) ATTRIBUTE_NORETURN; 1009 static void 1010 ash_vmsg_and_raise(int cond, const char *msg, va_list ap) 1011 { 1012 #if DEBUG 1013 if (msg) { 1014 TRACE(("ash_vmsg_and_raise(%d, \"", cond)); 1015 TRACEV((msg, ap)); 1016 TRACE(("\") pid=%d\n", getpid())); 1017 } else 1018 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid())); 1019 if (msg) 1020 #endif 1021 ash_vmsg(msg, ap); 1022 1023 flush_stdout_stderr(); 1024 raise_exception(cond); 1025 /* NOTREACHED */ 1026 } 1027 1028 static void ash_msg_and_raise_error(const char *, ...) ATTRIBUTE_NORETURN; 1029 static void 1030 ash_msg_and_raise_error(const char *msg, ...) 1031 { 1032 va_list ap; 1033 1034 va_start(ap, msg); 1035 ash_vmsg_and_raise(EXERROR, msg, ap); 1036 /* NOTREACHED */ 1037 va_end(ap); 1038 } 1039 1040 static void ash_msg_and_raise(int, const char *, ...) ATTRIBUTE_NORETURN; 1041 static void 1042 ash_msg_and_raise(int cond, const char *msg, ...) 1043 { 1044 va_list ap; 1045 1046 va_start(ap, msg); 1047 ash_vmsg_and_raise(cond, msg, ap); 1048 /* NOTREACHED */ 1049 va_end(ap); 1050 } 1051 1052 /* 1053 * error/warning routines for external builtins 1054 */ 1055 static void 1056 ash_msg(const char *fmt, ...) 1057 { 1058 va_list ap; 1059 1060 va_start(ap, fmt); 1061 ash_vmsg(fmt, ap); 1062 va_end(ap); 1063 } 1064 1065 /* 1066 * Return a string describing an error. The returned string may be a 1067 * pointer to a static buffer that will be overwritten on the next call. 1068 * Action describes the operation that got the error. 1069 */ 1070 static const char * 1071 errmsg(int e, const char *em) 1072 { 1073 if (e == ENOENT || e == ENOTDIR) { 1074 return em; 1075 } 1076 return strerror(e); 1077 } 1078 1079 1080 /* ============ Memory allocation */ 1081 1082 /* 1083 * It appears that grabstackstr() will barf with such alignments 1084 * because stalloc() will return a string allocated in a new stackblock. 1085 */ 1086 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE) 1087 enum { 1088 /* Most machines require the value returned from malloc to be aligned 1089 * in some way. The following macro will get this right 1090 * on many machines. */ 1091 SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1, 1092 /* Minimum size of a block */ 1093 MINSIZE = SHELL_ALIGN(504), 1094 }; 1095 1096 struct stack_block { 1097 struct stack_block *prev; 1098 char space[MINSIZE]; 1099 }; 1100 1101 struct stackmark { 1102 struct stack_block *stackp; 1103 char *stacknxt; 1104 size_t stacknleft; 1105 struct stackmark *marknext; 1106 }; 1107 1108 static struct stack_block stackbase; 1109 static struct stack_block *stackp = &stackbase; 1110 static struct stackmark *markp; 1111 static char *stacknxt = stackbase.space; 1112 static size_t stacknleft = MINSIZE; 1113 static char *sstrend = stackbase.space + MINSIZE; 1114 static int herefd = -1; 1115 1116 #define stackblock() ((void *)stacknxt) 1117 #define stackblocksize() stacknleft 1118 1119 static void * 1120 ckrealloc(void * p, size_t nbytes) 1121 { 1122 p = realloc(p, nbytes); 1123 if (!p) 1124 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1125 return p; 1126 } 1127 1128 static void * 1129 ckmalloc(size_t nbytes) 1130 { 1131 return ckrealloc(NULL, nbytes); 1132 } 1133 1134 /* 1135 * Make a copy of a string in safe storage. 1136 */ 1137 static char * 1138 ckstrdup(const char *s) 1139 { 1140 char *p = strdup(s); 1141 if (!p) 1142 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1143 return p; 1144 } 1145 1146 /* 1147 * Parse trees for commands are allocated in lifo order, so we use a stack 1148 * to make this more efficient, and also to avoid all sorts of exception 1149 * handling code to handle interrupts in the middle of a parse. 1150 * 1151 * The size 504 was chosen because the Ultrix malloc handles that size 1152 * well. 1153 */ 1154 static void * 1155 stalloc(size_t nbytes) 1156 { 1157 char *p; 1158 size_t aligned; 1159 1160 aligned = SHELL_ALIGN(nbytes); 1161 if (aligned > stacknleft) { 1162 size_t len; 1163 size_t blocksize; 1164 struct stack_block *sp; 1165 1166 blocksize = aligned; 1167 if (blocksize < MINSIZE) 1168 blocksize = MINSIZE; 1169 len = sizeof(struct stack_block) - MINSIZE + blocksize; 1170 if (len < blocksize) 1171 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1172 INT_OFF; 1173 sp = ckmalloc(len); 1174 sp->prev = stackp; 1175 stacknxt = sp->space; 1176 stacknleft = blocksize; 1177 sstrend = stacknxt + blocksize; 1178 stackp = sp; 1179 INT_ON; 1180 } 1181 p = stacknxt; 1182 stacknxt += aligned; 1183 stacknleft -= aligned; 1184 return p; 1185 } 1186 1187 static void 1188 stunalloc(void *p) 1189 { 1190 #if DEBUG 1191 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) { 1192 write(2, "stunalloc\n", 10); 1193 abort(); 1194 } 1195 #endif 1196 stacknleft += stacknxt - (char *)p; 1197 stacknxt = p; 1198 } 1199 1200 /* 1201 * Like strdup but works with the ash stack. 1202 */ 1203 static char * 1204 ststrdup(const char *p) 1205 { 1206 size_t len = strlen(p) + 1; 1207 return memcpy(stalloc(len), p, len); 1208 } 1209 1210 static void 1211 setstackmark(struct stackmark *mark) 1212 { 1213 mark->stackp = stackp; 1214 mark->stacknxt = stacknxt; 1215 mark->stacknleft = stacknleft; 1216 mark->marknext = markp; 1217 markp = mark; 1218 } 1219 1220 static void 1221 popstackmark(struct stackmark *mark) 1222 { 1223 struct stack_block *sp; 1224 1225 if (!mark->stackp) 1226 return; 1227 1228 INT_OFF; 1229 markp = mark->marknext; 1230 while (stackp != mark->stackp) { 1231 sp = stackp; 1232 stackp = sp->prev; 1233 free(sp); 1234 } 1235 stacknxt = mark->stacknxt; 1236 stacknleft = mark->stacknleft; 1237 sstrend = mark->stacknxt + mark->stacknleft; 1238 INT_ON; 1239 } 1240 1241 /* 1242 * When the parser reads in a string, it wants to stick the string on the 1243 * stack and only adjust the stack pointer when it knows how big the 1244 * string is. Stackblock (defined in stack.h) returns a pointer to a block 1245 * of space on top of the stack and stackblocklen returns the length of 1246 * this block. Growstackblock will grow this space by at least one byte, 1247 * possibly moving it (like realloc). Grabstackblock actually allocates the 1248 * part of the block that has been used. 1249 */ 1250 static void 1251 growstackblock(void) 1252 { 1253 size_t newlen; 1254 1255 newlen = stacknleft * 2; 1256 if (newlen < stacknleft) 1257 ash_msg_and_raise_error(bb_msg_memory_exhausted); 1258 if (newlen < 128) 1259 newlen += 128; 1260 1261 if (stacknxt == stackp->space && stackp != &stackbase) { 1262 struct stack_block *oldstackp; 1263 struct stackmark *xmark; 1264 struct stack_block *sp; 1265 struct stack_block *prevstackp; 1266 size_t grosslen; 1267 1268 INT_OFF; 1269 oldstackp = stackp; 1270 sp = stackp; 1271 prevstackp = sp->prev; 1272 grosslen = newlen + sizeof(struct stack_block) - MINSIZE; 1273 sp = ckrealloc(sp, grosslen); 1274 sp->prev = prevstackp; 1275 stackp = sp; 1276 stacknxt = sp->space; 1277 stacknleft = newlen; 1278 sstrend = sp->space + newlen; 1279 1280 /* 1281 * Stack marks pointing to the start of the old block 1282 * must be relocated to point to the new block 1283 */ 1284 xmark = markp; 1285 while (xmark != NULL && xmark->stackp == oldstackp) { 1286 xmark->stackp = stackp; 1287 xmark->stacknxt = stacknxt; 1288 xmark->stacknleft = stacknleft; 1289 xmark = xmark->marknext; 1290 } 1291 INT_ON; 1292 } else { 1293 char *oldspace = stacknxt; 1294 int oldlen = stacknleft; 1295 char *p = stalloc(newlen); 1296 1297 /* free the space we just allocated */ 1298 stacknxt = memcpy(p, oldspace, oldlen); 1299 stacknleft += newlen; 1300 } 1301 } 1302 1303 static void 1304 grabstackblock(size_t len) 1305 { 1306 len = SHELL_ALIGN(len); 1307 stacknxt += len; 1308 stacknleft -= len; 1309 } 1310 1311 /* 1312 * The following routines are somewhat easier to use than the above. 1313 * The user declares a variable of type STACKSTR, which may be declared 1314 * to be a register. The macro STARTSTACKSTR initializes things. Then 1315 * the user uses the macro STPUTC to add characters to the string. In 1316 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is 1317 * grown as necessary. When the user is done, she can just leave the 1318 * string there and refer to it using stackblock(). Or she can allocate 1319 * the space for it using grabstackstr(). If it is necessary to allow 1320 * someone else to use the stack temporarily and then continue to grow 1321 * the string, the user should use grabstack to allocate the space, and 1322 * then call ungrabstr(p) to return to the previous mode of operation. 1323 * 1324 * USTPUTC is like STPUTC except that it doesn't check for overflow. 1325 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there 1326 * is space for at least one character. 1327 */ 1328 static void * 1329 growstackstr(void) 1330 { 1331 size_t len = stackblocksize(); 1332 if (herefd >= 0 && len >= 1024) { 1333 full_write(herefd, stackblock(), len); 1334 return stackblock(); 1335 } 1336 growstackblock(); 1337 return stackblock() + len; 1338 } 1339 1340 /* 1341 * Called from CHECKSTRSPACE. 1342 */ 1343 static char * 1344 makestrspace(size_t newlen, char *p) 1345 { 1346 size_t len = p - stacknxt; 1347 size_t size = stackblocksize(); 1348 1349 for (;;) { 1350 size_t nleft; 1351 1352 size = stackblocksize(); 1353 nleft = size - len; 1354 if (nleft >= newlen) 1355 break; 1356 growstackblock(); 1357 } 1358 return stackblock() + len; 1359 } 1360 1361 static char * 1362 stack_nputstr(const char *s, size_t n, char *p) 1363 { 1364 p = makestrspace(n, p); 1365 p = memcpy(p, s, n) + n; 1366 return p; 1367 } 1368 1369 static char * 1370 stack_putstr(const char *s, char *p) 1371 { 1372 return stack_nputstr(s, strlen(s), p); 1373 } 1374 1375 static char * 1376 _STPUTC(int c, char *p) 1377 { 1378 if (p == sstrend) 1379 p = growstackstr(); 1380 *p++ = c; 1381 return p; 1382 } 1383 1384 #define STARTSTACKSTR(p) ((p) = stackblock()) 1385 #define STPUTC(c, p) ((p) = _STPUTC((c), (p))) 1386 #define CHECKSTRSPACE(n, p) \ 1387 do { \ 1388 char *q = (p); \ 1389 size_t l = (n); \ 1390 size_t m = sstrend - q; \ 1391 if (l > m) \ 1392 (p) = makestrspace(l, q); \ 1393 } while (0) 1394 #define USTPUTC(c, p) (*p++ = (c)) 1395 #define STACKSTRNUL(p) \ 1396 do { \ 1397 if ((p) == sstrend) \ 1398 p = growstackstr(); \ 1399 *p = '\0'; \ 1400 } while (0) 1401 #define STUNPUTC(p) (--p) 1402 #define STTOPC(p) (p[-1]) 1403 #define STADJUST(amount, p) (p += (amount)) 1404 1405 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock()) 1406 #define ungrabstackstr(s, p) stunalloc((s)) 1407 #define stackstrend() ((void *)sstrend) 1408 1409 1410 /* ============ String helpers */ 1411 1412 /* 1413 * prefix -- see if pfx is a prefix of string. 1414 */ 1415 static char * 1416 prefix(const char *string, const char *pfx) 1417 { 1418 while (*pfx) { 1419 if (*pfx++ != *string++) 1420 return 0; 1421 } 1422 return (char *) string; 1423 } 1424 1425 /* 1426 * Check for a valid number. This should be elsewhere. 1427 */ 1428 static int 1429 is_number(const char *p) 1430 { 1431 do { 1432 if (!isdigit(*p)) 1433 return 0; 1434 } while (*++p != '\0'); 1435 return 1; 1436 } 1437 1438 /* 1439 * Convert a string of digits to an integer, printing an error message on 1440 * failure. 1441 */ 1442 static int 1443 number(const char *s) 1444 { 1445 if (!is_number(s)) 1446 ash_msg_and_raise_error(illnum, s); 1447 return atoi(s); 1448 } 1449 1450 /* 1451 * Produce a possibly single quoted string suitable as input to the shell. 1452 * The return string is allocated on the stack. 1453 */ 1454 static char * 1455 single_quote(const char *s) 1456 { 1457 char *p; 1458 1459 STARTSTACKSTR(p); 1460 1461 do { 1462 char *q; 1463 size_t len; 1464 1465 len = strchrnul(s, '\'') - s; 1466 1467 q = p = makestrspace(len + 3, p); 1468 1469 *q++ = '\''; 1470 q = memcpy(q, s, len) + len; 1471 *q++ = '\''; 1472 s += len; 1473 1474 STADJUST(q - p, p); 1475 1476 len = strspn(s, "'"); 1477 if (!len) 1478 break; 1479 1480 q = p = makestrspace(len + 3, p); 1481 1482 *q++ = '"'; 1483 q = memcpy(q, s, len) + len; 1484 *q++ = '"'; 1485 s += len; 1486 1487 STADJUST(q - p, p); 1488 } while (*s); 1489 1490 USTPUTC(0, p); 1491 1492 return stackblock(); 1493 } 1494 1495 1496 /* ============ nextopt */ 1497 1498 static char **argptr; /* argument list for builtin commands */ 1499 static char *optionarg; /* set by nextopt (like getopt) */ 1500 static char *optptr; /* used by nextopt */ 1501 1502 /* 1503 * XXX - should get rid of. have all builtins use getopt(3). the 1504 * library getopt must have the BSD extension static variable "optreset" 1505 * otherwise it can't be used within the shell safely. 1506 * 1507 * Standard option processing (a la getopt) for builtin routines. The 1508 * only argument that is passed to nextopt is the option string; the 1509 * other arguments are unnecessary. It return the character, or '\0' on 1510 * end of input. 1511 */ 1512 static int 1513 nextopt(const char *optstring) 1514 { 1515 char *p; 1516 const char *q; 1517 char c; 1518 1519 p = optptr; 1520 if (p == NULL || *p == '\0') { 1521 p = *argptr; 1522 if (p == NULL || *p != '-' || *++p == '\0') 1523 return '\0'; 1524 argptr++; 1525 if (LONE_DASH(p)) /* check for "--" */ 1526 return '\0'; 1527 } 1528 c = *p++; 1529 for (q = optstring; *q != c; ) { 1530 if (*q == '\0') 1531 ash_msg_and_raise_error("illegal option -%c", c); 1532 if (*++q == ':') 1533 q++; 1534 } 1535 if (*++q == ':') { 1536 if (*p == '\0' && (p = *argptr++) == NULL) 1537 ash_msg_and_raise_error("no arg for -%c option", c); 1538 optionarg = p; 1539 p = NULL; 1540 } 1541 optptr = p; 1542 return c; 1543 } 1544 1545 1546 /* ============ Math support definitions */ 1547 1548 #if ENABLE_ASH_MATH_SUPPORT_64 1549 typedef int64_t arith_t; 1550 #define arith_t_type long long 1551 #else 1552 typedef long arith_t; 1553 #define arith_t_type long 1554 #endif 1555 1556 #if ENABLE_ASH_MATH_SUPPORT 1557 static arith_t dash_arith(const char *); 1558 static arith_t arith(const char *expr, int *perrcode); 1559 #endif 1560 1561 #if ENABLE_ASH_RANDOM_SUPPORT 1562 static unsigned long rseed; 1563 #ifndef DYNAMIC_VAR 1564 #define DYNAMIC_VAR 1565 #endif 1566 #endif 1567 1568 1569 /* ============ Shell variables */ 1570 1571 /* flags */ 1572 #define VEXPORT 0x01 /* variable is exported */ 1573 #define VREADONLY 0x02 /* variable cannot be modified */ 1574 #define VSTRFIXED 0x04 /* variable struct is statically allocated */ 1575 #define VTEXTFIXED 0x08 /* text is statically allocated */ 1576 #define VSTACK 0x10 /* text is allocated on the stack */ 1577 #define VUNSET 0x20 /* the variable is not set */ 1578 #define VNOFUNC 0x40 /* don't call the callback function */ 1579 #define VNOSET 0x80 /* do not set variable - just readonly test */ 1580 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */ 1581 #ifdef DYNAMIC_VAR 1582 # define VDYNAMIC 0x200 /* dynamic variable */ 1583 #else 1584 # define VDYNAMIC 0 1585 #endif 1586 1587 #ifdef IFS_BROKEN 1588 static const char defifsvar[] ALIGN1 = "IFS= \t\n"; 1589 #define defifs (defifsvar + 4) 1590 #else 1591 static const char defifs[] ALIGN1 = " \t\n"; 1592 #endif 1593 1594 struct shparam { 1595 int nparam; /* # of positional parameters (without $0) */ 1596 unsigned char malloc; /* if parameter list dynamically allocated */ 1597 char **p; /* parameter list */ 1598 #if ENABLE_ASH_GETOPTS 1599 int optind; /* next parameter to be processed by getopts */ 1600 int optoff; /* used by getopts */ 1601 #endif 1602 }; 1603 1604 static struct shparam shellparam; /* $@ current positional parameters */ 1605 1606 /* 1607 * Free the list of positional parameters. 1608 */ 1609 static void 1610 freeparam(volatile struct shparam *param) 1611 { 1612 char **ap; 1613 1614 if (param->malloc) { 1615 for (ap = param->p; *ap; ap++) 1616 free(*ap); 1617 free(param->p); 1618 } 1619 } 1620 1621 #if ENABLE_ASH_GETOPTS 1622 static void 1623 getoptsreset(const char *value) 1624 { 1625 shellparam.optind = number(value); 1626 shellparam.optoff = -1; 1627 } 1628 #endif 1629 1630 struct var { 1631 struct var *next; /* next entry in hash list */ 1632 int flags; /* flags are defined above */ 1633 const char *text; /* name=value */ 1634 void (*func)(const char *); /* function to be called when */ 1635 /* the variable gets set/unset */ 1636 }; 1637 1638 struct localvar { 1639 struct localvar *next; /* next local variable in list */ 1640 struct var *vp; /* the variable that was made local */ 1641 int flags; /* saved flags */ 1642 const char *text; /* saved text */ 1643 }; 1644 1645 /* Forward decls for varinit[] */ 1646 #if ENABLE_LOCALE_SUPPORT 1647 static void 1648 change_lc_all(const char *value) 1649 { 1650 if (value && *value != '\0') 1651 setlocale(LC_ALL, value); 1652 } 1653 static void 1654 change_lc_ctype(const char *value) 1655 { 1656 if (value && *value != '\0') 1657 setlocale(LC_CTYPE, value); 1658 } 1659 #endif 1660 #if ENABLE_ASH_MAIL 1661 static void chkmail(void); 1662 static void changemail(const char *); 1663 #endif 1664 static void changepath(const char *); 1665 #if ENABLE_ASH_RANDOM_SUPPORT 1666 static void change_random(const char *); 1667 #endif 1668 1669 static struct var varinit[] = { 1670 #ifdef IFS_BROKEN 1671 { NULL, VSTRFIXED|VTEXTFIXED, defifsvar, NULL }, 1672 #else 1673 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", NULL }, 1674 #endif 1675 #if ENABLE_ASH_MAIL 1676 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail }, 1677 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail }, 1678 #endif 1679 { NULL, VSTRFIXED|VTEXTFIXED, bb_PATH_root_path, changepath }, 1680 { NULL, VSTRFIXED|VTEXTFIXED, "PS1=$ ", NULL }, 1681 { NULL, VSTRFIXED|VTEXTFIXED, "PS2=> ", NULL }, 1682 { NULL, VSTRFIXED|VTEXTFIXED, "PS4=+ ", NULL }, 1683 #if ENABLE_ASH_GETOPTS 1684 { NULL, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset }, 1685 #endif 1686 #if ENABLE_ASH_RANDOM_SUPPORT 1687 { NULL, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random }, 1688 #endif 1689 #if ENABLE_LOCALE_SUPPORT 1690 { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all }, 1691 { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype }, 1692 #endif 1693 #if ENABLE_FEATURE_EDITING_SAVEHISTORY 1694 { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL }, 1695 #endif 1696 }; 1697 1698 #define vifs varinit[0] 1699 #if ENABLE_ASH_MAIL 1700 #define vmail (&vifs)[1] 1701 #define vmpath (&vmail)[1] 1702 #else 1703 #define vmpath vifs 1704 #endif 1705 #define vpath (&vmpath)[1] 1706 #define vps1 (&vpath)[1] 1707 #define vps2 (&vps1)[1] 1708 #define vps4 (&vps2)[1] 1709 #define voptind (&vps4)[1] 1710 #if ENABLE_ASH_GETOPTS 1711 #define vrandom (&voptind)[1] 1712 #else 1713 #define vrandom (&vps4)[1] 1714 #endif 1715 1716 /* 1717 * The following macros access the values of the above variables. 1718 * They have to skip over the name. They return the null string 1719 * for unset variables. 1720 */ 1721 #define ifsval() (vifs.text + 4) 1722 #define ifsset() ((vifs.flags & VUNSET) == 0) 1723 #define mailval() (vmail.text + 5) 1724 #define mpathval() (vmpath.text + 9) 1725 #define pathval() (vpath.text + 5) 1726 #define ps1val() (vps1.text + 4) 1727 #define ps2val() (vps2.text + 4) 1728 #define ps4val() (vps4.text + 4) 1729 #define optindval() (voptind.text + 7) 1730 1731 #define mpathset() ((vmpath.flags & VUNSET) == 0) 1732 1733 /* 1734 * The parsefile structure pointed to by the global variable parsefile 1735 * contains information about the current file being read. 1736 */ 1737 struct redirtab { 1738 struct redirtab *next; 1739 int renamed[10]; 1740 int nullredirs; 1741 }; 1742 1743 static struct redirtab *redirlist; 1744 static int nullredirs; 1745 static int preverrout_fd; /* save fd2 before print debug if xflag is set. */ 1746 1747 #define VTABSIZE 39 1748 1749 static struct var *vartab[VTABSIZE]; 1750 1751 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) 1752 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) 1753 1754 /* 1755 * Return of a legal variable name (a letter or underscore followed by zero or 1756 * more letters, underscores, and digits). 1757 */ 1758 static char * 1759 endofname(const char *name) 1760 { 1761 char *p; 1762 1763 p = (char *) name; 1764 if (!is_name(*p)) 1765 return p; 1766 while (*++p) { 1767 if (!is_in_name(*p)) 1768 break; 1769 } 1770 return p; 1771 } 1772 1773 /* 1774 * Compares two strings up to the first = or '\0'. The first 1775 * string must be terminated by '='; the second may be terminated by 1776 * either '=' or '\0'. 1777 */ 1778 static int 1779 varcmp(const char *p, const char *q) 1780 { 1781 int c, d; 1782 1783 while ((c = *p) == (d = *q)) { 1784 if (!c || c == '=') 1785 goto out; 1786 p++; 1787 q++; 1788 } 1789 if (c == '=') 1790 c = '\0'; 1791 if (d == '=') 1792 d = '\0'; 1793 out: 1794 return c - d; 1795 } 1796 1797 static int 1798 varequal(const char *a, const char *b) 1799 { 1800 return !varcmp(a, b); 1801 } 1802 1803 /* 1804 * Find the appropriate entry in the hash table from the name. 1805 */ 1806 static struct var ** 1807 hashvar(const char *p) 1808 { 1809 unsigned hashval; 1810 1811 hashval = ((unsigned char) *p) << 4; 1812 while (*p && *p != '=') 1813 hashval += (unsigned char) *p++; 1814 return &vartab[hashval % VTABSIZE]; 1815 } 1816 1817 static int 1818 vpcmp(const void *a, const void *b) 1819 { 1820 return varcmp(*(const char **)a, *(const char **)b); 1821 } 1822 1823 /* 1824 * This routine initializes the builtin variables. 1825 */ 1826 static void 1827 initvar(void) 1828 { 1829 struct var *vp; 1830 struct var *end; 1831 struct var **vpp; 1832 1833 /* 1834 * PS1 depends on uid 1835 */ 1836 #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT 1837 vps1.text = "PS1=\\w \\$ "; 1838 #else 1839 if (!geteuid()) 1840 vps1.text = "PS1=# "; 1841 #endif 1842 vp = varinit; 1843 end = vp + ARRAY_SIZE(varinit); 1844 do { 1845 vpp = hashvar(vp->text); 1846 vp->next = *vpp; 1847 *vpp = vp; 1848 } while (++vp < end); 1849 } 1850 1851 static struct var ** 1852 findvar(struct var **vpp, const char *name) 1853 { 1854 for (; *vpp; vpp = &(*vpp)->next) { 1855 if (varequal((*vpp)->text, name)) { 1856 break; 1857 } 1858 } 1859 return vpp; 1860 } 1861 1862 /* 1863 * Find the value of a variable. Returns NULL if not set. 1864 */ 1865 static char * 1866 lookupvar(const char *name) 1867 { 1868 struct var *v; 1869 1870 v = *findvar(hashvar(name), name); 1871 if (v) { 1872 #ifdef DYNAMIC_VAR 1873 /* 1874 * Dynamic variables are implemented roughly the same way they are 1875 * in bash. Namely, they're "special" so long as they aren't unset. 1876 * As soon as they're unset, they're no longer dynamic, and dynamic 1877 * lookup will no longer happen at that point. -- PFM. 1878 */ 1879 if ((v->flags & VDYNAMIC)) 1880 (*v->func)(NULL); 1881 #endif 1882 if (!(v->flags & VUNSET)) 1883 return strchrnul(v->text, '=') + 1; 1884 } 1885 return NULL; 1886 } 1887 1888 /* 1889 * Search the environment of a builtin command. 1890 */ 1891 static char * 1892 bltinlookup(const char *name) 1893 { 1894 struct strlist *sp; 1895 1896 for (sp = cmdenviron; sp; sp = sp->next) { 1897 if (varequal(sp->text, name)) 1898 return strchrnul(sp->text, '=') + 1; 1899 } 1900 return lookupvar(name); 1901 } 1902 1903 /* 1904 * Same as setvar except that the variable and value are passed in 1905 * the first argument as name=value. Since the first argument will 1906 * be actually stored in the table, it should not be a string that 1907 * will go away. 1908 * Called with interrupts off. 1909 */ 1910 static void 1911 setvareq(char *s, int flags) 1912 { 1913 struct var *vp, **vpp; 1914 1915 vpp = hashvar(s); 1916 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); 1917 vp = *findvar(vpp, s); 1918 if (vp) { 1919 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) { 1920 const char *n; 1921 1922 if (flags & VNOSAVE) 1923 free(s); 1924 n = vp->text; 1925 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n); 1926 } 1927 1928 if (flags & VNOSET) 1929 return; 1930 1931 if (vp->func && (flags & VNOFUNC) == 0) 1932 (*vp->func)(strchrnul(s, '=') + 1); 1933 1934 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) 1935 free((char*)vp->text); 1936 1937 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET); 1938 } else { 1939 if (flags & VNOSET) 1940 return; 1941 /* not found */ 1942 vp = ckmalloc(sizeof(*vp)); 1943 vp->next = *vpp; 1944 vp->func = NULL; 1945 *vpp = vp; 1946 } 1947 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE))) 1948 s = ckstrdup(s); 1949 vp->text = s; 1950 vp->flags = flags; 1951 } 1952 1953 /* 1954 * Set the value of a variable. The flags argument is ored with the 1955 * flags of the variable. If val is NULL, the variable is unset. 1956 */ 1957 static void 1958 setvar(const char *name, const char *val, int flags) 1959 { 1960 char *p, *q; 1961 size_t namelen; 1962 char *nameeq; 1963 size_t vallen; 1964 1965 q = endofname(name); 1966 p = strchrnul(q, '='); 1967 namelen = p - name; 1968 if (!namelen || p != q) 1969 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name); 1970 vallen = 0; 1971 if (val == NULL) { 1972 flags |= VUNSET; 1973 } else { 1974 vallen = strlen(val); 1975 } 1976 INT_OFF; 1977 nameeq = ckmalloc(namelen + vallen + 2); 1978 p = memcpy(nameeq, name, namelen) + namelen; 1979 if (val) { 1980 *p++ = '='; 1981 p = memcpy(p, val, vallen) + vallen; 1982 } 1983 *p = '\0'; 1984 setvareq(nameeq, flags | VNOSAVE); 1985 INT_ON; 1986 } 1987 1988 #if ENABLE_ASH_GETOPTS 1989 /* 1990 * Safe version of setvar, returns 1 on success 0 on failure. 1991 */ 1992 static int 1993 setvarsafe(const char *name, const char *val, int flags) 1994 { 1995 int err; 1996 volatile int saveint; 1997 struct jmploc *volatile savehandler = exception_handler; 1998 struct jmploc jmploc; 1999 2000 SAVE_INT(saveint); 2001 if (setjmp(jmploc.loc)) 2002 err = 1; 2003 else { 2004 exception_handler = &jmploc; 2005 setvar(name, val, flags); 2006 err = 0; 2007 } 2008 exception_handler = savehandler; 2009 RESTORE_INT(saveint); 2010 return err; 2011 } 2012 #endif 2013 2014 /* 2015 * Unset the specified variable. 2016 */ 2017 static int 2018 unsetvar(const char *s) 2019 { 2020 struct var **vpp; 2021 struct var *vp; 2022 int retval; 2023 2024 vpp = findvar(hashvar(s), s); 2025 vp = *vpp; 2026 retval = 2; 2027 if (vp) { 2028 int flags = vp->flags; 2029 2030 retval = 1; 2031 if (flags & VREADONLY) 2032 goto out; 2033 #ifdef DYNAMIC_VAR 2034 vp->flags &= ~VDYNAMIC; 2035 #endif 2036 if (flags & VUNSET) 2037 goto ok; 2038 if ((flags & VSTRFIXED) == 0) { 2039 INT_OFF; 2040 if ((flags & (VTEXTFIXED|VSTACK)) == 0) 2041 free((char*)vp->text); 2042 *vpp = vp->next; 2043 free(vp); 2044 INT_ON; 2045 } else { 2046 setvar(s, 0, 0); 2047 vp->flags &= ~VEXPORT; 2048 } 2049 ok: 2050 retval = 0; 2051 } 2052 out: 2053 return retval; 2054 } 2055 2056 /* 2057 * Process a linked list of variable assignments. 2058 */ 2059 static void 2060 listsetvar(struct strlist *list_set_var, int flags) 2061 { 2062 struct strlist *lp = list_set_var; 2063 2064 if (!lp) 2065 return; 2066 INT_OFF; 2067 do { 2068 setvareq(lp->text, flags); 2069 lp = lp->next; 2070 } while (lp); 2071 INT_ON; 2072 } 2073 2074 /* 2075 * Generate a list of variables satisfying the given conditions. 2076 */ 2077 static char ** 2078 listvars(int on, int off, char ***end) 2079 { 2080 struct var **vpp; 2081 struct var *vp; 2082 char **ep; 2083 int mask; 2084 2085 STARTSTACKSTR(ep); 2086 vpp = vartab; 2087 mask = on | off; 2088 do { 2089 for (vp = *vpp; vp; vp = vp->next) { 2090 if ((vp->flags & mask) == on) { 2091 if (ep == stackstrend()) 2092 ep = growstackstr(); 2093 *ep++ = (char *) vp->text; 2094 } 2095 } 2096 } while (++vpp < vartab + VTABSIZE); 2097 if (ep == stackstrend()) 2098 ep = growstackstr(); 2099 if (end) 2100 *end = ep; 2101 *ep++ = NULL; 2102 return grabstackstr(ep); 2103 } 2104 2105 2106 /* ============ Path search helper 2107 * 2108 * The variable path (passed by reference) should be set to the start 2109 * of the path before the first call; padvance will update 2110 * this value as it proceeds. Successive calls to padvance will return 2111 * the possible path expansions in sequence. If an option (indicated by 2112 * a percent sign) appears in the path entry then the global variable 2113 * pathopt will be set to point to it; otherwise pathopt will be set to 2114 * NULL. 2115 */ 2116 static const char *pathopt; /* set by padvance */ 2117 2118 static char * 2119 padvance(const char **path, const char *name) 2120 { 2121 const char *p; 2122 char *q; 2123 const char *start; 2124 size_t len; 2125 2126 if (*path == NULL) 2127 return NULL; 2128 start = *path; 2129 for (p = start; *p && *p != ':' && *p != '%'; p++); 2130 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 2131 while (stackblocksize() < len) 2132 growstackblock(); 2133 q = stackblock(); 2134 if (p != start) { 2135 memcpy(q, start, p - start); 2136 q += p - start; 2137 *q++ = '/'; 2138 } 2139 strcpy(q, name); 2140 pathopt = NULL; 2141 if (*p == '%') { 2142 pathopt = ++p; 2143 while (*p && *p != ':') p++; 2144 } 2145 if (*p == ':') 2146 *path = p + 1; 2147 else 2148 *path = NULL; 2149 return stalloc(len); 2150 } 2151 2152 2153 /* ============ Prompt */ 2154 560 2155 static int doprompt; /* if set, prompt the user */ 561 2156 static int needprompt; /* true if interactive and at start of line */ 562 static int lasttoken; /* last token read */ 563 static char *wordtext; /* text of last word returned by readtoken */ 564 static int checkkwd; 565 static struct nodelist *backquotelist; 566 static union node *redirnode; 567 static struct heredoc *heredoc; 568 static int quoteflag; /* set if (part of) last token was quoted */ 569 static int startlinno; /* line # where last token started */ 570 571 static union node *parsecmd(int); 572 static void fixredir(union node *, const char *, int); 573 static const char *const *findkwd(const char *); 574 static char *endofname(const char *); 575 576 /* shell.h */ 577 578 typedef void *pointer; 579 580 static char nullstr[1]; /* zero length string */ 581 static const char spcstr[] = " "; 582 static const char snlfmt[] = "%s\n"; 583 static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' }; 584 static const char illnum[] = "Illegal number: %s"; 585 static const char homestr[] = "HOME"; 586 587 #ifdef DEBUG 588 #define TRACE(param) trace param 589 #define TRACEV(param) tracev param 2157 2158 #if ENABLE_FEATURE_EDITING 2159 static line_input_t *line_input_state; 2160 static const char *cmdedit_prompt; 2161 static void 2162 putprompt(const char *s) 2163 { 2164 if (ENABLE_ASH_EXPAND_PRMT) { 2165 free((char*)cmdedit_prompt); 2166 cmdedit_prompt = ckstrdup(s); 2167 return; 2168 } 2169 cmdedit_prompt = s; 2170 } 590 2171 #else 591 #define TRACE(param) 592 #define TRACEV(param) 593 #endif 594 595 #if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96) 596 #define __builtin_expect(x, expected_value) (x) 597 #endif 598 599 #define xlikely(x) __builtin_expect((x),1) 600 601 602 #define TEOF 0 603 #define TNL 1 604 #define TREDIR 2 605 #define TWORD 3 606 #define TSEMI 4 607 #define TBACKGND 5 608 #define TAND 6 609 #define TOR 7 610 #define TPIPE 8 611 #define TLP 9 612 #define TRP 10 613 #define TENDCASE 11 614 #define TENDBQUOTE 12 615 #define TNOT 13 616 #define TCASE 14 617 #define TDO 15 618 #define TDONE 16 619 #define TELIF 17 620 #define TELSE 18 621 #define TESAC 19 622 #define TFI 20 623 #define TFOR 21 624 #define TIF 22 625 #define TIN 23 626 #define TTHEN 24 627 #define TUNTIL 25 628 #define TWHILE 26 629 #define TBEGIN 27 630 #define TEND 28 631 632 /* first char is indicating which tokens mark the end of a list */ 633 static const char *const tokname_array[] = { 634 "\1end of file", 635 "\0newline", 636 "\0redirection", 637 "\0word", 638 "\0;", 639 "\0&", 640 "\0&&", 641 "\0||", 642 "\0|", 643 "\0(", 644 "\1)", 645 "\1;;", 646 "\1`", 647 #define KWDOFFSET 13 648 /* the following are keywords */ 649 "\0!", 650 "\0case", 651 "\1do", 652 "\1done", 653 "\1elif", 654 "\1else", 655 "\1esac", 656 "\1fi", 657 "\0for", 658 "\0if", 659 "\0in", 660 "\1then", 661 "\0until", 662 "\0while", 663 "\0{", 664 "\1}", 665 }; 666 667 static const char *tokname(int tok) 668 { 669 static char buf[16]; 670 671 if (tok >= TSEMI) 672 buf[0] = '"'; 673 sprintf(buf + (tok >= TSEMI), "%s%c", 674 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0)); 675 return buf; 676 } 677 678 /* machdep.h */ 679 680 /* 681 * Most machines require the value returned from malloc to be aligned 682 * in some way. The following macro will get this right on many machines. 683 */ 684 685 #define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1) 686 /* 687 * It appears that grabstackstr() will barf with such alignments 688 * because stalloc() will return a string allocated in a new stackblock. 689 */ 690 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE) 691 692 /* 693 * This file was generated by the mksyntax program. 694 */ 695 2172 static void 2173 putprompt(const char *s) 2174 { 2175 out2str(s); 2176 } 2177 #endif 2178 2179 #if ENABLE_ASH_EXPAND_PRMT 2180 /* expandstr() needs parsing machinery, so it is far away ahead... */ 2181 static const char *expandstr(const char *ps); 2182 #else 2183 #define expandstr(s) s 2184 #endif 2185 2186 static void 2187 setprompt(int whichprompt) 2188 { 2189 const char *prompt; 2190 #if ENABLE_ASH_EXPAND_PRMT 2191 struct stackmark smark; 2192 #endif 2193 2194 needprompt = 0; 2195 2196 switch (whichprompt) { 2197 case 1: 2198 prompt = ps1val(); 2199 break; 2200 case 2: 2201 prompt = ps2val(); 2202 break; 2203 default: /* 0 */ 2204 prompt = nullstr; 2205 } 2206 #if ENABLE_ASH_EXPAND_PRMT 2207 setstackmark(&smark); 2208 stalloc(stackblocksize()); 2209 #endif 2210 putprompt(expandstr(prompt)); 2211 #if ENABLE_ASH_EXPAND_PRMT 2212 popstackmark(&smark); 2213 #endif 2214 } 2215 2216 2217 /* ============ The cd and pwd commands */ 2218 2219 #define CD_PHYSICAL 1 2220 #define CD_PRINT 2 2221 2222 static int docd(const char *, int); 2223 2224 static char *curdir = nullstr; /* current working directory */ 2225 static char *physdir = nullstr; /* physical working directory */ 2226 2227 static int 2228 cdopt(void) 2229 { 2230 int flags = 0; 2231 int i, j; 2232 2233 j = 'L'; 2234 while ((i = nextopt("LP"))) { 2235 if (i != j) { 2236 flags ^= CD_PHYSICAL; 2237 j = i; 2238 } 2239 } 2240 2241 return flags; 2242 } 2243 2244 /* 2245 * Update curdir (the name of the current directory) in response to a 2246 * cd command. 2247 */ 2248 static const char * 2249 updatepwd(const char *dir) 2250 { 2251 char *new; 2252 char *p; 2253 char *cdcomppath; 2254 const char *lim; 2255 2256 cdcomppath = ststrdup(dir); 2257 STARTSTACKSTR(new); 2258 if (*dir != '/') { 2259 if (curdir == nullstr) 2260 return 0; 2261 new = stack_putstr(curdir, new); 2262 } 2263 new = makestrspace(strlen(dir) + 2, new); 2264 lim = stackblock() + 1; 2265 if (*dir != '/') { 2266 if (new[-1] != '/') 2267 USTPUTC('/', new); 2268 if (new > lim && *lim == '/') 2269 lim++; 2270 } else { 2271 USTPUTC('/', new); 2272 cdcomppath++; 2273 if (dir[1] == '/' && dir[2] != '/') { 2274 USTPUTC('/', new); 2275 cdcomppath++; 2276 lim++; 2277 } 2278 } 2279 p = strtok(cdcomppath, "/"); 2280 while (p) { 2281 switch (*p) { 2282 case '.': 2283 if (p[1] == '.' && p[2] == '\0') { 2284 while (new > lim) { 2285 STUNPUTC(new); 2286 if (new[-1] == '/') 2287 break; 2288 } 2289 break; 2290 } 2291 if (p[1] == '\0') 2292 break; 2293 /* fall through */ 2294 default: 2295 new = stack_putstr(p, new); 2296 USTPUTC('/', new); 2297 } 2298 p = strtok(0, "/"); 2299 } 2300 if (new > lim) 2301 STUNPUTC(new); 2302 *new = 0; 2303 return stackblock(); 2304 } 2305 2306 /* 2307 * Find out what the current directory is. If we already know the current 2308 * directory, this routine returns immediately. 2309 */ 2310 static char * 2311 getpwd(void) 2312 { 2313 char *dir = getcwd(0, 0); 2314 return dir ? dir : nullstr; 2315 } 2316 2317 static void 2318 setpwd(const char *val, int setold) 2319 { 2320 char *oldcur, *dir; 2321 2322 oldcur = dir = curdir; 2323 2324 if (setold) { 2325 setvar("OLDPWD", oldcur, VEXPORT); 2326 } 2327 INT_OFF; 2328 if (physdir != nullstr) { 2329 if (physdir != oldcur) 2330 free(physdir); 2331 physdir = nullstr; 2332 } 2333 if (oldcur == val || !val) { 2334 char *s = getpwd(); 2335 physdir = s; 2336 if (!val) 2337 dir = s; 2338 } else 2339 dir = ckstrdup(val); 2340 if (oldcur != dir && oldcur != nullstr) { 2341 free(oldcur); 2342 } 2343 curdir = dir; 2344 INT_ON; 2345 setvar("PWD", dir, VEXPORT); 2346 } 2347 2348 static void hashcd(void); 2349 2350 /* 2351 * Actually do the chdir. We also call hashcd to let the routines in exec.c 2352 * know that the current directory has changed. 2353 */ 2354 static int 2355 docd(const char *dest, int flags) 2356 { 2357 const char *dir = 0; 2358 int err; 2359 2360 TRACE(("docd(\"%s\", %d) called\n", dest, flags)); 2361 2362 INT_OFF; 2363 if (!(flags & CD_PHYSICAL)) { 2364 dir = updatepwd(dest); 2365 if (dir) 2366 dest = dir; 2367 } 2368 err = chdir(dest); 2369 if (err) 2370 goto out; 2371 setpwd(dir, 1); 2372 hashcd(); 2373 out: 2374 INT_ON; 2375 return err; 2376 } 2377 2378 static int 2379 cdcmd(int argc, char **argv) 2380 { 2381 const char *dest; 2382 const char *path; 2383 const char *p; 2384 char c; 2385 struct stat statb; 2386 int flags; 2387 2388 flags = cdopt(); 2389 dest = *argptr; 2390 if (!dest) 2391 dest = bltinlookup(homestr); 2392 else if (LONE_DASH(dest)) { 2393 dest = bltinlookup("OLDPWD"); 2394 flags |= CD_PRINT; 2395 } 2396 if (!dest) 2397 dest = nullstr; 2398 if (*dest == '/') 2399 goto step7; 2400 if (*dest == '.') { 2401 c = dest[1]; 2402 dotdot: 2403 switch (c) { 2404 case '\0': 2405 case '/': 2406 goto step6; 2407 case '.': 2408 c = dest[2]; 2409 if (c != '.') 2410 goto dotdot; 2411 } 2412 } 2413 if (!*dest) 2414 dest = "."; 2415 path = bltinlookup("CDPATH"); 2416 if (!path) { 2417 step6: 2418 step7: 2419 p = dest; 2420 goto docd; 2421 } 2422 do { 2423 c = *path; 2424 p = padvance(&path, dest); 2425 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { 2426 if (c && c != ':') 2427 flags |= CD_PRINT; 2428 docd: 2429 if (!docd(p, flags)) 2430 goto out; 2431 break; 2432 } 2433 } while (path); 2434 ash_msg_and_raise_error("can't cd to %s", dest); 2435 /* NOTREACHED */ 2436 out: 2437 if (flags & CD_PRINT) 2438 out1fmt(snlfmt, curdir); 2439 return 0; 2440 } 2441 2442 static int 2443 pwdcmd(int argc, char **argv) 2444 { 2445 int flags; 2446 const char *dir = curdir; 2447 2448 flags = cdopt(); 2449 if (flags) { 2450 if (physdir == nullstr) 2451 setpwd(dir, 0); 2452 dir = physdir; 2453 } 2454 out1fmt(snlfmt, dir); 2455 return 0; 2456 } 2457 2458 2459 /* ============ ... */ 2460 2461 #define IBUFSIZ (BUFSIZ + 1) 2462 #define basebuf bb_common_bufsiz1 /* buffer for top level input file */ 696 2463 697 2464 /* Syntax classes */ … … 712 2479 #define CIGN 14 /* character should be ignored */ 713 2480 714 #if def CONFIG_ASH_ALIAS2481 #if ENABLE_ASH_ALIAS 715 2482 #define SYNBASE 130 716 2483 #define PEOF -130 … … 723 2490 #endif 724 2491 725 #define is_digit(c) ((unsigned)((c) - '0') <= 9) 726 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) 727 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) 728 729 /* C99 say: "char" declaration may be signed or unsigned default */ 730 #define SC2INT(chr2may_be_negative_int) (int)((signed char)chr2may_be_negative_int) 731 732 /* 733 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise 734 * (assuming ascii char codes, as the original implementation did) 735 */ 736 #define is_special(c) \ 737 ( (((unsigned int)c) - 33 < 32) \ 738 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1)) 739 740 #define digit_val(c) ((c) - '0') 741 742 /* 743 * This file was generated by the mksyntax program. 744 */ 745 746 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE 2492 /* number syntax index */ 2493 #define BASESYNTAX 0 /* not in quotes */ 2494 #define DQSYNTAX 1 /* in double quotes */ 2495 #define SQSYNTAX 2 /* in single quotes */ 2496 #define ARISYNTAX 3 /* in arithmetic */ 2497 2498 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE 747 2499 #define USE_SIT_FUNCTION 748 2500 #endif 749 2501 750 /* number syntax index */ 751 #define BASESYNTAX 0 /* not in quotes */ 752 #define DQSYNTAX 1 /* in double quotes */ 753 #define SQSYNTAX 2 /* in single quotes */ 754 #define ARISYNTAX 3 /* in arithmetic */ 755 756 #ifdef CONFIG_ASH_MATH_SUPPORT 2502 #if ENABLE_ASH_MATH_SUPPORT 757 2503 static const char S_I_T[][4] = { 758 #if def CONFIG_ASH_ALIAS759 { CSPCL, CIGN, CIGN, CIGN},/* 0, PEOA */760 #endif 761 { CSPCL, CWORD, CWORD, CWORD},/* 1, ' ' */762 { CNL, CNL, CNL, CNL},/* 2, \n */763 { CWORD, CCTL, CCTL, CWORD},/* 3, !*-/:=?[]~ */764 { CDQUOTE, CENDQUOTE, CWORD, CWORD},/* 4, '"' */765 { CVAR, CVAR, CWORD, CVAR},/* 5, $ */766 { CSQUOTE, CWORD, CENDQUOTE, CWORD},/* 6, "'" */767 { CSPCL, CWORD, CWORD, CLP},/* 7, ( */768 { CSPCL, CWORD, CWORD, CRP},/* 8, ) */769 { CBACK, CBACK, CCTL, CBACK},/* 9, \ */770 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE},/* 10, ` */771 { CENDVAR, CENDVAR, CWORD, CENDVAR},/* 11, } */2504 #if ENABLE_ASH_ALIAS 2505 { CSPCL, CIGN, CIGN, CIGN }, /* 0, PEOA */ 2506 #endif 2507 { CSPCL, CWORD, CWORD, CWORD }, /* 1, ' ' */ 2508 { CNL, CNL, CNL, CNL }, /* 2, \n */ 2509 { CWORD, CCTL, CCTL, CWORD }, /* 3, !*-/:=?[]~ */ 2510 { CDQUOTE, CENDQUOTE, CWORD, CWORD }, /* 4, '"' */ 2511 { CVAR, CVAR, CWORD, CVAR }, /* 5, $ */ 2512 { CSQUOTE, CWORD, CENDQUOTE, CWORD }, /* 6, "'" */ 2513 { CSPCL, CWORD, CWORD, CLP }, /* 7, ( */ 2514 { CSPCL, CWORD, CWORD, CRP }, /* 8, ) */ 2515 { CBACK, CBACK, CCTL, CBACK }, /* 9, \ */ 2516 { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* 10, ` */ 2517 { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* 11, } */ 772 2518 #ifndef USE_SIT_FUNCTION 773 { CENDFILE, CENDFILE, CENDFILE, CENDFILE},/* 12, PEOF */774 { CWORD, CWORD, CWORD, CWORD},/* 13, 0-9A-Za-z */775 { CCTL, CCTL, CCTL, CCTL}/* 14, CTLESC ... */2519 { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */ 2520 { CWORD, CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */ 2521 { CCTL, CCTL, CCTL, CCTL } /* 14, CTLESC ... */ 776 2522 #endif 777 2523 }; 778 2524 #else 779 2525 static const char S_I_T[][3] = { 780 #if def CONFIG_ASH_ALIAS781 { CSPCL, CIGN, CIGN},/* 0, PEOA */782 #endif 783 { CSPCL, CWORD, CWORD},/* 1, ' ' */784 { CNL, CNL, CNL},/* 2, \n */785 { CWORD, CCTL, CCTL},/* 3, !*-/:=?[]~ */786 { CDQUOTE, CENDQUOTE, CWORD},/* 4, '"' */787 { CVAR, CVAR, CWORD},/* 5, $ */788 { CSQUOTE, CWORD, CENDQUOTE},/* 6, "'" */789 { CSPCL, CWORD, CWORD},/* 7, ( */790 { CSPCL, CWORD, CWORD},/* 8, ) */791 { CBACK, CBACK, CCTL},/* 9, \ */792 { CBQUOTE, CBQUOTE, CWORD},/* 10, ` */793 { CENDVAR, CENDVAR, CWORD},/* 11, } */2526 #if ENABLE_ASH_ALIAS 2527 { CSPCL, CIGN, CIGN }, /* 0, PEOA */ 2528 #endif 2529 { CSPCL, CWORD, CWORD }, /* 1, ' ' */ 2530 { CNL, CNL, CNL }, /* 2, \n */ 2531 { CWORD, CCTL, CCTL }, /* 3, !*-/:=?[]~ */ 2532 { CDQUOTE, CENDQUOTE, CWORD }, /* 4, '"' */ 2533 { CVAR, CVAR, CWORD }, /* 5, $ */ 2534 { CSQUOTE, CWORD, CENDQUOTE }, /* 6, "'" */ 2535 { CSPCL, CWORD, CWORD }, /* 7, ( */ 2536 { CSPCL, CWORD, CWORD }, /* 8, ) */ 2537 { CBACK, CBACK, CCTL }, /* 9, \ */ 2538 { CBQUOTE, CBQUOTE, CWORD }, /* 10, ` */ 2539 { CENDVAR, CENDVAR, CWORD }, /* 11, } */ 794 2540 #ifndef USE_SIT_FUNCTION 795 { CENDFILE, CENDFILE, CENDFILE},/* 12, PEOF */796 { CWORD, CWORD, CWORD},/* 13, 0-9A-Za-z */797 { CCTL, CCTL, CCTL}/* 14, CTLESC ... */2541 { CENDFILE, CENDFILE, CENDFILE }, /* 12, PEOF */ 2542 { CWORD, CWORD, CWORD }, /* 13, 0-9A-Za-z */ 2543 { CCTL, CCTL, CCTL } /* 14, CTLESC ... */ 798 2544 #endif 799 2545 }; 800 #endif /* CONFIG_ASH_MATH_SUPPORT */2546 #endif /* ASH_MATH_SUPPORT */ 801 2547 802 2548 #ifdef USE_SIT_FUNCTION 803 2549 804 #define U_C(c) ((unsigned char)(c)) 805 806 static int SIT(int c, int syntax) 807 { 808 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~"; 809 #ifdef CONFIG_ASH_ALIAS 810 static const char syntax_index_table[] = { 2550 static int 2551 SIT(int c, int syntax) 2552 { 2553 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~"; 2554 #if ENABLE_ASH_ALIAS 2555 static const char syntax_index_table[] ALIGN1 = { 811 2556 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */ 812 2557 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */ … … 815 2560 }; 816 2561 #else 817 static const char syntax_index_table[] = {2562 static const char syntax_index_table[] ALIGN1 = { 818 2563 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */ 819 2564 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */ … … 827 2572 if (c == PEOF) /* 2^8+2 */ 828 2573 return CENDFILE; 829 #if def CONFIG_ASH_ALIAS2574 #if ENABLE_ASH_ALIAS 830 2575 if (c == PEOA) /* 2^8+1 */ 831 2576 indx = 0; 832 2577 else 833 2578 #endif 834 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK)) 835 return CCTL; 836 else { 2579 #define U_C(c) ((unsigned char)(c)) 2580 2581 if ((unsigned char)c >= (unsigned char)(CTLESC) 2582 && (unsigned char)c <= (unsigned char)(CTLQUOTEMARK) 2583 ) { 2584 return CCTL; 2585 } else { 837 2586 s = strchr(spec_symbls, c); 838 if (s == 0 || *s == 0)2587 if (s == NULL || *s == '\0') 839 2588 return CWORD; 840 2589 indx = syntax_index_table[(s - spec_symbls)]; … … 843 2592 } 844 2593 845 #else /* USE_SIT_FUNCTION */ 846 847 #define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax] 848 849 #ifdef CONFIG_ASH_ALIAS 850 #define CSPCL_CIGN_CIGN_CIGN 0 851 #define CSPCL_CWORD_CWORD_CWORD 1 852 #define CNL_CNL_CNL_CNL 2 853 #define CWORD_CCTL_CCTL_CWORD 3 854 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4 855 #define CVAR_CVAR_CWORD_CVAR 5 856 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6 857 #define CSPCL_CWORD_CWORD_CLP 7 858 #define CSPCL_CWORD_CWORD_CRP 8 859 #define CBACK_CBACK_CCTL_CBACK 9 860 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10 861 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11 862 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12 863 #define CWORD_CWORD_CWORD_CWORD 13 864 #define CCTL_CCTL_CCTL_CCTL 14 2594 #else /* !USE_SIT_FUNCTION */ 2595 2596 #if ENABLE_ASH_ALIAS 2597 #define CSPCL_CIGN_CIGN_CIGN 0 2598 #define CSPCL_CWORD_CWORD_CWORD 1 2599 #define CNL_CNL_CNL_CNL 2 2600 #define CWORD_CCTL_CCTL_CWORD 3 2601 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4 2602 #define CVAR_CVAR_CWORD_CVAR 5 2603 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6 2604 #define CSPCL_CWORD_CWORD_CLP 7 2605 #define CSPCL_CWORD_CWORD_CRP 8 2606 #define CBACK_CBACK_CCTL_CBACK 9 2607 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10 2608 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11 2609 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12 2610 #define CWORD_CWORD_CWORD_CWORD 13 2611 #define CCTL_CCTL_CCTL_CCTL 14 865 2612 #else 866 #define CSPCL_CWORD_CWORD_CWORD 867 #define CNL_CNL_CNL_CNL 868 #define CWORD_CCTL_CCTL_CWORD 869 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 870 #define CVAR_CVAR_CWORD_CVAR 871 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 872 #define CSPCL_CWORD_CWORD_CLP 873 #define CSPCL_CWORD_CWORD_CRP 874 #define CBACK_CBACK_CCTL_CBACK 875 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 876 #define CENDVAR_CENDVAR_CWORD_CENDVAR 877 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 878 #define CWORD_CWORD_CWORD_CWORD 879 #define CCTL_CCTL_CCTL_CCTL 2613 #define CSPCL_CWORD_CWORD_CWORD 0 2614 #define CNL_CNL_CNL_CNL 1 2615 #define CWORD_CCTL_CCTL_CWORD 2 2616 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3 2617 #define CVAR_CVAR_CWORD_CVAR 4 2618 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5 2619 #define CSPCL_CWORD_CWORD_CLP 6 2620 #define CSPCL_CWORD_CWORD_CRP 7 2621 #define CBACK_CBACK_CCTL_CBACK 8 2622 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9 2623 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10 2624 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11 2625 #define CWORD_CWORD_CWORD_CWORD 12 2626 #define CCTL_CCTL_CCTL_CCTL 13 880 2627 #endif 881 2628 … … 883 2630 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */ 884 2631 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE, 885 #if def CONFIG_ASH_ALIAS2632 #if ENABLE_ASH_ALIAS 886 2633 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN, 887 2634 #endif … … 1144 2891 }; 1145 2892 2893 #define SIT(c, syntax) (S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]) 2894 1146 2895 #endif /* USE_SIT_FUNCTION */ 1147 2896 1148 /* alias.c */ 1149 2897 2898 /* ============ Alias handling */ 2899 2900 #if ENABLE_ASH_ALIAS 2901 2902 #define ALIASINUSE 1 2903 #define ALIASDEAD 2 1150 2904 1151 2905 #define ATABSIZE 39 1152 2906 1153 static int funcblocksize; /* size of structures in function */ 1154 static int funcstringsize; /* size of strings in node */ 1155 static pointer funcblock; /* block to allocate function from */ 1156 static char *funcstring; /* block to allocate strings from */ 1157 1158 static const short nodesize[26] = { 1159 SHELL_ALIGN(sizeof (struct ncmd)), 1160 SHELL_ALIGN(sizeof (struct npipe)), 1161 SHELL_ALIGN(sizeof (struct nredir)), 1162 SHELL_ALIGN(sizeof (struct nredir)), 1163 SHELL_ALIGN(sizeof (struct nredir)), 1164 SHELL_ALIGN(sizeof (struct nbinary)), 1165 SHELL_ALIGN(sizeof (struct nbinary)), 1166 SHELL_ALIGN(sizeof (struct nbinary)), 1167 SHELL_ALIGN(sizeof (struct nif)), 1168 SHELL_ALIGN(sizeof (struct nbinary)), 1169 SHELL_ALIGN(sizeof (struct nbinary)), 1170 SHELL_ALIGN(sizeof (struct nfor)), 1171 SHELL_ALIGN(sizeof (struct ncase)), 1172 SHELL_ALIGN(sizeof (struct nclist)), 1173 SHELL_ALIGN(sizeof (struct narg)), 1174 SHELL_ALIGN(sizeof (struct narg)), 1175 SHELL_ALIGN(sizeof (struct nfile)), 1176 SHELL_ALIGN(sizeof (struct nfile)), 1177 SHELL_ALIGN(sizeof (struct nfile)), 1178 SHELL_ALIGN(sizeof (struct nfile)), 1179 SHELL_ALIGN(sizeof (struct nfile)), 1180 SHELL_ALIGN(sizeof (struct ndup)), 1181 SHELL_ALIGN(sizeof (struct ndup)), 1182 SHELL_ALIGN(sizeof (struct nhere)), 1183 SHELL_ALIGN(sizeof (struct nhere)), 1184 SHELL_ALIGN(sizeof (struct nnot)), 2907 struct alias { 2908 struct alias *next; 2909 char *name; 2910 char *val; 2911 int flag; 1185 2912 }; 1186 2913 1187 1188 static void calcsize(union node *); 1189 static void sizenodelist(struct nodelist *); 1190 static union node *copynode(union node *); 1191 static struct nodelist *copynodelist(struct nodelist *); 1192 static char *nodesavestr(char *); 1193 1194 1195 static int evalstring(char *, int mask); 1196 union node; /* BLETCH for ansi C */ 1197 static void evaltree(union node *, int); 1198 static void evalbackcmd(union node *, struct backcmd *); 1199 1200 static int evalskip; /* set if we are skipping commands */ 1201 static int skipcount; /* number of levels to skip */ 1202 static int funcnest; /* depth of function calls */ 1203 1204 /* reasons for skipping commands (see comment on breakcmd routine) */ 1205 #define SKIPBREAK (1 << 0) 1206 #define SKIPCONT (1 << 1) 1207 #define SKIPFUNC (1 << 2) 1208 #define SKIPFILE (1 << 3) 1209 #define SKIPEVAL (1 << 4) 1210 1211 /* 1212 * This file was generated by the mkbuiltins program. 1213 */ 1214 1215 #if JOBS 1216 static int bgcmd(int, char **); 1217 #endif 1218 static int breakcmd(int, char **); 1219 static int cdcmd(int, char **); 1220 #ifdef CONFIG_ASH_CMDCMD 1221 static int commandcmd(int, char **); 1222 #endif 1223 static int dotcmd(int, char **); 1224 static int evalcmd(int, char **); 1225 #ifdef CONFIG_ASH_BUILTIN_ECHO 1226 static int echocmd(int, char **); 1227 #endif 1228 #ifdef CONFIG_ASH_BUILTIN_TEST 1229 static int testcmd(int, char **); 1230 #endif 1231 static int execcmd(int, char **); 1232 static int exitcmd(int, char **); 1233 static int exportcmd(int, char **); 1234 static int falsecmd(int, char **); 1235 #if JOBS 1236 static int fgcmd(int, char **); 1237 #endif 1238 #ifdef CONFIG_ASH_GETOPTS 1239 static int getoptscmd(int, char **); 1240 #endif 1241 static int hashcmd(int, char **); 1242 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET 1243 static int helpcmd(int argc, char **argv); 1244 #endif 1245 #if JOBS 1246 static int jobscmd(int, char **); 1247 #endif 1248 #ifdef CONFIG_ASH_MATH_SUPPORT 1249 static int letcmd(int, char **); 1250 #endif 1251 static int localcmd(int, char **); 1252 static int pwdcmd(int, char **); 1253 static int readcmd(int, char **); 1254 static int returncmd(int, char **); 1255 static int setcmd(int, char **); 1256 static int shiftcmd(int, char **); 1257 static int timescmd(int, char **); 1258 static int trapcmd(int, char **); 1259 static int truecmd(int, char **); 1260 static int typecmd(int, char **); 1261 static int umaskcmd(int, char **); 1262 static int unsetcmd(int, char **); 1263 static int waitcmd(int, char **); 1264 static int ulimitcmd(int, char **); 1265 #if JOBS 1266 static int killcmd(int, char **); 1267 #endif 1268 1269 /* mail.h */ 1270 1271 #ifdef CONFIG_ASH_MAIL 1272 static void chkmail(void); 1273 static void changemail(const char *); 1274 #endif 1275 1276 /* exec.h */ 1277 1278 /* values of cmdtype */ 1279 #define CMDUNKNOWN -1 /* no entry in table for command */ 1280 #define CMDNORMAL 0 /* command is an executable program */ 1281 #define CMDFUNCTION 1 /* command is a shell function */ 1282 #define CMDBUILTIN 2 /* command is a shell builtin */ 1283 1284 struct builtincmd { 1285 const char *name; 1286 int (*builtin)(int, char **); 1287 /* unsigned flags; */ 1288 }; 1289 1290 1291 #define COMMANDCMD (builtincmd + 5 + \ 1292 2 * ENABLE_ASH_BUILTIN_TEST + \ 1293 ENABLE_ASH_ALIAS + \ 1294 ENABLE_ASH_JOB_CONTROL) 1295 #define EXECCMD (builtincmd + 7 + \ 1296 2 * ENABLE_ASH_BUILTIN_TEST + \ 1297 ENABLE_ASH_ALIAS + \ 1298 ENABLE_ASH_JOB_CONTROL + \ 1299 ENABLE_ASH_CMDCMD + \ 1300 ENABLE_ASH_BUILTIN_ECHO) 1301 1302 #define BUILTIN_NOSPEC "0" 1303 #define BUILTIN_SPECIAL "1" 1304 #define BUILTIN_REGULAR "2" 1305 #define BUILTIN_SPEC_REG "3" 1306 #define BUILTIN_ASSIGN "4" 1307 #define BUILTIN_SPEC_ASSG "5" 1308 #define BUILTIN_REG_ASSG "6" 1309 #define BUILTIN_SPEC_REG_ASSG "7" 1310 1311 #define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1) 1312 #define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2) 1313 #define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4) 1314 1315 /* make sure to keep these in proper order since it is searched via bsearch() */ 1316 static const struct builtincmd builtincmd[] = { 1317 { BUILTIN_SPEC_REG ".", dotcmd }, 1318 { BUILTIN_SPEC_REG ":", truecmd }, 1319 #ifdef CONFIG_ASH_BUILTIN_TEST 1320 { BUILTIN_REGULAR "[", testcmd }, 1321 { BUILTIN_REGULAR "[[", testcmd }, 1322 #endif 1323 #ifdef CONFIG_ASH_ALIAS 1324 { BUILTIN_REG_ASSG "alias", aliascmd }, 1325 #endif 1326 #if JOBS 1327 { BUILTIN_REGULAR "bg", bgcmd }, 1328 #endif 1329 { BUILTIN_SPEC_REG "break", breakcmd }, 1330 { BUILTIN_REGULAR "cd", cdcmd }, 1331 { BUILTIN_NOSPEC "chdir", cdcmd }, 1332 #ifdef CONFIG_ASH_CMDCMD 1333 { BUILTIN_REGULAR "command", commandcmd }, 1334 #endif 1335 { BUILTIN_SPEC_REG "continue", breakcmd }, 1336 #ifdef CONFIG_ASH_BUILTIN_ECHO 1337 { BUILTIN_REGULAR "echo", echocmd }, 1338 #endif 1339 { BUILTIN_SPEC_REG "eval", evalcmd }, 1340 { BUILTIN_SPEC_REG "exec", execcmd }, 1341 { BUILTIN_SPEC_REG "exit", exitcmd }, 1342 { BUILTIN_SPEC_REG_ASSG "export", exportcmd }, 1343 { BUILTIN_REGULAR "false", falsecmd }, 1344 #if JOBS 1345 { BUILTIN_REGULAR "fg", fgcmd }, 1346 #endif 1347 #ifdef CONFIG_ASH_GETOPTS 1348 { BUILTIN_REGULAR "getopts", getoptscmd }, 1349 #endif 1350 { BUILTIN_NOSPEC "hash", hashcmd }, 1351 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET 1352 { BUILTIN_NOSPEC "help", helpcmd }, 1353 #endif 1354 #if JOBS 1355 { BUILTIN_REGULAR "jobs", jobscmd }, 1356 { BUILTIN_REGULAR "kill", killcmd }, 1357 #endif 1358 #ifdef CONFIG_ASH_MATH_SUPPORT 1359 { BUILTIN_NOSPEC "let", letcmd }, 1360 #endif 1361 { BUILTIN_ASSIGN "local", localcmd }, 1362 { BUILTIN_NOSPEC "pwd", pwdcmd }, 1363 { BUILTIN_REGULAR "read", readcmd }, 1364 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd }, 1365 { BUILTIN_SPEC_REG "return", returncmd }, 1366 { BUILTIN_SPEC_REG "set", setcmd }, 1367 { BUILTIN_SPEC_REG "shift", shiftcmd }, 1368 { BUILTIN_SPEC_REG "source", dotcmd }, 1369 #ifdef CONFIG_ASH_BUILTIN_TEST 1370 { BUILTIN_REGULAR "test", testcmd }, 1371 #endif 1372 { BUILTIN_SPEC_REG "times", timescmd }, 1373 { BUILTIN_SPEC_REG "trap", trapcmd }, 1374 { BUILTIN_REGULAR "true", truecmd }, 1375 { BUILTIN_NOSPEC "type", typecmd }, 1376 { BUILTIN_NOSPEC "ulimit", ulimitcmd }, 1377 { BUILTIN_REGULAR "umask", umaskcmd }, 1378 #ifdef CONFIG_ASH_ALIAS 1379 { BUILTIN_REGULAR "unalias", unaliascmd }, 1380 #endif 1381 { BUILTIN_SPEC_REG "unset", unsetcmd }, 1382 { BUILTIN_REGULAR "wait", waitcmd }, 1383 }; 1384 1385 #define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) ) 1386 1387 1388 1389 struct cmdentry { 1390 int cmdtype; 1391 union param { 1392 int index; 1393 const struct builtincmd *cmd; 1394 struct funcnode *func; 1395 } u; 1396 }; 1397 1398 1399 /* action to find_command() */ 1400 #define DO_ERR 0x01 /* prints errors */ 1401 #define DO_ABS 0x02 /* checks absolute paths */ 1402 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */ 1403 #define DO_ALTPATH 0x08 /* using alternate path */ 1404 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */ 1405 1406 static const char *pathopt; /* set by padvance */ 1407 1408 static void shellexec(char **, const char *, int) 1409 ATTRIBUTE_NORETURN; 1410 static char *padvance(const char **, const char *); 1411 static void find_command(char *, struct cmdentry *, int, const char *); 1412 static struct builtincmd *find_builtin(const char *); 1413 static void hashcd(void); 1414 static void changepath(const char *); 1415 static void defun(char *, union node *); 1416 static void unsetfunc(const char *); 1417 1418 #ifdef CONFIG_ASH_MATH_SUPPORT_64 1419 typedef int64_t arith_t; 1420 #define arith_t_type (long long) 1421 #else 1422 typedef long arith_t; 1423 #define arith_t_type (long) 1424 #endif 1425 1426 #ifdef CONFIG_ASH_MATH_SUPPORT 1427 static arith_t dash_arith(const char *); 1428 static arith_t arith(const char *expr, int *perrcode); 1429 #endif 1430 1431 #ifdef CONFIG_ASH_RANDOM_SUPPORT 1432 static unsigned long rseed; 1433 static void change_random(const char *); 1434 # ifndef DYNAMIC_VAR 1435 # define DYNAMIC_VAR 1436 # endif 1437 #endif 1438 1439 /* init.h */ 1440 1441 static void reset(void); 1442 1443 /* var.h */ 1444 1445 /* 1446 * Shell variables. 1447 */ 1448 1449 /* flags */ 1450 #define VEXPORT 0x01 /* variable is exported */ 1451 #define VREADONLY 0x02 /* variable cannot be modified */ 1452 #define VSTRFIXED 0x04 /* variable struct is statically allocated */ 1453 #define VTEXTFIXED 0x08 /* text is statically allocated */ 1454 #define VSTACK 0x10 /* text is allocated on the stack */ 1455 #define VUNSET 0x20 /* the variable is not set */ 1456 #define VNOFUNC 0x40 /* don't call the callback function */ 1457 #define VNOSET 0x80 /* do not set variable - just readonly test */ 1458 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */ 1459 #ifdef DYNAMIC_VAR 1460 # define VDYNAMIC 0x200 /* dynamic variable */ 1461 # else 1462 # define VDYNAMIC 0 1463 #endif 1464 1465 struct var { 1466 struct var *next; /* next entry in hash list */ 1467 int flags; /* flags are defined above */ 1468 const char *text; /* name=value */ 1469 void (*func)(const char *); /* function to be called when */ 1470 /* the variable gets set/unset */ 1471 }; 1472 1473 struct localvar { 1474 struct localvar *next; /* next local variable in list */ 1475 struct var *vp; /* the variable that was made local */ 1476 int flags; /* saved flags */ 1477 const char *text; /* saved text */ 1478 }; 1479 1480 1481 static struct localvar *localvars; 1482 1483 /* 1484 * Shell variables. 1485 */ 1486 1487 #ifdef CONFIG_ASH_GETOPTS 1488 static void getoptsreset(const char *); 1489 #endif 1490 1491 #ifdef CONFIG_LOCALE_SUPPORT 1492 #include <locale.h> 1493 static void change_lc_all(const char *value); 1494 static void change_lc_ctype(const char *value); 1495 #endif 1496 1497 1498 #define VTABSIZE 39 1499 1500 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin"; 1501 #ifdef IFS_BROKEN 1502 static const char defifsvar[] = "IFS= \t\n"; 1503 #define defifs (defifsvar + 4) 1504 #else 1505 static const char defifs[] = " \t\n"; 1506 #endif 1507 1508 1509 static struct var varinit[] = { 1510 #ifdef IFS_BROKEN 1511 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 }, 1512 #else 1513 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 }, 1514 #endif 1515 1516 #ifdef CONFIG_ASH_MAIL 1517 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail }, 1518 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail }, 1519 #endif 1520 1521 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath }, 1522 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 }, 1523 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 }, 1524 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 }, 1525 #ifdef CONFIG_ASH_GETOPTS 1526 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset }, 1527 #endif 1528 #ifdef CONFIG_ASH_RANDOM_SUPPORT 1529 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random }, 1530 #endif 1531 #ifdef CONFIG_LOCALE_SUPPORT 1532 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all }, 1533 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype }, 1534 #endif 1535 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY 1536 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL }, 1537 #endif 1538 }; 1539 1540 #define vifs varinit[0] 1541 #ifdef CONFIG_ASH_MAIL 1542 #define vmail (&vifs)[1] 1543 #define vmpath (&vmail)[1] 1544 #else 1545 #define vmpath vifs 1546 #endif 1547 #define vpath (&vmpath)[1] 1548 #define vps1 (&vpath)[1] 1549 #define vps2 (&vps1)[1] 1550 #define vps4 (&vps2)[1] 1551 #define voptind (&vps4)[1] 1552 #ifdef CONFIG_ASH_GETOPTS 1553 #define vrandom (&voptind)[1] 1554 #else 1555 #define vrandom (&vps4)[1] 1556 #endif 1557 #define defpath (defpathvar + 5) 1558 1559 /* 1560 * The following macros access the values of the above variables. 1561 * They have to skip over the name. They return the null string 1562 * for unset variables. 1563 */ 1564 1565 #define ifsval() (vifs.text + 4) 1566 #define ifsset() ((vifs.flags & VUNSET) == 0) 1567 #define mailval() (vmail.text + 5) 1568 #define mpathval() (vmpath.text + 9) 1569 #define pathval() (vpath.text + 5) 1570 #define ps1val() (vps1.text + 4) 1571 #define ps2val() (vps2.text + 4) 1572 #define ps4val() (vps4.text + 4) 1573 #define optindval() (voptind.text + 7) 1574 1575 #define mpathset() ((vmpath.flags & VUNSET) == 0) 1576 1577 static void setvar(const char *, const char *, int); 1578 static void setvareq(char *, int); 1579 static void listsetvar(struct strlist *, int); 1580 static char *lookupvar(const char *); 1581 static char *bltinlookup(const char *); 1582 static char **listvars(int, int, char ***); 1583 #define environment() listvars(VEXPORT, VUNSET, 0) 1584 static int showvars(const char *, int, int); 1585 static void poplocalvars(void); 1586 static int unsetvar(const char *); 1587 #ifdef CONFIG_ASH_GETOPTS 1588 static int setvarsafe(const char *, const char *, int); 1589 #endif 1590 static int varcmp(const char *, const char *); 1591 static struct var **hashvar(const char *); 1592 1593 1594 static inline int varequal(const char *a, const char *b) { 1595 return !varcmp(a, b); 1596 } 1597 1598 1599 static int loopnest; /* current loop nesting level */ 1600 1601 /* 1602 * The parsefile structure pointed to by the global variable parsefile 1603 * contains information about the current file being read. 1604 */ 1605 1606 1607 struct redirtab { 1608 struct redirtab *next; 1609 int renamed[10]; 1610 int nullredirs; 1611 }; 1612 1613 static struct redirtab *redirlist; 1614 static int nullredirs; 1615 1616 extern char **environ; 1617 1618 /* output.h */ 1619 1620 1621 static void outstr(const char *, FILE *); 1622 static void outcslow(int, FILE *); 1623 static void flushall(void); 1624 static void flusherr(void); 1625 static int out1fmt(const char *, ...) 1626 __attribute__((__format__(__printf__,1,2))); 1627 static int fmtstr(char *, size_t, const char *, ...) 1628 __attribute__((__format__(__printf__,3,4))); 1629 1630 static int preverrout_fd; /* save fd2 before print debug if xflag is set. */ 1631 1632 1633 static void out1str(const char *p) 1634 { 1635 outstr(p, stdout); 1636 } 1637 1638 static void out2str(const char *p) 1639 { 1640 outstr(p, stderr); 1641 flusherr(); 1642 } 1643 1644 /* 1645 * Initialization code. 1646 */ 1647 1648 /* 1649 * This routine initializes the builtin variables. 1650 */ 1651 1652 static inline void 1653 initvar(void) 1654 { 1655 struct var *vp; 1656 struct var *end; 1657 struct var **vpp; 1658 1659 /* 1660 * PS1 depends on uid 1661 */ 1662 #if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT) 1663 vps1.text = "PS1=\\w \\$ "; 1664 #else 1665 if (!geteuid()) 1666 vps1.text = "PS1=# "; 1667 #endif 1668 vp = varinit; 1669 end = vp + sizeof(varinit) / sizeof(varinit[0]); 1670 do { 1671 vpp = hashvar(vp->text); 1672 vp->next = *vpp; 1673 *vpp = vp; 1674 } while (++vp < end); 1675 } 1676 1677 static inline void 1678 init(void) 1679 { 1680 1681 /* from input.c: */ 1682 { 1683 basepf.nextc = basepf.buf = basebuf; 1684 } 1685 1686 /* from trap.c: */ 1687 { 1688 signal(SIGCHLD, SIG_DFL); 1689 } 1690 1691 /* from var.c: */ 1692 { 1693 char **envp; 1694 char ppid[32]; 1695 const char *p; 1696 struct stat st1, st2; 1697 1698 initvar(); 1699 for (envp = environ ; envp && *envp ; envp++) { 1700 if (strchr(*envp, '=')) { 1701 setvareq(*envp, VEXPORT|VTEXTFIXED); 1702 } 1703 } 1704 1705 snprintf(ppid, sizeof(ppid), "%d", (int) getppid()); 1706 setvar("PPID", ppid, 0); 1707 1708 p = lookupvar("PWD"); 1709 if (p) 1710 if (*p != '/' || stat(p, &st1) || stat(".", &st2) || 1711 st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) 1712 p = 0; 1713 setpwd(p, 0); 1714 } 1715 } 1716 1717 /* PEOF (the end of file marker) */ 1718 1719 enum { 1720 INPUT_PUSH_FILE = 1, 1721 INPUT_NOFILE_OK = 2, 1722 }; 1723 1724 /* 1725 * The input line number. Input.c just defines this variable, and saves 1726 * and restores it when files are pushed and popped. The user of this 1727 * package must set its value. 1728 */ 1729 1730 static int pgetc(void); 1731 static int pgetc2(void); 1732 static int preadbuffer(void); 1733 static void pungetc(void); 1734 static void pushstring(char *, void *); 1735 static void popstring(void); 1736 static void setinputfd(int, int); 1737 static void setinputstring(char *); 1738 static void popfile(void); 1739 static void popallfiles(void); 1740 static void closescript(void); 1741 1742 1743 /* jobs.h */ 1744 2914 static struct alias *atab[ATABSIZE]; 2915 2916 static struct alias ** 2917 __lookupalias(const char *name) { 2918 unsigned int hashval; 2919 struct alias **app; 2920 const char *p; 2921 unsigned int ch; 2922 2923 p = name; 2924 2925 ch = (unsigned char)*p; 2926 hashval = ch << 4; 2927 while (ch) { 2928 hashval += ch; 2929 ch = (unsigned char)*++p; 2930 } 2931 app = &atab[hashval % ATABSIZE]; 2932 2933 for (; *app; app = &(*app)->next) { 2934 if (strcmp(name, (*app)->name) == 0) { 2935 break; 2936 } 2937 } 2938 2939 return app; 2940 } 2941 2942 static struct alias * 2943 lookupalias(const char *name, int check) 2944 { 2945 struct alias *ap = *__lookupalias(name); 2946 2947 if (check && ap && (ap->flag & ALIASINUSE)) 2948 return NULL; 2949 return ap; 2950 } 2951 2952 static struct alias * 2953 freealias(struct alias *ap) 2954 { 2955 struct alias *next; 2956 2957 if (ap->flag & ALIASINUSE) { 2958 ap->flag |= ALIASDEAD; 2959 return ap; 2960 } 2961 2962 next = ap->next; 2963 free(ap->name); 2964 free(ap->val); 2965 free(ap); 2966 return next; 2967 } 2968 2969 static void 2970 setalias(const char *name, const char *val) 2971 { 2972 struct alias *ap, **app; 2973 2974 app = __lookupalias(name); 2975 ap = *app; 2976 INT_OFF; 2977 if (ap) { 2978 if (!(ap->flag & ALIASINUSE)) { 2979 free(ap->val); 2980 } 2981 ap->val = ckstrdup(val); 2982 ap->flag &= ~ALIASDEAD; 2983 } else { 2984 /* not found */ 2985 ap = ckmalloc(sizeof(struct alias)); 2986 ap->name = ckstrdup(name); 2987 ap->val = ckstrdup(val); 2988 ap->flag = 0; 2989 ap->next = 0; 2990 *app = ap; 2991 } 2992 INT_ON; 2993 } 2994 2995 static int 2996 unalias(const char *name) 2997 { 2998 struct alias **app; 2999 3000 app = __lookupalias(name); 3001 3002 if (*app) { 3003 INT_OFF; 3004 *app = freealias(*app); 3005 INT_ON; 3006 return 0; 3007 } 3008 3009 return 1; 3010 } 3011 3012 static void 3013 rmaliases(void) 3014 { 3015 struct alias *ap, **app; 3016 int i; 3017 3018 INT_OFF; 3019 for (i = 0; i < ATABSIZE; i++) { 3020 app = &atab[i]; 3021 for (ap = *app; ap; ap = *app) { 3022 *app = freealias(*app); 3023 if (ap == *app) { 3024 app = &ap->next; 3025 } 3026 } 3027 } 3028 INT_ON; 3029 } 3030 3031 static void 3032 printalias(const struct alias *ap) 3033 { 3034 out1fmt("%s=%s\n", ap->name, single_quote(ap->val)); 3035 } 3036 3037 /* 3038 * TODO - sort output 3039 */ 3040 static int 3041 aliascmd(int argc, char **argv) 3042 { 3043 char *n, *v; 3044 int ret = 0; 3045 struct alias *ap; 3046 3047 if (argc == 1) { 3048 int i; 3049 3050 for (i = 0; i < ATABSIZE; i++) 3051 for (ap = atab[i]; ap; ap = ap->next) { 3052 printalias(ap); 3053 } 3054 return 0; 3055 } 3056 while ((n = *++argv) != NULL) { 3057 v = strchr(n+1, '='); 3058 if (v == NULL) { /* n+1: funny ksh stuff */ 3059 ap = *__lookupalias(n); 3060 if (ap == NULL) { 3061 fprintf(stderr, "%s: %s not found\n", "alias", n); 3062 ret = 1; 3063 } else 3064 printalias(ap); 3065 } else { 3066 *v++ = '\0'; 3067 setalias(n, v); 3068 } 3069 } 3070 3071 return ret; 3072 } 3073 3074 static int 3075 unaliascmd(int argc, char **argv) 3076 { 3077 int i; 3078 3079 while ((i = nextopt("a")) != '\0') { 3080 if (i == 'a') { 3081 rmaliases(); 3082 return 0; 3083 } 3084 } 3085 for (i = 0; *argptr; argptr++) { 3086 if (unalias(*argptr)) { 3087 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr); 3088 i = 1; 3089 } 3090 } 3091 3092 return i; 3093 } 3094 3095 #endif /* ASH_ALIAS */ 3096 3097 3098 /* ============ jobs.c */ 1745 3099 1746 3100 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ … … 1753 3107 #define SHOW_PID 0x04 /* include process pid */ 1754 3108 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */ 1755 1756 3109 1757 3110 /* … … 1791 3144 1792 3145 static pid_t backgndpid; /* pid of last background process */ 1793 static int job_warning; /* user was warned about stopped jobs */ 1794 #if JOBS 1795 static int jobctl; /* true if doing job control */ 1796 #endif 3146 static smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */ 1797 3147 1798 3148 static struct job *makejob(union node *, int); 1799 3149 static int forkshell(struct job *, union node *, int); 1800 3150 static int waitforjob(struct job *); 1801 static int stoppedjobs(void); 1802 1803 #if ! JOBS 1804 #define setjobctl(on) /* do nothing */3151 3152 #if !JOBS 3153 enum { jobctl = 0 }; 3154 #define setjobctl(on) do {} while (0) 1805 3155 #else 3156 static smallint jobctl; /* true if doing job control */ 1806 3157 static void setjobctl(int); 1807 static void showjobs(FILE *, int); 1808 #endif 1809 1810 /* main.h */ 1811 1812 1813 /* pid of main shell */ 1814 static int rootpid; 1815 /* shell level: 0 for the main shell, 1 for its children, and so on */ 1816 static int shlvl; 1817 #define rootshell (!shlvl) 1818 1819 static void readcmdfile(char *); 1820 static int cmdloop(int); 1821 1822 /* memalloc.h */ 1823 1824 1825 struct stackmark { 1826 struct stack_block *stackp; 1827 char *stacknxt; 1828 size_t stacknleft; 1829 struct stackmark *marknext; 1830 }; 1831 1832 /* minimum size of a block */ 1833 #define MINSIZE SHELL_ALIGN(504) 1834 1835 struct stack_block { 1836 struct stack_block *prev; 1837 char space[MINSIZE]; 1838 }; 1839 1840 static struct stack_block stackbase; 1841 static struct stack_block *stackp = &stackbase; 1842 static struct stackmark *markp; 1843 static char *stacknxt = stackbase.space; 1844 static size_t stacknleft = MINSIZE; 1845 static char *sstrend = stackbase.space + MINSIZE; 1846 static int herefd = -1; 1847 1848 1849 static pointer ckmalloc(size_t); 1850 static pointer ckrealloc(pointer, size_t); 1851 static char *savestr(const char *); 1852 static pointer stalloc(size_t); 1853 static void stunalloc(pointer); 1854 static void setstackmark(struct stackmark *); 1855 static void popstackmark(struct stackmark *); 1856 static void growstackblock(void); 1857 static void *growstackstr(void); 1858 static char *makestrspace(size_t, char *); 1859 static char *stnputs(const char *, size_t, char *); 1860 static char *stputs(const char *, char *); 1861 1862 1863 static inline char *_STPUTC(int c, char *p) { 1864 if (p == sstrend) 1865 p = growstackstr(); 1866 *p++ = c; 1867 return p; 1868 } 1869 1870 #define stackblock() ((void *)stacknxt) 1871 #define stackblocksize() stacknleft 1872 #define STARTSTACKSTR(p) ((p) = stackblock()) 1873 #define STPUTC(c, p) ((p) = _STPUTC((c), (p))) 1874 #define CHECKSTRSPACE(n, p) \ 1875 ({ \ 1876 char *q = (p); \ 1877 size_t l = (n); \ 1878 size_t m = sstrend - q; \ 1879 if (l > m) \ 1880 (p) = makestrspace(l, q); \ 1881 0; \ 1882 }) 1883 #define USTPUTC(c, p) (*p++ = (c)) 1884 #define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0')) 1885 #define STUNPUTC(p) (--p) 1886 #define STTOPC(p) p[-1] 1887 #define STADJUST(amount, p) (p += (amount)) 1888 1889 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock()) 1890 #define ungrabstackstr(s, p) stunalloc((s)) 1891 #define stackstrend() ((void *)sstrend) 1892 1893 #define ckfree(p) free((pointer)(p)) 1894 1895 /* mystring.h */ 1896 1897 1898 #define DOLATSTRLEN 4 1899 1900 static char *prefix(const char *, const char *); 1901 static int number(const char *); 1902 static int is_number(const char *); 1903 static char *single_quote(const char *); 1904 static char *sstrdup(const char *); 1905 1906 #define equal(s1, s2) (strcmp(s1, s2) == 0) 1907 #define scopy(s1, s2) ((void)strcpy(s2, s1)) 1908 1909 /* options.h */ 1910 1911 struct shparam { 1912 int nparam; /* # of positional parameters (without $0) */ 1913 unsigned char malloc; /* if parameter list dynamically allocated */ 1914 char **p; /* parameter list */ 1915 #ifdef CONFIG_ASH_GETOPTS 1916 int optind; /* next parameter to be processed by getopts */ 1917 int optoff; /* used by getopts */ 1918 #endif 1919 }; 1920 1921 1922 #define eflag optlist[0] 1923 #define fflag optlist[1] 1924 #define Iflag optlist[2] 1925 #define iflag optlist[3] 1926 #define mflag optlist[4] 1927 #define nflag optlist[5] 1928 #define sflag optlist[6] 1929 #define xflag optlist[7] 1930 #define vflag optlist[8] 1931 #define Cflag optlist[9] 1932 #define aflag optlist[10] 1933 #define bflag optlist[11] 1934 #define uflag optlist[12] 1935 #define viflag optlist[13] 1936 1937 #ifdef DEBUG 1938 #define nolog optlist[14] 1939 #define debug optlist[15] 1940 #endif 1941 1942 #ifndef CONFIG_FEATURE_COMMAND_EDITING_VI 1943 #define setvimode(on) viflag = 0 /* forcibly keep the option off */ 1944 #endif 1945 1946 /* options.c */ 1947 1948 1949 static const char *const optletters_optnames[] = { 1950 "e" "errexit", 1951 "f" "noglob", 1952 "I" "ignoreeof", 1953 "i" "interactive", 1954 "m" "monitor", 1955 "n" "noexec", 1956 "s" "stdin", 1957 "x" "xtrace", 1958 "v" "verbose", 1959 "C" "noclobber", 1960 "a" "allexport", 1961 "b" "notify", 1962 "u" "nounset", 1963 "\0" "vi", 1964 #ifdef DEBUG 1965 "\0" "nolog", 1966 "\0" "debug", 1967 #endif 1968 }; 1969 1970 #define optletters(n) optletters_optnames[(n)][0] 1971 #define optnames(n) (&optletters_optnames[(n)][1]) 1972 1973 #define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0])) 1974 1975 static char optlist[NOPTS]; 1976 1977 1978 static char *arg0; /* value of $0 */ 1979 static struct shparam shellparam; /* $@ current positional parameters */ 1980 static char **argptr; /* argument list for builtin commands */ 1981 static char *optionarg; /* set by nextopt (like getopt) */ 1982 static char *optptr; /* used by nextopt */ 1983 1984 static char *minusc; /* argument to -c option */ 1985 1986 1987 static void procargs(int, char **); 1988 static void optschanged(void); 1989 static void setparam(char **); 1990 static void freeparam(volatile struct shparam *); 1991 static int shiftcmd(int, char **); 1992 static int setcmd(int, char **); 1993 static int nextopt(const char *); 1994 1995 /* redir.h */ 1996 1997 /* flags passed to redirect */ 1998 #define REDIR_PUSH 01 /* save previous values of file descriptors */ 1999 #define REDIR_SAVEFD2 03 /* set preverrout */ 2000 2001 union node; 2002 static void redirect(union node *, int); 2003 static void popredir(int); 2004 static void clearredir(int); 2005 static int copyfd(int, int); 2006 static int redirectsafe(union node *, int); 2007 2008 /* show.h */ 2009 2010 2011 #ifdef DEBUG 2012 static void showtree(union node *); 2013 static void trace(const char *, ...); 2014 static void tracev(const char *, va_list); 2015 static void trargs(char **); 2016 static void trputc(int); 2017 static void trputs(const char *); 2018 static void opentrace(void); 2019 #endif 2020 2021 /* trap.h */ 2022 2023 2024 /* trap handler commands */ 2025 static char *trap[NSIG]; 2026 /* current value of signal */ 2027 static char sigmode[NSIG - 1]; 2028 /* indicates specified signal received */ 2029 static char gotsig[NSIG - 1]; 2030 2031 static void clear_traps(void); 2032 static void setsignal(int); 2033 static void ignoresig(int); 2034 static void onsig(int); 2035 static int dotrap(void); 2036 static void setinteractive(int); 2037 static void exitshell(void) ATTRIBUTE_NORETURN; 2038 static int decode_signal(const char *, int); 2039 2040 /* 2041 * This routine is called when an error or an interrupt occurs in an 2042 * interactive shell and control is returned to the main command loop. 2043 */ 2044 2045 static void 2046 reset(void) 2047 { 2048 /* from eval.c: */ 2049 { 2050 evalskip = 0; 2051 loopnest = 0; 2052 } 2053 2054 /* from input.c: */ 2055 { 2056 parselleft = parsenleft = 0; /* clear input buffer */ 2057 popallfiles(); 2058 } 2059 2060 /* from parser.c: */ 2061 { 2062 tokpushback = 0; 2063 checkkwd = 0; 2064 } 2065 2066 /* from redir.c: */ 2067 { 2068 clearredir(0); 2069 } 2070 2071 } 2072 2073 #ifdef CONFIG_ASH_ALIAS 2074 static struct alias *atab[ATABSIZE]; 2075 2076 static void setalias(const char *, const char *); 2077 static struct alias *freealias(struct alias *); 2078 static struct alias **__lookupalias(const char *); 2079 2080 static void 2081 setalias(const char *name, const char *val) 2082 { 2083 struct alias *ap, **app; 2084 2085 app = __lookupalias(name); 2086 ap = *app; 2087 INTOFF; 2088 if (ap) { 2089 if (!(ap->flag & ALIASINUSE)) { 2090 ckfree(ap->val); 2091 } 2092 ap->val = savestr(val); 2093 ap->flag &= ~ALIASDEAD; 2094 } else { 2095 /* not found */ 2096 ap = ckmalloc(sizeof (struct alias)); 2097 ap->name = savestr(name); 2098 ap->val = savestr(val); 2099 ap->flag = 0; 2100 ap->next = 0; 2101 *app = ap; 2102 } 2103 INTON; 2104 } 2105 2106 static int 2107 unalias(const char *name) 2108 { 2109 struct alias **app; 2110 2111 app = __lookupalias(name); 2112 2113 if (*app) { 2114 INTOFF; 2115 *app = freealias(*app); 2116 INTON; 2117 return (0); 2118 } 2119 2120 return (1); 2121 } 2122 2123 static void 2124 rmaliases(void) 2125 { 2126 struct alias *ap, **app; 2127 int i; 2128 2129 INTOFF; 2130 for (i = 0; i < ATABSIZE; i++) { 2131 app = &atab[i]; 2132 for (ap = *app; ap; ap = *app) { 2133 *app = freealias(*app); 2134 if (ap == *app) { 2135 app = &ap->next; 2136 } 2137 } 2138 } 2139 INTON; 2140 } 2141 2142 static struct alias * 2143 lookupalias(const char *name, int check) 2144 { 2145 struct alias *ap = *__lookupalias(name); 2146 2147 if (check && ap && (ap->flag & ALIASINUSE)) 2148 return (NULL); 2149 return (ap); 2150 } 2151 2152 /* 2153 * TODO - sort output 2154 */ 2155 static int 2156 aliascmd(int argc, char **argv) 2157 { 2158 char *n, *v; 2159 int ret = 0; 2160 struct alias *ap; 2161 2162 if (argc == 1) { 2163 int i; 2164 2165 for (i = 0; i < ATABSIZE; i++) 2166 for (ap = atab[i]; ap; ap = ap->next) { 2167 printalias(ap); 2168 } 2169 return (0); 2170 } 2171 while ((n = *++argv) != NULL) { 2172 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */ 2173 if ((ap = *__lookupalias(n)) == NULL) { 2174 fprintf(stderr, "%s: %s not found\n", "alias", n); 2175 ret = 1; 3158 #endif 3159 3160 /* 3161 * Set the signal handler for the specified signal. The routine figures 3162 * out what it should be set to. 3163 */ 3164 static void 3165 setsignal(int signo) 3166 { 3167 int action; 3168 char *t, tsig; 3169 struct sigaction act; 3170 3171 t = trap[signo]; 3172 if (t == NULL) 3173 action = S_DFL; 3174 else if (*t != '\0') 3175 action = S_CATCH; 3176 else 3177 action = S_IGN; 3178 if (rootshell && action == S_DFL) { 3179 switch (signo) { 3180 case SIGINT: 3181 if (iflag || minusc || sflag == 0) 3182 action = S_CATCH; 3183 break; 3184 case SIGQUIT: 3185 #if DEBUG 3186 if (debug) 3187 break; 3188 #endif 3189 /* FALLTHROUGH */ 3190 case SIGTERM: 3191 if (iflag) 3192 action = S_IGN; 3193 break; 3194 #if JOBS 3195 case SIGTSTP: 3196 case SIGTTOU: 3197 if (mflag) 3198 action = S_IGN; 3199 break; 3200 #endif 3201 } 3202 } 3203 3204 t = &sigmode[signo - 1]; 3205 tsig = *t; 3206 if (tsig == 0) { 3207 /* 3208 * current setting unknown 3209 */ 3210 if (sigaction(signo, 0, &act) == -1) { 3211 /* 3212 * Pretend it worked; maybe we should give a warning 3213 * here, but other shells don't. We don't alter 3214 * sigmode, so that we retry every time. 3215 */ 3216 return; 3217 } 3218 if (act.sa_handler == SIG_IGN) { 3219 if (mflag 3220 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU) 3221 ) { 3222 tsig = S_IGN; /* don't hard ignore these */ 2176 3223 } else 2177 printalias(ap);3224 tsig = S_HARD_IGN; 2178 3225 } else { 2179 *v++ = '\0'; 2180 setalias(n, v); 2181 } 2182 } 2183 2184 return (ret); 2185 } 2186 2187 static int 2188 unaliascmd(int argc, char **argv) 2189 { 2190 int i; 2191 2192 while ((i = nextopt("a")) != '\0') { 2193 if (i == 'a') { 2194 rmaliases(); 2195 return (0); 2196 } 2197 } 2198 for (i = 0; *argptr; argptr++) { 2199 if (unalias(*argptr)) { 2200 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr); 2201 i = 1; 2202 } 2203 } 2204 2205 return (i); 2206 } 2207 2208 static struct alias * 2209 freealias(struct alias *ap) { 2210 struct alias *next; 2211 2212 if (ap->flag & ALIASINUSE) { 2213 ap->flag |= ALIASDEAD; 2214 return ap; 2215 } 2216 2217 next = ap->next; 2218 ckfree(ap->name); 2219 ckfree(ap->val); 2220 ckfree(ap); 2221 return next; 2222 } 2223 2224 static void 2225 printalias(const struct alias *ap) { 2226 out1fmt("%s=%s\n", ap->name, single_quote(ap->val)); 2227 } 2228 2229 static struct alias ** 2230 __lookupalias(const char *name) { 2231 unsigned int hashval; 2232 struct alias **app; 2233 const char *p; 2234 unsigned int ch; 2235 2236 p = name; 2237 2238 ch = (unsigned char)*p; 2239 hashval = ch << 4; 2240 while (ch) { 2241 hashval += ch; 2242 ch = (unsigned char)*++p; 2243 } 2244 app = &atab[hashval % ATABSIZE]; 2245 2246 for (; *app; app = &(*app)->next) { 2247 if (equal(name, (*app)->name)) { 2248 break; 2249 } 2250 } 2251 2252 return app; 2253 } 2254 #endif /* CONFIG_ASH_ALIAS */ 2255 2256 2257 /* cd.c */ 2258 2259 /* 2260 * The cd and pwd commands. 2261 */ 2262 2263 #define CD_PHYSICAL 1 2264 #define CD_PRINT 2 2265 2266 static int docd(const char *, int); 2267 static int cdopt(void); 2268 2269 static char *curdir = nullstr; /* current working directory */ 2270 static char *physdir = nullstr; /* physical working directory */ 2271 2272 static int 2273 cdopt(void) 2274 { 2275 int flags = 0; 2276 int i, j; 2277 2278 j = 'L'; 2279 while ((i = nextopt("LP"))) { 2280 if (i != j) { 2281 flags ^= CD_PHYSICAL; 2282 j = i; 2283 } 2284 } 2285 2286 return flags; 2287 } 2288 2289 static int 2290 cdcmd(int argc, char **argv) 2291 { 2292 const char *dest; 2293 const char *path; 2294 const char *p; 2295 char c; 2296 struct stat statb; 2297 int flags; 2298 2299 flags = cdopt(); 2300 dest = *argptr; 2301 if (!dest) 2302 dest = bltinlookup(homestr); 2303 else if (dest[0] == '-' && dest[1] == '\0') { 2304 dest = bltinlookup("OLDPWD"); 2305 flags |= CD_PRINT; 2306 } 2307 if (!dest) 2308 dest = nullstr; 2309 if (*dest == '/') 2310 goto step7; 2311 if (*dest == '.') { 2312 c = dest[1]; 2313 dotdot: 2314 switch (c) { 2315 case '\0': 2316 case '/': 2317 goto step6; 2318 case '.': 2319 c = dest[2]; 2320 if (c != '.') 2321 goto dotdot; 2322 } 2323 } 2324 if (!*dest) 2325 dest = "."; 2326 if (!(path = bltinlookup("CDPATH"))) { 2327 step6: 2328 step7: 2329 p = dest; 2330 goto docd; 2331 } 2332 do { 2333 c = *path; 2334 p = padvance(&path, dest); 2335 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { 2336 if (c && c != ':') 2337 flags |= CD_PRINT; 2338 docd: 2339 if (!docd(p, flags)) 2340 goto out; 2341 break; 2342 } 2343 } while (path); 2344 sh_error("can't cd to %s", dest); 2345 /* NOTREACHED */ 2346 out: 2347 if (flags & CD_PRINT) 2348 out1fmt(snlfmt, curdir); 2349 return 0; 2350 } 2351 2352 2353 /* 2354 * Update curdir (the name of the current directory) in response to a 2355 * cd command. 2356 */ 2357 2358 static inline const char * 2359 updatepwd(const char *dir) 2360 { 2361 char *new; 2362 char *p; 2363 char *cdcomppath; 2364 const char *lim; 2365 2366 cdcomppath = sstrdup(dir); 2367 STARTSTACKSTR(new); 2368 if (*dir != '/') { 2369 if (curdir == nullstr) 2370 return 0; 2371 new = stputs(curdir, new); 2372 } 2373 new = makestrspace(strlen(dir) + 2, new); 2374 lim = stackblock() + 1; 2375 if (*dir != '/') { 2376 if (new[-1] != '/') 2377 USTPUTC('/', new); 2378 if (new > lim && *lim == '/') 2379 lim++; 2380 } else { 2381 USTPUTC('/', new); 2382 cdcomppath++; 2383 if (dir[1] == '/' && dir[2] != '/') { 2384 USTPUTC('/', new); 2385 cdcomppath++; 2386 lim++; 2387 } 2388 } 2389 p = strtok(cdcomppath, "/"); 2390 while (p) { 2391 switch(*p) { 2392 case '.': 2393 if (p[1] == '.' && p[2] == '\0') { 2394 while (new > lim) { 2395 STUNPUTC(new); 2396 if (new[-1] == '/') 2397 break; 2398 } 2399 break; 2400 } else if (p[1] == '\0') 2401 break; 2402 /* fall through */ 2403 default: 2404 new = stputs(p, new); 2405 USTPUTC('/', new); 2406 } 2407 p = strtok(0, "/"); 2408 } 2409 if (new > lim) 2410 STUNPUTC(new); 2411 *new = 0; 2412 return stackblock(); 2413 } 2414 2415 /* 2416 * Actually do the chdir. We also call hashcd to let the routines in exec.c 2417 * know that the current directory has changed. 2418 */ 2419 2420 static int 2421 docd(const char *dest, int flags) 2422 { 2423 const char *dir = 0; 2424 int err; 2425 2426 TRACE(("docd(\"%s\", %d) called\n", dest, flags)); 2427 2428 INTOFF; 2429 if (!(flags & CD_PHYSICAL)) { 2430 dir = updatepwd(dest); 2431 if (dir) 2432 dest = dir; 2433 } 2434 err = chdir(dest); 2435 if (err) 2436 goto out; 2437 setpwd(dir, 1); 2438 hashcd(); 2439 out: 2440 INTON; 2441 return err; 2442 } 2443 2444 /* 2445 * Find out what the current directory is. If we already know the current 2446 * directory, this routine returns immediately. 2447 */ 2448 static inline char * 2449 getpwd(void) 2450 { 2451 char *dir = getcwd(0, 0); 2452 return dir ? dir : nullstr; 2453 } 2454 2455 static int 2456 pwdcmd(int argc, char **argv) 2457 { 2458 int flags; 2459 const char *dir = curdir; 2460 2461 flags = cdopt(); 2462 if (flags) { 2463 if (physdir == nullstr) 2464 setpwd(dir, 0); 2465 dir = physdir; 2466 } 2467 out1fmt(snlfmt, dir); 2468 return 0; 2469 } 2470 2471 static void 2472 setpwd(const char *val, int setold) 2473 { 2474 char *oldcur, *dir; 2475 2476 oldcur = dir = curdir; 2477 2478 if (setold) { 2479 setvar("OLDPWD", oldcur, VEXPORT); 2480 } 2481 INTOFF; 2482 if (physdir != nullstr) { 2483 if (physdir != oldcur) 2484 free(physdir); 2485 physdir = nullstr; 2486 } 2487 if (oldcur == val || !val) { 2488 char *s = getpwd(); 2489 physdir = s; 2490 if (!val) 2491 dir = s; 2492 } else 2493 dir = savestr(val); 2494 if (oldcur != dir && oldcur != nullstr) { 2495 free(oldcur); 2496 } 2497 curdir = dir; 2498 INTON; 2499 setvar("PWD", dir, VEXPORT); 2500 } 2501 2502 /* error.c */ 2503 2504 /* 2505 * Errors and exceptions. 2506 */ 2507 2508 /* 2509 * Code to handle exceptions in C. 2510 */ 2511 2512 2513 2514 static void exverror(int, const char *, va_list) 2515 ATTRIBUTE_NORETURN; 2516 2517 /* 2518 * Called to raise an exception. Since C doesn't include exceptions, we 2519 * just do a longjmp to the exception handler. The type of exception is 2520 * stored in the global variable "exception". 2521 */ 2522 2523 static void 2524 exraise(int e) 2525 { 2526 #ifdef DEBUG 2527 if (handler == NULL) 2528 abort(); 2529 #endif 2530 INTOFF; 2531 2532 exception = e; 2533 longjmp(handler->loc, 1); 2534 } 2535 2536 2537 /* 2538 * Called from trap.c when a SIGINT is received. (If the user specifies 2539 * that SIGINT is to be trapped or ignored using the trap builtin, then 2540 * this routine is not called.) Suppressint is nonzero when interrupts 2541 * are held using the INTOFF macro. (The test for iflag is just 2542 * defensive programming.) 2543 */ 2544 2545 static void 2546 onint(void) { 2547 int i; 2548 2549 intpending = 0; 2550 #if 0 2551 /* comment by vodz: its strange for me, this programm don`t use other 2552 signal block */ 2553 sigsetmask(0); 2554 #endif 2555 i = EXSIG; 2556 if (gotsig[SIGINT - 1] && !trap[SIGINT]) { 2557 if (!(rootshell && iflag)) { 2558 signal(SIGINT, SIG_DFL); 2559 raise(SIGINT); 2560 } 2561 i = EXINT; 2562 } 2563 exraise(i); 2564 /* NOTREACHED */ 2565 } 2566 2567 static void 2568 exvwarning(const char *msg, va_list ap) 2569 { 2570 FILE *errs; 2571 2572 errs = stderr; 2573 fprintf(errs, "%s: ", arg0); 2574 if (commandname) { 2575 const char *fmt = (!iflag || parsefile->fd) ? 2576 "%s: %d: " : "%s: "; 2577 fprintf(errs, fmt, commandname, startlinno); 2578 } 2579 vfprintf(errs, msg, ap); 2580 outcslow('\n', errs); 2581 } 2582 2583 /* 2584 * Exverror is called to raise the error exception. If the second argument 2585 * is not NULL then error prints an error message using printf style 2586 * formatting. It then raises the error exception. 2587 */ 2588 static void 2589 exverror(int cond, const char *msg, va_list ap) 2590 { 2591 #ifdef DEBUG 2592 if (msg) { 2593 TRACE(("exverror(%d, \"", cond)); 2594 TRACEV((msg, ap)); 2595 TRACE(("\") pid=%d\n", getpid())); 2596 } else 2597 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid())); 2598 if (msg) 2599 #endif 2600 exvwarning(msg, ap); 2601 2602 flushall(); 2603 exraise(cond); 2604 /* NOTREACHED */ 2605 } 2606 2607 2608 static void 2609 sh_error(const char *msg, ...) 2610 { 2611 va_list ap; 2612 2613 va_start(ap, msg); 2614 exverror(EXERROR, msg, ap); 2615 /* NOTREACHED */ 2616 va_end(ap); 2617 } 2618 2619 2620 static void 2621 exerror(int cond, const char *msg, ...) 2622 { 2623 va_list ap; 2624 2625 va_start(ap, msg); 2626 exverror(cond, msg, ap); 2627 /* NOTREACHED */ 2628 va_end(ap); 2629 } 2630 2631 /* 2632 * error/warning routines for external builtins 2633 */ 2634 2635 static void 2636 sh_warnx(const char *fmt, ...) 2637 { 2638 va_list ap; 2639 2640 va_start(ap, fmt); 2641 exvwarning(fmt, ap); 2642 va_end(ap); 2643 } 2644 2645 2646 /* 2647 * Return a string describing an error. The returned string may be a 2648 * pointer to a static buffer that will be overwritten on the next call. 2649 * Action describes the operation that got the error. 2650 */ 2651 2652 static const char * 2653 errmsg(int e, const char *em) 2654 { 2655 if(e == ENOENT || e == ENOTDIR) { 2656 2657 return em; 2658 } 2659 return strerror(e); 2660 } 2661 2662 2663 /* eval.c */ 2664 2665 /* 2666 * Evaluate a command. 2667 */ 2668 2669 /* flags in argument to evaltree */ 2670 #define EV_EXIT 01 /* exit after evaluating tree */ 2671 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ 2672 #define EV_BACKCMD 04 /* command executing within back quotes */ 2673 2674 2675 static void evalloop(union node *, int); 2676 static void evalfor(union node *, int); 2677 static void evalcase(union node *, int); 2678 static void evalsubshell(union node *, int); 2679 static void expredir(union node *); 2680 static void evalpipe(union node *, int); 2681 static void evalcommand(union node *, int); 2682 static int evalbltin(const struct builtincmd *, int, char **); 2683 static int evalfun(struct funcnode *, int, char **, int); 2684 static void prehash(union node *); 2685 static int bltincmd(int, char **); 2686 2687 2688 static const struct builtincmd bltin = { 2689 "\0\0", bltincmd 2690 }; 2691 2692 2693 /* 2694 * Called to reset things after an exception. 2695 */ 2696 2697 /* 2698 * The eval command. 2699 */ 2700 2701 static int 2702 evalcmd(int argc, char **argv) 2703 { 2704 char *p; 2705 char *concat; 2706 char **ap; 2707 2708 if (argc > 1) { 2709 p = argv[1]; 2710 if (argc > 2) { 2711 STARTSTACKSTR(concat); 2712 ap = argv + 2; 2713 for (;;) { 2714 concat = stputs(p, concat); 2715 if ((p = *ap++) == NULL) 2716 break; 2717 STPUTC(' ', concat); 2718 } 2719 STPUTC('\0', concat); 2720 p = grabstackstr(concat); 2721 } 2722 evalstring(p, ~SKIPEVAL); 2723 2724 } 2725 return exitstatus; 2726 } 2727 2728 2729 /* 2730 * Execute a command or commands contained in a string. 2731 */ 2732 2733 static int 2734 evalstring(char *s, int mask) 2735 { 2736 union node *n; 2737 struct stackmark smark; 2738 int skip; 2739 2740 setinputstring(s); 2741 setstackmark(&smark); 2742 2743 skip = 0; 2744 while ((n = parsecmd(0)) != NEOF) { 2745 evaltree(n, 0); 2746 popstackmark(&smark); 2747 skip = evalskip; 2748 if (skip) 2749 break; 2750 } 2751 popfile(); 2752 2753 skip &= mask; 2754 evalskip = skip; 2755 return skip; 2756 } 2757 2758 2759 2760 /* 2761 * Evaluate a parse tree. The value is left in the global variable 2762 * exitstatus. 2763 */ 2764 2765 static void 2766 evaltree(union node *n, int flags) 2767 { 2768 int checkexit = 0; 2769 void (*evalfn)(union node *, int); 2770 unsigned isor; 2771 int status; 2772 if (n == NULL) { 2773 TRACE(("evaltree(NULL) called\n")); 2774 goto out; 2775 } 2776 TRACE(("pid %d, evaltree(%p: %d, %d) called\n", 2777 getpid(), n, n->type, flags)); 2778 switch (n->type) { 2779 default: 2780 #ifdef DEBUG 2781 out1fmt("Node type = %d\n", n->type); 2782 fflush(stdout); 3226 tsig = S_RESET; /* force to be set */ 3227 } 3228 } 3229 if (tsig == S_HARD_IGN || tsig == action) 3230 return; 3231 switch (action) { 3232 case S_CATCH: 3233 act.sa_handler = onsig; 2783 3234 break; 2784 #endif 2785 case NNOT: 2786 evaltree(n->nnot.com, EV_TESTED); 2787 status = !exitstatus; 2788 goto setstatus; 2789 case NREDIR: 2790 expredir(n->nredir.redirect); 2791 status = redirectsafe(n->nredir.redirect, REDIR_PUSH); 2792 if (!status) { 2793 evaltree(n->nredir.n, flags & EV_TESTED); 2794 status = exitstatus; 2795 } 2796 popredir(0); 2797 goto setstatus; 2798 case NCMD: 2799 evalfn = evalcommand; 2800 checkexit: 2801 if (eflag && !(flags & EV_TESTED)) 2802 checkexit = ~0; 2803 goto calleval; 2804 case NFOR: 2805 evalfn = evalfor; 2806 goto calleval; 2807 case NWHILE: 2808 case NUNTIL: 2809 evalfn = evalloop; 2810 goto calleval; 2811 case NSUBSHELL: 2812 case NBACKGND: 2813 evalfn = evalsubshell; 2814 goto calleval; 2815 case NPIPE: 2816 evalfn = evalpipe; 2817 goto checkexit; 2818 case NCASE: 2819 evalfn = evalcase; 2820 goto calleval; 2821 case NAND: 2822 case NOR: 2823 case NSEMI: 2824 #if NAND + 1 != NOR 2825 #error NAND + 1 != NOR 2826 #endif 2827 #if NOR + 1 != NSEMI 2828 #error NOR + 1 != NSEMI 2829 #endif 2830 isor = n->type - NAND; 2831 evaltree( 2832 n->nbinary.ch1, 2833 (flags | ((isor >> 1) - 1)) & EV_TESTED 2834 ); 2835 if (!exitstatus == isor) 2836 break; 2837 if (!evalskip) { 2838 n = n->nbinary.ch2; 2839 evaln: 2840 evalfn = evaltree; 2841 calleval: 2842 evalfn(n, flags); 2843 break; 2844 } 2845 break; 2846 case NIF: 2847 evaltree(n->nif.test, EV_TESTED); 2848 if (evalskip) 2849 break; 2850 if (exitstatus == 0) { 2851 n = n->nif.ifpart; 2852 goto evaln; 2853 } else if (n->nif.elsepart) { 2854 n = n->nif.elsepart; 2855 goto evaln; 2856 } 2857 goto success; 2858 case NDEFUN: 2859 defun(n->narg.text, n->narg.next); 2860 success: 2861 status = 0; 2862 setstatus: 2863 exitstatus = status; 2864 break; 2865 } 2866 out: 2867 if ((checkexit & exitstatus)) 2868 evalskip |= SKIPEVAL; 2869 else if (pendingsigs && dotrap()) 2870 goto exexit; 2871 2872 if (flags & EV_EXIT) { 2873 exexit: 2874 exraise(EXEXIT); 2875 } 2876 } 2877 2878 2879 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3) 2880 static 2881 #endif 2882 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__)); 2883 2884 2885 static void 2886 evalloop(union node *n, int flags) 2887 { 2888 int status; 2889 2890 loopnest++; 2891 status = 0; 2892 flags &= EV_TESTED; 2893 for (;;) { 2894 int i; 2895 2896 evaltree(n->nbinary.ch1, EV_TESTED); 2897 if (evalskip) { 2898 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { 2899 evalskip = 0; 2900 continue; 2901 } 2902 if (evalskip == SKIPBREAK && --skipcount <= 0) 2903 evalskip = 0; 2904 break; 2905 } 2906 i = exitstatus; 2907 if (n->type != NWHILE) 2908 i = !i; 2909 if (i != 0) 2910 break; 2911 evaltree(n->nbinary.ch2, flags); 2912 status = exitstatus; 2913 if (evalskip) 2914 goto skipping; 2915 } 2916 loopnest--; 2917 exitstatus = status; 2918 } 2919 2920 2921 2922 static void 2923 evalfor(union node *n, int flags) 2924 { 2925 struct arglist arglist; 2926 union node *argp; 2927 struct strlist *sp; 2928 struct stackmark smark; 2929 2930 setstackmark(&smark); 2931 arglist.lastp = &arglist.list; 2932 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { 2933 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD); 2934 /* XXX */ 2935 if (evalskip) 2936 goto out; 2937 } 2938 *arglist.lastp = NULL; 2939 2940 exitstatus = 0; 2941 loopnest++; 2942 flags &= EV_TESTED; 2943 for (sp = arglist.list ; sp ; sp = sp->next) { 2944 setvar(n->nfor.var, sp->text, 0); 2945 evaltree(n->nfor.body, flags); 2946 if (evalskip) { 2947 if (evalskip == SKIPCONT && --skipcount <= 0) { 2948 evalskip = 0; 2949 continue; 2950 } 2951 if (evalskip == SKIPBREAK && --skipcount <= 0) 2952 evalskip = 0; 2953 break; 2954 } 2955 } 2956 loopnest--; 2957 out: 2958 popstackmark(&smark); 2959 } 2960 2961 2962 2963 static void 2964 evalcase(union node *n, int flags) 2965 { 2966 union node *cp; 2967 union node *patp; 2968 struct arglist arglist; 2969 struct stackmark smark; 2970 2971 setstackmark(&smark); 2972 arglist.lastp = &arglist.list; 2973 expandarg(n->ncase.expr, &arglist, EXP_TILDE); 2974 exitstatus = 0; 2975 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { 2976 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { 2977 if (casematch(patp, arglist.list->text)) { 2978 if (evalskip == 0) { 2979 evaltree(cp->nclist.body, flags); 2980 } 2981 goto out; 2982 } 2983 } 2984 } 2985 out: 2986 popstackmark(&smark); 2987 } 2988 2989 2990 2991 /* 2992 * Kick off a subshell to evaluate a tree. 2993 */ 2994 2995 static void 2996 evalsubshell(union node *n, int flags) 2997 { 2998 struct job *jp; 2999 int backgnd = (n->type == NBACKGND); 3000 int status; 3001 3002 expredir(n->nredir.redirect); 3003 if (!backgnd && flags & EV_EXIT && !trap[0]) 3004 goto nofork; 3005 INTOFF; 3006 jp = makejob(n, 1); 3007 if (forkshell(jp, n, backgnd) == 0) { 3008 INTON; 3009 flags |= EV_EXIT; 3010 if (backgnd) 3011 flags &=~ EV_TESTED; 3012 nofork: 3013 redirect(n->nredir.redirect, 0); 3014 evaltreenr(n->nredir.n, flags); 3015 /* never returns */ 3016 } 3017 status = 0; 3018 if (! backgnd) 3019 status = waitforjob(jp); 3020 exitstatus = status; 3021 INTON; 3022 } 3023 3024 3025 3026 /* 3027 * Compute the names of the files in a redirection list. 3028 */ 3029 3030 static void 3031 expredir(union node *n) 3032 { 3033 union node *redir; 3034 3035 for (redir = n ; redir ; redir = redir->nfile.next) { 3036 struct arglist fn; 3037 fn.lastp = &fn.list; 3038 switch (redir->type) { 3039 case NFROMTO: 3040 case NFROM: 3041 case NTO: 3042 case NCLOBBER: 3043 case NAPPEND: 3044 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 3045 redir->nfile.expfname = fn.list->text; 3046 break; 3047 case NFROMFD: 3048 case NTOFD: 3049 if (redir->ndup.vname) { 3050 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); 3051 fixredir(redir, fn.list->text, 1); 3052 } 3053 break; 3054 } 3055 } 3056 } 3057 3058 3059 3060 /* 3061 * Evaluate a pipeline. All the processes in the pipeline are children 3062 * of the process creating the pipeline. (This differs from some versions 3063 * of the shell, which make the last process in a pipeline the parent 3064 * of all the rest.) 3065 */ 3066 3067 static void 3068 evalpipe(union node *n, int flags) 3069 { 3070 struct job *jp; 3071 struct nodelist *lp; 3072 int pipelen; 3073 int prevfd; 3074 int pip[2]; 3075 3076 TRACE(("evalpipe(0x%lx) called\n", (long)n)); 3077 pipelen = 0; 3078 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) 3079 pipelen++; 3080 flags |= EV_EXIT; 3081 INTOFF; 3082 jp = makejob(n, pipelen); 3083 prevfd = -1; 3084 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 3085 prehash(lp->n); 3086 pip[1] = -1; 3087 if (lp->next) { 3088 if (pipe(pip) < 0) { 3089 close(prevfd); 3090 sh_error("Pipe call failed"); 3091 } 3092 } 3093 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 3094 INTON; 3095 if (pip[1] >= 0) { 3096 close(pip[0]); 3097 } 3098 if (prevfd > 0) { 3099 dup2(prevfd, 0); 3100 close(prevfd); 3101 } 3102 if (pip[1] > 1) { 3103 dup2(pip[1], 1); 3104 close(pip[1]); 3105 } 3106 evaltreenr(lp->n, flags); 3107 /* never returns */ 3108 } 3109 if (prevfd >= 0) 3110 close(prevfd); 3111 prevfd = pip[0]; 3112 close(pip[1]); 3113 } 3114 if (n->npipe.backgnd == 0) { 3115 exitstatus = waitforjob(jp); 3116 TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 3117 } 3118 INTON; 3119 } 3120 3121 3122 3123 /* 3124 * Execute a command inside back quotes. If it's a builtin command, we 3125 * want to save its output in a block obtained from malloc. Otherwise 3126 * we fork off a subprocess and get the output of the command via a pipe. 3127 * Should be called with interrupts off. 3128 */ 3129 3130 static void 3131 evalbackcmd(union node *n, struct backcmd *result) 3132 { 3133 int saveherefd; 3134 3135 result->fd = -1; 3136 result->buf = NULL; 3137 result->nleft = 0; 3138 result->jp = NULL; 3139 if (n == NULL) { 3140 goto out; 3141 } 3142 3143 saveherefd = herefd; 3144 herefd = -1; 3145 3146 { 3147 int pip[2]; 3148 struct job *jp; 3149 3150 if (pipe(pip) < 0) 3151 sh_error("Pipe call failed"); 3152 jp = makejob(n, 1); 3153 if (forkshell(jp, n, FORK_NOJOB) == 0) { 3154 FORCEINTON; 3155 close(pip[0]); 3156 if (pip[1] != 1) { 3157 close(1); 3158 copyfd(pip[1], 1); 3159 close(pip[1]); 3160 } 3161 eflag = 0; 3162 evaltreenr(n, EV_EXIT); 3163 /* NOTREACHED */ 3164 } 3165 close(pip[1]); 3166 result->fd = pip[0]; 3167 result->jp = jp; 3168 } 3169 herefd = saveherefd; 3170 out: 3171 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 3172 result->fd, result->buf, result->nleft, result->jp)); 3173 } 3174 3175 #ifdef CONFIG_ASH_CMDCMD 3176 static inline char ** 3177 parse_command_args(char **argv, const char **path) 3178 { 3179 char *cp, c; 3180 3181 for (;;) { 3182 cp = *++argv; 3183 if (!cp) 3184 return 0; 3185 if (*cp++ != '-') 3186 break; 3187 if (!(c = *cp++)) 3188 break; 3189 if (c == '-' && !*cp) { 3190 argv++; 3191 break; 3192 } 3193 do { 3194 switch (c) { 3195 case 'p': 3196 *path = defpath; 3197 break; 3198 default: 3199 /* run 'typecmd' for other options */ 3200 return 0; 3201 } 3202 } while ((c = *cp++)); 3203 } 3204 return argv; 3205 } 3206 #endif 3207 3208 static inline int 3209 isassignment(const char *p) 3210 { 3211 const char *q = endofname(p); 3212 if (p == q) 3213 return 0; 3214 return *q == '='; 3215 } 3216 3217 #ifdef CONFIG_ASH_EXPAND_PRMT 3218 static const char *expandstr(const char *ps); 3219 #else 3220 #define expandstr(s) s 3221 #endif 3222 3223 /* 3224 * Execute a simple command. 3225 */ 3226 3227 static void 3228 evalcommand(union node *cmd, int flags) 3229 { 3230 struct stackmark smark; 3231 union node *argp; 3232 struct arglist arglist; 3233 struct arglist varlist; 3234 char **argv; 3235 int argc; 3236 const struct strlist *sp; 3237 struct cmdentry cmdentry; 3238 struct job *jp; 3239 char *lastarg; 3240 const char *path; 3241 int spclbltin; 3242 int cmd_is_exec; 3243 int status; 3244 char **nargv; 3245 struct builtincmd *bcmd; 3246 int pseudovarflag = 0; 3247 3248 /* First expand the arguments. */ 3249 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 3250 setstackmark(&smark); 3251 back_exitstatus = 0; 3252 3253 cmdentry.cmdtype = CMDBUILTIN; 3254 cmdentry.u.cmd = &bltin; 3255 varlist.lastp = &varlist.list; 3256 *varlist.lastp = NULL; 3257 arglist.lastp = &arglist.list; 3258 *arglist.lastp = NULL; 3259 3260 argc = 0; 3261 if (cmd->ncmd.args) 3262 { 3263 bcmd = find_builtin(cmd->ncmd.args->narg.text); 3264 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd); 3265 } 3266 3267 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) { 3268 struct strlist **spp; 3269 3270 spp = arglist.lastp; 3271 if (pseudovarflag && isassignment(argp->narg.text)) 3272 expandarg(argp, &arglist, EXP_VARTILDE); 3273 else 3274 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 3275 3276 for (sp = *spp; sp; sp = sp->next) 3277 argc++; 3278 } 3279 3280 argv = nargv = stalloc(sizeof (char *) * (argc + 1)); 3281 for (sp = arglist.list ; sp ; sp = sp->next) { 3282 TRACE(("evalcommand arg: %s\n", sp->text)); 3283 *nargv++ = sp->text; 3284 } 3285 *nargv = NULL; 3286 3287 lastarg = NULL; 3288 if (iflag && funcnest == 0 && argc > 0) 3289 lastarg = nargv[-1]; 3290 3291 preverrout_fd = 2; 3292 expredir(cmd->ncmd.redirect); 3293 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2); 3294 3295 path = vpath.text; 3296 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { 3297 struct strlist **spp; 3298 char *p; 3299 3300 spp = varlist.lastp; 3301 expandarg(argp, &varlist, EXP_VARTILDE); 3302 3303 /* 3304 * Modify the command lookup path, if a PATH= assignment 3305 * is present 3306 */ 3307 p = (*spp)->text; 3308 if (varequal(p, path)) 3309 path = p; 3310 } 3311 3312 /* Print the command if xflag is set. */ 3313 if (xflag) { 3314 int n; 3315 const char *p = " %s"; 3316 3317 p++; 3318 dprintf(preverrout_fd, p, expandstr(ps4val())); 3319 3320 sp = varlist.list; 3321 for(n = 0; n < 2; n++) { 3322 while (sp) { 3323 dprintf(preverrout_fd, p, sp->text); 3324 sp = sp->next; 3325 if(*p == '%') { 3326 p--; 3327 } 3328 } 3329 sp = arglist.list; 3330 } 3331 bb_full_write(preverrout_fd, "\n", 1); 3332 } 3333 3334 cmd_is_exec = 0; 3335 spclbltin = -1; 3336 3337 /* Now locate the command. */ 3338 if (argc) { 3339 const char *oldpath; 3340 int cmd_flag = DO_ERR; 3341 3342 path += 5; 3343 oldpath = path; 3344 for (;;) { 3345 find_command(argv[0], &cmdentry, cmd_flag, path); 3346 if (cmdentry.cmdtype == CMDUNKNOWN) { 3347 status = 127; 3348 flusherr(); 3349 goto bail; 3350 } 3351 3352 /* implement bltin and command here */ 3353 if (cmdentry.cmdtype != CMDBUILTIN) 3354 break; 3355 if (spclbltin < 0) 3356 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd); 3357 if (cmdentry.u.cmd == EXECCMD) 3358 cmd_is_exec++; 3359 #ifdef CONFIG_ASH_CMDCMD 3360 if (cmdentry.u.cmd == COMMANDCMD) { 3361 3362 path = oldpath; 3363 nargv = parse_command_args(argv, &path); 3364 if (!nargv) 3365 break; 3366 argc -= nargv - argv; 3367 argv = nargv; 3368 cmd_flag |= DO_NOFUNC; 3369 } else 3370 #endif 3371 break; 3372 } 3373 } 3374 3375 if (status) { 3376 /* We have a redirection error. */ 3377 if (spclbltin > 0) 3378 exraise(EXERROR); 3379 bail: 3380 exitstatus = status; 3381 goto out; 3382 } 3383 3384 /* Execute the command. */ 3385 switch (cmdentry.cmdtype) { 3386 default: 3387 /* Fork off a child process if necessary. */ 3388 if (!(flags & EV_EXIT) || trap[0]) { 3389 INTOFF; 3390 jp = makejob(cmd, 1); 3391 if (forkshell(jp, cmd, FORK_FG) != 0) { 3392 exitstatus = waitforjob(jp); 3393 INTON; 3394 break; 3395 } 3396 FORCEINTON; 3397 } 3398 listsetvar(varlist.list, VEXPORT|VSTACK); 3399 shellexec(argv, path, cmdentry.u.index); 3400 /* NOTREACHED */ 3401 3402 case CMDBUILTIN: 3403 cmdenviron = varlist.list; 3404 if (cmdenviron) { 3405 struct strlist *list = cmdenviron; 3406 int i = VNOSET; 3407 if (spclbltin > 0 || argc == 0) { 3408 i = 0; 3409 if (cmd_is_exec && argc > 1) 3410 i = VEXPORT; 3411 } 3412 listsetvar(list, i); 3413 } 3414 if (evalbltin(cmdentry.u.cmd, argc, argv)) { 3415 int exit_status; 3416 int i, j; 3417 3418 i = exception; 3419 if (i == EXEXIT) 3420 goto raise; 3421 3422 exit_status = 2; 3423 j = 0; 3424 if (i == EXINT) 3425 j = SIGINT; 3426 if (i == EXSIG) 3427 j = pendingsigs; 3428 if (j) 3429 exit_status = j + 128; 3430 exitstatus = exit_status; 3431 3432 if (i == EXINT || spclbltin > 0) { 3433 raise: 3434 longjmp(handler->loc, 1); 3435 } 3436 FORCEINTON; 3437 } 3438 break; 3439 3440 case CMDFUNCTION: 3441 listsetvar(varlist.list, 0); 3442 if (evalfun(cmdentry.u.func, argc, argv, flags)) 3443 goto raise; 3444 break; 3445 } 3446 3447 out: 3448 popredir(cmd_is_exec); 3449 if (lastarg) 3450 /* dsl: I think this is intended to be used to support 3451 * '_' in 'vi' command mode during line editing... 3452 * However I implemented that within libedit itself. 3453 */ 3454 setvar("_", lastarg, 0); 3455 popstackmark(&smark); 3456 } 3457 3458 static int 3459 evalbltin(const struct builtincmd *cmd, int argc, char **argv) { 3460 char *volatile savecmdname; 3461 struct jmploc *volatile savehandler; 3462 struct jmploc jmploc; 3463 int i; 3464 3465 savecmdname = commandname; 3466 if ((i = setjmp(jmploc.loc))) 3467 goto cmddone; 3468 savehandler = handler; 3469 handler = &jmploc; 3470 commandname = argv[0]; 3471 argptr = argv + 1; 3472 optptr = NULL; /* initialize nextopt */ 3473 exitstatus = (*cmd->builtin)(argc, argv); 3474 flushall(); 3475 cmddone: 3476 exitstatus |= ferror(stdout); 3477 clearerr(stdout); 3478 commandname = savecmdname; 3479 exsig = 0; 3480 handler = savehandler; 3481 3482 return i; 3483 } 3484 3485 static int 3486 evalfun(struct funcnode *func, int argc, char **argv, int flags) 3487 { 3488 volatile struct shparam saveparam; 3489 struct localvar *volatile savelocalvars; 3490 struct jmploc *volatile savehandler; 3491 struct jmploc jmploc; 3492 int e; 3493 3494 saveparam = shellparam; 3495 savelocalvars = localvars; 3496 if ((e = setjmp(jmploc.loc))) { 3497 goto funcdone; 3498 } 3499 INTOFF; 3500 savehandler = handler; 3501 handler = &jmploc; 3502 localvars = NULL; 3503 shellparam.malloc = 0; 3504 func->count++; 3505 funcnest++; 3506 INTON; 3507 shellparam.nparam = argc - 1; 3508 shellparam.p = argv + 1; 3509 #ifdef CONFIG_ASH_GETOPTS 3510 shellparam.optind = 1; 3511 shellparam.optoff = -1; 3512 #endif 3513 evaltree(&func->n, flags & EV_TESTED); 3514 funcdone: 3515 INTOFF; 3516 funcnest--; 3517 freefunc(func); 3518 poplocalvars(); 3519 localvars = savelocalvars; 3520 freeparam(&shellparam); 3521 shellparam = saveparam; 3522 handler = savehandler; 3523 INTON; 3524 evalskip &= ~SKIPFUNC; 3525 return e; 3526 } 3527 3528 3529 static inline int 3530 goodname(const char *p) 3531 { 3532 return !*endofname(p); 3533 } 3534 3535 /* 3536 * Search for a command. This is called before we fork so that the 3537 * location of the command will be available in the parent as well as 3538 * the child. The check for "goodname" is an overly conservative 3539 * check that the name will not be subject to expansion. 3540 */ 3541 3542 static void 3543 prehash(union node *n) 3544 { 3545 struct cmdentry entry; 3546 3547 if (n->type == NCMD && n->ncmd.args) 3548 if (goodname(n->ncmd.args->narg.text)) 3549 find_command(n->ncmd.args->narg.text, &entry, 0, 3550 pathval()); 3551 } 3552 3553 3554 3555 /* 3556 * Builtin commands. Builtin commands whose functions are closely 3557 * tied to evaluation are implemented here. 3558 */ 3559 3560 /* 3561 * No command given. 3562 */ 3563 3564 static int 3565 bltincmd(int argc, char **argv) 3566 { 3567 /* 3568 * Preserve exitstatus of a previous possible redirection 3569 * as POSIX mandates 3570 */ 3571 return back_exitstatus; 3572 } 3573 3574 3575 /* 3576 * Handle break and continue commands. Break, continue, and return are 3577 * all handled by setting the evalskip flag. The evaluation routines 3578 * above all check this flag, and if it is set they start skipping 3579 * commands rather than executing them. The variable skipcount is 3580 * the number of loops to break/continue, or the number of function 3581 * levels to return. (The latter is always 1.) It should probably 3582 * be an error to break out of more loops than exist, but it isn't 3583 * in the standard shell so we don't make it one here. 3584 */ 3585 3586 static int 3587 breakcmd(int argc, char **argv) 3588 { 3589 int n = argc > 1 ? number(argv[1]) : 1; 3590 3591 if (n <= 0) 3592 sh_error(illnum, argv[1]); 3593 if (n > loopnest) 3594 n = loopnest; 3595 if (n > 0) { 3596 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; 3597 skipcount = n; 3598 } 3599 return 0; 3600 } 3601 3602 3603 /* 3604 * The return command. 3605 */ 3606 3607 static int 3608 returncmd(int argc, char **argv) 3609 { 3610 /* 3611 * If called outside a function, do what ksh does; 3612 * skip the rest of the file. 3613 */ 3614 evalskip = funcnest ? SKIPFUNC : SKIPFILE; 3615 return argv[1] ? number(argv[1]) : exitstatus; 3616 } 3617 3618 3619 static int 3620 falsecmd(int argc, char **argv) 3621 { 3622 return 1; 3623 } 3624 3625 3626 static int 3627 truecmd(int argc, char **argv) 3628 { 3629 return 0; 3630 } 3631 3632 3633 static int 3634 execcmd(int argc, char **argv) 3635 { 3636 if (argc > 1) { 3637 iflag = 0; /* exit on error */ 3638 mflag = 0; 3639 optschanged(); 3640 shellexec(argv + 1, pathval(), 0); 3641 } 3642 return 0; 3643 } 3644 3645 3646 /* exec.c */ 3647 3648 /* 3649 * When commands are first encountered, they are entered in a hash table. 3650 * This ensures that a full path search will not have to be done for them 3651 * on each invocation. 3652 * 3653 * We should investigate converting to a linear search, even though that 3654 * would make the command name "hash" a misnomer. 3655 */ 3656 3657 #define CMDTABLESIZE 31 /* should be prime */ 3658 #define ARB 1 /* actual size determined at run time */ 3659 3660 3661 3662 struct tblentry { 3663 struct tblentry *next; /* next entry in hash chain */ 3664 union param param; /* definition of builtin function */ 3665 short cmdtype; /* index identifying command */ 3666 char rehash; /* if set, cd done since entry created */ 3667 char cmdname[ARB]; /* name of command */ 3668 }; 3669 3670 3671 static struct tblentry *cmdtable[CMDTABLESIZE]; 3672 static int builtinloc = -1; /* index in path of %builtin, or -1 */ 3673 3674 3675 static void tryexec(char *, char **, char **); 3676 static void clearcmdentry(int); 3677 static struct tblentry *cmdlookup(const char *, int); 3678 static void delete_cmd_entry(void); 3679 3680 3681 /* 3682 * Exec a program. Never returns. If you change this routine, you may 3683 * have to change the find_command routine as well. 3684 */ 3685 3686 static void 3687 shellexec(char **argv, const char *path, int idx) 3688 { 3689 char *cmdname; 3690 int e; 3691 char **envp; 3692 int exerrno; 3693 3694 clearredir(1); 3695 envp = environment(); 3696 if (strchr(argv[0], '/') != NULL 3697 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL 3698 || find_applet_by_name(argv[0]) 3699 #endif 3700 ) { 3701 tryexec(argv[0], argv, envp); 3702 e = errno; 3703 } else { 3704 e = ENOENT; 3705 while ((cmdname = padvance(&path, argv[0])) != NULL) { 3706 if (--idx < 0 && pathopt == NULL) { 3707 tryexec(cmdname, argv, envp); 3708 if (errno != ENOENT && errno != ENOTDIR) 3709 e = errno; 3710 } 3711 stunalloc(cmdname); 3712 } 3713 } 3714 3715 /* Map to POSIX errors */ 3716 switch (e) { 3717 case EACCES: 3718 exerrno = 126; 3719 break; 3720 case ENOENT: 3721 exerrno = 127; 3235 case S_IGN: 3236 act.sa_handler = SIG_IGN; 3722 3237 break; 3723 3238 default: 3724 exerrno = 2; 3725 break; 3726 } 3727 exitstatus = exerrno; 3728 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n", 3729 argv[0], e, suppressint )); 3730 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC)); 3731 /* NOTREACHED */ 3732 } 3733 3734 3735 static void 3736 tryexec(char *cmd, char **argv, char **envp) 3737 { 3738 int repeated = 0; 3739 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL 3740 if(find_applet_by_name(cmd) != NULL) { 3741 /* re-exec ourselves with the new arguments */ 3742 execve(CONFIG_BUSYBOX_EXEC_PATH,argv,envp); 3743 /* If they called chroot or otherwise made the binary no longer 3744 * executable, fall through */ 3745 } 3746 #endif 3747 3748 repeat: 3749 #ifdef SYSV 3750 do { 3751 execve(cmd, argv, envp); 3752 } while (errno == EINTR); 3753 #else 3754 execve(cmd, argv, envp); 3755 #endif 3756 if (repeated++) { 3757 ckfree(argv); 3758 } else if (errno == ENOEXEC) { 3759 char **ap; 3760 char **new; 3761 3762 for (ap = argv; *ap; ap++) 3763 ; 3764 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *)); 3765 ap[1] = cmd; 3766 *ap = cmd = (char *)DEFAULT_SHELL; 3767 ap += 2; 3768 argv++; 3769 while ((*ap++ = *argv++)) 3770 ; 3771 argv = new; 3772 goto repeat; 3773 } 3774 } 3775 3776 3777 3778 /* 3779 * Do a path search. The variable path (passed by reference) should be 3780 * set to the start of the path before the first call; padvance will update 3781 * this value as it proceeds. Successive calls to padvance will return 3782 * the possible path expansions in sequence. If an option (indicated by 3783 * a percent sign) appears in the path entry then the global variable 3784 * pathopt will be set to point to it; otherwise pathopt will be set to 3785 * NULL. 3786 */ 3787 3788 static char * 3789 padvance(const char **path, const char *name) 3790 { 3791 const char *p; 3792 char *q; 3793 const char *start; 3794 size_t len; 3795 3796 if (*path == NULL) 3797 return NULL; 3798 start = *path; 3799 for (p = start ; *p && *p != ':' && *p != '%' ; p++); 3800 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ 3801 while (stackblocksize() < len) 3802 growstackblock(); 3803 q = stackblock(); 3804 if (p != start) { 3805 memcpy(q, start, p - start); 3806 q += p - start; 3807 *q++ = '/'; 3808 } 3809 strcpy(q, name); 3810 pathopt = NULL; 3811 if (*p == '%') { 3812 pathopt = ++p; 3813 while (*p && *p != ':') p++; 3814 } 3815 if (*p == ':') 3816 *path = p + 1; 3817 else 3818 *path = NULL; 3819 return stalloc(len); 3820 } 3821 3822 3823 /*** Command hashing code ***/ 3824 3825 static void 3826 printentry(struct tblentry *cmdp) 3827 { 3828 int idx; 3829 const char *path; 3830 char *name; 3831 3832 idx = cmdp->param.index; 3833 path = pathval(); 3834 do { 3835 name = padvance(&path, cmdp->cmdname); 3836 stunalloc(name); 3837 } while (--idx >= 0); 3838 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); 3839 } 3840 3841 3842 static int 3843 hashcmd(int argc, char **argv) 3844 { 3845 struct tblentry **pp; 3846 struct tblentry *cmdp; 3847 int c; 3848 struct cmdentry entry; 3849 char *name; 3850 3851 while ((c = nextopt("r")) != '\0') { 3852 clearcmdentry(0); 3853 return 0; 3854 } 3855 if (*argptr == NULL) { 3856 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { 3857 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { 3858 if (cmdp->cmdtype == CMDNORMAL) 3859 printentry(cmdp); 3860 } 3861 } 3862 return 0; 3863 } 3864 c = 0; 3865 while ((name = *argptr) != NULL) { 3866 if ((cmdp = cmdlookup(name, 0)) != NULL 3867 && (cmdp->cmdtype == CMDNORMAL 3868 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) 3869 delete_cmd_entry(); 3870 find_command(name, &entry, DO_ERR, pathval()); 3871 if (entry.cmdtype == CMDUNKNOWN) 3872 c = 1; 3873 argptr++; 3874 } 3875 return c; 3876 } 3877 3878 3879 /* 3880 * Resolve a command name. If you change this routine, you may have to 3881 * change the shellexec routine as well. 3882 */ 3883 3884 static void 3885 find_command(char *name, struct cmdentry *entry, int act, const char *path) 3886 { 3887 struct tblentry *cmdp; 3888 int idx; 3889 int prev; 3890 char *fullname; 3891 struct stat statb; 3892 int e; 3893 int updatetbl; 3894 struct builtincmd *bcmd; 3895 3896 /* If name contains a slash, don't use PATH or hash table */ 3897 if (strchr(name, '/') != NULL) { 3898 entry->u.index = -1; 3899 if (act & DO_ABS) { 3900 while (stat(name, &statb) < 0) { 3901 #ifdef SYSV 3902 if (errno == EINTR) 3903 continue; 3904 #endif 3905 entry->cmdtype = CMDUNKNOWN; 3906 return; 3907 } 3908 } 3909 entry->cmdtype = CMDNORMAL; 3910 return; 3911 } 3912 3913 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL 3914 if (find_applet_by_name(name)) { 3915 entry->cmdtype = CMDNORMAL; 3916 entry->u.index = -1; 3917 return; 3918 } 3919 #endif 3920 3921 updatetbl = (path == pathval()); 3922 if (!updatetbl) { 3923 act |= DO_ALTPATH; 3924 if (strstr(path, "%builtin") != NULL) 3925 act |= DO_ALTBLTIN; 3926 } 3927 3928 /* If name is in the table, check answer will be ok */ 3929 if ((cmdp = cmdlookup(name, 0)) != NULL) { 3930 int bit; 3931 3932 switch (cmdp->cmdtype) { 3933 default: 3934 #if DEBUG 3935 abort(); 3936 #endif 3937 case CMDNORMAL: 3938 bit = DO_ALTPATH; 3939 break; 3940 case CMDFUNCTION: 3941 bit = DO_NOFUNC; 3942 break; 3943 case CMDBUILTIN: 3944 bit = DO_ALTBLTIN; 3945 break; 3946 } 3947 if (act & bit) { 3948 updatetbl = 0; 3949 cmdp = NULL; 3950 } else if (cmdp->rehash == 0) 3951 /* if not invalidated by cd, we're done */ 3952 goto success; 3953 } 3954 3955 /* If %builtin not in path, check for builtin next */ 3956 bcmd = find_builtin(name); 3957 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || ( 3958 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0 3959 ))) 3960 goto builtin_success; 3961 3962 /* We have to search path. */ 3963 prev = -1; /* where to start */ 3964 if (cmdp && cmdp->rehash) { /* doing a rehash */ 3965 if (cmdp->cmdtype == CMDBUILTIN) 3966 prev = builtinloc; 3967 else 3968 prev = cmdp->param.index; 3969 } 3970 3971 e = ENOENT; 3972 idx = -1; 3973 loop: 3974 while ((fullname = padvance(&path, name)) != NULL) { 3975 stunalloc(fullname); 3976 idx++; 3977 if (pathopt) { 3978 if (prefix(pathopt, "builtin")) { 3979 if (bcmd) 3980 goto builtin_success; 3981 continue; 3982 } else if (!(act & DO_NOFUNC) && 3983 prefix(pathopt, "func")) { 3984 /* handled below */ 3985 } else { 3986 /* ignore unimplemented options */ 3987 continue; 3988 } 3989 } 3990 /* if rehash, don't redo absolute path names */ 3991 if (fullname[0] == '/' && idx <= prev) { 3992 if (idx < prev) 3993 continue; 3994 TRACE(("searchexec \"%s\": no change\n", name)); 3995 goto success; 3996 } 3997 while (stat(fullname, &statb) < 0) { 3998 #ifdef SYSV 3999 if (errno == EINTR) 4000 continue; 4001 #endif 4002 if (errno != ENOENT && errno != ENOTDIR) 4003 e = errno; 4004 goto loop; 4005 } 4006 e = EACCES; /* if we fail, this will be the error */ 4007 if (!S_ISREG(statb.st_mode)) 4008 continue; 4009 if (pathopt) { /* this is a %func directory */ 4010 stalloc(strlen(fullname) + 1); 4011 readcmdfile(fullname); 4012 if ((cmdp = cmdlookup(name, 0)) == NULL || 4013 cmdp->cmdtype != CMDFUNCTION) 4014 sh_error("%s not defined in %s", name, fullname); 4015 stunalloc(fullname); 4016 goto success; 4017 } 4018 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); 4019 if (!updatetbl) { 4020 entry->cmdtype = CMDNORMAL; 4021 entry->u.index = idx; 4022 return; 4023 } 4024 INTOFF; 4025 cmdp = cmdlookup(name, 1); 4026 cmdp->cmdtype = CMDNORMAL; 4027 cmdp->param.index = idx; 4028 INTON; 4029 goto success; 4030 } 4031 4032 /* We failed. If there was an entry for this command, delete it */ 4033 if (cmdp && updatetbl) 4034 delete_cmd_entry(); 4035 if (act & DO_ERR) 4036 sh_warnx("%s: %s", name, errmsg(e, E_EXEC)); 4037 entry->cmdtype = CMDUNKNOWN; 4038 return; 4039 4040 builtin_success: 4041 if (!updatetbl) { 4042 entry->cmdtype = CMDBUILTIN; 4043 entry->u.cmd = bcmd; 4044 return; 4045 } 4046 INTOFF; 4047 cmdp = cmdlookup(name, 1); 4048 cmdp->cmdtype = CMDBUILTIN; 4049 cmdp->param.cmd = bcmd; 4050 INTON; 4051 success: 4052 cmdp->rehash = 0; 4053 entry->cmdtype = cmdp->cmdtype; 4054 entry->u = cmdp->param; 4055 } 4056 4057 4058 /* 4059 * Wrapper around strcmp for qsort/bsearch/... 4060 */ 4061 static int pstrcmp(const void *a, const void *b) 4062 { 4063 return strcmp((const char *) a, (*(const char *const *) b) + 1); 4064 } 4065 4066 /* 4067 * Search the table of builtin commands. 4068 */ 4069 4070 static struct builtincmd * 4071 find_builtin(const char *name) 4072 { 4073 struct builtincmd *bp; 4074 4075 bp = bsearch( 4076 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd), 4077 pstrcmp 4078 ); 4079 return bp; 4080 } 4081 4082 4083 4084 /* 4085 * Called when a cd is done. Marks all commands so the next time they 4086 * are executed they will be rehashed. 4087 */ 4088 4089 static void 4090 hashcd(void) 4091 { 4092 struct tblentry **pp; 4093 struct tblentry *cmdp; 4094 4095 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { 4096 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { 4097 if (cmdp->cmdtype == CMDNORMAL || ( 4098 cmdp->cmdtype == CMDBUILTIN && 4099 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) && 4100 builtinloc > 0 4101 )) 4102 cmdp->rehash = 1; 4103 } 4104 } 4105 } 4106 4107 4108 4109 /* 4110 * Fix command hash table when PATH changed. 4111 * Called before PATH is changed. The argument is the new value of PATH; 4112 * pathval() still returns the old value at this point. 4113 * Called with interrupts off. 4114 */ 4115 4116 static void 4117 changepath(const char *newval) 4118 { 4119 const char *old, *new; 4120 int idx; 4121 int firstchange; 4122 int idx_bltin; 4123 4124 old = pathval(); 4125 new = newval; 4126 firstchange = 9999; /* assume no change */ 4127 idx = 0; 4128 idx_bltin = -1; 4129 for (;;) { 4130 if (*old != *new) { 4131 firstchange = idx; 4132 if ((*old == '\0' && *new == ':') 4133 || (*old == ':' && *new == '\0')) 4134 firstchange++; 4135 old = new; /* ignore subsequent differences */ 4136 } 4137 if (*new == '\0') 4138 break; 4139 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin")) 4140 idx_bltin = idx; 4141 if (*new == ':') { 4142 idx++; 4143 } 4144 new++, old++; 4145 } 4146 if (builtinloc < 0 && idx_bltin >= 0) 4147 builtinloc = idx_bltin; /* zap builtins */ 4148 if (builtinloc >= 0 && idx_bltin < 0) 4149 firstchange = 0; 4150 clearcmdentry(firstchange); 4151 builtinloc = idx_bltin; 4152 } 4153 4154 4155 /* 4156 * Clear out command entries. The argument specifies the first entry in 4157 * PATH which has changed. 4158 */ 4159 4160 static void 4161 clearcmdentry(int firstchange) 4162 { 4163 struct tblentry **tblp; 4164 struct tblentry **pp; 4165 struct tblentry *cmdp; 4166 4167 INTOFF; 4168 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) { 4169 pp = tblp; 4170 while ((cmdp = *pp) != NULL) { 4171 if ((cmdp->cmdtype == CMDNORMAL && 4172 cmdp->param.index >= firstchange) 4173 || (cmdp->cmdtype == CMDBUILTIN && 4174 builtinloc >= firstchange)) { 4175 *pp = cmdp->next; 4176 ckfree(cmdp); 4177 } else { 4178 pp = &cmdp->next; 4179 } 4180 } 4181 } 4182 INTON; 4183 } 4184 4185 4186 4187 /* 4188 * Locate a command in the command hash table. If "add" is nonzero, 4189 * add the command to the table if it is not already present. The 4190 * variable "lastcmdentry" is set to point to the address of the link 4191 * pointing to the entry, so that delete_cmd_entry can delete the 4192 * entry. 4193 * 4194 * Interrupts must be off if called with add != 0. 4195 */ 4196 4197 static struct tblentry **lastcmdentry; 4198 4199 4200 static struct tblentry * 4201 cmdlookup(const char *name, int add) 4202 { 4203 unsigned int hashval; 4204 const char *p; 4205 struct tblentry *cmdp; 4206 struct tblentry **pp; 4207 4208 p = name; 4209 hashval = (unsigned char)*p << 4; 4210 while (*p) 4211 hashval += (unsigned char)*p++; 4212 hashval &= 0x7FFF; 4213 pp = &cmdtable[hashval % CMDTABLESIZE]; 4214 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { 4215 if (equal(cmdp->cmdname, name)) 4216 break; 4217 pp = &cmdp->next; 4218 } 4219 if (add && cmdp == NULL) { 4220 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB 4221 + strlen(name) + 1); 4222 cmdp->next = NULL; 4223 cmdp->cmdtype = CMDUNKNOWN; 4224 strcpy(cmdp->cmdname, name); 4225 } 4226 lastcmdentry = pp; 4227 return cmdp; 4228 } 4229 4230 /* 4231 * Delete the command entry returned on the last lookup. 4232 */ 4233 4234 static void 4235 delete_cmd_entry(void) 4236 { 4237 struct tblentry *cmdp; 4238 4239 INTOFF; 4240 cmdp = *lastcmdentry; 4241 *lastcmdentry = cmdp->next; 4242 if (cmdp->cmdtype == CMDFUNCTION) 4243 freefunc(cmdp->param.func); 4244 ckfree(cmdp); 4245 INTON; 4246 } 4247 4248 4249 /* 4250 * Add a new command entry, replacing any existing command entry for 4251 * the same name - except special builtins. 4252 */ 4253 4254 static inline void 4255 addcmdentry(char *name, struct cmdentry *entry) 4256 { 4257 struct tblentry *cmdp; 4258 4259 cmdp = cmdlookup(name, 1); 4260 if (cmdp->cmdtype == CMDFUNCTION) { 4261 freefunc(cmdp->param.func); 4262 } 4263 cmdp->cmdtype = entry->cmdtype; 4264 cmdp->param = entry->u; 4265 cmdp->rehash = 0; 4266 } 4267 4268 /* 4269 * Make a copy of a parse tree. 4270 */ 4271 4272 static inline struct funcnode * 4273 copyfunc(union node *n) 4274 { 4275 struct funcnode *f; 4276 size_t blocksize; 4277 4278 funcblocksize = offsetof(struct funcnode, n); 4279 funcstringsize = 0; 4280 calcsize(n); 4281 blocksize = funcblocksize; 4282 f = ckmalloc(blocksize + funcstringsize); 4283 funcblock = (char *) f + offsetof(struct funcnode, n); 4284 funcstring = (char *) f + blocksize; 4285 copynode(n); 4286 f->count = 0; 4287 return f; 4288 } 4289 4290 /* 4291 * Define a shell function. 4292 */ 4293 4294 static void 4295 defun(char *name, union node *func) 4296 { 4297 struct cmdentry entry; 4298 4299 INTOFF; 4300 entry.cmdtype = CMDFUNCTION; 4301 entry.u.func = copyfunc(func); 4302 addcmdentry(name, &entry); 4303 INTON; 4304 } 4305 4306 4307 /* 4308 * Delete a function if it exists. 4309 */ 4310 4311 static void 4312 unsetfunc(const char *name) 4313 { 4314 struct tblentry *cmdp; 4315 4316 if ((cmdp = cmdlookup(name, 0)) != NULL && 4317 cmdp->cmdtype == CMDFUNCTION) 4318 delete_cmd_entry(); 4319 } 4320 4321 /* 4322 * Locate and print what a word is... 4323 */ 4324 4325 4326 #ifdef CONFIG_ASH_CMDCMD 4327 static int 4328 describe_command(char *command, int describe_command_verbose) 4329 #else 4330 #define describe_command_verbose 1 4331 static int 4332 describe_command(char *command) 4333 #endif 4334 { 4335 struct cmdentry entry; 4336 struct tblentry *cmdp; 4337 #ifdef CONFIG_ASH_ALIAS 4338 const struct alias *ap; 4339 #endif 4340 const char *path = pathval(); 4341 4342 if (describe_command_verbose) { 4343 out1str(command); 4344 } 4345 4346 /* First look at the keywords */ 4347 if (findkwd(command)) { 4348 out1str(describe_command_verbose ? " is a shell keyword" : command); 4349 goto out; 4350 } 4351 4352 #ifdef CONFIG_ASH_ALIAS 4353 /* Then look at the aliases */ 4354 if ((ap = lookupalias(command, 0)) != NULL) { 4355 if (describe_command_verbose) { 4356 out1fmt(" is an alias for %s", ap->val); 4357 } else { 4358 out1str("alias "); 4359 printalias(ap); 4360 return 0; 4361 } 4362 goto out; 4363 } 4364 #endif 4365 /* Then check if it is a tracked alias */ 4366 if ((cmdp = cmdlookup(command, 0)) != NULL) { 4367 entry.cmdtype = cmdp->cmdtype; 4368 entry.u = cmdp->param; 4369 } else { 4370 /* Finally use brute force */ 4371 find_command(command, &entry, DO_ABS, path); 4372 } 4373 4374 switch (entry.cmdtype) { 4375 case CMDNORMAL: { 4376 int j = entry.u.index; 4377 char *p; 4378 if (j == -1) { 4379 p = command; 4380 } else { 4381 do { 4382 p = padvance(&path, command); 4383 stunalloc(p); 4384 } while (--j >= 0); 4385 } 4386 if (describe_command_verbose) { 4387 out1fmt(" is%s %s", 4388 (cmdp ? " a tracked alias for" : nullstr), p 4389 ); 4390 } else { 4391 out1str(p); 4392 } 4393 break; 4394 } 4395 4396 case CMDFUNCTION: 4397 if (describe_command_verbose) { 4398 out1str(" is a shell function"); 4399 } else { 4400 out1str(command); 4401 } 4402 break; 4403 4404 case CMDBUILTIN: 4405 if (describe_command_verbose) { 4406 out1fmt(" is a %sshell builtin", 4407 IS_BUILTIN_SPECIAL(entry.u.cmd) ? 4408 "special " : nullstr 4409 ); 4410 } else { 4411 out1str(command); 4412 } 4413 break; 4414 4415 default: 4416 if (describe_command_verbose) { 4417 out1str(": not found\n"); 4418 } 4419 return 127; 4420 } 4421 4422 out: 4423 outstr("\n", stdout); 4424 return 0; 4425 } 4426 4427 static int 4428 typecmd(int argc, char **argv) 4429 { 4430 int i; 4431 int err = 0; 4432 4433 for (i = 1; i < argc; i++) { 4434 #ifdef CONFIG_ASH_CMDCMD 4435 err |= describe_command(argv[i], 1); 4436 #else 4437 err |= describe_command(argv[i]); 4438 #endif 4439 } 4440 return err; 4441 } 4442 4443 #ifdef CONFIG_ASH_CMDCMD 4444 static int 4445 commandcmd(int argc, char **argv) 4446 { 4447 int c; 4448 enum { 4449 VERIFY_BRIEF = 1, 4450 VERIFY_VERBOSE = 2, 4451 } verify = 0; 4452 4453 while ((c = nextopt("pvV")) != '\0') 4454 if (c == 'V') 4455 verify |= VERIFY_VERBOSE; 4456 else if (c == 'v') 4457 verify |= VERIFY_BRIEF; 4458 #ifdef DEBUG 4459 else if (c != 'p') 4460 abort(); 4461 #endif 4462 if (verify) 4463 return describe_command(*argptr, verify - VERIFY_BRIEF); 4464 4465 return 0; 4466 } 4467 #endif 4468 4469 /* expand.c */ 4470 4471 /* 4472 * Routines to expand arguments to commands. We have to deal with 4473 * backquotes, shell variables, and file metacharacters. 4474 */ 4475 4476 /* 4477 * _rmescape() flags 4478 */ 4479 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ 4480 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ 4481 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */ 4482 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ 4483 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ 4484 4485 /* 4486 * Structure specifying which parts of the string should be searched 4487 * for IFS characters. 4488 */ 4489 4490 struct ifsregion { 4491 struct ifsregion *next; /* next region in list */ 4492 int begoff; /* offset of start of region */ 4493 int endoff; /* offset of end of region */ 4494 int nulonly; /* search for nul bytes only */ 4495 }; 4496 4497 /* output of current string */ 4498 static char *expdest; 4499 /* list of back quote expressions */ 4500 static struct nodelist *argbackq; 4501 /* first struct in list of ifs regions */ 4502 static struct ifsregion ifsfirst; 4503 /* last struct in list */ 4504 static struct ifsregion *ifslastp; 4505 /* holds expanded arg list */ 4506 static struct arglist exparg; 4507 4508 static void argstr(char *, int); 4509 static char *exptilde(char *, char *, int); 4510 static void expbackq(union node *, int, int); 4511 static const char *subevalvar(char *, char *, int, int, int, int, int); 4512 static char *evalvar(char *, int); 4513 static void strtodest(const char *, int, int); 4514 static void memtodest(const char *p, size_t len, int syntax, int quotes); 4515 static ssize_t varvalue(char *, int, int); 4516 static void recordregion(int, int, int); 4517 static void removerecordregions(int); 4518 static void ifsbreakup(char *, struct arglist *); 4519 static void ifsfree(void); 4520 static void expandmeta(struct strlist *, int); 4521 static int patmatch(char *, const char *); 4522 4523 static int cvtnum(arith_t); 4524 static size_t esclen(const char *, const char *); 4525 static char *scanleft(char *, char *, char *, char *, int, int); 4526 static char *scanright(char *, char *, char *, char *, int, int); 4527 static void varunset(const char *, const char *, const char *, int) 4528 ATTRIBUTE_NORETURN; 4529 4530 4531 #define pmatch(a, b) !fnmatch((a), (b), 0) 4532 /* 4533 * Prepare a pattern for a expmeta (internal glob(3)) call. 4534 * 4535 * Returns an stalloced string. 4536 */ 4537 4538 static inline char * 4539 preglob(const char *pattern, int quoted, int flag) { 4540 flag |= RMESCAPE_GLOB; 4541 if (quoted) { 4542 flag |= RMESCAPE_QUOTED; 4543 } 4544 return _rmescapes((char *)pattern, flag); 4545 } 4546 4547 4548 static size_t 4549 esclen(const char *start, const char *p) { 4550 size_t esc = 0; 4551 4552 while (p > start && *--p == CTLESC) { 4553 esc++; 4554 } 4555 return esc; 4556 } 4557 4558 4559 /* 4560 * Expand shell variables and backquotes inside a here document. 4561 */ 4562 4563 static inline void 4564 expandhere(union node *arg, int fd) 4565 { 4566 herefd = fd; 4567 expandarg(arg, (struct arglist *)NULL, 0); 4568 bb_full_write(fd, stackblock(), expdest - (char *)stackblock()); 4569 } 4570 4571 4572 /* 4573 * Perform variable substitution and command substitution on an argument, 4574 * placing the resulting list of arguments in arglist. If EXP_FULL is true, 4575 * perform splitting and file name expansion. When arglist is NULL, perform 4576 * here document expansion. 4577 */ 4578 4579 void 4580 expandarg(union node *arg, struct arglist *arglist, int flag) 4581 { 4582 struct strlist *sp; 4583 char *p; 4584 4585 argbackq = arg->narg.backquote; 4586 STARTSTACKSTR(expdest); 4587 ifsfirst.next = NULL; 4588 ifslastp = NULL; 4589 argstr(arg->narg.text, flag); 4590 p = _STPUTC('\0', expdest); 4591 expdest = p - 1; 4592 if (arglist == NULL) { 4593 return; /* here document expanded */ 4594 } 4595 p = grabstackstr(p); 4596 exparg.lastp = &exparg.list; 4597 /* 4598 * TODO - EXP_REDIR 4599 */ 4600 if (flag & EXP_FULL) { 4601 ifsbreakup(p, &exparg); 4602 *exparg.lastp = NULL; 4603 exparg.lastp = &exparg.list; 4604 expandmeta(exparg.list, flag); 4605 } else { 4606 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ 4607 rmescapes(p); 4608 sp = (struct strlist *)stalloc(sizeof (struct strlist)); 4609 sp->text = p; 4610 *exparg.lastp = sp; 4611 exparg.lastp = &sp->next; 4612 } 4613 if (ifsfirst.next) 4614 ifsfree(); 4615 *exparg.lastp = NULL; 4616 if (exparg.list) { 4617 *arglist->lastp = exparg.list; 4618 arglist->lastp = exparg.lastp; 4619 } 4620 } 4621 4622 4623 /* 4624 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC 4625 * characters to allow for further processing. Otherwise treat 4626 * $@ like $* since no splitting will be performed. 4627 */ 4628 4629 static void 4630 argstr(char *p, int flag) 4631 { 4632 static const char spclchars[] = { 4633 '=', 4634 ':', 4635 CTLQUOTEMARK, 4636 CTLENDVAR, 4637 CTLESC, 4638 CTLVAR, 4639 CTLBACKQ, 4640 CTLBACKQ | CTLQUOTE, 4641 #ifdef CONFIG_ASH_MATH_SUPPORT 4642 CTLENDARI, 4643 #endif 4644 0 4645 }; 4646 const char *reject = spclchars; 4647 int c; 4648 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ 4649 int breakall = flag & EXP_WORD; 4650 int inquotes; 4651 size_t length; 4652 int startloc; 4653 4654 if (!(flag & EXP_VARTILDE)) { 4655 reject += 2; 4656 } else if (flag & EXP_VARTILDE2) { 4657 reject++; 4658 } 4659 inquotes = 0; 4660 length = 0; 4661 if (flag & EXP_TILDE) { 4662 char *q; 4663 4664 flag &= ~EXP_TILDE; 4665 tilde: 4666 q = p; 4667 if (*q == CTLESC && (flag & EXP_QWORD)) 4668 q++; 4669 if (*q == '~') 4670 p = exptilde(p, q, flag); 4671 } 4672 start: 4673 startloc = expdest - (char *)stackblock(); 4674 for (;;) { 4675 length += strcspn(p + length, reject); 4676 c = p[length]; 4677 if (c && (!(c & 0x80) 4678 #ifdef CONFIG_ASH_MATH_SUPPORT 4679 || c == CTLENDARI 4680 #endif 4681 )) { 4682 /* c == '=' || c == ':' || c == CTLENDARI */ 4683 length++; 4684 } 4685 if (length > 0) { 4686 int newloc; 4687 expdest = stnputs(p, length, expdest); 4688 newloc = expdest - (char *)stackblock(); 4689 if (breakall && !inquotes && newloc > startloc) { 4690 recordregion(startloc, newloc, 0); 4691 } 4692 startloc = newloc; 4693 } 4694 p += length + 1; 4695 length = 0; 4696 4697 switch (c) { 4698 case '\0': 4699 goto breakloop; 4700 case '=': 4701 if (flag & EXP_VARTILDE2) { 4702 p--; 4703 continue; 4704 } 4705 flag |= EXP_VARTILDE2; 4706 reject++; 4707 /* fall through */ 4708 case ':': 4709 /* 4710 * sort of a hack - expand tildes in variable 4711 * assignments (after the first '=' and after ':'s). 4712 */ 4713 if (*--p == '~') { 4714 goto tilde; 4715 } 4716 continue; 4717 } 4718 4719 switch (c) { 4720 case CTLENDVAR: /* ??? */ 4721 goto breakloop; 4722 case CTLQUOTEMARK: 4723 /* "$@" syntax adherence hack */ 4724 if ( 4725 !inquotes && 4726 !memcmp(p, dolatstr, DOLATSTRLEN) && 4727 (p[4] == CTLQUOTEMARK || ( 4728 p[4] == CTLENDVAR && 4729 p[5] == CTLQUOTEMARK 4730 )) 4731 ) { 4732 p = evalvar(p + 1, flag) + 1; 4733 goto start; 4734 } 4735 inquotes = !inquotes; 4736 addquote: 4737 if (quotes) { 4738 p--; 4739 length++; 4740 startloc++; 4741 } 4742 break; 4743 case CTLESC: 4744 startloc++; 4745 length++; 4746 goto addquote; 4747 case CTLVAR: 4748 p = evalvar(p, flag); 4749 goto start; 4750 case CTLBACKQ: 4751 c = 0; 4752 case CTLBACKQ|CTLQUOTE: 4753 expbackq(argbackq->n, c, quotes); 4754 argbackq = argbackq->next; 4755 goto start; 4756 #ifdef CONFIG_ASH_MATH_SUPPORT 4757 case CTLENDARI: 4758 p--; 4759 expari(quotes); 4760 goto start; 4761 #endif 4762 } 4763 } 4764 breakloop: 4765 ; 4766 } 4767 4768 static char * 4769 exptilde(char *startp, char *p, int flag) 4770 { 4771 char c; 4772 char *name; 4773 struct passwd *pw; 4774 const char *home; 4775 int quotes = flag & (EXP_FULL | EXP_CASE); 4776 int startloc; 4777 4778 name = p + 1; 4779 4780 while ((c = *++p) != '\0') { 4781 switch(c) { 4782 case CTLESC: 4783 return (startp); 4784 case CTLQUOTEMARK: 4785 return (startp); 4786 case ':': 4787 if (flag & EXP_VARTILDE) 4788 goto done; 4789 break; 4790 case '/': 4791 case CTLENDVAR: 4792 goto done; 4793 } 4794 } 4795 done: 4796 *p = '\0'; 4797 if (*name == '\0') { 4798 home = lookupvar(homestr); 4799 } else { 4800 if ((pw = getpwnam(name)) == NULL) 4801 goto lose; 4802 home = pw->pw_dir; 4803 } 4804 if (!home || !*home) 4805 goto lose; 4806 *p = c; 4807 startloc = expdest - (char *)stackblock(); 4808 strtodest(home, SQSYNTAX, quotes); 4809 recordregion(startloc, expdest - (char *)stackblock(), 0); 4810 return (p); 4811 lose: 4812 *p = c; 4813 return (startp); 4814 } 4815 4816 4817 static void 4818 removerecordregions(int endoff) 4819 { 4820 if (ifslastp == NULL) 4821 return; 4822 4823 if (ifsfirst.endoff > endoff) { 4824 while (ifsfirst.next != NULL) { 4825 struct ifsregion *ifsp; 4826 INTOFF; 4827 ifsp = ifsfirst.next->next; 4828 ckfree(ifsfirst.next); 4829 ifsfirst.next = ifsp; 4830 INTON; 4831 } 4832 if (ifsfirst.begoff > endoff) 4833 ifslastp = NULL; 4834 else { 4835 ifslastp = &ifsfirst; 4836 ifsfirst.endoff = endoff; 4837 } 4838 return; 4839 } 4840 4841 ifslastp = &ifsfirst; 4842 while (ifslastp->next && ifslastp->next->begoff < endoff) 4843 ifslastp=ifslastp->next; 4844 while (ifslastp->next != NULL) { 4845 struct ifsregion *ifsp; 4846 INTOFF; 4847 ifsp = ifslastp->next->next; 4848 ckfree(ifslastp->next); 4849 ifslastp->next = ifsp; 4850 INTON; 4851 } 4852 if (ifslastp->endoff > endoff) 4853 ifslastp->endoff = endoff; 4854 } 4855 4856 4857 #ifdef CONFIG_ASH_MATH_SUPPORT 4858 /* 4859 * Expand arithmetic expression. Backup to start of expression, 4860 * evaluate, place result in (backed up) result, adjust string position. 4861 */ 4862 void 4863 expari(int quotes) 4864 { 4865 char *p, *start; 4866 int begoff; 4867 int flag; 4868 int len; 4869 4870 /* ifsfree(); */ 4871 4872 /* 4873 * This routine is slightly over-complicated for 4874 * efficiency. Next we scan backwards looking for the 4875 * start of arithmetic. 4876 */ 4877 start = stackblock(); 4878 p = expdest - 1; 4879 *p = '\0'; 4880 p--; 4881 do { 4882 int esc; 4883 4884 while (*p != CTLARI) { 4885 p--; 4886 #ifdef DEBUG 4887 if (p < start) { 4888 sh_error("missing CTLARI (shouldn't happen)"); 4889 } 4890 #endif 4891 } 4892 4893 esc = esclen(start, p); 4894 if (!(esc % 2)) { 4895 break; 4896 } 4897 4898 p -= esc + 1; 4899 } while (1); 4900 4901 begoff = p - start; 4902 4903 removerecordregions(begoff); 4904 4905 flag = p[1]; 4906 4907 expdest = p; 4908 4909 if (quotes) 4910 rmescapes(p + 2); 4911 4912 len = cvtnum(dash_arith(p + 2)); 4913 4914 if (flag != '"') 4915 recordregion(begoff, begoff + len, 0); 4916 } 4917 #endif 4918 4919 /* 4920 * Expand stuff in backwards quotes. 4921 */ 4922 4923 static void 4924 expbackq(union node *cmd, int quoted, int quotes) 4925 { 4926 struct backcmd in; 4927 int i; 4928 char buf[128]; 4929 char *p; 4930 char *dest; 4931 int startloc; 4932 int syntax = quoted? DQSYNTAX : BASESYNTAX; 4933 struct stackmark smark; 4934 4935 INTOFF; 4936 setstackmark(&smark); 4937 dest = expdest; 4938 startloc = dest - (char *)stackblock(); 4939 grabstackstr(dest); 4940 evalbackcmd(cmd, (struct backcmd *) &in); 4941 popstackmark(&smark); 4942 4943 p = in.buf; 4944 i = in.nleft; 4945 if (i == 0) 4946 goto read; 4947 for (;;) { 4948 memtodest(p, i, syntax, quotes); 4949 read: 4950 if (in.fd < 0) 4951 break; 4952 i = safe_read(in.fd, buf, sizeof buf); 4953 TRACE(("expbackq: read returns %d\n", i)); 4954 if (i <= 0) 4955 break; 4956 p = buf; 4957 } 4958 4959 if (in.buf) 4960 ckfree(in.buf); 4961 if (in.fd >= 0) { 4962 close(in.fd); 4963 back_exitstatus = waitforjob(in.jp); 4964 } 4965 INTON; 4966 4967 /* Eat all trailing newlines */ 4968 dest = expdest; 4969 for (; dest > (char *)stackblock() && dest[-1] == '\n';) 4970 STUNPUTC(dest); 4971 expdest = dest; 4972 4973 if (quoted == 0) 4974 recordregion(startloc, dest - (char *)stackblock(), 0); 4975 TRACE(("evalbackq: size=%d: \"%.*s\"\n", 4976 (dest - (char *)stackblock()) - startloc, 4977 (dest - (char *)stackblock()) - startloc, 4978 stackblock() + startloc)); 4979 } 4980 4981 4982 static char * 4983 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes, 4984 int zero) 4985 { 4986 char *loc; 4987 char *loc2; 4988 char c; 4989 4990 loc = startp; 4991 loc2 = rmesc; 4992 do { 4993 int match; 4994 const char *s = loc2; 4995 c = *loc2; 4996 if (zero) { 4997 *loc2 = '\0'; 4998 s = rmesc; 4999 } 5000 match = pmatch(str, s); 5001 *loc2 = c; 5002 if (match) 5003 return loc; 5004 if (quotes && *loc == CTLESC) 5005 loc++; 5006 loc++; 5007 loc2++; 5008 } while (c); 5009 return 0; 5010 } 5011 5012 5013 static char * 5014 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes, 5015 int zero) 5016 { 5017 int esc = 0; 5018 char *loc; 5019 char *loc2; 5020 5021 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) { 5022 int match; 5023 char c = *loc2; 5024 const char *s = loc2; 5025 if (zero) { 5026 *loc2 = '\0'; 5027 s = rmesc; 5028 } 5029 match = pmatch(str, s); 5030 *loc2 = c; 5031 if (match) 5032 return loc; 5033 loc--; 5034 if (quotes) { 5035 if (--esc < 0) { 5036 esc = esclen(startp, loc); 5037 } 5038 if (esc % 2) { 5039 esc--; 5040 loc--; 5041 } 5042 } 5043 } 5044 return 0; 5045 } 5046 5047 static const char * 5048 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes) 5049 { 5050 char *startp; 5051 char *loc; 5052 int saveherefd = herefd; 5053 struct nodelist *saveargbackq = argbackq; 5054 int amount; 5055 char *rmesc, *rmescend; 5056 int zero; 5057 char *(*scan)(char *, char *, char *, char *, int , int); 5058 5059 herefd = -1; 5060 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0); 5061 STPUTC('\0', expdest); 5062 herefd = saveherefd; 5063 argbackq = saveargbackq; 5064 startp = stackblock() + startloc; 5065 5066 switch (subtype) { 5067 case VSASSIGN: 5068 setvar(str, startp, 0); 5069 amount = startp - expdest; 5070 STADJUST(amount, expdest); 5071 return startp; 5072 5073 case VSQUESTION: 5074 varunset(p, str, startp, varflags); 5075 /* NOTREACHED */ 5076 } 5077 5078 subtype -= VSTRIMRIGHT; 5079 #ifdef DEBUG 5080 if (subtype < 0 || subtype > 3) 5081 abort(); 5082 #endif 5083 5084 rmesc = startp; 5085 rmescend = stackblock() + strloc; 5086 if (quotes) { 5087 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW); 5088 if (rmesc != startp) { 5089 rmescend = expdest; 5090 startp = stackblock() + startloc; 5091 } 5092 } 5093 rmescend--; 5094 str = stackblock() + strloc; 5095 preglob(str, varflags & VSQUOTE, 0); 5096 5097 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */ 5098 zero = subtype >> 1; 5099 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */ 5100 scan = (subtype & 1) ^ zero ? scanleft : scanright; 5101 5102 loc = scan(startp, rmesc, rmescend, str, quotes, zero); 5103 if (loc) { 5104 if (zero) { 5105 memmove(startp, loc, str - loc); 5106 loc = startp + (str - loc) - 1; 5107 } 5108 *loc = '\0'; 5109 amount = loc - expdest; 5110 STADJUST(amount, expdest); 5111 } 5112 return loc; 5113 } 5114 5115 5116 /* 5117 * Expand a variable, and return a pointer to the next character in the 5118 * input string. 5119 */ 5120 static char * 5121 evalvar(char *p, int flag) 5122 { 5123 int subtype; 5124 int varflags; 5125 char *var; 5126 int patloc; 5127 int c; 5128 int startloc; 5129 ssize_t varlen; 5130 int easy; 5131 int quotes; 5132 int quoted; 5133 5134 quotes = flag & (EXP_FULL | EXP_CASE); 5135 varflags = *p++; 5136 subtype = varflags & VSTYPE; 5137 quoted = varflags & VSQUOTE; 5138 var = p; 5139 easy = (!quoted || (*var == '@' && shellparam.nparam)); 5140 startloc = expdest - (char *)stackblock(); 5141 p = strchr(p, '=') + 1; 5142 5143 again: 5144 varlen = varvalue(var, varflags, flag); 5145 if (varflags & VSNUL) 5146 varlen--; 5147 5148 if (subtype == VSPLUS) { 5149 varlen = -1 - varlen; 5150 goto vsplus; 5151 } 5152 5153 if (subtype == VSMINUS) { 5154 vsplus: 5155 if (varlen < 0) { 5156 argstr( 5157 p, flag | EXP_TILDE | 5158 (quoted ? EXP_QWORD : EXP_WORD) 5159 ); 5160 goto end; 5161 } 5162 if (easy) 5163 goto record; 5164 goto end; 5165 } 5166 5167 if (subtype == VSASSIGN || subtype == VSQUESTION) { 5168 if (varlen < 0) { 5169 if (subevalvar(p, var, 0, subtype, startloc, 5170 varflags, 0)) { 5171 varflags &= ~VSNUL; 5172 /* 5173 * Remove any recorded regions beyond 5174 * start of variable 5175 */ 5176 removerecordregions(startloc); 5177 goto again; 5178 } 5179 goto end; 5180 } 5181 if (easy) 5182 goto record; 5183 goto end; 5184 } 5185 5186 if (varlen < 0 && uflag) 5187 varunset(p, var, 0, 0); 5188 5189 if (subtype == VSLENGTH) { 5190 cvtnum(varlen > 0 ? varlen : 0); 5191 goto record; 5192 } 5193 5194 if (subtype == VSNORMAL) { 5195 if (!easy) 5196 goto end; 5197 record: 5198 recordregion(startloc, expdest - (char *)stackblock(), quoted); 5199 goto end; 5200 } 5201 5202 #ifdef DEBUG 5203 switch (subtype) { 5204 case VSTRIMLEFT: 5205 case VSTRIMLEFTMAX: 5206 case VSTRIMRIGHT: 5207 case VSTRIMRIGHTMAX: 5208 break; 5209 default: 5210 abort(); 5211 } 5212 #endif 5213 5214 if (varlen >= 0) { 5215 /* 5216 * Terminate the string and start recording the pattern 5217 * right after it 5218 */ 5219 STPUTC('\0', expdest); 5220 patloc = expdest - (char *)stackblock(); 5221 if (subevalvar(p, NULL, patloc, subtype, 5222 startloc, varflags, quotes) == 0) { 5223 int amount = expdest - ( 5224 (char *)stackblock() + patloc - 1 5225 ); 5226 STADJUST(-amount, expdest); 5227 } 5228 /* Remove any recorded regions beyond start of variable */ 5229 removerecordregions(startloc); 5230 goto record; 5231 } 5232 5233 end: 5234 if (subtype != VSNORMAL) { /* skip to end of alternative */ 5235 int nesting = 1; 5236 for (;;) { 5237 if ((c = *p++) == CTLESC) 5238 p++; 5239 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { 5240 if (varlen >= 0) 5241 argbackq = argbackq->next; 5242 } else if (c == CTLVAR) { 5243 if ((*p++ & VSTYPE) != VSNORMAL) 5244 nesting++; 5245 } else if (c == CTLENDVAR) { 5246 if (--nesting == 0) 5247 break; 5248 } 5249 } 5250 } 5251 return p; 5252 } 5253 5254 5255 /* 5256 * Put a string on the stack. 5257 */ 5258 5259 static void 5260 memtodest(const char *p, size_t len, int syntax, int quotes) { 5261 char *q = expdest; 5262 5263 q = makestrspace(len * 2, q); 5264 5265 while (len--) { 5266 int c = SC2INT(*p++); 5267 if (!c) 5268 continue; 5269 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK)) 5270 USTPUTC(CTLESC, q); 5271 USTPUTC(c, q); 5272 } 5273 5274 expdest = q; 5275 } 5276 5277 5278 static void 5279 strtodest(const char *p, int syntax, int quotes) 5280 { 5281 memtodest(p, strlen(p), syntax, quotes); 5282 } 5283 5284 5285 /* 5286 * Add the value of a specialized variable to the stack string. 5287 */ 5288 5289 static ssize_t 5290 varvalue(char *name, int varflags, int flags) 5291 { 5292 int num; 5293 char *p; 5294 int i; 5295 int sep = 0; 5296 int sepq = 0; 5297 ssize_t len = 0; 5298 char **ap; 5299 int syntax; 5300 int quoted = varflags & VSQUOTE; 5301 int subtype = varflags & VSTYPE; 5302 int quotes = flags & (EXP_FULL | EXP_CASE); 5303 5304 if (quoted && (flags & EXP_FULL)) 5305 sep = 1 << CHAR_BIT; 5306 5307 syntax = quoted ? DQSYNTAX : BASESYNTAX; 5308 switch (*name) { 5309 case '$': 5310 num = rootpid; 5311 goto numvar; 5312 case '?': 5313 num = exitstatus; 5314 goto numvar; 5315 case '#': 5316 num = shellparam.nparam; 5317 goto numvar; 5318 case '!': 5319 num = backgndpid; 5320 if (num == 0) 5321 return -1; 5322 numvar: 5323 len = cvtnum(num); 5324 break; 5325 case '-': 5326 p = makestrspace(NOPTS, expdest); 5327 for (i = NOPTS - 1; i >= 0; i--) { 5328 if (optlist[i]) { 5329 USTPUTC(optletters(i), p); 5330 len++; 5331 } 5332 } 5333 expdest = p; 5334 break; 5335 case '@': 5336 if (sep) 5337 goto param; 5338 /* fall through */ 5339 case '*': 5340 sep = ifsset() ? SC2INT(ifsval()[0]) : ' '; 5341 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK)) 5342 sepq = 1; 5343 param: 5344 if (!(ap = shellparam.p)) 5345 return -1; 5346 while ((p = *ap++)) { 5347 size_t partlen; 5348 5349 partlen = strlen(p); 5350 len += partlen; 5351 5352 if (!(subtype == VSPLUS || subtype == VSLENGTH)) 5353 memtodest(p, partlen, syntax, quotes); 5354 5355 if (*ap && sep) { 5356 char *q; 5357 5358 len++; 5359 if (subtype == VSPLUS || subtype == VSLENGTH) { 5360 continue; 5361 } 5362 q = expdest; 5363 if (sepq) 5364 STPUTC(CTLESC, q); 5365 STPUTC(sep, q); 5366 expdest = q; 5367 } 5368 } 5369 return len; 5370 case '0': 5371 case '1': 5372 case '2': 5373 case '3': 5374 case '4': 5375 case '5': 5376 case '6': 5377 case '7': 5378 case '8': 5379 case '9': 5380 num = atoi(name); 5381 if (num < 0 || num > shellparam.nparam) 5382 return -1; 5383 p = num ? shellparam.p[num - 1] : arg0; 5384 goto value; 5385 default: 5386 p = lookupvar(name); 5387 value: 5388 if (!p) 5389 return -1; 5390 5391 len = strlen(p); 5392 if (!(subtype == VSPLUS || subtype == VSLENGTH)) 5393 memtodest(p, len, syntax, quotes); 5394 return len; 5395 } 5396 5397 if (subtype == VSPLUS || subtype == VSLENGTH) 5398 STADJUST(-len, expdest); 5399 return len; 5400 } 5401 5402 5403 /* 5404 * Record the fact that we have to scan this region of the 5405 * string for IFS characters. 5406 */ 5407 5408 static void 5409 recordregion(int start, int end, int nulonly) 5410 { 5411 struct ifsregion *ifsp; 5412 5413 if (ifslastp == NULL) { 5414 ifsp = &ifsfirst; 5415 } else { 5416 INTOFF; 5417 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion)); 5418 ifsp->next = NULL; 5419 ifslastp->next = ifsp; 5420 INTON; 5421 } 5422 ifslastp = ifsp; 5423 ifslastp->begoff = start; 5424 ifslastp->endoff = end; 5425 ifslastp->nulonly = nulonly; 5426 } 5427 5428 5429 /* 5430 * Break the argument string into pieces based upon IFS and add the 5431 * strings to the argument list. The regions of the string to be 5432 * searched for IFS characters have been stored by recordregion. 5433 */ 5434 static void 5435 ifsbreakup(char *string, struct arglist *arglist) 5436 { 5437 struct ifsregion *ifsp; 5438 struct strlist *sp; 5439 char *start; 5440 char *p; 5441 char *q; 5442 const char *ifs, *realifs; 5443 int ifsspc; 5444 int nulonly; 5445 5446 5447 start = string; 5448 if (ifslastp != NULL) { 5449 ifsspc = 0; 5450 nulonly = 0; 5451 realifs = ifsset() ? ifsval() : defifs; 5452 ifsp = &ifsfirst; 5453 do { 5454 p = string + ifsp->begoff; 5455 nulonly = ifsp->nulonly; 5456 ifs = nulonly ? nullstr : realifs; 5457 ifsspc = 0; 5458 while (p < string + ifsp->endoff) { 5459 q = p; 5460 if (*p == CTLESC) 5461 p++; 5462 if (strchr(ifs, *p)) { 5463 if (!nulonly) 5464 ifsspc = (strchr(defifs, *p) != NULL); 5465 /* Ignore IFS whitespace at start */ 5466 if (q == start && ifsspc) { 5467 p++; 5468 start = p; 5469 continue; 5470 } 5471 *q = '\0'; 5472 sp = (struct strlist *)stalloc(sizeof *sp); 5473 sp->text = start; 5474 *arglist->lastp = sp; 5475 arglist->lastp = &sp->next; 5476 p++; 5477 if (!nulonly) { 5478 for (;;) { 5479 if (p >= string + ifsp->endoff) { 5480 break; 5481 } 5482 q = p; 5483 if (*p == CTLESC) 5484 p++; 5485 if (strchr(ifs, *p) == NULL ) { 5486 p = q; 5487 break; 5488 } else if (strchr(defifs, *p) == NULL) { 5489 if (ifsspc) { 5490 p++; 5491 ifsspc = 0; 5492 } else { 5493 p = q; 5494 break; 5495 } 5496 } else 5497 p++; 5498 } 5499 } 5500 start = p; 5501 } else 5502 p++; 5503 } 5504 } while ((ifsp = ifsp->next) != NULL); 5505 if (nulonly) 5506 goto add; 5507 } 5508 5509 if (!*start) 5510 return; 5511 5512 add: 5513 sp = (struct strlist *)stalloc(sizeof *sp); 5514 sp->text = start; 5515 *arglist->lastp = sp; 5516 arglist->lastp = &sp->next; 5517 } 5518 5519 static void 5520 ifsfree(void) 5521 { 5522 struct ifsregion *p; 5523 5524 INTOFF; 5525 p = ifsfirst.next; 5526 do { 5527 struct ifsregion *ifsp; 5528 ifsp = p->next; 5529 ckfree(p); 5530 p = ifsp; 5531 } while (p); 5532 ifslastp = NULL; 5533 ifsfirst.next = NULL; 5534 INTON; 5535 } 5536 5537 static void expmeta(char *, char *); 5538 static struct strlist *expsort(struct strlist *); 5539 static struct strlist *msort(struct strlist *, int); 5540 5541 static char *expdir; 5542 5543 5544 static void 5545 expandmeta(struct strlist *str, int flag) 5546 { 5547 static const char metachars[] = { 5548 '*', '?', '[', 0 5549 }; 5550 /* TODO - EXP_REDIR */ 5551 5552 while (str) { 5553 struct strlist **savelastp; 5554 struct strlist *sp; 5555 char *p; 5556 5557 if (fflag) 5558 goto nometa; 5559 if (!strpbrk(str->text, metachars)) 5560 goto nometa; 5561 savelastp = exparg.lastp; 5562 5563 INTOFF; 5564 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); 5565 { 5566 int i = strlen(str->text); 5567 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ 5568 } 5569 5570 expmeta(expdir, p); 5571 ckfree(expdir); 5572 if (p != str->text) 5573 ckfree(p); 5574 INTON; 5575 if (exparg.lastp == savelastp) { 5576 /* 5577 * no matches 5578 */ 5579 nometa: 5580 *exparg.lastp = str; 5581 rmescapes(str->text); 5582 exparg.lastp = &str->next; 5583 } else { 5584 *exparg.lastp = NULL; 5585 *savelastp = sp = expsort(*savelastp); 5586 while (sp->next != NULL) 5587 sp = sp->next; 5588 exparg.lastp = &sp->next; 5589 } 5590 str = str->next; 5591 } 5592 } 5593 5594 /* 5595 * Add a file name to the list. 5596 */ 5597 5598 static void 5599 addfname(const char *name) 5600 { 5601 struct strlist *sp; 5602 5603 sp = (struct strlist *)stalloc(sizeof *sp); 5604 sp->text = sstrdup(name); 5605 *exparg.lastp = sp; 5606 exparg.lastp = &sp->next; 5607 } 5608 5609 5610 /* 5611 * Do metacharacter (i.e. *, ?, [...]) expansion. 5612 */ 5613 5614 static void 5615 expmeta(char *enddir, char *name) 5616 { 5617 char *p; 5618 const char *cp; 5619 char *start; 5620 char *endname; 5621 int metaflag; 5622 struct stat statb; 5623 DIR *dirp; 5624 struct dirent *dp; 5625 int atend; 5626 int matchdot; 5627 5628 metaflag = 0; 5629 start = name; 5630 for (p = name; *p; p++) { 5631 if (*p == '*' || *p == '?') 5632 metaflag = 1; 5633 else if (*p == '[') { 5634 char *q = p + 1; 5635 if (*q == '!') 5636 q++; 5637 for (;;) { 5638 if (*q == '\\') 5639 q++; 5640 if (*q == '/' || *q == '\0') 5641 break; 5642 if (*++q == ']') { 5643 metaflag = 1; 5644 break; 5645 } 5646 } 5647 } else if (*p == '\\') 5648 p++; 5649 else if (*p == '/') { 5650 if (metaflag) 5651 goto out; 5652 start = p + 1; 5653 } 5654 } 5655 out: 5656 if (metaflag == 0) { /* we've reached the end of the file name */ 5657 if (enddir != expdir) 5658 metaflag++; 5659 p = name; 5660 do { 5661 if (*p == '\\') 5662 p++; 5663 *enddir++ = *p; 5664 } while (*p++); 5665 if (metaflag == 0 || lstat(expdir, &statb) >= 0) 5666 addfname(expdir); 5667 return; 5668 } 5669 endname = p; 5670 if (name < start) { 5671 p = name; 5672 do { 5673 if (*p == '\\') 5674 p++; 5675 *enddir++ = *p++; 5676 } while (p < start); 5677 } 5678 if (enddir == expdir) { 5679 cp = "."; 5680 } else if (enddir == expdir + 1 && *expdir == '/') { 5681 cp = "/"; 5682 } else { 5683 cp = expdir; 5684 enddir[-1] = '\0'; 5685 } 5686 if ((dirp = opendir(cp)) == NULL) 5687 return; 5688 if (enddir != expdir) 5689 enddir[-1] = '/'; 5690 if (*endname == 0) { 5691 atend = 1; 5692 } else { 5693 atend = 0; 5694 *endname++ = '\0'; 5695 } 5696 matchdot = 0; 5697 p = start; 5698 if (*p == '\\') 5699 p++; 5700 if (*p == '.') 5701 matchdot++; 5702 while (! intpending && (dp = readdir(dirp)) != NULL) { 5703 if (dp->d_name[0] == '.' && ! matchdot) 5704 continue; 5705 if (pmatch(start, dp->d_name)) { 5706 if (atend) { 5707 scopy(dp->d_name, enddir); 5708 addfname(expdir); 5709 } else { 5710 for (p = enddir, cp = dp->d_name; 5711 (*p++ = *cp++) != '\0';) 5712 continue; 5713 p[-1] = '/'; 5714 expmeta(p, endname); 5715 } 5716 } 5717 } 5718 closedir(dirp); 5719 if (! atend) 5720 endname[-1] = '/'; 5721 } 5722 5723 /* 5724 * Sort the results of file name expansion. It calculates the number of 5725 * strings to sort and then calls msort (short for merge sort) to do the 5726 * work. 5727 */ 5728 5729 static struct strlist * 5730 expsort(struct strlist *str) 5731 { 5732 int len; 5733 struct strlist *sp; 5734 5735 len = 0; 5736 for (sp = str ; sp ; sp = sp->next) 5737 len++; 5738 return msort(str, len); 5739 } 5740 5741 5742 static struct strlist * 5743 msort(struct strlist *list, int len) 5744 { 5745 struct strlist *p, *q = NULL; 5746 struct strlist **lpp; 5747 int half; 5748 int n; 5749 5750 if (len <= 1) 5751 return list; 5752 half = len >> 1; 5753 p = list; 5754 for (n = half ; --n >= 0 ; ) { 5755 q = p; 5756 p = p->next; 5757 } 5758 q->next = NULL; /* terminate first half of list */ 5759 q = msort(list, half); /* sort first half of list */ 5760 p = msort(p, len - half); /* sort second half */ 5761 lpp = &list; 5762 for (;;) { 5763 #ifdef CONFIG_LOCALE_SUPPORT 5764 if (strcoll(p->text, q->text) < 0) 5765 #else 5766 if (strcmp(p->text, q->text) < 0) 5767 #endif 5768 { 5769 *lpp = p; 5770 lpp = &p->next; 5771 if ((p = *lpp) == NULL) { 5772 *lpp = q; 5773 break; 5774 } 5775 } else { 5776 *lpp = q; 5777 lpp = &q->next; 5778 if ((q = *lpp) == NULL) { 5779 *lpp = p; 5780 break; 5781 } 5782 } 5783 } 5784 return list; 5785 } 5786 5787 5788 /* 5789 * Returns true if the pattern matches the string. 5790 */ 5791 5792 static inline int 5793 patmatch(char *pattern, const char *string) 5794 { 5795 return pmatch(preglob(pattern, 0, 0), string); 5796 } 5797 5798 5799 /* 5800 * Remove any CTLESC characters from a string. 5801 */ 5802 5803 static char * 5804 _rmescapes(char *str, int flag) 5805 { 5806 char *p, *q, *r; 5807 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 }; 5808 unsigned inquotes; 5809 int notescaped; 5810 int globbing; 5811 5812 p = strpbrk(str, qchars); 5813 if (!p) { 5814 return str; 5815 } 5816 q = p; 5817 r = str; 5818 if (flag & RMESCAPE_ALLOC) { 5819 size_t len = p - str; 5820 size_t fulllen = len + strlen(p) + 1; 5821 5822 if (flag & RMESCAPE_GROW) { 5823 r = makestrspace(fulllen, expdest); 5824 } else if (flag & RMESCAPE_HEAP) { 5825 r = ckmalloc(fulllen); 5826 } else { 5827 r = stalloc(fulllen); 5828 } 5829 q = r; 5830 if (len > 0) { 5831 q = mempcpy(q, str, len); 5832 } 5833 } 5834 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; 5835 globbing = flag & RMESCAPE_GLOB; 5836 notescaped = globbing; 5837 while (*p) { 5838 if (*p == CTLQUOTEMARK) { 5839 inquotes = ~inquotes; 5840 p++; 5841 notescaped = globbing; 5842 continue; 5843 } 5844 if (*p == '\\') { 5845 /* naked back slash */ 5846 notescaped = 0; 5847 goto copy; 5848 } 5849 if (*p == CTLESC) { 5850 p++; 5851 if (notescaped && inquotes && *p != '/') { 5852 *q++ = '\\'; 5853 } 5854 } 5855 notescaped = globbing; 5856 copy: 5857 *q++ = *p++; 5858 } 5859 *q = '\0'; 5860 if (flag & RMESCAPE_GROW) { 5861 expdest = r; 5862 STADJUST(q - r + 1, expdest); 5863 } 5864 return r; 5865 } 5866 5867 5868 /* 5869 * See if a pattern matches in a case statement. 5870 */ 5871 5872 int 5873 casematch(union node *pattern, char *val) 5874 { 5875 struct stackmark smark; 5876 int result; 5877 5878 setstackmark(&smark); 5879 argbackq = pattern->narg.backquote; 5880 STARTSTACKSTR(expdest); 5881 ifslastp = NULL; 5882 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); 5883 STACKSTRNUL(expdest); 5884 result = patmatch(stackblock(), val); 5885 popstackmark(&smark); 5886 return result; 5887 } 5888 5889 /* 5890 * Our own itoa(). 5891 */ 5892 5893 static int 5894 cvtnum(arith_t num) 5895 { 5896 int len; 5897 5898 expdest = makestrspace(32, expdest); 5899 #ifdef CONFIG_ASH_MATH_SUPPORT_64 5900 len = fmtstr(expdest, 32, "%lld", (long long) num); 5901 #else 5902 len = fmtstr(expdest, 32, "%ld", num); 5903 #endif 5904 STADJUST(len, expdest); 5905 return len; 5906 } 5907 5908 static void 5909 varunset(const char *end, const char *var, const char *umsg, int varflags) 5910 { 5911 const char *msg; 5912 const char *tail; 5913 5914 tail = nullstr; 5915 msg = "parameter not set"; 5916 if (umsg) { 5917 if (*end == CTLENDVAR) { 5918 if (varflags & VSNUL) 5919 tail = " or null"; 5920 } else 5921 msg = umsg; 5922 } 5923 sh_error("%.*s: %s%s", end - var - 1, var, msg, tail); 5924 } 5925 5926 5927 /* input.c */ 5928 5929 /* 5930 * This implements the input routines used by the parser. 5931 */ 5932 5933 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ 5934 5935 static void pushfile(void); 5936 5937 /* 5938 * Read a character from the script, returning PEOF on end of file. 5939 * Nul characters in the input are silently discarded. 5940 */ 5941 5942 5943 #define pgetc_as_macro() (--parsenleft >= 0? SC2INT(*parsenextc++) : preadbuffer()) 5944 5945 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE 5946 #define pgetc_macro() pgetc() 5947 static int 5948 pgetc(void) 5949 { 5950 return pgetc_as_macro(); 5951 } 5952 #else 5953 #define pgetc_macro() pgetc_as_macro() 5954 static int 5955 pgetc(void) 5956 { 5957 return pgetc_macro(); 5958 } 5959 #endif 5960 5961 5962 /* 5963 * Same as pgetc(), but ignores PEOA. 5964 */ 5965 #ifdef CONFIG_ASH_ALIAS 5966 static int pgetc2(void) 5967 { 5968 int c; 5969 5970 do { 5971 c = pgetc_macro(); 5972 } while (c == PEOA); 5973 return c; 5974 } 5975 #else 5976 static inline int pgetc2(void) 5977 { 5978 return pgetc_macro(); 5979 } 5980 #endif 5981 5982 /* 5983 * Read a line from the script. 5984 */ 5985 5986 static inline char * 5987 pfgets(char *line, int len) 5988 { 5989 char *p = line; 5990 int nleft = len; 5991 int c; 5992 5993 while (--nleft > 0) { 5994 c = pgetc2(); 5995 if (c == PEOF) { 5996 if (p == line) 5997 return NULL; 5998 break; 5999 } 6000 *p++ = c; 6001 if (c == '\n') 6002 break; 6003 } 6004 *p = '\0'; 6005 return line; 6006 } 6007 6008 6009 6010 #ifdef CONFIG_FEATURE_COMMAND_EDITING 6011 #ifdef CONFIG_ASH_EXPAND_PRMT 6012 static char *cmdedit_prompt; 6013 #else 6014 static const char *cmdedit_prompt; 6015 #endif 6016 static inline void putprompt(const char *s) 6017 { 6018 #ifdef CONFIG_ASH_EXPAND_PRMT 6019 free(cmdedit_prompt); 6020 cmdedit_prompt = bb_xstrdup(s); 6021 #else 6022 cmdedit_prompt = s; 6023 #endif 6024 } 6025 #else 6026 static inline void putprompt(const char *s) 6027 { 6028 out2str(s); 6029 } 6030 #endif 6031 6032 static inline int 6033 preadfd(void) 6034 { 6035 int nr; 6036 char *buf = parsefile->buf; 6037 parsenextc = buf; 6038 6039 retry: 6040 #ifdef CONFIG_FEATURE_COMMAND_EDITING 6041 if (!iflag || parsefile->fd) 6042 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 6043 else { 6044 #ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION 6045 cmdedit_path_lookup = pathval(); 6046 #endif 6047 nr = cmdedit_read_input((char *) cmdedit_prompt, buf); 6048 if(nr == 0) { 6049 /* Ctrl+C presend */ 6050 if(trap[SIGINT]) { 6051 buf[0] = '\n'; 6052 buf[1] = 0; 6053 raise(SIGINT); 6054 return 1; 6055 } 6056 goto retry; 6057 } 6058 if(nr < 0 && errno == 0) { 6059 /* Ctrl+D presend */ 6060 nr = 0; 6061 } 6062 } 6063 #else 6064 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 6065 #endif 6066 6067 if (nr < 0) { 6068 if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 6069 int flags = fcntl(0, F_GETFL, 0); 6070 if (flags >= 0 && flags & O_NONBLOCK) { 6071 flags &=~ O_NONBLOCK; 6072 if (fcntl(0, F_SETFL, flags) >= 0) { 6073 out2str("sh: turning off NDELAY mode\n"); 6074 goto retry; 6075 } 6076 } 6077 } 6078 } 6079 return nr; 6080 } 6081 6082 /* 6083 * Refill the input buffer and return the next input character: 6084 * 6085 * 1) If a string was pushed back on the input, pop it; 6086 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading 6087 * from a string so we can't refill the buffer, return EOF. 6088 * 3) If the is more stuff in this buffer, use it else call read to fill it. 6089 * 4) Process input up to the next newline, deleting nul characters. 6090 */ 6091 6092 int 6093 preadbuffer(void) 6094 { 6095 char *q; 6096 int more; 6097 char savec; 6098 6099 while (parsefile->strpush) { 6100 #ifdef CONFIG_ASH_ALIAS 6101 if (parsenleft == -1 && parsefile->strpush->ap && 6102 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') { 6103 return PEOA; 6104 } 6105 #endif 6106 popstring(); 6107 if (--parsenleft >= 0) 6108 return SC2INT(*parsenextc++); 6109 } 6110 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) 6111 return PEOF; 6112 flushall(); 6113 6114 more = parselleft; 6115 if (more <= 0) { 6116 again: 6117 if ((more = preadfd()) <= 0) { 6118 parselleft = parsenleft = EOF_NLEFT; 6119 return PEOF; 6120 } 6121 } 6122 6123 q = parsenextc; 6124 6125 /* delete nul characters */ 6126 for (;;) { 6127 int c; 6128 6129 more--; 6130 c = *q; 6131 6132 if (!c) 6133 memmove(q, q + 1, more); 6134 else { 6135 q++; 6136 if (c == '\n') { 6137 parsenleft = q - parsenextc - 1; 6138 break; 6139 } 6140 } 6141 6142 if (more <= 0) { 6143 parsenleft = q - parsenextc - 1; 6144 if (parsenleft < 0) 6145 goto again; 6146 break; 6147 } 6148 } 6149 parselleft = more; 6150 6151 savec = *q; 6152 *q = '\0'; 6153 6154 if (vflag) { 6155 out2str(parsenextc); 6156 } 6157 6158 *q = savec; 6159 6160 return SC2INT(*parsenextc++); 6161 } 6162 6163 /* 6164 * Undo the last call to pgetc. Only one character may be pushed back. 6165 * PEOF may be pushed back. 6166 */ 6167 6168 void 6169 pungetc(void) 6170 { 6171 parsenleft++; 6172 parsenextc--; 6173 } 6174 6175 /* 6176 * Push a string back onto the input at this current parsefile level. 6177 * We handle aliases this way. 6178 */ 6179 void 6180 pushstring(char *s, void *ap) 6181 { 6182 struct strpush *sp; 6183 size_t len; 6184 6185 len = strlen(s); 6186 INTOFF; 6187 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ 6188 if (parsefile->strpush) { 6189 sp = ckmalloc(sizeof (struct strpush)); 6190 sp->prev = parsefile->strpush; 6191 parsefile->strpush = sp; 6192 } else 6193 sp = parsefile->strpush = &(parsefile->basestrpush); 6194 sp->prevstring = parsenextc; 6195 sp->prevnleft = parsenleft; 6196 #ifdef CONFIG_ASH_ALIAS 6197 sp->ap = (struct alias *)ap; 6198 if (ap) { 6199 ((struct alias *)ap)->flag |= ALIASINUSE; 6200 sp->string = s; 6201 } 6202 #endif 6203 parsenextc = s; 6204 parsenleft = len; 6205 INTON; 6206 } 6207 6208 void 6209 popstring(void) 6210 { 6211 struct strpush *sp = parsefile->strpush; 6212 6213 INTOFF; 6214 #ifdef CONFIG_ASH_ALIAS 6215 if (sp->ap) { 6216 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') { 6217 checkkwd |= CHKALIAS; 6218 } 6219 if (sp->string != sp->ap->val) { 6220 ckfree(sp->string); 6221 } 6222 sp->ap->flag &= ~ALIASINUSE; 6223 if (sp->ap->flag & ALIASDEAD) { 6224 unalias(sp->ap->name); 6225 } 6226 } 6227 #endif 6228 parsenextc = sp->prevstring; 6229 parsenleft = sp->prevnleft; 6230 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ 6231 parsefile->strpush = sp->prev; 6232 if (sp != &(parsefile->basestrpush)) 6233 ckfree(sp); 6234 INTON; 6235 } 6236 6237 /* 6238 * Set the input to take input from a file. If push is set, push the 6239 * old input onto the stack first. 6240 */ 6241 6242 static int 6243 setinputfile(const char *fname, int flags) 6244 { 6245 int fd; 6246 int fd2; 6247 6248 INTOFF; 6249 if ((fd = open(fname, O_RDONLY)) < 0) { 6250 if (flags & INPUT_NOFILE_OK) 6251 goto out; 6252 sh_error("Can't open %s", fname); 6253 } 6254 if (fd < 10) { 6255 fd2 = copyfd(fd, 10); 6256 close(fd); 6257 if (fd2 < 0) 6258 sh_error("Out of file descriptors"); 6259 fd = fd2; 6260 } 6261 setinputfd(fd, flags & INPUT_PUSH_FILE); 6262 out: 6263 INTON; 6264 return fd; 6265 } 6266 6267 6268 /* 6269 * Like setinputfile, but takes an open file descriptor. Call this with 6270 * interrupts off. 6271 */ 6272 6273 static void 6274 setinputfd(int fd, int push) 6275 { 6276 (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 6277 if (push) { 6278 pushfile(); 6279 parsefile->buf = 0; 6280 } 6281 parsefile->fd = fd; 6282 if (parsefile->buf == NULL) 6283 parsefile->buf = ckmalloc(IBUFSIZ); 6284 parselleft = parsenleft = 0; 6285 plinno = 1; 6286 } 6287 6288 6289 /* 6290 * Like setinputfile, but takes input from a string. 6291 */ 6292 6293 static void 6294 setinputstring(char *string) 6295 { 6296 INTOFF; 6297 pushfile(); 6298 parsenextc = string; 6299 parsenleft = strlen(string); 6300 parsefile->buf = NULL; 6301 plinno = 1; 6302 INTON; 6303 } 6304 6305 6306 /* 6307 * To handle the "." command, a stack of input files is used. Pushfile 6308 * adds a new entry to the stack and popfile restores the previous level. 6309 */ 6310 6311 static void 6312 pushfile(void) 6313 { 6314 struct parsefile *pf; 6315 6316 parsefile->nleft = parsenleft; 6317 parsefile->lleft = parselleft; 6318 parsefile->nextc = parsenextc; 6319 parsefile->linno = plinno; 6320 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile)); 6321 pf->prev = parsefile; 6322 pf->fd = -1; 6323 pf->strpush = NULL; 6324 pf->basestrpush.prev = NULL; 6325 parsefile = pf; 6326 } 6327 6328 6329 static void 6330 popfile(void) 6331 { 6332 struct parsefile *pf = parsefile; 6333 6334 INTOFF; 6335 if (pf->fd >= 0) 6336 close(pf->fd); 6337 if (pf->buf) 6338 ckfree(pf->buf); 6339 while (pf->strpush) 6340 popstring(); 6341 parsefile = pf->prev; 6342 ckfree(pf); 6343 parsenleft = parsefile->nleft; 6344 parselleft = parsefile->lleft; 6345 parsenextc = parsefile->nextc; 6346 plinno = parsefile->linno; 6347 INTON; 6348 } 6349 6350 6351 /* 6352 * Return to top level. 6353 */ 6354 6355 static void 6356 popallfiles(void) 6357 { 6358 while (parsefile != &basepf) 6359 popfile(); 6360 } 6361 6362 6363 /* 6364 * Close the file(s) that the shell is reading commands from. Called 6365 * after a fork is done. 6366 */ 6367 6368 static void 6369 closescript(void) 6370 { 6371 popallfiles(); 6372 if (parsefile->fd > 0) { 6373 close(parsefile->fd); 6374 parsefile->fd = 0; 6375 } 6376 } 6377 6378 /* jobs.c */ 3239 act.sa_handler = SIG_DFL; 3240 } 3241 *t = action; 3242 act.sa_flags = 0; 3243 sigfillset(&act.sa_mask); 3244 sigaction(signo, &act, 0); 3245 } 6379 3246 6380 3247 /* mode flags for set_curjob */ … … 6387 3254 #define DOWAIT_BLOCK 1 6388 3255 3256 #if JOBS 3257 /* pgrp of shell on invocation */ 3258 static int initialpgrp; 3259 static int ttyfd = -1; 3260 #endif 6389 3261 /* array of jobs */ 6390 3262 static struct job *jobtab; 6391 3263 /* size of array */ 6392 3264 static unsigned njobs; 6393 #if JOBS6394 /* pgrp of shell on invocation */6395 static int initialpgrp;6396 static int ttyfd = -1;6397 #endif6398 3265 /* current job */ 6399 3266 static struct job *curjob; 6400 3267 /* number of presumed living untracked jobs */ 6401 3268 static int jobless; 6402 6403 static void set_curjob(struct job *, unsigned);6404 #if JOBS6405 static int restartjob(struct job *, int);6406 static void xtcsetpgrp(int, pid_t);6407 static char *commandtext(union node *);6408 static void cmdlist(union node *, int);6409 static void cmdtxt(union node *);6410 static void cmdputs(const char *);6411 static void showpipe(struct job *, FILE *);6412 #endif6413 static int sprint_status(char *, int, int);6414 static void freejob(struct job *);6415 static struct job *getjob(const char *, int);6416 static struct job *growjobtab(void);6417 static void forkchild(struct job *, union node *, int);6418 static void forkparent(struct job *, union node *, int, pid_t);6419 static int dowait(int, struct job *);6420 static int getstatus(struct job *);6421 3269 6422 3270 static void … … 6440 3288 switch (mode) { 6441 3289 default: 6442 #if defDEBUG3290 #if DEBUG 6443 3291 abort(); 6444 3292 #endif … … 6468 3316 } 6469 3317 3318 #if JOBS || DEBUG 3319 static int 3320 jobno(const struct job *jp) 3321 { 3322 return jp - jobtab + 1; 3323 } 3324 #endif 3325 3326 /* 3327 * Convert a job name to a job structure. 3328 */ 3329 static struct job * 3330 getjob(const char *name, int getctl) 3331 { 3332 struct job *jp; 3333 struct job *found; 3334 const char *err_msg = "No such job: %s"; 3335 unsigned num; 3336 int c; 3337 const char *p; 3338 char *(*match)(const char *, const char *); 3339 3340 jp = curjob; 3341 p = name; 3342 if (!p) 3343 goto currentjob; 3344 3345 if (*p != '%') 3346 goto err; 3347 3348 c = *++p; 3349 if (!c) 3350 goto currentjob; 3351 3352 if (!p[1]) { 3353 if (c == '+' || c == '%') { 3354 currentjob: 3355 err_msg = "No current job"; 3356 goto check; 3357 } 3358 if (c == '-') { 3359 if (jp) 3360 jp = jp->prev_job; 3361 err_msg = "No previous job"; 3362 check: 3363 if (!jp) 3364 goto err; 3365 goto gotit; 3366 } 3367 } 3368 3369 if (is_number(p)) { 3370 num = atoi(p); 3371 if (num < njobs) { 3372 jp = jobtab + num - 1; 3373 if (jp->used) 3374 goto gotit; 3375 goto err; 3376 } 3377 } 3378 3379 match = prefix; 3380 if (*p == '?') { 3381 match = strstr; 3382 p++; 3383 } 3384 3385 found = 0; 3386 while (1) { 3387 if (!jp) 3388 goto err; 3389 if (match(jp->ps[0].cmd, p)) { 3390 if (found) 3391 goto err; 3392 found = jp; 3393 err_msg = "%s: ambiguous"; 3394 } 3395 jp = jp->prev_job; 3396 } 3397 3398 gotit: 6470 3399 #if JOBS 3400 err_msg = "job %s not created under job control"; 3401 if (getctl && jp->jobctl == 0) 3402 goto err; 3403 #endif 3404 return jp; 3405 err: 3406 ash_msg_and_raise_error(err_msg, name); 3407 } 3408 3409 /* 3410 * Mark a job structure as unused. 3411 */ 3412 static void 3413 freejob(struct job *jp) 3414 { 3415 struct procstat *ps; 3416 int i; 3417 3418 INT_OFF; 3419 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) { 3420 if (ps->cmd != nullstr) 3421 free(ps->cmd); 3422 } 3423 if (jp->ps != &jp->ps0) 3424 free(jp->ps); 3425 jp->used = 0; 3426 set_curjob(jp, CUR_DELETE); 3427 INT_ON; 3428 } 3429 3430 #if JOBS 3431 static void 3432 xtcsetpgrp(int fd, pid_t pgrp) 3433 { 3434 if (tcsetpgrp(fd, pgrp)) 3435 ash_msg_and_raise_error("cannot set tty process group (%m)"); 3436 } 3437 6471 3438 /* 6472 3439 * Turn job control on and off. … … 6478 3445 * Called with interrupts off. 6479 3446 */ 6480 6481 void 3447 static void 6482 3448 setjobctl(int on) 6483 3449 { … … 6491 3457 ofd = fd = open(_PATH_TTY, O_RDWR); 6492 3458 if (fd < 0) { 3459 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails. 3460 * That sometimes helps to acquire controlling tty. 3461 * Obviously, a workaround for bugs when someone 3462 * failed to provide a controlling tty to bash! :) */ 6493 3463 fd += 3; 6494 3464 while (!isatty(fd) && --fd >= 0) … … 6501 3471 fcntl(fd, F_SETFD, FD_CLOEXEC); 6502 3472 do { /* while we are in the background */ 6503 if ((pgrp = tcgetpgrp(fd)) < 0) { 6504 out: 6505 sh_warnx("can't access tty; job control turned off"); 3473 pgrp = tcgetpgrp(fd); 3474 if (pgrp < 0) { 3475 out: 3476 ash_msg("can't access tty; job control turned off"); 6506 3477 mflag = on = 0; 6507 3478 goto close; … … 6523 3494 fd = ttyfd; 6524 3495 pgrp = initialpgrp; 6525 xtcsetpgrp(fd, pgrp); 3496 /* was xtcsetpgrp, but this can make exiting ash 3497 * with pty already deleted loop forever */ 3498 tcsetpgrp(fd, pgrp); 6526 3499 setpgid(0, pgrp); 6527 3500 setsignal(SIGTSTP); 6528 3501 setsignal(SIGTTOU); 6529 3502 setsignal(SIGTTIN); 6530 close:3503 close: 6531 3504 close(fd); 6532 3505 fd = -1; … … 6539 3512 killcmd(int argc, char **argv) 6540 3513 { 6541 int signo = -1; 6542 int list = 0; 6543 int i; 6544 pid_t pid; 6545 struct job *jp; 6546 6547 if (argc <= 1) { 6548 usage: 6549 sh_error( 6550 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n" 6551 "kill -l [exitstatus]" 6552 ); 6553 } 6554 6555 if (**++argv == '-') { 6556 signo = decode_signal(*argv + 1, 1); 6557 if (signo < 0) { 6558 int c; 6559 6560 while ((c = nextopt("ls:")) != '\0') 6561 switch (c) { 6562 default: 6563 #ifdef DEBUG 6564 abort(); 6565 #endif 6566 case 'l': 6567 list = 1; 6568 break; 6569 case 's': 6570 signo = decode_signal(optionarg, 1); 6571 if (signo < 0) { 6572 sh_error( 6573 "invalid signal number or name: %s", 6574 optionarg 6575 ); 6576 } 6577 break; 6578 } 6579 argv = argptr; 6580 } else 6581 argv++; 6582 } 6583 6584 if (!list && signo < 0) 6585 signo = SIGTERM; 6586 6587 if ((signo < 0 || !*argv) ^ list) { 6588 goto usage; 6589 } 6590 6591 if (list) { 6592 const char *name; 6593 6594 if (!*argv) { 6595 for (i = 1; i < NSIG; i++) { 6596 name = u_signal_names(0, &i, 1); 6597 if (name) 6598 out1fmt(snlfmt, name); 3514 if (argv[1] && strcmp(argv[1], "-l") != 0) { 3515 int i = 1; 3516 do { 3517 if (argv[i][0] == '%') { 3518 struct job *jp = getjob(argv[i], 0); 3519 unsigned pid = jp->ps[0].pid; 3520 /* Enough space for ' -NNN<nul>' */ 3521 argv[i] = alloca(sizeof(int)*3 + 3); 3522 /* kill_main has matching code to expect 3523 * leading space. Needed to not confuse 3524 * negative pids with "kill -SIGNAL_NO" syntax */ 3525 sprintf(argv[i], " -%u", pid); 6599 3526 } 6600 return 0; 6601 } 6602 name = u_signal_names(*argptr, &signo, -1); 6603 if (name) 6604 out1fmt(snlfmt, name); 6605 else 6606 sh_error("invalid signal number or exit status: %s", *argptr); 6607 return 0; 6608 } 6609 6610 i = 0; 6611 do { 6612 if (**argv == '%') { 6613 jp = getjob(*argv, 0); 6614 pid = -jp->ps[0].pid; 6615 } else { 6616 pid = **argv == '-' ? 6617 -number(*argv + 1) : number(*argv); 6618 } 6619 if (kill(pid, signo) != 0) { 6620 sh_warnx("(%d) - %m", pid); 6621 i = 1; 6622 } 6623 } while (*++argv); 6624 6625 return i; 6626 } 6627 #endif /* JOBS */ 6628 6629 #if defined(JOBS) || defined(DEBUG) 6630 static int 6631 jobno(const struct job *jp) 6632 { 6633 return jp - jobtab + 1; 6634 } 6635 #endif 6636 6637 #if JOBS 6638 static int 6639 fgcmd(int argc, char **argv) 6640 { 6641 struct job *jp; 6642 FILE *out; 6643 int mode; 6644 int retval; 6645 6646 mode = (**argv == 'f') ? FORK_FG : FORK_BG; 6647 nextopt(nullstr); 6648 argv = argptr; 6649 out = stdout; 6650 do { 6651 jp = getjob(*argv, 1); 6652 if (mode == FORK_BG) { 6653 set_curjob(jp, CUR_RUNNING); 6654 fprintf(out, "[%d] ", jobno(jp)); 6655 } 6656 outstr(jp->ps->cmd, out); 6657 showpipe(jp, out); 6658 retval = restartjob(jp, mode); 6659 } while (*argv && *++argv); 6660 return retval; 6661 } 6662 6663 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd"))); 3527 } while (argv[++i]); 3528 } 3529 return kill_main(argc, argv); 3530 } 3531 3532 static void 3533 showpipe(struct job *jp, FILE *out) 3534 { 3535 struct procstat *sp; 3536 struct procstat *spend; 3537 3538 spend = jp->ps + jp->nprocs; 3539 for (sp = jp->ps + 1; sp < spend; sp++) 3540 fprintf(out, " | %s", sp->cmd); 3541 outcslow('\n', out); 3542 flush_stdout_stderr(); 3543 } 6664 3544 6665 3545 … … 6672 3552 pid_t pgid; 6673 3553 6674 INT OFF;3554 INT_OFF; 6675 3555 if (jp->state == JOBDONE) 6676 3556 goto out; … … 6686 3566 ps->status = -1; 6687 3567 } 6688 } while (ps++, --i); 6689 out: 3568 ps++; 3569 } while (--i); 3570 out: 6690 3571 status = (mode == FORK_FG) ? waitforjob(jp) : 0; 6691 INT ON;3572 INT_ON; 6692 3573 return status; 3574 } 3575 3576 static int 3577 fg_bgcmd(int argc, char **argv) 3578 { 3579 struct job *jp; 3580 FILE *out; 3581 int mode; 3582 int retval; 3583 3584 mode = (**argv == 'f') ? FORK_FG : FORK_BG; 3585 nextopt(nullstr); 3586 argv = argptr; 3587 out = stdout; 3588 do { 3589 jp = getjob(*argv, 1); 3590 if (mode == FORK_BG) { 3591 set_curjob(jp, CUR_RUNNING); 3592 fprintf(out, "[%d] ", jobno(jp)); 3593 } 3594 outstr(jp->ps->cmd, out); 3595 showpipe(jp, out); 3596 retval = restartjob(jp, mode); 3597 } while (*argv && *++argv); 3598 return retval; 6693 3599 } 6694 3600 #endif … … 6728 3634 col = fmtstr(s, 16, "Done"); 6729 3635 } 6730 6731 out: 3636 out: 6732 3637 return col; 6733 3638 } 6734 6735 #if JOBS6736 static void6737 showjob(FILE *out, struct job *jp, int mode)6738 {6739 struct procstat *ps;6740 struct procstat *psend;6741 int col;6742 int indent;6743 char s[80];6744 6745 ps = jp->ps;6746 6747 if (mode & SHOW_PGID) {6748 /* just output process (group) id of pipeline */6749 fprintf(out, "%d\n", ps->pid);6750 return;6751 }6752 6753 col = fmtstr(s, 16, "[%d] ", jobno(jp));6754 indent = col;6755 6756 if (jp == curjob)6757 s[col - 2] = '+';6758 else if (curjob && jp == curjob->prev_job)6759 s[col - 2] = '-';6760 6761 if (mode & SHOW_PID)6762 col += fmtstr(s + col, 16, "%d ", ps->pid);6763 6764 psend = ps + jp->nprocs;6765 6766 if (jp->state == JOBRUNNING) {6767 scopy("Running", s + col);6768 col += strlen("Running");6769 } else {6770 int status = psend[-1].status;6771 #if JOBS6772 if (jp->state == JOBSTOPPED)6773 status = jp->stopstatus;6774 #endif6775 col += sprint_status(s + col, status, 0);6776 }6777 6778 goto start;6779 6780 do {6781 /* for each process */6782 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;6783 6784 start:6785 fprintf(out, "%s%*c%s",6786 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd6787 );6788 if (!(mode & SHOW_PID)) {6789 showpipe(jp, out);6790 break;6791 }6792 if (++ps == psend) {6793 outcslow('\n', out);6794 break;6795 }6796 } while (1);6797 6798 jp->changed = 0;6799 6800 if (jp->state == JOBDONE) {6801 TRACE(("showjob: freeing job %d\n", jobno(jp)));6802 freejob(jp);6803 }6804 }6805 6806 6807 static int6808 jobscmd(int argc, char **argv)6809 {6810 int mode, m;6811 FILE *out;6812 6813 mode = 0;6814 while ((m = nextopt("lp")))6815 if (m == 'l')6816 mode = SHOW_PID;6817 else6818 mode = SHOW_PGID;6819 6820 out = stdout;6821 argv = argptr;6822 if (*argv)6823 do6824 showjob(out, getjob(*argv,0), mode);6825 while (*++argv);6826 else6827 showjobs(out, mode);6828 6829 return 0;6830 }6831 6832 6833 /*6834 * Print a list of jobs. If "change" is nonzero, only print jobs whose6835 * statuses have changed since the last call to showjobs.6836 */6837 6838 static void6839 showjobs(FILE *out, int mode)6840 {6841 struct job *jp;6842 6843 TRACE(("showjobs(%x) called\n", mode));6844 6845 /* If not even one one job changed, there is nothing to do */6846 while (dowait(DOWAIT_NORMAL, NULL) > 0)6847 continue;6848 6849 for (jp = curjob; jp; jp = jp->prev_job) {6850 if (!(mode & SHOW_CHANGED) || jp->changed)6851 showjob(out, jp, mode);6852 }6853 }6854 #endif /* JOBS */6855 6856 /*6857 * Mark a job structure as unused.6858 */6859 6860 static void6861 freejob(struct job *jp)6862 {6863 struct procstat *ps;6864 int i;6865 6866 INTOFF;6867 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {6868 if (ps->cmd != nullstr)6869 ckfree(ps->cmd);6870 }6871 if (jp->ps != &jp->ps0)6872 ckfree(jp->ps);6873 jp->used = 0;6874 set_curjob(jp, CUR_DELETE);6875 INTON;6876 }6877 6878 6879 static int6880 waitcmd(int argc, char **argv)6881 {6882 struct job *job;6883 int retval;6884 struct job *jp;6885 6886 EXSIGON();6887 6888 nextopt(nullstr);6889 retval = 0;6890 6891 argv = argptr;6892 if (!*argv) {6893 /* wait for all jobs */6894 for (;;) {6895 jp = curjob;6896 while (1) {6897 if (!jp) {6898 /* no running procs */6899 goto out;6900 }6901 if (jp->state == JOBRUNNING)6902 break;6903 jp->waited = 1;6904 jp = jp->prev_job;6905 }6906 dowait(DOWAIT_BLOCK, 0);6907 }6908 }6909 6910 retval = 127;6911 do {6912 if (**argv != '%') {6913 pid_t pid = number(*argv);6914 job = curjob;6915 goto start;6916 do {6917 if (job->ps[job->nprocs - 1].pid == pid)6918 break;6919 job = job->prev_job;6920 start:6921 if (!job)6922 goto repeat;6923 } while (1);6924 } else6925 job = getjob(*argv, 0);6926 /* loop until process terminated or stopped */6927 while (job->state == JOBRUNNING)6928 dowait(DOWAIT_BLOCK, 0);6929 job->waited = 1;6930 retval = getstatus(job);6931 repeat:6932 ;6933 } while (*++argv);6934 6935 out:6936 return retval;6937 }6938 6939 6940 /*6941 * Convert a job name to a job structure.6942 */6943 6944 static struct job *6945 getjob(const char *name, int getctl)6946 {6947 struct job *jp;6948 struct job *found;6949 const char *err_msg = "No such job: %s";6950 unsigned num;6951 int c;6952 const char *p;6953 char *(*match)(const char *, const char *);6954 6955 jp = curjob;6956 p = name;6957 if (!p)6958 goto currentjob;6959 6960 if (*p != '%')6961 goto err;6962 6963 c = *++p;6964 if (!c)6965 goto currentjob;6966 6967 if (!p[1]) {6968 if (c == '+' || c == '%') {6969 currentjob:6970 err_msg = "No current job";6971 goto check;6972 } else if (c == '-') {6973 if (jp)6974 jp = jp->prev_job;6975 err_msg = "No previous job";6976 check:6977 if (!jp)6978 goto err;6979 goto gotit;6980 }6981 }6982 6983 if (is_number(p)) {6984 num = atoi(p);6985 if (num < njobs) {6986 jp = jobtab + num - 1;6987 if (jp->used)6988 goto gotit;6989 goto err;6990 }6991 }6992 6993 match = prefix;6994 if (*p == '?') {6995 match = strstr;6996 p++;6997 }6998 6999 found = 0;7000 while (1) {7001 if (!jp)7002 goto err;7003 if (match(jp->ps[0].cmd, p)) {7004 if (found)7005 goto err;7006 found = jp;7007 err_msg = "%s: ambiguous";7008 }7009 jp = jp->prev_job;7010 }7011 7012 gotit:7013 #if JOBS7014 err_msg = "job %s not created under job control";7015 if (getctl && jp->jobctl == 0)7016 goto err;7017 #endif7018 return jp;7019 err:7020 sh_error(err_msg, name);7021 }7022 7023 7024 /*7025 * Return a new job structure.7026 * Called with interrupts off.7027 */7028 7029 static struct job *7030 makejob(union node *node, int nprocs)7031 {7032 int i;7033 struct job *jp;7034 7035 for (i = njobs, jp = jobtab ; ; jp++) {7036 if (--i < 0) {7037 jp = growjobtab();7038 break;7039 }7040 if (jp->used == 0)7041 break;7042 if (jp->state != JOBDONE || !jp->waited)7043 continue;7044 #if JOBS7045 if (jobctl)7046 continue;7047 #endif7048 freejob(jp);7049 break;7050 }7051 memset(jp, 0, sizeof(*jp));7052 #if JOBS7053 if (jobctl)7054 jp->jobctl = 1;7055 #endif7056 jp->prev_job = curjob;7057 curjob = jp;7058 jp->used = 1;7059 jp->ps = &jp->ps0;7060 if (nprocs > 1) {7061 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));7062 }7063 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,7064 jobno(jp)));7065 return jp;7066 }7067 7068 static struct job *7069 growjobtab(void)7070 {7071 size_t len;7072 ptrdiff_t offset;7073 struct job *jp, *jq;7074 7075 len = njobs * sizeof(*jp);7076 jq = jobtab;7077 jp = ckrealloc(jq, len + 4 * sizeof(*jp));7078 7079 offset = (char *)jp - (char *)jq;7080 if (offset) {7081 /* Relocate pointers */7082 size_t l = len;7083 7084 jq = (struct job *)((char *)jq + l);7085 while (l) {7086 l -= sizeof(*jp);7087 jq--;7088 #define joff(p) ((struct job *)((char *)(p) + l))7089 #define jmove(p) (p) = (void *)((char *)(p) + offset)7090 if (xlikely(joff(jp)->ps == &jq->ps0))7091 jmove(joff(jp)->ps);7092 if (joff(jp)->prev_job)7093 jmove(joff(jp)->prev_job);7094 }7095 if (curjob)7096 jmove(curjob);7097 #undef joff7098 #undef jmove7099 }7100 7101 njobs += 4;7102 jobtab = jp;7103 jp = (struct job *)((char *)jp + len);7104 jq = jp + 3;7105 do {7106 jq->used = 0;7107 } while (--jq >= jp);7108 return jp;7109 }7110 7111 7112 /*7113 * Fork off a subshell. If we are doing job control, give the subshell its7114 * own process group. Jp is a job structure that the job is to be added to.7115 * N is the command that will be evaluated by the child. Both jp and n may7116 * be NULL. The mode parameter can be one of the following:7117 * FORK_FG - Fork off a foreground process.7118 * FORK_BG - Fork off a background process.7119 * FORK_NOJOB - Like FORK_FG, but don't give the process its own7120 * process group even if job control is on.7121 *7122 * When job control is turned off, background processes have their standard7123 * input redirected to /dev/null (except for the second and later processes7124 * in a pipeline).7125 *7126 * Called with interrupts off.7127 */7128 7129 static inline void7130 forkchild(struct job *jp, union node *n, int mode)7131 {7132 int oldlvl;7133 7134 TRACE(("Child shell %d\n", getpid()));7135 oldlvl = shlvl;7136 shlvl++;7137 7138 closescript();7139 clear_traps();7140 #if JOBS7141 /* do job control only in root shell */7142 jobctl = 0;7143 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {7144 pid_t pgrp;7145 7146 if (jp->nprocs == 0)7147 pgrp = getpid();7148 else7149 pgrp = jp->ps[0].pid;7150 /* This can fail because we are doing it in the parent also */7151 (void)setpgid(0, pgrp);7152 if (mode == FORK_FG)7153 xtcsetpgrp(ttyfd, pgrp);7154 setsignal(SIGTSTP);7155 setsignal(SIGTTOU);7156 } else7157 #endif7158 if (mode == FORK_BG) {7159 ignoresig(SIGINT);7160 ignoresig(SIGQUIT);7161 if (jp->nprocs == 0) {7162 close(0);7163 if (open(bb_dev_null, O_RDONLY) != 0)7164 sh_error("Can't open %s", bb_dev_null);7165 }7166 }7167 if (!oldlvl && iflag) {7168 setsignal(SIGINT);7169 setsignal(SIGQUIT);7170 setsignal(SIGTERM);7171 }7172 for (jp = curjob; jp; jp = jp->prev_job)7173 freejob(jp);7174 jobless = 0;7175 }7176 7177 static inline void7178 forkparent(struct job *jp, union node *n, int mode, pid_t pid)7179 {7180 TRACE(("In parent shell: child = %d\n", pid));7181 if (!jp) {7182 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);7183 jobless++;7184 return;7185 }7186 #if JOBS7187 if (mode != FORK_NOJOB && jp->jobctl) {7188 int pgrp;7189 7190 if (jp->nprocs == 0)7191 pgrp = pid;7192 else7193 pgrp = jp->ps[0].pid;7194 /* This can fail because we are doing it in the child also */7195 (void)setpgid(pid, pgrp);7196 }7197 #endif7198 if (mode == FORK_BG) {7199 backgndpid = pid; /* set $! */7200 set_curjob(jp, CUR_RUNNING);7201 }7202 if (jp) {7203 struct procstat *ps = &jp->ps[jp->nprocs++];7204 ps->pid = pid;7205 ps->status = -1;7206 ps->cmd = nullstr;7207 #if JOBS7208 if (jobctl && n)7209 ps->cmd = commandtext(n);7210 #endif7211 }7212 }7213 7214 static int7215 forkshell(struct job *jp, union node *n, int mode)7216 {7217 int pid;7218 7219 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));7220 pid = fork();7221 if (pid < 0) {7222 TRACE(("Fork failed, errno=%d", errno));7223 if (jp)7224 freejob(jp);7225 sh_error("Cannot fork");7226 }7227 if (pid == 0)7228 forkchild(jp, n, mode);7229 else7230 forkparent(jp, n, mode, pid);7231 return pid;7232 }7233 7234 /*7235 * Wait for job to finish.7236 *7237 * Under job control we have the problem that while a child process is7238 * running interrupts generated by the user are sent to the child but not7239 * to the shell. This means that an infinite loop started by an inter-7240 * active user may be hard to kill. With job control turned off, an7241 * interactive user may place an interactive program inside a loop. If7242 * the interactive program catches interrupts, the user doesn't want7243 * these interrupts to also abort the loop. The approach we take here7244 * is to have the shell ignore interrupt signals while waiting for a7245 * foreground process to terminate, and then send itself an interrupt7246 * signal if the child process was terminated by an interrupt signal.7247 * Unfortunately, some programs want to do a bit of cleanup and then7248 * exit on interrupt; unless these processes terminate themselves by7249 * sending a signal to themselves (instead of calling exit) they will7250 * confuse this approach.7251 *7252 * Called with interrupts off.7253 */7254 7255 int7256 waitforjob(struct job *jp)7257 {7258 int st;7259 7260 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));7261 while (jp->state == JOBRUNNING) {7262 dowait(DOWAIT_BLOCK, jp);7263 }7264 st = getstatus(jp);7265 #if JOBS7266 if (jp->jobctl) {7267 xtcsetpgrp(ttyfd, rootpid);7268 /*7269 * This is truly gross.7270 * If we're doing job control, then we did a TIOCSPGRP which7271 * caused us (the shell) to no longer be in the controlling7272 * session -- so we wouldn't have seen any ^C/SIGINT. So, we7273 * intuit from the subprocess exit status whether a SIGINT7274 * occurred, and if so interrupt ourselves. Yuck. - mycroft7275 */7276 if (jp->sigint)7277 raise(SIGINT);7278 }7279 if (jp->state == JOBDONE)7280 #endif7281 freejob(jp);7282 return st;7283 }7284 7285 3639 7286 3640 /* … … 7312 3666 * and the jobs command may give out of date information. 7313 3667 */ 7314 7315 static inline int 3668 static int 7316 3669 waitproc(int block, int *status) 7317 3670 { … … 7330 3683 * Wait for a process to terminate. 7331 3684 */ 7332 7333 3685 static int 7334 3686 dowait(int block, struct job *job) … … 7345 3697 if (pid <= 0) 7346 3698 return pid; 7347 INT OFF;3699 INT_OFF; 7348 3700 thisjob = NULL; 7349 3701 for (jp = curjob; jp; jp = jp->prev_job) { … … 7357 3709 do { 7358 3710 if (sp->pid == pid) { 7359 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status)); 3711 TRACE(("Job %d: changing status of proc %d " 3712 "from 0x%x to 0x%x\n", 3713 jobno(jp), pid, sp->status, status)); 7360 3714 sp->status = status; 7361 3715 thisjob = jp; … … 7382 3736 goto out; 7383 3737 7384 gotjob:3738 gotjob: 7385 3739 if (state != JOBRUNNING) { 7386 3740 thisjob->changed = 1; 7387 3741 7388 3742 if (thisjob->state != state) { 7389 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state)); 3743 TRACE(("Job %d: changing state from %d to %d\n", 3744 jobno(thisjob), thisjob->state, state)); 7390 3745 thisjob->state = state; 7391 3746 #if JOBS … … 7397 3752 } 7398 3753 7399 out:7400 INT ON;3754 out: 3755 INT_ON; 7401 3756 7402 3757 if (thisjob && thisjob == job) { … … 7414 3769 } 7415 3770 7416 7417 /* 7418 * return 1 if there are stopped jobs, otherwise 0 7419 */ 7420 7421 int 7422 stoppedjobs(void) 3771 #if JOBS 3772 static void 3773 showjob(FILE *out, struct job *jp, int mode) 3774 { 3775 struct procstat *ps; 3776 struct procstat *psend; 3777 int col; 3778 int indent_col; 3779 char s[80]; 3780 3781 ps = jp->ps; 3782 3783 if (mode & SHOW_PGID) { 3784 /* just output process (group) id of pipeline */ 3785 fprintf(out, "%d\n", ps->pid); 3786 return; 3787 } 3788 3789 col = fmtstr(s, 16, "[%d] ", jobno(jp)); 3790 indent_col = col; 3791 3792 if (jp == curjob) 3793 s[col - 2] = '+'; 3794 else if (curjob && jp == curjob->prev_job) 3795 s[col - 2] = '-'; 3796 3797 if (mode & SHOW_PID) 3798 col += fmtstr(s + col, 16, "%d ", ps->pid); 3799 3800 psend = ps + jp->nprocs; 3801 3802 if (jp->state == JOBRUNNING) { 3803 strcpy(s + col, "Running"); 3804 col += sizeof("Running") - 1; 3805 } else { 3806 int status = psend[-1].status; 3807 if (jp->state == JOBSTOPPED) 3808 status = jp->stopstatus; 3809 col += sprint_status(s + col, status, 0); 3810 } 3811 3812 goto start; 3813 3814 do { 3815 /* for each process */ 3816 col = fmtstr(s, 48, " |\n%*c%d ", indent_col, ' ', ps->pid) - 3; 3817 start: 3818 fprintf(out, "%s%*c%s", 3819 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd 3820 ); 3821 if (!(mode & SHOW_PID)) { 3822 showpipe(jp, out); 3823 break; 3824 } 3825 if (++ps == psend) { 3826 outcslow('\n', out); 3827 break; 3828 } 3829 } while (1); 3830 3831 jp->changed = 0; 3832 3833 if (jp->state == JOBDONE) { 3834 TRACE(("showjob: freeing job %d\n", jobno(jp))); 3835 freejob(jp); 3836 } 3837 } 3838 3839 /* 3840 * Print a list of jobs. If "change" is nonzero, only print jobs whose 3841 * statuses have changed since the last call to showjobs. 3842 */ 3843 static void 3844 showjobs(FILE *out, int mode) 7423 3845 { 7424 3846 struct job *jp; 3847 3848 TRACE(("showjobs(%x) called\n", mode)); 3849 3850 /* If not even one one job changed, there is nothing to do */ 3851 while (dowait(DOWAIT_NORMAL, NULL) > 0) 3852 continue; 3853 3854 for (jp = curjob; jp; jp = jp->prev_job) { 3855 if (!(mode & SHOW_CHANGED) || jp->changed) { 3856 showjob(out, jp, mode); 3857 } 3858 } 3859 } 3860 3861 static int 3862 jobscmd(int argc, char **argv) 3863 { 3864 int mode, m; 3865 3866 mode = 0; 3867 while ((m = nextopt("lp"))) { 3868 if (m == 'l') 3869 mode = SHOW_PID; 3870 else 3871 mode = SHOW_PGID; 3872 } 3873 3874 argv = argptr; 3875 if (*argv) { 3876 do 3877 showjob(stdout, getjob(*argv,0), mode); 3878 while (*++argv); 3879 } else 3880 showjobs(stdout, mode); 3881 3882 return 0; 3883 } 3884 #endif /* JOBS */ 3885 3886 static int 3887 getstatus(struct job *job) 3888 { 3889 int status; 7425 3890 int retval; 7426 3891 3892 status = job->ps[job->nprocs - 1].status; 3893 retval = WEXITSTATUS(status); 3894 if (!WIFEXITED(status)) { 3895 #if JOBS 3896 retval = WSTOPSIG(status); 3897 if (!WIFSTOPPED(status)) 3898 #endif 3899 { 3900 /* XXX: limits number of signals */ 3901 retval = WTERMSIG(status); 3902 #if JOBS 3903 if (retval == SIGINT) 3904 job->sigint = 1; 3905 #endif 3906 } 3907 retval += 128; 3908 } 3909 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n", 3910 jobno(job), job->nprocs, status, retval)); 3911 return retval; 3912 } 3913 3914 static int 3915 waitcmd(int argc, char **argv) 3916 { 3917 struct job *job; 3918 int retval; 3919 struct job *jp; 3920 3921 EXSIGON; 3922 3923 nextopt(nullstr); 7427 3924 retval = 0; 7428 if (job_warning) 7429 goto out; 7430 jp = curjob; 7431 if (jp && jp->state == JOBSTOPPED) { 7432 out2str("You have stopped jobs.\n"); 7433 job_warning = 2; 7434 retval++; 7435 } 7436 7437 out: 3925 3926 argv = argptr; 3927 if (!*argv) { 3928 /* wait for all jobs */ 3929 for (;;) { 3930 jp = curjob; 3931 while (1) { 3932 if (!jp) { 3933 /* no running procs */ 3934 goto out; 3935 } 3936 if (jp->state == JOBRUNNING) 3937 break; 3938 jp->waited = 1; 3939 jp = jp->prev_job; 3940 } 3941 dowait(DOWAIT_BLOCK, 0); 3942 } 3943 } 3944 3945 retval = 127; 3946 do { 3947 if (**argv != '%') { 3948 pid_t pid = number(*argv); 3949 job = curjob; 3950 goto start; 3951 do { 3952 if (job->ps[job->nprocs - 1].pid == pid) 3953 break; 3954 job = job->prev_job; 3955 start: 3956 if (!job) 3957 goto repeat; 3958 } while (1); 3959 } else 3960 job = getjob(*argv, 0); 3961 /* loop until process terminated or stopped */ 3962 while (job->state == JOBRUNNING) 3963 dowait(DOWAIT_BLOCK, 0); 3964 job->waited = 1; 3965 retval = getstatus(job); 3966 repeat: 3967 ; 3968 } while (*++argv); 3969 3970 out: 7438 3971 return retval; 7439 3972 } 7440 3973 3974 static struct job * 3975 growjobtab(void) 3976 { 3977 size_t len; 3978 ptrdiff_t offset; 3979 struct job *jp, *jq; 3980 3981 len = njobs * sizeof(*jp); 3982 jq = jobtab; 3983 jp = ckrealloc(jq, len + 4 * sizeof(*jp)); 3984 3985 offset = (char *)jp - (char *)jq; 3986 if (offset) { 3987 /* Relocate pointers */ 3988 size_t l = len; 3989 3990 jq = (struct job *)((char *)jq + l); 3991 while (l) { 3992 l -= sizeof(*jp); 3993 jq--; 3994 #define joff(p) ((struct job *)((char *)(p) + l)) 3995 #define jmove(p) (p) = (void *)((char *)(p) + offset) 3996 if (joff(jp)->ps == &jq->ps0) 3997 jmove(joff(jp)->ps); 3998 if (joff(jp)->prev_job) 3999 jmove(joff(jp)->prev_job); 4000 } 4001 if (curjob) 4002 jmove(curjob); 4003 #undef joff 4004 #undef jmove 4005 } 4006 4007 njobs += 4; 4008 jobtab = jp; 4009 jp = (struct job *)((char *)jp + len); 4010 jq = jp + 3; 4011 do { 4012 jq->used = 0; 4013 } while (--jq >= jp); 4014 return jp; 4015 } 4016 4017 /* 4018 * Return a new job structure. 4019 * Called with interrupts off. 4020 */ 4021 static struct job * 4022 makejob(union node *node, int nprocs) 4023 { 4024 int i; 4025 struct job *jp; 4026 4027 for (i = njobs, jp = jobtab; ; jp++) { 4028 if (--i < 0) { 4029 jp = growjobtab(); 4030 break; 4031 } 4032 if (jp->used == 0) 4033 break; 4034 if (jp->state != JOBDONE || !jp->waited) 4035 continue; 4036 #if JOBS 4037 if (jobctl) 4038 continue; 4039 #endif 4040 freejob(jp); 4041 break; 4042 } 4043 memset(jp, 0, sizeof(*jp)); 4044 #if JOBS 4045 /* jp->jobctl is a bitfield. 4046 * "jp->jobctl |= jobctl" likely to give awful code */ 4047 if (jobctl) 4048 jp->jobctl = 1; 4049 #endif 4050 jp->prev_job = curjob; 4051 curjob = jp; 4052 jp->used = 1; 4053 jp->ps = &jp->ps0; 4054 if (nprocs > 1) { 4055 jp->ps = ckmalloc(nprocs * sizeof(struct procstat)); 4056 } 4057 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs, 4058 jobno(jp))); 4059 return jp; 4060 } 4061 4062 #if JOBS 7441 4063 /* 7442 4064 * Return a string identifying a command (to be printed by the 7443 4065 * jobs command). 7444 4066 */ 7445 7446 #if JOBS7447 4067 static char *cmdnextc; 7448 7449 static char *7450 commandtext(union node *n)7451 {7452 char *name;7453 7454 STARTSTACKSTR(cmdnextc);7455 cmdtxt(n);7456 name = stackblock();7457 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",7458 name, cmdnextc, cmdnextc));7459 return savestr(name);7460 }7461 7462 static void7463 cmdtxt(union node *n)7464 {7465 union node *np;7466 struct nodelist *lp;7467 const char *p;7468 char s[2];7469 7470 if (!n)7471 return;7472 switch (n->type) {7473 default:7474 #if DEBUG7475 abort();7476 #endif7477 case NPIPE:7478 lp = n->npipe.cmdlist;7479 for (;;) {7480 cmdtxt(lp->n);7481 lp = lp->next;7482 if (!lp)7483 break;7484 cmdputs(" | ");7485 }7486 break;7487 case NSEMI:7488 p = "; ";7489 goto binop;7490 case NAND:7491 p = " && ";7492 goto binop;7493 case NOR:7494 p = " || ";7495 binop:7496 cmdtxt(n->nbinary.ch1);7497 cmdputs(p);7498 n = n->nbinary.ch2;7499 goto donode;7500 case NREDIR:7501 case NBACKGND:7502 n = n->nredir.n;7503 goto donode;7504 case NNOT:7505 cmdputs("!");7506 n = n->nnot.com;7507 donode:7508 cmdtxt(n);7509 break;7510 case NIF:7511 cmdputs("if ");7512 cmdtxt(n->nif.test);7513 cmdputs("; then ");7514 n = n->nif.ifpart;7515 if (n->nif.elsepart) {7516 cmdtxt(n);7517 cmdputs("; else ");7518 n = n->nif.elsepart;7519 }7520 p = "; fi";7521 goto dotail;7522 case NSUBSHELL:7523 cmdputs("(");7524 n = n->nredir.n;7525 p = ")";7526 goto dotail;7527 case NWHILE:7528 p = "while ";7529 goto until;7530 case NUNTIL:7531 p = "until ";7532 until:7533 cmdputs(p);7534 cmdtxt(n->nbinary.ch1);7535 n = n->nbinary.ch2;7536 p = "; done";7537 dodo:7538 cmdputs("; do ");7539 dotail:7540 cmdtxt(n);7541 goto dotail2;7542 case NFOR:7543 cmdputs("for ");7544 cmdputs(n->nfor.var);7545 cmdputs(" in ");7546 cmdlist(n->nfor.args, 1);7547 n = n->nfor.body;7548 p = "; done";7549 goto dodo;7550 case NDEFUN:7551 cmdputs(n->narg.text);7552 p = "() { ... }";7553 goto dotail2;7554 case NCMD:7555 cmdlist(n->ncmd.args, 1);7556 cmdlist(n->ncmd.redirect, 0);7557 break;7558 case NARG:7559 p = n->narg.text;7560 dotail2:7561 cmdputs(p);7562 break;7563 case NHERE:7564 case NXHERE:7565 p = "<<...";7566 goto dotail2;7567 case NCASE:7568 cmdputs("case ");7569 cmdputs(n->ncase.expr->narg.text);7570 cmdputs(" in ");7571 for (np = n->ncase.cases; np; np = np->nclist.next) {7572 cmdtxt(np->nclist.pattern);7573 cmdputs(") ");7574 cmdtxt(np->nclist.body);7575 cmdputs(";; ");7576 }7577 p = "esac";7578 goto dotail2;7579 case NTO:7580 p = ">";7581 goto redir;7582 case NCLOBBER:7583 p = ">|";7584 goto redir;7585 case NAPPEND:7586 p = ">>";7587 goto redir;7588 case NTOFD:7589 p = ">&";7590 goto redir;7591 case NFROM:7592 p = "<";7593 goto redir;7594 case NFROMFD:7595 p = "<&";7596 goto redir;7597 case NFROMTO:7598 p = "<>";7599 redir:7600 s[0] = n->nfile.fd + '0';7601 s[1] = '\0';7602 cmdputs(s);7603 cmdputs(p);7604 if (n->type == NTOFD || n->type == NFROMFD) {7605 s[0] = n->ndup.dupfd + '0';7606 p = s;7607 goto dotail2;7608 } else {7609 n = n->nfile.fname;7610 goto donode;7611 }7612 }7613 }7614 7615 static void7616 cmdlist(union node *np, int sep)7617 {7618 for (; np; np = np->narg.next) {7619 if (!sep)7620 cmdputs(spcstr);7621 cmdtxt(np);7622 if (sep && np->narg.next)7623 cmdputs(spcstr);7624 }7625 }7626 4068 7627 4069 static void … … 7637 4079 "%", "%%", "#", "##" 7638 4080 }; 4081 7639 4082 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc); 7640 4083 p = s; … … 7651 4094 else 7652 4095 str = "${"; 7653 if (!(subtype & VSQUOTE) != !(quoted & 1)) { 7654 quoted ^= 1; 7655 c = '"'; 7656 } else 4096 if (!(subtype & VSQUOTE) == !(quoted & 1)) 7657 4097 goto dostr; 4098 quoted ^= 1; 4099 c = '"'; 7658 4100 break; 7659 4101 case CTLENDVAR: … … 7668 4110 str = "\"$(...)\""; 7669 4111 goto dostr; 7670 #if def CONFIG_ASH_MATH_SUPPORT4112 #if ENABLE_ASH_MATH_SUPPORT 7671 4113 case CTLARI: 7672 4114 str = "$(("; … … 7704 4146 } 7705 4147 USTPUTC(c, nextc); 7706 checkstr:4148 checkstr: 7707 4149 if (!str) 7708 4150 continue; 7709 dostr:4151 dostr: 7710 4152 while ((c = *str++)) { 7711 4153 USTPUTC(c, nextc); … … 7719 4161 } 7720 4162 7721 7722 static void 7723 showpipe(struct job *jp, FILE *out) 7724 { 7725 struct procstat *sp; 7726 struct procstat *spend; 7727 7728 spend = jp->ps + jp->nprocs; 7729 for (sp = jp->ps + 1; sp < spend; sp++) 7730 fprintf(out, " | %s", sp->cmd); 7731 outcslow('\n', out); 7732 flushall(); 7733 } 7734 7735 static void 7736 xtcsetpgrp(int fd, pid_t pgrp) 7737 { 7738 if (tcsetpgrp(fd, pgrp)) 7739 sh_error("Cannot set tty process group (%m)"); 4163 /* cmdtxt() and cmdlist() call each other */ 4164 static void cmdtxt(union node *n); 4165 4166 static void 4167 cmdlist(union node *np, int sep) 4168 { 4169 for (; np; np = np->narg.next) { 4170 if (!sep) 4171 cmdputs(" "); 4172 cmdtxt(np); 4173 if (sep && np->narg.next) 4174 cmdputs(" "); 4175 } 4176 } 4177 4178 static void 4179 cmdtxt(union node *n) 4180 { 4181 union node *np; 4182 struct nodelist *lp; 4183 const char *p; 4184 char s[2]; 4185 4186 if (!n) 4187 return; 4188 switch (n->type) { 4189 default: 4190 #if DEBUG 4191 abort(); 4192 #endif 4193 case NPIPE: 4194 lp = n->npipe.cmdlist; 4195 for (;;) { 4196 cmdtxt(lp->n); 4197 lp = lp->next; 4198 if (!lp) 4199 break; 4200 cmdputs(" | "); 4201 } 4202 break; 4203 case NSEMI: 4204 p = "; "; 4205 goto binop; 4206 case NAND: 4207 p = " && "; 4208 goto binop; 4209 case NOR: 4210 p = " || "; 4211 binop: 4212 cmdtxt(n->nbinary.ch1); 4213 cmdputs(p); 4214 n = n->nbinary.ch2; 4215 goto donode; 4216 case NREDIR: 4217 case NBACKGND: 4218 n = n->nredir.n; 4219 goto donode; 4220 case NNOT: 4221 cmdputs("!"); 4222 n = n->nnot.com; 4223 donode: 4224 cmdtxt(n); 4225 break; 4226 case NIF: 4227 cmdputs("if "); 4228 cmdtxt(n->nif.test); 4229 cmdputs("; then "); 4230 n = n->nif.ifpart; 4231 if (n->nif.elsepart) { 4232 cmdtxt(n); 4233 cmdputs("; else "); 4234 n = n->nif.elsepart; 4235 } 4236 p = "; fi"; 4237 goto dotail; 4238 case NSUBSHELL: 4239 cmdputs("("); 4240 n = n->nredir.n; 4241 p = ")"; 4242 goto dotail; 4243 case NWHILE: 4244 p = "while "; 4245 goto until; 4246 case NUNTIL: 4247 p = "until "; 4248 until: 4249 cmdputs(p); 4250 cmdtxt(n->nbinary.ch1); 4251 n = n->nbinary.ch2; 4252 p = "; done"; 4253 dodo: 4254 cmdputs("; do "); 4255 dotail: 4256 cmdtxt(n); 4257 goto dotail2; 4258 case NFOR: 4259 cmdputs("for "); 4260 cmdputs(n->nfor.var); 4261 cmdputs(" in "); 4262 cmdlist(n->nfor.args, 1); 4263 n = n->nfor.body; 4264 p = "; done"; 4265 goto dodo; 4266 case NDEFUN: 4267 cmdputs(n->narg.text); 4268 p = "() { ... }"; 4269 goto dotail2; 4270 case NCMD: 4271 cmdlist(n->ncmd.args, 1); 4272 cmdlist(n->ncmd.redirect, 0); 4273 break; 4274 case NARG: 4275 p = n->narg.text; 4276 dotail2: 4277 cmdputs(p); 4278 break; 4279 case NHERE: 4280 case NXHERE: 4281 p = "<<..."; 4282 goto dotail2; 4283 case NCASE: 4284 cmdputs("case "); 4285 cmdputs(n->ncase.expr->narg.text); 4286 cmdputs(" in "); 4287 for (np = n->ncase.cases; np; np = np->nclist.next) { 4288 cmdtxt(np->nclist.pattern); 4289 cmdputs(") "); 4290 cmdtxt(np->nclist.body); 4291 cmdputs(";; "); 4292 } 4293 p = "esac"; 4294 goto dotail2; 4295 case NTO: 4296 p = ">"; 4297 goto redir; 4298 case NCLOBBER: 4299 p = ">|"; 4300 goto redir; 4301 case NAPPEND: 4302 p = ">>"; 4303 goto redir; 4304 case NTOFD: 4305 p = ">&"; 4306 goto redir; 4307 case NFROM: 4308 p = "<"; 4309 goto redir; 4310 case NFROMFD: 4311 p = "<&"; 4312 goto redir; 4313 case NFROMTO: 4314 p = "<>"; 4315 redir: 4316 s[0] = n->nfile.fd + '0'; 4317 s[1] = '\0'; 4318 cmdputs(s); 4319 cmdputs(p); 4320 if (n->type == NTOFD || n->type == NFROMFD) { 4321 s[0] = n->ndup.dupfd + '0'; 4322 p = s; 4323 goto dotail2; 4324 } 4325 n = n->nfile.fname; 4326 goto donode; 4327 } 4328 } 4329 4330 static char * 4331 commandtext(union node *n) 4332 { 4333 char *name; 4334 4335 STARTSTACKSTR(cmdnextc); 4336 cmdtxt(n); 4337 name = stackblock(); 4338 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n", 4339 name, cmdnextc, cmdnextc)); 4340 return ckstrdup(name); 7740 4341 } 7741 4342 #endif /* JOBS */ 7742 4343 4344 /* 4345 * Fork off a subshell. If we are doing job control, give the subshell its 4346 * own process group. Jp is a job structure that the job is to be added to. 4347 * N is the command that will be evaluated by the child. Both jp and n may 4348 * be NULL. The mode parameter can be one of the following: 4349 * FORK_FG - Fork off a foreground process. 4350 * FORK_BG - Fork off a background process. 4351 * FORK_NOJOB - Like FORK_FG, but don't give the process its own 4352 * process group even if job control is on. 4353 * 4354 * When job control is turned off, background processes have their standard 4355 * input redirected to /dev/null (except for the second and later processes 4356 * in a pipeline). 4357 * 4358 * Called with interrupts off. 4359 */ 4360 /* 4361 * Clear traps on a fork. 4362 */ 4363 static void 4364 clear_traps(void) 4365 { 4366 char **tp; 4367 4368 for (tp = trap; tp < &trap[NSIG]; tp++) { 4369 if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 4370 INT_OFF; 4371 free(*tp); 4372 *tp = NULL; 4373 if (tp != &trap[0]) 4374 setsignal(tp - trap); 4375 INT_ON; 4376 } 4377 } 4378 } 4379 4380 /* Lives far away from here, needed for forkchild */ 4381 static void closescript(void); 4382 /* Called after fork(), in child */ 4383 static void 4384 forkchild(struct job *jp, union node *n, int mode) 4385 { 4386 int oldlvl; 4387 4388 TRACE(("Child shell %d\n", getpid())); 4389 oldlvl = shlvl; 4390 shlvl++; 4391 4392 closescript(); 4393 clear_traps(); 4394 #if JOBS 4395 /* do job control only in root shell */ 4396 jobctl = 0; 4397 if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) { 4398 pid_t pgrp; 4399 4400 if (jp->nprocs == 0) 4401 pgrp = getpid(); 4402 else 4403 pgrp = jp->ps[0].pid; 4404 /* This can fail because we are doing it in the parent also */ 4405 (void)setpgid(0, pgrp); 4406 if (mode == FORK_FG) 4407 xtcsetpgrp(ttyfd, pgrp); 4408 setsignal(SIGTSTP); 4409 setsignal(SIGTTOU); 4410 } else 4411 #endif 4412 if (mode == FORK_BG) { 4413 ignoresig(SIGINT); 4414 ignoresig(SIGQUIT); 4415 if (jp->nprocs == 0) { 4416 close(0); 4417 if (open(bb_dev_null, O_RDONLY) != 0) 4418 ash_msg_and_raise_error("can't open %s", bb_dev_null); 4419 } 4420 } 4421 if (!oldlvl && iflag) { 4422 setsignal(SIGINT); 4423 setsignal(SIGQUIT); 4424 setsignal(SIGTERM); 4425 } 4426 #if JOBS 4427 /* For "jobs | cat" to work like in bash, we must retain list of jobs 4428 * in child, but we do need to remove ourself */ 4429 if (jp) 4430 freejob(jp); 4431 #else 4432 for (jp = curjob; jp; jp = jp->prev_job) 4433 freejob(jp); 4434 #endif 4435 jobless = 0; 4436 } 4437 4438 /* Called after fork(), in parent */ 4439 static void 4440 forkparent(struct job *jp, union node *n, int mode, pid_t pid) 4441 { 4442 TRACE(("In parent shell: child = %d\n", pid)); 4443 if (!jp) { 4444 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0); 4445 jobless++; 4446 return; 4447 } 4448 #if JOBS 4449 if (mode != FORK_NOJOB && jp->jobctl) { 4450 int pgrp; 4451 4452 if (jp->nprocs == 0) 4453 pgrp = pid; 4454 else 4455 pgrp = jp->ps[0].pid; 4456 /* This can fail because we are doing it in the child also */ 4457 setpgid(pid, pgrp); 4458 } 4459 #endif 4460 if (mode == FORK_BG) { 4461 backgndpid = pid; /* set $! */ 4462 set_curjob(jp, CUR_RUNNING); 4463 } 4464 if (jp) { 4465 struct procstat *ps = &jp->ps[jp->nprocs++]; 4466 ps->pid = pid; 4467 ps->status = -1; 4468 ps->cmd = nullstr; 4469 #if JOBS 4470 if (jobctl && n) 4471 ps->cmd = commandtext(n); 4472 #endif 4473 } 4474 } 4475 7743 4476 static int 7744 getstatus(struct job *job) { 4477 forkshell(struct job *jp, union node *n, int mode) 4478 { 4479 int pid; 4480 4481 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); 4482 pid = fork(); 4483 if (pid < 0) { 4484 TRACE(("Fork failed, errno=%d", errno)); 4485 if (jp) 4486 freejob(jp); 4487 ash_msg_and_raise_error("cannot fork"); 4488 } 4489 if (pid == 0) 4490 forkchild(jp, n, mode); 4491 else 4492 forkparent(jp, n, mode, pid); 4493 return pid; 4494 } 4495 4496 /* 4497 * Wait for job to finish. 4498 * 4499 * Under job control we have the problem that while a child process is 4500 * running interrupts generated by the user are sent to the child but not 4501 * to the shell. This means that an infinite loop started by an inter- 4502 * active user may be hard to kill. With job control turned off, an 4503 * interactive user may place an interactive program inside a loop. If 4504 * the interactive program catches interrupts, the user doesn't want 4505 * these interrupts to also abort the loop. The approach we take here 4506 * is to have the shell ignore interrupt signals while waiting for a 4507 * foreground process to terminate, and then send itself an interrupt 4508 * signal if the child process was terminated by an interrupt signal. 4509 * Unfortunately, some programs want to do a bit of cleanup and then 4510 * exit on interrupt; unless these processes terminate themselves by 4511 * sending a signal to themselves (instead of calling exit) they will 4512 * confuse this approach. 4513 * 4514 * Called with interrupts off. 4515 */ 4516 static int 4517 waitforjob(struct job *jp) 4518 { 4519 int st; 4520 4521 TRACE(("waitforjob(%%%d) called\n", jobno(jp))); 4522 while (jp->state == JOBRUNNING) { 4523 dowait(DOWAIT_BLOCK, jp); 4524 } 4525 st = getstatus(jp); 4526 #if JOBS 4527 if (jp->jobctl) { 4528 xtcsetpgrp(ttyfd, rootpid); 4529 /* 4530 * This is truly gross. 4531 * If we're doing job control, then we did a TIOCSPGRP which 4532 * caused us (the shell) to no longer be in the controlling 4533 * session -- so we wouldn't have seen any ^C/SIGINT. So, we 4534 * intuit from the subprocess exit status whether a SIGINT 4535 * occurred, and if so interrupt ourselves. Yuck. - mycroft 4536 */ 4537 if (jp->sigint) 4538 raise(SIGINT); 4539 } 4540 if (jp->state == JOBDONE) 4541 #endif 4542 freejob(jp); 4543 return st; 4544 } 4545 4546 /* 4547 * return 1 if there are stopped jobs, otherwise 0 4548 */ 4549 static int 4550 stoppedjobs(void) 4551 { 4552 struct job *jp; 4553 int retval; 4554 4555 retval = 0; 4556 if (job_warning) 4557 goto out; 4558 jp = curjob; 4559 if (jp && jp->state == JOBSTOPPED) { 4560 out2str("You have stopped jobs.\n"); 4561 job_warning = 2; 4562 retval++; 4563 } 4564 out: 4565 return retval; 4566 } 4567 4568 4569 /* ============ redir.c 4570 * 4571 * Code for dealing with input/output redirection. 4572 */ 4573 4574 #define EMPTY -2 /* marks an unused slot in redirtab */ 4575 #ifndef PIPE_BUF 4576 # define PIPESIZE 4096 /* amount of buffering in a pipe */ 4577 #else 4578 # define PIPESIZE PIPE_BUF 4579 #endif 4580 4581 /* 4582 * Open a file in noclobber mode. 4583 * The code was copied from bash. 4584 */ 4585 static int 4586 noclobberopen(const char *fname) 4587 { 4588 int r, fd; 4589 struct stat finfo, finfo2; 4590 4591 /* 4592 * If the file exists and is a regular file, return an error 4593 * immediately. 4594 */ 4595 r = stat(fname, &finfo); 4596 if (r == 0 && S_ISREG(finfo.st_mode)) { 4597 errno = EEXIST; 4598 return -1; 4599 } 4600 4601 /* 4602 * If the file was not present (r != 0), make sure we open it 4603 * exclusively so that if it is created before we open it, our open 4604 * will fail. Make sure that we do not truncate an existing file. 4605 * Note that we don't turn on O_EXCL unless the stat failed -- if the 4606 * file was not a regular file, we leave O_EXCL off. 4607 */ 4608 if (r != 0) 4609 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666); 4610 fd = open(fname, O_WRONLY|O_CREAT, 0666); 4611 4612 /* If the open failed, return the file descriptor right away. */ 4613 if (fd < 0) 4614 return fd; 4615 4616 /* 4617 * OK, the open succeeded, but the file may have been changed from a 4618 * non-regular file to a regular file between the stat and the open. 4619 * We are assuming that the O_EXCL open handles the case where FILENAME 4620 * did not exist and is symlinked to an existing file between the stat 4621 * and open. 4622 */ 4623 4624 /* 4625 * If we can open it and fstat the file descriptor, and neither check 4626 * revealed that it was a regular file, and the file has not been 4627 * replaced, return the file descriptor. 4628 */ 4629 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) 4630 && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino) 4631 return fd; 4632 4633 /* The file has been replaced. badness. */ 4634 close(fd); 4635 errno = EEXIST; 4636 return -1; 4637 } 4638 4639 /* 4640 * Handle here documents. Normally we fork off a process to write the 4641 * data to a pipe. If the document is short, we can stuff the data in 4642 * the pipe without forking. 4643 */ 4644 /* openhere needs this forward reference */ 4645 static void expandhere(union node *arg, int fd); 4646 static int 4647 openhere(union node *redir) 4648 { 4649 int pip[2]; 4650 size_t len = 0; 4651 4652 if (pipe(pip) < 0) 4653 ash_msg_and_raise_error("pipe call failed"); 4654 if (redir->type == NHERE) { 4655 len = strlen(redir->nhere.doc->narg.text); 4656 if (len <= PIPESIZE) { 4657 full_write(pip[1], redir->nhere.doc->narg.text, len); 4658 goto out; 4659 } 4660 } 4661 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 4662 close(pip[0]); 4663 signal(SIGINT, SIG_IGN); 4664 signal(SIGQUIT, SIG_IGN); 4665 signal(SIGHUP, SIG_IGN); 4666 #ifdef SIGTSTP 4667 signal(SIGTSTP, SIG_IGN); 4668 #endif 4669 signal(SIGPIPE, SIG_DFL); 4670 if (redir->type == NHERE) 4671 full_write(pip[1], redir->nhere.doc->narg.text, len); 4672 else 4673 expandhere(redir->nhere.doc, pip[1]); 4674 _exit(0); 4675 } 4676 out: 4677 close(pip[1]); 4678 return pip[0]; 4679 } 4680 4681 static int 4682 openredirect(union node *redir) 4683 { 4684 char *fname; 4685 int f; 4686 4687 switch (redir->nfile.type) { 4688 case NFROM: 4689 fname = redir->nfile.expfname; 4690 f = open(fname, O_RDONLY); 4691 if (f < 0) 4692 goto eopen; 4693 break; 4694 case NFROMTO: 4695 fname = redir->nfile.expfname; 4696 f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666); 4697 if (f < 0) 4698 goto ecreate; 4699 break; 4700 case NTO: 4701 /* Take care of noclobber mode. */ 4702 if (Cflag) { 4703 fname = redir->nfile.expfname; 4704 f = noclobberopen(fname); 4705 if (f < 0) 4706 goto ecreate; 4707 break; 4708 } 4709 /* FALLTHROUGH */ 4710 case NCLOBBER: 4711 fname = redir->nfile.expfname; 4712 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666); 4713 if (f < 0) 4714 goto ecreate; 4715 break; 4716 case NAPPEND: 4717 fname = redir->nfile.expfname; 4718 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); 4719 if (f < 0) 4720 goto ecreate; 4721 break; 4722 default: 4723 #if DEBUG 4724 abort(); 4725 #endif 4726 /* Fall through to eliminate warning. */ 4727 case NTOFD: 4728 case NFROMFD: 4729 f = -1; 4730 break; 4731 case NHERE: 4732 case NXHERE: 4733 f = openhere(redir); 4734 break; 4735 } 4736 4737 return f; 4738 ecreate: 4739 ash_msg_and_raise_error("cannot create %s: %s", fname, errmsg(errno, "nonexistent directory")); 4740 eopen: 4741 ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "no such file")); 4742 } 4743 4744 /* 4745 * Copy a file descriptor to be >= to. Returns -1 4746 * if the source file descriptor is closed, EMPTY if there are no unused 4747 * file descriptors left. 4748 */ 4749 static int 4750 copyfd(int from, int to) 4751 { 4752 int newfd; 4753 4754 newfd = fcntl(from, F_DUPFD, to); 4755 if (newfd < 0) { 4756 if (errno == EMFILE) 4757 return EMPTY; 4758 ash_msg_and_raise_error("%d: %m", from); 4759 } 4760 return newfd; 4761 } 4762 4763 static void 4764 dupredirect(union node *redir, int f) 4765 { 4766 int fd = redir->nfile.fd; 4767 4768 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { 4769 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ 4770 copyfd(redir->ndup.dupfd, fd); 4771 } 4772 return; 4773 } 4774 4775 if (f != fd) { 4776 copyfd(f, fd); 4777 close(f); 4778 } 4779 } 4780 4781 /* 4782 * Process a list of redirection commands. If the REDIR_PUSH flag is set, 4783 * old file descriptors are stashed away so that the redirection can be 4784 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the 4785 * standard output, and the standard error if it becomes a duplicate of 4786 * stdout, is saved in memory. 4787 */ 4788 /* flags passed to redirect */ 4789 #define REDIR_PUSH 01 /* save previous values of file descriptors */ 4790 #define REDIR_SAVEFD2 03 /* set preverrout */ 4791 static void 4792 redirect(union node *redir, int flags) 4793 { 4794 union node *n; 4795 struct redirtab *sv; 4796 int i; 4797 int fd; 4798 int newfd; 4799 int *p; 4800 nullredirs++; 4801 if (!redir) { 4802 return; 4803 } 4804 sv = NULL; 4805 INT_OFF; 4806 if (flags & REDIR_PUSH) { 4807 struct redirtab *q; 4808 q = ckmalloc(sizeof(struct redirtab)); 4809 q->next = redirlist; 4810 redirlist = q; 4811 q->nullredirs = nullredirs - 1; 4812 for (i = 0; i < 10; i++) 4813 q->renamed[i] = EMPTY; 4814 nullredirs = 0; 4815 sv = q; 4816 } 4817 n = redir; 4818 do { 4819 fd = n->nfile.fd; 4820 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) 4821 && n->ndup.dupfd == fd) 4822 continue; /* redirect from/to same file descriptor */ 4823 4824 newfd = openredirect(n); 4825 if (fd == newfd) 4826 continue; 4827 if (sv && *(p = &sv->renamed[fd]) == EMPTY) { 4828 i = fcntl(fd, F_DUPFD, 10); 4829 4830 if (i == -1) { 4831 i = errno; 4832 if (i != EBADF) { 4833 close(newfd); 4834 errno = i; 4835 ash_msg_and_raise_error("%d: %m", fd); 4836 /* NOTREACHED */ 4837 } 4838 } else { 4839 *p = i; 4840 close(fd); 4841 } 4842 } else { 4843 close(fd); 4844 } 4845 dupredirect(n, newfd); 4846 } while ((n = n->nfile.next)); 4847 INT_ON; 4848 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0) 4849 preverrout_fd = sv->renamed[2]; 4850 } 4851 4852 /* 4853 * Undo the effects of the last redirection. 4854 */ 4855 static void 4856 popredir(int drop) 4857 { 4858 struct redirtab *rp; 4859 int i; 4860 4861 if (--nullredirs >= 0) 4862 return; 4863 INT_OFF; 4864 rp = redirlist; 4865 for (i = 0; i < 10; i++) { 4866 if (rp->renamed[i] != EMPTY) { 4867 if (!drop) { 4868 close(i); 4869 copyfd(rp->renamed[i], i); 4870 } 4871 close(rp->renamed[i]); 4872 } 4873 } 4874 redirlist = rp->next; 4875 nullredirs = rp->nullredirs; 4876 free(rp); 4877 INT_ON; 4878 } 4879 4880 /* 4881 * Undo all redirections. Called on error or interrupt. 4882 */ 4883 4884 /* 4885 * Discard all saved file descriptors. 4886 */ 4887 static void 4888 clearredir(int drop) 4889 { 4890 for (;;) { 4891 nullredirs = 0; 4892 if (!redirlist) 4893 break; 4894 popredir(drop); 4895 } 4896 } 4897 4898 static int 4899 redirectsafe(union node *redir, int flags) 4900 { 4901 int err; 4902 volatile int saveint; 4903 struct jmploc *volatile savehandler = exception_handler; 4904 struct jmploc jmploc; 4905 4906 SAVE_INT(saveint); 4907 err = setjmp(jmploc.loc) * 2; 4908 if (!err) { 4909 exception_handler = &jmploc; 4910 redirect(redir, flags); 4911 } 4912 exception_handler = savehandler; 4913 if (err && exception != EXERROR) 4914 longjmp(exception_handler->loc, 1); 4915 RESTORE_INT(saveint); 4916 return err; 4917 } 4918 4919 4920 /* ============ Routines to expand arguments to commands 4921 * 4922 * We have to deal with backquotes, shell variables, and file metacharacters. 4923 */ 4924 4925 /* 4926 * expandarg flags 4927 */ 4928 #define EXP_FULL 0x1 /* perform word splitting & file globbing */ 4929 #define EXP_TILDE 0x2 /* do normal tilde expansion */ 4930 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ 4931 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ 4932 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ 4933 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */ 4934 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ 4935 #define EXP_WORD 0x80 /* expand word in parameter expansion */ 4936 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */ 4937 /* 4938 * _rmescape() flags 4939 */ 4940 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ 4941 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ 4942 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */ 4943 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ 4944 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ 4945 4946 /* 4947 * Structure specifying which parts of the string should be searched 4948 * for IFS characters. 4949 */ 4950 struct ifsregion { 4951 struct ifsregion *next; /* next region in list */ 4952 int begoff; /* offset of start of region */ 4953 int endoff; /* offset of end of region */ 4954 int nulonly; /* search for nul bytes only */ 4955 }; 4956 4957 struct arglist { 4958 struct strlist *list; 4959 struct strlist **lastp; 4960 }; 4961 4962 /* output of current string */ 4963 static char *expdest; 4964 /* list of back quote expressions */ 4965 static struct nodelist *argbackq; 4966 /* first struct in list of ifs regions */ 4967 static struct ifsregion ifsfirst; 4968 /* last struct in list */ 4969 static struct ifsregion *ifslastp; 4970 /* holds expanded arg list */ 4971 static struct arglist exparg; 4972 4973 /* 4974 * Our own itoa(). 4975 */ 4976 static int 4977 cvtnum(arith_t num) 4978 { 4979 int len; 4980 4981 expdest = makestrspace(32, expdest); 4982 #if ENABLE_ASH_MATH_SUPPORT_64 4983 len = fmtstr(expdest, 32, "%lld", (long long) num); 4984 #else 4985 len = fmtstr(expdest, 32, "%ld", num); 4986 #endif 4987 STADJUST(len, expdest); 4988 return len; 4989 } 4990 4991 static size_t 4992 esclen(const char *start, const char *p) 4993 { 4994 size_t esc = 0; 4995 4996 while (p > start && *--p == CTLESC) { 4997 esc++; 4998 } 4999 return esc; 5000 } 5001 5002 /* 5003 * Remove any CTLESC characters from a string. 5004 */ 5005 static char * 5006 _rmescapes(char *str, int flag) 5007 { 5008 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' }; 5009 5010 char *p, *q, *r; 5011 unsigned inquotes; 5012 int notescaped; 5013 int globbing; 5014 5015 p = strpbrk(str, qchars); 5016 if (!p) { 5017 return str; 5018 } 5019 q = p; 5020 r = str; 5021 if (flag & RMESCAPE_ALLOC) { 5022 size_t len = p - str; 5023 size_t fulllen = len + strlen(p) + 1; 5024 5025 if (flag & RMESCAPE_GROW) { 5026 r = makestrspace(fulllen, expdest); 5027 } else if (flag & RMESCAPE_HEAP) { 5028 r = ckmalloc(fulllen); 5029 } else { 5030 r = stalloc(fulllen); 5031 } 5032 q = r; 5033 if (len > 0) { 5034 q = memcpy(q, str, len) + len; 5035 } 5036 } 5037 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; 5038 globbing = flag & RMESCAPE_GLOB; 5039 notescaped = globbing; 5040 while (*p) { 5041 if (*p == CTLQUOTEMARK) { 5042 inquotes = ~inquotes; 5043 p++; 5044 notescaped = globbing; 5045 continue; 5046 } 5047 if (*p == '\\') { 5048 /* naked back slash */ 5049 notescaped = 0; 5050 goto copy; 5051 } 5052 if (*p == CTLESC) { 5053 p++; 5054 if (notescaped && inquotes && *p != '/') { 5055 *q++ = '\\'; 5056 } 5057 } 5058 notescaped = globbing; 5059 copy: 5060 *q++ = *p++; 5061 } 5062 *q = '\0'; 5063 if (flag & RMESCAPE_GROW) { 5064 expdest = r; 5065 STADJUST(q - r + 1, expdest); 5066 } 5067 return r; 5068 } 5069 #define rmescapes(p) _rmescapes((p), 0) 5070 5071 #define pmatch(a, b) !fnmatch((a), (b), 0) 5072 5073 /* 5074 * Prepare a pattern for a expmeta (internal glob(3)) call. 5075 * 5076 * Returns an stalloced string. 5077 */ 5078 static char * 5079 preglob(const char *pattern, int quoted, int flag) 5080 { 5081 flag |= RMESCAPE_GLOB; 5082 if (quoted) { 5083 flag |= RMESCAPE_QUOTED; 5084 } 5085 return _rmescapes((char *)pattern, flag); 5086 } 5087 5088 /* 5089 * Put a string on the stack. 5090 */ 5091 static void 5092 memtodest(const char *p, size_t len, int syntax, int quotes) 5093 { 5094 char *q = expdest; 5095 5096 q = makestrspace(len * 2, q); 5097 5098 while (len--) { 5099 int c = signed_char2int(*p++); 5100 if (!c) 5101 continue; 5102 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK)) 5103 USTPUTC(CTLESC, q); 5104 USTPUTC(c, q); 5105 } 5106 5107 expdest = q; 5108 } 5109 5110 static void 5111 strtodest(const char *p, int syntax, int quotes) 5112 { 5113 memtodest(p, strlen(p), syntax, quotes); 5114 } 5115 5116 /* 5117 * Record the fact that we have to scan this region of the 5118 * string for IFS characters. 5119 */ 5120 static void 5121 recordregion(int start, int end, int nulonly) 5122 { 5123 struct ifsregion *ifsp; 5124 5125 if (ifslastp == NULL) { 5126 ifsp = &ifsfirst; 5127 } else { 5128 INT_OFF; 5129 ifsp = ckmalloc(sizeof(*ifsp)); 5130 ifsp->next = NULL; 5131 ifslastp->next = ifsp; 5132 INT_ON; 5133 } 5134 ifslastp = ifsp; 5135 ifslastp->begoff = start; 5136 ifslastp->endoff = end; 5137 ifslastp->nulonly = nulonly; 5138 } 5139 5140 static void 5141 removerecordregions(int endoff) 5142 { 5143 if (ifslastp == NULL) 5144 return; 5145 5146 if (ifsfirst.endoff > endoff) { 5147 while (ifsfirst.next != NULL) { 5148 struct ifsregion *ifsp; 5149 INT_OFF; 5150 ifsp = ifsfirst.next->next; 5151 free(ifsfirst.next); 5152 ifsfirst.next = ifsp; 5153 INT_ON; 5154 } 5155 if (ifsfirst.begoff > endoff) 5156 ifslastp = NULL; 5157 else { 5158 ifslastp = &ifsfirst; 5159 ifsfirst.endoff = endoff; 5160 } 5161 return; 5162 } 5163 5164 ifslastp = &ifsfirst; 5165 while (ifslastp->next && ifslastp->next->begoff < endoff) 5166 ifslastp=ifslastp->next; 5167 while (ifslastp->next != NULL) { 5168 struct ifsregion *ifsp; 5169 INT_OFF; 5170 ifsp = ifslastp->next->next; 5171 free(ifslastp->next); 5172 ifslastp->next = ifsp; 5173 INT_ON; 5174 } 5175 if (ifslastp->endoff > endoff) 5176 ifslastp->endoff = endoff; 5177 } 5178 5179 static char * 5180 exptilde(char *startp, char *p, int flag) 5181 { 5182 char c; 5183 char *name; 5184 struct passwd *pw; 5185 const char *home; 5186 int quotes = flag & (EXP_FULL | EXP_CASE); 5187 int startloc; 5188 5189 name = p + 1; 5190 5191 while ((c = *++p) != '\0') { 5192 switch (c) { 5193 case CTLESC: 5194 return startp; 5195 case CTLQUOTEMARK: 5196 return startp; 5197 case ':': 5198 if (flag & EXP_VARTILDE) 5199 goto done; 5200 break; 5201 case '/': 5202 case CTLENDVAR: 5203 goto done; 5204 } 5205 } 5206 done: 5207 *p = '\0'; 5208 if (*name == '\0') { 5209 home = lookupvar(homestr); 5210 } else { 5211 pw = getpwnam(name); 5212 if (pw == NULL) 5213 goto lose; 5214 home = pw->pw_dir; 5215 } 5216 if (!home || !*home) 5217 goto lose; 5218 *p = c; 5219 startloc = expdest - (char *)stackblock(); 5220 strtodest(home, SQSYNTAX, quotes); 5221 recordregion(startloc, expdest - (char *)stackblock(), 0); 5222 return p; 5223 lose: 5224 *p = c; 5225 return startp; 5226 } 5227 5228 /* 5229 * Execute a command inside back quotes. If it's a builtin command, we 5230 * want to save its output in a block obtained from malloc. Otherwise 5231 * we fork off a subprocess and get the output of the command via a pipe. 5232 * Should be called with interrupts off. 5233 */ 5234 struct backcmd { /* result of evalbackcmd */ 5235 int fd; /* file descriptor to read from */ 5236 char *buf; /* buffer */ 5237 int nleft; /* number of chars in buffer */ 5238 struct job *jp; /* job structure for command */ 5239 }; 5240 5241 /* These forward decls are needed to use "eval" code for backticks handling: */ 5242 static int back_exitstatus; /* exit status of backquoted command */ 5243 #define EV_EXIT 01 /* exit after evaluating tree */ 5244 static void evaltree(union node *, int); 5245 5246 static void 5247 evalbackcmd(union node *n, struct backcmd *result) 5248 { 5249 int saveherefd; 5250 5251 result->fd = -1; 5252 result->buf = NULL; 5253 result->nleft = 0; 5254 result->jp = NULL; 5255 if (n == NULL) { 5256 goto out; 5257 } 5258 5259 saveherefd = herefd; 5260 herefd = -1; 5261 5262 { 5263 int pip[2]; 5264 struct job *jp; 5265 5266 if (pipe(pip) < 0) 5267 ash_msg_and_raise_error("pipe call failed"); 5268 jp = makejob(n, 1); 5269 if (forkshell(jp, n, FORK_NOJOB) == 0) { 5270 FORCE_INT_ON; 5271 close(pip[0]); 5272 if (pip[1] != 1) { 5273 close(1); 5274 copyfd(pip[1], 1); 5275 close(pip[1]); 5276 } 5277 eflag = 0; 5278 evaltree(n, EV_EXIT); /* actually evaltreenr... */ 5279 /* NOTREACHED */ 5280 } 5281 close(pip[1]); 5282 result->fd = pip[0]; 5283 result->jp = jp; 5284 } 5285 herefd = saveherefd; 5286 out: 5287 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", 5288 result->fd, result->buf, result->nleft, result->jp)); 5289 } 5290 5291 /* 5292 * Expand stuff in backwards quotes. 5293 */ 5294 static void 5295 expbackq(union node *cmd, int quoted, int quotes) 5296 { 5297 struct backcmd in; 5298 int i; 5299 char buf[128]; 5300 char *p; 5301 char *dest; 5302 int startloc; 5303 int syntax = quoted? DQSYNTAX : BASESYNTAX; 5304 struct stackmark smark; 5305 5306 INT_OFF; 5307 setstackmark(&smark); 5308 dest = expdest; 5309 startloc = dest - (char *)stackblock(); 5310 grabstackstr(dest); 5311 evalbackcmd(cmd, &in); 5312 popstackmark(&smark); 5313 5314 p = in.buf; 5315 i = in.nleft; 5316 if (i == 0) 5317 goto read; 5318 for (;;) { 5319 memtodest(p, i, syntax, quotes); 5320 read: 5321 if (in.fd < 0) 5322 break; 5323 i = safe_read(in.fd, buf, sizeof(buf)); 5324 TRACE(("expbackq: read returns %d\n", i)); 5325 if (i <= 0) 5326 break; 5327 p = buf; 5328 } 5329 5330 if (in.buf) 5331 free(in.buf); 5332 if (in.fd >= 0) { 5333 close(in.fd); 5334 back_exitstatus = waitforjob(in.jp); 5335 } 5336 INT_ON; 5337 5338 /* Eat all trailing newlines */ 5339 dest = expdest; 5340 for (; dest > (char *)stackblock() && dest[-1] == '\n';) 5341 STUNPUTC(dest); 5342 expdest = dest; 5343 5344 if (quoted == 0) 5345 recordregion(startloc, dest - (char *)stackblock(), 0); 5346 TRACE(("evalbackq: size=%d: \"%.*s\"\n", 5347 (dest - (char *)stackblock()) - startloc, 5348 (dest - (char *)stackblock()) - startloc, 5349 stackblock() + startloc)); 5350 } 5351 5352 #if ENABLE_ASH_MATH_SUPPORT 5353 /* 5354 * Expand arithmetic expression. Backup to start of expression, 5355 * evaluate, place result in (backed up) result, adjust string position. 5356 */ 5357 static void 5358 expari(int quotes) 5359 { 5360 char *p, *start; 5361 int begoff; 5362 int flag; 5363 int len; 5364 5365 /* ifsfree(); */ 5366 5367 /* 5368 * This routine is slightly over-complicated for 5369 * efficiency. Next we scan backwards looking for the 5370 * start of arithmetic. 5371 */ 5372 start = stackblock(); 5373 p = expdest - 1; 5374 *p = '\0'; 5375 p--; 5376 do { 5377 int esc; 5378 5379 while (*p != CTLARI) { 5380 p--; 5381 #if DEBUG 5382 if (p < start) { 5383 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)"); 5384 } 5385 #endif 5386 } 5387 5388 esc = esclen(start, p); 5389 if (!(esc % 2)) { 5390 break; 5391 } 5392 5393 p -= esc + 1; 5394 } while (1); 5395 5396 begoff = p - start; 5397 5398 removerecordregions(begoff); 5399 5400 flag = p[1]; 5401 5402 expdest = p; 5403 5404 if (quotes) 5405 rmescapes(p + 2); 5406 5407 len = cvtnum(dash_arith(p + 2)); 5408 5409 if (flag != '"') 5410 recordregion(begoff, begoff + len, 0); 5411 } 5412 #endif 5413 5414 /* argstr needs it */ 5415 static char *evalvar(char *p, int flag); 5416 5417 /* 5418 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC 5419 * characters to allow for further processing. Otherwise treat 5420 * $@ like $* since no splitting will be performed. 5421 */ 5422 static void 5423 argstr(char *p, int flag) 5424 { 5425 static const char spclchars[] ALIGN1 = { 5426 '=', 5427 ':', 5428 CTLQUOTEMARK, 5429 CTLENDVAR, 5430 CTLESC, 5431 CTLVAR, 5432 CTLBACKQ, 5433 CTLBACKQ | CTLQUOTE, 5434 #if ENABLE_ASH_MATH_SUPPORT 5435 CTLENDARI, 5436 #endif 5437 0 5438 }; 5439 const char *reject = spclchars; 5440 int c; 5441 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ 5442 int breakall = flag & EXP_WORD; 5443 int inquotes; 5444 size_t length; 5445 int startloc; 5446 5447 if (!(flag & EXP_VARTILDE)) { 5448 reject += 2; 5449 } else if (flag & EXP_VARTILDE2) { 5450 reject++; 5451 } 5452 inquotes = 0; 5453 length = 0; 5454 if (flag & EXP_TILDE) { 5455 char *q; 5456 5457 flag &= ~EXP_TILDE; 5458 tilde: 5459 q = p; 5460 if (*q == CTLESC && (flag & EXP_QWORD)) 5461 q++; 5462 if (*q == '~') 5463 p = exptilde(p, q, flag); 5464 } 5465 start: 5466 startloc = expdest - (char *)stackblock(); 5467 for (;;) { 5468 length += strcspn(p + length, reject); 5469 c = p[length]; 5470 if (c && (!(c & 0x80) 5471 #if ENABLE_ASH_MATH_SUPPORT 5472 || c == CTLENDARI 5473 #endif 5474 )) { 5475 /* c == '=' || c == ':' || c == CTLENDARI */ 5476 length++; 5477 } 5478 if (length > 0) { 5479 int newloc; 5480 expdest = stack_nputstr(p, length, expdest); 5481 newloc = expdest - (char *)stackblock(); 5482 if (breakall && !inquotes && newloc > startloc) { 5483 recordregion(startloc, newloc, 0); 5484 } 5485 startloc = newloc; 5486 } 5487 p += length + 1; 5488 length = 0; 5489 5490 switch (c) { 5491 case '\0': 5492 goto breakloop; 5493 case '=': 5494 if (flag & EXP_VARTILDE2) { 5495 p--; 5496 continue; 5497 } 5498 flag |= EXP_VARTILDE2; 5499 reject++; 5500 /* fall through */ 5501 case ':': 5502 /* 5503 * sort of a hack - expand tildes in variable 5504 * assignments (after the first '=' and after ':'s). 5505 */ 5506 if (*--p == '~') { 5507 goto tilde; 5508 } 5509 continue; 5510 } 5511 5512 switch (c) { 5513 case CTLENDVAR: /* ??? */ 5514 goto breakloop; 5515 case CTLQUOTEMARK: 5516 /* "$@" syntax adherence hack */ 5517 if ( 5518 !inquotes && 5519 !memcmp(p, dolatstr, 4) && 5520 (p[4] == CTLQUOTEMARK || ( 5521 p[4] == CTLENDVAR && 5522 p[5] == CTLQUOTEMARK 5523 )) 5524 ) { 5525 p = evalvar(p + 1, flag) + 1; 5526 goto start; 5527 } 5528 inquotes = !inquotes; 5529 addquote: 5530 if (quotes) { 5531 p--; 5532 length++; 5533 startloc++; 5534 } 5535 break; 5536 case CTLESC: 5537 startloc++; 5538 length++; 5539 goto addquote; 5540 case CTLVAR: 5541 p = evalvar(p, flag); 5542 goto start; 5543 case CTLBACKQ: 5544 c = 0; 5545 case CTLBACKQ|CTLQUOTE: 5546 expbackq(argbackq->n, c, quotes); 5547 argbackq = argbackq->next; 5548 goto start; 5549 #if ENABLE_ASH_MATH_SUPPORT 5550 case CTLENDARI: 5551 p--; 5552 expari(quotes); 5553 goto start; 5554 #endif 5555 } 5556 } 5557 breakloop: 5558 ; 5559 } 5560 5561 static char * 5562 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes, 5563 int zero) 5564 { 5565 char *loc; 5566 char *loc2; 5567 char c; 5568 5569 loc = startp; 5570 loc2 = rmesc; 5571 do { 5572 int match; 5573 const char *s = loc2; 5574 c = *loc2; 5575 if (zero) { 5576 *loc2 = '\0'; 5577 s = rmesc; 5578 } 5579 match = pmatch(str, s); 5580 *loc2 = c; 5581 if (match) 5582 return loc; 5583 if (quotes && *loc == CTLESC) 5584 loc++; 5585 loc++; 5586 loc2++; 5587 } while (c); 5588 return 0; 5589 } 5590 5591 static char * 5592 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes, 5593 int zero) 5594 { 5595 int esc = 0; 5596 char *loc; 5597 char *loc2; 5598 5599 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) { 5600 int match; 5601 char c = *loc2; 5602 const char *s = loc2; 5603 if (zero) { 5604 *loc2 = '\0'; 5605 s = rmesc; 5606 } 5607 match = pmatch(str, s); 5608 *loc2 = c; 5609 if (match) 5610 return loc; 5611 loc--; 5612 if (quotes) { 5613 if (--esc < 0) { 5614 esc = esclen(startp, loc); 5615 } 5616 if (esc % 2) { 5617 esc--; 5618 loc--; 5619 } 5620 } 5621 } 5622 return 0; 5623 } 5624 5625 static void varunset(const char *, const char *, const char *, int) ATTRIBUTE_NORETURN; 5626 static void 5627 varunset(const char *end, const char *var, const char *umsg, int varflags) 5628 { 5629 const char *msg; 5630 const char *tail; 5631 5632 tail = nullstr; 5633 msg = "parameter not set"; 5634 if (umsg) { 5635 if (*end == CTLENDVAR) { 5636 if (varflags & VSNUL) 5637 tail = " or null"; 5638 } else 5639 msg = umsg; 5640 } 5641 ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail); 5642 } 5643 5644 static const char * 5645 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes) 5646 { 5647 char *startp; 5648 char *loc; 5649 int saveherefd = herefd; 5650 struct nodelist *saveargbackq = argbackq; 5651 int amount; 5652 char *rmesc, *rmescend; 5653 int zero; 5654 char *(*scan)(char *, char *, char *, char *, int , int); 5655 5656 herefd = -1; 5657 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0); 5658 STPUTC('\0', expdest); 5659 herefd = saveherefd; 5660 argbackq = saveargbackq; 5661 startp = stackblock() + startloc; 5662 5663 switch (subtype) { 5664 case VSASSIGN: 5665 setvar(str, startp, 0); 5666 amount = startp - expdest; 5667 STADJUST(amount, expdest); 5668 return startp; 5669 5670 case VSQUESTION: 5671 varunset(p, str, startp, varflags); 5672 /* NOTREACHED */ 5673 } 5674 5675 subtype -= VSTRIMRIGHT; 5676 #if DEBUG 5677 if (subtype < 0 || subtype > 3) 5678 abort(); 5679 #endif 5680 5681 rmesc = startp; 5682 rmescend = stackblock() + strloc; 5683 if (quotes) { 5684 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW); 5685 if (rmesc != startp) { 5686 rmescend = expdest; 5687 startp = stackblock() + startloc; 5688 } 5689 } 5690 rmescend--; 5691 str = stackblock() + strloc; 5692 preglob(str, varflags & VSQUOTE, 0); 5693 5694 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */ 5695 zero = subtype >> 1; 5696 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */ 5697 scan = (subtype & 1) ^ zero ? scanleft : scanright; 5698 5699 loc = scan(startp, rmesc, rmescend, str, quotes, zero); 5700 if (loc) { 5701 if (zero) { 5702 memmove(startp, loc, str - loc); 5703 loc = startp + (str - loc) - 1; 5704 } 5705 *loc = '\0'; 5706 amount = loc - expdest; 5707 STADJUST(amount, expdest); 5708 } 5709 return loc; 5710 } 5711 5712 /* 5713 * Add the value of a specialized variable to the stack string. 5714 */ 5715 static ssize_t 5716 varvalue(char *name, int varflags, int flags) 5717 { 5718 int num; 5719 char *p; 5720 int i; 5721 int sep = 0; 5722 int sepq = 0; 5723 ssize_t len = 0; 5724 char **ap; 5725 int syntax; 5726 int quoted = varflags & VSQUOTE; 5727 int subtype = varflags & VSTYPE; 5728 int quotes = flags & (EXP_FULL | EXP_CASE); 5729 5730 if (quoted && (flags & EXP_FULL)) 5731 sep = 1 << CHAR_BIT; 5732 5733 syntax = quoted ? DQSYNTAX : BASESYNTAX; 5734 switch (*name) { 5735 case '$': 5736 num = rootpid; 5737 goto numvar; 5738 case '?': 5739 num = exitstatus; 5740 goto numvar; 5741 case '#': 5742 num = shellparam.nparam; 5743 goto numvar; 5744 case '!': 5745 num = backgndpid; 5746 if (num == 0) 5747 return -1; 5748 numvar: 5749 len = cvtnum(num); 5750 break; 5751 case '-': 5752 p = makestrspace(NOPTS, expdest); 5753 for (i = NOPTS - 1; i >= 0; i--) { 5754 if (optlist[i]) { 5755 USTPUTC(optletters(i), p); 5756 len++; 5757 } 5758 } 5759 expdest = p; 5760 break; 5761 case '@': 5762 if (sep) 5763 goto param; 5764 /* fall through */ 5765 case '*': 5766 sep = ifsset() ? signed_char2int(ifsval()[0]) : ' '; 5767 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK)) 5768 sepq = 1; 5769 param: 5770 ap = shellparam.p; 5771 if (!ap) 5772 return -1; 5773 while ((p = *ap++)) { 5774 size_t partlen; 5775 5776 partlen = strlen(p); 5777 len += partlen; 5778 5779 if (!(subtype == VSPLUS || subtype == VSLENGTH)) 5780 memtodest(p, partlen, syntax, quotes); 5781 5782 if (*ap && sep) { 5783 char *q; 5784 5785 len++; 5786 if (subtype == VSPLUS || subtype == VSLENGTH) { 5787 continue; 5788 } 5789 q = expdest; 5790 if (sepq) 5791 STPUTC(CTLESC, q); 5792 STPUTC(sep, q); 5793 expdest = q; 5794 } 5795 } 5796 return len; 5797 case '0': 5798 case '1': 5799 case '2': 5800 case '3': 5801 case '4': 5802 case '5': 5803 case '6': 5804 case '7': 5805 case '8': 5806 case '9': 5807 num = atoi(name); 5808 if (num < 0 || num > shellparam.nparam) 5809 return -1; 5810 p = num ? shellparam.p[num - 1] : arg0; 5811 goto value; 5812 default: 5813 p = lookupvar(name); 5814 value: 5815 if (!p) 5816 return -1; 5817 5818 len = strlen(p); 5819 if (!(subtype == VSPLUS || subtype == VSLENGTH)) 5820 memtodest(p, len, syntax, quotes); 5821 return len; 5822 } 5823 5824 if (subtype == VSPLUS || subtype == VSLENGTH) 5825 STADJUST(-len, expdest); 5826 return len; 5827 } 5828 5829 /* 5830 * Expand a variable, and return a pointer to the next character in the 5831 * input string. 5832 */ 5833 static char * 5834 evalvar(char *p, int flag) 5835 { 5836 int subtype; 5837 int varflags; 5838 char *var; 5839 int patloc; 5840 int c; 5841 int startloc; 5842 ssize_t varlen; 5843 int easy; 5844 int quotes; 5845 int quoted; 5846 5847 quotes = flag & (EXP_FULL | EXP_CASE); 5848 varflags = *p++; 5849 subtype = varflags & VSTYPE; 5850 quoted = varflags & VSQUOTE; 5851 var = p; 5852 easy = (!quoted || (*var == '@' && shellparam.nparam)); 5853 startloc = expdest - (char *)stackblock(); 5854 p = strchr(p, '=') + 1; 5855 5856 again: 5857 varlen = varvalue(var, varflags, flag); 5858 if (varflags & VSNUL) 5859 varlen--; 5860 5861 if (subtype == VSPLUS) { 5862 varlen = -1 - varlen; 5863 goto vsplus; 5864 } 5865 5866 if (subtype == VSMINUS) { 5867 vsplus: 5868 if (varlen < 0) { 5869 argstr( 5870 p, flag | EXP_TILDE | 5871 (quoted ? EXP_QWORD : EXP_WORD) 5872 ); 5873 goto end; 5874 } 5875 if (easy) 5876 goto record; 5877 goto end; 5878 } 5879 5880 if (subtype == VSASSIGN || subtype == VSQUESTION) { 5881 if (varlen < 0) { 5882 if (subevalvar(p, var, 0, subtype, startloc, varflags, 0)) { 5883 varflags &= ~VSNUL; 5884 /* 5885 * Remove any recorded regions beyond 5886 * start of variable 5887 */ 5888 removerecordregions(startloc); 5889 goto again; 5890 } 5891 goto end; 5892 } 5893 if (easy) 5894 goto record; 5895 goto end; 5896 } 5897 5898 if (varlen < 0 && uflag) 5899 varunset(p, var, 0, 0); 5900 5901 if (subtype == VSLENGTH) { 5902 cvtnum(varlen > 0 ? varlen : 0); 5903 goto record; 5904 } 5905 5906 if (subtype == VSNORMAL) { 5907 if (!easy) 5908 goto end; 5909 record: 5910 recordregion(startloc, expdest - (char *)stackblock(), quoted); 5911 goto end; 5912 } 5913 5914 #if DEBUG 5915 switch (subtype) { 5916 case VSTRIMLEFT: 5917 case VSTRIMLEFTMAX: 5918 case VSTRIMRIGHT: 5919 case VSTRIMRIGHTMAX: 5920 break; 5921 default: 5922 abort(); 5923 } 5924 #endif 5925 5926 if (varlen >= 0) { 5927 /* 5928 * Terminate the string and start recording the pattern 5929 * right after it 5930 */ 5931 STPUTC('\0', expdest); 5932 patloc = expdest - (char *)stackblock(); 5933 if (subevalvar(p, NULL, patloc, subtype, 5934 startloc, varflags, quotes) == 0) { 5935 int amount = expdest - ( 5936 (char *)stackblock() + patloc - 1 5937 ); 5938 STADJUST(-amount, expdest); 5939 } 5940 /* Remove any recorded regions beyond start of variable */ 5941 removerecordregions(startloc); 5942 goto record; 5943 } 5944 5945 end: 5946 if (subtype != VSNORMAL) { /* skip to end of alternative */ 5947 int nesting = 1; 5948 for (;;) { 5949 c = *p++; 5950 if (c == CTLESC) 5951 p++; 5952 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { 5953 if (varlen >= 0) 5954 argbackq = argbackq->next; 5955 } else if (c == CTLVAR) { 5956 if ((*p++ & VSTYPE) != VSNORMAL) 5957 nesting++; 5958 } else if (c == CTLENDVAR) { 5959 if (--nesting == 0) 5960 break; 5961 } 5962 } 5963 } 5964 return p; 5965 } 5966 5967 /* 5968 * Break the argument string into pieces based upon IFS and add the 5969 * strings to the argument list. The regions of the string to be 5970 * searched for IFS characters have been stored by recordregion. 5971 */ 5972 static void 5973 ifsbreakup(char *string, struct arglist *arglist) 5974 { 5975 struct ifsregion *ifsp; 5976 struct strlist *sp; 5977 char *start; 5978 char *p; 5979 char *q; 5980 const char *ifs, *realifs; 5981 int ifsspc; 5982 int nulonly; 5983 5984 start = string; 5985 if (ifslastp != NULL) { 5986 ifsspc = 0; 5987 nulonly = 0; 5988 realifs = ifsset() ? ifsval() : defifs; 5989 ifsp = &ifsfirst; 5990 do { 5991 p = string + ifsp->begoff; 5992 nulonly = ifsp->nulonly; 5993 ifs = nulonly ? nullstr : realifs; 5994 ifsspc = 0; 5995 while (p < string + ifsp->endoff) { 5996 q = p; 5997 if (*p == CTLESC) 5998 p++; 5999 if (!strchr(ifs, *p)) { 6000 p++; 6001 continue; 6002 } 6003 if (!nulonly) 6004 ifsspc = (strchr(defifs, *p) != NULL); 6005 /* Ignore IFS whitespace at start */ 6006 if (q == start && ifsspc) { 6007 p++; 6008 start = p; 6009 continue; 6010 } 6011 *q = '\0'; 6012 sp = stalloc(sizeof(*sp)); 6013 sp->text = start; 6014 *arglist->lastp = sp; 6015 arglist->lastp = &sp->next; 6016 p++; 6017 if (!nulonly) { 6018 for (;;) { 6019 if (p >= string + ifsp->endoff) { 6020 break; 6021 } 6022 q = p; 6023 if (*p == CTLESC) 6024 p++; 6025 if (strchr(ifs, *p) == NULL ) { 6026 p = q; 6027 break; 6028 } else if (strchr(defifs, *p) == NULL) { 6029 if (ifsspc) { 6030 p++; 6031 ifsspc = 0; 6032 } else { 6033 p = q; 6034 break; 6035 } 6036 } else 6037 p++; 6038 } 6039 } 6040 start = p; 6041 } /* while */ 6042 ifsp = ifsp->next; 6043 } while (ifsp != NULL); 6044 if (nulonly) 6045 goto add; 6046 } 6047 6048 if (!*start) 6049 return; 6050 6051 add: 6052 sp = stalloc(sizeof(*sp)); 6053 sp->text = start; 6054 *arglist->lastp = sp; 6055 arglist->lastp = &sp->next; 6056 } 6057 6058 static void 6059 ifsfree(void) 6060 { 6061 struct ifsregion *p; 6062 6063 INT_OFF; 6064 p = ifsfirst.next; 6065 do { 6066 struct ifsregion *ifsp; 6067 ifsp = p->next; 6068 free(p); 6069 p = ifsp; 6070 } while (p); 6071 ifslastp = NULL; 6072 ifsfirst.next = NULL; 6073 INT_ON; 6074 } 6075 6076 /* 6077 * Add a file name to the list. 6078 */ 6079 static void 6080 addfname(const char *name) 6081 { 6082 struct strlist *sp; 6083 6084 sp = stalloc(sizeof(*sp)); 6085 sp->text = ststrdup(name); 6086 *exparg.lastp = sp; 6087 exparg.lastp = &sp->next; 6088 } 6089 6090 static char *expdir; 6091 6092 /* 6093 * Do metacharacter (i.e. *, ?, [...]) expansion. 6094 */ 6095 static void 6096 expmeta(char *enddir, char *name) 6097 { 6098 char *p; 6099 const char *cp; 6100 char *start; 6101 char *endname; 6102 int metaflag; 6103 struct stat statb; 6104 DIR *dirp; 6105 struct dirent *dp; 6106 int atend; 6107 int matchdot; 6108 6109 metaflag = 0; 6110 start = name; 6111 for (p = name; *p; p++) { 6112 if (*p == '*' || *p == '?') 6113 metaflag = 1; 6114 else if (*p == '[') { 6115 char *q = p + 1; 6116 if (*q == '!') 6117 q++; 6118 for (;;) { 6119 if (*q == '\\') 6120 q++; 6121 if (*q == '/' || *q == '\0') 6122 break; 6123 if (*++q == ']') { 6124 metaflag = 1; 6125 break; 6126 } 6127 } 6128 } else if (*p == '\\') 6129 p++; 6130 else if (*p == '/') { 6131 if (metaflag) 6132 goto out; 6133 start = p + 1; 6134 } 6135 } 6136 out: 6137 if (metaflag == 0) { /* we've reached the end of the file name */ 6138 if (enddir != expdir) 6139 metaflag++; 6140 p = name; 6141 do { 6142 if (*p == '\\') 6143 p++; 6144 *enddir++ = *p; 6145 } while (*p++); 6146 if (metaflag == 0 || lstat(expdir, &statb) >= 0) 6147 addfname(expdir); 6148 return; 6149 } 6150 endname = p; 6151 if (name < start) { 6152 p = name; 6153 do { 6154 if (*p == '\\') 6155 p++; 6156 *enddir++ = *p++; 6157 } while (p < start); 6158 } 6159 if (enddir == expdir) { 6160 cp = "."; 6161 } else if (enddir == expdir + 1 && *expdir == '/') { 6162 cp = "/"; 6163 } else { 6164 cp = expdir; 6165 enddir[-1] = '\0'; 6166 } 6167 dirp = opendir(cp); 6168 if (dirp == NULL) 6169 return; 6170 if (enddir != expdir) 6171 enddir[-1] = '/'; 6172 if (*endname == 0) { 6173 atend = 1; 6174 } else { 6175 atend = 0; 6176 *endname++ = '\0'; 6177 } 6178 matchdot = 0; 6179 p = start; 6180 if (*p == '\\') 6181 p++; 6182 if (*p == '.') 6183 matchdot++; 6184 while (! intpending && (dp = readdir(dirp)) != NULL) { 6185 if (dp->d_name[0] == '.' && ! matchdot) 6186 continue; 6187 if (pmatch(start, dp->d_name)) { 6188 if (atend) { 6189 strcpy(enddir, dp->d_name); 6190 addfname(expdir); 6191 } else { 6192 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';) 6193 continue; 6194 p[-1] = '/'; 6195 expmeta(p, endname); 6196 } 6197 } 6198 } 6199 closedir(dirp); 6200 if (! atend) 6201 endname[-1] = '/'; 6202 } 6203 6204 static struct strlist * 6205 msort(struct strlist *list, int len) 6206 { 6207 struct strlist *p, *q = NULL; 6208 struct strlist **lpp; 6209 int half; 6210 int n; 6211 6212 if (len <= 1) 6213 return list; 6214 half = len >> 1; 6215 p = list; 6216 for (n = half; --n >= 0; ) { 6217 q = p; 6218 p = p->next; 6219 } 6220 q->next = NULL; /* terminate first half of list */ 6221 q = msort(list, half); /* sort first half of list */ 6222 p = msort(p, len - half); /* sort second half */ 6223 lpp = &list; 6224 for (;;) { 6225 #if ENABLE_LOCALE_SUPPORT 6226 if (strcoll(p->text, q->text) < 0) 6227 #else 6228 if (strcmp(p->text, q->text) < 0) 6229 #endif 6230 { 6231 *lpp = p; 6232 lpp = &p->next; 6233 p = *lpp; 6234 if (p == NULL) { 6235 *lpp = q; 6236 break; 6237 } 6238 } else { 6239 *lpp = q; 6240 lpp = &q->next; 6241 q = *lpp; 6242 if (q == NULL) { 6243 *lpp = p; 6244 break; 6245 } 6246 } 6247 } 6248 return list; 6249 } 6250 6251 /* 6252 * Sort the results of file name expansion. It calculates the number of 6253 * strings to sort and then calls msort (short for merge sort) to do the 6254 * work. 6255 */ 6256 static struct strlist * 6257 expsort(struct strlist *str) 6258 { 6259 int len; 6260 struct strlist *sp; 6261 6262 len = 0; 6263 for (sp = str; sp; sp = sp->next) 6264 len++; 6265 return msort(str, len); 6266 } 6267 6268 static void 6269 expandmeta(struct strlist *str, int flag) 6270 { 6271 static const char metachars[] ALIGN1 = { 6272 '*', '?', '[', 0 6273 }; 6274 /* TODO - EXP_REDIR */ 6275 6276 while (str) { 6277 struct strlist **savelastp; 6278 struct strlist *sp; 6279 char *p; 6280 6281 if (fflag) 6282 goto nometa; 6283 if (!strpbrk(str->text, metachars)) 6284 goto nometa; 6285 savelastp = exparg.lastp; 6286 6287 INT_OFF; 6288 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); 6289 { 6290 int i = strlen(str->text); 6291 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ 6292 } 6293 6294 expmeta(expdir, p); 6295 free(expdir); 6296 if (p != str->text) 6297 free(p); 6298 INT_ON; 6299 if (exparg.lastp == savelastp) { 6300 /* 6301 * no matches 6302 */ 6303 nometa: 6304 *exparg.lastp = str; 6305 rmescapes(str->text); 6306 exparg.lastp = &str->next; 6307 } else { 6308 *exparg.lastp = NULL; 6309 *savelastp = sp = expsort(*savelastp); 6310 while (sp->next != NULL) 6311 sp = sp->next; 6312 exparg.lastp = &sp->next; 6313 } 6314 str = str->next; 6315 } 6316 } 6317 6318 /* 6319 * Perform variable substitution and command substitution on an argument, 6320 * placing the resulting list of arguments in arglist. If EXP_FULL is true, 6321 * perform splitting and file name expansion. When arglist is NULL, perform 6322 * here document expansion. 6323 */ 6324 static void 6325 expandarg(union node *arg, struct arglist *arglist, int flag) 6326 { 6327 struct strlist *sp; 6328 char *p; 6329 6330 argbackq = arg->narg.backquote; 6331 STARTSTACKSTR(expdest); 6332 ifsfirst.next = NULL; 6333 ifslastp = NULL; 6334 argstr(arg->narg.text, flag); 6335 p = _STPUTC('\0', expdest); 6336 expdest = p - 1; 6337 if (arglist == NULL) { 6338 return; /* here document expanded */ 6339 } 6340 p = grabstackstr(p); 6341 exparg.lastp = &exparg.list; 6342 /* 6343 * TODO - EXP_REDIR 6344 */ 6345 if (flag & EXP_FULL) { 6346 ifsbreakup(p, &exparg); 6347 *exparg.lastp = NULL; 6348 exparg.lastp = &exparg.list; 6349 expandmeta(exparg.list, flag); 6350 } else { 6351 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ 6352 rmescapes(p); 6353 sp = stalloc(sizeof(*sp)); 6354 sp->text = p; 6355 *exparg.lastp = sp; 6356 exparg.lastp = &sp->next; 6357 } 6358 if (ifsfirst.next) 6359 ifsfree(); 6360 *exparg.lastp = NULL; 6361 if (exparg.list) { 6362 *arglist->lastp = exparg.list; 6363 arglist->lastp = exparg.lastp; 6364 } 6365 } 6366 6367 /* 6368 * Expand shell variables and backquotes inside a here document. 6369 */ 6370 static void 6371 expandhere(union node *arg, int fd) 6372 { 6373 herefd = fd; 6374 expandarg(arg, (struct arglist *)NULL, 0); 6375 full_write(fd, stackblock(), expdest - (char *)stackblock()); 6376 } 6377 6378 /* 6379 * Returns true if the pattern matches the string. 6380 */ 6381 static int 6382 patmatch(char *pattern, const char *string) 6383 { 6384 return pmatch(preglob(pattern, 0, 0), string); 6385 } 6386 6387 /* 6388 * See if a pattern matches in a case statement. 6389 */ 6390 static int 6391 casematch(union node *pattern, char *val) 6392 { 6393 struct stackmark smark; 6394 int result; 6395 6396 setstackmark(&smark); 6397 argbackq = pattern->narg.backquote; 6398 STARTSTACKSTR(expdest); 6399 ifslastp = NULL; 6400 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); 6401 STACKSTRNUL(expdest); 6402 result = patmatch(stackblock(), val); 6403 popstackmark(&smark); 6404 return result; 6405 } 6406 6407 6408 /* ============ find_command */ 6409 6410 struct builtincmd { 6411 const char *name; 6412 int (*builtin)(int, char **); 6413 /* unsigned flags; */ 6414 }; 6415 #define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1) 6416 #define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2) 6417 #define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4) 6418 6419 struct cmdentry { 6420 int cmdtype; 6421 union param { 6422 int index; 6423 const struct builtincmd *cmd; 6424 struct funcnode *func; 6425 } u; 6426 }; 6427 /* values of cmdtype */ 6428 #define CMDUNKNOWN -1 /* no entry in table for command */ 6429 #define CMDNORMAL 0 /* command is an executable program */ 6430 #define CMDFUNCTION 1 /* command is a shell function */ 6431 #define CMDBUILTIN 2 /* command is a shell builtin */ 6432 6433 /* action to find_command() */ 6434 #define DO_ERR 0x01 /* prints errors */ 6435 #define DO_ABS 0x02 /* checks absolute paths */ 6436 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */ 6437 #define DO_ALTPATH 0x08 /* using alternate path */ 6438 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */ 6439 6440 static void find_command(char *, struct cmdentry *, int, const char *); 6441 6442 6443 /* ============ Hashing commands */ 6444 6445 /* 6446 * When commands are first encountered, they are entered in a hash table. 6447 * This ensures that a full path search will not have to be done for them 6448 * on each invocation. 6449 * 6450 * We should investigate converting to a linear search, even though that 6451 * would make the command name "hash" a misnomer. 6452 */ 6453 6454 #define CMDTABLESIZE 31 /* should be prime */ 6455 #define ARB 1 /* actual size determined at run time */ 6456 6457 struct tblentry { 6458 struct tblentry *next; /* next entry in hash chain */ 6459 union param param; /* definition of builtin function */ 6460 short cmdtype; /* index identifying command */ 6461 char rehash; /* if set, cd done since entry created */ 6462 char cmdname[ARB]; /* name of command */ 6463 }; 6464 6465 static struct tblentry *cmdtable[CMDTABLESIZE]; 6466 static int builtinloc = -1; /* index in path of %builtin, or -1 */ 6467 6468 static void 6469 tryexec(char *cmd, char **argv, char **envp) 6470 { 6471 int repeated = 0; 6472 6473 #if ENABLE_FEATURE_SH_STANDALONE 6474 if (strchr(cmd, '/') == NULL) { 6475 const struct bb_applet *a; 6476 6477 a = find_applet_by_name(cmd); 6478 if (a) { 6479 if (a->noexec) { 6480 current_applet = a; 6481 run_current_applet_and_exit(argv); 6482 } 6483 /* re-exec ourselves with the new arguments */ 6484 execve(bb_busybox_exec_path, argv, envp); 6485 /* If they called chroot or otherwise made the binary no longer 6486 * executable, fall through */ 6487 } 6488 } 6489 #endif 6490 6491 repeat: 6492 #ifdef SYSV 6493 do { 6494 execve(cmd, argv, envp); 6495 } while (errno == EINTR); 6496 #else 6497 execve(cmd, argv, envp); 6498 #endif 6499 if (repeated++) { 6500 free(argv); 6501 } else if (errno == ENOEXEC) { 6502 char **ap; 6503 char **new; 6504 6505 for (ap = argv; *ap; ap++) 6506 ; 6507 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *)); 6508 ap[1] = cmd; 6509 ap[0] = cmd = (char *)DEFAULT_SHELL; 6510 ap += 2; 6511 argv++; 6512 while ((*ap++ = *argv++)) 6513 ; 6514 argv = new; 6515 goto repeat; 6516 } 6517 } 6518 6519 /* 6520 * Exec a program. Never returns. If you change this routine, you may 6521 * have to change the find_command routine as well. 6522 */ 6523 #define environment() listvars(VEXPORT, VUNSET, 0) 6524 static void shellexec(char **, const char *, int) ATTRIBUTE_NORETURN; 6525 static void 6526 shellexec(char **argv, const char *path, int idx) 6527 { 6528 char *cmdname; 6529 int e; 6530 char **envp; 6531 int exerrno; 6532 6533 clearredir(1); 6534 envp = environment(); 6535 if (strchr(argv[0], '/') 6536 #if ENABLE_FEATURE_SH_STANDALONE 6537 || find_applet_by_name(argv[0]) 6538 #endif 6539 ) { 6540 tryexec(argv[0], argv, envp); 6541 e = errno; 6542 } else { 6543 e = ENOENT; 6544 while ((cmdname = padvance(&path, argv[0])) != NULL) { 6545 if (--idx < 0 && pathopt == NULL) { 6546 tryexec(cmdname, argv, envp); 6547 if (errno != ENOENT && errno != ENOTDIR) 6548 e = errno; 6549 } 6550 stunalloc(cmdname); 6551 } 6552 } 6553 6554 /* Map to POSIX errors */ 6555 switch (e) { 6556 case EACCES: 6557 exerrno = 126; 6558 break; 6559 case ENOENT: 6560 exerrno = 127; 6561 break; 6562 default: 6563 exerrno = 2; 6564 break; 6565 } 6566 exitstatus = exerrno; 6567 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n", 6568 argv[0], e, suppressint )); 6569 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found")); 6570 /* NOTREACHED */ 6571 } 6572 6573 static void 6574 printentry(struct tblentry *cmdp) 6575 { 6576 int idx; 6577 const char *path; 6578 char *name; 6579 6580 idx = cmdp->param.index; 6581 path = pathval(); 6582 do { 6583 name = padvance(&path, cmdp->cmdname); 6584 stunalloc(name); 6585 } while (--idx >= 0); 6586 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); 6587 } 6588 6589 /* 6590 * Clear out command entries. The argument specifies the first entry in 6591 * PATH which has changed. 6592 */ 6593 static void 6594 clearcmdentry(int firstchange) 6595 { 6596 struct tblentry **tblp; 6597 struct tblentry **pp; 6598 struct tblentry *cmdp; 6599 6600 INT_OFF; 6601 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) { 6602 pp = tblp; 6603 while ((cmdp = *pp) != NULL) { 6604 if ((cmdp->cmdtype == CMDNORMAL && 6605 cmdp->param.index >= firstchange) 6606 || (cmdp->cmdtype == CMDBUILTIN && 6607 builtinloc >= firstchange) 6608 ) { 6609 *pp = cmdp->next; 6610 free(cmdp); 6611 } else { 6612 pp = &cmdp->next; 6613 } 6614 } 6615 } 6616 INT_ON; 6617 } 6618 6619 /* 6620 * Locate a command in the command hash table. If "add" is nonzero, 6621 * add the command to the table if it is not already present. The 6622 * variable "lastcmdentry" is set to point to the address of the link 6623 * pointing to the entry, so that delete_cmd_entry can delete the 6624 * entry. 6625 * 6626 * Interrupts must be off if called with add != 0. 6627 */ 6628 static struct tblentry **lastcmdentry; 6629 6630 static struct tblentry * 6631 cmdlookup(const char *name, int add) 6632 { 6633 unsigned int hashval; 6634 const char *p; 6635 struct tblentry *cmdp; 6636 struct tblentry **pp; 6637 6638 p = name; 6639 hashval = (unsigned char)*p << 4; 6640 while (*p) 6641 hashval += (unsigned char)*p++; 6642 hashval &= 0x7FFF; 6643 pp = &cmdtable[hashval % CMDTABLESIZE]; 6644 for (cmdp = *pp; cmdp; cmdp = cmdp->next) { 6645 if (strcmp(cmdp->cmdname, name) == 0) 6646 break; 6647 pp = &cmdp->next; 6648 } 6649 if (add && cmdp == NULL) { 6650 cmdp = *pp = ckmalloc(sizeof(struct tblentry) - ARB 6651 + strlen(name) + 1); 6652 cmdp->next = NULL; 6653 cmdp->cmdtype = CMDUNKNOWN; 6654 strcpy(cmdp->cmdname, name); 6655 } 6656 lastcmdentry = pp; 6657 return cmdp; 6658 } 6659 6660 /* 6661 * Delete the command entry returned on the last lookup. 6662 */ 6663 static void 6664 delete_cmd_entry(void) 6665 { 6666 struct tblentry *cmdp; 6667 6668 INT_OFF; 6669 cmdp = *lastcmdentry; 6670 *lastcmdentry = cmdp->next; 6671 if (cmdp->cmdtype == CMDFUNCTION) 6672 freefunc(cmdp->param.func); 6673 free(cmdp); 6674 INT_ON; 6675 } 6676 6677 /* 6678 * Add a new command entry, replacing any existing command entry for 6679 * the same name - except special builtins. 6680 */ 6681 static void 6682 addcmdentry(char *name, struct cmdentry *entry) 6683 { 6684 struct tblentry *cmdp; 6685 6686 cmdp = cmdlookup(name, 1); 6687 if (cmdp->cmdtype == CMDFUNCTION) { 6688 freefunc(cmdp->param.func); 6689 } 6690 cmdp->cmdtype = entry->cmdtype; 6691 cmdp->param = entry->u; 6692 cmdp->rehash = 0; 6693 } 6694 6695 static int 6696 hashcmd(int argc, char **argv) 6697 { 6698 struct tblentry **pp; 6699 struct tblentry *cmdp; 6700 int c; 6701 struct cmdentry entry; 6702 char *name; 6703 6704 while ((c = nextopt("r")) != '\0') { 6705 clearcmdentry(0); 6706 return 0; 6707 } 6708 if (*argptr == NULL) { 6709 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) { 6710 for (cmdp = *pp; cmdp; cmdp = cmdp->next) { 6711 if (cmdp->cmdtype == CMDNORMAL) 6712 printentry(cmdp); 6713 } 6714 } 6715 return 0; 6716 } 6717 c = 0; 6718 while ((name = *argptr) != NULL) { 6719 cmdp = cmdlookup(name, 0); 6720 if (cmdp != NULL 6721 && (cmdp->cmdtype == CMDNORMAL 6722 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) 6723 delete_cmd_entry(); 6724 find_command(name, &entry, DO_ERR, pathval()); 6725 if (entry.cmdtype == CMDUNKNOWN) 6726 c = 1; 6727 argptr++; 6728 } 6729 return c; 6730 } 6731 6732 /* 6733 * Called when a cd is done. Marks all commands so the next time they 6734 * are executed they will be rehashed. 6735 */ 6736 static void 6737 hashcd(void) 6738 { 6739 struct tblentry **pp; 6740 struct tblentry *cmdp; 6741 6742 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) { 6743 for (cmdp = *pp; cmdp; cmdp = cmdp->next) { 6744 if (cmdp->cmdtype == CMDNORMAL || ( 6745 cmdp->cmdtype == CMDBUILTIN && 6746 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) && 6747 builtinloc > 0 6748 )) 6749 cmdp->rehash = 1; 6750 } 6751 } 6752 } 6753 6754 /* 6755 * Fix command hash table when PATH changed. 6756 * Called before PATH is changed. The argument is the new value of PATH; 6757 * pathval() still returns the old value at this point. 6758 * Called with interrupts off. 6759 */ 6760 static void 6761 changepath(const char *newval) 6762 { 6763 const char *old, *new; 6764 int idx; 6765 int firstchange; 6766 int idx_bltin; 6767 6768 old = pathval(); 6769 new = newval; 6770 firstchange = 9999; /* assume no change */ 6771 idx = 0; 6772 idx_bltin = -1; 6773 for (;;) { 6774 if (*old != *new) { 6775 firstchange = idx; 6776 if ((*old == '\0' && *new == ':') 6777 || (*old == ':' && *new == '\0')) 6778 firstchange++; 6779 old = new; /* ignore subsequent differences */ 6780 } 6781 if (*new == '\0') 6782 break; 6783 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin")) 6784 idx_bltin = idx; 6785 if (*new == ':') { 6786 idx++; 6787 } 6788 new++, old++; 6789 } 6790 if (builtinloc < 0 && idx_bltin >= 0) 6791 builtinloc = idx_bltin; /* zap builtins */ 6792 if (builtinloc >= 0 && idx_bltin < 0) 6793 firstchange = 0; 6794 clearcmdentry(firstchange); 6795 builtinloc = idx_bltin; 6796 } 6797 6798 #define TEOF 0 6799 #define TNL 1 6800 #define TREDIR 2 6801 #define TWORD 3 6802 #define TSEMI 4 6803 #define TBACKGND 5 6804 #define TAND 6 6805 #define TOR 7 6806 #define TPIPE 8 6807 #define TLP 9 6808 #define TRP 10 6809 #define TENDCASE 11 6810 #define TENDBQUOTE 12 6811 #define TNOT 13 6812 #define TCASE 14 6813 #define TDO 15 6814 #define TDONE 16 6815 #define TELIF 17 6816 #define TELSE 18 6817 #define TESAC 19 6818 #define TFI 20 6819 #define TFOR 21 6820 #define TIF 22 6821 #define TIN 23 6822 #define TTHEN 24 6823 #define TUNTIL 25 6824 #define TWHILE 26 6825 #define TBEGIN 27 6826 #define TEND 28 6827 6828 /* first char is indicating which tokens mark the end of a list */ 6829 static const char *const tokname_array[] = { 6830 "\1end of file", 6831 "\0newline", 6832 "\0redirection", 6833 "\0word", 6834 "\0;", 6835 "\0&", 6836 "\0&&", 6837 "\0||", 6838 "\0|", 6839 "\0(", 6840 "\1)", 6841 "\1;;", 6842 "\1`", 6843 #define KWDOFFSET 13 6844 /* the following are keywords */ 6845 "\0!", 6846 "\0case", 6847 "\1do", 6848 "\1done", 6849 "\1elif", 6850 "\1else", 6851 "\1esac", 6852 "\1fi", 6853 "\0for", 6854 "\0if", 6855 "\0in", 6856 "\1then", 6857 "\0until", 6858 "\0while", 6859 "\0{", 6860 "\1}", 6861 }; 6862 6863 static const char * 6864 tokname(int tok) 6865 { 6866 static char buf[16]; 6867 6868 //try this: 6869 //if (tok < TSEMI) return tokname_array[tok] + 1; 6870 //sprintf(buf, "\"%s\"", tokname_array[tok] + 1); 6871 //return buf; 6872 6873 if (tok >= TSEMI) 6874 buf[0] = '"'; 6875 sprintf(buf + (tok >= TSEMI), "%s%c", 6876 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0)); 6877 return buf; 6878 } 6879 6880 /* Wrapper around strcmp for qsort/bsearch/... */ 6881 static int 6882 pstrcmp(const void *a, const void *b) 6883 { 6884 return strcmp((char*) a, (*(char**) b) + 1); 6885 } 6886 6887 static const char *const * 6888 findkwd(const char *s) 6889 { 6890 return bsearch(s, tokname_array + KWDOFFSET, 6891 ARRAY_SIZE(tokname_array) - KWDOFFSET, 6892 sizeof(tokname_array[0]), pstrcmp); 6893 } 6894 6895 /* 6896 * Locate and print what a word is... 6897 */ 6898 static int 6899 describe_command(char *command, int describe_command_verbose) 6900 { 6901 struct cmdentry entry; 6902 struct tblentry *cmdp; 6903 #if ENABLE_ASH_ALIAS 6904 const struct alias *ap; 6905 #endif 6906 const char *path = pathval(); 6907 6908 if (describe_command_verbose) { 6909 out1str(command); 6910 } 6911 6912 /* First look at the keywords */ 6913 if (findkwd(command)) { 6914 out1str(describe_command_verbose ? " is a shell keyword" : command); 6915 goto out; 6916 } 6917 6918 #if ENABLE_ASH_ALIAS 6919 /* Then look at the aliases */ 6920 ap = lookupalias(command, 0); 6921 if (ap != NULL) { 6922 if (!describe_command_verbose) { 6923 out1str("alias "); 6924 printalias(ap); 6925 return 0; 6926 } 6927 out1fmt(" is an alias for %s", ap->val); 6928 goto out; 6929 } 6930 #endif 6931 /* Then check if it is a tracked alias */ 6932 cmdp = cmdlookup(command, 0); 6933 if (cmdp != NULL) { 6934 entry.cmdtype = cmdp->cmdtype; 6935 entry.u = cmdp->param; 6936 } else { 6937 /* Finally use brute force */ 6938 find_command(command, &entry, DO_ABS, path); 6939 } 6940 6941 switch (entry.cmdtype) { 6942 case CMDNORMAL: { 6943 int j = entry.u.index; 6944 char *p; 6945 if (j == -1) { 6946 p = command; 6947 } else { 6948 do { 6949 p = padvance(&path, command); 6950 stunalloc(p); 6951 } while (--j >= 0); 6952 } 6953 if (describe_command_verbose) { 6954 out1fmt(" is%s %s", 6955 (cmdp ? " a tracked alias for" : nullstr), p 6956 ); 6957 } else { 6958 out1str(p); 6959 } 6960 break; 6961 } 6962 6963 case CMDFUNCTION: 6964 if (describe_command_verbose) { 6965 out1str(" is a shell function"); 6966 } else { 6967 out1str(command); 6968 } 6969 break; 6970 6971 case CMDBUILTIN: 6972 if (describe_command_verbose) { 6973 out1fmt(" is a %sshell builtin", 6974 IS_BUILTIN_SPECIAL(entry.u.cmd) ? 6975 "special " : nullstr 6976 ); 6977 } else { 6978 out1str(command); 6979 } 6980 break; 6981 6982 default: 6983 if (describe_command_verbose) { 6984 out1str(": not found\n"); 6985 } 6986 return 127; 6987 } 6988 out: 6989 outstr("\n", stdout); 6990 return 0; 6991 } 6992 6993 static int 6994 typecmd(int argc, char **argv) 6995 { 6996 int i = 1; 6997 int err = 0; 6998 int verbose = 1; 6999 7000 /* type -p ... ? (we don't bother checking for 'p') */ 7001 if (argv[1] && argv[1][0] == '-') { 7002 i++; 7003 verbose = 0; 7004 } 7005 while (i < argc) { 7006 err |= describe_command(argv[i++], verbose); 7007 } 7008 return err; 7009 } 7010 7011 #if ENABLE_ASH_CMDCMD 7012 static int 7013 commandcmd(int argc, char **argv) 7014 { 7015 int c; 7016 enum { 7017 VERIFY_BRIEF = 1, 7018 VERIFY_VERBOSE = 2, 7019 } verify = 0; 7020 7021 while ((c = nextopt("pvV")) != '\0') 7022 if (c == 'V') 7023 verify |= VERIFY_VERBOSE; 7024 else if (c == 'v') 7025 verify |= VERIFY_BRIEF; 7026 #if DEBUG 7027 else if (c != 'p') 7028 abort(); 7029 #endif 7030 if (verify) 7031 return describe_command(*argptr, verify - VERIFY_BRIEF); 7032 7033 return 0; 7034 } 7035 #endif 7036 7037 7038 /* ============ eval.c */ 7039 7040 static int funcblocksize; /* size of structures in function */ 7041 static int funcstringsize; /* size of strings in node */ 7042 static void *funcblock; /* block to allocate function from */ 7043 static char *funcstring; /* block to allocate strings from */ 7044 7045 /* flags in argument to evaltree */ 7046 #define EV_EXIT 01 /* exit after evaluating tree */ 7047 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ 7048 #define EV_BACKCMD 04 /* command executing within back quotes */ 7049 7050 static const short nodesize[26] = { 7051 SHELL_ALIGN(sizeof(struct ncmd)), 7052 SHELL_ALIGN(sizeof(struct npipe)), 7053 SHELL_ALIGN(sizeof(struct nredir)), 7054 SHELL_ALIGN(sizeof(struct nredir)), 7055 SHELL_ALIGN(sizeof(struct nredir)), 7056 SHELL_ALIGN(sizeof(struct nbinary)), 7057 SHELL_ALIGN(sizeof(struct nbinary)), 7058 SHELL_ALIGN(sizeof(struct nbinary)), 7059 SHELL_ALIGN(sizeof(struct nif)), 7060 SHELL_ALIGN(sizeof(struct nbinary)), 7061 SHELL_ALIGN(sizeof(struct nbinary)), 7062 SHELL_ALIGN(sizeof(struct nfor)), 7063 SHELL_ALIGN(sizeof(struct ncase)), 7064 SHELL_ALIGN(sizeof(struct nclist)), 7065 SHELL_ALIGN(sizeof(struct narg)), 7066 SHELL_ALIGN(sizeof(struct narg)), 7067 SHELL_ALIGN(sizeof(struct nfile)), 7068 SHELL_ALIGN(sizeof(struct nfile)), 7069 SHELL_ALIGN(sizeof(struct nfile)), 7070 SHELL_ALIGN(sizeof(struct nfile)), 7071 SHELL_ALIGN(sizeof(struct nfile)), 7072 SHELL_ALIGN(sizeof(struct ndup)), 7073 SHELL_ALIGN(sizeof(struct ndup)), 7074 SHELL_ALIGN(sizeof(struct nhere)), 7075 SHELL_ALIGN(sizeof(struct nhere)), 7076 SHELL_ALIGN(sizeof(struct nnot)), 7077 }; 7078 7079 static void calcsize(union node *n); 7080 7081 static void 7082 sizenodelist(struct nodelist *lp) 7083 { 7084 while (lp) { 7085 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); 7086 calcsize(lp->n); 7087 lp = lp->next; 7088 } 7089 } 7090 7091 static void 7092 calcsize(union node *n) 7093 { 7094 if (n == NULL) 7095 return; 7096 funcblocksize += nodesize[n->type]; 7097 switch (n->type) { 7098 case NCMD: 7099 calcsize(n->ncmd.redirect); 7100 calcsize(n->ncmd.args); 7101 calcsize(n->ncmd.assign); 7102 break; 7103 case NPIPE: 7104 sizenodelist(n->npipe.cmdlist); 7105 break; 7106 case NREDIR: 7107 case NBACKGND: 7108 case NSUBSHELL: 7109 calcsize(n->nredir.redirect); 7110 calcsize(n->nredir.n); 7111 break; 7112 case NAND: 7113 case NOR: 7114 case NSEMI: 7115 case NWHILE: 7116 case NUNTIL: 7117 calcsize(n->nbinary.ch2); 7118 calcsize(n->nbinary.ch1); 7119 break; 7120 case NIF: 7121 calcsize(n->nif.elsepart); 7122 calcsize(n->nif.ifpart); 7123 calcsize(n->nif.test); 7124 break; 7125 case NFOR: 7126 funcstringsize += strlen(n->nfor.var) + 1; 7127 calcsize(n->nfor.body); 7128 calcsize(n->nfor.args); 7129 break; 7130 case NCASE: 7131 calcsize(n->ncase.cases); 7132 calcsize(n->ncase.expr); 7133 break; 7134 case NCLIST: 7135 calcsize(n->nclist.body); 7136 calcsize(n->nclist.pattern); 7137 calcsize(n->nclist.next); 7138 break; 7139 case NDEFUN: 7140 case NARG: 7141 sizenodelist(n->narg.backquote); 7142 funcstringsize += strlen(n->narg.text) + 1; 7143 calcsize(n->narg.next); 7144 break; 7145 case NTO: 7146 case NCLOBBER: 7147 case NFROM: 7148 case NFROMTO: 7149 case NAPPEND: 7150 calcsize(n->nfile.fname); 7151 calcsize(n->nfile.next); 7152 break; 7153 case NTOFD: 7154 case NFROMFD: 7155 calcsize(n->ndup.vname); 7156 calcsize(n->ndup.next); 7157 break; 7158 case NHERE: 7159 case NXHERE: 7160 calcsize(n->nhere.doc); 7161 calcsize(n->nhere.next); 7162 break; 7163 case NNOT: 7164 calcsize(n->nnot.com); 7165 break; 7166 }; 7167 } 7168 7169 static char * 7170 nodeckstrdup(char *s) 7171 { 7172 char *rtn = funcstring; 7173 7174 strcpy(funcstring, s); 7175 funcstring += strlen(s) + 1; 7176 return rtn; 7177 } 7178 7179 static union node *copynode(union node *); 7180 7181 static struct nodelist * 7182 copynodelist(struct nodelist *lp) 7183 { 7184 struct nodelist *start; 7185 struct nodelist **lpp; 7186 7187 lpp = &start; 7188 while (lp) { 7189 *lpp = funcblock; 7190 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist)); 7191 (*lpp)->n = copynode(lp->n); 7192 lp = lp->next; 7193 lpp = &(*lpp)->next; 7194 } 7195 *lpp = NULL; 7196 return start; 7197 } 7198 7199 static union node * 7200 copynode(union node *n) 7201 { 7202 union node *new; 7203 7204 if (n == NULL) 7205 return NULL; 7206 new = funcblock; 7207 funcblock = (char *) funcblock + nodesize[n->type]; 7208 7209 switch (n->type) { 7210 case NCMD: 7211 new->ncmd.redirect = copynode(n->ncmd.redirect); 7212 new->ncmd.args = copynode(n->ncmd.args); 7213 new->ncmd.assign = copynode(n->ncmd.assign); 7214 break; 7215 case NPIPE: 7216 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 7217 new->npipe.backgnd = n->npipe.backgnd; 7218 break; 7219 case NREDIR: 7220 case NBACKGND: 7221 case NSUBSHELL: 7222 new->nredir.redirect = copynode(n->nredir.redirect); 7223 new->nredir.n = copynode(n->nredir.n); 7224 break; 7225 case NAND: 7226 case NOR: 7227 case NSEMI: 7228 case NWHILE: 7229 case NUNTIL: 7230 new->nbinary.ch2 = copynode(n->nbinary.ch2); 7231 new->nbinary.ch1 = copynode(n->nbinary.ch1); 7232 break; 7233 case NIF: 7234 new->nif.elsepart = copynode(n->nif.elsepart); 7235 new->nif.ifpart = copynode(n->nif.ifpart); 7236 new->nif.test = copynode(n->nif.test); 7237 break; 7238 case NFOR: 7239 new->nfor.var = nodeckstrdup(n->nfor.var); 7240 new->nfor.body = copynode(n->nfor.body); 7241 new->nfor.args = copynode(n->nfor.args); 7242 break; 7243 case NCASE: 7244 new->ncase.cases = copynode(n->ncase.cases); 7245 new->ncase.expr = copynode(n->ncase.expr); 7246 break; 7247 case NCLIST: 7248 new->nclist.body = copynode(n->nclist.body); 7249 new->nclist.pattern = copynode(n->nclist.pattern); 7250 new->nclist.next = copynode(n->nclist.next); 7251 break; 7252 case NDEFUN: 7253 case NARG: 7254 new->narg.backquote = copynodelist(n->narg.backquote); 7255 new->narg.text = nodeckstrdup(n->narg.text); 7256 new->narg.next = copynode(n->narg.next); 7257 break; 7258 case NTO: 7259 case NCLOBBER: 7260 case NFROM: 7261 case NFROMTO: 7262 case NAPPEND: 7263 new->nfile.fname = copynode(n->nfile.fname); 7264 new->nfile.fd = n->nfile.fd; 7265 new->nfile.next = copynode(n->nfile.next); 7266 break; 7267 case NTOFD: 7268 case NFROMFD: 7269 new->ndup.vname = copynode(n->ndup.vname); 7270 new->ndup.dupfd = n->ndup.dupfd; 7271 new->ndup.fd = n->ndup.fd; 7272 new->ndup.next = copynode(n->ndup.next); 7273 break; 7274 case NHERE: 7275 case NXHERE: 7276 new->nhere.doc = copynode(n->nhere.doc); 7277 new->nhere.fd = n->nhere.fd; 7278 new->nhere.next = copynode(n->nhere.next); 7279 break; 7280 case NNOT: 7281 new->nnot.com = copynode(n->nnot.com); 7282 break; 7283 }; 7284 new->type = n->type; 7285 return new; 7286 } 7287 7288 /* 7289 * Make a copy of a parse tree. 7290 */ 7291 static struct funcnode * 7292 copyfunc(union node *n) 7293 { 7294 struct funcnode *f; 7295 size_t blocksize; 7296 7297 funcblocksize = offsetof(struct funcnode, n); 7298 funcstringsize = 0; 7299 calcsize(n); 7300 blocksize = funcblocksize; 7301 f = ckmalloc(blocksize + funcstringsize); 7302 funcblock = (char *) f + offsetof(struct funcnode, n); 7303 funcstring = (char *) f + blocksize; 7304 copynode(n); 7305 f->count = 0; 7306 return f; 7307 } 7308 7309 /* 7310 * Define a shell function. 7311 */ 7312 static void 7313 defun(char *name, union node *func) 7314 { 7315 struct cmdentry entry; 7316 7317 INT_OFF; 7318 entry.cmdtype = CMDFUNCTION; 7319 entry.u.func = copyfunc(func); 7320 addcmdentry(name, &entry); 7321 INT_ON; 7322 } 7323 7324 static int evalskip; /* set if we are skipping commands */ 7325 /* reasons for skipping commands (see comment on breakcmd routine) */ 7326 #define SKIPBREAK (1 << 0) 7327 #define SKIPCONT (1 << 1) 7328 #define SKIPFUNC (1 << 2) 7329 #define SKIPFILE (1 << 3) 7330 #define SKIPEVAL (1 << 4) 7331 static int skipcount; /* number of levels to skip */ 7332 static int funcnest; /* depth of function calls */ 7333 7334 /* forward decl way out to parsing code - dotrap needs it */ 7335 static int evalstring(char *s, int mask); 7336 7337 /* 7338 * Called to execute a trap. Perhaps we should avoid entering new trap 7339 * handlers while we are executing a trap handler. 7340 */ 7341 static int 7342 dotrap(void) 7343 { 7344 char *p; 7345 char *q; 7346 int i; 7347 int savestatus; 7348 int skip = 0; 7349 7350 savestatus = exitstatus; 7351 pendingsig = 0; 7352 xbarrier(); 7353 7354 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) { 7355 if (!*q) 7356 continue; 7357 *q = '\0'; 7358 7359 p = trap[i + 1]; 7360 if (!p) 7361 continue; 7362 skip = evalstring(p, SKIPEVAL); 7363 exitstatus = savestatus; 7364 if (skip) 7365 break; 7366 } 7367 7368 return skip; 7369 } 7370 7371 /* forward declarations - evaluation is fairly recursive business... */ 7372 static void evalloop(union node *, int); 7373 static void evalfor(union node *, int); 7374 static void evalcase(union node *, int); 7375 static void evalsubshell(union node *, int); 7376 static void expredir(union node *); 7377 static void evalpipe(union node *, int); 7378 static void evalcommand(union node *, int); 7379 static int evalbltin(const struct builtincmd *, int, char **); 7380 static void prehash(union node *); 7381 7382 /* 7383 * Evaluate a parse tree. The value is left in the global variable 7384 * exitstatus. 7385 */ 7386 static void 7387 evaltree(union node *n, int flags) 7388 { 7389 int checkexit = 0; 7390 void (*evalfn)(union node *, int); 7391 unsigned isor; 7745 7392 int status; 7746 int retval; 7747 7748 status = job->ps[job->nprocs - 1].status; 7749 retval = WEXITSTATUS(status); 7750 if (!WIFEXITED(status)) { 7393 if (n == NULL) { 7394 TRACE(("evaltree(NULL) called\n")); 7395 goto out; 7396 } 7397 TRACE(("pid %d, evaltree(%p: %d, %d) called\n", 7398 getpid(), n, n->type, flags)); 7399 switch (n->type) { 7400 default: 7401 #if DEBUG 7402 out1fmt("Node type = %d\n", n->type); 7403 fflush(stdout); 7404 break; 7405 #endif 7406 case NNOT: 7407 evaltree(n->nnot.com, EV_TESTED); 7408 status = !exitstatus; 7409 goto setstatus; 7410 case NREDIR: 7411 expredir(n->nredir.redirect); 7412 status = redirectsafe(n->nredir.redirect, REDIR_PUSH); 7413 if (!status) { 7414 evaltree(n->nredir.n, flags & EV_TESTED); 7415 status = exitstatus; 7416 } 7417 popredir(0); 7418 goto setstatus; 7419 case NCMD: 7420 evalfn = evalcommand; 7421 checkexit: 7422 if (eflag && !(flags & EV_TESTED)) 7423 checkexit = ~0; 7424 goto calleval; 7425 case NFOR: 7426 evalfn = evalfor; 7427 goto calleval; 7428 case NWHILE: 7429 case NUNTIL: 7430 evalfn = evalloop; 7431 goto calleval; 7432 case NSUBSHELL: 7433 case NBACKGND: 7434 evalfn = evalsubshell; 7435 goto calleval; 7436 case NPIPE: 7437 evalfn = evalpipe; 7438 goto checkexit; 7439 case NCASE: 7440 evalfn = evalcase; 7441 goto calleval; 7442 case NAND: 7443 case NOR: 7444 case NSEMI: 7445 #if NAND + 1 != NOR 7446 #error NAND + 1 != NOR 7447 #endif 7448 #if NOR + 1 != NSEMI 7449 #error NOR + 1 != NSEMI 7450 #endif 7451 isor = n->type - NAND; 7452 evaltree( 7453 n->nbinary.ch1, 7454 (flags | ((isor >> 1) - 1)) & EV_TESTED 7455 ); 7456 if (!exitstatus == isor) 7457 break; 7458 if (!evalskip) { 7459 n = n->nbinary.ch2; 7460 evaln: 7461 evalfn = evaltree; 7462 calleval: 7463 evalfn(n, flags); 7464 break; 7465 } 7466 break; 7467 case NIF: 7468 evaltree(n->nif.test, EV_TESTED); 7469 if (evalskip) 7470 break; 7471 if (exitstatus == 0) { 7472 n = n->nif.ifpart; 7473 goto evaln; 7474 } else if (n->nif.elsepart) { 7475 n = n->nif.elsepart; 7476 goto evaln; 7477 } 7478 goto success; 7479 case NDEFUN: 7480 defun(n->narg.text, n->narg.next); 7481 success: 7482 status = 0; 7483 setstatus: 7484 exitstatus = status; 7485 break; 7486 } 7487 out: 7488 if ((checkexit & exitstatus)) 7489 evalskip |= SKIPEVAL; 7490 else if (pendingsig && dotrap()) 7491 goto exexit; 7492 7493 if (flags & EV_EXIT) { 7494 exexit: 7495 raise_exception(EXEXIT); 7496 } 7497 } 7498 7499 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3) 7500 static 7501 #endif 7502 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__)); 7503 7504 static int loopnest; /* current loop nesting level */ 7505 7506 static void 7507 evalloop(union node *n, int flags) 7508 { 7509 int status; 7510 7511 loopnest++; 7512 status = 0; 7513 flags &= EV_TESTED; 7514 for (;;) { 7515 int i; 7516 7517 evaltree(n->nbinary.ch1, EV_TESTED); 7518 if (evalskip) { 7519 skipping: 7520 if (evalskip == SKIPCONT && --skipcount <= 0) { 7521 evalskip = 0; 7522 continue; 7523 } 7524 if (evalskip == SKIPBREAK && --skipcount <= 0) 7525 evalskip = 0; 7526 break; 7527 } 7528 i = exitstatus; 7529 if (n->type != NWHILE) 7530 i = !i; 7531 if (i != 0) 7532 break; 7533 evaltree(n->nbinary.ch2, flags); 7534 status = exitstatus; 7535 if (evalskip) 7536 goto skipping; 7537 } 7538 loopnest--; 7539 exitstatus = status; 7540 } 7541 7542 static void 7543 evalfor(union node *n, int flags) 7544 { 7545 struct arglist arglist; 7546 union node *argp; 7547 struct strlist *sp; 7548 struct stackmark smark; 7549 7550 setstackmark(&smark); 7551 arglist.lastp = &arglist.list; 7552 for (argp = n->nfor.args; argp; argp = argp->narg.next) { 7553 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD); 7554 /* XXX */ 7555 if (evalskip) 7556 goto out; 7557 } 7558 *arglist.lastp = NULL; 7559 7560 exitstatus = 0; 7561 loopnest++; 7562 flags &= EV_TESTED; 7563 for (sp = arglist.list; sp; sp = sp->next) { 7564 setvar(n->nfor.var, sp->text, 0); 7565 evaltree(n->nfor.body, flags); 7566 if (evalskip) { 7567 if (evalskip == SKIPCONT && --skipcount <= 0) { 7568 evalskip = 0; 7569 continue; 7570 } 7571 if (evalskip == SKIPBREAK && --skipcount <= 0) 7572 evalskip = 0; 7573 break; 7574 } 7575 } 7576 loopnest--; 7577 out: 7578 popstackmark(&smark); 7579 } 7580 7581 static void 7582 evalcase(union node *n, int flags) 7583 { 7584 union node *cp; 7585 union node *patp; 7586 struct arglist arglist; 7587 struct stackmark smark; 7588 7589 setstackmark(&smark); 7590 arglist.lastp = &arglist.list; 7591 expandarg(n->ncase.expr, &arglist, EXP_TILDE); 7592 exitstatus = 0; 7593 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) { 7594 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) { 7595 if (casematch(patp, arglist.list->text)) { 7596 if (evalskip == 0) { 7597 evaltree(cp->nclist.body, flags); 7598 } 7599 goto out; 7600 } 7601 } 7602 } 7603 out: 7604 popstackmark(&smark); 7605 } 7606 7607 /* 7608 * Kick off a subshell to evaluate a tree. 7609 */ 7610 static void 7611 evalsubshell(union node *n, int flags) 7612 { 7613 struct job *jp; 7614 int backgnd = (n->type == NBACKGND); 7615 int status; 7616 7617 expredir(n->nredir.redirect); 7618 if (!backgnd && flags & EV_EXIT && !trap[0]) 7619 goto nofork; 7620 INT_OFF; 7621 jp = makejob(n, 1); 7622 if (forkshell(jp, n, backgnd) == 0) { 7623 INT_ON; 7624 flags |= EV_EXIT; 7625 if (backgnd) 7626 flags &=~ EV_TESTED; 7627 nofork: 7628 redirect(n->nredir.redirect, 0); 7629 evaltreenr(n->nredir.n, flags); 7630 /* never returns */ 7631 } 7632 status = 0; 7633 if (! backgnd) 7634 status = waitforjob(jp); 7635 exitstatus = status; 7636 INT_ON; 7637 } 7638 7639 /* 7640 * Compute the names of the files in a redirection list. 7641 */ 7642 static void fixredir(union node *, const char *, int); 7643 static void 7644 expredir(union node *n) 7645 { 7646 union node *redir; 7647 7648 for (redir = n; redir; redir = redir->nfile.next) { 7649 struct arglist fn; 7650 7651 memset(&fn, 0, sizeof(fn)); 7652 fn.lastp = &fn.list; 7653 switch (redir->type) { 7654 case NFROMTO: 7655 case NFROM: 7656 case NTO: 7657 case NCLOBBER: 7658 case NAPPEND: 7659 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); 7660 redir->nfile.expfname = fn.list->text; 7661 break; 7662 case NFROMFD: 7663 case NTOFD: 7664 if (redir->ndup.vname) { 7665 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); 7666 if (fn.list == NULL) 7667 ash_msg_and_raise_error("redir error"); 7668 fixredir(redir, fn.list->text, 1); 7669 } 7670 break; 7671 } 7672 } 7673 } 7674 7675 /* 7676 * Evaluate a pipeline. All the processes in the pipeline are children 7677 * of the process creating the pipeline. (This differs from some versions 7678 * of the shell, which make the last process in a pipeline the parent 7679 * of all the rest.) 7680 */ 7681 static void 7682 evalpipe(union node *n, int flags) 7683 { 7684 struct job *jp; 7685 struct nodelist *lp; 7686 int pipelen; 7687 int prevfd; 7688 int pip[2]; 7689 7690 TRACE(("evalpipe(0x%lx) called\n", (long)n)); 7691 pipelen = 0; 7692 for (lp = n->npipe.cmdlist; lp; lp = lp->next) 7693 pipelen++; 7694 flags |= EV_EXIT; 7695 INT_OFF; 7696 jp = makejob(n, pipelen); 7697 prevfd = -1; 7698 for (lp = n->npipe.cmdlist; lp; lp = lp->next) { 7699 prehash(lp->n); 7700 pip[1] = -1; 7701 if (lp->next) { 7702 if (pipe(pip) < 0) { 7703 close(prevfd); 7704 ash_msg_and_raise_error("pipe call failed"); 7705 } 7706 } 7707 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { 7708 INT_ON; 7709 if (pip[1] >= 0) { 7710 close(pip[0]); 7711 } 7712 if (prevfd > 0) { 7713 dup2(prevfd, 0); 7714 close(prevfd); 7715 } 7716 if (pip[1] > 1) { 7717 dup2(pip[1], 1); 7718 close(pip[1]); 7719 } 7720 evaltreenr(lp->n, flags); 7721 /* never returns */ 7722 } 7723 if (prevfd >= 0) 7724 close(prevfd); 7725 prevfd = pip[0]; 7726 close(pip[1]); 7727 } 7728 if (n->npipe.backgnd == 0) { 7729 exitstatus = waitforjob(jp); 7730 TRACE(("evalpipe: job done exit status %d\n", exitstatus)); 7731 } 7732 INT_ON; 7733 } 7734 7735 /* 7736 * Controls whether the shell is interactive or not. 7737 */ 7738 static void 7739 setinteractive(int on) 7740 { 7741 static int is_interactive; 7742 7743 if (++on == is_interactive) 7744 return; 7745 is_interactive = on; 7746 setsignal(SIGINT); 7747 setsignal(SIGQUIT); 7748 setsignal(SIGTERM); 7749 #if !ENABLE_FEATURE_SH_EXTRA_QUIET 7750 if (is_interactive > 1) { 7751 /* Looks like they want an interactive shell */ 7752 static smallint did_banner; 7753 7754 if (!did_banner) { 7755 out1fmt( 7756 "\n\n" 7757 "%s built-in shell (ash)\n" 7758 "Enter 'help' for a list of built-in commands." 7759 "\n\n", 7760 bb_banner); 7761 did_banner = 1; 7762 } 7763 } 7764 #endif 7765 } 7766 7767 #if ENABLE_FEATURE_EDITING_VI 7768 #define setvimode(on) do { \ 7769 if (on) line_input_state->flags |= VI_MODE; \ 7770 else line_input_state->flags &= ~VI_MODE; \ 7771 } while (0) 7772 #else 7773 #define setvimode(on) viflag = 0 /* forcibly keep the option off */ 7774 #endif 7775 7776 static void 7777 optschanged(void) 7778 { 7779 #if DEBUG 7780 opentrace(); 7781 #endif 7782 setinteractive(iflag); 7783 setjobctl(mflag); 7784 setvimode(viflag); 7785 } 7786 7787 static struct localvar *localvars; 7788 7789 /* 7790 * Called after a function returns. 7791 * Interrupts must be off. 7792 */ 7793 static void 7794 poplocalvars(void) 7795 { 7796 struct localvar *lvp; 7797 struct var *vp; 7798 7799 while ((lvp = localvars) != NULL) { 7800 localvars = lvp->next; 7801 vp = lvp->vp; 7802 TRACE(("poplocalvar %s", vp ? vp->text : "-")); 7803 if (vp == NULL) { /* $- saved */ 7804 memcpy(optlist, lvp->text, sizeof(optlist)); 7805 free((char*)lvp->text); 7806 optschanged(); 7807 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { 7808 unsetvar(vp->text); 7809 } else { 7810 if (vp->func) 7811 (*vp->func)(strchrnul(lvp->text, '=') + 1); 7812 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) 7813 free((char*)vp->text); 7814 vp->flags = lvp->flags; 7815 vp->text = lvp->text; 7816 } 7817 free(lvp); 7818 } 7819 } 7820 7821 static int 7822 evalfun(struct funcnode *func, int argc, char **argv, int flags) 7823 { 7824 volatile struct shparam saveparam; 7825 struct localvar *volatile savelocalvars; 7826 struct jmploc *volatile savehandler; 7827 struct jmploc jmploc; 7828 int e; 7829 7830 saveparam = shellparam; 7831 savelocalvars = localvars; 7832 e = setjmp(jmploc.loc); 7833 if (e) { 7834 goto funcdone; 7835 } 7836 INT_OFF; 7837 savehandler = exception_handler; 7838 exception_handler = &jmploc; 7839 localvars = NULL; 7840 shellparam.malloc = 0; 7841 func->count++; 7842 funcnest++; 7843 INT_ON; 7844 shellparam.nparam = argc - 1; 7845 shellparam.p = argv + 1; 7846 #if ENABLE_ASH_GETOPTS 7847 shellparam.optind = 1; 7848 shellparam.optoff = -1; 7849 #endif 7850 evaltree(&func->n, flags & EV_TESTED); 7851 funcdone: 7852 INT_OFF; 7853 funcnest--; 7854 freefunc(func); 7855 poplocalvars(); 7856 localvars = savelocalvars; 7857 freeparam(&shellparam); 7858 shellparam = saveparam; 7859 exception_handler = savehandler; 7860 INT_ON; 7861 evalskip &= ~SKIPFUNC; 7862 return e; 7863 } 7864 7865 #if ENABLE_ASH_CMDCMD 7866 static char ** 7867 parse_command_args(char **argv, const char **path) 7868 { 7869 char *cp, c; 7870 7871 for (;;) { 7872 cp = *++argv; 7873 if (!cp) 7874 return 0; 7875 if (*cp++ != '-') 7876 break; 7877 c = *cp++; 7878 if (!c) 7879 break; 7880 if (c == '-' && !*cp) { 7881 argv++; 7882 break; 7883 } 7884 do { 7885 switch (c) { 7886 case 'p': 7887 *path = bb_default_path; 7888 break; 7889 default: 7890 /* run 'typecmd' for other options */ 7891 return 0; 7892 } 7893 c = *cp++; 7894 } while (c); 7895 } 7896 return argv; 7897 } 7898 #endif 7899 7900 /* 7901 * Make a variable a local variable. When a variable is made local, it's 7902 * value and flags are saved in a localvar structure. The saved values 7903 * will be restored when the shell function returns. We handle the name 7904 * "-" as a special case. 7905 */ 7906 static void 7907 mklocal(char *name) 7908 { 7909 struct localvar *lvp; 7910 struct var **vpp; 7911 struct var *vp; 7912 7913 INT_OFF; 7914 lvp = ckmalloc(sizeof(struct localvar)); 7915 if (LONE_DASH(name)) { 7916 char *p; 7917 p = ckmalloc(sizeof(optlist)); 7918 lvp->text = memcpy(p, optlist, sizeof(optlist)); 7919 vp = NULL; 7920 } else { 7921 char *eq; 7922 7923 vpp = hashvar(name); 7924 vp = *findvar(vpp, name); 7925 eq = strchr(name, '='); 7926 if (vp == NULL) { 7927 if (eq) 7928 setvareq(name, VSTRFIXED); 7929 else 7930 setvar(name, NULL, VSTRFIXED); 7931 vp = *vpp; /* the new variable */ 7932 lvp->flags = VUNSET; 7933 } else { 7934 lvp->text = vp->text; 7935 lvp->flags = vp->flags; 7936 vp->flags |= VSTRFIXED|VTEXTFIXED; 7937 if (eq) 7938 setvareq(name, 0); 7939 } 7940 } 7941 lvp->vp = vp; 7942 lvp->next = localvars; 7943 localvars = lvp; 7944 INT_ON; 7945 } 7946 7947 /* 7948 * The "local" command. 7949 */ 7950 static int 7951 localcmd(int argc, char **argv) 7952 { 7953 char *name; 7954 7955 argv = argptr; 7956 while ((name = *argv++) != NULL) { 7957 mklocal(name); 7958 } 7959 return 0; 7960 } 7961 7962 static int 7963 falsecmd(int argc, char **argv) 7964 { 7965 return 1; 7966 } 7967 7968 static int 7969 truecmd(int argc, char **argv) 7970 { 7971 return 0; 7972 } 7973 7974 static int 7975 execcmd(int argc, char **argv) 7976 { 7977 if (argc > 1) { 7978 iflag = 0; /* exit on error */ 7979 mflag = 0; 7980 optschanged(); 7981 shellexec(argv + 1, pathval(), 0); 7982 } 7983 return 0; 7984 } 7985 7986 /* 7987 * The return command. 7988 */ 7989 static int 7990 returncmd(int argc, char **argv) 7991 { 7992 /* 7993 * If called outside a function, do what ksh does; 7994 * skip the rest of the file. 7995 */ 7996 evalskip = funcnest ? SKIPFUNC : SKIPFILE; 7997 return argv[1] ? number(argv[1]) : exitstatus; 7998 } 7999 8000 /* Forward declarations for builtintab[] */ 8001 static int breakcmd(int, char **); 8002 static int dotcmd(int, char **); 8003 static int evalcmd(int, char **); 8004 #if ENABLE_ASH_BUILTIN_ECHO 8005 static int echocmd(int, char **); 8006 #endif 8007 #if ENABLE_ASH_BUILTIN_TEST 8008 static int testcmd(int, char **); 8009 #endif 8010 static int exitcmd(int, char **); 8011 static int exportcmd(int, char **); 8012 #if ENABLE_ASH_GETOPTS 8013 static int getoptscmd(int, char **); 8014 #endif 8015 #if !ENABLE_FEATURE_SH_EXTRA_QUIET 8016 static int helpcmd(int argc, char **argv); 8017 #endif 8018 #if ENABLE_ASH_MATH_SUPPORT 8019 static int letcmd(int, char **); 8020 #endif 8021 static int readcmd(int, char **); 8022 static int setcmd(int, char **); 8023 static int shiftcmd(int, char **); 8024 static int timescmd(int, char **); 8025 static int trapcmd(int, char **); 8026 static int umaskcmd(int, char **); 8027 static int unsetcmd(int, char **); 8028 static int ulimitcmd(int, char **); 8029 8030 #define BUILTIN_NOSPEC "0" 8031 #define BUILTIN_SPECIAL "1" 8032 #define BUILTIN_REGULAR "2" 8033 #define BUILTIN_SPEC_REG "3" 8034 #define BUILTIN_ASSIGN "4" 8035 #define BUILTIN_SPEC_ASSG "5" 8036 #define BUILTIN_REG_ASSG "6" 8037 #define BUILTIN_SPEC_REG_ASSG "7" 8038 8039 /* make sure to keep these in proper order since it is searched via bsearch() */ 8040 static const struct builtincmd builtintab[] = { 8041 { BUILTIN_SPEC_REG ".", dotcmd }, 8042 { BUILTIN_SPEC_REG ":", truecmd }, 8043 #if ENABLE_ASH_BUILTIN_TEST 8044 { BUILTIN_REGULAR "[", testcmd }, 8045 { BUILTIN_REGULAR "[[", testcmd }, 8046 #endif 8047 #if ENABLE_ASH_ALIAS 8048 { BUILTIN_REG_ASSG "alias", aliascmd }, 8049 #endif 7751 8050 #if JOBS 7752 retval = WSTOPSIG(status); 7753 if (!WIFSTOPPED(status)) 7754 #endif 7755 { 7756 /* XXX: limits number of signals */ 7757 retval = WTERMSIG(status); 8051 { BUILTIN_REGULAR "bg", fg_bgcmd }, 8052 #endif 8053 { BUILTIN_SPEC_REG "break", breakcmd }, 8054 { BUILTIN_REGULAR "cd", cdcmd }, 8055 { BUILTIN_NOSPEC "chdir", cdcmd }, 8056 #if ENABLE_ASH_CMDCMD 8057 { BUILTIN_REGULAR "command", commandcmd }, 8058 #endif 8059 { BUILTIN_SPEC_REG "continue", breakcmd }, 8060 #if ENABLE_ASH_BUILTIN_ECHO 8061 { BUILTIN_REGULAR "echo", echocmd }, 8062 #endif 8063 { BUILTIN_SPEC_REG "eval", evalcmd }, 8064 { BUILTIN_SPEC_REG "exec", execcmd }, 8065 { BUILTIN_SPEC_REG "exit", exitcmd }, 8066 { BUILTIN_SPEC_REG_ASSG "export", exportcmd }, 8067 { BUILTIN_REGULAR "false", falsecmd }, 7758 8068 #if JOBS 7759 if (retval == SIGINT) 7760 job->sigint = 1; 7761 #endif 7762 } 7763 retval += 128; 7764 } 7765 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n", 7766 jobno(job), job->nprocs, status, retval)); 7767 return retval; 7768 } 7769 7770 #ifdef CONFIG_ASH_MAIL 7771 /* mail.c */ 7772 7773 /* 7774 * Routines to check for mail. (Perhaps make part of main.c?) 7775 */ 8069 { BUILTIN_REGULAR "fg", fg_bgcmd }, 8070 #endif 8071 #if ENABLE_ASH_GETOPTS 8072 { BUILTIN_REGULAR "getopts", getoptscmd }, 8073 #endif 8074 { BUILTIN_NOSPEC "hash", hashcmd }, 8075 #if !ENABLE_FEATURE_SH_EXTRA_QUIET 8076 { BUILTIN_NOSPEC "help", helpcmd }, 8077 #endif 8078 #if JOBS 8079 { BUILTIN_REGULAR "jobs", jobscmd }, 8080 { BUILTIN_REGULAR "kill", killcmd }, 8081 #endif 8082 #if ENABLE_ASH_MATH_SUPPORT 8083 { BUILTIN_NOSPEC "let", letcmd }, 8084 #endif 8085 { BUILTIN_ASSIGN "local", localcmd }, 8086 { BUILTIN_NOSPEC "pwd", pwdcmd }, 8087 { BUILTIN_REGULAR "read", readcmd }, 8088 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd }, 8089 { BUILTIN_SPEC_REG "return", returncmd }, 8090 { BUILTIN_SPEC_REG "set", setcmd }, 8091 { BUILTIN_SPEC_REG "shift", shiftcmd }, 8092 { BUILTIN_SPEC_REG "source", dotcmd }, 8093 #if ENABLE_ASH_BUILTIN_TEST 8094 { BUILTIN_REGULAR "test", testcmd }, 8095 #endif 8096 { BUILTIN_SPEC_REG "times", timescmd }, 8097 { BUILTIN_SPEC_REG "trap", trapcmd }, 8098 { BUILTIN_REGULAR "true", truecmd }, 8099 { BUILTIN_NOSPEC "type", typecmd }, 8100 { BUILTIN_NOSPEC "ulimit", ulimitcmd }, 8101 { BUILTIN_REGULAR "umask", umaskcmd }, 8102 #if ENABLE_ASH_ALIAS 8103 { BUILTIN_REGULAR "unalias", unaliascmd }, 8104 #endif 8105 { BUILTIN_SPEC_REG "unset", unsetcmd }, 8106 { BUILTIN_REGULAR "wait", waitcmd }, 8107 }; 8108 8109 8110 #define COMMANDCMD (builtintab + 5 + \ 8111 2 * ENABLE_ASH_BUILTIN_TEST + \ 8112 ENABLE_ASH_ALIAS + \ 8113 ENABLE_ASH_JOB_CONTROL) 8114 #define EXECCMD (builtintab + 7 + \ 8115 2 * ENABLE_ASH_BUILTIN_TEST + \ 8116 ENABLE_ASH_ALIAS + \ 8117 ENABLE_ASH_JOB_CONTROL + \ 8118 ENABLE_ASH_CMDCMD + \ 8119 ENABLE_ASH_BUILTIN_ECHO) 8120 8121 /* 8122 * Search the table of builtin commands. 8123 */ 8124 static struct builtincmd * 8125 find_builtin(const char *name) 8126 { 8127 struct builtincmd *bp; 8128 8129 bp = bsearch( 8130 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]), 8131 pstrcmp 8132 ); 8133 return bp; 8134 } 8135 8136 /* 8137 * Execute a simple command. 8138 */ 8139 static int back_exitstatus; /* exit status of backquoted command */ 8140 static int 8141 isassignment(const char *p) 8142 { 8143 const char *q = endofname(p); 8144 if (p == q) 8145 return 0; 8146 return *q == '='; 8147 } 8148 static int 8149 bltincmd(int argc, char **argv) 8150 { 8151 /* Preserve exitstatus of a previous possible redirection 8152 * as POSIX mandates */ 8153 return back_exitstatus; 8154 } 8155 static void 8156 evalcommand(union node *cmd, int flags) 8157 { 8158 static const struct builtincmd bltin = { 8159 "\0\0", bltincmd 8160 }; 8161 struct stackmark smark; 8162 union node *argp; 8163 struct arglist arglist; 8164 struct arglist varlist; 8165 char **argv; 8166 int argc; 8167 const struct strlist *sp; 8168 struct cmdentry cmdentry; 8169 struct job *jp; 8170 char *lastarg; 8171 const char *path; 8172 int spclbltin; 8173 int cmd_is_exec; 8174 int status; 8175 char **nargv; 8176 struct builtincmd *bcmd; 8177 int pseudovarflag = 0; 8178 8179 /* First expand the arguments. */ 8180 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); 8181 setstackmark(&smark); 8182 back_exitstatus = 0; 8183 8184 cmdentry.cmdtype = CMDBUILTIN; 8185 cmdentry.u.cmd = &bltin; 8186 varlist.lastp = &varlist.list; 8187 *varlist.lastp = NULL; 8188 arglist.lastp = &arglist.list; 8189 *arglist.lastp = NULL; 8190 8191 argc = 0; 8192 if (cmd->ncmd.args) { 8193 bcmd = find_builtin(cmd->ncmd.args->narg.text); 8194 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd); 8195 } 8196 8197 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) { 8198 struct strlist **spp; 8199 8200 spp = arglist.lastp; 8201 if (pseudovarflag && isassignment(argp->narg.text)) 8202 expandarg(argp, &arglist, EXP_VARTILDE); 8203 else 8204 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); 8205 8206 for (sp = *spp; sp; sp = sp->next) 8207 argc++; 8208 } 8209 8210 argv = nargv = stalloc(sizeof(char *) * (argc + 1)); 8211 for (sp = arglist.list; sp; sp = sp->next) { 8212 TRACE(("evalcommand arg: %s\n", sp->text)); 8213 *nargv++ = sp->text; 8214 } 8215 *nargv = NULL; 8216 8217 lastarg = NULL; 8218 if (iflag && funcnest == 0 && argc > 0) 8219 lastarg = nargv[-1]; 8220 8221 preverrout_fd = 2; 8222 expredir(cmd->ncmd.redirect); 8223 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2); 8224 8225 path = vpath.text; 8226 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { 8227 struct strlist **spp; 8228 char *p; 8229 8230 spp = varlist.lastp; 8231 expandarg(argp, &varlist, EXP_VARTILDE); 8232 8233 /* 8234 * Modify the command lookup path, if a PATH= assignment 8235 * is present 8236 */ 8237 p = (*spp)->text; 8238 if (varequal(p, path)) 8239 path = p; 8240 } 8241 8242 /* Print the command if xflag is set. */ 8243 if (xflag) { 8244 int n; 8245 const char *p = " %s"; 8246 8247 p++; 8248 dprintf(preverrout_fd, p, expandstr(ps4val())); 8249 8250 sp = varlist.list; 8251 for (n = 0; n < 2; n++) { 8252 while (sp) { 8253 dprintf(preverrout_fd, p, sp->text); 8254 sp = sp->next; 8255 if (*p == '%') { 8256 p--; 8257 } 8258 } 8259 sp = arglist.list; 8260 } 8261 full_write(preverrout_fd, "\n", 1); 8262 } 8263 8264 cmd_is_exec = 0; 8265 spclbltin = -1; 8266 8267 /* Now locate the command. */ 8268 if (argc) { 8269 const char *oldpath; 8270 int cmd_flag = DO_ERR; 8271 8272 path += 5; 8273 oldpath = path; 8274 for (;;) { 8275 find_command(argv[0], &cmdentry, cmd_flag, path); 8276 if (cmdentry.cmdtype == CMDUNKNOWN) { 8277 status = 127; 8278 flush_stderr(); 8279 goto bail; 8280 } 8281 8282 /* implement bltin and command here */ 8283 if (cmdentry.cmdtype != CMDBUILTIN) 8284 break; 8285 if (spclbltin < 0) 8286 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd); 8287 if (cmdentry.u.cmd == EXECCMD) 8288 cmd_is_exec++; 8289 #if ENABLE_ASH_CMDCMD 8290 if (cmdentry.u.cmd == COMMANDCMD) { 8291 path = oldpath; 8292 nargv = parse_command_args(argv, &path); 8293 if (!nargv) 8294 break; 8295 argc -= nargv - argv; 8296 argv = nargv; 8297 cmd_flag |= DO_NOFUNC; 8298 } else 8299 #endif 8300 break; 8301 } 8302 } 8303 8304 if (status) { 8305 /* We have a redirection error. */ 8306 if (spclbltin > 0) 8307 raise_exception(EXERROR); 8308 bail: 8309 exitstatus = status; 8310 goto out; 8311 } 8312 8313 /* Execute the command. */ 8314 switch (cmdentry.cmdtype) { 8315 default: 8316 /* Fork off a child process if necessary. */ 8317 if (!(flags & EV_EXIT) || trap[0]) { 8318 INT_OFF; 8319 jp = makejob(cmd, 1); 8320 if (forkshell(jp, cmd, FORK_FG) != 0) { 8321 exitstatus = waitforjob(jp); 8322 INT_ON; 8323 break; 8324 } 8325 FORCE_INT_ON; 8326 } 8327 listsetvar(varlist.list, VEXPORT|VSTACK); 8328 shellexec(argv, path, cmdentry.u.index); 8329 /* NOTREACHED */ 8330 8331 case CMDBUILTIN: 8332 cmdenviron = varlist.list; 8333 if (cmdenviron) { 8334 struct strlist *list = cmdenviron; 8335 int i = VNOSET; 8336 if (spclbltin > 0 || argc == 0) { 8337 i = 0; 8338 if (cmd_is_exec && argc > 1) 8339 i = VEXPORT; 8340 } 8341 listsetvar(list, i); 8342 } 8343 if (evalbltin(cmdentry.u.cmd, argc, argv)) { 8344 int exit_status; 8345 int i, j; 8346 8347 i = exception; 8348 if (i == EXEXIT) 8349 goto raise; 8350 8351 exit_status = 2; 8352 j = 0; 8353 if (i == EXINT) 8354 j = SIGINT; 8355 if (i == EXSIG) 8356 j = pendingsig; 8357 if (j) 8358 exit_status = j + 128; 8359 exitstatus = exit_status; 8360 8361 if (i == EXINT || spclbltin > 0) { 8362 raise: 8363 longjmp(exception_handler->loc, 1); 8364 } 8365 FORCE_INT_ON; 8366 } 8367 break; 8368 8369 case CMDFUNCTION: 8370 listsetvar(varlist.list, 0); 8371 if (evalfun(cmdentry.u.func, argc, argv, flags)) 8372 goto raise; 8373 break; 8374 } 8375 8376 out: 8377 popredir(cmd_is_exec); 8378 if (lastarg) 8379 /* dsl: I think this is intended to be used to support 8380 * '_' in 'vi' command mode during line editing... 8381 * However I implemented that within libedit itself. 8382 */ 8383 setvar("_", lastarg, 0); 8384 popstackmark(&smark); 8385 } 8386 8387 static int 8388 evalbltin(const struct builtincmd *cmd, int argc, char **argv) 8389 { 8390 char *volatile savecmdname; 8391 struct jmploc *volatile savehandler; 8392 struct jmploc jmploc; 8393 int i; 8394 8395 savecmdname = commandname; 8396 i = setjmp(jmploc.loc); 8397 if (i) 8398 goto cmddone; 8399 savehandler = exception_handler; 8400 exception_handler = &jmploc; 8401 commandname = argv[0]; 8402 argptr = argv + 1; 8403 optptr = NULL; /* initialize nextopt */ 8404 exitstatus = (*cmd->builtin)(argc, argv); 8405 flush_stdout_stderr(); 8406 cmddone: 8407 exitstatus |= ferror(stdout); 8408 clearerr(stdout); 8409 commandname = savecmdname; 8410 exsig = 0; 8411 exception_handler = savehandler; 8412 8413 return i; 8414 } 8415 8416 static int 8417 goodname(const char *p) 8418 { 8419 return !*endofname(p); 8420 } 8421 8422 8423 /* 8424 * Search for a command. This is called before we fork so that the 8425 * location of the command will be available in the parent as well as 8426 * the child. The check for "goodname" is an overly conservative 8427 * check that the name will not be subject to expansion. 8428 */ 8429 static void 8430 prehash(union node *n) 8431 { 8432 struct cmdentry entry; 8433 8434 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text)) 8435 find_command(n->ncmd.args->narg.text, &entry, 0, pathval()); 8436 } 8437 8438 8439 /* ============ Builtin commands 8440 * 8441 * Builtin commands whose functions are closely tied to evaluation 8442 * are implemented here. 8443 */ 8444 8445 /* 8446 * Handle break and continue commands. Break, continue, and return are 8447 * all handled by setting the evalskip flag. The evaluation routines 8448 * above all check this flag, and if it is set they start skipping 8449 * commands rather than executing them. The variable skipcount is 8450 * the number of loops to break/continue, or the number of function 8451 * levels to return. (The latter is always 1.) It should probably 8452 * be an error to break out of more loops than exist, but it isn't 8453 * in the standard shell so we don't make it one here. 8454 */ 8455 static int 8456 breakcmd(int argc, char **argv) 8457 { 8458 int n = argc > 1 ? number(argv[1]) : 1; 8459 8460 if (n <= 0) 8461 ash_msg_and_raise_error(illnum, argv[1]); 8462 if (n > loopnest) 8463 n = loopnest; 8464 if (n > 0) { 8465 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK; 8466 skipcount = n; 8467 } 8468 return 0; 8469 } 8470 8471 8472 /* ============ input.c 8473 * 8474 * This implements the input routines used by the parser. 8475 */ 8476 8477 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ 8478 8479 enum { 8480 INPUT_PUSH_FILE = 1, 8481 INPUT_NOFILE_OK = 2, 8482 }; 8483 8484 /* 8485 * NEOF is returned by parsecmd when it encounters an end of file. It 8486 * must be distinct from NULL, so we use the address of a variable that 8487 * happens to be handy. 8488 */ 8489 static int plinno = 1; /* input line number */ 8490 /* number of characters left in input buffer */ 8491 static int parsenleft; /* copy of parsefile->nleft */ 8492 static int parselleft; /* copy of parsefile->lleft */ 8493 /* next character in input buffer */ 8494 static char *parsenextc; /* copy of parsefile->nextc */ 8495 8496 static int checkkwd; 8497 /* values of checkkwd variable */ 8498 #define CHKALIAS 0x1 8499 #define CHKKWD 0x2 8500 #define CHKNL 0x4 8501 8502 static void 8503 popstring(void) 8504 { 8505 struct strpush *sp = parsefile->strpush; 8506 8507 INT_OFF; 8508 #if ENABLE_ASH_ALIAS 8509 if (sp->ap) { 8510 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') { 8511 checkkwd |= CHKALIAS; 8512 } 8513 if (sp->string != sp->ap->val) { 8514 free(sp->string); 8515 } 8516 sp->ap->flag &= ~ALIASINUSE; 8517 if (sp->ap->flag & ALIASDEAD) { 8518 unalias(sp->ap->name); 8519 } 8520 } 8521 #endif 8522 parsenextc = sp->prevstring; 8523 parsenleft = sp->prevnleft; 8524 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ 8525 parsefile->strpush = sp->prev; 8526 if (sp != &(parsefile->basestrpush)) 8527 free(sp); 8528 INT_ON; 8529 } 8530 8531 static int 8532 preadfd(void) 8533 { 8534 int nr; 8535 char *buf = parsefile->buf; 8536 parsenextc = buf; 8537 8538 retry: 8539 #if ENABLE_FEATURE_EDITING 8540 if (!iflag || parsefile->fd) 8541 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 8542 else { 8543 #if ENABLE_FEATURE_TAB_COMPLETION 8544 line_input_state->path_lookup = pathval(); 8545 #endif 8546 nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state); 8547 if (nr == 0) { 8548 /* Ctrl+C pressed */ 8549 if (trap[SIGINT]) { 8550 buf[0] = '\n'; 8551 buf[1] = '\0'; 8552 raise(SIGINT); 8553 return 1; 8554 } 8555 goto retry; 8556 } 8557 if (nr < 0 && errno == 0) { 8558 /* Ctrl+D presend */ 8559 nr = 0; 8560 } 8561 } 8562 #else 8563 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); 8564 #endif 8565 8566 if (nr < 0) { 8567 if (parsefile->fd == 0 && errno == EWOULDBLOCK) { 8568 int flags = fcntl(0, F_GETFL); 8569 if (flags >= 0 && flags & O_NONBLOCK) { 8570 flags &=~ O_NONBLOCK; 8571 if (fcntl(0, F_SETFL, flags) >= 0) { 8572 out2str("sh: turning off NDELAY mode\n"); 8573 goto retry; 8574 } 8575 } 8576 } 8577 } 8578 return nr; 8579 } 8580 8581 /* 8582 * Refill the input buffer and return the next input character: 8583 * 8584 * 1) If a string was pushed back on the input, pop it; 8585 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading 8586 * from a string so we can't refill the buffer, return EOF. 8587 * 3) If the is more stuff in this buffer, use it else call read to fill it. 8588 * 4) Process input up to the next newline, deleting nul characters. 8589 */ 8590 static int 8591 preadbuffer(void) 8592 { 8593 char *q; 8594 int more; 8595 char savec; 8596 8597 while (parsefile->strpush) { 8598 #if ENABLE_ASH_ALIAS 8599 if (parsenleft == -1 && parsefile->strpush->ap && 8600 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') { 8601 return PEOA; 8602 } 8603 #endif 8604 popstring(); 8605 if (--parsenleft >= 0) 8606 return signed_char2int(*parsenextc++); 8607 } 8608 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) 8609 return PEOF; 8610 flush_stdout_stderr(); 8611 8612 more = parselleft; 8613 if (more <= 0) { 8614 again: 8615 more = preadfd(); 8616 if (more <= 0) { 8617 parselleft = parsenleft = EOF_NLEFT; 8618 return PEOF; 8619 } 8620 } 8621 8622 q = parsenextc; 8623 8624 /* delete nul characters */ 8625 for (;;) { 8626 int c; 8627 8628 more--; 8629 c = *q; 8630 8631 if (!c) 8632 memmove(q, q + 1, more); 8633 else { 8634 q++; 8635 if (c == '\n') { 8636 parsenleft = q - parsenextc - 1; 8637 break; 8638 } 8639 } 8640 8641 if (more <= 0) { 8642 parsenleft = q - parsenextc - 1; 8643 if (parsenleft < 0) 8644 goto again; 8645 break; 8646 } 8647 } 8648 parselleft = more; 8649 8650 savec = *q; 8651 *q = '\0'; 8652 8653 if (vflag) { 8654 out2str(parsenextc); 8655 } 8656 8657 *q = savec; 8658 8659 return signed_char2int(*parsenextc++); 8660 } 8661 8662 #define pgetc_as_macro() (--parsenleft >= 0? signed_char2int(*parsenextc++) : preadbuffer()) 8663 static int 8664 pgetc(void) 8665 { 8666 return pgetc_as_macro(); 8667 } 8668 8669 #if ENABLE_ASH_OPTIMIZE_FOR_SIZE 8670 #define pgetc_macro() pgetc() 8671 #else 8672 #define pgetc_macro() pgetc_as_macro() 8673 #endif 8674 8675 /* 8676 * Same as pgetc(), but ignores PEOA. 8677 */ 8678 #if ENABLE_ASH_ALIAS 8679 static int 8680 pgetc2(void) 8681 { 8682 int c; 8683 8684 do { 8685 c = pgetc_macro(); 8686 } while (c == PEOA); 8687 return c; 8688 } 8689 #else 8690 static int 8691 pgetc2(void) 8692 { 8693 return pgetc_macro(); 8694 } 8695 #endif 8696 8697 /* 8698 * Read a line from the script. 8699 */ 8700 static char * 8701 pfgets(char *line, int len) 8702 { 8703 char *p = line; 8704 int nleft = len; 8705 int c; 8706 8707 while (--nleft > 0) { 8708 c = pgetc2(); 8709 if (c == PEOF) { 8710 if (p == line) 8711 return NULL; 8712 break; 8713 } 8714 *p++ = c; 8715 if (c == '\n') 8716 break; 8717 } 8718 *p = '\0'; 8719 return line; 8720 } 8721 8722 /* 8723 * Undo the last call to pgetc. Only one character may be pushed back. 8724 * PEOF may be pushed back. 8725 */ 8726 static void 8727 pungetc(void) 8728 { 8729 parsenleft++; 8730 parsenextc--; 8731 } 8732 8733 /* 8734 * Push a string back onto the input at this current parsefile level. 8735 * We handle aliases this way. 8736 */ 8737 static void 8738 pushstring(char *s, void *ap) 8739 { 8740 struct strpush *sp; 8741 size_t len; 8742 8743 len = strlen(s); 8744 INT_OFF; 8745 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ 8746 if (parsefile->strpush) { 8747 sp = ckmalloc(sizeof(struct strpush)); 8748 sp->prev = parsefile->strpush; 8749 parsefile->strpush = sp; 8750 } else 8751 sp = parsefile->strpush = &(parsefile->basestrpush); 8752 sp->prevstring = parsenextc; 8753 sp->prevnleft = parsenleft; 8754 #if ENABLE_ASH_ALIAS 8755 sp->ap = (struct alias *)ap; 8756 if (ap) { 8757 ((struct alias *)ap)->flag |= ALIASINUSE; 8758 sp->string = s; 8759 } 8760 #endif 8761 parsenextc = s; 8762 parsenleft = len; 8763 INT_ON; 8764 } 8765 8766 /* 8767 * To handle the "." command, a stack of input files is used. Pushfile 8768 * adds a new entry to the stack and popfile restores the previous level. 8769 */ 8770 static void 8771 pushfile(void) 8772 { 8773 struct parsefile *pf; 8774 8775 parsefile->nleft = parsenleft; 8776 parsefile->lleft = parselleft; 8777 parsefile->nextc = parsenextc; 8778 parsefile->linno = plinno; 8779 pf = ckmalloc(sizeof(*pf)); 8780 pf->prev = parsefile; 8781 pf->fd = -1; 8782 pf->strpush = NULL; 8783 pf->basestrpush.prev = NULL; 8784 parsefile = pf; 8785 } 8786 8787 static void 8788 popfile(void) 8789 { 8790 struct parsefile *pf = parsefile; 8791 8792 INT_OFF; 8793 if (pf->fd >= 0) 8794 close(pf->fd); 8795 if (pf->buf) 8796 free(pf->buf); 8797 while (pf->strpush) 8798 popstring(); 8799 parsefile = pf->prev; 8800 free(pf); 8801 parsenleft = parsefile->nleft; 8802 parselleft = parsefile->lleft; 8803 parsenextc = parsefile->nextc; 8804 plinno = parsefile->linno; 8805 INT_ON; 8806 } 8807 8808 /* 8809 * Return to top level. 8810 */ 8811 static void 8812 popallfiles(void) 8813 { 8814 while (parsefile != &basepf) 8815 popfile(); 8816 } 8817 8818 /* 8819 * Close the file(s) that the shell is reading commands from. Called 8820 * after a fork is done. 8821 */ 8822 static void 8823 closescript(void) 8824 { 8825 popallfiles(); 8826 if (parsefile->fd > 0) { 8827 close(parsefile->fd); 8828 parsefile->fd = 0; 8829 } 8830 } 8831 8832 /* 8833 * Like setinputfile, but takes an open file descriptor. Call this with 8834 * interrupts off. 8835 */ 8836 static void 8837 setinputfd(int fd, int push) 8838 { 8839 fcntl(fd, F_SETFD, FD_CLOEXEC); 8840 if (push) { 8841 pushfile(); 8842 parsefile->buf = 0; 8843 } 8844 parsefile->fd = fd; 8845 if (parsefile->buf == NULL) 8846 parsefile->buf = ckmalloc(IBUFSIZ); 8847 parselleft = parsenleft = 0; 8848 plinno = 1; 8849 } 8850 8851 /* 8852 * Set the input to take input from a file. If push is set, push the 8853 * old input onto the stack first. 8854 */ 8855 static int 8856 setinputfile(const char *fname, int flags) 8857 { 8858 int fd; 8859 int fd2; 8860 8861 INT_OFF; 8862 fd = open(fname, O_RDONLY); 8863 if (fd < 0) { 8864 if (flags & INPUT_NOFILE_OK) 8865 goto out; 8866 ash_msg_and_raise_error("can't open %s", fname); 8867 } 8868 if (fd < 10) { 8869 fd2 = copyfd(fd, 10); 8870 close(fd); 8871 if (fd2 < 0) 8872 ash_msg_and_raise_error("out of file descriptors"); 8873 fd = fd2; 8874 } 8875 setinputfd(fd, flags & INPUT_PUSH_FILE); 8876 out: 8877 INT_ON; 8878 return fd; 8879 } 8880 8881 /* 8882 * Like setinputfile, but takes input from a string. 8883 */ 8884 static void 8885 setinputstring(char *string) 8886 { 8887 INT_OFF; 8888 pushfile(); 8889 parsenextc = string; 8890 parsenleft = strlen(string); 8891 parsefile->buf = NULL; 8892 plinno = 1; 8893 INT_ON; 8894 } 8895 8896 8897 /* ============ mail.c 8898 * 8899 * Routines to check for mail. 8900 */ 8901 8902 #if ENABLE_ASH_MAIL 7776 8903 7777 8904 #define MAXMBOXES 10 … … 7782 8909 static int mail_var_path_changed; 7783 8910 7784 7785 7786 8911 /* 7787 8912 * Print appropriate message(s) if mail has arrived. … … 7790 8915 * so we just update the values. 7791 8916 */ 7792 7793 8917 static void 7794 8918 chkmail(void) … … 7809 8933 if (*p == '\0') 7810 8934 continue; 7811 for (q = p ; *q; q++);7812 #if defDEBUG8935 for (q = p; *q; q++); 8936 #if DEBUG 7813 8937 if (q[-1] != '/') 7814 8938 abort(); … … 7831 8955 } 7832 8956 7833 7834 8957 static void 7835 8958 changemail(const char *val) … … 7838 8961 } 7839 8962 7840 #endif /* CONFIG_ASH_MAIL */ 7841 7842 /* main.c */ 7843 7844 7845 #if PROFILE 7846 static short profile_buf[16384]; 7847 extern int etext(); 7848 #endif 7849 7850 static int isloginsh; 7851 7852 static void read_profile(const char *); 7853 7854 /* 7855 * Main routine. We initialize things, parse the arguments, execute 7856 * profiles if we're a login shell, and then call cmdloop to execute 7857 * commands. The setjmp call sets up the location to jump to when an 7858 * exception occurs. When an exception occurs the variable "state" 7859 * is used to figure out how far we had gotten. 7860 */ 7861 7862 int 7863 ash_main(int argc, char **argv) 7864 { 7865 char *shinit; 7866 volatile int state; 7867 struct jmploc jmploc; 7868 struct stackmark smark; 7869 7870 #ifdef __GLIBC__ 7871 dash_errno = __errno_location(); 7872 #endif 7873 7874 #if PROFILE 7875 monitor(4, etext, profile_buf, sizeof profile_buf, 50); 7876 #endif 7877 state = 0; 7878 if (setjmp(jmploc.loc)) { 7879 int e; 7880 int s; 7881 7882 reset(); 7883 7884 e = exception; 7885 if (e == EXERROR) 7886 exitstatus = 2; 7887 s = state; 7888 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) 7889 exitshell(); 7890 7891 if (e == EXINT) { 7892 outcslow('\n', stderr); 7893 } 7894 popstackmark(&smark); 7895 FORCEINTON; /* enable interrupts */ 7896 if (s == 1) 7897 goto state1; 7898 else if (s == 2) 7899 goto state2; 7900 else if (s == 3) 7901 goto state3; 7902 else 7903 goto state4; 7904 } 7905 handler = &jmploc; 7906 #ifdef DEBUG 7907 opentrace(); 7908 trputs("Shell args: "); trargs(argv); 7909 #endif 7910 rootpid = getpid(); 7911 7912 #ifdef CONFIG_ASH_RANDOM_SUPPORT 7913 rseed = rootpid + ((time_t)time((time_t *)0)); 7914 #endif 7915 init(); 7916 setstackmark(&smark); 7917 procargs(argc, argv); 7918 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY 7919 if ( iflag ) { 7920 const char *hp = lookupvar("HISTFILE"); 7921 7922 if(hp == NULL ) { 7923 hp = lookupvar("HOME"); 7924 if(hp != NULL) { 7925 char *defhp = concat_path_file(hp, ".ash_history"); 7926 setvar("HISTFILE", defhp, 0); 7927 free(defhp); 7928 } 7929 } 7930 } 7931 #endif 7932 if (argv[0] && argv[0][0] == '-') 7933 isloginsh = 1; 7934 if (isloginsh) { 7935 state = 1; 7936 read_profile("/etc/profile"); 7937 state1: 7938 state = 2; 7939 read_profile(".profile"); 7940 } 7941 state2: 7942 state = 3; 7943 if ( 7944 #ifndef linux 7945 getuid() == geteuid() && getgid() == getegid() && 7946 #endif 7947 iflag 7948 ) { 7949 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { 7950 read_profile(shinit); 7951 } 7952 } 7953 state3: 7954 state = 4; 7955 if (minusc) 7956 evalstring(minusc, 0); 7957 7958 if (sflag || minusc == NULL) { 7959 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY 7960 if ( iflag ) { 7961 const char *hp = lookupvar("HISTFILE"); 7962 7963 if(hp != NULL ) 7964 load_history ( hp ); 7965 } 7966 #endif 7967 state4: /* XXX ??? - why isn't this before the "if" statement */ 7968 cmdloop(1); 7969 } 7970 #if PROFILE 7971 monitor(0); 7972 #endif 7973 #if GPROF 7974 { 7975 extern void _mcleanup(void); 7976 _mcleanup(); 7977 } 7978 #endif 7979 exitshell(); 7980 /* NOTREACHED */ 7981 } 7982 7983 7984 /* 7985 * Read and execute commands. "Top" is nonzero for the top level command 7986 * loop; it turns on prompting if the shell is interactive. 7987 */ 7988 7989 static int 7990 cmdloop(int top) 7991 { 7992 union node *n; 7993 struct stackmark smark; 7994 int inter; 7995 int numeof = 0; 7996 7997 TRACE(("cmdloop(%d) called\n", top)); 7998 for (;;) { 7999 int skip; 8000 8001 setstackmark(&smark); 8002 #if JOBS 8003 if (jobctl) 8004 showjobs(stderr, SHOW_CHANGED); 8005 #endif 8006 inter = 0; 8007 if (iflag && top) { 8008 inter++; 8009 #ifdef CONFIG_ASH_MAIL 8010 chkmail(); 8011 #endif 8012 } 8013 n = parsecmd(inter); 8014 /* showtree(n); DEBUG */ 8015 if (n == NEOF) { 8016 if (!top || numeof >= 50) 8017 break; 8018 if (!stoppedjobs()) { 8019 if (!Iflag) 8020 break; 8021 out2str("\nUse \"exit\" to leave shell.\n"); 8022 } 8023 numeof++; 8024 } else if (nflag == 0) { 8025 job_warning = (job_warning == 2) ? 1 : 0; 8026 numeof = 0; 8027 evaltree(n, 0); 8028 } 8029 popstackmark(&smark); 8030 skip = evalskip; 8031 8032 if (skip) { 8033 evalskip = 0; 8034 return skip & SKIPEVAL; 8035 } 8036 } 8037 8038 return 0; 8039 } 8040 8041 8042 /* 8043 * Read /etc/profile or .profile. Return on error. 8044 */ 8045 8046 static void 8047 read_profile(const char *name) 8048 { 8049 int skip; 8050 8051 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0) 8052 return; 8053 8054 skip = cmdloop(0); 8055 popfile(); 8056 8057 if (skip) 8058 exitshell(); 8059 } 8060 8061 8062 /* 8063 * Read a file containing shell functions. 8064 */ 8065 8066 static void 8067 readcmdfile(char *name) 8068 { 8069 setinputfile(name, INPUT_PUSH_FILE); 8070 cmdloop(0); 8071 popfile(); 8072 } 8073 8074 8075 /* 8076 * Take commands from a file. To be compatible we should do a path 8077 * search for the file, which is necessary to find sub-commands. 8078 */ 8079 8080 static inline char * 8081 find_dot_file(char *name) 8082 { 8083 char *fullname; 8084 const char *path = pathval(); 8085 struct stat statb; 8086 8087 /* don't try this for absolute or relative paths */ 8088 if (strchr(name, '/')) 8089 return name; 8090 8091 while ((fullname = padvance(&path, name)) != NULL) { 8092 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { 8093 /* 8094 * Don't bother freeing here, since it will 8095 * be freed by the caller. 8096 */ 8097 return fullname; 8098 } 8099 stunalloc(fullname); 8100 } 8101 8102 /* not found in the PATH */ 8103 sh_error(not_found_msg, name); 8104 /* NOTREACHED */ 8105 } 8106 8107 static int dotcmd(int argc, char **argv) 8108 { 8109 struct strlist *sp; 8110 volatile struct shparam saveparam; 8111 int status = 0; 8112 8113 for (sp = cmdenviron; sp; sp = sp->next) 8114 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED); 8115 8116 if (argc >= 2) { /* That's what SVR2 does */ 8117 char *fullname; 8118 8119 fullname = find_dot_file(argv[1]); 8120 8121 if (argc > 2) { 8122 saveparam = shellparam; 8123 shellparam.malloc = 0; 8124 shellparam.nparam = argc - 2; 8125 shellparam.p = argv + 2; 8126 }; 8127 8128 setinputfile(fullname, INPUT_PUSH_FILE); 8129 commandname = fullname; 8130 cmdloop(0); 8131 popfile(); 8132 8133 if (argc > 2) { 8134 freeparam(&shellparam); 8135 shellparam = saveparam; 8136 }; 8137 status = exitstatus; 8138 } 8139 return status; 8140 } 8141 8142 8143 static int 8144 exitcmd(int argc, char **argv) 8145 { 8146 if (stoppedjobs()) 8147 return 0; 8148 if (argc > 1) 8149 exitstatus = number(argv[1]); 8150 exraise(EXEXIT); 8151 /* NOTREACHED */ 8152 } 8153 8154 #ifdef CONFIG_ASH_BUILTIN_ECHO 8155 static int 8156 echocmd(int argc, char **argv) 8157 { 8158 return bb_echo(argc, argv); 8159 } 8160 #endif 8161 8162 #ifdef CONFIG_ASH_BUILTIN_TEST 8163 static int 8164 testcmd(int argc, char **argv) 8165 { 8166 return bb_test(argc, argv); 8167 } 8168 #endif 8169 8170 /* memalloc.c */ 8171 8172 /* 8173 * Same for malloc, realloc, but returns an error when out of space. 8174 */ 8175 8176 static pointer 8177 ckrealloc(pointer p, size_t nbytes) 8178 { 8179 p = realloc(p, nbytes); 8180 if (p == NULL) 8181 sh_error(bb_msg_memory_exhausted); 8182 return p; 8183 } 8184 8185 static pointer 8186 ckmalloc(size_t nbytes) 8187 { 8188 return ckrealloc(NULL, nbytes); 8189 } 8190 8191 /* 8192 * Make a copy of a string in safe storage. 8193 */ 8194 8195 static char * 8196 savestr(const char *s) 8197 { 8198 char *p = strdup(s); 8199 if (!p) 8200 sh_error(bb_msg_memory_exhausted); 8201 return p; 8202 } 8203 8204 8205 /* 8206 * Parse trees for commands are allocated in lifo order, so we use a stack 8207 * to make this more efficient, and also to avoid all sorts of exception 8208 * handling code to handle interrupts in the middle of a parse. 8209 * 8210 * The size 504 was chosen because the Ultrix malloc handles that size 8211 * well. 8212 */ 8213 8214 8215 static pointer 8216 stalloc(size_t nbytes) 8217 { 8218 char *p; 8219 size_t aligned; 8220 8221 aligned = SHELL_ALIGN(nbytes); 8222 if (aligned > stacknleft) { 8223 size_t len; 8224 size_t blocksize; 8225 struct stack_block *sp; 8226 8227 blocksize = aligned; 8228 if (blocksize < MINSIZE) 8229 blocksize = MINSIZE; 8230 len = sizeof(struct stack_block) - MINSIZE + blocksize; 8231 if (len < blocksize) 8232 sh_error(bb_msg_memory_exhausted); 8233 INTOFF; 8234 sp = ckmalloc(len); 8235 sp->prev = stackp; 8236 stacknxt = sp->space; 8237 stacknleft = blocksize; 8238 sstrend = stacknxt + blocksize; 8239 stackp = sp; 8240 INTON; 8241 } 8242 p = stacknxt; 8243 stacknxt += aligned; 8244 stacknleft -= aligned; 8245 return p; 8246 } 8247 8248 8249 void 8250 stunalloc(pointer p) 8251 { 8252 #ifdef DEBUG 8253 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) { 8254 write(2, "stunalloc\n", 10); 8255 abort(); 8256 } 8257 #endif 8258 stacknleft += stacknxt - (char *)p; 8259 stacknxt = p; 8260 } 8261 8262 8263 void 8264 setstackmark(struct stackmark *mark) 8265 { 8266 mark->stackp = stackp; 8267 mark->stacknxt = stacknxt; 8268 mark->stacknleft = stacknleft; 8269 mark->marknext = markp; 8270 markp = mark; 8271 } 8272 8273 8274 void 8275 popstackmark(struct stackmark *mark) 8276 { 8277 struct stack_block *sp; 8278 8279 INTOFF; 8280 markp = mark->marknext; 8281 while (stackp != mark->stackp) { 8282 sp = stackp; 8283 stackp = sp->prev; 8284 ckfree(sp); 8285 } 8286 stacknxt = mark->stacknxt; 8287 stacknleft = mark->stacknleft; 8288 sstrend = mark->stacknxt + mark->stacknleft; 8289 INTON; 8290 } 8291 8292 8293 /* 8294 * When the parser reads in a string, it wants to stick the string on the 8295 * stack and only adjust the stack pointer when it knows how big the 8296 * string is. Stackblock (defined in stack.h) returns a pointer to a block 8297 * of space on top of the stack and stackblocklen returns the length of 8298 * this block. Growstackblock will grow this space by at least one byte, 8299 * possibly moving it (like realloc). Grabstackblock actually allocates the 8300 * part of the block that has been used. 8301 */ 8302 8303 void 8304 growstackblock(void) 8305 { 8306 size_t newlen; 8307 8308 newlen = stacknleft * 2; 8309 if (newlen < stacknleft) 8310 sh_error(bb_msg_memory_exhausted); 8311 if (newlen < 128) 8312 newlen += 128; 8313 8314 if (stacknxt == stackp->space && stackp != &stackbase) { 8315 struct stack_block *oldstackp; 8316 struct stackmark *xmark; 8317 struct stack_block *sp; 8318 struct stack_block *prevstackp; 8319 size_t grosslen; 8320 8321 INTOFF; 8322 oldstackp = stackp; 8323 sp = stackp; 8324 prevstackp = sp->prev; 8325 grosslen = newlen + sizeof(struct stack_block) - MINSIZE; 8326 sp = ckrealloc((pointer)sp, grosslen); 8327 sp->prev = prevstackp; 8328 stackp = sp; 8329 stacknxt = sp->space; 8330 stacknleft = newlen; 8331 sstrend = sp->space + newlen; 8332 8333 /* 8334 * Stack marks pointing to the start of the old block 8335 * must be relocated to point to the new block 8336 */ 8337 xmark = markp; 8338 while (xmark != NULL && xmark->stackp == oldstackp) { 8339 xmark->stackp = stackp; 8340 xmark->stacknxt = stacknxt; 8341 xmark->stacknleft = stacknleft; 8342 xmark = xmark->marknext; 8343 } 8344 INTON; 8345 } else { 8346 char *oldspace = stacknxt; 8347 int oldlen = stacknleft; 8348 char *p = stalloc(newlen); 8349 8350 /* free the space we just allocated */ 8351 stacknxt = memcpy(p, oldspace, oldlen); 8352 stacknleft += newlen; 8353 } 8354 } 8355 8356 static inline void 8357 grabstackblock(size_t len) 8358 { 8359 len = SHELL_ALIGN(len); 8360 stacknxt += len; 8361 stacknleft -= len; 8362 } 8363 8364 /* 8365 * The following routines are somewhat easier to use than the above. 8366 * The user declares a variable of type STACKSTR, which may be declared 8367 * to be a register. The macro STARTSTACKSTR initializes things. Then 8368 * the user uses the macro STPUTC to add characters to the string. In 8369 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is 8370 * grown as necessary. When the user is done, she can just leave the 8371 * string there and refer to it using stackblock(). Or she can allocate 8372 * the space for it using grabstackstr(). If it is necessary to allow 8373 * someone else to use the stack temporarily and then continue to grow 8374 * the string, the user should use grabstack to allocate the space, and 8375 * then call ungrabstr(p) to return to the previous mode of operation. 8376 * 8377 * USTPUTC is like STPUTC except that it doesn't check for overflow. 8378 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there 8379 * is space for at least one character. 8380 */ 8381 8382 void * 8383 growstackstr(void) 8384 { 8385 size_t len = stackblocksize(); 8386 if (herefd >= 0 && len >= 1024) { 8387 bb_full_write(herefd, stackblock(), len); 8388 return stackblock(); 8389 } 8390 growstackblock(); 8391 return stackblock() + len; 8392 } 8393 8394 /* 8395 * Called from CHECKSTRSPACE. 8396 */ 8397 8398 char * 8399 makestrspace(size_t newlen, char *p) 8400 { 8401 size_t len = p - stacknxt; 8402 size_t size = stackblocksize(); 8403 8404 for (;;) { 8405 size_t nleft; 8406 8407 size = stackblocksize(); 8408 nleft = size - len; 8409 if (nleft >= newlen) 8410 break; 8411 growstackblock(); 8412 } 8413 return stackblock() + len; 8414 } 8415 8416 char * 8417 stnputs(const char *s, size_t n, char *p) 8418 { 8419 p = makestrspace(n, p); 8420 p = mempcpy(p, s, n); 8421 return p; 8422 } 8423 8424 char * 8425 stputs(const char *s, char *p) 8426 { 8427 return stnputs(s, strlen(s), p); 8428 } 8429 8430 /* mystring.c */ 8431 8432 /* 8433 * String functions. 8434 * 8435 * number(s) Convert a string of digits to an integer. 8436 * is_number(s) Return true if s is a string of digits. 8437 */ 8438 8439 /* 8440 * prefix -- see if pfx is a prefix of string. 8441 */ 8442 8443 char * 8444 prefix(const char *string, const char *pfx) 8445 { 8446 while (*pfx) { 8447 if (*pfx++ != *string++) 8448 return 0; 8449 } 8450 return (char *) string; 8451 } 8452 8453 8454 /* 8455 * Convert a string of digits to an integer, printing an error message on 8456 * failure. 8457 */ 8458 8459 int 8460 number(const char *s) 8461 { 8462 8463 if (! is_number(s)) 8464 sh_error(illnum, s); 8465 return atoi(s); 8466 } 8467 8468 8469 /* 8470 * Check for a valid number. This should be elsewhere. 8471 */ 8472 8473 int 8474 is_number(const char *p) 8475 { 8476 do { 8477 if (! is_digit(*p)) 8478 return 0; 8479 } while (*++p != '\0'); 8480 return 1; 8481 } 8482 8483 8484 /* 8485 * Produce a possibly single quoted string suitable as input to the shell. 8486 * The return string is allocated on the stack. 8487 */ 8488 8489 char * 8490 single_quote(const char *s) { 8491 char *p; 8492 8493 STARTSTACKSTR(p); 8494 8495 do { 8496 char *q; 8497 size_t len; 8498 8499 len = strchrnul(s, '\'') - s; 8500 8501 q = p = makestrspace(len + 3, p); 8502 8503 *q++ = '\''; 8504 q = mempcpy(q, s, len); 8505 *q++ = '\''; 8506 s += len; 8507 8508 STADJUST(q - p, p); 8509 8510 len = strspn(s, "'"); 8511 if (!len) 8512 break; 8513 8514 q = p = makestrspace(len + 3, p); 8515 8516 *q++ = '"'; 8517 q = mempcpy(q, s, len); 8518 *q++ = '"'; 8519 s += len; 8520 8521 STADJUST(q - p, p); 8522 } while (*s); 8523 8524 USTPUTC(0, p); 8525 8526 return stackblock(); 8527 } 8528 8529 /* 8530 * Like strdup but works with the ash stack. 8531 */ 8532 8533 char * 8534 sstrdup(const char *p) 8535 { 8536 size_t len = strlen(p) + 1; 8537 return memcpy(stalloc(len), p, len); 8538 } 8539 8540 8541 static void 8542 calcsize(union node *n) 8543 { 8544 if (n == NULL) 8545 return; 8546 funcblocksize += nodesize[n->type]; 8547 switch (n->type) { 8548 case NCMD: 8549 calcsize(n->ncmd.redirect); 8550 calcsize(n->ncmd.args); 8551 calcsize(n->ncmd.assign); 8552 break; 8553 case NPIPE: 8554 sizenodelist(n->npipe.cmdlist); 8555 break; 8556 case NREDIR: 8557 case NBACKGND: 8558 case NSUBSHELL: 8559 calcsize(n->nredir.redirect); 8560 calcsize(n->nredir.n); 8561 break; 8562 case NAND: 8563 case NOR: 8564 case NSEMI: 8565 case NWHILE: 8566 case NUNTIL: 8567 calcsize(n->nbinary.ch2); 8568 calcsize(n->nbinary.ch1); 8569 break; 8570 case NIF: 8571 calcsize(n->nif.elsepart); 8572 calcsize(n->nif.ifpart); 8573 calcsize(n->nif.test); 8574 break; 8575 case NFOR: 8576 funcstringsize += strlen(n->nfor.var) + 1; 8577 calcsize(n->nfor.body); 8578 calcsize(n->nfor.args); 8579 break; 8580 case NCASE: 8581 calcsize(n->ncase.cases); 8582 calcsize(n->ncase.expr); 8583 break; 8584 case NCLIST: 8585 calcsize(n->nclist.body); 8586 calcsize(n->nclist.pattern); 8587 calcsize(n->nclist.next); 8588 break; 8589 case NDEFUN: 8590 case NARG: 8591 sizenodelist(n->narg.backquote); 8592 funcstringsize += strlen(n->narg.text) + 1; 8593 calcsize(n->narg.next); 8594 break; 8595 case NTO: 8596 case NCLOBBER: 8597 case NFROM: 8598 case NFROMTO: 8599 case NAPPEND: 8600 calcsize(n->nfile.fname); 8601 calcsize(n->nfile.next); 8602 break; 8603 case NTOFD: 8604 case NFROMFD: 8605 calcsize(n->ndup.vname); 8606 calcsize(n->ndup.next); 8607 break; 8608 case NHERE: 8609 case NXHERE: 8610 calcsize(n->nhere.doc); 8611 calcsize(n->nhere.next); 8612 break; 8613 case NNOT: 8614 calcsize(n->nnot.com); 8615 break; 8616 }; 8617 } 8618 8619 8620 static void 8621 sizenodelist(struct nodelist *lp) 8622 { 8623 while (lp) { 8624 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); 8625 calcsize(lp->n); 8626 lp = lp->next; 8627 } 8628 } 8629 8630 8631 static union node * 8632 copynode(union node *n) 8633 { 8634 union node *new; 8635 8636 if (n == NULL) 8637 return NULL; 8638 new = funcblock; 8639 funcblock = (char *) funcblock + nodesize[n->type]; 8640 switch (n->type) { 8641 case NCMD: 8642 new->ncmd.redirect = copynode(n->ncmd.redirect); 8643 new->ncmd.args = copynode(n->ncmd.args); 8644 new->ncmd.assign = copynode(n->ncmd.assign); 8645 break; 8646 case NPIPE: 8647 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); 8648 new->npipe.backgnd = n->npipe.backgnd; 8649 break; 8650 case NREDIR: 8651 case NBACKGND: 8652 case NSUBSHELL: 8653 new->nredir.redirect = copynode(n->nredir.redirect); 8654 new->nredir.n = copynode(n->nredir.n); 8655 break; 8656 case NAND: 8657 case NOR: 8658 case NSEMI: 8659 case NWHILE: 8660 case NUNTIL: 8661 new->nbinary.ch2 = copynode(n->nbinary.ch2); 8662 new->nbinary.ch1 = copynode(n->nbinary.ch1); 8663 break; 8664 case NIF: 8665 new->nif.elsepart = copynode(n->nif.elsepart); 8666 new->nif.ifpart = copynode(n->nif.ifpart); 8667 new->nif.test = copynode(n->nif.test); 8668 break; 8669 case NFOR: 8670 new->nfor.var = nodesavestr(n->nfor.var); 8671 new->nfor.body = copynode(n->nfor.body); 8672 new->nfor.args = copynode(n->nfor.args); 8673 break; 8674 case NCASE: 8675 new->ncase.cases = copynode(n->ncase.cases); 8676 new->ncase.expr = copynode(n->ncase.expr); 8677 break; 8678 case NCLIST: 8679 new->nclist.body = copynode(n->nclist.body); 8680 new->nclist.pattern = copynode(n->nclist.pattern); 8681 new->nclist.next = copynode(n->nclist.next); 8682 break; 8683 case NDEFUN: 8684 case NARG: 8685 new->narg.backquote = copynodelist(n->narg.backquote); 8686 new->narg.text = nodesavestr(n->narg.text); 8687 new->narg.next = copynode(n->narg.next); 8688 break; 8689 case NTO: 8690 case NCLOBBER: 8691 case NFROM: 8692 case NFROMTO: 8693 case NAPPEND: 8694 new->nfile.fname = copynode(n->nfile.fname); 8695 new->nfile.fd = n->nfile.fd; 8696 new->nfile.next = copynode(n->nfile.next); 8697 break; 8698 case NTOFD: 8699 case NFROMFD: 8700 new->ndup.vname = copynode(n->ndup.vname); 8701 new->ndup.dupfd = n->ndup.dupfd; 8702 new->ndup.fd = n->ndup.fd; 8703 new->ndup.next = copynode(n->ndup.next); 8704 break; 8705 case NHERE: 8706 case NXHERE: 8707 new->nhere.doc = copynode(n->nhere.doc); 8708 new->nhere.fd = n->nhere.fd; 8709 new->nhere.next = copynode(n->nhere.next); 8710 break; 8711 case NNOT: 8712 new->nnot.com = copynode(n->nnot.com); 8713 break; 8714 }; 8715 new->type = n->type; 8716 return new; 8717 } 8718 8719 8720 static struct nodelist * 8721 copynodelist(struct nodelist *lp) 8722 { 8723 struct nodelist *start; 8724 struct nodelist **lpp; 8725 8726 lpp = &start; 8727 while (lp) { 8728 *lpp = funcblock; 8729 funcblock = (char *) funcblock + 8730 SHELL_ALIGN(sizeof(struct nodelist)); 8731 (*lpp)->n = copynode(lp->n); 8732 lp = lp->next; 8733 lpp = &(*lpp)->next; 8734 } 8735 *lpp = NULL; 8736 return start; 8737 } 8738 8739 8740 static char * 8741 nodesavestr(char *s) 8742 { 8743 char *rtn = funcstring; 8744 8745 funcstring = stpcpy(funcstring, s) + 1; 8746 return rtn; 8747 } 8748 8749 8750 /* 8751 * Free a parse tree. 8752 */ 8753 8754 static void 8755 freefunc(struct funcnode *f) 8756 { 8757 if (f && --f->count < 0) 8758 ckfree(f); 8759 } 8760 8761 8762 static void options(int); 8763 static void setoption(int, int); 8764 8765 8766 /* 8767 * Process the shell command line arguments. 8768 */ 8769 8770 void 8771 procargs(int argc, char **argv) 8772 { 8773 int i; 8774 const char *xminusc; 8775 char **xargv; 8776 8777 xargv = argv; 8778 arg0 = xargv[0]; 8779 if (argc > 0) 8780 xargv++; 8781 for (i = 0; i < NOPTS; i++) 8782 optlist[i] = 2; 8783 argptr = xargv; 8784 options(1); 8785 xargv = argptr; 8786 xminusc = minusc; 8787 if (*xargv == NULL) { 8788 if (xminusc) 8789 sh_error(bb_msg_requires_arg, "-c"); 8790 sflag = 1; 8791 } 8792 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) 8793 iflag = 1; 8794 if (mflag == 2) 8795 mflag = iflag; 8796 for (i = 0; i < NOPTS; i++) 8797 if (optlist[i] == 2) 8798 optlist[i] = 0; 8799 #if DEBUG == 2 8800 debug = 1; 8801 #endif 8802 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ 8803 if (xminusc) { 8804 minusc = *xargv++; 8805 if (*xargv) 8806 goto setarg0; 8807 } else if (!sflag) { 8808 setinputfile(*xargv, 0); 8809 setarg0: 8810 arg0 = *xargv++; 8811 commandname = arg0; 8812 } 8813 8814 shellparam.p = xargv; 8815 #ifdef CONFIG_ASH_GETOPTS 8963 #endif /* ASH_MAIL */ 8964 8965 8966 /* ============ ??? */ 8967 8968 /* 8969 * Set the shell parameters. 8970 */ 8971 static void 8972 setparam(char **argv) 8973 { 8974 char **newparam; 8975 char **ap; 8976 int nparam; 8977 8978 for (nparam = 0; argv[nparam]; nparam++); 8979 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap)); 8980 while (*argv) { 8981 *ap++ = ckstrdup(*argv++); 8982 } 8983 *ap = NULL; 8984 freeparam(&shellparam); 8985 shellparam.malloc = 1; 8986 shellparam.nparam = nparam; 8987 shellparam.p = newparam; 8988 #if ENABLE_ASH_GETOPTS 8816 8989 shellparam.optind = 1; 8817 8990 shellparam.optoff = -1; 8818 8991 #endif 8819 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 8820 while (*xargv) { 8821 shellparam.nparam++; 8822 xargv++; 8823 } 8824 optschanged(); 8825 } 8826 8827 8828 void 8829 optschanged(void) 8830 { 8831 #ifdef DEBUG 8832 opentrace(); 8833 #endif 8834 setinteractive(iflag); 8835 setjobctl(mflag); 8836 setvimode(viflag); 8837 } 8838 8839 static inline void 8992 } 8993 8994 /* 8995 * Process shell options. The global variable argptr contains a pointer 8996 * to the argument list; we advance it past the options. 8997 */ 8998 static void 8840 8999 minus_o(char *name, int val) 8841 9000 { 8842 9001 int i; 8843 9002 8844 if (name == NULL) { 8845 out1str("Current option settings\n"); 8846 for (i = 0; i < NOPTS; i++) 8847 out1fmt("%-16s%s\n", optnames(i), 8848 optlist[i] ? "on" : "off"); 8849 } else { 8850 for (i = 0; i < NOPTS; i++) 8851 if (equal(name, optnames(i))) { 9003 if (name) { 9004 for (i = 0; i < NOPTS; i++) { 9005 if (strcmp(name, optnames(i)) == 0) { 8852 9006 optlist[i] = val; 8853 9007 return; 8854 9008 } 8855 sh_error("Illegal option -o %s", name); 8856 } 8857 } 8858 8859 /* 8860 * Process shell options. The global variable argptr contains a pointer 8861 * to the argument list; we advance it past the options. 8862 */ 8863 9009 } 9010 ash_msg_and_raise_error("illegal option -o %s", name); 9011 } 9012 out1str("Current option settings\n"); 9013 for (i = 0; i < NOPTS; i++) 9014 out1fmt("%-16s%s\n", optnames(i), 9015 optlist[i] ? "on" : "off"); 9016 } 9017 static void 9018 setoption(int flag, int val) 9019 { 9020 int i; 9021 9022 for (i = 0; i < NOPTS; i++) { 9023 if (optletters(i) == flag) { 9024 optlist[i] = val; 9025 return; 9026 } 9027 } 9028 ash_msg_and_raise_error("illegal option -%c", flag); 9029 /* NOTREACHED */ 9030 } 8864 9031 static void 8865 9032 options(int cmdline) … … 8872 9039 minusc = NULL; 8873 9040 while ((p = *argptr) != NULL) { 9041 c = *p++; 9042 if (c != '-' && c != '+') 9043 break; 8874 9044 argptr++; 8875 if ((c = *p++) == '-') { 9045 val = 0; /* val = 0 if c == '+' */ 9046 if (c == '-') { 8876 9047 val = 1; 8877 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {9048 if (p[0] == '\0' || LONE_DASH(p)) { 8878 9049 if (!cmdline) { 8879 9050 /* "-" means turn off -x and -v */ … … 8886 9057 break; /* "-" or "--" terminates options */ 8887 9058 } 8888 } else if (c == '+') { 8889 val = 0; 8890 } else { 8891 argptr--; 8892 break; 8893 } 9059 } 9060 /* first char was + or - */ 8894 9061 while ((c = *p++) != '\0') { 9062 /* bash 3.2 indeed handles -c CMD and +c CMD the same */ 8895 9063 if (c == 'c' && cmdline) { 8896 minusc = p; /* command is after shell args */9064 minusc = p; /* command is after shell args */ 8897 9065 } else if (c == 'o') { 8898 9066 minus_o(*argptr, val); 8899 9067 if (*argptr) 8900 9068 argptr++; 8901 } else if (cmdline && (c == '-')) { // long options 9069 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */ 9070 isloginsh = 1; 9071 /* bash does not accept +-login, we also won't */ 9072 } else if (cmdline && val && (c == '-')) { /* long options */ 8902 9073 if (strcmp(p, "login") == 0) 8903 9074 isloginsh = 1; … … 8910 9081 } 8911 9082 8912 8913 static void8914 setoption(int flag, int val)8915 {8916 int i;8917 8918 for (i = 0; i < NOPTS; i++)8919 if (optletters(i) == flag) {8920 optlist[i] = val;8921 return;8922 }8923 sh_error("Illegal option -%c", flag);8924 /* NOTREACHED */8925 }8926 8927 8928 8929 /*8930 * Set the shell parameters.8931 */8932 8933 void8934 setparam(char **argv)8935 {8936 char **newparam;8937 char **ap;8938 int nparam;8939 8940 for (nparam = 0 ; argv[nparam] ; nparam++);8941 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);8942 while (*argv) {8943 *ap++ = savestr(*argv++);8944 }8945 *ap = NULL;8946 freeparam(&shellparam);8947 shellparam.malloc = 1;8948 shellparam.nparam = nparam;8949 shellparam.p = newparam;8950 #ifdef CONFIG_ASH_GETOPTS8951 shellparam.optind = 1;8952 shellparam.optoff = -1;8953 #endif8954 }8955 8956 8957 /*8958 * Free the list of positional parameters.8959 */8960 8961 void8962 freeparam(volatile struct shparam *param)8963 {8964 char **ap;8965 8966 if (param->malloc) {8967 for (ap = param->p ; *ap ; ap++)8968 ckfree(*ap);8969 ckfree(param->p);8970 }8971 }8972 8973 8974 8975 9083 /* 8976 9084 * The shift builtin command. 8977 9085 */ 8978 8979 int 9086 static int 8980 9087 shiftcmd(int argc, char **argv) 8981 9088 { … … 8987 9094 n = number(argv[1]); 8988 9095 if (n > shellparam.nparam) 8989 sh_error("can't shift that many");8990 INT OFF;9096 ash_msg_and_raise_error("can't shift that many"); 9097 INT_OFF; 8991 9098 shellparam.nparam -= n; 8992 for (ap1 = shellparam.p ; --n >= 0; ap1++) {9099 for (ap1 = shellparam.p; --n >= 0; ap1++) { 8993 9100 if (shellparam.malloc) 8994 ckfree(*ap1);9101 free(*ap1); 8995 9102 } 8996 9103 ap2 = shellparam.p; 8997 9104 while ((*ap2++ = *ap1++) != NULL); 8998 #if def CONFIG_ASH_GETOPTS9105 #if ENABLE_ASH_GETOPTS 8999 9106 shellparam.optind = 1; 9000 9107 shellparam.optoff = -1; 9001 9108 #endif 9002 INT ON;9109 INT_ON; 9003 9110 return 0; 9004 9111 } 9005 9112 9006 9113 /* 9114 * POSIX requires that 'set' (but not export or readonly) output the 9115 * variables in lexicographic order - by the locale's collating order (sigh). 9116 * Maybe we could keep them in an ordered balanced binary tree 9117 * instead of hashed lists. 9118 * For now just roll 'em through qsort for printing... 9119 */ 9120 static int 9121 showvars(const char *sep_prefix, int on, int off) 9122 { 9123 const char *sep; 9124 char **ep, **epend; 9125 9126 ep = listvars(on, off, &epend); 9127 qsort(ep, epend - ep, sizeof(char *), vpcmp); 9128 9129 sep = *sep_prefix ? " " : sep_prefix; 9130 9131 for (; ep < epend; ep++) { 9132 const char *p; 9133 const char *q; 9134 9135 p = strchrnul(*ep, '='); 9136 q = nullstr; 9137 if (*p) 9138 q = single_quote(++p); 9139 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q); 9140 } 9141 return 0; 9142 } 9007 9143 9008 9144 /* 9009 9145 * The set command builtin. 9010 9146 */ 9011 9012 int 9147 static int 9013 9148 setcmd(int argc, char **argv) 9014 9149 { 9015 9150 if (argc == 1) 9016 9151 return showvars(nullstr, 0, VUNSET); 9017 INT OFF;9152 INT_OFF; 9018 9153 options(0); 9019 9154 optschanged(); … … 9021 9156 setparam(argptr); 9022 9157 } 9023 INT ON;9158 INT_ON; 9024 9159 return 0; 9025 9160 } 9026 9161 9027 9028 #ifdef CONFIG_ASH_GETOPTS 9029 static void 9030 getoptsreset(const char *value) 9031 { 9032 shellparam.optind = number(value); 9033 shellparam.optoff = -1; 9034 } 9035 #endif 9036 9037 #ifdef CONFIG_LOCALE_SUPPORT 9038 static void change_lc_all(const char *value) 9039 { 9040 if (value != 0 && *value != 0) 9041 setlocale(LC_ALL, value); 9042 } 9043 9044 static void change_lc_ctype(const char *value) 9045 { 9046 if (value != 0 && *value != 0) 9047 setlocale(LC_CTYPE, value); 9048 } 9049 9050 #endif 9051 9052 #ifdef CONFIG_ASH_RANDOM_SUPPORT 9162 #if ENABLE_ASH_RANDOM_SUPPORT 9053 9163 /* Roughly copied from bash.. */ 9054 static void change_random(const char *value) 9055 { 9056 if(value == NULL) { 9164 static void 9165 change_random(const char *value) 9166 { 9167 if (value == NULL) { 9057 9168 /* "get", generate */ 9058 9169 char buf[16]; … … 9070 9181 #endif 9071 9182 9072 9073 #ifdef CONFIG_ASH_GETOPTS 9183 #if ENABLE_ASH_GETOPTS 9074 9184 static int 9075 9185 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff) … … 9082 9192 char **optnext; 9083 9193 9084 if (*param_optind < 1)9194 if (*param_optind < 1) 9085 9195 return 1; 9086 9196 optnext = optfirst + *param_optind - 1; … … 9094 9204 p = *optnext; 9095 9205 if (p == NULL || *p != '-' || *++p == '\0') { 9096 atend:9206 atend: 9097 9207 p = NULL; 9098 9208 done = 1; … … 9100 9210 } 9101 9211 optnext++; 9102 if ( p[0] == '-' && p[1] == '\0') /* check for "--" */9212 if (LONE_DASH(p)) /* check for "--" */ 9103 9213 goto atend; 9104 9214 } … … 9113 9223 } else { 9114 9224 fprintf(stderr, "Illegal option -%c\n", c); 9115 (void)unsetvar("OPTARG");9225 unsetvar("OPTARG"); 9116 9226 } 9117 9227 c = '?'; … … 9131 9241 } else { 9132 9242 fprintf(stderr, "No arg for -%c option\n", c); 9133 (void)unsetvar("OPTARG");9243 unsetvar("OPTARG"); 9134 9244 c = '?'; 9135 9245 } … … 9143 9253 } else 9144 9254 err |= setvarsafe("OPTARG", nullstr, 0); 9145 9146 out: 9255 out: 9147 9256 *optoff = p ? p - *(optnext - 1) : -1; 9148 9257 *param_optind = optnext - optfirst + 1; … … 9155 9264 *param_optind = 1; 9156 9265 *optoff = -1; 9157 flush all();9158 exraise(EXERROR);9266 flush_stdout_stderr(); 9267 raise_exception(EXERROR); 9159 9268 } 9160 9269 return done; … … 9167 9276 * then it's the first time getopts has been called. 9168 9277 */ 9169 9170 int 9278 static int 9171 9279 getoptscmd(int argc, char **argv) 9172 9280 { … … 9174 9282 9175 9283 if (argc < 3) 9176 sh_error("Usage: getopts optstring var [arg]");9177 elseif (argc == 3) {9284 ash_msg_and_raise_error("usage: getopts optstring var [arg]"); 9285 if (argc == 3) { 9178 9286 optbase = shellparam.p; 9179 9287 if (shellparam.optind > shellparam.nparam + 1) { … … 9181 9289 shellparam.optoff = -1; 9182 9290 } 9183 } 9184 else { 9291 } else { 9185 9292 optbase = &argv[3]; 9186 9293 if (shellparam.optind > argc - 2) { … … 9191 9298 9192 9299 return getopts(argv[1], argv[2], optbase, &shellparam.optind, 9193 &shellparam.optoff); 9194 } 9195 #endif /* CONFIG_ASH_GETOPTS */ 9196 9197 /* 9198 * XXX - should get rid of. have all builtins use getopt(3). the 9199 * library getopt must have the BSD extension static variable "optreset" 9200 * otherwise it can't be used within the shell safely. 9201 * 9202 * Standard option processing (a la getopt) for builtin routines. The 9203 * only argument that is passed to nextopt is the option string; the 9204 * other arguments are unnecessary. It return the character, or '\0' on 9205 * end of input. 9206 */ 9207 9208 static int 9209 nextopt(const char *optstring) 9210 { 9211 char *p; 9212 const char *q; 9213 char c; 9214 9215 if ((p = optptr) == NULL || *p == '\0') { 9216 p = *argptr; 9217 if (p == NULL || *p != '-' || *++p == '\0') 9218 return '\0'; 9219 argptr++; 9220 if (p[0] == '-' && p[1] == '\0') /* check for "--" */ 9221 return '\0'; 9222 } 9223 c = *p++; 9224 for (q = optstring ; *q != c ; ) { 9225 if (*q == '\0') 9226 sh_error("Illegal option -%c", c); 9227 if (*++q == ':') 9228 q++; 9229 } 9230 if (*++q == ':') { 9231 if (*p == '\0' && (p = *argptr++) == NULL) 9232 sh_error("No arg for -%c option", c); 9233 optionarg = p; 9234 p = NULL; 9235 } 9236 optptr = p; 9237 return c; 9238 } 9239 9240 9241 /* output.c */ 9242 9243 void 9244 outstr(const char *p, FILE *file) 9245 { 9246 INTOFF; 9247 fputs(p, file); 9248 INTON; 9249 } 9250 9251 void 9252 flushall(void) 9253 { 9254 INTOFF; 9255 fflush(stdout); 9256 fflush(stderr); 9257 INTON; 9258 } 9259 9260 void 9261 flusherr(void) 9262 { 9263 INTOFF; 9264 fflush(stderr); 9265 INTON; 9266 } 9267 9268 static void 9269 outcslow(int c, FILE *dest) 9270 { 9271 INTOFF; 9272 putc(c, dest); 9273 fflush(dest); 9274 INTON; 9275 } 9276 9277 9278 static int 9279 out1fmt(const char *fmt, ...) 9280 { 9281 va_list ap; 9282 int r; 9283 9284 INTOFF; 9285 va_start(ap, fmt); 9286 r = vprintf(fmt, ap); 9287 va_end(ap); 9288 INTON; 9289 return r; 9290 } 9291 9292 9293 int 9294 fmtstr(char *outbuf, size_t length, const char *fmt, ...) 9295 { 9296 va_list ap; 9297 int ret; 9298 9299 va_start(ap, fmt); 9300 INTOFF; 9301 ret = vsnprintf(outbuf, length, fmt, ap); 9302 va_end(ap); 9303 INTON; 9304 return ret; 9305 } 9306 9307 9308 9309 /* parser.c */ 9310 9311 9312 /* 9313 * Shell command parser. 9314 */ 9300 &shellparam.optoff); 9301 } 9302 #endif /* ASH_GETOPTS */ 9303 9304 9305 /* ============ Shell parser */ 9306 9307 static int tokpushback; /* last token pushed back */ 9308 #define NEOF ((union node *)&tokpushback) 9309 static int parsebackquote; /* nonzero if we are inside backquotes */ 9310 static int lasttoken; /* last token read */ 9311 static char *wordtext; /* text of last word returned by readtoken */ 9312 static struct nodelist *backquotelist; 9313 static union node *redirnode; 9314 static struct heredoc *heredoc; 9315 static int quoteflag; /* set if (part of) last token was quoted */ 9316 9317 static void raise_error_syntax(const char *) ATTRIBUTE_NORETURN; 9318 static void 9319 raise_error_syntax(const char *msg) 9320 { 9321 ash_msg_and_raise_error("syntax error: %s", msg); 9322 /* NOTREACHED */ 9323 } 9324 9325 /* 9326 * Called when an unexpected token is read during the parse. The argument 9327 * is the token that is expected, or -1 if more than one type of token can 9328 * occur at this point. 9329 */ 9330 static void raise_error_unexpected_syntax(int) ATTRIBUTE_NORETURN; 9331 static void 9332 raise_error_unexpected_syntax(int token) 9333 { 9334 char msg[64]; 9335 int l; 9336 9337 l = sprintf(msg, "%s unexpected", tokname(lasttoken)); 9338 if (token >= 0) 9339 sprintf(msg + l, " (expecting %s)", tokname(token)); 9340 raise_error_syntax(msg); 9341 /* NOTREACHED */ 9342 } 9315 9343 9316 9344 #define EOFMARKLEN 79 9317 9318 9345 9319 9346 struct heredoc { … … 9324 9351 }; 9325 9352 9326 9327 9328 9353 static struct heredoc *heredoclist; /* list of here documents to read */ 9329 9354 9330 9331 static union node *list(int); 9355 /* parsing is heavily cross-recursive, need these forward decls */ 9332 9356 static union node *andor(void); 9333 9357 static union node *pipeline(void); 9334 static union node *command(void); 9335 static union node *simplecmd(void); 9336 static union node *makename(void); 9337 static void parsefname(void); 9358 static union node *parse_command(void); 9338 9359 static void parseheredoc(void); 9339 9360 static char peektoken(void); 9340 9361 static int readtoken(void); 9341 static int xxreadtoken(void);9342 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);9343 static int noexpand(char *);9344 static void synexpect(int) ATTRIBUTE_NORETURN;9345 static void synerror(const char *) ATTRIBUTE_NORETURN;9346 static void setprompt(int);9347 9348 9349 9350 9351 /*9352 * Read and parse a command. Returns NEOF on end of file. (NULL is a9353 * valid parse tree indicating a blank line.)9354 */9355 9356 union node *9357 parsecmd(int interact)9358 {9359 int t;9360 9361 tokpushback = 0;9362 doprompt = interact;9363 if (doprompt)9364 setprompt(doprompt);9365 needprompt = 0;9366 t = readtoken();9367 if (t == TEOF)9368 return NEOF;9369 if (t == TNL)9370 return NULL;9371 tokpushback++;9372 return list(1);9373 }9374 9375 9362 9376 9363 static union node * … … 9402 9389 if (n1 == NULL) { 9403 9390 n1 = n2; 9404 } 9405 else { 9406 n3 = (union node *)stalloc(sizeof (struct nbinary)); 9391 } else { 9392 n3 = stalloc(sizeof(struct nbinary)); 9407 9393 n3->type = NSEMI; 9408 9394 n3->nbinary.ch1 = n1; … … 9435 9421 default: 9436 9422 if (nlflag == 1) 9437 synexpect(-1);9423 raise_error_unexpected_syntax(-1); 9438 9424 tokpushback++; 9439 9425 return n1; … … 9442 9428 } 9443 9429 9444 9445 9446 9430 static union node * 9447 9431 andor(void) … … 9452 9436 n1 = pipeline(); 9453 9437 for (;;) { 9454 if ((t = readtoken()) == TAND) { 9438 t = readtoken(); 9439 if (t == TAND) { 9455 9440 t = NAND; 9456 9441 } else if (t == TOR) { … … 9462 9447 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9463 9448 n2 = pipeline(); 9464 n3 = (union node *)stalloc(sizeof(struct nbinary));9449 n3 = stalloc(sizeof(struct nbinary)); 9465 9450 n3->type = t; 9466 9451 n3->nbinary.ch1 = n1; … … 9469 9454 } 9470 9455 } 9471 9472 9473 9456 9474 9457 static union node * … … 9486 9469 } else 9487 9470 tokpushback++; 9488 n1 = command();9471 n1 = parse_command(); 9489 9472 if (readtoken() == TPIPE) { 9490 pipenode = (union node *)stalloc(sizeof(struct npipe));9473 pipenode = stalloc(sizeof(struct npipe)); 9491 9474 pipenode->type = NPIPE; 9492 9475 pipenode->npipe.backgnd = 0; 9493 lp = (struct nodelist *)stalloc(sizeof(struct nodelist));9476 lp = stalloc(sizeof(struct nodelist)); 9494 9477 pipenode->npipe.cmdlist = lp; 9495 9478 lp->n = n1; 9496 9479 do { 9497 9480 prev = lp; 9498 lp = (struct nodelist *)stalloc(sizeof(struct nodelist));9481 lp = stalloc(sizeof(struct nodelist)); 9499 9482 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9500 lp->n = command();9483 lp->n = parse_command(); 9501 9484 prev->next = lp; 9502 9485 } while (readtoken() == TPIPE); … … 9506 9489 tokpushback++; 9507 9490 if (negate) { 9508 n2 = (union node *)stalloc(sizeof(struct nnot));9491 n2 = stalloc(sizeof(struct nnot)); 9509 9492 n2->type = NNOT; 9510 9493 n2->nnot.com = n1; 9511 9494 return n2; 9512 } else 9513 return n1; 9514 } 9515 9516 9495 } 9496 return n1; 9497 } 9517 9498 9518 9499 static union node * 9519 command(void) 9520 { 9521 union node *n1, *n2; 9522 union node *ap, **app; 9523 union node *cp, **cpp; 9524 union node *redir, **rpp; 9525 union node **rpp2; 9526 int t; 9527 9528 redir = NULL; 9529 rpp2 = &redir; 9530 9531 switch (readtoken()) { 9532 default: 9533 synexpect(-1); 9534 /* NOTREACHED */ 9535 case TIF: 9536 n1 = (union node *)stalloc(sizeof (struct nif)); 9537 n1->type = NIF; 9538 n1->nif.test = list(0); 9539 if (readtoken() != TTHEN) 9540 synexpect(TTHEN); 9541 n1->nif.ifpart = list(0); 9542 n2 = n1; 9543 while (readtoken() == TELIF) { 9544 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); 9545 n2 = n2->nif.elsepart; 9546 n2->type = NIF; 9547 n2->nif.test = list(0); 9548 if (readtoken() != TTHEN) 9549 synexpect(TTHEN); 9550 n2->nif.ifpart = list(0); 9551 } 9552 if (lasttoken == TELSE) 9553 n2->nif.elsepart = list(0); 9500 makename(void) 9501 { 9502 union node *n; 9503 9504 n = stalloc(sizeof(struct narg)); 9505 n->type = NARG; 9506 n->narg.next = NULL; 9507 n->narg.text = wordtext; 9508 n->narg.backquote = backquotelist; 9509 return n; 9510 } 9511 9512 static void 9513 fixredir(union node *n, const char *text, int err) 9514 { 9515 TRACE(("Fix redir %s %d\n", text, err)); 9516 if (!err) 9517 n->ndup.vname = NULL; 9518 9519 if (isdigit(text[0]) && text[1] == '\0') 9520 n->ndup.dupfd = text[0] - '0'; 9521 else if (LONE_DASH(text)) 9522 n->ndup.dupfd = -1; 9523 else { 9524 if (err) 9525 raise_error_syntax("Bad fd number"); 9526 n->ndup.vname = makename(); 9527 } 9528 } 9529 9530 /* 9531 * Returns true if the text contains nothing to expand (no dollar signs 9532 * or backquotes). 9533 */ 9534 static int 9535 noexpand(char *text) 9536 { 9537 char *p; 9538 char c; 9539 9540 p = text; 9541 while ((c = *p++) != '\0') { 9542 if (c == CTLQUOTEMARK) 9543 continue; 9544 if (c == CTLESC) 9545 p++; 9546 else if (SIT(c, BASESYNTAX) == CCTL) 9547 return 0; 9548 } 9549 return 1; 9550 } 9551 9552 static void 9553 parsefname(void) 9554 { 9555 union node *n = redirnode; 9556 9557 if (readtoken() != TWORD) 9558 raise_error_unexpected_syntax(-1); 9559 if (n->type == NHERE) { 9560 struct heredoc *here = heredoc; 9561 struct heredoc *p; 9562 int i; 9563 9564 if (quoteflag == 0) 9565 n->type = NXHERE; 9566 TRACE(("Here document %d\n", n->type)); 9567 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 9568 raise_error_syntax("Illegal eof marker for << redirection"); 9569 rmescapes(wordtext); 9570 here->eofmark = wordtext; 9571 here->next = NULL; 9572 if (heredoclist == NULL) 9573 heredoclist = here; 9554 9574 else { 9555 n2->nif.elsepart = NULL; 9556 tokpushback++; 9557 } 9558 t = TFI; 9559 break; 9560 case TWHILE: 9561 case TUNTIL: { 9562 int got; 9563 n1 = (union node *)stalloc(sizeof (struct nbinary)); 9564 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; 9565 n1->nbinary.ch1 = list(0); 9566 if ((got=readtoken()) != TDO) { 9567 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : "")); 9568 synexpect(TDO); 9569 } 9570 n1->nbinary.ch2 = list(0); 9571 t = TDONE; 9572 break; 9573 } 9574 case TFOR: 9575 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 9576 synerror("Bad for loop variable"); 9577 n1 = (union node *)stalloc(sizeof (struct nfor)); 9578 n1->type = NFOR; 9579 n1->nfor.var = wordtext; 9580 checkkwd = CHKKWD | CHKALIAS; 9581 if (readtoken() == TIN) { 9582 app = ≈ 9583 while (readtoken() == TWORD) { 9584 n2 = (union node *)stalloc(sizeof (struct narg)); 9585 n2->type = NARG; 9586 n2->narg.text = wordtext; 9587 n2->narg.backquote = backquotelist; 9588 *app = n2; 9589 app = &n2->narg.next; 9590 } 9591 *app = NULL; 9592 n1->nfor.args = ap; 9593 if (lasttoken != TNL && lasttoken != TSEMI) 9594 synexpect(-1); 9595 } else { 9596 n2 = (union node *)stalloc(sizeof (struct narg)); 9597 n2->type = NARG; 9598 n2->narg.text = (char *)dolatstr; 9599 n2->narg.backquote = NULL; 9600 n2->narg.next = NULL; 9601 n1->nfor.args = n2; 9602 /* 9603 * Newline or semicolon here is optional (but note 9604 * that the original Bourne shell only allowed NL). 9605 */ 9606 if (lasttoken != TNL && lasttoken != TSEMI) 9607 tokpushback++; 9608 } 9609 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9610 if (readtoken() != TDO) 9611 synexpect(TDO); 9612 n1->nfor.body = list(0); 9613 t = TDONE; 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 = CHKKWD | CHKALIAS; 9627 } while (readtoken() == TNL); 9628 if (lasttoken != TIN) 9629 synexpect(TIN); 9630 cpp = &n1->ncase.cases; 9631 next_case: 9632 checkkwd = CHKNL | CHKKWD; 9633 t = readtoken(); 9634 while(t != TESAC) { 9635 if (lasttoken == TLP) 9636 readtoken(); 9637 *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); 9638 cp->type = NCLIST; 9639 app = &cp->nclist.pattern; 9640 for (;;) { 9641 *app = ap = (union node *)stalloc(sizeof (struct narg)); 9642 ap->type = NARG; 9643 ap->narg.text = wordtext; 9644 ap->narg.backquote = backquotelist; 9645 if (readtoken() != TPIPE) 9646 break; 9647 app = &ap->narg.next; 9648 readtoken(); 9649 } 9650 ap->narg.next = NULL; 9651 if (lasttoken != TRP) 9652 synexpect(TRP); 9653 cp->nclist.body = list(2); 9654 9655 cpp = &cp->nclist.next; 9656 9657 checkkwd = CHKNL | CHKKWD; 9658 if ((t = readtoken()) != TESAC) { 9659 if (t != TENDCASE) 9660 synexpect(TENDCASE); 9661 else 9662 goto next_case; 9663 } 9664 } 9665 *cpp = NULL; 9666 goto redir; 9667 case TLP: 9668 n1 = (union node *)stalloc(sizeof (struct nredir)); 9669 n1->type = NSUBSHELL; 9670 n1->nredir.n = list(0); 9671 n1->nredir.redirect = NULL; 9672 t = TRP; 9673 break; 9674 case TBEGIN: 9675 n1 = list(0); 9676 t = TEND; 9677 break; 9678 case TWORD: 9679 case TREDIR: 9680 tokpushback++; 9681 return simplecmd(); 9682 } 9683 9684 if (readtoken() != t) 9685 synexpect(t); 9686 9687 redir: 9688 /* Now check for redirection which may follow command */ 9689 checkkwd = CHKKWD | CHKALIAS; 9690 rpp = rpp2; 9691 while (readtoken() == TREDIR) { 9692 *rpp = n2 = redirnode; 9693 rpp = &n2->nfile.next; 9694 parsefname(); 9695 } 9696 tokpushback++; 9697 *rpp = NULL; 9698 if (redir) { 9699 if (n1->type != NSUBSHELL) { 9700 n2 = (union node *)stalloc(sizeof (struct nredir)); 9701 n2->type = NREDIR; 9702 n2->nredir.n = n1; 9703 n1 = n2; 9704 } 9705 n1->nredir.redirect = redir; 9706 } 9707 9708 return n1; 9709 } 9710 9575 for (p = heredoclist; p->next; p = p->next); 9576 p->next = here; 9577 } 9578 } else if (n->type == NTOFD || n->type == NFROMFD) { 9579 fixredir(n, wordtext, 0); 9580 } else { 9581 n->nfile.fname = makename(); 9582 } 9583 } 9711 9584 9712 9585 static union node * 9713 simplecmd(void) { 9586 simplecmd(void) 9587 { 9714 9588 union node *args, **app; 9715 9589 union node *n = NULL; … … 9730 9604 switch (readtoken()) { 9731 9605 case TWORD: 9732 n = (union node *)stalloc(sizeof(struct narg));9606 n = stalloc(sizeof(struct narg)); 9733 9607 n->type = NARG; 9734 9608 n->narg.text = wordtext; … … 9749 9623 break; 9750 9624 case TLP: 9751 if ( 9752 args && app == &args->narg.next && 9753 !vars && !redir 9625 if (args && app == &args->narg.next 9626 && !vars && !redir 9754 9627 ) { 9755 9628 struct builtincmd *bcmd; … … 9758 9631 /* We have a function */ 9759 9632 if (readtoken() != TRP) 9760 synexpect(TRP);9633 raise_error_unexpected_syntax(TRP); 9761 9634 name = n->narg.text; 9762 if ( 9763 !goodname(name) || ( 9764 (bcmd = find_builtin(name)) && 9765 IS_BUILTIN_SPECIAL(bcmd) 9766 ) 9767 ) 9768 synerror("Bad function name"); 9635 if (!goodname(name) 9636 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd)) 9637 ) { 9638 raise_error_syntax("Bad function name"); 9639 } 9769 9640 n->type = NDEFUN; 9770 9641 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9771 n->narg.next = command();9642 n->narg.next = parse_command(); 9772 9643 return n; 9773 9644 } … … 9778 9649 } 9779 9650 } 9780 out:9651 out: 9781 9652 *app = NULL; 9782 9653 *vpp = NULL; 9783 9654 *rpp = NULL; 9784 n = (union node *)stalloc(sizeof(struct ncmd));9655 n = stalloc(sizeof(struct ncmd)); 9785 9656 n->type = NCMD; 9786 9657 n->ncmd.args = args; … … 9791 9662 9792 9663 static union node * 9793 makename(void) 9794 { 9795 union node *n; 9796 9797 n = (union node *)stalloc(sizeof (struct narg)); 9798 n->type = NARG; 9799 n->narg.next = NULL; 9800 n->narg.text = wordtext; 9801 n->narg.backquote = backquotelist; 9802 return n; 9803 } 9804 9805 void fixredir(union node *n, const char *text, int err) 9806 { 9807 TRACE(("Fix redir %s %d\n", text, err)); 9808 if (!err) 9809 n->ndup.vname = NULL; 9810 9811 if (is_digit(text[0]) && text[1] == '\0') 9812 n->ndup.dupfd = digit_val(text[0]); 9813 else if (text[0] == '-' && text[1] == '\0') 9814 n->ndup.dupfd = -1; 9815 else { 9816 9817 if (err) 9818 synerror("Bad fd number"); 9819 else 9820 n->ndup.vname = makename(); 9821 } 9822 } 9823 9824 9825 static void 9826 parsefname(void) 9827 { 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 (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 9841 synerror("Illegal eof marker for << redirection"); 9842 rmescapes(wordtext); 9843 here->eofmark = wordtext; 9844 here->next = NULL; 9845 if (heredoclist == NULL) 9846 heredoclist = here; 9664 parse_command(void) 9665 { 9666 union node *n1, *n2; 9667 union node *ap, **app; 9668 union node *cp, **cpp; 9669 union node *redir, **rpp; 9670 union node **rpp2; 9671 int t; 9672 9673 redir = NULL; 9674 rpp2 = &redir; 9675 9676 switch (readtoken()) { 9677 default: 9678 raise_error_unexpected_syntax(-1); 9679 /* NOTREACHED */ 9680 case TIF: 9681 n1 = stalloc(sizeof(struct nif)); 9682 n1->type = NIF; 9683 n1->nif.test = list(0); 9684 if (readtoken() != TTHEN) 9685 raise_error_unexpected_syntax(TTHEN); 9686 n1->nif.ifpart = list(0); 9687 n2 = n1; 9688 while (readtoken() == TELIF) { 9689 n2->nif.elsepart = stalloc(sizeof(struct nif)); 9690 n2 = n2->nif.elsepart; 9691 n2->type = NIF; 9692 n2->nif.test = list(0); 9693 if (readtoken() != TTHEN) 9694 raise_error_unexpected_syntax(TTHEN); 9695 n2->nif.ifpart = list(0); 9696 } 9697 if (lasttoken == TELSE) 9698 n2->nif.elsepart = list(0); 9847 9699 else { 9848 for (p = heredoclist ; p->next ; p = p->next); 9849 p->next = here; 9850 } 9851 } else if (n->type == NTOFD || n->type == NFROMFD) { 9852 fixredir(n, wordtext, 0); 9853 } else { 9854 n->nfile.fname = makename(); 9855 } 9856 } 9857 9858 9859 /* 9860 * Input any here documents. 9861 */ 9862 9863 static void 9864 parseheredoc(void) 9865 { 9866 struct heredoc *here; 9867 union node *n; 9868 9869 here = heredoclist; 9870 heredoclist = 0; 9871 9872 while (here) { 9873 if (needprompt) { 9874 setprompt(2); 9875 } 9876 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 9877 here->eofmark, here->striptabs); 9878 n = (union node *)stalloc(sizeof (struct narg)); 9879 n->narg.type = NARG; 9880 n->narg.next = NULL; 9881 n->narg.text = wordtext; 9882 n->narg.backquote = backquotelist; 9883 here->here->nhere.doc = n; 9884 here = here->next; 9885 } 9886 } 9887 9888 static char peektoken(void) 9889 { 9890 int t; 9891 9892 t = readtoken(); 9700 n2->nif.elsepart = NULL; 9701 tokpushback++; 9702 } 9703 t = TFI; 9704 break; 9705 case TWHILE: 9706 case TUNTIL: { 9707 int got; 9708 n1 = stalloc(sizeof(struct nbinary)); 9709 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL; 9710 n1->nbinary.ch1 = list(0); 9711 got = readtoken(); 9712 if (got != TDO) { 9713 TRACE(("expecting DO got %s %s\n", tokname(got), 9714 got == TWORD ? wordtext : "")); 9715 raise_error_unexpected_syntax(TDO); 9716 } 9717 n1->nbinary.ch2 = list(0); 9718 t = TDONE; 9719 break; 9720 } 9721 case TFOR: 9722 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 9723 raise_error_syntax("Bad for loop variable"); 9724 n1 = stalloc(sizeof(struct nfor)); 9725 n1->type = NFOR; 9726 n1->nfor.var = wordtext; 9727 checkkwd = CHKKWD | CHKALIAS; 9728 if (readtoken() == TIN) { 9729 app = ≈ 9730 while (readtoken() == TWORD) { 9731 n2 = stalloc(sizeof(struct narg)); 9732 n2->type = NARG; 9733 n2->narg.text = wordtext; 9734 n2->narg.backquote = backquotelist; 9735 *app = n2; 9736 app = &n2->narg.next; 9737 } 9738 *app = NULL; 9739 n1->nfor.args = ap; 9740 if (lasttoken != TNL && lasttoken != TSEMI) 9741 raise_error_unexpected_syntax(-1); 9742 } else { 9743 n2 = stalloc(sizeof(struct narg)); 9744 n2->type = NARG; 9745 n2->narg.text = (char *)dolatstr; 9746 n2->narg.backquote = NULL; 9747 n2->narg.next = NULL; 9748 n1->nfor.args = n2; 9749 /* 9750 * Newline or semicolon here is optional (but note 9751 * that the original Bourne shell only allowed NL). 9752 */ 9753 if (lasttoken != TNL && lasttoken != TSEMI) 9754 tokpushback++; 9755 } 9756 checkkwd = CHKNL | CHKKWD | CHKALIAS; 9757 if (readtoken() != TDO) 9758 raise_error_unexpected_syntax(TDO); 9759 n1->nfor.body = list(0); 9760 t = TDONE; 9761 break; 9762 case TCASE: 9763 n1 = stalloc(sizeof(struct ncase)); 9764 n1->type = NCASE; 9765 if (readtoken() != TWORD) 9766 raise_error_unexpected_syntax(TWORD); 9767 n1->ncase.expr = n2 = stalloc(sizeof(struct narg)); 9768 n2->type = NARG; 9769 n2->narg.text = wordtext; 9770 n2->narg.backquote = backquotelist; 9771 n2->narg.next = NULL; 9772 do { 9773 checkkwd = CHKKWD | CHKALIAS; 9774 } while (readtoken() == TNL); 9775 if (lasttoken != TIN) 9776 raise_error_unexpected_syntax(TIN); 9777 cpp = &n1->ncase.cases; 9778 next_case: 9779 checkkwd = CHKNL | CHKKWD; 9780 t = readtoken(); 9781 while (t != TESAC) { 9782 if (lasttoken == TLP) 9783 readtoken(); 9784 *cpp = cp = stalloc(sizeof(struct nclist)); 9785 cp->type = NCLIST; 9786 app = &cp->nclist.pattern; 9787 for (;;) { 9788 *app = ap = stalloc(sizeof(struct narg)); 9789 ap->type = NARG; 9790 ap->narg.text = wordtext; 9791 ap->narg.backquote = backquotelist; 9792 if (readtoken() != TPIPE) 9793 break; 9794 app = &ap->narg.next; 9795 readtoken(); 9796 } 9797 ap->narg.next = NULL; 9798 if (lasttoken != TRP) 9799 raise_error_unexpected_syntax(TRP); 9800 cp->nclist.body = list(2); 9801 9802 cpp = &cp->nclist.next; 9803 9804 checkkwd = CHKNL | CHKKWD; 9805 t = readtoken(); 9806 if (t != TESAC) { 9807 if (t != TENDCASE) 9808 raise_error_unexpected_syntax(TENDCASE); 9809 goto next_case; 9810 } 9811 } 9812 *cpp = NULL; 9813 goto redir; 9814 case TLP: 9815 n1 = stalloc(sizeof(struct nredir)); 9816 n1->type = NSUBSHELL; 9817 n1->nredir.n = list(0); 9818 n1->nredir.redirect = NULL; 9819 t = TRP; 9820 break; 9821 case TBEGIN: 9822 n1 = list(0); 9823 t = TEND; 9824 break; 9825 case TWORD: 9826 case TREDIR: 9827 tokpushback++; 9828 return simplecmd(); 9829 } 9830 9831 if (readtoken() != t) 9832 raise_error_unexpected_syntax(t); 9833 9834 redir: 9835 /* Now check for redirection which may follow command */ 9836 checkkwd = CHKKWD | CHKALIAS; 9837 rpp = rpp2; 9838 while (readtoken() == TREDIR) { 9839 *rpp = n2 = redirnode; 9840 rpp = &n2->nfile.next; 9841 parsefname(); 9842 } 9893 9843 tokpushback++; 9894 return tokname_array[t][0]; 9895 } 9896 9897 static int 9898 readtoken(void) 9899 { 9900 int t; 9901 #ifdef DEBUG 9902 int alreadyseen = tokpushback; 9903 #endif 9904 9905 #ifdef CONFIG_ASH_ALIAS 9906 top: 9907 #endif 9908 9909 t = xxreadtoken(); 9910 9911 /* 9912 * eat newlines 9913 */ 9914 if (checkkwd & CHKNL) { 9915 while (t == TNL) { 9916 parseheredoc(); 9917 t = xxreadtoken(); 9918 } 9919 } 9920 9921 if (t != TWORD || quoteflag) { 9922 goto out; 9923 } 9924 9925 /* 9926 * check for keywords 9927 */ 9928 if (checkkwd & CHKKWD) { 9929 const char *const *pp; 9930 9931 if ((pp = findkwd(wordtext))) { 9932 lasttoken = t = pp - tokname_array; 9933 TRACE(("keyword %s recognized\n", tokname(t))); 9934 goto out; 9935 } 9936 } 9937 9938 if (checkkwd & CHKALIAS) { 9939 #ifdef CONFIG_ASH_ALIAS 9940 struct alias *ap; 9941 if ((ap = lookupalias(wordtext, 1)) != NULL) { 9942 if (*ap->val) { 9943 pushstring(ap->val, ap); 9944 } 9945 goto top; 9946 } 9947 #endif 9948 } 9949 out: 9950 checkkwd = 0; 9951 #ifdef DEBUG 9952 if (!alreadyseen) 9953 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : "")); 9954 else 9955 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : "")); 9956 #endif 9957 return (t); 9958 } 9959 9960 9961 /* 9962 * Read the next input token. 9963 * If the token is a word, we set backquotelist to the list of cmds in 9964 * backquotes. We set quoteflag to true if any part of the word was 9965 * quoted. 9966 * If the token is TREDIR, then we set redirnode to a structure containing 9967 * the redirection. 9968 * In all cases, the variable startlinno is set to the number of the line 9969 * on which the token starts. 9970 * 9971 * [Change comment: here documents and internal procedures] 9972 * [Readtoken shouldn't have any arguments. Perhaps we should make the 9973 * word parsing code into a separate routine. In this case, readtoken 9974 * doesn't need to have any internal procedures, but parseword does. 9975 * We could also make parseoperator in essence the main routine, and 9976 * have parseword (readtoken1?) handle both words and redirection.] 9977 */ 9978 9979 #define NEW_xxreadtoken 9980 #ifdef NEW_xxreadtoken 9981 9982 /* singles must be first! */ 9983 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 }; 9984 9985 static const char xxreadtoken_tokens[] = { 9986 TNL, TLP, TRP, /* only single occurrence allowed */ 9987 TBACKGND, TPIPE, TSEMI, /* if single occurrence */ 9988 TEOF, /* corresponds to trailing nul */ 9989 TAND, TOR, TENDCASE, /* if double occurrence */ 9990 }; 9991 9992 #define xxreadtoken_doubles \ 9993 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars)) 9994 #define xxreadtoken_singles \ 9995 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1) 9996 9997 static int xxreadtoken(void) 9998 { 9999 int c; 10000 10001 if (tokpushback) { 10002 tokpushback = 0; 10003 return lasttoken; 10004 } 10005 if (needprompt) { 10006 setprompt(2); 10007 } 10008 startlinno = plinno; 10009 for (;;) { /* until token or start of word found */ 10010 c = pgetc_macro(); 10011 10012 if ((c != ' ') && (c != '\t') 10013 #ifdef CONFIG_ASH_ALIAS 10014 && (c != PEOA) 10015 #endif 10016 ) { 10017 if (c == '#') { 10018 while ((c = pgetc()) != '\n' && c != PEOF); 10019 pungetc(); 10020 } else if (c == '\\') { 10021 if (pgetc() != '\n') { 10022 pungetc(); 10023 goto READTOKEN1; 10024 } 10025 startlinno = ++plinno; 10026 if (doprompt) 10027 setprompt(2); 10028 } else { 10029 const char *p 10030 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1; 10031 10032 if (c != PEOF) { 10033 if (c == '\n') { 10034 plinno++; 10035 needprompt = doprompt; 10036 } 10037 10038 p = strchr(xxreadtoken_chars, c); 10039 if (p == NULL) { 10040 READTOKEN1: 10041 return readtoken1(c, BASESYNTAX, (char *) NULL, 0); 10042 } 10043 10044 if (p - xxreadtoken_chars >= xxreadtoken_singles) { 10045 if (pgetc() == *p) { /* double occurrence? */ 10046 p += xxreadtoken_doubles + 1; 10047 } else { 10048 pungetc(); 10049 } 10050 } 10051 } 10052 10053 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars]; 10054 } 10055 } 10056 } 10057 } 10058 10059 10060 #else 10061 #define RETURN(token) return lasttoken = token 10062 10063 static int 10064 xxreadtoken(void) 10065 { 10066 int c; 10067 10068 if (tokpushback) { 10069 tokpushback = 0; 10070 return lasttoken; 10071 } 10072 if (needprompt) { 10073 setprompt(2); 10074 } 10075 startlinno = plinno; 10076 for (;;) { /* until token or start of word found */ 10077 c = pgetc_macro(); 10078 switch (c) { 10079 case ' ': case '\t': 10080 #ifdef CONFIG_ASH_ALIAS 10081 case PEOA: 10082 #endif 10083 continue; 10084 case '#': 10085 while ((c = pgetc()) != '\n' && c != PEOF); 10086 pungetc(); 10087 continue; 10088 case '\\': 10089 if (pgetc() == '\n') { 10090 startlinno = ++plinno; 10091 if (doprompt) 10092 setprompt(2); 10093 continue; 10094 } 10095 pungetc(); 10096 goto breakloop; 10097 case '\n': 10098 plinno++; 10099 needprompt = doprompt; 10100 RETURN(TNL); 10101 case PEOF: 10102 RETURN(TEOF); 10103 case '&': 10104 if (pgetc() == '&') 10105 RETURN(TAND); 10106 pungetc(); 10107 RETURN(TBACKGND); 10108 case '|': 10109 if (pgetc() == '|') 10110 RETURN(TOR); 10111 pungetc(); 10112 RETURN(TPIPE); 10113 case ';': 10114 if (pgetc() == ';') 10115 RETURN(TENDCASE); 10116 pungetc(); 10117 RETURN(TSEMI); 10118 case '(': 10119 RETURN(TLP); 10120 case ')': 10121 RETURN(TRP); 10122 default: 10123 goto breakloop; 10124 } 10125 } 10126 breakloop: 10127 return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 10128 #undef RETURN 10129 } 10130 #endif /* NEW_xxreadtoken */ 10131 9844 *rpp = NULL; 9845 if (redir) { 9846 if (n1->type != NSUBSHELL) { 9847 n2 = stalloc(sizeof(struct nredir)); 9848 n2->type = NREDIR; 9849 n2->nredir.n = n1; 9850 n1 = n2; 9851 } 9852 n1->nredir.redirect = redir; 9853 } 9854 return n1; 9855 } 10132 9856 10133 9857 /* … … 10142 9866 * will run code that appears at the end of readtoken1. 10143 9867 */ 9868 9869 static int parsebackquote; /* nonzero if we are inside backquotes */ 10144 9870 10145 9871 #define CHECKEND() {goto checkend; checkend_return:;} … … 10196 9922 for (;;) { /* until end of line or end of word */ 10197 9923 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ 10198 switch (SIT(c, syntax)) {9924 switch (SIT(c, syntax)) { 10199 9925 case CNL: /* '\n' */ 10200 9926 if (syntax == BASESYNTAX) … … 10241 9967 case CSQUOTE: 10242 9968 syntax = SQSYNTAX; 10243 quotemark:9969 quotemark: 10244 9970 if (eofmark == NULL) { 10245 9971 USTPUTC(CTLQUOTEMARK, out); … … 10251 9977 goto quotemark; 10252 9978 case CENDQUOTE: 10253 if (eofmark != NULL && arinest == 0 && 10254 varnest == 0) { 9979 if (eofmark != NULL && arinest == 0 9980 && varnest == 0 9981 ) { 10255 9982 USTPUTC(c, out); 10256 9983 } else { … … 10277 10004 } 10278 10005 break; 10279 #if def CONFIG_ASH_MATH_SUPPORT10006 #if ENABLE_ASH_MATH_SUPPORT 10280 10007 case CLP: /* '(' in arithmetic */ 10281 10008 parenlevel++; … … 10318 10045 if (varnest == 0) 10319 10046 goto endword; /* exit outer loop */ 10320 #if def CONFIG_ASH_ALIAS10047 #if ENABLE_ASH_ALIAS 10321 10048 if (c != PEOA) 10322 10049 #endif … … 10327 10054 } 10328 10055 } 10329 endword:10330 #if def CONFIG_ASH_MATH_SUPPORT10056 endword: 10057 #if ENABLE_ASH_MATH_SUPPORT 10331 10058 if (syntax == ARISYNTAX) 10332 synerror("Missing '))'");10333 #endif 10334 if (syntax != BASESYNTAX && ! 10335 synerror("Unterminated quoted string");10059 raise_error_syntax("Missing '))'"); 10060 #endif 10061 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL) 10062 raise_error_syntax("Unterminated quoted string"); 10336 10063 if (varnest != 0) { 10337 10064 startlinno = plinno; 10338 10065 /* { */ 10339 synerror("Missing '}'");10066 raise_error_syntax("Missing '}'"); 10340 10067 } 10341 10068 USTPUTC('\0', out); … … 10346 10073 && quotef == 0 10347 10074 && len <= 2 10348 && (*out == '\0' || is _digit(*out))) {10075 && (*out == '\0' || isdigit(*out))) { 10349 10076 PARSEREDIR(); 10350 10077 return lasttoken = TREDIR; … … 10357 10084 grabstackblock(len); 10358 10085 wordtext = out; 10359 return lasttoken = TWORD; 10086 lasttoken = TWORD; 10087 return lasttoken; 10360 10088 /* end of readtoken routine */ 10361 10362 10363 10089 10364 10090 /* … … 10367 10093 * we are at the end of the here document, this routine sets the c to PEOF. 10368 10094 */ 10369 10370 10095 checkend: { 10371 10096 if (eofmark) { 10372 #if def CONFIG_ASH_ALIAS10097 #if ENABLE_ASH_ALIAS 10373 10098 if (c == PEOA) { 10374 10099 c = pgetc2(); … … 10381 10106 } 10382 10107 if (c == *eofmark) { 10383 if (pfgets(line, sizeof line) != NULL) {10108 if (pfgets(line, sizeof(line)) != NULL) { 10384 10109 char *p, *q; 10385 10110 10386 10111 p = line; 10387 for (q = eofmark + 1 ; *q && *p == *q; p++, q++);10112 for (q = eofmark + 1; *q && *p == *q; p++, q++); 10388 10113 if (*p == '\n' && *q == '\0') { 10389 10114 c = PEOF; … … 10399 10124 } 10400 10125 10401 10402 10126 /* 10403 10127 * Parse a redirection operator. The variable "out" points to a string … … 10405 10129 * first character of the redirection operator. 10406 10130 */ 10407 10408 10131 parseredir: { 10409 10132 char fd = *out; 10410 10133 union node *np; 10411 10134 10412 np = (union node *)stalloc(sizeof(struct nfile));10135 np = stalloc(sizeof(struct nfile)); 10413 10136 if (c == '>') { 10414 10137 np->nfile.fd = 1; … … 10426 10149 } else { /* c == '<' */ 10427 10150 np->nfile.fd = 0; 10428 switch (c = pgetc()) { 10151 c = pgetc(); 10152 switch (c) { 10429 10153 case '<': 10430 if (sizeof (struct nfile) != sizeof(struct nhere)) {10431 np = (union node *)stalloc(sizeof(struct nhere));10154 if (sizeof(struct nfile) != sizeof(struct nhere)) { 10155 np = stalloc(sizeof(struct nhere)); 10432 10156 np->nfile.fd = 0; 10433 10157 } 10434 10158 np->type = NHERE; 10435 heredoc = (struct heredoc *)stalloc(sizeof(struct heredoc));10159 heredoc = stalloc(sizeof(struct heredoc)); 10436 10160 heredoc->here = np; 10437 if ((c = pgetc()) == '-') { 10161 c = pgetc(); 10162 if (c == '-') { 10438 10163 heredoc->striptabs = 1; 10439 10164 } else { … … 10458 10183 } 10459 10184 if (fd != '\0') 10460 np->nfile.fd = digit_val(fd);10185 np->nfile.fd = fd - '0'; 10461 10186 redirnode = np; 10462 10187 goto parseredir_return; 10463 10188 } 10464 10189 10465 10466 10190 /* 10467 10191 * Parse a substitution. At this point, we have read the dollar sign … … 10469 10193 */ 10470 10194 10195 /* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise 10196 * (assuming ascii char codes, as the original implementation did) */ 10197 #define is_special(c) \ 10198 ((((unsigned int)c) - 33 < 32) \ 10199 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1)) 10471 10200 parsesub: { 10472 10201 int subtype; … … 10474 10203 int flags; 10475 10204 char *p; 10476 static const char types[] = "}-+?=";10205 static const char types[] ALIGN1 = "}-+?="; 10477 10206 10478 10207 c = pgetc(); … … 10485 10214 } else if (c == '(') { /* $(command) or $((arith)) */ 10486 10215 if (pgetc() == '(') { 10487 #if def CONFIG_ASH_MATH_SUPPORT10216 #if ENABLE_ASH_MATH_SUPPORT 10488 10217 PARSEARITH(); 10489 10218 #else 10490 synerror("We unsupport $((arith))");10219 raise_error_syntax("We unsupport $((arith))"); 10491 10220 #endif 10492 10221 } else { … … 10502 10231 c = pgetc(); 10503 10232 if (c == '#') { 10504 if ((c = pgetc()) == '}') 10233 c = pgetc(); 10234 if (c == '}') 10505 10235 c = '#'; 10506 10236 else 10507 10237 subtype = VSLENGTH; 10508 } 10509 else 10238 } else 10510 10239 subtype = 0; 10511 10240 } … … 10515 10244 c = pgetc(); 10516 10245 } while (c > PEOA_OR_PEOF && is_in_name(c)); 10517 } else if (is _digit(c)) {10246 } else if (isdigit(c)) { 10518 10247 do { 10519 10248 STPUTC(c, out); 10520 10249 c = pgetc(); 10521 } while (is_digit(c)); 10522 } 10523 else if (is_special(c)) { 10250 } while (isdigit(c)); 10251 } else if (is_special(c)) { 10524 10252 USTPUTC(c, out); 10525 10253 c = pgetc(); 10526 } 10527 else 10528 badsub: synerror("Bad substitution"); 10254 } else 10255 badsub: raise_error_syntax("Bad substitution"); 10529 10256 10530 10257 STPUTC('=', out); … … 10547 10274 int cc = c; 10548 10275 subtype = c == '#' ? VSTRIMLEFT : 10549 10276 VSTRIMRIGHT; 10550 10277 c = pgetc(); 10551 10278 if (c == cc) … … 10572 10299 } 10573 10300 10574 10575 10301 /* 10576 10302 * Called to parse command substitutions. Newstyle is set if the command … … 10579 10305 * characters on the top of the stack which must be preserved. 10580 10306 */ 10581 10582 10307 parsebackq: { 10583 10308 struct nodelist **nlpp; … … 10596 10321 if (setjmp(jmploc.loc)) { 10597 10322 if (str) 10598 ckfree(str);10323 free(str); 10599 10324 parsebackquote = 0; 10600 handler = savehandler;10601 longjmp( handler->loc, 1);10602 } 10603 INT OFF;10325 exception_handler = savehandler; 10326 longjmp(exception_handler->loc, 1); 10327 } 10328 INT_OFF; 10604 10329 str = NULL; 10605 10330 savelen = out - (char *)stackblock(); … … 10608 10333 memcpy(str, stackblock(), savelen); 10609 10334 } 10610 savehandler = handler;10611 handler = &jmploc;10612 INT ON;10335 savehandler = exception_handler; 10336 exception_handler = &jmploc; 10337 INT_ON; 10613 10338 if (oldstyle) { 10614 10339 /* We must read until the closing backquote, giving special … … 10626 10351 setprompt(2); 10627 10352 } 10628 switch (pc = pgetc()) { 10353 pc = pgetc(); 10354 switch (pc) { 10629 10355 case '`': 10630 10356 goto done; 10631 10357 10632 10358 case '\\': 10633 if ((pc = pgetc()) == '\n') { 10359 pc = pgetc(); 10360 if (pc == '\n') { 10634 10361 plinno++; 10635 10362 if (doprompt) … … 10644 10371 } 10645 10372 if (pc != '\\' && pc != '`' && pc != '$' 10646 10373 && (!dblquote || pc != '"')) 10647 10374 STPUTC('\\', pout); 10648 10375 if (pc > PEOA_OR_PEOF) { … … 10652 10379 10653 10380 case PEOF: 10654 #if def CONFIG_ASH_ALIAS10381 #if ENABLE_ASH_ALIAS 10655 10382 case PEOA: 10656 10383 #endif 10657 10384 startlinno = plinno; 10658 synerror("EOF in backquote substitution");10385 raise_error_syntax("EOF in backquote substitution"); 10659 10386 10660 10387 case '\n': … … 10668 10395 STPUTC(pc, pout); 10669 10396 } 10670 done:10397 done: 10671 10398 STPUTC('\0', pout); 10672 10399 psavelen = pout - (char *)stackblock(); … … 10679 10406 while (*nlpp) 10680 10407 nlpp = &(*nlpp)->next; 10681 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));10408 *nlpp = stalloc(sizeof(**nlpp)); 10682 10409 (*nlpp)->next = NULL; 10683 10410 parsebackquote = oldstyle; … … 10692 10419 if (oldstyle) 10693 10420 doprompt = saveprompt; 10694 else { 10695 if (readtoken() != TRP) 10696 synexpect(TRP); 10697 } 10421 else if (readtoken() != TRP) 10422 raise_error_unexpected_syntax(TRP); 10698 10423 10699 10424 (*nlpp)->n = n; … … 10712 10437 memcpy(out, str, savelen); 10713 10438 STADJUST(savelen, out); 10714 INT OFF;10715 ckfree(str);10439 INT_OFF; 10440 free(str); 10716 10441 str = NULL; 10717 INT ON;10442 INT_ON; 10718 10443 } 10719 10444 parsebackquote = savepbq; 10720 handler = savehandler;10445 exception_handler = savehandler; 10721 10446 if (arinest || dblquote) 10722 10447 USTPUTC(CTLBACKQ | CTLQUOTE, out); … … 10725 10450 if (oldstyle) 10726 10451 goto parsebackq_oldreturn; 10727 else 10728 goto parsebackq_newreturn; 10729 } 10730 10731 #ifdef CONFIG_ASH_MATH_SUPPORT 10452 goto parsebackq_newreturn; 10453 } 10454 10455 #if ENABLE_ASH_MATH_SUPPORT 10732 10456 /* 10733 10457 * Parse an arithmetic expansion (indicate start of one and set state) 10734 10458 */ 10735 10459 parsearith: { 10736 10737 10460 if (++arinest == 1) { 10738 10461 prevsyntax = syntax; … … 10740 10463 USTPUTC(CTLARI, out); 10741 10464 if (dblquote) 10742 USTPUTC('"', out);10465 USTPUTC('"', out); 10743 10466 else 10744 USTPUTC(' ', out);10467 USTPUTC(' ', out); 10745 10468 } else { 10746 10469 /* … … 10756 10479 } /* end of readtoken */ 10757 10480 10758 10759 10760 /* 10761 * Returns true if the text contains nothing to expand (no dollar signs 10762 * or backquotes). 10763 */ 10481 /* 10482 * Read the next input token. 10483 * If the token is a word, we set backquotelist to the list of cmds in 10484 * backquotes. We set quoteflag to true if any part of the word was 10485 * quoted. 10486 * If the token is TREDIR, then we set redirnode to a structure containing 10487 * the redirection. 10488 * In all cases, the variable startlinno is set to the number of the line 10489 * on which the token starts. 10490 * 10491 * [Change comment: here documents and internal procedures] 10492 * [Readtoken shouldn't have any arguments. Perhaps we should make the 10493 * word parsing code into a separate routine. In this case, readtoken 10494 * doesn't need to have any internal procedures, but parseword does. 10495 * We could also make parseoperator in essence the main routine, and 10496 * have parseword (readtoken1?) handle both words and redirection.] 10497 */ 10498 #define NEW_xxreadtoken 10499 #ifdef NEW_xxreadtoken 10500 /* singles must be first! */ 10501 static const char xxreadtoken_chars[7] ALIGN1 = { 10502 '\n', '(', ')', '&', '|', ';', 0 10503 }; 10504 10505 static const char xxreadtoken_tokens[] ALIGN1 = { 10506 TNL, TLP, TRP, /* only single occurrence allowed */ 10507 TBACKGND, TPIPE, TSEMI, /* if single occurrence */ 10508 TEOF, /* corresponds to trailing nul */ 10509 TAND, TOR, TENDCASE /* if double occurrence */ 10510 }; 10511 10512 #define xxreadtoken_doubles \ 10513 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars)) 10514 #define xxreadtoken_singles \ 10515 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1) 10764 10516 10765 10517 static int 10766 noexpand(char *text) 10767 { 10768 char *p; 10769 char c; 10770 10771 p = text; 10772 while ((c = *p++) != '\0') { 10773 if (c == CTLQUOTEMARK) 10518 xxreadtoken(void) 10519 { 10520 int c; 10521 10522 if (tokpushback) { 10523 tokpushback = 0; 10524 return lasttoken; 10525 } 10526 if (needprompt) { 10527 setprompt(2); 10528 } 10529 startlinno = plinno; 10530 for (;;) { /* until token or start of word found */ 10531 c = pgetc_macro(); 10532 10533 if ((c != ' ') && (c != '\t') 10534 #if ENABLE_ASH_ALIAS 10535 && (c != PEOA) 10536 #endif 10537 ) { 10538 if (c == '#') { 10539 while ((c = pgetc()) != '\n' && c != PEOF); 10540 pungetc(); 10541 } else if (c == '\\') { 10542 if (pgetc() != '\n') { 10543 pungetc(); 10544 goto READTOKEN1; 10545 } 10546 startlinno = ++plinno; 10547 if (doprompt) 10548 setprompt(2); 10549 } else { 10550 const char *p 10551 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1; 10552 10553 if (c != PEOF) { 10554 if (c == '\n') { 10555 plinno++; 10556 needprompt = doprompt; 10557 } 10558 10559 p = strchr(xxreadtoken_chars, c); 10560 if (p == NULL) { 10561 READTOKEN1: 10562 return readtoken1(c, BASESYNTAX, (char *) NULL, 0); 10563 } 10564 10565 if (p - xxreadtoken_chars >= xxreadtoken_singles) { 10566 if (pgetc() == *p) { /* double occurrence? */ 10567 p += xxreadtoken_doubles + 1; 10568 } else { 10569 pungetc(); 10570 } 10571 } 10572 } 10573 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars]; 10574 } 10575 } 10576 } /* for */ 10577 } 10578 #else 10579 #define RETURN(token) return lasttoken = token 10580 static int 10581 xxreadtoken(void) 10582 { 10583 int c; 10584 10585 if (tokpushback) { 10586 tokpushback = 0; 10587 return lasttoken; 10588 } 10589 if (needprompt) { 10590 setprompt(2); 10591 } 10592 startlinno = plinno; 10593 for (;;) { /* until token or start of word found */ 10594 c = pgetc_macro(); 10595 switch (c) { 10596 case ' ': case '\t': 10597 #if ENABLE_ASH_ALIAS 10598 case PEOA: 10599 #endif 10774 10600 continue; 10775 if (c == CTLESC) 10776 p++; 10777 else if (SIT(c, BASESYNTAX) == CCTL) 10778 return 0; 10779 } 10780 return 1; 10781 } 10782 10783 10784 /* 10785 * Return of a legal variable name (a letter or underscore followed by zero or 10786 * more letters, underscores, and digits). 10787 */ 10788 10789 static char * 10790 endofname(const char *name) 10791 { 10792 char *p; 10793 10794 p = (char *) name; 10795 if (! is_name(*p)) 10796 return p; 10797 while (*++p) { 10798 if (! is_in_name(*p)) 10799 break; 10800 } 10801 return p; 10802 } 10803 10804 10805 /* 10806 * Called when an unexpected token is read during the parse. The argument 10807 * is the token that is expected, or -1 if more than one type of token can 10808 * occur at this point. 10809 */ 10810 10811 static void synexpect(int token) 10812 { 10813 char msg[64]; 10814 int l; 10815 10816 l = sprintf(msg, "%s unexpected", tokname(lasttoken)); 10817 if (token >= 0) 10818 sprintf(msg + l, " (expecting %s)", tokname(token)); 10819 synerror(msg); 10820 /* NOTREACHED */ 10821 } 10822 10823 static void 10824 synerror(const char *msg) 10825 { 10826 sh_error("Syntax error: %s", msg); 10827 /* NOTREACHED */ 10828 } 10829 10830 10831 /* 10832 * called by editline -- any expansions to the prompt 10833 * should be added here. 10834 */ 10835 10836 #ifdef CONFIG_ASH_EXPAND_PRMT 10601 case '#': 10602 while ((c = pgetc()) != '\n' && c != PEOF); 10603 pungetc(); 10604 continue; 10605 case '\\': 10606 if (pgetc() == '\n') { 10607 startlinno = ++plinno; 10608 if (doprompt) 10609 setprompt(2); 10610 continue; 10611 } 10612 pungetc(); 10613 goto breakloop; 10614 case '\n': 10615 plinno++; 10616 needprompt = doprompt; 10617 RETURN(TNL); 10618 case PEOF: 10619 RETURN(TEOF); 10620 case '&': 10621 if (pgetc() == '&') 10622 RETURN(TAND); 10623 pungetc(); 10624 RETURN(TBACKGND); 10625 case '|': 10626 if (pgetc() == '|') 10627 RETURN(TOR); 10628 pungetc(); 10629 RETURN(TPIPE); 10630 case ';': 10631 if (pgetc() == ';') 10632 RETURN(TENDCASE); 10633 pungetc(); 10634 RETURN(TSEMI); 10635 case '(': 10636 RETURN(TLP); 10637 case ')': 10638 RETURN(TRP); 10639 default: 10640 goto breakloop; 10641 } 10642 } 10643 breakloop: 10644 return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 10645 #undef RETURN 10646 } 10647 #endif /* NEW_xxreadtoken */ 10648 10649 static int 10650 readtoken(void) 10651 { 10652 int t; 10653 #if DEBUG 10654 int alreadyseen = tokpushback; 10655 #endif 10656 10657 #if ENABLE_ASH_ALIAS 10658 top: 10659 #endif 10660 10661 t = xxreadtoken(); 10662 10663 /* 10664 * eat newlines 10665 */ 10666 if (checkkwd & CHKNL) { 10667 while (t == TNL) { 10668 parseheredoc(); 10669 t = xxreadtoken(); 10670 } 10671 } 10672 10673 if (t != TWORD || quoteflag) { 10674 goto out; 10675 } 10676 10677 /* 10678 * check for keywords 10679 */ 10680 if (checkkwd & CHKKWD) { 10681 const char *const *pp; 10682 10683 pp = findkwd(wordtext); 10684 if (pp) { 10685 lasttoken = t = pp - tokname_array; 10686 TRACE(("keyword %s recognized\n", tokname(t))); 10687 goto out; 10688 } 10689 } 10690 10691 if (checkkwd & CHKALIAS) { 10692 #if ENABLE_ASH_ALIAS 10693 struct alias *ap; 10694 ap = lookupalias(wordtext, 1); 10695 if (ap != NULL) { 10696 if (*ap->val) { 10697 pushstring(ap->val, ap); 10698 } 10699 goto top; 10700 } 10701 #endif 10702 } 10703 out: 10704 checkkwd = 0; 10705 #if DEBUG 10706 if (!alreadyseen) 10707 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : "")); 10708 else 10709 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : "")); 10710 #endif 10711 return t; 10712 } 10713 10714 static char 10715 peektoken(void) 10716 { 10717 int t; 10718 10719 t = readtoken(); 10720 tokpushback++; 10721 return tokname_array[t][0]; 10722 } 10723 10724 /* 10725 * Read and parse a command. Returns NEOF on end of file. (NULL is a 10726 * valid parse tree indicating a blank line.) 10727 */ 10728 static union node * 10729 parsecmd(int interact) 10730 { 10731 int t; 10732 10733 tokpushback = 0; 10734 doprompt = interact; 10735 if (doprompt) 10736 setprompt(doprompt); 10737 needprompt = 0; 10738 t = readtoken(); 10739 if (t == TEOF) 10740 return NEOF; 10741 if (t == TNL) 10742 return NULL; 10743 tokpushback++; 10744 return list(1); 10745 } 10746 10747 /* 10748 * Input any here documents. 10749 */ 10750 static void 10751 parseheredoc(void) 10752 { 10753 struct heredoc *here; 10754 union node *n; 10755 10756 here = heredoclist; 10757 heredoclist = 0; 10758 10759 while (here) { 10760 if (needprompt) { 10761 setprompt(2); 10762 } 10763 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 10764 here->eofmark, here->striptabs); 10765 n = stalloc(sizeof(struct narg)); 10766 n->narg.type = NARG; 10767 n->narg.next = NULL; 10768 n->narg.text = wordtext; 10769 n->narg.backquote = backquotelist; 10770 here->here->nhere.doc = n; 10771 here = here->next; 10772 } 10773 } 10774 10775 10776 /* 10777 * called by editline -- any expansions to the prompt should be added here. 10778 */ 10779 #if ENABLE_ASH_EXPAND_PRMT 10837 10780 static const char * 10838 10781 expandstr(const char *ps) … … 10855 10798 #endif 10856 10799 10857 static void setprompt(int whichprompt) 10858 { 10859 const char *prompt; 10860 #ifdef CONFIG_ASH_EXPAND_PRMT 10800 /* 10801 * Execute a command or commands contained in a string. 10802 */ 10803 static int 10804 evalstring(char *s, int mask) 10805 { 10806 union node *n; 10861 10807 struct stackmark smark; 10862 #endif 10863 10864 needprompt = 0; 10865 10866 switch (whichprompt) { 10867 case 1: 10868 prompt = ps1val(); 10869 break; 10870 case 2: 10871 prompt = ps2val(); 10872 break; 10873 default: /* 0 */ 10874 prompt = nullstr; 10875 } 10876 #ifdef CONFIG_ASH_EXPAND_PRMT 10808 int skip; 10809 10810 setinputstring(s); 10877 10811 setstackmark(&smark); 10878 stalloc(stackblocksize()); 10879 #endif 10880 putprompt(expandstr(prompt)); 10881 #ifdef CONFIG_ASH_EXPAND_PRMT 10882 popstackmark(&smark); 10883 #endif 10884 } 10885 10886 10887 static const char *const *findkwd(const char *s) 10888 { 10889 return bsearch(s, tokname_array + KWDOFFSET, 10890 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET, 10891 sizeof(const char *), pstrcmp); 10892 } 10893 10894 /* redir.c */ 10895 10896 /* 10897 * Code for dealing with input/output redirection. 10898 */ 10899 10900 #define EMPTY -2 /* marks an unused slot in redirtab */ 10901 #ifndef PIPE_BUF 10902 # define PIPESIZE 4096 /* amount of buffering in a pipe */ 10903 #else 10904 # define PIPESIZE PIPE_BUF 10905 #endif 10906 10907 /* 10908 * Open a file in noclobber mode. 10909 * The code was copied from bash. 10910 */ 10911 static inline int 10912 noclobberopen(const char *fname) 10913 { 10914 int r, fd; 10915 struct stat finfo, finfo2; 10916 10917 /* 10918 * If the file exists and is a regular file, return an error 10919 * immediately. 10920 */ 10921 r = stat(fname, &finfo); 10922 if (r == 0 && S_ISREG(finfo.st_mode)) { 10923 errno = EEXIST; 10924 return -1; 10925 } 10926 10927 /* 10928 * If the file was not present (r != 0), make sure we open it 10929 * exclusively so that if it is created before we open it, our open 10930 * will fail. Make sure that we do not truncate an existing file. 10931 * Note that we don't turn on O_EXCL unless the stat failed -- if the 10932 * file was not a regular file, we leave O_EXCL off. 10933 */ 10934 if (r != 0) 10935 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666); 10936 fd = open(fname, O_WRONLY|O_CREAT, 0666); 10937 10938 /* If the open failed, return the file descriptor right away. */ 10939 if (fd < 0) 10940 return fd; 10941 10942 /* 10943 * OK, the open succeeded, but the file may have been changed from a 10944 * non-regular file to a regular file between the stat and the open. 10945 * We are assuming that the O_EXCL open handles the case where FILENAME 10946 * did not exist and is symlinked to an existing file between the stat 10947 * and open. 10948 */ 10949 10950 /* 10951 * If we can open it and fstat the file descriptor, and neither check 10952 * revealed that it was a regular file, and the file has not been 10953 * replaced, return the file descriptor. 10954 */ 10955 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) && 10956 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino) 10957 return fd; 10958 10959 /* The file has been replaced. badness. */ 10960 close(fd); 10961 errno = EEXIST; 10962 return -1; 10963 } 10964 10965 /* 10966 * Handle here documents. Normally we fork off a process to write the 10967 * data to a pipe. If the document is short, we can stuff the data in 10968 * the pipe without forking. 10969 */ 10970 10971 static inline int 10972 openhere(union node *redir) 10973 { 10974 int pip[2]; 10975 size_t len = 0; 10976 10977 if (pipe(pip) < 0) 10978 sh_error("Pipe call failed"); 10979 if (redir->type == NHERE) { 10980 len = strlen(redir->nhere.doc->narg.text); 10981 if (len <= PIPESIZE) { 10982 bb_full_write(pip[1], redir->nhere.doc->narg.text, len); 10983 goto out; 10984 } 10985 } 10986 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { 10987 close(pip[0]); 10988 signal(SIGINT, SIG_IGN); 10989 signal(SIGQUIT, SIG_IGN); 10990 signal(SIGHUP, SIG_IGN); 10991 #ifdef SIGTSTP 10992 signal(SIGTSTP, SIG_IGN); 10993 #endif 10994 signal(SIGPIPE, SIG_DFL); 10995 if (redir->type == NHERE) 10996 bb_full_write(pip[1], redir->nhere.doc->narg.text, len); 10812 10813 skip = 0; 10814 while ((n = parsecmd(0)) != NEOF) { 10815 evaltree(n, 0); 10816 popstackmark(&smark); 10817 skip = evalskip; 10818 if (skip) 10819 break; 10820 } 10821 popfile(); 10822 10823 skip &= mask; 10824 evalskip = skip; 10825 return skip; 10826 } 10827 10828 /* 10829 * The eval command. 10830 */ 10831 static int 10832 evalcmd(int argc, char **argv) 10833 { 10834 char *p; 10835 char *concat; 10836 char **ap; 10837 10838 if (argc > 1) { 10839 p = argv[1]; 10840 if (argc > 2) { 10841 STARTSTACKSTR(concat); 10842 ap = argv + 2; 10843 for (;;) { 10844 concat = stack_putstr(p, concat); 10845 p = *ap++; 10846 if (p == NULL) 10847 break; 10848 STPUTC(' ', concat); 10849 } 10850 STPUTC('\0', concat); 10851 p = grabstackstr(concat); 10852 } 10853 evalstring(p, ~SKIPEVAL); 10854 10855 } 10856 return exitstatus; 10857 } 10858 10859 /* 10860 * Read and execute commands. "Top" is nonzero for the top level command 10861 * loop; it turns on prompting if the shell is interactive. 10862 */ 10863 static int 10864 cmdloop(int top) 10865 { 10866 union node *n; 10867 struct stackmark smark; 10868 int inter; 10869 int numeof = 0; 10870 10871 TRACE(("cmdloop(%d) called\n", top)); 10872 for (;;) { 10873 int skip; 10874 10875 setstackmark(&smark); 10876 #if JOBS 10877 if (jobctl) 10878 showjobs(stderr, SHOW_CHANGED); 10879 #endif 10880 inter = 0; 10881 if (iflag && top) { 10882 inter++; 10883 #if ENABLE_ASH_MAIL 10884 chkmail(); 10885 #endif 10886 } 10887 n = parsecmd(inter); 10888 /* showtree(n); DEBUG */ 10889 if (n == NEOF) { 10890 if (!top || numeof >= 50) 10891 break; 10892 if (!stoppedjobs()) { 10893 if (!Iflag) 10894 break; 10895 out2str("\nUse \"exit\" to leave shell.\n"); 10896 } 10897 numeof++; 10898 } else if (nflag == 0) { 10899 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */ 10900 job_warning >>= 1; 10901 numeof = 0; 10902 evaltree(n, 0); 10903 } 10904 popstackmark(&smark); 10905 skip = evalskip; 10906 10907 if (skip) { 10908 evalskip = 0; 10909 return skip & SKIPEVAL; 10910 } 10911 } 10912 return 0; 10913 } 10914 10915 /* 10916 * Take commands from a file. To be compatible we should do a path 10917 * search for the file, which is necessary to find sub-commands. 10918 */ 10919 static char * 10920 find_dot_file(char *name) 10921 { 10922 char *fullname; 10923 const char *path = pathval(); 10924 struct stat statb; 10925 10926 /* don't try this for absolute or relative paths */ 10927 if (strchr(name, '/')) 10928 return name; 10929 10930 while ((fullname = padvance(&path, name)) != NULL) { 10931 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { 10932 /* 10933 * Don't bother freeing here, since it will 10934 * be freed by the caller. 10935 */ 10936 return fullname; 10937 } 10938 stunalloc(fullname); 10939 } 10940 10941 /* not found in the PATH */ 10942 ash_msg_and_raise_error("%s: not found", name); 10943 /* NOTREACHED */ 10944 } 10945 10946 static int 10947 dotcmd(int argc, char **argv) 10948 { 10949 struct strlist *sp; 10950 volatile struct shparam saveparam; 10951 int status = 0; 10952 10953 for (sp = cmdenviron; sp; sp = sp->next) 10954 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED); 10955 10956 if (argc >= 2) { /* That's what SVR2 does */ 10957 char *fullname; 10958 10959 fullname = find_dot_file(argv[1]); 10960 10961 if (argc > 2) { 10962 saveparam = shellparam; 10963 shellparam.malloc = 0; 10964 shellparam.nparam = argc - 2; 10965 shellparam.p = argv + 2; 10966 }; 10967 10968 setinputfile(fullname, INPUT_PUSH_FILE); 10969 commandname = fullname; 10970 cmdloop(0); 10971 popfile(); 10972 10973 if (argc > 2) { 10974 freeparam(&shellparam); 10975 shellparam = saveparam; 10976 }; 10977 status = exitstatus; 10978 } 10979 return status; 10980 } 10981 10982 static int 10983 exitcmd(int argc, char **argv) 10984 { 10985 if (stoppedjobs()) 10986 return 0; 10987 if (argc > 1) 10988 exitstatus = number(argv[1]); 10989 raise_exception(EXEXIT); 10990 /* NOTREACHED */ 10991 } 10992 10993 #if ENABLE_ASH_BUILTIN_ECHO 10994 static int 10995 echocmd(int argc, char **argv) 10996 { 10997 return bb_echo(argv); 10998 } 10999 #endif 11000 11001 #if ENABLE_ASH_BUILTIN_TEST 11002 static int 11003 testcmd(int argc, char **argv) 11004 { 11005 return test_main(argc, argv); 11006 } 11007 #endif 11008 11009 /* 11010 * Read a file containing shell functions. 11011 */ 11012 static void 11013 readcmdfile(char *name) 11014 { 11015 setinputfile(name, INPUT_PUSH_FILE); 11016 cmdloop(0); 11017 popfile(); 11018 } 11019 11020 11021 /* ============ find_command inplementation */ 11022 11023 /* 11024 * Resolve a command name. If you change this routine, you may have to 11025 * change the shellexec routine as well. 11026 */ 11027 static void 11028 find_command(char *name, struct cmdentry *entry, int act, const char *path) 11029 { 11030 struct tblentry *cmdp; 11031 int idx; 11032 int prev; 11033 char *fullname; 11034 struct stat statb; 11035 int e; 11036 int updatetbl; 11037 struct builtincmd *bcmd; 11038 11039 /* If name contains a slash, don't use PATH or hash table */ 11040 if (strchr(name, '/') != NULL) { 11041 entry->u.index = -1; 11042 if (act & DO_ABS) { 11043 while (stat(name, &statb) < 0) { 11044 #ifdef SYSV 11045 if (errno == EINTR) 11046 continue; 11047 #endif 11048 entry->cmdtype = CMDUNKNOWN; 11049 return; 11050 } 11051 } 11052 entry->cmdtype = CMDNORMAL; 11053 return; 11054 } 11055 11056 /* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */ 11057 11058 updatetbl = (path == pathval()); 11059 if (!updatetbl) { 11060 act |= DO_ALTPATH; 11061 if (strstr(path, "%builtin") != NULL) 11062 act |= DO_ALTBLTIN; 11063 } 11064 11065 /* If name is in the table, check answer will be ok */ 11066 cmdp = cmdlookup(name, 0); 11067 if (cmdp != NULL) { 11068 int bit; 11069 11070 switch (cmdp->cmdtype) { 11071 default: 11072 #if DEBUG 11073 abort(); 11074 #endif 11075 case CMDNORMAL: 11076 bit = DO_ALTPATH; 11077 break; 11078 case CMDFUNCTION: 11079 bit = DO_NOFUNC; 11080 break; 11081 case CMDBUILTIN: 11082 bit = DO_ALTBLTIN; 11083 break; 11084 } 11085 if (act & bit) { 11086 updatetbl = 0; 11087 cmdp = NULL; 11088 } else if (cmdp->rehash == 0) 11089 /* if not invalidated by cd, we're done */ 11090 goto success; 11091 } 11092 11093 /* If %builtin not in path, check for builtin next */ 11094 bcmd = find_builtin(name); 11095 if (bcmd) { 11096 if (IS_BUILTIN_REGULAR(bcmd)) 11097 goto builtin_success; 11098 if (act & DO_ALTPATH) { 11099 if (!(act & DO_ALTBLTIN)) 11100 goto builtin_success; 11101 } else if (builtinloc <= 0) { 11102 goto builtin_success; 11103 } 11104 } 11105 11106 #if ENABLE_FEATURE_SH_STANDALONE 11107 if (find_applet_by_name(name)) { 11108 entry->cmdtype = CMDNORMAL; 11109 entry->u.index = -1; 11110 return; 11111 } 11112 #endif 11113 11114 /* We have to search path. */ 11115 prev = -1; /* where to start */ 11116 if (cmdp && cmdp->rehash) { /* doing a rehash */ 11117 if (cmdp->cmdtype == CMDBUILTIN) 11118 prev = builtinloc; 10997 11119 else 10998 expandhere(redir->nhere.doc, pip[1]); 10999 _exit(0); 11000 } 11001 out: 11002 close(pip[1]); 11003 return pip[0]; 11004 } 11005 11120 prev = cmdp->param.index; 11121 } 11122 11123 e = ENOENT; 11124 idx = -1; 11125 loop: 11126 while ((fullname = padvance(&path, name)) != NULL) { 11127 stunalloc(fullname); 11128 /* NB: code below will still use fullname 11129 * despite it being "unallocated" */ 11130 idx++; 11131 if (pathopt) { 11132 if (prefix(pathopt, "builtin")) { 11133 if (bcmd) 11134 goto builtin_success; 11135 continue; 11136 } else if (!(act & DO_NOFUNC) 11137 && prefix(pathopt, "func")) { 11138 /* handled below */ 11139 } else { 11140 /* ignore unimplemented options */ 11141 continue; 11142 } 11143 } 11144 /* if rehash, don't redo absolute path names */ 11145 if (fullname[0] == '/' && idx <= prev) { 11146 if (idx < prev) 11147 continue; 11148 TRACE(("searchexec \"%s\": no change\n", name)); 11149 goto success; 11150 } 11151 while (stat(fullname, &statb) < 0) { 11152 #ifdef SYSV 11153 if (errno == EINTR) 11154 continue; 11155 #endif 11156 if (errno != ENOENT && errno != ENOTDIR) 11157 e = errno; 11158 goto loop; 11159 } 11160 e = EACCES; /* if we fail, this will be the error */ 11161 if (!S_ISREG(statb.st_mode)) 11162 continue; 11163 if (pathopt) { /* this is a %func directory */ 11164 stalloc(strlen(fullname) + 1); 11165 /* NB: stalloc will return space pointed by fullname 11166 * (because we don't have any intervening allocations 11167 * between stunalloc above and this stalloc) */ 11168 readcmdfile(fullname); 11169 cmdp = cmdlookup(name, 0); 11170 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION) 11171 ash_msg_and_raise_error("%s not defined in %s", name, fullname); 11172 stunalloc(fullname); 11173 goto success; 11174 } 11175 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); 11176 if (!updatetbl) { 11177 entry->cmdtype = CMDNORMAL; 11178 entry->u.index = idx; 11179 return; 11180 } 11181 INT_OFF; 11182 cmdp = cmdlookup(name, 1); 11183 cmdp->cmdtype = CMDNORMAL; 11184 cmdp->param.index = idx; 11185 INT_ON; 11186 goto success; 11187 } 11188 11189 /* We failed. If there was an entry for this command, delete it */ 11190 if (cmdp && updatetbl) 11191 delete_cmd_entry(); 11192 if (act & DO_ERR) 11193 ash_msg("%s: %s", name, errmsg(e, "not found")); 11194 entry->cmdtype = CMDUNKNOWN; 11195 return; 11196 11197 builtin_success: 11198 if (!updatetbl) { 11199 entry->cmdtype = CMDBUILTIN; 11200 entry->u.cmd = bcmd; 11201 return; 11202 } 11203 INT_OFF; 11204 cmdp = cmdlookup(name, 1); 11205 cmdp->cmdtype = CMDBUILTIN; 11206 cmdp->param.cmd = bcmd; 11207 INT_ON; 11208 success: 11209 cmdp->rehash = 0; 11210 entry->cmdtype = cmdp->cmdtype; 11211 entry->u = cmdp->param; 11212 } 11213 11214 11215 /* ============ trap.c */ 11216 11217 /* 11218 * The trap builtin. 11219 */ 11006 11220 static int 11007 openredirect(union node *redir)11008 {11009 char *fname;11010 int f;11011 11012 switch (redir->nfile.type) {11013 case NFROM:11014 fname = redir->nfile.expfname;11015 if ((f = open(fname, O_RDONLY)) < 0)11016 goto eopen;11017 break;11018 case NFROMTO:11019 fname = redir->nfile.expfname;11020 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)11021 goto ecreate;11022 break;11023 case NTO:11024 /* Take care of noclobber mode. */11025 if (Cflag) {11026 fname = redir->nfile.expfname;11027 if ((f = noclobberopen(fname)) < 0)11028 goto ecreate;11029 break;11030 }11031 /* FALLTHROUGH */11032 case NCLOBBER:11033 fname = redir->nfile.expfname;11034 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)11035 goto ecreate;11036 break;11037 case NAPPEND:11038 fname = redir->nfile.expfname;11039 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)11040 goto ecreate;11041 break;11042 default:11043 #ifdef DEBUG11044 abort();11045 #endif11046 /* Fall through to eliminate warning. */11047 case NTOFD:11048 case NFROMFD:11049 f = -1;11050 break;11051 case NHERE:11052 case NXHERE:11053 f = openhere(redir);11054 break;11055 }11056 11057 return f;11058 ecreate:11059 sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));11060 eopen:11061 sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));11062 }11063 11064 static inline void11065 dupredirect(union node *redir, int f)11066 {11067 int fd = redir->nfile.fd;11068 11069 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {11070 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */11071 copyfd(redir->ndup.dupfd, fd);11072 }11073 return;11074 }11075 11076 if (f != fd) {11077 copyfd(f, fd);11078 close(f);11079 }11080 return;11081 }11082 11083 /*11084 * Process a list of redirection commands. If the REDIR_PUSH flag is set,11085 * old file descriptors are stashed away so that the redirection can be11086 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the11087 * standard output, and the standard error if it becomes a duplicate of11088 * stdout, is saved in memory.11089 */11090 11091 static void11092 redirect(union node *redir, int flags)11093 {11094 union node *n;11095 struct redirtab *sv;11096 int i;11097 int fd;11098 int newfd;11099 int *p;11100 nullredirs++;11101 if (!redir) {11102 return;11103 }11104 sv = NULL;11105 INTOFF;11106 if (flags & REDIR_PUSH) {11107 struct redirtab *q;11108 q = ckmalloc(sizeof (struct redirtab));11109 q->next = redirlist;11110 redirlist = q;11111 q->nullredirs = nullredirs - 1;11112 for (i = 0 ; i < 10 ; i++)11113 q->renamed[i] = EMPTY;11114 nullredirs = 0;11115 sv = q;11116 }11117 n = redir;11118 do {11119 fd = n->nfile.fd;11120 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&11121 n->ndup.dupfd == fd)11122 continue; /* redirect from/to same file descriptor */11123 11124 newfd = openredirect(n);11125 if (fd == newfd)11126 continue;11127 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {11128 i = fcntl(fd, F_DUPFD, 10);11129 11130 if (i == -1) {11131 i = errno;11132 if (i != EBADF) {11133 close(newfd);11134 errno = i;11135 sh_error("%d: %m", fd);11136 /* NOTREACHED */11137 }11138 } else {11139 *p = i;11140 close(fd);11141 }11142 } else {11143 close(fd);11144 }11145 dupredirect(n, newfd);11146 } while ((n = n->nfile.next));11147 INTON;11148 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)11149 preverrout_fd = sv->renamed[2];11150 }11151 11152 11153 /*11154 * Undo the effects of the last redirection.11155 */11156 11157 void11158 popredir(int drop)11159 {11160 struct redirtab *rp;11161 int i;11162 11163 if (--nullredirs >= 0)11164 return;11165 INTOFF;11166 rp = redirlist;11167 for (i = 0 ; i < 10 ; i++) {11168 if (rp->renamed[i] != EMPTY) {11169 if (!drop) {11170 close(i);11171 copyfd(rp->renamed[i], i);11172 }11173 close(rp->renamed[i]);11174 }11175 }11176 redirlist = rp->next;11177 nullredirs = rp->nullredirs;11178 ckfree(rp);11179 INTON;11180 }11181 11182 /*11183 * Undo all redirections. Called on error or interrupt.11184 */11185 11186 /*11187 * Discard all saved file descriptors.11188 */11189 11190 void11191 clearredir(int drop)11192 {11193 for (;;) {11194 nullredirs = 0;11195 if (!redirlist)11196 break;11197 popredir(drop);11198 }11199 }11200 11201 11202 /*11203 * Copy a file descriptor to be >= to. Returns -111204 * if the source file descriptor is closed, EMPTY if there are no unused11205 * file descriptors left.11206 */11207 11208 int11209 copyfd(int from, int to)11210 {11211 int newfd;11212 11213 newfd = fcntl(from, F_DUPFD, to);11214 if (newfd < 0) {11215 if (errno == EMFILE)11216 return EMPTY;11217 else11218 sh_error("%d: %m", from);11219 }11220 return newfd;11221 }11222 11223 11224 int11225 redirectsafe(union node *redir, int flags)11226 {11227 int err;11228 volatile int saveint;11229 struct jmploc *volatile savehandler = handler;11230 struct jmploc jmploc;11231 11232 SAVEINT(saveint);11233 if (!(err = setjmp(jmploc.loc) * 2)) {11234 handler = &jmploc;11235 redirect(redir, flags);11236 }11237 handler = savehandler;11238 if (err && exception != EXERROR)11239 longjmp(handler->loc, 1);11240 RESTOREINT(saveint);11241 return err;11242 }11243 11244 /* show.c */11245 11246 #ifdef DEBUG11247 static void shtree(union node *, int, char *, FILE*);11248 static void shcmd(union node *, FILE *);11249 static void sharg(union node *, FILE *);11250 static void indent(int, char *, FILE *);11251 static void trstring(char *);11252 11253 11254 void11255 showtree(union node *n)11256 {11257 trputs("showtree called\n");11258 shtree(n, 1, NULL, stdout);11259 }11260 11261 11262 static void11263 shtree(union node *n, int ind, char *pfx, FILE *fp)11264 {11265 struct nodelist *lp;11266 const char *s;11267 11268 if (n == NULL)11269 return;11270 11271 indent(ind, pfx, fp);11272 switch(n->type) {11273 case NSEMI:11274 s = "; ";11275 goto binop;11276 case NAND:11277 s = " && ";11278 goto binop;11279 case NOR:11280 s = " || ";11281 binop:11282 shtree(n->nbinary.ch1, ind, NULL, fp);11283 /* if (ind < 0) */11284 fputs(s, fp);11285 shtree(n->nbinary.ch2, ind, NULL, fp);11286 break;11287 case NCMD:11288 shcmd(n, fp);11289 if (ind >= 0)11290 putc('\n', fp);11291 break;11292 case NPIPE:11293 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {11294 shcmd(lp->n, fp);11295 if (lp->next)11296 fputs(" | ", fp);11297 }11298 if (n->npipe.backgnd)11299 fputs(" &", fp);11300 if (ind >= 0)11301 putc('\n', fp);11302 break;11303 default:11304 fprintf(fp, "<node type %d>", n->type);11305 if (ind >= 0)11306 putc('\n', fp);11307 break;11308 }11309 }11310 11311 11312 static void11313 shcmd(union node *cmd, FILE *fp)11314 {11315 union node *np;11316 int first;11317 const char *s;11318 int dftfd;11319 11320 first = 1;11321 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {11322 if (! first)11323 putchar(' ');11324 sharg(np, fp);11325 first = 0;11326 }11327 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {11328 if (! first)11329 putchar(' ');11330 switch (np->nfile.type) {11331 case NTO: s = ">"; dftfd = 1; break;11332 case NCLOBBER: s = ">|"; dftfd = 1; break;11333 case NAPPEND: s = ">>"; dftfd = 1; break;11334 case NTOFD: s = ">&"; dftfd = 1; break;11335 case NFROM: s = "<"; dftfd = 0; break;11336 case NFROMFD: s = "<&"; dftfd = 0; break;11337 case NFROMTO: s = "<>"; dftfd = 0; break;11338 default: s = "*error*"; dftfd = 0; break;11339 }11340 if (np->nfile.fd != dftfd)11341 fprintf(fp, "%d", np->nfile.fd);11342 fputs(s, fp);11343 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {11344 fprintf(fp, "%d", np->ndup.dupfd);11345 } else {11346 sharg(np->nfile.fname, fp);11347 }11348 first = 0;11349 }11350 }11351 11352 11353 11354 static void11355 sharg(union node *arg, FILE *fp)11356 {11357 char *p;11358 struct nodelist *bqlist;11359 int subtype;11360 11361 if (arg->type != NARG) {11362 out1fmt("<node type %d>\n", arg->type);11363 abort();11364 }11365 bqlist = arg->narg.backquote;11366 for (p = arg->narg.text ; *p ; p++) {11367 switch (*p) {11368 case CTLESC:11369 putc(*++p, fp);11370 break;11371 case CTLVAR:11372 putc('$', fp);11373 putc('{', fp);11374 subtype = *++p;11375 if (subtype == VSLENGTH)11376 putc('#', fp);11377 11378 while (*p != '=')11379 putc(*p++, fp);11380 11381 if (subtype & VSNUL)11382 putc(':', fp);11383 11384 switch (subtype & VSTYPE) {11385 case VSNORMAL:11386 putc('}', fp);11387 break;11388 case VSMINUS:11389 putc('-', fp);11390 break;11391 case VSPLUS:11392 putc('+', fp);11393 break;11394 case VSQUESTION:11395 putc('?', fp);11396 break;11397 case VSASSIGN:11398 putc('=', fp);11399 break;11400 case VSTRIMLEFT:11401 putc('#', fp);11402 break;11403 case VSTRIMLEFTMAX:11404 putc('#', fp);11405 putc('#', fp);11406 break;11407 case VSTRIMRIGHT:11408 putc('%', fp);11409 break;11410 case VSTRIMRIGHTMAX:11411 putc('%', fp);11412 putc('%', fp);11413 break;11414 case VSLENGTH:11415 break;11416 default:11417 out1fmt("<subtype %d>", subtype);11418 }11419 break;11420 case CTLENDVAR:11421 putc('}', fp);11422 break;11423 case CTLBACKQ:11424 case CTLBACKQ|CTLQUOTE:11425 putc('$', fp);11426 putc('(', fp);11427 shtree(bqlist->n, -1, NULL, fp);11428 putc(')', fp);11429 break;11430 default:11431 putc(*p, fp);11432 break;11433 }11434 }11435 }11436 11437 11438 static void11439 indent(int amount, char *pfx, FILE *fp)11440 {11441 int i;11442 11443 for (i = 0 ; i < amount ; i++) {11444 if (pfx && i == amount - 1)11445 fputs(pfx, fp);11446 putc('\t', fp);11447 }11448 }11449 11450 11451 11452 /*11453 * Debugging stuff.11454 */11455 11456 11457 FILE *tracefile;11458 11459 11460 void11461 trputc(int c)11462 {11463 if (debug != 1)11464 return;11465 putc(c, tracefile);11466 }11467 11468 void11469 trace(const char *fmt, ...)11470 {11471 va_list va;11472 11473 if (debug != 1)11474 return;11475 va_start(va, fmt);11476 (void) vfprintf(tracefile, fmt, va);11477 va_end(va);11478 }11479 11480 void11481 tracev(const char *fmt, va_list va)11482 {11483 if (debug != 1)11484 return;11485 (void) vfprintf(tracefile, fmt, va);11486 }11487 11488 11489 void11490 trputs(const char *s)11491 {11492 if (debug != 1)11493 return;11494 fputs(s, tracefile);11495 }11496 11497 11498 static void11499 trstring(char *s)11500 {11501 char *p;11502 char c;11503 11504 if (debug != 1)11505 return;11506 putc('"', tracefile);11507 for (p = s ; *p ; p++) {11508 switch (*p) {11509 case '\n': c = 'n'; goto backslash;11510 case '\t': c = 't'; goto backslash;11511 case '\r': c = 'r'; goto backslash;11512 case '"': c = '"'; goto backslash;11513 case '\\': c = '\\'; goto backslash;11514 case CTLESC: c = 'e'; goto backslash;11515 case CTLVAR: c = 'v'; goto backslash;11516 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;11517 case CTLBACKQ: c = 'q'; goto backslash;11518 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;11519 backslash: putc('\\', tracefile);11520 putc(c, tracefile);11521 break;11522 default:11523 if (*p >= ' ' && *p <= '~')11524 putc(*p, tracefile);11525 else {11526 putc('\\', tracefile);11527 putc(*p >> 6 & 03, tracefile);11528 putc(*p >> 3 & 07, tracefile);11529 putc(*p & 07, tracefile);11530 }11531 break;11532 }11533 }11534 putc('"', tracefile);11535 }11536 11537 11538 void11539 trargs(char **ap)11540 {11541 if (debug != 1)11542 return;11543 while (*ap) {11544 trstring(*ap++);11545 if (*ap)11546 putc(' ', tracefile);11547 else11548 putc('\n', tracefile);11549 }11550 }11551 11552 11553 void11554 opentrace(void)11555 {11556 char s[100];11557 #ifdef O_APPEND11558 int flags;11559 #endif11560 11561 if (debug != 1) {11562 if (tracefile)11563 fflush(tracefile);11564 /* leave open because libedit might be using it */11565 return;11566 }11567 scopy("./trace", s);11568 if (tracefile) {11569 if (!freopen(s, "a", tracefile)) {11570 fprintf(stderr, "Can't re-open %s\n", s);11571 debug = 0;11572 return;11573 }11574 } else {11575 if ((tracefile = fopen(s, "a")) == NULL) {11576 fprintf(stderr, "Can't open %s\n", s);11577 debug = 0;11578 return;11579 }11580 }11581 #ifdef O_APPEND11582 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)11583 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);11584 #endif11585 setlinebuf(tracefile);11586 fputs("\nTracing started.\n", tracefile);11587 }11588 #endif /* DEBUG */11589 11590 11591 /* trap.c */11592 11593 /*11594 * Sigmode records the current value of the signal handlers for the various11595 * modes. A value of zero means that the current handler is not known.11596 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,11597 */11598 11599 #define S_DFL 1 /* default signal handling (SIG_DFL) */11600 #define S_CATCH 2 /* signal is caught */11601 #define S_IGN 3 /* signal is ignored (SIG_IGN) */11602 #define S_HARD_IGN 4 /* signal is ignored permenantly */11603 #define S_RESET 5 /* temporary - to reset a hard ignored sig */11604 11605 11606 11607 /*11608 * The trap builtin.11609 */11610 11611 int11612 11221 trapcmd(int argc, char **argv) 11613 11222 { … … 11619 11228 ap = argptr; 11620 11229 if (!*ap) { 11621 for (signo = 0 ; signo < NSIG; signo++) {11230 for (signo = 0; signo < NSIG; signo++) { 11622 11231 if (trap[signo] != NULL) { 11623 11232 const char *sn; 11624 11233 11625 sn = u_signal_names(0, &signo, 0); 11626 if (sn == NULL) 11627 sn = "???"; 11234 sn = get_signame(signo); 11628 11235 out1fmt("trap -- %s %s\n", 11629 11236 single_quote(trap[signo]), sn); … … 11637 11244 action = *ap++; 11638 11245 while (*ap) { 11639 if ((signo = decode_signal(*ap, 0)) < 0) 11640 sh_error("%s: bad trap", *ap); 11641 INTOFF; 11246 signo = get_signum(*ap); 11247 if (signo < 0) 11248 ash_msg_and_raise_error("%s: bad trap", *ap); 11249 INT_OFF; 11642 11250 if (action) { 11643 if ( action[0] == '-' && action[1] == '\0')11251 if (LONE_DASH(action)) 11644 11252 action = NULL; 11645 11253 else 11646 action = savestr(action);11254 action = ckstrdup(action); 11647 11255 } 11648 11256 if (trap[signo]) 11649 ckfree(trap[signo]);11257 free(trap[signo]); 11650 11258 trap[signo] = action; 11651 11259 if (signo != 0) 11652 11260 setsignal(signo); 11653 INT ON;11261 INT_ON; 11654 11262 ap++; 11655 11263 } … … 11658 11266 11659 11267 11660 /* 11661 * Clear traps on a fork. 11662 */ 11663 11664 void 11665 clear_traps(void) 11666 { 11667 char **tp; 11668 11669 for (tp = trap ; tp < &trap[NSIG] ; tp++) { 11670 if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 11671 INTOFF; 11672 ckfree(*tp); 11673 *tp = NULL; 11674 if (tp != &trap[0]) 11675 setsignal(tp - trap); 11676 INTON; 11677 } 11678 } 11679 } 11680 11681 11682 /* 11683 * Set the signal handler for the specified signal. The routine figures 11684 * out what it should be set to. 11685 */ 11686 11687 void 11688 setsignal(int signo) 11689 { 11690 int action; 11691 char *t, tsig; 11692 struct sigaction act; 11693 11694 if ((t = trap[signo]) == NULL) 11695 action = S_DFL; 11696 else if (*t != '\0') 11697 action = S_CATCH; 11698 else 11699 action = S_IGN; 11700 if (rootshell && action == S_DFL) { 11701 switch (signo) { 11702 case SIGINT: 11703 if (iflag || minusc || sflag == 0) 11704 action = S_CATCH; 11705 break; 11706 case SIGQUIT: 11707 #ifdef DEBUG 11708 if (debug) 11709 break; 11710 #endif 11711 /* FALLTHROUGH */ 11712 case SIGTERM: 11713 if (iflag) 11714 action = S_IGN; 11715 break; 11716 #if JOBS 11717 case SIGTSTP: 11718 case SIGTTOU: 11719 if (mflag) 11720 action = S_IGN; 11721 break; 11722 #endif 11723 } 11724 } 11725 11726 t = &sigmode[signo - 1]; 11727 tsig = *t; 11728 if (tsig == 0) { 11729 /* 11730 * current setting unknown 11731 */ 11732 if (sigaction(signo, 0, &act) == -1) { 11733 /* 11734 * Pretend it worked; maybe we should give a warning 11735 * here, but other shells don't. We don't alter 11736 * sigmode, so that we retry every time. 11737 */ 11738 return; 11739 } 11740 if (act.sa_handler == SIG_IGN) { 11741 if (mflag && (signo == SIGTSTP || 11742 signo == SIGTTIN || signo == SIGTTOU)) { 11743 tsig = S_IGN; /* don't hard ignore these */ 11744 } else 11745 tsig = S_HARD_IGN; 11746 } else { 11747 tsig = S_RESET; /* force to be set */ 11748 } 11749 } 11750 if (tsig == S_HARD_IGN || tsig == action) 11751 return; 11752 switch (action) { 11753 case S_CATCH: 11754 act.sa_handler = onsig; 11755 break; 11756 case S_IGN: 11757 act.sa_handler = SIG_IGN; 11758 break; 11759 default: 11760 act.sa_handler = SIG_DFL; 11761 } 11762 *t = action; 11763 act.sa_flags = 0; 11764 sigfillset(&act.sa_mask); 11765 sigaction(signo, &act, 0); 11766 } 11767 11768 /* 11769 * Ignore a signal. 11770 */ 11771 11772 void 11773 ignoresig(int signo) 11774 { 11775 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { 11776 signal(signo, SIG_IGN); 11777 } 11778 sigmode[signo - 1] = S_HARD_IGN; 11779 } 11780 11781 11782 /* 11783 * Signal handler. 11784 */ 11785 11786 void 11787 onsig(int signo) 11788 { 11789 gotsig[signo - 1] = 1; 11790 pendingsigs = signo; 11791 11792 if (exsig || (signo == SIGINT && !trap[SIGINT])) { 11793 if (!suppressint) 11794 onint(); 11795 intpending = 1; 11796 } 11797 } 11798 11799 11800 /* 11801 * Called to execute a trap. Perhaps we should avoid entering new trap 11802 * handlers while we are executing a trap handler. 11803 */ 11804 11805 int 11806 dotrap(void) 11807 { 11808 char *p; 11809 char *q; 11810 int i; 11811 int savestatus; 11812 int skip = 0; 11813 11814 savestatus = exitstatus; 11815 pendingsigs = 0; 11816 xbarrier(); 11817 11818 for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) { 11819 if (!*q) 11820 continue; 11821 *q = 0; 11822 11823 p = trap[i + 1]; 11824 if (!p) 11825 continue; 11826 skip = evalstring(p, SKIPEVAL); 11827 exitstatus = savestatus; 11828 if (skip) 11829 break; 11830 } 11831 11832 return skip; 11833 } 11834 11835 11836 /* 11837 * Controls whether the shell is interactive or not. 11838 */ 11839 11840 void 11841 setinteractive(int on) 11842 { 11843 static int is_interactive; 11844 11845 if (++on == is_interactive) 11846 return; 11847 is_interactive = on; 11848 setsignal(SIGINT); 11849 setsignal(SIGQUIT); 11850 setsignal(SIGTERM); 11851 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET 11852 if(is_interactive > 1) { 11853 /* Looks like they want an interactive shell */ 11854 static int do_banner; 11855 11856 if(!do_banner) { 11857 out1fmt( 11858 "\n\n%s Built-in shell (ash)\n" 11859 "Enter 'help' for a list of built-in commands.\n\n", 11860 BB_BANNER); 11861 do_banner++; 11862 } 11863 } 11864 #endif 11865 } 11866 11867 11868 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET 11869 /*** List the available builtins ***/ 11870 11871 static int helpcmd(int argc, char **argv) 11268 /* ============ Builtins */ 11269 11270 #if !ENABLE_FEATURE_SH_EXTRA_QUIET 11271 /* 11272 * Lists available builtins 11273 */ 11274 static int 11275 helpcmd(int argc, char **argv) 11872 11276 { 11873 11277 int col, i; 11874 11278 11875 11279 out1fmt("\nBuilt-in commands:\n-------------------\n"); 11876 for (col = 0, i = 0; i < NUMBUILTINS; i++) {11280 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) { 11877 11281 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), 11878 builtincmd[i].name + 1);11282 builtintab[i].name + 1); 11879 11283 if (col > 60) { 11880 11284 out1fmt("\n"); … … 11882 11286 } 11883 11287 } 11884 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL 11885 { 11886 extern const struct BB_applet applets[]; 11887 extern const size_t NUM_APPLETS; 11888 11889 for (i = 0; i < NUM_APPLETS; i++) { 11890 11891 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name); 11892 if (col > 60) { 11893 out1fmt("\n"); 11894 col = 0; 11895 } 11288 #if ENABLE_FEATURE_SH_STANDALONE 11289 for (i = 0; i < NUM_APPLETS; i++) { 11290 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name); 11291 if (col > 60) { 11292 out1fmt("\n"); 11293 col = 0; 11896 11294 } 11897 11295 } … … 11900 11298 return EXIT_SUCCESS; 11901 11299 } 11902 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */ 11903 11904 /* 11905 * Called to exit the shell. 11906 */ 11907 11908 void 11909 exitshell(void) 11910 { 11911 struct jmploc loc; 11912 char *p; 11913 int status; 11914 11915 status = exitstatus; 11916 TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); 11917 if (setjmp(loc.loc)) { 11918 if (exception == EXEXIT) 11919 _exit(exitstatus); 11920 goto out; 11921 } 11922 handler = &loc; 11923 if ((p = trap[0])) { 11924 trap[0] = NULL; 11925 evalstring(p, 0); 11926 } 11927 flushall(); 11928 setjobctl(0); 11929 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY 11930 if (iflag && rootshell) { 11931 const char *hp = lookupvar("HISTFILE"); 11932 11933 if(hp != NULL ) 11934 save_history ( hp ); 11935 } 11936 #endif 11937 out: 11938 _exit(status); 11939 /* NOTREACHED */ 11940 } 11941 11942 static int decode_signal(const char *string, int minsig) 11943 { 11944 int signo; 11945 const char *name = u_signal_names(string, &signo, minsig); 11946 11947 return name ? signo : -1; 11948 } 11949 11950 /* var.c */ 11951 11952 static struct var *vartab[VTABSIZE]; 11953 11954 static int vpcmp(const void *, const void *); 11955 static struct var **findvar(struct var **, const char *); 11956 11957 /* 11958 * Initialize the variable symbol tables and import the environment 11959 */ 11960 11961 11962 #ifdef CONFIG_ASH_GETOPTS 11963 /* 11964 * Safe version of setvar, returns 1 on success 0 on failure. 11965 */ 11966 11967 int 11968 setvarsafe(const char *name, const char *val, int flags) 11969 { 11970 int err; 11971 volatile int saveint; 11972 struct jmploc *volatile savehandler = handler; 11973 struct jmploc jmploc; 11974 11975 SAVEINT(saveint); 11976 if (setjmp(jmploc.loc)) 11977 err = 1; 11978 else { 11979 handler = &jmploc; 11980 setvar(name, val, flags); 11981 err = 0; 11982 } 11983 handler = savehandler; 11984 RESTOREINT(saveint); 11985 return err; 11986 } 11987 #endif 11988 11989 /* 11990 * Set the value of a variable. The flags argument is ored with the 11991 * flags of the variable. If val is NULL, the variable is unset. 11992 */ 11993 11994 static void 11995 setvar(const char *name, const char *val, int flags) 11996 { 11997 char *p, *q; 11998 size_t namelen; 11999 char *nameeq; 12000 size_t vallen; 12001 12002 q = endofname(name); 12003 p = strchrnul(q, '='); 12004 namelen = p - name; 12005 if (!namelen || p != q) 12006 sh_error("%.*s: bad variable name", namelen, name); 12007 vallen = 0; 12008 if (val == NULL) { 12009 flags |= VUNSET; 12010 } else { 12011 vallen = strlen(val); 12012 } 12013 INTOFF; 12014 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen); 12015 if (val) { 12016 *p++ = '='; 12017 p = mempcpy(p, val, vallen); 12018 } 12019 *p = '\0'; 12020 setvareq(nameeq, flags | VNOSAVE); 12021 INTON; 12022 } 12023 12024 12025 /* 12026 * Same as setvar except that the variable and value are passed in 12027 * the first argument as name=value. Since the first argument will 12028 * be actually stored in the table, it should not be a string that 12029 * will go away. 12030 * Called with interrupts off. 12031 */ 12032 12033 void 12034 setvareq(char *s, int flags) 12035 { 12036 struct var *vp, **vpp; 12037 12038 vpp = hashvar(s); 12039 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); 12040 vp = *findvar(vpp, s); 12041 if (vp) { 12042 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) { 12043 const char *n; 12044 12045 if (flags & VNOSAVE) 12046 free(s); 12047 n = vp->text; 12048 sh_error("%.*s: is read only", strchrnul(n, '=') - n, n); 12049 } 12050 12051 if (flags & VNOSET) 12052 return; 12053 12054 if (vp->func && (flags & VNOFUNC) == 0) 12055 (*vp->func)(strchrnul(s, '=') + 1); 12056 12057 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) 12058 ckfree(vp->text); 12059 12060 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET); 12061 } else { 12062 if (flags & VNOSET) 12063 return; 12064 /* not found */ 12065 vp = ckmalloc(sizeof (*vp)); 12066 vp->next = *vpp; 12067 vp->func = NULL; 12068 *vpp = vp; 12069 } 12070 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE))) 12071 s = savestr(s); 12072 vp->text = s; 12073 vp->flags = flags; 12074 } 12075 12076 12077 /* 12078 * Process a linked list of variable assignments. 12079 */ 12080 12081 static void 12082 listsetvar(struct strlist *list_set_var, int flags) 12083 { 12084 struct strlist *lp = list_set_var; 12085 12086 if (!lp) 12087 return; 12088 INTOFF; 12089 do { 12090 setvareq(lp->text, flags); 12091 } while ((lp = lp->next)); 12092 INTON; 12093 } 12094 12095 12096 /* 12097 * Find the value of a variable. Returns NULL if not set. 12098 */ 12099 12100 static char * 12101 lookupvar(const char *name) 12102 { 12103 struct var *v; 12104 12105 if ((v = *findvar(hashvar(name), name))) { 12106 #ifdef DYNAMIC_VAR 12107 /* 12108 * Dynamic variables are implemented roughly the same way they are 12109 * in bash. Namely, they're "special" so long as they aren't unset. 12110 * As soon as they're unset, they're no longer dynamic, and dynamic 12111 * lookup will no longer happen at that point. -- PFM. 12112 */ 12113 if((v->flags & VDYNAMIC)) 12114 (*v->func)(NULL); 12115 #endif 12116 if(!(v->flags & VUNSET)) 12117 return strchrnul(v->text, '=') + 1; 12118 } 12119 12120 return NULL; 12121 } 12122 12123 12124 /* 12125 * Search the environment of a builtin command. 12126 */ 12127 12128 static char * 12129 bltinlookup(const char *name) 12130 { 12131 struct strlist *sp; 12132 12133 for (sp = cmdenviron ; sp ; sp = sp->next) { 12134 if (varequal(sp->text, name)) 12135 return strchrnul(sp->text, '=') + 1; 12136 } 12137 return lookupvar(name); 12138 } 12139 12140 12141 /* 12142 * Generate a list of variables satisfying the given conditions. 12143 */ 12144 12145 static char ** 12146 listvars(int on, int off, char ***end) 12147 { 12148 struct var **vpp; 12149 struct var *vp; 12150 char **ep; 12151 int mask; 12152 12153 STARTSTACKSTR(ep); 12154 vpp = vartab; 12155 mask = on | off; 12156 do { 12157 for (vp = *vpp ; vp ; vp = vp->next) 12158 if ((vp->flags & mask) == on) { 12159 if (ep == stackstrend()) 12160 ep = growstackstr(); 12161 *ep++ = (char *) vp->text; 12162 } 12163 } while (++vpp < vartab + VTABSIZE); 12164 if (ep == stackstrend()) 12165 ep = growstackstr(); 12166 if (end) 12167 *end = ep; 12168 *ep++ = NULL; 12169 return grabstackstr(ep); 12170 } 12171 12172 12173 /* 12174 * POSIX requires that 'set' (but not export or readonly) output the 12175 * variables in lexicographic order - by the locale's collating order (sigh). 12176 * Maybe we could keep them in an ordered balanced binary tree 12177 * instead of hashed lists. 12178 * For now just roll 'em through qsort for printing... 12179 */ 12180 12181 static int 12182 showvars(const char *sep_prefix, int on, int off) 12183 { 12184 const char *sep; 12185 char **ep, **epend; 12186 12187 ep = listvars(on, off, &epend); 12188 qsort(ep, epend - ep, sizeof(char *), vpcmp); 12189 12190 sep = *sep_prefix ? spcstr : sep_prefix; 12191 12192 for (; ep < epend; ep++) { 12193 const char *p; 12194 const char *q; 12195 12196 p = strchrnul(*ep, '='); 12197 q = nullstr; 12198 if (*p) 12199 q = single_quote(++p); 12200 12201 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q); 12202 } 12203 12204 return 0; 12205 } 12206 12207 11300 #endif /* FEATURE_SH_EXTRA_QUIET */ 12208 11301 12209 11302 /* 12210 11303 * The export and readonly commands. 12211 11304 */ 12212 12213 11305 static int 12214 11306 exportcmd(int argc, char **argv) … … 12219 11311 char **aptr; 12220 11312 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; 12221 int notp; 12222 12223 notp = nextopt("p") - 'p'; 12224 if (notp && ((name = *(aptr = argptr)))) { 12225 do { 12226 if ((p = strchr(name, '=')) != NULL) { 12227 p++; 12228 } else { 12229 if ((vp = *findvar(hashvar(name), name))) { 12230 vp->flags |= flag; 12231 continue; 11313 11314 if (nextopt("p") != 'p') { 11315 aptr = argptr; 11316 name = *aptr; 11317 if (name) { 11318 do { 11319 p = strchr(name, '='); 11320 if (p != NULL) { 11321 p++; 11322 } else { 11323 vp = *findvar(hashvar(name), name); 11324 if (vp) { 11325 vp->flags |= flag; 11326 continue; 11327 } 12232 11328 } 12233 }12234 setvar(name, p, flag);12235 } while ((name = *++aptr) != NULL);12236 } else {12237 showvars(argv[0], flag, 0);12238 }11329 setvar(name, p, flag); 11330 } while ((name = *++aptr) != NULL); 11331 return 0; 11332 } 11333 } 11334 showvars(argv[0], flag, 0); 12239 11335 return 0; 12240 11336 } 12241 11337 12242 12243 /* 12244 * Make a variable a local variable. When a variable is made local, it's 12245 * value and flags are saved in a localvar structure. The saved values 12246 * will be restored when the shell function returns. We handle the name 12247 * "-" as a special case. 12248 */ 12249 12250 static inline void 12251 mklocal(char *name) 12252 { 12253 struct localvar *lvp; 12254 struct var **vpp; 12255 struct var *vp; 12256 12257 INTOFF; 12258 lvp = ckmalloc(sizeof (struct localvar)); 12259 if (name[0] == '-' && name[1] == '\0') { 12260 char *p; 12261 p = ckmalloc(sizeof(optlist)); 12262 lvp->text = memcpy(p, optlist, sizeof(optlist)); 12263 vp = NULL; 12264 } else { 12265 char *eq; 12266 12267 vpp = hashvar(name); 12268 vp = *findvar(vpp, name); 12269 eq = strchr(name, '='); 12270 if (vp == NULL) { 12271 if (eq) 12272 setvareq(name, VSTRFIXED); 12273 else 12274 setvar(name, NULL, VSTRFIXED); 12275 vp = *vpp; /* the new variable */ 12276 lvp->flags = VUNSET; 12277 } else { 12278 lvp->text = vp->text; 12279 lvp->flags = vp->flags; 12280 vp->flags |= VSTRFIXED|VTEXTFIXED; 12281 if (eq) 12282 setvareq(name, 0); 12283 } 12284 } 12285 lvp->vp = vp; 12286 lvp->next = localvars; 12287 localvars = lvp; 12288 INTON; 12289 } 12290 12291 /* 12292 * The "local" command. 12293 */ 12294 12295 static int 12296 localcmd(int argc, char **argv) 12297 { 12298 char *name; 12299 12300 argv = argptr; 12301 while ((name = *argv++) != NULL) { 12302 mklocal(name); 12303 } 12304 return 0; 12305 } 12306 12307 12308 /* 12309 * Called after a function returns. 12310 * Interrupts must be off. 12311 */ 12312 12313 static void 12314 poplocalvars(void) 12315 { 12316 struct localvar *lvp; 12317 struct var *vp; 12318 12319 while ((lvp = localvars) != NULL) { 12320 localvars = lvp->next; 12321 vp = lvp->vp; 12322 TRACE(("poplocalvar %s", vp ? vp->text : "-")); 12323 if (vp == NULL) { /* $- saved */ 12324 memcpy(optlist, lvp->text, sizeof(optlist)); 12325 ckfree(lvp->text); 12326 optschanged(); 12327 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { 12328 unsetvar(vp->text); 12329 } else { 12330 if (vp->func) 12331 (*vp->func)(strchrnul(lvp->text, '=') + 1); 12332 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) 12333 ckfree(vp->text); 12334 vp->flags = lvp->flags; 12335 vp->text = lvp->text; 12336 } 12337 ckfree(lvp); 12338 } 12339 } 12340 11338 /* 11339 * Delete a function if it exists. 11340 */ 11341 static void 11342 unsetfunc(const char *name) 11343 { 11344 struct tblentry *cmdp; 11345 11346 cmdp = cmdlookup(name, 0); 11347 if (cmdp!= NULL && cmdp->cmdtype == CMDFUNCTION) 11348 delete_cmd_entry(); 11349 } 12341 11350 12342 11351 /* … … 12345 11354 * with the same name. 12346 11355 */ 12347 12348 int 11356 static int 12349 11357 unsetcmd(int argc, char **argv) 12350 11358 { … … 12358 11366 } 12359 11367 12360 for (ap = argptr; *ap 11368 for (ap = argptr; *ap; ap++) { 12361 11369 if (flag != 'f') { 12362 11370 i = unsetvar(*ap); … … 12372 11380 12373 11381 12374 /*12375 * Unset the specified variable.12376 */12377 12378 int12379 unsetvar(const char *s)12380 {12381 struct var **vpp;12382 struct var *vp;12383 int retval;12384 12385 vpp = findvar(hashvar(s), s);12386 vp = *vpp;12387 retval = 2;12388 if (vp) {12389 int flags = vp->flags;12390 12391 retval = 1;12392 if (flags & VREADONLY)12393 goto out;12394 #ifdef DYNAMIC_VAR12395 vp->flags &= ~VDYNAMIC;12396 #endif12397 if (flags & VUNSET)12398 goto ok;12399 if ((flags & VSTRFIXED) == 0) {12400 INTOFF;12401 if ((flags & (VTEXTFIXED|VSTACK)) == 0)12402 ckfree(vp->text);12403 *vpp = vp->next;12404 ckfree(vp);12405 INTON;12406 } else {12407 setvar(s, 0, 0);12408 vp->flags &= ~VEXPORT;12409 }12410 ok:12411 retval = 0;12412 }12413 12414 out:12415 return retval;12416 }12417 12418 12419 12420 /*12421 * Find the appropriate entry in the hash table from the name.12422 */12423 12424 static struct var **12425 hashvar(const char *p)12426 {12427 unsigned int hashval;12428 12429 hashval = ((unsigned char) *p) << 4;12430 while (*p && *p != '=')12431 hashval += (unsigned char) *p++;12432 return &vartab[hashval % VTABSIZE];12433 }12434 12435 12436 12437 /*12438 * Compares two strings up to the first = or '\0'. The first12439 * string must be terminated by '='; the second may be terminated by12440 * either '=' or '\0'.12441 */12442 12443 int12444 varcmp(const char *p, const char *q)12445 {12446 int c, d;12447 12448 while ((c = *p) == (d = *q)) {12449 if (!c || c == '=')12450 goto out;12451 p++;12452 q++;12453 }12454 if (c == '=')12455 c = 0;12456 if (d == '=')12457 d = 0;12458 out:12459 return c - d;12460 }12461 12462 static int12463 vpcmp(const void *a, const void *b)12464 {12465 return varcmp(*(const char **)a, *(const char **)b);12466 }12467 12468 static struct var **12469 findvar(struct var **vpp, const char *name)12470 {12471 for (; *vpp; vpp = &(*vpp)->next) {12472 if (varequal((*vpp)->text, name)) {12473 break;12474 }12475 }12476 return vpp;12477 }12478 11382 /* setmode.c */ 12479 11383 12480 11384 #include <sys/times.h> 12481 11385 12482 static const unsigned char timescmd_str[] = {11386 static const unsigned char timescmd_str[] ALIGN1 = { 12483 11387 ' ', offsetof(struct tms, tms_utime), 12484 11388 '\n', offsetof(struct tms, tms_stime), … … 12488 11392 }; 12489 11393 12490 static int timescmd(int ac, char **av) 12491 { 12492 long int clk_tck, s, t; 11394 static int 11395 timescmd(int ac, char **av) 11396 { 11397 long clk_tck, s, t; 12493 11398 const unsigned char *p; 12494 11399 struct tms buf; … … 12510 11415 } 12511 11416 12512 #if def CONFIG_ASH_MATH_SUPPORT11417 #if ENABLE_ASH_MATH_SUPPORT 12513 11418 static arith_t 12514 11419 dash_arith(const char *s) … … 12517 11422 int errcode = 0; 12518 11423 12519 INT OFF;11424 INT_OFF; 12520 11425 result = arith(s, &errcode); 12521 11426 if (errcode < 0) { 12522 11427 if (errcode == -3) 12523 sh_error("exponent less than 0"); 12524 else if (errcode == -2) 12525 sh_error("divide by zero"); 12526 else if (errcode == -5) 12527 sh_error("expression recursion loop detected"); 12528 else 12529 synerror(s); 12530 } 12531 INTON; 12532 12533 return (result); 12534 } 12535 11428 ash_msg_and_raise_error("exponent less than 0"); 11429 if (errcode == -2) 11430 ash_msg_and_raise_error("divide by zero"); 11431 if (errcode == -5) 11432 ash_msg_and_raise_error("expression recursion loop detected"); 11433 raise_error_syntax(s); 11434 } 11435 INT_ON; 11436 11437 return result; 11438 } 12536 11439 12537 11440 /* … … 12541 11444 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> 12542 11445 */ 12543 12544 11446 static int 12545 11447 letcmd(int argc, char **argv) 12546 11448 { 12547 11449 char **ap; 12548 arith_t i ;11450 arith_t i = 0; 12549 11451 12550 11452 ap = argv + 1; 12551 if (!*ap)12552 sh_error("expression expected");11453 if (!*ap) 11454 ash_msg_and_raise_error("expression expected"); 12553 11455 for (ap = argv + 1; *ap; ap++) { 12554 11456 i = dash_arith(*ap); 12555 11457 } 12556 11458 12557 return (!i);12558 } 12559 #endif /* CONFIG_ASH_MATH_SUPPORT */12560 12561 /* miscbltin.c */ 12562 12563 /*11459 return !i; 11460 } 11461 #endif /* ASH_MATH_SUPPORT */ 11462 11463 11464 /* ============ miscbltin.c 11465 * 12564 11466 * Miscellaneous builtins. 12565 11467 */ … … 12567 11469 #undef rflag 12568 11470 12569 #ifdef __GLIBC__ 12570 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 11471 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 12571 11472 typedef enum __rlimit_resource rlim_t; 12572 11473 #endif 12573 #endif12574 12575 11474 12576 11475 /* … … 12580 11479 * This uses unbuffered input, which may be avoidable in some cases. 12581 11480 */ 12582 12583 11481 static int 12584 11482 readcmd(int argc, char **argv) … … 12594 11492 int status; 12595 11493 int i; 12596 #if defined(CONFIG_ASH_READ_NCHARS)11494 #if ENABLE_ASH_READ_NCHARS 12597 11495 int nch_flag = 0; 12598 11496 int nchars = 0; … … 12600 11498 struct termios tty, old_tty; 12601 11499 #endif 12602 #if defined(CONFIG_ASH_READ_TIMEOUT)11500 #if ENABLE_ASH_READ_TIMEOUT 12603 11501 fd_set set; 12604 11502 struct timeval ts; … … 12609 11507 rflag = 0; 12610 11508 prompt = NULL; 12611 #if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)11509 #if ENABLE_ASH_READ_NCHARS && ENABLE_ASH_READ_TIMEOUT 12612 11510 while ((i = nextopt("p:rt:n:s")) != '\0') 12613 #elif defined(CONFIG_ASH_READ_NCHARS)11511 #elif ENABLE_ASH_READ_NCHARS 12614 11512 while ((i = nextopt("p:rn:s")) != '\0') 12615 #elif defined(CONFIG_ASH_READ_TIMEOUT)11513 #elif ENABLE_ASH_READ_TIMEOUT 12616 11514 while ((i = nextopt("p:rt:")) != '\0') 12617 11515 #else … … 12619 11517 #endif 12620 11518 { 12621 switch (i) {11519 switch (i) { 12622 11520 case 'p': 12623 11521 prompt = optionarg; 12624 11522 break; 12625 #if defined(CONFIG_ASH_READ_NCHARS)11523 #if ENABLE_ASH_READ_NCHARS 12626 11524 case 'n': 12627 11525 nchars = strtol(optionarg, &p, 10); 12628 11526 if (*p) 12629 sh_error("invalid count");11527 ash_msg_and_raise_error("invalid count"); 12630 11528 nch_flag = (nchars > 0); 12631 11529 break; … … 12634 11532 break; 12635 11533 #endif 12636 #if defined(CONFIG_ASH_READ_TIMEOUT)11534 #if ENABLE_ASH_READ_TIMEOUT 12637 11535 case 't': 12638 11536 ts.tv_sec = strtol(optionarg, &p, 10); … … 12644 11542 ts.tv_usec = strtol(p, &p2, 10); 12645 11543 if (*p2) 12646 sh_error("invalid timeout");11544 ash_msg_and_raise_error("invalid timeout"); 12647 11545 scale = p2 - p; 12648 11546 /* normalize to usec */ 12649 11547 if (scale > 6) 12650 sh_error("invalid timeout");11548 ash_msg_and_raise_error("invalid timeout"); 12651 11549 while (scale++ < 6) 12652 11550 ts.tv_usec *= 10; 12653 11551 } 12654 11552 } else if (*p) { 12655 sh_error("invalid timeout");11553 ash_msg_and_raise_error("invalid timeout"); 12656 11554 } 12657 11555 if ( ! ts.tv_sec && ! ts.tv_usec) 12658 sh_error("invalid timeout");11556 ash_msg_and_raise_error("invalid timeout"); 12659 11557 break; 12660 11558 #endif … … 12669 11567 out2str(prompt); 12670 11568 } 12671 if (*(ap = argptr) == NULL) 12672 sh_error("arg count"); 12673 if ((ifs = bltinlookup("IFS")) == NULL) 11569 ap = argptr; 11570 if (*ap == NULL) 11571 ash_msg_and_raise_error("arg count"); 11572 ifs = bltinlookup("IFS"); 11573 if (ifs == NULL) 12674 11574 ifs = defifs; 12675 #if defined(CONFIG_ASH_READ_NCHARS)11575 #if ENABLE_ASH_READ_NCHARS 12676 11576 if (nch_flag || silent) { 12677 11577 tcgetattr(0, &tty); 12678 11578 old_tty = tty; 12679 11579 if (nch_flag) { 12680 12681 11580 tty.c_lflag &= ~ICANON; 11581 tty.c_cc[VMIN] = nchars; 12682 11582 } 12683 11583 if (silent) { 12684 11584 tty.c_lflag &= ~(ECHO|ECHOK|ECHONL); 12685 11585 12686 11586 } … … 12688 11588 } 12689 11589 #endif 12690 #if defined(CONFIG_ASH_READ_TIMEOUT)11590 #if ENABLE_ASH_READ_TIMEOUT 12691 11591 if (ts.tv_sec || ts.tv_usec) { 12692 FD_ZERO 12693 FD_SET 12694 12695 i = select 11592 FD_ZERO(&set); 11593 FD_SET(0, &set); 11594 11595 i = select(FD_SETSIZE, &set, NULL, NULL, &ts); 12696 11596 if (!i) { 12697 #if defined(CONFIG_ASH_READ_NCHARS)11597 #if ENABLE_ASH_READ_NCHARS 12698 11598 if (nch_flag) 12699 11599 tcsetattr(0, TCSANOW, &old_tty); … … 12707 11607 backslash = 0; 12708 11608 STARTSTACKSTR(p); 12709 #if defined(CONFIG_ASH_READ_NCHARS)11609 #if ENABLE_ASH_READ_NCHARS 12710 11610 while (!nch_flag || nchars--) 12711 11611 #else … … 12742 11642 STARTSTACKSTR(p); 12743 11643 } else { 12744 put:11644 put: 12745 11645 STPUTC(c, p); 12746 11646 } 12747 11647 } 12748 #if defined(CONFIG_ASH_READ_NCHARS)11648 #if ENABLE_ASH_READ_NCHARS 12749 11649 if (nch_flag || silent) 12750 11650 tcsetattr(0, TCSANOW, &old_tty); … … 12761 11661 } 12762 11662 12763 12764 static intumaskcmd(int argc, char **argv)12765 { 12766 static const char permuser[3] = "ugo";12767 static const char permmode[3] = "rwx";12768 static const short int permmask[]= {11663 static int 11664 umaskcmd(int argc, char **argv) 11665 { 11666 static const char permuser[3] ALIGN1 = "ugo"; 11667 static const char permmode[3] ALIGN1 = "rwx"; 11668 static const short permmask[] ALIGN2 = { 12769 11669 S_IRUSR, S_IWUSR, S_IXUSR, 12770 11670 S_IRGRP, S_IWGRP, S_IXGRP, … … 12781 11681 } 12782 11682 12783 INT OFF;11683 INT_OFF; 12784 11684 mask = umask(0); 12785 11685 umask(mask); 12786 INTON; 12787 12788 if ((ap = *argptr) == NULL) { 11686 INT_ON; 11687 11688 ap = *argptr; 11689 if (ap == NULL) { 12789 11690 if (symbolic_mode) { 12790 11691 char buf[18]; … … 12809 11710 } 12810 11711 } else { 12811 if (is _digit((unsigned char) *ap)) {11712 if (isdigit((unsigned char) *ap)) { 12812 11713 mask = 0; 12813 11714 do { 12814 11715 if (*ap >= '8' || *ap < '0') 12815 sh_error(illnum, argv[1]);11716 ash_msg_and_raise_error(illnum, argv[1]); 12816 11717 mask = (mask << 3) + (*ap - '0'); 12817 11718 } while (*++ap != '\0'); … … 12820 11721 mask = ~mask & 0777; 12821 11722 if (!bb_parse_mode(ap, &mask)) { 12822 sh_error("Illegal mode: %s", ap);11723 ash_msg_and_raise_error("illegal mode: %s", ap); 12823 11724 } 12824 11725 umask(~mask & 0777); … … 12879 11780 { "locks", RLIMIT_LOCKS, 1, 'w' }, 12880 11781 #endif 12881 { (char *) 0,0, 0, '\0' }11782 { NULL, 0, 0, '\0' } 12882 11783 }; 12883 11784 12884 11785 enum limtype { SOFT = 0x1, HARD = 0x2 }; 12885 11786 12886 static void printlim(enum limtype how, const struct rlimit *limit, 11787 static void 11788 printlim(enum limtype how, const struct rlimit *limit, 12887 11789 const struct limits *l) 12888 11790 { … … 12901 11803 } 12902 11804 12903 int11805 static int 12904 11806 ulimitcmd(int argc, char **argv) 12905 11807 { 12906 int 11808 int c; 12907 11809 rlim_t val = 0; 12908 11810 enum limtype how = SOFT | HARD; 12909 const struct limits 12910 int 12911 int 12912 struct rlimit 11811 const struct limits *l; 11812 int set, all = 0; 11813 int optc, what; 11814 struct rlimit limit; 12913 11815 12914 11816 what = 'f'; … … 12947 11849 "w" 12948 11850 #endif 12949 11851 )) != '\0') 12950 11852 switch (optc) { 12951 11853 case 'H': … … 12970 11872 12971 11873 if (all || argptr[1]) 12972 sh_error("too many arguments");11874 ash_msg_and_raise_error("too many arguments"); 12973 11875 if (strncmp(p, "unlimited\n", 9) == 0) 12974 11876 val = RLIM_INFINITY; … … 12976 11878 val = (rlim_t) 0; 12977 11879 12978 while ((c = *p++) >= '0' && c <= '9') 12979 { 11880 while ((c = *p++) >= '0' && c <= '9') { 12980 11881 val = (val * 10) + (long)(c - '0'); 12981 11882 if (val < (rlim_t) 0) … … 12983 11884 } 12984 11885 if (c) 12985 sh_error("bad number");11886 ash_msg_and_raise_error("bad number"); 12986 11887 val *= l->factor; 12987 11888 } … … 13003 11904 limit.rlim_cur = val; 13004 11905 if (setrlimit(l->cmd, &limit) < 0) 13005 sh_error("error setting limit (%m)");11906 ash_msg_and_raise_error("error setting limit (%m)"); 13006 11907 } else { 13007 11908 printlim(how, &limit, l); … … 13011 11912 13012 11913 13013 #ifdef CONFIG_ASH_MATH_SUPPORT 11914 /* ============ Math support */ 11915 11916 #if ENABLE_ASH_MATH_SUPPORT 13014 11917 13015 11918 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com> … … 13107 12010 */ 13108 12011 13109 13110 12012 #define arith_isspace(arithval) \ 13111 12013 (arithval == ' ' || arithval == '\n' || arithval == '\t') 13112 13113 12014 13114 12015 typedef unsigned char operator; … … 13141 12042 13142 12043 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */ 13143 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while(0)12044 #define convert_prec_is_assing(prec) do { if (prec == 3) prec = 2; } while (0) 13144 12045 13145 12046 /* conditional is right associativity too */ … … 13203 12104 #define NUMPTR (*numstackptr) 13204 12105 13205 static inline int tok_have_assign(operator op) 12106 static int 12107 tok_have_assign(operator op) 13206 12108 { 13207 12109 operator prec = PREC(op); … … 13212 12114 } 13213 12115 13214 static in line int is_right_associativity(operator prec)13215 { 13216 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) || 13217 prec == PREC(TOK_CONDITIONAL));13218 } 13219 12116 static int 12117 is_right_associativity(operator prec) 12118 { 12119 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) 12120 || prec == PREC(TOK_CONDITIONAL)); 12121 } 13220 12122 13221 12123 typedef struct ARITCH_VAR_NUM { … … 13227 12129 } v_n_t; 13228 12130 13229 13230 12131 typedef struct CHK_VAR_RECURSIVE_LOOPED { 13231 12132 const char *var; … … 13235 12136 static chk_var_recursive_looped_t *prev_chk_var_recursive; 13236 12137 13237 13238 static int arith_lookup_val(v_n_t *t) 13239 { 13240 if(t->var) { 13241 const char * p = lookupvar(t->var); 13242 13243 if(p) { 13244 int errcode; 13245 13246 /* recursive try as expression */ 13247 chk_var_recursive_looped_t *cur; 13248 chk_var_recursive_looped_t cur_save; 13249 13250 for(cur = prev_chk_var_recursive; cur; cur = cur->next) { 13251 if(strcmp(cur->var, t->var) == 0) { 13252 /* expression recursion loop detected */ 13253 return -5; 13254 } 13255 } 13256 /* save current lookuped var name */ 13257 cur = prev_chk_var_recursive; 13258 cur_save.var = t->var; 13259 cur_save.next = cur; 13260 prev_chk_var_recursive = &cur_save; 13261 13262 t->val = arith (p, &errcode); 13263 /* restore previous ptr after recursiving */ 13264 prev_chk_var_recursive = cur; 13265 return errcode; 13266 } else { 13267 /* allow undefined var as 0 */ 13268 t->val = 0; 13269 } 13270 } 13271 return 0; 12138 static int 12139 arith_lookup_val(v_n_t *t) 12140 { 12141 if (t->var) { 12142 const char * p = lookupvar(t->var); 12143 12144 if (p) { 12145 int errcode; 12146 12147 /* recursive try as expression */ 12148 chk_var_recursive_looped_t *cur; 12149 chk_var_recursive_looped_t cur_save; 12150 12151 for (cur = prev_chk_var_recursive; cur; cur = cur->next) { 12152 if (strcmp(cur->var, t->var) == 0) { 12153 /* expression recursion loop detected */ 12154 return -5; 12155 } 12156 } 12157 /* save current lookuped var name */ 12158 cur = prev_chk_var_recursive; 12159 cur_save.var = t->var; 12160 cur_save.next = cur; 12161 prev_chk_var_recursive = &cur_save; 12162 12163 t->val = arith (p, &errcode); 12164 /* restore previous ptr after recursiving */ 12165 prev_chk_var_recursive = cur; 12166 return errcode; 12167 } 12168 /* allow undefined var as 0 */ 12169 t->val = 0; 12170 } 12171 return 0; 13272 12172 } 13273 12173 … … 13275 12175 * stack. For a unary operator it will only change the top element, but a 13276 12176 * binary operator will pop two arguments and push a result */ 13277 static in line int12177 static int 13278 12178 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) 13279 12179 { … … 13282 12182 int ret_arith_lookup_val; 13283 12183 13284 if (NUMPTR == numstack) goto err; /* There is no operator that can work13285 without arguments */12184 /* There is no operator that can work without arguments */ 12185 if (NUMPTR == numstack) goto err; 13286 12186 numptr_m1 = NUMPTR - 1; 13287 12187 13288 12188 /* check operand is var with noninteger value */ 13289 12189 ret_arith_lookup_val = arith_lookup_val(numptr_m1); 13290 if (ret_arith_lookup_val)12190 if (ret_arith_lookup_val) 13291 12191 return ret_arith_lookup_val; 13292 12192 … … 13305 12205 /* Binary operators */ 13306 12206 13307 13308 13309 13310 13311 13312 13313 13314 if(! numptr_m1->contidional_second_val_initialized) {13315 13316 13317 }13318 rez = numptr_m1->contidional_second_val;13319 } else if(numptr_m1->contidional_second_val_initialized) {13320 13321 13322 13323 13324 if(op != TOK_ASSIGN) {13325 /* check operand is var with noninteger value for not '=' */13326 ret_arith_lookup_val = arith_lookup_val(numptr_m1);13327 if(ret_arith_lookup_val)13328 13329 13330 13331 13332 13333 13334 12207 /* check and binary operators need two arguments */ 12208 if (numptr_m1 == numstack) goto err; 12209 12210 /* ... and they pop one */ 12211 --NUMPTR; 12212 numptr_val = rez; 12213 if (op == TOK_CONDITIONAL) { 12214 if (! numptr_m1->contidional_second_val_initialized) { 12215 /* protect $((expr1 ? expr2)) without ": expr" */ 12216 goto err; 12217 } 12218 rez = numptr_m1->contidional_second_val; 12219 } else if (numptr_m1->contidional_second_val_initialized) { 12220 /* protect $((expr1 : expr2)) without "expr ? " */ 12221 goto err; 12222 } 12223 numptr_m1 = NUMPTR - 1; 12224 if (op != TOK_ASSIGN) { 12225 /* check operand is var with noninteger value for not '=' */ 12226 ret_arith_lookup_val = arith_lookup_val(numptr_m1); 12227 if (ret_arith_lookup_val) 12228 return ret_arith_lookup_val; 12229 } 12230 if (op == TOK_CONDITIONAL) { 12231 numptr_m1->contidional_second_val = rez; 12232 } 12233 rez = numptr_m1->val; 12234 if (op == TOK_BOR || op == TOK_OR_ASSIGN) 13335 12235 rez |= numptr_val; 13336 12236 else if (op == TOK_OR) 13337 12237 rez = numptr_val || rez; 13338 12238 else if (op == TOK_BAND || op == TOK_AND_ASSIGN) 13339 12239 rez &= numptr_val; 13340 12240 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN) 13341 12241 rez ^= numptr_val; 13342 12242 else if (op == TOK_AND) 13343 12243 rez = rez && numptr_val; 13344 12244 else if (op == TOK_EQ) 13345 12245 rez = (rez == numptr_val); 13346 12246 else if (op == TOK_NE) 13347 12247 rez = (rez != numptr_val); 13348 12248 else if (op == TOK_GE) 13349 12249 rez = (rez >= numptr_val); 13350 12250 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN) 13351 12251 rez >>= numptr_val; 13352 12252 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN) 13353 12253 rez <<= numptr_val; 13354 12254 else if (op == TOK_GT) 13355 12255 rez = (rez > numptr_val); 13356 12256 else if (op == TOK_LT) 13357 12257 rez = (rez < numptr_val); 13358 12258 else if (op == TOK_LE) 13359 12259 rez = (rez <= numptr_val); 13360 12260 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN) 13361 12261 rez *= numptr_val; 13362 12262 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN) 13363 12263 rez += numptr_val; 13364 12264 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN) 13365 12265 rez -= numptr_val; 13366 12266 else if (op == TOK_ASSIGN || op == TOK_COMMA) 13367 12267 rez = numptr_val; 13368 12268 else if (op == TOK_CONDITIONAL_SEP) { 13369 12269 if (numptr_m1 == numstack) { 13370 13371 12270 /* protect $((expr : expr)) without "expr ? " */ 12271 goto err; 13372 12272 } 13373 12273 numptr_m1->contidional_second_val_initialized = op; 13374 12274 numptr_m1->contidional_second_val = numptr_val; 13375 } 13376 else if (op == TOK_CONDITIONAL) { 12275 } else if (op == TOK_CONDITIONAL) { 13377 12276 rez = rez ? 13378 numptr_val : numptr_m1->contidional_second_val; 13379 } 13380 else if(op == TOK_EXPONENT) { 13381 if(numptr_val < 0) 12277 numptr_val : numptr_m1->contidional_second_val; 12278 } else if (op == TOK_EXPONENT) { 12279 if (numptr_val < 0) 13382 12280 return -3; /* exponent less than 0 */ 13383 12281 else { 13384 12282 arith_t c = 1; 13385 12283 13386 if (numptr_val)13387 while (numptr_val--)12284 if (numptr_val) 12285 while (numptr_val--) 13388 12286 c *= rez; 13389 12287 rez = c; 13390 12288 } 13391 } 13392 else if(numptr_val==0) /* zero divisor check */ 12289 } else if (numptr_val==0) /* zero divisor check */ 13393 12290 return -2; 13394 12291 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) 13395 12292 rez /= numptr_val; 13396 12293 else if (op == TOK_REM || op == TOK_REM_ASSIGN) 13397 12294 rez %= numptr_val; 13398 12295 } 13399 if (tok_have_assign(op)) {13400 char buf[ 32];13401 13402 if (numptr_m1->var == NULL) {12296 if (tok_have_assign(op)) { 12297 char buf[sizeof(arith_t_type)*3 + 2]; 12298 12299 if (numptr_m1->var == NULL) { 13403 12300 /* Hmm, 1=2 ? */ 13404 12301 goto err; 13405 12302 } 13406 12303 /* save to shell variable */ 13407 #if def CONFIG_ASH_MATH_SUPPORT_6413408 snprintf(buf, sizeof(buf), "%lld", arith_t_typerez);12304 #if ENABLE_ASH_MATH_SUPPORT_64 12305 snprintf(buf, sizeof(buf), "%lld", (arith_t_type) rez); 13409 12306 #else 13410 snprintf(buf, sizeof(buf), "%ld", arith_t_typerez);12307 snprintf(buf, sizeof(buf), "%ld", (arith_t_type) rez); 13411 12308 #endif 13412 12309 setvar(numptr_m1->var, buf, 0); 13413 12310 /* after saving, make previous value for v++ or v-- */ 13414 if (op == TOK_POST_INC)12311 if (op == TOK_POST_INC) 13415 12312 rez--; 13416 else if (op == TOK_POST_DEC)12313 else if (op == TOK_POST_DEC) 13417 12314 rez++; 13418 12315 } … … 13421 12318 numptr_m1->var = NULL; 13422 12319 return 0; 13423 err: return(-1); 13424 } 13425 13426 /* longest must first */ 13427 static const char op_tokens[] = { 12320 err: 12321 return -1; 12322 } 12323 12324 /* longest must be first */ 12325 static const char op_tokens[] ALIGN1 = { 13428 12326 '<','<','=',0, TOK_LSHIFT_ASSIGN, 13429 12327 '>','>','=',0, TOK_RSHIFT_ASSIGN, … … 13471 12369 #define endexpression &op_tokens[sizeof(op_tokens)-7] 13472 12370 13473 13474 static arith_t arith (const char *expr, int *perrcode) 13475 { 13476 register char arithval; /* Current character under analysis */ 13477 operator lasttok, op; 13478 operator prec; 13479 13480 const char *p = endexpression; 13481 int errcode; 13482 13483 size_t datasizes = strlen(expr) + 2; 13484 13485 /* Stack of integers */ 13486 /* The proof that there can be no more than strlen(startbuf)/2+1 integers 13487 * in any given correct or incorrect expression is left as an exercise to 13488 * the reader. */ 13489 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)), 13490 *numstackptr = numstack; 13491 /* Stack of operator tokens */ 13492 operator *stack = alloca((datasizes) * sizeof(operator)), 13493 *stackptr = stack; 13494 13495 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ 13496 *perrcode = errcode = 0; 13497 13498 while(1) { 13499 if ((arithval = *expr) == 0) { 13500 if (p == endexpression) { 13501 /* Null expression. */ 13502 return 0; 13503 } 13504 13505 /* This is only reached after all tokens have been extracted from the 13506 * input stream. If there are still tokens on the operator stack, they 13507 * are to be applied in order. At the end, there should be a final 13508 * result on the integer stack */ 13509 13510 if (expr != endexpression + 1) { 13511 /* If we haven't done so already, */ 13512 /* append a closing right paren */ 13513 expr = endexpression; 13514 /* and let the loop process it. */ 13515 continue; 13516 } 13517 /* At this point, we're done with the expression. */ 13518 if (numstackptr != numstack+1) { 13519 /* ... but if there isn't, it's bad */ 13520 err: 13521 return (*perrcode = -1); 13522 } 13523 if(numstack->var) { 13524 /* expression is $((var)) only, lookup now */ 13525 errcode = arith_lookup_val(numstack); 13526 } 13527 ret: 13528 *perrcode = errcode; 13529 return numstack->val; 13530 } else { 12371 static arith_t 12372 arith(const char *expr, int *perrcode) 12373 { 12374 char arithval; /* Current character under analysis */ 12375 operator lasttok, op; 12376 operator prec; 12377 12378 const char *p = endexpression; 12379 int errcode; 12380 12381 size_t datasizes = strlen(expr) + 2; 12382 12383 /* Stack of integers */ 12384 /* The proof that there can be no more than strlen(startbuf)/2+1 integers 12385 * in any given correct or incorrect expression is left as an exercise to 12386 * the reader. */ 12387 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)), 12388 *numstackptr = numstack; 12389 /* Stack of operator tokens */ 12390 operator *stack = alloca((datasizes) * sizeof(operator)), 12391 *stackptr = stack; 12392 12393 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ 12394 *perrcode = errcode = 0; 12395 12396 while (1) { 12397 arithval = *expr; 12398 if (arithval == 0) { 12399 if (p == endexpression) { 12400 /* Null expression. */ 12401 return 0; 12402 } 12403 12404 /* This is only reached after all tokens have been extracted from the 12405 * input stream. If there are still tokens on the operator stack, they 12406 * are to be applied in order. At the end, there should be a final 12407 * result on the integer stack */ 12408 12409 if (expr != endexpression + 1) { 12410 /* If we haven't done so already, */ 12411 /* append a closing right paren */ 12412 expr = endexpression; 12413 /* and let the loop process it. */ 12414 continue; 12415 } 12416 /* At this point, we're done with the expression. */ 12417 if (numstackptr != numstack+1) { 12418 /* ... but if there isn't, it's bad */ 12419 err: 12420 return (*perrcode = -1); 12421 } 12422 if (numstack->var) { 12423 /* expression is $((var)) only, lookup now */ 12424 errcode = arith_lookup_val(numstack); 12425 } 12426 ret: 12427 *perrcode = errcode; 12428 return numstack->val; 12429 } 12430 13531 12431 /* Continue processing the expression. */ 13532 12432 if (arith_isspace(arithval)) { … … 13534 12434 goto prologue; 13535 12435 } 13536 if((p = endofname(expr)) != expr) { 12436 p = endofname(expr); 12437 if (p != expr) { 13537 12438 size_t var_name_size = (p-expr) + 1; /* trailing zero */ 13538 12439 … … 13540 12441 safe_strncpy(numstackptr->var, expr, var_name_size); 13541 12442 expr = p; 13542 12443 num: 13543 12444 numstackptr->contidional_second_val_initialized = 0; 13544 12445 numstackptr++; 13545 12446 lasttok = TOK_NUM; 13546 12447 continue; 13547 } else if (is_digit(arithval)) { 12448 } 12449 if (isdigit(arithval)) { 13548 12450 numstackptr->var = NULL; 13549 #if def CONFIG_ASH_MATH_SUPPORT_6412451 #if ENABLE_ASH_MATH_SUPPORT_64 13550 12452 numstackptr->val = strtoll(expr, (char **) &expr, 0); 13551 12453 #else … … 13554 12456 goto num; 13555 12457 } 13556 for (p = op_tokens; ; p++) {12458 for (p = op_tokens; ; p++) { 13557 12459 const char *o; 13558 12460 13559 if (*p == 0) {12461 if (*p == 0) { 13560 12462 /* strange operator not found */ 13561 12463 goto err; 13562 12464 } 13563 for (o = expr; *p && *o == *p; p++)12465 for (o = expr; *p && *o == *p; p++) 13564 12466 o++; 13565 if (! *p) {12467 if (! *p) { 13566 12468 /* found */ 13567 12469 expr = o - 1; … … 13569 12471 } 13570 12472 /* skip tail uncompared token */ 13571 while (*p)12473 while (*p) 13572 12474 p++; 13573 12475 /* skip zero delim */ … … 13577 12479 13578 12480 /* post grammar: a++ reduce to num */ 13579 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)13580 12481 if (lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC) 12482 lasttok = TOK_NUM; 13581 12483 13582 12484 /* Plus and minus are binary (not unary) _only_ if the last … … 13585 12487 * It makes sense. */ 13586 12488 if (lasttok != TOK_NUM) { 13587 switch (op) {13588 13589 13590 13591 13592 13593 13594 13595 13596 13597 13598 13599 12489 switch (op) { 12490 case TOK_ADD: 12491 op = TOK_UPLUS; 12492 break; 12493 case TOK_SUB: 12494 op = TOK_UMINUS; 12495 break; 12496 case TOK_POST_INC: 12497 op = TOK_PRE_INC; 12498 break; 12499 case TOK_POST_DEC: 12500 op = TOK_PRE_DEC; 12501 break; 13600 12502 } 13601 12503 } … … 13619 12521 } 13620 12522 while (stackptr != stack) { 13621 if (op == TOK_RPAREN) { 13622 /* The algorithm employed here is simple: while we don't 13623 * hit an open paren nor the bottom of the stack, pop 13624 * tokens and apply them */ 13625 if (stackptr[-1] == TOK_LPAREN) { 13626 --stackptr; 13627 /* Any operator directly after a */ 13628 lasttok = TOK_NUM; 13629 /* close paren should consider itself binary */ 13630 goto prologue; 12523 if (op == TOK_RPAREN) { 12524 /* The algorithm employed here is simple: while we don't 12525 * hit an open paren nor the bottom of the stack, pop 12526 * tokens and apply them */ 12527 if (stackptr[-1] == TOK_LPAREN) { 12528 --stackptr; 12529 /* Any operator directly after a */ 12530 lasttok = TOK_NUM; 12531 /* close paren should consider itself binary */ 12532 goto prologue; 12533 } 12534 } else { 12535 operator prev_prec = PREC(stackptr[-1]); 12536 12537 convert_prec_is_assing(prec); 12538 convert_prec_is_assing(prev_prec); 12539 if (prev_prec < prec) 12540 break; 12541 /* check right assoc */ 12542 if (prev_prec == prec && is_right_associativity(prec)) 12543 break; 13631 12544 } 13632 } else { 13633 operator prev_prec = PREC(stackptr[-1]); 13634 13635 convert_prec_is_assing(prec); 13636 convert_prec_is_assing(prev_prec); 13637 if (prev_prec < prec) 13638 break; 13639 /* check right assoc */ 13640 if(prev_prec == prec && is_right_associativity(prec)) 13641 break; 13642 } 13643 errcode = arith_apply(*--stackptr, numstack, &numstackptr); 13644 if(errcode) goto ret; 12545 errcode = arith_apply(*--stackptr, numstack, &numstackptr); 12546 if (errcode) goto ret; 13645 12547 } 13646 12548 if (op == TOK_RPAREN) { … … 13651 12553 /* Push this operator to the stack and remember it. */ 13652 12554 *stackptr++ = lasttok = op; 13653 13654 prologue: 12555 prologue: 13655 12556 ++expr; 13656 } 13657 } 13658 } 13659 #endif /* CONFIG_ASH_MATH_SUPPORT */ 13660 13661 13662 #ifdef DEBUG 13663 const char *bb_applet_name = "debug stuff usage"; 12557 } /* while */ 12558 } 12559 #endif /* ASH_MATH_SUPPORT */ 12560 12561 12562 /* ============ main() and helpers */ 12563 12564 /* 12565 * Called to exit the shell. 12566 */ 12567 static void exitshell(void) ATTRIBUTE_NORETURN; 12568 static void 12569 exitshell(void) 12570 { 12571 struct jmploc loc; 12572 char *p; 12573 int status; 12574 12575 status = exitstatus; 12576 TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); 12577 if (setjmp(loc.loc)) { 12578 if (exception == EXEXIT) 12579 /* dash bug: it just does _exit(exitstatus) here 12580 * but we have to do setjobctl(0) first! 12581 * (bug is still not fixed in dash-0.5.3 - if you run dash 12582 * under Midnight Commander, on exit from dash MC is backgrounded) */ 12583 status = exitstatus; 12584 goto out; 12585 } 12586 exception_handler = &loc; 12587 p = trap[0]; 12588 if (p) { 12589 trap[0] = NULL; 12590 evalstring(p, 0); 12591 } 12592 flush_stdout_stderr(); 12593 out: 12594 setjobctl(0); 12595 _exit(status); 12596 /* NOTREACHED */ 12597 } 12598 12599 static void 12600 init(void) 12601 { 12602 /* from input.c: */ 12603 basepf.nextc = basepf.buf = basebuf; 12604 12605 /* from trap.c: */ 12606 signal(SIGCHLD, SIG_DFL); 12607 12608 /* from var.c: */ 12609 { 12610 char **envp; 12611 char ppid[sizeof(int)*3 + 1]; 12612 const char *p; 12613 struct stat st1, st2; 12614 12615 initvar(); 12616 for (envp = environ; envp && *envp; envp++) { 12617 if (strchr(*envp, '=')) { 12618 setvareq(*envp, VEXPORT|VTEXTFIXED); 12619 } 12620 } 12621 12622 snprintf(ppid, sizeof(ppid), "%u", (unsigned) getppid()); 12623 setvar("PPID", ppid, 0); 12624 12625 p = lookupvar("PWD"); 12626 if (p) 12627 if (*p != '/' || stat(p, &st1) || stat(".", &st2) 12628 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) 12629 p = '\0'; 12630 setpwd(p, 0); 12631 } 12632 } 12633 12634 /* 12635 * Process the shell command line arguments. 12636 */ 12637 static void 12638 procargs(int argc, char **argv) 12639 { 12640 int i; 12641 const char *xminusc; 12642 char **xargv; 12643 12644 xargv = argv; 12645 arg0 = xargv[0]; 12646 if (argc > 0) 12647 xargv++; 12648 for (i = 0; i < NOPTS; i++) 12649 optlist[i] = 2; 12650 argptr = xargv; 12651 options(1); 12652 xargv = argptr; 12653 xminusc = minusc; 12654 if (*xargv == NULL) { 12655 if (xminusc) 12656 ash_msg_and_raise_error(bb_msg_requires_arg, "-c"); 12657 sflag = 1; 12658 } 12659 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) 12660 iflag = 1; 12661 if (mflag == 2) 12662 mflag = iflag; 12663 for (i = 0; i < NOPTS; i++) 12664 if (optlist[i] == 2) 12665 optlist[i] = 0; 12666 #if DEBUG == 2 12667 debug = 1; 12668 #endif 12669 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ 12670 if (xminusc) { 12671 minusc = *xargv++; 12672 if (*xargv) 12673 goto setarg0; 12674 } else if (!sflag) { 12675 setinputfile(*xargv, 0); 12676 setarg0: 12677 arg0 = *xargv++; 12678 commandname = arg0; 12679 } 12680 12681 shellparam.p = xargv; 12682 #if ENABLE_ASH_GETOPTS 12683 shellparam.optind = 1; 12684 shellparam.optoff = -1; 12685 #endif 12686 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ 12687 while (*xargv) { 12688 shellparam.nparam++; 12689 xargv++; 12690 } 12691 optschanged(); 12692 } 12693 12694 /* 12695 * Read /etc/profile or .profile. 12696 */ 12697 static void 12698 read_profile(const char *name) 12699 { 12700 int skip; 12701 12702 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0) 12703 return; 12704 skip = cmdloop(0); 12705 popfile(); 12706 if (skip) 12707 exitshell(); 12708 } 12709 12710 /* 12711 * This routine is called when an error or an interrupt occurs in an 12712 * interactive shell and control is returned to the main command loop. 12713 */ 12714 static void 12715 reset(void) 12716 { 12717 /* from eval.c: */ 12718 evalskip = 0; 12719 loopnest = 0; 12720 /* from input.c: */ 12721 parselleft = parsenleft = 0; /* clear input buffer */ 12722 popallfiles(); 12723 /* from parser.c: */ 12724 tokpushback = 0; 12725 checkkwd = 0; 12726 /* from redir.c: */ 12727 clearredir(0); 12728 } 12729 12730 #if PROFILE 12731 static short profile_buf[16384]; 12732 extern int etext(); 12733 #endif 12734 12735 /* 12736 * Main routine. We initialize things, parse the arguments, execute 12737 * profiles if we're a login shell, and then call cmdloop to execute 12738 * commands. The setjmp call sets up the location to jump to when an 12739 * exception occurs. When an exception occurs the variable "state" 12740 * is used to figure out how far we had gotten. 12741 */ 12742 int ash_main(int argc, char **argv); 12743 int ash_main(int argc, char **argv) 12744 { 12745 char *shinit; 12746 volatile int state; 12747 struct jmploc jmploc; 12748 struct stackmark smark; 12749 12750 #if PROFILE 12751 monitor(4, etext, profile_buf, sizeof(profile_buf), 50); 12752 #endif 12753 12754 #if ENABLE_FEATURE_EDITING 12755 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); 12756 #endif 12757 state = 0; 12758 if (setjmp(jmploc.loc)) { 12759 int e; 12760 int s; 12761 12762 reset(); 12763 12764 e = exception; 12765 if (e == EXERROR) 12766 exitstatus = 2; 12767 s = state; 12768 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) 12769 exitshell(); 12770 12771 if (e == EXINT) { 12772 outcslow('\n', stderr); 12773 } 12774 popstackmark(&smark); 12775 FORCE_INT_ON; /* enable interrupts */ 12776 if (s == 1) 12777 goto state1; 12778 if (s == 2) 12779 goto state2; 12780 if (s == 3) 12781 goto state3; 12782 goto state4; 12783 } 12784 exception_handler = &jmploc; 12785 #if DEBUG 12786 opentrace(); 12787 trace_puts("Shell args: "); 12788 trace_puts_args(argv); 12789 #endif 12790 rootpid = getpid(); 12791 12792 #if ENABLE_ASH_RANDOM_SUPPORT 12793 rseed = rootpid + time(NULL); 12794 #endif 12795 init(); 12796 setstackmark(&smark); 12797 procargs(argc, argv); 12798 #if ENABLE_FEATURE_EDITING_SAVEHISTORY 12799 if (iflag) { 12800 const char *hp = lookupvar("HISTFILE"); 12801 12802 if (hp == NULL) { 12803 hp = lookupvar("HOME"); 12804 if (hp != NULL) { 12805 char *defhp = concat_path_file(hp, ".ash_history"); 12806 setvar("HISTFILE", defhp, 0); 12807 free(defhp); 12808 } 12809 } 12810 } 12811 #endif 12812 if (argv[0] && argv[0][0] == '-') 12813 isloginsh = 1; 12814 if (isloginsh) { 12815 state = 1; 12816 read_profile("/etc/profile"); 12817 state1: 12818 state = 2; 12819 read_profile(".profile"); 12820 } 12821 state2: 12822 state = 3; 12823 if ( 12824 #ifndef linux 12825 getuid() == geteuid() && getgid() == getegid() && 12826 #endif 12827 iflag 12828 ) { 12829 shinit = lookupvar("ENV"); 12830 if (shinit != NULL && *shinit != '\0') { 12831 read_profile(shinit); 12832 } 12833 } 12834 state3: 12835 state = 4; 12836 if (minusc) 12837 evalstring(minusc, 0); 12838 12839 if (sflag || minusc == NULL) { 12840 #if ENABLE_FEATURE_EDITING_SAVEHISTORY 12841 if ( iflag ) { 12842 const char *hp = lookupvar("HISTFILE"); 12843 12844 if (hp != NULL) 12845 line_input_state->hist_file = hp; 12846 } 12847 #endif 12848 state4: /* XXX ??? - why isn't this before the "if" statement */ 12849 cmdloop(1); 12850 } 12851 #if PROFILE 12852 monitor(0); 12853 #endif 12854 #ifdef GPROF 12855 { 12856 extern void _mcleanup(void); 12857 _mcleanup(); 12858 } 12859 #endif 12860 exitshell(); 12861 /* NOTREACHED */ 12862 } 12863 12864 #if DEBUG 12865 const char *applet_name = "debug stuff usage"; 13664 12866 int main(int argc, char **argv) 13665 12867 { … … 13667 12869 } 13668 12870 #endif 12871 13669 12872 13670 12873 /*-
Note:
See TracChangeset
for help on using the changeset viewer.