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