diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2016-10-02 21:12:02 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-10-02 21:12:02 +0200 |
commit | 61508d9624703f2d0da8776e6a5e2333eadd5be9 (patch) | |
tree | 46ff0e0f9558af9b50011b4dfa07fecafa89d5a2 | |
parent | ebedb9478d0d91d8aecf28531907e3a277450d0d (diff) | |
download | busybox-w32-61508d9624703f2d0da8776e6a5e2333eadd5be9.tar.gz busybox-w32-61508d9624703f2d0da8776e6a5e2333eadd5be9.tar.bz2 busybox-w32-61508d9624703f2d0da8776e6a5e2333eadd5be9.zip |
hush: fix var3.tests
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | shell/hush.c | 420 | ||||
-rw-r--r-- | shell/hush_test/hush-vars/var3.is.in.bugs | 0 | ||||
-rw-r--r-- | shell/hush_test/hush-vars/var3.right (renamed from shell/hush_test/hush-bugs/var3.right) | 0 | ||||
-rwxr-xr-x | shell/hush_test/hush-vars/var3.tests (renamed from shell/hush_test/hush-bugs/var3.tests) | 0 |
4 files changed, 214 insertions, 206 deletions
diff --git a/shell/hush.c b/shell/hush.c index 8054d1d45..5990d690c 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -8733,6 +8733,14 @@ static void helper_export_local(char **argv, int exp, int lvl) | |||
8733 | continue; | 8733 | continue; |
8734 | } | 8734 | } |
8735 | } | 8735 | } |
8736 | #if ENABLE_HUSH_LOCAL | ||
8737 | if (exp == 0 /* local? */ | ||
8738 | && var && var->func_nest_level == lvl | ||
8739 | ) { | ||
8740 | /* "local x=abc; ...; local x" - ignore second local decl */ | ||
8741 | continue; | ||
8742 | } | ||
8743 | #endif | ||
8736 | /* Exporting non-existing variable. | 8744 | /* Exporting non-existing variable. |
8737 | * bash does not put it in environment, | 8745 | * bash does not put it in environment, |
8738 | * but remembers that it is exported, | 8746 | * but remembers that it is exported, |
@@ -8807,6 +8815,212 @@ static int FAST_FUNC builtin_local(char **argv) | |||
8807 | } | 8815 | } |
8808 | #endif | 8816 | #endif |
8809 | 8817 | ||
8818 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#unset */ | ||
8819 | static int FAST_FUNC builtin_unset(char **argv) | ||
8820 | { | ||
8821 | int ret; | ||
8822 | unsigned opts; | ||
8823 | |||
8824 | /* "!": do not abort on errors */ | ||
8825 | /* "+": stop at 1st non-option */ | ||
8826 | opts = getopt32(argv, "!+vf"); | ||
8827 | if (opts == (unsigned)-1) | ||
8828 | return EXIT_FAILURE; | ||
8829 | if (opts == 3) { | ||
8830 | bb_error_msg("unset: -v and -f are exclusive"); | ||
8831 | return EXIT_FAILURE; | ||
8832 | } | ||
8833 | argv += optind; | ||
8834 | |||
8835 | ret = EXIT_SUCCESS; | ||
8836 | while (*argv) { | ||
8837 | if (!(opts & 2)) { /* not -f */ | ||
8838 | if (unset_local_var(*argv)) { | ||
8839 | /* unset <nonexistent_var> doesn't fail. | ||
8840 | * Error is when one tries to unset RO var. | ||
8841 | * Message was printed by unset_local_var. */ | ||
8842 | ret = EXIT_FAILURE; | ||
8843 | } | ||
8844 | } | ||
8845 | #if ENABLE_HUSH_FUNCTIONS | ||
8846 | else { | ||
8847 | unset_func(*argv); | ||
8848 | } | ||
8849 | #endif | ||
8850 | argv++; | ||
8851 | } | ||
8852 | return ret; | ||
8853 | } | ||
8854 | |||
8855 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set | ||
8856 | * built-in 'set' handler | ||
8857 | * SUSv3 says: | ||
8858 | * set [-abCefhmnuvx] [-o option] [argument...] | ||
8859 | * set [+abCefhmnuvx] [+o option] [argument...] | ||
8860 | * set -- [argument...] | ||
8861 | * set -o | ||
8862 | * set +o | ||
8863 | * Implementations shall support the options in both their hyphen and | ||
8864 | * plus-sign forms. These options can also be specified as options to sh. | ||
8865 | * Examples: | ||
8866 | * Write out all variables and their values: set | ||
8867 | * Set $1, $2, and $3 and set "$#" to 3: set c a b | ||
8868 | * Turn on the -x and -v options: set -xv | ||
8869 | * Unset all positional parameters: set -- | ||
8870 | * Set $1 to the value of x, even if it begins with '-' or '+': set -- "$x" | ||
8871 | * Set the positional parameters to the expansion of x, even if x expands | ||
8872 | * with a leading '-' or '+': set -- $x | ||
8873 | * | ||
8874 | * So far, we only support "set -- [argument...]" and some of the short names. | ||
8875 | */ | ||
8876 | static int FAST_FUNC builtin_set(char **argv) | ||
8877 | { | ||
8878 | int n; | ||
8879 | char **pp, **g_argv; | ||
8880 | char *arg = *++argv; | ||
8881 | |||
8882 | if (arg == NULL) { | ||
8883 | struct variable *e; | ||
8884 | for (e = G.top_var; e; e = e->next) | ||
8885 | puts(e->varstr); | ||
8886 | return EXIT_SUCCESS; | ||
8887 | } | ||
8888 | |||
8889 | do { | ||
8890 | if (strcmp(arg, "--") == 0) { | ||
8891 | ++argv; | ||
8892 | goto set_argv; | ||
8893 | } | ||
8894 | if (arg[0] != '+' && arg[0] != '-') | ||
8895 | break; | ||
8896 | for (n = 1; arg[n]; ++n) { | ||
8897 | if (set_mode((arg[0] == '-'), arg[n], argv[1])) | ||
8898 | goto error; | ||
8899 | if (arg[n] == 'o' && argv[1]) | ||
8900 | argv++; | ||
8901 | } | ||
8902 | } while ((arg = *++argv) != NULL); | ||
8903 | /* Now argv[0] is 1st argument */ | ||
8904 | |||
8905 | if (arg == NULL) | ||
8906 | return EXIT_SUCCESS; | ||
8907 | set_argv: | ||
8908 | |||
8909 | /* NB: G.global_argv[0] ($0) is never freed/changed */ | ||
8910 | g_argv = G.global_argv; | ||
8911 | if (G.global_args_malloced) { | ||
8912 | pp = g_argv; | ||
8913 | while (*++pp) | ||
8914 | free(*pp); | ||
8915 | g_argv[1] = NULL; | ||
8916 | } else { | ||
8917 | G.global_args_malloced = 1; | ||
8918 | pp = xzalloc(sizeof(pp[0]) * 2); | ||
8919 | pp[0] = g_argv[0]; /* retain $0 */ | ||
8920 | g_argv = pp; | ||
8921 | } | ||
8922 | /* This realloc's G.global_argv */ | ||
8923 | G.global_argv = pp = add_strings_to_strings(g_argv, argv, /*dup:*/ 1); | ||
8924 | |||
8925 | n = 1; | ||
8926 | while (*++pp) | ||
8927 | n++; | ||
8928 | G.global_argc = n; | ||
8929 | |||
8930 | return EXIT_SUCCESS; | ||
8931 | |||
8932 | /* Nothing known, so abort */ | ||
8933 | error: | ||
8934 | bb_error_msg("set: %s: invalid option", arg); | ||
8935 | return EXIT_FAILURE; | ||
8936 | } | ||
8937 | |||
8938 | static int FAST_FUNC builtin_shift(char **argv) | ||
8939 | { | ||
8940 | int n = 1; | ||
8941 | argv = skip_dash_dash(argv); | ||
8942 | if (argv[0]) { | ||
8943 | n = atoi(argv[0]); | ||
8944 | } | ||
8945 | if (n >= 0 && n < G.global_argc) { | ||
8946 | if (G.global_args_malloced) { | ||
8947 | int m = 1; | ||
8948 | while (m <= n) | ||
8949 | free(G.global_argv[m++]); | ||
8950 | } | ||
8951 | G.global_argc -= n; | ||
8952 | memmove(&G.global_argv[1], &G.global_argv[n+1], | ||
8953 | G.global_argc * sizeof(G.global_argv[0])); | ||
8954 | return EXIT_SUCCESS; | ||
8955 | } | ||
8956 | return EXIT_FAILURE; | ||
8957 | } | ||
8958 | |||
8959 | /* Interruptibility of read builtin in bash | ||
8960 | * (tested on bash-4.2.8 by sending signals (not by ^C)): | ||
8961 | * | ||
8962 | * Empty trap makes read ignore corresponding signal, for any signal. | ||
8963 | * | ||
8964 | * SIGINT: | ||
8965 | * - terminates non-interactive shell; | ||
8966 | * - interrupts read in interactive shell; | ||
8967 | * if it has non-empty trap: | ||
8968 | * - executes trap and returns to command prompt in interactive shell; | ||
8969 | * - executes trap and returns to read in non-interactive shell; | ||
8970 | * SIGTERM: | ||
8971 | * - is ignored (does not interrupt) read in interactive shell; | ||
8972 | * - terminates non-interactive shell; | ||
8973 | * if it has non-empty trap: | ||
8974 | * - executes trap and returns to read; | ||
8975 | * SIGHUP: | ||
8976 | * - terminates shell (regardless of interactivity); | ||
8977 | * if it has non-empty trap: | ||
8978 | * - executes trap and returns to read; | ||
8979 | */ | ||
8980 | static int FAST_FUNC builtin_read(char **argv) | ||
8981 | { | ||
8982 | const char *r; | ||
8983 | char *opt_n = NULL; | ||
8984 | char *opt_p = NULL; | ||
8985 | char *opt_t = NULL; | ||
8986 | char *opt_u = NULL; | ||
8987 | const char *ifs; | ||
8988 | int read_flags; | ||
8989 | |||
8990 | /* "!": do not abort on errors. | ||
8991 | * Option string must start with "sr" to match BUILTIN_READ_xxx | ||
8992 | */ | ||
8993 | read_flags = getopt32(argv, "!srn:p:t:u:", &opt_n, &opt_p, &opt_t, &opt_u); | ||
8994 | if (read_flags == (uint32_t)-1) | ||
8995 | return EXIT_FAILURE; | ||
8996 | argv += optind; | ||
8997 | ifs = get_local_var_value("IFS"); /* can be NULL */ | ||
8998 | |||
8999 | again: | ||
9000 | r = shell_builtin_read(set_local_var_from_halves, | ||
9001 | argv, | ||
9002 | ifs, | ||
9003 | read_flags, | ||
9004 | opt_n, | ||
9005 | opt_p, | ||
9006 | opt_t, | ||
9007 | opt_u | ||
9008 | ); | ||
9009 | |||
9010 | if ((uintptr_t)r == 1 && errno == EINTR) { | ||
9011 | unsigned sig = check_and_run_traps(); | ||
9012 | if (sig && sig != SIGINT) | ||
9013 | goto again; | ||
9014 | } | ||
9015 | |||
9016 | if ((uintptr_t)r > 1) { | ||
9017 | bb_error_msg("%s", r); | ||
9018 | r = (char*)(uintptr_t)1; | ||
9019 | } | ||
9020 | |||
9021 | return (uintptr_t)r; | ||
9022 | } | ||
9023 | |||
8810 | static int FAST_FUNC builtin_trap(char **argv) | 9024 | static int FAST_FUNC builtin_trap(char **argv) |
8811 | { | 9025 | { |
8812 | int sig; | 9026 | int sig; |
@@ -9075,175 +9289,6 @@ static int FAST_FUNC builtin_pwd(char **argv UNUSED_PARAM) | |||
9075 | return EXIT_SUCCESS; | 9289 | return EXIT_SUCCESS; |
9076 | } | 9290 | } |
9077 | 9291 | ||
9078 | /* Interruptibility of read builtin in bash | ||
9079 | * (tested on bash-4.2.8 by sending signals (not by ^C)): | ||
9080 | * | ||
9081 | * Empty trap makes read ignore corresponding signal, for any signal. | ||
9082 | * | ||
9083 | * SIGINT: | ||
9084 | * - terminates non-interactive shell; | ||
9085 | * - interrupts read in interactive shell; | ||
9086 | * if it has non-empty trap: | ||
9087 | * - executes trap and returns to command prompt in interactive shell; | ||
9088 | * - executes trap and returns to read in non-interactive shell; | ||
9089 | * SIGTERM: | ||
9090 | * - is ignored (does not interrupt) read in interactive shell; | ||
9091 | * - terminates non-interactive shell; | ||
9092 | * if it has non-empty trap: | ||
9093 | * - executes trap and returns to read; | ||
9094 | * SIGHUP: | ||
9095 | * - terminates shell (regardless of interactivity); | ||
9096 | * if it has non-empty trap: | ||
9097 | * - executes trap and returns to read; | ||
9098 | */ | ||
9099 | static int FAST_FUNC builtin_read(char **argv) | ||
9100 | { | ||
9101 | const char *r; | ||
9102 | char *opt_n = NULL; | ||
9103 | char *opt_p = NULL; | ||
9104 | char *opt_t = NULL; | ||
9105 | char *opt_u = NULL; | ||
9106 | const char *ifs; | ||
9107 | int read_flags; | ||
9108 | |||
9109 | /* "!": do not abort on errors. | ||
9110 | * Option string must start with "sr" to match BUILTIN_READ_xxx | ||
9111 | */ | ||
9112 | read_flags = getopt32(argv, "!srn:p:t:u:", &opt_n, &opt_p, &opt_t, &opt_u); | ||
9113 | if (read_flags == (uint32_t)-1) | ||
9114 | return EXIT_FAILURE; | ||
9115 | argv += optind; | ||
9116 | ifs = get_local_var_value("IFS"); /* can be NULL */ | ||
9117 | |||
9118 | again: | ||
9119 | r = shell_builtin_read(set_local_var_from_halves, | ||
9120 | argv, | ||
9121 | ifs, | ||
9122 | read_flags, | ||
9123 | opt_n, | ||
9124 | opt_p, | ||
9125 | opt_t, | ||
9126 | opt_u | ||
9127 | ); | ||
9128 | |||
9129 | if ((uintptr_t)r == 1 && errno == EINTR) { | ||
9130 | unsigned sig = check_and_run_traps(); | ||
9131 | if (sig && sig != SIGINT) | ||
9132 | goto again; | ||
9133 | } | ||
9134 | |||
9135 | if ((uintptr_t)r > 1) { | ||
9136 | bb_error_msg("%s", r); | ||
9137 | r = (char*)(uintptr_t)1; | ||
9138 | } | ||
9139 | |||
9140 | return (uintptr_t)r; | ||
9141 | } | ||
9142 | |||
9143 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set | ||
9144 | * built-in 'set' handler | ||
9145 | * SUSv3 says: | ||
9146 | * set [-abCefhmnuvx] [-o option] [argument...] | ||
9147 | * set [+abCefhmnuvx] [+o option] [argument...] | ||
9148 | * set -- [argument...] | ||
9149 | * set -o | ||
9150 | * set +o | ||
9151 | * Implementations shall support the options in both their hyphen and | ||
9152 | * plus-sign forms. These options can also be specified as options to sh. | ||
9153 | * Examples: | ||
9154 | * Write out all variables and their values: set | ||
9155 | * Set $1, $2, and $3 and set "$#" to 3: set c a b | ||
9156 | * Turn on the -x and -v options: set -xv | ||
9157 | * Unset all positional parameters: set -- | ||
9158 | * Set $1 to the value of x, even if it begins with '-' or '+': set -- "$x" | ||
9159 | * Set the positional parameters to the expansion of x, even if x expands | ||
9160 | * with a leading '-' or '+': set -- $x | ||
9161 | * | ||
9162 | * So far, we only support "set -- [argument...]" and some of the short names. | ||
9163 | */ | ||
9164 | static int FAST_FUNC builtin_set(char **argv) | ||
9165 | { | ||
9166 | int n; | ||
9167 | char **pp, **g_argv; | ||
9168 | char *arg = *++argv; | ||
9169 | |||
9170 | if (arg == NULL) { | ||
9171 | struct variable *e; | ||
9172 | for (e = G.top_var; e; e = e->next) | ||
9173 | puts(e->varstr); | ||
9174 | return EXIT_SUCCESS; | ||
9175 | } | ||
9176 | |||
9177 | do { | ||
9178 | if (strcmp(arg, "--") == 0) { | ||
9179 | ++argv; | ||
9180 | goto set_argv; | ||
9181 | } | ||
9182 | if (arg[0] != '+' && arg[0] != '-') | ||
9183 | break; | ||
9184 | for (n = 1; arg[n]; ++n) { | ||
9185 | if (set_mode((arg[0] == '-'), arg[n], argv[1])) | ||
9186 | goto error; | ||
9187 | if (arg[n] == 'o' && argv[1]) | ||
9188 | argv++; | ||
9189 | } | ||
9190 | } while ((arg = *++argv) != NULL); | ||
9191 | /* Now argv[0] is 1st argument */ | ||
9192 | |||
9193 | if (arg == NULL) | ||
9194 | return EXIT_SUCCESS; | ||
9195 | set_argv: | ||
9196 | |||
9197 | /* NB: G.global_argv[0] ($0) is never freed/changed */ | ||
9198 | g_argv = G.global_argv; | ||
9199 | if (G.global_args_malloced) { | ||
9200 | pp = g_argv; | ||
9201 | while (*++pp) | ||
9202 | free(*pp); | ||
9203 | g_argv[1] = NULL; | ||
9204 | } else { | ||
9205 | G.global_args_malloced = 1; | ||
9206 | pp = xzalloc(sizeof(pp[0]) * 2); | ||
9207 | pp[0] = g_argv[0]; /* retain $0 */ | ||
9208 | g_argv = pp; | ||
9209 | } | ||
9210 | /* This realloc's G.global_argv */ | ||
9211 | G.global_argv = pp = add_strings_to_strings(g_argv, argv, /*dup:*/ 1); | ||
9212 | |||
9213 | n = 1; | ||
9214 | while (*++pp) | ||
9215 | n++; | ||
9216 | G.global_argc = n; | ||
9217 | |||
9218 | return EXIT_SUCCESS; | ||
9219 | |||
9220 | /* Nothing known, so abort */ | ||
9221 | error: | ||
9222 | bb_error_msg("set: %s: invalid option", arg); | ||
9223 | return EXIT_FAILURE; | ||
9224 | } | ||
9225 | |||
9226 | static int FAST_FUNC builtin_shift(char **argv) | ||
9227 | { | ||
9228 | int n = 1; | ||
9229 | argv = skip_dash_dash(argv); | ||
9230 | if (argv[0]) { | ||
9231 | n = atoi(argv[0]); | ||
9232 | } | ||
9233 | if (n >= 0 && n < G.global_argc) { | ||
9234 | if (G.global_args_malloced) { | ||
9235 | int m = 1; | ||
9236 | while (m <= n) | ||
9237 | free(G.global_argv[m++]); | ||
9238 | } | ||
9239 | G.global_argc -= n; | ||
9240 | memmove(&G.global_argv[1], &G.global_argv[n+1], | ||
9241 | G.global_argc * sizeof(G.global_argv[0])); | ||
9242 | return EXIT_SUCCESS; | ||
9243 | } | ||
9244 | return EXIT_FAILURE; | ||
9245 | } | ||
9246 | |||
9247 | static int FAST_FUNC builtin_source(char **argv) | 9292 | static int FAST_FUNC builtin_source(char **argv) |
9248 | { | 9293 | { |
9249 | char *arg_path, *filename; | 9294 | char *arg_path, *filename; |
@@ -9334,43 +9379,6 @@ static int FAST_FUNC builtin_umask(char **argv) | |||
9334 | return !rc; /* rc != 0 - success */ | 9379 | return !rc; /* rc != 0 - success */ |
9335 | } | 9380 | } |
9336 | 9381 | ||
9337 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#unset */ | ||
9338 | static int FAST_FUNC builtin_unset(char **argv) | ||
9339 | { | ||
9340 | int ret; | ||
9341 | unsigned opts; | ||
9342 | |||
9343 | /* "!": do not abort on errors */ | ||
9344 | /* "+": stop at 1st non-option */ | ||
9345 | opts = getopt32(argv, "!+vf"); | ||
9346 | if (opts == (unsigned)-1) | ||
9347 | return EXIT_FAILURE; | ||
9348 | if (opts == 3) { | ||
9349 | bb_error_msg("unset: -v and -f are exclusive"); | ||
9350 | return EXIT_FAILURE; | ||
9351 | } | ||
9352 | argv += optind; | ||
9353 | |||
9354 | ret = EXIT_SUCCESS; | ||
9355 | while (*argv) { | ||
9356 | if (!(opts & 2)) { /* not -f */ | ||
9357 | if (unset_local_var(*argv)) { | ||
9358 | /* unset <nonexistent_var> doesn't fail. | ||
9359 | * Error is when one tries to unset RO var. | ||
9360 | * Message was printed by unset_local_var. */ | ||
9361 | ret = EXIT_FAILURE; | ||
9362 | } | ||
9363 | } | ||
9364 | #if ENABLE_HUSH_FUNCTIONS | ||
9365 | else { | ||
9366 | unset_func(*argv); | ||
9367 | } | ||
9368 | #endif | ||
9369 | argv++; | ||
9370 | } | ||
9371 | return ret; | ||
9372 | } | ||
9373 | |||
9374 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/wait.html */ | 9382 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/wait.html */ |
9375 | static int FAST_FUNC builtin_wait(char **argv) | 9383 | static int FAST_FUNC builtin_wait(char **argv) |
9376 | { | 9384 | { |
diff --git a/shell/hush_test/hush-vars/var3.is.in.bugs b/shell/hush_test/hush-vars/var3.is.in.bugs deleted file mode 100644 index e69de29bb..000000000 --- a/shell/hush_test/hush-vars/var3.is.in.bugs +++ /dev/null | |||
diff --git a/shell/hush_test/hush-bugs/var3.right b/shell/hush_test/hush-vars/var3.right index 8eb0e3337..8eb0e3337 100644 --- a/shell/hush_test/hush-bugs/var3.right +++ b/shell/hush_test/hush-vars/var3.right | |||
diff --git a/shell/hush_test/hush-bugs/var3.tests b/shell/hush_test/hush-vars/var3.tests index 97b102cbe..97b102cbe 100755 --- a/shell/hush_test/hush-bugs/var3.tests +++ b/shell/hush_test/hush-vars/var3.tests | |||