aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-02-01 01:43:16 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-02-01 01:43:16 +0000
commit489f93ebae0b02edbb7c654c7950f2bfba6bb18b (patch)
tree17eb2c58b3c2fb113bf22992bfce6f1ac6196988
parent00ccf95bc8c6433a176ab09c4812063e33df2240 (diff)
downloadbusybox-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.c1323
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
20extern 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 */
183static int newfile(char *s); 185static int newfile(char *s);
184static char *findeq(char *cp);
185static char *cclass(char *p, int sub); 186static char *cclass(char *p, int sub);
186static void initarea(void);
187extern int msh_main(int argc, char **argv);
188 187
189 188
190struct brkcon { 189struct brkcon {
@@ -254,6 +253,13 @@ static int yynerrs; /* yacc */
254static char line[LINELIM]; 253static char line[LINELIM];
255static char *elinep; 254static char *elinep;
256 255
256#if ENABLE_FEATURE_EDITING
257static char *current_prompt;
258static line_input_t *line_input_state;
259#endif
260
261static 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 *);
262static builtin_func_ptr inbuilt(char *s); 268static builtin_func_ptr inbuilt(char *s);
263 269
264static char *rexecve(char *c, char **v, char **envp); 270static char *rexecve(char *c, char **v, char **envp);
265static char *space(int n);
266static char *strsave(char *s, int a);
267static char *evalstr(char *cp, int f); 271static char *evalstr(char *cp, int f);
268static char *putn(int n); 272static char *putn(int n);
269static char *unquote(char *as); 273static char *unquote(char *as);
270static struct var *lookup(char *n);
271static int rlookup(char *n); 274static int rlookup(char *n);
272static struct wdblock *glob(char *cp, struct wdblock *wb); 275static struct wdblock *glob(char *cp, struct wdblock *wb);
273static int my_getc(int ec); 276static int my_getc(int ec);
@@ -291,16 +294,6 @@ static void runtrap(int i);
291static int gmatch(char *s, char *p); 294static int gmatch(char *s, char *p);
292 295
293 296
294/*
295 * error handling
296 */
297static void leave(void); /* abort shell (or fail in subshell) */
298static void fail(void); /* fail but return to process next command */
299static void warn(const char *s);
300static 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 -------- */
323typedef union { 315typedef 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
357static struct op *pipeline(int cf); 349static struct op *pipeline(int cf);
358static struct op *andor(void); 350static 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
402static int yyparse(void); 394static int yyparse(void);
403static struct var *lookup(char *n);
404static void setval(struct var *vp, char *val);
405static void nameval(struct var *vp, char *val, char *name);
406static void export(struct var *vp);
407static void ronly(struct var *vp);
408static int isassign(char *s);
409static int checkname(char *cp);
410static int assign(char *s, int cf);
411static void putvlist(int f, int out);
412static int eqname(char *n1, char *n2);
413 395
414static int execute(struct op *t, int *pin, int *pout, int act); 396static 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);
519static struct wdblock *newword(int nw); 501static struct wdblock *newword(int nw);
520static char **getwords(struct wdblock *wb); 502static char **getwords(struct wdblock *wb);
521 503
522/* -------- area.h -------- */
523
524/*
525 * storage allocation
526 */
527static char *getcell(unsigned nbytes);
528static void garbage(void);
529static void setarea(char *cp, int a);
530static int getarea(char *cp);
531static void freearea(int a);
532static void freecell(char *cp);
533static 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
541static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp); 506static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp);
@@ -674,9 +639,8 @@ static const struct builtincmd builtincmds[] = {
674static struct op *scantree(struct op *); 639static struct op *scantree(struct op *);
675static struct op *dowholefile(int, int); 640static struct op *dowholefile(int, int);
676 641
677/* Globals */
678extern char **environ; /* environment pointer */
679 642
643/* Globals */
680static char **dolv; 644static char **dolv;
681static int dolc; 645static int dolc;
682static int exstat; 646static 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 */
777static char *current_prompt; 741static void fail(void)
778#endif 742{
743 longjmp(failpt, 1);
744 /* NOTREACHED */
745}
746
747/* abort shell (or fail in subshell) */
748static void leave(void) ATTRIBUTE_NORETURN;
749static 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
762static 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
773static 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 803static void initarea(void)
787static line_input_t *line_input_state; 804{
788#endif 805 brkaddr = xmalloc(AREASIZE);
806 brktop = brkaddr + AREASIZE;
789 807
790int 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
818static 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)); 887static 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"); 901static 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())); 911static 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"); 920static 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 925static 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; 947static 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': 957static 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) { 972static 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 */ 980static 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 */
993static 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 */
1037static 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; 1076static 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)) { 1081static void export(struct var *vp)
963 dolc--; /* keyword */ 1082{
964 } else { 1083 vp->status |= EXPORT;
965 ap++; 1084}
966 } 1085
1086static 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
1092static 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)); 1120static 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
1139static 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
1151static 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 */
1170static void sig(int i)
1171{
1172 trapset = i;
1173 signal(i, sig);
987} 1174}
988 1175
1176static 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
989static void setdash(void) 1191static 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
1122static void fail(void)
1123{
1124 longjmp(failpt, 1);
1125 /* NOTREACHED */
1126}
1127
1128static 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
1141static 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
1152static 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
1165static int newenv(int f) 1323static 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
1254static 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
1264static 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 */
1280static void sig(int i)
1281{
1282 trapset = i;
1283 signal(i, sig);
1284}
1285
1286static 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 */
1308static 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 */
1348static 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 */
1360static 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
1395static void export(struct var *vp)
1396{
1397 vp->status |= EXPORT;
1398}
1399
1400static 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
1406static 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
1419static 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
1438static 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
1450static 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
1465static 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
1473static 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
1570static 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
1585char *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
1653static 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
1666static 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
1676static 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
1685int getarea(char *cp)
1686{
1687 return ((struct region *) cp - 1)->area;
1688}
1689
1690static 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
5087int 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.