static char *sccsid
= "@(#)find.c 4.7 (Berkeley) %G%";
/* find COMPILE: cc -o find -s -O -i find.c -lS */
#define A_DAY 86400L /* a day full of seconds */
#define EQ(x, y) (strcmp(x, y)==0)
int Nn
; /* number of nodes */
main(argc
, argv
) char *argv
[];
register char *cp
, *sp
= 0;
Home
[strlen(Home
) - 1] = '\0';
Argc
= argc
; Argv
= argv
;
usage
: fprintf(stderr
, "Usage: find path-list predicate-list\n");
for(Ai
= paths
= 1; Ai
< (argc
-1); ++Ai
, ++paths
)
if(*Argv
[Ai
] == '-' || EQ(Argv
[Ai
], "(") || EQ(Argv
[Ai
], "!"))
if(paths
== 1) /* no path-list */
if(!(exlist
= exp())) { /* parse and compile the arguments */
fprintf(stderr
, "find: parsing error\n");
fprintf(stderr
, "find: missing conjunction\n");
for(Pi
= 1; Pi
< paths
; ++Pi
) {
strcpy(Pathname
, Argv
[Pi
]);
if(cp
= rindex(Pathname
, '/')) {
if(chdir(*Pathname
? Pathname
: "/") == -1) {
fprintf(stderr
, "find: bad starting directory\n");
Fname
= sp
? sp
: Pathname
;
descend(Pathname
, Fname
, exlist
); /* to find files that match */
strcpy(Pathname
, "TRAILER!!!");
printf("%D blocks\n", Blocks
*10);
/* compile time functions: priority is exp()<e1()<e2()<e3() */
struct anode
*exp() { /* parse ALTERNATION (-o) */
register struct anode
* p1
;
p1
= e1() /* get left operand */ ;
return(mk(or, p1
, exp()));
else if(Ai
<= Argc
) --Ai
;
struct anode
*e1() { /* parse CONCATENATION (formerly -a) */
register struct anode
* p1
;
return(mk(and, p1
, e1()));
} else if(EQ(a
, "(") || EQ(a
, "!") || (*a
=='-' && !EQ(a
, "-o"))) {
} else if(Ai
<= Argc
) --Ai
;
struct anode
*e2() { /* parse NOT (!) */
fprintf(stderr
, "find: operand follows operand\n");
return(mk(not, e3(), (struct anode
*)0));
else if(Ai
<= Argc
) --Ai
;
struct anode
*e3() { /* parse parens and predicates */
int exeq(), ok(), glob(), mtime(), atime(), user(),
group(), size(), perm(), links(), print(),
type(), ino(), cpio(), newer();
if(!EQ(a
, ")")) goto err
;
else if(EQ(a
, "-print")) {
return(mk(print
, (struct anode
*)0, (struct anode
*)0));
return(mk(glob
, (struct anode
*)b
, (struct anode
*)0));
return(mk(mtime
, (struct anode
*)atoi(b
), (struct anode
*)s
));
return(mk(atime
, (struct anode
*)atoi(b
), (struct anode
*)s
));
else if(EQ(a
, "-user")) {
if((i
=getunum("/etc/passwd", b
)) == -1) {
return mk(user
, (struct anode
*)atoi(b
), (struct anode
*)s
);
fprintf(stderr
, "find: cannot find -user name\n");
return(mk(user
, (struct anode
*)i
, (struct anode
*)s
));
return(mk(ino
, (struct anode
*)atoi(b
), (struct anode
*)s
));
else if(EQ(a
, "-group")) {
if((i
=getunum("/etc/group", b
)) == -1) {
return mk(group
, (struct anode
*)atoi(b
), (struct anode
*)s
);
fprintf(stderr
, "find: cannot find -group name\n");
return(mk(group
, (struct anode
*)i
, (struct anode
*)s
));
} else if(EQ(a
, "-size"))
return(mk(size
, (struct anode
*)atoi(b
), (struct anode
*)s
));
return(mk(links
, (struct anode
*)atoi(b
), (struct anode
*)s
));
else if(EQ(a
, "-perm")) {
return(mk(perm
, (struct anode
*)i
, (struct anode
*)s
));
else if(EQ(a
, "-type")) {
return(mk(type
, (struct anode
*)i
, (struct anode
*)0));
else if (EQ(a
, "-exec")) {
while(!EQ(nxtarg(), ";"));
return(mk(exeq
, (struct anode
*)i
, (struct anode
*)0));
while(!EQ(nxtarg(), ";"));
return(mk(ok
, (struct anode
*)i
, (struct anode
*)0));
else if(EQ(a
, "-cpio")) {
if((Cpio
= creat(b
, 0666)) < 0) {
fprintf(stderr
, "find: cannot create < %s >\n", s
);
Buf
= (short *)sbrk(512);
Wp
= Dbuf
= (short *)sbrk(5120);
return(mk(cpio
, (struct anode
*)0, (struct anode
*)0));
else if(EQ(a
, "-newer")) {
if(stat(b
, &Statb
) < 0) {
fprintf(stderr
, "find: cannot access < %s >\n", b
);
return mk(newer
, (struct anode
*)0, (struct anode
*)0);
err
: fprintf(stderr
, "find: bad option < %s >\n", a
);
struct anode
*mk(f
, l
, r
)
char *nxtarg() { /* get next arg from command line */
fprintf(stderr
, "find: incomplete statement\n");
/* execution time functions */
register struct anode
*p
;
return(((*p
->L
->F
)(p
->L
)) && ((*p
->R
->F
)(p
->R
))?1:0);
register struct anode
*p
;
return(((*p
->L
->F
)(p
->L
)) || ((*p
->R
->F
)(p
->R
))?1:0);
register struct anode
*p
;
return( !((*p
->L
->F
)(p
->L
)));
register struct { int f
; char *pat
; } *p
;
return(gmatch(Fname
, p
->pat
));
register struct { int f
, t
, s
; } *p
;
return(scomp((int)((Now
- Statb
.st_mtime
) / A_DAY
), p
->t
, p
->s
));
register struct { int f
, t
, s
; } *p
;
return(scomp((int)((Now
- Statb
.st_atime
) / A_DAY
), p
->t
, p
->s
));
register struct { int f
, u
, s
; } *p
;
return(scomp(Statb
.st_uid
, p
->u
, p
->s
));
register struct { int f
, u
, s
; } *p
;
return(scomp((int)Statb
.st_ino
, p
->u
, p
->s
));
register struct { int f
, u
; } *p
;
return(p
->u
== Statb
.st_gid
);
register struct { int f
, link
, s
; } *p
;
return(scomp(Statb
.st_nlink
, p
->link
, p
->s
));
register struct { int f
, sz
, s
; } *p
;
return(scomp((int)((Statb
.st_size
+511)>>9), p
->sz
, p
->s
));
register struct { int f
, per
, s
; } *p
;
i
= (p
->s
=='-') ? p
->per
: 07777; /* '-' means only arg bits */
return((Statb
.st_mode
& i
& 07777) == p
->per
);
register struct { int f
, per
, s
; } *p
;
return((Statb
.st_mode
&S_IFMT
)==p
->per
);
register struct { int f
, com
; } *p
;
fflush(stdout
); /* to flush possible `-print' */
struct { int f
, com
; } *p
;
fflush(stdout
); /* to flush possible `-print' */
fprintf(stderr
, "< %s ... %s > ? ", Argv
[p
->com
], Pathname
);
if((c
=getchar())=='y') yes
= 1;
while(c
!='\n') c
= getchar();
if(yes
) return(doex(p
->com
));
#define MKSHORT(v, lv) {U.l=1L;if(U.c[0]) U.l=lv, v[0]=U.s[1], v[1]=U.s[0]; else U.l=lv, v[0]=U.s[0], v[1]=U.s[1];}
union { long l
; short s
[2]; char c
[4]; } U
;
U
.s
[0] = v
[1], U
.s
[1] = v
[0];
U
.s
[0] = v
[0], U
.s
[1] = v
[1];
strcpy(hdr
.h_name
, !strncmp(Pathname
, "./", 2)? Pathname
+2: Pathname
);
hdr
.h_namesize
= strlen(hdr
.h_name
) + 1;
hdr
.h_uid
= Statb
.st_uid
;
hdr
.h_gid
= Statb
.st_gid
;
hdr
.h_dev
= Statb
.st_dev
;
hdr
.h_ino
= Statb
.st_ino
;
hdr
.h_mode
= Statb
.st_mode
;
MKSHORT(hdr
.h_mtime
, Statb
.st_mtime
);
hdr
.h_nlink
= Statb
.st_nlink
;
fsz
= hdr
.h_mode
& S_IFREG
? Statb
.st_size
: 0L;
MKSHORT(hdr
.h_filesize
, fsz
);
hdr
.h_rdev
= Statb
.st_rdev
;
if(EQ(hdr
.h_name
, "TRAILER!!!")) {
bwrite((short *)&hdr
, (sizeof hdr
-256)+hdr
.h_namesize
);
if(!mklong(hdr
.h_filesize
))
if((ifile
= open(Fname
, 0)) < 0) {
fprintf(stderr
, "find: cannot copy < %s >\n", hdr
.h_name
);
bwrite((short *)&hdr
, (sizeof hdr
-256)+hdr
.h_namesize
);
for(fsz
= mklong(hdr
.h_filesize
); fsz
> 0; fsz
-= 512) {
if(read(ifile
, (char *)Buf
, ct
) < 0)
return Statb
.st_mtime
> Newer
;
scomp(a
, b
, s
) /* funny signed compare */
if(strcmp(na
, ";")==0) break;
if(strcmp(na
, "{}")==0) nargv
[np
++] = Pathname
;
int (*old
)() = signal(SIGINT
, SIG_IGN
);
int (*oldq
)() = signal(SIGQUIT
, SIG_IGN
);
execvp(nargv
[0], nargv
, np
);
getunum(f
, s
) char *f
, *s
; { /* find user/group name and return number */
c
= '\n'; /* prime with a CR */
while((c
= *sp
++ = getc(pin
)) != ':')
while((c
=getc(pin
)) != ':')
while((*sp
= getc(pin
)) != ':') sp
++;
} while((c
= getc(pin
)) != EOF
);
descend(name
, fname
, exlist
)
register struct direct
*dp
;
if (lstat(fname
, &Statb
)<0) {
fprintf(stderr
, "find: bad status < %s >\n", name
);
if((Statb
.st_mode
&S_IFMT
)!=S_IFDIR
)
for (c1
= name
; *c1
; ++c1
);
if ((dir
= opendir(".")) == NULL
) {
fprintf(stderr
, "find: cannot open < %s >\n", name
);
for (dp
= readdir(dir
); dp
!= NULL
; dp
= readdir(dir
)) {
if ((dp
->d_name
[0]=='.' && dp
->d_name
[1]=='\0') ||
(dp
->d_name
[0]=='.' && dp
->d_name
[1]=='.' && dp
->d_name
[2]=='\0'))
if(!descend(name
, Fname
, exlist
)) {
if(chdir(Pathname
) == -1) {
fprintf(stderr
, "find: bad directory tree\n");
fprintf(stderr
, "find: bad directory <%s>\n", name
);
gmatch(s
, p
) /* string match as in glob */
if (*s
=='.' && *p
!='.') return(0);
return(amatch(++s
, ++p
));
k
|= lc
<= scc
& scc
<= (cc
=p
[1]);
if(scc
) return(amatch(++s
, ++p
));
if (amatch(s
++, p
)) return(1);
if(write(Cpio
, (char *)Dbuf
, Bufsize
)<0) {
fprintf(stderr
, "find: errno: %d, ", errno
);
fprintf(stderr
, "find: can't %s\n", x
? "write output": "read input");
if((statb
.st_mode
&S_IFMT
) != S_IFCHR
)
fprintf(stderr
, "If you want to go on, type device/file name %s\n",
devtty
= fopen("/dev/tty", "r");
str
[strlen(str
) - 1] = '\0';
if((f
= open(str
, x
? 1: 0)) < 0) {
fprintf(stderr
, "That didn't work");