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