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. |