diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-02-01 01:43:16 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-02-01 01:43:16 +0000 |
| commit | 489f93ebae0b02edbb7c654c7950f2bfba6bb18b (patch) | |
| tree | 17eb2c58b3c2fb113bf22992bfce6f1ac6196988 | |
| parent | 00ccf95bc8c6433a176ab09c4812063e33df2240 (diff) | |
| download | busybox-w32-489f93ebae0b02edbb7c654c7950f2bfba6bb18b.tar.gz busybox-w32-489f93ebae0b02edbb7c654c7950f2bfba6bb18b.tar.bz2 busybox-w32-489f93ebae0b02edbb7c654c7950f2bfba6bb18b.zip | |
msh: cleaning up for -Wwrite-strings part #2
| -rw-r--r-- | shell/msh.c | 1323 |
1 files changed, 648 insertions, 675 deletions
diff --git a/shell/msh.c b/shell/msh.c index b71066abc..d821dfd20 100644 --- a/shell/msh.c +++ b/shell/msh.c | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | #include <sys/times.h> | 17 | #include <sys/times.h> |
| 18 | #include "busybox.h" | 18 | #include "busybox.h" |
| 19 | 19 | ||
| 20 | extern char **environ; | ||
| 21 | |||
| 20 | 22 | ||
| 21 | /*#define MSHDEBUG 1*/ | 23 | /*#define MSHDEBUG 1*/ |
| 22 | 24 | ||
| @@ -181,10 +183,7 @@ static const char *const T_CMD_NAMES[] = { | |||
| 181 | 183 | ||
| 182 | /* PROTOTYPES */ | 184 | /* PROTOTYPES */ |
| 183 | static int newfile(char *s); | 185 | static int newfile(char *s); |
| 184 | static char *findeq(char *cp); | ||
| 185 | static char *cclass(char *p, int sub); | 186 | static char *cclass(char *p, int sub); |
| 186 | static void initarea(void); | ||
| 187 | extern int msh_main(int argc, char **argv); | ||
| 188 | 187 | ||
| 189 | 188 | ||
| 190 | struct brkcon { | 189 | struct brkcon { |
| @@ -254,6 +253,13 @@ static int yynerrs; /* yacc */ | |||
| 254 | static char line[LINELIM]; | 253 | static char line[LINELIM]; |
| 255 | static char *elinep; | 254 | static char *elinep; |
| 256 | 255 | ||
| 256 | #if ENABLE_FEATURE_EDITING | ||
| 257 | static char *current_prompt; | ||
| 258 | static line_input_t *line_input_state; | ||
| 259 | #endif | ||
| 260 | |||
| 261 | static int areanum; /* current allocation area */ | ||
| 262 | |||
| 257 | 263 | ||
| 258 | /* | 264 | /* |
| 259 | * other functions | 265 | * other functions |
| @@ -262,12 +268,9 @@ typedef int (*builtin_func_ptr)(struct op *); | |||
| 262 | static builtin_func_ptr inbuilt(char *s); | 268 | static builtin_func_ptr inbuilt(char *s); |
| 263 | 269 | ||
| 264 | static char *rexecve(char *c, char **v, char **envp); | 270 | static char *rexecve(char *c, char **v, char **envp); |
| 265 | static char *space(int n); | ||
| 266 | static char *strsave(char *s, int a); | ||
| 267 | static char *evalstr(char *cp, int f); | 271 | static char *evalstr(char *cp, int f); |
| 268 | static char *putn(int n); | 272 | static char *putn(int n); |
| 269 | static char *unquote(char *as); | 273 | static char *unquote(char *as); |
| 270 | static struct var *lookup(char *n); | ||
| 271 | static int rlookup(char *n); | 274 | static int rlookup(char *n); |
| 272 | static struct wdblock *glob(char *cp, struct wdblock *wb); | 275 | static struct wdblock *glob(char *cp, struct wdblock *wb); |
| 273 | static int my_getc(int ec); | 276 | static int my_getc(int ec); |
| @@ -291,16 +294,6 @@ static void runtrap(int i); | |||
| 291 | static int gmatch(char *s, char *p); | 294 | static int gmatch(char *s, char *p); |
| 292 | 295 | ||
| 293 | 296 | ||
| 294 | /* | ||
| 295 | * error handling | ||
| 296 | */ | ||
| 297 | static void leave(void); /* abort shell (or fail in subshell) */ | ||
| 298 | static void fail(void); /* fail but return to process next command */ | ||
| 299 | static void warn(const char *s); | ||
| 300 | static void sig(int i); /* default signal handler */ | ||
| 301 | |||
| 302 | |||
| 303 | |||
| 304 | /* -------- area stuff -------- */ | 297 | /* -------- area stuff -------- */ |
| 305 | 298 | ||
| 306 | #define REGSIZE sizeof(struct region) | 299 | #define REGSIZE sizeof(struct region) |
| @@ -318,7 +311,6 @@ struct region { | |||
| 318 | }; | 311 | }; |
| 319 | 312 | ||
| 320 | 313 | ||
| 321 | |||
| 322 | /* -------- grammar stuff -------- */ | 314 | /* -------- grammar stuff -------- */ |
| 323 | typedef union { | 315 | typedef union { |
| 324 | char *cp; | 316 | char *cp; |
| @@ -327,32 +319,32 @@ typedef union { | |||
| 327 | struct op *o; | 319 | struct op *o; |
| 328 | } YYSTYPE; | 320 | } YYSTYPE; |
| 329 | 321 | ||
| 330 | #define WORD 256 | 322 | #define WORD 256 |
| 331 | #define LOGAND 257 | 323 | #define LOGAND 257 |
| 332 | #define LOGOR 258 | 324 | #define LOGOR 258 |
| 333 | #define BREAK 259 | 325 | #define BREAK 259 |
| 334 | #define IF 260 | 326 | #define IF 260 |
| 335 | #define THEN 261 | 327 | #define THEN 261 |
| 336 | #define ELSE 262 | 328 | #define ELSE 262 |
| 337 | #define ELIF 263 | 329 | #define ELIF 263 |
| 338 | #define FI 264 | 330 | #define FI 264 |
| 339 | #define CASE 265 | 331 | #define CASE 265 |
| 340 | #define ESAC 266 | 332 | #define ESAC 266 |
| 341 | #define FOR 267 | 333 | #define FOR 267 |
| 342 | #define WHILE 268 | 334 | #define WHILE 268 |
| 343 | #define UNTIL 269 | 335 | #define UNTIL 269 |
| 344 | #define DO 270 | 336 | #define DO 270 |
| 345 | #define DONE 271 | 337 | #define DONE 271 |
| 346 | #define IN 272 | 338 | #define IN 272 |
| 347 | /* Added for "." file expansion */ | 339 | /* Added for "." file expansion */ |
| 348 | #define DOT 273 | 340 | #define DOT 273 |
| 349 | 341 | ||
| 350 | #define YYERRCODE 300 | 342 | #define YYERRCODE 300 |
| 351 | 343 | ||
| 352 | /* flags to yylex */ | 344 | /* flags to yylex */ |
| 353 | #define CONTIN 01 /* skip new lines to complete command */ | 345 | #define CONTIN 01 /* skip new lines to complete command */ |
| 354 | 346 | ||
| 355 | #define SYNTAXERR zzerr() | 347 | #define SYNTAXERR zzerr() |
| 356 | 348 | ||
| 357 | static struct op *pipeline(int cf); | 349 | static struct op *pipeline(int cf); |
| 358 | static struct op *andor(void); | 350 | static struct op *andor(void); |
| @@ -400,16 +392,6 @@ struct var { | |||
| 400 | #define GETCELL 04 /* name & value space was got with getcell */ | 392 | #define GETCELL 04 /* name & value space was got with getcell */ |
| 401 | 393 | ||
| 402 | static int yyparse(void); | 394 | static int yyparse(void); |
| 403 | static struct var *lookup(char *n); | ||
| 404 | static void setval(struct var *vp, char *val); | ||
| 405 | static void nameval(struct var *vp, char *val, char *name); | ||
| 406 | static void export(struct var *vp); | ||
| 407 | static void ronly(struct var *vp); | ||
| 408 | static int isassign(char *s); | ||
| 409 | static int checkname(char *cp); | ||
| 410 | static int assign(char *s, int cf); | ||
| 411 | static void putvlist(int f, int out); | ||
| 412 | static int eqname(char *n1, char *n2); | ||
| 413 | 395 | ||
| 414 | static int execute(struct op *t, int *pin, int *pout, int act); | 396 | static int execute(struct op *t, int *pin, int *pout, int act); |
| 415 | 397 | ||
| @@ -519,23 +501,6 @@ static struct wdblock *addword(char *wd, struct wdblock *wb); | |||
| 519 | static struct wdblock *newword(int nw); | 501 | static struct wdblock *newword(int nw); |
| 520 | static char **getwords(struct wdblock *wb); | 502 | static char **getwords(struct wdblock *wb); |
| 521 | 503 | ||
| 522 | /* -------- area.h -------- */ | ||
| 523 | |||
| 524 | /* | ||
| 525 | * storage allocation | ||
| 526 | */ | ||
| 527 | static char *getcell(unsigned nbytes); | ||
| 528 | static void garbage(void); | ||
| 529 | static void setarea(char *cp, int a); | ||
| 530 | static int getarea(char *cp); | ||
| 531 | static void freearea(int a); | ||
| 532 | static void freecell(char *cp); | ||
| 533 | static int areanum; /* current allocation area */ | ||
| 534 | |||
| 535 | #define NEW(type) (type *)getcell(sizeof(type)) | ||
| 536 | #define DELETE(obj) freecell((char *)obj) | ||
| 537 | |||
| 538 | |||
| 539 | /* -------- misc stuff -------- */ | 504 | /* -------- misc stuff -------- */ |
| 540 | 505 | ||
| 541 | static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp); | 506 | static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp); |
| @@ -674,9 +639,8 @@ static const struct builtincmd builtincmds[] = { | |||
| 674 | static struct op *scantree(struct op *); | 639 | static struct op *scantree(struct op *); |
| 675 | static struct op *dowholefile(int, int); | 640 | static struct op *dowholefile(int, int); |
| 676 | 641 | ||
| 677 | /* Globals */ | ||
| 678 | extern char **environ; /* environment pointer */ | ||
| 679 | 642 | ||
| 643 | /* Globals */ | ||
| 680 | static char **dolv; | 644 | static char **dolv; |
| 681 | static int dolc; | 645 | static int dolc; |
| 682 | static int exstat; | 646 | static int exstat; |
| @@ -773,219 +737,457 @@ void print_tree(struct op *head) | |||
| 773 | #endif /* MSHDEBUG */ | 737 | #endif /* MSHDEBUG */ |
| 774 | 738 | ||
| 775 | 739 | ||
| 776 | #if ENABLE_FEATURE_EDITING | 740 | /* fail but return to process next command */ |
| 777 | static char *current_prompt; | 741 | static void fail(void) |
| 778 | #endif | 742 | { |
| 743 | longjmp(failpt, 1); | ||
| 744 | /* NOTREACHED */ | ||
| 745 | } | ||
| 746 | |||
| 747 | /* abort shell (or fail in subshell) */ | ||
| 748 | static void leave(void) ATTRIBUTE_NORETURN; | ||
| 749 | static void leave(void) | ||
| 750 | { | ||
| 751 | DBGPRINTF(("LEAVE: leave called!\n")); | ||
| 752 | |||
| 753 | if (execflg) | ||
| 754 | fail(); | ||
| 755 | scraphere(); | ||
| 756 | freehere(1); | ||
| 757 | runtrap(0); | ||
| 758 | _exit(exstat); | ||
| 759 | /* NOTREACHED */ | ||
| 760 | } | ||
| 761 | |||
| 762 | static void warn(const char *s) | ||
| 763 | { | ||
| 764 | if (*s) { | ||
| 765 | prs(s); | ||
| 766 | exstat = -1; | ||
| 767 | } | ||
| 768 | prs("\n"); | ||
| 769 | if (flag['e']) | ||
| 770 | leave(); | ||
| 771 | } | ||
| 772 | |||
| 773 | static void err(const char *s) | ||
| 774 | { | ||
| 775 | warn(s); | ||
| 776 | if (flag['n']) | ||
| 777 | return; | ||
| 778 | if (!interactive) | ||
| 779 | leave(); | ||
| 780 | if (e.errpt) | ||
| 781 | longjmp(e.errpt, 1); | ||
| 782 | closeall(); | ||
| 783 | e.iop = e.iobase = iostack; | ||
| 784 | } | ||
| 785 | |||
| 786 | /* -------- area.c -------- */ | ||
| 779 | 787 | ||
| 780 | /* -------- sh.c -------- */ | ||
| 781 | /* | 788 | /* |
| 782 | * shell | 789 | * All memory between (char *)areabot and (char *)(areatop+1) is |
| 790 | * exclusively administered by the area management routines. | ||
| 791 | * It is assumed that sbrk() and brk() manipulate the high end. | ||
| 783 | */ | 792 | */ |
| 784 | 793 | ||
| 794 | #define sbrk(X) ({ \ | ||
| 795 | void * __q = (void *)-1; \ | ||
| 796 | if (brkaddr + (int)(X) < brktop) { \ | ||
| 797 | __q = brkaddr; \ | ||
| 798 | brkaddr += (int)(X); \ | ||
| 799 | } \ | ||
| 800 | __q; \ | ||
| 801 | }) | ||
| 785 | 802 | ||
| 786 | #if ENABLE_FEATURE_EDITING | 803 | static void initarea(void) |
| 787 | static line_input_t *line_input_state; | 804 | { |
| 788 | #endif | 805 | brkaddr = xmalloc(AREASIZE); |
| 806 | brktop = brkaddr + AREASIZE; | ||
| 789 | 807 | ||
| 790 | int msh_main(int argc, char **argv) | 808 | while ((long) sbrk(0) & ALIGN) |
| 809 | sbrk(1); | ||
| 810 | areabot = (struct region *) sbrk(REGSIZE); | ||
| 811 | |||
| 812 | areabot->next = areabot; | ||
| 813 | areabot->area = BUSY; | ||
| 814 | areatop = areabot; | ||
| 815 | areanxt = areabot; | ||
| 816 | } | ||
| 817 | |||
| 818 | static char *getcell(unsigned nbytes) | ||
| 791 | { | 819 | { |
| 792 | int f; | 820 | int nregio; |
| 793 | char *s; | 821 | struct region *p, *q; |
| 794 | int cflag; | 822 | int i; |
| 795 | char *name, **ap; | ||
| 796 | int (*iof) (struct ioarg *); | ||
| 797 | 823 | ||
| 798 | #if ENABLE_FEATURE_EDITING | 824 | if (nbytes == 0) { |
| 799 | line_input_state = new_line_input_t(FOR_SHELL); | 825 | puts("getcell(0)"); |
| 800 | #endif | 826 | abort(); |
| 827 | } | ||
| 828 | /* silly and defeats the algorithm */ | ||
| 829 | /* | ||
| 830 | * round upwards and add administration area | ||
| 831 | */ | ||
| 832 | nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1; | ||
| 833 | p = areanxt; | ||
| 834 | for (;;) { | ||
| 835 | if (p->area > areanum) { | ||
| 836 | /* | ||
| 837 | * merge free cells | ||
| 838 | */ | ||
| 839 | while ((q = p->next)->area > areanum && q != areanxt) | ||
| 840 | p->next = q->next; | ||
| 841 | /* | ||
| 842 | * exit loop if cell big enough | ||
| 843 | */ | ||
| 844 | if (q >= p + nregio) | ||
| 845 | goto found; | ||
| 846 | } | ||
| 847 | p = p->next; | ||
| 848 | if (p == areanxt) | ||
| 849 | break; | ||
| 850 | } | ||
| 851 | i = nregio >= GROWBY ? nregio : GROWBY; | ||
| 852 | p = (struct region *) sbrk(i * REGSIZE); | ||
| 853 | if (p == (struct region *) -1) | ||
| 854 | return NULL; | ||
| 855 | p--; | ||
| 856 | if (p != areatop) { | ||
| 857 | puts("not contig"); | ||
| 858 | abort(); /* allocated areas are contiguous */ | ||
| 859 | } | ||
| 860 | q = p + i; | ||
| 861 | p->next = q; | ||
| 862 | p->area = FREE; | ||
| 863 | q->next = areabot; | ||
| 864 | q->area = BUSY; | ||
| 865 | areatop = q; | ||
| 866 | found: | ||
| 867 | /* | ||
| 868 | * we found a FREE area big enough, pointed to by 'p', and up to 'q' | ||
| 869 | */ | ||
| 870 | areanxt = p + nregio; | ||
| 871 | if (areanxt < q) { | ||
| 872 | /* | ||
| 873 | * split into requested area and rest | ||
| 874 | */ | ||
| 875 | if (areanxt + 1 > q) { | ||
| 876 | puts("OOM"); | ||
| 877 | abort(); /* insufficient space left for admin */ | ||
| 878 | } | ||
| 879 | areanxt->next = q; | ||
| 880 | areanxt->area = FREE; | ||
| 881 | p->next = areanxt; | ||
| 882 | } | ||
| 883 | p->area = areanum; | ||
| 884 | return (char *) (p + 1); | ||
| 885 | } | ||
| 801 | 886 | ||
| 802 | DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ)); | 887 | static void freecell(char *cp) |
| 888 | { | ||
| 889 | struct region *p; | ||
| 803 | 890 | ||
| 804 | initarea(); | 891 | p = (struct region *) cp; |
| 805 | ap = environ; | 892 | if (p != NULL) { |
| 806 | if (ap != NULL) { | 893 | p--; |
| 807 | while (*ap) | 894 | if (p < areanxt) |
| 808 | assign(*ap++, !COPYV); | 895 | areanxt = p; |
| 809 | for (ap = environ; *ap;) | 896 | p->area = FREE; |
| 810 | export(lookup(*ap++)); | ||
| 811 | } | 897 | } |
| 812 | closeall(); | 898 | } |
| 813 | areanum = 1; | 899 | #define DELETE(obj) freecell((char *)obj) |
| 814 | 900 | ||
| 815 | shell = lookup("SHELL"); | 901 | static void freearea(int a) |
| 816 | if (shell->value == null) | 902 | { |
| 817 | setval(shell, (char *)DEFAULT_SHELL); | 903 | struct region *p, *top; |
| 818 | export(shell); | ||
| 819 | 904 | ||
| 820 | homedir = lookup("HOME"); | 905 | top = areatop; |
| 821 | if (homedir->value == null) | 906 | for (p = areabot; p != top; p = p->next) |
| 822 | setval(homedir, "/"); | 907 | if (p->area >= a) |
| 823 | export(homedir); | 908 | p->area = FREE; |
| 909 | } | ||
| 824 | 910 | ||
| 825 | setval(lookup("$"), putn(getpid())); | 911 | static void setarea(char *cp, int a) |
| 912 | { | ||
| 913 | struct region *p; | ||
| 826 | 914 | ||
| 827 | path = lookup("PATH"); | 915 | p = (struct region *) cp; |
| 828 | if (path->value == null) { | 916 | if (p != NULL) |
| 829 | if (geteuid() == 0) | 917 | (p - 1)->area = a; |
| 830 | setval(path, "/sbin:/bin:/usr/sbin:/usr/bin"); | 918 | } |
| 831 | else | ||
| 832 | setval(path, "/bin:/usr/bin"); | ||
| 833 | } | ||
| 834 | export(path); | ||
| 835 | 919 | ||
| 836 | ifs = lookup("IFS"); | 920 | static int getarea(char *cp) |
| 837 | if (ifs->value == null) | 921 | { |
| 838 | setval(ifs, " \t\n"); | 922 | return ((struct region *) cp - 1)->area; |
| 923 | } | ||
| 839 | 924 | ||
| 840 | #ifdef MSHDEBUG | 925 | static void garbage(void) |
| 841 | mshdbg_var = lookup("MSHDEBUG"); | 926 | { |
| 842 | if (mshdbg_var->value == null) | 927 | struct region *p, *q, *top; |
| 843 | setval(mshdbg_var, "0"); | ||
| 844 | #endif | ||
| 845 | 928 | ||
| 846 | prompt = lookup("PS1"); | 929 | top = areatop; |
| 847 | #if ENABLE_FEATURE_EDITING_FANCY_PROMPT | 930 | for (p = areabot; p != top; p = p->next) { |
| 848 | if (prompt->value == null) | 931 | if (p->area > areanum) { |
| 849 | #endif | 932 | while ((q = p->next)->area > areanum) |
| 850 | setval(prompt, DEFAULT_USER_PROMPT); | 933 | p->next = q->next; |
| 851 | if (geteuid() == 0) { | 934 | areanxt = p; |
| 852 | setval(prompt, DEFAULT_ROOT_PROMPT); | 935 | } |
| 853 | prompt->status &= ~EXPORT; | 936 | } |
| 937 | #ifdef SHRINKBY | ||
| 938 | if (areatop >= q + SHRINKBY && q->area > areanum) { | ||
| 939 | brk((char *) (q + 1)); | ||
| 940 | q->next = areabot; | ||
| 941 | q->area = BUSY; | ||
| 942 | areatop = q; | ||
| 854 | } | 943 | } |
| 855 | cprompt = lookup("PS2"); | ||
| 856 | #if ENABLE_FEATURE_EDITING_FANCY_PROMPT | ||
| 857 | if (cprompt->value == null) | ||
| 858 | #endif | 944 | #endif |
| 859 | setval(cprompt, "> "); | 945 | } |
| 860 | 946 | ||
| 861 | iof = filechar; | 947 | static char *space(int n) |
| 862 | cflag = 0; | 948 | { |
| 863 | name = *argv++; | 949 | char *cp; |
| 864 | if (--argc >= 1) { | ||
| 865 | if (argv[0][0] == '-' && argv[0][1] != '\0') { | ||
| 866 | for (s = argv[0] + 1; *s; s++) | ||
| 867 | switch (*s) { | ||
| 868 | case 'c': | ||
| 869 | prompt->status &= ~EXPORT; | ||
| 870 | cprompt->status &= ~EXPORT; | ||
| 871 | setval(prompt, ""); | ||
| 872 | setval(cprompt, ""); | ||
| 873 | cflag = 1; | ||
| 874 | if (--argc > 0) | ||
| 875 | PUSHIO(aword, *++argv, iof = nlchar); | ||
| 876 | break; | ||
| 877 | 950 | ||
| 878 | case 'q': | 951 | cp = getcell(n); |
| 879 | qflag = SIG_DFL; | 952 | if (cp == '\0') |
| 880 | break; | 953 | err("out of string space"); |
| 954 | return cp; | ||
| 955 | } | ||
| 881 | 956 | ||
| 882 | case 's': | 957 | static char *strsave(const char *s, int a) |
| 883 | /* standard input */ | 958 | { |
| 884 | break; | 959 | char *cp; |
| 885 | 960 | ||
| 886 | case 't': | 961 | cp = space(strlen(s) + 1); |
| 887 | prompt->status &= ~EXPORT; | 962 | if (cp != NULL) { |
| 888 | setval(prompt, ""); | 963 | setarea(cp, a); |
| 889 | iof = linechar; | 964 | strcpy(cp, s); |
| 890 | break; | 965 | return cp; |
| 966 | } | ||
| 967 | return ""; | ||
| 968 | } | ||
| 891 | 969 | ||
| 892 | case 'i': | 970 | /* -------- var.c -------- */ |
| 893 | interactive++; | ||
| 894 | default: | ||
| 895 | if (*s >= 'a' && *s <= 'z') | ||
| 896 | flag[(int) *s]++; | ||
| 897 | } | ||
| 898 | } else { | ||
| 899 | argv--; | ||
| 900 | argc++; | ||
| 901 | } | ||
| 902 | 971 | ||
| 903 | if (iof == filechar && --argc > 0) { | 972 | static int eqname(const char *n1, const char *n2) |
| 904 | setval(prompt, ""); | 973 | { |
| 905 | setval(cprompt, ""); | 974 | for (; *n1 != '=' && *n1 != '\0'; n1++) |
| 906 | prompt->status &= ~EXPORT; | 975 | if (*n2++ != *n1) |
| 907 | cprompt->status &= ~EXPORT; | 976 | return 0; |
| 977 | return *n2 == '\0' || *n2 == '='; | ||
| 978 | } | ||
| 908 | 979 | ||
| 909 | /* Shell is non-interactive, activate printf-based debug */ | 980 | static char *findeq(const char *cp) |
| 910 | #ifdef MSHDEBUG | 981 | { |
| 911 | mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0'); | 982 | while (*cp != '\0' && *cp != '=') |
| 912 | if (mshdbg < 0) | 983 | cp++; |
| 913 | mshdbg = 0; | 984 | return cp; |
| 914 | #endif | 985 | } |
| 915 | DBGPRINTF(("MSH_MAIN: calling newfile()\n")); | ||
| 916 | 986 | ||
| 917 | name = *++argv; | 987 | /* |
| 918 | if (newfile(name)) | 988 | * Find the given name in the dictionary |
| 919 | exit(1); /* Exit on error */ | 989 | * and return its value. If the name was |
| 920 | } | 990 | * not previously there, enter it now and |
| 991 | * return a null value. | ||
| 992 | */ | ||
| 993 | static struct var *lookup(const char *n) | ||
| 994 | { | ||
| 995 | struct var *vp; | ||
| 996 | char *cp; | ||
| 997 | int c; | ||
| 998 | static struct var dummy; | ||
| 999 | |||
| 1000 | if (isdigit(*n)) { | ||
| 1001 | dummy.name = n; | ||
| 1002 | for (c = 0; isdigit(*n) && c < 1000; n++) | ||
| 1003 | c = c * 10 + *n - '0'; | ||
| 1004 | dummy.status = RONLY; | ||
| 1005 | dummy.value = (c <= dolc ? dolv[c] : null); | ||
| 1006 | return &dummy; | ||
| 1007 | } | ||
| 1008 | for (vp = vlist; vp; vp = vp->next) | ||
| 1009 | if (eqname(vp->name, n)) | ||
| 1010 | return vp; | ||
| 1011 | cp = findeq(n); | ||
| 1012 | vp = (struct var *) space(sizeof(*vp)); | ||
| 1013 | if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) { | ||
| 1014 | dummy.name = dummy.value = ""; | ||
| 1015 | return &dummy; | ||
| 921 | } | 1016 | } |
| 1017 | for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++); | ||
| 1018 | if (*cp == '\0') | ||
| 1019 | *cp = '='; | ||
| 1020 | *++cp = '\0'; | ||
| 1021 | setarea((char *) vp, 0); | ||
| 1022 | setarea((char *) vp->name, 0); | ||
| 1023 | vp->value = null; | ||
| 1024 | vp->next = vlist; | ||
| 1025 | vp->status = GETCELL; | ||
| 1026 | vlist = vp; | ||
| 1027 | return vp; | ||
| 1028 | } | ||
| 922 | 1029 | ||
| 923 | setdash(); | 1030 | /* |
| 1031 | * if name is not NULL, it must be | ||
| 1032 | * a prefix of the space `val', | ||
| 1033 | * and end with `='. | ||
| 1034 | * this is all so that exporting | ||
| 1035 | * values is reasonably painless. | ||
| 1036 | */ | ||
| 1037 | static void nameval(struct var *vp, const char *val, const char *name) | ||
| 1038 | { | ||
| 1039 | const char *cp; | ||
| 1040 | char *xp; | ||
| 1041 | int fl; | ||
| 924 | 1042 | ||
| 925 | /* This won't be true if PUSHIO has been called, say from newfile() above */ | 1043 | if (vp->status & RONLY) { |
| 926 | if (e.iop < iostack) { | 1044 | xp = vp->name; |
| 927 | PUSHIO(afile, 0, iof); | 1045 | while (*xp && *xp != '=') |
| 928 | if (isatty(0) && isatty(1) && !cflag) { | 1046 | putc(*xp++, stderr); |
| 929 | interactive++; | 1047 | err(" is read-only"); |
| 930 | #if !ENABLE_FEATURE_SH_EXTRA_QUIET | 1048 | return; |
| 931 | #ifdef MSHDEBUG | ||
| 932 | printf("\n\n%s Built-in shell (msh with debug)\n", BB_BANNER); | ||
| 933 | #else | ||
| 934 | printf("\n\n%s Built-in shell (msh)\n", BB_BANNER); | ||
| 935 | #endif | ||
| 936 | printf("Enter 'help' for a list of built-in commands.\n\n"); | ||
| 937 | #endif | ||
| 938 | } | ||
| 939 | } | 1049 | } |
| 940 | 1050 | fl = 0; | |
| 941 | signal(SIGQUIT, qflag); | 1051 | if (name == NULL) { |
| 942 | if (name && name[0] == '-') { | 1052 | xp = space(strlen(vp->name) + strlen(val) + 2); |
| 943 | interactive++; | 1053 | if (xp == NULL) |
| 944 | f = open(".profile", 0); | 1054 | return; |
| 945 | if (f >= 0) | 1055 | /* make string: name=value */ |
| 946 | next(remap(f)); | 1056 | setarea(xp, 0); |
| 947 | f = open("/etc/profile", 0); | 1057 | name = xp; |
| 948 | if (f >= 0) | 1058 | cp = vp->name; |
| 949 | next(remap(f)); | 1059 | while ((*xp = *cp++) != '\0' && *xp != '=') |
| 1060 | xp++; | ||
| 1061 | *xp++ = '='; | ||
| 1062 | strcpy(xp, val); | ||
| 1063 | val = xp; | ||
| 1064 | fl = GETCELL; | ||
| 950 | } | 1065 | } |
| 951 | if (interactive) | 1066 | if (vp->status & GETCELL) |
| 952 | signal(SIGTERM, sig); | 1067 | freecell(vp->name); /* form new string `name=value' */ |
| 1068 | vp->name = name; | ||
| 1069 | vp->value = val; | ||
| 1070 | vp->status |= fl; | ||
| 1071 | } | ||
| 953 | 1072 | ||
| 954 | if (signal(SIGINT, SIG_IGN) != SIG_IGN) | 1073 | /* |
| 955 | signal(SIGINT, onintr); | 1074 | * give variable at `vp' the value `val'. |
| 956 | dolv = argv; | 1075 | */ |
| 957 | dolc = argc; | 1076 | static void setval(struct var *vp, const char *val) |
| 958 | dolv[0] = name; | 1077 | { |
| 959 | if (dolc > 1) { | 1078 | nameval(vp, val, NULL); |
| 960 | for (ap = ++argv; --argc > 0;) { | 1079 | } |
| 961 | *ap = *argv++; | 1080 | |
| 962 | if (assign(*ap, !COPYV)) { | 1081 | static void export(struct var *vp) |
| 963 | dolc--; /* keyword */ | 1082 | { |
| 964 | } else { | 1083 | vp->status |= EXPORT; |
| 965 | ap++; | 1084 | } |
| 966 | } | 1085 | |
| 1086 | static void ronly(struct var *vp) | ||
| 1087 | { | ||
| 1088 | if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */ | ||
| 1089 | vp->status |= RONLY; | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | static int isassign(const char *s) | ||
| 1093 | { | ||
| 1094 | unsigned char c; | ||
| 1095 | DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s)); | ||
| 1096 | |||
| 1097 | /* no isalpha() - we shouldn't use locale */ | ||
| 1098 | c = *s; | ||
| 1099 | if (c != '_' | ||
| 1100 | && (unsigned)((c|0x20) - 'a') > 25 /* not letter */ | ||
| 1101 | ) { | ||
| 1102 | return 0; | ||
| 1103 | } | ||
| 1104 | while (1) { | ||
| 1105 | c = *++s; | ||
| 1106 | if (c == '\0') | ||
| 1107 | return 0; | ||
| 1108 | if (c == '=') | ||
| 1109 | return 1; | ||
| 1110 | c |= 0x20; /* lowercase letters, doesn't affect numbers */ | ||
| 1111 | if (c != '_' | ||
| 1112 | && (unsigned)(c - '0') > 9 /* not number */ | ||
| 1113 | && (unsigned)(c - 'a') > 25 /* not letter */ | ||
| 1114 | ) { | ||
| 1115 | return 0; | ||
| 967 | } | 1116 | } |
| 968 | } | 1117 | } |
| 969 | setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc)); | 1118 | } |
| 970 | 1119 | ||
| 971 | DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop %p, iostack %p\n", interactive, e.iop, iostack)); | 1120 | static int assign(const char *s, int cf) |
| 1121 | { | ||
| 1122 | char *cp; | ||
| 1123 | struct var *vp; | ||
| 972 | 1124 | ||
| 973 | for (;;) { | 1125 | DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf)); |
| 974 | if (interactive && e.iop <= iostack) { | 1126 | |
| 975 | #if ENABLE_FEATURE_EDITING | 1127 | if (!isalpha(*s) && *s != '_') |
| 976 | current_prompt = prompt->value; | 1128 | return 0; |
| 977 | #else | 1129 | for (cp = s; *cp != '='; cp++) |
| 978 | prs(prompt->value); | 1130 | if (*cp == '\0' || (!isalnum(*cp) && *cp != '_')) |
| 979 | #endif | 1131 | return 0; |
| 1132 | vp = lookup(s); | ||
| 1133 | nameval(vp, ++cp, cf == COPYV ? NULL : s); | ||
| 1134 | if (cf != COPYV) | ||
| 1135 | vp->status &= ~GETCELL; | ||
| 1136 | return 1; | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | static int checkname(char *cp) | ||
| 1140 | { | ||
| 1141 | DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp)); | ||
| 1142 | |||
| 1143 | if (!isalpha(*cp++) && *(cp - 1) != '_') | ||
| 1144 | return 0; | ||
| 1145 | while (*cp) | ||
| 1146 | if (!isalnum(*cp++) && *(cp - 1) != '_') | ||
| 1147 | return 0; | ||
| 1148 | return 1; | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | static void putvlist(int f, int out) | ||
| 1152 | { | ||
| 1153 | struct var *vp; | ||
| 1154 | |||
| 1155 | for (vp = vlist; vp; vp = vp->next) | ||
| 1156 | if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) { | ||
| 1157 | if (vp->status & EXPORT) | ||
| 1158 | write(out, "export ", 7); | ||
| 1159 | if (vp->status & RONLY) | ||
| 1160 | write(out, "readonly ", 9); | ||
| 1161 | write(out, vp->name, (int) (findeq(vp->name) - vp->name)); | ||
| 1162 | write(out, "\n", 1); | ||
| 980 | } | 1163 | } |
| 981 | onecommand(); | 1164 | } |
| 982 | /* Ensure that getenv("PATH") stays current */ | ||
| 983 | setenv("PATH", path->value, 1); | ||
| 984 | } | ||
| 985 | 1165 | ||
| 986 | DBGPRINTF(("MSH_MAIN: returning.\n")); | 1166 | |
| 1167 | /* | ||
| 1168 | * trap handling | ||
| 1169 | */ | ||
| 1170 | static void sig(int i) | ||
| 1171 | { | ||
| 1172 | trapset = i; | ||
| 1173 | signal(i, sig); | ||
| 987 | } | 1174 | } |
| 988 | 1175 | ||
| 1176 | static void runtrap(int i) | ||
| 1177 | { | ||
| 1178 | char *trapstr; | ||
| 1179 | |||
| 1180 | trapstr = trap[i]; | ||
| 1181 | if (trapstr == NULL) | ||
| 1182 | return; | ||
| 1183 | |||
| 1184 | if (i == 0) | ||
| 1185 | trap[i] = NULL; | ||
| 1186 | |||
| 1187 | RUN(aword, trapstr, nlchar); | ||
| 1188 | } | ||
| 1189 | |||
| 1190 | |||
| 989 | static void setdash(void) | 1191 | static void setdash(void) |
| 990 | { | 1192 | { |
| 991 | char *cp; | 1193 | char *cp; |
| @@ -1083,7 +1285,6 @@ static void onecommand(void) | |||
| 1083 | setjmp(failpt); /* Bruce Evans' fix */ | 1285 | setjmp(failpt); /* Bruce Evans' fix */ |
| 1084 | failpt = m1; | 1286 | failpt = m1; |
| 1085 | if (setjmp(failpt) || yyparse() || intr) { | 1287 | if (setjmp(failpt) || yyparse() || intr) { |
| 1086 | |||
| 1087 | DBGPRINTF(("ONECOMMAND: this is not good.\n")); | 1288 | DBGPRINTF(("ONECOMMAND: this is not good.\n")); |
| 1088 | 1289 | ||
| 1089 | while (e.oenv) | 1290 | while (e.oenv) |
| @@ -1119,49 +1320,6 @@ static void onecommand(void) | |||
| 1119 | } | 1320 | } |
| 1120 | } | 1321 | } |
| 1121 | 1322 | ||
| 1122 | static void fail(void) | ||
| 1123 | { | ||
| 1124 | longjmp(failpt, 1); | ||
| 1125 | /* NOTREACHED */ | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | static void leave(void) | ||
| 1129 | { | ||
| 1130 | DBGPRINTF(("LEAVE: leave called!\n")); | ||
| 1131 | |||
| 1132 | if (execflg) | ||
| 1133 | fail(); | ||
| 1134 | scraphere(); | ||
| 1135 | freehere(1); | ||
| 1136 | runtrap(0); | ||
| 1137 | _exit(exstat); | ||
| 1138 | /* NOTREACHED */ | ||
| 1139 | } | ||
| 1140 | |||
| 1141 | static void warn(const char *s) | ||
| 1142 | { | ||
| 1143 | if (*s) { | ||
| 1144 | prs(s); | ||
| 1145 | exstat = -1; | ||
| 1146 | } | ||
| 1147 | prs("\n"); | ||
| 1148 | if (flag['e']) | ||
| 1149 | leave(); | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | static void err(const char *s) | ||
| 1153 | { | ||
| 1154 | warn(s); | ||
| 1155 | if (flag['n']) | ||
| 1156 | return; | ||
| 1157 | if (!interactive) | ||
| 1158 | leave(); | ||
| 1159 | if (e.errpt) | ||
| 1160 | longjmp(e.errpt, 1); | ||
| 1161 | closeall(); | ||
| 1162 | e.iop = e.iobase = iostack; | ||
| 1163 | } | ||
| 1164 | |||
| 1165 | static int newenv(int f) | 1323 | static int newenv(int f) |
| 1166 | { | 1324 | { |
| 1167 | struct env *ep; | 1325 | struct env *ep; |
| @@ -1251,232 +1409,6 @@ static void onintr(int s) /* ANSI C requires a parameter */ | |||
| 1251 | } | 1409 | } |
| 1252 | } | 1410 | } |
| 1253 | 1411 | ||
| 1254 | static char *space(int n) | ||
| 1255 | { | ||
| 1256 | char *cp; | ||
| 1257 | |||
| 1258 | cp = getcell(n); | ||
| 1259 | if (cp == '\0') | ||
| 1260 | err("out of string space"); | ||
| 1261 | return cp; | ||
| 1262 | } | ||
| 1263 | |||
| 1264 | static char *strsave(char *s, int a) | ||
| 1265 | { | ||
| 1266 | char *cp; | ||
| 1267 | |||
| 1268 | cp = space(strlen(s) + 1); | ||
| 1269 | if (cp != NULL) { | ||
| 1270 | setarea(cp, a); | ||
| 1271 | strcpy(cp, s); | ||
| 1272 | return cp; | ||
| 1273 | } | ||
| 1274 | return ""; | ||
| 1275 | } | ||
| 1276 | |||
| 1277 | /* | ||
| 1278 | * trap handling | ||
| 1279 | */ | ||
| 1280 | static void sig(int i) | ||
| 1281 | { | ||
| 1282 | trapset = i; | ||
| 1283 | signal(i, sig); | ||
| 1284 | } | ||
| 1285 | |||
| 1286 | static void runtrap(int i) | ||
| 1287 | { | ||
| 1288 | char *trapstr; | ||
| 1289 | |||
| 1290 | trapstr = trap[i]; | ||
| 1291 | if (trapstr == NULL) | ||
| 1292 | return; | ||
| 1293 | |||
| 1294 | if (i == 0) | ||
| 1295 | trap[i] = NULL; | ||
| 1296 | |||
| 1297 | RUN(aword, trapstr, nlchar); | ||
| 1298 | } | ||
| 1299 | |||
| 1300 | /* -------- var.c -------- */ | ||
| 1301 | |||
| 1302 | /* | ||
| 1303 | * Find the given name in the dictionary | ||
| 1304 | * and return its value. If the name was | ||
| 1305 | * not previously there, enter it now and | ||
| 1306 | * return a null value. | ||
| 1307 | */ | ||
| 1308 | static struct var *lookup(char *n) | ||
| 1309 | { | ||
| 1310 | struct var *vp; | ||
| 1311 | char *cp; | ||
| 1312 | int c; | ||
| 1313 | static struct var dummy; | ||
| 1314 | |||
| 1315 | if (isdigit(*n)) { | ||
| 1316 | dummy.name = n; | ||
| 1317 | for (c = 0; isdigit(*n) && c < 1000; n++) | ||
| 1318 | c = c * 10 + *n - '0'; | ||
| 1319 | dummy.status = RONLY; | ||
| 1320 | dummy.value = c <= dolc ? dolv[c] : null; | ||
| 1321 | return &dummy; | ||
| 1322 | } | ||
| 1323 | for (vp = vlist; vp; vp = vp->next) | ||
| 1324 | if (eqname(vp->name, n)) | ||
| 1325 | return vp; | ||
| 1326 | cp = findeq(n); | ||
| 1327 | vp = (struct var *) space(sizeof(*vp)); | ||
| 1328 | if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) { | ||
| 1329 | dummy.name = dummy.value = ""; | ||
| 1330 | return &dummy; | ||
| 1331 | } | ||
| 1332 | for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++); | ||
| 1333 | if (*cp == 0) | ||
| 1334 | *cp = '='; | ||
| 1335 | *++cp = '\0'; | ||
| 1336 | setarea((char *) vp, 0); | ||
| 1337 | setarea((char *) vp->name, 0); | ||
| 1338 | vp->value = null; | ||
| 1339 | vp->next = vlist; | ||
| 1340 | vp->status = GETCELL; | ||
| 1341 | vlist = vp; | ||
| 1342 | return vp; | ||
| 1343 | } | ||
| 1344 | |||
| 1345 | /* | ||
| 1346 | * give variable at `vp' the value `val'. | ||
| 1347 | */ | ||
| 1348 | static void setval(struct var *vp, char *val) | ||
| 1349 | { | ||
| 1350 | nameval(vp, val, (char *) NULL); | ||
| 1351 | } | ||
| 1352 | |||
| 1353 | /* | ||
| 1354 | * if name is not NULL, it must be | ||
| 1355 | * a prefix of the space `val', | ||
| 1356 | * and end with `='. | ||
| 1357 | * this is all so that exporting | ||
| 1358 | * values is reasonably painless. | ||
| 1359 | */ | ||
| 1360 | static void nameval(struct var *vp, char *val, char *name) | ||
| 1361 | { | ||
| 1362 | char *cp, *xp; | ||
| 1363 | char *nv; | ||
| 1364 | int fl; | ||
| 1365 | |||
| 1366 | if (vp->status & RONLY) { | ||
| 1367 | for (xp = vp->name; *xp && *xp != '=';) | ||
| 1368 | putc(*xp++, stderr); | ||
| 1369 | err(" is read-only"); | ||
| 1370 | return; | ||
| 1371 | } | ||
| 1372 | fl = 0; | ||
| 1373 | if (name == NULL) { | ||
| 1374 | xp = space(strlen(vp->name) + strlen(val) + 2); | ||
| 1375 | if (xp == NULL) | ||
| 1376 | return; | ||
| 1377 | /* make string: name=value */ | ||
| 1378 | setarea((char *) xp, 0); | ||
| 1379 | name = xp; | ||
| 1380 | for (cp = vp->name; (*xp = *cp++) && *xp != '='; xp++); | ||
| 1381 | if (*xp++ == '\0') | ||
| 1382 | xp[-1] = '='; | ||
| 1383 | nv = xp; | ||
| 1384 | for (cp = val; (*xp++ = *cp++) != '\0';); | ||
| 1385 | val = nv; | ||
| 1386 | fl = GETCELL; | ||
| 1387 | } | ||
| 1388 | if (vp->status & GETCELL) | ||
| 1389 | freecell(vp->name); /* form new string `name=value' */ | ||
| 1390 | vp->name = name; | ||
| 1391 | vp->value = val; | ||
| 1392 | vp->status |= fl; | ||
| 1393 | } | ||
| 1394 | |||
| 1395 | static void export(struct var *vp) | ||
| 1396 | { | ||
| 1397 | vp->status |= EXPORT; | ||
| 1398 | } | ||
| 1399 | |||
| 1400 | static void ronly(struct var *vp) | ||
| 1401 | { | ||
| 1402 | if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */ | ||
| 1403 | vp->status |= RONLY; | ||
| 1404 | } | ||
| 1405 | |||
| 1406 | static int isassign(char *s) | ||
| 1407 | { | ||
| 1408 | DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s)); | ||
| 1409 | |||
| 1410 | if (!isalpha((int) *s) && *s != '_') | ||
| 1411 | return 0; | ||
| 1412 | for (; *s != '='; s++) | ||
| 1413 | if (*s == '\0' || (!isalnum(*s) && *s != '_')) | ||
| 1414 | return 0; | ||
| 1415 | |||
| 1416 | return 1; | ||
| 1417 | } | ||
| 1418 | |||
| 1419 | static int assign(char *s, int cf) | ||
| 1420 | { | ||
| 1421 | char *cp; | ||
| 1422 | struct var *vp; | ||
| 1423 | |||
| 1424 | DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf)); | ||
| 1425 | |||
| 1426 | if (!isalpha(*s) && *s != '_') | ||
| 1427 | return 0; | ||
| 1428 | for (cp = s; *cp != '='; cp++) | ||
| 1429 | if (*cp == '\0' || (!isalnum(*cp) && *cp != '_')) | ||
| 1430 | return 0; | ||
| 1431 | vp = lookup(s); | ||
| 1432 | nameval(vp, ++cp, cf == COPYV ? (char *) NULL : s); | ||
| 1433 | if (cf != COPYV) | ||
| 1434 | vp->status &= ~GETCELL; | ||
| 1435 | return 1; | ||
| 1436 | } | ||
| 1437 | |||
| 1438 | static int checkname(char *cp) | ||
| 1439 | { | ||
| 1440 | DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp)); | ||
| 1441 | |||
| 1442 | if (!isalpha(*cp++) && *(cp - 1) != '_') | ||
| 1443 | return 0; | ||
| 1444 | while (*cp) | ||
| 1445 | if (!isalnum(*cp++) && *(cp - 1) != '_') | ||
| 1446 | return 0; | ||
| 1447 | return 1; | ||
| 1448 | } | ||
| 1449 | |||
| 1450 | static void putvlist(int f, int out) | ||
| 1451 | { | ||
| 1452 | struct var *vp; | ||
| 1453 | |||
| 1454 | for (vp = vlist; vp; vp = vp->next) | ||
| 1455 | if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) { | ||
| 1456 | if (vp->status & EXPORT) | ||
| 1457 | write(out, "export ", 7); | ||
| 1458 | if (vp->status & RONLY) | ||
| 1459 | write(out, "readonly ", 9); | ||
| 1460 | write(out, vp->name, (int) (findeq(vp->name) - vp->name)); | ||
| 1461 | write(out, "\n", 1); | ||
| 1462 | } | ||
| 1463 | } | ||
| 1464 | |||
| 1465 | static int eqname(char *n1, char *n2) | ||
| 1466 | { | ||
| 1467 | for (; *n1 != '=' && *n1 != '\0'; n1++) | ||
| 1468 | if (*n2++ != *n1) | ||
| 1469 | return 0; | ||
| 1470 | return *n2 == '\0' || *n2 == '='; | ||
| 1471 | } | ||
| 1472 | |||
| 1473 | static char *findeq(char *cp) | ||
| 1474 | { | ||
| 1475 | while (*cp != '\0' && *cp != '=') | ||
| 1476 | cp++; | ||
| 1477 | return cp; | ||
| 1478 | } | ||
| 1479 | |||
| 1480 | /* -------- gmatch.c -------- */ | 1412 | /* -------- gmatch.c -------- */ |
| 1481 | /* | 1413 | /* |
| 1482 | * int gmatch(string, pattern) | 1414 | * int gmatch(string, pattern) |
| @@ -1550,165 +1482,6 @@ static char *cclass(char *p, int sub) | |||
| 1550 | } | 1482 | } |
| 1551 | 1483 | ||
| 1552 | 1484 | ||
| 1553 | /* -------- area.c -------- */ | ||
| 1554 | |||
| 1555 | /* | ||
| 1556 | * All memory between (char *)areabot and (char *)(areatop+1) is | ||
| 1557 | * exclusively administered by the area management routines. | ||
| 1558 | * It is assumed that sbrk() and brk() manipulate the high end. | ||
| 1559 | */ | ||
| 1560 | |||
| 1561 | #define sbrk(X) ({ \ | ||
| 1562 | void * __q = (void *)-1; \ | ||
| 1563 | if (brkaddr + (int)(X) < brktop) { \ | ||
| 1564 | __q = brkaddr; \ | ||
| 1565 | brkaddr += (int)(X); \ | ||
| 1566 | } \ | ||
| 1567 | __q; \ | ||
| 1568 | }) | ||
| 1569 | |||
| 1570 | static void initarea(void) | ||
| 1571 | { | ||
| 1572 | brkaddr = xmalloc(AREASIZE); | ||
| 1573 | brktop = brkaddr + AREASIZE; | ||
| 1574 | |||
| 1575 | while ((long) sbrk(0) & ALIGN) | ||
| 1576 | sbrk(1); | ||
| 1577 | areabot = (struct region *) sbrk(REGSIZE); | ||
| 1578 | |||
| 1579 | areabot->next = areabot; | ||
| 1580 | areabot->area = BUSY; | ||
| 1581 | areatop = areabot; | ||
| 1582 | areanxt = areabot; | ||
| 1583 | } | ||
| 1584 | |||
| 1585 | char *getcell(unsigned nbytes) | ||
| 1586 | { | ||
| 1587 | int nregio; | ||
| 1588 | struct region *p, *q; | ||
| 1589 | int i; | ||
| 1590 | |||
| 1591 | if (nbytes == 0) { | ||
| 1592 | puts("getcell(0)"); | ||
| 1593 | abort(); | ||
| 1594 | } | ||
| 1595 | /* silly and defeats the algorithm */ | ||
| 1596 | /* | ||
| 1597 | * round upwards and add administration area | ||
| 1598 | */ | ||
| 1599 | nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1; | ||
| 1600 | for (p = areanxt;;) { | ||
| 1601 | if (p->area > areanum) { | ||
| 1602 | /* | ||
| 1603 | * merge free cells | ||
| 1604 | */ | ||
| 1605 | while ((q = p->next)->area > areanum && q != areanxt) | ||
| 1606 | p->next = q->next; | ||
| 1607 | /* | ||
| 1608 | * exit loop if cell big enough | ||
| 1609 | */ | ||
| 1610 | if (q >= p + nregio) | ||
| 1611 | goto found; | ||
| 1612 | } | ||
| 1613 | p = p->next; | ||
| 1614 | if (p == areanxt) | ||
| 1615 | break; | ||
| 1616 | } | ||
| 1617 | i = nregio >= GROWBY ? nregio : GROWBY; | ||
| 1618 | p = (struct region *) sbrk(i * REGSIZE); | ||
| 1619 | if (p == (struct region *) -1) | ||
| 1620 | return NULL; | ||
| 1621 | p--; | ||
| 1622 | if (p != areatop) { | ||
| 1623 | puts("not contig"); | ||
| 1624 | abort(); /* allocated areas are contiguous */ | ||
| 1625 | } | ||
| 1626 | q = p + i; | ||
| 1627 | p->next = q; | ||
| 1628 | p->area = FREE; | ||
| 1629 | q->next = areabot; | ||
| 1630 | q->area = BUSY; | ||
| 1631 | areatop = q; | ||
| 1632 | found: | ||
| 1633 | /* | ||
| 1634 | * we found a FREE area big enough, pointed to by 'p', and up to 'q' | ||
| 1635 | */ | ||
| 1636 | areanxt = p + nregio; | ||
| 1637 | if (areanxt < q) { | ||
| 1638 | /* | ||
| 1639 | * split into requested area and rest | ||
| 1640 | */ | ||
| 1641 | if (areanxt + 1 > q) { | ||
| 1642 | puts("OOM"); | ||
| 1643 | abort(); /* insufficient space left for admin */ | ||
| 1644 | } | ||
| 1645 | areanxt->next = q; | ||
| 1646 | areanxt->area = FREE; | ||
| 1647 | p->next = areanxt; | ||
| 1648 | } | ||
| 1649 | p->area = areanum; | ||
| 1650 | return (char *) (p + 1); | ||
| 1651 | } | ||
| 1652 | |||
| 1653 | static void freecell(char *cp) | ||
| 1654 | { | ||
| 1655 | struct region *p; | ||
| 1656 | |||
| 1657 | p = (struct region *) cp; | ||
| 1658 | if (p != NULL) { | ||
| 1659 | p--; | ||
| 1660 | if (p < areanxt) | ||
| 1661 | areanxt = p; | ||
| 1662 | p->area = FREE; | ||
| 1663 | } | ||
| 1664 | } | ||
| 1665 | |||
| 1666 | static void freearea(int a) | ||
| 1667 | { | ||
| 1668 | struct region *p, *top; | ||
| 1669 | |||
| 1670 | top = areatop; | ||
| 1671 | for (p = areabot; p != top; p = p->next) | ||
| 1672 | if (p->area >= a) | ||
| 1673 | p->area = FREE; | ||
| 1674 | } | ||
| 1675 | |||
| 1676 | static void setarea(char *cp, int a) | ||
| 1677 | { | ||
| 1678 | struct region *p; | ||
| 1679 | |||
| 1680 | p = (struct region *) cp; | ||
| 1681 | if (p != NULL) | ||
| 1682 | (p - 1)->area = a; | ||
| 1683 | } | ||
| 1684 | |||
| 1685 | int getarea(char *cp) | ||
| 1686 | { | ||
| 1687 | return ((struct region *) cp - 1)->area; | ||
| 1688 | } | ||
| 1689 | |||
| 1690 | static void garbage(void) | ||
| 1691 | { | ||
| 1692 | struct region *p, *q, *top; | ||
| 1693 | |||
| 1694 | top = areatop; | ||
| 1695 | for (p = areabot; p != top; p = p->next) { | ||
| 1696 | if (p->area > areanum) { | ||
| 1697 | while ((q = p->next)->area > areanum) | ||
| 1698 | p->next = q->next; | ||
| 1699 | areanxt = p; | ||
| 1700 | } | ||
| 1701 | } | ||
| 1702 | #ifdef SHRINKBY | ||
| 1703 | if (areatop >= q + SHRINKBY && q->area > areanum) { | ||
| 1704 | brk((char *) (q + 1)); | ||
| 1705 | q->next = areabot; | ||
| 1706 | q->area = BUSY; | ||
| 1707 | areatop = q; | ||
| 1708 | } | ||
| 1709 | #endif | ||
| 1710 | } | ||
| 1711 | |||
| 1712 | /* -------- csyn.c -------- */ | 1485 | /* -------- csyn.c -------- */ |
| 1713 | /* | 1486 | /* |
| 1714 | * shell: syntax (C version) | 1487 | * shell: syntax (C version) |
| @@ -2591,9 +2364,7 @@ static int execute(struct op *t, int *pin, int *pout, int act) | |||
| 2591 | break; | 2364 | break; |
| 2592 | 2365 | ||
| 2593 | case TCOM: | 2366 | case TCOM: |
| 2594 | { | 2367 | rv = forkexec(t, pin, pout, act, wp); |
| 2595 | rv = forkexec(t, pin, pout, act, wp); | ||
| 2596 | } | ||
| 2597 | break; | 2368 | break; |
| 2598 | 2369 | ||
| 2599 | case TPIPE: | 2370 | case TPIPE: |
| @@ -2846,8 +2617,7 @@ forkexec(struct op *t, int *pin, int *pout, int act, char **wp) | |||
| 2846 | return -1; | 2617 | return -1; |
| 2847 | } | 2618 | } |
| 2848 | 2619 | ||
| 2849 | if (newpid > 0) { /* Parent */ | 2620 | if (newpid > 0) { /* Parent */ |
| 2850 | |||
| 2851 | /* Restore values */ | 2621 | /* Restore values */ |
| 2852 | pin = hpin; | 2622 | pin = hpin; |
| 2853 | pout = hpout; | 2623 | pout = hpout; |
| @@ -2856,12 +2626,10 @@ forkexec(struct op *t, int *pin, int *pout, int act, char **wp) | |||
| 2856 | intr = hintr; | 2626 | intr = hintr; |
| 2857 | brklist = hbrklist; | 2627 | brklist = hbrklist; |
| 2858 | execflg = hexecflg; | 2628 | execflg = hexecflg; |
| 2859 | |||
| 2860 | /* moved up | 2629 | /* moved up |
| 2861 | if (i == -1) | 2630 | if (i == -1) |
| 2862 | return rv; | 2631 | return rv; |
| 2863 | */ | 2632 | */ |
| 2864 | |||
| 2865 | if (pin != NULL) | 2633 | if (pin != NULL) |
| 2866 | closepipe(pin); | 2634 | closepipe(pin); |
| 2867 | 2635 | ||
| @@ -3566,12 +3334,12 @@ static int dotrap(struct op *t) | |||
| 3566 | } else | 3334 | } else |
| 3567 | setsig(n, SIG_IGN); | 3335 | setsig(n, SIG_IGN); |
| 3568 | } else { | 3336 | } else { |
| 3569 | if (interactive) | 3337 | if (interactive) { |
| 3570 | if (n == SIGINT) | 3338 | if (n == SIGINT) |
| 3571 | setsig(n, onintr); | 3339 | setsig(n, onintr); |
| 3572 | else | 3340 | else |
| 3573 | setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL); | 3341 | setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL); |
| 3574 | else | 3342 | } else |
| 3575 | setsig(n, SIG_DFL); | 3343 | setsig(n, SIG_DFL); |
| 3576 | } | 3344 | } |
| 3577 | } | 3345 | } |
| @@ -5311,6 +5079,211 @@ static void freehere(int area) | |||
| 5311 | } | 5079 | } |
| 5312 | 5080 | ||
| 5313 | 5081 | ||
| 5082 | /* -------- sh.c -------- */ | ||
| 5083 | /* | ||
| 5084 | * shell | ||
| 5085 | */ | ||
| 5086 | |||
| 5087 | int msh_main(int argc, char **argv) | ||
| 5088 | { | ||
| 5089 | int f; | ||
| 5090 | char *s; | ||
| 5091 | int cflag; | ||
| 5092 | char *name, **ap; | ||
| 5093 | int (*iof) (struct ioarg *); | ||
| 5094 | |||
| 5095 | #if ENABLE_FEATURE_EDITING | ||
| 5096 | line_input_state = new_line_input_t(FOR_SHELL); | ||
| 5097 | #endif | ||
| 5098 | |||
| 5099 | DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ)); | ||
| 5100 | |||
| 5101 | initarea(); | ||
| 5102 | ap = environ; | ||
| 5103 | if (ap != NULL) { | ||
| 5104 | while (*ap) | ||
| 5105 | assign(*ap++, !COPYV); | ||
| 5106 | for (ap = environ; *ap;) | ||
| 5107 | export(lookup(*ap++)); | ||
| 5108 | } | ||
| 5109 | closeall(); | ||
| 5110 | areanum = 1; | ||
| 5111 | |||
| 5112 | shell = lookup("SHELL"); | ||
| 5113 | if (shell->value == null) | ||
| 5114 | setval(shell, (char *)DEFAULT_SHELL); | ||
| 5115 | export(shell); | ||
| 5116 | |||
| 5117 | homedir = lookup("HOME"); | ||
| 5118 | if (homedir->value == null) | ||
| 5119 | setval(homedir, "/"); | ||
| 5120 | export(homedir); | ||
| 5121 | |||
| 5122 | setval(lookup("$"), putn(getpid())); | ||
| 5123 | |||
| 5124 | path = lookup("PATH"); | ||
| 5125 | if (path->value == null) { | ||
| 5126 | if (geteuid() == 0) | ||
| 5127 | setval(path, "/sbin:/bin:/usr/sbin:/usr/bin"); | ||
| 5128 | else | ||
| 5129 | setval(path, "/bin:/usr/bin"); | ||
| 5130 | } | ||
| 5131 | export(path); | ||
| 5132 | |||
| 5133 | ifs = lookup("IFS"); | ||
| 5134 | if (ifs->value == null) | ||
| 5135 | setval(ifs, " \t\n"); | ||
| 5136 | |||
| 5137 | #ifdef MSHDEBUG | ||
| 5138 | mshdbg_var = lookup("MSHDEBUG"); | ||
| 5139 | if (mshdbg_var->value == null) | ||
| 5140 | setval(mshdbg_var, "0"); | ||
| 5141 | #endif | ||
| 5142 | |||
| 5143 | prompt = lookup("PS1"); | ||
| 5144 | #if ENABLE_FEATURE_EDITING_FANCY_PROMPT | ||
| 5145 | if (prompt->value == null) | ||
| 5146 | #endif | ||
| 5147 | setval(prompt, DEFAULT_USER_PROMPT); | ||
| 5148 | if (geteuid() == 0) { | ||
| 5149 | setval(prompt, DEFAULT_ROOT_PROMPT); | ||
| 5150 | prompt->status &= ~EXPORT; | ||
| 5151 | } | ||
| 5152 | cprompt = lookup("PS2"); | ||
| 5153 | #if ENABLE_FEATURE_EDITING_FANCY_PROMPT | ||
| 5154 | if (cprompt->value == null) | ||
| 5155 | #endif | ||
| 5156 | setval(cprompt, "> "); | ||
| 5157 | |||
| 5158 | iof = filechar; | ||
| 5159 | cflag = 0; | ||
| 5160 | name = *argv++; | ||
| 5161 | if (--argc >= 1) { | ||
| 5162 | if (argv[0][0] == '-' && argv[0][1] != '\0') { | ||
| 5163 | for (s = argv[0] + 1; *s; s++) | ||
| 5164 | switch (*s) { | ||
| 5165 | case 'c': | ||
| 5166 | prompt->status &= ~EXPORT; | ||
| 5167 | cprompt->status &= ~EXPORT; | ||
| 5168 | setval(prompt, ""); | ||
| 5169 | setval(cprompt, ""); | ||
| 5170 | cflag = 1; | ||
| 5171 | if (--argc > 0) | ||
| 5172 | PUSHIO(aword, *++argv, iof = nlchar); | ||
| 5173 | break; | ||
| 5174 | |||
| 5175 | case 'q': | ||
| 5176 | qflag = SIG_DFL; | ||
| 5177 | break; | ||
| 5178 | |||
| 5179 | case 's': | ||
| 5180 | /* standard input */ | ||
| 5181 | break; | ||
| 5182 | |||
| 5183 | case 't': | ||
| 5184 | prompt->status &= ~EXPORT; | ||
| 5185 | setval(prompt, ""); | ||
| 5186 | iof = linechar; | ||
| 5187 | break; | ||
| 5188 | |||
| 5189 | case 'i': | ||
| 5190 | interactive++; | ||
| 5191 | default: | ||
| 5192 | if (*s >= 'a' && *s <= 'z') | ||
| 5193 | flag[(int) *s]++; | ||
| 5194 | } | ||
| 5195 | } else { | ||
| 5196 | argv--; | ||
| 5197 | argc++; | ||
| 5198 | } | ||
| 5199 | |||
| 5200 | if (iof == filechar && --argc > 0) { | ||
| 5201 | setval(prompt, ""); | ||
| 5202 | setval(cprompt, ""); | ||
| 5203 | prompt->status &= ~EXPORT; | ||
| 5204 | cprompt->status &= ~EXPORT; | ||
| 5205 | |||
| 5206 | /* Shell is non-interactive, activate printf-based debug */ | ||
| 5207 | #ifdef MSHDEBUG | ||
| 5208 | mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0'); | ||
| 5209 | if (mshdbg < 0) | ||
| 5210 | mshdbg = 0; | ||
| 5211 | #endif | ||
| 5212 | DBGPRINTF(("MSH_MAIN: calling newfile()\n")); | ||
| 5213 | |||
| 5214 | name = *++argv; | ||
| 5215 | if (newfile(name)) | ||
| 5216 | exit(1); /* Exit on error */ | ||
| 5217 | } | ||
| 5218 | } | ||
| 5219 | |||
| 5220 | setdash(); | ||
| 5221 | |||
| 5222 | /* This won't be true if PUSHIO has been called, say from newfile() above */ | ||
| 5223 | if (e.iop < iostack) { | ||
| 5224 | PUSHIO(afile, 0, iof); | ||
| 5225 | if (isatty(0) && isatty(1) && !cflag) { | ||
| 5226 | interactive++; | ||
| 5227 | #if !ENABLE_FEATURE_SH_EXTRA_QUIET | ||
| 5228 | #ifdef MSHDEBUG | ||
| 5229 | printf("\n\n%s Built-in shell (msh with debug)\n", BB_BANNER); | ||
| 5230 | #else | ||
| 5231 | printf("\n\n%s Built-in shell (msh)\n", BB_BANNER); | ||
| 5232 | #endif | ||
| 5233 | printf("Enter 'help' for a list of built-in commands.\n\n"); | ||
| 5234 | #endif | ||
| 5235 | } | ||
| 5236 | } | ||
| 5237 | |||
| 5238 | signal(SIGQUIT, qflag); | ||
| 5239 | if (name && name[0] == '-') { | ||
| 5240 | interactive++; | ||
| 5241 | f = open(".profile", 0); | ||
| 5242 | if (f >= 0) | ||
| 5243 | next(remap(f)); | ||
| 5244 | f = open("/etc/profile", 0); | ||
| 5245 | if (f >= 0) | ||
| 5246 | next(remap(f)); | ||
| 5247 | } | ||
| 5248 | if (interactive) | ||
| 5249 | signal(SIGTERM, sig); | ||
| 5250 | |||
| 5251 | if (signal(SIGINT, SIG_IGN) != SIG_IGN) | ||
| 5252 | signal(SIGINT, onintr); | ||
| 5253 | dolv = argv; | ||
| 5254 | dolc = argc; | ||
| 5255 | dolv[0] = name; | ||
| 5256 | if (dolc > 1) { | ||
| 5257 | for (ap = ++argv; --argc > 0;) { | ||
| 5258 | *ap = *argv++; | ||
| 5259 | if (assign(*ap, !COPYV)) { | ||
| 5260 | dolc--; /* keyword */ | ||
| 5261 | } else { | ||
| 5262 | ap++; | ||
| 5263 | } | ||
| 5264 | } | ||
| 5265 | } | ||
| 5266 | setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc)); | ||
| 5267 | |||
| 5268 | DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop %p, iostack %p\n", interactive, e.iop, iostack)); | ||
| 5269 | |||
| 5270 | for (;;) { | ||
| 5271 | if (interactive && e.iop <= iostack) { | ||
| 5272 | #if ENABLE_FEATURE_EDITING | ||
| 5273 | current_prompt = prompt->value; | ||
| 5274 | #else | ||
| 5275 | prs(prompt->value); | ||
| 5276 | #endif | ||
| 5277 | } | ||
| 5278 | onecommand(); | ||
| 5279 | /* Ensure that getenv("PATH") stays current */ | ||
| 5280 | setenv("PATH", path->value, 1); | ||
| 5281 | } | ||
| 5282 | |||
| 5283 | DBGPRINTF(("MSH_MAIN: returning.\n")); | ||
| 5284 | } | ||
| 5285 | |||
| 5286 | |||
| 5314 | /* | 5287 | /* |
| 5315 | * Copyright (c) 1987,1997, Prentice Hall | 5288 | * Copyright (c) 1987,1997, Prentice Hall |
| 5316 | * All rights reserved. | 5289 | * All rights reserved. |
