find.c revision 116333
150565Sphk/*- 250565Sphk * Copyright (c) 1991, 1993, 1994 350565Sphk * The Regents of the University of California. All rights reserved. 450565Sphk * 550565Sphk * This code is derived from software contributed to Berkeley by 650565Sphk * Cimarron D. Taylor of the University of California, Berkeley. 750565Sphk * 850565Sphk * Redistribution and use in source and binary forms, with or without 950565Sphk * modification, are permitted provided that the following conditions 1050565Sphk * are met: 1150565Sphk * 1. Redistributions of source code must retain the above copyright 1250565Sphk * notice, this list of conditions and the following disclaimer. 1350565Sphk * 2. Redistributions in binary form must reproduce the above copyright 1450565Sphk * notice, this list of conditions and the following disclaimer in the 1550565Sphk * documentation and/or other materials provided with the distribution. 1651111Sjulian * 3. All advertising materials mentioning features or use of this software 1760041Sphk * must display the following acknowledgement: 1850565Sphk * This product includes software developed by the University of 1950565Sphk * California, Berkeley and its contributors. 2050565Sphk * 4. Neither the name of the University nor the names of its contributors 2161953Snbm * may be used to endorse or promote products derived from this software 2250728Sphk * without specific prior written permission. 2350565Sphk * 2450565Sphk * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2550565Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2650565Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2750565Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2850565Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2950565Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3050565Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3161717Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3261717Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3350565Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3462617Simp * SUCH DAMAGE. 3562617Simp */ 3662617Simp 3762617Simp#ifndef lint 3862617Simp#if 0 3962617Simpstatic char sccsid[] = "@(#)find.c 8.5 (Berkeley) 8/5/94"; 4062617Simp#else 4162617Simp#endif 4262617Simp#endif /* not lint */ 4362617Simp 4462617Simp#include <sys/cdefs.h> 4550565Sphk__FBSDID("$FreeBSD: head/usr.bin/find/find.c 116333 2003-06-14 13:00:21Z markm $"); 4651215Sphk 4750565Sphk#include <sys/types.h> 4850565Sphk#include <sys/stat.h> 4950565Sphk 5051198Sphk#include <err.h> 5151198Sphk#include <errno.h> 5250565Sphk#include <fts.h> 5351198Sphk#include <regex.h> 5451215Sphk#include <stdio.h> 5551215Sphk#include <stdlib.h> 5651215Sphk#include <string.h> 5751215Sphk 5851215Sphk#include "find.h" 5951215Sphk 6051215Sphkstatic int find_compare(const FTSENT * const *s1, const FTSENT * const *s2); 6150565Sphk 6250565Sphk/* 6353437Sjkh * find_compare -- 6453437Sjkh * tell fts_open() how to order the traversal of the hierarchy. 6551243Sphk * This variant gives lexicographical order, i.e., alphabetical 6661717Sphk * order within each directory. 6750565Sphk */ 6850565Sphkstatic int 6950565Sphkfind_compare(const FTSENT * const *s1, const FTSENT * const *s2) 7052917Sphk{ 7151215Sphk 7261717Sphk return (strcoll((*s1)->fts_name, (*s2)->fts_name)); 7350565Sphk} 7450565Sphk 7550565Sphk/* 7650728Sphk * find_formplan -- 7750728Sphk * process the command line and create a "plan" corresponding to the 7850728Sphk * command arguments. 7950728Sphk */ 8050728SphkPLAN * 8150728Sphkfind_formplan(char *argv[]) 8250728Sphk{ 8350728Sphk PLAN *plan, *tail, *new; 8450728Sphk 8550728Sphk /* 8650728Sphk * for each argument in the command line, determine what kind of node 8750728Sphk * it is, create the appropriate node type and add the new plan node 8850728Sphk * to the end of the existing plan. The resulting plan is a linked 8950728Sphk * list of plan nodes. For example, the string: 9050728Sphk * 9150728Sphk * % find . -name foo -newer bar -print 9250728Sphk * 9350728Sphk * results in the plan: 9450728Sphk * 9550728Sphk * [-name foo]--> [-newer bar]--> [-print] 9650728Sphk * 9750728Sphk * in this diagram, `[-name foo]' represents the plan node generated 9850728Sphk * by c_name() with an argument of foo and `-->' represents the 9950728Sphk * plan->next pointer. 10050728Sphk */ 10150728Sphk for (plan = tail = NULL; *argv;) { 10250728Sphk if (!(new = find_create(&argv))) 10350728Sphk continue; 10450728Sphk if (plan == NULL) 10550728Sphk tail = plan = new; 10657325Ssos else { 10757325Ssos tail->next = new; 10850728Sphk tail = new; 10950728Sphk } 11050565Sphk } 11156767Sphk 11250565Sphk /* 11361717Sphk * if the user didn't specify one of -print, -ok or -exec, then -print 11461717Sphk * is assumed so we bracket the current expression with parens, if 11557325Ssos * necessary, and add a -print node on the end. 11657325Ssos */ 11750565Sphk if (!isoutput) { 11850565Sphk OPTION *p; 11950565Sphk char **argv1 = 0; 12061717Sphk 12161717Sphk if (plan == NULL) { 12261717Sphk p = lookup_option("-print"); 12361717Sphk new = (p->create)(p, &argv1); 12461717Sphk tail = plan = new; 12561717Sphk } else { 12661717Sphk p = lookup_option("("); 12761717Sphk new = (p->create)(p, &argv1); 12861717Sphk new->next = plan; 12961953Snbm plan = new; 13062573Sphk p = lookup_option(")"); 13161953Snbm new = (p->create)(p, &argv1); 13261953Snbm tail->next = new; 13361953Snbm tail = new; 13461953Snbm p = lookup_option("-print"); 13561953Snbm new = (p->create)(p, &argv1); 13661953Snbm tail->next = new; 13761953Snbm tail = new; 13861953Snbm } 13961953Snbm } 14061953Snbm 14161953Snbm /* 14261953Snbm * the command line has been completely processed into a search plan 14361953Snbm * except for the (, ), !, and -o operators. Rearrange the plan so 14461953Snbm * that the portions of the plan which are affected by the operators 14561953Snbm * are moved into operator nodes themselves. For example: 14661953Snbm * 14761953Snbm * [!]--> [-name foo]--> [-print] 14861953Snbm * 14961953Snbm * becomes 15061953Snbm * 15161953Snbm * [! [-name foo] ]--> [-print] 15261953Snbm * 15361953Snbm * and 15461953Snbm * 15561953Snbm * [(]--> [-depth]--> [-name foo]--> [)]--> [-print] 15661953Snbm * 15750728Sphk * becomes 15850728Sphk * 15950728Sphk * [expr [-depth]-->[-name foo] ]--> [-print] 16050728Sphk * 16150565Sphk * operators are handled in order of precedence. 16250565Sphk */ 16350565Sphk 16450565Sphk plan = paren_squish(plan); /* ()'s */ 16550565Sphk plan = not_squish(plan); /* !'s */ 16650565Sphk plan = or_squish(plan); /* -o's */ 16750565Sphk return (plan); 16850728Sphk} 16950565Sphk 17050728SphkFTS *tree; /* pointer to top of FTS hierarchy */ 17150565Sphk 17250565Sphk/* 17350565Sphk * find_execute -- 17450728Sphk * take a search plan and an array of search paths and executes the plan 17552917Sphk * over all FTSENT's returned for the given search paths. 17652917Sphk */ 17754815Sphkint 17854815Sphkfind_execute(PLAN *plan, char *paths[]) 17954815Sphk{ 18052917Sphk FTSENT *entry; 18152917Sphk PLAN *p; 18252917Sphk int rval; 18351860Sphk 18451878Ssos tree = fts_open(paths, ftsoptions, (issort ? find_compare : NULL)); 18551878Ssos if (tree == NULL) 18651826Sphk err(1, "ftsopen"); 18751860Sphk 18851826Sphk for (rval = 0; (entry = fts_read(tree)) != NULL;) { 18951826Sphk switch (entry->fts_info) { 19062617Simp case FTS_D: 19150728Sphk if (isdepth) 19250728Sphk continue; 19352917Sphk break; 19450728Sphk case FTS_DP: 19552917Sphk if (!isdepth) 19650565Sphk continue; 19750728Sphk break; 19851924Sphk case FTS_DNR: 19952917Sphk case FTS_ERR: 20052917Sphk case FTS_NS: 20152917Sphk (void)fflush(stdout); 20252917Sphk warnx("%s: %s", 20352917Sphk entry->fts_path, strerror(entry->fts_errno)); 20452917Sphk rval = 1; 20550728Sphk continue; 20650565Sphk#ifdef FTS_W 20750565Sphk case FTS_W: 20850565Sphk continue; 20950565Sphk#endif /* FTS_W */ 21050565Sphk } 21150565Sphk#define BADCH " \t\n\\'\"" 21250565Sphk if (isxargs && strpbrk(entry->fts_path, BADCH)) { 21350565Sphk (void)fflush(stdout); 21462617Simp warnx("%s: illegal path", entry->fts_path); 21550565Sphk rval = 1; 21650565Sphk continue; 21762617Simp } 21862617Simp 21951822Sphk if (mindepth != -1 && entry->fts_level < mindepth) 22051826Sphk continue; 22151924Sphk 22251826Sphk /* 22350565Sphk * Call all the functions in the execution plan until one is 22450565Sphk * false or all have been executed. This is where we do all 22550565Sphk * the work specified by the user on the command line. 22650565Sphk */ 22759249Sphk for (p = plan; p && (p->execute)(p, entry); p = p->next); 22850565Sphk 22950565Sphk if (maxdepth != -1 && entry->fts_level >= maxdepth) { 23050565Sphk if (fts_set(tree, entry, FTS_SKIP)) 23150565Sphk err(1, "%s", entry->fts_path); 23262617Simp continue; 23362617Simp } 23462617Simp } 23562617Simp /* Finish any pending -exec ... {} + functions. */ 23650565Sphk for (p = plan; p != NULL; p = p->next) 23750565Sphk if (p->execute == f_exec && p->flags & F_EXECPLUS) 23859249Sphk (p->execute)(p, NULL); 23959249Sphk if (errno) 24050565Sphk err(1, "fts_read"); 24150565Sphk return (rval); 24250565Sphk} 24350565Sphk