GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/find/find.c Lines: 51 71 71.8 %
Date: 2016-12-06 Branches: 33 52 63.5 %

Line Branch Exec Source
1
/*	$OpenBSD: find.c,v 1.20 2015/10/10 20:35:00 deraadt 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
6
{
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
23
	for (plan = tail = NULL; *argv;) {
78
11
		if (!(new = find_create(&argv)))
79
			continue;
80
11
		if (plan == NULL)
81
6
			tail = plan = new;
82
		else {
83
5
			tail->next = new;
84
5
			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
6
	if (!isoutput) {
94
4
		if (plan == NULL) {
95
			new = c_print(NULL, NULL, 0);
96
			tail = plan = new;
97
		} else {
98
4
			new = c_openparen(NULL, NULL, 0);
99
4
			new->next = plan;
100
4
			plan = new;
101
4
			new = c_closeparen(NULL, NULL, 0);
102
4
			tail->next = new;
103
4
			tail = new;
104
4
			new = c_print(NULL, NULL, 0);
105
4
			tail->next = new;
106
4
			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
6
	plan = paren_squish(plan);		/* ()'s */
134
6
	plan = not_squish(plan);		/* !'s */
135
6
	plan = or_squish(plan);			/* -o's */
136
6
	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
6
{
153
	sigset_t fullset, oset;
154
	int r, rval;
155
	PLAN *p;
156
157
6
	if (mayexecve == 0)
158
6
		if (pledge("stdio rpath getpw wpath cpath", NULL) == -1)
159
			err(1, "pledge");
160
161
6
	rval = 0;
162
163
6
	if (!(tree = fts_open(paths, ftsoptions, NULL)))
164
		err(1, "fts_open");
165
166
6
	sigfillset(&fullset);
167
	for (;;) {
168
101362
		(void)sigprocmask(SIG_BLOCK, &fullset, &oset);
169
101362
		entry = fts_read(tree);
170
101362
		(void)sigprocmask(SIG_SETMASK, &oset, NULL);
171
101362
		if (entry == NULL) {
172
6
			if (errno)
173
				err(1, "fts_read");
174
			break;
175
		}
176
177

101356
		switch (entry->fts_info) {
178
		case FTS_D:
179
10030
			if (isdepth)
180
				continue;
181
			break;
182
		case FTS_DP:
183
10030
			if (!isdepth)
184
10030
				continue;
185
			break;
186
		case FTS_DNR:
187
		case FTS_ERR:
188
		case FTS_NS:
189
			(void)fflush(stdout);
190
			warnc(entry->fts_errno, "%s", entry->fts_path);
191
			rval = 1;
192
			continue;
193
		}
194
#define	BADCH	" \t\n\\'\""
195

91326
		if (isxargs && strpbrk(entry->fts_path, BADCH)) {
196
			(void)fflush(stdout);
197
			warnx("%s: illegal path", entry->fts_path);
198
			rval = 1;
199
			continue;
200
		}
201
202
		/*
203
		 * Call all the functions in the execution plan until one is
204
		 * false or all have been executed.  This is where we do all
205
		 * the work specified by the user on the command line.
206
		 */
207

91326
		for (p = plan; p && (p->eval)(p, entry); p = p->next)
208
		    ;
209
	}
210
6
	(void)fts_close(tree);
211
212
	/*
213
	 * Cleanup any plans with leftover state.
214
	 * Keep the last non-zero return value.
215
	 */
216
6
	if ((r = find_traverse(plan, plan_cleanup, NULL)) != 0)
217
		rval = r;
218
6
	return (rval);
219
}
220
221
/*
222
 * find_traverse --
223
 *	traverse the plan tree and execute func() on all plans.  This
224
 *	does not evaluate each plan's eval() function; it is intended
225
 *	for operations that must run on all plans, such as state
226
 *	cleanup.
227
 *
228
 *	If any func() returns non-zero, then so will find_traverse().
229
 */
230
int
231
find_traverse(PLAN *plan, int (*func)(PLAN *, void *), void *arg)
232
10
{
233
	PLAN *p;
234
	int r, rval;
235
236
10
	rval = 0;
237
29
	for (p = plan; p; p = p->next) {
238
19
		if ((r = func(p, arg)) != 0)
239
			rval = r;
240
19
		if (p->type == N_EXPR || p->type == N_OR) {
241
4
			if (p->p_data[0])
242
4
				if ((r = find_traverse(p->p_data[0],
243
					    func, arg)) != 0)
244
					rval = r;
245
4
			if (p->p_data[1])
246
				if ((r = find_traverse(p->p_data[1],
247
					    func, arg)) != 0)
248
					rval = r;
249
		}
250
	}
251
10
	return rval;
252
}