xref: /original-bsd/usr.bin/find/find.c (revision 95b555db)
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Cimarron D. Taylor of the University of California, Berkeley.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 char copyright[] =
13 "@(#) Copyright (c) 1990 The Regents of the University of California.\n\
14  All rights reserved.\n";
15 #endif /* not lint */
16 
17 #ifndef lint
18 static char sccsid[] = "@(#)find.c	4.37 (Berkeley) 04/27/91";
19 #endif /* not lint */
20 
21 #include <sys/param.h>
22 #include <sys/stat.h>
23 #include <sys/errno.h>
24 #include <time.h>
25 #include <fts.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include "find.h"
30 
31 FTS *tree;			/* pointer to top of FTS hierarchy */
32 time_t now;			/* time find was run */
33 				/* options for the ftsopen(3) call */
34 int ftsoptions = FTS_NOSTAT|FTS_PHYSICAL;
35 int isdeprecated;		/* using deprecated syntax */
36 int isdepth;			/* do directories on post-order visit */
37 int isoutput;			/* user specified output operator */
38 int isrelative;			/* can do -exec/ok on relative path */
39 int isxargs;			/* don't permit xargs delimiting chars */
40 
41 main(argc, argv)
42 	int argc;
43 	char **argv;
44 {
45 	PLAN *plan;
46 	char **p, **paths;
47 	PLAN *find_formplan();
48 	time_t time();
49 	void newsyntax(), oldsyntax();
50 
51 	(void)time(&now);			/* initialize the time-of-day */
52 
53 	if (argc < 2)
54 		usage();
55 
56 	paths = argv;
57 
58 	/*
59 	 * if arguments start with an option, treat it like new syntax;
60 	 * otherwise, if has a "-option" anywhere (which isn't an argument
61 	 * to another command) treat it as old syntax.
62 	 */
63 	if (argv[1][0] != '-')
64 		for (p = argv + 1; *p; ++p) {
65 			if (!strcmp(*p, "exec") || !strcmp(*p, "ok")) {
66 				while (p[1] && strcmp(*++p, ";"));
67 				continue;
68 			}
69 			if (**p == '-') {
70 				isdeprecated = 1;
71 				oldsyntax(&argv);
72 				break;
73 			}
74 		}
75 	if (!isdeprecated)
76 		newsyntax(argc, &argv);
77 
78 	plan = find_formplan(argv);		/* execution plan */
79 	find_execute(plan, paths);
80 }
81 
82 /*
83  * find_formplan --
84  *	process the command line and create a "plan" corresponding to the
85  *	command arguments.
86  */
87 PLAN *
88 find_formplan(argv)
89 	char **argv;
90 {
91 	PLAN *plan, *tail, *new;
92 	PLAN *c_print(), *find_create(), *not_squish(), *or_squish();
93 	PLAN *paren_squish();
94 
95 	/*
96 	 * for each argument in the command line, determine what kind of node
97 	 * it is, create the appropriate node type and add the new plan node
98 	 * to the end of the existing plan.  The resulting plan is a linked
99 	 * list of plan nodes.  For example, the string:
100 	 *
101 	 *	% find . -name foo -newer bar -print
102 	 *
103 	 * results in the plan:
104 	 *
105 	 *	[-name foo]--> [-newer bar]--> [-print]
106 	 *
107 	 * in this diagram, `[-name foo]' represents the plan node generated
108 	 * by c_name() with an argument of foo and `-->' represents the
109 	 * plan->next pointer.
110 	 */
111 	for (plan = NULL; *argv;) {
112 		if (!(new = find_create(&argv)))
113 			continue;
114 		if (plan == NULL)
115 			tail = plan = new;
116 		else {
117 			tail->next = new;
118 			tail = new;
119 		}
120 	}
121 
122 	/*
123 	 * if the user didn't specify one of -print, -ok or -exec, then -print
124 	 * is assumed so we add a -print node on the end.  It is possible that
125 	 * the user might want the -print someplace else on the command line,
126 	 * but there's no way to know that.
127 	 */
128 	if (!isoutput) {
129 		new = c_print();
130 		if (plan == NULL)
131 			tail = plan = new;
132 		else {
133 			tail->next = new;
134 			tail = new;
135 		}
136 	}
137 
138 	/*
139 	 * the command line has been completely processed into a search plan
140 	 * except for the (, ), !, and -o operators.  Rearrange the plan so
141 	 * that the portions of the plan which are affected by the operators
142 	 * are moved into operator nodes themselves.  For example:
143 	 *
144 	 *	[!]--> [-name foo]--> [-print]
145 	 *
146 	 * becomes
147 	 *
148 	 *	[! [-name foo] ]--> [-print]
149 	 *
150 	 * and
151 	 *
152 	 *	[(]--> [-depth]--> [-name foo]--> [)]--> [-print]
153 	 *
154 	 * becomes
155 	 *
156 	 *	[expr [-depth]-->[-name foo] ]--> [-print]
157 	 *
158 	 * operators are handled in order of precedence.
159 	 */
160 
161 	plan = paren_squish(plan);		/* ()'s */
162 	plan = not_squish(plan);		/* !'s */
163 	plan = or_squish(plan);			/* -o's */
164 	return(plan);
165 }
166 
167 /*
168  * find_execute --
169  *	take a search plan and an array of search paths and executes the plan
170  *	over all FTSENT's returned for the given search paths.
171  */
172 find_execute(plan, paths)
173 	PLAN *plan;		/* search plan */
174 	char **paths;		/* array of pathnames to traverse */
175 {
176 	register FTSENT *entry;
177 	PLAN *p;
178 
179 	if (!(tree = fts_open(paths, ftsoptions, (int (*)())NULL))) {
180 		error("ftsopen", errno);
181 		exit(1);
182 	}
183 
184 	while (entry = fts_read(tree)) {
185 		switch(entry->fts_info) {
186 		case FTS_D:
187 			if (isdepth)
188 				continue;
189 			break;
190 		case FTS_DP:
191 			if (!isdepth)
192 				continue;
193 			break;
194 		case FTS_DNR:
195 		case FTS_ERR:
196 		case FTS_NS:
197 			error(entry->fts_path, errno);
198 			continue;
199 		}
200 
201 #define	BADCH	" \t\n\\'\""
202 		if (isxargs && strpbrk(entry->fts_path, BADCH)) {
203 			(void)fprintf(stderr,
204 			    "find: illegal path: %s\n", entry->fts_path);
205 			continue;
206 		}
207 
208 		/*
209 		 * call all the functions in the execution plan until one is
210 		 * false or all have been executed.  This is where we do all
211 		 * the work specified by the user on the command line.
212 		 */
213 		for (p = plan; p && (p->eval)(p, entry); p = p->next);
214 	}
215 	(void)fts_close(tree);
216 }
217