diff options
author | vda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2007-02-23 01:03:40 +0000 |
---|---|---|
committer | vda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2007-02-23 01:03:40 +0000 |
commit | 439c291be500b06d5052c1dc8507382bac8676cb (patch) | |
tree | dd28e83b8452df20cd13e8d83a5347741b977469 /shell | |
parent | 817ec0fbc18b22200c0cad5b5dbbb34c8c80ff56 (diff) | |
download | busybox-w32-439c291be500b06d5052c1dc8507382bac8676cb.tar.gz busybox-w32-439c291be500b06d5052c1dc8507382bac8676cb.tar.bz2 busybox-w32-439c291be500b06d5052c1dc8507382bac8676cb.zip |
ash: cleanup part 1
git-svn-id: svn://busybox.net/trunk/busybox@17953 69ca8d6d-28ef-0310-b511-8ec308f3f277
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 1125 |
1 files changed, 539 insertions, 586 deletions
diff --git a/shell/ash.c b/shell/ash.c index e262c0e13..379e8ab7f 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -503,6 +503,289 @@ errmsg(int e, const char *em) | |||
503 | } | 503 | } |
504 | 504 | ||
505 | 505 | ||
506 | /* ============ Memory allocation */ | ||
507 | |||
508 | /* | ||
509 | * It appears that grabstackstr() will barf with such alignments | ||
510 | * because stalloc() will return a string allocated in a new stackblock. | ||
511 | */ | ||
512 | #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE) | ||
513 | enum { | ||
514 | /* Most machines require the value returned from malloc to be aligned | ||
515 | * in some way. The following macro will get this right | ||
516 | * on many machines. */ | ||
517 | SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1, | ||
518 | /* Minimum size of a block */ | ||
519 | MINSIZE = SHELL_ALIGN(504), | ||
520 | }; | ||
521 | |||
522 | struct stack_block { | ||
523 | struct stack_block *prev; | ||
524 | char space[MINSIZE]; | ||
525 | }; | ||
526 | |||
527 | struct stackmark { | ||
528 | struct stack_block *stackp; | ||
529 | char *stacknxt; | ||
530 | size_t stacknleft; | ||
531 | struct stackmark *marknext; | ||
532 | }; | ||
533 | |||
534 | static struct stack_block stackbase; | ||
535 | static struct stack_block *stackp = &stackbase; | ||
536 | static struct stackmark *markp; | ||
537 | static char *stacknxt = stackbase.space; | ||
538 | static size_t stacknleft = MINSIZE; | ||
539 | static char *sstrend = stackbase.space + MINSIZE; | ||
540 | static int herefd = -1; | ||
541 | |||
542 | #define stackblock() ((void *)stacknxt) | ||
543 | #define stackblocksize() stacknleft | ||
544 | |||
545 | static void * | ||
546 | ckrealloc(void * p, size_t nbytes) | ||
547 | { | ||
548 | p = realloc(p, nbytes); | ||
549 | if (!p) | ||
550 | ash_msg_and_raise_error(bb_msg_memory_exhausted); | ||
551 | return p; | ||
552 | } | ||
553 | |||
554 | static void * | ||
555 | ckmalloc(size_t nbytes) | ||
556 | { | ||
557 | return ckrealloc(NULL, nbytes); | ||
558 | } | ||
559 | |||
560 | /* | ||
561 | * Make a copy of a string in safe storage. | ||
562 | */ | ||
563 | static char * | ||
564 | ckstrdup(const char *s) | ||
565 | { | ||
566 | char *p = strdup(s); | ||
567 | if (!p) | ||
568 | ash_msg_and_raise_error(bb_msg_memory_exhausted); | ||
569 | return p; | ||
570 | } | ||
571 | |||
572 | /* | ||
573 | * Parse trees for commands are allocated in lifo order, so we use a stack | ||
574 | * to make this more efficient, and also to avoid all sorts of exception | ||
575 | * handling code to handle interrupts in the middle of a parse. | ||
576 | * | ||
577 | * The size 504 was chosen because the Ultrix malloc handles that size | ||
578 | * well. | ||
579 | */ | ||
580 | static void * | ||
581 | stalloc(size_t nbytes) | ||
582 | { | ||
583 | char *p; | ||
584 | size_t aligned; | ||
585 | |||
586 | aligned = SHELL_ALIGN(nbytes); | ||
587 | if (aligned > stacknleft) { | ||
588 | size_t len; | ||
589 | size_t blocksize; | ||
590 | struct stack_block *sp; | ||
591 | |||
592 | blocksize = aligned; | ||
593 | if (blocksize < MINSIZE) | ||
594 | blocksize = MINSIZE; | ||
595 | len = sizeof(struct stack_block) - MINSIZE + blocksize; | ||
596 | if (len < blocksize) | ||
597 | ash_msg_and_raise_error(bb_msg_memory_exhausted); | ||
598 | INT_OFF; | ||
599 | sp = ckmalloc(len); | ||
600 | sp->prev = stackp; | ||
601 | stacknxt = sp->space; | ||
602 | stacknleft = blocksize; | ||
603 | sstrend = stacknxt + blocksize; | ||
604 | stackp = sp; | ||
605 | INT_ON; | ||
606 | } | ||
607 | p = stacknxt; | ||
608 | stacknxt += aligned; | ||
609 | stacknleft -= aligned; | ||
610 | return p; | ||
611 | } | ||
612 | |||
613 | static void | ||
614 | stunalloc(void *p) | ||
615 | { | ||
616 | #if DEBUG | ||
617 | if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) { | ||
618 | write(2, "stunalloc\n", 10); | ||
619 | abort(); | ||
620 | } | ||
621 | #endif | ||
622 | stacknleft += stacknxt - (char *)p; | ||
623 | stacknxt = p; | ||
624 | } | ||
625 | |||
626 | static void | ||
627 | setstackmark(struct stackmark *mark) | ||
628 | { | ||
629 | mark->stackp = stackp; | ||
630 | mark->stacknxt = stacknxt; | ||
631 | mark->stacknleft = stacknleft; | ||
632 | mark->marknext = markp; | ||
633 | markp = mark; | ||
634 | } | ||
635 | |||
636 | static void | ||
637 | popstackmark(struct stackmark *mark) | ||
638 | { | ||
639 | struct stack_block *sp; | ||
640 | |||
641 | INT_OFF; | ||
642 | markp = mark->marknext; | ||
643 | while (stackp != mark->stackp) { | ||
644 | sp = stackp; | ||
645 | stackp = sp->prev; | ||
646 | free(sp); | ||
647 | } | ||
648 | stacknxt = mark->stacknxt; | ||
649 | stacknleft = mark->stacknleft; | ||
650 | sstrend = mark->stacknxt + mark->stacknleft; | ||
651 | INT_ON; | ||
652 | } | ||
653 | |||
654 | /* | ||
655 | * When the parser reads in a string, it wants to stick the string on the | ||
656 | * stack and only adjust the stack pointer when it knows how big the | ||
657 | * string is. Stackblock (defined in stack.h) returns a pointer to a block | ||
658 | * of space on top of the stack and stackblocklen returns the length of | ||
659 | * this block. Growstackblock will grow this space by at least one byte, | ||
660 | * possibly moving it (like realloc). Grabstackblock actually allocates the | ||
661 | * part of the block that has been used. | ||
662 | */ | ||
663 | static void | ||
664 | growstackblock(void) | ||
665 | { | ||
666 | size_t newlen; | ||
667 | |||
668 | newlen = stacknleft * 2; | ||
669 | if (newlen < stacknleft) | ||
670 | ash_msg_and_raise_error(bb_msg_memory_exhausted); | ||
671 | if (newlen < 128) | ||
672 | newlen += 128; | ||
673 | |||
674 | if (stacknxt == stackp->space && stackp != &stackbase) { | ||
675 | struct stack_block *oldstackp; | ||
676 | struct stackmark *xmark; | ||
677 | struct stack_block *sp; | ||
678 | struct stack_block *prevstackp; | ||
679 | size_t grosslen; | ||
680 | |||
681 | INT_OFF; | ||
682 | oldstackp = stackp; | ||
683 | sp = stackp; | ||
684 | prevstackp = sp->prev; | ||
685 | grosslen = newlen + sizeof(struct stack_block) - MINSIZE; | ||
686 | sp = ckrealloc(sp, grosslen); | ||
687 | sp->prev = prevstackp; | ||
688 | stackp = sp; | ||
689 | stacknxt = sp->space; | ||
690 | stacknleft = newlen; | ||
691 | sstrend = sp->space + newlen; | ||
692 | |||
693 | /* | ||
694 | * Stack marks pointing to the start of the old block | ||
695 | * must be relocated to point to the new block | ||
696 | */ | ||
697 | xmark = markp; | ||
698 | while (xmark != NULL && xmark->stackp == oldstackp) { | ||
699 | xmark->stackp = stackp; | ||
700 | xmark->stacknxt = stacknxt; | ||
701 | xmark->stacknleft = stacknleft; | ||
702 | xmark = xmark->marknext; | ||
703 | } | ||
704 | INT_ON; | ||
705 | } else { | ||
706 | char *oldspace = stacknxt; | ||
707 | int oldlen = stacknleft; | ||
708 | char *p = stalloc(newlen); | ||
709 | |||
710 | /* free the space we just allocated */ | ||
711 | stacknxt = memcpy(p, oldspace, oldlen); | ||
712 | stacknleft += newlen; | ||
713 | } | ||
714 | } | ||
715 | |||
716 | static void | ||
717 | grabstackblock(size_t len) | ||
718 | { | ||
719 | len = SHELL_ALIGN(len); | ||
720 | stacknxt += len; | ||
721 | stacknleft -= len; | ||
722 | } | ||
723 | |||
724 | /* | ||
725 | * The following routines are somewhat easier to use than the above. | ||
726 | * The user declares a variable of type STACKSTR, which may be declared | ||
727 | * to be a register. The macro STARTSTACKSTR initializes things. Then | ||
728 | * the user uses the macro STPUTC to add characters to the string. In | ||
729 | * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is | ||
730 | * grown as necessary. When the user is done, she can just leave the | ||
731 | * string there and refer to it using stackblock(). Or she can allocate | ||
732 | * the space for it using grabstackstr(). If it is necessary to allow | ||
733 | * someone else to use the stack temporarily and then continue to grow | ||
734 | * the string, the user should use grabstack to allocate the space, and | ||
735 | * then call ungrabstr(p) to return to the previous mode of operation. | ||
736 | * | ||
737 | * USTPUTC is like STPUTC except that it doesn't check for overflow. | ||
738 | * CHECKSTACKSPACE can be called before USTPUTC to ensure that there | ||
739 | * is space for at least one character. | ||
740 | */ | ||
741 | static void * | ||
742 | growstackstr(void) | ||
743 | { | ||
744 | size_t len = stackblocksize(); | ||
745 | if (herefd >= 0 && len >= 1024) { | ||
746 | full_write(herefd, stackblock(), len); | ||
747 | return stackblock(); | ||
748 | } | ||
749 | growstackblock(); | ||
750 | return stackblock() + len; | ||
751 | } | ||
752 | |||
753 | /* | ||
754 | * Called from CHECKSTRSPACE. | ||
755 | */ | ||
756 | static char * | ||
757 | makestrspace(size_t newlen, char *p) | ||
758 | { | ||
759 | size_t len = p - stacknxt; | ||
760 | size_t size = stackblocksize(); | ||
761 | |||
762 | for (;;) { | ||
763 | size_t nleft; | ||
764 | |||
765 | size = stackblocksize(); | ||
766 | nleft = size - len; | ||
767 | if (nleft >= newlen) | ||
768 | break; | ||
769 | growstackblock(); | ||
770 | } | ||
771 | return stackblock() + len; | ||
772 | } | ||
773 | |||
774 | static char * | ||
775 | stack_nputstr(const char *s, size_t n, char *p) | ||
776 | { | ||
777 | p = makestrspace(n, p); | ||
778 | p = memcpy(p, s, n) + n; | ||
779 | return p; | ||
780 | } | ||
781 | |||
782 | static char * | ||
783 | stack_putstr(const char *s, char *p) | ||
784 | { | ||
785 | return stack_nputstr(s, strlen(s), p); | ||
786 | } | ||
787 | |||
788 | |||
506 | /* ============ Unsorted yet */ | 789 | /* ============ Unsorted yet */ |
507 | 790 | ||
508 | 791 | ||
@@ -773,9 +1056,7 @@ static union node *redirnode; | |||
773 | static struct heredoc *heredoc; | 1056 | static struct heredoc *heredoc; |
774 | static int quoteflag; /* set if (part of) last token was quoted */ | 1057 | static int quoteflag; /* set if (part of) last token was quoted */ |
775 | 1058 | ||
776 | static union node *parsecmd(int); | ||
777 | static void fixredir(union node *, const char *, int); | 1059 | static void fixredir(union node *, const char *, int); |
778 | static const char *const *findkwd(const char *); | ||
779 | static char *endofname(const char *); | 1060 | static char *endofname(const char *); |
780 | 1061 | ||
781 | /* shell.h */ | 1062 | /* shell.h */ |
@@ -867,7 +1148,8 @@ static const char *const tokname_array[] = { | |||
867 | "\1}", | 1148 | "\1}", |
868 | }; | 1149 | }; |
869 | 1150 | ||
870 | static const char *tokname(int tok) | 1151 | static const char * |
1152 | tokname(int tok) | ||
871 | { | 1153 | { |
872 | static char buf[16]; | 1154 | static char buf[16]; |
873 | 1155 | ||
@@ -878,24 +1160,20 @@ static const char *tokname(int tok) | |||
878 | return buf; | 1160 | return buf; |
879 | } | 1161 | } |
880 | 1162 | ||
881 | /* machdep.h */ | 1163 | /* Wrapper around strcmp for qsort/bsearch/... */ |
882 | 1164 | static int | |
883 | /* | 1165 | pstrcmp(const void *a, const void *b) |
884 | * Most machines require the value returned from malloc to be aligned | 1166 | { |
885 | * in some way. The following macro will get this right on many machines. | 1167 | return strcmp((const char *) a, (*(const char *const *) b) + 1); |
886 | */ | 1168 | } |
887 | |||
888 | #define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1) | ||
889 | /* | ||
890 | * It appears that grabstackstr() will barf with such alignments | ||
891 | * because stalloc() will return a string allocated in a new stackblock. | ||
892 | */ | ||
893 | #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE) | ||
894 | |||
895 | /* | ||
896 | * This file was generated by the mksyntax program. | ||
897 | */ | ||
898 | 1169 | ||
1170 | static const char *const * | ||
1171 | findkwd(const char *s) | ||
1172 | { | ||
1173 | return bsearch(s, tokname_array + KWDOFFSET, | ||
1174 | (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET, | ||
1175 | sizeof(const char *), pstrcmp); | ||
1176 | } | ||
899 | 1177 | ||
900 | /* Syntax classes */ | 1178 | /* Syntax classes */ |
901 | #define CWORD 0 /* character is nothing special */ | 1179 | #define CWORD 0 /* character is nothing special */ |
@@ -1006,7 +1284,8 @@ static const char S_I_T[][3] = { | |||
1006 | 1284 | ||
1007 | #define U_C(c) ((unsigned char)(c)) | 1285 | #define U_C(c) ((unsigned char)(c)) |
1008 | 1286 | ||
1009 | static int SIT(int c, int syntax) | 1287 | static int |
1288 | SIT(int c, int syntax) | ||
1010 | { | 1289 | { |
1011 | static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~"; | 1290 | static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~"; |
1012 | #if ENABLE_ASH_ALIAS | 1291 | #if ENABLE_ASH_ALIAS |
@@ -1392,13 +1671,8 @@ static void calcsize(union node *); | |||
1392 | static void sizenodelist(struct nodelist *); | 1671 | static void sizenodelist(struct nodelist *); |
1393 | static union node *copynode(union node *); | 1672 | static union node *copynode(union node *); |
1394 | static struct nodelist *copynodelist(struct nodelist *); | 1673 | static struct nodelist *copynodelist(struct nodelist *); |
1395 | static char *nodesavestr(char *); | 1674 | static char *nodeckstrdup(char *); |
1396 | |||
1397 | 1675 | ||
1398 | static int evalstring(char *, int mask); | ||
1399 | union node; /* BLETCH for ansi C */ | ||
1400 | static void evaltree(union node *, int); | ||
1401 | static void evalbackcmd(union node *, struct backcmd *); | ||
1402 | 1676 | ||
1403 | static int evalskip; /* set if we are skipping commands */ | 1677 | static int evalskip; /* set if we are skipping commands */ |
1404 | static int skipcount; /* number of levels to skip */ | 1678 | static int skipcount; /* number of levels to skip */ |
@@ -1637,16 +1911,16 @@ static void change_random(const char *); | |||
1637 | # endif | 1911 | # endif |
1638 | #endif | 1912 | #endif |
1639 | 1913 | ||
1640 | /* init.h */ | ||
1641 | |||
1642 | static void reset(void); | ||
1643 | |||
1644 | /* var.h */ | 1914 | /* var.h */ |
1645 | 1915 | ||
1646 | /* | 1916 | /* |
1647 | * Shell variables. | 1917 | * Shell variables. |
1648 | */ | 1918 | */ |
1649 | 1919 | ||
1920 | #if ENABLE_ASH_GETOPTS | ||
1921 | static void getoptsreset(const char *); | ||
1922 | #endif | ||
1923 | |||
1650 | /* flags */ | 1924 | /* flags */ |
1651 | #define VEXPORT 0x01 /* variable is exported */ | 1925 | #define VEXPORT 0x01 /* variable is exported */ |
1652 | #define VREADONLY 0x02 /* variable cannot be modified */ | 1926 | #define VREADONLY 0x02 /* variable cannot be modified */ |
@@ -1684,11 +1958,6 @@ static struct localvar *localvars; | |||
1684 | /* | 1958 | /* |
1685 | * Shell variables. | 1959 | * Shell variables. |
1686 | */ | 1960 | */ |
1687 | |||
1688 | #if ENABLE_ASH_GETOPTS | ||
1689 | static void getoptsreset(const char *); | ||
1690 | #endif | ||
1691 | |||
1692 | #if ENABLE_LOCALE_SUPPORT | 1961 | #if ENABLE_LOCALE_SUPPORT |
1693 | static void change_lc_all(const char *value); | 1962 | static void change_lc_all(const char *value); |
1694 | static void change_lc_ctype(const char *value); | 1963 | static void change_lc_ctype(const char *value); |
@@ -1950,46 +2219,6 @@ static void showjobs(FILE *, int); | |||
1950 | 2219 | ||
1951 | static void readcmdfile(char *); | 2220 | static void readcmdfile(char *); |
1952 | 2221 | ||
1953 | /* memalloc.h */ | ||
1954 | |||
1955 | |||
1956 | struct stackmark { | ||
1957 | struct stack_block *stackp; | ||
1958 | char *stacknxt; | ||
1959 | size_t stacknleft; | ||
1960 | struct stackmark *marknext; | ||
1961 | }; | ||
1962 | |||
1963 | /* minimum size of a block */ | ||
1964 | #define MINSIZE SHELL_ALIGN(504) | ||
1965 | |||
1966 | struct stack_block { | ||
1967 | struct stack_block *prev; | ||
1968 | char space[MINSIZE]; | ||
1969 | }; | ||
1970 | |||
1971 | static struct stack_block stackbase; | ||
1972 | static struct stack_block *stackp = &stackbase; | ||
1973 | static struct stackmark *markp; | ||
1974 | static char *stacknxt = stackbase.space; | ||
1975 | static size_t stacknleft = MINSIZE; | ||
1976 | static char *sstrend = stackbase.space + MINSIZE; | ||
1977 | static int herefd = -1; | ||
1978 | |||
1979 | |||
1980 | static void *ckmalloc(size_t); | ||
1981 | static void *ckrealloc(void *, size_t); | ||
1982 | static char *savestr(const char *); | ||
1983 | static void *stalloc(size_t); | ||
1984 | static void stunalloc(void *); | ||
1985 | static void setstackmark(struct stackmark *); | ||
1986 | static void popstackmark(struct stackmark *); | ||
1987 | static void growstackblock(void); | ||
1988 | static void *growstackstr(void); | ||
1989 | static char *makestrspace(size_t, char *); | ||
1990 | static char *stnputs(const char *, size_t, char *); | ||
1991 | static char *stputs(const char *, char *); | ||
1992 | |||
1993 | 2222 | ||
1994 | static char *_STPUTC(int c, char *p) | 2223 | static char *_STPUTC(int c, char *p) |
1995 | { | 2224 | { |
@@ -1999,8 +2228,6 @@ static char *_STPUTC(int c, char *p) | |||
1999 | return p; | 2228 | return p; |
2000 | } | 2229 | } |
2001 | 2230 | ||
2002 | #define stackblock() ((void *)stacknxt) | ||
2003 | #define stackblocksize() stacknleft | ||
2004 | #define STARTSTACKSTR(p) ((p) = stackblock()) | 2231 | #define STARTSTACKSTR(p) ((p) = stackblock()) |
2005 | #define STPUTC(c, p) ((p) = _STPUTC((c), (p))) | 2232 | #define STPUTC(c, p) ((p) = _STPUTC((c), (p))) |
2006 | #define CHECKSTRSPACE(n, p) \ | 2233 | #define CHECKSTRSPACE(n, p) \ |
@@ -2070,7 +2297,6 @@ static int nextopt(const char *); | |||
2070 | #define REDIR_PUSH 01 /* save previous values of file descriptors */ | 2297 | #define REDIR_PUSH 01 /* save previous values of file descriptors */ |
2071 | #define REDIR_SAVEFD2 03 /* set preverrout */ | 2298 | #define REDIR_SAVEFD2 03 /* set preverrout */ |
2072 | 2299 | ||
2073 | union node; | ||
2074 | static void redirect(union node *, int); | 2300 | static void redirect(union node *, int); |
2075 | static void popredir(int); | 2301 | static void popredir(int); |
2076 | static void clearredir(int); | 2302 | static void clearredir(int); |
@@ -2137,29 +2363,6 @@ static int is_safe_applet(char *name) | |||
2137 | } | 2363 | } |
2138 | 2364 | ||
2139 | 2365 | ||
2140 | /* | ||
2141 | * This routine is called when an error or an interrupt occurs in an | ||
2142 | * interactive shell and control is returned to the main command loop. | ||
2143 | */ | ||
2144 | static void | ||
2145 | reset(void) | ||
2146 | { | ||
2147 | /* from eval.c: */ | ||
2148 | evalskip = 0; | ||
2149 | loopnest = 0; | ||
2150 | |||
2151 | /* from input.c: */ | ||
2152 | parselleft = parsenleft = 0; /* clear input buffer */ | ||
2153 | popallfiles(); | ||
2154 | |||
2155 | /* from parser.c: */ | ||
2156 | tokpushback = 0; | ||
2157 | checkkwd = 0; | ||
2158 | |||
2159 | /* from redir.c: */ | ||
2160 | clearredir(0); | ||
2161 | } | ||
2162 | |||
2163 | #if ENABLE_ASH_ALIAS | 2366 | #if ENABLE_ASH_ALIAS |
2164 | static struct alias *atab[ATABSIZE]; | 2367 | static struct alias *atab[ATABSIZE]; |
2165 | 2368 | ||
@@ -2179,13 +2382,13 @@ setalias(const char *name, const char *val) | |||
2179 | if (!(ap->flag & ALIASINUSE)) { | 2382 | if (!(ap->flag & ALIASINUSE)) { |
2180 | free(ap->val); | 2383 | free(ap->val); |
2181 | } | 2384 | } |
2182 | ap->val = savestr(val); | 2385 | ap->val = ckstrdup(val); |
2183 | ap->flag &= ~ALIASDEAD; | 2386 | ap->flag &= ~ALIASDEAD; |
2184 | } else { | 2387 | } else { |
2185 | /* not found */ | 2388 | /* not found */ |
2186 | ap = ckmalloc(sizeof(struct alias)); | 2389 | ap = ckmalloc(sizeof(struct alias)); |
2187 | ap->name = savestr(name); | 2390 | ap->name = ckstrdup(name); |
2188 | ap->val = savestr(val); | 2391 | ap->val = ckstrdup(val); |
2189 | ap->flag = 0; | 2392 | ap->flag = 0; |
2190 | ap->next = 0; | 2393 | ap->next = 0; |
2191 | *app = ap; | 2394 | *app = ap; |
@@ -2461,7 +2664,7 @@ static const char * updatepwd(const char *dir) | |||
2461 | if (*dir != '/') { | 2664 | if (*dir != '/') { |
2462 | if (curdir == nullstr) | 2665 | if (curdir == nullstr) |
2463 | return 0; | 2666 | return 0; |
2464 | new = stputs(curdir, new); | 2667 | new = stack_putstr(curdir, new); |
2465 | } | 2668 | } |
2466 | new = makestrspace(strlen(dir) + 2, new); | 2669 | new = makestrspace(strlen(dir) + 2, new); |
2467 | lim = stackblock() + 1; | 2670 | lim = stackblock() + 1; |
@@ -2494,7 +2697,7 @@ static const char * updatepwd(const char *dir) | |||
2494 | break; | 2697 | break; |
2495 | /* fall through */ | 2698 | /* fall through */ |
2496 | default: | 2699 | default: |
2497 | new = stputs(p, new); | 2700 | new = stack_putstr(p, new); |
2498 | USTPUTC('/', new); | 2701 | USTPUTC('/', new); |
2499 | } | 2702 | } |
2500 | p = strtok(0, "/"); | 2703 | p = strtok(0, "/"); |
@@ -2582,7 +2785,7 @@ setpwd(const char *val, int setold) | |||
2582 | if (!val) | 2785 | if (!val) |
2583 | dir = s; | 2786 | dir = s; |
2584 | } else | 2787 | } else |
2585 | dir = savestr(val); | 2788 | dir = ckstrdup(val); |
2586 | if (oldcur != dir && oldcur != nullstr) { | 2789 | if (oldcur != dir && oldcur != nullstr) { |
2587 | free(oldcur); | 2790 | free(oldcur); |
2588 | } | 2791 | } |
@@ -2621,70 +2824,6 @@ static const struct builtincmd bltin = { | |||
2621 | }; | 2824 | }; |
2622 | 2825 | ||
2623 | 2826 | ||
2624 | /* | ||
2625 | * Called to reset things after an exception. | ||
2626 | */ | ||
2627 | |||
2628 | /* | ||
2629 | * The eval command. | ||
2630 | */ | ||
2631 | static int | ||
2632 | evalcmd(int argc, char **argv) | ||
2633 | { | ||
2634 | char *p; | ||
2635 | char *concat; | ||
2636 | char **ap; | ||
2637 | |||
2638 | if (argc > 1) { | ||
2639 | p = argv[1]; | ||
2640 | if (argc > 2) { | ||
2641 | STARTSTACKSTR(concat); | ||
2642 | ap = argv + 2; | ||
2643 | for (;;) { | ||
2644 | concat = stputs(p, concat); | ||
2645 | p = *ap++; | ||
2646 | if (p == NULL) | ||
2647 | break; | ||
2648 | STPUTC(' ', concat); | ||
2649 | } | ||
2650 | STPUTC('\0', concat); | ||
2651 | p = grabstackstr(concat); | ||
2652 | } | ||
2653 | evalstring(p, ~SKIPEVAL); | ||
2654 | |||
2655 | } | ||
2656 | return exitstatus; | ||
2657 | } | ||
2658 | |||
2659 | |||
2660 | /* | ||
2661 | * Execute a command or commands contained in a string. | ||
2662 | */ | ||
2663 | static int | ||
2664 | evalstring(char *s, int mask) | ||
2665 | { | ||
2666 | union node *n; | ||
2667 | struct stackmark smark; | ||
2668 | int skip; | ||
2669 | |||
2670 | setinputstring(s); | ||
2671 | setstackmark(&smark); | ||
2672 | |||
2673 | skip = 0; | ||
2674 | while ((n = parsecmd(0)) != NEOF) { | ||
2675 | evaltree(n, 0); | ||
2676 | popstackmark(&smark); | ||
2677 | skip = evalskip; | ||
2678 | if (skip) | ||
2679 | break; | ||
2680 | } | ||
2681 | popfile(); | ||
2682 | |||
2683 | skip &= mask; | ||
2684 | evalskip = skip; | ||
2685 | return skip; | ||
2686 | } | ||
2687 | |||
2688 | 2827 | ||
2689 | /* | 2828 | /* |
2690 | * Evaluate a parse tree. The value is left in the global variable | 2829 | * Evaluate a parse tree. The value is left in the global variable |
@@ -3993,15 +4132,6 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
3993 | 4132 | ||
3994 | 4133 | ||
3995 | /* | 4134 | /* |
3996 | * Wrapper around strcmp for qsort/bsearch/... | ||
3997 | */ | ||
3998 | static int pstrcmp(const void *a, const void *b) | ||
3999 | { | ||
4000 | return strcmp((const char *) a, (*(const char *const *) b) + 1); | ||
4001 | } | ||
4002 | |||
4003 | |||
4004 | /* | ||
4005 | * Search the table of builtin commands. | 4135 | * Search the table of builtin commands. |
4006 | */ | 4136 | */ |
4007 | static struct builtincmd * | 4137 | static struct builtincmd * |
@@ -4606,7 +4736,7 @@ argstr(char *p, int flag) | |||
4606 | } | 4736 | } |
4607 | if (length > 0) { | 4737 | if (length > 0) { |
4608 | int newloc; | 4738 | int newloc; |
4609 | expdest = stnputs(p, length, expdest); | 4739 | expdest = stack_nputstr(p, length, expdest); |
4610 | newloc = expdest - (char *)stackblock(); | 4740 | newloc = expdest - (char *)stackblock(); |
4611 | if (breakall && !inquotes && newloc > startloc) { | 4741 | if (breakall && !inquotes && newloc > startloc) { |
4612 | recordregion(startloc, newloc, 0); | 4742 | recordregion(startloc, newloc, 0); |
@@ -7370,7 +7500,7 @@ commandtext(union node *n) | |||
7370 | name = stackblock(); | 7500 | name = stackblock(); |
7371 | TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n", | 7501 | TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n", |
7372 | name, cmdnextc, cmdnextc)); | 7502 | name, cmdnextc, cmdnextc)); |
7373 | return savestr(name); | 7503 | return ckstrdup(name); |
7374 | } | 7504 | } |
7375 | 7505 | ||
7376 | static void | 7506 | static void |
@@ -7753,79 +7883,11 @@ changemail(const char *val) | |||
7753 | #endif /* ASH_MAIL */ | 7883 | #endif /* ASH_MAIL */ |
7754 | 7884 | ||
7755 | /* | 7885 | /* |
7756 | * Read and execute commands. "Top" is nonzero for the top level command | ||
7757 | * loop; it turns on prompting if the shell is interactive. | ||
7758 | */ | ||
7759 | static int | ||
7760 | cmdloop(int top) | ||
7761 | { | ||
7762 | union node *n; | ||
7763 | struct stackmark smark; | ||
7764 | int inter; | ||
7765 | int numeof = 0; | ||
7766 | |||
7767 | TRACE(("cmdloop(%d) called\n", top)); | ||
7768 | for (;;) { | ||
7769 | int skip; | ||
7770 | |||
7771 | setstackmark(&smark); | ||
7772 | #if JOBS | ||
7773 | if (jobctl) | ||
7774 | showjobs(stderr, SHOW_CHANGED); | ||
7775 | #endif | ||
7776 | inter = 0; | ||
7777 | if (iflag && top) { | ||
7778 | inter++; | ||
7779 | #if ENABLE_ASH_MAIL | ||
7780 | chkmail(); | ||
7781 | #endif | ||
7782 | } | ||
7783 | n = parsecmd(inter); | ||
7784 | /* showtree(n); DEBUG */ | ||
7785 | if (n == NEOF) { | ||
7786 | if (!top || numeof >= 50) | ||
7787 | break; | ||
7788 | if (!stoppedjobs()) { | ||
7789 | if (!Iflag) | ||
7790 | break; | ||
7791 | out2str("\nUse \"exit\" to leave shell.\n"); | ||
7792 | } | ||
7793 | numeof++; | ||
7794 | } else if (nflag == 0) { | ||
7795 | job_warning = (job_warning == 2) ? 1 : 0; | ||
7796 | numeof = 0; | ||
7797 | evaltree(n, 0); | ||
7798 | } | ||
7799 | popstackmark(&smark); | ||
7800 | skip = evalskip; | ||
7801 | |||
7802 | if (skip) { | ||
7803 | evalskip = 0; | ||
7804 | return skip & SKIPEVAL; | ||
7805 | } | ||
7806 | } | ||
7807 | |||
7808 | return 0; | ||
7809 | } | ||
7810 | |||
7811 | |||
7812 | /* | ||
7813 | * Read a file containing shell functions. | ||
7814 | */ | ||
7815 | static void | ||
7816 | readcmdfile(char *name) | ||
7817 | { | ||
7818 | setinputfile(name, INPUT_PUSH_FILE); | ||
7819 | cmdloop(0); | ||
7820 | popfile(); | ||
7821 | } | ||
7822 | |||
7823 | |||
7824 | /* | ||
7825 | * Take commands from a file. To be compatible we should do a path | 7886 | * Take commands from a file. To be compatible we should do a path |
7826 | * search for the file, which is necessary to find sub-commands. | 7887 | * search for the file, which is necessary to find sub-commands. |
7827 | */ | 7888 | */ |
7828 | static char * find_dot_file(char *name) | 7889 | static char * |
7890 | find_dot_file(char *name) | ||
7829 | { | 7891 | { |
7830 | char *fullname; | 7892 | char *fullname; |
7831 | const char *path = pathval(); | 7893 | const char *path = pathval(); |
@@ -7851,322 +7913,6 @@ static char * find_dot_file(char *name) | |||
7851 | /* NOTREACHED */ | 7913 | /* NOTREACHED */ |
7852 | } | 7914 | } |
7853 | 7915 | ||
7854 | static int dotcmd(int argc, char **argv) | ||
7855 | { | ||
7856 | struct strlist *sp; | ||
7857 | volatile struct shparam saveparam; | ||
7858 | int status = 0; | ||
7859 | |||
7860 | for (sp = cmdenviron; sp; sp = sp->next) | ||
7861 | setvareq(xstrdup(sp->text), VSTRFIXED | VTEXTFIXED); | ||
7862 | |||
7863 | if (argc >= 2) { /* That's what SVR2 does */ | ||
7864 | char *fullname; | ||
7865 | |||
7866 | fullname = find_dot_file(argv[1]); | ||
7867 | |||
7868 | if (argc > 2) { | ||
7869 | saveparam = shellparam; | ||
7870 | shellparam.malloc = 0; | ||
7871 | shellparam.nparam = argc - 2; | ||
7872 | shellparam.p = argv + 2; | ||
7873 | }; | ||
7874 | |||
7875 | setinputfile(fullname, INPUT_PUSH_FILE); | ||
7876 | commandname = fullname; | ||
7877 | cmdloop(0); | ||
7878 | popfile(); | ||
7879 | |||
7880 | if (argc > 2) { | ||
7881 | freeparam(&shellparam); | ||
7882 | shellparam = saveparam; | ||
7883 | }; | ||
7884 | status = exitstatus; | ||
7885 | } | ||
7886 | return status; | ||
7887 | } | ||
7888 | |||
7889 | |||
7890 | static int | ||
7891 | exitcmd(int argc, char **argv) | ||
7892 | { | ||
7893 | if (stoppedjobs()) | ||
7894 | return 0; | ||
7895 | if (argc > 1) | ||
7896 | exitstatus = number(argv[1]); | ||
7897 | raise_exception(EXEXIT); | ||
7898 | /* NOTREACHED */ | ||
7899 | } | ||
7900 | |||
7901 | #if ENABLE_ASH_BUILTIN_ECHO | ||
7902 | static int | ||
7903 | echocmd(int argc, char **argv) | ||
7904 | { | ||
7905 | return bb_echo(argv); | ||
7906 | } | ||
7907 | #endif | ||
7908 | |||
7909 | #if ENABLE_ASH_BUILTIN_TEST | ||
7910 | static int | ||
7911 | testcmd(int argc, char **argv) | ||
7912 | { | ||
7913 | return bb_test(argc, argv); | ||
7914 | } | ||
7915 | #endif | ||
7916 | |||
7917 | /* memalloc.c */ | ||
7918 | |||
7919 | /* | ||
7920 | * Same for malloc, realloc, but returns an error when out of space. | ||
7921 | */ | ||
7922 | static void * | ||
7923 | ckrealloc(void * p, size_t nbytes) | ||
7924 | { | ||
7925 | p = realloc(p, nbytes); | ||
7926 | if (p == NULL) | ||
7927 | ash_msg_and_raise_error(bb_msg_memory_exhausted); | ||
7928 | return p; | ||
7929 | } | ||
7930 | |||
7931 | static void * | ||
7932 | ckmalloc(size_t nbytes) | ||
7933 | { | ||
7934 | return ckrealloc(NULL, nbytes); | ||
7935 | } | ||
7936 | |||
7937 | /* | ||
7938 | * Make a copy of a string in safe storage. | ||
7939 | */ | ||
7940 | static char * | ||
7941 | savestr(const char *s) | ||
7942 | { | ||
7943 | char *p = strdup(s); | ||
7944 | if (!p) | ||
7945 | ash_msg_and_raise_error(bb_msg_memory_exhausted); | ||
7946 | return p; | ||
7947 | } | ||
7948 | |||
7949 | |||
7950 | /* | ||
7951 | * Parse trees for commands are allocated in lifo order, so we use a stack | ||
7952 | * to make this more efficient, and also to avoid all sorts of exception | ||
7953 | * handling code to handle interrupts in the middle of a parse. | ||
7954 | * | ||
7955 | * The size 504 was chosen because the Ultrix malloc handles that size | ||
7956 | * well. | ||
7957 | */ | ||
7958 | static void * | ||
7959 | stalloc(size_t nbytes) | ||
7960 | { | ||
7961 | char *p; | ||
7962 | size_t aligned; | ||
7963 | |||
7964 | aligned = SHELL_ALIGN(nbytes); | ||
7965 | if (aligned > stacknleft) { | ||
7966 | size_t len; | ||
7967 | size_t blocksize; | ||
7968 | struct stack_block *sp; | ||
7969 | |||
7970 | blocksize = aligned; | ||
7971 | if (blocksize < MINSIZE) | ||
7972 | blocksize = MINSIZE; | ||
7973 | len = sizeof(struct stack_block) - MINSIZE + blocksize; | ||
7974 | if (len < blocksize) | ||
7975 | ash_msg_and_raise_error(bb_msg_memory_exhausted); | ||
7976 | INT_OFF; | ||
7977 | sp = ckmalloc(len); | ||
7978 | sp->prev = stackp; | ||
7979 | stacknxt = sp->space; | ||
7980 | stacknleft = blocksize; | ||
7981 | sstrend = stacknxt + blocksize; | ||
7982 | stackp = sp; | ||
7983 | INT_ON; | ||
7984 | } | ||
7985 | p = stacknxt; | ||
7986 | stacknxt += aligned; | ||
7987 | stacknleft -= aligned; | ||
7988 | return p; | ||
7989 | } | ||
7990 | |||
7991 | |||
7992 | static void | ||
7993 | stunalloc(void *p) | ||
7994 | { | ||
7995 | #if DEBUG | ||
7996 | if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) { | ||
7997 | write(2, "stunalloc\n", 10); | ||
7998 | abort(); | ||
7999 | } | ||
8000 | #endif | ||
8001 | stacknleft += stacknxt - (char *)p; | ||
8002 | stacknxt = p; | ||
8003 | } | ||
8004 | |||
8005 | |||
8006 | static void | ||
8007 | setstackmark(struct stackmark *mark) | ||
8008 | { | ||
8009 | mark->stackp = stackp; | ||
8010 | mark->stacknxt = stacknxt; | ||
8011 | mark->stacknleft = stacknleft; | ||
8012 | mark->marknext = markp; | ||
8013 | markp = mark; | ||
8014 | } | ||
8015 | |||
8016 | |||
8017 | static void | ||
8018 | popstackmark(struct stackmark *mark) | ||
8019 | { | ||
8020 | struct stack_block *sp; | ||
8021 | |||
8022 | INT_OFF; | ||
8023 | markp = mark->marknext; | ||
8024 | while (stackp != mark->stackp) { | ||
8025 | sp = stackp; | ||
8026 | stackp = sp->prev; | ||
8027 | free(sp); | ||
8028 | } | ||
8029 | stacknxt = mark->stacknxt; | ||
8030 | stacknleft = mark->stacknleft; | ||
8031 | sstrend = mark->stacknxt + mark->stacknleft; | ||
8032 | INT_ON; | ||
8033 | } | ||
8034 | |||
8035 | |||
8036 | /* | ||
8037 | * When the parser reads in a string, it wants to stick the string on the | ||
8038 | * stack and only adjust the stack pointer when it knows how big the | ||
8039 | * string is. Stackblock (defined in stack.h) returns a pointer to a block | ||
8040 | * of space on top of the stack and stackblocklen returns the length of | ||
8041 | * this block. Growstackblock will grow this space by at least one byte, | ||
8042 | * possibly moving it (like realloc). Grabstackblock actually allocates the | ||
8043 | * part of the block that has been used. | ||
8044 | */ | ||
8045 | static void | ||
8046 | growstackblock(void) | ||
8047 | { | ||
8048 | size_t newlen; | ||
8049 | |||
8050 | newlen = stacknleft * 2; | ||
8051 | if (newlen < stacknleft) | ||
8052 | ash_msg_and_raise_error(bb_msg_memory_exhausted); | ||
8053 | if (newlen < 128) | ||
8054 | newlen += 128; | ||
8055 | |||
8056 | if (stacknxt == stackp->space && stackp != &stackbase) { | ||
8057 | struct stack_block *oldstackp; | ||
8058 | struct stackmark *xmark; | ||
8059 | struct stack_block *sp; | ||
8060 | struct stack_block *prevstackp; | ||
8061 | size_t grosslen; | ||
8062 | |||
8063 | INT_OFF; | ||
8064 | oldstackp = stackp; | ||
8065 | sp = stackp; | ||
8066 | prevstackp = sp->prev; | ||
8067 | grosslen = newlen + sizeof(struct stack_block) - MINSIZE; | ||
8068 | sp = ckrealloc(sp, grosslen); | ||
8069 | sp->prev = prevstackp; | ||
8070 | stackp = sp; | ||
8071 | stacknxt = sp->space; | ||
8072 | stacknleft = newlen; | ||
8073 | sstrend = sp->space + newlen; | ||
8074 | |||
8075 | /* | ||
8076 | * Stack marks pointing to the start of the old block | ||
8077 | * must be relocated to point to the new block | ||
8078 | */ | ||
8079 | xmark = markp; | ||
8080 | while (xmark != NULL && xmark->stackp == oldstackp) { | ||
8081 | xmark->stackp = stackp; | ||
8082 | xmark->stacknxt = stacknxt; | ||
8083 | xmark->stacknleft = stacknleft; | ||
8084 | xmark = xmark->marknext; | ||
8085 | } | ||
8086 | INT_ON; | ||
8087 | } else { | ||
8088 | char *oldspace = stacknxt; | ||
8089 | int oldlen = stacknleft; | ||
8090 | char *p = stalloc(newlen); | ||
8091 | |||
8092 | /* free the space we just allocated */ | ||
8093 | stacknxt = memcpy(p, oldspace, oldlen); | ||
8094 | stacknleft += newlen; | ||
8095 | } | ||
8096 | } | ||
8097 | |||
8098 | static void grabstackblock(size_t len) | ||
8099 | { | ||
8100 | len = SHELL_ALIGN(len); | ||
8101 | stacknxt += len; | ||
8102 | stacknleft -= len; | ||
8103 | } | ||
8104 | |||
8105 | |||
8106 | /* | ||
8107 | * The following routines are somewhat easier to use than the above. | ||
8108 | * The user declares a variable of type STACKSTR, which may be declared | ||
8109 | * to be a register. The macro STARTSTACKSTR initializes things. Then | ||
8110 | * the user uses the macro STPUTC to add characters to the string. In | ||
8111 | * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is | ||
8112 | * grown as necessary. When the user is done, she can just leave the | ||
8113 | * string there and refer to it using stackblock(). Or she can allocate | ||
8114 | * the space for it using grabstackstr(). If it is necessary to allow | ||
8115 | * someone else to use the stack temporarily and then continue to grow | ||
8116 | * the string, the user should use grabstack to allocate the space, and | ||
8117 | * then call ungrabstr(p) to return to the previous mode of operation. | ||
8118 | * | ||
8119 | * USTPUTC is like STPUTC except that it doesn't check for overflow. | ||
8120 | * CHECKSTACKSPACE can be called before USTPUTC to ensure that there | ||
8121 | * is space for at least one character. | ||
8122 | */ | ||
8123 | static void * | ||
8124 | growstackstr(void) | ||
8125 | { | ||
8126 | size_t len = stackblocksize(); | ||
8127 | if (herefd >= 0 && len >= 1024) { | ||
8128 | full_write(herefd, stackblock(), len); | ||
8129 | return stackblock(); | ||
8130 | } | ||
8131 | growstackblock(); | ||
8132 | return stackblock() + len; | ||
8133 | } | ||
8134 | |||
8135 | /* | ||
8136 | * Called from CHECKSTRSPACE. | ||
8137 | */ | ||
8138 | static char * | ||
8139 | makestrspace(size_t newlen, char *p) | ||
8140 | { | ||
8141 | size_t len = p - stacknxt; | ||
8142 | size_t size = stackblocksize(); | ||
8143 | |||
8144 | for (;;) { | ||
8145 | size_t nleft; | ||
8146 | |||
8147 | size = stackblocksize(); | ||
8148 | nleft = size - len; | ||
8149 | if (nleft >= newlen) | ||
8150 | break; | ||
8151 | growstackblock(); | ||
8152 | } | ||
8153 | return stackblock() + len; | ||
8154 | } | ||
8155 | |||
8156 | static char * | ||
8157 | stnputs(const char *s, size_t n, char *p) | ||
8158 | { | ||
8159 | p = makestrspace(n, p); | ||
8160 | p = memcpy(p, s, n) + n; | ||
8161 | return p; | ||
8162 | } | ||
8163 | |||
8164 | static char * | ||
8165 | stputs(const char *s, char *p) | ||
8166 | { | ||
8167 | return stnputs(s, strlen(s), p); | ||
8168 | } | ||
8169 | |||
8170 | /* mystring.c */ | 7916 | /* mystring.c */ |
8171 | 7917 | ||
8172 | /* | 7918 | /* |
@@ -8404,7 +8150,7 @@ copynode(union node *n) | |||
8404 | new->nif.test = copynode(n->nif.test); | 8150 | new->nif.test = copynode(n->nif.test); |
8405 | break; | 8151 | break; |
8406 | case NFOR: | 8152 | case NFOR: |
8407 | new->nfor.var = nodesavestr(n->nfor.var); | 8153 | new->nfor.var = nodeckstrdup(n->nfor.var); |
8408 | new->nfor.body = copynode(n->nfor.body); | 8154 | new->nfor.body = copynode(n->nfor.body); |
8409 | new->nfor.args = copynode(n->nfor.args); | 8155 | new->nfor.args = copynode(n->nfor.args); |
8410 | break; | 8156 | break; |
@@ -8420,7 +8166,7 @@ copynode(union node *n) | |||
8420 | case NDEFUN: | 8166 | case NDEFUN: |
8421 | case NARG: | 8167 | case NARG: |
8422 | new->narg.backquote = copynodelist(n->narg.backquote); | 8168 | new->narg.backquote = copynodelist(n->narg.backquote); |
8423 | new->narg.text = nodesavestr(n->narg.text); | 8169 | new->narg.text = nodeckstrdup(n->narg.text); |
8424 | new->narg.next = copynode(n->narg.next); | 8170 | new->narg.next = copynode(n->narg.next); |
8425 | break; | 8171 | break; |
8426 | case NTO: | 8172 | case NTO: |
@@ -8474,7 +8220,7 @@ copynodelist(struct nodelist *lp) | |||
8474 | 8220 | ||
8475 | 8221 | ||
8476 | static char * | 8222 | static char * |
8477 | nodesavestr(char *s) | 8223 | nodeckstrdup(char *s) |
8478 | { | 8224 | { |
8479 | char *rtn = funcstring; | 8225 | char *rtn = funcstring; |
8480 | 8226 | ||
@@ -8612,7 +8358,7 @@ setparam(char **argv) | |||
8612 | for (nparam = 0; argv[nparam]; nparam++); | 8358 | for (nparam = 0; argv[nparam]; nparam++); |
8613 | ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap)); | 8359 | ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap)); |
8614 | while (*argv) { | 8360 | while (*argv) { |
8615 | *ap++ = savestr(*argv++); | 8361 | *ap++ = ckstrdup(*argv++); |
8616 | } | 8362 | } |
8617 | *ap = NULL; | 8363 | *ap = NULL; |
8618 | freeparam(&shellparam); | 8364 | freeparam(&shellparam); |
@@ -9411,7 +9157,8 @@ makename(void) | |||
9411 | return n; | 9157 | return n; |
9412 | } | 9158 | } |
9413 | 9159 | ||
9414 | static void fixredir(union node *n, const char *text, int err) | 9160 | static void |
9161 | fixredir(union node *n, const char *text, int err) | ||
9415 | { | 9162 | { |
9416 | TRACE(("Fix redir %s %d\n", text, err)); | 9163 | TRACE(("Fix redir %s %d\n", text, err)); |
9417 | if (!err) | 9164 | if (!err) |
@@ -9491,7 +9238,8 @@ parseheredoc(void) | |||
9491 | } | 9238 | } |
9492 | } | 9239 | } |
9493 | 9240 | ||
9494 | static char peektoken(void) | 9241 | static char |
9242 | peektoken(void) | ||
9495 | { | 9243 | { |
9496 | int t; | 9244 | int t; |
9497 | 9245 | ||
@@ -10453,13 +10201,195 @@ static void setprompt(int whichprompt) | |||
10453 | } | 10201 | } |
10454 | 10202 | ||
10455 | 10203 | ||
10456 | static const char *const *findkwd(const char *s) | 10204 | /* |
10205 | * Execute a command or commands contained in a string. | ||
10206 | */ | ||
10207 | static int | ||
10208 | evalstring(char *s, int mask) | ||
10457 | { | 10209 | { |
10458 | return bsearch(s, tokname_array + KWDOFFSET, | 10210 | union node *n; |
10459 | (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET, | 10211 | struct stackmark smark; |
10460 | sizeof(const char *), pstrcmp); | 10212 | int skip; |
10213 | |||
10214 | setinputstring(s); | ||
10215 | setstackmark(&smark); | ||
10216 | |||
10217 | skip = 0; | ||
10218 | while ((n = parsecmd(0)) != NEOF) { | ||
10219 | evaltree(n, 0); | ||
10220 | popstackmark(&smark); | ||
10221 | skip = evalskip; | ||
10222 | if (skip) | ||
10223 | break; | ||
10224 | } | ||
10225 | popfile(); | ||
10226 | |||
10227 | skip &= mask; | ||
10228 | evalskip = skip; | ||
10229 | return skip; | ||
10461 | } | 10230 | } |
10462 | 10231 | ||
10232 | /* | ||
10233 | * The eval command. | ||
10234 | */ | ||
10235 | static int | ||
10236 | evalcmd(int argc, char **argv) | ||
10237 | { | ||
10238 | char *p; | ||
10239 | char *concat; | ||
10240 | char **ap; | ||
10241 | |||
10242 | if (argc > 1) { | ||
10243 | p = argv[1]; | ||
10244 | if (argc > 2) { | ||
10245 | STARTSTACKSTR(concat); | ||
10246 | ap = argv + 2; | ||
10247 | for (;;) { | ||
10248 | concat = stack_putstr(p, concat); | ||
10249 | p = *ap++; | ||
10250 | if (p == NULL) | ||
10251 | break; | ||
10252 | STPUTC(' ', concat); | ||
10253 | } | ||
10254 | STPUTC('\0', concat); | ||
10255 | p = grabstackstr(concat); | ||
10256 | } | ||
10257 | evalstring(p, ~SKIPEVAL); | ||
10258 | |||
10259 | } | ||
10260 | return exitstatus; | ||
10261 | } | ||
10262 | |||
10263 | /* | ||
10264 | * Read and execute commands. "Top" is nonzero for the top level command | ||
10265 | * loop; it turns on prompting if the shell is interactive. | ||
10266 | */ | ||
10267 | static int | ||
10268 | cmdloop(int top) | ||
10269 | { | ||
10270 | union node *n; | ||
10271 | struct stackmark smark; | ||
10272 | int inter; | ||
10273 | int numeof = 0; | ||
10274 | |||
10275 | TRACE(("cmdloop(%d) called\n", top)); | ||
10276 | for (;;) { | ||
10277 | int skip; | ||
10278 | |||
10279 | setstackmark(&smark); | ||
10280 | #if JOBS | ||
10281 | if (jobctl) | ||
10282 | showjobs(stderr, SHOW_CHANGED); | ||
10283 | #endif | ||
10284 | inter = 0; | ||
10285 | if (iflag && top) { | ||
10286 | inter++; | ||
10287 | #if ENABLE_ASH_MAIL | ||
10288 | chkmail(); | ||
10289 | #endif | ||
10290 | } | ||
10291 | n = parsecmd(inter); | ||
10292 | /* showtree(n); DEBUG */ | ||
10293 | if (n == NEOF) { | ||
10294 | if (!top || numeof >= 50) | ||
10295 | break; | ||
10296 | if (!stoppedjobs()) { | ||
10297 | if (!Iflag) | ||
10298 | break; | ||
10299 | out2str("\nUse \"exit\" to leave shell.\n"); | ||
10300 | } | ||
10301 | numeof++; | ||
10302 | } else if (nflag == 0) { | ||
10303 | job_warning = (job_warning == 2) ? 1 : 0; | ||
10304 | numeof = 0; | ||
10305 | evaltree(n, 0); | ||
10306 | } | ||
10307 | popstackmark(&smark); | ||
10308 | skip = evalskip; | ||
10309 | |||
10310 | if (skip) { | ||
10311 | evalskip = 0; | ||
10312 | return skip & SKIPEVAL; | ||
10313 | } | ||
10314 | } | ||
10315 | return 0; | ||
10316 | } | ||
10317 | |||
10318 | static int | ||
10319 | dotcmd(int argc, char **argv) | ||
10320 | { | ||
10321 | struct strlist *sp; | ||
10322 | volatile struct shparam saveparam; | ||
10323 | int status = 0; | ||
10324 | |||
10325 | for (sp = cmdenviron; sp; sp = sp->next) | ||
10326 | setvareq(xstrdup(sp->text), VSTRFIXED | VTEXTFIXED); | ||
10327 | |||
10328 | if (argc >= 2) { /* That's what SVR2 does */ | ||
10329 | char *fullname; | ||
10330 | |||
10331 | fullname = find_dot_file(argv[1]); | ||
10332 | |||
10333 | if (argc > 2) { | ||
10334 | saveparam = shellparam; | ||
10335 | shellparam.malloc = 0; | ||
10336 | shellparam.nparam = argc - 2; | ||
10337 | shellparam.p = argv + 2; | ||
10338 | }; | ||
10339 | |||
10340 | setinputfile(fullname, INPUT_PUSH_FILE); | ||
10341 | commandname = fullname; | ||
10342 | cmdloop(0); | ||
10343 | popfile(); | ||
10344 | |||
10345 | if (argc > 2) { | ||
10346 | freeparam(&shellparam); | ||
10347 | shellparam = saveparam; | ||
10348 | }; | ||
10349 | status = exitstatus; | ||
10350 | } | ||
10351 | return status; | ||
10352 | } | ||
10353 | |||
10354 | static int | ||
10355 | exitcmd(int argc, char **argv) | ||
10356 | { | ||
10357 | if (stoppedjobs()) | ||
10358 | return 0; | ||
10359 | if (argc > 1) | ||
10360 | exitstatus = number(argv[1]); | ||
10361 | raise_exception(EXEXIT); | ||
10362 | /* NOTREACHED */ | ||
10363 | } | ||
10364 | |||
10365 | #if ENABLE_ASH_BUILTIN_ECHO | ||
10366 | static int | ||
10367 | echocmd(int argc, char **argv) | ||
10368 | { | ||
10369 | return bb_echo(argv); | ||
10370 | } | ||
10371 | #endif | ||
10372 | |||
10373 | #if ENABLE_ASH_BUILTIN_TEST | ||
10374 | static int | ||
10375 | testcmd(int argc, char **argv) | ||
10376 | { | ||
10377 | return bb_test(argc, argv); | ||
10378 | } | ||
10379 | #endif | ||
10380 | |||
10381 | /* | ||
10382 | * Read a file containing shell functions. | ||
10383 | */ | ||
10384 | static void | ||
10385 | readcmdfile(char *name) | ||
10386 | { | ||
10387 | setinputfile(name, INPUT_PUSH_FILE); | ||
10388 | cmdloop(0); | ||
10389 | popfile(); | ||
10390 | } | ||
10391 | |||
10392 | |||
10463 | /* redir.c */ | 10393 | /* redir.c */ |
10464 | 10394 | ||
10465 | /* | 10395 | /* |
@@ -10477,7 +10407,8 @@ static const char *const *findkwd(const char *s) | |||
10477 | * Open a file in noclobber mode. | 10407 | * Open a file in noclobber mode. |
10478 | * The code was copied from bash. | 10408 | * The code was copied from bash. |
10479 | */ | 10409 | */ |
10480 | static int noclobberopen(const char *fname) | 10410 | static int |
10411 | noclobberopen(const char *fname) | ||
10481 | { | 10412 | { |
10482 | int r, fd; | 10413 | int r, fd; |
10483 | struct stat finfo, finfo2; | 10414 | struct stat finfo, finfo2; |
@@ -10536,7 +10467,8 @@ static int noclobberopen(const char *fname) | |||
10536 | * data to a pipe. If the document is short, we can stuff the data in | 10467 | * data to a pipe. If the document is short, we can stuff the data in |
10537 | * the pipe without forking. | 10468 | * the pipe without forking. |
10538 | */ | 10469 | */ |
10539 | static int openhere(union node *redir) | 10470 | static int |
10471 | openhere(union node *redir) | ||
10540 | { | 10472 | { |
10541 | int pip[2]; | 10473 | int pip[2]; |
10542 | size_t len = 0; | 10474 | size_t len = 0; |
@@ -10633,7 +10565,8 @@ openredirect(union node *redir) | |||
10633 | ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "No such file")); | 10565 | ash_msg_and_raise_error("cannot open %s: %s", fname, errmsg(errno, "No such file")); |
10634 | } | 10566 | } |
10635 | 10567 | ||
10636 | static void dupredirect(union node *redir, int f) | 10568 | static void |
10569 | dupredirect(union node *redir, int f) | ||
10637 | { | 10570 | { |
10638 | int fd = redir->nfile.fd; | 10571 | int fd = redir->nfile.fd; |
10639 | 10572 | ||
@@ -11208,7 +11141,7 @@ trapcmd(int argc, char **argv) | |||
11208 | if (LONE_DASH(action)) | 11141 | if (LONE_DASH(action)) |
11209 | action = NULL; | 11142 | action = NULL; |
11210 | else | 11143 | else |
11211 | action = savestr(action); | 11144 | action = ckstrdup(action); |
11212 | } | 11145 | } |
11213 | if (trap[signo]) | 11146 | if (trap[signo]) |
11214 | free(trap[signo]); | 11147 | free(trap[signo]); |
@@ -11614,7 +11547,7 @@ setvareq(char *s, int flags) | |||
11614 | *vpp = vp; | 11547 | *vpp = vp; |
11615 | } | 11548 | } |
11616 | if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE))) | 11549 | if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE))) |
11617 | s = savestr(s); | 11550 | s = ckstrdup(s); |
11618 | vp->text = s; | 11551 | vp->text = s; |
11619 | vp->flags = flags; | 11552 | vp->flags = flags; |
11620 | } | 11553 | } |
@@ -13311,6 +13244,26 @@ read_profile(const char *name) | |||
13311 | exitshell(); | 13244 | exitshell(); |
13312 | } | 13245 | } |
13313 | 13246 | ||
13247 | /* | ||
13248 | * This routine is called when an error or an interrupt occurs in an | ||
13249 | * interactive shell and control is returned to the main command loop. | ||
13250 | */ | ||
13251 | static void | ||
13252 | reset(void) | ||
13253 | { | ||
13254 | /* from eval.c: */ | ||
13255 | evalskip = 0; | ||
13256 | loopnest = 0; | ||
13257 | /* from input.c: */ | ||
13258 | parselleft = parsenleft = 0; /* clear input buffer */ | ||
13259 | popallfiles(); | ||
13260 | /* from parser.c: */ | ||
13261 | tokpushback = 0; | ||
13262 | checkkwd = 0; | ||
13263 | /* from redir.c: */ | ||
13264 | clearredir(0); | ||
13265 | } | ||
13266 | |||
13314 | #if PROFILE | 13267 | #if PROFILE |
13315 | static short profile_buf[16384]; | 13268 | static short profile_buf[16384]; |
13316 | extern int etext(); | 13269 | extern int etext(); |
@@ -13404,9 +13357,9 @@ int ash_main(int argc, char **argv) | |||
13404 | state = 3; | 13357 | state = 3; |
13405 | if ( | 13358 | if ( |
13406 | #ifndef linux | 13359 | #ifndef linux |
13407 | getuid() == geteuid() && getgid() == getegid() && | 13360 | getuid() == geteuid() && getgid() == getegid() && |
13408 | #endif | 13361 | #endif |
13409 | iflag | 13362 | iflag |
13410 | ) { | 13363 | ) { |
13411 | shinit = lookupvar("ENV"); | 13364 | shinit = lookupvar("ENV"); |
13412 | if (shinit != NULL && *shinit != '\0') { | 13365 | if (shinit != NULL && *shinit != '\0') { |