14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1982-2010 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 78462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * David Korn <dgk@research.att.com> * 184887Schin * * 194887Schin ***********************************************************************/ 204887Schin #pragma prototyped 214887Schin /* 224887Schin * test expression 234887Schin * [ expression ] 244887Schin * 254887Schin * David Korn 264887Schin * AT&T Labs 274887Schin * 284887Schin */ 294887Schin 304887Schin 314887Schin #include "defs.h" 324887Schin #include <error.h> 334887Schin #include <ls.h> 344887Schin #include "io.h" 354887Schin #include "terminal.h" 364887Schin #include "test.h" 374887Schin #include "builtins.h" 384887Schin #include "FEATURE/externs" 394887Schin #include "FEATURE/poll" 404887Schin #include <tmx.h> 414887Schin 424887Schin #if !_lib_setregid 434887Schin # undef _lib_setreuid 444887Schin #endif /* _lib_setregid */ 454887Schin 464887Schin #ifdef S_ISSOCK 474887Schin # if _pipe_socketpair 484887Schin # if _socketpair_shutdown_mode 494887Schin # 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)) 504887Schin # else 514887Schin # define isapipe(f,p) (test_stat(f,p)>=0&&S_ISFIFO((p)->st_mode)||S_ISSOCK((p)->st_mode)&&(p)->st_ino) 524887Schin # endif 534887Schin # else 544887Schin # define isapipe(f,p) (test_stat(f,p)>=0&&S_ISFIFO((p)->st_mode)||S_ISSOCK((p)->st_mode)&&(p)->st_ino) 554887Schin # endif 564887Schin # define isasock(f,p) (test_stat(f,p)>=0&&S_ISSOCK((p)->st_mode)) 574887Schin #else 584887Schin # define isapipe(f,p) (test_stat(f,p)>=0&&S_ISFIFO((p)->st_mode)) 594887Schin # define isasock(f,p) (0) 604887Schin #endif 614887Schin 624887Schin #define permission(a,f) (sh_access(a,f)==0) 634887Schin static time_t test_time(const char*, const char*); 644887Schin static int test_stat(const char*, struct stat*); 654887Schin static int test_mode(const char*); 664887Schin 674887Schin /* single char string compare */ 684887Schin #define c_eq(a,c) (*a==c && *(a+1)==0) 694887Schin /* two character string compare */ 704887Schin #define c2_eq(a,c1,c2) (*a==c1 && *(a+1)==c2 && *(a+2)==0) 714887Schin 724887Schin struct test 734887Schin { 744887Schin Shell_t *sh; 754887Schin int ap; 764887Schin int ac; 774887Schin char **av; 784887Schin }; 794887Schin 804887Schin static char *nxtarg(struct test*,int); 814887Schin static int expr(struct test*,int); 824887Schin static int e3(struct test*); 834887Schin 844887Schin static int test_strmatch(const char *str, const char *pat) 854887Schin { 864887Schin int match[2*(MATCH_MAX+1)],n; 874887Schin register int c, m=0; 884887Schin register const char *cp=pat; 894887Schin while(c = *cp++) 904887Schin { 914887Schin if(c=='(') 924887Schin m++; 934887Schin if(c=='\\' && *cp) 944887Schin cp++; 954887Schin } 964887Schin if(m) 974887Schin m++; 984887Schin else 994887Schin match[0] = 0; 1004887Schin if(m > elementsof(match)/2) 1014887Schin m = elementsof(match)/2; 1024887Schin n = strgrpmatch(str, pat, match, m, STR_MAXIMAL|STR_LEFT|STR_RIGHT); 1034887Schin if(m==0 && n==1) 1044887Schin match[1] = strlen(str); 1054887Schin if(n) 1064887Schin sh_setmatch(str, -1, n, match); 1074887Schin return(n); 1084887Schin } 1094887Schin 1104887Schin int b_test(int argc, char *argv[],void *extra) 1114887Schin { 1124887Schin struct test tdata; 1134887Schin register char *cp = argv[0]; 1144887Schin register int not; 1158462SApril.Chin@Sun.COM tdata.sh = ((Shbltin_t*)extra)->shp; 1164887Schin tdata.av = argv; 1174887Schin tdata.ap = 1; 1184887Schin if(c_eq(cp,'[')) 1194887Schin { 1204887Schin cp = argv[--argc]; 1214887Schin if(!c_eq(cp, ']')) 1224887Schin errormsg(SH_DICT,ERROR_exit(2),e_missing,"']'"); 1234887Schin } 1244887Schin if(argc <= 1) 1254887Schin return(1); 1264887Schin cp = argv[1]; 1278462SApril.Chin@Sun.COM if(c_eq(cp,'(') && argc<=6 && c_eq(argv[argc-1],')')) 1288462SApril.Chin@Sun.COM { 1298462SApril.Chin@Sun.COM /* special case ( binop ) to conform with standard */ 1308462SApril.Chin@Sun.COM if(!(argc==4 && (not=sh_lookup(cp=argv[2],shtab_testops)))) 1318462SApril.Chin@Sun.COM { 1328462SApril.Chin@Sun.COM cp = (++argv)[1]; 1338462SApril.Chin@Sun.COM argc -= 2; 1348462SApril.Chin@Sun.COM } 1358462SApril.Chin@Sun.COM } 1364887Schin not = c_eq(cp,'!'); 1374887Schin /* posix portion for test */ 1384887Schin switch(argc) 1394887Schin { 1404887Schin case 5: 1414887Schin if(!not) 1424887Schin break; 1434887Schin argv++; 1444887Schin /* fall through */ 1454887Schin case 4: 1464887Schin { 1474887Schin register int op = sh_lookup(cp=argv[2],shtab_testops); 1484887Schin if(op&TEST_BINOP) 1494887Schin break; 1504887Schin if(!op) 1514887Schin { 1524887Schin if(argc==5) 1534887Schin break; 1544887Schin if(not && cp[0]=='-' && cp[2]==0) 1554887Schin return(test_unop(cp[1],argv[3])!=0); 1564887Schin else if(argv[1][0]=='-' && argv[1][2]==0) 1574887Schin return(!test_unop(argv[1][1],cp)); 1584887Schin errormsg(SH_DICT,ERROR_exit(2),e_badop,cp); 1594887Schin } 1604887Schin return(test_binop(op,argv[1],argv[3])^(argc!=5)); 1614887Schin } 1624887Schin case 3: 1634887Schin if(not) 1644887Schin return(*argv[2]!=0); 1654887Schin if(cp[0] != '-' || cp[2] || cp[1]=='?') 1664887Schin { 1674887Schin if(cp[0]=='-' && (cp[1]=='-' || cp[1]=='?') && 1684887Schin strcmp(argv[2],"--")==0) 1694887Schin { 1704887Schin char *av[3]; 1714887Schin av[0] = argv[0]; 1724887Schin av[1] = argv[1]; 1734887Schin av[2] = 0; 1744887Schin optget(av,sh_opttest); 1754887Schin errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg); 1764887Schin return(2); 1774887Schin } 1784887Schin break; 1794887Schin } 1804887Schin return(!test_unop(cp[1],argv[2])); 1814887Schin case 2: 1824887Schin return(*cp==0); 1834887Schin } 1844887Schin tdata.ac = argc; 1854887Schin return(!expr(&tdata,0)); 1864887Schin } 1874887Schin 1884887Schin /* 1894887Schin * evaluate a test expression. 1904887Schin * flag is 0 on outer level 1914887Schin * flag is 1 when in parenthesis 1924887Schin * flag is 2 when evaluating -a 1934887Schin */ 1944887Schin static int expr(struct test *tp,register int flag) 1954887Schin { 1964887Schin register int r; 1974887Schin register char *p; 1984887Schin r = e3(tp); 1994887Schin while(tp->ap < tp->ac) 2004887Schin { 2014887Schin p = nxtarg(tp,0); 2024887Schin /* check for -o and -a */ 2034887Schin if(flag && c_eq(p,')')) 2044887Schin { 2054887Schin tp->ap--; 2064887Schin break; 2074887Schin } 2084887Schin if(*p=='-' && *(p+2)==0) 2094887Schin { 2104887Schin if(*++p == 'o') 2114887Schin { 2124887Schin if(flag==2) 2134887Schin { 2144887Schin tp->ap--; 2154887Schin break; 2164887Schin } 2174887Schin r |= expr(tp,3); 2184887Schin continue; 2194887Schin } 2204887Schin else if(*p == 'a') 2214887Schin { 2224887Schin r &= expr(tp,2); 2234887Schin continue; 2244887Schin } 2254887Schin } 2264887Schin if(flag==0) 2274887Schin break; 2284887Schin errormsg(SH_DICT,ERROR_exit(2),e_badsyntax); 2294887Schin } 2304887Schin return(r); 2314887Schin } 2324887Schin 2334887Schin static char *nxtarg(struct test *tp,int mt) 2344887Schin { 2354887Schin if(tp->ap >= tp->ac) 2364887Schin { 2374887Schin if(mt) 2384887Schin { 2394887Schin tp->ap++; 2404887Schin return(0); 2414887Schin } 2424887Schin errormsg(SH_DICT,ERROR_exit(2),e_argument); 2434887Schin } 2444887Schin return(tp->av[tp->ap++]); 2454887Schin } 2464887Schin 2474887Schin 2484887Schin static int e3(struct test *tp) 2494887Schin { 2504887Schin register char *arg, *cp; 2514887Schin register int op; 2524887Schin char *binop; 2534887Schin arg=nxtarg(tp,0); 2544887Schin if(arg && c_eq(arg, '!')) 2554887Schin return(!e3(tp)); 2564887Schin if(c_eq(arg, '(')) 2574887Schin { 2584887Schin op = expr(tp,1); 2594887Schin cp = nxtarg(tp,0); 2604887Schin if(!cp || !c_eq(cp, ')')) 2614887Schin errormsg(SH_DICT,ERROR_exit(2),e_missing,"')'"); 2624887Schin return(op); 2634887Schin } 2644887Schin cp = nxtarg(tp,1); 2654887Schin if(cp!=0 && (c_eq(cp,'=') || c2_eq(cp,'!','='))) 2664887Schin goto skip; 2674887Schin if(c2_eq(arg,'-','t')) 2684887Schin { 26910898Sroland.mainz@nrubsig.org if(cp) 27010898Sroland.mainz@nrubsig.org { 27110898Sroland.mainz@nrubsig.org op = strtol(cp,&binop, 10); 27210898Sroland.mainz@nrubsig.org return(*binop?0:tty_check(op)); 27310898Sroland.mainz@nrubsig.org } 2744887Schin else 2754887Schin { 2764887Schin /* test -t with no arguments */ 2774887Schin tp->ap--; 2784887Schin return(tty_check(1)); 2794887Schin } 2804887Schin } 2814887Schin if(*arg=='-' && arg[2]==0) 2824887Schin { 2834887Schin op = arg[1]; 2844887Schin if(!cp) 2854887Schin { 2864887Schin /* for backward compatibility with new flags */ 2874887Schin if(op==0 || !strchr(test_opchars+10,op)) 2884887Schin return(1); 2894887Schin errormsg(SH_DICT,ERROR_exit(2),e_argument); 2904887Schin } 2914887Schin if(strchr(test_opchars,op)) 2924887Schin return(test_unop(op,cp)); 2934887Schin } 2944887Schin if(!cp) 2954887Schin { 2964887Schin tp->ap--; 2974887Schin return(*arg!=0); 2984887Schin } 2994887Schin skip: 3004887Schin op = sh_lookup(binop=cp,shtab_testops); 3014887Schin if(!(op&TEST_BINOP)) 3024887Schin cp = nxtarg(tp,0); 3034887Schin if(!op) 3044887Schin errormsg(SH_DICT,ERROR_exit(2),e_badop,binop); 30510898Sroland.mainz@nrubsig.org if(op==TEST_AND || op==TEST_OR) 3064887Schin tp->ap--; 3074887Schin return(test_binop(op,arg,cp)); 3084887Schin } 3094887Schin 3104887Schin int test_unop(register int op,register const char *arg) 3114887Schin { 3124887Schin struct stat statb; 3134887Schin int f; 3144887Schin switch(op) 3154887Schin { 3164887Schin case 'r': 3174887Schin return(permission(arg, R_OK)); 3184887Schin case 'w': 3194887Schin return(permission(arg, W_OK)); 3204887Schin case 'x': 3214887Schin return(permission(arg, X_OK)); 3224887Schin case 'V': 3234887Schin #if SHOPT_FS_3D 3244887Schin { 3254887Schin register int offset = staktell(); 3264887Schin if(stat(arg,&statb)<0 || !S_ISREG(statb.st_mode)) 3274887Schin return(0); 3284887Schin /* add trailing / */ 3294887Schin stakputs(arg); 3304887Schin stakputc('/'); 3314887Schin stakputc(0); 3324887Schin arg = (const char*)stakptr(offset); 3334887Schin stakseek(offset); 3344887Schin /* FALL THRU */ 3354887Schin } 3364887Schin #else 3374887Schin return(0); 3384887Schin #endif /* SHOPT_FS_3D */ 3394887Schin case 'd': 3404887Schin return(test_stat(arg,&statb)>=0 && S_ISDIR(statb.st_mode)); 3414887Schin case 'c': 3424887Schin return(test_stat(arg,&statb)>=0 && S_ISCHR(statb.st_mode)); 3434887Schin case 'b': 3444887Schin return(test_stat(arg,&statb)>=0 && S_ISBLK(statb.st_mode)); 3454887Schin case 'f': 3464887Schin return(test_stat(arg,&statb)>=0 && S_ISREG(statb.st_mode)); 3474887Schin case 'u': 3484887Schin return(test_mode(arg)&S_ISUID); 3494887Schin case 'g': 3504887Schin return(test_mode(arg)&S_ISGID); 3514887Schin case 'k': 3524887Schin #ifdef S_ISVTX 3534887Schin return(test_mode(arg)&S_ISVTX); 3544887Schin #else 3554887Schin return(0); 3564887Schin #endif /* S_ISVTX */ 3574887Schin #if SHOPT_TEST_L 3584887Schin case 'l': 3594887Schin #endif 3604887Schin case 'L': 3614887Schin case 'h': /* undocumented, and hopefully will disappear */ 3624887Schin if(*arg==0 || arg[strlen(arg)-1]=='/' || lstat(arg,&statb)<0) 3634887Schin return(0); 3644887Schin return(S_ISLNK(statb.st_mode)); 3654887Schin 3664887Schin case 'C': 3674887Schin #ifdef S_ISCTG 3684887Schin return(test_stat(arg,&statb)>=0 && S_ISCTG(statb.st_mode)); 3694887Schin #else 3704887Schin return(0); 3714887Schin #endif /* S_ISCTG */ 3724887Schin case 'H': 3734887Schin #ifdef S_ISCDF 3744887Schin { 3754887Schin register int offset = staktell(); 3764887Schin if(test_stat(arg,&statb)>=0 && S_ISCDF(statb.st_mode)) 3774887Schin return(1); 3784887Schin stakputs(arg); 3794887Schin stakputc('+'); 3804887Schin stakputc(0); 3814887Schin arg = (const char*)stakptr(offset); 3824887Schin stakseek(offset); 3834887Schin return(test_stat(arg,&statb)>=0 && S_ISCDF(statb.st_mode)); 3844887Schin } 3854887Schin #else 3864887Schin return(0); 3874887Schin #endif /* S_ISCDF */ 3884887Schin 3894887Schin case 'S': 3904887Schin return(isasock(arg,&statb)); 3914887Schin case 'N': 3924887Schin return(test_stat(arg,&statb)>=0 && tmxgetmtime(&statb) > tmxgetatime(&statb)); 3934887Schin case 'p': 3944887Schin return(isapipe(arg,&statb)); 3954887Schin case 'n': 3964887Schin return(*arg != 0); 3974887Schin case 'z': 3984887Schin return(*arg == 0); 3994887Schin case 's': 4004887Schin sfsync(sfstdout); 4014887Schin case 'O': 4024887Schin case 'G': 4034887Schin if(*arg==0 || test_stat(arg,&statb)<0) 4044887Schin return(0); 4054887Schin if(op=='s') 4064887Schin return(statb.st_size>0); 4074887Schin else if(op=='O') 4084887Schin return(statb.st_uid==sh.userid); 4094887Schin return(statb.st_gid==sh.groupid); 4104887Schin case 'a': 4114887Schin case 'e': 4124887Schin return(permission(arg, F_OK)); 4134887Schin case 'o': 4144887Schin f=1; 4154887Schin if(*arg=='?') 4164887Schin return(sh_lookopt(arg+1,&f)>0); 4174887Schin op = sh_lookopt(arg,&f); 4184887Schin return(op && (f==(sh_isoption(op)!=0))); 4194887Schin case 't': 42010898Sroland.mainz@nrubsig.org { 42110898Sroland.mainz@nrubsig.org char *last; 42210898Sroland.mainz@nrubsig.org op = strtol(arg,&last, 10); 42310898Sroland.mainz@nrubsig.org return(*last?0:tty_check(op)); 42410898Sroland.mainz@nrubsig.org } 42510898Sroland.mainz@nrubsig.org case 'v': 42610898Sroland.mainz@nrubsig.org case 'R': 42710898Sroland.mainz@nrubsig.org { 42810898Sroland.mainz@nrubsig.org Namval_t *np; 42910898Sroland.mainz@nrubsig.org Namarr_t *ap; 43010898Sroland.mainz@nrubsig.org int isref; 43110898Sroland.mainz@nrubsig.org if(!(np = nv_open(arg,sh.var_tree,NV_VARNAME|NV_NOFAIL|NV_NOADD|NV_NOREF))) 43210898Sroland.mainz@nrubsig.org return(0); 43310898Sroland.mainz@nrubsig.org isref = nv_isref(np); 43410898Sroland.mainz@nrubsig.org if(op=='R') 43510898Sroland.mainz@nrubsig.org return(isref); 43610898Sroland.mainz@nrubsig.org if(isref) 43710898Sroland.mainz@nrubsig.org { 43810898Sroland.mainz@nrubsig.org if(np->nvalue.cp) 43910898Sroland.mainz@nrubsig.org np = nv_refnode(np); 44010898Sroland.mainz@nrubsig.org else 44110898Sroland.mainz@nrubsig.org return(0); 44210898Sroland.mainz@nrubsig.org 44310898Sroland.mainz@nrubsig.org } 44410898Sroland.mainz@nrubsig.org if(ap = nv_arrayptr(np)) 44510898Sroland.mainz@nrubsig.org return(nv_arrayisset(np,ap)); 44610898Sroland.mainz@nrubsig.org return(!nv_isnull(np) || nv_isattr(np,NV_INTEGER)); 44710898Sroland.mainz@nrubsig.org } 4484887Schin default: 4494887Schin { 4504887Schin static char a[3] = "-?"; 4514887Schin a[1]= op; 4524887Schin errormsg(SH_DICT,ERROR_exit(2),e_badop,a); 4534887Schin /* NOTREACHED */ 4544887Schin return(0); 4554887Schin } 4564887Schin } 4574887Schin } 4584887Schin 4594887Schin int test_binop(register int op,const char *left,const char *right) 4604887Schin { 4614887Schin register double lnum,rnum; 4624887Schin if(op&TEST_ARITH) 4634887Schin { 4644887Schin while(*left=='0') 4654887Schin left++; 4664887Schin while(*right=='0') 4674887Schin right++; 4684887Schin lnum = sh_arith(left); 4694887Schin rnum = sh_arith(right); 4704887Schin } 4714887Schin switch(op) 4724887Schin { 4734887Schin /* op must be one of the following values */ 4744887Schin case TEST_AND: 4754887Schin case TEST_OR: 4764887Schin return(*left!=0); 4774887Schin case TEST_PEQ: 4784887Schin return(test_strmatch(left, right)); 4794887Schin case TEST_PNE: 4804887Schin return(!test_strmatch(left, right)); 4814887Schin case TEST_SGT: 4824887Schin return(strcoll(left, right)>0); 4834887Schin case TEST_SLT: 4844887Schin return(strcoll(left, right)<0); 4854887Schin case TEST_SEQ: 4864887Schin return(strcmp(left, right)==0); 4874887Schin case TEST_SNE: 4884887Schin return(strcmp(left, right)!=0); 4894887Schin case TEST_EF: 4904887Schin return(test_inode(left,right)); 4914887Schin case TEST_NT: 4924887Schin return(test_time(left,right)>0); 4934887Schin case TEST_OT: 4944887Schin return(test_time(left,right)<0); 4954887Schin case TEST_EQ: 4964887Schin return(lnum==rnum); 4974887Schin case TEST_NE: 4984887Schin return(lnum!=rnum); 4994887Schin case TEST_GT: 5004887Schin return(lnum>rnum); 5014887Schin case TEST_LT: 5024887Schin return(lnum<rnum); 5034887Schin case TEST_GE: 5044887Schin return(lnum>=rnum); 5054887Schin case TEST_LE: 5064887Schin return(lnum<=rnum); 5074887Schin } 5084887Schin /* NOTREACHED */ 5094887Schin return(0); 5104887Schin } 5114887Schin 5124887Schin /* 5134887Schin * returns the modification time of f1 - modification time of f2 5144887Schin */ 5154887Schin 5164887Schin static time_t test_time(const char *file1,const char *file2) 5174887Schin { 5184887Schin Time_t t1, t2; 5194887Schin struct stat statb1,statb2; 5204887Schin int r=test_stat(file2,&statb2); 5214887Schin if(test_stat(file1,&statb1)<0) 5224887Schin return(r<0?0:-1); 5234887Schin if(r<0) 5244887Schin return(1); 5254887Schin t1 = tmxgetmtime(&statb1); 5264887Schin t2 = tmxgetmtime(&statb2); 5274887Schin if (t1 > t2) 5284887Schin return(1); 5294887Schin if (t1 < t2) 5304887Schin return(-1); 5314887Schin return(0); 5324887Schin } 5334887Schin 5344887Schin /* 5354887Schin * return true if inode of two files are the same 5364887Schin */ 5374887Schin 5384887Schin int test_inode(const char *file1,const char *file2) 5394887Schin { 5404887Schin struct stat stat1,stat2; 5414887Schin if(test_stat(file1,&stat1)>=0 && test_stat(file2,&stat2)>=0) 5424887Schin if(stat1.st_dev == stat2.st_dev && stat1.st_ino == stat2.st_ino) 5434887Schin return(1); 5444887Schin return(0); 5454887Schin } 5464887Schin 5474887Schin 5484887Schin /* 5494887Schin * This version of access checks against effective uid/gid 5504887Schin * The static buffer statb is shared with test_mode. 5514887Schin */ 5524887Schin 5534887Schin int sh_access(register const char *name, register int mode) 5544887Schin { 5554887Schin struct stat statb; 5564887Schin if(*name==0) 5574887Schin return(-1); 5584887Schin if(strmatch(name,(char*)e_devfdNN)) 5594887Schin return(sh_ioaccess((int)strtol(name+8, (char**)0, 10),mode)); 5604887Schin /* can't use access function for execute permission with root */ 5614887Schin if(mode==X_OK && sh.euserid==0) 5624887Schin goto skip; 5634887Schin if(sh.userid==sh.euserid && sh.groupid==sh.egroupid) 5644887Schin return(access(name,mode)); 5654887Schin #ifdef _lib_setreuid 5664887Schin /* swap the real uid to effective, check access then restore */ 5674887Schin /* first swap real and effective gid, if different */ 5684887Schin if(sh.groupid==sh.euserid || setregid(sh.egroupid,sh.groupid)==0) 5694887Schin { 5704887Schin /* next swap real and effective uid, if needed */ 5714887Schin if(sh.userid==sh.euserid || setreuid(sh.euserid,sh.userid)==0) 5724887Schin { 5734887Schin mode = access(name,mode); 5744887Schin /* restore ids */ 5754887Schin if(sh.userid!=sh.euserid) 5764887Schin setreuid(sh.userid,sh.euserid); 5774887Schin if(sh.groupid!=sh.egroupid) 5784887Schin setregid(sh.groupid,sh.egroupid); 5794887Schin return(mode); 5804887Schin } 5814887Schin else if(sh.groupid!=sh.egroupid) 5824887Schin setregid(sh.groupid,sh.egroupid); 5834887Schin } 5844887Schin #endif /* _lib_setreuid */ 5854887Schin skip: 5864887Schin if(test_stat(name, &statb) == 0) 5874887Schin { 5884887Schin if(mode == F_OK) 5894887Schin return(mode); 5904887Schin else if(sh.euserid == 0) 5914887Schin { 5924887Schin if(!S_ISREG(statb.st_mode) || mode!=X_OK) 5934887Schin return(0); 5944887Schin /* root needs execute permission for someone */ 5954887Schin mode = (S_IXUSR|S_IXGRP|S_IXOTH); 5964887Schin } 5974887Schin else if(sh.euserid == statb.st_uid) 5984887Schin mode <<= 6; 5994887Schin else if(sh.egroupid == statb.st_gid) 6004887Schin mode <<= 3; 6014887Schin #ifdef _lib_getgroups 6024887Schin /* on some systems you can be in several groups */ 6034887Schin else 6044887Schin { 6054887Schin static int maxgroups; 6064887Schin gid_t *groups; 6074887Schin register int n; 6084887Schin if(maxgroups==0) 6094887Schin { 6104887Schin /* first time */ 6114887Schin if((maxgroups=getgroups(0,(gid_t*)0)) <= 0) 6124887Schin { 6134887Schin /* pre-POSIX system */ 6144887Schin maxgroups=NGROUPS_MAX; 6154887Schin } 6164887Schin } 6174887Schin groups = (gid_t*)stakalloc((maxgroups+1)*sizeof(gid_t)); 6184887Schin n = getgroups(maxgroups,groups); 6194887Schin while(--n >= 0) 6204887Schin { 6214887Schin if(groups[n] == statb.st_gid) 6224887Schin { 6234887Schin mode <<= 3; 6244887Schin break; 6254887Schin } 6264887Schin } 6274887Schin } 6284887Schin # endif /* _lib_getgroups */ 6294887Schin if(statb.st_mode & mode) 6304887Schin return(0); 6314887Schin } 6324887Schin return(-1); 6334887Schin } 6344887Schin 6354887Schin /* 6364887Schin * Return the mode bits of file <file> 6374887Schin * If <file> is null, then the previous stat buffer is used. 6384887Schin * The mode bits are zero if the file doesn't exist. 6394887Schin */ 6404887Schin 6414887Schin static int test_mode(register const char *file) 6424887Schin { 6434887Schin struct stat statb; 6444887Schin if(file && (*file==0 || test_stat(file,&statb)<0)) 6454887Schin return(0); 6464887Schin return(statb.st_mode); 6474887Schin } 6484887Schin 6494887Schin /* 6504887Schin * do an fstat() for /dev/fd/n, otherwise stat() 6514887Schin */ 6524887Schin static int test_stat(const char *name,struct stat *buff) 6534887Schin { 6544887Schin if(*name==0) 6554887Schin { 6564887Schin errno = ENOENT; 6574887Schin return(-1); 6584887Schin } 6594887Schin if(strmatch(name,(char*)e_devfdNN)) 6604887Schin return(fstat((int)strtol(name+8, (char**)0, 10),buff)); 6614887Schin else 6624887Schin return(stat(name,buff)); 6634887Schin } 664