1 /* find -- search for files in a directory hierarchy (fts version)
2 Copyright (C) 1990, 91, 92, 93, 94, 2000,
3 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20 /* This file was written by James Youngman, based on find.c.
22 GNU find was written by Eric Decker <cire@cisco.com>,
23 with enhancements by David MacKenzie <djm@gnu.org>,
24 Jay Plett <jay@silence.princeton.nj.us>,
25 and Tim Wood <axolotl!tim@toad.com>.
26 The idea for -print0 and xargs -0 came from
27 Dan Bernstein <brnstnd@kramden.acf.nyu.edu>.
34 #define USE_SAFE_CHDIR 1
35 #undef STAT_MOUNTPOINTS
48 #if defined(HAVE_FCNTL_H)
52 #include "../gnulib/lib/xalloc.h"
62 #include "dircallback.h"
70 # define _(Text) gettext (Text)
73 #define textdomain(Domain)
74 #define bindtextdomain(Package, Directory)
77 # define N_(String) gettext_noop (String)
79 /* See locate.c for explanation as to why not use (String) */
80 # define N_(String) String
84 static void set_close_on_exec(int fd
)
86 #if defined(F_GETFD) && defined(FD_CLOEXEC)
88 flags
= fcntl(fd
, F_GETFD
);
92 fcntl(fd
, F_SETFD
, flags
);
99 /* FTS_TIGHT_CYCLE_CHECK tries to work around Savannah bug #17877
100 * (but actually using it doesn't fix the bug).
102 static int ftsoptions
= FTS_NOSTAT
|FTS_TIGHT_CYCLE_CHECK
;
104 static int prev_depth
= INT_MIN
; /* fts_level can be < 0 */
105 static int curr_fd
= -1;
107 int get_current_dirfd(void)
109 if (ftsoptions
& FTS_CWDFD
)
111 assert(curr_fd
!= -1);
112 assert( (AT_FDCWD
== curr_fd
) || (curr_fd
>= 0) );
114 if (AT_FDCWD
== curr_fd
)
115 return starting_desc
;
125 static void left_dir(void)
127 if (ftsoptions
& FTS_CWDFD
)
142 * Signal that we are now inside a directory pointed to by dirfd.
143 * The caller can't tell if this is the first time this happens, so
144 * we have to be careful not to call dup() more than once
146 static void inside_dir(int dirfd
)
148 if (ftsoptions
& FTS_CWDFD
)
150 assert(dirfd
== AT_FDCWD
|| dirfd
>= 0);
152 state
.cwd_dir_fd
= dirfd
;
155 if (AT_FDCWD
== dirfd
)
161 curr_fd
= dup(dirfd
);
162 set_close_on_exec(curr_fd
);
166 /* curr_fd is invalid, but dirfd is also invalid.
167 * This should not have happened.
169 assert(curr_fd
>= 0 || dirfd
>= 0);
175 /* FTS_CWDFD is not in use. We can always assume that
176 * AT_FDCWD refers to the directory we are currentl searching.
178 * Therefore there is nothing to do.
185 #ifdef STAT_MOUNTPOINTS
186 static void init_mounted_dev_list(void);
189 /* We have encountered an error which should affect the exit status.
190 * This is normally used to change the exit status from 0 to 1.
191 * However, if the exit status is already 2 for example, we don't want to
195 error_severity(int level
)
197 if (state
.exit_status
< level
)
198 state
.exit_status
= level
;
202 #define STRINGIFY(X) #X
203 #define HANDLECASE(N) case N: return #N;
206 get_fts_info_name(int info
)
213 HANDLECASE(FTS_DEFAULT
);
219 HANDLECASE(FTS_INIT
);
221 HANDLECASE(FTS_NSOK
);
223 HANDLECASE(FTS_SLNONE
);
226 sprintf(buf
, "[%d]", info
);
232 visit(FTS
*p
, FTSENT
*ent
, struct stat
*pstat
)
234 struct predicate
*eval_tree
;
236 state
.curdepth
= ent
->fts_level
;
237 state
.have_stat
= (ent
->fts_info
!= FTS_NS
) && (ent
->fts_info
!= FTS_NSOK
);
238 state
.rel_pathname
= ent
->fts_accpath
;
239 state
.cwd_dir_fd
= p
->fts_cwd_fd
;
241 /* Apply the predicates to this path. */
242 eval_tree
= get_eval_tree();
243 apply_predicate(ent
->fts_path
, pstat
, eval_tree
);
245 /* Deal with any side effects of applying the predicates. */
246 if (state
.stop_at_current_level
)
248 fts_set(p
, ent
, FTS_SKIP
);
253 partial_quotearg_n(int n
, char *s
, size_t len
, enum quoting_style style
)
257 return quotearg_n_style(n
, style
, "");
266 result
= quotearg_n_style(n
, style
, s
);
273 /* We've detected a filesystem loop. This is caused by one of
276 * 1. Option -L is in effect and we've hit a symbolic link that
277 * points to an ancestor. This is harmless. We won't traverse the
280 * 2. We have hit a real cycle in the directory hierarchy. In this
281 * case, we issue a diagnostic message (POSIX requires this) and we
282 * skip that directory entry.
285 issue_loop_warning(FTSENT
* ent
)
287 if (S_ISLNK(ent
->fts_statp
->st_mode
))
290 _("Symbolic link %s is part of a loop in the directory hierarchy; we have already visited the directory to which it points."),
291 safely_quote_err_filename(0, ent
->fts_path
));
295 /* We have found an infinite loop. POSIX requires us to
296 * issue a diagnostic. Usually we won't get to here
297 * because when the leaf optimisation is on, it will cause
298 * the subdirectory to be skipped. If /a/b/c/d is a hard
299 * link to /a/b, then the link count of /a/b/c is 2,
300 * because the ".." entry of /a/b/c/d points to /a, not
304 _("Filesystem loop detected; "
305 "%s is part of the same filesystem loop as %s."),
306 safely_quote_err_filename(0, ent
->fts_path
),
307 partial_quotearg_n(1,
308 ent
->fts_cycle
->fts_path
,
309 ent
->fts_cycle
->fts_pathlen
,
310 options
.err_quoting_style
));
315 * Return true if NAME corresponds to a file which forms part of a
316 * symbolic link loop. The command
317 * rm -f a b; ln -s a b; ln -s b a
318 * produces such a loop.
321 symlink_loop(const char *name
)
325 if (following_links())
326 rv
= stat(name
, &stbuf
);
328 rv
= lstat(name
, &stbuf
);
329 return (0 != rv
) && (ELOOP
== errno
);
334 complete_execdirs_cb(void *context
)
337 /* By the tme this callback is called, the current directory is correct. */
338 complete_pending_execdirs(AT_FDCWD
);
343 show_outstanding_execdirs(FILE *fp
)
345 if (options
.debug_options
& DebugExec
)
350 fprintf(fp
, "Outstanding execdirs:");
356 if (pred_is(p
, pred_execdir
))
358 else if (pred_is(p
, pred_okdir
))
365 const struct exec_val
*execp
= &p
->args
.exec_vec
;
368 fprintf(fp
, "%s ", pfx
);
370 fprintf(fp
, "multiple ");
371 fprintf(fp
, "%d args: ", execp
->state
.cmd_argc
);
372 for (i
=0; i
<execp
->state
.cmd_argc
; ++i
)
374 fprintf(fp
, "%s ", execp
->state
.cmd_argv
[i
]);
381 fprintf(fp
, " none\n");
385 /* No debug output is wanted. */
393 consider_visiting(FTS
*p
, FTSENT
*ent
)
399 if (options
.debug_options
& DebugSearch
)
401 "consider_visiting: fts_info=%-6s, fts_level=%2d, prev_depth=%d "
402 "fts_path=%s, fts_accpath=%s\n",
403 get_fts_info_name(ent
->fts_info
),
404 (int)ent
->fts_level
, prev_depth
,
405 quotearg_n_style(0, options
.err_quoting_style
, ent
->fts_path
),
406 quotearg_n_style(1, options
.err_quoting_style
, ent
->fts_accpath
));
408 if (ent
->fts_info
== FTS_DP
)
412 else if (ent
->fts_level
> prev_depth
|| ent
->fts_level
==0)
416 inside_dir(p
->fts_cwd_fd
);
417 prev_depth
= ent
->fts_level
;
420 /* Cope with various error conditions. */
421 if (ent
->fts_info
== FTS_ERR
422 || ent
->fts_info
== FTS_DNR
)
424 error(0, ent
->fts_errno
, "%s",
425 safely_quote_err_filename(0, ent
->fts_path
));
429 else if (ent
->fts_info
== FTS_DC
)
431 issue_loop_warning(ent
);
435 else if (ent
->fts_info
== FTS_SLNONE
)
437 /* fts_read() claims that ent->fts_accpath is a broken symbolic
438 * link. That would be fine, but if this is part of a symbolic
439 * link loop, we diagnose the problem and also ensure that the
440 * eventual return value is nonzero. Note that while the path
441 * we stat is local (fts_accpath), we print the fill path name
442 * of the file (fts_path) in the error message.
444 if (symlink_loop(ent
->fts_accpath
))
446 error(0, ELOOP
, "%s", safely_quote_err_filename(0, ent
->fts_path
));
451 else if (ent
->fts_info
== FTS_NS
)
453 if (ent
->fts_level
== 0)
455 /* e.g., nonexistent starting point */
456 error(0, ent
->fts_errno
, "%s",
457 safely_quote_err_filename(0, ent
->fts_path
));
458 error_severity(1); /* remember problem */
463 /* The following if statement fixes Savannah bug #19605
464 * (failure to diagnose a symbolic link loop)
466 if (symlink_loop(ent
->fts_accpath
))
468 error(0, ELOOP
, "%s",
469 safely_quote_err_filename(0, ent
->fts_path
));
476 /* Cope with the usual cases. */
477 if (ent
->fts_info
== FTS_NSOK
478 || ent
->fts_info
== FTS_NS
/* e.g. symlink loop */)
480 assert(!state
.have_stat
);
481 assert(!state
.have_type
);
482 state
.type
= mode
= 0;
486 state
.have_stat
= true;
487 state
.have_type
= true;
488 statbuf
= *(ent
->fts_statp
);
489 state
.type
= mode
= statbuf
.st_mode
;
493 /* Savannah bug #16378. */
494 error(0, 0, _("Warning: file %s appears to have mode 0000"),
495 quotearg_n_style(0, options
.err_quoting_style
, ent
->fts_path
));
501 if (!digest_mode(mode
, ent
->fts_path
, ent
->fts_name
, &statbuf
, 0))
505 /* examine this item. */
507 isdir
= S_ISDIR(statbuf
.st_mode
)
508 || (FTS_D
== ent
->fts_info
)
509 || (FTS_DP
== ent
->fts_info
)
510 || (FTS_DC
== ent
->fts_info
);
512 if (isdir
&& (ent
->fts_info
== FTS_NSOK
))
514 /* This is a directory, but fts did not stat it, so
515 * presumably would not be planning to search its
516 * children. Force a stat of the file so that the
517 * children can be checked.
519 fts_set(p
, ent
, FTS_AGAIN
);
523 if (options
.maxdepth
>= 0)
525 if (ent
->fts_level
>= options
.maxdepth
)
527 fts_set(p
, ent
, FTS_SKIP
); /* descend no further */
529 if (ent
->fts_level
> options
.maxdepth
)
530 ignore
= 1; /* don't even look at this one */
534 if ( (ent
->fts_info
== FTS_D
) && !options
.do_dir_first
)
536 /* this is the preorder visit, but user said -depth */
539 else if ( (ent
->fts_info
== FTS_DP
) && options
.do_dir_first
)
541 /* this is the postorder visit, but user didn't say -depth */
544 else if (ent
->fts_level
< options
.mindepth
)
551 visit(p
, ent
, &statbuf
);
554 /* XXX: if we allow a build-up of pending arguments for "-execdir foo {} +"
555 * we need to execute them in the same directory as we found the item.
556 * If we are trying to do "find a -execdir echo {} +", we will need to
558 * a while in the original working directory
560 * c while in b (just before leaving b)
562 * These restrictions are hard to satisfy while using fts(). The reason is
563 * that it doesn't tell us just before we leave a directory. For the moment,
564 * we punt and don't allow the arguments to build up.
566 if (state
.execdirs_outstanding
)
568 show_outstanding_execdirs(stderr
);
569 run_in_dir(p
->fts_cwd_fd
, complete_execdirs_cb
, NULL
);
572 if (ent
->fts_info
== FTS_DP
)
574 /* we're leaving a directory. */
575 state
.stop_at_current_level
= false;
589 state
.starting_path_length
= strlen(arg
);
590 inside_dir(AT_FDCWD
);
595 switch (options
.symlink_handling
)
597 case SYMLINK_ALWAYS_DEREF
:
598 ftsoptions
|= FTS_COMFOLLOW
|FTS_LOGICAL
;
601 case SYMLINK_DEREF_ARGSONLY
:
602 ftsoptions
|= FTS_COMFOLLOW
|FTS_PHYSICAL
;
605 case SYMLINK_NEVER_DEREF
:
606 ftsoptions
|= FTS_PHYSICAL
;
610 if (options
.stay_on_filesystem
)
611 ftsoptions
|= FTS_XDEV
;
613 p
= fts_open(arglist
, ftsoptions
, NULL
);
616 error (0, errno
, _("cannot search %s"),
617 safely_quote_err_filename(0, arg
));
621 while ( (ent
=fts_read(p
)) != NULL
)
623 state
.have_stat
= false;
624 state
.have_type
= false;
626 consider_visiting(p
, ent
);
635 process_all_startpoints(int argc
, char *argv
[])
639 /* figure out how many start points there are */
640 for (i
= 0; i
< argc
&& !looks_like_expression(argv
[i
], true); i
++)
642 state
.starting_path_length
= strlen(argv
[i
]); /* TODO: is this redundant? */
649 * We use a temporary variable here because some actions modify
650 * the path temporarily. Hence if we use a string constant,
651 * we get a coredump. The best example of this is if we say
652 * "find -printf %H" (note, not "find . -printf %H").
654 char defaultpath
[2] = ".";
663 main (int argc
, char **argv
)
665 int end_of_leading_options
= 0; /* First arg after any -H/-L etc. */
666 struct predicate
*eval_tree
;
668 program_name
= argv
[0];
669 state
.exit_status
= 0;
670 state
.execdirs_outstanding
= false;
671 state
.cwd_dir_fd
= AT_FDCWD
;
673 /* Set the option defaults before we do the the locale
674 * initialisation as check_nofollow() needs to be executed in the
677 set_option_defaults(&options
);
679 #ifdef HAVE_SETLOCALE
680 setlocale (LC_ALL
, "");
683 bindtextdomain (PACKAGE
, LOCALEDIR
);
684 textdomain (PACKAGE
);
685 atexit (close_stdout
);
687 /* Check for -P, -H or -L options. Also -D and -O, which are
688 * both GNU extensions.
690 end_of_leading_options
= process_leading_options(argc
, argv
);
692 if (options
.debug_options
& DebugStat
)
693 options
.xstat
= debug_stat
;
696 fprintf (stderr
, "cur_day_start = %s", ctime (&options
.cur_day_start
));
700 /* We are now processing the part of the "find" command line
701 * after the -H/-L options (if any).
703 eval_tree
= build_expression_tree(argc
, argv
, end_of_leading_options
);
705 /* safely_chdir() needs to check that it has ended up in the right place.
706 * To avoid bailing out when something gets automounted, it checks if
707 * the target directory appears to have had a directory mounted on it as
708 * we chdir()ed. The problem with this is that in order to notice that
709 * a filesystem was mounted, we would need to lstat() all the mount points.
710 * That strategy loses if our machine is a client of a dead NFS server.
712 * Hence if safely_chdir() and wd_sanity_check() can manage without needing
713 * to know the mounted device list, we do that.
715 if (!options
.open_nofollow_available
)
717 #ifdef STAT_MOUNTPOINTS
718 init_mounted_dev_list();
723 starting_desc
= open (".", O_RDONLY
724 #if defined O_LARGEFILE
728 if (0 <= starting_desc
&& fchdir (starting_desc
) != 0)
730 close (starting_desc
);
733 if (starting_desc
< 0)
735 starting_dir
= xgetcwd ();
737 error (1, errno
, _("cannot get current directory"));
741 process_all_startpoints(argc
-end_of_leading_options
, argv
+end_of_leading_options
);
743 /* If "-exec ... {} +" has been used, there may be some
744 * partially-full command lines which have been built,
745 * but which are not yet complete. Execute those now.
747 show_success_rates(eval_tree
);
749 return state
.exit_status
;
753 is_fts_enabled(int *fts_options
)
755 /* this version of find (i.e. this main()) uses fts. */
756 *fts_options
= ftsoptions
;