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 2b624e3..4d92038 100644 --- a/coreutils/test.c +++ b/coreutils/test.c @@ -4,31 +4,19 @@ * * Copyright (c) by a whole pile of folks: * - * test(1); version 7-like -- author Erik Baalbergen - * modified by Eric Gisin to be used as built-in. - * modified by Arnold Robbins to add SVR3 compatibility - * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket). - * modified by J.T. Conklin for NetBSD. - * modified by Herbert Xu to be used as built-in in ash. - * modified by Erik Andersen <andersen@codepoet.org> to be used - * in busybox. + * test(1); version 7-like -- author Erik Baalbergen + * modified by Eric Gisin to be used as built-in. + * modified by Arnold Robbins to add SVR3 compatibility + * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket). + * modified by J.T. Conklin for NetBSD. + * modified by Herbert Xu to be used as built-in in ash. + * modified by Erik Andersen <andersen@codepoet.org> to be used + * in busybox. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. * * Original copyright notice states: - * "This program is in the Public Domain." + * "This program is in the Public Domain." */ #include <sys/types.h> @@ -37,13 +25,14 @@ #include <errno.h> #include <stdlib.h> #include <string.h> +#include <setjmp.h> #include "busybox.h" /* test(1) accepts the following grammar: oexpr ::= aexpr | aexpr "-o" oexpr ; aexpr ::= nexpr | nexpr "-a" aexpr ; nexpr ::= primary | "!" primary - primary ::= unary-operator operand + primary ::= unary-operator operand | operand binary-operator operand | operand | "(" oexpr ")" @@ -128,7 +117,7 @@ static const struct t_op { "-t", FILTT, UNOP}, { "-z", STREZ, UNOP}, { "-n", STRNZ, UNOP}, { - "-h", FILSYM, UNOP}, /* for backwards compat */ + "-h", FILSYM, UNOP}, /* for backwards compat */ { "-O", FILUID, UNOP}, { "-G", FILGID, UNOP}, { @@ -182,36 +171,56 @@ static int test_eaccess(char *path, int mode); static int is_a_group_member(gid_t gid); static void initialize_group_array(void); -int test_main(int argc, char **argv) +static jmp_buf leaving; + +int bb_test(int argc, char **argv) { int res; - if (strcmp(bb_applet_name, "[") == 0) { - if (strcmp(argv[--argc], "]")) - bb_error_msg_and_die("missing ]"); + if (strcmp(argv[0], "[") == 0) { + if (strcmp(argv[--argc], "]")) { + bb_error_msg("missing ]"); + return 2; + } argv[argc] = NULL; - } - if (strcmp(bb_applet_name, "[[") == 0) { - if (strcmp(argv[--argc], "]]")) - bb_error_msg_and_die("missing ]]"); + } else if (strcmp(argv[0], "[[") == 0) { + if (strcmp(argv[--argc], "]]")) { + bb_error_msg("missing ]]"); + return 2; + } argv[argc] = NULL; } + + res = setjmp(leaving); + if (res) + return res; + + /* resetting ngroups is probably unnecessary. it will + * force a new call to getgroups(), which prevents using + * group data fetched during a previous call. but the + * only way the group data could be stale is if there's + * been an intervening call to setgroups(), and this + * isn't likely in the case of a shell. paranoia + * prevails... + */ + ngroups = 0; + /* Implement special cases from POSIX.2, section 4.62.4 */ switch (argc) { case 1: - exit(1); + return 1; case 2: - exit(*argv[1] == '\0'); + return *argv[1] == '\0'; case 3: if (argv[1][0] == '!' && argv[1][1] == '\0') { - exit(!(*argv[2] == '\0')); + return *argv[2] != '\0'; } break; case 4: if (argv[1][0] != '!' || argv[1][1] != '\0') { if (t_lex(argv[2]), t_wp_op && t_wp_op->op_type == BINOP) { t_wp = &argv[1]; - exit(binop() == 0); + return binop() == 0; } } break; @@ -219,7 +228,7 @@ int test_main(int argc, char **argv) if (argv[1][0] == '!' && argv[1][1] == '\0') { if (t_lex(argv[3]), t_wp_op && t_wp_op->op_type == BINOP) { t_wp = &argv[2]; - exit(!(binop() == 0)); + return binop() != 0; } } break; @@ -228,10 +237,21 @@ int test_main(int argc, char **argv) t_wp = &argv[1]; res = !oexpr(t_lex(*t_wp)); - if (*t_wp != NULL && *++t_wp != NULL) - bb_error_msg_and_die("%s: unknown operand", *t_wp); + if (*t_wp != NULL && *++t_wp != NULL) { + bb_error_msg("%s: unknown operand", *t_wp); + return 2; + } + return res; +} - return (res); +static void syntax(const char *op, const char *msg) +{ + if (op && *op) { + bb_error_msg("%s: %s", op, msg); + } else { + bb_error_msg("%s", msg); + } + longjmp(leaving, 2); } static arith_t oexpr(enum token n) @@ -269,18 +289,18 @@ static arith_t primary(enum token n) arith_t res; if (n == EOI) { - bb_error_msg_and_die("argument expected"); + syntax(NULL, "argument expected"); } if (n == LPAREN) { res = oexpr(t_lex(*++t_wp)); if (t_lex(*++t_wp) != RPAREN) - bb_error_msg_and_die("closing paren expected"); + syntax(NULL, "closing paren expected"); return res; } if (t_wp_op && t_wp_op->op_type == UNOP) { /* unary expression */ if (*++t_wp == NULL) - bb_error_msg_and_die(bb_msg_requires_arg, t_wp_op->op_text); + syntax(t_wp_op->op_text, "argument expected"); switch (n) { case STREZ: return strlen(*t_wp) == 0; @@ -310,7 +330,7 @@ static int binop(void) op = t_wp_op; if ((opnd2 = *++t_wp) == (char *) 0) - bb_error_msg_and_die(bb_msg_requires_arg, op->op_text); + syntax(op->op_text, "argument expected"); switch (op->op_num) { case STREQ: @@ -460,11 +480,11 @@ static arith_t getn(const char *s) #endif if (errno != 0) - bb_error_msg_and_die("%s: out of range", s); + syntax(s, "out of range"); /* p = bb_skip_whitespace(p); avoid const warning */ if (*(bb_skip_whitespace(p))) - bb_error_msg_and_die("%s: bad number", s); + syntax(s, "bad number"); return r; } @@ -516,7 +536,7 @@ static int test_eaccess(char *path, int mode) return (0); } - if (st.st_uid == euid) /* owner */ + if (st.st_uid == euid) /* owner */ mode <<= 6; else if (is_a_group_member(st.st_gid)) mode <<= 3; @@ -553,3 +573,12 @@ static int is_a_group_member(gid_t gid) return (0); } + + +/* applet entry point */ + +int test_main(int argc, char **argv) +{ + exit(bb_test(argc, argv)); +} + |