1*53835Selan /* 2*53835Selan * The expr and test commands. 3*53835Selan * 4*53835Selan * Copyright (C) 1989 by Kenneth Almquist. All rights reserved. 5*53835Selan * This file is part of ash, which is distributed under the terms specified 6*53835Selan * by the Ash General Public License. See the file named LICENSE. 7*53835Selan */ 8*53835Selan 9*53835Selan #define PRINT 10*53835Selan 11*53835Selan 12*53835Selan #include <stdio.h> 13*53835Selan #include <errno.h> 14*53835Selan #include <sys/types.h> 15*53835Selan #include <sys/stat.h> 16*53835Selan #include "operators.h" 17*53835Selan #include "extern.h" 18*53835Selan 19*53835Selan #define STACKSIZE 12 20*53835Selan #define NESTINCR 16 21*53835Selan 22*53835Selan /* data types */ 23*53835Selan #define STRING 0 24*53835Selan #define INTEGER 1 25*53835Selan #define BOOLEAN 2 26*53835Selan 27*53835Selan #define INITARGS(argv) if (argv[0] == NULL) {fputs("Argc is zero\n", stderr); exit(2);} else 28*53835Selan 29*53835Selan #define IS_BANG(s) (s[0] == '!' && s[1] == '\0') 30*53835Selan 31*53835Selan #define equal(s1, s2) (strcmp(s1, s2) == 0) 32*53835Selan 33*53835Selan 34*53835Selan /* 35*53835Selan * This structure hold a value. The type keyword specifies the type of 36*53835Selan * the value, and the union u holds the value. The value of a boolean 37*53835Selan * is stored in u.num (1 = TRUE, 0 = FALSE). 38*53835Selan */ 39*53835Selan 40*53835Selan struct value { 41*53835Selan int type; 42*53835Selan union { 43*53835Selan char *string; 44*53835Selan long num; 45*53835Selan } u; 46*53835Selan }; 47*53835Selan 48*53835Selan struct operator { 49*53835Selan short op; /* which operator */ 50*53835Selan short pri; /* priority of operator */ 51*53835Selan }; 52*53835Selan 53*53835Selan 54*53835Selan struct filestat { 55*53835Selan char *name; /* name of file */ 56*53835Selan int rcode; /* return code from stat */ 57*53835Selan struct stat stat; /* status info on file */ 58*53835Selan }; 59*53835Selan 60*53835Selan static int expr_is_false __P((struct value *)); 61*53835Selan static void expr_operator __P((int, struct value *, struct filestat *)); 62*53835Selan static int lookup_op __P((char *, char *const*)); 63*53835Selan static long atol __P((const char *)); 64*53835Selan static int posix_binary_op __P((char **)); 65*53835Selan static int posix_unary_op __P((char **)); 66*53835Selan static int int_tcheck __P((char *)); 67*53835Selan 68*53835Selan int 69*53835Selan main(argc, argv) 70*53835Selan int argc; 71*53835Selan char **argv; 72*53835Selan { 73*53835Selan char **ap; 74*53835Selan char *opname; 75*53835Selan char c; 76*53835Selan char *p; 77*53835Selan int nest; /* parenthises nesting */ 78*53835Selan int op; 79*53835Selan int pri; 80*53835Selan int skipping; 81*53835Selan int binary; 82*53835Selan struct operator opstack[STACKSIZE]; 83*53835Selan struct operator *opsp; 84*53835Selan struct value valstack[STACKSIZE + 1]; 85*53835Selan struct value *valsp; 86*53835Selan struct filestat fs; 87*53835Selan int ret_val; 88*53835Selan 89*53835Selan INITARGS(argv); 90*53835Selan if (**argv == '[') { 91*53835Selan if (! equal(argv[argc - 1], "]")) 92*53835Selan error("missing ]"); 93*53835Selan argv[argc - 1] = NULL; 94*53835Selan } 95*53835Selan ap = argv + 1; 96*53835Selan fs.name = NULL; 97*53835Selan 98*53835Selan /* 99*53835Selan * Test(1) implements an inherently ambiguous grammer. In order to 100*53835Selan * assure some degree of consistency, we special case the POSIX 101*53835Selan * requirements to assure correct evaluation for POSIX following 102*53835Selan * scripts. The following special cases comply with POSIX 103*53835Selan * P1003.2/D11.2 Section 4.62.4. 104*53835Selan */ 105*53835Selan switch(argc - 1) { 106*53835Selan case 0: /* % test */ 107*53835Selan #ifdef PRINT 108*53835Selan printf("1\n"); 109*53835Selan #endif 110*53835Selan return 1; 111*53835Selan break; 112*53835Selan case 1: /* % test arg */ 113*53835Selan #ifdef PRINT 114*53835Selan printf("%d\n", (*argv[1] == '\0')? 1 : 0); 115*53835Selan #endif 116*53835Selan return (*argv[1] == '\0')? 1 : 0; 117*53835Selan break; 118*53835Selan case 2: /* % test op arg */ 119*53835Selan opname = argv[1]; 120*53835Selan if (IS_BANG(opname)) { 121*53835Selan #ifdef PRINT 122*53835Selan printf("%d\n", (*argv[2] == '\0')? 1 : 0); 123*53835Selan #endif 124*53835Selan return (*argv[2] == '\0')? 1 : 0; 125*53835Selan } else { 126*53835Selan ret_val = posix_unary_op(&argv[1]); 127*53835Selan if (ret_val >= 0) { 128*53835Selan #ifdef PRINT 129*53835Selan printf("%d\n", ret_val); 130*53835Selan #endif 131*53835Selan return ret_val; 132*53835Selan } 133*53835Selan } 134*53835Selan break; 135*53835Selan case 3: /* % test arg1 op arg2 */ 136*53835Selan if (IS_BANG(argv[1])) { 137*53835Selan ret_val = posix_unary_op(&argv[1]); 138*53835Selan if (ret_val >= 0) { 139*53835Selan #ifdef PRINT 140*53835Selan printf("%d\n", !ret_val); 141*53835Selan #endif 142*53835Selan return !ret_val; 143*53835Selan } 144*53835Selan } else { 145*53835Selan ret_val = posix_binary_op(&argv[1]); 146*53835Selan if (ret_val >= 0) { 147*53835Selan #ifdef PRINT 148*53835Selan printf("%d\n", ret_val); 149*53835Selan #endif 150*53835Selan return ret_val; 151*53835Selan } 152*53835Selan } 153*53835Selan break; 154*53835Selan case 4: /* % test ! arg1 op arg2 */ 155*53835Selan if (IS_BANG(argv[1])) { 156*53835Selan ret_val = posix_binary_op(&argv[2]); 157*53835Selan if (ret_val >= 0) { 158*53835Selan #ifdef PRINT 159*53835Selan printf("%d\n", !ret_val); 160*53835Selan #endif 161*53835Selan return !ret_val; 162*53835Selan } 163*53835Selan } 164*53835Selan break; 165*53835Selan default: 166*53835Selan break; 167*53835Selan } 168*53835Selan 169*53835Selan /* 170*53835Selan * We use operator precedence parsing, evaluating the expression 171*53835Selan * as we parse it. Parentheses are handled by bumping up the 172*53835Selan * priority of operators using the variable "nest." We use the 173*53835Selan * variable "skipping" to turn off evaluation temporarily for the 174*53835Selan * short circuit boolean operators. (It is important do the short 175*53835Selan * circuit evaluation because under NFS a stat operation can take 176*53835Selan * infinitely long.) 177*53835Selan */ 178*53835Selan 179*53835Selan opsp = opstack + STACKSIZE; 180*53835Selan valsp = valstack; 181*53835Selan nest = 0; 182*53835Selan skipping = 0; 183*53835Selan if (*ap == NULL) { 184*53835Selan valstack[0].type = BOOLEAN; 185*53835Selan valstack[0].u.num = 0; 186*53835Selan goto done; 187*53835Selan } 188*53835Selan for (;;) { 189*53835Selan opname = *ap++; 190*53835Selan if (opname == NULL) 191*53835Selan goto syntax; 192*53835Selan if (opname[0] == '(' && opname[1] == '\0') { 193*53835Selan nest += NESTINCR; 194*53835Selan continue; 195*53835Selan } else if (*ap && (op = lookup_op(opname, unary_op)) >= 0) { 196*53835Selan if (opsp == &opstack[0]) 197*53835Selan goto overflow; 198*53835Selan --opsp; 199*53835Selan opsp->op = op; 200*53835Selan opsp->pri = op_priority[op] + nest; 201*53835Selan continue; 202*53835Selan 203*53835Selan } else { 204*53835Selan valsp->type = STRING; 205*53835Selan valsp->u.string = opname; 206*53835Selan valsp++; 207*53835Selan } 208*53835Selan for (;;) { 209*53835Selan opname = *ap++; 210*53835Selan if (opname == NULL) { 211*53835Selan if (nest != 0) 212*53835Selan goto syntax; 213*53835Selan pri = 0; 214*53835Selan break; 215*53835Selan } 216*53835Selan if (opname[0] != ')' || opname[1] != '\0') { 217*53835Selan if ((op = lookup_op(opname, binary_op)) < 0) 218*53835Selan goto syntax; 219*53835Selan op += FIRST_BINARY_OP; 220*53835Selan pri = op_priority[op] + nest; 221*53835Selan break; 222*53835Selan } 223*53835Selan if ((nest -= NESTINCR) < 0) 224*53835Selan goto syntax; 225*53835Selan } 226*53835Selan while (opsp < &opstack[STACKSIZE] && opsp->pri >= pri) { 227*53835Selan binary = opsp->op; 228*53835Selan for (;;) { 229*53835Selan valsp--; 230*53835Selan c = op_argflag[opsp->op]; 231*53835Selan if (c == OP_INT) { 232*53835Selan if (valsp->type == STRING && 233*53835Selan int_tcheck(valsp->u.string)) 234*53835Selan valsp->u.num = 235*53835Selan atol(valsp->u.string); 236*53835Selan valsp->type = INTEGER; 237*53835Selan } else if (c >= OP_STRING) { /* OP_STRING or OP_FILE */ 238*53835Selan if (valsp->type == INTEGER) { 239*53835Selan p = stalloc(32); 240*53835Selan #ifdef SHELL 241*53835Selan fmtstr(p, 32, "%d", valsp->u.num); 242*53835Selan #else 243*53835Selan sprintf(p, "%d", valsp->u.num); 244*53835Selan #endif 245*53835Selan valsp->u.string = p; 246*53835Selan } else if (valsp->type == BOOLEAN) { 247*53835Selan if (valsp->u.num) 248*53835Selan valsp->u.string = "true"; 249*53835Selan else 250*53835Selan valsp->u.string = ""; 251*53835Selan } 252*53835Selan valsp->type = STRING; 253*53835Selan if (c == OP_FILE 254*53835Selan && (fs.name == NULL 255*53835Selan || ! equal(fs.name, valsp->u.string))) { 256*53835Selan fs.name = valsp->u.string; 257*53835Selan fs.rcode = stat(valsp->u.string, &fs.stat); 258*53835Selan } 259*53835Selan } 260*53835Selan if (binary < FIRST_BINARY_OP) 261*53835Selan break; 262*53835Selan binary = 0; 263*53835Selan } 264*53835Selan if (! skipping) 265*53835Selan expr_operator(opsp->op, valsp, &fs); 266*53835Selan else if (opsp->op == AND1 || opsp->op == OR1) 267*53835Selan skipping--; 268*53835Selan valsp++; /* push value */ 269*53835Selan opsp++; /* pop operator */ 270*53835Selan } 271*53835Selan if (opname == NULL) 272*53835Selan break; 273*53835Selan if (opsp == &opstack[0]) 274*53835Selan goto overflow; 275*53835Selan if (op == AND1 || op == AND2) { 276*53835Selan op = AND1; 277*53835Selan if (skipping || expr_is_false(valsp - 1)) 278*53835Selan skipping++; 279*53835Selan } 280*53835Selan if (op == OR1 || op == OR2) { 281*53835Selan op = OR1; 282*53835Selan if (skipping || ! expr_is_false(valsp - 1)) 283*53835Selan skipping++; 284*53835Selan } 285*53835Selan opsp--; 286*53835Selan opsp->op = op; 287*53835Selan opsp->pri = pri; 288*53835Selan } 289*53835Selan done: 290*53835Selan #ifdef PRINT 291*53835Selan if (valstack[0].type == STRING) 292*53835Selan printf("%s\n", valstack[0].u.string); 293*53835Selan else if (valstack[0].type == INTEGER) 294*53835Selan printf("%ld\n", valstack[0].u.num); 295*53835Selan 296*53835Selan else if (valstack[0].u.num != 0) 297*53835Selan printf("true\n"); 298*53835Selan #endif 299*53835Selan 300*53835Selan return expr_is_false(&valstack[0]); 301*53835Selan 302*53835Selan syntax: error("syntax error"); 303*53835Selan overflow: error("Expression too complex"); 304*53835Selan 305*53835Selan } 306*53835Selan 307*53835Selan 308*53835Selan static int 309*53835Selan expr_is_false(val) 310*53835Selan struct value *val; 311*53835Selan { 312*53835Selan if (val->type == STRING) { 313*53835Selan if (val->u.string[0] == '\0') 314*53835Selan return 1; 315*53835Selan } else { /* INTEGER or BOOLEAN */ 316*53835Selan if (val->u.num == 0) 317*53835Selan return 1; 318*53835Selan } 319*53835Selan return 0; 320*53835Selan } 321*53835Selan 322*53835Selan 323*53835Selan /* 324*53835Selan * Execute an operator. Op is the operator. Sp is the stack pointer; 325*53835Selan * sp[0] refers to the first operand, sp[1] refers to the second operand 326*53835Selan * (if any), and the result is placed in sp[0]. The operands are converted 327*53835Selan * to the type expected by the operator before expr_operator is called. 328*53835Selan * Fs is a pointer to a structure which holds the value of the last call 329*53835Selan * to stat, to avoid repeated stat calls on the same file. 330*53835Selan */ 331*53835Selan 332*53835Selan static void 333*53835Selan expr_operator(op, sp, fs) 334*53835Selan int op; 335*53835Selan struct value *sp; 336*53835Selan struct filestat *fs; 337*53835Selan { 338*53835Selan int i; 339*53835Selan 340*53835Selan switch (op) { 341*53835Selan case NOT: 342*53835Selan sp->u.num = expr_is_false(sp); 343*53835Selan sp->type = BOOLEAN; 344*53835Selan break; 345*53835Selan case ISEXIST: 346*53835Selan if (fs == NULL || (fs->rcode == -1 && errno == ENOENT)) 347*53835Selan goto false; 348*53835Selan else 349*53835Selan goto true; 350*53835Selan case ISREAD: 351*53835Selan i = 04; 352*53835Selan goto permission; 353*53835Selan case ISWRITE: 354*53835Selan i = 02; 355*53835Selan goto permission; 356*53835Selan case ISEXEC: 357*53835Selan i = 01; 358*53835Selan permission: 359*53835Selan if (fs->stat.st_uid == geteuid()) 360*53835Selan i <<= 6; 361*53835Selan else if (fs->stat.st_gid == getegid()) 362*53835Selan i <<= 3; 363*53835Selan goto filebit; /* true if (stat.st_mode & i) != 0 */ 364*53835Selan case ISFILE: 365*53835Selan i = S_IFREG; 366*53835Selan goto filetype; 367*53835Selan case ISDIR: 368*53835Selan i = S_IFDIR; 369*53835Selan goto filetype; 370*53835Selan case ISCHAR: 371*53835Selan i = S_IFCHR; 372*53835Selan goto filetype; 373*53835Selan case ISBLOCK: 374*53835Selan i = S_IFBLK; 375*53835Selan goto filetype; 376*53835Selan case ISFIFO: 377*53835Selan #ifdef S_IFIFO 378*53835Selan i = S_IFIFO; 379*53835Selan goto filetype; 380*53835Selan #else 381*53835Selan goto false; 382*53835Selan #endif 383*53835Selan filetype: 384*53835Selan if ((fs->stat.st_mode & S_IFMT) == i && fs->rcode >= 0) { 385*53835Selan true: 386*53835Selan sp->u.num = 1; 387*53835Selan } else { 388*53835Selan false: 389*53835Selan sp->u.num = 0; 390*53835Selan } 391*53835Selan sp->type = BOOLEAN; 392*53835Selan break; 393*53835Selan case ISSETUID: 394*53835Selan i = S_ISUID; 395*53835Selan goto filebit; 396*53835Selan case ISSETGID: 397*53835Selan i = S_ISGID; 398*53835Selan goto filebit; 399*53835Selan case ISSTICKY: 400*53835Selan i = S_ISVTX; 401*53835Selan filebit: 402*53835Selan if (fs->stat.st_mode & i && fs->rcode >= 0) 403*53835Selan goto true; 404*53835Selan goto false; 405*53835Selan case ISSIZE: 406*53835Selan sp->u.num = fs->rcode >= 0? fs->stat.st_size : 0L; 407*53835Selan sp->type = INTEGER; 408*53835Selan break; 409*53835Selan case ISTTY: 410*53835Selan sp->u.num = isatty(sp->u.num); 411*53835Selan sp->type = BOOLEAN; 412*53835Selan break; 413*53835Selan case NULSTR: 414*53835Selan if (sp->u.string[0] == '\0') 415*53835Selan goto true; 416*53835Selan goto false; 417*53835Selan case STRLEN: 418*53835Selan sp->u.num = strlen(sp->u.string); 419*53835Selan sp->type = INTEGER; 420*53835Selan break; 421*53835Selan case OR1: 422*53835Selan case AND1: 423*53835Selan /* 424*53835Selan * These operators are mostly handled by the parser. If we 425*53835Selan * get here it means that both operands were evaluated, so 426*53835Selan * the value is the value of the second operand. 427*53835Selan */ 428*53835Selan *sp = *(sp + 1); 429*53835Selan break; 430*53835Selan case STREQ: 431*53835Selan case STRNE: 432*53835Selan i = 0; 433*53835Selan if (equal(sp->u.string, (sp + 1)->u.string)) 434*53835Selan i++; 435*53835Selan if (op == STRNE) 436*53835Selan i = 1 - i; 437*53835Selan sp->u.num = i; 438*53835Selan sp->type = BOOLEAN; 439*53835Selan break; 440*53835Selan case EQ: 441*53835Selan if (sp->u.num == (sp + 1)->u.num) 442*53835Selan goto true; 443*53835Selan goto false; 444*53835Selan case NE: 445*53835Selan if (sp->u.num != (sp + 1)->u.num) 446*53835Selan goto true; 447*53835Selan goto false; 448*53835Selan case GT: 449*53835Selan if (sp->u.num > (sp + 1)->u.num) 450*53835Selan goto true; 451*53835Selan goto false; 452*53835Selan case LT: 453*53835Selan if (sp->u.num < (sp + 1)->u.num) 454*53835Selan goto true; 455*53835Selan goto false; 456*53835Selan case LE: 457*53835Selan if (sp->u.num <= (sp + 1)->u.num) 458*53835Selan goto true; 459*53835Selan goto false; 460*53835Selan case GE: 461*53835Selan if (sp->u.num >= (sp + 1)->u.num) 462*53835Selan goto true; 463*53835Selan goto false; 464*53835Selan 465*53835Selan } 466*53835Selan } 467*53835Selan 468*53835Selan 469*53835Selan static int 470*53835Selan lookup_op(name, table) 471*53835Selan char *name; 472*53835Selan char *const*table; 473*53835Selan { 474*53835Selan register char *const*tp; 475*53835Selan register char const *p; 476*53835Selan char c = name[1]; 477*53835Selan 478*53835Selan for (tp = table ; (p = *tp) != NULL ; tp++) { 479*53835Selan if (p[1] == c && equal(p, name)) 480*53835Selan return tp - table; 481*53835Selan } 482*53835Selan return -1; 483*53835Selan } 484*53835Selan 485*53835Selan static int 486*53835Selan posix_unary_op(argv) 487*53835Selan char **argv; 488*53835Selan { 489*53835Selan int op, c; 490*53835Selan char *opname; 491*53835Selan struct filestat fs; 492*53835Selan struct value valp; 493*53835Selan 494*53835Selan opname = *argv; 495*53835Selan if ((op = lookup_op(opname, unary_op)) < 0) 496*53835Selan return -1; 497*53835Selan c = op_argflag[op]; 498*53835Selan opname = argv[1]; 499*53835Selan valp.u.string = opname; 500*53835Selan if (c == OP_FILE) { 501*53835Selan fs.name = opname; 502*53835Selan fs.rcode = stat(opname, &fs.stat); 503*53835Selan } else if (c != OP_STRING) 504*53835Selan return -1; 505*53835Selan 506*53835Selan expr_operator(op, &valp, &fs); 507*53835Selan return (valp.u.num == 0); 508*53835Selan } 509*53835Selan 510*53835Selan 511*53835Selan static int 512*53835Selan posix_binary_op(argv) 513*53835Selan char **argv; 514*53835Selan { 515*53835Selan int op, c; 516*53835Selan char *opname; 517*53835Selan struct value v[2]; 518*53835Selan 519*53835Selan opname = argv[1]; 520*53835Selan if ((op = lookup_op(opname, binary_op)) < 0) 521*53835Selan return -1; 522*53835Selan op += FIRST_BINARY_OP; 523*53835Selan c = op_argflag[op]; 524*53835Selan 525*53835Selan if (c == OP_INT && int_tcheck(argv[0]) && int_tcheck(argv[2])) { 526*53835Selan v[0].u.num = atol(argv[0]); 527*53835Selan v[1].u.num = atol(argv[2]); 528*53835Selan } 529*53835Selan expr_operator(op, v, NULL); 530*53835Selan return (v[0].u.num == 0); 531*53835Selan } 532*53835Selan 533*53835Selan /* 534*53835Selan * Integer type checking. 535*53835Selan */ 536*53835Selan static int 537*53835Selan int_tcheck(v) 538*53835Selan char *v; 539*53835Selan { 540*53835Selan char *p; 541*53835Selan char outbuf[512]; 542*53835Selan 543*53835Selan for (p = v; *p != '\0'; p++) 544*53835Selan if (*p < '0' || *p > '9') { 545*53835Selan snprintf(outbuf, sizeof(outbuf), 546*53835Selan "Illegal operand \"%s\" -- expected integer.", v); 547*53835Selan 548*53835Selan error(outbuf); 549*53835Selan } 550*53835Selan return 1; 551*53835Selan } 552*53835Selan 553*53835Selan 554*53835Selan 555*53835Selan 556*53835Selan 557*53835Selan 558*53835Selan 559*53835Selan 560*53835Selan 561*53835Selan 562