Fixed Savannah bug #19483
[findutils.git] / find / ftsfind.c
blobed87657085abf5dfce6ce44823cef74787ebc83d
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)
8 any later version.
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,
18 USA.*/
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>.
31 #include "defs.h"
34 #define USE_SAFE_CHDIR 1
35 #undef STAT_MOUNTPOINTS
38 #include <errno.h>
39 #include <assert.h>
41 #ifdef HAVE_FCNTL_H
42 #include <fcntl.h>
43 #else
44 #include <sys/file.h>
45 #endif
47 #include <unistd.h>
48 #if defined(HAVE_FCNTL_H)
49 #include <fcntl.h>
50 #endif
52 #include "../gnulib/lib/xalloc.h"
53 #include "closeout.h"
54 #include <modetype.h>
55 #include "quotearg.h"
56 #include "quote.h"
57 #include "fts_.h"
58 #include "openat.h"
59 #include "save-cwd.h"
61 #ifdef HAVE_LOCALE_H
62 #include <locale.h>
63 #endif
65 #if ENABLE_NLS
66 # include <libintl.h>
67 # define _(Text) gettext (Text)
68 #else
69 # define _(Text) Text
70 #define textdomain(Domain)
71 #define bindtextdomain(Package, Directory)
72 #endif
73 #ifdef gettext_noop
74 # define N_(String) gettext_noop (String)
75 #else
76 /* See locate.c for explanation as to why not use (String) */
77 # define N_(String) String
78 #endif
81 static void set_close_on_exec(int fd)
83 #if defined(F_GETFD) && defined(FD_CLOEXEC)
84 int flags;
85 flags = fcntl(fd, F_GETFD);
86 if (flags >= 0)
88 flags |= FD_CLOEXEC;
89 fcntl(fd, F_SETFD, flags);
91 #endif
96 /* FTS_TIGHT_CYCLE_CHECK tries to work around Savannah bug #17877
97 * (but actually using it doesn't fix the bug).
99 static int ftsoptions = FTS_NOSTAT|FTS_TIGHT_CYCLE_CHECK;
101 static int prev_depth = INT_MIN; /* fts_level can be < 0 */
102 static int curr_fd = -1;
104 int get_current_dirfd(void)
106 if (ftsoptions & FTS_CWDFD)
108 assert(curr_fd != -1);
109 assert( (AT_FDCWD == curr_fd) || (curr_fd >= 0) );
111 if (AT_FDCWD == curr_fd)
112 return starting_desc;
113 else
114 return curr_fd;
116 else
118 return AT_FDCWD;
122 static void left_dir(void)
124 if (ftsoptions & FTS_CWDFD)
126 if (curr_fd >= 0)
128 close(curr_fd);
129 curr_fd = -1;
132 else
134 /* do nothing. */
139 * Signal that we are now inside a directory pointed to by dirfd.
140 * The caller can't tell if this is the first time this happens, so
141 * we have to be careful not to call dup() more than once
143 static void inside_dir(int dirfd)
145 if (ftsoptions & FTS_CWDFD)
147 assert(dirfd == AT_FDCWD || dirfd >= 0);
149 state.cwd_dir_fd = dirfd;
150 if (curr_fd < 0)
152 if (AT_FDCWD == dirfd)
154 curr_fd = AT_FDCWD;
156 else if (dirfd >= 0)
158 curr_fd = dup(dirfd);
159 set_close_on_exec(curr_fd);
161 else
163 /* curr_fd is invalid, but dirfd is also invalid.
164 * This should not have happened.
166 assert(curr_fd >= 0 || dirfd >= 0);
170 else
172 /* FTS_CWDFD is not in use. We can always assume that
173 * AT_FDCWD refers to the directory we are currentl searching.
175 * Therefore there is nothing to do.
182 #ifdef STAT_MOUNTPOINTS
183 static void init_mounted_dev_list(void);
184 #endif
186 /* We have encountered an error which should affect the exit status.
187 * This is normally used to change the exit status from 0 to 1.
188 * However, if the exit status is already 2 for example, we don't want to
189 * reduce it to 1.
191 static void
192 error_severity(int level)
194 if (state.exit_status < level)
195 state.exit_status = level;
199 #define STRINGIFY(X) #X
200 #define HANDLECASE(N) case N: return #N;
202 static char *
203 get_fts_info_name(int info)
205 static char buf[10];
206 switch (info)
208 HANDLECASE(FTS_D);
209 HANDLECASE(FTS_DC);
210 HANDLECASE(FTS_DEFAULT);
211 HANDLECASE(FTS_DNR);
212 HANDLECASE(FTS_DOT);
213 HANDLECASE(FTS_DP);
214 HANDLECASE(FTS_ERR);
215 HANDLECASE(FTS_F);
216 HANDLECASE(FTS_INIT);
217 HANDLECASE(FTS_NS);
218 HANDLECASE(FTS_NSOK);
219 HANDLECASE(FTS_SL);
220 HANDLECASE(FTS_SLNONE);
221 HANDLECASE(FTS_W);
222 default:
223 sprintf(buf, "[%d]", info);
224 return buf;
228 static void
229 visit(FTS *p, FTSENT *ent, struct stat *pstat)
231 struct predicate *eval_tree;
233 state.curdepth = ent->fts_level;
234 state.have_stat = (ent->fts_info != FTS_NS) && (ent->fts_info != FTS_NSOK);
235 state.rel_pathname = ent->fts_accpath;
236 state.cwd_dir_fd = p->fts_cwd_fd;
238 /* Apply the predicates to this path. */
239 eval_tree = get_eval_tree();
240 (*(eval_tree)->pred_func)(ent->fts_path, pstat, eval_tree);
242 /* Deal with any side effects of applying the predicates. */
243 if (state.stop_at_current_level)
245 fts_set(p, ent, FTS_SKIP);
249 static const char*
250 partial_quotearg_n(int n, char *s, size_t len, enum quoting_style style)
252 if (0 == len)
254 return quotearg_n_style(n, style, "");
256 else
258 char saved;
259 const char *result;
261 saved = s[len];
262 s[len] = 0;
263 result = quotearg_n_style(n, style, s);
264 s[len] = saved;
265 return result;
270 /* We've detected a filesystem loop. This is caused by one of
271 * two things:
273 * 1. Option -L is in effect and we've hit a symbolic link that
274 * points to an ancestor. This is harmless. We won't traverse the
275 * symbolic link.
277 * 2. We have hit a real cycle in the directory hierarchy. In this
278 * case, we issue a diagnostic message (POSIX requires this) and we
279 * skip that directory entry.
281 static void
282 issue_loop_warning(FTSENT * ent)
284 if (S_ISLNK(ent->fts_statp->st_mode))
286 error(0, 0,
287 _("Symbolic link %s is part of a loop in the directory hierarchy; we have already visited the directory to which it points."),
288 quotearg_n_style(0, locale_quoting_style, ent->fts_path));
290 else
292 /* We have found an infinite loop. POSIX requires us to
293 * issue a diagnostic. Usually we won't get to here
294 * because when the leaf optimisation is on, it will cause
295 * the subdirectory to be skipped. If /a/b/c/d is a hard
296 * link to /a/b, then the link count of /a/b/c is 2,
297 * because the ".." entry of /a/b/c/d points to /a, not
298 * to /a/b/c.
300 error(0, 0,
301 _("Filesystem loop detected; "
302 "%s is part of the same filesystem loop as %s."),
303 quotearg_n_style(0, locale_quoting_style, ent->fts_path),
304 partial_quotearg_n(1,
305 ent->fts_cycle->fts_path,
306 ent->fts_cycle->fts_pathlen,
307 locale_quoting_style));
312 * Return true if NAME corresponds to a file which forms part of a
313 * symbolic link loop. The command
314 * rm -f a b; ln -s a b; ln -s b a
315 * produces such a loop.
317 static boolean
318 symlink_loop(const char *name)
320 struct stat stbuf;
321 int rv;
322 if (following_links())
323 rv = stat(name, &stbuf);
324 else
325 rv = lstat(name, &stbuf);
326 return (0 != rv) && (ELOOP == errno);
330 static int
331 complete_execdirs_cb(void *context)
333 (void) context;
334 /* By the tme this callback is called, the current directory is correct. */
335 complete_pending_execdirs(AT_FDCWD);
338 static int
339 show_outstanding_execdirs(FILE *fp)
341 if (options.debug_options & DebugExec)
343 int seen=0;
344 struct predicate *p;
345 p = get_eval_tree();
346 fprintf(fp, "Outstanding execdirs:");
348 while (p)
350 const char *pfx;
352 if (p->pred_func == pred_execdir)
353 pfx = "-execdir";
354 else if (p->pred_func == pred_okdir)
355 pfx = "-okdir";
356 else
357 pfx = NULL;
358 if (pfx)
360 int i;
361 const struct exec_val *execp = &p->args.exec_vec;
362 ++seen;
364 fprintf(fp, "%s ", pfx);
365 if (execp->multiple)
366 fprintf(fp, "multiple ");
367 fprintf(fp, "%d args: ", execp->state.cmd_argc);
368 for (i=0; i<execp->state.cmd_argc; ++i)
370 fprintf(fp, "%s ", execp->state.cmd_argv[i]);
372 fprintf(fp, "\n");
374 p = p->pred_next;
376 if (!seen)
377 fprintf(fp, " none\n");
379 else
381 /* No debug output is wanted. */
388 static void
389 consider_visiting(FTS *p, FTSENT *ent)
391 struct stat statbuf;
392 mode_t mode;
393 int ignore, isdir;
394 boolean dirchanged;
396 if (options.debug_options & DebugSearch)
397 fprintf(stderr,
398 "consider_visiting: fts_info=%-6s, fts_level=%2d, prev_depth=%d "
399 "fts_path=%s, fts_accpath=%s\n",
400 get_fts_info_name(ent->fts_info),
401 (int)ent->fts_level, prev_depth,
402 quotearg_n_style(0, locale_quoting_style, ent->fts_path),
403 quotearg_n_style(1, locale_quoting_style, ent->fts_accpath));
405 if (ent->fts_info == FTS_DP)
407 left_dir();
409 else if (ent->fts_level > prev_depth || ent->fts_level==0)
411 left_dir();
413 inside_dir(p->fts_cwd_fd);
414 prev_depth = ent->fts_level;
417 /* Cope with various error conditions. */
418 if (ent->fts_info == FTS_ERR
419 || ent->fts_info == FTS_DNR)
421 error(0, ent->fts_errno, ent->fts_path);
422 error_severity(1);
423 return;
425 else if (ent->fts_info == FTS_DC)
427 issue_loop_warning(ent);
428 error_severity(1);
429 return;
431 else if (ent->fts_info == FTS_SLNONE)
433 /* fts_read() claims that ent->fts_accpath is a broken symbolic
434 * link. That would be fine, but if this is part of a symbolic
435 * link loop, we diagnose the problem and also ensure that the
436 * eventual return value is nonzero. Note that while the path
437 * we stat is local (fts_accpath), we print the fill path name
438 * of the file (fts_path) in the error message.
440 if (symlink_loop(ent->fts_accpath))
442 error(0, ELOOP, ent->fts_path);
443 error_severity(1);
444 return;
447 else if (ent->fts_info == FTS_NS)
449 if (ent->fts_level == 0)
451 /* e.g., nonexistent starting point */
452 error(0, ent->fts_errno, ent->fts_path);
453 error_severity(1); /* remember problem */
454 return;
456 else
458 /* The following if statement fixes Savannah bug #19605
459 * (failure to diagnose a symbolic link loop)
461 if (symlink_loop(ent->fts_accpath))
463 error(0, ELOOP, ent->fts_path);
464 error_severity(1);
465 return;
470 /* Cope with the usual cases. */
471 if (ent->fts_info == FTS_NSOK
472 || ent->fts_info == FTS_NS /* e.g. symlink loop */)
474 assert(!state.have_stat);
475 assert(!state.have_type);
476 state.type = mode = 0;
478 else
480 state.have_stat = true;
481 state.have_type = true;
482 statbuf = *(ent->fts_statp);
483 state.type = mode = statbuf.st_mode;
486 if (mode)
488 if (!digest_mode(mode, ent->fts_path, ent->fts_name, &statbuf, 0))
489 return;
492 /* examine this item. */
493 ignore = 0;
494 isdir = S_ISDIR(statbuf.st_mode)
495 || (FTS_D == ent->fts_info)
496 || (FTS_DP == ent->fts_info)
497 || (FTS_DC == ent->fts_info);
499 if (isdir && (ent->fts_info == FTS_NSOK))
501 /* This is a directory, but fts did not stat it, so
502 * presumably would not be planning to search its
503 * children. Force a stat of the file so that the
504 * children can be checked.
506 fts_set(p, ent, FTS_AGAIN);
507 return;
510 if (options.maxdepth >= 0)
512 if (ent->fts_level >= options.maxdepth)
514 fts_set(p, ent, FTS_SKIP); /* descend no further */
516 if (ent->fts_level > options.maxdepth)
517 ignore = 1; /* don't even look at this one */
521 if ( (ent->fts_info == FTS_D) && !options.do_dir_first )
523 /* this is the preorder visit, but user said -depth */
524 ignore = 1;
526 else if ( (ent->fts_info == FTS_DP) && options.do_dir_first )
528 /* this is the postorder visit, but user didn't say -depth */
529 ignore = 1;
531 else if (ent->fts_level < options.mindepth)
533 ignore = 1;
536 if (!ignore)
538 visit(p, ent, &statbuf);
541 /* XXX: if we allow a build-up of pending arguments for "-execdir foo {} +"
542 * we need to execute them in the same directory as we found the item.
543 * If we are trying to do "find a -execdir echo {} +", we will need to
544 * echo
545 * a while in the original working directory
546 * b while in a
547 * c while in b (just before leaving b)
549 * These restrictions are hard to satisfy while using fts(). The reason is
550 * that it doesn't tell us just before we leave a directory. For the moment,
551 * we punt and don't allow the arguments to build up.
553 if (state.execdirs_outstanding)
555 show_outstanding_execdirs(stderr);
556 run_in_dir(p->fts_cwd_fd, complete_execdirs_cb);
559 if (ent->fts_info == FTS_DP)
561 /* we're leaving a directory. */
562 state.stop_at_current_level = false;
568 static void
569 find(char *arg)
571 char * arglist[2];
572 FTS *p;
573 FTSENT *ent;
576 state.starting_path_length = strlen(arg);
577 inside_dir(AT_FDCWD);
579 arglist[0] = arg;
580 arglist[1] = NULL;
582 switch (options.symlink_handling)
584 case SYMLINK_ALWAYS_DEREF:
585 ftsoptions |= FTS_COMFOLLOW|FTS_LOGICAL;
586 break;
588 case SYMLINK_DEREF_ARGSONLY:
589 ftsoptions |= FTS_COMFOLLOW|FTS_PHYSICAL;
590 break;
592 case SYMLINK_NEVER_DEREF:
593 ftsoptions |= FTS_PHYSICAL;
594 break;
597 if (options.stay_on_filesystem)
598 ftsoptions |= FTS_XDEV;
600 p = fts_open(arglist, ftsoptions, NULL);
601 if (NULL == p)
603 error (0, errno,
604 _("cannot search %s"),
605 quotearg_n_style(0, locale_quoting_style, arg));
607 else
609 while ( (ent=fts_read(p)) != NULL )
611 state.have_stat = false;
612 state.have_type = false;
613 state.type = 0;
614 consider_visiting(p, ent);
616 fts_close(p);
617 p = NULL;
622 static void
623 process_all_startpoints(int argc, char *argv[])
625 int i;
627 /* figure out how many start points there are */
628 for (i = 0; i < argc && !looks_like_expression(argv[i], true); i++)
630 state.starting_path_length = strlen(argv[i]); /* TODO: is this redundant? */
631 find(argv[i]);
634 if (i == 0)
637 * We use a temporary variable here because some actions modify
638 * the path temporarily. Hence if we use a string constant,
639 * we get a coredump. The best example of this is if we say
640 * "find -printf %H" (note, not "find . -printf %H").
642 char defaultpath[2] = ".";
643 find(defaultpath);
651 main (int argc, char **argv)
653 int end_of_leading_options = 0; /* First arg after any -H/-L etc. */
654 struct predicate *eval_tree;
656 program_name = argv[0];
657 state.exit_status = 0;
658 state.execdirs_outstanding = false;
659 state.cwd_dir_fd = AT_FDCWD;
661 /* Set the option defaults before we do the the locale
662 * initialisation as check_nofollow() needs to be executed in the
663 * POSIX locale.
665 set_option_defaults(&options);
667 #ifdef HAVE_SETLOCALE
668 setlocale (LC_ALL, "");
669 #endif
671 bindtextdomain (PACKAGE, LOCALEDIR);
672 textdomain (PACKAGE);
673 atexit (close_stdout);
675 /* Check for -P, -H or -L options. Also -D and -O, which are
676 * both GNU extensions.
678 end_of_leading_options = process_leading_options(argc, argv);
680 if (options.debug_options & DebugStat)
681 options.xstat = debug_stat;
683 #ifdef DEBUG
684 fprintf (stderr, "cur_day_start = %s", ctime (&options.cur_day_start));
685 #endif /* DEBUG */
688 /* We are now processing the part of the "find" command line
689 * after the -H/-L options (if any).
691 eval_tree = build_expression_tree(argc, argv, end_of_leading_options);
693 /* safely_chdir() needs to check that it has ended up in the right place.
694 * To avoid bailing out when something gets automounted, it checks if
695 * the target directory appears to have had a directory mounted on it as
696 * we chdir()ed. The problem with this is that in order to notice that
697 * a filesystem was mounted, we would need to lstat() all the mount points.
698 * That strategy loses if our machine is a client of a dead NFS server.
700 * Hence if safely_chdir() and wd_sanity_check() can manage without needing
701 * to know the mounted device list, we do that.
703 if (!options.open_nofollow_available)
705 #ifdef STAT_MOUNTPOINTS
706 init_mounted_dev_list();
707 #endif
711 starting_desc = open (".", O_RDONLY
712 #if defined O_LARGEFILE
713 |O_LARGEFILE
714 #endif
716 if (0 <= starting_desc && fchdir (starting_desc) != 0)
718 close (starting_desc);
719 starting_desc = -1;
721 if (starting_desc < 0)
723 starting_dir = xgetcwd ();
724 if (! starting_dir)
725 error (1, errno, _("cannot get current directory"));
729 process_all_startpoints(argc-end_of_leading_options, argv+end_of_leading_options);
731 /* If "-exec ... {} +" has been used, there may be some
732 * partially-full command lines which have been built,
733 * but which are not yet complete. Execute those now.
735 cleanup();
736 return state.exit_status;
739 boolean
740 is_fts_enabled(int *fts_options)
742 /* this version of find (i.e. this main()) uses fts. */
743 *fts_options = ftsoptions;
744 return true;