AUSAM/source/S/find.c
#include <local-system>
/* find -- find files in a pathname.
* Use of find is documented in /usr/man/man1/find.1 .
*
* In addition, find has a secret first arg "+" which
* causes each file name to be printed along with a period
* if the predicates succeed.
*
* ian J aug '76
* to cause end-of-arg list to be a terminator
*
* Piers Lauder Nov '77
* use new library function "execc"
* to execute commands
*
* Kevin Hill Aug '78
* Fixed two minor bugs:
* 1. Could not find user 'root' (!)
* (pre-AUSAM only);
* 2. Lied about size of files, as did not
* round size up to nearest block-size.
*
* ian J Nov '78
* do not null terminate command arglist, so ps will give
* correct identification of the command
*
*/
#ifdef AUSAM
#include <passwd.h>
#endif AUSAM
int randlast;
char *pathname;
int verbose;
struct anode
{
int(*F)();
struct anode *L, *R;
} node[100], *exp(), *e1(), *e2(), *e3(), *mk();
int nn; /* number of nodes */
char *fname, *path;
long now;
long time();
struct
{
int hiword, loword;
};
int ap, ac;
char **av;
struct ibuf
{
int idev;
int inum;
int iflags;
#ifdef AUSAM
unsigned iuid;
#endif AUSAM
char inl;
#ifndef AUSAM
char iuid;
char igid;
#endif AUSAM
char isize0;
char *isize;
int iaddr[8];
long iatime;
long imtime;
} statb;
main(argc, argv)
char *argv[];
{
struct anode *exlist;
int find();
now = time();
time(&now);
ac = argc;
av = argv;
ap = 2;
pathname = argv[1];
if(compstr(argv[1], "+") == 0)
{
verbose++;
ap++;
pathname = argv[2];
}
else
verbose = 0;
if(argc < 3)
{
printf("Insufficient args\n");
exit(9);
}
if(!(exlist = exp()))
{ /* parse and compile the arguments */
printf("Odd usage\n");
exit(9);
}
if(ap < argc)
{
printf("Missing conjunction\n");
exit(9);
}
descend(pathname, 'f', find, exlist); /* to find files that match */
}
/* compile time functions: priority is exp()<e1()<e2()<e3() */
struct anode *exp()
{ /* parse -o ... */
int or();
int p1;
char *na;
p1 = e1() /* get left operand */ ;
if(compstr(na = nxtarg(), "-o") == 0)
{
randlast--;
return(mk(&or, p1, exp()));
}
else if(*na != 0)
--ap;
return(p1);
}
struct anode *e1()
{ /* parse -a */
int and();
int p1;
char *na;
p1 = e2();
if(compstr(na = nxtarg(), "-a") == 0)
{
randlast--;
return(mk(&and, p1, e1()));
}
else if(*na != 0)
--ap;
return(p1);
}
struct anode *e2()
{ /* parse not (!) */
int not();
char *na;
if(randlast)
{
printf("operand follows operand.\n");
exit(9);
}
randlast++;
if(compstr(na = nxtarg(), "!") == 0)
return(mk(¬, e3(), 0));
else if(*na != 0)
--ap;
return(e3());
}
struct anode *e3()
{ /* parse parens and predicates */
int exeq(), ok(), glob(), mtime(), atime(), user(), group(), size(), perm(), links(), print(), type();
int p1, i;
char *a, *b, *c, s; /* ianj */
a = nxtarg();
if(compstr(a, "(") == 0)
{
randlast--;
p1 = exp();
a = nxtarg();
if(compstr(a, ")") != 0)
goto err;
return(p1);
}
else if(compstr(a, "-print") == 0)
{
return(mk(&print, 0, 0));
}
b = nxtarg();
s = *b;
if(s == '+')
b++;
if(compstr(a, "-name") == 0)
return(mk(&glob, b, 0));
else if(compstr(a, "-mtime") == 0)
return(mk(&mtime, atoi(b), s));
else if(compstr(a, "-atime") == 0)
return(mk(&atime, atoi(b), s));
else if(compstr(a, "-user") == 0)
{
if((i = getunum(b)) == -1)
{
printf("Cannot find user \"%s\"\n", b);
exit(9);
}
return(mk(&user, i, s));
}
else if(compstr(a, "-group") == 0)
return(mk(&group, atoi(b), s));
else if(compstr(a, "-size") == 0)
return(mk(&size, atoi(b), s));
else if(compstr(a, "-links") == 0)
return(mk(&links, atoi(b), s));
else if(compstr(a, "-perm") == 0)
{
for(i = 0; *b; ++b)
{
if(*b == '-')
continue;
i =<< 3;
i = i+(*b-'0');
}
return(mk(&perm, i, s));
}
else if(compstr(a, "-type") == 0)
{
i = s == 'd'?040000:s == 'b'?060000:s == 'c'?020000:000000;
return(mk(&type, i, 0));
}
else if(compstr(a, "-exec") == 0)
{
i = ap-1;
while(compstr(c = nxtarg(), ";") != 0 && *c); /* ianj */
return(mk(&exeq, i, 0));
}
else if(compstr(a, "-ok") == 0)
{
i = ap-1;
while(compstr(c = nxtarg(), ";") != 0 && *c); /* ianj */
return(mk(&ok, i, 0));
}
err:
printf("Bad option: \"%s\" \"%s\"\n", a, b);
exit(9);
}
struct anode *mk(f, l, r)
struct anode *l, *r;
{ /*make an expression node*/
node[nn].F = f;
node[nn].L = l;
node[nn].R = r;
return(&(node[nn++]));
}
nxtarg()
{ /* get next arg from command line */
if(ap >= ac)
return("");
return(av[ap++]);
}
find(exlist, fullname) /* execute predicat list with current file */
struct anode *exlist;
char *fullname;
{
register int i;
path = fullname;
if(verbose)
printf("%s", path);
for(i = 0; fullname[i]; ++i)
if(fullname[i] == '/')
fname = &fullname[i+1];
i = (*exlist->F)(exlist);
if(verbose)
if(i)
printf(".\n");
else
printf("\n");
}
/* execution time functions */
and(p)
struct anode *p;
{
return(((*p->L->F)(p->L)) && ((*p->R->F)(p->R))?1:0);
}
or(p)
struct anode *p;
{
return(((*p->L->F)(p->L)) || ((*p->R->F)(p->R))?1:0);
}
not(p)
struct anode *p;
{
return(!((*p->L->F)(p->L)));
}
glob(p)
struct
{
int f;
char *pat;
} *p;
{
return(gmatch(fname, p->pat));
}
print()
{
printf("%s\n", path);
return(1);
}
mtime(p)
struct
{
int f, t, s;
} *p;
{
register int integ;
return(scomp(integ = (now-statb.imtime)/84600l, p->t, p->s));
}
atime(p)
struct
{
int f, t, s;
} *p;
{
register int integ;
return(scomp(integ = (now-statb.iatime)/84600l, p->t, p->s));
}
user(p)
struct
{
int f, u, s;
} *p;
{
return(scomp(statb.iuid, p->u, p->s));
}
group(p)
struct
{
int f, u;
} *p;
{
#ifdef AUSAM
static struct
{
unsigned igid;
} statb {-1 };
#endif AUSAM
return(p->u == statb.igid);
}
links(p)
struct
{
int f, link, s;
} *p;
{
return(scomp(statb.inl, p->link, p->s));
}
size(p)
struct
{
int f, sz, s;
} *p;
{
register int i;
if(i = ((statb.isize+0777)>>9)&0177)
i =| statb.isize0<<7;
else if(statb.isize)
i = (statb.isize0+1)<<7;
else
i = statb.isize0<<7;
return(scomp(i, p->sz, p->s));
}
perm(p)
struct
{
int f, per, s;
} *p;
{
int i;
i = (p->s == '-')?p->per:03777; /* '-' means only arg bits */
return((statb.iflags&i&017777) == p->per);
}
type(p)
struct
{
int f, per, s;
} *p;
{
return((statb.iflags&060000) == p->per);
}
exeq(p)
struct
{
int f, com;
} *p;
{
return(doex(p->com));
}
ok(p)
struct
{
int f, com;
} *p;
{
char c;
int yes;
yes = 0;
printf("%s ... %s ...? ", av[p->com], path);
if((c = getchar()) == 'y')
yes = 1;
while(c != '\n')
c = getchar();
if(yes)
return(doex(p->com));
return(0);
}
/* support functions */
scomp(a, b, s)
char s;
{ /* funny signed compare */
if(s == '+')
return(a > b);
if(s == '-')
return(a < (b*-1));
return(a == b);
}
doex(com)
{
int ccode;
int np, i, c;
char *nargv[50], *ncom, *na;
ccode = np = 0;
while((na = av[com++]) != -1)
{
if(compstr(na, ";") == 0)
break;
if(compstr(na, "{}") == 0)
nargv[np++] = path;
else
nargv[np++] = na;
}
nargv[np] = 0;
if(np == 0)
return(9);
if(fork()) /*parent*/
waitx(&ccode);
else
{ /*child*/
execc(nargv[0], nargv);
exit(9);
}
return(ccode?0:1);
}
#ifdef AUSAM
unsigned getunum(s)
char *s;
{
struct pwent pe;
pe.pw_strings[LNAME] = s;
if(getpwuid(&pe, 0, 0) < 0)
return(0177777);
else
return(pe.pw_uid);
}
#else
char fin[518];
getunum(s)
char *s;
{ /* find username in /etc/passwd & return num. */
int i;
char str[20], *sp, c;
i = -1;
fin[0] = open("/etc/passwd", 0);
while(c = getchar())
{
sp = str;
*sp++ = c;
while((*sp = getchar()) != ':')
if(!*sp++)
goto RET;
*sp = '\0';
if(compstr(str, s) == 0)
{
while((c = getchar()) != ':')
if(!c)
goto RET;
sp = str;
while((*sp = getchar()) != ':')
sp++;
*sp = '\0';
i = atoi(str);
break;
}
while((c = getchar()) != '\n')
if(!c)
goto RET;
}
RET:
close(fin);
fin[0] = 0;
return(i);
}
#endif AUSAM
compstr(s1, s2)
char s1[], s2[];
{ /* compare strings: */
register char *c1, *c2;
c1 = s1;
c2 = s2;
while(*c1 == *c2)
if(*c1++ == '\0')
return(0); /* s1 == s2 */
else
c2++;
return(*c1 > *c2?1:-1);
}
int descend(name, goal, func, arg)
int(*func)();
char *name, goal;
{
int dir /* open directory */ , offset /* in directory */ ;
int dsize, top;
struct
{
int dinode;
char dname[14];
} dentry[32];
register int i, j, k;
char aname[128];
#ifndef AUSAM
if(stat(name, &statb) < 0)
#else AUSAM
if(newstat(name, &statb) < 0)
#endif AUSAM
{
printf("--bad status %s\n", name);
return(0);
}
/*
if((statb.iflags&060000)!=040000){ /*not a directory*/
/*
if(goal=='f'||goal=='b') /* search goal for files */
/*
(*func)(arg,name);
return(1);
} else if(goal=='d' || goal=='b') /* search goal is directories */
/*
(*func)(arg,name);
*/
(*func)(arg, name);
if((statb.iflags&060000) != 040000)
return(1);
top = statb.isize;
for(offset = 0; offset < top; offset =+ 512)
{ /* each block */
dsize = 512 < (top-offset)?512:(top-offset);
if((dir = open(name, 0)) < 0)
{
printf("--cannot open %s\n", name);
return(0);
}
if(offset)
seek(dir, offset, 0);
if(read(dir, &dentry, dsize) < 0)
{
printf("--cannot read %s\n", name);
return(0);
}
close(dir);
for(i = 0; i < (dsize>>4); ++i)
{ /* each dir. entry */
if(dentry[i].dinode == 0 || compstr(dentry[i].dname, ".") == 0 || compstr(dentry[i].dname, "..")
== 0)
continue;
if(dentry[i].dinode == -1)
break;
for(j = 0; aname[j] = name[j]; ++j);
if(aname[j-1] != '/')
aname[j++] = '/';
for(k = 0; (aname[j++] = dentry[i].dname[k]) && k < 13; ++k);
aname[j] = '\0';
if(descend(aname, goal, func, arg) == 0)
printf("--%s\n", name);
}
}
return(1);
}
gmatch(s, p) /* string match as in glob */
char *s, *p;
{
if(*s == '.' && *p != '.')
return(0);
return(amatch(s, p));
}
amatch(s, p)
char *s, *p;
{
register int cc, scc, k;
int c, lc;
scc = *s;
lc = 077777;
switch(c = *p)
{
case '[':
k = 0;
while(cc = *++p)
{
switch(cc)
{
case ']':
if(k)
return(amatch(++s, ++p));
else
return(0);
case '-':
k =| lc <= scc&scc <= (cc = p[1]);
}
if(scc == (lc = cc))
k++;
}
return(0);
case '?':
caseq:
if(scc)
return(amatch(++s, ++p));
return(0);
case '*':
return(umatch(s, ++p));
case 0:
return(!scc);
}
if(c == scc)
goto caseq;
return(0);
}
umatch(s, p)
char *s, *p;
{
if(*p == 0)
return(1);
while(*s)
if(amatch(s++, p))
return(1);
return(0);
}