1717a08b6SSheldon Hearn /* $NetBSD: test.c,v 1.21 1999/04/05 09:48:38 kleink Exp $ */ 2717a08b6SSheldon Hearn 3717a08b6SSheldon Hearn /* 4717a08b6SSheldon Hearn * test(1); version 7-like -- author Erik Baalbergen 5717a08b6SSheldon Hearn * modified by Eric Gisin to be used as built-in. 6717a08b6SSheldon Hearn * modified by Arnold Robbins to add SVR3 compatibility 7717a08b6SSheldon Hearn * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket). 8717a08b6SSheldon Hearn * modified by J.T. Conklin for NetBSD. 94b88c807SRodney W. Grimes * 10717a08b6SSheldon Hearn * This program is in the Public Domain. 114b88c807SRodney W. Grimes */ 124b88c807SRodney W. Grimes 134b88c807SRodney W. Grimes #ifndef lint 149ba8bd65SPhilippe Charnier static const char rcsid[] = 152a456239SPeter Wemm "$FreeBSD$"; 164b88c807SRodney W. Grimes #endif /* not lint */ 174b88c807SRodney W. Grimes 18717a08b6SSheldon Hearn #include <sys/types.h> 19007d3350SEivind Eklund #include <sys/stat.h> 204b88c807SRodney W. Grimes 214b88c807SRodney W. Grimes #include <ctype.h> 224b88c807SRodney W. Grimes #include <err.h> 234b88c807SRodney W. Grimes #include <errno.h> 246dca6515SKris Kennaway #include <limits.h> 2525e04004SAkinori MUSHA #include <stdarg.h> 264b88c807SRodney W. Grimes #include <stdio.h> 274b88c807SRodney W. Grimes #include <stdlib.h> 284b88c807SRodney W. Grimes #include <string.h> 294b88c807SRodney W. Grimes #include <unistd.h> 304b88c807SRodney W. Grimes 31d90c5c4aSAkinori MUSHA #ifdef SHELL 32d90c5c4aSAkinori MUSHA #define main testcmd 33d90c5c4aSAkinori MUSHA #include "bltin/bltin.h" 34d919a882SAkinori MUSHA #else 35d919a882SAkinori MUSHA static void error(const char *, ...) __attribute__((__noreturn__)); 36d919a882SAkinori MUSHA 37d919a882SAkinori MUSHA static void 38d919a882SAkinori MUSHA #ifdef __STDC__ 39d919a882SAkinori MUSHA error(const char *msg, ...) 40d919a882SAkinori MUSHA #else 41d919a882SAkinori MUSHA error(va_alist) 42d919a882SAkinori MUSHA va_dcl 43d919a882SAkinori MUSHA #endif 44d919a882SAkinori MUSHA { 45d919a882SAkinori MUSHA va_list ap; 46d919a882SAkinori MUSHA #ifndef __STDC__ 47d919a882SAkinori MUSHA const char *msg; 48d919a882SAkinori MUSHA 49d919a882SAkinori MUSHA va_start(ap); 50d919a882SAkinori MUSHA msg = va_arg(ap, const char *); 51d919a882SAkinori MUSHA #else 52d919a882SAkinori MUSHA va_start(ap, msg); 53d919a882SAkinori MUSHA #endif 54d919a882SAkinori MUSHA verrx(2, msg, ap); 55d919a882SAkinori MUSHA /*NOTREACHED*/ 56d919a882SAkinori MUSHA va_end(ap); 57d919a882SAkinori MUSHA } 58d90c5c4aSAkinori MUSHA #endif 59d90c5c4aSAkinori MUSHA 60717a08b6SSheldon Hearn /* test(1) accepts the following grammar: 61717a08b6SSheldon Hearn oexpr ::= aexpr | aexpr "-o" oexpr ; 62717a08b6SSheldon Hearn aexpr ::= nexpr | nexpr "-a" aexpr ; 63717a08b6SSheldon Hearn nexpr ::= primary | "!" primary 64717a08b6SSheldon Hearn primary ::= unary-operator operand 65717a08b6SSheldon Hearn | operand binary-operator operand 66717a08b6SSheldon Hearn | operand 67717a08b6SSheldon Hearn | "(" oexpr ")" 68717a08b6SSheldon Hearn ; 69717a08b6SSheldon Hearn unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"| 70717a08b6SSheldon Hearn "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S"; 714b88c807SRodney W. Grimes 72717a08b6SSheldon Hearn binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"| 73717a08b6SSheldon Hearn "-nt"|"-ot"|"-ef"; 74717a08b6SSheldon Hearn operand ::= <any legal UNIX file name> 754b88c807SRodney W. Grimes */ 76717a08b6SSheldon Hearn 77717a08b6SSheldon Hearn enum token { 78717a08b6SSheldon Hearn EOI, 79717a08b6SSheldon Hearn FILRD, 80717a08b6SSheldon Hearn FILWR, 81717a08b6SSheldon Hearn FILEX, 82717a08b6SSheldon Hearn FILEXIST, 83717a08b6SSheldon Hearn FILREG, 84717a08b6SSheldon Hearn FILDIR, 85717a08b6SSheldon Hearn FILCDEV, 86717a08b6SSheldon Hearn FILBDEV, 87717a08b6SSheldon Hearn FILFIFO, 88717a08b6SSheldon Hearn FILSOCK, 89717a08b6SSheldon Hearn FILSYM, 90717a08b6SSheldon Hearn FILGZ, 91717a08b6SSheldon Hearn FILTT, 92717a08b6SSheldon Hearn FILSUID, 93717a08b6SSheldon Hearn FILSGID, 94717a08b6SSheldon Hearn FILSTCK, 95717a08b6SSheldon Hearn FILNT, 96717a08b6SSheldon Hearn FILOT, 97717a08b6SSheldon Hearn FILEQ, 98717a08b6SSheldon Hearn FILUID, 99717a08b6SSheldon Hearn FILGID, 100717a08b6SSheldon Hearn STREZ, 101717a08b6SSheldon Hearn STRNZ, 102717a08b6SSheldon Hearn STREQ, 103717a08b6SSheldon Hearn STRNE, 104717a08b6SSheldon Hearn STRLT, 105717a08b6SSheldon Hearn STRGT, 106717a08b6SSheldon Hearn INTEQ, 107717a08b6SSheldon Hearn INTNE, 108717a08b6SSheldon Hearn INTGE, 109717a08b6SSheldon Hearn INTGT, 110717a08b6SSheldon Hearn INTLE, 111717a08b6SSheldon Hearn INTLT, 112717a08b6SSheldon Hearn UNOT, 113717a08b6SSheldon Hearn BAND, 114717a08b6SSheldon Hearn BOR, 115717a08b6SSheldon Hearn LPAREN, 116717a08b6SSheldon Hearn RPAREN, 117717a08b6SSheldon Hearn OPERAND 1184b88c807SRodney W. Grimes }; 1194b88c807SRodney W. Grimes 120717a08b6SSheldon Hearn enum token_types { 121717a08b6SSheldon Hearn UNOP, 122717a08b6SSheldon Hearn BINOP, 123717a08b6SSheldon Hearn BUNOP, 124717a08b6SSheldon Hearn BBINOP, 125717a08b6SSheldon Hearn PAREN 1264b88c807SRodney W. Grimes }; 1274b88c807SRodney W. Grimes 128717a08b6SSheldon Hearn struct t_op { 129717a08b6SSheldon Hearn const char *op_text; 130717a08b6SSheldon Hearn short op_num, op_type; 131717a08b6SSheldon Hearn } const ops [] = { 132717a08b6SSheldon Hearn {"-r", FILRD, UNOP}, 133717a08b6SSheldon Hearn {"-w", FILWR, UNOP}, 134717a08b6SSheldon Hearn {"-x", FILEX, UNOP}, 135717a08b6SSheldon Hearn {"-e", FILEXIST,UNOP}, 136717a08b6SSheldon Hearn {"-f", FILREG, UNOP}, 137717a08b6SSheldon Hearn {"-d", FILDIR, UNOP}, 138717a08b6SSheldon Hearn {"-c", FILCDEV,UNOP}, 139717a08b6SSheldon Hearn {"-b", FILBDEV,UNOP}, 140717a08b6SSheldon Hearn {"-p", FILFIFO,UNOP}, 141717a08b6SSheldon Hearn {"-u", FILSUID,UNOP}, 142717a08b6SSheldon Hearn {"-g", FILSGID,UNOP}, 143717a08b6SSheldon Hearn {"-k", FILSTCK,UNOP}, 144717a08b6SSheldon Hearn {"-s", FILGZ, UNOP}, 145717a08b6SSheldon Hearn {"-t", FILTT, UNOP}, 146717a08b6SSheldon Hearn {"-z", STREZ, UNOP}, 147717a08b6SSheldon Hearn {"-n", STRNZ, UNOP}, 148717a08b6SSheldon Hearn {"-h", FILSYM, UNOP}, /* for backwards compat */ 149717a08b6SSheldon Hearn {"-O", FILUID, UNOP}, 150717a08b6SSheldon Hearn {"-G", FILGID, UNOP}, 151717a08b6SSheldon Hearn {"-L", FILSYM, UNOP}, 152717a08b6SSheldon Hearn {"-S", FILSOCK,UNOP}, 153717a08b6SSheldon Hearn {"=", STREQ, BINOP}, 154717a08b6SSheldon Hearn {"!=", STRNE, BINOP}, 155717a08b6SSheldon Hearn {"<", STRLT, BINOP}, 156717a08b6SSheldon Hearn {">", STRGT, BINOP}, 157717a08b6SSheldon Hearn {"-eq", INTEQ, BINOP}, 158717a08b6SSheldon Hearn {"-ne", INTNE, BINOP}, 159717a08b6SSheldon Hearn {"-ge", INTGE, BINOP}, 160717a08b6SSheldon Hearn {"-gt", INTGT, BINOP}, 161717a08b6SSheldon Hearn {"-le", INTLE, BINOP}, 162717a08b6SSheldon Hearn {"-lt", INTLT, BINOP}, 163717a08b6SSheldon Hearn {"-nt", FILNT, BINOP}, 164717a08b6SSheldon Hearn {"-ot", FILOT, BINOP}, 165717a08b6SSheldon Hearn {"-ef", FILEQ, BINOP}, 166717a08b6SSheldon Hearn {"!", UNOT, BUNOP}, 167717a08b6SSheldon Hearn {"-a", BAND, BBINOP}, 168717a08b6SSheldon Hearn {"-o", BOR, BBINOP}, 169717a08b6SSheldon Hearn {"(", LPAREN, PAREN}, 170717a08b6SSheldon Hearn {")", RPAREN, PAREN}, 171717a08b6SSheldon Hearn {0, 0, 0} 1724b88c807SRodney W. Grimes }; 1734b88c807SRodney W. Grimes 174717a08b6SSheldon Hearn struct t_op const *t_wp_op; 175717a08b6SSheldon Hearn char **t_wp; 176717a08b6SSheldon Hearn 177717a08b6SSheldon Hearn static int aexpr __P((enum token)); 178717a08b6SSheldon Hearn static int binop __P((void)); 1796dca6515SKris Kennaway static int equalf __P((const char *, const char *)); 180717a08b6SSheldon Hearn static int filstat __P((char *, enum token)); 181717a08b6SSheldon Hearn static int getn __P((const char *)); 182de96f240SStefan Eßer static quad_t getq __P((const char *)); 183de96f240SStefan Eßer static int intcmp __P((const char *, const char *)); 1846dca6515SKris Kennaway static int isoperand __P((void)); 1856dca6515SKris Kennaway int main __P((int, char **)); 186717a08b6SSheldon Hearn static int newerf __P((const char *, const char *)); 1876dca6515SKris Kennaway static int nexpr __P((enum token)); 1886dca6515SKris Kennaway static int oexpr __P((enum token)); 189717a08b6SSheldon Hearn static int olderf __P((const char *, const char *)); 1906dca6515SKris Kennaway static int primary __P((enum token)); 1916dca6515SKris Kennaway static void syntax __P((const char *, const char *)); 1926dca6515SKris Kennaway static enum token t_lex __P((char *)); 1934b88c807SRodney W. Grimes 1944b88c807SRodney W. Grimes int 1954b88c807SRodney W. Grimes main(argc, argv) 1964b88c807SRodney W. Grimes int argc; 197717a08b6SSheldon Hearn char **argv; 1984b88c807SRodney W. Grimes { 199717a08b6SSheldon Hearn int res; 2009abf3043SSheldon Hearn char *p; 2014b88c807SRodney W. Grimes 2029abf3043SSheldon Hearn if ((p = rindex(argv[0], '/')) == NULL) 2039abf3043SSheldon Hearn p = argv[0]; 2049abf3043SSheldon Hearn else 2059abf3043SSheldon Hearn p++; 2069abf3043SSheldon Hearn if (strcmp(p, "[") == 0) { 207bd90b9c7SAkinori MUSHA if (strcmp(argv[--argc], "]") != 0) 208d919a882SAkinori MUSHA error("missing ]"); 2094b88c807SRodney W. Grimes argv[argc] = NULL; 2104b88c807SRodney W. Grimes } 2114b88c807SRodney W. Grimes 212bd90b9c7SAkinori MUSHA /* no expression => false */ 213bd90b9c7SAkinori MUSHA if (--argc <= 0) 214bd90b9c7SAkinori MUSHA return 1; 215bd90b9c7SAkinori MUSHA 2162a6d85a9SBrian Feldman /* XXX work around the absence of an eaccess(2) syscall */ 217d2fed466SBrian Feldman (void)setgid(getegid()); 218d2fed466SBrian Feldman (void)setuid(geteuid()); 219d2fed466SBrian Feldman 220717a08b6SSheldon Hearn t_wp = &argv[1]; 221717a08b6SSheldon Hearn res = !oexpr(t_lex(*t_wp)); 222717a08b6SSheldon Hearn 223717a08b6SSheldon Hearn if (*t_wp != NULL && *++t_wp != NULL) 224717a08b6SSheldon Hearn syntax(*t_wp, "unexpected operator"); 225717a08b6SSheldon Hearn 226717a08b6SSheldon Hearn return res; 2274b88c807SRodney W. Grimes } 228717a08b6SSheldon Hearn 229717a08b6SSheldon Hearn static void 230717a08b6SSheldon Hearn syntax(op, msg) 231717a08b6SSheldon Hearn const char *op; 232717a08b6SSheldon Hearn const char *msg; 233717a08b6SSheldon Hearn { 234717a08b6SSheldon Hearn 235717a08b6SSheldon Hearn if (op && *op) 236d919a882SAkinori MUSHA error("%s: %s", op, msg); 237717a08b6SSheldon Hearn else 238d919a882SAkinori MUSHA error("%s", msg); 2394b88c807SRodney W. Grimes } 240717a08b6SSheldon Hearn 241717a08b6SSheldon Hearn static int 242717a08b6SSheldon Hearn oexpr(n) 243717a08b6SSheldon Hearn enum token n; 244717a08b6SSheldon Hearn { 245717a08b6SSheldon Hearn int res; 246717a08b6SSheldon Hearn 247717a08b6SSheldon Hearn res = aexpr(n); 248717a08b6SSheldon Hearn if (t_lex(*++t_wp) == BOR) 249717a08b6SSheldon Hearn return oexpr(t_lex(*++t_wp)) || res; 250717a08b6SSheldon Hearn t_wp--; 251717a08b6SSheldon Hearn return res; 2524b88c807SRodney W. Grimes } 253717a08b6SSheldon Hearn 254717a08b6SSheldon Hearn static int 255717a08b6SSheldon Hearn aexpr(n) 256717a08b6SSheldon Hearn enum token n; 257717a08b6SSheldon Hearn { 258717a08b6SSheldon Hearn int res; 259717a08b6SSheldon Hearn 260717a08b6SSheldon Hearn res = nexpr(n); 261717a08b6SSheldon Hearn if (t_lex(*++t_wp) == BAND) 262717a08b6SSheldon Hearn return aexpr(t_lex(*++t_wp)) && res; 263717a08b6SSheldon Hearn t_wp--; 264717a08b6SSheldon Hearn return res; 265717a08b6SSheldon Hearn } 266717a08b6SSheldon Hearn 267717a08b6SSheldon Hearn static int 268717a08b6SSheldon Hearn nexpr(n) 269717a08b6SSheldon Hearn enum token n; /* token */ 270717a08b6SSheldon Hearn { 271717a08b6SSheldon Hearn if (n == UNOT) 272717a08b6SSheldon Hearn return !nexpr(t_lex(*++t_wp)); 273717a08b6SSheldon Hearn return primary(n); 274717a08b6SSheldon Hearn } 275717a08b6SSheldon Hearn 276717a08b6SSheldon Hearn static int 277717a08b6SSheldon Hearn primary(n) 278717a08b6SSheldon Hearn enum token n; 279717a08b6SSheldon Hearn { 280717a08b6SSheldon Hearn enum token nn; 281717a08b6SSheldon Hearn int res; 282717a08b6SSheldon Hearn 283717a08b6SSheldon Hearn if (n == EOI) 284717a08b6SSheldon Hearn return 0; /* missing expression */ 285717a08b6SSheldon Hearn if (n == LPAREN) { 286717a08b6SSheldon Hearn if ((nn = t_lex(*++t_wp)) == RPAREN) 287717a08b6SSheldon Hearn return 0; /* missing expression */ 288717a08b6SSheldon Hearn res = oexpr(nn); 289717a08b6SSheldon Hearn if (t_lex(*++t_wp) != RPAREN) 290717a08b6SSheldon Hearn syntax(NULL, "closing paren expected"); 291717a08b6SSheldon Hearn return res; 292717a08b6SSheldon Hearn } 293717a08b6SSheldon Hearn if (t_wp_op && t_wp_op->op_type == UNOP) { 294717a08b6SSheldon Hearn /* unary expression */ 295717a08b6SSheldon Hearn if (*++t_wp == NULL) 296717a08b6SSheldon Hearn syntax(t_wp_op->op_text, "argument expected"); 297717a08b6SSheldon Hearn switch (n) { 298717a08b6SSheldon Hearn case STREZ: 299717a08b6SSheldon Hearn return strlen(*t_wp) == 0; 300717a08b6SSheldon Hearn case STRNZ: 301717a08b6SSheldon Hearn return strlen(*t_wp) != 0; 302717a08b6SSheldon Hearn case FILTT: 303717a08b6SSheldon Hearn return isatty(getn(*t_wp)); 3044b88c807SRodney W. Grimes default: 305717a08b6SSheldon Hearn return filstat(*t_wp, n); 306717a08b6SSheldon Hearn } 3074b88c807SRodney W. Grimes } 3084b88c807SRodney W. Grimes 309717a08b6SSheldon Hearn if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) { 310717a08b6SSheldon Hearn return binop(); 3114b88c807SRodney W. Grimes } 312717a08b6SSheldon Hearn 313717a08b6SSheldon Hearn return strlen(*t_wp) > 0; 3144b88c807SRodney W. Grimes } 3154b88c807SRodney W. Grimes 3164b88c807SRodney W. Grimes static int 317717a08b6SSheldon Hearn binop() 3184b88c807SRodney W. Grimes { 319717a08b6SSheldon Hearn const char *opnd1, *opnd2; 320717a08b6SSheldon Hearn struct t_op const *op; 3214b88c807SRodney W. Grimes 322717a08b6SSheldon Hearn opnd1 = *t_wp; 323717a08b6SSheldon Hearn (void) t_lex(*++t_wp); 324717a08b6SSheldon Hearn op = t_wp_op; 3254b88c807SRodney W. Grimes 326717a08b6SSheldon Hearn if ((opnd2 = *++t_wp) == NULL) 327717a08b6SSheldon Hearn syntax(op->op_text, "argument expected"); 3284b88c807SRodney W. Grimes 329717a08b6SSheldon Hearn switch (op->op_num) { 3304b88c807SRodney W. Grimes case STREQ: 331717a08b6SSheldon Hearn return strcmp(opnd1, opnd2) == 0; 3324b88c807SRodney W. Grimes case STRNE: 333717a08b6SSheldon Hearn return strcmp(opnd1, opnd2) != 0; 334717a08b6SSheldon Hearn case STRLT: 335717a08b6SSheldon Hearn return strcmp(opnd1, opnd2) < 0; 336717a08b6SSheldon Hearn case STRGT: 337717a08b6SSheldon Hearn return strcmp(opnd1, opnd2) > 0; 338717a08b6SSheldon Hearn case INTEQ: 339de96f240SStefan Eßer return intcmp(opnd1, opnd2) == 0; 340717a08b6SSheldon Hearn case INTNE: 341de96f240SStefan Eßer return intcmp(opnd1, opnd2) != 0; 342717a08b6SSheldon Hearn case INTGE: 343de96f240SStefan Eßer return intcmp(opnd1, opnd2) >= 0; 344717a08b6SSheldon Hearn case INTGT: 345de96f240SStefan Eßer return intcmp(opnd1, opnd2) > 0; 346717a08b6SSheldon Hearn case INTLE: 347de96f240SStefan Eßer return intcmp(opnd1, opnd2) <= 0; 348717a08b6SSheldon Hearn case INTLT: 349de96f240SStefan Eßer return intcmp(opnd1, opnd2) < 0; 350717a08b6SSheldon Hearn case FILNT: 351717a08b6SSheldon Hearn return newerf (opnd1, opnd2); 352717a08b6SSheldon Hearn case FILOT: 353717a08b6SSheldon Hearn return olderf (opnd1, opnd2); 354717a08b6SSheldon Hearn case FILEQ: 355717a08b6SSheldon Hearn return equalf (opnd1, opnd2); 356717a08b6SSheldon Hearn default: 357717a08b6SSheldon Hearn abort(); 358717a08b6SSheldon Hearn /* NOTREACHED */ 359717a08b6SSheldon Hearn } 360717a08b6SSheldon Hearn } 361717a08b6SSheldon Hearn 362717a08b6SSheldon Hearn static int 363717a08b6SSheldon Hearn filstat(nm, mode) 364717a08b6SSheldon Hearn char *nm; 365717a08b6SSheldon Hearn enum token mode; 366717a08b6SSheldon Hearn { 367717a08b6SSheldon Hearn struct stat s; 368717a08b6SSheldon Hearn 369717a08b6SSheldon Hearn if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s)) 370717a08b6SSheldon Hearn return 0; 371717a08b6SSheldon Hearn 372717a08b6SSheldon Hearn switch (mode) { 373717a08b6SSheldon Hearn case FILRD: 374717a08b6SSheldon Hearn return access(nm, R_OK) == 0; 375717a08b6SSheldon Hearn case FILWR: 376717a08b6SSheldon Hearn return access(nm, W_OK) == 0; 377717a08b6SSheldon Hearn case FILEX: 3782a6d85a9SBrian Feldman /* XXX work around access(2) false positives for superuser */ 379d2fed466SBrian Feldman if (access(nm, X_OK) != 0) 380eb5e5558SBrian Feldman return 0; 381d2fed466SBrian Feldman if (S_ISDIR(s.st_mode) || getuid() != 0) 382eb5e5558SBrian Feldman return 1; 383d2fed466SBrian Feldman return (s.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0; 384717a08b6SSheldon Hearn case FILEXIST: 385717a08b6SSheldon Hearn return access(nm, F_OK) == 0; 386717a08b6SSheldon Hearn case FILREG: 387717a08b6SSheldon Hearn return S_ISREG(s.st_mode); 388717a08b6SSheldon Hearn case FILDIR: 389717a08b6SSheldon Hearn return S_ISDIR(s.st_mode); 390717a08b6SSheldon Hearn case FILCDEV: 391717a08b6SSheldon Hearn return S_ISCHR(s.st_mode); 392717a08b6SSheldon Hearn case FILBDEV: 393717a08b6SSheldon Hearn return S_ISBLK(s.st_mode); 394717a08b6SSheldon Hearn case FILFIFO: 395717a08b6SSheldon Hearn return S_ISFIFO(s.st_mode); 396717a08b6SSheldon Hearn case FILSOCK: 397717a08b6SSheldon Hearn return S_ISSOCK(s.st_mode); 398717a08b6SSheldon Hearn case FILSYM: 399717a08b6SSheldon Hearn return S_ISLNK(s.st_mode); 400717a08b6SSheldon Hearn case FILSUID: 401717a08b6SSheldon Hearn return (s.st_mode & S_ISUID) != 0; 402717a08b6SSheldon Hearn case FILSGID: 403717a08b6SSheldon Hearn return (s.st_mode & S_ISGID) != 0; 404717a08b6SSheldon Hearn case FILSTCK: 405717a08b6SSheldon Hearn return (s.st_mode & S_ISVTX) != 0; 406717a08b6SSheldon Hearn case FILGZ: 407717a08b6SSheldon Hearn return s.st_size > (off_t)0; 408717a08b6SSheldon Hearn case FILUID: 409717a08b6SSheldon Hearn return s.st_uid == geteuid(); 410717a08b6SSheldon Hearn case FILGID: 411717a08b6SSheldon Hearn return s.st_gid == getegid(); 412717a08b6SSheldon Hearn default: 413717a08b6SSheldon Hearn return 1; 414717a08b6SSheldon Hearn } 415717a08b6SSheldon Hearn } 416717a08b6SSheldon Hearn 417717a08b6SSheldon Hearn static enum token 418717a08b6SSheldon Hearn t_lex(s) 419717a08b6SSheldon Hearn char *s; 420717a08b6SSheldon Hearn { 421717a08b6SSheldon Hearn struct t_op const *op = ops; 422717a08b6SSheldon Hearn 423717a08b6SSheldon Hearn if (s == 0) { 424717a08b6SSheldon Hearn t_wp_op = NULL; 425717a08b6SSheldon Hearn return EOI; 426717a08b6SSheldon Hearn } 427717a08b6SSheldon Hearn while (op->op_text) { 428717a08b6SSheldon Hearn if (strcmp(s, op->op_text) == 0) { 429717a08b6SSheldon Hearn if ((op->op_type == UNOP && isoperand()) || 430717a08b6SSheldon Hearn (op->op_num == LPAREN && *(t_wp+1) == 0)) 4314b88c807SRodney W. Grimes break; 432717a08b6SSheldon Hearn t_wp_op = op; 433717a08b6SSheldon Hearn return op->op_num; 4344b88c807SRodney W. Grimes } 435717a08b6SSheldon Hearn op++; 436717a08b6SSheldon Hearn } 437717a08b6SSheldon Hearn t_wp_op = NULL; 438717a08b6SSheldon Hearn return OPERAND; 4394b88c807SRodney W. Grimes } 4404b88c807SRodney W. Grimes 4414b88c807SRodney W. Grimes static int 442717a08b6SSheldon Hearn isoperand() 4434b88c807SRodney W. Grimes { 444717a08b6SSheldon Hearn struct t_op const *op = ops; 445717a08b6SSheldon Hearn char *s; 446717a08b6SSheldon Hearn char *t; 4474b88c807SRodney W. Grimes 448717a08b6SSheldon Hearn if ((s = *(t_wp+1)) == 0) 449717a08b6SSheldon Hearn return 1; 450717a08b6SSheldon Hearn if ((t = *(t_wp+2)) == 0) 451717a08b6SSheldon Hearn return 0; 452717a08b6SSheldon Hearn while (op->op_text) { 453717a08b6SSheldon Hearn if (strcmp(s, op->op_text) == 0) 454717a08b6SSheldon Hearn return op->op_type == BINOP && 455717a08b6SSheldon Hearn (t[0] != ')' || t[1] != '\0'); 456717a08b6SSheldon Hearn op++; 457717a08b6SSheldon Hearn } 458717a08b6SSheldon Hearn return 0; 4594b88c807SRodney W. Grimes } 4604b88c807SRodney W. Grimes 461717a08b6SSheldon Hearn /* atoi with error detection */ 4624b88c807SRodney W. Grimes static int 463717a08b6SSheldon Hearn getn(s) 464717a08b6SSheldon Hearn const char *s; 4654b88c807SRodney W. Grimes { 466717a08b6SSheldon Hearn char *p; 467717a08b6SSheldon Hearn long r; 4684b88c807SRodney W. Grimes 4694b88c807SRodney W. Grimes errno = 0; 470717a08b6SSheldon Hearn r = strtol(s, &p, 10); 471717a08b6SSheldon Hearn 472717a08b6SSheldon Hearn if (errno != 0) 4739ea42c8eSAndrey A. Chernov error((errno == EINVAL) ? "%s: bad number" : 4749ea42c8eSAndrey A. Chernov "%s: out of range", s); 475717a08b6SSheldon Hearn 476717a08b6SSheldon Hearn while (isspace((unsigned char)*p)) 477717a08b6SSheldon Hearn p++; 478717a08b6SSheldon Hearn 479717a08b6SSheldon Hearn if (*p) 480d919a882SAkinori MUSHA error("%s: bad number", s); 481717a08b6SSheldon Hearn 482717a08b6SSheldon Hearn return (int) r; 4834b88c807SRodney W. Grimes } 4844b88c807SRodney W. Grimes 485de96f240SStefan Eßer /* atoi with error detection and 64 bit range */ 486de96f240SStefan Eßer static quad_t 487de96f240SStefan Eßer getq(s) 488de96f240SStefan Eßer const char *s; 489de96f240SStefan Eßer { 490de96f240SStefan Eßer char *p; 491de96f240SStefan Eßer quad_t r; 492de96f240SStefan Eßer 493de96f240SStefan Eßer errno = 0; 494de96f240SStefan Eßer r = strtoq(s, &p, 10); 495de96f240SStefan Eßer 496de96f240SStefan Eßer if (errno != 0) 4979ea42c8eSAndrey A. Chernov error((errno == EINVAL) ? "%s: bad number" : 4989ea42c8eSAndrey A. Chernov "%s: out of range", s); 499de96f240SStefan Eßer 500de96f240SStefan Eßer while (isspace((unsigned char)*p)) 501de96f240SStefan Eßer p++; 502de96f240SStefan Eßer 503de96f240SStefan Eßer if (*p) 504d919a882SAkinori MUSHA error("%s: bad number", s); 505de96f240SStefan Eßer 506de96f240SStefan Eßer return r; 507de96f240SStefan Eßer } 508de96f240SStefan Eßer 509de96f240SStefan Eßer static int 510de96f240SStefan Eßer intcmp (s1, s2) 511de96f240SStefan Eßer const char *s1, *s2; 512de96f240SStefan Eßer { 513de96f240SStefan Eßer quad_t q1, q2; 514de96f240SStefan Eßer 515de96f240SStefan Eßer 516de96f240SStefan Eßer q1 = getq(s1); 517de96f240SStefan Eßer q2 = getq(s2); 518de96f240SStefan Eßer 519de96f240SStefan Eßer if (q1 > q2) 520de96f240SStefan Eßer return 1; 521de96f240SStefan Eßer 522de96f240SStefan Eßer if (q1 < q2) 523de96f240SStefan Eßer return -1; 524de96f240SStefan Eßer 525de96f240SStefan Eßer return 0; 526de96f240SStefan Eßer } 527de96f240SStefan Eßer 528717a08b6SSheldon Hearn static int 529717a08b6SSheldon Hearn newerf (f1, f2) 530717a08b6SSheldon Hearn const char *f1, *f2; 5314b88c807SRodney W. Grimes { 532717a08b6SSheldon Hearn struct stat b1, b2; 5334b88c807SRodney W. Grimes 534717a08b6SSheldon Hearn return (stat (f1, &b1) == 0 && 535717a08b6SSheldon Hearn stat (f2, &b2) == 0 && 536717a08b6SSheldon Hearn b1.st_mtime > b2.st_mtime); 5374b88c807SRodney W. Grimes } 5384b88c807SRodney W. Grimes 539717a08b6SSheldon Hearn static int 540717a08b6SSheldon Hearn olderf (f1, f2) 541717a08b6SSheldon Hearn const char *f1, *f2; 5424b88c807SRodney W. Grimes { 543717a08b6SSheldon Hearn struct stat b1, b2; 5444b88c807SRodney W. Grimes 545717a08b6SSheldon Hearn return (stat (f1, &b1) == 0 && 546717a08b6SSheldon Hearn stat (f2, &b2) == 0 && 547717a08b6SSheldon Hearn b1.st_mtime < b2.st_mtime); 548717a08b6SSheldon Hearn } 549717a08b6SSheldon Hearn 550717a08b6SSheldon Hearn static int 551717a08b6SSheldon Hearn equalf (f1, f2) 552717a08b6SSheldon Hearn const char *f1, *f2; 553717a08b6SSheldon Hearn { 554717a08b6SSheldon Hearn struct stat b1, b2; 555717a08b6SSheldon Hearn 556717a08b6SSheldon Hearn return (stat (f1, &b1) == 0 && 557717a08b6SSheldon Hearn stat (f2, &b2) == 0 && 558717a08b6SSheldon Hearn b1.st_dev == b2.st_dev && 559717a08b6SSheldon Hearn b1.st_ino == b2.st_ino); 5604b88c807SRodney W. Grimes } 561