hush: implement "readonly" builtin
function old new delta builtin_readonly - 70 +70 helper_export_local 152 174 +22 bltins1 348 360 +12 expand_one_var 1620 1625 +5 builtin_export 168 173 +5 set_pwd_var 36 40 +4 set_local_var 410 414 +4 set_vars_and_save_old 85 88 +3 set_local_var_from_halves 24 27 +3 run_pipe 1551 1554 +3 run_list 1046 1048 +2 builtin_type 116 114 -2 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 10/1 up/down: 133/-2) Total: 131 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
826360ff23
commit
1e660422b1
99
shell/hush.c
99
shell/hush.c
@ -48,7 +48,7 @@
|
|||||||
* tilde expansion
|
* tilde expansion
|
||||||
* aliases
|
* aliases
|
||||||
* builtins mandated by standards we don't support:
|
* builtins mandated by standards we don't support:
|
||||||
* [un]alias, command, fc, getopts, readonly, times:
|
* [un]alias, command, fc, getopts, times:
|
||||||
* command -v CMD: print "/path/to/CMD"
|
* command -v CMD: print "/path/to/CMD"
|
||||||
* prints "CMD" for builtins
|
* prints "CMD" for builtins
|
||||||
* prints "alias ALIAS='EXPANSION'" for aliases
|
* prints "alias ALIAS='EXPANSION'" for aliases
|
||||||
@ -57,8 +57,7 @@
|
|||||||
* command [-p] CMD: run CMD, even if a function CMD also exists
|
* command [-p] CMD: run CMD, even if a function CMD also exists
|
||||||
* (can use this to override standalone shell as well)
|
* (can use this to override standalone shell as well)
|
||||||
* -p: use default $PATH
|
* -p: use default $PATH
|
||||||
* readonly VAR[=VAL]...: make VARs readonly
|
* command BLTIN: disables special-ness (e.g. errors do not abort)
|
||||||
* readonly [-p]: list all such VARs (-p has no effect in bash)
|
|
||||||
* getopts: getopt() for shells
|
* getopts: getopt() for shells
|
||||||
* times: print getrusage(SELF/CHILDREN).ru_utime/ru_stime
|
* times: print getrusage(SELF/CHILDREN).ru_utime/ru_stime
|
||||||
* fc -l[nr] [BEG] [END]: list range of commands in history
|
* fc -l[nr] [BEG] [END]: list range of commands in history
|
||||||
@ -239,6 +238,12 @@
|
|||||||
//config: help
|
//config: help
|
||||||
//config: export -n unexports variables. It is a bash extension.
|
//config: export -n unexports variables. It is a bash extension.
|
||||||
//config:
|
//config:
|
||||||
|
//config:config HUSH_READONLY
|
||||||
|
//config: bool "readonly builtin"
|
||||||
|
//config: default y
|
||||||
|
//config: help
|
||||||
|
//config: Enable support for read-only variables.
|
||||||
|
//config:
|
||||||
//config:config HUSH_KILL
|
//config:config HUSH_KILL
|
||||||
//config: bool "kill builtin (supports kill %jobspec)"
|
//config: bool "kill builtin (supports kill %jobspec)"
|
||||||
//config: default y
|
//config: default y
|
||||||
@ -964,6 +969,9 @@ static int builtin_exit(char **argv) FAST_FUNC;
|
|||||||
#if ENABLE_HUSH_EXPORT
|
#if ENABLE_HUSH_EXPORT
|
||||||
static int builtin_export(char **argv) FAST_FUNC;
|
static int builtin_export(char **argv) FAST_FUNC;
|
||||||
#endif
|
#endif
|
||||||
|
#if ENABLE_HUSH_READONLY
|
||||||
|
static int builtin_readonly(char **argv) FAST_FUNC;
|
||||||
|
#endif
|
||||||
#if ENABLE_HUSH_JOB
|
#if ENABLE_HUSH_JOB
|
||||||
static int builtin_fg_bg(char **argv) FAST_FUNC;
|
static int builtin_fg_bg(char **argv) FAST_FUNC;
|
||||||
static int builtin_jobs(char **argv) FAST_FUNC;
|
static int builtin_jobs(char **argv) FAST_FUNC;
|
||||||
@ -1082,6 +1090,9 @@ static const struct built_in_command bltins1[] = {
|
|||||||
#if ENABLE_HUSH_READ
|
#if ENABLE_HUSH_READ
|
||||||
BLTIN("read" , builtin_read , "Input into variable"),
|
BLTIN("read" , builtin_read , "Input into variable"),
|
||||||
#endif
|
#endif
|
||||||
|
#if ENABLE_HUSH_READONLY
|
||||||
|
BLTIN("readonly" , builtin_readonly, "Make variables read-only"),
|
||||||
|
#endif
|
||||||
#if ENABLE_HUSH_FUNCTIONS
|
#if ENABLE_HUSH_FUNCTIONS
|
||||||
BLTIN("return" , builtin_return , "Return from function"),
|
BLTIN("return" , builtin_return , "Return from function"),
|
||||||
#endif
|
#endif
|
||||||
@ -2052,19 +2063,10 @@ static const char* FAST_FUNC get_local_var_value(const char *name)
|
|||||||
* -1: clear export flag and unsetenv the variable
|
* -1: clear export flag and unsetenv the variable
|
||||||
* flg_read_only is set only when we handle -R var=val
|
* flg_read_only is set only when we handle -R var=val
|
||||||
*/
|
*/
|
||||||
#if !BB_MMU && ENABLE_HUSH_LOCAL
|
static int set_local_var(char *str,
|
||||||
/* all params are used */
|
int flg_export UNUSED_PARAM,
|
||||||
#elif BB_MMU && ENABLE_HUSH_LOCAL
|
int local_lvl UNUSED_PARAM,
|
||||||
#define set_local_var(str, flg_export, local_lvl, flg_read_only) \
|
int flg_read_only UNUSED_PARAM)
|
||||||
set_local_var(str, flg_export, local_lvl)
|
|
||||||
#elif BB_MMU && !ENABLE_HUSH_LOCAL
|
|
||||||
#define set_local_var(str, flg_export, local_lvl, flg_read_only) \
|
|
||||||
set_local_var(str, flg_export)
|
|
||||||
#elif !BB_MMU && !ENABLE_HUSH_LOCAL
|
|
||||||
#define set_local_var(str, flg_export, local_lvl, flg_read_only) \
|
|
||||||
set_local_var(str, flg_export, flg_read_only)
|
|
||||||
#endif
|
|
||||||
static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_only)
|
|
||||||
{
|
{
|
||||||
struct variable **var_pp;
|
struct variable **var_pp;
|
||||||
struct variable *cur;
|
struct variable *cur;
|
||||||
@ -2088,9 +2090,7 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_
|
|||||||
|
|
||||||
/* We found an existing var with this name */
|
/* We found an existing var with this name */
|
||||||
if (cur->flg_read_only) {
|
if (cur->flg_read_only) {
|
||||||
#if !BB_MMU
|
|
||||||
if (!flg_read_only)
|
if (!flg_read_only)
|
||||||
#endif
|
|
||||||
bb_error_msg("%s: readonly variable", str);
|
bb_error_msg("%s: readonly variable", str);
|
||||||
free(str);
|
free(str);
|
||||||
return -1;
|
return -1;
|
||||||
@ -2158,10 +2158,12 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_
|
|||||||
|
|
||||||
set_str_and_exp:
|
set_str_and_exp:
|
||||||
cur->varstr = str;
|
cur->varstr = str;
|
||||||
#if !BB_MMU
|
|
||||||
cur->flg_read_only = flg_read_only;
|
|
||||||
#endif
|
|
||||||
exp:
|
exp:
|
||||||
|
#if !BB_MMU || ENABLE_HUSH_READONLY
|
||||||
|
if (flg_read_only != 0) {
|
||||||
|
cur->flg_read_only = flg_read_only;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (flg_export == 1)
|
if (flg_export == 1)
|
||||||
cur->flg_export = 1;
|
cur->flg_export = 1;
|
||||||
if (name_len == 4 && cur->varstr[0] == 'P' && cur->varstr[1] == 'S')
|
if (name_len == 4 && cur->varstr[0] == 'P' && cur->varstr[1] == 'S')
|
||||||
@ -9308,12 +9310,11 @@ static void print_escaped(const char *s)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLE_HUSH_EXPORT || ENABLE_HUSH_LOCAL
|
#if ENABLE_HUSH_EXPORT || ENABLE_HUSH_LOCAL || ENABLE_HUSH_READONLY
|
||||||
# if !ENABLE_HUSH_LOCAL
|
static int helper_export_local(char **argv,
|
||||||
#define helper_export_local(argv, exp, lvl) \
|
int exp UNUSED_PARAM,
|
||||||
helper_export_local(argv, exp)
|
int ro UNUSED_PARAM,
|
||||||
# endif
|
int lvl UNUSED_PARAM)
|
||||||
static void helper_export_local(char **argv, int exp, int lvl)
|
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
char *name = *argv;
|
char *name = *argv;
|
||||||
@ -9346,7 +9347,7 @@ static void helper_export_local(char **argv, int exp, int lvl)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
# if ENABLE_HUSH_LOCAL
|
# if ENABLE_HUSH_LOCAL
|
||||||
if (exp == 0 /* local? */
|
if (exp == 0 && ro == 0 /* local? */
|
||||||
&& var && var->func_nest_level == lvl
|
&& var && var->func_nest_level == lvl
|
||||||
) {
|
) {
|
||||||
/* "local x=abc; ...; local x" - ignore second local decl */
|
/* "local x=abc; ...; local x" - ignore second local decl */
|
||||||
@ -9357,16 +9358,23 @@ static void helper_export_local(char **argv, int exp, int lvl)
|
|||||||
* bash does not put it in environment,
|
* bash does not put it in environment,
|
||||||
* but remembers that it is exported,
|
* but remembers that it is exported,
|
||||||
* and does put it in env when it is set later.
|
* and does put it in env when it is set later.
|
||||||
* We just set it to "" and export. */
|
* We just set it to "" and export.
|
||||||
|
*/
|
||||||
/* Or, it's "local NAME" (without =VALUE).
|
/* Or, it's "local NAME" (without =VALUE).
|
||||||
* bash sets the value to "". */
|
* bash sets the value to "".
|
||||||
|
*/
|
||||||
|
/* Or, it's "readonly NAME" (without =VALUE).
|
||||||
|
* bash remembers NAME and disallows its creation
|
||||||
|
* in the future.
|
||||||
|
*/
|
||||||
name = xasprintf("%s=", name);
|
name = xasprintf("%s=", name);
|
||||||
} else {
|
} else {
|
||||||
/* (Un)exporting/making local NAME=VALUE */
|
/* (Un)exporting/making local NAME=VALUE */
|
||||||
name = xstrdup(name);
|
name = xstrdup(name);
|
||||||
}
|
}
|
||||||
set_local_var(name, /*exp:*/ exp, /*lvl:*/ lvl, /*ro:*/ 0);
|
set_local_var(name, /*exp:*/ exp, /*lvl:*/ lvl, /*ro:*/ ro);
|
||||||
} while (*++argv);
|
} while (*++argv);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -9412,9 +9420,7 @@ static int FAST_FUNC builtin_export(char **argv)
|
|||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
helper_export_local(argv, (opt_unexport ? -1 : 1), 0);
|
return helper_export_local(argv, /*exp:*/ (opt_unexport ? -1 : 1), /*ro:*/ 0, /*lvl:*/ 0);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -9425,11 +9431,32 @@ static int FAST_FUNC builtin_local(char **argv)
|
|||||||
bb_error_msg("%s: not in a function", argv[0]);
|
bb_error_msg("%s: not in a function", argv[0]);
|
||||||
return EXIT_FAILURE; /* bash compat */
|
return EXIT_FAILURE; /* bash compat */
|
||||||
}
|
}
|
||||||
helper_export_local(argv, 0, G.func_nest_level);
|
argv++;
|
||||||
return EXIT_SUCCESS;
|
return helper_export_local(argv, /*exp:*/ 0, /*ro:*/ 0, /*lvl:*/ G.func_nest_level);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ENABLE_HUSH_READONLY
|
||||||
|
static int FAST_FUNC builtin_readonly(char **argv)
|
||||||
|
{
|
||||||
|
if (*++argv == NULL) {
|
||||||
|
/* bash: readonly [-p]: list all readonly VARs
|
||||||
|
* (-p has no effect in bash)
|
||||||
|
*/
|
||||||
|
struct variable *e;
|
||||||
|
for (e = G.top_var; e; e = e->next) {
|
||||||
|
if (e->flg_read_only) {
|
||||||
|
//TODO: quote value: readonly VAR='VAL'
|
||||||
|
printf("readonly %s\n", e->varstr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
return helper_export_local(argv, /*exp:*/ 0, /*ro:*/ 1, /*lvl:*/ 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if ENABLE_HUSH_UNSET
|
#if ENABLE_HUSH_UNSET
|
||||||
/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#unset */
|
/* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#unset */
|
||||||
static int FAST_FUNC builtin_unset(char **argv)
|
static int FAST_FUNC builtin_unset(char **argv)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user