blob: 75ed4e208106e7257ff8db35e5888b02b0740d0f [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersen17d49ef1999-10-06 20:25:32 +00002/*
3 * Mini find implementation for busybox
4 *
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
Eric Andersenc4996011999-10-20 22:08:37 +00006 *
Matt Kraai096370d2001-02-07 03:52:38 +00007 * Reworked by David Douthitt <n9ubh@callsign.net> and
8 * Matt Kraai <kraai@alumni.carnegiemellon.edu>.
Eric Andersen17d49ef1999-10-06 20:25:32 +00009 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25
26#include <stdio.h>
27#include <unistd.h>
28#include <dirent.h>
Eric Andersened3ef502001-01-27 08:24:39 +000029#include <string.h>
30#include <stdlib.h>
Matt Kraai096370d2001-02-07 03:52:38 +000031#include <fnmatch.h>
32#include <time.h>
33#include <ctype.h>
Eric Andersencbe31da2001-02-20 06:14:08 +000034#include "busybox.h"
Eric Andersen17d49ef1999-10-06 20:25:32 +000035
Eric Andersen97d86f22003-01-23 05:27:42 +000036//XXX just found out about libbb/messages.c . maybe move stuff there ? - ghoz
"Vladimir N. Oleynik"007a0112005-09-22 11:11:11 +000037static const char msg_req_arg[] = "option `%s' requires an argument";
38static const char msg_invalid_arg[] = "invalid argument `%s' to `%s'";
Eric Andersen17d49ef1999-10-06 20:25:32 +000039
Matt Kraai096370d2001-02-07 03:52:38 +000040static char *pattern;
41
Rob Landleycee605c2005-10-06 16:39:17 +000042#ifdef CONFIG_FEATURE_FIND_TYPE
Matt Kraai096370d2001-02-07 03:52:38 +000043static int type_mask = 0;
44#endif
45
Rob Landleycee605c2005-10-06 16:39:17 +000046#ifdef CONFIG_FEATURE_FIND_PERM
Matt Kraai096370d2001-02-07 03:52:38 +000047static char perm_char = 0;
48static int perm_mask = 0;
49#endif
50
Rob Landleycee605c2005-10-06 16:39:17 +000051#ifdef CONFIG_FEATURE_FIND_MTIME
Matt Kraai096370d2001-02-07 03:52:38 +000052static char mtime_char;
53static int mtime_days;
54#endif
Eric Andersen17d49ef1999-10-06 20:25:32 +000055
Rob Landleycee605c2005-10-06 16:39:17 +000056#ifdef CONFIG_FEATURE_FIND_XDEV
Robert Griebl41369af2002-07-24 00:34:48 +000057static dev_t *xdev_dev;
58static int xdev_count = 0;
59#endif
60
Rob Landleycee605c2005-10-06 16:39:17 +000061#ifdef CONFIG_FEATURE_FIND_NEWER
Eric Andersen14f5c8d2005-04-16 19:39:00 +000062static time_t newer_mtime;
Eric Andersen97d86f22003-01-23 05:27:42 +000063#endif
64
Rob Landleycee605c2005-10-06 16:39:17 +000065#ifdef CONFIG_FEATURE_FIND_INUM
Eric Andersen97d86f22003-01-23 05:27:42 +000066static ino_t inode_num;
67#endif
Robert Griebl41369af2002-07-24 00:34:48 +000068
Rob Landleycee605c2005-10-06 16:39:17 +000069#ifdef CONFIG_FEATURE_FIND_EXEC
Rob Landley5d3a0e82005-10-04 03:34:39 +000070static char **exec_str;
71static int num_matches;
72static int exec_opt;
73#endif
74
Erik Andersen3364d782000-03-28 00:58:14 +000075static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
Eric Andersen17d49ef1999-10-06 20:25:32 +000076{
Matt Kraai096370d2001-02-07 03:52:38 +000077 if (pattern != NULL) {
78 const char *tmp = strrchr(fileName, '/');
Erik Andersene49d5ec2000-02-08 19:58:47 +000079
80 if (tmp == NULL)
Matt Kraai096370d2001-02-07 03:52:38 +000081 tmp = fileName;
Erik Andersene49d5ec2000-02-08 19:58:47 +000082 else
83 tmp++;
Matt Kraai096370d2001-02-07 03:52:38 +000084 if (!(fnmatch(pattern, tmp, FNM_PERIOD) == 0))
85 goto no_match;
Erik Andersene49d5ec2000-02-08 19:58:47 +000086 }
Rob Landleycee605c2005-10-06 16:39:17 +000087#ifdef CONFIG_FEATURE_FIND_TYPE
88 if (type_mask != 0) {
Matt Kraai096370d2001-02-07 03:52:38 +000089 if (!((statbuf->st_mode & S_IFMT) == type_mask))
90 goto no_match;
91 }
Rob Landleycee605c2005-10-06 16:39:17 +000092#endif
93#ifdef CONFIG_FEATURE_FIND_PERM
94 if (perm_mask != 0) {
Matt Kraai096370d2001-02-07 03:52:38 +000095 if (!((isdigit(perm_char) && (statbuf->st_mode & 07777) == perm_mask) ||
96 (perm_char == '-' && (statbuf->st_mode & perm_mask) == perm_mask) ||
97 (perm_char == '+' && (statbuf->st_mode & perm_mask) != 0)))
98 goto no_match;
99 }
Rob Landleycee605c2005-10-06 16:39:17 +0000100#endif
101#ifdef CONFIG_FEATURE_FIND_MTIME
102 if (mtime_char != 0) {
Matt Kraai096370d2001-02-07 03:52:38 +0000103 time_t file_age = time(NULL) - statbuf->st_mtime;
104 time_t mtime_secs = mtime_days * 24 * 60 * 60;
Glenn L McGrath49b0f862002-12-11 21:22:21 +0000105 if (!((isdigit(mtime_char) && file_age >= mtime_secs &&
106 file_age < mtime_secs + 24 * 60 * 60) ||
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000107 (mtime_char == '+' && file_age >= mtime_secs + 24 * 60 * 60) ||
Glenn L McGrath49b0f862002-12-11 21:22:21 +0000108 (mtime_char == '-' && file_age < mtime_secs)))
Matt Kraai096370d2001-02-07 03:52:38 +0000109 goto no_match;
110 }
Rob Landleycee605c2005-10-06 16:39:17 +0000111#endif
112#ifdef CONFIG_FEATURE_FIND_XDEV
113 if (xdev_count) {
Robert Griebl41369af2002-07-24 00:34:48 +0000114 int i;
115 for (i=0; i<xdev_count; i++) {
116 if (xdev_dev[i] == statbuf-> st_dev)
117 break;
118 }
119 if (i == xdev_count) {
120 if(S_ISDIR(statbuf->st_mode))
121 return SKIP;
122 else
123 goto no_match;
124 }
125 }
Rob Landleycee605c2005-10-06 16:39:17 +0000126#endif
127#ifdef CONFIG_FEATURE_FIND_NEWER
128 if (newer_mtime != 0) {
Eric Andersen97d86f22003-01-23 05:27:42 +0000129 time_t file_age = newer_mtime - statbuf->st_mtime;
130 if (file_age >= 0)
131 goto no_match;
132 }
Rob Landleycee605c2005-10-06 16:39:17 +0000133#endif
134#ifdef CONFIG_FEATURE_FIND_INUM
135 if (inode_num != 0) {
Eric Andersen97d86f22003-01-23 05:27:42 +0000136 if (!(statbuf->st_ino == inode_num))
137 goto no_match;
138 }
Rob Landleycee605c2005-10-06 16:39:17 +0000139#endif
140#ifdef CONFIG_FEATURE_FIND_EXEC
141 if (exec_opt) {
Rob Landley5d3a0e82005-10-04 03:34:39 +0000142 int i;
143 char *cmd_string = "";
144 for (i = 0; i < num_matches; i++)
145 cmd_string = bb_xasprintf("%s%s%s", cmd_string, exec_str[i], fileName);
146 cmd_string = bb_xasprintf("%s%s", cmd_string, exec_str[num_matches]);
147 system(cmd_string);
148 goto no_match;
149 }
Rob Landleycee605c2005-10-06 16:39:17 +0000150#endif
Rob Landley5d3a0e82005-10-04 03:34:39 +0000151
Matt Kraai096370d2001-02-07 03:52:38 +0000152 puts(fileName);
153no_match:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000154 return (TRUE);
Eric Andersen17d49ef1999-10-06 20:25:32 +0000155}
156
Rob Landleycee605c2005-10-06 16:39:17 +0000157#ifdef CONFIG_FEATURE_FIND_TYPE
Matt Kraai096370d2001-02-07 03:52:38 +0000158static int find_type(char *type)
159{
160 int mask = 0;
161
162 switch (type[0]) {
163 case 'b':
164 mask = S_IFBLK;
165 break;
166 case 'c':
167 mask = S_IFCHR;
168 break;
169 case 'd':
170 mask = S_IFDIR;
171 break;
172 case 'p':
173 mask = S_IFIFO;
174 break;
175 case 'f':
176 mask = S_IFREG;
177 break;
178 case 'l':
179 mask = S_IFLNK;
180 break;
181 case 's':
182 mask = S_IFSOCK;
183 break;
184 }
185
186 if (mask == 0 || type[1] != '\0')
Manuel Novoa III cad53642003-03-19 09:13:01 +0000187 bb_error_msg_and_die(msg_invalid_arg, type, "-type");
Matt Kraai096370d2001-02-07 03:52:38 +0000188
189 return mask;
190}
191#endif
192
Eric Andersen17d49ef1999-10-06 20:25:32 +0000193int find_main(int argc, char **argv)
194{
Matt Kraai096370d2001-02-07 03:52:38 +0000195 int dereference = FALSE;
196 int i, firstopt, status = EXIT_SUCCESS;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000197
Matt Kraai096370d2001-02-07 03:52:38 +0000198 for (firstopt = 1; firstopt < argc; firstopt++) {
199 if (argv[firstopt][0] == '-')
200 break;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000201 }
Eric Andersen17d49ef1999-10-06 20:25:32 +0000202
Erik Andersene49d5ec2000-02-08 19:58:47 +0000203 /* Parse any options */
Matt Kraai096370d2001-02-07 03:52:38 +0000204 for (i = firstopt; i < argc; i++) {
205 if (strcmp(argv[i], "-follow") == 0)
206 dereference = TRUE;
Mark Whitleye0a7f912001-03-28 22:04:42 +0000207 else if (strcmp(argv[i], "-print") == 0) {
208 ;
209 }
Matt Kraai096370d2001-02-07 03:52:38 +0000210 else if (strcmp(argv[i], "-name") == 0) {
211 if (++i == argc)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000212 bb_error_msg_and_die(msg_req_arg, "-name");
Matt Kraai096370d2001-02-07 03:52:38 +0000213 pattern = argv[i];
Rob Landleycee605c2005-10-06 16:39:17 +0000214#ifdef CONFIG_FEATURE_FIND_TYPE
215 } else if (strcmp(argv[i], "-type") == 0) {
Matt Kraai096370d2001-02-07 03:52:38 +0000216 if (++i == argc)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000217 bb_error_msg_and_die(msg_req_arg, "-type");
Matt Kraai096370d2001-02-07 03:52:38 +0000218 type_mask = find_type(argv[i]);
Rob Landleycee605c2005-10-06 16:39:17 +0000219#endif
220#ifdef CONFIG_FEATURE_FIND_PERM
221 } else if (strcmp(argv[i], "-perm") == 0) {
Matt Kraai096370d2001-02-07 03:52:38 +0000222 char *end;
223 if (++i == argc)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000224 bb_error_msg_and_die(msg_req_arg, "-perm");
Matt Kraai096370d2001-02-07 03:52:38 +0000225 perm_mask = strtol(argv[i], &end, 8);
Eric Andersen97d86f22003-01-23 05:27:42 +0000226 if ((end[0] != '\0') || (perm_mask > 07777))
Manuel Novoa III cad53642003-03-19 09:13:01 +0000227 bb_error_msg_and_die(msg_invalid_arg, argv[i], "-perm");
Matt Kraai096370d2001-02-07 03:52:38 +0000228 if ((perm_char = argv[i][0]) == '-')
229 perm_mask = -perm_mask;
Rob Landleycee605c2005-10-06 16:39:17 +0000230#endif
231#ifdef CONFIG_FEATURE_FIND_MTIME
232 } else if (strcmp(argv[i], "-mtime") == 0) {
Matt Kraai096370d2001-02-07 03:52:38 +0000233 char *end;
234 if (++i == argc)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000235 bb_error_msg_and_die(msg_req_arg, "-mtime");
Matt Kraai096370d2001-02-07 03:52:38 +0000236 mtime_days = strtol(argv[i], &end, 10);
237 if (end[0] != '\0')
Manuel Novoa III cad53642003-03-19 09:13:01 +0000238 bb_error_msg_and_die(msg_invalid_arg, argv[i], "-mtime");
Matt Kraai096370d2001-02-07 03:52:38 +0000239 if ((mtime_char = argv[i][0]) == '-')
240 mtime_days = -mtime_days;
Rob Landleycee605c2005-10-06 16:39:17 +0000241#endif
242#ifdef CONFIG_FEATURE_FIND_XDEV
243 } else if (strcmp(argv[i], "-xdev") == 0) {
Robert Griebl41369af2002-07-24 00:34:48 +0000244 struct stat stbuf;
245
246 xdev_count = ( firstopt - 1 ) ? ( firstopt - 1 ) : 1;
247 xdev_dev = xmalloc ( xdev_count * sizeof( dev_t ));
248
249 if ( firstopt == 1 ) {
250 if ( stat ( ".", &stbuf ) < 0 )
Manuel Novoa III cad53642003-03-19 09:13:01 +0000251 bb_error_msg_and_die("could not stat '.'" );
Robert Griebl41369af2002-07-24 00:34:48 +0000252 xdev_dev [0] = stbuf. st_dev;
253 }
254 else {
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000255
Robert Griebl41369af2002-07-24 00:34:48 +0000256 for (i = 1; i < firstopt; i++) {
257 if ( stat ( argv [i], &stbuf ) < 0 )
Manuel Novoa III cad53642003-03-19 09:13:01 +0000258 bb_error_msg_and_die("could not stat '%s'", argv [i] );
Robert Griebl41369af2002-07-24 00:34:48 +0000259 xdev_dev [i-1] = stbuf. st_dev;
260 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000261 }
Rob Landleycee605c2005-10-06 16:39:17 +0000262#endif
263#ifdef CONFIG_FEATURE_FIND_NEWER
264 } else if (strcmp(argv[i], "-newer") == 0) {
Eric Andersen97d86f22003-01-23 05:27:42 +0000265 struct stat stat_newer;
266 if (++i == argc)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000267 bb_error_msg_and_die(msg_req_arg, "-newer");
Eric Andersen97d86f22003-01-23 05:27:42 +0000268 if (stat (argv[i], &stat_newer) != 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000269 bb_error_msg_and_die("file %s not found", argv[i]);
Eric Andersen97d86f22003-01-23 05:27:42 +0000270 newer_mtime = stat_newer.st_mtime;
Rob Landleycee605c2005-10-06 16:39:17 +0000271#endif
272#ifdef CONFIG_FEATURE_FIND_INUM
273 } else if (strcmp(argv[i], "-inum") == 0) {
Eric Andersen97d86f22003-01-23 05:27:42 +0000274 char *end;
275 if (++i == argc)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000276 bb_error_msg_and_die(msg_req_arg, "-inum");
Eric Andersen97d86f22003-01-23 05:27:42 +0000277 inode_num = strtol(argv[i], &end, 10);
278 if (end[0] != '\0')
Manuel Novoa III cad53642003-03-19 09:13:01 +0000279 bb_error_msg_and_die(msg_invalid_arg, argv[i], "-inum");
Rob Landleycee605c2005-10-06 16:39:17 +0000280#endif
281#ifdef CONFIG_FEATURE_FIND_EXEC
282 } else if (strcmp(argv[i], "-exec") == 0) {
Rob Landley5d3a0e82005-10-04 03:34:39 +0000283 int b_pos;
284 char *cmd_string = "";
285
286 while (i++) {
287 if (i == argc)
288 bb_error_msg_and_die(msg_req_arg, "-exec");
289 if (*argv[i] == ';')
290 break;
291 cmd_string = bb_xasprintf("%s %s", cmd_string, argv[i]);
292 }
293
294 if (*cmd_string == 0)
295 bb_error_msg_and_die(msg_req_arg, "-exec");
296 cmd_string++;
297 exec_str = xmalloc(sizeof(char *));
298
299 while ((b_pos = strstr(cmd_string, "{}") - cmd_string), (b_pos >= 0)) {
300 num_matches++;
301 exec_str = xrealloc(exec_str, (num_matches + 1) * sizeof(char *));
302 exec_str[num_matches - 1] = bb_xstrndup(cmd_string, b_pos);
303 cmd_string += b_pos + 2;
304 }
305 exec_str[num_matches] = bb_xstrdup(cmd_string);
306 exec_opt = 1;
Rob Landleycee605c2005-10-06 16:39:17 +0000307#endif
Matt Kraai096370d2001-02-07 03:52:38 +0000308 } else
Manuel Novoa III cad53642003-03-19 09:13:01 +0000309 bb_show_usage();
Erik Andersene49d5ec2000-02-08 19:58:47 +0000310 }
311
Matt Kraai096370d2001-02-07 03:52:38 +0000312 if (firstopt == 1) {
Matt Kraai1f0c4362001-12-20 23:13:26 +0000313 if (! recursive_action(".", TRUE, dereference, FALSE, fileAction,
314 fileAction, NULL))
Matt Kraai096370d2001-02-07 03:52:38 +0000315 status = EXIT_FAILURE;
316 } else {
317 for (i = 1; i < firstopt; i++) {
Matt Kraai1f0c4362001-12-20 23:13:26 +0000318 if (! recursive_action(argv[i], TRUE, dereference, FALSE, fileAction,
319 fileAction, NULL))
Matt Kraai096370d2001-02-07 03:52:38 +0000320 status = EXIT_FAILURE;
321 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000322 }
323
Matt Kraai096370d2001-02-07 03:52:38 +0000324 return status;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000325}