X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=coreutils%2Ftest.c;h=2b624e308f3ac4d18e74e0c6e673e159536bb633;hb=5929edc1fac4340f99ed84e92bf3a2bedd4177c2;hp=36da4db0b76ad8c98d43163a856bb1fedb43f1b9;hpb=b610615be9aedfac07d1e01f12575707fa3a227c;p=oweals%2Fbusybox.git diff --git a/coreutils/test.c b/coreutils/test.c index 36da4db0b..2b624e308 100644 --- a/coreutils/test.c +++ b/coreutils/test.c @@ -2,16 +2,16 @@ /* * test implementation for busybox * - * Copyright (c) by a whole pile of folks: + * 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 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 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 @@ -28,20 +28,16 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Original copyright notice states: - * "This program is in the Public Domain." + * "This program is in the Public Domain." */ -#include "internal.h" #include -#include #include #include #include #include #include -#define BB_DECLARE_EXTERN -#define bb_need_help -#include "messages.c" +#include "busybox.h" /* test(1) accepts the following grammar: oexpr ::= aexpr | aexpr "-o" oexpr ; @@ -55,7 +51,7 @@ unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"| "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S"; - binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"| + binary-operator ::= "="|"=="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"| "-nt"|"-ot"|"-ef"; operand ::= */ @@ -111,119 +107,119 @@ enum token_types { PAREN }; -struct t_op { +static const struct t_op { const char *op_text; short op_num, op_type; -} const ops [] = { - {"-r", FILRD, UNOP}, - {"-w", FILWR, UNOP}, - {"-x", FILEX, UNOP}, - {"-e", FILEXIST,UNOP}, - {"-f", FILREG, UNOP}, - {"-d", FILDIR, UNOP}, - {"-c", FILCDEV,UNOP}, - {"-b", FILBDEV,UNOP}, - {"-p", FILFIFO,UNOP}, - {"-u", FILSUID,UNOP}, - {"-g", FILSGID,UNOP}, - {"-k", FILSTCK,UNOP}, - {"-s", FILGZ, UNOP}, - {"-t", FILTT, UNOP}, - {"-z", STREZ, UNOP}, - {"-n", STRNZ, UNOP}, - {"-h", FILSYM, UNOP}, /* for backwards compat */ - {"-O", FILUID, UNOP}, - {"-G", FILGID, UNOP}, - {"-L", FILSYM, UNOP}, - {"-S", FILSOCK,UNOP}, - {"=", STREQ, BINOP}, - {"!=", STRNE, BINOP}, - {"<", STRLT, BINOP}, - {">", STRGT, BINOP}, - {"-eq", INTEQ, BINOP}, - {"-ne", INTNE, BINOP}, - {"-ge", INTGE, BINOP}, - {"-gt", INTGT, BINOP}, - {"-le", INTLE, BINOP}, - {"-lt", INTLT, BINOP}, - {"-nt", FILNT, BINOP}, - {"-ot", FILOT, BINOP}, - {"-ef", FILEQ, BINOP}, - {"!", UNOT, BUNOP}, - {"-a", BAND, BBINOP}, - {"-o", BOR, BBINOP}, - {"(", LPAREN, PAREN}, - {")", RPAREN, PAREN}, - {0, 0, 0} +} ops[] = { + { + "-r", FILRD, UNOP}, { + "-w", FILWR, UNOP}, { + "-x", FILEX, UNOP}, { + "-e", FILEXIST, UNOP}, { + "-f", FILREG, UNOP}, { + "-d", FILDIR, UNOP}, { + "-c", FILCDEV, UNOP}, { + "-b", FILBDEV, UNOP}, { + "-p", FILFIFO, UNOP}, { + "-u", FILSUID, UNOP}, { + "-g", FILSGID, UNOP}, { + "-k", FILSTCK, UNOP}, { + "-s", FILGZ, UNOP}, { + "-t", FILTT, UNOP}, { + "-z", STREZ, UNOP}, { + "-n", STRNZ, UNOP}, { + "-h", FILSYM, UNOP}, /* for backwards compat */ + { + "-O", FILUID, UNOP}, { + "-G", FILGID, UNOP}, { + "-L", FILSYM, UNOP}, { + "-S", FILSOCK, UNOP}, { + "=", STREQ, BINOP}, { + "==", STREQ, BINOP}, { + "!=", STRNE, BINOP}, { + "<", STRLT, BINOP}, { + ">", STRGT, BINOP}, { + "-eq", INTEQ, BINOP}, { + "-ne", INTNE, BINOP}, { + "-ge", INTGE, BINOP}, { + "-gt", INTGT, BINOP}, { + "-le", INTLE, BINOP}, { + "-lt", INTLT, BINOP}, { + "-nt", FILNT, BINOP}, { + "-ot", FILOT, BINOP}, { + "-ef", FILEQ, BINOP}, { + "!", UNOT, BUNOP}, { + "-a", BAND, BBINOP}, { + "-o", BOR, BBINOP}, { + "(", LPAREN, PAREN}, { + ")", RPAREN, PAREN}, { + 0, 0, 0} }; -char **t_wp; -struct t_op const *t_wp_op; +#ifdef CONFIG_FEATURE_TEST_64 +typedef int64_t arith_t; +#else +typedef int arith_t; +#endif + +static char **t_wp; +static struct t_op const *t_wp_op; static gid_t *group_array = NULL; static int ngroups; -static enum token t_lex(); -static int oexpr(); -static int aexpr(); -static int nexpr(); -static int binop(); -static int primary(); -static int filstat(); -static int getn(); -static int newerf(); -static int olderf(); -static int equalf(); -static void syntax(); -static int test_eaccess(); -static int is_a_group_member(); -static void initialize_group_array(); - -extern int -test_main(int argc, char** argv) +static enum token t_lex(char *s); +static arith_t oexpr(enum token n); +static arith_t aexpr(enum token n); +static arith_t nexpr(enum token n); +static int binop(void); +static arith_t primary(enum token n); +static int filstat(char *nm, enum token mode); +static arith_t getn(const char *s); +static int newerf(const char *f1, const char *f2); +static int olderf(const char *f1, const char *f2); +static int equalf(const char *f1, const char *f2); +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) { - int res; + int res; - if (strcmp(argv[0], "[") == 0) { + if (strcmp(bb_applet_name, "[") == 0) { if (strcmp(argv[--argc], "]")) - fatalError("missing ]\n"); + bb_error_msg_and_die("missing ]"); argv[argc] = NULL; } - if (strcmp(argv[1], dash_dash_help) == 0) { - usage("test EXPRESSION\n" - "or [ EXPRESSION ]\n" -#ifndef BB_FEATURE_TRIVIAL_HELP - "\nChecks file types and compares values returning an exit\n" - "code determined by the value of EXPRESSION.\n" -#endif - ); + if (strcmp(bb_applet_name, "[[") == 0) { + if (strcmp(argv[--argc], "]]")) + bb_error_msg_and_die("missing ]]"); + argv[argc] = NULL; } - /* Implement special cases from POSIX.2, section 4.62.4 */ switch (argc) { case 1: - exit( 1); + exit(1); case 2: - exit (*argv[1] == '\0'); + exit(*argv[1] == '\0'); case 3: if (argv[1][0] == '!' && argv[1][1] == '\0') { - exit (!(*argv[2] == '\0')); + exit(!(*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) { + if (t_lex(argv[2]), t_wp_op && t_wp_op->op_type == BINOP) { t_wp = &argv[1]; - exit (binop() == 0); + exit(binop() == 0); } } break; case 5: if (argv[1][0] == '!' && argv[1][1] == '\0') { - if (t_lex(argv[3]), - t_wp_op && t_wp_op->op_type == BINOP) { + if (t_lex(argv[3]), t_wp_op && t_wp_op->op_type == BINOP) { t_wp = &argv[2]; - exit (!(binop() == 0)); + exit(!(binop() == 0)); } } break; @@ -233,40 +229,26 @@ test_main(int argc, char** argv) res = !oexpr(t_lex(*t_wp)); if (*t_wp != NULL && *++t_wp != NULL) - syntax(*t_wp, "unknown operand"); - - return( res); -} + bb_error_msg_and_die("%s: unknown operand", *t_wp); -static void -syntax(op, msg) - char *op; - char *msg; -{ - if (op && *op) - fatalError("%s: %s\n", op, msg); - else - fatalError("%s\n", msg); + return (res); } -static int -oexpr(n) - enum token n; +static arith_t oexpr(enum token n) { - int res; + arith_t res; res = aexpr(n); - if (t_lex(*++t_wp) == BOR) + if (t_lex(*++t_wp) == BOR) { return oexpr(t_lex(*++t_wp)) || res; + } t_wp--; return res; } -static int -aexpr(n) - enum token n; +static arith_t aexpr(enum token n) { - int res; + arith_t res; res = nexpr(n); if (t_lex(*++t_wp) == BAND) @@ -275,33 +257,30 @@ aexpr(n) return res; } -static int -nexpr(n) - enum token n; /* token */ +static arith_t nexpr(enum token n) { if (n == UNOT) return !nexpr(t_lex(*++t_wp)); return primary(n); } -static int -primary(n) - enum token n; +static arith_t primary(enum token n) { - int res; + arith_t res; - if (n == EOI) - syntax(NULL, "argument expected"); + if (n == EOI) { + bb_error_msg_and_die("argument expected"); + } if (n == LPAREN) { res = oexpr(t_lex(*++t_wp)); if (t_lex(*++t_wp) != RPAREN) - syntax(NULL, "closing paren expected"); + bb_error_msg_and_die("closing paren expected"); return res; } if (t_wp_op && t_wp_op->op_type == UNOP) { /* unary expression */ if (*++t_wp == NULL) - syntax(t_wp_op->op_text, "argument expected"); + bb_error_msg_and_die(bb_msg_requires_arg, t_wp_op->op_text); switch (n) { case STREZ: return strlen(*t_wp) == 0; @@ -316,13 +295,12 @@ primary(n) if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) { return binop(); - } + } return strlen(*t_wp) > 0; } -static int -binop() +static int binop(void) { const char *opnd1, *opnd2; struct t_op const *op; @@ -331,9 +309,9 @@ binop() (void) t_lex(*++t_wp); op = t_wp_op; - if ((opnd2 = *++t_wp) == (char *)0) - syntax(op->op_text, "argument expected"); - + if ((opnd2 = *++t_wp) == (char *) 0) + bb_error_msg_and_die(bb_msg_requires_arg, op->op_text); + switch (op->op_num) { case STREQ: return strcmp(opnd1, opnd2) == 0; @@ -356,23 +334,20 @@ binop() case INTLT: return getn(opnd1) < getn(opnd2); case FILNT: - return newerf (opnd1, opnd2); + return newerf(opnd1, opnd2); case FILOT: - return olderf (opnd1, opnd2); + return olderf(opnd1, opnd2); case FILEQ: - return equalf (opnd1, opnd2); + return equalf(opnd1, opnd2); } /* NOTREACHED */ return 1; } -static int -filstat(nm, mode) - char *nm; - enum token mode; +static int filstat(char *nm, enum token mode) { struct stat s; - int i; + unsigned int i; if (mode == FILSYM) { #ifdef S_IFLNK @@ -384,7 +359,7 @@ filstat(nm, mode) return 0; } - if (stat(nm, &s) != 0) + if (stat(nm, &s) != 0) return 0; switch (mode) { @@ -441,21 +416,19 @@ filstat(nm, mode) return 1; } -filetype: + filetype: return ((s.st_mode & S_IFMT) == i); -filebit: + filebit: return ((s.st_mode & i) != 0); } -static enum token -t_lex(s) - char *s; +static enum token t_lex(char *s) { struct t_op const *op = ops; if (s == 0) { - t_wp_op = (struct t_op *)0; + t_wp_op = (struct t_op *) 0; return EOI; } while (op->op_text) { @@ -465,85 +438,77 @@ t_lex(s) } op++; } - t_wp_op = (struct t_op *)0; + t_wp_op = (struct t_op *) 0; return OPERAND; } /* atoi with error detection */ -static int -getn(s) - char *s; +static arith_t getn(const char *s) { char *p; +#ifdef CONFIG_FEATURE_TEST_64 + long long r; +#else long r; +#endif errno = 0; +#ifdef CONFIG_FEATURE_TEST_64 + r = strtoll(s, &p, 10); +#else r = strtol(s, &p, 10); +#endif if (errno != 0) - fatalError("%s: out of range\n", s); + bb_error_msg_and_die("%s: out of range", s); - while (isspace(*p)) - p++; - - if (*p) - fatalError("%s: bad number\n", s); + /* p = bb_skip_whitespace(p); avoid const warning */ + if (*(bb_skip_whitespace(p))) + bb_error_msg_and_die("%s: bad number", s); - return (int) r; + return r; } -static int -newerf (f1, f2) -char *f1, *f2; +static int newerf(const char *f1, const char *f2) { struct stat b1, b2; - return (stat (f1, &b1) == 0 && - stat (f2, &b2) == 0 && - b1.st_mtime > b2.st_mtime); + return (stat(f1, &b1) == 0 && + stat(f2, &b2) == 0 && b1.st_mtime > b2.st_mtime); } -static int -olderf (f1, f2) -char *f1, *f2; +static int olderf(const char *f1, const char *f2) { struct stat b1, b2; - return (stat (f1, &b1) == 0 && - stat (f2, &b2) == 0 && - b1.st_mtime < b2.st_mtime); + return (stat(f1, &b1) == 0 && + stat(f2, &b2) == 0 && b1.st_mtime < b2.st_mtime); } -static int -equalf (f1, f2) -char *f1, *f2; +static int equalf(const char *f1, const char *f2) { struct stat b1, b2; - return (stat (f1, &b1) == 0 && - stat (f2, &b2) == 0 && - b1.st_dev == b2.st_dev && - b1.st_ino == b2.st_ino); + return (stat(f1, &b1) == 0 && + stat(f2, &b2) == 0 && + b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino); } /* Do the same thing access(2) does, but use the effective uid and gid, and don't make the mistake of telling root that any file is executable. */ -static int -test_eaccess (path, mode) -char *path; -int mode; +static int test_eaccess(char *path, int mode) { struct stat st; - int euid = geteuid(); + unsigned int euid = geteuid(); - if (stat (path, &st) < 0) + if (stat(path, &st) < 0) return (-1); if (euid == 0) { /* Root can read or write any file. */ if (mode != X_OK) - return (0); + return (0); /* Root can execute any file that has any one of the execute bits set. */ @@ -551,9 +516,9 @@ 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)) + else if (is_a_group_member(st.st_gid)) mode <<= 3; if (st.st_mode & mode) @@ -562,20 +527,15 @@ int mode; return (-1); } -static void -initialize_group_array () +static void initialize_group_array(void) { ngroups = getgroups(0, NULL); - if ((group_array = realloc(group_array, ngroups * sizeof(gid_t))) == NULL) - fatalError("Out of space\n"); - + group_array = xrealloc(group_array, ngroups * sizeof(gid_t)); getgroups(ngroups, group_array); } /* Return non-zero if GID is one that we have in our groups list. */ -static int -is_a_group_member (gid) -gid_t gid; +static int is_a_group_member(gid_t gid) { register int i; @@ -584,7 +544,7 @@ gid_t gid; return (1); if (ngroups == 0) - initialize_group_array (); + initialize_group_array(); /* Search through the list looking for GID. */ for (i = 0; i < ngroups; i++)