string.h is ANSI C include file
[unix-history] / usr / src / usr.bin / find / find.c
CommitLineData
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
12char 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
38dde0cd 18static char sccsid[] = "@(#)find.c 4.27 (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>
38dde0cd 25#include <string.h>
45fc66f9
KB
26#include <errno.h>
27#include "find.h"
28
29FTS *tree; /* pointer to top of FTS hierarchy */
30time_t now; /* time find was run */
31dev_t curdev = (dev_t)-1; /* device number of current tree */
32int ftsoptions; /* options passed to ftsopen() */
202dd4ce 33int deprecated; /* old or new syntax */
45fc66f9
KB
34int depth; /* set by -depth option */
35int output_specified; /* one of -print, -ok or -exec was specified */
36int xdev; /* set by -xdev option */
46b257b1 37
46b257b1
KM
38main(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 */
78PLAN *
79find_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 */
162find_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}