diff options
Diffstat (limited to 'coreutils/test.c')
-rw-r--r-- | coreutils/test.c | 123 |
1 files changed, 76 insertions, 47 deletions
diff --git a/coreutils/test.c b/coreutils/test.c index 2b624e308..4d920380d 100644 --- a/coreutils/test.c +++ b/coreutils/test.c | |||
@@ -4,31 +4,19 @@ | |||
4 | * | 4 | * |
5 | * Copyright (c) by a whole pile of folks: | 5 | * Copyright (c) by a whole pile of folks: |
6 | * | 6 | * |
7 | * test(1); version 7-like -- author Erik Baalbergen | 7 | * test(1); version 7-like -- author Erik Baalbergen |
8 | * modified by Eric Gisin to be used as built-in. | 8 | * modified by Eric Gisin to be used as built-in. |
9 | * modified by Arnold Robbins to add SVR3 compatibility | 9 | * modified by Arnold Robbins to add SVR3 compatibility |
10 | * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket). | 10 | * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket). |
11 | * modified by J.T. Conklin for NetBSD. | 11 | * modified by J.T. Conklin for NetBSD. |
12 | * modified by Herbert Xu to be used as built-in in ash. | 12 | * modified by Herbert Xu to be used as built-in in ash. |
13 | * modified by Erik Andersen <andersen@codepoet.org> to be used | 13 | * modified by Erik Andersen <andersen@codepoet.org> to be used |
14 | * in busybox. | 14 | * in busybox. |
15 | * | 15 | * |
16 | * This program is free software; you can redistribute it and/or modify | 16 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2 of the License, or | ||
19 | * (at your option) any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
24 | * General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
29 | * | 17 | * |
30 | * Original copyright notice states: | 18 | * Original copyright notice states: |
31 | * "This program is in the Public Domain." | 19 | * "This program is in the Public Domain." |
32 | */ | 20 | */ |
33 | 21 | ||
34 | #include <sys/types.h> | 22 | #include <sys/types.h> |
@@ -37,13 +25,14 @@ | |||
37 | #include <errno.h> | 25 | #include <errno.h> |
38 | #include <stdlib.h> | 26 | #include <stdlib.h> |
39 | #include <string.h> | 27 | #include <string.h> |
28 | #include <setjmp.h> | ||
40 | #include "busybox.h" | 29 | #include "busybox.h" |
41 | 30 | ||
42 | /* test(1) accepts the following grammar: | 31 | /* test(1) accepts the following grammar: |
43 | oexpr ::= aexpr | aexpr "-o" oexpr ; | 32 | oexpr ::= aexpr | aexpr "-o" oexpr ; |
44 | aexpr ::= nexpr | nexpr "-a" aexpr ; | 33 | aexpr ::= nexpr | nexpr "-a" aexpr ; |
45 | nexpr ::= primary | "!" primary | 34 | nexpr ::= primary | "!" primary |
46 | primary ::= unary-operator operand | 35 | primary ::= unary-operator operand |
47 | | operand binary-operator operand | 36 | | operand binary-operator operand |
48 | | operand | 37 | | operand |
49 | | "(" oexpr ")" | 38 | | "(" oexpr ")" |
@@ -128,7 +117,7 @@ static const struct t_op { | |||
128 | "-t", FILTT, UNOP}, { | 117 | "-t", FILTT, UNOP}, { |
129 | "-z", STREZ, UNOP}, { | 118 | "-z", STREZ, UNOP}, { |
130 | "-n", STRNZ, UNOP}, { | 119 | "-n", STRNZ, UNOP}, { |
131 | "-h", FILSYM, UNOP}, /* for backwards compat */ | 120 | "-h", FILSYM, UNOP}, /* for backwards compat */ |
132 | { | 121 | { |
133 | "-O", FILUID, UNOP}, { | 122 | "-O", FILUID, UNOP}, { |
134 | "-G", FILGID, UNOP}, { | 123 | "-G", FILGID, UNOP}, { |
@@ -182,36 +171,56 @@ static int test_eaccess(char *path, int mode); | |||
182 | static int is_a_group_member(gid_t gid); | 171 | static int is_a_group_member(gid_t gid); |
183 | static void initialize_group_array(void); | 172 | static void initialize_group_array(void); |
184 | 173 | ||
185 | int test_main(int argc, char **argv) | 174 | static jmp_buf leaving; |
175 | |||
176 | int bb_test(int argc, char **argv) | ||
186 | { | 177 | { |
187 | int res; | 178 | int res; |
188 | 179 | ||
189 | if (strcmp(bb_applet_name, "[") == 0) { | 180 | if (strcmp(argv[0], "[") == 0) { |
190 | if (strcmp(argv[--argc], "]")) | 181 | if (strcmp(argv[--argc], "]")) { |
191 | bb_error_msg_and_die("missing ]"); | 182 | bb_error_msg("missing ]"); |
183 | return 2; | ||
184 | } | ||
192 | argv[argc] = NULL; | 185 | argv[argc] = NULL; |
193 | } | 186 | } else if (strcmp(argv[0], "[[") == 0) { |
194 | if (strcmp(bb_applet_name, "[[") == 0) { | 187 | if (strcmp(argv[--argc], "]]")) { |
195 | if (strcmp(argv[--argc], "]]")) | 188 | bb_error_msg("missing ]]"); |
196 | bb_error_msg_and_die("missing ]]"); | 189 | return 2; |
190 | } | ||
197 | argv[argc] = NULL; | 191 | argv[argc] = NULL; |
198 | } | 192 | } |
193 | |||
194 | res = setjmp(leaving); | ||
195 | if (res) | ||
196 | return res; | ||
197 | |||
198 | /* resetting ngroups is probably unnecessary. it will | ||
199 | * force a new call to getgroups(), which prevents using | ||
200 | * group data fetched during a previous call. but the | ||
201 | * only way the group data could be stale is if there's | ||
202 | * been an intervening call to setgroups(), and this | ||
203 | * isn't likely in the case of a shell. paranoia | ||
204 | * prevails... | ||
205 | */ | ||
206 | ngroups = 0; | ||
207 | |||
199 | /* Implement special cases from POSIX.2, section 4.62.4 */ | 208 | /* Implement special cases from POSIX.2, section 4.62.4 */ |
200 | switch (argc) { | 209 | switch (argc) { |
201 | case 1: | 210 | case 1: |
202 | exit(1); | 211 | return 1; |
203 | case 2: | 212 | case 2: |
204 | exit(*argv[1] == '\0'); | 213 | return *argv[1] == '\0'; |
205 | case 3: | 214 | case 3: |
206 | if (argv[1][0] == '!' && argv[1][1] == '\0') { | 215 | if (argv[1][0] == '!' && argv[1][1] == '\0') { |
207 | exit(!(*argv[2] == '\0')); | 216 | return *argv[2] != '\0'; |
208 | } | 217 | } |
209 | break; | 218 | break; |
210 | case 4: | 219 | case 4: |
211 | if (argv[1][0] != '!' || argv[1][1] != '\0') { | 220 | if (argv[1][0] != '!' || argv[1][1] != '\0') { |
212 | if (t_lex(argv[2]), t_wp_op && t_wp_op->op_type == BINOP) { | 221 | if (t_lex(argv[2]), t_wp_op && t_wp_op->op_type == BINOP) { |
213 | t_wp = &argv[1]; | 222 | t_wp = &argv[1]; |
214 | exit(binop() == 0); | 223 | return binop() == 0; |
215 | } | 224 | } |
216 | } | 225 | } |
217 | break; | 226 | break; |
@@ -219,7 +228,7 @@ int test_main(int argc, char **argv) | |||
219 | if (argv[1][0] == '!' && argv[1][1] == '\0') { | 228 | if (argv[1][0] == '!' && argv[1][1] == '\0') { |
220 | if (t_lex(argv[3]), t_wp_op && t_wp_op->op_type == BINOP) { | 229 | if (t_lex(argv[3]), t_wp_op && t_wp_op->op_type == BINOP) { |
221 | t_wp = &argv[2]; | 230 | t_wp = &argv[2]; |
222 | exit(!(binop() == 0)); | 231 | return binop() != 0; |
223 | } | 232 | } |
224 | } | 233 | } |
225 | break; | 234 | break; |
@@ -228,10 +237,21 @@ int test_main(int argc, char **argv) | |||
228 | t_wp = &argv[1]; | 237 | t_wp = &argv[1]; |
229 | res = !oexpr(t_lex(*t_wp)); | 238 | res = !oexpr(t_lex(*t_wp)); |
230 | 239 | ||
231 | if (*t_wp != NULL && *++t_wp != NULL) | 240 | if (*t_wp != NULL && *++t_wp != NULL) { |
232 | bb_error_msg_and_die("%s: unknown operand", *t_wp); | 241 | bb_error_msg("%s: unknown operand", *t_wp); |
242 | return 2; | ||
243 | } | ||
244 | return res; | ||
245 | } | ||
233 | 246 | ||
234 | return (res); | 247 | static void syntax(const char *op, const char *msg) |
248 | { | ||
249 | if (op && *op) { | ||
250 | bb_error_msg("%s: %s", op, msg); | ||
251 | } else { | ||
252 | bb_error_msg("%s", msg); | ||
253 | } | ||
254 | longjmp(leaving, 2); | ||
235 | } | 255 | } |
236 | 256 | ||
237 | static arith_t oexpr(enum token n) | 257 | static arith_t oexpr(enum token n) |
@@ -269,18 +289,18 @@ static arith_t primary(enum token n) | |||
269 | arith_t res; | 289 | arith_t res; |
270 | 290 | ||
271 | if (n == EOI) { | 291 | if (n == EOI) { |
272 | bb_error_msg_and_die("argument expected"); | 292 | syntax(NULL, "argument expected"); |
273 | } | 293 | } |
274 | if (n == LPAREN) { | 294 | if (n == LPAREN) { |
275 | res = oexpr(t_lex(*++t_wp)); | 295 | res = oexpr(t_lex(*++t_wp)); |
276 | if (t_lex(*++t_wp) != RPAREN) | 296 | if (t_lex(*++t_wp) != RPAREN) |
277 | bb_error_msg_and_die("closing paren expected"); | 297 | syntax(NULL, "closing paren expected"); |
278 | return res; | 298 | return res; |
279 | } | 299 | } |
280 | if (t_wp_op && t_wp_op->op_type == UNOP) { | 300 | if (t_wp_op && t_wp_op->op_type == UNOP) { |
281 | /* unary expression */ | 301 | /* unary expression */ |
282 | if (*++t_wp == NULL) | 302 | if (*++t_wp == NULL) |
283 | bb_error_msg_and_die(bb_msg_requires_arg, t_wp_op->op_text); | 303 | syntax(t_wp_op->op_text, "argument expected"); |
284 | switch (n) { | 304 | switch (n) { |
285 | case STREZ: | 305 | case STREZ: |
286 | return strlen(*t_wp) == 0; | 306 | return strlen(*t_wp) == 0; |
@@ -310,7 +330,7 @@ static int binop(void) | |||
310 | op = t_wp_op; | 330 | op = t_wp_op; |
311 | 331 | ||
312 | if ((opnd2 = *++t_wp) == (char *) 0) | 332 | if ((opnd2 = *++t_wp) == (char *) 0) |
313 | bb_error_msg_and_die(bb_msg_requires_arg, op->op_text); | 333 | syntax(op->op_text, "argument expected"); |
314 | 334 | ||
315 | switch (op->op_num) { | 335 | switch (op->op_num) { |
316 | case STREQ: | 336 | case STREQ: |
@@ -460,11 +480,11 @@ static arith_t getn(const char *s) | |||
460 | #endif | 480 | #endif |
461 | 481 | ||
462 | if (errno != 0) | 482 | if (errno != 0) |
463 | bb_error_msg_and_die("%s: out of range", s); | 483 | syntax(s, "out of range"); |
464 | 484 | ||
465 | /* p = bb_skip_whitespace(p); avoid const warning */ | 485 | /* p = bb_skip_whitespace(p); avoid const warning */ |
466 | if (*(bb_skip_whitespace(p))) | 486 | if (*(bb_skip_whitespace(p))) |
467 | bb_error_msg_and_die("%s: bad number", s); | 487 | syntax(s, "bad number"); |
468 | 488 | ||
469 | return r; | 489 | return r; |
470 | } | 490 | } |
@@ -516,7 +536,7 @@ static int test_eaccess(char *path, int mode) | |||
516 | return (0); | 536 | return (0); |
517 | } | 537 | } |
518 | 538 | ||
519 | if (st.st_uid == euid) /* owner */ | 539 | if (st.st_uid == euid) /* owner */ |
520 | mode <<= 6; | 540 | mode <<= 6; |
521 | else if (is_a_group_member(st.st_gid)) | 541 | else if (is_a_group_member(st.st_gid)) |
522 | mode <<= 3; | 542 | mode <<= 3; |
@@ -553,3 +573,12 @@ static int is_a_group_member(gid_t gid) | |||
553 | 573 | ||
554 | return (0); | 574 | return (0); |
555 | } | 575 | } |
576 | |||
577 | |||
578 | /* applet entry point */ | ||
579 | |||
580 | int test_main(int argc, char **argv) | ||
581 | { | ||
582 | exit(bb_test(argc, argv)); | ||
583 | } | ||
584 | |||