blob: 1e15e88994319730fc942343cef41f4352cb6ad6 [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 *
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +000010 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Eric Andersen17d49ef1999-10-06 20:25:32 +000011 */
12
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +000013#include "busybox.h"
Eric Andersen17d49ef1999-10-06 20:25:32 +000014#include <stdio.h>
15#include <unistd.h>
16#include <dirent.h>
Eric Andersened3ef502001-01-27 08:24:39 +000017#include <string.h>
18#include <stdlib.h>
Matt Kraai096370d2001-02-07 03:52:38 +000019#include <fnmatch.h>
20#include <time.h>
21#include <ctype.h>
Eric Andersen17d49ef1999-10-06 20:25:32 +000022
Matt Kraai096370d2001-02-07 03:52:38 +000023static char *pattern;
Paul Foxd7384292006-05-12 14:47:20 +000024#ifdef CONFIG_FEATURE_FIND_PRINT0
25static char printsep = '\n';
26#endif
Matt Kraai096370d2001-02-07 03:52:38 +000027
Rob Landleycee605c2005-10-06 16:39:17 +000028#ifdef CONFIG_FEATURE_FIND_TYPE
Matt Kraai096370d2001-02-07 03:52:38 +000029static int type_mask = 0;
30#endif
31
Rob Landleycee605c2005-10-06 16:39:17 +000032#ifdef CONFIG_FEATURE_FIND_PERM
Matt Kraai096370d2001-02-07 03:52:38 +000033static char perm_char = 0;
34static int perm_mask = 0;
35#endif
36
Rob Landleycee605c2005-10-06 16:39:17 +000037#ifdef CONFIG_FEATURE_FIND_MTIME
Matt Kraai096370d2001-02-07 03:52:38 +000038static char mtime_char;
39static int mtime_days;
40#endif
Eric Andersen17d49ef1999-10-06 20:25:32 +000041
Paul Fox72d1a232006-01-13 21:05:41 +000042#ifdef CONFIG_FEATURE_FIND_MMIN
43static char mmin_char;
44static int mmin_mins;
45#endif
46
Rob Landleycee605c2005-10-06 16:39:17 +000047#ifdef CONFIG_FEATURE_FIND_XDEV
Robert Griebl41369af2002-07-24 00:34:48 +000048static dev_t *xdev_dev;
49static int xdev_count = 0;
50#endif
51
Rob Landleycee605c2005-10-06 16:39:17 +000052#ifdef CONFIG_FEATURE_FIND_NEWER
Eric Andersen14f5c8d2005-04-16 19:39:00 +000053static time_t newer_mtime;
Eric Andersen97d86f22003-01-23 05:27:42 +000054#endif
55
Rob Landleycee605c2005-10-06 16:39:17 +000056#ifdef CONFIG_FEATURE_FIND_INUM
Eric Andersen97d86f22003-01-23 05:27:42 +000057static ino_t inode_num;
58#endif
Robert Griebl41369af2002-07-24 00:34:48 +000059
Rob Landleycee605c2005-10-06 16:39:17 +000060#ifdef CONFIG_FEATURE_FIND_EXEC
Rob Landley5d3a0e82005-10-04 03:34:39 +000061static char **exec_str;
62static int num_matches;
63static int exec_opt;
64#endif
65
Erik Andersen3364d782000-03-28 00:58:14 +000066static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
Eric Andersen17d49ef1999-10-06 20:25:32 +000067{
Paul Fox8416a2d2006-03-27 16:42:33 +000068#ifdef CONFIG_FEATURE_FIND_XDEV
69 if (S_ISDIR(statbuf->st_mode) && xdev_count) {
70 int i;
71 for (i=0; i<xdev_count; i++) {
72 if (xdev_dev[i] != statbuf->st_dev)
73 return SKIP;
74 }
75 }
76#endif
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
Paul Fox72d1a232006-01-13 21:05:41 +0000112#ifdef CONFIG_FEATURE_FIND_MMIN
113 if (mmin_char != 0) {
114 time_t file_age = time(NULL) - statbuf->st_mtime;
115 time_t mmin_secs = mmin_mins * 60;
116 if (!((isdigit(mmin_char) && file_age >= mmin_secs &&
117 file_age < mmin_secs + 60) ||
118 (mmin_char == '+' && file_age >= mmin_secs + 60) ||
119 (mmin_char == '-' && file_age < mmin_secs)))
120 goto no_match;
121 }
122#endif
Rob Landleycee605c2005-10-06 16:39:17 +0000123#ifdef CONFIG_FEATURE_FIND_NEWER
124 if (newer_mtime != 0) {
Eric Andersen97d86f22003-01-23 05:27:42 +0000125 time_t file_age = newer_mtime - statbuf->st_mtime;
126 if (file_age >= 0)
127 goto no_match;
128 }
Rob Landleycee605c2005-10-06 16:39:17 +0000129#endif
130#ifdef CONFIG_FEATURE_FIND_INUM
131 if (inode_num != 0) {
Eric Andersen97d86f22003-01-23 05:27:42 +0000132 if (!(statbuf->st_ino == inode_num))
133 goto no_match;
134 }
Rob Landleycee605c2005-10-06 16:39:17 +0000135#endif
136#ifdef CONFIG_FEATURE_FIND_EXEC
137 if (exec_opt) {
Rob Landley5d3a0e82005-10-04 03:34:39 +0000138 int i;
139 char *cmd_string = "";
140 for (i = 0; i < num_matches; i++)
141 cmd_string = bb_xasprintf("%s%s%s", cmd_string, exec_str[i], fileName);
142 cmd_string = bb_xasprintf("%s%s", cmd_string, exec_str[num_matches]);
143 system(cmd_string);
144 goto no_match;
145 }
Rob Landleycee605c2005-10-06 16:39:17 +0000146#endif
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000147
Paul Foxd7384292006-05-12 14:47:20 +0000148#ifdef CONFIG_FEATURE_FIND_PRINT0
149 printf("%s%c", fileName, printsep);
150#else
Matt Kraai096370d2001-02-07 03:52:38 +0000151 puts(fileName);
Paul Foxd7384292006-05-12 14:47:20 +0000152#endif
Matt Kraai096370d2001-02-07 03:52:38 +0000153no_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')
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000187 bb_error_msg_and_die(bb_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 }
Paul Foxd7384292006-05-12 14:47:20 +0000210#ifdef CONFIG_FEATURE_FIND_PRINT0
211 else if (strcmp(argv[i], "-print0") == 0)
212 printsep = '\0';
213#endif
Matt Kraai096370d2001-02-07 03:52:38 +0000214 else if (strcmp(argv[i], "-name") == 0) {
215 if (++i == argc)
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000216 bb_error_msg_and_die(bb_msg_requires_arg, "-name");
Matt Kraai096370d2001-02-07 03:52:38 +0000217 pattern = argv[i];
Rob Landleycee605c2005-10-06 16:39:17 +0000218#ifdef CONFIG_FEATURE_FIND_TYPE
219 } else if (strcmp(argv[i], "-type") == 0) {
Matt Kraai096370d2001-02-07 03:52:38 +0000220 if (++i == argc)
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000221 bb_error_msg_and_die(bb_msg_requires_arg, "-type");
Matt Kraai096370d2001-02-07 03:52:38 +0000222 type_mask = find_type(argv[i]);
Rob Landleycee605c2005-10-06 16:39:17 +0000223#endif
224#ifdef CONFIG_FEATURE_FIND_PERM
225 } else if (strcmp(argv[i], "-perm") == 0) {
Matt Kraai096370d2001-02-07 03:52:38 +0000226 char *end;
227 if (++i == argc)
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000228 bb_error_msg_and_die(bb_msg_requires_arg, "-perm");
Matt Kraai096370d2001-02-07 03:52:38 +0000229 perm_mask = strtol(argv[i], &end, 8);
Eric Andersen97d86f22003-01-23 05:27:42 +0000230 if ((end[0] != '\0') || (perm_mask > 07777))
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000231 bb_error_msg_and_die(bb_msg_invalid_arg, argv[i], "-perm");
Matt Kraai096370d2001-02-07 03:52:38 +0000232 if ((perm_char = argv[i][0]) == '-')
233 perm_mask = -perm_mask;
Rob Landleycee605c2005-10-06 16:39:17 +0000234#endif
235#ifdef CONFIG_FEATURE_FIND_MTIME
236 } else if (strcmp(argv[i], "-mtime") == 0) {
Matt Kraai096370d2001-02-07 03:52:38 +0000237 char *end;
238 if (++i == argc)
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000239 bb_error_msg_and_die(bb_msg_requires_arg, "-mtime");
Matt Kraai096370d2001-02-07 03:52:38 +0000240 mtime_days = strtol(argv[i], &end, 10);
241 if (end[0] != '\0')
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000242 bb_error_msg_and_die(bb_msg_invalid_arg, argv[i], "-mtime");
Matt Kraai096370d2001-02-07 03:52:38 +0000243 if ((mtime_char = argv[i][0]) == '-')
244 mtime_days = -mtime_days;
Rob Landleycee605c2005-10-06 16:39:17 +0000245#endif
Paul Fox72d1a232006-01-13 21:05:41 +0000246#ifdef CONFIG_FEATURE_FIND_MMIN
247 } else if (strcmp(argv[i], "-mmin") == 0) {
248 char *end;
249 if (++i == argc)
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000250 bb_error_msg_and_die(bb_msg_requires_arg, "-mmin");
Paul Fox72d1a232006-01-13 21:05:41 +0000251 mmin_mins = strtol(argv[i], &end, 10);
252 if (end[0] != '\0')
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000253 bb_error_msg_and_die(bb_msg_invalid_arg, argv[i], "-mmin");
Paul Fox72d1a232006-01-13 21:05:41 +0000254 if ((mmin_char = argv[i][0]) == '-')
255 mmin_mins = -mmin_mins;
256#endif
Rob Landleycee605c2005-10-06 16:39:17 +0000257#ifdef CONFIG_FEATURE_FIND_XDEV
258 } else if (strcmp(argv[i], "-xdev") == 0) {
Robert Griebl41369af2002-07-24 00:34:48 +0000259 struct stat stbuf;
260
261 xdev_count = ( firstopt - 1 ) ? ( firstopt - 1 ) : 1;
262 xdev_dev = xmalloc ( xdev_count * sizeof( dev_t ));
263
264 if ( firstopt == 1 ) {
Rob Landleyc5b1d4d2006-03-13 15:45:16 +0000265 xstat ( ".", &stbuf );
Robert Griebl41369af2002-07-24 00:34:48 +0000266 xdev_dev [0] = stbuf. st_dev;
267 }
268 else {
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000269
Robert Griebl41369af2002-07-24 00:34:48 +0000270 for (i = 1; i < firstopt; i++) {
Rob Landleyc5b1d4d2006-03-13 15:45:16 +0000271 xstat ( argv [i], &stbuf );
Robert Griebl41369af2002-07-24 00:34:48 +0000272 xdev_dev [i-1] = stbuf. st_dev;
273 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000274 }
Rob Landleycee605c2005-10-06 16:39:17 +0000275#endif
276#ifdef CONFIG_FEATURE_FIND_NEWER
277 } else if (strcmp(argv[i], "-newer") == 0) {
Eric Andersen97d86f22003-01-23 05:27:42 +0000278 struct stat stat_newer;
279 if (++i == argc)
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000280 bb_error_msg_and_die(bb_msg_requires_arg, "-newer");
Rob Landleyc5b1d4d2006-03-13 15:45:16 +0000281 xstat (argv[i], &stat_newer);
Eric Andersen97d86f22003-01-23 05:27:42 +0000282 newer_mtime = stat_newer.st_mtime;
Rob Landleycee605c2005-10-06 16:39:17 +0000283#endif
284#ifdef CONFIG_FEATURE_FIND_INUM
285 } else if (strcmp(argv[i], "-inum") == 0) {
Eric Andersen97d86f22003-01-23 05:27:42 +0000286 char *end;
287 if (++i == argc)
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000288 bb_error_msg_and_die(bb_msg_requires_arg, "-inum");
Eric Andersen97d86f22003-01-23 05:27:42 +0000289 inode_num = strtol(argv[i], &end, 10);
290 if (end[0] != '\0')
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000291 bb_error_msg_and_die(bb_msg_invalid_arg, argv[i], "-inum");
Rob Landleycee605c2005-10-06 16:39:17 +0000292#endif
293#ifdef CONFIG_FEATURE_FIND_EXEC
294 } else if (strcmp(argv[i], "-exec") == 0) {
Rob Landley5d3a0e82005-10-04 03:34:39 +0000295 int b_pos;
296 char *cmd_string = "";
297
298 while (i++) {
299 if (i == argc)
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000300 bb_error_msg_and_die(bb_msg_requires_arg, "-exec");
Rob Landley5d3a0e82005-10-04 03:34:39 +0000301 if (*argv[i] == ';')
302 break;
303 cmd_string = bb_xasprintf("%s %s", cmd_string, argv[i]);
304 }
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000305
Rob Landley5d3a0e82005-10-04 03:34:39 +0000306 if (*cmd_string == 0)
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +0000307 bb_error_msg_and_die(bb_msg_requires_arg, "-exec");
Rob Landley5d3a0e82005-10-04 03:34:39 +0000308 cmd_string++;
309 exec_str = xmalloc(sizeof(char *));
310
311 while ((b_pos = strstr(cmd_string, "{}") - cmd_string), (b_pos >= 0)) {
312 num_matches++;
313 exec_str = xrealloc(exec_str, (num_matches + 1) * sizeof(char *));
314 exec_str[num_matches - 1] = bb_xstrndup(cmd_string, b_pos);
315 cmd_string += b_pos + 2;
316 }
317 exec_str[num_matches] = bb_xstrdup(cmd_string);
318 exec_opt = 1;
Rob Landleycee605c2005-10-06 16:39:17 +0000319#endif
Matt Kraai096370d2001-02-07 03:52:38 +0000320 } else
Manuel Novoa III cad53642003-03-19 09:13:01 +0000321 bb_show_usage();
Erik Andersene49d5ec2000-02-08 19:58:47 +0000322 }
323
Matt Kraai096370d2001-02-07 03:52:38 +0000324 if (firstopt == 1) {
Matt Kraai1f0c4362001-12-20 23:13:26 +0000325 if (! recursive_action(".", TRUE, dereference, FALSE, fileAction,
326 fileAction, NULL))
Matt Kraai096370d2001-02-07 03:52:38 +0000327 status = EXIT_FAILURE;
328 } else {
329 for (i = 1; i < firstopt; i++) {
Matt Kraai1f0c4362001-12-20 23:13:26 +0000330 if (! recursive_action(argv[i], TRUE, dereference, FALSE, fileAction,
331 fileAction, NULL))
Matt Kraai096370d2001-02-07 03:52:38 +0000332 status = EXIT_FAILURE;
333 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000334 }
335
Matt Kraai096370d2001-02-07 03:52:38 +0000336 return status;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000337}