xref: /csrg-svn/usr.bin/find/function.c (revision 54555)
140947Sbostic /*-
240947Sbostic  * Copyright (c) 1990 The Regents of the University of California.
340947Sbostic  * All rights reserved.
440947Sbostic  *
540947Sbostic  * This code is derived from software contributed to Berkeley by
640947Sbostic  * Cimarron D. Taylor of the University of California, Berkeley.
740947Sbostic  *
840947Sbostic  * %sccs.include.redist.c%
940947Sbostic  */
1040947Sbostic 
1140947Sbostic #ifndef lint
12*54555Sbostic static char sccsid[] = "@(#)function.c	5.21 (Berkeley) 06/29/92";
1340947Sbostic #endif /* not lint */
1440947Sbostic 
1545868Sbostic #include <sys/param.h>
1651833Sbostic #include <sys/ucred.h>
1740947Sbostic #include <sys/stat.h>
1840947Sbostic #include <sys/wait.h>
1940947Sbostic #include <sys/mount.h>
2047192Sbostic #include <errno.h>
2140947Sbostic #include <grp.h>
2240947Sbostic #include <pwd.h>
2340947Sbostic #include <fts.h>
2440947Sbostic #include <unistd.h>
2540947Sbostic #include <tzfile.h>
2640947Sbostic #include <stdio.h>
2747192Sbostic #include <stdlib.h>
2842047Sbostic #include <string.h>
2940947Sbostic #include "find.h"
3040947Sbostic 
3140947Sbostic #define	COMPARE(a, b) { \
3240947Sbostic 	switch(plan->flags) { \
3350437Sbostic 	case F_EQUAL: \
3440947Sbostic 		return(a == b); \
3550437Sbostic 	case F_LESSTHAN: \
3640947Sbostic 		return(a < b); \
3750437Sbostic 	case F_GREATER: \
3840947Sbostic 		return(a > b); \
3940947Sbostic 	} \
4042255Sbostic 	return(0); \
4140947Sbostic }
4240947Sbostic 
4349868Sbostic static PLAN *palloc __P((enum ntype, int (*)()));
4440947Sbostic 
4540947Sbostic /*
4640947Sbostic  * find_parsenum --
4740947Sbostic  *	Parse a string of the form [+-]# and return the value.
4840947Sbostic  */
4940947Sbostic long
5040947Sbostic find_parsenum(plan, option, str, endch)
5140947Sbostic 	PLAN *plan;
5240947Sbostic 	char *option, *str, *endch;
5340947Sbostic {
5440947Sbostic 	long value;
5540947Sbostic 	char *endchar;		/* pointer to character ending conversion */
5640947Sbostic 
5740947Sbostic 	/* determine comparison from leading + or - */
5840947Sbostic 	switch(*str) {
5940947Sbostic 	case '+':
6040947Sbostic 		++str;
6150437Sbostic 		plan->flags = F_GREATER;
6240947Sbostic 		break;
6340947Sbostic 	case '-':
6440947Sbostic 		++str;
6550437Sbostic 		plan->flags = F_LESSTHAN;
6640947Sbostic 		break;
6740947Sbostic 	default:
6850437Sbostic 		plan->flags = F_EQUAL;
6940947Sbostic 		break;
7040947Sbostic 	}
7140947Sbostic 
7240947Sbostic 	/*
7340947Sbostic 	 * convert the string with strtol().  Note, if strtol() returns zero
7440947Sbostic 	 * and endchar points to the beginning of the string we know we have
7540947Sbostic 	 * a syntax error.
7640947Sbostic 	 */
7740947Sbostic 	value = strtol(str, &endchar, 10);
7840947Sbostic 	if (!value && endchar == str ||
7940947Sbostic 	    endchar[0] && (!endch || endchar[0] != *endch))
8049868Sbostic 		err("%s: %s", option, "illegal numeric value");
8140947Sbostic 	if (endch)
8240947Sbostic 		*endch = endchar[0];
8340947Sbostic 	return(value);
8440947Sbostic }
8540947Sbostic 
8640947Sbostic /*
8740947Sbostic  * -atime n functions --
8840947Sbostic  *
8940947Sbostic  *	True if the difference between the file access time and the
9040947Sbostic  *	current time is n 24 hour periods.
9140947Sbostic  *
9240947Sbostic  */
9340947Sbostic f_atime(plan, entry)
9440947Sbostic 	PLAN *plan;
9540947Sbostic 	FTSENT *entry;
9640947Sbostic {
9740947Sbostic 	extern time_t now;
9840947Sbostic 
9952239Sbostic 	COMPARE((now - entry->fts_statp->st_atime +
10042255Sbostic 	    SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
10140947Sbostic }
10240947Sbostic 
10340947Sbostic PLAN *
10440947Sbostic c_atime(arg)
10540947Sbostic 	char *arg;
10640947Sbostic {
10740947Sbostic 	PLAN *new;
10840947Sbostic 
10940947Sbostic 	ftsoptions &= ~FTS_NOSTAT;
11040947Sbostic 
11149868Sbostic 	new = palloc(N_ATIME, f_atime);
11249868Sbostic 	new->t_data = find_parsenum(new, "-atime", arg, NULL);
11340947Sbostic 	return(new);
11440947Sbostic }
11540947Sbostic /*
11640947Sbostic  * -ctime n functions --
11740947Sbostic  *
11840947Sbostic  *	True if the difference between the last change of file
11940947Sbostic  *	status information and the current time is n 24 hour periods.
12040947Sbostic  */
12140947Sbostic f_ctime(plan, entry)
12240947Sbostic 	PLAN *plan;
12340947Sbostic 	FTSENT *entry;
12440947Sbostic {
12540947Sbostic 	extern time_t now;
12640947Sbostic 
12752239Sbostic 	COMPARE((now - entry->fts_statp->st_ctime +
12842255Sbostic 	    SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
12940947Sbostic }
13040947Sbostic 
13140947Sbostic PLAN *
13240947Sbostic c_ctime(arg)
13340947Sbostic 	char *arg;
13440947Sbostic {
13540947Sbostic 	PLAN *new;
13640947Sbostic 
13740947Sbostic 	ftsoptions &= ~FTS_NOSTAT;
13840947Sbostic 
13949868Sbostic 	new = palloc(N_CTIME, f_ctime);
14040947Sbostic 	new->t_data = find_parsenum(new, "-ctime", arg, (char *)NULL);
14140947Sbostic 	return(new);
14240947Sbostic }
14340947Sbostic 
14440947Sbostic /*
14540947Sbostic  * -depth functions --
14640947Sbostic  *
14740947Sbostic  *	Always true, causes descent of the directory hierarchy to be done
14840947Sbostic  *	so that all entries in a directory are acted on before the directory
14940947Sbostic  *	itself.
15040947Sbostic  */
15140947Sbostic /* ARGSUSED */
15240947Sbostic f_always_true(plan, entry)
15340947Sbostic 	PLAN *plan;
15440947Sbostic 	FTSENT *entry;
15540947Sbostic {
15642255Sbostic 	return(1);
15740947Sbostic }
15840947Sbostic 
15940947Sbostic PLAN *
16040947Sbostic c_depth()
16140947Sbostic {
16245615Sbostic 	isdepth = 1;
16340947Sbostic 
16449868Sbostic 	return(palloc(N_DEPTH, f_always_true));
16540947Sbostic }
16640947Sbostic 
16740947Sbostic /*
16840947Sbostic  * [-exec | -ok] utility [arg ... ] ; functions --
16940947Sbostic  *
17040947Sbostic  *	True if the executed utility returns a zero value as exit status.
17140947Sbostic  *	The end of the primary expression is delimited by a semicolon.  If
17240947Sbostic  *	"{}" occurs anywhere, it gets replaced by the current pathname.
17340947Sbostic  *	The current directory for the execution of utility is the same as
17440947Sbostic  *	the current directory when the find utility was started.
17540947Sbostic  *
17640947Sbostic  *	The primary -ok is different in that it requests affirmation of the
17740947Sbostic  *	user before executing the utility.
17840947Sbostic  */
17940947Sbostic f_exec(plan, entry)
18040947Sbostic 	register PLAN *plan;
18140947Sbostic 	FTSENT *entry;
18240947Sbostic {
18349869Sbostic 	extern int dotfd;
18440947Sbostic 	register int cnt;
18547192Sbostic 	pid_t pid;
18647192Sbostic 	int status;
18740947Sbostic 
18840947Sbostic 	for (cnt = 0; plan->e_argv[cnt]; ++cnt)
18940947Sbostic 		if (plan->e_len[cnt])
19045616Sbostic 			brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt],
19149869Sbostic 			    entry->fts_path, plan->e_len[cnt]);
19240947Sbostic 
19350437Sbostic 	if (plan->flags == F_NEEDOK && !queryuser(plan->e_argv))
19442255Sbostic 		return(0);
19540947Sbostic 
19640947Sbostic 	switch(pid = vfork()) {
19740947Sbostic 	case -1:
19849868Sbostic 		err("fork: %s", strerror(errno));
19940947Sbostic 		/* NOTREACHED */
20040947Sbostic 	case 0:
20149869Sbostic 		if (fchdir(dotfd)) {
20249869Sbostic 			(void)fprintf(stderr,
20349869Sbostic 			    "find: chdir: %s\n", strerror(errno));
20449869Sbostic 			_exit(1);
20549869Sbostic 		}
20640947Sbostic 		execvp(plan->e_argv[0], plan->e_argv);
20749869Sbostic 		(void)fprintf(stderr,
20849869Sbostic 		    "find: %s: %s\n", plan->e_argv[0], strerror(errno));
20949869Sbostic 		_exit(1);
21040947Sbostic 	}
21147192Sbostic 	pid = waitpid(pid, &status, 0);
21247192Sbostic 	return(pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
21340947Sbostic }
21440947Sbostic 
21540947Sbostic /*
21640947Sbostic  * c_exec --
21740947Sbostic  *	build three parallel arrays, one with pointers to the strings passed
21840947Sbostic  *	on the command line, one with (possibly duplicated) pointers to the
21940947Sbostic  *	argv array, and one with integer values that are lengths of the
22040947Sbostic  *	strings, but also flags meaning that the string has to be massaged.
22140947Sbostic  */
22240947Sbostic PLAN *
22340947Sbostic c_exec(argvp, isok)
22440947Sbostic 	char ***argvp;
22540947Sbostic 	int isok;
22640947Sbostic {
22740947Sbostic 	PLAN *new;			/* node returned */
22840947Sbostic 	register int cnt;
22940947Sbostic 	register char **argv, **ap, *p;
23040947Sbostic 
23147192Sbostic 	isoutput = 1;
23240947Sbostic 
23349868Sbostic 	new = palloc(N_EXEC, f_exec);
23450437Sbostic 	if (isok)
23550437Sbostic 		new->flags = F_NEEDOK;
23640947Sbostic 
23740947Sbostic 	for (ap = argv = *argvp;; ++ap) {
23840947Sbostic 		if (!*ap)
23949868Sbostic 			err("%s: %s",
24049868Sbostic 			    isok ? "-ok" : "-exec", "no terminating \";\"");
24140947Sbostic 		if (**ap == ';')
24240947Sbostic 			break;
24340947Sbostic 	}
24440947Sbostic 
24540947Sbostic 	cnt = ap - *argvp + 1;
24640947Sbostic 	new->e_argv = (char **)emalloc((u_int)cnt * sizeof(char *));
24740947Sbostic 	new->e_orig = (char **)emalloc((u_int)cnt * sizeof(char *));
24845868Sbostic 	new->e_len = (int *)emalloc((u_int)cnt * sizeof(int));
24940947Sbostic 
25040947Sbostic 	for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
25140947Sbostic 		new->e_orig[cnt] = *argv;
25240947Sbostic 		for (p = *argv; *p; ++p)
25340947Sbostic 			if (p[0] == '{' && p[1] == '}') {
25445868Sbostic 				new->e_argv[cnt] = emalloc((u_int)MAXPATHLEN);
25545868Sbostic 				new->e_len[cnt] = MAXPATHLEN;
25640947Sbostic 				break;
25740947Sbostic 			}
25840947Sbostic 		if (!*p) {
25940947Sbostic 			new->e_argv[cnt] = *argv;
26040947Sbostic 			new->e_len[cnt] = 0;
26140947Sbostic 		}
26240947Sbostic 	}
26340947Sbostic 	new->e_argv[cnt] = new->e_orig[cnt] = NULL;
26440947Sbostic 
26540947Sbostic 	*argvp = argv + 1;
26640947Sbostic 	return(new);
26740947Sbostic }
26840947Sbostic 
26940947Sbostic /*
27040947Sbostic  * -follow functions --
27140947Sbostic  *
27240947Sbostic  *	Always true, causes symbolic links to be followed on a global
27340947Sbostic  *	basis.
27440947Sbostic  */
27540947Sbostic PLAN *
27640947Sbostic c_follow()
27740947Sbostic {
27840947Sbostic 	ftsoptions &= ~FTS_PHYSICAL;
27940947Sbostic 	ftsoptions |= FTS_LOGICAL;
28040947Sbostic 
28149868Sbostic 	return(palloc(N_FOLLOW, f_always_true));
28240947Sbostic }
28340947Sbostic 
28440947Sbostic /*
28540947Sbostic  * -fstype functions --
28640947Sbostic  *
28740947Sbostic  *	True if the file is of a certain type.
28840947Sbostic  */
28940947Sbostic f_fstype(plan, entry)
29040947Sbostic 	PLAN *plan;
29140947Sbostic 	FTSENT *entry;
29240947Sbostic {
29342275Sbostic 	static dev_t curdev;	/* need a guaranteed illegal dev value */
29442275Sbostic 	static int first = 1;
29540947Sbostic 	struct statfs sb;
29642255Sbostic 	static short val;
29745626Sbostic 	char *p, save[2];
29840947Sbostic 
29950437Sbostic 	/* Only check when we cross mount point. */
30052239Sbostic 	if (first || curdev != entry->fts_statp->st_dev) {
30152239Sbostic 		curdev = entry->fts_statp->st_dev;
30245626Sbostic 
30345626Sbostic 		/*
30445626Sbostic 		 * Statfs follows symlinks; find wants the link's file system,
30545626Sbostic 		 * not where it points.
30645626Sbostic 		 */
30745626Sbostic 		if (entry->fts_info == FTS_SL ||
30845626Sbostic 		    entry->fts_info == FTS_SLNONE) {
30945626Sbostic 			if (p = rindex(entry->fts_accpath, '/'))
31045626Sbostic 				++p;
31145626Sbostic 			else
31245626Sbostic 				p = entry->fts_accpath;
31345626Sbostic 			save[0] = p[0];
31445626Sbostic 			p[0] = '.';
31545626Sbostic 			save[1] = p[1];
31645626Sbostic 			p[1] = '\0';
31745626Sbostic 
31845626Sbostic 		} else
31945626Sbostic 			p = NULL;
32045626Sbostic 
32149868Sbostic 		if (statfs(entry->fts_accpath, &sb))
32249868Sbostic 			err("%s: %s", entry->fts_accpath, strerror(errno));
32345626Sbostic 
32445626Sbostic 		if (p) {
32545626Sbostic 			p[0] = save[0];
32645626Sbostic 			p[1] = save[1];
32745626Sbostic 		}
32845626Sbostic 
32942275Sbostic 		first = 0;
33050437Sbostic 		switch(plan->flags) {
33150437Sbostic 		case F_MTFLAG:
33250437Sbostic 			val = sb.f_flags;
33350437Sbostic 			break;
33450437Sbostic 		case F_MTTYPE:
33550437Sbostic 			val = sb.f_type;
33650437Sbostic 			break;
33750437Sbostic 		}
33840947Sbostic 	}
33950437Sbostic 	switch(plan->flags) {
34050437Sbostic 	case F_MTFLAG:
34150437Sbostic 		return(val & plan->mt_data);
34250437Sbostic 	case F_MTTYPE:
34350437Sbostic 		return(val == plan->mt_data);
34450437Sbostic 	}
34540947Sbostic }
34640947Sbostic 
34740947Sbostic PLAN *
34840947Sbostic c_fstype(arg)
34940947Sbostic 	char *arg;
35040947Sbostic {
35140947Sbostic 	register PLAN *new;
35240947Sbostic 
35340947Sbostic 	ftsoptions &= ~FTS_NOSTAT;
35440947Sbostic 
35549868Sbostic 	new = palloc(N_FSTYPE, f_fstype);
35640947Sbostic 	switch(*arg) {
35742255Sbostic 	case 'l':
35842255Sbostic 		if (!strcmp(arg, "local")) {
35950437Sbostic 			new->flags = F_MTFLAG;
36050437Sbostic 			new->mt_data = MNT_LOCAL;
36142255Sbostic 			return(new);
36242255Sbostic 		}
36342255Sbostic 		break;
36440947Sbostic 	case 'm':
36540947Sbostic 		if (!strcmp(arg, "mfs")) {
36650437Sbostic 			new->flags = F_MTTYPE;
36750437Sbostic 			new->mt_data = MOUNT_MFS;
36840947Sbostic 			return(new);
36940947Sbostic 		}
37040947Sbostic 		break;
37140947Sbostic 	case 'n':
37240947Sbostic 		if (!strcmp(arg, "nfs")) {
37350437Sbostic 			new->flags = F_MTTYPE;
37450437Sbostic 			new->mt_data = MOUNT_NFS;
37540947Sbostic 			return(new);
37640947Sbostic 		}
37740947Sbostic 		break;
37840947Sbostic 	case 'p':
37940947Sbostic 		if (!strcmp(arg, "pc")) {
38050437Sbostic 			new->flags = F_MTTYPE;
38150437Sbostic 			new->mt_data = MOUNT_PC;
38240947Sbostic 			return(new);
38340947Sbostic 		}
38440947Sbostic 		break;
38550437Sbostic 	case 'r':
38650437Sbostic 		if (!strcmp(arg, "rdonly")) {
38750437Sbostic 			new->flags = F_MTFLAG;
38850437Sbostic 			new->mt_data = MNT_RDONLY;
38950437Sbostic 			return(new);
39050437Sbostic 		}
39150437Sbostic 		break;
39240947Sbostic 	case 'u':
39340947Sbostic 		if (!strcmp(arg, "ufs")) {
39450437Sbostic 			new->flags = F_MTTYPE;
39550437Sbostic 			new->mt_data = MOUNT_UFS;
39640947Sbostic 			return(new);
39740947Sbostic 		}
39840947Sbostic 		break;
39940947Sbostic 	}
40049868Sbostic 	err("unknown file type %s", arg);
40140947Sbostic 	/* NOTREACHED */
40240947Sbostic }
40340947Sbostic 
40440947Sbostic /*
40540947Sbostic  * -group gname functions --
40640947Sbostic  *
40740947Sbostic  *	True if the file belongs to the group gname.  If gname is numeric and
40840947Sbostic  *	an equivalent of the getgrnam() function does not return a valid group
40940947Sbostic  *	name, gname is taken as a group ID.
41040947Sbostic  */
41140947Sbostic f_group(plan, entry)
41240947Sbostic 	PLAN *plan;
41340947Sbostic 	FTSENT *entry;
41440947Sbostic {
41552239Sbostic 	return(entry->fts_statp->st_gid == plan->g_data);
41640947Sbostic }
41740947Sbostic 
41840947Sbostic PLAN *
41940947Sbostic c_group(gname)
42040947Sbostic 	char *gname;
42140947Sbostic {
42240947Sbostic 	PLAN *new;
42340947Sbostic 	struct group *g;
42440947Sbostic 	gid_t gid;
42540947Sbostic 
42640947Sbostic 	ftsoptions &= ~FTS_NOSTAT;
42740947Sbostic 
42840947Sbostic 	g = getgrnam(gname);
42940947Sbostic 	if (g == NULL) {
43040947Sbostic 		gid = atoi(gname);
43140947Sbostic 		if (gid == 0 && gname[0] != '0')
43249868Sbostic 			err("%s: %s", "-group", "no such group");
43340947Sbostic 	} else
43440947Sbostic 		gid = g->gr_gid;
43540947Sbostic 
43649868Sbostic 	new = palloc(N_GROUP, f_group);
43740947Sbostic 	new->g_data = gid;
43840947Sbostic 	return(new);
43940947Sbostic }
44040947Sbostic 
44140947Sbostic /*
44240947Sbostic  * -inum n functions --
44340947Sbostic  *
44440947Sbostic  *	True if the file has inode # n.
44540947Sbostic  */
44640947Sbostic f_inum(plan, entry)
44740947Sbostic 	PLAN *plan;
44840947Sbostic 	FTSENT *entry;
44940947Sbostic {
45052239Sbostic 	COMPARE(entry->fts_statp->st_ino, plan->i_data);
45140947Sbostic }
45240947Sbostic 
45340947Sbostic PLAN *
45440947Sbostic c_inum(arg)
45540947Sbostic 	char *arg;
45640947Sbostic {
45740947Sbostic 	PLAN *new;
45840947Sbostic 
45940947Sbostic 	ftsoptions &= ~FTS_NOSTAT;
46040947Sbostic 
46149868Sbostic 	new = palloc(N_INUM, f_inum);
46240947Sbostic 	new->i_data = find_parsenum(new, "-inum", arg, (char *)NULL);
46340947Sbostic 	return(new);
46440947Sbostic }
46540947Sbostic 
46640947Sbostic /*
46740947Sbostic  * -links n functions --
46840947Sbostic  *
46940947Sbostic  *	True if the file has n links.
47040947Sbostic  */
47140947Sbostic f_links(plan, entry)
47240947Sbostic 	PLAN *plan;
47340947Sbostic 	FTSENT *entry;
47440947Sbostic {
47552239Sbostic 	COMPARE(entry->fts_statp->st_nlink, plan->l_data);
47640947Sbostic }
47740947Sbostic 
47840947Sbostic PLAN *
47940947Sbostic c_links(arg)
48040947Sbostic 	char *arg;
48140947Sbostic {
48240947Sbostic 	PLAN *new;
48340947Sbostic 
48440947Sbostic 	ftsoptions &= ~FTS_NOSTAT;
48540947Sbostic 
48649868Sbostic 	new = palloc(N_LINKS, f_links);
48745616Sbostic 	new->l_data = (nlink_t)find_parsenum(new, "-links", arg, (char *)NULL);
48840947Sbostic 	return(new);
48940947Sbostic }
49040947Sbostic 
49140947Sbostic /*
49240947Sbostic  * -ls functions --
49340947Sbostic  *
49440947Sbostic  *	Always true - prints the current entry to stdout in "ls" format.
49540947Sbostic  */
49640947Sbostic /* ARGSUSED */
49740947Sbostic f_ls(plan, entry)
49840947Sbostic 	PLAN *plan;
49940947Sbostic 	FTSENT *entry;
50040947Sbostic {
50152239Sbostic 	printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
50242255Sbostic 	return(1);
50340947Sbostic }
50440947Sbostic 
50540947Sbostic PLAN *
50640947Sbostic c_ls()
50740947Sbostic {
50840947Sbostic 	ftsoptions &= ~FTS_NOSTAT;
50945615Sbostic 	isoutput = 1;
51040947Sbostic 
51149868Sbostic 	return(palloc(N_LS, f_ls));
51240947Sbostic }
51340947Sbostic 
51440947Sbostic /*
51550437Sbostic  * -mtime n functions --
51650437Sbostic  *
51750437Sbostic  *	True if the difference between the file modification time and the
51850437Sbostic  *	current time is n 24 hour periods.
51950437Sbostic  */
52050437Sbostic f_mtime(plan, entry)
52150437Sbostic 	PLAN *plan;
52250437Sbostic 	FTSENT *entry;
52350437Sbostic {
52450437Sbostic 	extern time_t now;
52550437Sbostic 
52652239Sbostic 	COMPARE((now - entry->fts_statp->st_mtime + SECSPERDAY - 1) /
52750437Sbostic 	    SECSPERDAY, plan->t_data);
52850437Sbostic }
52950437Sbostic 
53050437Sbostic PLAN *
53150437Sbostic c_mtime(arg)
53250437Sbostic 	char *arg;
53350437Sbostic {
53450437Sbostic 	PLAN *new;
53550437Sbostic 
53650437Sbostic 	ftsoptions &= ~FTS_NOSTAT;
53750437Sbostic 
53850437Sbostic 	new = palloc(N_MTIME, f_mtime);
53950437Sbostic 	new->t_data = find_parsenum(new, "-mtime", arg, (char *)NULL);
54050437Sbostic 	return(new);
54150437Sbostic }
54250437Sbostic 
54350437Sbostic /*
54440947Sbostic  * -name functions --
54540947Sbostic  *
54640947Sbostic  *	True if the basename of the filename being examined
54740947Sbostic  *	matches pattern using Pattern Matching Notation S3.14
54840947Sbostic  */
54940947Sbostic f_name(plan, entry)
55040947Sbostic 	PLAN *plan;
55140947Sbostic 	FTSENT *entry;
55240947Sbostic {
553*54555Sbostic 	return(!fnmatch(plan->c_data, entry->fts_name, 0));
55440947Sbostic }
55540947Sbostic 
55640947Sbostic PLAN *
55740947Sbostic c_name(pattern)
55840947Sbostic 	char *pattern;
55940947Sbostic {
56040947Sbostic 	PLAN *new;
56140947Sbostic 
56249868Sbostic 	new = palloc(N_NAME, f_name);
56340947Sbostic 	new->c_data = pattern;
56440947Sbostic 	return(new);
56540947Sbostic }
56640947Sbostic 
56740947Sbostic /*
56840947Sbostic  * -newer file functions --
56940947Sbostic  *
57040947Sbostic  *	True if the current file has been modified more recently
57140947Sbostic  *	then the modification time of the file named by the pathname
57240947Sbostic  *	file.
57340947Sbostic  */
57440947Sbostic f_newer(plan, entry)
57540947Sbostic 	PLAN *plan;
57640947Sbostic 	FTSENT *entry;
57740947Sbostic {
57852239Sbostic 	return(entry->fts_statp->st_mtime > plan->t_data);
57940947Sbostic }
58040947Sbostic 
58140947Sbostic PLAN *
58240947Sbostic c_newer(filename)
58340947Sbostic 	char *filename;
58440947Sbostic {
58540947Sbostic 	PLAN *new;
58640947Sbostic 	struct stat sb;
58740947Sbostic 
58840947Sbostic 	ftsoptions &= ~FTS_NOSTAT;
58940947Sbostic 
59049868Sbostic 	if (stat(filename, &sb))
59149868Sbostic 		err("%s: %s", filename, strerror(errno));
59249868Sbostic 	new = palloc(N_NEWER, f_newer);
59340947Sbostic 	new->t_data = sb.st_mtime;
59440947Sbostic 	return(new);
59540947Sbostic }
59640947Sbostic 
59740947Sbostic /*
59840947Sbostic  * -nogroup functions --
59940947Sbostic  *
60040947Sbostic  *	True if file belongs to a user ID for which the equivalent
60140947Sbostic  *	of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
60240947Sbostic  */
60340947Sbostic /* ARGSUSED */
60440947Sbostic f_nogroup(plan, entry)
60540947Sbostic 	PLAN *plan;
60640947Sbostic 	FTSENT *entry;
60740947Sbostic {
60845615Sbostic 	char *group_from_gid();
60945615Sbostic 
61052239Sbostic 	return(group_from_gid(entry->fts_statp->st_gid, 1) ? 1 : 0);
61140947Sbostic }
61240947Sbostic 
61340947Sbostic PLAN *
61440947Sbostic c_nogroup()
61540947Sbostic {
61640947Sbostic 	ftsoptions &= ~FTS_NOSTAT;
61740947Sbostic 
61849868Sbostic 	return(palloc(N_NOGROUP, f_nogroup));
61940947Sbostic }
62040947Sbostic 
62140947Sbostic /*
62240947Sbostic  * -nouser functions --
62340947Sbostic  *
62440947Sbostic  *	True if file belongs to a user ID for which the equivalent
62540947Sbostic  *	of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
62640947Sbostic  */
62740947Sbostic /* ARGSUSED */
62840947Sbostic f_nouser(plan, entry)
62940947Sbostic 	PLAN *plan;
63040947Sbostic 	FTSENT *entry;
63140947Sbostic {
63245615Sbostic 	char *user_from_uid();
63345615Sbostic 
63452239Sbostic 	return(user_from_uid(entry->fts_statp->st_uid, 1) ? 1 : 0);
63540947Sbostic }
63640947Sbostic 
63740947Sbostic PLAN *
63840947Sbostic c_nouser()
63940947Sbostic {
64040947Sbostic 	ftsoptions &= ~FTS_NOSTAT;
64140947Sbostic 
64249868Sbostic 	return(palloc(N_NOUSER, f_nouser));
64340947Sbostic }
64440947Sbostic 
64540947Sbostic /*
64650437Sbostic  * -path functions --
64750437Sbostic  *
64850437Sbostic  *	True if the path of the filename being examined
64950437Sbostic  *	matches pattern using Pattern Matching Notation S3.14
65050437Sbostic  */
65150437Sbostic f_path(plan, entry)
65250437Sbostic 	PLAN *plan;
65350437Sbostic 	FTSENT *entry;
65450437Sbostic {
655*54555Sbostic 	return(!fnmatch(plan->c_data, entry->fts_path, 0));
65650437Sbostic }
65750437Sbostic 
65850437Sbostic PLAN *
65950437Sbostic c_path(pattern)
66050437Sbostic 	char *pattern;
66150437Sbostic {
66250437Sbostic 	PLAN *new;
66350437Sbostic 
66450437Sbostic 	new = palloc(N_NAME, f_path);
66550437Sbostic 	new->c_data = pattern;
66650437Sbostic 	return(new);
66750437Sbostic }
66850437Sbostic 
66950437Sbostic /*
67040947Sbostic  * -perm functions --
67140947Sbostic  *
67240947Sbostic  *	The mode argument is used to represent file mode bits.  If it starts
67340947Sbostic  *	with a leading digit, it's treated as an octal mode, otherwise as a
67440947Sbostic  *	symbolic mode.
67540947Sbostic  */
67640947Sbostic f_perm(plan, entry)
67740947Sbostic 	PLAN *plan;
67840947Sbostic 	FTSENT *entry;
67940947Sbostic {
68040947Sbostic 	mode_t mode;
68140947Sbostic 
68252239Sbostic 	mode = entry->fts_statp->st_mode &
68340947Sbostic 	    (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
68450437Sbostic 	if (plan->flags == F_ATLEAST)
68540947Sbostic 		return((plan->m_data | mode) == mode);
68640947Sbostic 	else
68740947Sbostic 		return(mode == plan->m_data);
68840947Sbostic 	/* NOTREACHED */
68940947Sbostic }
69040947Sbostic 
69140947Sbostic PLAN *
69240947Sbostic c_perm(perm)
69340947Sbostic 	char *perm;
69440947Sbostic {
69540947Sbostic 	PLAN *new;
69647192Sbostic 	mode_t *set;
69740947Sbostic 
69840947Sbostic 	ftsoptions &= ~FTS_NOSTAT;
69940947Sbostic 
70049868Sbostic 	new = palloc(N_PERM, f_perm);
70140947Sbostic 
70240947Sbostic 	if (*perm == '-') {
70350437Sbostic 		new->flags = F_ATLEAST;
70440947Sbostic 		++perm;
70540947Sbostic 	}
70640947Sbostic 
70744764Strent 	if ((set = setmode(perm)) == NULL)
70849868Sbostic 		err("%s: %s", "-perm", "illegal mode string");
70940947Sbostic 
71044764Strent 	new->m_data = getmode(set, 0);
71140947Sbostic 	return(new);
71240947Sbostic }
71340947Sbostic 
71440947Sbostic /*
71540947Sbostic  * -print functions --
71640947Sbostic  *
71740947Sbostic  *	Always true, causes the current pathame to be written to
71840947Sbostic  *	standard output.
71940947Sbostic  */
72040947Sbostic /* ARGSUSED */
72140947Sbostic f_print(plan, entry)
72240947Sbostic 	PLAN *plan;
72340947Sbostic 	FTSENT *entry;
72440947Sbostic {
72542255Sbostic 	(void)printf("%s\n", entry->fts_path);
72642255Sbostic 	return(1);
72740947Sbostic }
72840947Sbostic 
72940947Sbostic PLAN *
73040947Sbostic c_print()
73140947Sbostic {
73245615Sbostic 	isoutput = 1;
73340947Sbostic 
73449868Sbostic 	return(palloc(N_PRINT, f_print));
73540947Sbostic }
73640947Sbostic 
73740947Sbostic /*
73840947Sbostic  * -prune functions --
73940947Sbostic  *
74040947Sbostic  *	Prune a portion of the hierarchy.
74140947Sbostic  */
74240947Sbostic /* ARGSUSED */
74340947Sbostic f_prune(plan, entry)
74440947Sbostic 	PLAN *plan;
74540947Sbostic 	FTSENT *entry;
74640947Sbostic {
74740947Sbostic 	extern FTS *tree;
74840947Sbostic 
74949868Sbostic 	if (fts_set(tree, entry, FTS_SKIP))
75049868Sbostic 		err("%s: %s", entry->fts_path, strerror(errno));
75142255Sbostic 	return(1);
75240947Sbostic }
75340947Sbostic 
75440947Sbostic PLAN *
75540947Sbostic c_prune()
75640947Sbostic {
75749868Sbostic 	return(palloc(N_PRUNE, f_prune));
75840947Sbostic }
75940947Sbostic 
76040947Sbostic /*
76140947Sbostic  * -size n[c] functions --
76240947Sbostic  *
76340947Sbostic  *	True if the file size in bytes, divided by an implementation defined
76440947Sbostic  *	value and rounded up to the next integer, is n.  If n is followed by
76540947Sbostic  *	a c, the size is in bytes.
76640947Sbostic  */
76740947Sbostic #define	FIND_SIZE	512
76840947Sbostic static int divsize = 1;
76940947Sbostic 
77040947Sbostic f_size(plan, entry)
77140947Sbostic 	PLAN *plan;
77240947Sbostic 	FTSENT *entry;
77340947Sbostic {
77440947Sbostic 	off_t size;
77540947Sbostic 
77652239Sbostic 	size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) /
77752239Sbostic 	    FIND_SIZE : entry->fts_statp->st_size;
77840947Sbostic 	COMPARE(size, plan->o_data);
77940947Sbostic }
78040947Sbostic 
78140947Sbostic PLAN *
78240947Sbostic c_size(arg)
78340947Sbostic 	char *arg;
78440947Sbostic {
78540947Sbostic 	PLAN *new;
78640947Sbostic 	char endch;
78740947Sbostic 
78840947Sbostic 	ftsoptions &= ~FTS_NOSTAT;
78940947Sbostic 
79049868Sbostic 	new = palloc(N_SIZE, f_size);
79140947Sbostic 	new->o_data = find_parsenum(new, "-size", arg, &endch);
79240947Sbostic 	if (endch == 'c')
79340947Sbostic 		divsize = 0;
79440947Sbostic 	return(new);
79540947Sbostic }
79640947Sbostic 
79740947Sbostic /*
79840947Sbostic  * -type c functions --
79940947Sbostic  *
80040947Sbostic  *	True if the type of the file is c, where c is b, c, d, p, or f for
80140947Sbostic  *	block special file, character special file, directory, FIFO, or
80240947Sbostic  *	regular file, respectively.
80340947Sbostic  */
80440947Sbostic f_type(plan, entry)
80540947Sbostic 	PLAN *plan;
80640947Sbostic 	FTSENT *entry;
80740947Sbostic {
80852239Sbostic 	return((entry->fts_statp->st_mode & S_IFMT) == plan->m_data);
80940947Sbostic }
81040947Sbostic 
81140947Sbostic PLAN *
81240947Sbostic c_type(typestring)
81340947Sbostic 	char *typestring;
81440947Sbostic {
81540947Sbostic 	PLAN *new;
81640947Sbostic 	mode_t  mask;
81740947Sbostic 
81840947Sbostic 	ftsoptions &= ~FTS_NOSTAT;
81940947Sbostic 
82040947Sbostic 	switch (typestring[0]) {
82140947Sbostic 	case 'b':
82240947Sbostic 		mask = S_IFBLK;
82340947Sbostic 		break;
82440947Sbostic 	case 'c':
82540947Sbostic 		mask = S_IFCHR;
82640947Sbostic 		break;
82740947Sbostic 	case 'd':
82840947Sbostic 		mask = S_IFDIR;
82940947Sbostic 		break;
83040947Sbostic 	case 'f':
83140947Sbostic 		mask = S_IFREG;
83240947Sbostic 		break;
83340947Sbostic 	case 'l':
83440947Sbostic 		mask = S_IFLNK;
83540947Sbostic 		break;
83640947Sbostic 	case 'p':
83740947Sbostic 		mask = S_IFIFO;
83840947Sbostic 		break;
83940947Sbostic 	case 's':
84040947Sbostic 		mask = S_IFSOCK;
84140947Sbostic 		break;
84240947Sbostic 	default:
84349868Sbostic 		err("%s: %s", "-type", "unknown type");
84440947Sbostic 	}
84540947Sbostic 
84649868Sbostic 	new = palloc(N_TYPE, f_type);
84740947Sbostic 	new->m_data = mask;
84840947Sbostic 	return(new);
84940947Sbostic }
85040947Sbostic 
85140947Sbostic /*
85240947Sbostic  * -user uname functions --
85340947Sbostic  *
85440947Sbostic  *	True if the file belongs to the user uname.  If uname is numeric and
85540947Sbostic  *	an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
85640947Sbostic  *	return a valid user name, uname is taken as a user ID.
85740947Sbostic  */
85840947Sbostic f_user(plan, entry)
85940947Sbostic 	PLAN *plan;
86040947Sbostic 	FTSENT *entry;
86140947Sbostic {
86252239Sbostic 	return(entry->fts_statp->st_uid == plan->u_data);
86340947Sbostic }
86440947Sbostic 
86540947Sbostic PLAN *
86640947Sbostic c_user(username)
86740947Sbostic 	char *username;
86840947Sbostic {
86940947Sbostic 	PLAN *new;
87040947Sbostic 	struct passwd *p;
87140947Sbostic 	uid_t uid;
87240947Sbostic 
87340947Sbostic 	ftsoptions &= ~FTS_NOSTAT;
87440947Sbostic 
87540947Sbostic 	p = getpwnam(username);
87640947Sbostic 	if (p == NULL) {
87740947Sbostic 		uid = atoi(username);
87840947Sbostic 		if (uid == 0 && username[0] != '0')
87949868Sbostic 			err("%s: %s", "-user", "no such user");
88040947Sbostic 	} else
88140947Sbostic 		uid = p->pw_uid;
88240947Sbostic 
88349868Sbostic 	new = palloc(N_USER, f_user);
88440947Sbostic 	new->u_data = uid;
88540947Sbostic 	return(new);
88640947Sbostic }
88740947Sbostic 
88840947Sbostic /*
88940947Sbostic  * -xdev functions --
89040947Sbostic  *
89140947Sbostic  *	Always true, causes find not to decend past directories that have a
89240947Sbostic  *	different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
89340947Sbostic  */
89440947Sbostic PLAN *
89540947Sbostic c_xdev()
89640947Sbostic {
89742275Sbostic 	ftsoptions |= FTS_XDEV;
89840947Sbostic 
89949868Sbostic 	return(palloc(N_XDEV, f_always_true));
90040947Sbostic }
90140947Sbostic 
90240947Sbostic /*
90340947Sbostic  * ( expression ) functions --
90440947Sbostic  *
90540947Sbostic  *	True if expression is true.
90640947Sbostic  */
90740947Sbostic f_expr(plan, entry)
90840947Sbostic 	PLAN *plan;
90940947Sbostic 	FTSENT *entry;
91040947Sbostic {
91140947Sbostic 	register PLAN *p;
91240947Sbostic 	register int state;
91340947Sbostic 
91440947Sbostic 	for (p = plan->p_data[0];
91540947Sbostic 	    p && (state = (p->eval)(p, entry)); p = p->next);
91640947Sbostic 	return(state);
91740947Sbostic }
91840947Sbostic 
91940947Sbostic /*
92049864Sbostic  * N_OPENPAREN and N_CLOSEPAREN nodes are temporary place markers.  They are
92140947Sbostic  * eliminated during phase 2 of find_formplan() --- the '(' node is converted
92249864Sbostic  * to a N_EXPR node containing the expression and the ')' node is discarded.
92340947Sbostic  */
92440947Sbostic PLAN *
92540947Sbostic c_openparen()
92640947Sbostic {
92749868Sbostic 	return(palloc(N_OPENPAREN, (int (*)())-1));
92840947Sbostic }
92940947Sbostic 
93040947Sbostic PLAN *
93140947Sbostic c_closeparen()
93240947Sbostic {
93349868Sbostic 	return(palloc(N_CLOSEPAREN, (int (*)())-1));
93440947Sbostic }
93540947Sbostic 
93640947Sbostic /*
93740947Sbostic  * ! expression functions --
93840947Sbostic  *
93940947Sbostic  *	Negation of a primary; the unary NOT operator.
94040947Sbostic  */
94140947Sbostic f_not(plan, entry)
94240947Sbostic 	PLAN *plan;
94340947Sbostic 	FTSENT *entry;
94440947Sbostic {
94540947Sbostic 	register PLAN *p;
94640947Sbostic 	register int state;
94740947Sbostic 
94840947Sbostic 	for (p = plan->p_data[0];
94940947Sbostic 	    p && (state = (p->eval)(p, entry)); p = p->next);
95040947Sbostic 	return(!state);
95140947Sbostic }
95240947Sbostic 
95340947Sbostic PLAN *
95440947Sbostic c_not()
95540947Sbostic {
95649868Sbostic 	return(palloc(N_NOT, f_not));
95740947Sbostic }
95840947Sbostic 
95940947Sbostic /*
96040947Sbostic  * expression -o expression functions --
96140947Sbostic  *
96240947Sbostic  *	Alternation of primaries; the OR operator.  The second expression is
96340947Sbostic  * not evaluated if the first expression is true.
96440947Sbostic  */
96540947Sbostic f_or(plan, entry)
96640947Sbostic 	PLAN *plan;
96740947Sbostic 	FTSENT *entry;
96840947Sbostic {
96940947Sbostic 	register PLAN *p;
97040947Sbostic 	register int state;
97140947Sbostic 
97240947Sbostic 	for (p = plan->p_data[0];
97340947Sbostic 	    p && (state = (p->eval)(p, entry)); p = p->next);
97440947Sbostic 
97540947Sbostic 	if (state)
97642255Sbostic 		return(1);
97740947Sbostic 
97840947Sbostic 	for (p = plan->p_data[1];
97940947Sbostic 	    p && (state = (p->eval)(p, entry)); p = p->next);
98040947Sbostic 	return(state);
98140947Sbostic }
98240947Sbostic 
98340947Sbostic PLAN *
98440947Sbostic c_or()
98540947Sbostic {
98649868Sbostic 	return(palloc(N_OR, f_or));
98749868Sbostic }
98849868Sbostic 
98949868Sbostic static PLAN *
99049868Sbostic palloc(t, f)
99149868Sbostic 	enum ntype t;
99249868Sbostic 	int (*f)();
99349868Sbostic {
99440947Sbostic 	PLAN *new;
99540947Sbostic 
99649868Sbostic 	if (new = malloc(sizeof(PLAN))) {
99749868Sbostic 		new->type = t;
99849868Sbostic 		new->eval = f;
99949868Sbostic 		new->flags = 0;
100049868Sbostic 		new->next = NULL;
100149868Sbostic 		return(new);
100249868Sbostic 	}
100349868Sbostic 	err("%s", strerror(errno));
100449868Sbostic 	/* NOTREACHED */
100540947Sbostic }
1006