aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2001-05-19 03:00:46 +0000
committerEric Andersen <andersen@codepoet.org>2001-05-19 03:00:46 +0000
commit9ffb7dd9a4688161140a4c19221247566886ef55 (patch)
treeae31dd5e3f2c2edf2b4784835de11195d11769b9
parent6197c51834c36a36cfc0b9a5cc146e6d79a9f5c9 (diff)
downloadbusybox-w32-9ffb7dd9a4688161140a4c19221247566886ef55.tar.gz
busybox-w32-9ffb7dd9a4688161140a4c19221247566886ef55.tar.bz2
busybox-w32-9ffb7dd9a4688161140a4c19221247566886ef55.zip
This is a patch from Vladimir:
> I rewrite *local_variable* function in hush.c with: > 1) remove many memory leaks > 2) add support read_only protect (require write builtin function for set this, > I write this special for variable HUSH_VERION=0.01) > 3) commad read set only local variable now > 4) remove many error messages if "set unset export" not defined variable > (bash syntax not put and set error code). Hmm, if I set result to -1, you hush > called waitpid and returned with error "no waitpid" ( i not found place this > error). > 5) destroy error in new version check xgetcwd()==NULL and set "(unknow)" - > this have error: crashe in next call `pwd`, but xgetcwd(not null) called > free(arg). > 6) next add integraion with libbb Valdimir's patch missed two cases of local variable handling FOO=bar export FOO=baz unset FOO and export FOO=bar FOO=baz which were working before, so I fixed those two cases.
-rw-r--r--hush.c382
-rw-r--r--shell/hush.c382
2 files changed, 368 insertions, 396 deletions
diff --git a/hush.c b/hush.c
index 59568189f..a1e65b24e 100644
--- a/hush.c
+++ b/hush.c
@@ -227,6 +227,14 @@ struct close_me {
227 struct close_me *next; 227 struct close_me *next;
228}; 228};
229 229
230struct variables {
231 char *name;
232 char *value;
233 int flg_export;
234 int flg_read_only;
235 struct variables *next;
236};
237
230/* globals, connect us to the outside world 238/* globals, connect us to the outside world
231 * the first three support $?, $#, and $1 */ 239 * the first three support $?, $#, and $1 */
232char **global_argv; 240char **global_argv;
@@ -248,13 +256,14 @@ static const char *cwd;
248static struct jobset *job_list; 256static struct jobset *job_list;
249static unsigned int last_bg_pid; 257static unsigned int last_bg_pid;
250static char *PS1; 258static char *PS1;
251static char *PS2; 259static char PS2[] = "> ";
252static char **__shell_local_env; 260
261struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 };
262
263struct variables *top_vars = &shell_ver;
253 264
254#define B_CHUNK (100) 265#define B_CHUNK (100)
255#define B_NOSPAC 1 266#define B_NOSPAC 1
256#define MAX_LINE 256 /* for cwd */
257#define MAX_READ 256 /* for builtin_read */
258 267
259typedef struct { 268typedef struct {
260 char *data; 269 char *data;
@@ -303,12 +312,12 @@ static void debug_printf(const char *format, ...)
303 va_end(args); 312 va_end(args);
304} 313}
305#else 314#else
306static void debug_printf(const char *format, ...) { } 315static inline void debug_printf(const char *format, ...) { }
307#endif 316#endif
308#define final_printf debug_printf 317#define final_printf debug_printf
309 318
310void __syntax(char *file, int line) { 319static void __syntax(char *file, int line) {
311 fprintf(stderr,"syntax error %s:%d\n",file,line); 320 error_msg("syntax error %s:%d", file, line);
312} 321}
313#define syntax() __syntax(__FILE__, __LINE__) 322#define syntax() __syntax(__FILE__, __LINE__)
314 323
@@ -362,7 +371,6 @@ static int globhack(const char *src, int flags, glob_t *pglob);
362static int glob_needed(const char *s); 371static int glob_needed(const char *s);
363static int xglob(o_string *dest, int flags, glob_t *pglob); 372static int xglob(o_string *dest, int flags, glob_t *pglob);
364/* variable assignment: */ 373/* variable assignment: */
365static int set_local_var(const char *s);
366static int is_assignment(const char *s); 374static int is_assignment(const char *s);
367/* data structure manipulation: */ 375/* data structure manipulation: */
368static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input); 376static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input);
@@ -390,8 +398,8 @@ static void remove_bg_job(struct pipe *pi);
390static void free_pipe(struct pipe *pi); 398static void free_pipe(struct pipe *pi);
391/* local variable support */ 399/* local variable support */
392static char *get_local_var(const char *var); 400static char *get_local_var(const char *var);
393static int set_local_var(const char *s);
394static void unset_local_var(const char *name); 401static void unset_local_var(const char *name);
402static int set_local_var(const char *s, int flg_export);
395 403
396 404
397/* Table of built-in functions. They can be forked or not, depending on 405/* Table of built-in functions. They can be forked or not, depending on
@@ -427,6 +435,17 @@ static struct built_in_command bltins[] = {
427 {NULL, NULL, NULL} 435 {NULL, NULL, NULL}
428}; 436};
429 437
438static const char *set_cwd(void)
439{
440 if(cwd==unknown)
441 cwd = NULL; /* xgetcwd(arg) called free(arg) */
442 cwd = xgetcwd((char *)cwd);
443 if (!cwd)
444 cwd = unknown;
445 return cwd;
446}
447
448
430/* built-in 'cd <path>' handler */ 449/* built-in 'cd <path>' handler */
431static int builtin_cd(struct child_prog *child) 450static int builtin_cd(struct child_prog *child)
432{ 451{
@@ -439,9 +458,7 @@ static int builtin_cd(struct child_prog *child)
439 printf("cd: %s: %s\n", newdir, strerror(errno)); 458 printf("cd: %s: %s\n", newdir, strerror(errno));
440 return EXIT_FAILURE; 459 return EXIT_FAILURE;
441 } 460 }
442 cwd = xgetcwd((char *)cwd); 461 set_cwd();
443 if (!cwd)
444 cwd = unknown;
445 return EXIT_SUCCESS; 462 return EXIT_SUCCESS;
446} 463}
447 464
@@ -477,43 +494,48 @@ static int builtin_exit(struct child_prog *child)
477/* built-in 'export VAR=value' handler */ 494/* built-in 'export VAR=value' handler */
478static int builtin_export(struct child_prog *child) 495static int builtin_export(struct child_prog *child)
479{ 496{
480 int res; 497 int res = 0;
481 char *value, *name = child->argv[1]; 498 char *name = child->argv[1];
482 499
483 if (name == NULL) { 500 if (name == NULL) {
484 return (builtin_env(child)); 501 return (builtin_env(child));
485 } 502 }
486 503
487 value = strchr(name, '='); 504 name = strdup(name);
505
506 if(name) {
507 char *value = strchr(name, '=');
508
488 if (!value) { 509 if (!value) {
489 /* They are exporting something without an =VALUE. 510 char *tmp;
490 * Assume this is a local shell variable they are exporting */ 511 /* They are exporting something without an =VALUE */
491 name = get_local_var(name); 512
492 if (! name ) { 513 value = get_local_var(name);
493 error_msg("export failed"); 514 if (value) {
494 return (EXIT_FAILURE); 515 size_t ln = strlen(name);
516
517 tmp = realloc(name, ln+strlen(value)+2);
518 if(tmp==NULL)
519 res = -1;
520 else {
521 sprintf(tmp+ln, "=%s", value);
522 name = tmp;
523 }
524 } else {
525 /* bash not put error and set error code
526 if exporting not defined variable */
527 res = 1;
495 } 528 }
496 /* FIXME -- I leak memory!!!!! */ 529 }
497 value = malloc(strlen(child->argv[1]) + strlen(name) + 2); 530 }
498 sprintf(value, "%s=%s", child->argv[1], name); 531 if (res<0)
499 } else {
500 /* Bourne shells always put exported variables into the
501 * local shell variable list. Do that first... */
502 set_local_var(name);
503 /* FIXME -- I leak memory!!!!! */
504 value = strdup(name);
505 }
506
507 /* FIXME -- I leak memory!!!!!
508 * It seems most putenv implementations place the very char* pointer
509 * we pass in directly into the environ array, so the memory holding
510 * this string has to be persistant. We can't even use the memory for
511 * the local shell variable list, since where that memory is keeps
512 * changing due to reallocs... */
513 res = putenv(value);
514 if (res)
515 perror_msg("export"); 532 perror_msg("export");
516 return (res); 533 else if(res==0)
534 res = set_local_var(name, 1);
535 else
536 res = 0;
537 free(name);
538 return res;
517} 539}
518 540
519/* built-in 'fg' and 'bg' handler */ 541/* built-in 'fg' and 'bg' handler */
@@ -605,66 +627,52 @@ static int builtin_jobs(struct child_prog *child)
605/* built-in 'pwd' handler */ 627/* built-in 'pwd' handler */
606static int builtin_pwd(struct child_prog *dummy) 628static int builtin_pwd(struct child_prog *dummy)
607{ 629{
608 cwd = xgetcwd((char *)cwd); 630 puts(set_cwd());
609 if (!cwd)
610 cwd = unknown;
611 puts(cwd);
612 return EXIT_SUCCESS; 631 return EXIT_SUCCESS;
613} 632}
614 633
615/* built-in 'read VAR' handler */ 634/* built-in 'read VAR' handler */
616static int builtin_read(struct child_prog *child) 635static int builtin_read(struct child_prog *child)
617{ 636{
618 int res = 0, len, newlen; 637 int res;
619 char *s;
620 char string[MAX_READ];
621 638
622 if (child->argv[1]) { 639 if (child->argv[1]) {
623 /* argument (VAR) given: put "VAR=" into buffer */ 640 char string[BUFSIZ];
624 strcpy(string, child->argv[1]); 641 char *var = 0;
625 len = strlen(string); 642
626 string[len++] = '='; 643 string[0] = 0; /* for correct work if stdin have "only EOF" */
627 string[len] = '\0'; 644 /* read string */
628 /* XXX would it be better to go through in_str? */ 645 fgets(string, sizeof(string), stdin);
629 fgets(&string[len], sizeof(string) - len, stdin); /* read string */ 646 chomp(string);
630 newlen = strlen(string); 647 var = malloc(strlen(child->argv[1])+strlen(string)+2);
631 if(newlen > len) 648 if(var) {
632 string[--newlen] = '\0'; /* chomp trailing newline */ 649 sprintf(var, "%s=%s", child->argv[1], string);
633 /* 650 res = set_local_var(var, 0);
634 ** string should now contain "VAR=<value>" 651 } else
635 ** copy it (putenv() won't do that, so we must make sure
636 ** the string resides in a static buffer!)
637 */
638 res = -1; 652 res = -1;
639 if((s = strdup(string)))
640 res = putenv(s);
641 if (res) 653 if (res)
642 fprintf(stderr, "read: %s\n", strerror(errno)); 654 fprintf(stderr, "read: %m\n");
655 free(var); /* not move up - saved errno */
656 return res;
657 } else {
658 do res=getchar(); while(res!='\n' && res!=EOF);
659 return 0;
643 } 660 }
644 else
645 fgets(string, sizeof(string), stdin);
646
647 return (res);
648} 661}
649 662
650/* built-in 'set VAR=value' handler */ 663/* built-in 'set VAR=value' handler */
651static int builtin_set(struct child_prog *child) 664static int builtin_set(struct child_prog *child)
652{ 665{
653 int res;
654 char *temp = child->argv[1]; 666 char *temp = child->argv[1];
667 struct variables *e;
668
669 if (temp == NULL)
670 for(e = top_vars; e; e=e->next)
671 printf("%s=%s\n", e->name, e->value);
672 else
673 set_local_var(temp, 0);
655 674
656 if (child->argv[1] == NULL) {
657 char **e = __shell_local_env;
658 if (e == NULL) return EXIT_FAILURE;
659 for (; *e; e++) {
660 puts(*e);
661 }
662 return EXIT_SUCCESS; 675 return EXIT_SUCCESS;
663 }
664 res = set_local_var(temp);
665 if (res)
666 fprintf(stderr, "set: %s\n", strerror(errno));
667 return (res);
668} 676}
669 677
670 678
@@ -697,7 +705,7 @@ static int builtin_source(struct child_prog *child)
697 /* XXX search through $PATH is missing */ 705 /* XXX search through $PATH is missing */
698 input = fopen(child->argv[1], "r"); 706 input = fopen(child->argv[1], "r");
699 if (!input) { 707 if (!input) {
700 fprintf(stderr, "Couldn't open file '%s'\n", child->argv[1]); 708 error_msg("Couldn't open file '%s'", child->argv[1]);
701 return EXIT_FAILURE; 709 return EXIT_FAILURE;
702 } 710 }
703 711
@@ -732,11 +740,7 @@ static int builtin_umask(struct child_prog *child)
732/* built-in 'unset VAR' handler */ 740/* built-in 'unset VAR' handler */
733static int builtin_unset(struct child_prog *child) 741static int builtin_unset(struct child_prog *child)
734{ 742{
735 if (child->argv[1] == NULL) { 743 /* bash returned already true */
736 fprintf(stderr, "unset: parameter required.\n");
737 return EXIT_FAILURE;
738 }
739 unsetenv(child->argv[1]);
740 unset_local_var(child->argv[1]); 744 unset_local_var(child->argv[1]);
741 return EXIT_SUCCESS; 745 return EXIT_SUCCESS;
742} 746}
@@ -998,8 +1002,7 @@ static int setup_redirects(struct child_prog *prog, int squirrel[])
998 if (openfd < 0) { 1002 if (openfd < 0) {
999 /* this could get lost if stderr has been redirected, but 1003 /* this could get lost if stderr has been redirected, but
1000 bash and ash both lose it as well (though zsh doesn't!) */ 1004 bash and ash both lose it as well (though zsh doesn't!) */
1001 fprintf(stderr,"error opening %s: %s\n", redir->word.gl_pathv[0], 1005 perror_msg("error opening %s", redir->word.gl_pathv[0]);
1002 strerror(errno));
1003 return 1; 1006 return 1;
1004 } 1007 }
1005 } else { 1008 } else {
@@ -1160,10 +1163,9 @@ static void insert_bg_job(struct pipe *pi)
1160 /* physically copy the struct job */ 1163 /* physically copy the struct job */
1161 memcpy(thejob, pi, sizeof(struct pipe)); 1164 memcpy(thejob, pi, sizeof(struct pipe));
1162 thejob->next = NULL; 1165 thejob->next = NULL;
1163 //thejob->num_progs = 0;
1164 thejob->running_progs = thejob->num_progs; 1166 thejob->running_progs = thejob->num_progs;
1165 thejob->stopped_progs = 0; 1167 thejob->stopped_progs = 0;
1166 thejob->text = xmalloc(MAX_LINE); 1168 thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */
1167 1169
1168 //if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0]) 1170 //if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0])
1169 { 1171 {
@@ -1327,7 +1329,7 @@ static int run_pipe_real(struct pipe *pi)
1327 if (i!=0 && child->argv[i]==NULL) { 1329 if (i!=0 && child->argv[i]==NULL) {
1328 /* assignments, but no command: set the local environment */ 1330 /* assignments, but no command: set the local environment */
1329 for (i=0; child->argv[i]!=NULL; i++) { 1331 for (i=0; child->argv[i]!=NULL; i++) {
1330 set_local_var(child->argv[i]); 1332 set_local_var(child->argv[i], 0);
1331 } 1333 }
1332 return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ 1334 return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */
1333 } 1335 }
@@ -1646,12 +1648,10 @@ static int xglob(o_string *dest, int flags, glob_t *pglob)
1646 gr = globhack(dest->data, flags, pglob); 1648 gr = globhack(dest->data, flags, pglob);
1647 debug_printf("globhack returned %d\n",gr); 1649 debug_printf("globhack returned %d\n",gr);
1648 } 1650 }
1649 if (gr == GLOB_NOSPACE) { 1651 if (gr == GLOB_NOSPACE)
1650 fprintf(stderr,"out of memory during glob\n"); 1652 error_msg_and_die("out of memory during glob");
1651 exit(1);
1652 }
1653 if (gr != 0) { /* GLOB_ABORTED ? */ 1653 if (gr != 0) { /* GLOB_ABORTED ? */
1654 fprintf(stderr,"glob(3) error %d\n",gr); 1654 error_msg("glob(3) error %d",gr);
1655 } 1655 }
1656 /* globprint(glob_target); */ 1656 /* globprint(glob_target); */
1657 return gr; 1657 return gr;
@@ -1660,129 +1660,113 @@ static int xglob(o_string *dest, int flags, glob_t *pglob)
1660/* This is used to get/check local shell variables */ 1660/* This is used to get/check local shell variables */
1661static char *get_local_var(const char *s) 1661static char *get_local_var(const char *s)
1662{ 1662{
1663 char **p; 1663 struct variables *cur;
1664 int len;
1665 1664
1666 if (!s) 1665 if (!s)
1667 return NULL; 1666 return NULL;
1668 if (!__shell_local_env) 1667 for (cur = top_vars; cur; cur=cur->next)
1669 return NULL; 1668 if(strcmp(cur->name, s)==0)
1670 len = strlen(s); 1669 return cur->value;
1671
1672 for (p = __shell_local_env; *p; p++) {
1673 if (memcmp(s, *p, len) == 0 && (*p)[len] == '=') {
1674 return *p + len + 1;
1675 }
1676 }
1677 return NULL; 1670 return NULL;
1678} 1671}
1679 1672
1680/* This is used to set local shell variables */ 1673/* This is used to set local shell variables
1681static int set_local_var(const char *s) 1674 flg_export==0 if only local (not exporting) variable
1675 flg_export==1 if "new" exporting environ
1676 flg_export>1 if current startup environ (not call putenv()) */
1677static int set_local_var(const char *s, int flg_export)
1682{ 1678{
1683 char **ep; 1679 char *name, *value;
1684 char *tmp,*name, *value;
1685 size_t size;
1686 size_t namelen;
1687 size_t vallen;
1688 int result=0; 1680 int result=0;
1681 struct variables *cur;
1682 char *newval = 0;
1689 1683
1690 name=tmp=strdup(s); 1684 name=strdup(s);
1691 1685
1692 /* Assume when we enter this function that we are already in 1686 /* Assume when we enter this function that we are already in
1693 * NAME=VALUE format. So the first order of business is to 1687 * NAME=VALUE format. So the first order of business is to
1694 * split 's' on the '=' into 'name' and 'value' */ 1688 * split 's' on the '=' into 'name' and 'value' */
1695 value = strchr(name, '='); 1689 value = strchr(name, '=');
1696 if (!value) { 1690 if (value==0 || (newval = strdup(value+1))==0) {
1697 result = -1; 1691 result = -1;
1698 goto done_already; 1692 } else {
1699 } 1693 *value++ = 0;
1700 *value='\0';
1701 ++value;
1702
1703 namelen = strlen (name);
1704 vallen = strlen (value);
1705 1694
1706 /* Now see how many local environment entries we have, and check 1695 for(cur = top_vars; cur; cur = cur->next)
1707 * if we match an existing environment entry (so we can overwrite it) */ 1696 if(strcmp(cur->name, name)==0)
1708 size = 0;
1709 for (ep = __shell_local_env; ep && *ep != NULL; ++ep) {
1710 if (!memcmp (*ep, name, namelen) && (*ep)[namelen] == '=')
1711 break; 1697 break;
1712 else
1713 ++size;
1714 }
1715 1698
1716 if (ep == NULL || *ep == NULL) { 1699 if(cur) {
1717 static char **last_environ = NULL; 1700 if(strcmp(cur->value, value)==0) {
1718 char **new_environ = (char **) malloc((size + 2) * sizeof(char *)); 1701 result = cur->flg_export == flg_export;
1719 if (new_environ == NULL) { 1702 } else {
1720 result = -1; 1703 if(cur->flg_read_only) {
1721 goto done_already;
1722 }
1723 memcpy((__ptr_t) new_environ, (__ptr_t) __shell_local_env,
1724 size * sizeof(char *));
1725
1726 new_environ[size] = malloc (namelen + 1 + vallen + 1);
1727 if (new_environ[size] == NULL) {
1728 free (new_environ);
1729 errno=ENOMEM;
1730 result = -1; 1704 result = -1;
1731 goto done_already; 1705 error_msg("%s: readonly variable", name);
1706 } else {
1707 free(cur->value);
1708 cur->value = newval;
1709 newval = 0; /* protect free */
1732 } 1710 }
1733 memcpy (new_environ[size], name, namelen); 1711 }
1734 new_environ[size][namelen] = '='; 1712 } else {
1735 memcpy (&new_environ[size][namelen + 1], value, vallen + 1); 1713 cur = malloc(sizeof(struct variables));
1736 1714 if(cur==0) {
1737 new_environ[size + 1] = NULL;
1738
1739 if (last_environ != NULL)
1740 free ((__ptr_t) last_environ);
1741 last_environ = new_environ;
1742 __shell_local_env = new_environ;
1743 }
1744 else {
1745 size_t len = strlen (*ep);
1746 if (len < namelen + 1 + vallen) {
1747 char *new = malloc (namelen + 1 + vallen + 1);
1748 if (new == NULL) {
1749 result = -1; 1715 result = -1;
1750 goto done_already; 1716 } else {
1717 cur->name = strdup(name);
1718 if(cur->name == 0) {
1719 free(cur);
1720 result = -1;
1721 } else {
1722 struct variables *bottom = top_vars;
1723
1724 cur->value = newval;
1725 newval = 0; /* protect free */
1726 cur->next = 0;
1727 cur->flg_export = flg_export;
1728 cur->flg_read_only = 0;
1729 while(bottom->next) bottom=bottom->next;
1730 bottom->next = cur;
1751 } 1731 }
1752 *ep = new;
1753 memcpy (*ep, name, namelen);
1754 (*ep)[namelen] = '=';
1755 } 1732 }
1756 memcpy (&(*ep)[namelen + 1], value, vallen + 1);
1757 } 1733 }
1758
1759 /* One last little detail... If this variable is already
1760 * in the environment we must set it there as well... */
1761 tmp = getenv(name);
1762 if (tmp) {
1763 /* FIXME -- I leak memory!!!!! */
1764 putenv(strdup(s));
1765 } 1734 }
1766 1735
1767done_already: 1736 if((result==0 && flg_export==1) || (result>0 && cur->flg_export>0)) {
1737 *(value-1) = '=';
1738 result = putenv(name);
1739 } else {
1768 free(name); 1740 free(name);
1741 if(result>0) /* equivalent to previous set */
1742 result = 0;
1743 }
1744 free(newval);
1769 return result; 1745 return result;
1770} 1746}
1771 1747
1772static void unset_local_var(const char *name) 1748static void unset_local_var(const char *name)
1773{ 1749{
1774 char **ep, **dp; 1750 struct variables *cur;
1775 size_t namelen;
1776 1751
1777 if (!name) 1752 if (name) {
1753 for (cur = top_vars; cur; cur=cur->next)
1754 if(strcmp(cur->name, name)==0)
1755 break;
1756 if(cur!=0) {
1757 struct variables *next = top_vars;
1758 if(cur==next)
1778 return; 1759 return;
1779 namelen = strlen(name); 1760 else {
1780 for (dp = ep = __shell_local_env; ep && *ep != NULL; ++ep) { 1761 if(cur->flg_export)
1781 if (memcmp (*ep, name, namelen)==0 && (*ep)[namelen] == '=') { 1762 unsetenv(cur->name);
1782 *dp = *ep; 1763 free(cur->name);
1783 ++dp; 1764 free(cur->value);
1784 *ep = NULL; 1765 while (next->next != cur)
1785 break; 1766 next = next->next;
1767 next->next = cur->next;
1768 }
1769 free(cur);
1786 } 1770 }
1787 } 1771 }
1788} 1772}
@@ -1963,7 +1947,7 @@ static int done_word(o_string *dest, struct p_context *ctx)
1963 if (ctx->pending_redirect) { 1947 if (ctx->pending_redirect) {
1964 ctx->pending_redirect=NULL; 1948 ctx->pending_redirect=NULL;
1965 if (glob_target->gl_pathc != 1) { 1949 if (glob_target->gl_pathc != 1) {
1966 fprintf(stderr, "ambiguous redirect\n"); 1950 error_msg("ambiguous redirect");
1967 return 1; 1951 return 1;
1968 } 1952 }
1969 } else { 1953 } else {
@@ -2049,7 +2033,7 @@ static int redirect_dup_num(struct in_str *input)
2049 } 2033 }
2050 if (ok) return d; 2034 if (ok) return d;
2051 2035
2052 fprintf(stderr, "ambiguous redirect\n"); 2036 error_msg("ambiguous redirect");
2053 return -2; 2037 return -2;
2054} 2038}
2055 2039
@@ -2261,7 +2245,7 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i
2261 case '-': 2245 case '-':
2262 case '_': 2246 case '_':
2263 /* still unhandled, but should be eventually */ 2247 /* still unhandled, but should be eventually */
2264 fprintf(stderr,"unhandled syntax: $%c\n",ch); 2248 error_msg("unhandled syntax: $%c",ch);
2265 return 1; 2249 return 1;
2266 break; 2250 break;
2267 default: 2251 default:
@@ -2505,16 +2489,14 @@ int shell_main(int argc, char **argv)
2505 int opt; 2489 int opt;
2506 FILE *input; 2490 FILE *input;
2507 struct jobset joblist_end = { NULL, NULL }; 2491 struct jobset joblist_end = { NULL, NULL };
2492 char **e = environ;
2508 2493
2509 /* (re?) initialize globals */ 2494 /* initialize globals */
2510 ifs=NULL; 2495 if (e) {
2511 fake_mode=0; 2496 for (; *e; e++)
2512 interactive=0; 2497 set_local_var(*e, 2); /* without call putenv() */
2513 close_me_head = NULL; 2498 }
2514 job_list = &joblist_end; 2499 job_list = &joblist_end;
2515 last_bg_pid=0;
2516 PS2 = "> ";
2517 __shell_local_env = 0;
2518 2500
2519 last_return_code=EXIT_SUCCESS; 2501 last_return_code=EXIT_SUCCESS;
2520 2502
@@ -2581,9 +2563,13 @@ int shell_main(int argc, char **argv)
2581 fake_mode++; 2563 fake_mode++;
2582 break; 2564 break;
2583 default: 2565 default:
2566#ifndef BB_VER
2584 fprintf(stderr, "Usage: sh [FILE]...\n" 2567 fprintf(stderr, "Usage: sh [FILE]...\n"
2585 " or: sh -c command [args]...\n\n"); 2568 " or: sh -c command [args]...\n\n");
2586 exit(EXIT_FAILURE); 2569 exit(EXIT_FAILURE);
2570#else
2571 show_usage();
2572#endif
2587 } 2573 }
2588 } 2574 }
2589 /* A shell is interactive if the `-i' flag was given, or if all of 2575 /* A shell is interactive if the `-i' flag was given, or if all of
diff --git a/shell/hush.c b/shell/hush.c
index 59568189f..a1e65b24e 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -227,6 +227,14 @@ struct close_me {
227 struct close_me *next; 227 struct close_me *next;
228}; 228};
229 229
230struct variables {
231 char *name;
232 char *value;
233 int flg_export;
234 int flg_read_only;
235 struct variables *next;
236};
237
230/* globals, connect us to the outside world 238/* globals, connect us to the outside world
231 * the first three support $?, $#, and $1 */ 239 * the first three support $?, $#, and $1 */
232char **global_argv; 240char **global_argv;
@@ -248,13 +256,14 @@ static const char *cwd;
248static struct jobset *job_list; 256static struct jobset *job_list;
249static unsigned int last_bg_pid; 257static unsigned int last_bg_pid;
250static char *PS1; 258static char *PS1;
251static char *PS2; 259static char PS2[] = "> ";
252static char **__shell_local_env; 260
261struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 };
262
263struct variables *top_vars = &shell_ver;
253 264
254#define B_CHUNK (100) 265#define B_CHUNK (100)
255#define B_NOSPAC 1 266#define B_NOSPAC 1
256#define MAX_LINE 256 /* for cwd */
257#define MAX_READ 256 /* for builtin_read */
258 267
259typedef struct { 268typedef struct {
260 char *data; 269 char *data;
@@ -303,12 +312,12 @@ static void debug_printf(const char *format, ...)
303 va_end(args); 312 va_end(args);
304} 313}
305#else 314#else
306static void debug_printf(const char *format, ...) { } 315static inline void debug_printf(const char *format, ...) { }
307#endif 316#endif
308#define final_printf debug_printf 317#define final_printf debug_printf
309 318
310void __syntax(char *file, int line) { 319static void __syntax(char *file, int line) {
311 fprintf(stderr,"syntax error %s:%d\n",file,line); 320 error_msg("syntax error %s:%d", file, line);
312} 321}
313#define syntax() __syntax(__FILE__, __LINE__) 322#define syntax() __syntax(__FILE__, __LINE__)
314 323
@@ -362,7 +371,6 @@ static int globhack(const char *src, int flags, glob_t *pglob);
362static int glob_needed(const char *s); 371static int glob_needed(const char *s);
363static int xglob(o_string *dest, int flags, glob_t *pglob); 372static int xglob(o_string *dest, int flags, glob_t *pglob);
364/* variable assignment: */ 373/* variable assignment: */
365static int set_local_var(const char *s);
366static int is_assignment(const char *s); 374static int is_assignment(const char *s);
367/* data structure manipulation: */ 375/* data structure manipulation: */
368static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input); 376static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input);
@@ -390,8 +398,8 @@ static void remove_bg_job(struct pipe *pi);
390static void free_pipe(struct pipe *pi); 398static void free_pipe(struct pipe *pi);
391/* local variable support */ 399/* local variable support */
392static char *get_local_var(const char *var); 400static char *get_local_var(const char *var);
393static int set_local_var(const char *s);
394static void unset_local_var(const char *name); 401static void unset_local_var(const char *name);
402static int set_local_var(const char *s, int flg_export);
395 403
396 404
397/* Table of built-in functions. They can be forked or not, depending on 405/* Table of built-in functions. They can be forked or not, depending on
@@ -427,6 +435,17 @@ static struct built_in_command bltins[] = {
427 {NULL, NULL, NULL} 435 {NULL, NULL, NULL}
428}; 436};
429 437
438static const char *set_cwd(void)
439{
440 if(cwd==unknown)
441 cwd = NULL; /* xgetcwd(arg) called free(arg) */
442 cwd = xgetcwd((char *)cwd);
443 if (!cwd)
444 cwd = unknown;
445 return cwd;
446}
447
448
430/* built-in 'cd <path>' handler */ 449/* built-in 'cd <path>' handler */
431static int builtin_cd(struct child_prog *child) 450static int builtin_cd(struct child_prog *child)
432{ 451{
@@ -439,9 +458,7 @@ static int builtin_cd(struct child_prog *child)
439 printf("cd: %s: %s\n", newdir, strerror(errno)); 458 printf("cd: %s: %s\n", newdir, strerror(errno));
440 return EXIT_FAILURE; 459 return EXIT_FAILURE;
441 } 460 }
442 cwd = xgetcwd((char *)cwd); 461 set_cwd();
443 if (!cwd)
444 cwd = unknown;
445 return EXIT_SUCCESS; 462 return EXIT_SUCCESS;
446} 463}
447 464
@@ -477,43 +494,48 @@ static int builtin_exit(struct child_prog *child)
477/* built-in 'export VAR=value' handler */ 494/* built-in 'export VAR=value' handler */
478static int builtin_export(struct child_prog *child) 495static int builtin_export(struct child_prog *child)
479{ 496{
480 int res; 497 int res = 0;
481 char *value, *name = child->argv[1]; 498 char *name = child->argv[1];
482 499
483 if (name == NULL) { 500 if (name == NULL) {
484 return (builtin_env(child)); 501 return (builtin_env(child));
485 } 502 }
486 503
487 value = strchr(name, '='); 504 name = strdup(name);
505
506 if(name) {
507 char *value = strchr(name, '=');
508
488 if (!value) { 509 if (!value) {
489 /* They are exporting something without an =VALUE. 510 char *tmp;
490 * Assume this is a local shell variable they are exporting */ 511 /* They are exporting something without an =VALUE */
491 name = get_local_var(name); 512
492 if (! name ) { 513 value = get_local_var(name);
493 error_msg("export failed"); 514 if (value) {
494 return (EXIT_FAILURE); 515 size_t ln = strlen(name);
516
517 tmp = realloc(name, ln+strlen(value)+2);
518 if(tmp==NULL)
519 res = -1;
520 else {
521 sprintf(tmp+ln, "=%s", value);
522 name = tmp;
523 }
524 } else {
525 /* bash not put error and set error code
526 if exporting not defined variable */
527 res = 1;
495 } 528 }
496 /* FIXME -- I leak memory!!!!! */ 529 }
497 value = malloc(strlen(child->argv[1]) + strlen(name) + 2); 530 }
498 sprintf(value, "%s=%s", child->argv[1], name); 531 if (res<0)
499 } else {
500 /* Bourne shells always put exported variables into the
501 * local shell variable list. Do that first... */
502 set_local_var(name);
503 /* FIXME -- I leak memory!!!!! */
504 value = strdup(name);
505 }
506
507 /* FIXME -- I leak memory!!!!!
508 * It seems most putenv implementations place the very char* pointer
509 * we pass in directly into the environ array, so the memory holding
510 * this string has to be persistant. We can't even use the memory for
511 * the local shell variable list, since where that memory is keeps
512 * changing due to reallocs... */
513 res = putenv(value);
514 if (res)
515 perror_msg("export"); 532 perror_msg("export");
516 return (res); 533 else if(res==0)
534 res = set_local_var(name, 1);
535 else
536 res = 0;
537 free(name);
538 return res;
517} 539}
518 540
519/* built-in 'fg' and 'bg' handler */ 541/* built-in 'fg' and 'bg' handler */
@@ -605,66 +627,52 @@ static int builtin_jobs(struct child_prog *child)
605/* built-in 'pwd' handler */ 627/* built-in 'pwd' handler */
606static int builtin_pwd(struct child_prog *dummy) 628static int builtin_pwd(struct child_prog *dummy)
607{ 629{
608 cwd = xgetcwd((char *)cwd); 630 puts(set_cwd());
609 if (!cwd)
610 cwd = unknown;
611 puts(cwd);
612 return EXIT_SUCCESS; 631 return EXIT_SUCCESS;
613} 632}
614 633
615/* built-in 'read VAR' handler */ 634/* built-in 'read VAR' handler */
616static int builtin_read(struct child_prog *child) 635static int builtin_read(struct child_prog *child)
617{ 636{
618 int res = 0, len, newlen; 637 int res;
619 char *s;
620 char string[MAX_READ];
621 638
622 if (child->argv[1]) { 639 if (child->argv[1]) {
623 /* argument (VAR) given: put "VAR=" into buffer */ 640 char string[BUFSIZ];
624 strcpy(string, child->argv[1]); 641 char *var = 0;
625 len = strlen(string); 642
626 string[len++] = '='; 643 string[0] = 0; /* for correct work if stdin have "only EOF" */
627 string[len] = '\0'; 644 /* read string */
628 /* XXX would it be better to go through in_str? */ 645 fgets(string, sizeof(string), stdin);
629 fgets(&string[len], sizeof(string) - len, stdin); /* read string */ 646 chomp(string);
630 newlen = strlen(string); 647 var = malloc(strlen(child->argv[1])+strlen(string)+2);
631 if(newlen > len) 648 if(var) {
632 string[--newlen] = '\0'; /* chomp trailing newline */ 649 sprintf(var, "%s=%s", child->argv[1], string);
633 /* 650 res = set_local_var(var, 0);
634 ** string should now contain "VAR=<value>" 651 } else
635 ** copy it (putenv() won't do that, so we must make sure
636 ** the string resides in a static buffer!)
637 */
638 res = -1; 652 res = -1;
639 if((s = strdup(string)))
640 res = putenv(s);
641 if (res) 653 if (res)
642 fprintf(stderr, "read: %s\n", strerror(errno)); 654 fprintf(stderr, "read: %m\n");
655 free(var); /* not move up - saved errno */
656 return res;
657 } else {
658 do res=getchar(); while(res!='\n' && res!=EOF);
659 return 0;
643 } 660 }
644 else
645 fgets(string, sizeof(string), stdin);
646
647 return (res);
648} 661}
649 662
650/* built-in 'set VAR=value' handler */ 663/* built-in 'set VAR=value' handler */
651static int builtin_set(struct child_prog *child) 664static int builtin_set(struct child_prog *child)
652{ 665{
653 int res;
654 char *temp = child->argv[1]; 666 char *temp = child->argv[1];
667 struct variables *e;
668
669 if (temp == NULL)
670 for(e = top_vars; e; e=e->next)
671 printf("%s=%s\n", e->name, e->value);
672 else
673 set_local_var(temp, 0);
655 674
656 if (child->argv[1] == NULL) {
657 char **e = __shell_local_env;
658 if (e == NULL) return EXIT_FAILURE;
659 for (; *e; e++) {
660 puts(*e);
661 }
662 return EXIT_SUCCESS; 675 return EXIT_SUCCESS;
663 }
664 res = set_local_var(temp);
665 if (res)
666 fprintf(stderr, "set: %s\n", strerror(errno));
667 return (res);
668} 676}
669 677
670 678
@@ -697,7 +705,7 @@ static int builtin_source(struct child_prog *child)
697 /* XXX search through $PATH is missing */ 705 /* XXX search through $PATH is missing */
698 input = fopen(child->argv[1], "r"); 706 input = fopen(child->argv[1], "r");
699 if (!input) { 707 if (!input) {
700 fprintf(stderr, "Couldn't open file '%s'\n", child->argv[1]); 708 error_msg("Couldn't open file '%s'", child->argv[1]);
701 return EXIT_FAILURE; 709 return EXIT_FAILURE;
702 } 710 }
703 711
@@ -732,11 +740,7 @@ static int builtin_umask(struct child_prog *child)
732/* built-in 'unset VAR' handler */ 740/* built-in 'unset VAR' handler */
733static int builtin_unset(struct child_prog *child) 741static int builtin_unset(struct child_prog *child)
734{ 742{
735 if (child->argv[1] == NULL) { 743 /* bash returned already true */
736 fprintf(stderr, "unset: parameter required.\n");
737 return EXIT_FAILURE;
738 }
739 unsetenv(child->argv[1]);
740 unset_local_var(child->argv[1]); 744 unset_local_var(child->argv[1]);
741 return EXIT_SUCCESS; 745 return EXIT_SUCCESS;
742} 746}
@@ -998,8 +1002,7 @@ static int setup_redirects(struct child_prog *prog, int squirrel[])
998 if (openfd < 0) { 1002 if (openfd < 0) {
999 /* this could get lost if stderr has been redirected, but 1003 /* this could get lost if stderr has been redirected, but
1000 bash and ash both lose it as well (though zsh doesn't!) */ 1004 bash and ash both lose it as well (though zsh doesn't!) */
1001 fprintf(stderr,"error opening %s: %s\n", redir->word.gl_pathv[0], 1005 perror_msg("error opening %s", redir->word.gl_pathv[0]);
1002 strerror(errno));
1003 return 1; 1006 return 1;
1004 } 1007 }
1005 } else { 1008 } else {
@@ -1160,10 +1163,9 @@ static void insert_bg_job(struct pipe *pi)
1160 /* physically copy the struct job */ 1163 /* physically copy the struct job */
1161 memcpy(thejob, pi, sizeof(struct pipe)); 1164 memcpy(thejob, pi, sizeof(struct pipe));
1162 thejob->next = NULL; 1165 thejob->next = NULL;
1163 //thejob->num_progs = 0;
1164 thejob->running_progs = thejob->num_progs; 1166 thejob->running_progs = thejob->num_progs;
1165 thejob->stopped_progs = 0; 1167 thejob->stopped_progs = 0;
1166 thejob->text = xmalloc(MAX_LINE); 1168 thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */
1167 1169
1168 //if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0]) 1170 //if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0])
1169 { 1171 {
@@ -1327,7 +1329,7 @@ static int run_pipe_real(struct pipe *pi)
1327 if (i!=0 && child->argv[i]==NULL) { 1329 if (i!=0 && child->argv[i]==NULL) {
1328 /* assignments, but no command: set the local environment */ 1330 /* assignments, but no command: set the local environment */
1329 for (i=0; child->argv[i]!=NULL; i++) { 1331 for (i=0; child->argv[i]!=NULL; i++) {
1330 set_local_var(child->argv[i]); 1332 set_local_var(child->argv[i], 0);
1331 } 1333 }
1332 return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ 1334 return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */
1333 } 1335 }
@@ -1646,12 +1648,10 @@ static int xglob(o_string *dest, int flags, glob_t *pglob)
1646 gr = globhack(dest->data, flags, pglob); 1648 gr = globhack(dest->data, flags, pglob);
1647 debug_printf("globhack returned %d\n",gr); 1649 debug_printf("globhack returned %d\n",gr);
1648 } 1650 }
1649 if (gr == GLOB_NOSPACE) { 1651 if (gr == GLOB_NOSPACE)
1650 fprintf(stderr,"out of memory during glob\n"); 1652 error_msg_and_die("out of memory during glob");
1651 exit(1);
1652 }
1653 if (gr != 0) { /* GLOB_ABORTED ? */ 1653 if (gr != 0) { /* GLOB_ABORTED ? */
1654 fprintf(stderr,"glob(3) error %d\n",gr); 1654 error_msg("glob(3) error %d",gr);
1655 } 1655 }
1656 /* globprint(glob_target); */ 1656 /* globprint(glob_target); */
1657 return gr; 1657 return gr;
@@ -1660,129 +1660,113 @@ static int xglob(o_string *dest, int flags, glob_t *pglob)
1660/* This is used to get/check local shell variables */ 1660/* This is used to get/check local shell variables */
1661static char *get_local_var(const char *s) 1661static char *get_local_var(const char *s)
1662{ 1662{
1663 char **p; 1663 struct variables *cur;
1664 int len;
1665 1664
1666 if (!s) 1665 if (!s)
1667 return NULL; 1666 return NULL;
1668 if (!__shell_local_env) 1667 for (cur = top_vars; cur; cur=cur->next)
1669 return NULL; 1668 if(strcmp(cur->name, s)==0)
1670 len = strlen(s); 1669 return cur->value;
1671
1672 for (p = __shell_local_env; *p; p++) {
1673 if (memcmp(s, *p, len) == 0 && (*p)[len] == '=') {
1674 return *p + len + 1;
1675 }
1676 }
1677 return NULL; 1670 return NULL;
1678} 1671}
1679 1672
1680/* This is used to set local shell variables */ 1673/* This is used to set local shell variables
1681static int set_local_var(const char *s) 1674 flg_export==0 if only local (not exporting) variable
1675 flg_export==1 if "new" exporting environ
1676 flg_export>1 if current startup environ (not call putenv()) */
1677static int set_local_var(const char *s, int flg_export)
1682{ 1678{
1683 char **ep; 1679 char *name, *value;
1684 char *tmp,*name, *value;
1685 size_t size;
1686 size_t namelen;
1687 size_t vallen;
1688 int result=0; 1680 int result=0;
1681 struct variables *cur;
1682 char *newval = 0;
1689 1683
1690 name=tmp=strdup(s); 1684 name=strdup(s);
1691 1685
1692 /* Assume when we enter this function that we are already in 1686 /* Assume when we enter this function that we are already in
1693 * NAME=VALUE format. So the first order of business is to 1687 * NAME=VALUE format. So the first order of business is to
1694 * split 's' on the '=' into 'name' and 'value' */ 1688 * split 's' on the '=' into 'name' and 'value' */
1695 value = strchr(name, '='); 1689 value = strchr(name, '=');
1696 if (!value) { 1690 if (value==0 || (newval = strdup(value+1))==0) {
1697 result = -1; 1691 result = -1;
1698 goto done_already; 1692 } else {
1699 } 1693 *value++ = 0;
1700 *value='\0';
1701 ++value;
1702
1703 namelen = strlen (name);
1704 vallen = strlen (value);
1705 1694
1706 /* Now see how many local environment entries we have, and check 1695 for(cur = top_vars; cur; cur = cur->next)
1707 * if we match an existing environment entry (so we can overwrite it) */ 1696 if(strcmp(cur->name, name)==0)
1708 size = 0;
1709 for (ep = __shell_local_env; ep && *ep != NULL; ++ep) {
1710 if (!memcmp (*ep, name, namelen) && (*ep)[namelen] == '=')
1711 break; 1697 break;
1712 else
1713 ++size;
1714 }
1715 1698
1716 if (ep == NULL || *ep == NULL) { 1699 if(cur) {
1717 static char **last_environ = NULL; 1700 if(strcmp(cur->value, value)==0) {
1718 char **new_environ = (char **) malloc((size + 2) * sizeof(char *)); 1701 result = cur->flg_export == flg_export;
1719 if (new_environ == NULL) { 1702 } else {
1720 result = -1; 1703 if(cur->flg_read_only) {
1721 goto done_already;
1722 }
1723 memcpy((__ptr_t) new_environ, (__ptr_t) __shell_local_env,
1724 size * sizeof(char *));
1725
1726 new_environ[size] = malloc (namelen + 1 + vallen + 1);
1727 if (new_environ[size] == NULL) {
1728 free (new_environ);
1729 errno=ENOMEM;
1730 result = -1; 1704 result = -1;
1731 goto done_already; 1705 error_msg("%s: readonly variable", name);
1706 } else {
1707 free(cur->value);
1708 cur->value = newval;
1709 newval = 0; /* protect free */
1732 } 1710 }
1733 memcpy (new_environ[size], name, namelen); 1711 }
1734 new_environ[size][namelen] = '='; 1712 } else {
1735 memcpy (&new_environ[size][namelen + 1], value, vallen + 1); 1713 cur = malloc(sizeof(struct variables));
1736 1714 if(cur==0) {
1737 new_environ[size + 1] = NULL;
1738
1739 if (last_environ != NULL)
1740 free ((__ptr_t) last_environ);
1741 last_environ = new_environ;
1742 __shell_local_env = new_environ;
1743 }
1744 else {
1745 size_t len = strlen (*ep);
1746 if (len < namelen + 1 + vallen) {
1747 char *new = malloc (namelen + 1 + vallen + 1);
1748 if (new == NULL) {
1749 result = -1; 1715 result = -1;
1750 goto done_already; 1716 } else {
1717 cur->name = strdup(name);
1718 if(cur->name == 0) {
1719 free(cur);
1720 result = -1;
1721 } else {
1722 struct variables *bottom = top_vars;
1723
1724 cur->value = newval;
1725 newval = 0; /* protect free */
1726 cur->next = 0;
1727 cur->flg_export = flg_export;
1728 cur->flg_read_only = 0;
1729 while(bottom->next) bottom=bottom->next;
1730 bottom->next = cur;
1751 } 1731 }
1752 *ep = new;
1753 memcpy (*ep, name, namelen);
1754 (*ep)[namelen] = '=';
1755 } 1732 }
1756 memcpy (&(*ep)[namelen + 1], value, vallen + 1);
1757 } 1733 }
1758
1759 /* One last little detail... If this variable is already
1760 * in the environment we must set it there as well... */
1761 tmp = getenv(name);
1762 if (tmp) {
1763 /* FIXME -- I leak memory!!!!! */
1764 putenv(strdup(s));
1765 } 1734 }
1766 1735
1767done_already: 1736 if((result==0 && flg_export==1) || (result>0 && cur->flg_export>0)) {
1737 *(value-1) = '=';
1738 result = putenv(name);
1739 } else {
1768 free(name); 1740 free(name);
1741 if(result>0) /* equivalent to previous set */
1742 result = 0;
1743 }
1744 free(newval);
1769 return result; 1745 return result;
1770} 1746}
1771 1747
1772static void unset_local_var(const char *name) 1748static void unset_local_var(const char *name)
1773{ 1749{
1774 char **ep, **dp; 1750 struct variables *cur;
1775 size_t namelen;
1776 1751
1777 if (!name) 1752 if (name) {
1753 for (cur = top_vars; cur; cur=cur->next)
1754 if(strcmp(cur->name, name)==0)
1755 break;
1756 if(cur!=0) {
1757 struct variables *next = top_vars;
1758 if(cur==next)
1778 return; 1759 return;
1779 namelen = strlen(name); 1760 else {
1780 for (dp = ep = __shell_local_env; ep && *ep != NULL; ++ep) { 1761 if(cur->flg_export)
1781 if (memcmp (*ep, name, namelen)==0 && (*ep)[namelen] == '=') { 1762 unsetenv(cur->name);
1782 *dp = *ep; 1763 free(cur->name);
1783 ++dp; 1764 free(cur->value);
1784 *ep = NULL; 1765 while (next->next != cur)
1785 break; 1766 next = next->next;
1767 next->next = cur->next;
1768 }
1769 free(cur);
1786 } 1770 }
1787 } 1771 }
1788} 1772}
@@ -1963,7 +1947,7 @@ static int done_word(o_string *dest, struct p_context *ctx)
1963 if (ctx->pending_redirect) { 1947 if (ctx->pending_redirect) {
1964 ctx->pending_redirect=NULL; 1948 ctx->pending_redirect=NULL;
1965 if (glob_target->gl_pathc != 1) { 1949 if (glob_target->gl_pathc != 1) {
1966 fprintf(stderr, "ambiguous redirect\n"); 1950 error_msg("ambiguous redirect");
1967 return 1; 1951 return 1;
1968 } 1952 }
1969 } else { 1953 } else {
@@ -2049,7 +2033,7 @@ static int redirect_dup_num(struct in_str *input)
2049 } 2033 }
2050 if (ok) return d; 2034 if (ok) return d;
2051 2035
2052 fprintf(stderr, "ambiguous redirect\n"); 2036 error_msg("ambiguous redirect");
2053 return -2; 2037 return -2;
2054} 2038}
2055 2039
@@ -2261,7 +2245,7 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i
2261 case '-': 2245 case '-':
2262 case '_': 2246 case '_':
2263 /* still unhandled, but should be eventually */ 2247 /* still unhandled, but should be eventually */
2264 fprintf(stderr,"unhandled syntax: $%c\n",ch); 2248 error_msg("unhandled syntax: $%c",ch);
2265 return 1; 2249 return 1;
2266 break; 2250 break;
2267 default: 2251 default:
@@ -2505,16 +2489,14 @@ int shell_main(int argc, char **argv)
2505 int opt; 2489 int opt;
2506 FILE *input; 2490 FILE *input;
2507 struct jobset joblist_end = { NULL, NULL }; 2491 struct jobset joblist_end = { NULL, NULL };
2492 char **e = environ;
2508 2493
2509 /* (re?) initialize globals */ 2494 /* initialize globals */
2510 ifs=NULL; 2495 if (e) {
2511 fake_mode=0; 2496 for (; *e; e++)
2512 interactive=0; 2497 set_local_var(*e, 2); /* without call putenv() */
2513 close_me_head = NULL; 2498 }
2514 job_list = &joblist_end; 2499 job_list = &joblist_end;
2515 last_bg_pid=0;
2516 PS2 = "> ";
2517 __shell_local_env = 0;
2518 2500
2519 last_return_code=EXIT_SUCCESS; 2501 last_return_code=EXIT_SUCCESS;
2520 2502
@@ -2581,9 +2563,13 @@ int shell_main(int argc, char **argv)
2581 fake_mode++; 2563 fake_mode++;
2582 break; 2564 break;
2583 default: 2565 default:
2566#ifndef BB_VER
2584 fprintf(stderr, "Usage: sh [FILE]...\n" 2567 fprintf(stderr, "Usage: sh [FILE]...\n"
2585 " or: sh -c command [args]...\n\n"); 2568 " or: sh -c command [args]...\n\n");
2586 exit(EXIT_FAILURE); 2569 exit(EXIT_FAILURE);
2570#else
2571 show_usage();
2572#endif
2587 } 2573 }
2588 } 2574 }
2589 /* A shell is interactive if the `-i' flag was given, or if all of 2575 /* A shell is interactive if the `-i' flag was given, or if all of