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