Ignore:
Timestamp:
Nov 4, 2007, 3:16:40 AM (16 years ago)
Author:
Bruno Cornec
Message:

Update to busybox 1.7.2

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.5/mindi-busybox/coreutils/test.c

    r902 r1765  
    1313 *     modified by Erik Andersen <andersen@codepoet.org> to be used
    1414 *     in busybox.
     15 *     modified by Bernhard Fischer to be useable (i.e. a bit less bloaty).
    1516 *
    1617 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     
    2021 */
    2122
    22 #include "busybox.h"
    23 #include <unistd.h>
    24 #include <ctype.h>
    25 #include <errno.h>
    26 #include <string.h>
     23#include "libbb.h"
    2724#include <setjmp.h>
     25
     26/* This is a NOEXEC applet. Be very careful! */
     27
    2828
    2929/* test(1) accepts the following grammar:
     
    8686    OPERAND
    8787};
    88 
     88#define is_int_op(a) (((unsigned char)((a) - INTEQ)) <= 5)
     89#define is_str_op(a) (((unsigned char)((a) - STREZ)) <= 5)
     90#define is_file_op(a) (((unsigned char)((a) - FILNT)) <= 2)
     91#define is_file_access(a) (((unsigned char)((a) - FILRD)) <= 2)
     92#define is_file_type(a) (((unsigned char)((a) - FILREG)) <= 5)
     93#define is_file_bit(a) (((unsigned char)((a) - FILSUID)) <= 2)
    8994enum token_types {
    9095    UNOP,
     
    96101
    97102static const struct t_op {
    98     const char *op_text;
    99     short op_num, op_type;
     103    char op_text[4];
     104    unsigned char op_num, op_type;
    100105} ops[] = {
    101     {
    102     "-r", FILRD, UNOP}, {
    103     "-w", FILWR, UNOP}, {
    104     "-x", FILEX, UNOP}, {
    105     "-e", FILEXIST, UNOP}, {
    106     "-f", FILREG, UNOP}, {
    107     "-d", FILDIR, UNOP}, {
    108     "-c", FILCDEV, UNOP}, {
    109     "-b", FILBDEV, UNOP}, {
    110     "-p", FILFIFO, UNOP}, {
    111     "-u", FILSUID, UNOP}, {
    112     "-g", FILSGID, UNOP}, {
    113     "-k", FILSTCK, UNOP}, {
    114     "-s", FILGZ, UNOP}, {
    115     "-t", FILTT, UNOP}, {
    116     "-z", STREZ, UNOP}, {
    117     "-n", STRNZ, UNOP}, {
    118     "-h", FILSYM, UNOP},    /* for backwards compat */
    119     {
    120     "-O", FILUID, UNOP}, {
    121     "-G", FILGID, UNOP}, {
    122     "-L", FILSYM, UNOP}, {
    123     "-S", FILSOCK, UNOP}, {
    124     "=", STREQ, BINOP}, {
    125     "==", STREQ, BINOP}, {
    126     "!=", STRNE, BINOP}, {
    127     "<", STRLT, BINOP}, {
    128     ">", STRGT, BINOP}, {
    129     "-eq", INTEQ, BINOP}, {
    130     "-ne", INTNE, BINOP}, {
    131     "-ge", INTGE, BINOP}, {
    132     "-gt", INTGT, BINOP}, {
    133     "-le", INTLE, BINOP}, {
    134     "-lt", INTLT, BINOP}, {
    135     "-nt", FILNT, BINOP}, {
    136     "-ot", FILOT, BINOP}, {
    137     "-ef", FILEQ, BINOP}, {
    138     "!", UNOT, BUNOP}, {
    139     "-a", BAND, BBINOP}, {
    140     "-o", BOR, BBINOP}, {
    141     "(", LPAREN, PAREN}, {
    142     ")", RPAREN, PAREN}, {
    143     0, 0, 0}
     106    { "-r", FILRD   , UNOP   },
     107    { "-w", FILWR   , UNOP   },
     108    { "-x", FILEX   , UNOP   },
     109    { "-e", FILEXIST, UNOP   },
     110    { "-f", FILREG  , UNOP   },
     111    { "-d", FILDIR  , UNOP   },
     112    { "-c", FILCDEV , UNOP   },
     113    { "-b", FILBDEV , UNOP   },
     114    { "-p", FILFIFO , UNOP   },
     115    { "-u", FILSUID , UNOP   },
     116    { "-g", FILSGID , UNOP   },
     117    { "-k", FILSTCK , UNOP   },
     118    { "-s", FILGZ   , UNOP   },
     119    { "-t", FILTT   , UNOP   },
     120    { "-z", STREZ   , UNOP   },
     121    { "-n", STRNZ   , UNOP   },
     122    { "-h", FILSYM  , UNOP   },    /* for backwards compat */
     123
     124    { "-O" , FILUID , UNOP   },
     125    { "-G" , FILGID , UNOP   },
     126    { "-L" , FILSYM , UNOP   },
     127    { "-S" , FILSOCK, UNOP   },
     128    { "="  , STREQ  , BINOP  },
     129    { "==" , STREQ  , BINOP  },
     130    { "!=" , STRNE  , BINOP  },
     131    { "<"  , STRLT  , BINOP  },
     132    { ">"  , STRGT  , BINOP  },
     133    { "-eq", INTEQ  , BINOP  },
     134    { "-ne", INTNE  , BINOP  },
     135    { "-ge", INTGE  , BINOP  },
     136    { "-gt", INTGT  , BINOP  },
     137    { "-le", INTLE  , BINOP  },
     138    { "-lt", INTLT  , BINOP  },
     139    { "-nt", FILNT  , BINOP  },
     140    { "-ot", FILOT  , BINOP  },
     141    { "-ef", FILEQ  , BINOP  },
     142    { "!"  , UNOT   , BUNOP  },
     143    { "-a" , BAND   , BBINOP },
     144    { "-o" , BOR    , BBINOP },
     145    { "("  , LPAREN , PAREN  },
     146    { ")"  , RPAREN , PAREN  },
    144147};
    145148
    146 #ifdef CONFIG_FEATURE_TEST_64
     149
     150#if ENABLE_FEATURE_TEST_64
    147151typedef int64_t arith_t;
    148152#else
     
    150154#endif
    151155
     156/* Cannot eliminate these static data (do the G trick)
     157 * because of test_main usage from other applets */
    152158static char **t_wp;
    153159static struct t_op const *t_wp_op;
    154160static gid_t *group_array;
    155161static int ngroups;
     162static jmp_buf leaving;
    156163
    157164static enum token t_lex(char *s);
     
    163170static int filstat(char *nm, enum token mode);
    164171static arith_t getn(const char *s);
     172/* UNUSED
    165173static int newerf(const char *f1, const char *f2);
    166174static int olderf(const char *f1, const char *f2);
    167175static int equalf(const char *f1, const char *f2);
     176*/
    168177static int test_eaccess(char *path, int mode);
    169178static int is_a_group_member(gid_t gid);
    170179static void initialize_group_array(void);
    171180
    172 static jmp_buf leaving;
    173 
    174 int bb_test(int argc, char **argv)
     181int test_main(int argc, char **argv)
    175182{
    176183    int res;
    177 
    178     if (strcmp(argv[0], "[") == 0) {
    179         if (strcmp(argv[--argc], "]")) {
    180             bb_error_msg("missing ]");
    181             return 2;
    182         }
    183         argv[argc] = NULL;
    184     } else if (strcmp(argv[0], "[[") == 0) {
    185         if (strcmp(argv[--argc], "]]")) {
    186             bb_error_msg("missing ]]");
    187             return 2;
     184    const char *arg0;
     185    bool _off;
     186
     187    arg0 = bb_basename(argv[0]);
     188    if (arg0[0] == '[') {
     189        --argc;
     190        if (!arg0[1]) { /* "[" ? */
     191            if (NOT_LONE_CHAR(argv[argc], ']')) {
     192                bb_error_msg("missing ]");
     193                return 2;
     194            }
     195        } else { /* assuming "[[" */
     196            if (strcmp(argv[argc], "]]") != 0) {
     197                bb_error_msg("missing ]]");
     198                return 2;
     199            }
    188200        }
    189201        argv[argc] = NULL;
     
    202214     * prevails...
    203215     */
    204      ngroups = 0;
     216    ngroups = 0;
    205217
    206218    /* Implement special cases from POSIX.2, section 4.62.4 */
    207     switch (argc) {
    208     case 1:
     219    if (argc == 1)
    209220        return 1;
    210     case 2:
     221    if (argc == 2)
    211222        return *argv[1] == '\0';
    212     case 3:
    213         if (argv[1][0] == '!' && argv[1][1] == '\0') {
     223//assert(argc);
     224    /* remember if we saw argc==4 which wants *no* '!' test */
     225    _off = argc - 4;
     226    if (_off ?
     227        (LONE_CHAR(argv[1], '!'))
     228        : (argv[1][0] != '!' || argv[1][1] != '\0'))
     229    {
     230        if (argc == 3)
    214231            return *argv[2] != '\0';
     232
     233        t_lex(argv[2 + _off]);
     234        if (t_wp_op && t_wp_op->op_type == BINOP) {
     235            t_wp = &argv[1 + _off];
     236            return binop() == _off;
    215237        }
    216         break;
    217     case 4:
    218         if (argv[1][0] != '!' || argv[1][1] != '\0') {
    219             if (t_lex(argv[2]), t_wp_op && t_wp_op->op_type == BINOP) {
    220                 t_wp = &argv[1];
    221                 return binop() == 0;
    222             }
    223         }
    224         break;
    225     case 5:
    226         if (argv[1][0] == '!' && argv[1][1] == '\0') {
    227             if (t_lex(argv[3]), t_wp_op && t_wp_op->op_type == BINOP) {
    228                 t_wp = &argv[2];
    229                 return binop() != 0;
    230             }
    231         }
    232         break;
    233     }
    234 
     238    }
    235239    t_wp = &argv[1];
    236240    res = !oexpr(t_lex(*t_wp));
     
    243247}
    244248
     249static void syntax(const char *op, const char *msg) ATTRIBUTE_NORETURN;
    245250static void syntax(const char *op, const char *msg)
    246251{
     
    248253        bb_error_msg("%s: %s", op, msg);
    249254    } else {
    250         bb_error_msg("%s", msg);
     255        bb_error_msg("%s: %s"+4, msg);
    251256    }
    252257    longjmp(leaving, 2);
     
    300305        if (*++t_wp == NULL)
    301306            syntax(t_wp_op->op_text, "argument expected");
    302         switch (n) {
    303         case STREZ:
    304             return strlen(*t_wp) == 0;
    305         case STRNZ:
    306             return strlen(*t_wp) != 0;
    307         case FILTT:
     307        if (n == STREZ)
     308            return t_wp[0][0] == '\0';
     309        if (n == STRNZ)
     310            return t_wp[0][0] != '\0';
     311        if (n == FILTT)
    308312            return isatty(getn(*t_wp));
    309         default:
    310             return filstat(*t_wp, n);
    311         }
    312     }
    313 
    314     if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
     313        return filstat(*t_wp, n);
     314    }
     315
     316    t_lex(t_wp[1]);
     317    if (t_wp_op && t_wp_op->op_type == BINOP) {
    315318        return binop();
    316319    }
    317320
    318     return strlen(*t_wp) > 0;
     321    return t_wp[0][0] != '\0';
    319322}
    320323
     
    323326    const char *opnd1, *opnd2;
    324327    struct t_op const *op;
     328    arith_t val1, val2;
    325329
    326330    opnd1 = *t_wp;
     
    328332    op = t_wp_op;
    329333
    330     if ((opnd2 = *++t_wp) == (char *) 0)
     334    opnd2 = *++t_wp;
     335    if (opnd2 == NULL)
    331336        syntax(op->op_text, "argument expected");
    332337
    333     switch (op->op_num) {
    334     case STREQ:
    335         return strcmp(opnd1, opnd2) == 0;
    336     case STRNE:
    337         return strcmp(opnd1, opnd2) != 0;
    338     case STRLT:
    339         return strcmp(opnd1, opnd2) < 0;
    340     case STRGT:
    341         return strcmp(opnd1, opnd2) > 0;
    342     case INTEQ:
    343         return getn(opnd1) == getn(opnd2);
    344     case INTNE:
    345         return getn(opnd1) != getn(opnd2);
    346     case INTGE:
    347         return getn(opnd1) >= getn(opnd2);
    348     case INTGT:
    349         return getn(opnd1) > getn(opnd2);
    350     case INTLE:
    351         return getn(opnd1) <= getn(opnd2);
    352     case INTLT:
    353         return getn(opnd1) < getn(opnd2);
    354     case FILNT:
    355         return newerf(opnd1, opnd2);
    356     case FILOT:
    357         return olderf(opnd1, opnd2);
    358     case FILEQ:
    359         return equalf(opnd1, opnd2);
    360     }
    361     /* NOTREACHED */
    362     return 1;
     338    if (is_int_op(op->op_num)) {
     339        val1 = getn(opnd1);
     340        val2 = getn(opnd2);
     341        if (op->op_num == INTEQ)
     342            return val1 == val2;
     343        if (op->op_num == INTNE)
     344            return val1 != val2;
     345        if (op->op_num == INTGE)
     346            return val1 >= val2;
     347        if (op->op_num == INTGT)
     348            return val1 >  val2;
     349        if (op->op_num == INTLE)
     350            return val1 <= val2;
     351        if (op->op_num == INTLT)
     352            return val1 <  val2;
     353    }
     354    if (is_str_op(op->op_num)) {
     355        val1 = strcmp(opnd1, opnd2);
     356        if (op->op_num == STREQ)
     357            return val1 == 0;
     358        if (op->op_num == STRNE)
     359            return val1 != 0;
     360        if (op->op_num == STRLT)
     361            return val1 < 0;
     362        if (op->op_num == STRGT)
     363            return val1 > 0;
     364    }
     365    /* We are sure that these three are by now the only binops we didn't check
     366     * yet, so we do not check if the class is correct:
     367     */
     368/*  if (is_file_op(op->op_num)) */
     369    {
     370        struct stat b1, b2;
     371
     372        if (stat(opnd1, &b1) || stat(opnd2, &b2))
     373            return 0; /* false, since at least one stat failed */
     374        if (op->op_num == FILNT)
     375            return b1.st_mtime > b2.st_mtime;
     376        if (op->op_num == FILOT)
     377            return b1.st_mtime < b2.st_mtime;
     378        if (op->op_num == FILEQ)
     379            return b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino;
     380    }
     381    return 1; /* NOTREACHED */
    363382}
    364383
     
    366385{
    367386    struct stat s;
    368     unsigned int i;
     387    int i = i; /* gcc 3.x thinks it can be used uninitialized */
    369388
    370389    if (mode == FILSYM) {
     
    380399    if (stat(nm, &s) != 0)
    381400        return 0;
    382 
    383     switch (mode) {
    384     case FILRD:
    385         return test_eaccess(nm, R_OK) == 0;
    386     case FILWR:
    387         return test_eaccess(nm, W_OK) == 0;
    388     case FILEX:
    389         return test_eaccess(nm, X_OK) == 0;
    390     case FILEXIST:
     401    if (mode == FILEXIST)
    391402        return 1;
    392     case FILREG:
    393         i = S_IFREG;
    394         goto filetype;
    395     case FILDIR:
    396         i = S_IFDIR;
    397         goto filetype;
    398     case FILCDEV:
    399         i = S_IFCHR;
    400         goto filetype;
    401     case FILBDEV:
    402         i = S_IFBLK;
    403         goto filetype;
    404     case FILFIFO:
     403    if (is_file_access(mode)) {
     404        if (mode == FILRD)
     405            i = R_OK;
     406        if (mode == FILWR)
     407            i = W_OK;
     408        if (mode == FILEX)
     409            i = X_OK;
     410        return test_eaccess(nm, i) == 0;
     411    }
     412    if (is_file_type(mode)) {
     413        if (mode == FILREG)
     414            i = S_IFREG;
     415        if (mode == FILDIR)
     416            i = S_IFDIR;
     417        if (mode == FILCDEV)
     418            i = S_IFCHR;
     419        if (mode == FILBDEV)
     420            i = S_IFBLK;
     421        if (mode == FILFIFO) {
    405422#ifdef S_IFIFO
    406         i = S_IFIFO;
    407         goto filetype;
     423            i = S_IFIFO;
    408424#else
    409         return 0;
     425            return 0;
    410426#endif
    411     case FILSOCK:
     427        }
     428        if (mode == FILSOCK) {
    412429#ifdef S_IFSOCK
    413         i = S_IFSOCK;
    414         goto filetype;
     430            i = S_IFSOCK;
    415431#else
    416         return 0;
     432            return 0;
    417433#endif
    418     case FILSUID:
    419         i = S_ISUID;
    420         goto filebit;
    421     case FILSGID:
    422         i = S_ISGID;
    423         goto filebit;
    424     case FILSTCK:
    425         i = S_ISVTX;
    426         goto filebit;
    427     case FILGZ:
     434        }
     435 filetype:
     436        return ((s.st_mode & S_IFMT) == i);
     437    }
     438    if (is_file_bit(mode)) {
     439        if (mode == FILSUID)
     440            i = S_ISUID;
     441        if (mode == FILSGID)
     442            i = S_ISGID;
     443        if (mode == FILSTCK)
     444            i = S_ISVTX;
     445        return ((s.st_mode & i) != 0);
     446    }
     447    if (mode == FILGZ)
    428448        return s.st_size > 0L;
    429     case FILUID:
     449    if (mode == FILUID)
    430450        return s.st_uid == geteuid();
    431     case FILGID:
     451    if (mode == FILGID)
    432452        return s.st_gid == getegid();
    433     default:
    434         return 1;
    435     }
    436 
    437   filetype:
    438     return ((s.st_mode & S_IFMT) == i);
    439 
    440   filebit:
    441     return ((s.st_mode & i) != 0);
     453    return 1; /* NOTREACHED */
    442454}
    443455
    444456static enum token t_lex(char *s)
    445457{
    446     struct t_op const *op = ops;
    447 
    448     if (s == 0) {
    449         t_wp_op = (struct t_op *) 0;
     458    const struct t_op *op;
     459
     460    t_wp_op = NULL;
     461    if (s == NULL) {
    450462        return EOI;
    451463    }
    452     while (op->op_text) {
     464
     465    op = ops;
     466    do {
    453467        if (strcmp(s, op->op_text) == 0) {
    454468            t_wp_op = op;
     
    456470        }
    457471        op++;
    458     }
    459     t_wp_op = (struct t_op *) 0;
     472    } while (op < ops + ARRAY_SIZE(ops));
     473
    460474    return OPERAND;
    461475}
    462476
    463477/* atoi with error detection */
     478//XXX: FIXME: duplicate of existing libbb function?
    464479static arith_t getn(const char *s)
    465480{
    466481    char *p;
    467 #ifdef CONFIG_FEATURE_TEST_64
     482#if ENABLE_FEATURE_TEST_64
    468483    long long r;
    469484#else
     
    472487
    473488    errno = 0;
    474 #ifdef CONFIG_FEATURE_TEST_64
     489#if ENABLE_FEATURE_TEST_64
    475490    r = strtoll(s, &p, 10);
    476491#else
     
    487502}
    488503
     504/* UNUSED
    489505static int newerf(const char *f1, const char *f2)
    490506{
     
    511527            b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino);
    512528}
     529*/
    513530
    514531/* Do the same thing access(2) does, but use the effective uid and gid,
     
    521538
    522539    if (stat(path, &st) < 0)
    523         return (-1);
     540        return -1;
    524541
    525542    if (euid == 0) {
    526543        /* Root can read or write any file. */
    527544        if (mode != X_OK)
    528             return (0);
     545            return 0;
    529546
    530547        /* Root can execute any file that has any one of the execute
    531548           bits set. */
    532549        if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
    533             return (0);
     550            return 0;
    534551    }
    535552
     
    540557
    541558    if (st.st_mode & mode)
    542         return (0);
    543 
    544     return (-1);
     559        return 0;
     560
     561    return -1;
    545562}
    546563
     
    549566    ngroups = getgroups(0, NULL);
    550567    if (ngroups > 0) {
    551         group_array = xmalloc(ngroups * sizeof(gid_t));
     568        /* FIXME: ash tries so hard to not die on OOM,
     569         * and we spoil it with just one xrealloc here */
     570        /* We realloc, because test_main can be entered repeatedly by shell.
     571         * Testcase (ash): 'while true; do test -x some_file; done'
     572         * and watch top. (some_file must have owner != you) */
     573        group_array = xrealloc(group_array, ngroups * sizeof(gid_t));
    552574        getgroups(ngroups, group_array);
    553575    }
     
    555577
    556578/* Return non-zero if GID is one that we have in our groups list. */
     579//XXX: FIXME: duplicate of existing libbb function?
     580// see toplevel TODO file:
     581// possible code duplication ingroup() and is_a_group_member()
    557582static int is_a_group_member(gid_t gid)
    558583{
    559     register int i;
     584    int i;
    560585
    561586    /* Short-circuit if possible, maybe saving a call to getgroups(). */
    562587    if (gid == getgid() || gid == getegid())
    563         return (1);
     588        return 1;
    564589
    565590    if (ngroups == 0)
     
    569594    for (i = 0; i < ngroups; i++)
    570595        if (gid == group_array[i])
    571             return (1);
    572 
    573     return (0);
    574 }
    575 
    576 
    577 /* applet entry point */
    578 
    579 int test_main(int argc, char **argv)
    580 {
    581     exit(bb_test(argc, argv));
    582 }
    583 
     596            return 1;
     597
     598    return 0;
     599}
Note: See TracChangeset for help on using the changeset viewer.