diff options
author | andersen <andersen@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2001-05-15 23:21:41 +0000 |
---|---|---|
committer | andersen <andersen@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2001-05-15 23:21:41 +0000 |
commit | 6d8030f99aa680856a2c9a7ea3582d73961f085f (patch) | |
tree | 5554e694d9363f88a0b11fa78cfd72fe25d3b537 /shell | |
parent | 0b0f359bfec843349d7603541e9c6e0ab635851e (diff) | |
download | busybox-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.c | 134 |
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); | |||
325 | static int builtin_jobs(struct child_prog *child); | 324 | static int builtin_jobs(struct child_prog *child); |
326 | static int builtin_pwd(struct child_prog *child); | 325 | static int builtin_pwd(struct child_prog *child); |
327 | static int builtin_read(struct child_prog *child); | 326 | static int builtin_read(struct child_prog *child); |
327 | static int builtin_set(struct child_prog *child); | ||
328 | static int builtin_shift(struct child_prog *child); | 328 | static int builtin_shift(struct child_prog *child); |
329 | static int builtin_source(struct child_prog *child); | 329 | static int builtin_source(struct child_prog *child); |
330 | static int builtin_umask(struct child_prog *child); | 330 | static int builtin_umask(struct child_prog *child); |
@@ -388,6 +388,11 @@ static void checkjobs(); | |||
388 | static void insert_bg_job(struct pipe *pi); | 388 | static void insert_bg_job(struct pipe *pi); |
389 | static void remove_bg_job(struct pipe *pi); | 389 | static void remove_bg_job(struct pipe *pi); |
390 | static void free_pipe(struct pipe *pi); | 390 | static void free_pipe(struct pipe *pi); |
391 | /* local variable support */ | ||
392 | static char *get_local_var(const char *var); | ||
393 | static int set_local_var(const char *s); | ||
394 | static 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) | |||
472 | static int builtin_export(struct child_prog *child) | 478 | static 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 */ | ||
651 | static 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 */ |
620 | static int builtin_shift(struct child_prog *child) | 672 | static 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 */ |
1667 | static 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 */ | ||
1614 | static int set_local_var(const char *s) | 1687 | static 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 | |||
1691 | done_already: | 1773 | done_already: |
1692 | free(name); | 1774 | free(name); |
1693 | return result; | 1775 | return result; |
1694 | } | 1776 | } |
1695 | 1777 | ||
1696 | char *get_local_var(const char *var) | 1778 | static 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 | ||
1713 | static int is_assignment(const char *s) | 1796 | static 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); |