static bool process_all_startpoints (int argc, char *argv[]) { int i; /* figure out how many start points there are */ for (i = 0; i < argc && !looks_like_expression (argv[i], true); i++) { state.starting_path_length = strlen (argv[i]); /* TODO: is this redundant? */ if (!find (argv[i])) return false; } if (i == 0) { /* * We use a temporary variable here because some actions modify * the path temporarily. Hence if we use a string constant, * we get a coredump. The best example of this is if we say * "find -printf %H" (note, not "find . -printf %H"). */ char defaultpath[2] = "."; return find (defaultpath); } return true; }
/* CAUTION: this is the entry point for the oldfind executable, which is not the binary that * will actually get installed. See ftsfind.c. */ int main (int argc, char **argv) { int i; int end_of_leading_options = 0; /* First arg after any -H/-L etc. */ struct predicate *eval_tree; if (argv[0]) set_program_name (argv[0]); else set_program_name ("find"); state.exit_status = 0; if (fd_leak_check_is_enabled ()) { remember_non_cloexec_fds (); } record_initial_cwd (); state.already_issued_stat_error_msg = false; state.shared_files = sharefile_init ("w"); if (NULL == state.shared_files) { error (EXIT_FAILURE, errno, _("Failed to initialize shared-file hash table")); } /* Set the option defaults before we do the locale * initialisation as check_nofollow () needs to be executed in the * POSIX locale. */ set_option_defaults (&options); #ifdef HAVE_SETLOCALE setlocale (LC_ALL, ""); #endif bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); if (atexit (close_stdin)) { error (EXIT_FAILURE, errno, _("The atexit library function failed")); } /* Check for -P, -H or -L options. */ end_of_leading_options = process_leading_options (argc, argv); if (options.debug_options & DebugStat) options.xstat = debug_stat; #ifdef DEBUG fprintf (stderr, "cur_day_start = %s", ctime (&options.cur_day_start)); #endif /* DEBUG */ /* state.cwd_dir_fd has to be initialized before we call build_expression_tree () * because command-line parsing may lead us to stat some files. */ state.cwd_dir_fd = AT_FDCWD; /* We are now processing the part of the "find" command line * after the -H/-L options (if any). */ eval_tree = build_expression_tree (argc, argv, end_of_leading_options); /* safely_chdir () needs to check that it has ended up in the right place. * To avoid bailing out when something gets automounted, it checks if * the target directory appears to have had a directory mounted on it as * we chdir ()ed. The problem with this is that in order to notice that * a file system was mounted, we would need to lstat () all the mount points. * That strategy loses if our machine is a client of a dead NFS server. * * Hence if safely_chdir () and wd_sanity_check () can manage without needing * to know the mounted device list, we do that. */ if (!options.open_nofollow_available) { #ifdef STAT_MOUNTPOINTS init_mounted_dev_list (0); #endif } set_stat_placeholders (&starting_stat_buf); if ((*options.xstat) (".", &starting_stat_buf) != 0) error (EXIT_FAILURE, errno, _("cannot stat current directory")); /* If no paths are given, default to ".". */ for (i = end_of_leading_options; i < argc && !looks_like_expression (argv[i], true); i++) { process_top_path (argv[i], 0, starting_stat_buf.st_ino); } /* If there were no path arguments, default to ".". */ if (i == end_of_leading_options) { /* * We use a temporary variable here because some actions modify * the path temporarily. Hence if we use a string constant, * we get a coredump. The best example of this is if we say * "find -printf %H" (note, not "find . -printf %H"). */ char defaultpath[2] = "."; process_top_path (defaultpath, 0, starting_stat_buf.st_ino); } /* If "-exec ... {} +" has been used, there may be some * partially-full command lines which have been built, * but which are not yet complete. Execute those now. */ show_success_rates (eval_tree); cleanup (); return state.exit_status; }
struct predicate* build_expression_tree (int argc, char *argv[], int end_of_leading_options) { const struct parser_table *parse_entry; /* Pointer to the parsing table entry for this expression. */ char *predicate_name; /* Name of predicate being parsed. */ struct predicate *cur_pred; const struct parser_table *entry_close, *entry_print, *entry_open; int i, oldi; predicates = NULL; /* Find where in ARGV the predicates begin by skipping the list of * start points. As a side effect, also figure out which is the * first and last start point. */ start_points = argv + end_of_leading_options; for (i = end_of_leading_options; i < argc && !looks_like_expression(argv[i], true); i++) { ++num_start_points; } /* Enclose the expression in `( ... )' so a default -print will apply to the whole expression. */ entry_open = find_parser ("("); entry_close = find_parser (")"); entry_print = find_parser ("print"); assert (entry_open != NULL); assert (entry_close != NULL); assert (entry_print != NULL); parse_openparen (entry_open, argv, &argc); last_pred->p_name = "("; predicates->artificial = true; parse_begin_user_args (argv, argc, last_pred, predicates); pred_sanity_check (last_pred); /* Build the input order list. */ while (i < argc ) { state.already_issued_stat_error_msg = false; if (!looks_like_expression (argv[i], false)) { error (0, 0, _("paths must precede expression: %s"), argv[i]); usage (stderr, 1, NULL); } predicate_name = argv[i]; parse_entry = find_parser (predicate_name); if (parse_entry == NULL) { /* Command line option not recognized */ error (EXIT_FAILURE, 0, _("unknown predicate `%s'"), predicate_name); } /* We have recognised a test of the form -foo. Eat that, * unless it is a predicate like -newerXY. */ if (parse_entry->type != ARG_SPECIAL_PARSE) { i++; } oldi = i; if (!(*(parse_entry->parser_func)) (parse_entry, argv, &i)) { if (argv[i]) { if ( (ARG_SPECIAL_PARSE == parse_entry->type) && (i == oldi) ) { /* The special parse function spat out the * predicate. It must be invalid, or not tasty. */ error (EXIT_FAILURE, 0, _("invalid predicate `%s'"), predicate_name); } else { error (EXIT_FAILURE, 0, _("invalid argument `%s' to `%s'"), argv[i], predicate_name); } } else { /* Command line option requires an argument */ error (EXIT_FAILURE, 0, _("missing argument to `%s'"), predicate_name); } } else { last_pred->p_name = predicate_name; /* If the parser consumed an argument, save it. */ if (i != oldi) last_pred->arg_text = argv[oldi]; else last_pred->arg_text = NULL; } pred_sanity_check(last_pred); pred_sanity_check(predicates); /* XXX: expensive */ } parse_end_user_args (argv, argc, last_pred, predicates); if (predicates->pred_next == NULL) { /* No predicates that do something other than set a global variable were given; remove the unneeded initial `(' and add `-print'. */ cur_pred = predicates; predicates = last_pred = predicates->pred_next; free (cur_pred); parse_print (entry_print, argv, &argc); last_pred->p_name = "-print"; pred_sanity_check(last_pred); pred_sanity_check(predicates); /* XXX: expensive */ } else if (!default_prints (predicates->pred_next)) { /* One or more predicates that produce output were given; remove the unneeded initial `('. */ cur_pred = predicates; predicates = predicates->pred_next; pred_sanity_check (predicates); /* XXX: expensive */ free (cur_pred); } else { /* `( user-supplied-expression ) -print'. */ parse_closeparen (entry_close, argv, &argc); last_pred->p_name = ")"; last_pred->artificial = true; pred_sanity_check (last_pred); parse_print (entry_print, argv, &argc); last_pred->p_name = "-print"; last_pred->artificial = true; pred_sanity_check (last_pred); pred_sanity_check (predicates); /* XXX: expensive */ } if (options.debug_options & (DebugExpressionTree|DebugTreeOpt)) { fprintf (stderr, "Predicate List:\n"); print_list (stderr, predicates); } /* do a sanity check */ check_option_combinations (predicates); pred_sanity_check (predicates); /* Done parsing the predicates. Build the evaluation tree. */ cur_pred = predicates; eval_tree = get_expr (&cur_pred, NO_PREC, NULL); calculate_derived_rates (eval_tree); /* Check if we have any left-over predicates (this fixes * Debian bug #185202). */ if (cur_pred != NULL) { /* cur_pred->p_name is often NULL here */ if (pred_is (cur_pred, pred_closeparen)) { /* e.g. "find \( -true \) \)" */ error (EXIT_FAILURE, 0, _("you have too many ')'")); } else { if (cur_pred->p_name) error (EXIT_FAILURE, 0, _("unexpected extra predicate '%s'"), cur_pred->p_name); else error (EXIT_FAILURE, 0, _("unexpected extra predicate")); } } if (options.debug_options & (DebugExpressionTree|DebugTreeOpt)) { fprintf (stderr, "Eval Tree:\n"); print_tree (stderr, eval_tree, 0); } estimate_costs (eval_tree); /* Rearrange the eval tree in optimal-predicate order. */ opt_expr (&eval_tree); /* Check that the tree is in normalised order (opt_expr does this) */ check_normalization (eval_tree, true); do_arm_swaps (eval_tree); /* Check that the tree is still in normalised order */ check_normalization (eval_tree, true); if (options.debug_options & (DebugExpressionTree|DebugTreeOpt)) { fprintf (stderr, "Optimized Eval Tree:\n"); print_tree (stderr, eval_tree, 0); fprintf (stderr, "Optimized command line:\n"); print_optlist (stderr, eval_tree); fprintf (stderr, "\n"); } return eval_tree; }