|
|
1.1 ! root 1: /* ! 2: * test(1); version 7-like -- author Erik Baalbergen ! 3: * modified by Eric Gisin to be used as built-in. ! 4: * modified by Arnold Robbins to add SVR3 compatibility ! 5: * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket). ! 6: */ ! 7: ! 8: static char *RCSid = "$Header: c_test.c,v 3.1 88/11/03 09:14:43 egisin Exp $"; ! 9: ! 10: #include <stddef.h> ! 11: #include <stdlib.h> ! 12: #include <string.h> ! 13: #include <signal.h> ! 14: #include <errno.h> ! 15: #include <setjmp.h> ! 16: #include <sys/types.h> ! 17: #include <sys/stat.h> ! 18: #include "sh.h" ! 19: ! 20: /* test(1) accepts the following grammar: ! 21: expr ::= bexpr | bexpr "-o" expr ; ! 22: bexpr ::= primary | primary "-a" bexpr ; ! 23: primary ::= unary-operator operand ! 24: | operand binary-operator operand ! 25: | operand ! 26: | "(" expr ")" ! 27: | "!" expr ! 28: ; ! 29: unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"| ! 30: "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S"; ! 31: ! 32: binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"| ! 33: "-nt"|"-ot"|"-ef"; ! 34: operand ::= <any legal UNIX file name> ! 35: */ ! 36: ! 37: #define EOI 0 ! 38: #define FILRD 1 ! 39: #define FILWR 2 ! 40: #define FILREG 3 ! 41: #define FILID 4 ! 42: #define FILGZ 5 ! 43: #define FILTT 6 ! 44: #define STZER 7 ! 45: #define STNZE 8 ! 46: #define STEQL 9 ! 47: #define STNEQ 10 ! 48: #define INTEQ 11 ! 49: #define INTNE 12 ! 50: #define INTGE 13 ! 51: #define INTGT 14 ! 52: #define INTLE 15 ! 53: #define INTLT 16 ! 54: #define UNEGN 17 ! 55: #define BAND 18 ! 56: #define BOR 19 ! 57: #define LPAREN 20 ! 58: #define RPAREN 21 ! 59: #define OPERAND 22 ! 60: #define FILEX 23 ! 61: #define FILCDEV 24 ! 62: #define FILBDEV 25 ! 63: #define FILFIFO 26 ! 64: #define FILSETU 27 ! 65: #define FILSETG 28 ! 66: #define FILSTCK 29 ! 67: #define FILSYM 30 ! 68: #define FILNT 31 ! 69: #define FILOT 32 ! 70: #define FILEQ 33 ! 71: #define FILSOCK 34 ! 72: #define FILUID 35 ! 73: #define FILGID 36 ! 74: #define OPTION 37 ! 75: ! 76: #define UNOP 1 ! 77: #define BINOP 2 ! 78: #define BUNOP 3 ! 79: #define BBINOP 4 ! 80: #define PAREN 5 ! 81: ! 82: struct t_op { ! 83: char *op_text; ! 84: short op_num, op_type; ! 85: } Const ops [] = { ! 86: {"-r", FILRD, UNOP}, ! 87: {"-w", FILWR, UNOP}, ! 88: {"-x", FILEX, UNOP}, ! 89: {"-f", FILREG, UNOP}, ! 90: {"-d", FILID, UNOP}, ! 91: {"-c", FILCDEV,UNOP}, ! 92: {"-b", FILBDEV,UNOP}, ! 93: {"-p", FILFIFO,UNOP}, ! 94: {"-u", FILSETU,UNOP}, ! 95: {"-g", FILSETG,UNOP}, ! 96: {"-k", FILSTCK,UNOP}, ! 97: {"-s", FILGZ, UNOP}, ! 98: {"-t", FILTT, UNOP}, ! 99: {"-z", STZER, UNOP}, ! 100: {"-n", STNZE, UNOP}, ! 101: #if 0 /* conficts with binary -o */ ! 102: {"-o", OPTION, UNOP}, ! 103: #endif ! 104: {"-U", FILUID, UNOP}, ! 105: {"-G", FILGID, UNOP}, ! 106: {"-L", FILSYM, UNOP}, ! 107: {"-S", FILSOCK,UNOP}, ! 108: {"=", STEQL, BINOP}, ! 109: {"!=", STNEQ, BINOP}, ! 110: {"-eq", INTEQ, BINOP}, ! 111: {"-ne", INTNE, BINOP}, ! 112: {"-ge", INTGE, BINOP}, ! 113: {"-gt", INTGT, BINOP}, ! 114: {"-le", INTLE, BINOP}, ! 115: {"-lt", INTLT, BINOP}, ! 116: {"-nt", FILNT, BINOP}, ! 117: {"-ot", FILOT, BINOP}, ! 118: {"-ef", FILEQ, BINOP}, ! 119: {"!", UNEGN, BUNOP}, ! 120: {"-a", BAND, BBINOP}, ! 121: {"-o", BOR, BBINOP}, ! 122: {"(", LPAREN, PAREN}, ! 123: {")", RPAREN, PAREN}, ! 124: {0, 0, 0} ! 125: }; ! 126: ! 127: char **t_wp; ! 128: struct t_op Const *t_wp_op; ! 129: ! 130: int ! 131: c_test(wp) ! 132: char **wp; ! 133: { ! 134: t_wp = wp+1; ! 135: if (strcmp(wp[0], "[") == 0) { ! 136: while (*wp != NULL) ! 137: wp++; ! 138: if (strcmp(*--wp, "]") != 0) ! 139: errorf("[: missing ]\n"); ! 140: *wp = NULL; ! 141: } ! 142: #if 0 ! 143: if (*t_wp == NULL) ! 144: mypr("*t_wp == NULL\n"); ! 145: else if (!expr(t_lex(*t_wp))) ! 146: mypr("expr returned 0\n"); ! 147: #endif ! 148: return *t_wp == NULL || !expr(t_lex(*t_wp)); ! 149: } ! 150: ! 151: static ! 152: syntax() ! 153: { ! 154: errorf("test: syntax error\n"); ! 155: } ! 156: ! 157: expr(n) ! 158: { ! 159: int res; ! 160: ! 161: if (n == EOI) ! 162: syntax(); ! 163: res = bexpr(n); ! 164: if (t_lex(*++t_wp) == BOR) ! 165: return expr(t_lex(*++t_wp)) || res; ! 166: t_wp--; ! 167: return res; ! 168: } ! 169: ! 170: bexpr(n) ! 171: { ! 172: int res; ! 173: ! 174: if (n == EOI) ! 175: syntax(); ! 176: res = primary(n); ! 177: if (t_lex(*++t_wp) == BAND) ! 178: return bexpr(t_lex(*++t_wp)) && res; ! 179: t_wp--; ! 180: return res; ! 181: } ! 182: ! 183: primary(n) ! 184: int n; /* token */ ! 185: { ! 186: register char *opnd1, *opnd2; ! 187: int res; ! 188: ! 189: if (n == EOI) ! 190: syntax(); ! 191: if (n == UNEGN) ! 192: return !expr(t_lex(*++t_wp)); ! 193: if (n == LPAREN) { ! 194: res = expr(t_lex(*++t_wp)); ! 195: if (t_lex(*++t_wp) != RPAREN) ! 196: syntax(); ! 197: return res; ! 198: } ! 199: if (n == OPERAND) { ! 200: opnd1 = *t_wp; ! 201: (void) t_lex(*++t_wp); ! 202: if (t_wp_op && t_wp_op->op_type == BINOP) { ! 203: struct t_op Const *op = t_wp_op; ! 204: ! 205: if ((opnd2 = *++t_wp) == (char *)0) ! 206: syntax(); ! 207: ! 208: switch (op->op_num) { ! 209: case STEQL: ! 210: return strcmp(opnd1, opnd2) == 0; ! 211: case STNEQ: ! 212: return strcmp(opnd1, opnd2) != 0; ! 213: case INTEQ: ! 214: return evaluate(opnd1) == evaluate(opnd2); ! 215: case INTNE: ! 216: return evaluate(opnd1) != evaluate(opnd2); ! 217: case INTGE: ! 218: return evaluate(opnd1) >= evaluate(opnd2); ! 219: case INTGT: ! 220: return evaluate(opnd1) > evaluate(opnd2); ! 221: case INTLE: ! 222: return evaluate(opnd1) <= evaluate(opnd2); ! 223: case INTLT: ! 224: return evaluate(opnd1) < evaluate(opnd2); ! 225: case FILNT: ! 226: return newerf (opnd1, opnd2); ! 227: case FILOT: ! 228: return olderf (opnd1, opnd2); ! 229: case FILEQ: ! 230: return equalf (opnd1, opnd2); ! 231: } ! 232: } ! 233: t_wp--; ! 234: return strlen(opnd1) > 0; ! 235: } ! 236: if (t_wp_op->op_type == UNOP) { ! 237: /* unary expression */ ! 238: if (*++t_wp == NULL && n != FILTT) ! 239: syntax(); ! 240: switch (n) { ! 241: case OPTION: ! 242: return flag[option(*t_wp)]; ! 243: case STZER: ! 244: return strlen(*t_wp) == 0; ! 245: case STNZE: ! 246: return strlen(*t_wp) != 0; ! 247: case FILTT: ! 248: if (!digit(**t_wp)) ! 249: return filstat("0", n); ! 250: default: /* all other FIL* */ ! 251: return filstat(*t_wp, n); ! 252: } ! 253: } ! 254: syntax(); ! 255: } ! 256: ! 257: filstat(nm, mode) ! 258: char *nm; ! 259: { ! 260: struct stat s; ! 261: ! 262: switch (mode) { ! 263: case FILRD: ! 264: return access(nm, 4) == 0; ! 265: case FILWR: ! 266: return access(nm, 2) == 0; ! 267: case FILEX: ! 268: return access(nm, 1) == 0; ! 269: case FILREG: ! 270: return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFREG; ! 271: case FILID: ! 272: return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFDIR; ! 273: case FILCDEV: ! 274: return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFCHR; ! 275: case FILBDEV: ! 276: return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFBLK; ! 277: case FILFIFO: ! 278: #ifdef S_IFIFO ! 279: return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFIFO; ! 280: #else ! 281: return 0; ! 282: #endif ! 283: case FILSETU: ! 284: return stat(nm, &s) == 0 && (s.st_mode & S_ISUID) == S_ISUID; ! 285: case FILSETG: ! 286: return stat(nm, &s) == 0 && (s.st_mode & S_ISGID) == S_ISGID; ! 287: case FILSTCK: ! 288: return stat(nm, &s) == 0 && (s.st_mode & S_ISVTX) == S_ISVTX; ! 289: case FILGZ: ! 290: return stat(nm, &s) == 0 && s.st_size > 0L; ! 291: case FILTT: ! 292: return isatty(getn(nm)); ! 293: case FILUID: ! 294: return stat(nm, &s) == 0 && s.st_uid == geteuid(); ! 295: case FILGID: ! 296: return stat(nm, &s) == 0 && s.st_gid == getegid(); ! 297: #ifdef S_IFLNK ! 298: case FILSYM: ! 299: return lstat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFLNK; ! 300: #endif ! 301: #ifdef S_IFSOCK ! 302: case FILSOCK: ! 303: return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFSOCK; ! 304: #endif ! 305: default: ! 306: return 1; ! 307: } ! 308: } ! 309: ! 310: int ! 311: t_lex(s) ! 312: register char *s; ! 313: { ! 314: register struct t_op Const *op = ops; ! 315: ! 316: if (s == 0) ! 317: return EOI; ! 318: while (op->op_text) { ! 319: if (strcmp(s, op->op_text) == 0) { ! 320: t_wp_op = op; ! 321: return op->op_num; ! 322: } ! 323: op++; ! 324: } ! 325: t_wp_op = (struct t_op *)0; ! 326: return OPERAND; ! 327: } ! 328: ! 329: newerf (f1, f2) ! 330: char *f1, *f2; ! 331: { ! 332: struct stat b1, b2; ! 333: ! 334: return (stat (f1, &b1) == 0 && ! 335: stat (f2, &b2) == 0 && ! 336: b1.st_mtime > b2.st_mtime); ! 337: } ! 338: ! 339: olderf (f1, f2) ! 340: char *f1, *f2; ! 341: { ! 342: struct stat b1, b2; ! 343: ! 344: return (stat (f1, &b1) == 0 && ! 345: stat (f2, &b2) == 0 && ! 346: b1.st_mtime < b2.st_mtime); ! 347: } ! 348: ! 349: equalf (f1, f2) ! 350: char *f1, *f2; ! 351: { ! 352: struct stat b1, b2; ! 353: ! 354: return (stat (f1, &b1) == 0 && ! 355: stat (f2, &b2) == 0 && ! 356: b1.st_dev == b2.st_dev && ! 357: b1.st_ino == b2.st_ino); ! 358: } ! 359:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.