1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * David Korn <dgk@research.att.com> * 18 * * 19 ***********************************************************************/ 20 #pragma prototyped 21 /* 22 * test expression 23 * [ expression ] 24 * 25 * David Korn 26 * AT&T Labs 27 * 28 */ 29 30 31 #include "defs.h" 32 #include <ctype.h> 33 #include <error.h> 34 #include <ls.h> 35 #include "io.h" 36 #include "terminal.h" 37 #include "test.h" 38 #include "builtins.h" 39 #include "FEATURE/externs" 40 #include "FEATURE/poll" 41 #include <tmx.h> 42 43 #if !_lib_setregid 44 # undef _lib_setreuid 45 #endif /* _lib_setregid */ 46 47 #ifdef S_ISSOCK 48 # if _pipe_socketpair 49 # if _socketpair_shutdown_mode 50 # define isapipe(f,p) (test_stat(f,p)>=0&&S_ISFIFO((p)->st_mode)||S_ISSOCK((p)->st_mode)&&(p)->st_ino&&((p)->st_mode&(S_IRUSR|S_IWUSR))!=(S_IRUSR|S_IWUSR)) 51 # else 52 # define isapipe(f,p) (test_stat(f,p)>=0&&S_ISFIFO((p)->st_mode)||S_ISSOCK((p)->st_mode)&&(p)->st_ino) 53 # endif 54 # else 55 # define isapipe(f,p) (test_stat(f,p)>=0&&S_ISFIFO((p)->st_mode)||S_ISSOCK((p)->st_mode)&&(p)->st_ino) 56 # endif 57 # define isasock(f,p) (test_stat(f,p)>=0&&S_ISSOCK((p)->st_mode)) 58 #else 59 # define isapipe(f,p) (test_stat(f,p)>=0&&S_ISFIFO((p)->st_mode)) 60 # define isasock(f,p) (0) 61 #endif 62 63 #define permission(a,f) (sh_access(a,f)==0) 64 static time_t test_time(const char*, const char*); 65 static int test_stat(const char*, struct stat*); 66 static int test_mode(const char*); 67 68 /* single char string compare */ 69 #define c_eq(a,c) (*a==c && *(a+1)==0) 70 /* two character string compare */ 71 #define c2_eq(a,c1,c2) (*a==c1 && *(a+1)==c2 && *(a+2)==0) 72 73 struct test 74 { 75 Shell_t *sh; 76 int ap; 77 int ac; 78 char **av; 79 }; 80 81 static char *nxtarg(struct test*,int); 82 static int expr(struct test*,int); 83 static int e3(struct test*); 84 85 static int test_strmatch(const char *str, const char *pat) 86 { 87 int match[2*(MATCH_MAX+1)],n; 88 register int c, m=0; 89 register const char *cp=pat; 90 while(c = *cp++) 91 { 92 if(c=='(') 93 m++; 94 if(c=='\\' && *cp) 95 cp++; 96 } 97 if(m) 98 m++; 99 else 100 match[0] = 0; 101 if(m > elementsof(match)/2) 102 m = elementsof(match)/2; 103 n = strgrpmatch(str, pat, match, m, STR_MAXIMAL|STR_LEFT|STR_RIGHT); 104 if(m==0 && n==1) 105 match[1] = strlen(str); 106 if(n) 107 sh_setmatch(str, -1, n, match); 108 return(n); 109 } 110 111 int b_test(int argc, char *argv[],void *extra) 112 { 113 struct test tdata; 114 register char *cp = argv[0]; 115 register int not; 116 tdata.sh = (Shell_t*)extra; 117 tdata.av = argv; 118 tdata.ap = 1; 119 if(c_eq(cp,'[')) 120 { 121 cp = argv[--argc]; 122 if(!c_eq(cp, ']')) 123 errormsg(SH_DICT,ERROR_exit(2),e_missing,"']'"); 124 } 125 if(argc <= 1) 126 return(1); 127 cp = argv[1]; 128 not = c_eq(cp,'!'); 129 /* posix portion for test */ 130 switch(argc) 131 { 132 case 5: 133 if(!not) 134 break; 135 argv++; 136 /* fall through */ 137 case 4: 138 { 139 register int op = sh_lookup(cp=argv[2],shtab_testops); 140 if(op&TEST_BINOP) 141 break; 142 if(!op) 143 { 144 if(argc==5) 145 break; 146 if(not && cp[0]=='-' && cp[2]==0) 147 return(test_unop(cp[1],argv[3])!=0); 148 else if(argv[1][0]=='-' && argv[1][2]==0) 149 return(!test_unop(argv[1][1],cp)); 150 errormsg(SH_DICT,ERROR_exit(2),e_badop,cp); 151 } 152 return(test_binop(op,argv[1],argv[3])^(argc!=5)); 153 } 154 case 3: 155 if(not) 156 return(*argv[2]!=0); 157 if(cp[0] != '-' || cp[2] || cp[1]=='?') 158 { 159 if(cp[0]=='-' && (cp[1]=='-' || cp[1]=='?') && 160 strcmp(argv[2],"--")==0) 161 { 162 char *av[3]; 163 av[0] = argv[0]; 164 av[1] = argv[1]; 165 av[2] = 0; 166 optget(av,sh_opttest); 167 errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg); 168 return(2); 169 } 170 break; 171 } 172 return(!test_unop(cp[1],argv[2])); 173 case 2: 174 return(*cp==0); 175 } 176 if(argc==5) 177 argv--; 178 tdata.ac = argc; 179 return(!expr(&tdata,0)); 180 } 181 182 /* 183 * evaluate a test expression. 184 * flag is 0 on outer level 185 * flag is 1 when in parenthesis 186 * flag is 2 when evaluating -a 187 */ 188 static int expr(struct test *tp,register int flag) 189 { 190 register int r; 191 register char *p; 192 r = e3(tp); 193 while(tp->ap < tp->ac) 194 { 195 p = nxtarg(tp,0); 196 /* check for -o and -a */ 197 if(flag && c_eq(p,')')) 198 { 199 tp->ap--; 200 break; 201 } 202 if(*p=='-' && *(p+2)==0) 203 { 204 if(*++p == 'o') 205 { 206 if(flag==2) 207 { 208 tp->ap--; 209 break; 210 } 211 r |= expr(tp,3); 212 continue; 213 } 214 else if(*p == 'a') 215 { 216 r &= expr(tp,2); 217 continue; 218 } 219 } 220 if(flag==0) 221 break; 222 errormsg(SH_DICT,ERROR_exit(2),e_badsyntax); 223 } 224 return(r); 225 } 226 227 static char *nxtarg(struct test *tp,int mt) 228 { 229 if(tp->ap >= tp->ac) 230 { 231 if(mt) 232 { 233 tp->ap++; 234 return(0); 235 } 236 errormsg(SH_DICT,ERROR_exit(2),e_argument); 237 } 238 return(tp->av[tp->ap++]); 239 } 240 241 242 static int e3(struct test *tp) 243 { 244 register char *arg, *cp; 245 register int op; 246 char *binop; 247 arg=nxtarg(tp,0); 248 if(arg && c_eq(arg, '!')) 249 return(!e3(tp)); 250 if(c_eq(arg, '(')) 251 { 252 op = expr(tp,1); 253 cp = nxtarg(tp,0); 254 if(!cp || !c_eq(cp, ')')) 255 errormsg(SH_DICT,ERROR_exit(2),e_missing,"')'"); 256 return(op); 257 } 258 cp = nxtarg(tp,1); 259 if(cp!=0 && (c_eq(cp,'=') || c2_eq(cp,'!','='))) 260 goto skip; 261 if(c2_eq(arg,'-','t')) 262 { 263 if(cp && isdigit(*cp)) 264 return(*(cp+1)?0:tty_check(*cp-'0')); 265 else 266 { 267 /* test -t with no arguments */ 268 tp->ap--; 269 return(tty_check(1)); 270 } 271 } 272 if(*arg=='-' && arg[2]==0) 273 { 274 op = arg[1]; 275 if(!cp) 276 { 277 /* for backward compatibility with new flags */ 278 if(op==0 || !strchr(test_opchars+10,op)) 279 return(1); 280 errormsg(SH_DICT,ERROR_exit(2),e_argument); 281 } 282 if(strchr(test_opchars,op)) 283 return(test_unop(op,cp)); 284 } 285 if(!cp) 286 { 287 tp->ap--; 288 return(*arg!=0); 289 } 290 skip: 291 op = sh_lookup(binop=cp,shtab_testops); 292 if(!(op&TEST_BINOP)) 293 cp = nxtarg(tp,0); 294 if(!op) 295 errormsg(SH_DICT,ERROR_exit(2),e_badop,binop); 296 if(op==TEST_AND | op==TEST_OR) 297 tp->ap--; 298 return(test_binop(op,arg,cp)); 299 } 300 301 int test_unop(register int op,register const char *arg) 302 { 303 struct stat statb; 304 int f; 305 switch(op) 306 { 307 case 'r': 308 return(permission(arg, R_OK)); 309 case 'w': 310 return(permission(arg, W_OK)); 311 case 'x': 312 return(permission(arg, X_OK)); 313 case 'V': 314 #if SHOPT_FS_3D 315 { 316 register int offset = staktell(); 317 if(stat(arg,&statb)<0 || !S_ISREG(statb.st_mode)) 318 return(0); 319 /* add trailing / */ 320 stakputs(arg); 321 stakputc('/'); 322 stakputc(0); 323 arg = (const char*)stakptr(offset); 324 stakseek(offset); 325 /* FALL THRU */ 326 } 327 #else 328 return(0); 329 #endif /* SHOPT_FS_3D */ 330 case 'd': 331 return(test_stat(arg,&statb)>=0 && S_ISDIR(statb.st_mode)); 332 case 'c': 333 return(test_stat(arg,&statb)>=0 && S_ISCHR(statb.st_mode)); 334 case 'b': 335 return(test_stat(arg,&statb)>=0 && S_ISBLK(statb.st_mode)); 336 case 'f': 337 return(test_stat(arg,&statb)>=0 && S_ISREG(statb.st_mode)); 338 case 'u': 339 return(test_mode(arg)&S_ISUID); 340 case 'g': 341 return(test_mode(arg)&S_ISGID); 342 case 'k': 343 #ifdef S_ISVTX 344 return(test_mode(arg)&S_ISVTX); 345 #else 346 return(0); 347 #endif /* S_ISVTX */ 348 #if SHOPT_TEST_L 349 case 'l': 350 #endif 351 case 'L': 352 case 'h': /* undocumented, and hopefully will disappear */ 353 if(*arg==0 || arg[strlen(arg)-1]=='/' || lstat(arg,&statb)<0) 354 return(0); 355 return(S_ISLNK(statb.st_mode)); 356 357 case 'C': 358 #ifdef S_ISCTG 359 return(test_stat(arg,&statb)>=0 && S_ISCTG(statb.st_mode)); 360 #else 361 return(0); 362 #endif /* S_ISCTG */ 363 case 'H': 364 #ifdef S_ISCDF 365 { 366 register int offset = staktell(); 367 if(test_stat(arg,&statb)>=0 && S_ISCDF(statb.st_mode)) 368 return(1); 369 stakputs(arg); 370 stakputc('+'); 371 stakputc(0); 372 arg = (const char*)stakptr(offset); 373 stakseek(offset); 374 return(test_stat(arg,&statb)>=0 && S_ISCDF(statb.st_mode)); 375 } 376 #else 377 return(0); 378 #endif /* S_ISCDF */ 379 380 case 'S': 381 return(isasock(arg,&statb)); 382 case 'N': 383 return(test_stat(arg,&statb)>=0 && tmxgetmtime(&statb) > tmxgetatime(&statb)); 384 case 'p': 385 return(isapipe(arg,&statb)); 386 case 'n': 387 return(*arg != 0); 388 case 'z': 389 return(*arg == 0); 390 case 's': 391 sfsync(sfstdout); 392 case 'O': 393 case 'G': 394 if(*arg==0 || test_stat(arg,&statb)<0) 395 return(0); 396 if(op=='s') 397 return(statb.st_size>0); 398 else if(op=='O') 399 return(statb.st_uid==sh.userid); 400 return(statb.st_gid==sh.groupid); 401 case 'a': 402 case 'e': 403 return(permission(arg, F_OK)); 404 case 'o': 405 f=1; 406 if(*arg=='?') 407 return(sh_lookopt(arg+1,&f)>0); 408 op = sh_lookopt(arg,&f); 409 return(op && (f==(sh_isoption(op)!=0))); 410 case 't': 411 if(isdigit(*arg) && arg[1]==0) 412 return(tty_check(*arg-'0')); 413 return(0); 414 default: 415 { 416 static char a[3] = "-?"; 417 a[1]= op; 418 errormsg(SH_DICT,ERROR_exit(2),e_badop,a); 419 /* NOTREACHED */ 420 return(0); 421 } 422 } 423 } 424 425 int test_binop(register int op,const char *left,const char *right) 426 { 427 register double lnum,rnum; 428 if(op&TEST_ARITH) 429 { 430 while(*left=='0') 431 left++; 432 while(*right=='0') 433 right++; 434 lnum = sh_arith(left); 435 rnum = sh_arith(right); 436 } 437 switch(op) 438 { 439 /* op must be one of the following values */ 440 case TEST_AND: 441 case TEST_OR: 442 return(*left!=0); 443 case TEST_PEQ: 444 return(test_strmatch(left, right)); 445 case TEST_PNE: 446 return(!test_strmatch(left, right)); 447 case TEST_SGT: 448 return(strcoll(left, right)>0); 449 case TEST_SLT: 450 return(strcoll(left, right)<0); 451 case TEST_SEQ: 452 return(strcmp(left, right)==0); 453 case TEST_SNE: 454 return(strcmp(left, right)!=0); 455 case TEST_EF: 456 return(test_inode(left,right)); 457 case TEST_NT: 458 return(test_time(left,right)>0); 459 case TEST_OT: 460 return(test_time(left,right)<0); 461 case TEST_EQ: 462 return(lnum==rnum); 463 case TEST_NE: 464 return(lnum!=rnum); 465 case TEST_GT: 466 return(lnum>rnum); 467 case TEST_LT: 468 return(lnum<rnum); 469 case TEST_GE: 470 return(lnum>=rnum); 471 case TEST_LE: 472 return(lnum<=rnum); 473 } 474 /* NOTREACHED */ 475 return(0); 476 } 477 478 /* 479 * returns the modification time of f1 - modification time of f2 480 */ 481 482 static time_t test_time(const char *file1,const char *file2) 483 { 484 Time_t t1, t2; 485 struct stat statb1,statb2; 486 int r=test_stat(file2,&statb2); 487 if(test_stat(file1,&statb1)<0) 488 return(r<0?0:-1); 489 if(r<0) 490 return(1); 491 t1 = tmxgetmtime(&statb1); 492 t2 = tmxgetmtime(&statb2); 493 if (t1 > t2) 494 return(1); 495 if (t1 < t2) 496 return(-1); 497 return(0); 498 } 499 500 /* 501 * return true if inode of two files are the same 502 */ 503 504 int test_inode(const char *file1,const char *file2) 505 { 506 struct stat stat1,stat2; 507 if(test_stat(file1,&stat1)>=0 && test_stat(file2,&stat2)>=0) 508 if(stat1.st_dev == stat2.st_dev && stat1.st_ino == stat2.st_ino) 509 return(1); 510 return(0); 511 } 512 513 514 /* 515 * This version of access checks against effective uid/gid 516 * The static buffer statb is shared with test_mode. 517 */ 518 519 int sh_access(register const char *name, register int mode) 520 { 521 struct stat statb; 522 if(*name==0) 523 return(-1); 524 if(strmatch(name,(char*)e_devfdNN)) 525 return(sh_ioaccess((int)strtol(name+8, (char**)0, 10),mode)); 526 /* can't use access function for execute permission with root */ 527 if(mode==X_OK && sh.euserid==0) 528 goto skip; 529 if(sh.userid==sh.euserid && sh.groupid==sh.egroupid) 530 return(access(name,mode)); 531 #ifdef _lib_setreuid 532 /* swap the real uid to effective, check access then restore */ 533 /* first swap real and effective gid, if different */ 534 if(sh.groupid==sh.euserid || setregid(sh.egroupid,sh.groupid)==0) 535 { 536 /* next swap real and effective uid, if needed */ 537 if(sh.userid==sh.euserid || setreuid(sh.euserid,sh.userid)==0) 538 { 539 mode = access(name,mode); 540 /* restore ids */ 541 if(sh.userid!=sh.euserid) 542 setreuid(sh.userid,sh.euserid); 543 if(sh.groupid!=sh.egroupid) 544 setregid(sh.groupid,sh.egroupid); 545 return(mode); 546 } 547 else if(sh.groupid!=sh.egroupid) 548 setregid(sh.groupid,sh.egroupid); 549 } 550 #endif /* _lib_setreuid */ 551 skip: 552 if(test_stat(name, &statb) == 0) 553 { 554 if(mode == F_OK) 555 return(mode); 556 else if(sh.euserid == 0) 557 { 558 if(!S_ISREG(statb.st_mode) || mode!=X_OK) 559 return(0); 560 /* root needs execute permission for someone */ 561 mode = (S_IXUSR|S_IXGRP|S_IXOTH); 562 } 563 else if(sh.euserid == statb.st_uid) 564 mode <<= 6; 565 else if(sh.egroupid == statb.st_gid) 566 mode <<= 3; 567 #ifdef _lib_getgroups 568 /* on some systems you can be in several groups */ 569 else 570 { 571 static int maxgroups; 572 gid_t *groups; 573 register int n; 574 if(maxgroups==0) 575 { 576 /* first time */ 577 if((maxgroups=getgroups(0,(gid_t*)0)) <= 0) 578 { 579 /* pre-POSIX system */ 580 maxgroups=NGROUPS_MAX; 581 } 582 } 583 groups = (gid_t*)stakalloc((maxgroups+1)*sizeof(gid_t)); 584 n = getgroups(maxgroups,groups); 585 while(--n >= 0) 586 { 587 if(groups[n] == statb.st_gid) 588 { 589 mode <<= 3; 590 break; 591 } 592 } 593 } 594 # endif /* _lib_getgroups */ 595 if(statb.st_mode & mode) 596 return(0); 597 } 598 return(-1); 599 } 600 601 /* 602 * Return the mode bits of file <file> 603 * If <file> is null, then the previous stat buffer is used. 604 * The mode bits are zero if the file doesn't exist. 605 */ 606 607 static int test_mode(register const char *file) 608 { 609 struct stat statb; 610 if(file && (*file==0 || test_stat(file,&statb)<0)) 611 return(0); 612 return(statb.st_mode); 613 } 614 615 /* 616 * do an fstat() for /dev/fd/n, otherwise stat() 617 */ 618 static int test_stat(const char *name,struct stat *buff) 619 { 620 if(*name==0) 621 { 622 errno = ENOENT; 623 return(-1); 624 } 625 if(strmatch(name,(char*)e_devfdNN)) 626 return(fstat((int)strtol(name+8, (char**)0, 10),buff)); 627 else 628 return(stat(name,buff)); 629 } 630