aboutsummaryrefslogtreecommitdiff
path: root/findutils/find.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-10-29 00:21:47 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-10-29 00:21:47 +0000
commitdf0553bbd2c28336795aea6e723414029390a1c4 (patch)
tree487f021cabc468fed900fa0bae6ef8b9deb3f8c9 /findutils/find.c
parent656f746e7443a431240adcd042457b8441248848 (diff)
downloadbusybox-w32-df0553bbd2c28336795aea6e723414029390a1c4.tar.gz
busybox-w32-df0553bbd2c28336795aea6e723414029390a1c4.tar.bz2
busybox-w32-df0553bbd2c28336795aea6e723414029390a1c4.zip
find: fix -exec to work like stock find does.
Diffstat (limited to 'findutils/find.c')
-rw-r--r--findutils/find.c253
1 files changed, 155 insertions, 98 deletions
diff --git a/findutils/find.c b/findutils/find.c
index 8618f3a97..7869840e2 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -10,55 +10,108 @@
10 * Licensed under the GPL version 2, see the file LICENSE in this tarball. 10 * Licensed under the GPL version 2, see the file LICENSE in this tarball.
11 */ 11 */
12 12
13/* findutils-4.1.20:
14 *
15 * # find file.txt -exec 'echo {}' '{} {}' ';'
16 * find: echo file.txt: No such file or directory
17 * # find file.txt -exec 'echo' '{} {}' '; '
18 * find: missing argument to `-exec'
19 * # find file.txt -exec 'echo {}' '{} {}' ';' junk
20 * find: paths must precede expression
21 * # find file.txt -exec 'echo {}' '{} {}' ';' junk ';'
22 * find: paths must precede expression
23 * # find file.txt -exec 'echo' '{} {}' ';'
24 * file.txt file.txt
25 * (strace: execve("/bin/echo", ["echo", "file.txt file.txt"], [ 30 vars ]))
26 *
27 * bboxed find rev 16467: above - works, below - doesn't
28 *
29 * # find file.txt -exec 'echo' '{} {}' ';' -print -exec pwd ';'
30 * file.txt file.txt
31 * file.txt
32 * /tmp
33 */
34
13#include "busybox.h" 35#include "busybox.h"
14#include <fnmatch.h> 36#include <fnmatch.h>
15 37
16static char *pattern; 38static char *pattern;
17#ifdef CONFIG_FEATURE_FIND_PRINT0 39#if ENABLE_FEATURE_FIND_PRINT0
18static char printsep = '\n'; 40static char printsep = '\n';
19#endif 41#endif
20 42
21#ifdef CONFIG_FEATURE_FIND_TYPE 43#if ENABLE_FEATURE_FIND_TYPE
22static int type_mask = 0; 44static int type_mask = 0;
23#endif 45#endif
24 46
25#ifdef CONFIG_FEATURE_FIND_PERM 47#if ENABLE_FEATURE_FIND_PERM
26static char perm_char = 0; 48static char perm_char = 0;
27static int perm_mask = 0; 49static int perm_mask = 0;
28#endif 50#endif
29 51
30#ifdef CONFIG_FEATURE_FIND_MTIME 52#if ENABLE_FEATURE_FIND_MTIME
31static char mtime_char; 53static char mtime_char;
32static int mtime_days; 54static int mtime_days;
33#endif 55#endif
34 56
35#ifdef CONFIG_FEATURE_FIND_MMIN 57#if ENABLE_FEATURE_FIND_MMIN
36static char mmin_char; 58static char mmin_char;
37static int mmin_mins; 59static int mmin_mins;
38#endif 60#endif
39 61
40#ifdef CONFIG_FEATURE_FIND_XDEV 62#if ENABLE_FEATURE_FIND_XDEV
41static dev_t *xdev_dev; 63static dev_t *xdev_dev;
42static int xdev_count = 0; 64static int xdev_count = 0;
43#endif 65#endif
44 66
45#ifdef CONFIG_FEATURE_FIND_NEWER 67#if ENABLE_FEATURE_FIND_NEWER
46static time_t newer_mtime; 68static time_t newer_mtime;
47#endif 69#endif
48 70
49#ifdef CONFIG_FEATURE_FIND_INUM 71#if ENABLE_FEATURE_FIND_INUM
50static ino_t inode_num; 72static ino_t inode_num;
51#endif 73#endif
52 74
53#ifdef CONFIG_FEATURE_FIND_EXEC 75#if ENABLE_FEATURE_FIND_EXEC
54static char **exec_str; 76static char **exec_argv;
55static int num_matches; 77static int *subst_count;
56static int exec_opt; 78static int exec_argc;
57#endif 79#endif
58 80
81static int count_subst(const char *str)
82{
83 int count = 0;
84 while ((str = strstr(str, "{}"))) {
85 count++;
86 str++;
87 }
88 return count;
89}
90
91
92static char* subst(const char *src, int count, const char* filename)
93{
94 char *buf, *dst, *end;
95 int flen = strlen(filename);
96//puts(src);
97 /* we replace each '{}' with filename: growth by strlen-2 */
98 buf = dst = xmalloc(strlen(src) + count*(flen-2) + 1);
99 while ((end = strstr(src, "{}"))) {
100 memcpy(dst, src, end - src);
101 dst += end - src;
102 src = end + 2;
103 memcpy(dst, filename, flen);
104 dst += flen;
105 }
106 strcpy(dst, src);
107//puts(buf);
108 return buf;
109}
110
111
59static int fileAction(const char *fileName, struct stat *statbuf, void* junk, int depth) 112static int fileAction(const char *fileName, struct stat *statbuf, void* junk, int depth)
60{ 113{
61#ifdef CONFIG_FEATURE_FIND_XDEV 114#if ENABLE_FEATURE_FIND_XDEV
62 if (S_ISDIR(statbuf->st_mode) && xdev_count) { 115 if (S_ISDIR(statbuf->st_mode) && xdev_count) {
63 int i; 116 int i;
64 for (i=0; i<xdev_count; i++) { 117 for (i=0; i<xdev_count; i++) {
@@ -77,13 +130,13 @@ static int fileAction(const char *fileName, struct stat *statbuf, void* junk, in
77 if (fnmatch(pattern, tmp, FNM_PERIOD) != 0) 130 if (fnmatch(pattern, tmp, FNM_PERIOD) != 0)
78 goto no_match; 131 goto no_match;
79 } 132 }
80#ifdef CONFIG_FEATURE_FIND_TYPE 133#if ENABLE_FEATURE_FIND_TYPE
81 if (type_mask != 0) { 134 if (type_mask != 0) {
82 if (!((statbuf->st_mode & S_IFMT) == type_mask)) 135 if (!((statbuf->st_mode & S_IFMT) == type_mask))
83 goto no_match; 136 goto no_match;
84 } 137 }
85#endif 138#endif
86#ifdef CONFIG_FEATURE_FIND_PERM 139#if ENABLE_FEATURE_FIND_PERM
87 if (perm_mask != 0) { 140 if (perm_mask != 0) {
88 if (!((isdigit(perm_char) && (statbuf->st_mode & 07777) == perm_mask) || 141 if (!((isdigit(perm_char) && (statbuf->st_mode & 07777) == perm_mask) ||
89 (perm_char == '-' && (statbuf->st_mode & perm_mask) == perm_mask) || 142 (perm_char == '-' && (statbuf->st_mode & perm_mask) == perm_mask) ||
@@ -91,7 +144,7 @@ static int fileAction(const char *fileName, struct stat *statbuf, void* junk, in
91 goto no_match; 144 goto no_match;
92 } 145 }
93#endif 146#endif
94#ifdef CONFIG_FEATURE_FIND_MTIME 147#if ENABLE_FEATURE_FIND_MTIME
95 if (mtime_char != 0) { 148 if (mtime_char != 0) {
96 time_t file_age = time(NULL) - statbuf->st_mtime; 149 time_t file_age = time(NULL) - statbuf->st_mtime;
97 time_t mtime_secs = mtime_days * 24 * 60 * 60; 150 time_t mtime_secs = mtime_days * 24 * 60 * 60;
@@ -102,7 +155,7 @@ static int fileAction(const char *fileName, struct stat *statbuf, void* junk, in
102 goto no_match; 155 goto no_match;
103 } 156 }
104#endif 157#endif
105#ifdef CONFIG_FEATURE_FIND_MMIN 158#if ENABLE_FEATURE_FIND_MMIN
106 if (mmin_char != 0) { 159 if (mmin_char != 0) {
107 time_t file_age = time(NULL) - statbuf->st_mtime; 160 time_t file_age = time(NULL) - statbuf->st_mtime;
108 time_t mmin_secs = mmin_mins * 60; 161 time_t mmin_secs = mmin_mins * 60;
@@ -113,32 +166,37 @@ static int fileAction(const char *fileName, struct stat *statbuf, void* junk, in
113 goto no_match; 166 goto no_match;
114 } 167 }
115#endif 168#endif
116#ifdef CONFIG_FEATURE_FIND_NEWER 169#if ENABLE_FEATURE_FIND_NEWER
117 if (newer_mtime != 0) { 170 if (newer_mtime != 0) {
118 time_t file_age = newer_mtime - statbuf->st_mtime; 171 time_t file_age = newer_mtime - statbuf->st_mtime;
119 if (file_age >= 0) 172 if (file_age >= 0)
120 goto no_match; 173 goto no_match;
121 } 174 }
122#endif 175#endif
123#ifdef CONFIG_FEATURE_FIND_INUM 176#if ENABLE_FEATURE_FIND_INUM
124 if (inode_num != 0) { 177 if (inode_num != 0) {
125 if (!(statbuf->st_ino == inode_num)) 178 if (!(statbuf->st_ino == inode_num))
126 goto no_match; 179 goto no_match;
127 } 180 }
128#endif 181#endif
129#ifdef CONFIG_FEATURE_FIND_EXEC 182#if ENABLE_FEATURE_FIND_EXEC
130 if (exec_opt) { 183 if (exec_argc) {
131 int i; 184 int i;
132 char *cmd_string = ""; 185 char *argv[exec_argc+1];
133 for (i = 0; i < num_matches; i++) 186 for (i = 0; i < exec_argc; i++)
134 cmd_string = xasprintf("%s%s%s", cmd_string, exec_str[i], fileName); 187 argv[i] = subst(exec_argv[i], subst_count[i], fileName);
135 cmd_string = xasprintf("%s%s", cmd_string, exec_str[num_matches]); 188 argv[i] = NULL; /* terminate the list */
136 system(cmd_string); 189 errno = 0;
190 wait4pid(spawn(argv));
191 if (errno)
192 bb_perror_msg("%s", argv[0]);
193 for (i = 0; i < exec_argc; i++)
194 free(argv[i]);
137 goto no_match; 195 goto no_match;
138 } 196 }
139#endif 197#endif
140 198
141#ifdef CONFIG_FEATURE_FIND_PRINT0 199#if ENABLE_FEATURE_FIND_PRINT0
142 printf("%s%c", fileName, printsep); 200 printf("%s%c", fileName, printsep);
143#else 201#else
144 puts(fileName); 202 puts(fileName);
@@ -147,7 +205,7 @@ static int fileAction(const char *fileName, struct stat *statbuf, void* junk, in
147 return TRUE; 205 return TRUE;
148} 206}
149 207
150#ifdef CONFIG_FEATURE_FIND_TYPE 208#if ENABLE_FEATURE_FIND_TYPE
151static int find_type(char *type) 209static int find_type(char *type)
152{ 210{
153 int mask = 0; 211 int mask = 0;
@@ -186,7 +244,7 @@ static int find_type(char *type)
186int find_main(int argc, char **argv) 244int find_main(int argc, char **argv)
187{ 245{
188 int dereference = FALSE; 246 int dereference = FALSE;
189 int i, firstopt, status = EXIT_SUCCESS; 247 int i, j, firstopt, status = EXIT_SUCCESS;
190 248
191 for (firstopt = 1; firstopt < argc; firstopt++) { 249 for (firstopt = 1; firstopt < argc; firstopt++) {
192 if (argv[firstopt][0] == '-') 250 if (argv[firstopt][0] == '-')
@@ -195,54 +253,62 @@ int find_main(int argc, char **argv)
195 253
196 /* Parse any options */ 254 /* Parse any options */
197 for (i = firstopt; i < argc; i++) { 255 for (i = firstopt; i < argc; i++) {
198 if (strcmp(argv[i], "-follow") == 0) 256 char *arg = argv[i];
257 char *arg1 = argv[i+1];
258 if (strcmp(arg, "-follow") == 0)
199 dereference = TRUE; 259 dereference = TRUE;
200 else if (strcmp(argv[i], "-print") == 0) { 260 else if (strcmp(arg, "-print") == 0) {
201 ; 261 ;
202 } 262 }
203#ifdef CONFIG_FEATURE_FIND_PRINT0 263#if ENABLE_FEATURE_FIND_PRINT0
204 else if (strcmp(argv[i], "-print0") == 0) 264 else if (strcmp(arg, "-print0") == 0)
205 printsep = '\0'; 265 printsep = '\0';
206#endif 266#endif
207 else if (strcmp(argv[i], "-name") == 0) { 267 else if (strcmp(arg, "-name") == 0) {
208 if (++i == argc) 268 if (++i == argc)
209 bb_error_msg_and_die(bb_msg_requires_arg, "-name"); 269 bb_error_msg_and_die(bb_msg_requires_arg, arg);
210 pattern = argv[i]; 270 pattern = arg1;
211#ifdef CONFIG_FEATURE_FIND_TYPE 271#if ENABLE_FEATURE_FIND_TYPE
212 } else if (strcmp(argv[i], "-type") == 0) { 272 } else if (strcmp(arg, "-type") == 0) {
213 if (++i == argc) 273 if (++i == argc)
214 bb_error_msg_and_die(bb_msg_requires_arg, "-type"); 274 bb_error_msg_and_die(bb_msg_requires_arg, arg);
215 type_mask = find_type(argv[i]); 275 type_mask = find_type(arg1);
216#endif 276#endif
217#ifdef CONFIG_FEATURE_FIND_PERM 277#if ENABLE_FEATURE_FIND_PERM
218 } else if (strcmp(argv[i], "-perm") == 0) { 278/* TODO:
279 * -perm mode File's permission bits are exactly mode (octal or symbolic).
280 * Symbolic modes use mode 0 as a point of departure.
281 * -perm -mode All of the permission bits mode are set for the file.
282 * -perm +mode Any of the permission bits mode are set for the file.
283 */
284 } else if (strcmp(arg, "-perm") == 0) {
219 if (++i == argc) 285 if (++i == argc)
220 bb_error_msg_and_die(bb_msg_requires_arg, "-perm"); 286 bb_error_msg_and_die(bb_msg_requires_arg, arg);
221 perm_mask = xstrtol_range(argv[i], 8, 0, 07777); 287 perm_mask = xstrtol_range(arg1, 8, 0, 07777);
222 perm_char = argv[i][0]; 288 perm_char = arg1[0];
223 if (perm_char == '-') 289 if (perm_char == '-')
224 perm_mask = -perm_mask; 290 perm_mask = -perm_mask;
225#endif 291#endif
226#ifdef CONFIG_FEATURE_FIND_MTIME 292#if ENABLE_FEATURE_FIND_MTIME
227 } else if (strcmp(argv[i], "-mtime") == 0) { 293 } else if (strcmp(arg, "-mtime") == 0) {
228 if (++i == argc) 294 if (++i == argc)
229 bb_error_msg_and_die(bb_msg_requires_arg, "-mtime"); 295 bb_error_msg_and_die(bb_msg_requires_arg, arg);
230 mtime_days = xatol(argv[i]); 296 mtime_days = xatol(arg1);
231 mtime_char = argv[i][0]; 297 mtime_char = arg1[0];
232 if (mtime_char == '-') 298 if (mtime_char == '-')
233 mtime_days = -mtime_days; 299 mtime_days = -mtime_days;
234#endif 300#endif
235#ifdef CONFIG_FEATURE_FIND_MMIN 301#if ENABLE_FEATURE_FIND_MMIN
236 } else if (strcmp(argv[i], "-mmin") == 0) { 302 } else if (strcmp(arg, "-mmin") == 0) {
237 if (++i == argc) 303 if (++i == argc)
238 bb_error_msg_and_die(bb_msg_requires_arg, "-mmin"); 304 bb_error_msg_and_die(bb_msg_requires_arg, arg);
239 mmin_mins = xatol(argv[i]); 305 mmin_mins = xatol(arg1);
240 mmin_char = argv[i][0]; 306 mmin_char = arg1[0];
241 if (mmin_char == '-') 307 if (mmin_char == '-')
242 mmin_mins = -mmin_mins; 308 mmin_mins = -mmin_mins;
243#endif 309#endif
244#ifdef CONFIG_FEATURE_FIND_XDEV 310#if ENABLE_FEATURE_FIND_XDEV
245 } else if (strcmp(argv[i], "-xdev") == 0) { 311 } else if (strcmp(arg, "-xdev") == 0) {
246 struct stat stbuf; 312 struct stat stbuf;
247 313
248 xdev_count = (firstopt - 1) ? (firstopt - 1) : 1; 314 xdev_count = (firstopt - 1) ? (firstopt - 1) : 1;
@@ -251,55 +317,46 @@ int find_main(int argc, char **argv)
251 if (firstopt == 1) { 317 if (firstopt == 1) {
252 xstat(".", &stbuf); 318 xstat(".", &stbuf);
253 xdev_dev[0] = stbuf.st_dev; 319 xdev_dev[0] = stbuf.st_dev;
254 } 320 } else {
255 else { 321 for (j = 1; j < firstopt; i++) {
256 322 xstat(argv[j], &stbuf);
257 for (i = 1; i < firstopt; i++) { 323 xdev_dev[j-1] = stbuf.st_dev;
258 xstat(argv[i], &stbuf);
259 xdev_dev[i-1] = stbuf.st_dev;
260 } 324 }
261 } 325 }
262#endif 326#endif
263#ifdef CONFIG_FEATURE_FIND_NEWER 327#if ENABLE_FEATURE_FIND_NEWER
264 } else if (strcmp(argv[i], "-newer") == 0) { 328 } else if (strcmp(arg, "-newer") == 0) {
265 struct stat stat_newer; 329 struct stat stat_newer;
266 if (++i == argc) 330 if (++i == argc)
267 bb_error_msg_and_die(bb_msg_requires_arg, "-newer"); 331 bb_error_msg_and_die(bb_msg_requires_arg, arg);
268 xstat(argv[i], &stat_newer); 332 xstat(arg1, &stat_newer);
269 newer_mtime = stat_newer.st_mtime; 333 newer_mtime = stat_newer.st_mtime;
270#endif 334#endif
271#ifdef CONFIG_FEATURE_FIND_INUM 335#if ENABLE_FEATURE_FIND_INUM
272 } else if (strcmp(argv[i], "-inum") == 0) { 336 } else if (strcmp(arg, "-inum") == 0) {
273 if (++i == argc) 337 if (++i == argc)
274 bb_error_msg_and_die(bb_msg_requires_arg, "-inum"); 338 bb_error_msg_and_die(bb_msg_requires_arg, arg);
275 inode_num = xatoul(argv[i]); 339 inode_num = xatoul(arg1);
276#endif 340#endif
277#ifdef CONFIG_FEATURE_FIND_EXEC 341#if ENABLE_FEATURE_FIND_EXEC
278 } else if (strcmp(argv[i], "-exec") == 0) { 342 } else if (strcmp(arg, "-exec") == 0) {
279 int b_pos; 343 i++; /* now: argv[i] is the first arg after -exec */
280 char *cmd_string = ""; 344 exec_argv = &argv[i];
281 345 exec_argc = i;
282 while (i++) { 346 while (1) {
283 if (i == argc) 347 if (i == argc) /* did not see ';' till end */
284 bb_error_msg_and_die(bb_msg_requires_arg, "-exec"); 348 bb_error_msg_and_die(bb_msg_requires_arg, arg);
285 if (*argv[i] == ';') 349 if (argv[i][0] == ';' && argv[i][1] == '\0')
286 break; 350 break;
287 cmd_string = xasprintf("%s %s", cmd_string, argv[i]); 351 i++;
288 }
289
290 if (*cmd_string == 0)
291 bb_error_msg_and_die(bb_msg_requires_arg, "-exec");
292 cmd_string++;
293 exec_str = xmalloc(sizeof(char *));
294
295 while ((b_pos = strstr(cmd_string, "{}") - cmd_string), (b_pos >= 0)) {
296 num_matches++;
297 exec_str = xrealloc(exec_str, (num_matches + 1) * sizeof(char *));
298 exec_str[num_matches - 1] = xstrndup(cmd_string, b_pos);
299 cmd_string += b_pos + 2;
300 } 352 }
301 exec_str[num_matches] = xstrdup(cmd_string); 353 exec_argc = i - exec_argc; /* number of --exec arguments */
302 exec_opt = 1; 354 if (exec_argc == 0)
355 bb_error_msg_and_die(bb_msg_requires_arg, arg);
356 subst_count = xmalloc(exec_argc * sizeof(int));
357 j = exec_argc;
358 while (j--)
359 subst_count[j] = count_subst(exec_argv[j]);
303#endif 360#endif
304 } else 361 } else
305 bb_show_usage(); 362 bb_show_usage();
@@ -311,8 +368,8 @@ int find_main(int argc, char **argv)
311 status = EXIT_FAILURE; 368 status = EXIT_FAILURE;
312 } else { 369 } else {
313 for (i = 1; i < firstopt; i++) { 370 for (i = 1; i < firstopt; i++) {
314 if (!recursive_action(argv[i], TRUE, dereference, FALSE, fileAction, 371 if (!recursive_action(argv[i], TRUE, dereference, FALSE,
315 fileAction, NULL, 0)) 372 fileAction, fileAction, NULL, 0))
316 status = EXIT_FAILURE; 373 status = EXIT_FAILURE;
317 } 374 }
318 } 375 }