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