aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-07-17 21:10:50 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-07-17 21:10:50 +0200
commit1e660422b16510f8bcdb764d632bb1da391c4a35 (patch)
tree8da138bec87d5b823b46797cb82ef28ca4e224c9
parent826360ff238eb23191950dd4c5051195eab9733a (diff)
downloadbusybox-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.c99
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
965static int builtin_export(char **argv) FAST_FUNC; 970static int builtin_export(char **argv) FAST_FUNC;
966#endif 971#endif
972#if ENABLE_HUSH_READONLY
973static int builtin_readonly(char **argv) FAST_FUNC;
974#endif
967#if ENABLE_HUSH_JOB 975#if ENABLE_HUSH_JOB
968static int builtin_fg_bg(char **argv) FAST_FUNC; 976static int builtin_fg_bg(char **argv) FAST_FUNC;
969static int builtin_jobs(char **argv) FAST_FUNC; 977static 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 2066static 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
2067static 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 9314static 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)
9316static 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
9440static 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 */
9435static int FAST_FUNC builtin_unset(char **argv) 9462static int FAST_FUNC builtin_unset(char **argv)