Home | History | Annotate | Line # | Download | only in find
find.c revision 1.18.2.1.2.1
      1  1.18.2.1.2.1      reed /*	$NetBSD: find.c,v 1.18.2.1.2.1 2005/10/11 22:56:27 reed Exp $	*/
      2           1.8       tls 
      3           1.1       cgd /*-
      4          1.10       mrg  * Copyright (c) 1991, 1993, 1994
      5           1.5       jtc  *	The Regents of the University of California.  All rights reserved.
      6           1.1       cgd  *
      7           1.1       cgd  * This code is derived from software contributed to Berkeley by
      8           1.1       cgd  * Cimarron D. Taylor of the University of California, Berkeley.
      9           1.1       cgd  *
     10           1.1       cgd  * Redistribution and use in source and binary forms, with or without
     11           1.1       cgd  * modification, are permitted provided that the following conditions
     12           1.1       cgd  * are met:
     13           1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     14           1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     15           1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     16           1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     17           1.1       cgd  *    documentation and/or other materials provided with the distribution.
     18          1.18       agc  * 3. Neither the name of the University nor the names of its contributors
     19           1.1       cgd  *    may be used to endorse or promote products derived from this software
     20           1.1       cgd  *    without specific prior written permission.
     21           1.1       cgd  *
     22           1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23           1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24           1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25           1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26           1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27           1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28           1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29           1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30           1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31           1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32           1.1       cgd  * SUCH DAMAGE.
     33           1.1       cgd  */
     34           1.1       cgd 
     35           1.9     lukem #include <sys/cdefs.h>
     36           1.1       cgd #ifndef lint
     37           1.9     lukem #if 0
     38          1.10       mrg static char sccsid[] = "from: @(#)find.c	8.5 (Berkeley) 8/5/94";
     39           1.9     lukem #else
     40  1.18.2.1.2.1      reed __RCSID("$NetBSD: find.c,v 1.18.2.1.2.1 2005/10/11 22:56:27 reed Exp $");
     41           1.9     lukem #endif
     42           1.1       cgd #endif /* not lint */
     43           1.1       cgd 
     44           1.1       cgd #include <sys/types.h>
     45           1.1       cgd #include <sys/stat.h>
     46           1.5       jtc 
     47           1.5       jtc #include <err.h>
     48           1.5       jtc #include <errno.h>
     49           1.1       cgd #include <fts.h>
     50          1.17      yamt #include <signal.h>
     51           1.1       cgd #include <stdio.h>
     52           1.1       cgd #include <string.h>
     53           1.1       cgd #include <stdlib.h>
     54           1.5       jtc 
     55           1.1       cgd #include "find.h"
     56           1.1       cgd 
     57          1.12     itohy static int ftscompare __P((const FTSENT **, const FTSENT **));
     58          1.12     itohy 
     59          1.17      yamt static void sig_lock __P((sigset_t *));
     60          1.17      yamt static void sig_unlock __P((const sigset_t *));
     61          1.17      yamt 
     62           1.1       cgd /*
     63           1.1       cgd  * find_formplan --
     64           1.1       cgd  *	process the command line and create a "plan" corresponding to the
     65           1.1       cgd  *	command arguments.
     66           1.1       cgd  */
     67           1.1       cgd PLAN *
     68           1.1       cgd find_formplan(argv)
     69           1.1       cgd 	char **argv;
     70           1.1       cgd {
     71           1.1       cgd 	PLAN *plan, *tail, *new;
     72           1.1       cgd 
     73           1.1       cgd 	/*
     74           1.1       cgd 	 * for each argument in the command line, determine what kind of node
     75           1.1       cgd 	 * it is, create the appropriate node type and add the new plan node
     76           1.1       cgd 	 * to the end of the existing plan.  The resulting plan is a linked
     77           1.1       cgd 	 * list of plan nodes.  For example, the string:
     78           1.1       cgd 	 *
     79           1.1       cgd 	 *	% find . -name foo -newer bar -print
     80           1.1       cgd 	 *
     81           1.1       cgd 	 * results in the plan:
     82           1.1       cgd 	 *
     83           1.1       cgd 	 *	[-name foo]--> [-newer bar]--> [-print]
     84           1.1       cgd 	 *
     85           1.1       cgd 	 * in this diagram, `[-name foo]' represents the plan node generated
     86           1.1       cgd 	 * by c_name() with an argument of foo and `-->' represents the
     87           1.1       cgd 	 * plan->next pointer.
     88           1.1       cgd 	 */
     89           1.5       jtc 	for (plan = tail = NULL; *argv;) {
     90           1.1       cgd 		if (!(new = find_create(&argv)))
     91           1.1       cgd 			continue;
     92           1.1       cgd 		if (plan == NULL)
     93           1.1       cgd 			tail = plan = new;
     94           1.1       cgd 		else {
     95           1.1       cgd 			tail->next = new;
     96           1.1       cgd 			tail = new;
     97           1.1       cgd 		}
     98           1.1       cgd 	}
     99          1.12     itohy 
    100           1.1       cgd 	/*
    101  1.18.2.1.2.1      reed 	 * if the user didn't specify one of -print, -ok, -fprint, or -exec,
    102  1.18.2.1.2.1      reed 	 * then -print is assumed so we bracket the current expression with
    103  1.18.2.1.2.1      reed 	 * parens, if necessary, and add a -print node on the end.
    104           1.1       cgd 	 */
    105           1.1       cgd 	if (!isoutput) {
    106           1.6       cgd 		if (plan == NULL) {
    107          1.11  christos 			new = c_print(NULL, 0);
    108           1.1       cgd 			tail = plan = new;
    109           1.6       cgd 		} else {
    110          1.11  christos 			new = c_openparen(NULL, 0);
    111           1.6       cgd 			new->next = plan;
    112           1.6       cgd 			plan = new;
    113          1.11  christos 			new = c_closeparen(NULL, 0);
    114           1.6       cgd 			tail->next = new;
    115           1.6       cgd 			tail = new;
    116          1.11  christos 			new = c_print(NULL, 0);
    117           1.1       cgd 			tail->next = new;
    118           1.1       cgd 			tail = new;
    119           1.1       cgd 		}
    120           1.1       cgd 	}
    121          1.12     itohy 
    122           1.1       cgd 	/*
    123           1.1       cgd 	 * the command line has been completely processed into a search plan
    124           1.1       cgd 	 * except for the (, ), !, and -o operators.  Rearrange the plan so
    125           1.1       cgd 	 * that the portions of the plan which are affected by the operators
    126           1.1       cgd 	 * are moved into operator nodes themselves.  For example:
    127           1.1       cgd 	 *
    128           1.1       cgd 	 *	[!]--> [-name foo]--> [-print]
    129           1.1       cgd 	 *
    130           1.1       cgd 	 * becomes
    131           1.1       cgd 	 *
    132           1.1       cgd 	 *	[! [-name foo] ]--> [-print]
    133           1.1       cgd 	 *
    134           1.1       cgd 	 * and
    135           1.1       cgd 	 *
    136           1.1       cgd 	 *	[(]--> [-depth]--> [-name foo]--> [)]--> [-print]
    137           1.1       cgd 	 *
    138           1.1       cgd 	 * becomes
    139           1.1       cgd 	 *
    140           1.1       cgd 	 *	[expr [-depth]-->[-name foo] ]--> [-print]
    141           1.1       cgd 	 *
    142           1.1       cgd 	 * operators are handled in order of precedence.
    143           1.1       cgd 	 */
    144           1.1       cgd 
    145           1.1       cgd 	plan = paren_squish(plan);		/* ()'s */
    146           1.1       cgd 	plan = not_squish(plan);		/* !'s */
    147           1.1       cgd 	plan = or_squish(plan);			/* -o's */
    148           1.5       jtc 	return (plan);
    149           1.1       cgd }
    150          1.12     itohy 
    151          1.12     itohy static int
    152          1.12     itohy ftscompare(e1, e2)
    153          1.12     itohy 	const FTSENT **e1, **e2;
    154          1.12     itohy {
    155          1.14     enami 
    156          1.14     enami 	return (strcoll((*e1)->fts_name, (*e2)->fts_name));
    157          1.12     itohy }
    158          1.12     itohy 
    159          1.17      yamt static void
    160          1.17      yamt sig_lock(s)
    161          1.17      yamt 	sigset_t *s;
    162          1.17      yamt {
    163          1.17      yamt 	sigset_t new;
    164          1.17      yamt 
    165          1.17      yamt 	sigemptyset(&new);
    166          1.17      yamt 	sigaddset(&new, SIGINFO); /* block SIGINFO */
    167          1.17      yamt 	sigprocmask(SIG_BLOCK, &new, s);
    168          1.17      yamt }
    169          1.17      yamt 
    170          1.17      yamt static void
    171          1.17      yamt sig_unlock(s)
    172          1.17      yamt 	const sigset_t *s;
    173          1.17      yamt {
    174          1.17      yamt 
    175          1.17      yamt 	sigprocmask(SIG_SETMASK, s, NULL);
    176          1.17      yamt }
    177          1.17      yamt 
    178           1.1       cgd FTS *tree;			/* pointer to top of FTS hierarchy */
    179          1.16      yamt FTSENT *g_entry;		/* shared with SIGINFO handler */
    180           1.1       cgd 
    181           1.1       cgd /*
    182           1.1       cgd  * find_execute --
    183           1.1       cgd  *	take a search plan and an array of search paths and executes the plan
    184           1.1       cgd  *	over all FTSENT's returned for the given search paths.
    185           1.1       cgd  */
    186          1.10       mrg int
    187           1.1       cgd find_execute(plan, paths)
    188           1.1       cgd 	PLAN *plan;		/* search plan */
    189           1.1       cgd 	char **paths;		/* array of pathnames to traverse */
    190           1.1       cgd {
    191           1.1       cgd 	PLAN *p;
    192          1.10       mrg 	int rval;
    193          1.17      yamt 	sigset_t s;
    194          1.12     itohy 
    195          1.12     itohy 	if (!(tree = fts_open(paths, ftsoptions, issort ? ftscompare : NULL)))
    196           1.5       jtc 		err(1, "ftsopen");
    197           1.1       cgd 
    198          1.17      yamt 	sig_lock(&s);
    199          1.17      yamt 	for (rval = 0; (g_entry = fts_read(tree)) != NULL; sig_lock(&s)) {
    200          1.17      yamt 		sig_unlock(&s);
    201          1.16      yamt 		switch (g_entry->fts_info) {
    202           1.1       cgd 		case FTS_D:
    203           1.1       cgd 			if (isdepth)
    204           1.1       cgd 				continue;
    205           1.1       cgd 			break;
    206           1.1       cgd 		case FTS_DP:
    207           1.1       cgd 			if (!isdepth)
    208           1.1       cgd 				continue;
    209           1.1       cgd 			break;
    210           1.1       cgd 		case FTS_DNR:
    211           1.1       cgd 		case FTS_ERR:
    212           1.1       cgd 		case FTS_NS:
    213           1.5       jtc 			(void)fflush(stdout);
    214          1.10       mrg 			warnx("%s: %s",
    215          1.16      yamt 			    g_entry->fts_path, strerror(g_entry->fts_errno));
    216          1.10       mrg 			rval = 1;
    217           1.1       cgd 			continue;
    218           1.1       cgd 		}
    219           1.1       cgd #define	BADCH	" \t\n\\'\""
    220          1.16      yamt 		if (isxargs && strpbrk(g_entry->fts_path, BADCH)) {
    221           1.5       jtc 			(void)fflush(stdout);
    222          1.16      yamt 			warnx("%s: illegal path", g_entry->fts_path);
    223          1.10       mrg 			rval = 1;
    224           1.1       cgd 			continue;
    225           1.1       cgd 		}
    226          1.12     itohy 
    227           1.1       cgd 		/*
    228          1.10       mrg 		 * Call all the functions in the execution plan until one is
    229           1.1       cgd 		 * false or all have been executed.  This is where we do all
    230           1.1       cgd 		 * the work specified by the user on the command line.
    231           1.1       cgd 		 */
    232          1.16      yamt 		for (p = plan; p && (p->eval)(p, g_entry); p = p->next)
    233           1.7       mrg 			;
    234           1.1       cgd 	}
    235          1.17      yamt 	sig_unlock(&s);
    236          1.10       mrg 	if (errno)
    237          1.10       mrg 		err(1, "fts_read");
    238           1.1       cgd 	(void)fts_close(tree);
    239          1.10       mrg 	return (rval);
    240           1.1       cgd }
    241