GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/find/find.c Lines: 50 71 70.4 %
Date: 2017-11-07 Branches: 41 66 62.1 %

Line Branch Exec Source
1
/*	$OpenBSD: find.c,v 1.22 2017/01/04 09:21:26 tb Exp $	*/
2
3
/*-
4
 * Copyright (c) 1991, 1993
5
 *	The Regents of the University of California.  All rights reserved.
6
 *
7
 * This code is derived from software contributed to Berkeley by
8
 * Cimarron D. Taylor of the University of California, Berkeley.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 * 3. Neither the name of the University nor the names of its contributors
19
 *    may be used to endorse or promote products derived from this software
20
 *    without specific prior written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
 * SUCH DAMAGE.
33
 */
34
35
#include <sys/types.h>
36
#include <sys/stat.h>
37
38
#include <err.h>
39
#include <errno.h>
40
#include <fts.h>
41
#include <signal.h>
42
#include <stdio.h>
43
#include <string.h>
44
#include <stdlib.h>
45
#include <unistd.h>
46
47
int	mayexecve;
48
49
#include "find.h"
50
51
/*
52
 * find_formplan --
53
 *	process the command line and create a "plan" corresponding to the
54
 *	command arguments.
55
 */
56
PLAN *
57
find_formplan(char **argv)
58
{
59
	PLAN *plan, *tail, *new;
60
61
	/*
62
	 * for each argument in the command line, determine what kind of node
63
	 * it is, create the appropriate node type and add the new plan node
64
	 * to the end of the existing plan.  The resulting plan is a linked
65
	 * list of plan nodes.  For example, the string:
66
	 *
67
	 *	% find . -name foo -newer bar -print
68
	 *
69
	 * results in the plan:
70
	 *
71
	 *	[-name foo]--> [-newer bar]--> [-print]
72
	 *
73
	 * in this diagram, `[-name foo]' represents the plan node generated
74
	 * by c_name() with an argument of foo and `-->' represents the
75
	 * plan->next pointer.
76
	 */
77
462
	for (plan = tail = NULL; *argv;) {
78
236
		if (!(new = find_create(&argv)))
79
			continue;
80
236
		if (plan == NULL)
81
113
			tail = plan = new;
82
		else {
83
123
			tail->next = new;
84
			tail = new;
85
		}
86
	}
87
88
	/*
89
	 * if the user didn't specify one of -print, -ok or -exec, then -print
90
	 * is assumed so we bracket the current expression with parens, if
91
	 * necessary, and add a -print node on the end.
92
	 */
93
113
	if (!isoutput) {
94
42
		if (plan == NULL) {
95
			new = c_print(NULL, NULL, 0);
96
			tail = plan = new;
97
		} else {
98
42
			new = c_openparen(NULL, NULL, 0);
99
42
			new->next = plan;
100
			plan = new;
101
42
			new = c_closeparen(NULL, NULL, 0);
102
42
			tail->next = new;
103
			tail = new;
104
42
			new = c_print(NULL, NULL, 0);
105
42
			tail->next = new;
106
			tail = new;
107
		}
108
	}
109
110
	/*
111
	 * the command line has been completely processed into a search plan
112
	 * except for the (, ), !, and -o operators.  Rearrange the plan so
113
	 * that the portions of the plan which are affected by the operators
114
	 * are moved into operator nodes themselves.  For example:
115
	 *
116
	 *	[!]--> [-name foo]--> [-print]
117
	 *
118
	 * becomes
119
	 *
120
	 *	[! [-name foo] ]--> [-print]
121
	 *
122
	 * and
123
	 *
124
	 *	[(]--> [-depth]--> [-name foo]--> [)]--> [-print]
125
	 *
126
	 * becomes
127
	 *
128
	 *	[expr [-depth]-->[-name foo] ]--> [-print]
129
	 *
130
	 * operators are handled in order of precedence.
131
	 */
132
133
113
	plan = paren_squish(plan);		/* ()'s */
134
113
	plan = not_squish(plan);		/* !'s */
135
113
	plan = or_squish(plan);			/* -o's */
136
113
	return (plan);
137
}
138
139
FTS *tree;			/* pointer to top of FTS hierarchy */
140
141
/*
142
 * find_execute --
143
 *	take a search plan and an array of search paths and executes the plan
144
 *	over all FTSENT's returned for the given search paths.
145
 */
