AUSAM/source/S/find.c

Compare this file to the similar file:
Show the results in this format:

#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(&not, 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);
}