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
test_strmatch(const char * str,const char * pat)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
b_test(int argc,char * argv[],void * extra)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 */
expr(struct test * tp,register int flag)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
nxtarg(struct test * tp,int mt)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
e3(struct test * tp)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
test_unop(register int op,register const char * arg)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
test_binop(register int op,const char * left,const char * right)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
test_time(const char * file1,const char * file2)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
test_inode(const char * file1,const char * file2)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
sh_access(register const char * name,register int mode)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
test_mode(register const char * file)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 */
test_stat(const char * name,struct stat * buff)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