1 | /* vi: set sw=4 ts=4: */
|
---|
2 | /*
|
---|
3 | * Mini find implementation for busybox
|
---|
4 | *
|
---|
5 | * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
|
---|
6 | *
|
---|
7 | * Reworked by David Douthitt <n9ubh@callsign.net> and
|
---|
8 | * Matt Kraai <kraai@alumni.carnegiemellon.edu>.
|
---|
9 | *
|
---|
10 | * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
|
---|
11 | */
|
---|
12 |
|
---|
13 | #include "busybox.h"
|
---|
14 | #include <stdio.h>
|
---|
15 | #include <unistd.h>
|
---|
16 | #include <dirent.h>
|
---|
17 | #include <string.h>
|
---|
18 | #include <stdlib.h>
|
---|
19 | #include <fnmatch.h>
|
---|
20 | #include <time.h>
|
---|
21 | #include <ctype.h>
|
---|
22 |
|
---|
23 | static char *pattern;
|
---|
24 | #ifdef CONFIG_FEATURE_FIND_PRINT0
|
---|
25 | static char printsep = '\n';
|
---|
26 | #endif
|
---|
27 |
|
---|
28 | #ifdef CONFIG_FEATURE_FIND_TYPE
|
---|
29 | static int type_mask = 0;
|
---|
30 | #endif
|
---|
31 |
|
---|
32 | #ifdef CONFIG_FEATURE_FIND_PERM
|
---|
33 | static char perm_char = 0;
|
---|
34 | static int perm_mask = 0;
|
---|
35 | #endif
|
---|
36 |
|
---|
37 | #ifdef CONFIG_FEATURE_FIND_MTIME
|
---|
38 | static char mtime_char;
|
---|
39 | static int mtime_days;
|
---|
40 | #endif
|
---|
41 |
|
---|
42 | #ifdef CONFIG_FEATURE_FIND_MMIN
|
---|
43 | static char mmin_char;
|
---|
44 | static int mmin_mins;
|
---|
45 | #endif
|
---|
46 |
|
---|
47 | #ifdef CONFIG_FEATURE_FIND_XDEV
|
---|
48 | static dev_t *xdev_dev;
|
---|
49 | static int xdev_count = 0;
|
---|
50 | #endif
|
---|
51 |
|
---|
52 | #ifdef CONFIG_FEATURE_FIND_NEWER
|
---|
53 | static time_t newer_mtime;
|
---|
54 | #endif
|
---|
55 |
|
---|
56 | #ifdef CONFIG_FEATURE_FIND_INUM
|
---|
57 | static ino_t inode_num;
|
---|
58 | #endif
|
---|
59 |
|
---|
60 | #ifdef CONFIG_FEATURE_FIND_EXEC
|
---|
61 | static char **exec_str;
|
---|
62 | static int num_matches;
|
---|
63 | static int exec_opt;
|
---|
64 | #endif
|
---|
65 |
|
---|
66 | static int fileAction(const char *fileName, struct stat *statbuf, void* junk)
|
---|
67 | {
|
---|
68 | #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
|
---|
77 | if (pattern != NULL) {
|
---|
78 | const char *tmp = strrchr(fileName, '/');
|
---|
79 |
|
---|
80 | if (tmp == NULL)
|
---|
81 | tmp = fileName;
|
---|
82 | else
|
---|
83 | tmp++;
|
---|
84 | if (!(fnmatch(pattern, tmp, FNM_PERIOD) == 0))
|
---|
85 | goto no_match;
|
---|
86 | }
|
---|
87 | #ifdef CONFIG_FEATURE_FIND_TYPE
|
---|
88 | if (type_mask != 0) {
|
---|
89 | if (!((statbuf->st_mode & S_IFMT) == type_mask))
|
---|
90 | goto no_match;
|
---|
91 | }
|
---|
92 | #endif
|
---|
93 | #ifdef CONFIG_FEATURE_FIND_PERM
|
---|
94 | if (perm_mask != 0) {
|
---|
95 | 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 | }
|
---|
100 | #endif
|
---|
101 | #ifdef CONFIG_FEATURE_FIND_MTIME
|
---|
102 | if (mtime_char != 0) {
|
---|
103 | time_t file_age = time(NULL) - statbuf->st_mtime;
|
---|
104 | time_t mtime_secs = mtime_days * 24 * 60 * 60;
|
---|
105 | if (!((isdigit(mtime_char) && file_age >= mtime_secs &&
|
---|
106 | file_age < mtime_secs + 24 * 60 * 60) ||
|
---|
107 | (mtime_char == '+' && file_age >= mtime_secs + 24 * 60 * 60) ||
|
---|
108 | (mtime_char == '-' && file_age < mtime_secs)))
|
---|
109 | goto no_match;
|
---|
110 | }
|
---|
111 | #endif
|
---|
112 | #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
|
---|
123 | #ifdef CONFIG_FEATURE_FIND_NEWER
|
---|
124 | if (newer_mtime != 0) {
|
---|
125 | time_t file_age = newer_mtime - statbuf->st_mtime;
|
---|
126 | if (file_age >= 0)
|
---|
127 | goto no_match;
|
---|
128 | }
|
---|
129 | #endif
|
---|
130 | #ifdef CONFIG_FEATURE_FIND_INUM
|
---|
131 | if (inode_num != 0) {
|
---|
132 | if (!(statbuf->st_ino == inode_num))
|
---|
133 | goto no_match;
|
---|
134 | }
|
---|
135 | #endif
|
---|
136 | #ifdef CONFIG_FEATURE_FIND_EXEC
|
---|
137 | if (exec_opt) {
|
---|
138 | 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 | }
|
---|
146 | #endif
|
---|
147 |
|
---|
148 | #ifdef CONFIG_FEATURE_FIND_PRINT0
|
---|
149 | printf("%s%c", fileName, printsep);
|
---|
150 | #else
|
---|
151 | puts(fileName);
|
---|
152 | #endif
|
---|
153 | no_match:
|
---|
154 | return (TRUE);
|
---|
155 | }
|
---|
156 |
|
---|
157 | #ifdef CONFIG_FEATURE_FIND_TYPE
|
---|
158 | static 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')
|
---|
187 | bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type");
|
---|
188 |
|
---|
189 | return mask;
|
---|
190 | }
|
---|
191 | #endif
|
---|
192 |
|
---|
193 | int find_main(int argc, char **argv)
|
---|
194 | {
|
---|
195 | int dereference = FALSE;
|
---|
196 | int i, firstopt, status = EXIT_SUCCESS;
|
---|
197 |
|
---|
198 | for (firstopt = 1; firstopt < argc; firstopt++) {
|
---|
199 | if (argv[firstopt][0] == '-')
|
---|
200 | break;
|
---|
201 | }
|
---|
202 |
|
---|
203 | /* Parse any options */
|
---|
204 | for (i = firstopt; i < argc; i++) {
|
---|
205 | if (strcmp(argv[i], "-follow") == 0)
|
---|
206 | dereference = TRUE;
|
---|
207 | else if (strcmp(argv[i], "-print") == 0) {
|
---|
208 | ;
|
---|
209 | }
|
---|
210 | #ifdef CONFIG_FEATURE_FIND_PRINT0
|
---|
211 | else if (strcmp(argv[i], "-print0") == 0)
|
---|
212 | printsep = '\0';
|
---|
213 | #endif
|
---|
214 | else if (strcmp(argv[i], "-name") == 0) {
|
---|
215 | if (++i == argc)
|
---|
216 | bb_error_msg_and_die(bb_msg_requires_arg, "-name");
|
---|
217 | pattern = argv[i];
|
---|
218 | #ifdef CONFIG_FEATURE_FIND_TYPE
|
---|
219 | } else if (strcmp(argv[i], "-type") == 0) {
|
---|
220 | if (++i == argc)
|
---|
221 | bb_error_msg_and_die(bb_msg_requires_arg, "-type");
|
---|
222 | type_mask = find_type(argv[i]);
|
---|
223 | #endif
|
---|
224 | #ifdef CONFIG_FEATURE_FIND_PERM
|
---|
225 | } else if (strcmp(argv[i], "-perm") == 0) {
|
---|
226 | char *end;
|
---|
227 | if (++i == argc)
|
---|
228 | bb_error_msg_and_die(bb_msg_requires_arg, "-perm");
|
---|
229 | perm_mask = strtol(argv[i], &end, 8);
|
---|
230 | if ((end[0] != '\0') || (perm_mask > 07777))
|
---|
231 | bb_error_msg_and_die(bb_msg_invalid_arg, argv[i], "-perm");
|
---|
232 | if ((perm_char = argv[i][0]) == '-')
|
---|
233 | perm_mask = -perm_mask;
|
---|
234 | #endif
|
---|
235 | #ifdef CONFIG_FEATURE_FIND_MTIME
|
---|
236 | } else if (strcmp(argv[i], "-mtime") == 0) {
|
---|
237 | char *end;
|
---|
238 | if (++i == argc)
|
---|
239 | bb_error_msg_and_die(bb_msg_requires_arg, "-mtime");
|
---|
240 | mtime_days = strtol(argv[i], &end, 10);
|
---|
241 | if (end[0] != '\0')
|
---|
242 | bb_error_msg_and_die(bb_msg_invalid_arg, argv[i], "-mtime");
|
---|
243 | if ((mtime_char = argv[i][0]) == '-')
|
---|
244 | mtime_days = -mtime_days;
|
---|
245 | #endif
|
---|
246 | #ifdef CONFIG_FEATURE_FIND_MMIN
|
---|
247 | } else if (strcmp(argv[i], "-mmin") == 0) {
|
---|
248 | char *end;
|
---|
249 | if (++i == argc)
|
---|
250 | bb_error_msg_and_die(bb_msg_requires_arg, "-mmin");
|
---|
251 | mmin_mins = strtol(argv[i], &end, 10);
|
---|
252 | if (end[0] != '\0')
|
---|
253 | bb_error_msg_and_die(bb_msg_invalid_arg, argv[i], "-mmin");
|
---|
254 | if ((mmin_char = argv[i][0]) == '-')
|
---|
255 | mmin_mins = -mmin_mins;
|
---|
256 | #endif
|
---|
257 | #ifdef CONFIG_FEATURE_FIND_XDEV
|
---|
258 | } else if (strcmp(argv[i], "-xdev") == 0) {
|
---|
259 | 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 ) {
|
---|
265 | xstat ( ".", &stbuf );
|
---|
266 | xdev_dev [0] = stbuf. st_dev;
|
---|
267 | }
|
---|
268 | else {
|
---|
269 |
|
---|
270 | for (i = 1; i < firstopt; i++) {
|
---|
271 | xstat ( argv [i], &stbuf );
|
---|
272 | xdev_dev [i-1] = stbuf. st_dev;
|
---|
273 | }
|
---|
274 | }
|
---|
275 | #endif
|
---|
276 | #ifdef CONFIG_FEATURE_FIND_NEWER
|
---|
277 | } else if (strcmp(argv[i], "-newer") == 0) {
|
---|
278 | struct stat stat_newer;
|
---|
279 | if (++i == argc)
|
---|
280 | bb_error_msg_and_die(bb_msg_requires_arg, "-newer");
|
---|
281 | xstat (argv[i], &stat_newer);
|
---|
282 | newer_mtime = stat_newer.st_mtime;
|
---|
283 | #endif
|
---|
284 | #ifdef CONFIG_FEATURE_FIND_INUM
|
---|
285 | } else if (strcmp(argv[i], "-inum") == 0) {
|
---|
286 | char *end;
|
---|
287 | if (++i == argc)
|
---|
288 | bb_error_msg_and_die(bb_msg_requires_arg, "-inum");
|
---|
289 | inode_num = strtol(argv[i], &end, 10);
|
---|
290 | if (end[0] != '\0')
|
---|
291 | bb_error_msg_and_die(bb_msg_invalid_arg, argv[i], "-inum");
|
---|
292 | #endif
|
---|
293 | #ifdef CONFIG_FEATURE_FIND_EXEC
|
---|
294 | } else if (strcmp(argv[i], "-exec") == 0) {
|
---|
295 | int b_pos;
|
---|
296 | char *cmd_string = "";
|
---|
297 |
|
---|
298 | while (i++) {
|
---|
299 | if (i == argc)
|
---|
300 | bb_error_msg_and_die(bb_msg_requires_arg, "-exec");
|
---|
301 | if (*argv[i] == ';')
|
---|
302 | break;
|
---|
303 | cmd_string = bb_xasprintf("%s %s", cmd_string, argv[i]);
|
---|
304 | }
|
---|
305 |
|
---|
306 | if (*cmd_string == 0)
|
---|
307 | bb_error_msg_and_die(bb_msg_requires_arg, "-exec");
|
---|
308 | 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;
|
---|
319 | #endif
|
---|
320 | } else
|
---|
321 | bb_show_usage();
|
---|
322 | }
|
---|
323 |
|
---|
324 | if (firstopt == 1) {
|
---|
325 | if (! recursive_action(".", TRUE, dereference, FALSE, fileAction,
|
---|
326 | fileAction, NULL))
|
---|
327 | status = EXIT_FAILURE;
|
---|
328 | } else {
|
---|
329 | for (i = 1; i < firstopt; i++) {
|
---|
330 | if (! recursive_action(argv[i], TRUE, dereference, FALSE, fileAction,
|
---|
331 | fileAction, NULL))
|
---|
332 | status = EXIT_FAILURE;
|
---|
333 | }
|
---|
334 | }
|
---|
335 |
|
---|
336 | return status;
|
---|
337 | }
|
---|