diff options
Diffstat (limited to 'shell/hush.c')
-rw-r--r-- | shell/hush.c | 53 |
1 files changed, 41 insertions, 12 deletions
diff --git a/shell/hush.c b/shell/hush.c index d086526..d59a5de 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1253,10 +1253,10 @@ static const char *get_local_var_value(const char *src) /* str holds "NAME=VAL" and is expected to be malloced. * We take ownership of it. * flg_export: - * 0: do not export - * 1: export - * -1: if NAME is set, leave export status alone - * if NAME is not set, do not export + * 0: do not change export flag + * (if creating new variable, flag will be 0) + * 1: set export flag and putenv the variable + * -1: clear export flag and unsetenv the variable * flg_read_only is set only when we handle -R var=val */ #if BB_MMU @@ -1297,6 +1297,7 @@ static int set_local_var(char *str, int flg_export, int flg_read_only) free(str); return -1; } +//TODO: optimize out redundant unsetenv/putenv's? debug_printf_env("%s: unsetenv '%s'\n", __func__, str); unsetenv(str); /* just in case */ *value = '='; @@ -1331,8 +1332,13 @@ static int set_local_var(char *str, int flg_export, int flg_read_only) if (flg_export == 1) cur->flg_export = 1; if (cur->flg_export) { - debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr); - return putenv(cur->varstr); + if (flg_export == -1) { + cur->flg_export = 0; + /* unsetenv was already done */ + } else { + debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr); + return putenv(cur->varstr); + } } return 0; } @@ -2214,7 +2220,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) val = NULL; } else { char *new_var = xasprintf("%s=%s", var, val); - set_local_var(new_var, -1, 0); + set_local_var(new_var, 0, 0); } } } @@ -6400,7 +6406,9 @@ static void print_escaped(const char *s) static int builtin_export(char **argv) { - if (*++argv == NULL) { + unsigned opt_unexport; + + if (argv[1] == NULL) { char **e = environ; if (e) { while (*e) { @@ -6426,15 +6434,33 @@ static int builtin_export(char **argv) return EXIT_SUCCESS; } +#if ENABLE_HUSH_EXPORT_N + opt_unexport = getopt32(argv, "+n"); /* "+": stop at 1st non-option */ + argv += optind; +#else + opt_unexport = 0; + argv++; +#endif + do { char *name = *argv; - /* So far we do not check that name is valid */ + /* So far we do not check that name is valid (TODO?) */ + if (strchr(name, '=') == NULL) { - /* Exporting a name without a =VALUE */ struct variable *var; var = get_local_var(name); + if (opt_unexport) { + /* export -n NAME (without =VALUE) */ + if (var) { + var->flg_export = 0; + debug_printf_env("%s: unsetenv '%s'\n", __func__, name); + unsetenv(name); + } /* else: export -n NOT_EXISTING_VAR: no-op */ + continue; + } + /* export NAME (without =VALUE) */ if (var) { var->flg_export = 1; debug_printf_env("%s: putenv '%s'\n", __func__, var->varstr); @@ -6448,10 +6474,13 @@ static int builtin_export(char **argv) * We just set it to "" and export. */ name = xasprintf("%s=", name); } else { - /* Exporting VAR=VALUE */ + /* (Un)exporting NAME=VALUE */ name = xstrdup(name); } - set_local_var(name, 1, 0); + set_local_var(name, + /*export:*/ (opt_unexport ? -1 : 1), + /*readonly:*/ 0 + ); } while (*++argv); return EXIT_SUCCESS; |