From 8440b32a3339eb4cf1e5b22621411fb91c7c1ad0 Mon Sep 17 00:00:00 2001 From: Kamil Dudka Date: Mon, 5 Apr 2010 23:53:06 +0000 Subject: [PATCH] - avoid assertion failure due to access permissions (#579476) --- findutils-4.5.7-bz579476.patch | 586 +++++++++++++++++++++++++++++++++ findutils.spec | 9 +- 2 files changed, 594 insertions(+), 1 deletion(-) create mode 100644 findutils-4.5.7-bz579476.patch diff --git a/findutils-4.5.7-bz579476.patch b/findutils-4.5.7-bz579476.patch new file mode 100644 index 0000000..60db1f3 --- /dev/null +++ b/findutils-4.5.7-bz579476.patch @@ -0,0 +1,586 @@ + ChangeLog | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ + NEWS | 1 + + find/defs.h | 12 ++++++- + find/find.c | 8 +++-- + find/ftsfind.c | 53 ++++++++++++++++------------------ + find/parser.c | 10 +++--- + find/pred.c | 8 ++-- + find/sharefile.c | 2 +- + find/tree.c | 1 + + find/util.c | 83 ++++++++++++++++++++++++++++++++++++++++++----------- + 10 files changed, 191 insertions(+), 61 deletions(-) + +diff --git a/ChangeLog b/ChangeLog +index abe1993..8bcae9b 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,77 @@ ++ 2010-04-05 James Youngman ++ ++ Don't issue an error message twice for the same target file. ++ * find/defs.h (struct state): New member, ++ already_issued_stat_error_msg, used to de-duplicate error ++ messages. If it is true, we already issued an error message for ++ the current target file. ++ Declare fatal_target_file_error, fatal_nontarget_file_error, ++ nonfatal_target_file_error, nonfatal_nontarget_file_error. ++ Between them, they replace fatal_file_error and ++ nonfatal_file_error. The *target_file_error versions are ++ de-duplicated and the nontarget_file_error_versions are not. ++ * find/util.c (nonfatal_nontarget_file_error): Implement. ++ (fatal_nontarget_file_error): Implement. ++ (nonfatal_target_file_error): Implement. ++ (fatal_target_file_error): Implement. ++ (fatal_file_error): Remove. ++ (nonfatal_file_error): Remove. ++ (error_severity): Define error_severity (moved from ftsfind.c) ++ (get_statinfo): Call nonfatal_target_file_error in order to avoid ++ a duplicate message. ALso call error_severity after a different ++ call to error to preserve the constraint that we exit with a ++ nonzero status if we issue a diagnostic. ++ (cleanup): Call nonfatal_nontarget_file_error instead of ++ nonfatal_file_error. ++ * find/tree.c (build_expression_tree): Initialise ++ state.already_issued_stat_error_msg. ++ * find/find.c (main): Initialise state.already_issued_stat_error_msg. ++ (wd_sanity_check): Call fatal_target_file_error instead of ++ fatal_file_error. ++ (chdir_back): Call fatal_nontarget_file_error instead of ++ fatal_file_error. ++ (process_path): Initialise state.already_issued_stat_error_msg. ++ * find/ftsfind.c (consider_visiting): Call ++ nonfatal_target_file_error instead of calling error directly. ++ (find): Call error_severity to ensure exit status is nonzero after ++ a call to error. ++ (main): Initialise state.already_issued_stat_error_msg. ++ (error_severity): Move to util.c. ++ * find/parser.c (collect_arg_stat_info): Call ++ fatal_target_file_error instead of fatal_file_error. ++ (parse_newerXY): Likewise. ++ (parse_samefile): Likewise. ++ (parse_samefile): Likewise. ++ (open_output_file): Call fatal_nontarget_file_error instead of ++ fatal_file_error. ++ * find/pred.c (checked_fprintf): Likewise. ++ (checked_print_quoted): Likewise. ++ (checked_fwrite): Likewise. ++ (checked_fflush): Likewise. ++ * find/sharefile.c (entry_free): Likewise. ++ ++ Fix Savannah bug #29435: fd_is_cloexec does not work on Fedora ++ buildhosts. ++ Fix open_cloexec on hosts which ignore O_CLOEXEC (i.e. old kernels). ++ * lib/fdleak.c (o_cloexec_works): New function, detects whether ++ the open flag O_CLOEXEC has any effect. ++ (open_cloexec): Call o_cloexec_works, just once, to find out ++ whether O_CLOEXEC is effective. If not, set the close-on-exec ++ flag on fds by calling set_cloexec_flag. ++ * NEWS: Mention this bugfix. ++ ++2010-04-04 Martin von Gagern ++ ++ Fix Savannah bug #27213: avoid failed assertions for ++ non-executable directories. ++ (consider_visiting): Continue (after issuing an error message) ++ even if ent->fts_info == FTS_NS. ++ * find/util.c (get_statinfo): If we cannot stat the file, issue a ++ diagnostic, but continue anyway. ++ * find/ftsfind.c (consider_visiting): Don't assert-fail if ++ ent->fts_info == FTS_NSOK. Don't assert-fail if state.type is ++ nonzero. ++ + 2010-04-04 James Youngman + + Fix Savannah bug #29435: fd_is_cloexec does not work on Fedora +diff --git a/NEWS b/NEWS +index e171b87..3f81b88 100644 +--- a/NEWS ++++ b/NEWS +@@ -4,6 +4,7 @@ GNU findutils NEWS - User visible changes. -*- outline -*- (allout) + + #29435: fd_is_cloexec does not work on Fedora buildhosts + ++#27213: avoid failed assertions for non-executable directories. + + * Major changes in release 4.5.7, 2010-04-03 + +diff --git a/find/defs.h b/find/defs.h +index 4ade8f4..b2e255a 100644 +--- a/find/defs.h ++++ b/find/defs.h +@@ -504,11 +504,16 @@ extern boolean check_nofollow(void); + void complete_pending_execs(struct predicate *p); + void complete_pending_execdirs(int dir_fd); /* Passing dir_fd is an unpleasant CodeSmell. */ + const char *safely_quote_err_filename (int n, char const *arg); +-void fatal_file_error(const char *name) ATTRIBUTE_NORETURN; +-void nonfatal_file_error(const char *name); ++ ++void fatal_target_file_error (int errno_value, const char *name) ATTRIBUTE_NORETURN; ++void fatal_nontarget_file_error (int errno_value, const char *name) ATTRIBUTE_NORETURN; ++void nonfatal_target_file_error (int erron_value, const char *name); ++void nonfatal_nontarget_file_error (int erron_value, const char *name); ++ + + int process_leading_options PARAMS((int argc, char *argv[])); + void set_option_defaults PARAMS((struct options *p)); ++void error_severity PARAMS((int level)); + + #if 0 + #define apply_predicate(pathname, stat_buf_ptr, node) \ +@@ -669,6 +674,9 @@ struct state + + /* Shared files, opened via the interface in sharefile.h. */ + sharefile_handle shared_files; ++ ++ /* Avoid multiple error messages for the same file. */ ++ boolean already_issued_stat_error_msg; + }; + + /* finddata.c */ +diff --git a/find/find.c b/find/find.c +index 336e120..e058814 100644 +--- a/find/find.c ++++ b/find/find.c +@@ -135,6 +135,7 @@ main (int argc, char **argv) + remember_non_cloexec_fds (); + } + ++ state.already_issued_stat_error_msg = false; + state.shared_files = sharefile_init ("w"); + if (NULL == state.shared_files) + { +@@ -472,7 +473,7 @@ wd_sanity_check (const char *thing_to_stat, + + set_stat_placeholders (newinfo); + if ((*options.xstat) (current_dir, newinfo) != 0) +- fatal_file_error (thing_to_stat); ++ fatal_target_file_error (errno, thing_to_stat); + + if (old_dev != newinfo->st_dev) + { +@@ -943,7 +944,7 @@ chdir_back (void) + #endif + + if (chdir (starting_dir) != 0) +- fatal_file_error (starting_dir); ++ fatal_nontarget_file_error (errno, starting_dir); + + wd_sanity_check (starting_dir, + program_name, +@@ -962,7 +963,7 @@ chdir_back (void) + + if (fchdir (starting_desc) != 0) + { +- fatal_file_error (starting_dir); ++ fatal_nontarget_file_error (errno, starting_dir); + } + } + } +@@ -1183,6 +1184,7 @@ process_path (char *pathname, char *name, boolean leaf, char *parent, + state.type = 0; + state.have_stat = false; + state.have_type = false; ++ state.already_issued_stat_error_msg = false; + + if (!digest_mode (&mode, pathname, name, &stat_buf, leaf)) + return 0; +diff --git a/find/ftsfind.c b/find/ftsfind.c +index b3a08f9..692d9f5 100644 +--- a/find/ftsfind.c ++++ b/find/ftsfind.c +@@ -173,18 +173,6 @@ inside_dir (int dir_fd) + static void init_mounted_dev_list (void); + #endif + +-/* We have encountered an error which should affect the exit status. +- * This is normally used to change the exit status from 0 to 1. +- * However, if the exit status is already 2 for example, we don't want to +- * reduce it to 1. +- */ +-static void +-error_severity (int level) +-{ +- if (state.exit_status < level) +- state.exit_status = level; +-} +- + + #define STRINGIFY(X) #X + #define HANDLECASE(N) case N: return #N; +@@ -371,9 +359,6 @@ show_outstanding_execdirs (FILE *fp) + /* No debug output is wanted. */ + } + } +- +- +- + + static void + consider_visiting (FTS *p, FTSENT *ent) +@@ -410,15 +395,13 @@ consider_visiting (FTS *p, FTSENT *ent) + if (ent->fts_info == FTS_ERR + || ent->fts_info == FTS_DNR) + { +- error (0, ent->fts_errno, "%s", +- safely_quote_err_filename (0, ent->fts_path)); +- error_severity (1); ++ nonfatal_target_file_error (ent->fts_errno, ent->fts_path); + return; + } + else if (ent->fts_info == FTS_DC) + { + issue_loop_warning (ent); +- error_severity (1); ++ error_severity (EXIT_FAILURE); + return; + } + else if (ent->fts_info == FTS_SLNONE) +@@ -432,8 +415,7 @@ consider_visiting (FTS *p, FTSENT *ent) + */ + if (symlink_loop (ent->fts_accpath)) + { +- error (0, ELOOP, "%s", safely_quote_err_filename (0, ent->fts_path)); +- error_severity (1); ++ nonfatal_target_file_error (ELOOP, ent->fts_path); + return; + } + } +@@ -442,9 +424,7 @@ consider_visiting (FTS *p, FTSENT *ent) + if (ent->fts_level == 0) + { + /* e.g., nonexistent starting point */ +- error (0, ent->fts_errno, "%s", +- safely_quote_err_filename (0, ent->fts_path)); +- error_severity (1); /* remember problem */ ++ nonfatal_target_file_error (ent->fts_errno, ent->fts_path); + return; + } + else +@@ -454,11 +434,24 @@ consider_visiting (FTS *p, FTSENT *ent) + */ + if (symlink_loop (ent->fts_accpath)) + { +- error (0, ELOOP, "%s", +- safely_quote_err_filename (0, ent->fts_path)); +- error_severity (1); ++ nonfatal_target_file_error (ELOOP, ent->fts_path); + return; + } ++ else ++ { ++ nonfatal_target_file_error (ent->fts_errno, ent->fts_path); ++ /* Continue despite the error, as file name without stat info ++ * might be better than not even processing the file name. This ++ * can lead to repeated error messages later on, though, if a ++ * predicate requires stat information. ++ * ++ * Not printing an error message here would be even more wrong, ++ * though, as this could cause the contents of a directory to be ++ * silently ignored, as the directory wouldn't be identified as ++ * such. ++ */ ++ } ++ + } + } + +@@ -467,7 +460,7 @@ consider_visiting (FTS *p, FTSENT *ent) + || ent->fts_info == FTS_NS /* e.g. symlink loop */) + { + assert (!state.have_stat); +- assert (ent->fts_info == FTS_NSOK || state.type != 0); ++ assert (ent->fts_info == FTS_NSOK || state.type == 0); + mode = state.type; + } + else +@@ -621,11 +614,13 @@ find (char *arg) + { + error (0, errno, _("cannot search %s"), + safely_quote_err_filename (0, arg)); ++ error_severity (EXIT_FAILURE); + } + else + { + while ( (ent=fts_read (p)) != NULL ) + { ++ state.already_issued_stat_error_msg = false; + state.have_stat = false; + state.have_type = !!ent->fts_statp->st_mode; + state.type = state.have_type ? ent->fts_statp->st_mode : 0; +@@ -640,6 +635,7 @@ find (char *arg) + error (0, errno, + _("failed to restore working directory after searching %s"), + arg); ++ error_severity (EXIT_FAILURE); + return false; + } + p = NULL; +@@ -689,6 +685,7 @@ main (int argc, char **argv) + else + set_program_name ("find"); + ++ state.already_issued_stat_error_msg = false; + state.exit_status = 0; + state.execdirs_outstanding = false; + state.cwd_dir_fd = AT_FDCWD; +diff --git a/find/parser.c b/find/parser.c +index 8238671..8668ce4 100644 +--- a/find/parser.c ++++ b/find/parser.c +@@ -744,7 +744,7 @@ collect_arg_stat_info (char **argv, int *arg_ptr, struct stat *p, + } + else + { +- fatal_file_error (filename); ++ fatal_target_file_error (errno, filename); + } + } + else +@@ -1685,7 +1685,7 @@ parse_newerXY (const struct parser_table* entry, char **argv, int *arg_ptr) + /* Stat the named file. */ + set_stat_placeholders (&stat_newer); + if ((*options.xstat) (argv[*arg_ptr], &stat_newer)) +- fatal_file_error (argv[*arg_ptr]); ++ fatal_target_file_error (errno, argv[*arg_ptr]); + + if (!get_stat_Ytime (&stat_newer, y, &our_pred->args.reftime.ts)) + { +@@ -2425,7 +2425,7 @@ parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr) + */ + if (0 != fstat (fd, &fst)) + { +- fatal_file_error (argv[*arg_ptr]); ++ fatal_target_file_error (errno, argv[*arg_ptr]); + } + else + { +@@ -2435,7 +2435,7 @@ parse_samefile (const struct parser_table* entry, char **argv, int *arg_ptr) + * destination of the link, not the link itself. + */ + if ((*options.xstat) (argv[*arg_ptr], &st)) +- fatal_file_error (argv[*arg_ptr]); ++ fatal_target_file_error (errno, argv[*arg_ptr]); + + if ((options.symlink_handling == SYMLINK_NEVER_DEREF) + && (!options.open_nofollow_available)) +@@ -3799,7 +3799,7 @@ open_output_file (const char *path, struct format_val *p) + + if (p->stream == NULL) + { +- fatal_file_error (path); ++ fatal_nontarget_file_error (errno, path); + } + } + +diff --git a/find/pred.c b/find/pred.c +index cb61ed2..44db6a6 100644 +--- a/find/pred.c ++++ b/find/pred.c +@@ -696,7 +696,7 @@ checked_fprintf (struct format_val *dest, const char *fmt, ...) + va_start (ap, fmt); + rv = vfprintf (dest->stream, fmt, ap); + if (rv < 0) +- nonfatal_file_error (dest->filename); ++ nonfatal_nontarget_file_error (errno, dest->filename); + } + + +@@ -707,7 +707,7 @@ checked_print_quoted (struct format_val *dest, + int rv = print_quoted (dest->stream, dest->quote_opts, dest->dest_is_tty, + format, s); + if (rv < 0) +- nonfatal_file_error (dest->filename); ++ nonfatal_nontarget_file_error (errno, dest->filename); + } + + +@@ -716,7 +716,7 @@ checked_fwrite (void *p, size_t siz, size_t nmemb, struct format_val *dest) + { + int items_written = fwrite (p, siz, nmemb, dest->stream); + if (items_written < nmemb) +- nonfatal_file_error (dest->filename); ++ nonfatal_nontarget_file_error (errno, dest->filename); + } + + static void +@@ -724,7 +724,7 @@ checked_fflush (struct format_val *dest) + { + if (0 != fflush (dest->stream)) + { +- nonfatal_file_error (dest->filename); ++ nonfatal_nontarget_file_error (errno, dest->filename); + } + } + +diff --git a/find/sharefile.c b/find/sharefile.c +index 8e0f4cc..1442d7b 100644 +--- a/find/sharefile.c ++++ b/find/sharefile.c +@@ -76,7 +76,7 @@ entry_free (void *pv) + if (p->fp) + { + if (0 != fclose (p->fp)) +- fatal_file_error (p->name); ++ fatal_nontarget_file_error (errno, p->name); + } + free (p->name); + free (p); +diff --git a/find/tree.c b/find/tree.c +index 08f2f0a..d07b125 100644 +--- a/find/tree.c ++++ b/find/tree.c +@@ -1283,6 +1283,7 @@ build_expression_tree (int argc, char *argv[], int end_of_leading_options) + /* 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]); +diff --git a/find/util.c b/find/util.c +index 3761a61..a789131 100644 +--- a/find/util.c ++++ b/find/util.c +@@ -210,15 +210,14 @@ get_statinfo (const char *pathname, const char *name, struct stat *p) + /* Savannah bug #16378. */ + error (0, 0, _("WARNING: file %s appears to have mode 0000"), + quotearg_n_style (0, options.err_quoting_style, name)); ++ error_severity (1); + } + } + else + { + if (!options.ignore_readdir_race || (errno != ENOENT) ) + { +- error (0, errno, "%s", +- safely_quote_err_filename (0, pathname)); +- state.exit_status = 1; ++ nonfatal_target_file_error (errno, pathname); + } + return -1; + } +@@ -272,6 +271,10 @@ get_info (const char *pathname, + int result = get_statinfo (pathname, state.rel_pathname, p); + if (result != 0) + { ++ return -1; /* failure. */ ++ } ++ else ++ { + /* Verify some postconditions. We can't check st_mode for + non-zero-ness because of Savannah bug #16378 (which is + that broken NFS servers can return st_mode==0). */ +@@ -283,10 +286,6 @@ get_info (const char *pathname, + { + assert (p->st_ino); + } +- return -1; /* failure. */ +- } +- else +- { + return 0; /* success. */ + } + } +@@ -486,7 +485,7 @@ cleanup (void) + } + + if (fflush (stdout) == EOF) +- nonfatal_file_error ("standard output"); ++ nonfatal_nontarget_file_error (errno, "standard output"); + } + + /* Savannah bug #16378 manifests as an assertion failure in pred_type() +@@ -1074,35 +1073,83 @@ safely_quote_err_filename (int n, char const *arg) + return quotearg_n_style (n, options.err_quoting_style, arg); + } + ++/* We have encountered an error which should affect the exit status. ++ * This is normally used to change the exit status from 0 to 1. ++ * However, if the exit status is already 2 for example, we don't want to ++ * reduce it to 1. ++ */ ++void ++error_severity (int level) ++{ ++ if (state.exit_status < level) ++ state.exit_status = level; ++} ++ + /* report_file_err + */ + static void +-report_file_err(int exitval, int errno_value, const char *name) ++report_file_err(int exitval, int errno_value, ++ boolean is_target_file, const char *name) + { + /* It is important that the errno value is passed in as a function + * argument before we call safely_quote_err_filename(), because otherwise + * we might find that safely_quote_err_filename() changes errno. + */ +- if (state.exit_status < 1) +- state.exit_status = 1; +- +- error (exitval, errno_value, "%s", safely_quote_err_filename (0, name)); ++ if (!is_target_file || !state.already_issued_stat_error_msg) ++ { ++ error (exitval, errno_value, "%s", safely_quote_err_filename (0, name)); ++ error_severity (1); ++ } ++ if (is_target_file) ++ { ++ state.already_issued_stat_error_msg = true; ++ } + } + +-/* fatal_file_error ++/* nonfatal_target_file_error + * + */ + void +-fatal_file_error(const char *name) ++nonfatal_target_file_error (int errno_value, const char *name) + { +- report_file_err (1, errno, name); ++ report_file_err (0, errno_value, true, name); ++} ++ ++/* fatal_target_file_error ++ * ++ * Report an error on a target file (i.e. a file we are searching). ++ * Such errors are only reported once per searched file. ++ * ++ */ ++void ++fatal_target_file_error(int errno_value, const char *name) ++{ ++ report_file_err (1, errno_value, true, name); + /*NOTREACHED*/ + abort (); + } + ++/* nonfatal_nontarget_file_error ++ * ++ */ + void +-nonfatal_file_error (const char *name) ++nonfatal_nontarget_file_error (int errno_value, const char *name) + { +- report_file_err (0, errno, name); ++ report_file_err (0, errno_value, false, name); + } + ++/* fatal_nontarget_file_error ++ * ++ */ ++void ++fatal_nontarget_file_error(int errno_value, const char *name) ++{ ++ /* We're going to exit fatally, so make sure we always isssue the error ++ * message, even if it will be duplicate. Motivation: otherwise it may ++ * not be clear what went wrong. ++ */ ++ state.already_issued_stat_error_msg = false; ++ report_file_err (1, errno_value, false, name); ++ /*NOTREACHED*/ ++ abort (); ++} diff --git a/findutils.spec b/findutils.spec index 8c3414e..0d1c777 100644 --- a/findutils.spec +++ b/findutils.spec @@ -1,7 +1,7 @@ Summary: The GNU versions of find utilities (find and xargs) Name: findutils Version: 4.5.7 -Release: 3%{?dist} +Release: 4%{?dist} Epoch: 1 License: GPLv3+ Group: Applications/File @@ -26,6 +26,9 @@ Patch4: findutils-4.5.7-warnings.patch # upstream commit a44cece Patch5: findutils-4.5.7-fdleak.patch +# rhbz #579476 (upstream bug #27213) +Patch6: findutils-4.5.7-bz579476.patch + Requires(post): /sbin/install-info Requires(preun): /sbin/install-info Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -53,6 +56,7 @@ useful for finding things on your system. %patch3 -p1 %patch4 -p1 %patch5 -p1 +%patch6 -p1 # needed because of findutils-4.4.0-no-locate.patch aclocal -I gnulib/m4 -I m4 @@ -110,6 +114,9 @@ rm -rf $RPM_BUILD_ROOT %{_infodir}/find-maint.info.gz %changelog +* Tue Apr 06 2010 Kamil Dudka - 1:4.5.7-4 +- avoid assertion failure due to access permissions (#579476) + * Sun Apr 04 2010 Kamil Dudka - 1:4.5.7-3 - upstream bugfix http://savannah.gnu.org/bugs/?29435