aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorandersen <andersen@69ca8d6d-28ef-0310-b511-8ec308f3f277>2001-05-15 23:21:41 +0000
committerandersen <andersen@69ca8d6d-28ef-0310-b511-8ec308f3f277>2001-05-15 23:21:41 +0000
commit6d8030f99aa680856a2c9a7ea3582d73961f085f (patch)
tree5554e694d9363f88a0b11fa78cfd72fe25d3b537 /shell
parent0b0f359bfec843349d7603541e9c6e0ab635851e (diff)
downloadbusybox-w32-6d8030f99aa680856a2c9a7ea3582d73961f085f.tar.gz
busybox-w32-6d8030f99aa680856a2c9a7ea3582d73961f085f.tar.bz2
busybox-w32-6d8030f99aa680856a2c9a7ea3582d73961f085f.zip
Fix the behavior of local shell variables to match that of bash and ash.
-Erik git-svn-id: svn://busybox.net/trunk/busybox@2651 69ca8d6d-28ef-0310-b511-8ec308f3f277
Diffstat (limited to 'shell')
-rw-r--r--shell/hush.c134
1 files changed, 109 insertions, 25 deletions
diff --git a/shell/hush.c b/shell/hush.c
index cfe0b826b..5a4966b07 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -55,7 +55,6 @@
55 * to-do: 55 * to-do:
56 * port selected bugfixes from post-0.49 busybox lash - done? 56 * port selected bugfixes from post-0.49 busybox lash - done?
57 * finish implementing reserved words: for, while, until, do, done 57 * finish implementing reserved words: for, while, until, do, done
58 * finish implementing local variable assignment
59 * change { and } from special chars to reserved words 58 * change { and } from special chars to reserved words
60 * builtins: break, continue, eval, return, set, trap, ulimit 59 * builtins: break, continue, eval, return, set, trap, ulimit
61 * test magic exec 60 * test magic exec
@@ -325,6 +324,7 @@ static int builtin_help(struct child_prog *child);
325static int builtin_jobs(struct child_prog *child); 324static int builtin_jobs(struct child_prog *child);
326static int builtin_pwd(struct child_prog *child); 325static int builtin_pwd(struct child_prog *child);
327static int builtin_read(struct child_prog *child); 326static int builtin_read(struct child_prog *child);
327static int builtin_set(struct child_prog *child);
328static int builtin_shift(struct child_prog *child); 328static int builtin_shift(struct child_prog *child);
329static int builtin_source(struct child_prog *child); 329static int builtin_source(struct child_prog *child);
330static int builtin_umask(struct child_prog *child); 330static int builtin_umask(struct child_prog *child);
@@ -388,6 +388,11 @@ static void checkjobs();
388static void insert_bg_job(struct pipe *pi); 388static void insert_bg_job(struct pipe *pi);
389static void remove_bg_job(struct pipe *pi); 389static void remove_bg_job(struct pipe *pi);
390static void free_pipe(struct pipe *pi); 390static void free_pipe(struct pipe *pi);
391/* local variable support */
392static char *get_local_var(const char *var);
393static int set_local_var(const char *s);
394static void unset_local_var(const char *name);
395
391 396
392/* Table of built-in functions. They can be forked or not, depending on 397/* Table of built-in functions. They can be forked or not, depending on
393 * context: within pipes, they fork. As simple commands, they do not. 398 * context: within pipes, they fork. As simple commands, they do not.
@@ -402,7 +407,8 @@ static struct built_in_command bltins[] = {
402 {"continue", "Continue for, while or until loop", builtin_not_written}, 407 {"continue", "Continue for, while or until loop", builtin_not_written},
403 {"env", "Print all environment variables", builtin_env}, 408 {"env", "Print all environment variables", builtin_env},
404 {"eval", "Construct and run shell command", builtin_not_written}, 409 {"eval", "Construct and run shell command", builtin_not_written},
405 {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec}, 410 {"exec", "Exec command, replacing this shell with the exec'd process",
411 builtin_exec},
406 {"exit", "Exit from shell()", builtin_exit}, 412 {"exit", "Exit from shell()", builtin_exit},
407 {"export", "Set environment variable", builtin_export}, 413 {"export", "Set environment variable", builtin_export},
408 {"fg", "Bring job into the foreground", builtin_fg_bg}, 414 {"fg", "Bring job into the foreground", builtin_fg_bg},
@@ -410,7 +416,7 @@ static struct built_in_command bltins[] = {
410 {"pwd", "Print current directory", builtin_pwd}, 416 {"pwd", "Print current directory", builtin_pwd},
411 {"read", "Input environment variable", builtin_read}, 417 {"read", "Input environment variable", builtin_read},
412 {"return", "Return from a function", builtin_not_written}, 418 {"return", "Return from a function", builtin_not_written},
413 {"set", "Set/unset shell options", builtin_not_written}, 419 {"set", "Set/unset shell local variables", builtin_set},
414 {"shift", "Shift positional parameters", builtin_shift}, 420 {"shift", "Shift positional parameters", builtin_shift},
415 {"trap", "Trap signals", builtin_not_written}, 421 {"trap", "Trap signals", builtin_not_written},
416 {"ulimit","Controls resource limits", builtin_not_written}, 422 {"ulimit","Controls resource limits", builtin_not_written},
@@ -472,16 +478,41 @@ static int builtin_exit(struct child_prog *child)
472static int builtin_export(struct child_prog *child) 478static int builtin_export(struct child_prog *child)
473{ 479{
474 int res; 480 int res;
481 char *value, *name = child->argv[1];
475 482
476 if (child->argv[1] == NULL) { 483 if (name == NULL) {
477 return (builtin_env(child)); 484 return (builtin_env(child));
478 } 485 }
479 /* FIXME -- I leak memory. This will be 486
480 * fixed up properly when we add local 487 value = strchr(name, '=');
481 * variable support -- I hope */ 488 if (!value) {
482 res = putenv(strdup(child->argv[1])); 489 /* They are exporting something without an =VALUE.
490 * Assume this is a local shell variable they are exporting */
491 name = get_local_var(name);
492 if (! name ) {
493 error_msg("export failed");
494 return (EXIT_FAILURE);
495 }
496 /* FIXME -- I leak memory!!!!! */
497 value = malloc(strlen(child->argv[1]) + strlen(name) + 2);
498 sprintf(value, "%s=%s", child->argv[1], name);
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);
483 if (res) 514 if (res)
484 fprintf(stderr, "export: %s\n", strerror(errno)); 515 perror_msg("export");
485 return (res); 516 return (res);
486} 517}
487 518
@@ -616,6 +647,27 @@ static int builtin_read(struct child_prog *child)
616 return (res); 647 return (res);
617} 648}
618 649
650/* built-in 'set VAR=value' handler */
651static int builtin_set(struct child_prog *child)
652{
653 int res;
654 char *temp = child->argv[1];
655
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;
663 }
664 res = set_local_var(temp);
665 if (res)
666 fprintf(stderr, "set: %s\n", strerror(errno));
667 return (res);
668}
669
670
619/* Built-in 'shift' handler */ 671/* Built-in 'shift' handler */
620static int builtin_shift(struct child_prog *child) 672static int builtin_shift(struct child_prog *child)
621{ 673{
@@ -685,6 +737,7 @@ static int builtin_unset(struct child_prog *child)
685 return EXIT_FAILURE; 737 return EXIT_FAILURE;
686 } 738 }
687 unsetenv(child->argv[1]); 739 unsetenv(child->argv[1]);
740 unset_local_var(child->argv[1]);
688 return EXIT_SUCCESS; 741 return EXIT_SUCCESS;
689} 742}
690 743
@@ -1610,7 +1663,27 @@ static int xglob(o_string *dest, int flags, glob_t *pglob)
1610 return gr; 1663 return gr;
1611} 1664}
1612 1665
1613/* This is used to set local variables (i.e. stuff not going into the environment) */ 1666/* This is used to get/check local shell variables */
1667static char *get_local_var(const char *s)
1668{
1669 char **p;
1670 int len;
1671
1672 if (!s)
1673 return NULL;
1674 if (!__shell_local_env)
1675 return NULL;
1676 len = strlen(s);
1677
1678 for (p = __shell_local_env; *p; p++) {
1679 if (memcmp(s, *p, len) == 0 && (*p)[len] == '=') {
1680 return *p + len + 1;
1681 }
1682 }
1683 return NULL;
1684}
1685
1686/* This is used to set local shell variables */
1614static int set_local_var(const char *s) 1687static int set_local_var(const char *s)
1615{ 1688{
1616 char **ep; 1689 char **ep;
@@ -1653,7 +1726,8 @@ static int set_local_var(const char *s)
1653 result = -1; 1726 result = -1;
1654 goto done_already; 1727 goto done_already;
1655 } 1728 }
1656 memcpy((__ptr_t) new_environ, (__ptr_t) __shell_local_env, size * sizeof(char *)); 1729 memcpy((__ptr_t) new_environ, (__ptr_t) __shell_local_env,
1730 size * sizeof(char *));
1657 1731
1658 new_environ[size] = malloc (namelen + 1 + vallen + 1); 1732 new_environ[size] = malloc (namelen + 1 + vallen + 1);
1659 if (new_environ[size] == NULL) { 1733 if (new_environ[size] == NULL) {
@@ -1688,26 +1762,35 @@ static int set_local_var(const char *s)
1688 memcpy (&(*ep)[namelen + 1], value, vallen + 1); 1762 memcpy (&(*ep)[namelen + 1], value, vallen + 1);
1689 } 1763 }
1690 1764
1765 /* One last little detail... If this variable is already
1766 * in the environment we must set it there as well... */
1767 tmp = getenv(name);
1768 if (tmp) {
1769 /* FIXME -- I leak memory!!!!! */
1770 putenv(strdup(s));
1771 }
1772
1691done_already: 1773done_already:
1692 free(name); 1774 free(name);
1693 return result; 1775 return result;
1694} 1776}
1695 1777
1696char *get_local_var(const char *var) 1778static void unset_local_var(const char *name)
1697{ 1779{
1698 char **p; 1780 char **ep, **dp;
1699 int len; 1781 size_t namelen;
1700
1701 len = strlen(var);
1702
1703 if (!__shell_local_env)
1704 return 0;
1705 1782
1706 for (p = __shell_local_env; *p; p++) { 1783 if (!name)
1707 if (memcmp(var, *p, len) == 0 && (*p)[len] == '=') 1784 return;
1708 return *p + len + 1; 1785 namelen = strlen(name);
1786 for (dp = ep = __shell_local_env; ep && *ep != NULL; ++ep) {
1787 if (memcmp (*ep, name, namelen)==0 && (*ep)[namelen] == '=') {
1788 *dp = *ep;
1789 ++dp;
1790 *ep = NULL;
1791 break;
1792 }
1709 } 1793 }
1710 return 0;
1711} 1794}
1712 1795
1713static int is_assignment(const char *s) 1796static int is_assignment(const char *s)
@@ -2112,8 +2195,9 @@ static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src)
2112{ 2195{
2113 const char *p=NULL; 2196 const char *p=NULL;
2114 if (src->data) { 2197 if (src->data) {
2115 p = get_local_var(src->data); 2198 p = getenv(src->data);
2116 if (!p) p = getenv(src->data); 2199 if (!p)
2200 p = get_local_var(src->data);
2117 } 2201 }
2118 if (p) parse_string(dest, ctx, p); /* recursion */ 2202 if (p) parse_string(dest, ctx, p); /* recursion */
2119 b_free(src); 2203 b_free(src);