1 /***********************************************************************
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 *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * David Korn <dgk@research.att.com> *
19 ***********************************************************************/
38 #include "FEATURE/externs"
39 #include "FEATURE/poll"
44 #endif /* _lib_setregid */
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))
51 # define isapipe(f,p) (test_stat(f,p)>=0&&S_ISFIFO((p)->st_mode)||S_ISSOCK((p)->st_mode)&&(p)->st_ino)
54 # define isapipe(f,p) (test_stat(f,p)>=0&&S_ISFIFO((p)->st_mode)||S_ISSOCK((p)->st_mode)&&(p)->st_ino)
56 # define isasock(f,p) (test_stat(f,p)>=0&&S_ISSOCK((p)->st_mode))
58 # define isapipe(f,p) (test_stat(f,p)>=0&&S_ISFIFO((p)->st_mode))
59 # define isasock(f,p) (0)
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*);
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)
80 static char *nxtarg(struct test
*,int);
81 static int expr(struct test
*,int);
82 static int e3(struct test
*);
84 static int test_strmatch(const char *str
, const char *pat
)
86 int match
[2*(MATCH_MAX
+1)],n
;
88 register const char *cp
=pat
;
100 if(m
> elementsof(match
)/2)
101 m
= elementsof(match
)/2;
102 n
= strgrpmatch(str
, pat
, match
, m
, STR_MAXIMAL
|STR_LEFT
|STR_RIGHT
);
104 match
[1] = strlen(str
);
106 sh_setmatch(str
, -1, n
, match
);
110 int b_test(int argc
, char *argv
[],void *extra
)
113 register char *cp
= argv
[0];
115 tdata
.sh
= ((Shbltin_t
*)extra
)->shp
;
122 errormsg(SH_DICT
,ERROR_exit(2),e_missing
,"']'");
127 if(c_eq(cp
,'(') && argc
<=6 && c_eq(argv
[argc
-1],')'))
129 /* special case ( binop ) to conform with standard */
130 if(!(argc
==4 && (not=sh_lookup(cp
=argv
[2],shtab_testops
))))
137 /* posix portion for test */
147 register int op
= sh_lookup(cp
=argv
[2],shtab_testops
);
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
);
160 return(test_binop(op
,argv
[1],argv
[3])^(argc
!=5));
165 if(cp
[0] != '-' || cp
[2] || cp
[1]=='?')
167 if(cp
[0]=='-' && (cp
[1]=='-' || cp
[1]=='?') &&
168 strcmp(argv
[2],"--")==0)
174 optget(av
,sh_opttest
);
175 errormsg(SH_DICT
,ERROR_usage(2), "%s",opt_info
.arg
);
180 return(!test_unop(cp
[1],argv
[2]));
185 return(!expr(&tdata
,0));
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
194 static int expr(struct test
*tp
,register int flag
)
199 while(tp
->ap
< tp
->ac
)
202 /* check for -o and -a */
203 if(flag
&& c_eq(p
,')'))
208 if(*p
=='-' && *(p
+2)==0)
228 errormsg(SH_DICT
,ERROR_exit(2),e_badsyntax
);
233 static char *nxtarg(struct test
*tp
,int mt
)
242 errormsg(SH_DICT
,ERROR_exit(2),e_argument
);
244 return(tp
->av
[tp
->ap
++]);
248 static int e3(struct test
*tp
)
250 register char *arg
, *cp
;
254 if(arg
&& c_eq(arg
, '!'))
260 if(!cp
|| !c_eq(cp
, ')'))
261 errormsg(SH_DICT
,ERROR_exit(2),e_missing
,"')'");
265 if(cp
!=0 && (c_eq(cp
,'=') || c2_eq(cp
,'!','=')))
267 if(c2_eq(arg
,'-','t'))
271 op
= strtol(cp
,&binop
, 10);
272 return(*binop
?0:tty_check(op
));
276 /* test -t with no arguments */
278 return(tty_check(1));
281 if(*arg
=='-' && arg
[2]==0)
286 /* for backward compatibility with new flags */
287 if(op
==0 || !strchr(test_opchars
+10,op
))
289 errormsg(SH_DICT
,ERROR_exit(2),e_argument
);
291 if(strchr(test_opchars
,op
))
292 return(test_unop(op
,cp
));
300 op
= sh_lookup(binop
=cp
,shtab_testops
);
304 errormsg(SH_DICT
,ERROR_exit(2),e_badop
,binop
);
305 if(op
==TEST_AND
|| op
==TEST_OR
)
307 return(test_binop(op
,arg
,cp
));
310 int test_unop(register int op
,register const char *arg
)
317 return(permission(arg
, R_OK
));
319 return(permission(arg
, W_OK
));
321 return(permission(arg
, X_OK
));
325 register int offset
= staktell();
326 if(stat(arg
,&statb
)<0 || !S_ISREG(statb
.st_mode
))
332 arg
= (const char*)stakptr(offset
);
338 #endif /* SHOPT_FS_3D */
340 return(test_stat(arg
,&statb
)>=0 && S_ISDIR(statb
.st_mode
));
342 return(test_stat(arg
,&statb
)>=0 && S_ISCHR(statb
.st_mode
));
344 return(test_stat(arg
,&statb
)>=0 && S_ISBLK(statb
.st_mode
));
346 return(test_stat(arg
,&statb
)>=0 && S_ISREG(statb
.st_mode
));
348 return(test_mode(arg
)&S_ISUID
);
350 return(test_mode(arg
)&S_ISGID
);
353 return(test_mode(arg
)&S_ISVTX
);
361 case 'h': /* undocumented, and hopefully will disappear */
362 if(*arg
==0 || arg
[strlen(arg
)-1]=='/' || lstat(arg
,&statb
)<0)
364 return(S_ISLNK(statb
.st_mode
));
368 return(test_stat(arg
,&statb
)>=0 && S_ISCTG(statb
.st_mode
));
375 register int offset
= staktell();
376 if(test_stat(arg
,&statb
)>=0 && S_ISCDF(statb
.st_mode
))
381 arg
= (const char*)stakptr(offset
);
383 return(test_stat(arg
,&statb
)>=0 && S_ISCDF(statb
.st_mode
));
390 return(isasock(arg
,&statb
));
392 return(test_stat(arg
,&statb
)>=0 && tmxgetmtime(&statb
) > tmxgetatime(&statb
));
394 return(isapipe(arg
,&statb
));
403 if(*arg
==0 || test_stat(arg
,&statb
)<0)
406 return(statb
.st_size
>0);
408 return(statb
.st_uid
==sh
.userid
);
409 return(statb
.st_gid
==sh
.groupid
);
412 return(permission(arg
, F_OK
));
416 return(sh_lookopt(arg
+1,&f
)>0);
417 op
= sh_lookopt(arg
,&f
);
418 return(op
&& (f
==(sh_isoption(op
)!=0)));
422 op
= strtol(arg
,&last
, 10);
423 return(*last
?0:tty_check(op
));
431 if(!(np
= nv_open(arg
,sh
.var_tree
,NV_VARNAME
|NV_NOFAIL
|NV_NOADD
|NV_NOREF
)))
433 isref
= nv_isref(np
);
444 if(ap
= nv_arrayptr(np
))
445 return(nv_arrayisset(np
,ap
));
446 return(!nv_isnull(np
) || nv_isattr(np
,NV_INTEGER
));
450 static char a
[3] = "-?";
452 errormsg(SH_DICT
,ERROR_exit(2),e_badop
,a
);
459 int test_binop(register int op
,const char *left
,const char *right
)
461 register double lnum
,rnum
;
468 lnum
= sh_arith(left
);
469 rnum
= sh_arith(right
);
473 /* op must be one of the following values */
478 return(test_strmatch(left
, right
));
480 return(!test_strmatch(left
, right
));
482 return(strcoll(left
, right
)>0);
484 return(strcoll(left
, right
)<0);
486 return(strcmp(left
, right
)==0);
488 return(strcmp(left
, right
)!=0);
490 return(test_inode(left
,right
));
492 return(test_time(left
,right
)>0);
494 return(test_time(left
,right
)<0);
513 * returns the modification time of f1 - modification time of f2
516 static time_t test_time(const char *file1
,const char *file2
)
519 struct stat statb1
,statb2
;
520 int r
=test_stat(file2
,&statb2
);
521 if(test_stat(file1
,&statb1
)<0)
525 t1
= tmxgetmtime(&statb1
);
526 t2
= tmxgetmtime(&statb2
);
535 * return true if inode of two files are the same
538 int test_inode(const char *file1
,const char *file2
)
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
)
549 * This version of access checks against effective uid/gid
550 * The static buffer statb is shared with test_mode.
553 int sh_access(register const char *name
, register int mode
)
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)
563 if(sh
.userid
==sh
.euserid
&& sh
.groupid
==sh
.egroupid
)
564 return(access(name
,mode
));
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)
570 /* next swap real and effective uid, if needed */
571 if(sh
.userid
==sh
.euserid
|| setreuid(sh
.euserid
,sh
.userid
)==0)
573 mode
= access(name
,mode
);
575 if(sh
.userid
!=sh
.euserid
)
576 setreuid(sh
.userid
,sh
.euserid
);
577 if(sh
.groupid
!=sh
.egroupid
)
578 setregid(sh
.groupid
,sh
.egroupid
);
581 else if(sh
.groupid
!=sh
.egroupid
)
582 setregid(sh
.groupid
,sh
.egroupid
);
584 #endif /* _lib_setreuid */
586 if(test_stat(name
, &statb
) == 0)
590 else if(sh
.euserid
== 0)
592 if(!S_ISREG(statb
.st_mode
) || mode
!=X_OK
)
594 /* root needs execute permission for someone */
595 mode
= (S_IXUSR
|S_IXGRP
|S_IXOTH
);
597 else if(sh
.euserid
== statb
.st_uid
)
599 else if(sh
.egroupid
== statb
.st_gid
)
601 #ifdef _lib_getgroups
602 /* on some systems you can be in several groups */
605 static int maxgroups
;
611 if((maxgroups
=getgroups(0,(gid_t
*)0)) <= 0)
613 /* pre-POSIX system */
614 maxgroups
=NGROUPS_MAX
;
617 groups
= (gid_t
*)stakalloc((maxgroups
+1)*sizeof(gid_t
));
618 n
= getgroups(maxgroups
,groups
);
621 if(groups
[n
] == statb
.st_gid
)
628 # endif /* _lib_getgroups */
629 if(statb
.st_mode
& mode
)
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.
641 static int test_mode(register const char *file
)
644 if(file
&& (*file
==0 || test_stat(file
,&statb
)<0))
646 return(statb
.st_mode
);
650 * do an fstat() for /dev/fd/n, otherwise stat()
652 static int test_stat(const char *name
,struct stat
*buff
)
659 if(strmatch(name
,(char*)e_devfdNN
))
660 return(fstat((int)strtol(name
+8, (char**)0, 10),buff
));
662 return(stat(name
,buff
));