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