Home | History | Annotate | Line # | Download | only in test
test.c revision 1.42
      1  1.42       kre /* $NetBSD: test.c,v 1.42 2018/09/12 23:33:31 kre Exp $ */
      2  1.15       cgd 
      3  1.13       jtc /*
      4  1.13       jtc  * test(1); version 7-like  --  author Erik Baalbergen
      5  1.13       jtc  * modified by Eric Gisin to be used as built-in.
      6  1.13       jtc  * modified by Arnold Robbins to add SVR3 compatibility
      7  1.13       jtc  * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
      8  1.13       jtc  * modified by J.T. Conklin for NetBSD.
      9   1.1     glass  *
     10  1.13       jtc  * This program is in the Public Domain.
     11   1.1     glass  */
     12   1.1     glass 
     13  1.17  christos #include <sys/cdefs.h>
     14   1.1     glass #ifndef lint
     15  1.42       kre __RCSID("$NetBSD: test.c,v 1.42 2018/09/12 23:33:31 kre Exp $");
     16  1.13       jtc #endif
     17   1.1     glass 
     18  1.23       wiz #include <sys/stat.h>
     19   1.1     glass #include <sys/types.h>
     20  1.23       wiz 
     21  1.13       jtc #include <ctype.h>
     22  1.23       wiz #include <err.h>
     23   1.1     glass #include <errno.h>
     24  1.33  christos #include <limits.h>
     25  1.35  christos #include <locale.h>
     26  1.13       jtc #include <stdio.h>
     27   1.1     glass #include <stdlib.h>
     28   1.1     glass #include <string.h>
     29  1.23       wiz #include <unistd.h>
     30  1.22  christos #include <stdarg.h>
     31   1.1     glass 
     32  1.13       jtc /* test(1) accepts the following grammar:
     33  1.13       jtc 	oexpr	::= aexpr | aexpr "-o" oexpr ;
     34  1.13       jtc 	aexpr	::= nexpr | nexpr "-a" aexpr ;
     35  1.14       cgd 	nexpr	::= primary | "!" primary
     36  1.13       jtc 	primary	::= unary-operator operand
     37  1.13       jtc 		| operand binary-operator operand
     38  1.13       jtc 		| operand
     39  1.13       jtc 		| "(" oexpr ")"
     40  1.13       jtc 		;
     41  1.13       jtc 	unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
     42  1.13       jtc 		"-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
     43  1.13       jtc 
     44  1.30   hubertf 	binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
     45  1.30   hubertf 			"-nt"|"-ot"|"-ef";
     46  1.13       jtc 	operand ::= <any legal UNIX file name>
     47  1.13       jtc */
     48  1.13       jtc 
     49  1.13       jtc enum token {
     50  1.13       jtc 	EOI,
     51  1.13       jtc 	FILRD,
     52  1.13       jtc 	FILWR,
     53  1.13       jtc 	FILEX,
     54  1.13       jtc 	FILEXIST,
     55  1.13       jtc 	FILREG,
     56  1.13       jtc 	FILDIR,
     57  1.13       jtc 	FILCDEV,
     58  1.13       jtc 	FILBDEV,
     59  1.13       jtc 	FILFIFO,
     60  1.13       jtc 	FILSOCK,
     61  1.13       jtc 	FILSYM,
     62  1.13       jtc 	FILGZ,
     63  1.13       jtc 	FILTT,
     64  1.13       jtc 	FILSUID,
     65  1.13       jtc 	FILSGID,
     66  1.13       jtc 	FILSTCK,
     67  1.13       jtc 	FILNT,
     68  1.13       jtc 	FILOT,
     69  1.13       jtc 	FILEQ,
     70  1.13       jtc 	FILUID,
     71  1.13       jtc 	FILGID,
     72  1.13       jtc 	STREZ,
     73  1.13       jtc 	STRNZ,
     74  1.13       jtc 	STREQ,
     75  1.13       jtc 	STRNE,
     76  1.13       jtc 	STRLT,
     77  1.13       jtc 	STRGT,
     78  1.13       jtc 	INTEQ,
     79  1.13       jtc 	INTNE,
     80  1.13       jtc 	INTGE,
     81  1.13       jtc 	INTGT,
     82  1.13       jtc 	INTLE,
     83  1.13       jtc 	INTLT,
     84  1.13       jtc 	UNOT,
     85  1.13       jtc 	BAND,
     86  1.13       jtc 	BOR,
     87  1.13       jtc 	LPAREN,
     88  1.13       jtc 	RPAREN,
     89  1.13       jtc 	OPERAND
     90  1.13       jtc };
     91   1.1     glass 
     92  1.13       jtc enum token_types {
     93  1.13       jtc 	UNOP,
     94  1.13       jtc 	BINOP,
     95  1.13       jtc 	BUNOP,
     96  1.13       jtc 	BBINOP,
     97  1.13       jtc 	PAREN
     98   1.1     glass };
     99   1.1     glass 
    100  1.31  christos struct t_op {
    101  1.13       jtc 	const char *op_text;
    102  1.13       jtc 	short op_num, op_type;
    103  1.31  christos };
    104  1.31  christos 
    105  1.31  christos static const struct t_op cop[] = {
    106  1.13       jtc 	{"!",	UNOT,	BUNOP},
    107  1.13       jtc 	{"(",	LPAREN,	PAREN},
    108  1.13       jtc 	{")",	RPAREN,	PAREN},
    109  1.31  christos 	{"<",	STRLT,	BINOP},
    110  1.31  christos 	{"=",	STREQ,	BINOP},
    111  1.31  christos 	{">",	STRGT,	BINOP},
    112  1.31  christos };
    113  1.31  christos 
    114  1.31  christos static const struct t_op cop2[] = {
    115  1.31  christos 	{"!=",	STRNE,	BINOP},
    116  1.31  christos };
    117  1.31  christos 
    118  1.31  christos static const struct t_op mop3[] = {
    119  1.31  christos 	{"ef",	FILEQ,	BINOP},
    120  1.31  christos 	{"eq",	INTEQ,	BINOP},
    121  1.31  christos 	{"ge",	INTGE,	BINOP},
    122  1.31  christos 	{"gt",	INTGT,	BINOP},
    123  1.31  christos 	{"le",	INTLE,	BINOP},
    124  1.31  christos 	{"lt",	INTLT,	BINOP},
    125  1.31  christos 	{"ne",	INTNE,	BINOP},
    126  1.31  christos 	{"nt",	FILNT,	BINOP},
    127  1.31  christos 	{"ot",	FILOT,	BINOP},
    128  1.31  christos };
    129  1.31  christos 
    130  1.31  christos static const struct t_op mop2[] = {
    131  1.31  christos 	{"G",	FILGID,	UNOP},
    132  1.31  christos 	{"L",	FILSYM,	UNOP},
    133  1.31  christos 	{"O",	FILUID,	UNOP},
    134  1.31  christos 	{"S",	FILSOCK,UNOP},
    135  1.31  christos 	{"a",	BAND,	BBINOP},
    136  1.31  christos 	{"b",	FILBDEV,UNOP},
    137  1.31  christos 	{"c",	FILCDEV,UNOP},
    138  1.31  christos 	{"d",	FILDIR,	UNOP},
    139  1.31  christos 	{"e",	FILEXIST,UNOP},
    140  1.31  christos 	{"f",	FILREG,	UNOP},
    141  1.31  christos 	{"g",	FILSGID,UNOP},
    142  1.31  christos 	{"h",	FILSYM,	UNOP},		/* for backwards compat */
    143  1.31  christos 	{"k",	FILSTCK,UNOP},
    144  1.31  christos 	{"n",	STRNZ,	UNOP},
    145  1.31  christos 	{"o",	BOR,	BBINOP},
    146  1.31  christos 	{"p",	FILFIFO,UNOP},
    147  1.31  christos 	{"r",	FILRD,	UNOP},
    148  1.31  christos 	{"s",	FILGZ,	UNOP},
    149  1.31  christos 	{"t",	FILTT,	UNOP},
    150  1.31  christos 	{"u",	FILSUID,UNOP},
    151  1.31  christos 	{"w",	FILWR,	UNOP},
    152  1.31  christos 	{"x",	FILEX,	UNOP},
    153  1.31  christos 	{"z",	STREZ,	UNOP},
    154   1.1     glass };
    155   1.1     glass 
    156  1.22  christos static char **t_wp;
    157  1.22  christos static struct t_op const *t_wp_op;
    158   1.1     glass 
    159  1.38     joerg __dead static void syntax(const char *, const char *);
    160  1.23       wiz static int oexpr(enum token);
    161  1.23       wiz static int aexpr(enum token);
    162  1.23       wiz static int nexpr(enum token);
    163  1.42       kre static struct t_op const *findop(const char *);
    164  1.23       wiz static int primary(enum token);
    165  1.23       wiz static int binop(void);
    166  1.42       kre static int perform_unop(enum token, const char *);
    167  1.42       kre static int perform_binop(enum token, const char *, const char *);
    168  1.33  christos static int test_access(struct stat *, mode_t);
    169  1.42       kre static int filstat(const char *, enum token);
    170  1.23       wiz static enum token t_lex(char *);
    171  1.23       wiz static int isoperand(void);
    172  1.36  christos static long long getn(const char *);
    173  1.23       wiz static int newerf(const char *, const char *);
    174  1.23       wiz static int olderf(const char *, const char *);
    175  1.23       wiz static int equalf(const char *, const char *);
    176  1.17  christos 
    177  1.42       kre static int one_arg(const char *);
    178  1.42       kre static int two_arg(const char *, const char *);
    179  1.42       kre static int three_arg(const char *, const char *, const char *);
    180  1.42       kre static int four_arg(const char *, const char *, const char *, const char *);
    181  1.42       kre 
    182  1.22  christos #if defined(SHELL)
    183  1.39     joerg extern void error(const char *, ...) __dead __printflike(1, 2);
    184  1.33  christos extern void *ckmalloc(size_t);
    185  1.22  christos #else
    186  1.39     joerg static void error(const char *, ...) __dead __printflike(1, 2);
    187  1.22  christos 
    188  1.22  christos static void
    189  1.22  christos error(const char *msg, ...)
    190  1.22  christos {
    191  1.22  christos 	va_list ap;
    192  1.22  christos 
    193  1.22  christos 	va_start(ap, msg);
    194  1.22  christos 	verrx(2, msg, ap);
    195  1.22  christos 	/*NOTREACHED*/
    196  1.22  christos 	va_end(ap);
    197  1.22  christos }
    198  1.33  christos 
    199  1.33  christos static void *ckmalloc(size_t);
    200  1.33  christos static void *
    201  1.33  christos ckmalloc(size_t nbytes)
    202  1.33  christos {
    203  1.33  christos 	void *p = malloc(nbytes);
    204  1.33  christos 
    205  1.33  christos 	if (!p)
    206  1.33  christos 		error("Not enough memory!");
    207  1.33  christos 	return p;
    208  1.33  christos }
    209  1.22  christos #endif
    210  1.22  christos 
    211  1.22  christos #ifdef SHELL
    212  1.23       wiz int testcmd(int, char **);
    213  1.22  christos 
    214  1.22  christos int
    215  1.23       wiz testcmd(int argc, char **argv)
    216  1.22  christos #else
    217   1.1     glass int
    218  1.24       wiz main(int argc, char *argv[])
    219  1.22  christos #endif
    220   1.1     glass {
    221  1.24       wiz 	int res;
    222  1.28  christos 	const char *argv0;
    223  1.22  christos 
    224  1.28  christos #ifdef SHELL
    225  1.28  christos 	argv0 = argv[0];
    226  1.28  christos #else
    227  1.24       wiz 	setprogname(argv[0]);
    228  1.35  christos 	(void)setlocale(LC_ALL, "");
    229  1.28  christos 	argv0 = getprogname();
    230  1.28  christos #endif
    231  1.28  christos 	if (strcmp(argv0, "[") == 0) {
    232   1.1     glass 		if (strcmp(argv[--argc], "]"))
    233  1.22  christos 			error("missing ]");
    234   1.1     glass 		argv[argc] = NULL;
    235   1.1     glass 	}
    236   1.1     glass 
    237  1.42       kre 	/*
    238  1.42       kre 	 * POSIX defines operations of test for up to 4 args
    239  1.42       kre 	 * (depending upon what the args are in some cases)
    240  1.42       kre 	 *
    241  1.42       kre 	 * arg count does not include the command name, (but argc does)
    242  1.42       kre 	 * nor the closing ']' when the command was '[' (removed above)
    243  1.42       kre 	 *
    244  1.42       kre 	 * None of the following allow -a or -o as an operator (those
    245  1.42       kre 	 * only apply in the evaluation of unspeicified expressions)
    246  1.42       kre 	 *
    247  1.42       kre 	 * Note that the xxx_arg() functions return "shell" true/false
    248  1.42       kre 	 * (0 == true, 1 == false) or -1 for "unspecified case"
    249  1.42       kre 	 *
    250  1.42       kre 	 * Other functions return C true/false (1 == true, 0 == false)
    251  1.42       kre 	 *
    252  1.42       kre 	 * Hence we simply return the result from xxx_arg(), but
    253  1.42       kre 	 * invert the result of oexpr() below before returning it.
    254  1.42       kre 	 */
    255  1.42       kre 	switch (argc - 1) {
    256  1.42       kre 	case -1:		/* impossible, but never mind */
    257  1.42       kre 	case 0:			/* test $a    where a=''    false */
    258  1.22  christos 		return 1;
    259  1.22  christos 
    260  1.42       kre 	case 1:			/* test "$a" */
    261  1.42       kre 		return one_arg(argv[1]);		/* always works */
    262  1.42       kre 
    263  1.42       kre 	case 2:			/* test op "$a" */
    264  1.42       kre 		res = two_arg(argv[1], argv[2]);
    265  1.42       kre 		if (res >= 0)
    266  1.42       kre 			return res;
    267  1.42       kre 		break;
    268  1.42       kre 
    269  1.42       kre 	case 3:			/* test "$a" op "$b" or test ! op "$a" */
    270  1.42       kre 		res = three_arg(argv[1], argv[2], argv[3]);
    271  1.42       kre 		if (res >= 0)
    272  1.42       kre 			return res;
    273  1.42       kre 		break;
    274  1.42       kre 
    275  1.42       kre 	case 4:			/* test ! "$a" op "$b" or test ( op "$a" ) */
    276  1.42       kre 		res = four_arg(argv[1], argv[2], argv[3], argv[4]);
    277  1.42       kre 		if (res >= 0)
    278  1.42       kre 			return res;
    279  1.42       kre 		break;
    280  1.42       kre 
    281  1.42       kre 	default:
    282  1.42       kre 		break;
    283  1.42       kre 	}
    284  1.42       kre 
    285  1.42       kre 	/*
    286  1.42       kre 	 * All other cases produce unspecified results
    287  1.42       kre 	 * (including cases above with small arg counts where the
    288  1.42       kre 	 * args are not what was expected to be seen)
    289  1.42       kre 	 *
    290  1.42       kre 	 * We fall back to the old method, of attempting to parse
    291  1.42       kre 	 * the expr (highly ambiguous as there is no distinction between
    292  1.42       kre 	 * operators and operands that happen to look like operators)
    293  1.42       kre 	 */
    294  1.42       kre 
    295  1.14       cgd 	t_wp = &argv[1];
    296  1.13       jtc 	res = !oexpr(t_lex(*t_wp));
    297  1.13       jtc 
    298  1.13       jtc 	if (*t_wp != NULL && *++t_wp != NULL)
    299  1.21    kleink 		syntax(*t_wp, "unexpected operator");
    300  1.13       jtc 
    301  1.13       jtc 	return res;
    302  1.13       jtc }
    303  1.13       jtc 
    304  1.13       jtc static void
    305  1.23       wiz syntax(const char *op, const char *msg)
    306  1.13       jtc {
    307  1.26    simonb 
    308  1.13       jtc 	if (op && *op)
    309  1.22  christos 		error("%s: %s", op, msg);
    310  1.13       jtc 	else
    311  1.22  christos 		error("%s", msg);
    312  1.42       kre }
    313  1.42       kre 
    314  1.42       kre static int
    315  1.42       kre one_arg(const char *arg)
    316  1.42       kre {
    317  1.42       kre 	/*
    318  1.42       kre 	 * True (exit 0, so false...) if arg is not a null string
    319  1.42       kre 	 * False (so exit 1, so true) if it is.
    320  1.42       kre 	 */
    321  1.42       kre 	return *arg == '\0';
    322  1.42       kre }
    323  1.42       kre 
    324  1.42       kre static int
    325  1.42       kre two_arg(const char *a1, const char *a2)
    326  1.42       kre {
    327  1.42       kre 	static struct t_op const *op;
    328  1.42       kre 
    329  1.42       kre 	if (a1[0] == '!' && a1[1] == 0)
    330  1.42       kre 		return !one_arg(a2);
    331  1.42       kre 
    332  1.42       kre 	op = findop(a1);
    333  1.42       kre 	if (op != NULL && op->op_type == UNOP)
    334  1.42       kre 		return !perform_unop(op->op_num, a2);
    335  1.42       kre 
    336  1.42       kre 	/*
    337  1.42       kre 	 * an extension, but as we've entered the realm of the unspecified
    338  1.42       kre 	 * we're allowed...		test ( $a )	where a=''
    339  1.42       kre 	 */
    340  1.42       kre 	if (a1[0] == '(' && a2[0] == ')' && (a1[1] | a2[1]) == 0)
    341  1.42       kre 		return 1;
    342  1.42       kre 
    343  1.42       kre 	return -1;
    344  1.42       kre }
    345  1.42       kre 
    346  1.42       kre static int
    347  1.42       kre three_arg(const char *a1, const char *a2, const char *a3)
    348  1.42       kre {
    349  1.42       kre 	static struct t_op const *op;
    350  1.42       kre 	int res;
    351  1.42       kre 
    352  1.42       kre 	op = findop(a2);
    353  1.42       kre 	if (op != NULL && op->op_type == BINOP)
    354  1.42       kre 		return !perform_binop(op->op_num, a1, a3);
    355  1.42       kre 
    356  1.42       kre 	if (a1[1] != '\0')
    357  1.42       kre 		return -1;
    358  1.42       kre 
    359  1.42       kre 	if (a1[0] == '!') {
    360  1.42       kre 		res = two_arg(a2, a3);
    361  1.42       kre 		if (res >= 0)
    362  1.42       kre 			res = !res;
    363  1.42       kre 		return res;
    364  1.42       kre 	}
    365  1.42       kre 
    366  1.42       kre 	if (a1[0] == '(' && a3[0] == ')' && a3[1] == '\0')
    367  1.42       kre 		return one_arg(a2);
    368  1.42       kre 
    369  1.42       kre 	return -1;
    370  1.42       kre }
    371  1.42       kre 
    372  1.42       kre static int
    373  1.42       kre four_arg(const char *a1, const char *a2, const char *a3, const char *a4)
    374  1.42       kre {
    375  1.42       kre 	int res;
    376  1.42       kre 
    377  1.42       kre 	if (a1[1] != '\0')
    378  1.42       kre 		return -1;
    379  1.42       kre 
    380  1.42       kre 	if (a1[0] == '!') {
    381  1.42       kre 		res = three_arg(a2, a3, a4);
    382  1.42       kre 		if (res >= 0)
    383  1.42       kre 			res = !res;
    384  1.42       kre 		return res;
    385  1.42       kre 	}
    386  1.42       kre 
    387  1.42       kre 	if (a1[0] == '(' && a4[0] == ')' && a4[1] == '\0')
    388  1.42       kre 		return two_arg(a2, a3);
    389  1.42       kre 
    390  1.42       kre 	return -1;
    391  1.13       jtc }
    392  1.13       jtc 
    393  1.13       jtc static int
    394  1.23       wiz oexpr(enum token n)
    395  1.13       jtc {
    396  1.13       jtc 	int res;
    397  1.13       jtc 
    398  1.13       jtc 	res = aexpr(n);
    399  1.32  christos 	if (*t_wp == NULL)
    400  1.32  christos 		return res;
    401  1.13       jtc 	if (t_lex(*++t_wp) == BOR)
    402  1.13       jtc 		return oexpr(t_lex(*++t_wp)) || res;
    403  1.13       jtc 	t_wp--;
    404  1.13       jtc 	return res;
    405  1.13       jtc }
    406  1.13       jtc 
    407  1.13       jtc static int
    408  1.23       wiz aexpr(enum token n)
    409  1.13       jtc {
    410  1.13       jtc 	int res;
    411  1.13       jtc 
    412  1.13       jtc 	res = nexpr(n);
    413  1.32  christos 	if (*t_wp == NULL)
    414  1.32  christos 		return res;
    415  1.13       jtc 	if (t_lex(*++t_wp) == BAND)
    416  1.13       jtc 		return aexpr(t_lex(*++t_wp)) && res;
    417  1.13       jtc 	t_wp--;
    418  1.13       jtc 	return res;
    419  1.13       jtc }
    420  1.13       jtc 
    421  1.13       jtc static int
    422  1.23       wiz nexpr(enum token n)
    423  1.13       jtc {
    424  1.26    simonb 
    425  1.13       jtc 	if (n == UNOT)
    426  1.13       jtc 		return !nexpr(t_lex(*++t_wp));
    427  1.13       jtc 	return primary(n);
    428  1.13       jtc }
    429  1.13       jtc 
    430  1.13       jtc static int
    431  1.23       wiz primary(enum token n)
    432  1.13       jtc {
    433  1.21    kleink 	enum token nn;
    434  1.13       jtc 	int res;
    435  1.13       jtc 
    436  1.13       jtc 	if (n == EOI)
    437  1.21    kleink 		return 0;		/* missing expression */
    438  1.13       jtc 	if (n == LPAREN) {
    439  1.21    kleink 		if ((nn = t_lex(*++t_wp)) == RPAREN)
    440  1.21    kleink 			return 0;	/* missing expression */
    441  1.21    kleink 		res = oexpr(nn);
    442  1.13       jtc 		if (t_lex(*++t_wp) != RPAREN)
    443  1.13       jtc 			syntax(NULL, "closing paren expected");
    444  1.13       jtc 		return res;
    445   1.1     glass 	}
    446  1.13       jtc 	if (t_wp_op && t_wp_op->op_type == UNOP) {
    447  1.13       jtc 		/* unary expression */
    448  1.13       jtc 		if (*++t_wp == NULL)
    449  1.13       jtc 			syntax(t_wp_op->op_text, "argument expected");
    450  1.42       kre 		return perform_unop(n, *t_wp);
    451  1.13       jtc 	}
    452  1.14       cgd 
    453  1.14       cgd 	if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) {
    454  1.14       cgd 		return binop();
    455  1.14       cgd 	}
    456  1.14       cgd 
    457  1.14       cgd 	return strlen(*t_wp) > 0;
    458  1.14       cgd }
    459  1.14       cgd 
    460  1.14       cgd static int
    461  1.42       kre perform_unop(enum token n, const char *opnd)
    462  1.42       kre {
    463  1.42       kre 	switch (n) {
    464  1.42       kre 	case STREZ:
    465  1.42       kre 		return strlen(opnd) == 0;
    466  1.42       kre 	case STRNZ:
    467  1.42       kre 		return strlen(opnd) != 0;
    468  1.42       kre 	case FILTT:
    469  1.42       kre 		return isatty((int)getn(opnd));
    470  1.42       kre 	default:
    471  1.42       kre 		return filstat(opnd, n);
    472  1.42       kre 	}
    473  1.42       kre }
    474  1.42       kre 
    475  1.42       kre static int
    476  1.23       wiz binop(void)
    477  1.14       cgd {
    478  1.16       tls 	const char *opnd1, *opnd2;
    479  1.14       cgd 	struct t_op const *op;
    480  1.14       cgd 
    481  1.13       jtc 	opnd1 = *t_wp;
    482  1.13       jtc 	(void) t_lex(*++t_wp);
    483  1.14       cgd 	op = t_wp_op;
    484  1.13       jtc 
    485  1.26    simonb 	if ((opnd2 = *++t_wp) == NULL)
    486  1.14       cgd 		syntax(op->op_text, "argument expected");
    487  1.13       jtc 
    488  1.42       kre 	return perform_binop(op->op_num, opnd1, opnd2);
    489  1.42       kre }
    490  1.42       kre 
    491  1.42       kre static int
    492  1.42       kre perform_binop(enum token op_num, const char *opnd1, const char *opnd2)
    493  1.42       kre {
    494  1.42       kre 	switch (op_num) {
    495  1.14       cgd 	case STREQ:
    496  1.14       cgd 		return strcmp(opnd1, opnd2) == 0;
    497  1.14       cgd 	case STRNE:
    498  1.14       cgd 		return strcmp(opnd1, opnd2) != 0;
    499  1.14       cgd 	case STRLT:
    500  1.14       cgd 		return strcmp(opnd1, opnd2) < 0;
    501  1.14       cgd 	case STRGT:
    502  1.14       cgd 		return strcmp(opnd1, opnd2) > 0;
    503  1.14       cgd 	case INTEQ:
    504  1.14       cgd 		return getn(opnd1) == getn(opnd2);
    505  1.14       cgd 	case INTNE:
    506  1.14       cgd 		return getn(opnd1) != getn(opnd2);
    507  1.14       cgd 	case INTGE:
    508  1.14       cgd 		return getn(opnd1) >= getn(opnd2);
    509  1.14       cgd 	case INTGT:
    510  1.14       cgd 		return getn(opnd1) > getn(opnd2);
    511  1.14       cgd 	case INTLE:
    512  1.14       cgd 		return getn(opnd1) <= getn(opnd2);
    513  1.14       cgd 	case INTLT:
    514  1.14       cgd 		return getn(opnd1) < getn(opnd2);
    515  1.14       cgd 	case FILNT:
    516  1.26    simonb 		return newerf(opnd1, opnd2);
    517  1.14       cgd 	case FILOT:
    518  1.26    simonb 		return olderf(opnd1, opnd2);
    519  1.14       cgd 	case FILEQ:
    520  1.26    simonb 		return equalf(opnd1, opnd2);
    521  1.17  christos 	default:
    522  1.19   mycroft 		abort();
    523  1.17  christos 		/* NOTREACHED */
    524   1.1     glass 	}
    525   1.1     glass }
    526   1.1     glass 
    527  1.33  christos /*
    528  1.33  christos  * The manual, and IEEE POSIX 1003.2, suggests this should check the mode bits,
    529  1.33  christos  * not use access():
    530  1.33  christos  *
    531  1.33  christos  *	True shall indicate only that the write flag is on.  The file is not
    532  1.33  christos  *	writable on a read-only file system even if this test indicates true.
    533  1.33  christos  *
    534  1.33  christos  * Unfortunately IEEE POSIX 1003.1-2001, as quoted in SuSv3, says only:
    535  1.33  christos  *
    536  1.33  christos  *	True shall indicate that permission to read from file will be granted,
    537  1.33  christos  *	as defined in "File Read, Write, and Creation".
    538  1.33  christos  *
    539  1.33  christos  * and that section says:
    540  1.33  christos  *
    541  1.33  christos  *	When a file is to be read or written, the file shall be opened with an
    542  1.33  christos  *	access mode corresponding to the operation to be performed.  If file
    543  1.33  christos  *	access permissions deny access, the requested operation shall fail.
    544  1.33  christos  *
    545  1.33  christos  * and of course access permissions are described as one might expect:
    546  1.33  christos  *
    547  1.33  christos  *     * If a process has the appropriate privilege:
    548  1.33  christos  *
    549  1.33  christos  *        * If read, write, or directory search permission is requested,
    550  1.33  christos  *          access shall be granted.
    551  1.33  christos  *
    552  1.33  christos  *        * If execute permission is requested, access shall be granted if
    553  1.33  christos  *          execute permission is granted to at least one user by the file
    554  1.33  christos  *          permission bits or by an alternate access control mechanism;
    555  1.33  christos  *          otherwise, access shall be denied.
    556  1.33  christos  *
    557  1.33  christos  *   * Otherwise:
    558  1.33  christos  *
    559  1.33  christos  *        * The file permission bits of a file contain read, write, and
    560  1.33  christos  *          execute/search permissions for the file owner class, file group
    561  1.33  christos  *          class, and file other class.
    562  1.33  christos  *
    563  1.33  christos  *        * Access shall be granted if an alternate access control mechanism
    564  1.33  christos  *          is not enabled and the requested access permission bit is set for
    565  1.33  christos  *          the class (file owner class, file group class, or file other class)
    566  1.33  christos  *          to which the process belongs, or if an alternate access control
    567  1.33  christos  *          mechanism is enabled and it allows the requested access; otherwise,
    568  1.33  christos  *          access shall be denied.
    569  1.33  christos  *
    570  1.33  christos  * and when I first read this I thought:  surely we can't go about using
    571  1.33  christos  * open(O_WRONLY) to try this test!  However the POSIX 1003.1-2001 Rationale
    572  1.33  christos  * section for test does in fact say:
    573  1.33  christos  *
    574  1.33  christos  *	On historical BSD systems, test -w directory always returned false
    575  1.33  christos  *	because test tried to open the directory for writing, which always
    576  1.33  christos  *	fails.
    577  1.33  christos  *
    578  1.33  christos  * and indeed this is in fact true for Seventh Edition UNIX, UNIX 32V, and UNIX
    579  1.33  christos  * System III, and thus presumably also for BSD up to and including 4.3.
    580  1.33  christos  *
    581  1.33  christos  * Secondly I remembered why using open() and/or access() are bogus.  They
    582  1.33  christos  * don't work right for detecting read and write permissions bits when called
    583  1.33  christos  * by root.
    584  1.33  christos  *
    585  1.33  christos  * Interestingly the 'test' in 4.4BSD was closer to correct (as per
    586  1.33  christos  * 1003.2-1992) and it was implemented efficiently with stat() instead of
    587  1.33  christos  * open().
    588  1.33  christos  *
    589  1.33  christos  * This was apparently broken in NetBSD around about 1994/06/30 when the old
    590  1.33  christos  * 4.4BSD implementation was replaced with a (arguably much better coded)
    591  1.33  christos  * implementation derived from pdksh.
    592  1.33  christos  *
    593  1.33  christos  * Note that modern pdksh is yet different again, but still not correct, at
    594  1.33  christos  * least not w.r.t. 1003.2-1992.
    595  1.33  christos  *
    596  1.33  christos  * As I think more about it and read more of the related IEEE docs I don't like
    597  1.33  christos  * that wording about 'test -r' and 'test -w' in 1003.1-2001 at all.  I very
    598  1.33  christos  * much prefer the original wording in 1003.2-1992.  It is much more useful,
    599  1.33  christos  * and so that's what I've implemented.
    600  1.33  christos  *
    601  1.33  christos  * (Note that a strictly conforming implementation of 1003.1-2001 is in fact
    602  1.33  christos  * totally useless for the case in question since its 'test -w' and 'test -r'
    603  1.33  christos  * can never fail for root for any existing files, i.e. files for which 'test
    604  1.33  christos  * -e' succeeds.)
    605  1.33  christos  *
    606  1.33  christos  * The rationale for 1003.1-2001 suggests that the wording was "clarified" in
    607  1.33  christos  * 1003.1-2001 to align with the 1003.2b draft.  1003.2b Draft 12 (July 1999),
    608  1.33  christos  * which is the latest copy I have, does carry the same suggested wording as is
    609  1.33  christos  * in 1003.1-2001, with its rationale saying:
    610  1.33  christos  *
    611  1.33  christos  * 	This change is a clarification and is the result of interpretation
    612  1.33  christos  * 	request PASC 1003.2-92 #23 submitted for IEEE Std 1003.2-1992.
    613  1.33  christos  *
    614  1.33  christos  * That interpretation can be found here:
    615  1.33  christos  *
    616  1.33  christos  *   http://www.pasc.org/interps/unofficial/db/p1003.2/pasc-1003.2-23.html
    617  1.33  christos  *
    618  1.33  christos  * Not terribly helpful, unfortunately.  I wonder who that fence sitter was.
    619  1.33  christos  *
    620  1.33  christos  * Worse, IMVNSHO, I think the authors of 1003.2b-D12 have mis-interpreted the
    621  1.33  christos  * PASC interpretation and appear to be gone against at least one widely used
    622  1.33  christos  * implementation (namely 4.4BSD).  The problem is that for file access by root
    623  1.33  christos  * this means that if test '-r' and '-w' are to behave as if open() were called
    624  1.33  christos  * then there's no way for a shell script running as root to check if a file
    625  1.33  christos  * has certain access bits set other than by the grotty means of interpreting
    626  1.33  christos  * the output of 'ls -l'.  This was widely considered to be a bug in V7's
    627  1.33  christos  * "test" and is, I believe, one of the reasons why direct use of access() was
    628  1.33  christos  * avoided in some more recent implementations!
    629  1.33  christos  *
    630  1.33  christos  * I have always interpreted '-r' to match '-w' and '-x' as per the original
    631  1.33  christos  * wording in 1003.2-1992, not the other way around.  I think 1003.2b goes much
    632  1.33  christos  * too far the wrong way without any valid rationale and that it's best if we
    633  1.33  christos  * stick with 1003.2-1992 and test the flags, and not mimic the behaviour of
    634  1.33  christos  * open() since we already know very well how it will work -- existance of the
    635  1.33  christos  * file is all that matters to open() for root.
    636  1.33  christos  *
    637  1.33  christos  * Unfortunately the SVID is no help at all (which is, I guess, partly why
    638  1.33  christos  * we're in this mess in the first place :-).
    639  1.33  christos  *
    640  1.33  christos  * The SysV implementation (at least in the 'test' builtin in /bin/sh) does use
    641  1.33  christos  * access(name, 2) even though it also goes to much greater lengths for '-x'
    642  1.33  christos  * matching the 1003.2-1992 definition (which is no doubt where that definition
    643  1.33  christos  * came from).
    644  1.33  christos  *
    645  1.33  christos  * The ksh93 implementation uses access() for '-r' and '-w' if
    646  1.33  christos  * (euid==uid&&egid==gid), but uses st_mode for '-x' iff running as root.
    647  1.33  christos  * i.e. it does strictly conform to 1003.1-2001 (and presumably 1003.2b).
    648  1.33  christos  */
    649  1.33  christos static int
    650  1.33  christos test_access(struct stat *sp, mode_t stmode)
    651  1.33  christos {
    652  1.33  christos 	gid_t *groups;
    653  1.33  christos 	register int n;
    654  1.33  christos 	uid_t euid;
    655  1.33  christos 	int maxgroups;
    656  1.33  christos 
    657  1.33  christos 	/*
    658  1.33  christos 	 * I suppose we could use access() if not running as root and if we are
    659  1.33  christos 	 * running with ((euid == uid) && (egid == gid)), but we've already
    660  1.33  christos 	 * done the stat() so we might as well just test the permissions
    661  1.33  christos 	 * directly instead of asking the kernel to do it....
    662  1.33  christos 	 */
    663  1.33  christos 	euid = geteuid();
    664  1.33  christos 	if (euid == 0)				/* any bit is good enough */
    665  1.33  christos 		stmode = (stmode << 6) | (stmode << 3) | stmode;
    666  1.33  christos  	else if (sp->st_uid == euid)
    667  1.33  christos 		stmode <<= 6;
    668  1.33  christos 	else if (sp->st_gid == getegid())
    669  1.33  christos 		stmode <<= 3;
    670  1.33  christos 	else {
    671  1.33  christos 		/* XXX stolen almost verbatim from ksh93.... */
    672  1.33  christos 		/* on some systems you can be in several groups */
    673  1.33  christos 		if ((maxgroups = getgroups(0, NULL)) <= 0)
    674  1.33  christos 			maxgroups = NGROUPS_MAX;	/* pre-POSIX system? */
    675  1.33  christos 		groups = ckmalloc((maxgroups + 1) * sizeof(gid_t));
    676  1.33  christos 		n = getgroups(maxgroups, groups);
    677  1.33  christos 		while (--n >= 0) {
    678  1.33  christos 			if (groups[n] == sp->st_gid) {
    679  1.33  christos 				stmode <<= 3;
    680  1.33  christos 				break;
    681  1.33  christos 			}
    682  1.33  christos 		}
    683  1.33  christos 		free(groups);
    684  1.33  christos 	}
    685  1.33  christos 
    686  1.33  christos 	return sp->st_mode & stmode;
    687  1.33  christos }
    688  1.33  christos 
    689   1.1     glass static int
    690  1.42       kre filstat(const char *nm, enum token mode)
    691   1.1     glass {
    692  1.13       jtc 	struct stat s;
    693  1.13       jtc 
    694  1.18   mycroft 	if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s))
    695  1.13       jtc 		return 0;
    696   1.1     glass 
    697  1.13       jtc 	switch (mode) {
    698  1.13       jtc 	case FILRD:
    699  1.33  christos 		return test_access(&s, S_IROTH);
    700  1.13       jtc 	case FILWR:
    701  1.33  christos 		return test_access(&s, S_IWOTH);
    702  1.13       jtc 	case FILEX:
    703  1.33  christos 		return test_access(&s, S_IXOTH);
    704  1.13       jtc 	case FILEXIST:
    705  1.33  christos 		return 1; /* the successful lstat()/stat() is good enough */
    706  1.13       jtc 	case FILREG:
    707  1.18   mycroft 		return S_ISREG(s.st_mode);
    708  1.13       jtc 	case FILDIR:
    709  1.18   mycroft 		return S_ISDIR(s.st_mode);
    710  1.13       jtc 	case FILCDEV:
    711  1.18   mycroft 		return S_ISCHR(s.st_mode);
    712  1.13       jtc 	case FILBDEV:
    713  1.18   mycroft 		return S_ISBLK(s.st_mode);
    714  1.13       jtc 	case FILFIFO:
    715  1.18   mycroft 		return S_ISFIFO(s.st_mode);
    716  1.13       jtc 	case FILSOCK:
    717  1.18   mycroft 		return S_ISSOCK(s.st_mode);
    718  1.18   mycroft 	case FILSYM:
    719  1.18   mycroft 		return S_ISLNK(s.st_mode);
    720  1.13       jtc 	case FILSUID:
    721  1.18   mycroft 		return (s.st_mode & S_ISUID) != 0;
    722  1.13       jtc 	case FILSGID:
    723  1.18   mycroft 		return (s.st_mode & S_ISGID) != 0;
    724  1.13       jtc 	case FILSTCK:
    725  1.18   mycroft 		return (s.st_mode & S_ISVTX) != 0;
    726  1.13       jtc 	case FILGZ:
    727  1.18   mycroft 		return s.st_size > (off_t)0;
    728  1.13       jtc 	case FILUID:
    729  1.13       jtc 		return s.st_uid == geteuid();
    730  1.13       jtc 	case FILGID:
    731  1.13       jtc 		return s.st_gid == getegid();
    732  1.13       jtc 	default:
    733  1.13       jtc 		return 1;
    734  1.13       jtc 	}
    735   1.1     glass }
    736   1.1     glass 
    737  1.31  christos #define VTOC(x)	(const unsigned char *)((const struct t_op *)x)->op_text
    738  1.31  christos 
    739  1.31  christos static int
    740  1.31  christos compare1(const void *va, const void *vb)
    741  1.31  christos {
    742  1.31  christos 	const unsigned char *a = va;
    743  1.31  christos 	const unsigned char *b = VTOC(vb);
    744  1.31  christos 
    745  1.31  christos 	return a[0] - b[0];
    746  1.31  christos }
    747  1.31  christos 
    748  1.31  christos static int
    749  1.31  christos compare2(const void *va, const void *vb)
    750  1.31  christos {
    751  1.31  christos 	const unsigned char *a = va;
    752  1.31  christos 	const unsigned char *b = VTOC(vb);
    753  1.31  christos 	int z = a[0] - b[0];
    754  1.31  christos 
    755  1.31  christos 	return z ? z : (a[1] - b[1]);
    756  1.31  christos }
    757  1.31  christos 
    758  1.31  christos static struct t_op const *
    759  1.31  christos findop(const char *s)
    760  1.31  christos {
    761  1.31  christos 	if (s[0] == '-') {
    762  1.31  christos 		if (s[1] == '\0')
    763  1.31  christos 			return NULL;
    764  1.31  christos 		if (s[2] == '\0')
    765  1.31  christos 			return bsearch(s + 1, mop2, __arraycount(mop2),
    766  1.31  christos 			    sizeof(*mop2), compare1);
    767  1.31  christos 		else if (s[3] != '\0')
    768  1.31  christos 			return NULL;
    769  1.31  christos 		else
    770  1.31  christos 			return bsearch(s + 1, mop3, __arraycount(mop3),
    771  1.31  christos 			    sizeof(*mop3), compare2);
    772  1.31  christos 	} else {
    773  1.31  christos 		if (s[1] == '\0')
    774  1.31  christos 			return bsearch(s, cop, __arraycount(cop), sizeof(*cop),
    775  1.31  christos 			    compare1);
    776  1.31  christos 		else if (strcmp(s, cop2[0].op_text) == 0)
    777  1.31  christos 			return cop2;
    778  1.31  christos 		else
    779  1.31  christos 			return NULL;
    780  1.31  christos 	}
    781  1.31  christos }
    782  1.31  christos 
    783  1.13       jtc static enum token
    784  1.23       wiz t_lex(char *s)
    785   1.1     glass {
    786  1.24       wiz 	struct t_op const *op;
    787  1.24       wiz 
    788  1.31  christos 	if (s == NULL) {
    789  1.26    simonb 		t_wp_op = NULL;
    790  1.13       jtc 		return EOI;
    791  1.13       jtc 	}
    792  1.31  christos 
    793  1.31  christos 	if ((op = findop(s)) != NULL) {
    794  1.31  christos 		if (!((op->op_type == UNOP && isoperand()) ||
    795  1.31  christos 		    (op->op_num == LPAREN && *(t_wp+1) == 0))) {
    796  1.13       jtc 			t_wp_op = op;
    797  1.13       jtc 			return op->op_num;
    798  1.13       jtc 		}
    799  1.13       jtc 	}
    800  1.26    simonb 	t_wp_op = NULL;
    801  1.13       jtc 	return OPERAND;
    802  1.21    kleink }
    803  1.21    kleink 
    804  1.21    kleink static int
    805  1.23       wiz isoperand(void)
    806  1.21    kleink {
    807  1.24       wiz 	struct t_op const *op;
    808  1.24       wiz 	char *s, *t;
    809  1.21    kleink 
    810  1.21    kleink 	if ((s  = *(t_wp+1)) == 0)
    811  1.21    kleink 		return 1;
    812  1.21    kleink 	if ((t = *(t_wp+2)) == 0)
    813  1.21    kleink 		return 0;
    814  1.31  christos 	if ((op = findop(s)) != NULL)
    815  1.31  christos 		return op->op_type == BINOP && (t[0] != ')' || t[1] != '\0');
    816  1.21    kleink 	return 0;
    817   1.1     glass }
    818   1.1     glass 
    819  1.13       jtc /* atoi with error detection */
    820  1.36  christos static long long
    821  1.23       wiz getn(const char *s)
    822   1.1     glass {
    823   1.6       alm 	char *p;
    824  1.36  christos 	long long r;
    825   1.1     glass 
    826   1.6       alm 	errno = 0;
    827  1.36  christos 	r = strtoll(s, &p, 10);
    828  1.13       jtc 
    829   1.6       alm 	if (errno != 0)
    830  1.36  christos 	if (errno == ERANGE && (r == LLONG_MAX || r == LLONG_MIN))
    831  1.22  christos 	      error("%s: out of range", s);
    832  1.13       jtc 
    833  1.42       kre 	if (p != s)
    834  1.42       kre 		while (isspace((unsigned char)*p))
    835  1.42       kre 		      p++;
    836  1.13       jtc 
    837  1.37  christos 	if (*p || p == s)
    838  1.42       kre 	      error("'%s': bad number", s);
    839  1.13       jtc 
    840  1.36  christos 	return r;
    841   1.1     glass }
    842   1.1     glass 
    843  1.13       jtc static int
    844  1.26    simonb newerf(const char *f1, const char *f2)
    845   1.1     glass {
    846  1.13       jtc 	struct stat b1, b2;
    847  1.13       jtc 
    848  1.26    simonb 	return (stat(f1, &b1) == 0 &&
    849  1.26    simonb 		stat(f2, &b2) == 0 &&
    850  1.40  uebayasi 		timespeccmp(&b1.st_mtim, &b2.st_mtim, >));
    851   1.1     glass }
    852   1.1     glass 
    853  1.13       jtc static int
    854  1.26    simonb olderf(const char *f1, const char *f2)
    855   1.1     glass {
    856  1.13       jtc 	struct stat b1, b2;
    857  1.13       jtc 
    858  1.26    simonb 	return (stat(f1, &b1) == 0 &&
    859  1.26    simonb 		stat(f2, &b2) == 0 &&
    860  1.40  uebayasi 		timespeccmp(&b1.st_mtim, &b2.st_mtim, <));
    861   1.1     glass }
    862   1.1     glass 
    863  1.13       jtc static int
    864  1.26    simonb equalf(const char *f1, const char *f2)
    865  1.13       jtc {
    866  1.13       jtc 	struct stat b1, b2;
    867   1.1     glass 
    868  1.26    simonb 	return (stat(f1, &b1) == 0 &&
    869  1.26    simonb 		stat(f2, &b2) == 0 &&
    870  1.13       jtc 		b1.st_dev == b2.st_dev &&
    871  1.13       jtc 		b1.st_ino == b2.st_ino);
    872   1.1     glass }
    873