146
147
FTSENT *entry;			/* shared with SIGINFO handler */
148
149
int
150
find_execute(PLAN *plan,	/* search plan */
151
    char **paths)		/* array of pathnames to traverse */
152
{
153
226
	sigset_t fullset, oset;
154
	int r, rval;
155
	PLAN *p;
156
157
113
	if (mayexecve == 0) {
158
108
		if (isdelete) {
159
			if (pledge("stdio rpath cpath getpw flock wpath", NULL) == -1)
160
				err(1, "pledge");
161
		} else {
162
108
			if (pledge("stdio rpath getpw flock cpath wpath", NULL) == -1)
163
				err(1, "pledge");
164
		}
165
	} else {
166
5
		if (isdelete) {
167
			if (pledge("stdio rpath cpath getpw proc exec flock wpath", NULL)
168
			    == -1)
169
				err(1, "pledge");
170
		} else {
171
5
			if (pledge("stdio rpath getpw proc exec flock cpath wpath", NULL) == -1)
172
				err(1, "pledge");
173
		}
174
	}
175
176
	rval = 0;
177
178
113
	if (!(tree = fts_open(paths, ftsoptions, NULL)))
179
		err(1, "fts_open");
180
181
113
	sigfillset(&fullset);
182
113
	for (;;) {
183
2895682
		(void)sigprocmask(SIG_BLOCK, &fullset, &oset);
184
2895682
		entry = fts_read(tree);
185
2895682
		(void)sigprocmask(SIG_SETMASK, &oset, NULL);
186
2895682
		if (entry == NULL) {
187
113
			if (errno)
188
				err(1, "fts_read");
189
			break;
190
		}
191
192

3115492
		switch (entry->fts_info) {
193
		case FTS_D:
194
219923
			if (isdepth)
195
				continue;
196
			break;
197
		case FTS_DP:
198
219923
			if (!isdepth)
199
				continue;
200
			break;
201
		case FTS_DNR:
202
		case FTS_ERR:
203
		case FTS_NS:
204
			(void)fflush(stdout);
205
			warnc(entry->fts_errno, "%s", entry->fts_path);
206
			rval = 1;
207
			continue;
208
		}
209
#define	BADCH	" \t\n\\'\""
210

2675646
		if (isxargs && strpbrk(entry->fts_path, BADCH)) {
211
			(void)fflush(stdout);
212
			warnx("%s: illegal path", entry->fts_path);
213
			rval = 1;
214
			continue;
215
		}
216
217
		/*
218
		 * Call all the functions in the execution plan until one is
219
		 * false or all have been executed.  This is where we do all
220
		 * the work specified by the user on the command line.
221
		 */
222

8398861
		for (p = plan; p && (p->eval)(p, entry); p = p->next)
223
		    ;
224
	}
225
113
	(void)fts_close(tree);
226
227
	/*
228
	 * Cleanup any plans with leftover state.
229
	 * Keep the last non-zero return value.
230
	 */
231
113
	if ((r = find_traverse(plan, plan_cleanup, NULL)) != 0)
232
		rval = r;
233
113
	return (rval);
234
113
}
235
236
/*
237
 * find_traverse --
238
 *	traverse the plan tree and execute func() on all plans.  This
239
 *	does not evaluate each plan's eval() function; it is intended
240
 *	for operations that must run on all plans, such as state
241
 *	cleanup.
242
 *
243
 *	If any func() returns non-zero, then so will find_traverse().
244
 */
245
int
246
find_traverse(PLAN *plan, int (*func)(PLAN *, void *), void *arg)
247
{
248
	PLAN *p;
249
	int r, rval;
250
251
	rval = 0;
252
1116
	for (p = plan; p; p = p->next) {
253
303
		if ((r = func(p, arg)) != 0)
254
			rval = r;
255

561
		if (p->type == N_EXPR || p->type == N_OR) {
256
51
			if (p->p_data[0])
257
102
				if ((r = find_traverse(p->p_data[0],
258
51
					    func, arg)) != 0)
259
					rval = r;
260
51
			if (p->p_data[1])
261
12
				if ((r = find_traverse(p->p_data[1],
262
6
					    func, arg)) != 0)
263
					rval = r;
264
		}
265
	}
266
170
	return rval;
267
}