1/* sh.c - toybox shell 2 * 3 * Copyright 2006 Rob Landley <rob@landley.net> 4 * 5 * The POSIX-2008/SUSv4 spec for this is at: 6 * http://opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html 7 * and http://opengroup.org/onlinepubs/9699919799/utilities/sh.html 8 * 9 * The first link describes the following shell builtins: 10 * 11 * break colon continue dot eval exec exit export readonly return set shift 12 * times trap unset 13 * 14 * The second link (the utilities directory) also contains specs for the 15 * following shell builtins: 16 * 17 * alias bg cd command fc fg getopts hash jobs kill read type ulimit 18 * umask unalias wait 19 * 20 * Things like the bash man page are good to read too. 21 * 22 * TODO: "make sh" doesn't work (nofork builtins need to be included) 23 * TODO: test that $PS1 color changes work without stupid \[ \] hack 24 * TODO: make fake pty wrapper for test infrastructure 25 * TODO: // Handle embedded NUL bytes in the command line. 26 * TODO: var=val command 27 * existing but considered builtins: false kill pwd true time 28 * buitins: alias bg command fc fg getopts jobs newgrp read umask unalias wait 29 * "special" builtins: break continue : . eval exec export readonly return set 30 * shift times trap unset 31 * | & ; < > ( ) $ ` \ " ' <space> <tab> <newline> 32 * * ? [ # ~ = % 33 * ! { } case do done elif else esac fi for if in then until while 34 * [[ ]] function select 35 * $@ $* $# $? $- $$ $! $0 36 * ENV HOME IFS LANG LC_ALL LINENO PATH PPID PS1 PS2 PS4 PWD 37 * label: 38 * TODO: test exit from "trap EXIT" doesn't recurse 39 * TODO: ! history expansion 40 * 41 * bash man page: 42 * control operators || & && ; ;; ;& ;;& ( ) | |& <newline> 43 * reserved words 44 * ! case coproc do done elif else esac fi for function if in select 45 * then until while { } time [[ ]] 46 47 48 49USE_SH(NEWTOY(cd, NULL, TOYFLAG_NOFORK)) 50USE_SH(NEWTOY(exit, NULL, TOYFLAG_NOFORK)) 51 52USE_SH(NEWTOY(sh, "c:i", TOYFLAG_BIN)) 53USE_SH(OLDTOY(toysh, sh, TOYFLAG_BIN)) 54USE_SH(OLDTOY(bash, sh, TOYFLAG_BIN)) 55// Login lies in argv[0], so add some aliases to catch that 56USE_SH(OLDTOY(-sh, sh, 0)) 57USE_SH(OLDTOY(-toysh, sh, 0)) 58USE_SH(OLDTOY(-bash, sh, 0)) 59 60config SH 61 bool "sh (toysh)" 62 default n 63 help 64 usage: sh [-c command] [script] 65 66 Command shell. Runs a shell script, or reads input interactively 67 and responds to it. 68 69 -c command line to execute 70 -i interactive mode (default when STDIN is a tty) 71 72# These are here for the help text, they're not selectable and control nothing 73config CD 74 bool 75 default n 76 depends on SH 77 help 78 usage: cd [-PL] [path] 79 80 Change current directory. With no arguments, go $HOME. 81 82 -P Physical path: resolve symlinks in path 83 -L Local path: .. trims directories off $PWD (default) 84 85config EXIT 86 bool 87 default n 88 depends on SH 89 help 90 usage: exit [status] 91 92 Exit shell. If no return value supplied on command line, use value 93 of most recent command, or 0 if none. 94*/ 95 96#define FOR_sh 97#include "toys.h" 98 99GLOBALS( 100 char *command; 101 102 long lineno; 103 104 struct double_list functions; 105 unsigned options; 106 107 // Running jobs. 108 struct sh_job { 109 struct sh_job *next, *prev; 110 unsigned jobno; 111 112 // Every pipeline has at least one set of arguments or it's Not A Thing 113 struct sh_arg { 114 char **v; 115 int c; 116 } pipeline; 117 118 // null terminated array of running processes in pipeline 119 struct sh_process { 120 struct string_list *delete; // expanded strings 121 int pid, exit; // status? Stopped? Exited? 122 struct sh_arg arg; 123 } *procs, *proc; 124 } *jobs, *job; 125 unsigned jobcnt; 126) 127 128#define SH_NOCLOBBER 1 // set -C 129 130void cd_main(void) 131{ 132 char *dest = *toys.optargs ? *toys.optargs : getenv("HOME"); 133 134// TODO: -LPE@ 135// TODO: cd .. goes up $PWD path we used to get here, not ./.. 136 xchdir(dest ? dest : "/"); 137} 138 139void exit_main(void) 140{ 141 exit(*toys.optargs ? atoi(*toys.optargs) : 0); 142} 143 144// like error_msg() but exit from shell scripts 145void syntax_err(char *msg, ...) 146{ 147 va_list va; 148 149 va_start(va, msg); 150 verror_msg(msg, 0, va); 151 va_end(va); 152 153 if (*toys.optargs) xexit(); 154} 155 156// Print prompt, parsing escapes 157static void do_prompt(char *prompt) 158{ 159 char *s, c, cc; 160 161 if (!prompt) prompt = "\\$ "; 162 while (*prompt) { 163 c = *(prompt++); 164 165 if (c=='!') { 166 if (*prompt=='!') prompt++; 167 else { 168 printf("%ld", TT.lineno); 169 continue; 170 } 171 } else if (c=='\\') { 172 int i = 0; 173 174 cc = *(prompt++); 175 if (!cc) goto down; 176 177 // \nnn \dD{}hHjlstT@AuvVwW!#$ 178 // Ignore bash's "nonprintable" hack; query our cursor position instead. 179 if (cc=='[' || cc==']') continue; 180 else if (cc=='$') putchar(getuid() ? '$' : '#'); 181 else if (cc=='h' || cc=='H') { 182 *toybuf = 0; 183 gethostname(toybuf, sizeof(toybuf)-1); 184 if (cc=='h' && (s = strchr(toybuf, '.'))) *s = 0; 185 fputs(toybuf, stdout); 186 } else if (cc=='s') fputs(getbasename(*toys.argv), stdout); 187 else { 188 if (!(c = unescape(cc))) { 189 c = '\\'; 190 prompt--; 191 } 192 i++; 193 } 194 if (!i) continue; 195 } 196down: 197 putchar(c); 198 } 199 fflush(stdout); 200} 201 202// quote removal, brace, tilde, parameter/variable, $(command), 203// $((arithmetic)), split, path 204#define NO_PATH (1<<0) 205#define NO_SPLIT (1<<1) 206// TODO: ${name:?error} causes an error/abort here (syntax_err longjmp?) 207// TODO: $1 $@ $* need args marshalled down here: function+structure? 208// arg = append to this 209// new = string to expand 210// flags = type of expansions (not) to do 211// delete = append new allocations to this so they can be freed later 212// TODO: at_args: $1 $2 $3 $* $@ 213static void expand_arg(struct sh_arg *arg, char *new, unsigned flags, 214 struct string_list **delete) 215{ 216 if (!(arg->c&32)) arg->v = xrealloc(arg->v, sizeof(void *)*(arg->c+33)); 217 218 arg->v[arg->c++] = new; 219 arg->v[arg->c] = 0; 220 221/* 222 char *s = word, *new = 0; 223 224 // replacement 225 while (*s) { 226 if (*s == '$') { 227 s++; 228 } else if (*strchr("*?[{", *s)) { 229 s++; 230 } else if (*s == '<' || *s == '>') { 231 s++; 232 } else s++; 233 } 234 235 return new; 236*/ 237} 238 239// Assign one variable 240// s: key=val 241// type: 0 = whatever it was before, local otherwise 242#define TAKE_MEM 0x80000000 243// declare -aAilnrux 244// ft 245void setvar(char *s, unsigned type) 246{ 247 if (type&TAKE_MEM) type ^= TAKE_MEM; 248 else s = xstrdup(s); 249 250 // local, export, readonly, integer... 251 xsetenv(s, 0); 252} 253 254char *getvar(char *s) 255{ 256 return getenv(s); 257} 258 259// return length of match found at this point 260static int anystart(char *s, char **try) 261{ 262 while (*try) { 263 if (strstart(&s, *try)) return strlen(*try); 264 try++; 265 } 266 267 return 0; 268} 269 270static int anystr(char *s, char **try) 271{ 272 while (*try) if (!strcmp(s, *try++)) return 1; 273 274 return 0; 275} 276 277// return length of valid prefix that could go before redirect 278int redir_prefix(char *word) 279{ 280 char *s = word; 281 282 if (*s == '{') { 283 for (s++; isalnum(*s) || *s=='_'; s++); 284 if (*s == '}' && s != word+1) s++; 285 else s = word; 286 } else while (isdigit(*s)) s++; 287 288 return s-word; 289} 290 291// TODO |& 292 293// rd[0] = next, 1 = prev, 2 = len, 3-x = to/from redirection pairs. 294// Execute the commands in a pipeline segment 295struct sh_process *run_command(struct sh_arg *arg, int **rdlist) 296{ 297 struct sh_process *pp = xzalloc(sizeof(struct sh_process)); 298 struct toy_list *tl; 299 char *s, *ss, *sss; 300 unsigned envlen, j; 301 int fd, here = 0, rdcount = 0, *rd = 0, *rr, hfd = 0; 302 303 // Grab variable assignments 304 for (envlen = 0; envlen<arg->c; envlen++) { 305 s = arg->v[envlen]; 306 for (j=0; s[j] && (s[j]=='_' || !ispunct(s[j])); j++); 307 if (!j || s[j] != '=') break; 308 } 309 310 // perform assignments locally if there's no command 311 if (envlen == arg->c) { 312 for (j = 0; j<envlen; j++) { 313 struct sh_arg aa; 314 315 aa.c = 0; 316 expand_arg(&aa, arg->v[j], NO_PATH|NO_SPLIT, 0); 317 setvar(*aa.v, TAKE_MEM); 318 free(aa.v); 319 } 320 free(pp); 321 322 return 0; 323 } 324 325 // We vfork() instead of fork to support nommu systems, and do 326 // redirection setup in the parent process. Open new filehandles 327 // and move them to temporary values >10. The rd[] array has pairs of 328 // filehandles: child replaces fd1 with fd2 via dup2() and close() after 329 // the vfork(). fd2 is <<1, if bottom bit set don't close it (dup instead). 330 // If fd2 < 0 it's a here document (parent process writes to a pipe later). 331 332 // Expand arguments and perform redirections 333 for (j = envlen; j<arg->c; j++) { 334 335 // Is this a redirect? 336 ss = (s = arg->v[j]) + redir_prefix(arg->v[j]); 337 if (!anystr(ss, (char *[]){"<<<", "<<-", "<<", "<&", "<>", "<", ">>", ">&", 338 ">|", ">", "&>>", "&>", 0})) 339 { 340 // Nope: save/expand argument and loop 341 expand_arg(&pp->arg, s, 0, 0); 342 343 continue; 344 } 345 346 // Yes. Expand rd[] and find first unused filehandle >10 347 if (!(rdcount&31)) { 348 if (rd) dlist_lpop((void *)rdlist); 349 rd = xrealloc(rd, (2*rdcount+3+2*32)*sizeof(int *)); 350 dlist_add_nomalloc((void *)rdlist, (void *)rd); 351 } 352 rr = rd+3+rdcount; 353 if (!hfd) 354 for (hfd = 10; hfd<99999; hfd++) if (-1 == fcntl(hfd, F_GETFL)) break; 355 356 // error check: premature EOF, target fd too high, or redirect file splits 357 if (++j == arg->c || (isdigit(*s) && ss-s>5)) goto flush; 358 fd = pp->arg.c; 359 360 // expand arguments for everything but << and <<- 361 if (strncmp(ss, "<<", 2) || ss[2] == '<') { 362 expand_arg(&pp->arg, arg->v[j], NO_PATH|(NO_SPLIT*!strcmp(ss, "<<<")), 0); 363 if (fd+1 != pp->arg.c) goto flush; 364 sss = pp->arg.v[--pp->arg.c]; 365 } else dlist_add((void *)&pp->delete, sss = xstrdup(arg->v[j])); 366 367 // rd[] entries come in pairs: first is which fd gets redirected after 368 // vfork(), I.E. the [n] part of [n]<word 369 370 if (isdigit(*ss)) fd = atoi(ss); 371 else if (*ss == '{') { 372 ss++; 373 // when we close a filehandle, we _read_ from {var}, not write to it 374 if ((!strcmp(s, "<&") || !strcmp(s, ">&")) && !strcmp(sss, "-")) { 375 ss = xstrndup(ss, (s-ss)-1); 376 sss = getvar(ss); 377 free(ss); 378 fd = -1; 379 if (sss) fd = atoi(sss); 380 if (fd<0) goto flush; 381 if (fd>2) { 382 rr[0] = fd; 383 rr[1] = fd<<1; // close it 384 rdcount++; 385 } 386 continue; 387 } else setvar(xmprintf("%.*s=%d", (int)(s-ss), ss, hfd), TAKE_MEM); 388 } else fd = *ss != '<'; 389 *rr = fd; 390 391 // at this point for [n]<word s = start of [n], ss = start of <, sss = word 392 393 // second entry in this rd[] pair is new fd to dup2() after vfork(), 394 // I.E. for [n]<word the fd if you open("word"). It's stored <<1 and the 395 // low bit set means don't close(rr[1]) after dup2(rr[1]>>1, rr[0]); 396 397 // fd<0 means HERE document. Canned input stored earlier, becomes pipe later 398 if (!strcmp(s, "<<<") || !strcmp(s, "<<-") || !strcmp(s, "<<")) { 399 fd = --here<<2; 400 if (s[2] == '-') fd += 1; // zap tabs 401 if (s[strcspn(s, "\"'")]) fd += 2; // it was quoted so no expansion 402 rr[1] = fd; 403 rdcount++; 404 405 continue; 406 } 407 408 // Handle file descriptor duplication/close (&> &>> <& >& with number or -) 409 if (strchr(ss, '&') && ss[2] != '>') { 410 char *dig = sss; 411 412 // These redirect existing fd so nothing to open() 413 while (isdigit(dig)) dig++; 414 if (dig-sss>5) { 415 s = sss; 416 goto flush; 417 } 418 419// TODO can't check if fd is open here, must do it when actual redirects happen 420 if (!*dig || (*dig=='-' && !dig[1])) { 421 rr[1] = (((dig==sss) ? *rr : atoi(sss))<<1)+(*dig != '-'); 422 rdcount++; 423 424 continue; 425 } 426 } 427 428 // Permissions to open external file with: < > >> <& >& <> >| &>> &> 429 if (!strcmp(ss, "<>")) fd = O_CREAT|O_RDWR; 430 else if (strstr(ss, ">>")) fd = O_CREAT|O_APPEND; 431 else { 432 fd = (*ss != '<') ? O_CREAT|O_WRONLY|O_TRUNC : O_RDONLY; 433 if (!strcmp(ss, ">") && (TT.options&SH_NOCLOBBER)) { 434 struct stat st; 435 436 // Not _just_ O_EXCL: > /dev/null allowed 437 if (stat(sss, &st) || !S_ISREG(st.st_mode)) fd |= O_EXCL; 438 } 439 } 440 441 // Open the file 442// TODO: /dev/fd/# /dev/{stdin,stdout,stderr} /dev/{tcp,udp}/host/port 443 if (-1 == (fd = xcreate(sss, fd|WARN_ONLY, 777)) || hfd != dup2(fd, hfd)) { 444 pp->exit = 1; 445 s = 0; 446 447 goto flush; 448 } 449 if (fd != hfd) close(fd); 450 rr[1] = hfd<<1; 451 rdcount++; 452 453 // queue up a 2>&1 ? 454 if (strchr(ss, '&')) { 455 if (!(31&++rdcount)) rd = xrealloc(rd, (2*rdcount+66)*sizeof(int *)); 456 rr = rd+3+rdcount; 457 rr[0] = 2; 458 rr[1] = 1+(1<<1); 459 rdcount++; 460 } 461 } 462 if (rd) rd[2] = rdcount; 463 464// TODO: ok, now _use_ in_rd[in_rdcount] and rd[rdcount]. :) 465 466// TODO: handle ((math)) here 467 468// TODO use envlen 469// TODO: check for functions 470 471 // Is this command a builtin that should run in this process? 472 if ((tl = toy_find(*pp->arg.v)) 473 && (tl->flags & (TOYFLAG_NOFORK|TOYFLAG_MAYFORK))) 474 { 475 struct toy_context temp; 476 sigjmp_buf rebound; 477 478 // This fakes lots of what toybox_main() does. 479 memcpy(&temp, &toys, sizeof(struct toy_context)); 480 memset(&toys, 0, sizeof(struct toy_context)); 481 482// TODO: redirect stdin/out 483 if (!sigsetjmp(rebound, 1)) { 484 toys.rebound = &rebound; 485// must be null terminated 486 toy_init(tl, pp->arg.v); 487 tl->toy_main(); 488 } 489 pp->exit = toys.exitval; 490 if (toys.optargs != toys.argv+1) free(toys.optargs); 491 if (toys.old_umask) umask(toys.old_umask); 492 memcpy(&toys, &temp, sizeof(struct toy_context)); 493 } else { 494 int pipe[2]; 495 496 pipe[0] = 0; 497 pipe[1] = 1; 498// TODO: redirect and pipe 499// TODO: redirecting stderr needs xpopen3() or rethink 500 if (-1 == (pp->pid = xpopen_both(pp->arg.v, pipe))) 501 perror_msg("%s: vfork", *pp->arg.v); 502// TODO: don't close stdin/stdout! 503 else pp->exit = xpclose_both(pp->pid, 0); 504 } 505 506 s = 0; 507flush: 508 if (s) { 509 syntax_err("bad %s", s); 510 if (!pp->exit) pp->exit = 1; 511 } 512 for (j = 0; j<rdcount; j++) if (rd[4+2*j]>6) close(rd[4+2*j]>>1); 513 if (rdcount) free(dlist_lpop((void *)rdlist)); 514 515 return pp; 516} 517 518// parse next word from command line. Returns end, or 0 if need continuation 519// caller eats leading spaces 520static char *parse_word(char *start) 521{ 522 int i, j, quote = 0, q, qc = 0; 523 char *end = start, *s; 524 525 // (( is a special quote at the start of a word 526 if (strstart(&end, "((")) toybuf[quote++] = 255; 527 528 // find end of this word 529 while (*end) { 530 i = 0; 531 532 // barf if we're near overloading quote stack (nesting ridiculously deep) 533 if (quote>4000) { 534 syntax_err("tilt"); 535 return (void *)1; 536 } 537 538 q = quote ? toybuf[quote-1] : 0; 539 // Handle quote contexts 540 if (q) { 541 542 // when waiting for parentheses, they nest 543 if ((q == ')' || q == '\xff') && (*end == '(' || *end == ')')) { 544 if (*end == '(') qc++; 545 else if (qc) qc--; 546 else if (q == '\xff') { 547 // (( can end with )) or retroactively become two (( if we hit one ) 548 if (strstart(&end, "))")) quote--; 549 else return start+1; 550 } 551 end++; 552 553 // end quote? 554 } else if (*end == q) quote--, end++; 555 556 // single quote claims everything 557 else if (q == '\'') end++; 558 else i++; 559 560 // loop if we already handled a symbol 561 if (!i) continue; 562 } else { 563 // Things that only matter when unquoted 564 565 if (isspace(*end)) break; 566 567 // Things we should only return at the _start_ of a word 568 569 // Redirections. 123<<file- parses as 2 args: "123<<" "file-". 570 // Greedy matching: >&; becomes >& ; not > &; 571 s = end + redir_prefix(end); 572 j = anystart(s, (char *[]){"<<<", "<<-", "<<", "<&", "<>", "<", ">>", 573 ">&", ">|", ">", 0}); 574 if (j) s += j; 575 576 // Control characters 577 else s = end + anystart(end, (char *[]){";;&", ";;", ";&", ";", "||", 578 "|&", "|", "&&", "&>>", "&>", "&", "(", ")", 0}); 579 if (s != end) return (end == start) ? s : end; 580 i++; 581 } 582 583 // Things the same unquoted or in most non-single-quote contexts 584 585 // start new quote context? 586 if (strchr("\"'`", *end)) toybuf[quote++] = *end++; 587 else if (q != '"' && (strstart(&end, "<(") || strstart(&end,">("))) 588 toybuf[quote++]=')'; 589 590 // backslash escapes 591 else if (*end == '\\') { 592 if (!end[1] || (end[1]=='\n' && !end[2])) return 0; 593 end += 2; 594 } else if (*end++ == '$') { 595 if (-1 != (i = stridx("({[", *end))) { 596 toybuf[quote++] = ")}]"[i]; 597 end++; 598 } 599 } 600 } 601 602 return quote ? 0 : end; 603} 604 605// if then fi for while until select done done case esac break continue return 606 607// Allocate more space for arg, and possibly terminator 608void argxtend(struct sh_arg *arg) 609{ 610 if (!(arg->c&31)) arg->v = xrealloc(arg->v, (33+arg->c)*sizeof(void *)); 611} 612 613// Pipeline segments 614struct sh_pipeline { 615 struct sh_pipeline *next, *prev; 616 int count, here, type; 617 struct sh_arg arg[1]; 618}; 619 620// run a series of "command | command && command" with redirects. 621int run_pipeline(struct sh_pipeline **pl, int *rd) 622{ 623 struct sh_process *pp; 624 int rc = 0; 625 626 for (;;) { 627// TODO job control 628 if (!(pp = run_command((*pl)->arg, &rd))) rc = 0; 629 else { 630//wait4(pp); 631 llist_traverse(pp->delete, free); 632 rc = pp->exit; 633 free(pp); 634 } 635 636 if ((*pl)->next && !(*pl)->next->type) *pl = (*pl)->next; 637 else return rc; 638 } 639} 640 641 642 643// scratch space (state held between calls). Don't want to make it global yet 644// because this could be reentrant. 645struct sh_function { 646 char *name; 647 struct sh_pipeline *pipeline; 648 struct double_list *expect; 649// TODO: lifetime rules for arg? remember "shift" command. 650 struct sh_arg *arg; // arguments to function call 651 char *end; 652}; 653 654// Free one pipeline segment. 655void free_pipeline(void *pipeline) 656{ 657 struct sh_pipeline *pl = pipeline; 658 int i, j; 659 660 if (pl) for (j=0; j<=pl->count; j++) { 661 for (i = 0; i<=pl->arg->c; i++) free(pl->arg[j].v[i]); 662 free(pl->arg[j].v); 663 } 664 free(pl); 665} 666 667// Return end of current block, or NULL if we weren't in block and fell off end. 668struct sh_pipeline *block_end(struct sh_pipeline *pl) 669{ 670 int i = 0; 671 672 while (pl) { 673 if (pl->type == 1 || pl->type == 'f') i++; 674 else if (pl->type == 3) if (--i<1) break; 675 pl = pl->next; 676 } 677 678 return 0; 679} 680 681void free_function(struct sh_function *sp) 682{ 683 llist_traverse(sp->pipeline, free_pipeline); 684 llist_traverse(sp->expect, free); 685 memset(sp, 0, sizeof(struct sh_function)); 686} 687 688// TODO this has to add to a namespace context. Functions within functions... 689struct sh_pipeline *add_function(char *name, struct sh_pipeline *pl) 690{ 691dprintf(2, "stub add_function"); 692 693 return block_end(pl->next); 694} 695 696// Add a line of shell script to a shell function. Returns 0 if finished, 697// 1 to request another line of input (> prompt), -1 for syntax err 698static int parse_line(char *line, struct sh_function *sp) 699{ 700 char *start = line, *delete = 0, *end, *last = 0, *s, *ex, done = 0; 701 struct sh_pipeline *pl = sp->pipeline ? sp->pipeline->prev : 0; 702 struct sh_arg *arg = 0; 703 long i; 704 705 // Resume appending to last statement? 706 if (pl) { 707 arg = pl->arg; 708 709 // Extend/resume quoted block 710 if (arg->c<0) { 711 delete = start = xmprintf("%s%s", arg->v[arg->c = (-arg->c)-1], start); 712 free(arg->v[arg->c]); 713 arg->v[arg->c] = 0; 714 715 // is a HERE document in progress? 716 } else if (pl->count != pl->here) { 717 arg += 1+pl->here; 718 719 argxtend(arg); 720 if (strcmp(line, arg->v[arg->c])) { 721 // Add this line 722 arg->v[arg->c+1] = arg->v[arg->c]; 723 arg->v[arg->c++] = xstrdup(line); 724 // EOF hit, end HERE document 725 } else { 726 arg->v[arg->c] = 0; 727 pl->here++; 728 } 729 start = 0; 730 731 // Nope, new segment 732 } else pl = 0; 733 } 734 735 // Parse words, assemble argv[] pipelines, check flow control and HERE docs 736 if (start) for (;;) { 737 ex = sp->expect ? sp->expect->prev->data : 0; 738 739 // Look for << HERE redirections in completed pipeline segment 740 if (pl && pl->count == -1) { 741 pl->count = 0; 742 arg = pl->arg; 743 744 // find arguments of the form [{n}]<<[-] with another one after it 745 for (i = 0; i<arg->c; i++) { 746 s = arg->v[i] + redir_prefix(arg->v[i]); 747 if (strcmp(s, "<<") && strcmp(s, "<<-") && strcmp(s, "<<<")) continue; 748 if (i+1 == arg->c) goto flush; 749 750 // Add another arg[] to the pipeline segment (removing/readding to list 751 // because realloc can move pointer) 752 dlist_lpop(&sp->pipeline); 753 pl = xrealloc(pl, sizeof(*pl) + ++pl->count*sizeof(struct sh_arg)); 754 dlist_add_nomalloc((void *)&sp->pipeline, (void *)pl); 755 756 // queue up HERE EOF so input loop asks for more lines. 757 arg[pl->count].v = xzalloc(2*sizeof(void *)); 758 *arg[pl->count].v = arg->v[++i]; 759 arg[pl->count].c = -(s[2] == '<'); // note <<< as c = -1 760 } 761 pl = 0; 762 } 763 if (done) break; 764 s = 0; 765 766 // skip leading whitespace/comment here to know where next word starts 767 for (;;) { 768 if (isspace(*start)) ++start; 769 else if (*start=='#') while (*start && *start != '\n') ++start; 770 else break; 771 } 772 773 // Parse next word and detect overflow (too many nested quotes). 774 if ((end = parse_word(start)) == (void *)1) 775 goto flush; 776 777 // Is this a new pipeline segment? 778 if (!pl) { 779 pl = xzalloc(sizeof(struct sh_pipeline)); 780 arg = pl->arg; 781 dlist_add_nomalloc((void *)&sp->pipeline, (void *)pl); 782 } 783 argxtend(arg); 784 785 // Do we need to request another line to finish word (find ending quote)? 786 if (!end) { 787 // Save unparsed bit of this line, we'll need to re-parse it. 788 arg->v[arg->c] = xstrndup(start, strlen(start)); 789 arg->c = -(arg->c+1); 790 free(delete); 791 792 return 1; 793 } 794 795 // Ok, we have a word. What does it _mean_? 796 797 // Did we hit end of line or ) outside a function declaration? 798 // ) is only saved at start of a statement, ends current statement 799 if (end == start || (arg->c && *start == ')' && pl->type!='f')) { 800 arg->v[arg->c] = 0; 801 802 if (pl->type == 'f' && arg->c<3) { 803 s = "function()"; 804 goto flush; 805 } 806 807 // "for" on its own line is an error. 808 if (arg->c == 1 && ex && !memcmp(ex, "do\0A", 4)) { 809 s = "newline"; 810 goto flush; 811 } 812 813 // don't save blank pipeline segments 814 if (!arg->c) free_pipeline(dlist_lpop(&sp->pipeline)); 815 816 // stop at EOL, else continue with new pipeline segment for ) 817 if (end == start) done++; 818 pl->count = -1; 819 last = 0; 820 821 continue; 822 } 823 824 // Save argument (strdup) and check for flow control 825 s = arg->v[arg->c] = xstrndup(start, end-start); 826 start = end; 827 if (strchr(";|&", *s)) { 828 829 // flow control without a statement is an error 830 if (!arg->c) goto flush; 831 832 // treat ; as newline so we don't have to check both elsewhere. 833 if (!strcmp(s, ";")) { 834 arg->v[arg->c] = 0; 835 free(s); 836 s = 0; 837 } 838 last = s; 839 pl->count = -1; 840 841 continue; 842 } else arg->v[++arg->c] = 0; 843 844 // is a function() in progress? 845 if (arg->c>1 && !strcmp(s, "(")) pl->type = 'f'; 846 if (pl->type=='f') { 847 if (arg->c == 2 && strcmp(s, "(")) goto flush; 848 if (arg->c == 3) { 849 if (strcmp(s, ")")) goto flush; 850 851 // end function segment, expect function body 852 pl->count = -1; 853 last = 0; 854 dlist_add(&sp->expect, "}"); 855 dlist_add(&sp->expect, 0); 856 dlist_add(&sp->expect, "{"); 857 858 continue; 859 } 860 861 // a for/select must have at least one additional argument on same line 862 } else if (ex && !memcmp(ex, "do\0A", 4)) { 863 864 // Sanity check and break the segment 865 if (strncmp(s, "((", 2) && strchr(s, '=')) goto flush; 866 pl->count = -1; 867 sp->expect->prev->data = "do\0C"; 868 869 continue; 870 871 // flow control is the first word of a pipeline segment 872 } else if (arg->c>1) continue; 873 874 // Do we expect something that _must_ come next? (no multiple statements) 875 if (ex) { 876 // When waiting for { it must be next symbol, but can be on a new line. 877 if (!strcmp(ex, "{")) { 878 if (strcmp(s, "{")) goto flush; 879 free(arg->v[--arg->c]); // don't save the {, function starts the block 880 free(dlist_lpop(&sp->expect)); 881 882 continue; 883 884 // The "test" part of for/select loops can have (at most) one "in" line, 885 // for {((;;))|name [in...]} do 886 } else if (!memcmp(ex, "do\0C", 4)) { 887 if (strcmp(s, "do")) { 888 // can only have one "in" line between for/do, but not with for(()) 889 if (!pl->prev->type) goto flush; 890 if (!strncmp(pl->prev->arg->v[1], "((", 2)) goto flush; 891 else if (strcmp(s, "in")) goto flush; 892 893 continue; 894 } 895 } 896 } 897 898 // start of a new block? 899 900 // for/select requires variable name on same line, can't break segment yet 901 if (!strcmp(s, "for") || !strcmp(s, "select")) { 902 if (!pl->type) pl->type = 1; 903 dlist_add(&sp->expect, "do\0A"); 904 905 continue; 906 } 907 908 end = 0; 909 if (!strcmp(s, "if")) end = "then"; 910 else if (!strcmp(s, "while") || !strcmp(s, "until")) end = "do\0B"; 911 else if (!strcmp(s, "case")) end = "esac"; 912 else if (!strcmp(s, "{")) end = "}"; 913 else if (!strcmp(s, "[[")) end = "]]"; 914 else if (!strcmp(s, "(")) end = ")"; 915 916 // Expecting NULL means a statement: I.E. any otherwise unrecognized word 917 else if (sp->expect && !ex) { 918 free(dlist_lpop(&sp->expect)); 919 continue; 920 } else if (!ex) goto check; 921 922 // Did we start a new statement? 923 if (end) { 924 pl->type = 1; 925 926 // Only innermost statement needed in { { { echo ;} ;} ;} and such 927 if (sp->expect && !sp->expect->prev->data) free(dlist_lpop(&sp->expect)); 928 929 // If we got here we expect a specific word to end this block: is this it? 930 } else if (!strcmp(s, ex)) { 931 // can't "if | then" or "while && do", only ; & or newline works 932 if (last && (strcmp(ex, "then") || strcmp(last, "&"))) { 933 s = end; 934 goto flush; 935 } 936 937 free(dlist_lpop(&sp->expect)); 938 pl->type = anystr(s, (char *[]){"fi", "done", "esac", "}", "]]", ")", 0}) 939 ? 3 : 2; 940 941 // if it's a multipart block, what comes next? 942 if (!strcmp(s, "do")) end = "done"; 943 else if (!strcmp(s, "then")) end = "fi\0A"; 944 945 // fi could have elif, which queues a then. 946 } else if (!strcmp(ex, "fi")) { 947 if (!strcmp(s, "elif")) { 948 free(dlist_lpop(&sp->expect)); 949 end = "then"; 950 // catch duplicate else while we're here 951 } else if (!strcmp(s, "else")) { 952 if (ex[3] != 'A') { 953 s = "2 else"; 954 goto flush; 955 } 956 free(dlist_lpop(&sp->expect)); 957 end = "fi\0B"; 958 } 959 } 960 961 // Do we need to queue up the next thing to expect? 962 if (end) { 963 if (!pl->type) pl->type = 2; 964 dlist_add(&sp->expect, end); 965 dlist_add(&sp->expect, 0); // they're all preceded by a statement 966 pl->count = -1; 967 } 968 969check: 970 // syntax error check: these can't be the first word in an unexpected place 971 if (!pl->type && anystr(s, (char *[]){"then", "do", "esac", "}", "]]", ")", 972 "done", "fi", "elif", "else", 0})) goto flush; 973 } 974 free(delete); 975 976 // advance past <<< arguments (stored as here documents, but no new input) 977 pl = sp->pipeline->prev; 978 while (pl->count<pl->here && pl->arg[pl->count].c<0) 979 pl->arg[pl->count++].c = 0; 980 981 // return if HERE document pending or more flow control needed to complete 982 if (sp->expect) return 1; 983 if (sp->pipeline && pl->count != pl->here) return 1; 984 dlist_terminate(sp->pipeline); 985 986 // Don't need more input, can start executing. 987 988 return 0; 989 990flush: 991 if (s) syntax_err("bad %s", s); 992 free_function(sp); 993 994 return 0-!!s; 995} 996 997static void dump_state(struct sh_function *sp) 998{ 999 struct sh_pipeline *pl; 1000 int q = 0; 1001 long i; 1002 1003 if (sp->expect) { 1004 struct double_list *dl; 1005 1006 for (dl = sp->expect; dl; dl = (dl->next == sp->expect) ? 0 : dl->next) 1007 dprintf(2, "expecting %s\n", dl->data); 1008 if (sp->pipeline) 1009 dprintf(2, "pipeline count=%d here=%d\n", sp->pipeline->prev->count, 1010 sp->pipeline->prev->here); 1011 } 1012 1013 for (pl = sp->pipeline; pl ; pl = (pl->next == sp->pipeline) ? 0 : pl->next) { 1014 for (i = 0; i<pl->arg->c; i++) 1015 printf("arg[%d][%ld]=%s\n", q, i, pl->arg->v[i]); 1016 printf("type=%d term[%d]=%s\n", pl->type, q++, pl->arg->v[pl->arg->c]); 1017 } 1018} 1019 1020/* Flow control statements: 1021 1022 if/then/elif/else/fi, for select while until/do/done, case/esac, 1023 {/}, [[/]], (/), function assignment 1024*/ 1025 1026 1027 1028// run a shell function, handling flow control statements 1029static void run_function(struct sh_function *sp) 1030{ 1031 struct sh_pipeline *pl = sp->pipeline, *end; 1032 struct blockstack { 1033 struct blockstack *next; 1034 struct sh_pipeline *start, *end; 1035 int run, loop, *redir; 1036 1037 struct sh_arg farg; // for/select arg stack 1038 struct string_list *fdelete; // farg's cleanup list 1039 char *fvar; // for/select's iteration variable name 1040 } *blk = 0, *new; 1041 long i; 1042 1043 // iterate through the commands 1044 while (pl) { 1045 char *s = *pl->arg->v, *ss = pl->arg->v[1]; 1046//dprintf(2, "s=%s %s %d %s %d\n", s, ss, pl->type, blk ? blk->start->arg->v[0] : "X", blk ? blk->run : 0); 1047 // Normal executable statement? 1048 if (!pl->type) { 1049// TODO: break & is supported? Seriously? Also break > potato 1050// TODO: break multiple aguments 1051 if (!strcmp(s, "break") || !strcmp(s, "continue")) { 1052 1053 // How many layers to peel off? 1054 i = ss ? atol(ss) : 0; 1055 if (i<1) i = 1; 1056 if (!blk || pl->arg->c>2 || ss[strspn(ss, "0123456789")]) { 1057 syntax_err("bad %s", s); 1058 break; 1059 } 1060 i = atol(ss); 1061 if (!i) i++; 1062 while (i && blk) { 1063 if (--i && *s == 'c') { 1064 pl = blk->start; 1065 break; 1066 } 1067 pl = blk->end; 1068 llist_traverse(blk->fdelete, free); 1069 free(llist_pop(&blk)); 1070 } 1071 pl = pl->next; 1072 1073 continue; 1074 } 1075 1076// inherit redirects? 1077// returns last statement of pipeline 1078 if (!blk) toys.exitval = run_pipeline(&pl, 0); 1079 else if (blk->run) toys.exitval = run_pipeline(&pl, blk->redir); 1080 else while (pl->next && !pl->next->type) pl = pl->next; 1081 1082 // Starting a new block? 1083 } else if (pl->type == 1) { 1084 1085 // are we entering this block (rather than looping back to it)? 1086 if (!blk || blk->start != pl) { 1087 1088 // If it's a nested block we're not running, skip ahead. 1089 end = block_end(pl->next); 1090 if (blk && !blk->run) { 1091 pl = end; 1092 if (pl) pl = pl->next; 1093 continue; 1094 } 1095 1096 // It's a new block we're running, save context and add it to the stack. 1097 new = xzalloc(sizeof(*blk)); 1098 new->next = blk; 1099 blk = new; 1100 blk->start = pl; 1101 blk->end = end; 1102 blk->run = 1; 1103// TODO perform block end redirects to blk->redir 1104 } 1105 1106 // What flow control statement is this? 1107 1108 // if/then/elif/else/fi, while until/do/done - no special handling needed 1109 1110 // for select/do/done 1111 if (!strcmp(s, "for") || !strcmp(s, "select")) { 1112 if (blk->loop); 1113 else if (!strncmp(blk->fvar = ss, "((", 2)) { 1114 blk->loop = 1; 1115dprintf(2, "TODO skipped init for((;;)), need math parser\n"); 1116 } else { 1117 1118 // populate blk->farg with expanded arguments 1119 if (!pl->next->type) { 1120 for (i = 1; i<pl->next->arg->c; i++) 1121 expand_arg(&blk->farg, pl->next->arg->v[i], 0, &blk->fdelete); 1122 } else expand_arg(&blk->farg, "\"$@\"", 0, &blk->fdelete); 1123 } 1124 pl = pl->next; 1125 } 1126 1127/* TODO 1128case/esac 1129{/} 1130[[/]] 1131(/) 1132((/)) 1133function/} 1134*/ 1135 1136 // gearshift from block start to block body 1137 } else if (pl->type == 2) { 1138 1139 // Handle if statement 1140 if (!strcmp(s, "then")) blk->run = blk->run && !toys.exitval; 1141 else if (!strcmp(s, "else") || !strcmp(s, "elif")) blk->run = !blk->run; 1142 else if (!strcmp(s, "do")) { 1143 ss = *blk->start->arg->v; 1144 if (!strcmp(ss, "while")) blk->run = blk->run && !toys.exitval; 1145 else if (!strcmp(ss, "until")) blk->run = blk->run && toys.exitval; 1146 else if (blk->loop >= blk->farg.c) { 1147 blk->run = 0; 1148 pl = block_end(pl); 1149 continue; 1150 } else if (!strncmp(blk->fvar, "((", 2)) { 1151dprintf(2, "TODO skipped running for((;;)), need math parser\n"); 1152 } else setvar(xmprintf("%s=%s", blk->fvar, blk->farg.v[blk->loop++]), 1153 TAKE_MEM); 1154 } 1155 1156 // end of block 1157 } else if (pl->type == 3) { 1158 1159 // repeating block? 1160 if (blk->run && !strcmp(s, "done")) { 1161 pl = blk->start; 1162 continue; 1163 } 1164 1165 // if ending a block, pop stack. 1166 llist_traverse(blk->fdelete, free); 1167 free(llist_pop(&blk)); 1168 1169// TODO unwind redirects (cleanup blk->redir) 1170 1171 } else if (pl->type == 'f') pl = add_function(s, pl); 1172 1173 pl = pl->next; 1174 } 1175 1176 // Cleanup from syntax_err(); 1177 while (blk) { 1178 llist_traverse(blk->fdelete, free); 1179 free(llist_pop(&blk)); 1180 } 1181 1182 return; 1183} 1184 1185void subshell_imports(void) 1186{ 1187/* 1188 // TODO cull local variables because 'env "()=42" env | grep 42' works. 1189 1190 // vfork() means subshells have to export and then re-import locals/functions 1191 sprintf(toybuf, "(%d#%d)", getpid(), getppid()); 1192 if ((s = getenv(toybuf))) { 1193 char *from, *to, *ss; 1194 1195 unsetenv(toybuf); 1196 ss = s; 1197 1198 // Loop through packing \\ until \0 1199 for (from = to = s; *from; from++, to++) { 1200 *to = *from; 1201 if (*from != '\\') continue; 1202 if (from[1] == '\\' || from[1] == '0') from++; 1203 if (from[1] != '0') continue; 1204 *to = 0; 1205 1206 // save chunk 1207 for (ss = s; ss<to; ss++) { 1208 if (*ss == '=') { 1209 // first char of name is variable type ala declare 1210 if (s+1<ss && strchr("aAilnru", *s)) { 1211 setvar(ss, *s); 1212 1213 break; 1214 } 1215 } else if (!strncmp(ss, "(){", 3)) { 1216 FILE *ff = fmemopen(s, to-s, "r"); 1217 1218 while ((new = xgetline(ff, 0))) { 1219 if ((prompt = parse_line(new, &scratch))<0) break; 1220 free(new); 1221 } 1222 if (!prompt) { 1223 add_function(s, scratch.pipeline); 1224 free_function(&scratch); 1225 break; 1226 } 1227 fclose(ff); 1228 } else if (!isspace(*s) && !ispunct(*s)) continue; 1229 1230 error_exit("bad locals"); 1231 } 1232 s = from+1; 1233 } 1234 } 1235*/ 1236} 1237 1238void sh_main(void) 1239{ 1240 FILE *f; 1241 char *new; 1242 struct sh_function scratch; 1243 int prompt = 0; 1244 1245 // Set up signal handlers and grab control of this tty. 1246 1247 // Read environment for exports from parent shell 1248 subshell_imports(); 1249 1250 memset(&scratch, 0, sizeof(scratch)); 1251 if (TT.command) f = fmemopen(TT.command, strlen(TT.command), "r"); 1252 else if (*toys.optargs) f = xfopen(*toys.optargs, "r"); 1253 else { 1254 f = stdin; 1255 if (isatty(0)) toys.optflags |= FLAG_i; 1256 } 1257 1258 for (;;) { 1259 1260 // Prompt and read line 1261 if (f == stdin) { 1262 char *s = getenv(prompt ? "PS2" : "PS1"); 1263 1264 if (!s) s = prompt ? "> " : (getpid() ? "\\$ " : "# "); 1265 do_prompt(s); 1266 } else TT.lineno++; 1267 if (!(new = xgetline(f ? f : stdin, 0))) break; 1268 1269// TODO if (!isspace(*new)) add_to_history(line); 1270 1271 // returns 0 if line consumed, command if it needs more data 1272 prompt = parse_line(new, &scratch); 1273if (0) dump_state(&scratch); 1274 if (prompt != 1) { 1275// TODO: ./blah.sh one two three: put one two three in scratch.arg 1276 if (!prompt) run_function(&scratch); 1277 free_function(&scratch); 1278 prompt = 0; 1279 } 1280 free(new); 1281 } 1282 1283 if (prompt) error_exit("%ld:unfinished line"+4*!TT.lineno, TT.lineno); 1284 toys.exitval = f && ferror(f); 1285} 1286