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