diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-07-17 21:10:50 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-07-17 21:10:50 +0200 |
commit | 1e660422b16510f8bcdb764d632bb1da391c4a35 (patch) | |
tree | 8da138bec87d5b823b46797cb82ef28ca4e224c9 | |
parent | 826360ff238eb23191950dd4c5051195eab9733a (diff) | |
download | busybox-w32-1e660422b16510f8bcdb764d632bb1da391c4a35.tar.gz busybox-w32-1e660422b16510f8bcdb764d632bb1da391c4a35.tar.bz2 busybox-w32-1e660422b16510f8bcdb764d632bb1da391c4a35.zip |
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>
-rw-r--r-- | shell/hush.c | 99 |
1 files changed, 63 insertions, 36 deletions
diff --git a/shell/hush.c b/shell/hush.c index c8356f4b8..a68986329 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -48,7 +48,7 @@ | |||
48 | * tilde expansion | 48 | * tilde expansion |
49 | * aliases | 49 | * aliases |
50 | * builtins mandated by standards we don't support: | 50 | * builtins mandated by standards we don't support: |
51 | * [un]alias, command, fc, getopts, readonly, times: | 51 | * [un]alias, command, fc, getopts, times: |
52 | * command -v CMD: print "/path/to/CMD" | 52 | * command -v CMD: print "/path/to/CMD" |
53 | * prints "CMD" for builtins | 53 | * prints "CMD" for builtins |
54 | * prints "alias ALIAS='EXPANSION'" for aliases | 54 | * prints "alias ALIAS='EXPANSION'" for aliases |
@@ -57,8 +57,7 @@ | |||
57 | * command [-p] CMD: run CMD, even if a function CMD also exists | 57 | * command [-p] CMD: run CMD, even if a function CMD also exists |
58 | * (can use this to override standalone shell as well) | 58 | * (can use this to override standalone shell as well) |
59 | * -p: use default $PATH | 59 | * -p: use default $PATH |
60 | * readonly VAR[=VAL]...: make VARs readonly | 60 | * command BLTIN: disables special-ness (e.g. errors do not abort) |
61 | * readonly [-p]: list all such VARs (-p has no effect in bash) | ||
62 | * getopts: getopt() for shells | 61 | * getopts: getopt() for shells |
63 | * times: print getrusage(SELF/CHILDREN).ru_utime/ru_stime | 62 | * times: print getrusage(SELF/CHILDREN).ru_utime/ru_stime |
64 | * fc -l[nr] [BEG] [END]: list range of commands in history | 63 | * fc -l[nr] [BEG] [END]: list range of commands in history |
@@ -239,6 +238,12 @@ | |||
239 | //config: help | 238 | //config: help |
240 | //config: export -n unexports variables. It is a bash extension. | 239 | //config: export -n unexports variables. It is a bash extension. |
241 | //config: | 240 | //config: |
241 | //config:config HUSH_READONLY | ||
242 | //config: bool "readonly builtin" | ||
243 | //config: default y | ||
244 | //config: help | ||
245 | //config: Enable support for read-only variables. | ||
246 | //config: | ||
242 | //config:config HUSH_KILL | 247 | //config:config HUSH_KILL |
243 | //config: bool "kill builtin (supports kill %jobspec)" | 248 | //config: bool "kill builtin (supports kill %jobspec)" |
244 | //config: default y | 249 | //config: default y |
@@ -964,6 +969,9 @@ static int builtin_exit(char **argv) FAST_FUNC; | |||
964 | #if ENABLE_HUSH_EXPORT | 969 | #if ENABLE_HUSH_EXPORT |
965 | static int builtin_export(char **argv) FAST_FUNC; | 970 | static int builtin_export(char **argv) FAST_FUNC; |
966 | #endif | 971 | #endif |
972 | #if ENABLE_HUSH_READONLY | ||
973 | static int builtin_readonly(char **argv) FAST_FUNC; | ||
974 | #endif | ||
967 | #if ENABLE_HUSH_JOB | 975 | #if ENABLE_HUSH_JOB |
968 | static int builtin_fg_bg(char **argv) FAST_FUNC; | 976 | static int builtin_fg_bg(char **argv) FAST_FUNC; |
969 | static int builtin_jobs(char **argv) FAST_FUNC; | 977 | static int builtin_jobs(char **argv) FAST_FUNC; |
@@ -1082,6 +1090,9 @@ static const struct built_in_command bltins1[] = { | |||
1082 | #if ENABLE_HUSH_READ | 1090 | #if ENABLE_HUSH_READ |
1083 | BLTIN("read" , builtin_read , "Input into variable"), | 1091 | BLTIN("read" , builtin_read , "Input into variable"), |
1084 | #endif | 1092 | #endif |
1093 | #if ENABLE_HUSH_READONLY | ||
1094 | BLTIN("readonly" , builtin_readonly, "Make variables read-only"), | ||
1095 | #endif | ||
1085 | #if ENABLE_HUSH_FUNCTIONS | 1096 | #if ENABLE_HUSH_FUNCTIONS |
1086 | BLTIN("return" , builtin_return , "Return from function"), | 1097 | BLTIN("return" , builtin_return , "Return from function"), |
1087 | #endif | 1098 | #endif |
@@ -2052,19 +2063,10 @@ static const char* FAST_FUNC get_local_var_value(const char *name) | |||
2052 | * -1: clear export flag and unsetenv the variable | 2063 | * -1: clear export flag and unsetenv the variable |
2053 | * flg_read_only is set only when we handle -R var=val | 2064 | * flg_read_only is set only when we handle -R var=val |
2054 | */ | 2065 | */ |
2055 | #if !BB_MMU && ENABLE_HUSH_LOCAL | 2066 | static int set_local_var(char *str, |
2056 | /* all params are used */ | 2067 | int flg_export UNUSED_PARAM, |
2057 | #elif BB_MMU && ENABLE_HUSH_LOCAL | 2068 | int local_lvl UNUSED_PARAM, |
2058 | #define set_local_var(str, flg_export, local_lvl, flg_read_only) \ | 2069 | int flg_read_only UNUSED_PARAM) |
2059 | set_local_var(str, flg_export, local_lvl) | ||
2060 | #elif BB_MMU && !ENABLE_HUSH_LOCAL | ||
2061 | #define set_local_var(str, flg_export, local_lvl, flg_read_only) \ | ||
2062 | set_local_var(str, flg_export) | ||
2063 | #elif !BB_MMU && !ENABLE_HUSH_LOCAL | ||
2064 | #define set_local_var(str, flg_export, local_lvl, flg_read_only) \ | ||
2065 | set_local_var(str, flg_export, flg_read_only) | ||
2066 | #endif | ||
2067 | static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_only) | ||
2068 | { | 2070 | { |
2069 | struct variable **var_pp; | 2071 | struct variable **var_pp; |
2070 | struct variable *cur; | 2072 | struct variable *cur; |
@@ -2088,9 +2090,7 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_ | |||
2088 | 2090 | ||
2089 | /* We found an existing var with this name */ | 2091 | /* We found an existing var with this name */ |
2090 | if (cur->flg_read_only) { | 2092 | if (cur->flg_read_only) { |
2091 | #if !BB_MMU | ||
2092 | if (!flg_read_only) | 2093 | if (!flg_read_only) |
2093 | #endif | ||
2094 | bb_error_msg("%s: readonly variable", str); | 2094 | bb_error_msg("%s: readonly variable", str); |
2095 | free(str); | 2095 | free(str); |
2096 | return -1; | 2096 | return -1; |
@@ -2158,10 +2158,12 @@ static int set_local_var(char *str, int flg_export, int local_lvl, int flg_read_ | |||
2158 | 2158 | ||
2159 | set_str_and_exp: | 2159 | set_str_and_exp: |
2160 | cur->varstr = str; | 2160 | cur->varstr = str; |
2161 | #if !BB_MMU | ||
2162 | cur->flg_read_only = flg_read_only; | ||
2163 | #endif | ||
2164 | exp: | 2161 | exp: |
2162 | #if !BB_MMU || ENABLE_HUSH_READONLY | ||
2163 | if (flg_read_only != 0) { | ||
2164 | cur->flg_read_only = flg_read_only; | ||
2165 | } | ||
2166 | #endif | ||
2165 | if (flg_export == 1) | 2167 | if (flg_export == 1) |
2166 | cur->flg_export = 1; | 2168 | cur->flg_export = 1; |
2167 | if (name_len == 4 && cur->varstr[0] == 'P' && cur->varstr[1] == 'S') | 2169 | if (name_len == 4 && cur->varstr[0] == 'P' && cur->varstr[1] == 'S') |
@@ -9308,12 +9310,11 @@ static void print_escaped(const char *s) | |||
9308 | } | 9310 | } |
9309 | #endif | 9311 | #endif |
9310 | 9312 | ||
9311 | #if ENABLE_HUSH_EXPORT || ENABLE_HUSH_LOCAL | 9313 | #if ENABLE_HUSH_EXPORT || ENABLE_HUSH_LOCAL || ENABLE_HUSH_READONLY |
9312 | # if !ENABLE_HUSH_LOCAL | 9314 | static int helper_export_local(char **argv, |
9313 | #define helper_export_local(argv, exp, lvl) \ | 9315 | int exp UNUSED_PARAM, |
9314 | helper_export_local(argv, exp) | 9316 | int ro UNUSED_PARAM, |
9315 | # endif | 9317 | int lvl UNUSED_PARAM) |
9316 | static void helper_export_local(char **argv, int exp, int lvl) | ||
9317 | { | 9318 | { |
9318 | do { | 9319 | do { |
9319 | char *name = *argv; | 9320 | char *name = *argv; |
@@ -9346,7 +9347,7 @@ static void helper_export_local(char **argv, int exp, int lvl) | |||
9346 | } | 9347 | } |
9347 | } | 9348 | } |
9348 | # if ENABLE_HUSH_LOCAL | 9349 | # if ENABLE_HUSH_LOCAL |
9349 | if (exp == 0 /* local? */ | 9350 | if (exp == 0 && ro == 0 /* local? */ |
9350 | && var && var->func_nest_level == lvl | 9351 | && var && var->func_nest_level == lvl |
9351 | ) { | 9352 | ) { |
9352 | /* "local x=abc; ...; local x" - ignore second local decl */ | 9353 | /* "local x=abc; ...; local x" - ignore second local decl */ |
@@ -9357,16 +9358,23 @@ static void helper_export_local(char **argv, int exp, int lvl) | |||
9357 | * bash does not put it in environment, | 9358 | * bash does not put it in environment, |
9358 | * but remembers that it is exported, | 9359 | * but remembers that it is exported, |
9359 | * and does put it in env when it is set later. | 9360 | * and does put it in env when it is set later. |
9360 | * We just set it to "" and export. */ | 9361 | * We just set it to "" and export. |
9362 | */ | ||
9361 | /* Or, it's "local NAME" (without =VALUE). | 9363 | /* Or, it's "local NAME" (without =VALUE). |
9362 | * bash sets the value to "". */ | 9364 | * bash sets the value to "". |
9365 | */ | ||
9366 | /* Or, it's "readonly NAME" (without =VALUE). | ||
9367 | * bash remembers NAME and disallows its creation | ||
9368 | * in the future. | ||
9369 | */ | ||
9363 | name = xasprintf("%s=", name); | 9370 | name = xasprintf("%s=", name); |
9364 | } else { | 9371 | } else { |
9365 | /* (Un)exporting/making local NAME=VALUE */ | 9372 | /* (Un)exporting/making local NAME=VALUE */ |
9366 | name = xstrdup(name); | 9373 | name = xstrdup(name); |
9367 | } | 9374 | } |
9368 | set_local_var(name, /*exp:*/ exp, /*lvl:*/ lvl, /*ro:*/ 0); | 9375 | set_local_var(name, /*exp:*/ exp, /*lvl:*/ lvl, /*ro:*/ ro); |
9369 | } while (*++argv); | 9376 | } while (*++argv); |
9377 | return EXIT_SUCCESS; | ||
9370 | } | 9378 | } |
9371 | #endif | 9379 | #endif |
9372 | 9380 | ||
@@ -9412,9 +9420,7 @@ static int FAST_FUNC builtin_export(char **argv) | |||
9412 | return EXIT_SUCCESS; | 9420 | return EXIT_SUCCESS; |
9413 | } | 9421 | } |
9414 | 9422 | ||
9415 | helper_export_local(argv, (opt_unexport ? -1 : 1), 0); | 9423 | return helper_export_local(argv, /*exp:*/ (opt_unexport ? -1 : 1), /*ro:*/ 0, /*lvl:*/ 0); |
9416 | |||
9417 | return EXIT_SUCCESS; | ||
9418 | } | 9424 | } |
9419 | #endif | 9425 | #endif |
9420 | 9426 | ||
@@ -9425,11 +9431,32 @@ static int FAST_FUNC builtin_local(char **argv) | |||
9425 | bb_error_msg("%s: not in a function", argv[0]); | 9431 | bb_error_msg("%s: not in a function", argv[0]); |
9426 | return EXIT_FAILURE; /* bash compat */ | 9432 | return EXIT_FAILURE; /* bash compat */ |
9427 | } | 9433 | } |
9428 | helper_export_local(argv, 0, G.func_nest_level); | 9434 | argv++; |
9429 | return EXIT_SUCCESS; | 9435 | return helper_export_local(argv, /*exp:*/ 0, /*ro:*/ 0, /*lvl:*/ G.func_nest_level); |
9430 | } | 9436 | } |
9431 | #endif | 9437 | #endif |
9432 | 9438 | ||
9439 | #if ENABLE_HUSH_READONLY | ||
9440 | static int FAST_FUNC builtin_readonly(char **argv) | ||
9441 | { | ||
9442 | if (*++argv == NULL) { | ||
9443 | /* bash: readonly [-p]: list all readonly VARs | ||
9444 | * (-p has no effect in bash) | ||
9445 | */ | ||
9446 | struct variable *e; | ||
9447 | for (e = G.top_var; e; e = e->next) { | ||
9448 | if (e->flg_read_only) { | ||
9449 | //TODO: quote value: readonly VAR='VAL' | ||
9450 | printf("readonly %s\n", e->varstr); | ||
9451 | } | ||
9452 | } | ||
9453 | return EXIT_SUCCESS; | ||
9454 | } | ||
9455 | return helper_export_local(argv, /*exp:*/ 0, /*ro:*/ 1, /*lvl:*/ 0); | ||
9456 | } | ||
9457 | #endif | ||
9458 | |||
9459 | |||
9433 | #if ENABLE_HUSH_UNSET | 9460 | #if ENABLE_HUSH_UNSET |
9434 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#unset */ | 9461 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#unset */ |
9435 | static int FAST_FUNC builtin_unset(char **argv) | 9462 | static int FAST_FUNC builtin_unset(char **argv) |