commit 3afccfd019b92ae43602d73e169f833fd13d545b Author: overweight <5324761+overweight@user.noreply.gitee.com> Date: Mon Sep 30 10:38:48 2019 -0400 Package init diff --git a/Fix-bug-48314-find-fix-type-option-regression-on-som.patch b/Fix-bug-48314-find-fix-type-option-regression-on-som.patch new file mode 100644 index 0000000..ab8106a --- /dev/null +++ b/Fix-bug-48314-find-fix-type-option-regression-on-som.patch @@ -0,0 +1,108 @@ +From 26d48c7cf9c25ddc8874d5483c0b5156dcc62132 Mon Sep 17 00:00:00 2001 +From: Maximiliano Curia +Date: Thu, 30 Jun 2016 01:18:17 +0200 +Subject: [PATCH 069/224] Fix bug #48314: find: fix -type option regression on + some platforms + +Since commit v4.6.0-61-g6c37ce4, the option -type and -ltype is broken +on armel, armhf and mipsel at least. The reason is that the union member +args of the struct predicate was not completely initialized as its new +bool types[] member may be implemented larger than the union member +initialized: str. + +* find/tree.c (set_new_parent): Replace xmalloc() by xzalloc() to +initialize the complete new predicate structure. Therefore, remove all +individual NULL and false initializations. +(get_new_pred): Likewise, plus move the xzmalloc() invocations before +the if-condition to have only one place left for the allocation, thus +improving readability. + +Reported by Andreas Metzler in +https://savannah.gnu.org/bugs/?48314 + +Co-authored-by: Bernhard Voelker +Copyright-paperwork-exempt: Yes +--- + find/tree.c | 31 +++++-------------------------- + 1 file changed, 5 insertions(+), 26 deletions(-) + +diff --git a/find/tree.c b/find/tree.c +index 8a413f88..2bbfbe5a 100644 +--- a/find/tree.c ++++ b/find/tree.c +@@ -865,14 +865,11 @@ set_new_parent (struct predicate *curr, enum predicate_precedence high_prec, str + { + struct predicate *new_parent; + +- new_parent = xmalloc (sizeof (struct predicate)); ++ /* Allocate + initialize a new predicate. */ ++ new_parent = xzalloc (sizeof (struct predicate)); + new_parent->p_type = BI_OP; + new_parent->p_prec = high_prec; +- new_parent->need_stat = false; +- new_parent->need_type = false; +- new_parent->need_inum = false; + new_parent->p_cost = NeedsNothing; +- new_parent->arg_text = NULL; + + switch (high_prec) + { +@@ -895,14 +892,8 @@ set_new_parent (struct predicate *curr, enum predicate_precedence high_prec, str + ; /* empty */ + } + +- new_parent->side_effects = false; +- new_parent->no_default_print = false; +- new_parent->args.str = NULL; +- new_parent->pred_next = NULL; +- + /* Link in new_parent. + Pushes rest of left branch down 1 level to new_parent->pred_right. */ +- new_parent->pred_left = NULL; + new_parent->pred_right = curr; + *prevp = new_parent; + +@@ -1488,37 +1479,25 @@ get_new_pred (const struct parser_table *entry) + assert (entry->type != ARG_OPTION); + assert (entry->type != ARG_POSITIONAL_OPTION); + ++ /* Allocate + initialize a new predicate. */ ++ new_pred = xzalloc (sizeof (struct predicate)); + if (predicates == NULL) + { +- predicates = (struct predicate *) +- xmalloc (sizeof (struct predicate)); +- last_pred = predicates; ++ last_pred = predicates = new_pred; + } + else + { +- new_pred = xmalloc (sizeof (struct predicate)); + last_pred->pred_next = new_pred; + last_pred = new_pred; + } + last_pred->parser_entry = entry; +- last_pred->pred_func = NULL; +- last_pred->p_name = NULL; + last_pred->p_type = NO_TYPE; + last_pred->p_prec = NO_PREC; +- last_pred->side_effects = false; +- last_pred->no_default_print = false; + last_pred->need_stat = true; + last_pred->need_type = true; +- last_pred->need_inum = false; + last_pred->p_cost = NeedsUnknown; + last_pred->arg_text = "ThisShouldBeSetToSomethingElse"; +- last_pred->args.str = NULL; +- last_pred->args.scontext = NULL; +- last_pred->pred_next = NULL; +- last_pred->pred_left = NULL; +- last_pred->pred_right = NULL; + last_pred->literal_control_chars = options.literal_control_chars; +- last_pred->artificial = false; + last_pred->est_success_rate = 1.0; + init_pred_perf (last_pred); + return last_pred; +-- +2.19.1 + diff --git a/Remove-the-enable-id-cache-configure-option.patch b/Remove-the-enable-id-cache-configure-option.patch new file mode 100644 index 0000000..45ad0b0 --- /dev/null +++ b/Remove-the-enable-id-cache-configure-option.patch @@ -0,0 +1,32 @@ +From bcd85897c2e55d955c325f72791d3ff99eacf820 Mon Sep 17 00:00:00 2001 +From: James Youngman +Date: Wed, 30 Dec 2015 20:23:22 +0000 +Subject: [PATCH 011/224] Remove the --enable-id-cache configure option. + +* configure.ac: Remove the --enable-id-cache option. This option +became a no-op in findutils-4.5.15. Before that it did something +but the code was buggy. See https://savannah.gnu.org/bugs/?45062 +for details. +* NEWS: State that this configure option is removed. +--- + NEWS | 5 +++++ + configure.ac | 3 --- + 2 files changed, 5 insertions(+), 3 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 0b9ef281..bfc94f1c 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -15,9 +15,6 @@ AC_SUBST(AUXDIR,$ac_aux_dir) + dnl check for --with-fts + FIND_WITH_FTS + +-AC_ARG_ENABLE(id-cache, +-[ --enable-id-cache This currently has no effect.],) +- + AC_ARG_ENABLE(debug, + AS_HELP_STRING(--enable-debug,Enable debugging output which is likely to be interesting to people debugging findutils), + [ac_cv_debug=$enableval],[ac_cv_debug=no]) +-- +2.19.1 + diff --git a/Shorten-output-of-qmark_chars-after-replacing-a-mult.patch b/Shorten-output-of-qmark_chars-after-replacing-a-mult.patch new file mode 100644 index 0000000..9a37d11 --- /dev/null +++ b/Shorten-output-of-qmark_chars-after-replacing-a-mult.patch @@ -0,0 +1,30 @@ +From bb51d3581d52890cd1c2b0e5ee919c00b0ba9eb5 Mon Sep 17 00:00:00 2001 +From: James Youngman +Date: Thu, 5 Jul 2018 13:34:06 +0100 +Subject: [PATCH 175/224] Shorten output of qmark_chars after replacing a + multibyte characer. + +When qmark_chars() replaces a multibyte character with a single +character, this reduces the length of the string. When this happens, +terminate the now-shorter string at the new length. + +This is simple workaround for bug http://savannah.gnu.org/bugs/?54236. +--- + lib/printquoted.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/printquoted.c b/lib/printquoted.c +index 5a31664b..14665c95 100644 +--- a/lib/printquoted.c ++++ b/lib/printquoted.c +@@ -62,6 +62,7 @@ print_quoted (FILE *fp, + + /* Replace any remaining funny characters with '?'. */ + len = qmark_chars (buf, len); ++ buf[len] = 0; + + rv = fprintf (fp, format, buf); /* Print the quoted version */ + if (buf != smallbuf) +-- +2.19.1 + diff --git a/find-Fix-a-number-of-compiler-warnings-mostly-const-.patch b/find-Fix-a-number-of-compiler-warnings-mostly-const-.patch new file mode 100644 index 0000000..0e639b4 --- /dev/null +++ b/find-Fix-a-number-of-compiler-warnings-mostly-const-.patch @@ -0,0 +1,217 @@ +From e7b976a7e8b4023bd9ac2493341320f88aa9189c Mon Sep 17 00:00:00 2001 +From: James Youngman +Date: Sat, 2 Jan 2016 13:04:24 +0000 +Subject: [PATCH 023/224] find: Fix a number of compiler warnings (mostly + const-correctness). + +* find/find.c (get_current_dirfd): remove unused function. +(process_dir): make parameters const: parent, pathname, name. +(process_path): make parameters const: parent, pathname, name. +(at_top): Modify the function pointer parameter accordingly. +* find/ftsfind.c (get_fts_info_name): Now returns const char*, not +char*. +(show_outstanding_execdirs): Fix type of loop variable to avoid +possible overflow. +(process_all_startpoints): Avoid compiler warning about overflow +of int loop variable. +* find/defs.h (struct predicate): Make p_name const. +(struct state): make rel_pathname const. +* find/exec.c (impl_pred_exec): Make prefix const. +(launch): Silence compiler warning about unused parameter argc. +* find/pred.c (blank_rtrim): Make str parameter const, since we do +not modify it. +* find/util.c (debug_option_assoc): name and docstring are now +const qualified. +(show_valid_debug_options): Avoid signed/unsigned comparison by +using a size_t array index. +(set_stat_placeholders): Avoid a compiler warning on systems +lacking birth time fields (and on which this function therefore +does nothing). +--- + find/defs.h | 3 ++- + find/exec.c | 4 +++- + find/ftsfind.c | 6 ++++-- + find/oldfind.c | 28 +++++++++++++--------------- + find/util.c | 5 +++-- + 5 files changed, 25 insertions(+), 21 deletions(-) + +diff --git a/find/defs.h b/find/defs.h +index a4647e83..981c5336 100644 +--- a/find/defs.h ++++ b/find/defs.h +@@ -633,7 +633,8 @@ struct state + + /* The file being operated on, relative to the current directory. + Used for stat, readlink, remove, and opendir. */ +- char *rel_pathname; ++ const char *rel_pathname; ++ + /* The directory fd to which rel_pathname is relative. This is relevant + * when we're navigating the hierarchy with fts() and using FTS_CWDFD. + */ +diff --git a/find/exec.c b/find/exec.c +index f8bd4389..8d20143f 100644 +--- a/find/exec.c ++++ b/find/exec.c +@@ -114,7 +114,7 @@ impl_pred_exec (const char *pathname, + const char *target; + bool result; + const bool local = is_exec_in_local_dir (pred_ptr->pred_func); +- char *prefix; ++ const char *prefix; + size_t pfxlen; + + (void) stat_buf; +@@ -292,6 +292,8 @@ launch (struct buildcmd_control *ctl, void *usercontext, int argc, char **argv) + static int first_time = 1; + struct exec_val *execp = usercontext; + ++ (void) argc; /* silence compiler warning */ ++ + /* Make sure output of command doesn't get mixed with find output. */ + fflush (stdout); + fflush (stderr); +diff --git a/find/ftsfind.c b/find/ftsfind.c +index cbb46de9..5128e574 100644 +--- a/find/ftsfind.c ++++ b/find/ftsfind.c +@@ -152,7 +152,7 @@ static void init_mounted_dev_list (void); + #define STRINGIFY(X) #X + #define HANDLECASE(N) case N: return #N; + +-static char * ++static const char * + get_fts_info_name (int info) + { + static char buf[10]; +@@ -615,16 +615,18 @@ static bool + process_all_startpoints (int argc, char *argv[]) + { + int i; ++ bool empty = true; + + /* figure out how many start points there are */ + for (i = 0; i < argc && !looks_like_expression (argv[i], true); i++) + { ++ empty = false; + state.starting_path_length = strlen (argv[i]); /* TODO: is this redundant? */ + if (!find (argv[i])) + return false; + } + +- if (i == 0) ++ if (empty) + { + /* + * We use a temporary variable here because some actions modify +diff --git a/find/oldfind.c b/find/oldfind.c +index 986e7b4c..cd235c06 100644 +--- a/find/oldfind.c ++++ b/find/oldfind.c +@@ -95,11 +95,9 @@ enum + static void init_mounted_dev_list (int mandatory); + #endif + +-static void process_top_path (char *pathname, mode_t mode, ino_t inum); +-static int process_path (char *pathname, char *name, bool leaf, char *parent, mode_t type, ino_t inum); +-static void process_dir (char *pathname, char *name, int pathlen, const struct stat *statp, char *parent); +- +- ++static void process_top_path (const char *pathname, mode_t mode, ino_t inum); ++static int process_path (const char *pathname, const char *name, bool leaf, const char *parent, mode_t type, ino_t inum); ++static void process_dir (const char *pathname, const char *name, int pathlen, const struct stat *statp, const char *parent); + + /* A file descriptor open to the initial working directory. + Doing it this way allows us to work when the i.w.d. has +@@ -981,12 +979,12 @@ chdir_back (void) + * specified directory is a child of "." or is the root directory. + */ + static void +-at_top (char *pathname, ++at_top (const char *pathname, + mode_t mode, + ino_t inum, + struct stat *pstat, +- void (*action)(char *pathname, +- char *basename, ++ void (*action)(const char *pathname, ++ const char *basename, + int mode, + ino_t inum, + struct stat *pstat)) +@@ -1056,8 +1054,8 @@ at_top (char *pathname, + } + + +-static void do_process_top_dir (char *pathname, +- char *base, ++static void do_process_top_dir (const char *pathname, ++ const char *base, + int mode, + ino_t inum, + struct stat *pstat) +@@ -1069,8 +1067,8 @@ static void do_process_top_dir (char *pathname, + } + + static void +-do_process_predicate (char *pathname, +- char *base, ++do_process_predicate (const char *pathname, ++ const char *base, + int mode, + ino_t inum, + struct stat *pstat) +@@ -1095,7 +1093,7 @@ do_process_predicate (char *pathname, + and move to that. + */ + static void +-process_top_path (char *pathname, mode_t mode, ino_t inum) ++process_top_path (const char *pathname, mode_t mode, ino_t inum) + { + at_top (pathname, mode, inum, NULL, do_process_top_dir); + } +@@ -1181,7 +1179,7 @@ issue_loop_warning (const char *name, const char *pathname, int level) + Return nonzero iff PATHNAME is a directory. */ + + static int +-process_path (char *pathname, char *name, bool leaf, char *parent, ++process_path (const char *pathname, const char *name, bool leaf, const char *parent, + mode_t mode, ino_t inum) + { + struct stat stat_buf; +@@ -1307,7 +1305,7 @@ process_path (char *pathname, char *name, bool leaf, char *parent, + starting directory. */ + + static void +-process_dir (char *pathname, char *name, int pathlen, const struct stat *statp, char *parent) ++process_dir (const char *pathname, const char *name, int pathlen, const struct stat *statp, const char *parent) + { + int subdirs_left; /* Number of unexamined subdirs in PATHNAME. */ + bool subdirs_unreliable; /* if true, cannot use dir link count as subdir limif (if false, it may STILL be unreliable) */ +diff --git a/find/util.c b/find/util.c +index cf7965fc..1b4a07af 100644 +--- a/find/util.c ++++ b/find/util.c +@@ -55,9 +55,9 @@ + + struct debug_option_assoc + { +- char *name; ++ const char *name; + int val; +- char *docstring; ++ const char *docstring; + }; + static struct debug_option_assoc debugassoc[] = + { +@@ -176,6 +176,7 @@ usage (FILE *fp, int status, char *msg) + void + set_stat_placeholders (struct stat *p) + { ++ (void) p; /* silence warning for systems lacking these fields. */ + #if HAVE_STRUCT_STAT_ST_BIRTHTIME + p->st_birthtime = 0; + #endif +-- +2.19.1 + diff --git a/find-avoid-buffer-overflow-with-printf-T.patch b/find-avoid-buffer-overflow-with-printf-T.patch new file mode 100644 index 0000000..209c71e --- /dev/null +++ b/find-avoid-buffer-overflow-with-printf-T.patch @@ -0,0 +1,34 @@ +From febde26dd0e66dda5d4060fa29b85443ddc6a865 Mon Sep 17 00:00:00 2001 +From: Bernhard Voelker +Date: Mon, 28 Aug 2017 23:15:12 +0200 +Subject: [PATCH 117/224] find: avoid buffer-overflow with -printf '%T+' + +* find/print.c (format_date): Increase size of local variable +FMT to match the longest possible content. + +Fixes https://bugs.debian.org/873032 reported upstream by +Andreas Metzler in https://savannah.gnu.org/bugs/?51841; +fix proposed by Kamil Dudka. + +Bug introduced in commit v4.6.0-111-g95816b2, so no released version +ever saw this; therefore not adding a NEWS entry. +--- + find/print.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/find/print.c b/find/print.c +index 682197f4..6b568d9c 100644 +--- a/find/print.c ++++ b/find/print.c +@@ -611,7 +611,7 @@ format_date (struct timespec ts, int kind) + char ns_buf[NS_BUF_LEN]; /* -.9999999990 (- sign can happen!)*/ + int charsprinted, need_ns_suffix; + struct tm *tm; +- char fmt[6]; ++ char fmt[12]; + + /* human_readable() assumes we pass a buffer which is at least as + * long as LONGEST_HUMAN_READABLE. We use an assertion here to +-- +2.19.1 + diff --git a/find-avoid-strftime-s-non-portable-F-specifier.patch b/find-avoid-strftime-s-non-portable-F-specifier.patch new file mode 100644 index 0000000..fc5ed64 --- /dev/null +++ b/find-avoid-strftime-s-non-portable-F-specifier.patch @@ -0,0 +1,33 @@ +From 95816b29d46fb6b64754d4a66e7d918b3f134a1f Mon Sep 17 00:00:00 2001 +From: James Youngman +Date: Sun, 23 Jul 2017 22:19:42 +0100 +Subject: [PATCH 110/224] find: avoid strftime's non-portable %F specifier. + +* find/print.c (format_date): Avoid passing %F to strftime since +some implementation lack it. Pass the synonymous %Y-%m-%d +instead. This fixes a bug manifesting on HP Tru64 UNIX V5.1B. +Reported by Steven M. Schweda . +--- + find/print.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/find/print.c b/find/print.c +index db6155c9..682197f4 100644 +--- a/find/print.c ++++ b/find/print.c +@@ -631,7 +631,11 @@ format_date (struct timespec ts, int kind) + /* Format the main part of the time. */ + if (kind == '+') + { +- strcpy (fmt, "%F+%T"); ++ /* Avoid %F, some Unix versions lack it. For example: ++ HP Tru64 UNIX V5.1B (Rev. 2650); Wed Feb 17 22:59:59 CST 2016 ++ Also, some older HP-UX versions expand %F as the full month (like %B). ++ Reported by Steven M. Schweda */ ++ strcpy (fmt, "%Y-%m-%d+%T"); + need_ns_suffix = 1; + } + else +-- +2.19.1 + diff --git a/find-avoid-usage-in-more-error-cases.patch b/find-avoid-usage-in-more-error-cases.patch new file mode 100644 index 0000000..fe6c07f --- /dev/null +++ b/find-avoid-usage-in-more-error-cases.patch @@ -0,0 +1,43 @@ +From 50a7c5d1f572d50d6c9d43d04e9c9fd55d66b466 Mon Sep 17 00:00:00 2001 +From: Bernhard Voelker +Date: Thu, 10 Aug 2017 08:45:56 +0200 +Subject: [PATCH 113/224] find: avoid usage() in more error cases + +When the user passes a bad command line, then find(1) outputs the +error message followed by a short usage() text, e.g. (wrapped): + + $ find . -name a* b* + find: paths must precede expression: bfile + Usage: find [-H] [-L] [-P] [-Olevel] \ + [-D help|tree|search|stat|rates|opt|exec] [path...] [expression] + +Omit the usage() text in more cases like this in order to make the +error diagnostic more eye-catching. + +* find/tree.c (build_expression_tree): Exit with EXIT_FAILURE +immediately in more cases, i.e., without outputting also a short +usage() text. While at it, add quotes around the offending argument +in one another place. +* NEWS (Improvements): Mention the fix. + +Reported in https://savannah.gnu.org/bugs/?51711 +--- + NEWS | 3 +++ + find/tree.c | 17 +++++------------ + 2 files changed, 8 insertions(+), 12 deletions(-) +diff --git a/find/tree.c b/find/tree.c +index 2bbfbe5a..ee466ea6 100644 +--- a/find/tree.c ++++ b/find/tree.c +@@ -1281,10 +1281,7 @@ + { + 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); +- } ++ error (EXIT_FAILURE, 0, _("paths must precede expression: `%s'"), argv[i]); + + predicate_name = argv[i]; + parse_entry = find_parser (predicate_name); diff --git a/find-fix-memory-leak-in-mount-list-handling.patch b/find-fix-memory-leak-in-mount-list-handling.patch new file mode 100644 index 0000000..9ebd92b --- /dev/null +++ b/find-fix-memory-leak-in-mount-list-handling.patch @@ -0,0 +1,45 @@ +From c1556892a639f609e6d63cd456c2062419e06459 Mon Sep 17 00:00:00 2001 +From: Goffredo Baroncelli +Date: Fri, 27 Jan 2017 02:16:08 +0100 +Subject: [PATCH 090/224] find: fix memory leak in mount list handling + +The following gnulib commit added the structure member me_mntroot +which our free_file_system_list function didn't consider, thus leading +to a memory leak: +http://git.sv.gnu.org/cgit/gnulib.git/commit/?id=c6148bca89e9 + +* find/fstype.c (free_file_system_list): Use gnulib's free_mount_entry +function to free the mount list instead of free()ing all members here +manually. +* NEWS (Bug Fixes): Mention the fix. + +Reported in +http://lists.gnu.org/archive/html/findutils-patches/2016-12/msg00000.html +--- + NEWS | 3 +++ + find/fstype.c | 9 +-------- + 2 files changed, 4 insertions(+), 8 deletions(-) + +diff --git a/find/fstype.c b/find/fstype.c +index 535f9202..a0ac8bca 100644 +--- a/find/fstype.c ++++ b/find/fstype.c +@@ -75,14 +75,7 @@ free_file_system_list (struct mount_entry *p) + while (p) + { + struct mount_entry *pnext = p->me_next; +- +- free (p->me_devname); +- free (p->me_mountdir); +- +- if (p->me_type_malloced) +- free (p->me_type); +- p->me_next = NULL; +- free (p); ++ free_mount_entry (p); + p = pnext; + } + } +-- +2.19.1 + diff --git a/find-fix-printf-Y-output-to-N-for-broken-links.patch b/find-fix-printf-Y-output-to-N-for-broken-links.patch new file mode 100644 index 0000000..3cef09f --- /dev/null +++ b/find-fix-printf-Y-output-to-N-for-broken-links.patch @@ -0,0 +1,80 @@ +From 7b7a19c95f236cd18f48e44b7cc6794d21c0369f Mon Sep 17 00:00:00 2001 +From: Bernhard Voelker +Date: Fri, 20 Jul 2018 10:07:13 +0200 +Subject: [PATCH 181/224] find: fix -printf %Y output to 'N' for broken links + +The format %Y shall output 'N' for broken links (ENOENT), 'L' for ELOOP, +and '?' for any other error when stat()ing the symlink target. + +The %Y implementation implicitly fell back to lstat(); therefore it +output 'l' for dangling symlinks. + + $ ln -s ENOENT DANGLE + $ find -D stat DANGLE -printf '%y %Y %p\n' + fallback_stat(): stat(DANGLE) failed; falling back on lstat() + l l DANGLE + +* find/print.c (do_fprintf): For %Y, always follow links to determine +the type of the symlink target. +* find/testsuite/find.gnu/printf-symlink.exp: Add a test case for broken +links and the ELOOP case ... +* find/testsuite/find.gnu/printf-symlink.xo: ... with the expected output. +* NEWS (Bug fixes): Mention the fix. + +Bug introduced in version v4.5.8 with commit '25e7c5fbf9'. +--- + NEWS | 4 ++++ + find/print.c | 9 +++++---- + find/testsuite/find.gnu/printf-symlink.exp | 5 ++++- + find/testsuite/find.gnu/printf-symlink.xo | 4 ++++ + 4 files changed, 17 insertions(+), 5 deletions(-) + +diff --git a/find/print.c b/find/print.c +index 3af3e91d..545df96a 100644 +--- a/find/print.c ++++ b/find/print.c +@@ -1175,11 +1175,12 @@ do_fprintf (struct format_val *dest, + if (S_ISLNK (stat_buf->st_mode)) + { + struct stat sbuf; +- /* If we would normally follow links, do not do so. +- * If we would normally not follow links, do so. ++ /* %Y needs to stat the symlink target regardless of ++ * whether we would normally follow symbolic links or not. ++ * (Actually we do not even come here when following_links() ++ * other than the ENOENT case.) + */ +- if ((following_links () ? optionp_stat : optionl_stat) +- (state.rel_pathname, &sbuf) != 0) ++ if (fstatat (state.cwd_dir_fd, state.rel_pathname, &sbuf, 0) != 0) + { + if ( errno == ENOENT ) + { +diff --git a/find/testsuite/find.gnu/printf-symlink.exp b/find/testsuite/find.gnu/printf-symlink.exp +index 6acc3e68..453f07fc 100644 +--- a/find/testsuite/find.gnu/printf-symlink.exp ++++ b/find/testsuite/find.gnu/printf-symlink.exp +@@ -2,5 +2,8 @@ exec rm -rf tmp + exec mkdir tmp + exec touch tmp/file + exec ln -s file tmp/LINK +-find_start p {tmp/LINK -printf "RESULT: %y %Y %p\n" -printf "RESULT2: %Y %y %p\n" } ++exec ln -s ENOENT tmp/DANGLE ++exec ln -s SELF tmp/SELF ++exec ls -ls tmp ++find_start p {tmp/LINK tmp/DANGLE tmp/SELF -printf "RESULT: %y %Y %p\n" -printf "RESULT2: %Y %y %p\n" } + exec rm -rf tmp +diff --git a/find/testsuite/find.gnu/printf-symlink.xo b/find/testsuite/find.gnu/printf-symlink.xo +index cc2b69c4..08eb83c6 100644 +--- a/find/testsuite/find.gnu/printf-symlink.xo ++++ b/find/testsuite/find.gnu/printf-symlink.xo +@@ -1,2 +1,6 @@ + RESULT: l f tmp/LINK + RESULT2: f l tmp/LINK ++RESULT: l N tmp/DANGLE ++RESULT2: N l tmp/DANGLE ++RESULT: l L tmp/SELF ++RESULT2: L l tmp/SELF +-- +2.19.1 + diff --git a/find-fix-printf-h-for-arguments-with-one-or-more-tra.patch b/find-fix-printf-h-for-arguments-with-one-or-more-tra.patch new file mode 100644 index 0000000..5159a75 --- /dev/null +++ b/find-fix-printf-h-for-arguments-with-one-or-more-tra.patch @@ -0,0 +1,250 @@ +From 2a6129bfccec9f23a50f037e187f85c4d000bc87 Mon Sep 17 00:00:00 2001 +From: Bernhard Voelker +Date: Mon, 20 Feb 2017 18:53:48 +0100 +Subject: [PATCH 098/224] find: fix -printf '%h' for arguments with one or more + trailing slashes + +Previously, find would output the pathname name for the '%h' format +when that was passed with a trailing slash: + + $ mkdir foo + $ find foo/ -printf '%h/%f\n' + foo/foo/ + +* find/print.c (do_fprintf -> 'h'): Strip trailing slashes, i.e. any +number of directory separators, unless this is the root "/" directory. +* find/testsuite/find.gnu/printf-h.exp: Enhance test with various +combinations of "/", "./", "foo/", "./foo", "./foolink/", etc. +* find/testsuite/find.gnu/printf-h.xo: Add the expected output for the +above new test cases. +* NEWS: Mention the fix. + +Bug introduced in commit FINDUTILS_4_2_18-1-6-g0fd15a4. + +Reported by Tavian Barnes in + https://savannah.gnu.org/bugs/?50259 +--- + NEWS | 8 ++- + find/print.c | 21 +++++-- + find/testsuite/find.gnu/printf-h.exp | 94 ++++++++++++++++++++++++++-- + find/testsuite/find.gnu/printf-h.xo | 70 ++++++++++++++++++++- + 4 files changed, 181 insertions(+), 12 deletions(-) + +diff --git a/find/print.c b/find/print.c +index 20351572..db6155c9 100644 +--- a/find/print.c ++++ b/find/print.c +@@ -965,8 +965,18 @@ do_fprintf (struct format_val *dest, + case 'h': /* leading directories part of path */ + /* sanitised */ + { +- cp = strrchr (pathname, '/'); +- if (cp == NULL) /* No leading directories. */ ++ char *pname = strdup (pathname); ++ ++ /* Remove trailing slashes - unless it's the root '/' directory. */ ++ char *s = pname + strlen (pname) -1; ++ for ( ; pname <= s; s--) ++ if (*s != '/') ++ break; ++ if (pname < s && *(s+1) == '/') ++ *(s+1) = '\0'; ++ ++ s = strrchr (pname, '/'); ++ if (s == NULL) /* No leading directories. */ + { + /* If there is no slash in the pathname, we still + * print the string because it contains characters +@@ -976,11 +986,10 @@ do_fprintf (struct format_val *dest, + } + else + { +- char *s = strdup (pathname); +- s[cp - pathname] = 0; +- checked_print_quoted (dest, segment->text, s); +- free (s); ++ *s = '\0'; ++ checked_print_quoted (dest, segment->text, pname); + } ++ free (pname); + } + break; + +diff --git a/find/testsuite/find.gnu/printf-h.exp b/find/testsuite/find.gnu/printf-h.exp +index fb0187cc..094a37b5 100644 +--- a/find/testsuite/find.gnu/printf-h.exp ++++ b/find/testsuite/find.gnu/printf-h.exp +@@ -1,5 +1,91 @@ + # Test case for Savannah bug ID #12085. +-exec rm -rf tmp +-exec touch tmp +-find_start p {tmp -printf "RESULT: %h %f\n" } +-exec rm -rf tmp ++exec rm -rf foo ++exec mkdir foo foo/bar ++exec ln -s foo foolink ++# ++# Create the combinations with: ++# $ printf '%s \\\n' {,./,.//}{/,.,foo,foolink,foo/bar}{,/,//,/.,//.} | sort -u ++# ++# Manual check against installed version: ++# $ for opt in '' -H -L -P ; do ++# printf "\n=== Differences for option: '%s' ===\n" "$opt" ++# diff -u0 \ ++# <( /usr/bin/find $opt {,./,.//}{/,.,foo,foolink,foo/bar}{,/,//,/.,//.} \ ++# -maxdepth 1 -printf "%h/%f,%%p=%p,%%h='%h',%%f='%f'\n" ) \ ++# <( ./find $opt {,./,.//}{/,.,foo,foolink,foo/bar}{,/,//,/.,//.} \ ++# -maxdepth 1 -printf "%h/%f,%%p=%p,%%h='%h',%%f='%f'\n" ) ++# done | column -t -s, ++ ++find_start p {\ ++/ \ ++// \ ++/// \ ++///. \ ++//. \ ++. \ ++./ \ ++.// \ ++./// \ ++.//// \ ++.///// \ ++./////. \ ++.////. \ ++.///. \ ++.//. \ ++.//./ \ ++.//.// \ ++.//.//. \ ++.//./. \ ++./. \ ++././ \ ++./.// \ ++././/. \ ++././. \ ++.//foo \ ++.//foo/ \ ++.//foo// \ ++.//foo//. \ ++.//foo/. \ ++./foo \ ++./foo/ \ ++./foo// \ ++./foo//. \ ++./foo/. \ ++foo \ ++foo/ \ ++foo// \ ++foo//. \ ++foo/. \ ++.//foo/bar \ ++.//foo/bar/ \ ++.//foo/bar// \ ++.//foo/bar//. \ ++.//foo/bar/. \ ++./foo/bar \ ++./foo/bar/ \ ++./foo/bar// \ ++./foo/bar//. \ ++./foo/bar/. \ ++foo/bar \ ++foo/bar/ \ ++foo/bar// \ ++foo/bar//. \ ++foo/bar/. \ ++.//foolink \ ++.//foolink/ \ ++.//foolink// \ ++.//foolink//. \ ++.//foolink/. \ ++./foolink \ ++./foolink/ \ ++./foolink// \ ++./foolink//. \ ++./foolink/. \ ++foolink \ ++foolink/ \ ++foolink// \ ++foolink//. \ ++foolink/. \ ++-maxdepth 0 -printf "%p,%h,%f\n" } ++ ++exec rm -rf foo foolink +diff --git a/find/testsuite/find.gnu/printf-h.xo b/find/testsuite/find.gnu/printf-h.xo +index dc6ce01e..0ed6ad9d 100644 +--- a/find/testsuite/find.gnu/printf-h.xo ++++ b/find/testsuite/find.gnu/printf-h.xo +@@ -1 +1,69 @@ +-RESULT: . tmp ++/,,/ ++//,/,/ ++///,//,/ ++///.,//,. ++//.,/,. ++.,.,. ++./,.,./ ++.//,./,./ ++.///,.//,./ ++.////,.///,./ ++./////,.////,./ ++./////.,.////,. ++.////.,.///,. ++.///.,.//,. ++.//.,./,. ++.//./,./,./ ++.//.//,./,./ ++.//.//.,.//./,. ++.//./.,.//.,. ++./.,.,. ++././,.,./ ++././/,.,./ ++././/.,././,. ++././.,./.,. ++.//foo/bar,.//foo,bar ++.//foo/bar/,.//foo,bar/ ++.//foo/bar//,.//foo,bar/ ++.//foo/bar//.,.//foo/bar/,. ++.//foo/bar/.,.//foo/bar,. ++./foo/bar,./foo,bar ++./foo/bar/,./foo,bar/ ++./foo/bar//,./foo,bar/ ++./foo/bar//.,./foo/bar/,. ++./foo/bar/.,./foo/bar,. ++foo/bar,foo,bar ++foo/bar/,foo,bar/ ++foo/bar//,foo,bar/ ++foo/bar//.,foo/bar/,. ++foo/bar/.,foo/bar,. ++.//foo,./,foo ++.//foo/,./,foo/ ++.//foo//,./,foo/ ++.//foo//.,.//foo/,. ++.//foo/.,.//foo,. ++./foo,.,foo ++./foo/,.,foo/ ++./foo//,.,foo/ ++./foo//.,./foo/,. ++./foo/.,./foo,. ++foo,.,foo ++foo/,.,foo/ ++foo//,.,foo/ ++foo//.,foo/,. ++foo/.,foo,. ++.//foolink,./,foolink ++.//foolink/,./,foolink/ ++.//foolink//,./,foolink/ ++.//foolink//.,.//foolink/,. ++.//foolink/.,.//foolink,. ++./foolink,.,foolink ++./foolink/,.,foolink/ ++./foolink//,.,foolink/ ++./foolink//.,./foolink/,. ++./foolink/.,./foolink,. ++foolink,.,foolink ++foolink/,.,foolink/ ++foolink//,.,foolink/ ++foolink//.,foolink/,. ++foolink/.,foolink,. +-- +2.19.1 + diff --git a/find-give-helpful-hint-for-unquoted-patterns-errors.patch b/find-give-helpful-hint-for-unquoted-patterns-errors.patch new file mode 100644 index 0000000..589754f --- /dev/null +++ b/find-give-helpful-hint-for-unquoted-patterns-errors.patch @@ -0,0 +1,47 @@ +From 9530e31f6d4febf8ff08f931f70b40d41603ef8d Mon Sep 17 00:00:00 2001 +From: Assaf Gordon +Date: Wed, 16 Aug 2017 14:09:17 -0600 +Subject: [PATCH 114/224] find: give helpful hint for unquoted patterns errors + +Try to detect cases where the user provided an unquoted shell-glob +pattern (which was expanded by the shell before calling find(1), +resulting in an invalid usage). + + $ touch a.txt b.txt c.txt + $ find -name *.txt + find: paths must precede expression: `b.txt' + find: possible unquoted pattern after predicate `-name'? + +Continuation of + https://savannah.gnu.org/bugs/?51711 + https://lists.gnu.org/archive/html/bug-findutils/2017-08/msg00000.html + https://git.sv.gnu.org/cgit/findutils.git/commit/?id=50a7c5d1f572 + +* find/tree.c (build_expression_tree): If the offending argument is an +existing file, print a hint with the last (valid) predicate. +--- + find/tree.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/find/tree.c b/find/tree.c +index ee466ea6..cc7772d2 100644 +--- a/find/tree.c ++++ b/find/tree.c +@@ -1275,7 +1275,13 @@ build_expression_tree (int argc, char *argv[], int end_of_leading_options) + { + state.already_issued_stat_error_msg = false; + if (!looks_like_expression (argv[i], false)) +- error (EXIT_FAILURE, 0, _("paths must precede expression: `%s'"), argv[i]); ++ { ++ error (0, 0, _("paths must precede expression: `%s'"), argv[i]); ++ if (access(argv[i], F_OK)==0) ++ error (0, 0, _("possible unquoted pattern after predicate `%s'?"), ++ last_pred->p_name); ++ exit (EXIT_FAILURE); ++ } + + predicate_name = argv[i]; + parse_entry = find_parser (predicate_name); +-- +2.19.1 + diff --git a/find-handle-more-readdir-3-errors.patch b/find-handle-more-readdir-3-errors.patch new file mode 100644 index 0000000..4857c98 --- /dev/null +++ b/find-handle-more-readdir-3-errors.patch @@ -0,0 +1,89 @@ +From 7a6e548690b116878070665bd9844275823bb730 Mon Sep 17 00:00:00 2001 +From: Bernhard Voelker +Date: Wed, 2 Nov 2016 07:32:01 +0100 +Subject: [PATCH 080/224] find: handle more readdir(3) errors + +Similar to the FTS readdir fix in v4.6.0-72-g155c9d1, handle the last +two unhandled readdir(3) errors. + +* find/pred.c (pred_empty): Do the above. +* lib/fdleak.c (get_proc_max_fd): Likewise. While at it, fix the +condition to only skip "." and ".."; previously, also other files +beginning with ".." would have been skipped - that was theoretically, +as we only expect the FD files in "/proc/self/fd". +--- + find/pred.c | 10 ++++++++++ + lib/fdleak.c | 21 +++++++++++++++++---- + 2 files changed, 27 insertions(+), 4 deletions(-) + +diff --git a/find/pred.c b/find/pred.c +index f7e9b59c..c064606d 100644 +--- a/find/pred.c ++++ b/find/pred.c +@@ -380,6 +380,9 @@ pred_empty (const char *pathname, struct stat *stat_buf, struct predicate *pred_ + state.exit_status = 1; + return false; + } ++ /* errno is not touched in the loop body, so initializing it here ++ * once before the loop is enough to detect readdir(3) errors. */ ++ errno = 0; + for (dp = readdir (d); dp; dp = readdir (d)) + { + if (dp->d_name[0] != '.' +@@ -390,6 +393,13 @@ pred_empty (const char *pathname, struct stat *stat_buf, struct predicate *pred_ + break; + } + } ++ if (errno) ++ { ++ /* Handle errors from readdir(3). */ ++ error (0, errno, "%s", safely_quote_err_filename (0, pathname)); ++ state.exit_status = 1; ++ return false; ++ } + if (CLOSEDIR (d)) + { + error (0, errno, "%s", safely_quote_err_filename (0, pathname)); +diff --git a/lib/fdleak.c b/lib/fdleak.c +index 5dc4cb1e..cf19fa26 100644 +--- a/lib/fdleak.c ++++ b/lib/fdleak.c +@@ -19,6 +19,7 @@ + + /* system headers. */ + #include ++#include + #include + #include + #include +@@ -77,11 +78,23 @@ get_proc_max_fd (void) + int good = 0; + struct dirent *dent; + +- while ((dent=readdir (dir)) != NULL) +- { ++ while (1) ++ { ++ errno = 0; ++ dent = readdir (dir); ++ if (NULL == dent) ++ { ++ if (errno) ++ { ++ error (0, errno, "%s", quotearg_n_style (0, locale_quoting_style, path)); ++ good = 0; ++ } ++ break; ++ } ++ + if (dent->d_name[0] != '.' +- || (dent->d_name[0] != 0 +- && dent->d_name[1] != 0 && dent->d_name[1] != '.')) ++ || (dent->d_name[1] != 0 ++ && (dent->d_name[1] != '.' || dent->d_name[2] != 0))) + { + const int fd = safe_atoi (dent->d_name, literal_quoting_style); + if (fd > maxfd) +-- +2.19.1 + diff --git a/find-improve-warning-diagnostic-for-the-name-iname-w.patch b/find-improve-warning-diagnostic-for-the-name-iname-w.patch new file mode 100644 index 0000000..5f384ea --- /dev/null +++ b/find-improve-warning-diagnostic-for-the-name-iname-w.patch @@ -0,0 +1,73 @@ +From 66174c10c617a1a50fa804c1e2f9c6becd7c90f8 Mon Sep 17 00:00:00 2001 +From: Bernhard Voelker +Date: Wed, 26 Dec 2018 10:47:11 +0100 +Subject: [PATCH 207/224] find: improve warning diagnostic for the -name/-iname + with '/' in pattern + +* find/parser.c (check_name_arg): Add parameter ALT for the alternative +option to suggest. Avoid confusing quoting in the warning by making +the message more terse. +(parse_iname): Pass "-iwholename" as alternative parameter. +(parse_name): Pass "-wholename" as alternative parameter. + +Reported by Andreas Metzler in + https://sv.gnu.org/bugs/?55272 +--- + find/parser.c | 24 +++++++++++------------- + 1 file changed, 11 insertions(+), 13 deletions(-) + +diff --git a/find/parser.c b/find/parser.c +index ae456ddb..a3b9e762 100644 +--- a/find/parser.c ++++ b/find/parser.c +@@ -1257,20 +1257,18 @@ fnmatch_sanitycheck (void) + + + static bool +-check_name_arg (const char *pred, const char *arg) ++check_name_arg (const char *pred, const char *alt, const char *arg) + { + if (should_issue_warnings () && strchr (arg, '/')) + { +- error (0, 0,_("warning: Unix filenames usually don't contain slashes " +- "(though pathnames do). That means that '%s %s' will " +- "probably evaluate to false all the time on this system. " +- "You might find the '-wholename' test more useful, or " +- "perhaps '-samefile'. Alternatively, if you are using " +- "GNU grep, you could " +- "use 'find ... -print0 | grep -FzZ %s'."), +- pred, +- safely_quote_err_filename (0, arg), +- safely_quote_err_filename (1, arg)); ++ error (0, 0, ++ _("warning: %s matches against basenames only, " ++ "but the given pattern contains a directory separator (%s), " ++ "thus the expression will evaluate to false all the time. " ++ "Did you mean %s?"), ++ safely_quote_err_filename (0, pred), ++ safely_quote_err_filename (1, "/"), ++ safely_quote_err_filename (2, alt)); + } + return true; /* allow it anyway */ + } +@@ -1284,7 +1282,7 @@ parse_iname (const struct parser_table* entry, char **argv, int *arg_ptr) + fnmatch_sanitycheck (); + if (collect_arg (argv, arg_ptr, &name)) + { +- if (check_name_arg ("-iname", name)) ++ if (check_name_arg ("-iname", "-iwholename", name)) + { + struct predicate *our_pred = insert_primary (entry, name); + our_pred->need_stat = our_pred->need_type = false; +@@ -1471,7 +1469,7 @@ parse_name (const struct parser_table* entry, char **argv, int *arg_ptr) + if (collect_arg (argv, arg_ptr, &name)) + { + fnmatch_sanitycheck (); +- if (check_name_arg ("-name", name)) ++ if (check_name_arg ("-name", "-wholename", name)) + { + struct predicate *our_pred = insert_primary (entry, name); + our_pred->need_stat = our_pred->need_type = false; +-- +2.19.1 + diff --git a/find-make-delete-honour-the-ignore_readdir_race-opti.patch b/find-make-delete-honour-the-ignore_readdir_race-opti.patch new file mode 100644 index 0000000..d3e35bb --- /dev/null +++ b/find-make-delete-honour-the-ignore_readdir_race-opti.patch @@ -0,0 +1,89 @@ +From 0afb2efada7e435ae18ef7d3db0758464189f44f Mon Sep 17 00:00:00 2001 +From: Bernhard Voelker +Date: Tue, 30 Jan 2018 23:30:09 +0100 +Subject: [PATCH 159/224] find: make -delete honour the -ignore_readdir_race + option + +* find/pred.c (pred_delete): Return true when the -ignore_readdir_race +option is active and unlinkat() came back with ENOENT. +* doc/find.texi (Option -ignore_readdir_race): Document the change. +(Action -delete): Likewise. +* find/find.1: Likewise. +* NEWS (Bug Fixes): Mention the fix. + +For now, it seems a bit hard to add a proper test for this, +so the following shell snippet demonstrates the race: + + $ seq 10 | xargs touch + $ env time -f 'find exit status: %x\nfind time: %e' \ + find -ignore_readdir_race -type f \ + -delete \ + -exec sh -c 'sleep $(basename {})' \; \ + -printf 'find deleted: %p\n' \ + & \ + sleep 20; \ + seq 10 | xargs rm -fv; \ + wait $! + +Reported by Alexander Golubev in +https://savannah.gnu.org/bugs/?52981 +--- + NEWS | 4 ++++ + doc/find.texi | 15 ++++++++++++++- + find/find.1 | 22 ++++++++++++++++++++++ + find/pred.c | 6 ++++++ + 4 files changed, 46 insertions(+), 1 deletion(-) + +diff --git a/doc/find.texi b/doc/find.texi +index 3580be75..0089193e 100644 +--- a/doc/find.texi ++++ b/doc/find.texi +@@ -1424,7 +1424,15 @@ gives a significant increase in search speed. + If a file disappears after its name has been read from a directory but + before @code{find} gets around to examining the file with @code{stat}, + don't issue an error message. If you don't specify this option, an +-error message will be issued. This option can be useful in system ++error message will be issued. ++ ++Furthermore, @code{find} with the @samp{-ignore_readdir_race} option ++will ignore errors of the @samp{-delete} action in the case the file ++has disappeared since the parent directory was read: it will not output ++an error diagnostic, and the return code of the @samp{-delete} action ++will be true. ++ ++This option can be useful in system + scripts (cron scripts, for example) that examine areas of the + filesystem that change frequently (mail queues, temporary directories, + and so forth), because this scenario is common for those sorts of +@@ -2787,6 +2795,11 @@ explicitly. + + If @samp{-delete} fails, @code{find}'s exit status will be nonzero + (when it eventually exits). ++ ++Together with the @samp{-ignore_readdir_race} option, @code{find} will ++ignore errors of the @samp{-delete} action in the case the file has disappeared ++since the parent directory was read: it will not output an error diagnostic, and ++the return code of the @samp{-delete} action will be true. + @end deffn + + @node Adding Tests +diff --git a/find/pred.c b/find/pred.c +index 7e2a7bde..af3bacbc 100644 +--- a/find/pred.c ++++ b/find/pred.c +@@ -316,6 +316,12 @@ pred_delete (const char *pathname, struct stat *stat_buf, struct predicate *pred + } + else + { ++ if (ENOENT == errno && options.ignore_readdir_race) ++ { ++ /* Ignore unlink() error for vanished files. */ ++ errno = 0; ++ return true; ++ } + if (EISDIR == errno) + { + if ((flags & AT_REMOVEDIR) == 0) +-- +2.19.1 + diff --git a/find-make-pred_empty-safer-and-avoid-fd-leaks.patch b/find-make-pred_empty-safer-and-avoid-fd-leaks.patch new file mode 100644 index 0000000..211e598 --- /dev/null +++ b/find-make-pred_empty-safer-and-avoid-fd-leaks.patch @@ -0,0 +1,58 @@ +From 235f21673cd8e3458795cdadca6e78a3423ab024 Mon Sep 17 00:00:00 2001 +From: Bernhard Voelker +Date: Sat, 9 Feb 2019 15:57:19 +0100 +Subject: [PATCH 224/224] find: make pred_empty safer and avoid fd leaks + +There is a small race condition between the previous stat call +and openat/fdopendir (which cannot be avoided): if the directory +got replaced by another file type, then openat would succeed but the +subsequent fdopendir would fail with ENOTDIR. Detect this earlier +by passing the O_DIRECTORY flag. +Furthermore, the opened file descriptor was leaked in that case +(bug introduced in FINDUTILS_4_3_2-1-80-gb46b0d89 in 2007). +Later on, after a readdir error, also the directory stream was leaked +(bug introduced by myself in commit 7a6e548690b1). + +* find/pred.c (pred_empty): Add more flags to the openat call, +especially O_DIRECTORY; inspired by gnulib's opendirat module. +Close the file descriptor when fdopendir failed. +Close the directory stream when readdir failed. +--- + find/pred.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/find/pred.c b/find/pred.c +index e34a41dc..688103d6 100644 +--- a/find/pred.c ++++ b/find/pred.c +@@ -363,9 +363,9 @@ pred_empty (const char *pathname, struct stat *stat_buf, struct predicate *pred_ + errno = 0; + if ((fd = openat (state.cwd_dir_fd, state.rel_pathname, O_RDONLY + #if defined O_LARGEFILE +- |O_LARGEFILE ++ | O_LARGEFILE + #endif +- )) < 0) ++ | O_CLOEXEC | O_DIRECTORY | O_NOCTTY | O_NONBLOCK)) < 0) + { + error (0, errno, "%s", safely_quote_err_filename (0, pathname)); + state.exit_status = 1; +@@ -376,6 +376,7 @@ pred_empty (const char *pathname, struct stat *stat_buf, struct predicate *pred_ + { + error (0, errno, "%s", safely_quote_err_filename (0, pathname)); + state.exit_status = 1; ++ close (fd); + return false; + } + /* errno is not touched in the loop body, so initializing it here +@@ -396,6 +397,7 @@ pred_empty (const char *pathname, struct stat *stat_buf, struct predicate *pred_ + /* Handle errors from readdir(3). */ + error (0, errno, "%s", safely_quote_err_filename (0, pathname)); + state.exit_status = 1; ++ CLOSEDIR (d); + return false; + } + if (CLOSEDIR (d)) +-- +2.19.1 + diff --git a/find-printf-Y-handle-ENOTDIR-also-as-broken-symlink.patch b/find-printf-Y-handle-ENOTDIR-also-as-broken-symlink.patch new file mode 100644 index 0000000..19399ca --- /dev/null +++ b/find-printf-Y-handle-ENOTDIR-also-as-broken-symlink.patch @@ -0,0 +1,74 @@ +From ba6be2889642010c8f30affe403981aa2cc39631 Mon Sep 17 00:00:00 2001 +From: Bernhard Voelker +Date: Tue, 24 Jul 2018 08:34:38 +0200 +Subject: [PATCH 184/224] find -printf %Y: handle ENOTDIR also as broken + symlink + +The above command should output 'N' (for broken symlinks) not only in +the ENOENT case, but also when an intermediate part of the symlink target +file name is a file (ENOTDIR): + + $ touch file + $ ln -s file/ENOTDIR link + $ find link -printf '%Y %p\n' + N link + +Previously, find output 'l' as for a resolvable symlink. + +* find/print.c (do_fprintf): Treat ENOTDIR the same as ENOENT to detect +broken symlinks. +* find/testsuite/find.gnu/printf-symlink.exp: Extend the test, and ... +* find/testsuite/find.gnu/printf-symlink.xo: ... the expected output. +* NEWS (Bug fixes, #54262): Explicitly mention that both ENOENT and ENOTDIR +are used to detect broken symlinks. + +Suggested by Tavian Barnes. +--- + NEWS | 4 ++-- + find/print.c | 2 +- + find/testsuite/find.gnu/printf-symlink.exp | 3 ++- + find/testsuite/find.gnu/printf-symlink.xo | 2 ++ + 4 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/find/print.c b/find/print.c +index 24bd9692..1bfccbfc 100644 +--- a/find/print.c ++++ b/find/print.c +@@ -1182,7 +1182,7 @@ do_fprintf (struct format_val *dest, + */ + if (fstatat (state.cwd_dir_fd, state.rel_pathname, &sbuf, 0) != 0) + { +- if ( errno == ENOENT ) ++ if ( (errno == ENOENT) || (errno == ENOTDIR) ) + { + checked_fprintf (dest, segment->text, "N"); + break; +diff --git a/find/testsuite/find.gnu/printf-symlink.exp b/find/testsuite/find.gnu/printf-symlink.exp +index 453f07fc..077f18b5 100644 +--- a/find/testsuite/find.gnu/printf-symlink.exp ++++ b/find/testsuite/find.gnu/printf-symlink.exp +@@ -3,7 +3,8 @@ exec mkdir tmp + exec touch tmp/file + exec ln -s file tmp/LINK + exec ln -s ENOENT tmp/DANGLE ++exec ln -s file/ENOTDIR tmp/ENOTDIR + exec ln -s SELF tmp/SELF + exec ls -ls tmp +-find_start p {tmp/LINK tmp/DANGLE tmp/SELF -printf "RESULT: %y %Y %p\n" -printf "RESULT2: %Y %y %p\n" } ++find_start p {tmp/LINK tmp/DANGLE tmp/ENOTDIR tmp/SELF -printf "RESULT: %y %Y %p\n" -printf "RESULT2: %Y %y %p\n" } + exec rm -rf tmp +diff --git a/find/testsuite/find.gnu/printf-symlink.xo b/find/testsuite/find.gnu/printf-symlink.xo +index 08eb83c6..978c6673 100644 +--- a/find/testsuite/find.gnu/printf-symlink.xo ++++ b/find/testsuite/find.gnu/printf-symlink.xo +@@ -2,5 +2,7 @@ RESULT: l f tmp/LINK + RESULT2: f l tmp/LINK + RESULT: l N tmp/DANGLE + RESULT2: N l tmp/DANGLE ++RESULT: l N tmp/ENOTDIR ++RESULT2: N l tmp/ENOTDIR + RESULT: l L tmp/SELF + RESULT2: L l tmp/SELF +-- +2.19.1 + diff --git a/find-process-unreadable-directories-with-depth.patch b/find-process-unreadable-directories-with-depth.patch new file mode 100644 index 0000000..749d760 --- /dev/null +++ b/find-process-unreadable-directories-with-depth.patch @@ -0,0 +1,49 @@ +From 22ff99e150faa82980361e577cff643cc17e7fac Mon Sep 17 00:00:00 2001 +From: Bernhard Voelker +Date: Sun, 8 Jul 2018 00:17:27 +0200 +Subject: [PATCH 176/224] find: process unreadable directories with -depth + +* find/ftsfind.c (consider_visiting): Split the FTS_ERR and FTS_DNR +cases to be able to continue processing that entry in the latter case +(unreadable directory) when the -depth option is given. +* NEWS (Bug Fixes): Mention the fix. + +Reported by Tavian Barnes in https://savannah.gnu.org/bugs/?54171. +--- + NEWS | 4 ++++ + find/ftsfind.c | 15 +++++++++++++-- + 2 files changed, 17 insertions(+), 2 deletions(-) + +diff --git a/find/ftsfind.c b/find/ftsfind.c +index 0e2aca33..607ea8d3 100644 +--- a/find/ftsfind.c ++++ b/find/ftsfind.c +@@ -342,12 +342,23 @@ consider_visiting (FTS *p, FTSENT *ent) + statbuf.st_ino = ent->fts_statp->st_ino; + + /* Cope with various error conditions. */ +- if (ent->fts_info == FTS_ERR +- || ent->fts_info == FTS_DNR) ++ if (ent->fts_info == FTS_ERR) + { + nonfatal_target_file_error (ent->fts_errno, ent->fts_path); + return; + } ++ if (ent->fts_info == FTS_DNR) ++ { ++ nonfatal_target_file_error (ent->fts_errno, ent->fts_path); ++ if (options.do_dir_first) ++ { ++ /* Return for unreadable directories without -depth. ++ * With -depth, the directory itself has to be processed, yet the ++ * error message above has to be output. ++ */ ++ return; ++ } ++ } + else if (ent->fts_info == FTS_DC) + { + issue_loop_warning (ent); +-- +2.19.1 + diff --git a/findutils-4.4.2-xautofs.patch b/findutils-4.4.2-xautofs.patch new file mode 100644 index 0000000..c1ea81e --- /dev/null +++ b/findutils-4.4.2-xautofs.patch @@ -0,0 +1,132 @@ +From 17e470dc1acca4824b70328d733d5f99c12d0d65 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Wed, 11 May 2011 16:46:45 +0200 +Subject: [PATCH 3/4] findutils-4.4.2-xautofs.patch + +--- + doc/find.texi | 4 ++++ + find/defs.h | 3 +++ + find/find.1 | 3 +++ + find/ftsfind.c | 6 ++++++ + find/parser.c | 11 ++++++++++- + find/util.c | 1 + + 6 files changed, 27 insertions(+), 1 deletions(-) + +diff --git a/doc/find.texi b/doc/find.texi +index c584298..9731b71 100644 +--- a/doc/find.texi ++++ b/doc/find.texi +@@ -1446,6 +1446,10 @@ them. + There are two ways to avoid searching certain filesystems. One way is + to tell @code{find} to only search one filesystem: + ++@deffn Option -xautofs ++Don't descend directories on autofs filesystems. ++@end deffn ++ + @deffn Option -xdev + @deffnx Option -mount + Don't descend directories on other filesystems. These options are +diff --git a/find/defs.h b/find/defs.h +index 11d1d00..f95ce72 100644 +--- a/find/defs.h ++++ b/find/defs.h +@@ -557,6 +557,9 @@ struct options + /* If true, don't cross filesystem boundaries. */ + bool stay_on_filesystem; + ++ /* If true, don't descend directories on autofs filesystems. */ ++ bool bypass_autofs; ++ + /* If true, we ignore the problem where we find that a directory entry + * no longer exists by the time we get around to processing it. + */ +diff --git a/find/find.1 b/find/find.1 +index e851f82..a4799ff 100644 +--- a/find/find.1 ++++ b/find/find.1 +@@ -520,6 +520,9 @@ to stat them; this gives a significant increase in search speed. + .IP "\-version, \-\-version" + Print the \fBfind\fR version number and exit. + ++.IP \-xautofs ++Don't descend directories on autofs filesystems. ++ + .IP \-xdev + Don't descend directories on other filesystems. + +diff --git a/find/ftsfind.c b/find/ftsfind.c +index 9fdb8ef..bd7cc37 100644 +--- a/find/ftsfind.c ++++ b/find/ftsfind.c +@@ -485,6 +485,12 @@ consider_visiting (FTS *p, FTSENT *ent) + } + } + ++ if (options.bypass_autofs && ++ 0 == strcmp ("autofs", filesystem_type (&statbuf, ent->fts_name))) ++ { ++ fts_set(p, ent, FTS_SKIP); /* descend no further */ ++ } ++ + if ( (ent->fts_info == FTS_D) && !options.do_dir_first ) + { + /* this is the preorder visit, but user said -depth */ +diff --git a/find/parser.c b/find/parser.c +index 52a1ef6..995aec3 100644 +--- a/find/parser.c ++++ b/find/parser.c +@@ -146,6 +146,7 @@ static bool parse_user (const struct parser_table*, char *argv[], int * + static bool parse_version (const struct parser_table*, char *argv[], int *arg_ptr); + static bool parse_wholename (const struct parser_table*, char *argv[], int *arg_ptr); + static bool parse_xdev (const struct parser_table*, char *argv[], int *arg_ptr); ++static bool parse_xautofs (const struct parser_table*, char *argv[], int *arg_ptr); + static bool parse_ignore_race (const struct parser_table*, char *argv[], int *arg_ptr); + static bool parse_noignore_race (const struct parser_table*, char *argv[], int *arg_ptr); + static bool parse_warn (const struct parser_table*, char *argv[], int *arg_ptr); +@@ -306,6 +307,7 @@ static struct parser_table const parse_table[] = + PARSE_TEST_NP ("wholename", wholename), /* GNU, replaced -path, but anyway -path will soon be in POSIX */ + {ARG_TEST, "writable", parse_accesscheck, pred_writable}, /* GNU, 4.3.0+ */ + PARSE_OPTION ("xdev", xdev), /* POSIX */ ++ PARSE_OPTION ("xautofs", xautofs), + PARSE_TEST ("xtype", xtype), /* GNU */ + #ifdef UNIMPLEMENTED_UNIX + /* It's pretty ugly for find to know about archive formats. +@@ -1239,7 +1241,7 @@ operators (decreasing precedence; -and is implicit where no others are given):\n + positional options (always true): -daystart -follow -regextype\n\n\ + normal options (always true, specified before other expressions):\n\ + -depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf\n\ +- --version -xdev -ignore_readdir_race -noignore_readdir_race\n")); ++ --version -xautofs -xdev -ignore_readdir_race -noignore_readdir_race\n")); + puts (_("\ + tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\ + -cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME\n\ +@@ -2683,6 +2685,13 @@ parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr) + } + + static bool ++parse_xautofs (const struct parser_table* entry, char **argv, int *arg_ptr) ++{ ++ options.bypass_autofs = true; ++ return parse_noop (entry, argv, arg_ptr); ++} ++ ++static bool + parse_ignore_race (const struct parser_table* entry, char **argv, int *arg_ptr) + { + options.ignore_readdir_race = true; +diff --git a/find/util.c b/find/util.c +index 8577396..4d45f84 100644 +--- a/find/util.c ++++ b/find/util.c +@@ -1017,6 +1017,7 @@ set_option_defaults (struct options *p) + + p->full_days = false; + p->stay_on_filesystem = false; ++ p->bypass_autofs = false; + p->ignore_readdir_race = false; + + if (p->posixly_correct) +-- +1.7.4.4 + diff --git a/findutils-4.5.13-warnings.patch b/findutils-4.5.13-warnings.patch new file mode 100644 index 0000000..d04f6f8 --- /dev/null +++ b/findutils-4.5.13-warnings.patch @@ -0,0 +1,53 @@ +From 690d4bd9f29a805999a3ce4651dac9585ccc9917 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Wed, 11 May 2011 16:46:57 +0200 +Subject: [PATCH 1/2] findutils-4.5.7-warnings.patch + +--- + xargs/xargs.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/xargs/xargs.c b/xargs/xargs.c +index 5e373f2..c0a8676 100644 +--- a/xargs/xargs.c ++++ b/xargs/xargs.c +@@ -1289,7 +1289,8 @@ xargs_do_exec (struct buildcmd_control *ctl, void *usercontext, int argc, char * + * utility if we run it, for POSIX compliance on the + * handling of exit values. + */ +- write (fd[1], &errno, sizeof (int)); ++ int sink = write (fd[1], &errno, sizeof (int)); ++ (void) sink; + } + + close (fd[1]); +-- +1.7.1 + + +From c5654b9ca5f50daa1ca406ebd7b4546f24d00db6 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Mon, 23 Sep 2013 15:04:03 +0200 +Subject: [PATCH 2/2] parser: silence a [-Wmaybe-uninitialized] GCC warning + +... caused by a missing model of error() +--- + find/parser.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/find/parser.c b/find/parser.c +index 89d8bcf..8c399d7 100644 +--- a/find/parser.c ++++ b/find/parser.c +@@ -2723,7 +2723,7 @@ insert_type (char **argv, int *arg_ptr, + const struct parser_table *entry, + PRED_FUNC which_pred) + { +- mode_t type_cell; ++ mode_t type_cell /* to silence GCC warning */ = 0; + struct predicate *our_pred; + float rate = 0.5; + const char *typeletter; +-- +1.9.3 + diff --git a/findutils-4.5.15-no-locate.patch b/findutils-4.5.15-no-locate.patch new file mode 100644 index 0000000..7bf1f33 --- /dev/null +++ b/findutils-4.5.15-no-locate.patch @@ -0,0 +1,185 @@ +From 3e5e311d23ac0a5bd5930ddb4094f7555b886329 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Sat, 19 Dec 2015 22:56:40 +0100 +Subject: [PATCH 1/2] Revert "Don't include dblocation.texi from original spot, + symlink it." + +This reverts commit f59d88e456553dfe0b5185caf75e4041285fd595. +--- + configure.ac | 2 +- + doc/Makefile.am | 8 +------- + doc/find.texi | 2 +- + 3 files changed, 3 insertions(+), 9 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 7962719..ce0e768 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -70,7 +70,7 @@ AC_PROG_CPP + + dnl for gnulib + gl_EARLY +-AC_PROG_LN_S ++ + AC_PROG_INSTALL + AC_CHECK_TOOLS([AR], [ar]) + AC_CHECK_TOOLS([RANLIB], [ranlib], [:]) +diff --git a/doc/Makefile.am b/doc/Makefile.am +index f6f7443..6fbf57b 100644 +--- a/doc/Makefile.am ++++ b/doc/Makefile.am +@@ -16,11 +16,9 @@ AM_CFLAGS = $(WARN_CFLAGS) + + info_TEXINFOS = find.texi find-maint.texi + find_TEXINFOS = perm.texi parse-datetime.texi regexprops.texi fdl.texi +-BUILT_SOURCES = dblocation.texi +-nodist_find_TEXINFOS = dblocation.texi + find_maint_TEXINFOS = fdl.texi + MOSTLYCLEANFILES = find.cps +-CLEANFILES = find.txt find_mono.html findutils.texi_html_node.tar.gz dblocation.texi ++CLEANFILES = find.txt find_mono.html findutils.texi_html_node.tar.gz + + MAKEINFOTXT = $(MAKEINFO) --plaintext + +@@ -69,7 +67,3 @@ find_mono.html: find.texi + # for "make all" or "make install" (or even "make check"). + findutils.texi_html_node.tar.gz: find.html + tar zcf $@ $< +- +- +-dblocation.texi: ../locate/dblocation.texi +- $(LN_S) ../locate/dblocation.texi $@ +diff --git a/doc/find.texi b/doc/find.texi +index a83a645..c2714dd 100644 +--- a/doc/find.texi ++++ b/doc/find.texi +@@ -7,7 +7,7 @@ + @c %**end of header + + @include version.texi +-@include dblocation.texi ++@include ../locate/dblocation.texi + + @iftex + @finalout +-- +2.5.0 + + +From d5473caa86f689ebcadacc593f5a71781c99e829 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Wed, 11 May 2011 16:46:13 +0200 +Subject: [PATCH 2/2] findutils-4.4.0-no-locate.patch + +--- + Makefile.am | 2 +- + configure.ac | 2 -- + doc/find.texi | 24 ++++++++---------------- + 3 files changed, 9 insertions(+), 19 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index af82d54..6ad453b 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -9,7 +9,7 @@ DISTCLEANFILES = tool-versions.txt + + + # "tests" is the gnulib unit test dir. +-SUBDIRS = gl tests build-aux lib find xargs locate doc po m4 ++SUBDIRS = gl tests build-aux lib find xargs doc po m4 + + ACLOCAL_AMFLAGS = -I gl/m4 -I m4 + +diff --git a/configure.ac b/configure.ac +index ce0e768..521e665 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -248,8 +248,6 @@ find/testsuite/Makefile + gl/Makefile + gl/lib/Makefile + lib/Makefile +-locate/Makefile +-locate/testsuite/Makefile + m4/Makefile + po/Makefile.in + po/Makefile +diff --git a/doc/find.texi b/doc/find.texi +index c2714dd..01367a4 100644 +--- a/doc/find.texi ++++ b/doc/find.texi +@@ -7,7 +7,6 @@ + @c %**end of header + + @include version.texi +-@include ../locate/dblocation.texi + + @iftex + @finalout +@@ -571,8 +570,7 @@ the databases are updated, and the directories for which they contain + entries. + + Here is how to select which file name databases @code{locate} +-searches. The default is system-dependent. At the time this document +-was generated, the default was @file{@value{LOCATE_DB}}. ++searches. The default is system-dependent. + + @table @code + @item --database=@var{path} +@@ -2892,13 +2890,9 @@ thrashing the network. + directories are indexed by each database file. + + The default location for the locate database depends on how findutils +-is built, but the findutils installation accompanying this manual uses +-the default location @file{@value{LOCATE_DB}}. +- +-If no database exists at @file{@value{LOCATE_DB}} but the user did not +-specify where to look (by using @samp{-d} or setting +-@code{LOCATE_PATH}), then @code{locate} will also check for a +-``secure'' database in @file{/var/lib/slocate/slocate.db}. ++is built. If user did not specify where to look (by using @samp{-d} ++or setting @code{LOCATE_PATH}), then @code{locate} will also check for ++a ``secure'' database in @file{/var/lib/slocate/slocate.db}. + + @node Database Formats + @section Database Formats +@@ -3438,8 +3432,7 @@ present. + + @item --database=@var{path} + @itemx -d @var{path} +-Instead of searching the default @code{locate} database +-@file{@value{LOCATE_DB}}, @code{locate} searches the file ++@code{locate} searches the file + name databases in @var{path}, which is a colon-separated list of + database file names. You can also use the environment variable + @code{LOCATE_PATH} to set the list of database files to search. The +@@ -3614,8 +3607,7 @@ The environment variable @code{PRUNEFS} also sets this value. Default + is @file{nfs NFS proc}. + + @item --output=@var{dbfile} +-The database file to build. The default is system-dependent, but +-when this document was formatted it was @file{@value{LOCATE_DB}}. ++The database file to build. + + @item --localuser=@var{user} + The user to search the non-network directories as, using @code{su}. +@@ -5635,7 +5627,7 @@ why @code{xargs} is confused by your operating system). + @section Error Messages From @code{locate} + + @table @samp +-@item warning: database @file{@value{LOCATE_DB}} is more than 8 days old ++@item warning: database @file{LOCATE_DB} is more than 8 days old + The @code{locate} program relies on a database which is periodically + built by the @code{updatedb} program. That hasn't happened in a long + time. To fix this problem, run @code{updatedb} manually. This can +@@ -5643,7 +5635,7 @@ often happen on systems that are generally not left on, so the + periodic ``cron'' task which normally does this doesn't get a chance + to run. + +-@item locate database @file{@value{LOCATE_DB}} is corrupt or invalid ++@item locate database @file{LOCATE_DB} is corrupt or invalid + This should not happen. Re-run @code{updatedb}. If that works, but + @code{locate} still produces this error, run @code{locate --version} + and @code{updatedb --version}. These should produce the same output. +-- +2.5.0 + diff --git a/findutils-4.6.0-exec-args.patch b/findutils-4.6.0-exec-args.patch new file mode 100644 index 0000000..7f80aee --- /dev/null +++ b/findutils-4.6.0-exec-args.patch @@ -0,0 +1,226 @@ +From 443166adaf1c8b91e16a716f3b13f47493b895cc Mon Sep 17 00:00:00 2001 +From: Bernhard Voelker +Date: Tue, 31 May 2016 10:38:52 +0200 +Subject: [PATCH] Fix bug #48030: find: -exec + does not pass all arguments in + certain cases + +When the -exec arguments buffer (usually 128k) is full and the given +command has been executed with all that arguments, find(1) missed to +execute the command yet another time if only 1 another file would have +to be processed. +Both find(1), i.e., nowadays FTS-version, and oldfind are affected. +This bug was present since the implementation of '-exec +' in 2005, +see commit FINDUTILS_4_2_11-1-25-gf0a6ac6. + +* lib/buildcmd.c (bc_push_arg): Move the assignment to set 'state->todo' +to 1 down after the immediate execution which resets that flag. +* find/testsuite/sv-48030-exec-plus-bug.sh: Add a test. +* find/testsuite/Makefile.am (test_shell_progs): Reference the test. +* NEWS (Bug Fixes): Mention the fix. + +Reported by Joe Philip Ninan in +https://savannah.gnu.org/bugs/?48030 + +Upstream-commit: 8cdc9767e305c9566f537af9d1acf71d1bc6ee8e +Signed-off-by: Kamil Dudka +--- + find/testsuite/Makefile.am | 3 +- + find/testsuite/sv-48030-exec-plus-bug.sh | 143 +++++++++++++++++++++++++++++++ + lib/buildcmd.c | 10 +-- + 3 files changed, 150 insertions(+), 6 deletions(-) + create mode 100644 find/testsuite/sv-48030-exec-plus-bug.sh + +diff --git a/find/testsuite/Makefile.am b/find/testsuite/Makefile.am +index c1369c3..ab5dbe8 100644 +--- a/find/testsuite/Makefile.am ++++ b/find/testsuite/Makefile.am +@@ -258,7 +258,8 @@ test_escapechars.sh \ + test_escape_c.sh \ + test_inode.sh \ + sv-34079.sh \ +-sv-34976-execdir-fd-leak.sh ++sv-34976-execdir-fd-leak.sh \ ++sv-48030-exec-plus-bug.sh + + EXTRA_DIST = $(EXTRA_DIST_EXP) $(EXTRA_DIST_XO) $(EXTRA_DIST_GOLDEN) \ + $(test_shell_progs) binary_locations.sh checklists.py +diff --git a/find/testsuite/sv-48030-exec-plus-bug.sh b/find/testsuite/sv-48030-exec-plus-bug.sh +new file mode 100755 +index 0000000..4dbf149 +--- /dev/null ++++ b/find/testsuite/sv-48030-exec-plus-bug.sh +@@ -0,0 +1,143 @@ ++#! /bin/sh ++# Copyright (C) 2016 Free Software Foundation, Inc. ++# ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++ ++# This test verifies that find invokes the given command for the ++# multiple-argument sytax '-exec CMD {} +'. Between FINDUTILS-4.2.12 ++# and v4.6.0, find(1) would have failed to execute CMD another time ++# if there was only one last single file argument. ++ ++testname="$(basename $0)" ++ ++. "${srcdir}"/binary_locations.sh ++ ++die() { ++ echo "$@" >&2 ++ exit 1 ++} ++ ++# This is used to simplify checking of the return value ++# which is useful when ensuring a command fails as desired. ++# I.e., just doing `command ... &&fail=1` will not catch ++# a segfault in command for example. With this helper you ++# instead check an explicit exit code like ++# returns_ 1 command ... || fail ++returns_ () { ++ # Disable tracing so it doesn't interfere with stderr of the wrapped command ++ { set +x; } 2>/dev/null ++ ++ local exp_exit="$1" ++ shift ++ "$@" ++ test $? -eq $exp_exit && ret_=0 || ret_=1 ++ ++ set -x ++ { return $ret_; } 2>/dev/null ++} ++ ++# Define the nicest compare available (borrowed from gnulib). ++if diff_out_=`exec 2>/dev/null; diff -u "$0" "$0" < /dev/null` \ ++ && diff -u Makefile "$0" 2>/dev/null | grep '^[+]#!' >/dev/null; then ++ # diff accepts the -u option and does not (like AIX 7 'diff') produce an ++ # extra space on column 1 of every content line. ++ if test -z "$diff_out_"; then ++ compare () { diff -u "$@"; } ++ else ++ compare () ++ { ++ if diff -u "$@" > diff.out; then ++ # No differences were found, but Solaris 'diff' produces output ++ # "No differences encountered". Hide this output. ++ rm -f diff.out ++ true ++ else ++ cat diff.out ++ rm -f diff.out ++ false ++ fi ++ } ++ fi ++elif diff_out_=`exec 2>/dev/null; diff -c "$0" "$0" < /dev/null`; then ++ if test -z "$diff_out_"; then ++ compare () { diff -c "$@"; } ++ else ++ compare () ++ { ++ if diff -c "$@" > diff.out; then ++ # No differences were found, but AIX and HP-UX 'diff' produce output ++ # "No differences encountered" or "There are no differences between the ++ # files.". Hide this output. ++ rm -f diff.out ++ true ++ else ++ cat diff.out ++ rm -f diff.out ++ false ++ fi ++ } ++ fi ++elif cmp -s /dev/null /dev/null 2>/dev/null; then ++ compare () { cmp -s "$@"; } ++else ++ compare () { cmp "$@"; } ++fi ++ ++DIR='RashuBug' ++# Name of the CMD to execute: the file name must be 6 characters long ++# (to trigger the bug in combination with the test files). ++CMD='tstcmd' ++ ++# Create test files. ++make_test_data() { ++ # Create the CMD script and check that it works. ++ mkdir "$DIR" 'bin' \ ++ && echo 'printf "%s\n" "$@"' > "bin/$CMD" \ ++ && chmod +x "bin/$CMD" \ ++ && PATH="$PWD/bin:$PATH" \ ++ && [ $( "${ftsfind}" bin -maxdepth 0 -exec "$CMD" '{}' + ) = 'bin' ] \ ++ || return 1 ++ ++ # Create expected output file - also used for creating the test data. ++ { seq -f "${DIR}/abcdefghijklmnopqrstuv%04g" 901 && ++ seq -f "${DIR}/abcdefghijklmnopqrstu%04g" 902 3719 ++ } > exp2 \ ++ && LC_ALL=C sort exp2 > exp \ ++ && rm exp2 \ ++ || return 1 ++ ++ # Create test files, and check if test data has been created correctly. ++ xargs touch < exp \ ++ && [ -f "${DIR}/abcdefghijklmnopqrstu3719" ] \ ++ && [ 3719 = $( "${ftsfind}" "$DIR" -type f | wc -l ) ] \ ++ || return 1 ++} ++ ++set -x ++tmpdir="$(mktemp -d)" \ ++ && cd "$tmpdir" \ ++ && make_test_data "${tmpdir}" \ ++ || die "FAIL: failed to set up the test in ${tmpdir}" ++ ++fail=0 ++for exe in "${ftsfind}" "${oldfind}"; do ++ "$exe" "$DIR" -type f -exec "$CMD" '{}' + > out || fail=1 ++ LC_ALL=C sort out > out2 || fail=1 ++ compare exp out2 || fail=1 ++done ++ ++cd .. ++rm -rf "${tmpdir}" || exit 1 ++exit $fail +diff --git a/lib/buildcmd.c b/lib/buildcmd.c +index a58f67e..27e9ce5 100644 +--- a/lib/buildcmd.c ++++ b/lib/buildcmd.c +@@ -356,11 +356,6 @@ bc_push_arg (struct buildcmd_control *ctl, + + assert (arg != NULL); + +- if (!initial_args) +- { +- state->todo = 1; +- } +- + if (!terminate) + { + if (state->cmd_argv_chars + len + pfxlen > ctl->arg_max) +@@ -380,6 +375,11 @@ bc_push_arg (struct buildcmd_control *ctl, + bc_do_exec (ctl, state); + } + ++ if (!initial_args) ++ { ++ state->todo = 1; ++ } ++ + if (state->cmd_argc >= state->cmd_argv_alloc) + { + /* XXX: we could use extendbuf() here. */ +-- +2.5.5 + diff --git a/findutils-4.6.0-fts-update.patch b/findutils-4.6.0-fts-update.patch new file mode 100644 index 0000000..6025514 --- /dev/null +++ b/findutils-4.6.0-fts-update.patch @@ -0,0 +1,990 @@ +From f3337786e55909538aacfd7c29b1cf58ff444fbf Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Mon, 12 Feb 2018 12:45:36 +0100 +Subject: [PATCH 1/4] import gnulib's FTS module from upstream commit 281b825e + +--- + gl/lib/fts.c | 424 +++++++++++++++++++++++++++++----------------------------- + gl/lib/fts_.h | 10 +- + 2 files changed, 221 insertions(+), 213 deletions(-) + +diff --git a/gl/lib/fts.c b/gl/lib/fts.c +index c91d7a1..bfa73e3 100644 +--- a/gl/lib/fts.c ++++ b/gl/lib/fts.c +@@ -1,6 +1,6 @@ + /* Traverse a file hierarchy. + +- Copyright (C) 2004-2015 Free Software Foundation, Inc. ++ Copyright (C) 2004-2018 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by +@@ -13,7 +13,7 @@ + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License +- along with this program. If not, see . */ ++ along with this program. If not, see . */ + + /*- + * Copyright (c) 1990, 1993, 1994 +@@ -46,9 +46,9 @@ + + #include + +-#if defined(LIBC_SCCS) && !defined(lint) ++#if defined LIBC_SCCS && !defined GCC_LINT && !defined lint + static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94"; +-#endif /* LIBC_SCCS and not lint */ ++#endif + + #include "fts_.h" + +@@ -71,11 +71,7 @@ static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94"; + + #if ! _LIBC + # include "fcntl--.h" +-# include "dirent--.h" +-# include "unistd--.h" +-/* FIXME - use fcntl(F_DUPFD_CLOEXEC)/openat(O_CLOEXEC) once they are +- supported. */ +-# include "cloexec.h" ++# include "flexmember.h" + # include "openat.h" + # include "same-inode.h" + #endif +@@ -202,6 +198,14 @@ enum Fts_stat + while (false) + #endif + ++#ifndef FALLTHROUGH ++# if __GNUC__ < 7 ++# define FALLTHROUGH ((void) 0) ++# else ++# define FALLTHROUGH __attribute__ ((__fallthrough__)) ++# endif ++#endif ++ + static FTSENT *fts_alloc (FTS *, const char *, size_t) internal_function; + static FTSENT *fts_build (FTS *, int) internal_function; + static void fts_lfree (FTSENT *) internal_function; +@@ -296,14 +300,13 @@ static DIR * + internal_function + opendirat (int fd, char const *dir, int extra_flags, int *pdir_fd) + { +- int new_fd = openat (fd, dir, +- (O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK +- | extra_flags)); ++ int open_flags = (O_RDONLY | O_CLOEXEC | O_DIRECTORY | O_NOCTTY ++ | O_NONBLOCK | extra_flags); ++ int new_fd = openat (fd, dir, open_flags); + DIR *dirp; + + if (new_fd < 0) + return NULL; +- set_cloexec_flag (new_fd, true); + dirp = fdopendir (new_fd); + if (dirp) + *pdir_fd = new_fd; +@@ -366,15 +369,13 @@ static int + internal_function + diropen (FTS const *sp, char const *dir) + { +- int open_flags = (O_SEARCH | O_DIRECTORY | O_NOCTTY | O_NONBLOCK ++ int open_flags = (O_SEARCH | O_CLOEXEC | O_DIRECTORY | O_NOCTTY | O_NONBLOCK + | (ISSET (FTS_PHYSICAL) ? O_NOFOLLOW : 0) + | (ISSET (FTS_NOATIME) ? O_NOATIME : 0)); + + int fd = (ISSET (FTS_CWDFD) + ? openat (sp->fts_cwd_fd, dir, open_flags) + : open (dir, open_flags)); +- if (0 <= fd) +- set_cloexec_flag (fd, true); + return fd; + } + +@@ -470,6 +471,7 @@ fts_open (char * const *argv, + if ((parent = fts_alloc(sp, "", 0)) == NULL) + goto mem2; + parent->fts_level = FTS_ROOTPARENTLEVEL; ++ parent->fts_n_dirs_remaining = -1; + } + + /* The classic fts implementation would call fts_stat with +@@ -656,39 +658,139 @@ fts_close (FTS *sp) + return (0); + } + ++/* Minimum link count of a traditional Unix directory. When leaf ++ optimization is OK and MIN_DIR_NLINK <= st_nlink, then st_nlink is ++ an upper bound on the number of subdirectories (counting "." and ++ ".."). */ ++enum { MIN_DIR_NLINK = 2 }; ++ ++/* Whether leaf optimization is OK for a directory. */ ++enum leaf_optimization ++ { ++ /* st_nlink is not reliable for this directory's subdirectories. */ ++ NO_LEAF_OPTIMIZATION, ++ ++ /* Leaf optimization is OK, but is not useful for avoiding stat calls. */ ++ OK_LEAF_OPTIMIZATION, ++ ++ /* Leaf optimization is not only OK: it is useful for avoiding ++ stat calls, because dirent.d_type does not work. */ ++ NOSTAT_LEAF_OPTIMIZATION ++ }; ++ + #if defined __linux__ \ + && HAVE_SYS_VFS_H && HAVE_FSTATFS && HAVE_STRUCT_STATFS_F_TYPE + + # include + + /* Linux-specific constants from coreutils' src/fs.h */ +-# define S_MAGIC_TMPFS 0x1021994 ++# define S_MAGIC_AFS 0x5346414F + # define S_MAGIC_NFS 0x6969 ++# define S_MAGIC_PROC 0x9FA0 + # define S_MAGIC_REISERFS 0x52654973 ++# define S_MAGIC_TMPFS 0x1021994 + # define S_MAGIC_XFS 0x58465342 +-# define S_MAGIC_PROC 0x9FA0 + +-/* Return false if it is easy to determine the file system type of +- the directory on which DIR_FD is open, and sorting dirents on +- inode numbers is known not to improve traversal performance with +- that type of file system. Otherwise, return true. */ ++# ifdef HAVE___FSWORD_T ++typedef __fsword_t fsword; ++# else ++typedef long int fsword; ++# endif ++ ++/* Map a stat.st_dev number to a file system type number f_ftype. */ ++struct dev_type ++{ ++ dev_t st_dev; ++ fsword f_type; ++}; ++ ++/* Use a tiny initial size. If a traversal encounters more than ++ a few devices, the cost of growing/rehashing this table will be ++ rendered negligible by the number of inodes processed. */ ++enum { DEV_TYPE_HT_INITIAL_SIZE = 13 }; ++ ++static size_t ++dev_type_hash (void const *x, size_t table_size) ++{ ++ struct dev_type const *ax = x; ++ uintmax_t dev = ax->st_dev; ++ return dev % table_size; ++} ++ + static bool +-dirent_inode_sort_may_be_useful (int dir_fd) ++dev_type_compare (void const *x, void const *y) ++{ ++ struct dev_type const *ax = x; ++ struct dev_type const *ay = y; ++ return ax->st_dev == ay->st_dev; ++} ++ ++/* Return the file system type of P, or 0 if not known. ++ Try to cache known values. */ ++ ++static fsword ++filesystem_type (FTSENT const *p) ++{ ++ FTS *sp = p->fts_fts; ++ Hash_table *h = sp->fts_leaf_optimization_works_ht; ++ struct dev_type *ent; ++ struct statfs fs_buf; ++ ++ /* If we're not in CWDFD mode, don't bother with this optimization, ++ since the caller is not serious about performance. */ ++ if (!ISSET (FTS_CWDFD)) ++ return 0; ++ ++ if (! h) ++ h = sp->fts_leaf_optimization_works_ht ++ = hash_initialize (DEV_TYPE_HT_INITIAL_SIZE, NULL, dev_type_hash, ++ dev_type_compare, free); ++ if (h) ++ { ++ struct dev_type tmp; ++ tmp.st_dev = p->fts_statp->st_dev; ++ ent = hash_lookup (h, &tmp); ++ if (ent) ++ return ent->f_type; ++ } ++ ++ /* Look-up failed. Query directly and cache the result. */ ++ if (fstatfs (p->fts_fts->fts_cwd_fd, &fs_buf) != 0) ++ return 0; ++ ++ if (h) ++ { ++ struct dev_type *t2 = malloc (sizeof *t2); ++ if (t2) ++ { ++ t2->st_dev = p->fts_statp->st_dev; ++ t2->f_type = fs_buf.f_type; ++ ++ ent = hash_insert (h, t2); ++ if (ent) ++ fts_assert (ent == t2); ++ else ++ free (t2); ++ } ++ } ++ ++ return fs_buf.f_type; ++} ++ ++/* Return false if it is easy to determine the file system type of the ++ directory P, and sorting dirents on inode numbers is known not to ++ improve traversal performance with that type of file system. ++ Otherwise, return true. */ ++static bool ++dirent_inode_sort_may_be_useful (FTSENT const *p) + { + /* Skip the sort only if we can determine efficiently + that skipping it is the right thing to do. + The cost of performing an unnecessary sort is negligible, + while the cost of *not* performing it can be O(N^2) with + a very large constant. */ +- struct statfs fs_buf; +- +- /* If fstatfs fails, assume sorting would be useful. */ +- if (fstatfs (dir_fd, &fs_buf) != 0) +- return true; + +- /* FIXME: what about when f_type is not an integral type? +- deal with that if/when it's encountered. */ +- switch (fs_buf.f_type) ++ switch (filesystem_type (p)) + { + case S_MAGIC_TMPFS: + case S_MAGIC_NFS: +@@ -701,133 +803,58 @@ dirent_inode_sort_may_be_useful (int dir_fd) + } + } + +-/* Given a file descriptor DIR_FD open on a directory D, +- return true if it is valid to apply the leaf-optimization +- technique of counting directories in D via stat.st_nlink. */ +-static bool +-leaf_optimization_applies (int dir_fd) ++/* Given an FTS entry P for a directory D, ++ return true if it is both useful and valid to apply leaf optimization. ++ The optimization is useful only for file systems that lack usable ++ dirent.d_type info. The optimization is valid if an st_nlink value ++ of at least MIN_DIR_NLINK is an upper bound on the number of ++ subdirectories of D, counting "." and ".." as subdirectories. */ ++static enum leaf_optimization ++leaf_optimization (FTSENT const *p) + { +- struct statfs fs_buf; +- +- /* If fstatfs fails, assume we can't use the optimization. */ +- if (fstatfs (dir_fd, &fs_buf) != 0) +- return false; +- +- /* FIXME: do we need to detect AFS mount points? I doubt it, +- unless fstatfs can report S_MAGIC_REISERFS for such a directory. */ +- +- switch (fs_buf.f_type) ++ switch (filesystem_type (p)) + { +- case S_MAGIC_NFS: +- /* NFS provides usable dirent.d_type but not necessarily for all entries +- of large directories. See . */ +- return true; +- +- /* List here the file system types that lack usable dirent.d_type ++ /* List here the file system types that may lack usable dirent.d_type + info, yet for which the optimization does apply. */ + case S_MAGIC_REISERFS: +- case S_MAGIC_XFS: +- return true; +- ++ case S_MAGIC_XFS: /* XFS lacked it until 2013-08-22 commit. */ ++ return NOSTAT_LEAF_OPTIMIZATION; ++ ++ case 0: ++ /* Leaf optimization is unsafe if the file system type is unknown. */ ++ FALLTHROUGH; ++ case S_MAGIC_AFS: ++ /* Although AFS mount points are not counted in st_nlink, they ++ act like directories. See . */ ++ FALLTHROUGH; ++ case S_MAGIC_NFS: ++ /* NFS provides usable dirent.d_type but not necessarily for all entries ++ of large directories, so as per ++ NFS should return true. However st_nlink values are not accurate on ++ all implementations as per . */ ++ FALLTHROUGH; + case S_MAGIC_PROC: +- /* Explicitly listing this or any other file system type for which +- the optimization is not applicable is not necessary, but we leave +- it here to document the risk. Per http://bugs.debian.org/143111, +- /proc may have bogus stat.st_nlink values. */ +- /* fall through */ ++ /* Per /proc ++ may have bogus stat.st_nlink values. */ ++ return NO_LEAF_OPTIMIZATION; ++ + default: +- return false; ++ return OK_LEAF_OPTIMIZATION; + } + } + + #else + static bool +-dirent_inode_sort_may_be_useful (int dir_fd _GL_UNUSED) { return true; } +-static bool +-leaf_optimization_applies (int dir_fd _GL_UNUSED) { return false; } +-#endif +- +-/* link-count-optimization entry: +- map a stat.st_dev number to a boolean: leaf_optimization_works */ +-struct LCO_ent +-{ +- dev_t st_dev; +- bool opt_ok; +-}; +- +-/* Use a tiny initial size. If a traversal encounters more than +- a few devices, the cost of growing/rehashing this table will be +- rendered negligible by the number of inodes processed. */ +-enum { LCO_HT_INITIAL_SIZE = 13 }; +- +-static size_t +-LCO_hash (void const *x, size_t table_size) +-{ +- struct LCO_ent const *ax = x; +- return (uintmax_t) ax->st_dev % table_size; +-} +- +-static bool +-LCO_compare (void const *x, void const *y) ++dirent_inode_sort_may_be_useful (FTSENT const *p _GL_UNUSED) + { +- struct LCO_ent const *ax = x; +- struct LCO_ent const *ay = y; +- return ax->st_dev == ay->st_dev; ++ return true; + } +- +-/* Ask the same question as leaf_optimization_applies, but query +- the cache first (FTS.fts_leaf_optimization_works_ht), and if necessary, +- update that cache. */ +-static bool +-link_count_optimize_ok (FTSENT const *p) ++static enum leaf_optimization ++leaf_optimization (FTSENT const *p _GL_UNUSED) + { +- FTS *sp = p->fts_fts; +- Hash_table *h = sp->fts_leaf_optimization_works_ht; +- struct LCO_ent tmp; +- struct LCO_ent *ent; +- bool opt_ok; +- struct LCO_ent *t2; +- +- /* If we're not in CWDFD mode, don't bother with this optimization, +- since the caller is not serious about performance. */ +- if (!ISSET(FTS_CWDFD)) +- return false; +- +- /* map st_dev to the boolean, leaf_optimization_works */ +- if (h == NULL) +- { +- h = sp->fts_leaf_optimization_works_ht +- = hash_initialize (LCO_HT_INITIAL_SIZE, NULL, LCO_hash, +- LCO_compare, free); +- if (h == NULL) +- return false; +- } +- tmp.st_dev = p->fts_statp->st_dev; +- ent = hash_lookup (h, &tmp); +- if (ent) +- return ent->opt_ok; +- +- /* Look-up failed. Query directly and cache the result. */ +- t2 = malloc (sizeof *t2); +- if (t2 == NULL) +- return false; +- +- /* Is it ok to perform the optimization in the dir, FTS_CWD_FD? */ +- opt_ok = leaf_optimization_applies (sp->fts_cwd_fd); +- t2->opt_ok = opt_ok; +- t2->st_dev = p->fts_statp->st_dev; +- +- ent = hash_insert (h, t2); +- if (ent == NULL) +- { +- /* insertion failed */ +- free (t2); +- return false; +- } +- fts_assert (ent == t2); +- +- return opt_ok; ++ return NO_LEAF_OPTIMIZATION; + } ++#endif + + /* + * Special case of "/" at the end of the file name so that slashes aren't +@@ -1014,13 +1041,11 @@ check_for_dir: + if (p->fts_statp->st_size == FTS_STAT_REQUIRED) + { + FTSENT *parent = p->fts_parent; +- if (FTS_ROOTLEVEL < p->fts_level +- /* ->fts_n_dirs_remaining is not valid +- for command-line-specified names. */ +- && parent->fts_n_dirs_remaining == 0 ++ if (parent->fts_n_dirs_remaining == 0 + && ISSET(FTS_NOSTAT) + && ISSET(FTS_PHYSICAL) +- && link_count_optimize_ok (parent)) ++ && (leaf_optimization (parent) ++ == NOSTAT_LEAF_OPTIMIZATION)) + { + /* nothing more needed */ + } +@@ -1029,7 +1054,8 @@ check_for_dir: + p->fts_info = fts_stat(sp, p, false); + if (S_ISDIR(p->fts_statp->st_mode) + && p->fts_level != FTS_ROOTLEVEL +- && parent->fts_n_dirs_remaining) ++ && 0 < parent->fts_n_dirs_remaining ++ && parent->fts_n_dirs_remaining != (nlink_t) -1) + parent->fts_n_dirs_remaining--; + } + } +@@ -1298,8 +1324,6 @@ fts_build (register FTS *sp, int type) + bool descend; + bool doadjust; + ptrdiff_t level; +- nlink_t nlinks; +- bool nostat; + size_t len, maxlen, new_len; + char *cp; + int dir_fd; +@@ -1369,24 +1393,6 @@ fts_build (register FTS *sp, int type) + sorting, yet not so large that we risk exhausting memory. */ + max_entries = sp->fts_compar ? SIZE_MAX : FTS_MAX_READDIR_ENTRIES; + +- /* +- * Nlinks is the number of possible entries of type directory in the +- * directory if we're cheating on stat calls, 0 if we're not doing +- * any stat calls at all, (nlink_t) -1 if we're statting everything. +- */ +- if (type == BNAMES) { +- nlinks = 0; +- /* Be quiet about nostat, GCC. */ +- nostat = false; +- } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { +- nlinks = (cur->fts_statp->st_nlink +- - (ISSET(FTS_SEEDOT) ? 0 : 2)); +- nostat = true; +- } else { +- nlinks = -1; +- nostat = false; +- } +- + /* + * If we're going to need to stat anything or we want to descend + * and stay in the directory, chdir. If this fails we keep going, +@@ -1408,15 +1414,22 @@ fts_build (register FTS *sp, int type) + the required dirp and dir_fd. */ + descend = true; + } +- else if (nlinks || type == BREAD) { ++ else ++ { ++ /* Try to descend unless it is a names-only fts_children, ++ or the directory is known to lack subdirectories. */ ++ descend = (type != BNAMES ++ && ! (ISSET (FTS_NOSTAT) && ISSET (FTS_PHYSICAL) ++ && ! ISSET (FTS_SEEDOT) ++ && cur->fts_statp->st_nlink == MIN_DIR_NLINK ++ && (leaf_optimization (cur) ++ != NO_LEAF_OPTIMIZATION))); ++ if (descend || type == BREAD) ++ { + if (ISSET(FTS_CWDFD)) +- { +- dir_fd = dup (dir_fd); +- if (0 <= dir_fd) +- set_cloexec_flag (dir_fd, true); +- } ++ dir_fd = fcntl (dir_fd, F_DUPFD_CLOEXEC, STDERR_FILENO + 1); + if (dir_fd < 0 || fts_safe_changedir(sp, cur, dir_fd, NULL)) { +- if (nlinks && type == BREAD) ++ if (descend && type == BREAD) + cur->fts_errno = errno; + cur->fts_flags |= FTS_DONTCHDIR; + descend = false; +@@ -1426,8 +1439,8 @@ fts_build (register FTS *sp, int type) + cur->fts_dirp = NULL; + } else + descend = true; +- } else +- descend = false; ++ } ++ } + + /* + * Figure out the max file name length that can be stored in the +@@ -1458,11 +1471,19 @@ fts_build (register FTS *sp, int type) + tail = NULL; + nitems = 0; + while (cur->fts_dirp) { +- bool is_dir; + size_t d_namelen; ++ __set_errno (0); + struct dirent *dp = readdir(cur->fts_dirp); +- if (dp == NULL) ++ if (dp == NULL) { ++ if (errno) { ++ cur->fts_errno = errno; ++ /* If we've not read any items yet, treat ++ the error as if we can't access the dir. */ ++ cur->fts_info = (continue_readdir || nitems) ++ ? FTS_ERR : FTS_DNR; ++ } + break; ++ } + if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) + continue; + +@@ -1550,19 +1571,10 @@ mem1: saved_errno = errno; + to caller, when possible. */ + set_stat_type (p->fts_statp, D_TYPE (dp)); + fts_set_stat_required(p, !skip_stat); +- is_dir = (ISSET(FTS_PHYSICAL) +- && DT_MUST_BE(dp, DT_DIR)); + } else { + p->fts_info = fts_stat(sp, p, false); +- is_dir = (p->fts_info == FTS_D +- || p->fts_info == FTS_DC +- || p->fts_info == FTS_DOT); + } + +- /* Decrement link count if applicable. */ +- if (nlinks > 0 && is_dir) +- nlinks -= nostat; +- + /* We walk in directory order so "ls -f" doesn't get upset. */ + p->fts_link = NULL; + if (head == NULL) +@@ -1621,7 +1633,8 @@ mem1: saved_errno = errno; + + /* If didn't find anything, return NULL. */ + if (!nitems) { +- if (type == BREAD) ++ if (type == BREAD ++ && cur->fts_info != FTS_DNR && cur->fts_info != FTS_ERR) + cur->fts_info = FTS_DP; + fts_lfree(head); + return (NULL); +@@ -1633,8 +1646,7 @@ mem1: saved_errno = errno; + inode numbers. */ + if (nitems > _FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD + && !sp->fts_compar +- && ISSET (FTS_CWDFD) +- && dirent_inode_sort_may_be_useful (sp->fts_cwd_fd)) { ++ && dirent_inode_sort_may_be_useful (cur)) { + sp->fts_compar = fts_compare_ino; + head = fts_sort (sp, head, nitems); + sp->fts_compar = NULL; +@@ -1757,7 +1769,7 @@ fd_ring_check (FTS const *sp) + I_ring fd_w = sp->fts_fd_ring; + + int cwd_fd = sp->fts_cwd_fd; +- cwd_fd = dup (cwd_fd); ++ cwd_fd = fcntl (cwd_fd, F_DUPFD_CLOEXEC, STDERR_FILENO + 1); + char *dot = getcwdat (cwd_fd, NULL, 0); + error (0, 0, "===== check ===== cwd: %s", dot); + free (dot); +@@ -1766,7 +1778,8 @@ fd_ring_check (FTS const *sp) + int fd = i_ring_pop (&fd_w); + if (0 <= fd) + { +- int parent_fd = openat (cwd_fd, "..", O_SEARCH | O_NOATIME); ++ int open_flags = O_SEARCH | O_CLOEXEC | O_NOATIME; ++ int parent_fd = openat (cwd_fd, "..", open_flags); + if (parent_fd < 0) + { + // Warn? +@@ -1795,7 +1808,6 @@ internal_function + fts_stat(FTS *sp, register FTSENT *p, bool follow) + { + struct stat *sbp = p->fts_statp; +- int saved_errno; + + if (p->fts_level == FTS_ROOTLEVEL && ISSET(FTS_COMFOLLOW)) + follow = true; +@@ -1807,13 +1819,12 @@ fts_stat(FTS *sp, register FTSENT *p, bool follow) + */ + if (ISSET(FTS_LOGICAL) || follow) { + if (stat(p->fts_accpath, sbp)) { +- saved_errno = errno; + if (errno == ENOENT + && lstat(p->fts_accpath, sbp) == 0) { + __set_errno (0); + return (FTS_SLNONE); + } +- p->fts_errno = saved_errno; ++ p->fts_errno = errno; + goto err; + } + } else if (fstatat(sp->fts_cwd_fd, p->fts_accpath, sbp, +@@ -1824,8 +1835,11 @@ err: memset(sbp, 0, sizeof(struct stat)); + } + + if (S_ISDIR(sbp->st_mode)) { +- p->fts_n_dirs_remaining = (sbp->st_nlink +- - (ISSET(FTS_SEEDOT) ? 0 : 2)); ++ p->fts_n_dirs_remaining ++ = ((sbp->st_nlink < MIN_DIR_NLINK ++ || p->fts_level <= FTS_ROOTLEVEL) ++ ? -1 ++ : sbp->st_nlink - (ISSET (FTS_SEEDOT) ? 0 : MIN_DIR_NLINK)); + if (ISDOT(p->fts_name)) { + /* Command-line "." and ".." are real directories. */ + return (p->fts_level == FTS_ROOTLEVEL ? FTS_D : FTS_DOT); +@@ -1914,17 +1928,7 @@ fts_alloc (FTS *sp, const char *name, register size_t namelen) + * The file name is a variable length array. Allocate the FTSENT + * structure and the file name in one chunk. + */ +- len = offsetof(FTSENT, fts_name) + namelen + 1; +- /* Align the allocation size so that it works for FTSENT, +- so that trailing padding may be referenced by direct access +- to the flexible array members, without triggering undefined behavior +- by accessing bytes beyond the heap allocation. This implicit access +- was seen for example with ISDOT() and GCC 5.1.1 at -O2. +- Do not use alignof (FTSENT) here, since C11 prohibits +- taking the alignment of a structure containing a flexible +- array member. */ +- len += alignof (max_align_t) - 1; +- len &= ~ (alignof (max_align_t) - 1); ++ len = FLEXSIZEOF(FTSENT, fts_name, namelen + 1); + if ((p = malloc(len)) == NULL) + return (NULL); + +diff --git a/gl/lib/fts_.h b/gl/lib/fts_.h +index b9a3f12..70cc9e3 100644 +--- a/gl/lib/fts_.h ++++ b/gl/lib/fts_.h +@@ -1,6 +1,6 @@ + /* Traverse a file hierarchy. + +- Copyright (C) 2004-2015 Free Software Foundation, Inc. ++ Copyright (C) 2004-2018 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by +@@ -13,7 +13,7 @@ + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License +- along with this program. If not, see . */ ++ along with this program. If not, see . */ + + /* + * Copyright (c) 1989, 1993 +@@ -220,7 +220,11 @@ typedef struct _ftsent { + ptrdiff_t fts_level; /* depth (-1 to N) */ + + size_t fts_namelen; /* strlen(fts_name) */ +- nlink_t fts_n_dirs_remaining; /* count down from st_nlink */ ++ ++ /* If not (nlink_t) -1, an upper bound on the number of ++ remaining subdirectories of interest. If this becomes ++ zero, some work can be avoided. */ ++ nlink_t fts_n_dirs_remaining; + + # define FTS_D 1 /* preorder directory */ + # define FTS_DC 2 /* directory that causes cycles */ +-- +2.13.6 + + +From ea88dd373c60feab541fe037369805f326dc3494 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Mon, 12 Feb 2018 18:58:30 +0100 +Subject: [PATCH 2/4] fts: remove dependency on gnulib's fleximember.h + +... by reverting upstream commit edb9d82948cb23f67a19e1b435047a0570225df3 +--- + gl/lib/fts.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/gl/lib/fts.c b/gl/lib/fts.c +index bfa73e3..c37ebe2 100644 +--- a/gl/lib/fts.c ++++ b/gl/lib/fts.c +@@ -71,7 +71,6 @@ static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94"; + + #if ! _LIBC + # include "fcntl--.h" +-# include "flexmember.h" + # include "openat.h" + # include "same-inode.h" + #endif +@@ -1928,7 +1927,17 @@ fts_alloc (FTS *sp, const char *name, register size_t namelen) + * The file name is a variable length array. Allocate the FTSENT + * structure and the file name in one chunk. + */ +- len = FLEXSIZEOF(FTSENT, fts_name, namelen + 1); ++ len = offsetof(FTSENT, fts_name) + namelen + 1; ++ /* Align the allocation size so that it works for FTSENT, ++ so that trailing padding may be referenced by direct access ++ to the flexible array members, without triggering undefined behavior ++ by accessing bytes beyond the heap allocation. This implicit access ++ was seen for example with ISDOT() and GCC 5.1.1 at -O2. ++ Do not use alignof (FTSENT) here, since C11 prohibits ++ taking the alignment of a structure containing a flexible ++ array member. */ ++ len += alignof (max_align_t) - 1; ++ len &= ~ (alignof (max_align_t) - 1); + if ((p = malloc(len)) == NULL) + return (NULL); + +-- +2.13.6 + + +From 9c1720c99bbf8998dfdaa5976bca8bdc6d93f8e7 Mon Sep 17 00:00:00 2001 +From: Paul Eggert +Date: Thu, 5 Apr 2018 08:48:01 -0700 +Subject: [PATCH 3/4] fts: treat CIFS like NFS + +Problem reported by Kamil Dudka in: +https://lists.gnu.org/r/bug-gnulib/2018-04/msg00015.html +* lib/fts.c (S_MAGIC_CIFS): New macro. +(dirent_inode_sort_may_be_useful, leaf_optimization): +Treat CIFS like NFS. + +Upstream-commit: 2e53df541a30d438859087ed4b5a396e04697b9b +Signed-off-by: Kamil Dudka +--- + gl/lib/fts.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/gl/lib/fts.c b/gl/lib/fts.c +index c37ebe2..508ceac 100644 +--- a/gl/lib/fts.c ++++ b/gl/lib/fts.c +@@ -684,6 +684,7 @@ enum leaf_optimization + + /* Linux-specific constants from coreutils' src/fs.h */ + # define S_MAGIC_AFS 0x5346414F ++# define S_MAGIC_CIFS 0xFF534D42 + # define S_MAGIC_NFS 0x6969 + # define S_MAGIC_PROC 0x9FA0 + # define S_MAGIC_REISERFS 0x52654973 +@@ -791,8 +792,9 @@ dirent_inode_sort_may_be_useful (FTSENT const *p) + + switch (filesystem_type (p)) + { +- case S_MAGIC_TMPFS: ++ case S_MAGIC_CIFS: + case S_MAGIC_NFS: ++ case S_MAGIC_TMPFS: + /* On a file system of any of these types, sorting + is unnecessary, and hence wasteful. */ + return false; +@@ -826,6 +828,10 @@ leaf_optimization (FTSENT const *p) + /* Although AFS mount points are not counted in st_nlink, they + act like directories. See . */ + FALLTHROUGH; ++ case S_MAGIC_CIFS: ++ /* Leaf optimization causes 'find' to abort. See ++ . */ ++ FALLTHROUGH; + case S_MAGIC_NFS: + /* NFS provides usable dirent.d_type but not necessarily for all entries + of large directories, so as per +-- +2.14.3 + + +From ff64329a046e76ba553c15373ed61bbed814d286 Mon Sep 17 00:00:00 2001 +From: Paul Eggert +Date: Wed, 11 Apr 2018 12:50:35 -0700 +Subject: [PATCH 4/4] fts: fix bug in find across filesystems + +This fixes a bug I introduced last summer. +Problem reported by Kamil Dudka in: +https://lists.gnu.org/r/bug-gnulib/2018-04/msg00033.html +* lib/fts.c (filesystem_type, dirent_inode_sort_may_be_useful) +(leaf_optimization): +New arg for file descriptor. All callers changed. +(fts_build): Check for whether inodes should be sorted +before closing the directory. + +Upstream-commit: 81b8c0d3be98f5a77403599de3d06329b3e7673e +Signed-off-by: Kamil Dudka +--- + gl/lib/fts.c | 55 +++++++++++++++++++++++++++++++------------------------ + 1 file changed, 31 insertions(+), 24 deletions(-) + +diff --git a/gl/lib/fts.c b/gl/lib/fts.c +index 508ceac..175f12a 100644 +--- a/gl/lib/fts.c ++++ b/gl/lib/fts.c +@@ -725,11 +725,12 @@ dev_type_compare (void const *x, void const *y) + return ax->st_dev == ay->st_dev; + } + +-/* Return the file system type of P, or 0 if not known. ++/* Return the file system type of P with file descriptor FD, or 0 if not known. ++ If FD is negative, P's file descriptor is unavailable. + Try to cache known values. */ + + static fsword +-filesystem_type (FTSENT const *p) ++filesystem_type (FTSENT const *p, int fd) + { + FTS *sp = p->fts_fts; + Hash_table *h = sp->fts_leaf_optimization_works_ht; +@@ -755,7 +756,7 @@ filesystem_type (FTSENT const *p) + } + + /* Look-up failed. Query directly and cache the result. */ +- if (fstatfs (p->fts_fts->fts_cwd_fd, &fs_buf) != 0) ++ if (fd < 0 || fstatfs (fd, &fs_buf) != 0) + return 0; + + if (h) +@@ -777,12 +778,12 @@ filesystem_type (FTSENT const *p) + return fs_buf.f_type; + } + +-/* Return false if it is easy to determine the file system type of the +- directory P, and sorting dirents on inode numbers is known not to +- improve traversal performance with that type of file system. +- Otherwise, return true. */ ++/* Return true if sorting dirents on inode numbers is known to improve ++ traversal performance for the directory P with descriptor DIR_FD. ++ Return false otherwise. When in doubt, return true. ++ DIR_FD is negative if unavailable. */ + static bool +-dirent_inode_sort_may_be_useful (FTSENT const *p) ++dirent_inode_sort_may_be_useful (FTSENT const *p, int dir_fd) + { + /* Skip the sort only if we can determine efficiently + that skipping it is the right thing to do. +@@ -790,7 +791,7 @@ dirent_inode_sort_may_be_useful (FTSENT const *p) + while the cost of *not* performing it can be O(N^2) with + a very large constant. */ + +- switch (filesystem_type (p)) ++ switch (filesystem_type (p, dir_fd)) + { + case S_MAGIC_CIFS: + case S_MAGIC_NFS: +@@ -804,16 +805,17 @@ dirent_inode_sort_may_be_useful (FTSENT const *p) + } + } + +-/* Given an FTS entry P for a directory D, ++/* Given an FTS entry P for a directory with descriptor DIR_FD, + return true if it is both useful and valid to apply leaf optimization. + The optimization is useful only for file systems that lack usable + dirent.d_type info. The optimization is valid if an st_nlink value + of at least MIN_DIR_NLINK is an upper bound on the number of +- subdirectories of D, counting "." and ".." as subdirectories. */ ++ subdirectories of D, counting "." and ".." as subdirectories. ++ DIR_FD is negative if unavailable. */ + static enum leaf_optimization +-leaf_optimization (FTSENT const *p) ++leaf_optimization (FTSENT const *p, int dir_fd) + { +- switch (filesystem_type (p)) ++ switch (filesystem_type (p, dir_fd)) + { + /* List here the file system types that may lack usable dirent.d_type + info, yet for which the optimization does apply. */ +@@ -850,12 +852,13 @@ leaf_optimization (FTSENT const *p) + + #else + static bool +-dirent_inode_sort_may_be_useful (FTSENT const *p _GL_UNUSED) ++dirent_inode_sort_may_be_useful (FTSENT const *p _GL_UNUSED, ++ int dir_fd _GL_UNUSED) + { + return true; + } + static enum leaf_optimization +-leaf_optimization (FTSENT const *p _GL_UNUSED) ++leaf_optimization (FTSENT const *p _GL_UNUSED, int dir_fd _GL_UNUSED) + { + return NO_LEAF_OPTIMIZATION; + } +@@ -1049,7 +1052,7 @@ check_for_dir: + if (parent->fts_n_dirs_remaining == 0 + && ISSET(FTS_NOSTAT) + && ISSET(FTS_PHYSICAL) +- && (leaf_optimization (parent) ++ && (leaf_optimization (parent, sp->fts_cwd_fd) + == NOSTAT_LEAF_OPTIMIZATION)) + { + /* nothing more needed */ +@@ -1334,6 +1337,7 @@ fts_build (register FTS *sp, int type) + int dir_fd; + FTSENT *cur = sp->fts_cur; + bool continue_readdir = !!cur->fts_dirp; ++ bool sort_by_inode = false; + size_t max_entries; + + /* When cur->fts_dirp is non-NULL, that means we should +@@ -1427,7 +1431,7 @@ fts_build (register FTS *sp, int type) + && ! (ISSET (FTS_NOSTAT) && ISSET (FTS_PHYSICAL) + && ! ISSET (FTS_SEEDOT) + && cur->fts_statp->st_nlink == MIN_DIR_NLINK +- && (leaf_optimization (cur) ++ && (leaf_optimization (cur, dir_fd) + != NO_LEAF_OPTIMIZATION))); + if (descend || type == BREAD) + { +@@ -1588,6 +1592,15 @@ mem1: saved_errno = errno; + tail->fts_link = p; + tail = p; + } ++ ++ /* If there are many entries, no sorting function has been ++ specified, and this file system is of a type that may be ++ slow with a large number of entries, arrange to sort the ++ directory entries on increasing inode numbers. */ ++ if (nitems == _FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD ++ && !sp->fts_compar) ++ sort_by_inode = dirent_inode_sort_may_be_useful (cur, dir_fd); ++ + ++nitems; + if (max_entries <= nitems) { + /* When there are too many dir entries, leave +@@ -1645,13 +1658,7 @@ mem1: saved_errno = errno; + return (NULL); + } + +- /* If there are many entries, no sorting function has been specified, +- and this file system is of a type that may be slow with a large +- number of entries, then sort the directory entries on increasing +- inode numbers. */ +- if (nitems > _FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD +- && !sp->fts_compar +- && dirent_inode_sort_may_be_useful (cur)) { ++ if (sort_by_inode) { + sp->fts_compar = fts_compare_ino; + head = fts_sort (sp, head, nitems); + sp->fts_compar = NULL; +-- +2.14.3 + diff --git a/findutils-4.6.0-gnulib-fflush.patch b/findutils-4.6.0-gnulib-fflush.patch new file mode 100644 index 0000000..47ac93b --- /dev/null +++ b/findutils-4.6.0-gnulib-fflush.patch @@ -0,0 +1,142 @@ +From 80cdfba079627e15129a926a133825b961d41e36 Mon Sep 17 00:00:00 2001 +From: Paul Eggert +Date: Mon, 5 Mar 2018 10:56:29 -0800 +Subject: [PATCH] fflush: adjust to glibc 2.28 libio.h removal +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Problem reported by Daniel P. Berrangé in: +https://lists.gnu.org/r/bug-gnulib/2018-03/msg00000.html +* lib/fflush.c (clear_ungetc_buffer_preserving_position) +(disable_seek_optimization, rpl_fflush): +* lib/fpurge.c (fpurge): +* lib/freadahead.c (freadahead): +* lib/freading.c (freading): +* lib/fseeko.c (fseeko): +* lib/stdio-impl.h (_IO_IN_BACKUP) [_IO_EOF_SEEN]: +Define if not already defined. + +Upstream-commit: 4af4a4a71827c0bc5e0ec67af23edef4f15cee8e +Signed-off-by: Kamil Dudka +--- + gl/lib/fflush.c | 6 +++--- + gl/lib/fpurge.c | 2 +- + gl/lib/freadahead.c | 2 +- + gl/lib/freading.c | 2 +- + gl/lib/fseeko.c | 4 ++-- + gl/lib/stdio-impl.h | 6 ++++++ + 6 files changed, 14 insertions(+), 8 deletions(-) + +diff --git a/gl/lib/fflush.c b/gl/lib/fflush.c +index 5ae3e41..7a82470 100644 +--- a/gl/lib/fflush.c ++++ b/gl/lib/fflush.c +@@ -33,7 +33,7 @@ + #undef fflush + + +-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ ++#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ + + /* Clear the stream's ungetc buffer, preserving the value of ftello (fp). */ + static void +@@ -72,7 +72,7 @@ clear_ungetc_buffer (FILE *fp) + + #endif + +-#if ! (defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */) ++#if ! (defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */) + + # if (defined __sferror || defined __DragonFly__ || defined __ANDROID__) && defined __SNPT + /* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin, Android */ +@@ -148,7 +148,7 @@ rpl_fflush (FILE *stream) + if (stream == NULL || ! freading (stream)) + return fflush (stream); + +-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ ++#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ + + clear_ungetc_buffer_preserving_position (stream); + +diff --git a/gl/lib/fpurge.c b/gl/lib/fpurge.c +index f313b22..ecdf82d 100644 +--- a/gl/lib/fpurge.c ++++ b/gl/lib/fpurge.c +@@ -62,7 +62,7 @@ fpurge (FILE *fp) + /* Most systems provide FILE as a struct and the necessary bitmask in + , because they need it for implementing getc() and putc() as + fast macros. */ +-# if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ ++# if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ + fp->_IO_read_end = fp->_IO_read_ptr; + fp->_IO_write_ptr = fp->_IO_write_base; + /* Avoid memory leak when there is an active ungetc buffer. */ +diff --git a/gl/lib/freadahead.c b/gl/lib/freadahead.c +index 094daab..3f8101e 100644 +--- a/gl/lib/freadahead.c ++++ b/gl/lib/freadahead.c +@@ -25,7 +25,7 @@ + size_t + freadahead (FILE *fp) + { +-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ ++#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ + if (fp->_IO_write_ptr > fp->_IO_write_base) + return 0; + return (fp->_IO_read_end - fp->_IO_read_ptr) +diff --git a/gl/lib/freading.c b/gl/lib/freading.c +index 0512b19..8c48fe4 100644 +--- a/gl/lib/freading.c ++++ b/gl/lib/freading.c +@@ -31,7 +31,7 @@ freading (FILE *fp) + /* Most systems provide FILE as a struct and the necessary bitmask in + , because they need it for implementing getc() and putc() as + fast macros. */ +-# if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ ++# if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ + return ((fp->_flags & _IO_NO_WRITES) != 0 + || ((fp->_flags & (_IO_NO_READS | _IO_CURRENTLY_PUTTING)) == 0 + && fp->_IO_read_base != NULL)); +diff --git a/gl/lib/fseeko.c b/gl/lib/fseeko.c +index 1c65d2a..9026408 100644 +--- a/gl/lib/fseeko.c ++++ b/gl/lib/fseeko.c +@@ -47,7 +47,7 @@ fseeko (FILE *fp, off_t offset, int whence) + #endif + + /* These tests are based on fpurge.c. */ +-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ ++#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ + if (fp->_IO_read_end == fp->_IO_read_ptr + && fp->_IO_write_ptr == fp->_IO_write_base + && fp->_IO_save_base == NULL) +@@ -123,7 +123,7 @@ fseeko (FILE *fp, off_t offset, int whence) + return -1; + } + +-#if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ ++#if defined _IO_EOF_SEEN || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */ + fp->_flags &= ~_IO_EOF_SEEN; + fp->_offset = pos; + #elif defined __sferror || defined __DragonFly__ || defined __ANDROID__ +diff --git a/gl/lib/stdio-impl.h b/gl/lib/stdio-impl.h +index 502d891..ea38ee2 100644 +--- a/gl/lib/stdio-impl.h ++++ b/gl/lib/stdio-impl.h +@@ -18,6 +18,12 @@ + the same implementation of stdio extension API, except that some fields + have different naming conventions, or their access requires some casts. */ + ++/* Glibc 2.28 made _IO_IN_BACKUP private. For now, work around this ++ problem by defining it ourselves. FIXME: Do not rely on glibc ++ internals. */ ++#if !defined _IO_IN_BACKUP && defined _IO_EOF_SEEN ++# define _IO_IN_BACKUP 0x100 ++#endif + + /* BSD stdio derived implementations. */ + +-- +2.16.2 + diff --git a/findutils-4.6.0-gnulib-makedev.patch b/findutils-4.6.0-gnulib-makedev.patch new file mode 100644 index 0000000..5ed4b48 --- /dev/null +++ b/findutils-4.6.0-gnulib-makedev.patch @@ -0,0 +1,80 @@ +From 80628047a6cc83f82e0c410a82b8f7facd9d50f2 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Wed, 14 Sep 2016 19:21:42 -0500 +Subject: [PATCH] mountlist: include sysmacros.h for glibc + +On Fedora rawhide (glibc 2.25), './gnulib-tool --test mountlist' +reports: +../../gllib/mountlist.c: In function 'read_file_system_list': +../../gllib/mountlist.c:534:13: warning: '__makedev_from_sys_types' is deprecated: + In the GNU C Library, `makedev' is defined by . + For historical compatibility, it is currently defined by + as well, but we plan to remove this soon. + To use `makedev', include directly. + If you did not intend to use a system-defined macro `makedev', + you should #undef it after including . + [-Wdeprecated-declarations] + me->me_dev = makedev (devmaj, devmin); + ^~ +In file included from /usr/include/features.h:397:0, + from /usr/include/sys/types.h:25, + from ./sys/types.h:28, + from ../../gllib/mountlist.h:23, + from ../../gllib/mountlist.c:20: +/usr/include/sys/sysmacros.h:89:1: note: declared here + __SYSMACROS_DEFINE_MAKEDEV (__SYSMACROS_FST_IMPL_TEMPL) + ^ + +Fix it by including the right headers. We also need a fix to +autoconf's AC_HEADER_MAJOR, but that's a separate patch. + +* m4/mountlist.m4 (gl_PREREQ_MOUTLIST_EXTRA): Include +AC_HEADER_MAJOR. +* lib/mountlist.c (includes): Use correct headers. + +Signed-off-by: Eric Blake + +Upstream-commit: 4da63c5881f60f71999a943612da9112232b9161 +Signed-off-by: Kamil Dudka +--- + gl/lib/mountlist.c | 6 ++++++ + gl/m4/mountlist.m4 | 3 ++- + 2 files changed, 8 insertions(+), 1 deletion(-) + +diff --git a/gl/lib/mountlist.c b/gl/lib/mountlist.c +index c3d2852..0b6f92e 100644 +--- a/gl/lib/mountlist.c ++++ b/gl/lib/mountlist.c +@@ -37,6 +37,12 @@ + # include + #endif + ++#if MAJOR_IN_MKDEV ++# include ++#elif MAJOR_IN_SYSMACROS ++# include ++#endif ++ + #if defined MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */ + # if HAVE_SYS_UCRED_H + # include /* needed on OSF V4.0 for definition of NGROUPS, +diff --git a/gl/m4/mountlist.m4 b/gl/m4/mountlist.m4 +index ec58dc8..82b2dcb 100644 +--- a/gl/m4/mountlist.m4 ++++ b/gl/m4/mountlist.m4 +@@ -1,4 +1,4 @@ +-# serial 11 ++# serial 12 + dnl Copyright (C) 2002-2006, 2009-2015 Free Software Foundation, Inc. + dnl This file is free software; the Free Software Foundation + dnl gives unlimited permission to copy and/or distribute it, +@@ -15,5 +15,6 @@ AC_DEFUN([gl_PREREQ_MOUNTLIST_EXTRA], + [ + dnl Note gl_LIST_MOUNTED_FILE_SYSTEMS checks for mntent.h, not sys/mntent.h. + AC_CHECK_HEADERS([sys/mntent.h]) ++ AC_HEADER_MAJOR()dnl for use of makedev () + gl_FSTYPENAME + ]) +-- +2.16.2 + diff --git a/findutils-4.6.0-internal-noop.patch b/findutils-4.6.0-internal-noop.patch new file mode 100644 index 0000000..1c8fdd9 --- /dev/null +++ b/findutils-4.6.0-internal-noop.patch @@ -0,0 +1,195 @@ +From d844b7bbf3952998a906f21ba432aa62a3b9c7c6 Mon Sep 17 00:00:00 2001 +From: Bernhard Voelker +Date: Tue, 14 Jun 2016 20:49:42 +0200 +Subject: [PATCH] Fix bug #48180: find: avoid segfault for internal '-noop' + option + +The pseudo-option '-noop' was never meant to be exposed to the user +interface. If specified by the user, find(1) segfaulted. +Bug introduced in commit FINDUTILS_4_3_0-1-12-g6b8a4db. + +* find/parser.c (struct parser_table): Rename the parser_name element of +the ARG_NOOP entry from 'noop' to '--noop', thus indicating its pure +internal character. +(found_parser): Return NULL when the user has passed the '---noop' option; +the caller does the error handling. +* find/testsuite/sv-48180-refuse-noop.sh: Add test. +* find/testsuite/Makefile.am (test_shell_progs): Reference the test. +* NEWS (Bug fixes): Document the fix. + +Reported by Tavian Barnes in + https://savannah.gnu.org/bugs/?48180 + +Upstream-commit: 595060f28eb5f658fa8d98970959c617fab0f078 +Signed-off-by: Kamil Dudka +--- + find/parser.c | 6 +- + find/testsuite/Makefile.am | 3 +- + find/testsuite/sv-48180-refuse-noop.sh | 117 +++++++++++++++++++++++++++++++++ + 3 files changed, 124 insertions(+), 2 deletions(-) + create mode 100644 find/testsuite/sv-48180-refuse-noop.sh + +diff --git a/find/parser.c b/find/parser.c +index 2d45349..697b2a2 100644 +--- a/find/parser.c ++++ b/find/parser.c +@@ -321,7 +321,8 @@ static struct parser_table const parse_table[] = + */ + {ARG_TEST, "false", parse_false, pred_false}, /* GNU */ + {ARG_TEST, "true", parse_true, pred_true }, /* GNU */ +- {ARG_NOOP, "noop", NULL, pred_true }, /* GNU, internal use only */ ++ /* Internal pseudo-option, therefore 3 minus: ---noop. */ ++ {ARG_NOOP, "--noop", NULL, pred_true }, /* GNU, internal use only */ + + /* Various other cases that don't fit neatly into our macro scheme. */ + {ARG_TEST, "help", parse_help, NULL}, /* GNU */ +@@ -596,6 +597,9 @@ found_parser (const char *original_arg, const struct parser_table *entry) + */ + if (entry->type != ARG_POSITIONAL_OPTION) + { ++ if (entry->type == ARG_NOOP) ++ return NULL; /* internal use only, trap -noop here. */ ++ + /* Something other than -follow/-daystart. + * If this is an option, check if it followed + * a non-option and if so, issue a warning. +diff --git a/find/testsuite/Makefile.am b/find/testsuite/Makefile.am +index ab5dbe8..1371c70 100644 +--- a/find/testsuite/Makefile.am ++++ b/find/testsuite/Makefile.am +@@ -259,7 +259,8 @@ test_escape_c.sh \ + test_inode.sh \ + sv-34079.sh \ + sv-34976-execdir-fd-leak.sh \ +-sv-48030-exec-plus-bug.sh ++sv-48030-exec-plus-bug.sh \ ++sv-48180-refuse-noop.sh + + EXTRA_DIST = $(EXTRA_DIST_EXP) $(EXTRA_DIST_XO) $(EXTRA_DIST_GOLDEN) \ + $(test_shell_progs) binary_locations.sh checklists.py +diff --git a/find/testsuite/sv-48180-refuse-noop.sh b/find/testsuite/sv-48180-refuse-noop.sh +new file mode 100755 +index 0000000..974f0f0 +--- /dev/null ++++ b/find/testsuite/sv-48180-refuse-noop.sh +@@ -0,0 +1,117 @@ ++#! /bin/sh ++# Copyright (C) 2016 Free Software Foundation, Inc. ++# ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++# ++ ++# This test verifies that find refuses the internal -noop, ---noop option. ++# Between findutils-4.3.1 and 4.6, find dumped core ($? = 139). ++ ++testname="$(basename $0)" ++ ++. "${srcdir}"/binary_locations.sh ++ ++die() { ++ echo "$@" >&2 ++ exit 1 ++} ++ ++# This is used to simplify checking of the return value ++# which is useful when ensuring a command fails as desired. ++# I.e., just doing `command ... &&fail=1` will not catch ++# a segfault in command for example. With this helper you ++# instead check an explicit exit code like ++# returns_ 1 command ... || fail ++returns_ () { ++ # Disable tracing so it doesn't interfere with stderr of the wrapped command ++ { set +x; } 2>/dev/null ++ ++ local exp_exit="$1" ++ shift ++ "$@" ++ test $? -eq $exp_exit && ret_=0 || ret_=1 ++ ++ set -x ++ { return $ret_; } 2>/dev/null ++} ++ ++# Define the nicest compare available (borrowed from gnulib). ++if diff_out_=`exec 2>/dev/null; diff -u "$0" "$0" < /dev/null` \ ++ && diff -u Makefile "$0" 2>/dev/null | grep '^[+]#!' >/dev/null; then ++ # diff accepts the -u option and does not (like AIX 7 'diff') produce an ++ # extra space on column 1 of every content line. ++ if test -z "$diff_out_"; then ++ compare () { diff -u "$@"; } ++ else ++ compare () ++ { ++ if diff -u "$@" > diff.out; then ++ # No differences were found, but Solaris 'diff' produces output ++ # "No differences encountered". Hide this output. ++ rm -f diff.out ++ true ++ else ++ cat diff.out ++ rm -f diff.out ++ false ++ fi ++ } ++ fi ++elif diff_out_=`exec 2>/dev/null; diff -c "$0" "$0" < /dev/null`; then ++ if test -z "$diff_out_"; then ++ compare () { diff -c "$@"; } ++ else ++ compare () ++ { ++ if diff -c "$@" > diff.out; then ++ # No differences were found, but AIX and HP-UX 'diff' produce output ++ # "No differences encountered" or "There are no differences between the ++ # files.". Hide this output. ++ rm -f diff.out ++ true ++ else ++ cat diff.out ++ rm -f diff.out ++ false ++ fi ++ } ++ fi ++elif cmp -s /dev/null /dev/null 2>/dev/null; then ++ compare () { cmp -s "$@"; } ++else ++ compare () { cmp "$@"; } ++fi ++ ++set -x ++tmpdir="$(mktemp -d)" \ ++ && cd "$tmpdir" \ ++ || die "FAIL: failed to set up the test in ${tmpdir}" ++ ++fail=0 ++# Exercise both the previous name of the pseudo-option '-noop', ++# and the now renamed '---noop' option for both find executables. ++for exe in "${ftsfind}" "${oldfind}"; do ++ for opt in 'noop' '--noop'; do ++ out="${exe}${opt}.out" ++ err="${exe}${opt}.err" ++ returns_ 1 "$exe" "-${opt}" >"$out" 2> "$err" || fail=1 ++ compare /dev/null "$out" || fail=1 ++ grep "find: unknown predicate .-${opt}." "$err" \ ++ || { cat "$err"; fail=1; } ++ done ++done ++ ++cd .. ++rm -rf "$tmpdir" || exit 1 ++exit $fail +-- +2.5.5 + diff --git a/findutils-4.6.0-leaf-opt.patch b/findutils-4.6.0-leaf-opt.patch new file mode 100644 index 0000000..7fb3035 --- /dev/null +++ b/findutils-4.6.0-leaf-opt.patch @@ -0,0 +1,83 @@ +From 1328926a705fdb4728c1f255dd368de928736d39 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Fri, 25 Sep 2015 16:09:39 +0200 +Subject: [PATCH 1/2] fts: introduce the FTS_NOLEAF flag + +The flag is needed to implement the -noleaf option of find. +* lib/fts.c (link_count_optimize_ok): Implement the FTS_NOLEAF flag. +* lib/fts_.h (FTS_NOLEAF): New macro, shifted conflicting constants. +--- + gl/lib/fts.c | 4 ++++ + gl/lib/fts_.h | 12 +++++++++--- + 2 files changed, 13 insertions(+), 3 deletions(-) + +diff --git a/gl/lib/fts.c b/gl/lib/fts.c +index d2d404f..808466f 100644 +--- a/gl/lib/fts.c ++++ b/gl/lib/fts.c +@@ -736,6 +736,10 @@ filesystem_type (FTSENT const *p) + struct dev_type *ent; + struct statfs fs_buf; + ++ if (ISSET(FTS_NOLEAF)) ++ /* leaf optimization explicitly disabled by the FTS_NOLEAF flag */ ++ return 0; ++ + /* If we're not in CWDFD mode, don't bother with this optimization, + since the caller is not serious about performance. */ + if (!ISSET (FTS_CWDFD)) +diff --git a/gl/lib/fts_.h b/gl/lib/fts_.h +index 63d4b74..f1d519b 100644 +--- a/gl/lib/fts_.h ++++ b/gl/lib/fts_.h +@@ -155,10 +155,16 @@ typedef struct { + from input path names during fts_open initialization. */ + # define FTS_VERBATIM 0x1000 + +-# define FTS_OPTIONMASK 0x1fff /* valid user option mask */ ++ /* Disable leaf optimization (which eliminates stat() calls during traversal, ++ based on the count of nested directories stored in stat.st_nlink of each ++ directory). Note that the optimization is by default enabled only for ++ selected file systems, and only if the FTS_CWDFD flag is set. */ ++# define FTS_NOLEAF 0x2000 + +-# define FTS_NAMEONLY 0x2000 /* (private) child names only */ +-# define FTS_STOP 0x4000 /* (private) unrecoverable error */ ++# define FTS_OPTIONMASK 0x3fff /* valid user option mask */ ++ ++# define FTS_NAMEONLY 0x4000 /* (private) child names only */ ++# define FTS_STOP 0x8000 /* (private) unrecoverable error */ + int fts_options; /* fts_open options, global flags */ + + /* Map a directory's device number to a boolean. The boolean is +-- +2.5.0 + + +From c186934e6e37ddadf7511abb9b1045192757618e Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Fri, 25 Sep 2015 19:13:15 +0200 +Subject: [PATCH 2/2] ftsfind: propagate the -noleaf option to FTS + +* find/ftsfind.c (find): Propagate the -noleaf option to FTS. +--- + find/ftsfind.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/find/ftsfind.c b/find/ftsfind.c +index 5159470..e34b672 100644 +--- a/find/ftsfind.c ++++ b/find/ftsfind.c +@@ -559,6 +559,9 @@ find (char *arg) + if (options.stay_on_filesystem) + ftsoptions |= FTS_XDEV; + ++ if (options.no_leaf_check) ++ ftsoptions |= FTS_NOLEAF; ++ + p = fts_open (arglist, ftsoptions, NULL); + if (NULL == p) + { +-- +2.5.0 + diff --git a/findutils-4.6.0-man-exec.patch b/findutils-4.6.0-man-exec.patch new file mode 100644 index 0000000..6a64568 --- /dev/null +++ b/findutils-4.6.0-man-exec.patch @@ -0,0 +1,44 @@ +From a8ff1e964b2b8cd0b60362c76bd92795cee6b3c3 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Sun, 17 Apr 2016 22:36:13 +0200 +Subject: [PATCH] doc: clarify exit status handling of -exec command {} + + +* find/find.1 (-exec): Explain how exit status is propagated if the +-exec command {} + syntax is used. +(-execdir): Likewise. + +Reported at https://bugzilla.redhat.com/1325049 + +Upstream-commit: ae424b959c5e9bd23f9f686cb34653bc4cd1270e +Signed-off-by: Kamil Dudka +--- + find/find.1 | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/find/find.1 b/find/find.1 +index a36a0bc..c4aaf17 100644 +--- a/find/find.1 ++++ b/find/find.1 +@@ -1069,6 +1069,9 @@ command line is built in much the same way that + .B xargs + builds its command lines. Only one instance of `{}' is allowed within + the command. The command is executed in the starting directory. If ++any invocation returns a non-zero value as exit status, then ++.B find ++returns a non-zero exit status. If + .B find + encounters an error, this can sometimes cause an + immediate exit, so some pending commands may not be run +@@ -1104,6 +1107,9 @@ appropriately-named file in a directory in which you will run + The same applies to having entries in + .B $PATH + which are empty or which are not absolute directory names. If ++any invocation returns a non-zero value as exit status, then ++.B find ++returns a non-zero exit status. If + .B find + encounters an error, this can sometimes cause an + immediate exit, so some pending commands may not be run +-- +2.5.5 + diff --git a/findutils-4.6.0-mbrtowc-tests.patch b/findutils-4.6.0-mbrtowc-tests.patch new file mode 100644 index 0000000..a140654 --- /dev/null +++ b/findutils-4.6.0-mbrtowc-tests.patch @@ -0,0 +1,35 @@ +From 06a46ba755195810f2aeda01b12d1ccfe7c2dcfd Mon Sep 17 00:00:00 2001 +From: Daiki Ueno +Date: Mon, 28 Dec 2015 06:27:42 +0900 +Subject: [PATCH] maint: fix operator precedence in mbrtowc test + +This is a fix for test breakage introduced by commit 45228d96; the +equality expression must be parenthesized when negated with '!', +otherwise we always get: + + test-mbrtowc.c:49: assertion 'ret == (size_t)(-2)' failed + +* m4/mbrtowc.m4 (gl_MBRTOWC_EMPTY_INPUT): Negate the entire expression. + +Upstream-commit: 1f63650823cebf52044df840c81062ccb52163a2 +Signed-off-by: Kamil Dudka +--- + gl/m4/mbrtowc.m4 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/gl/m4/mbrtowc.m4 b/gl/m4/mbrtowc.m4 +index deb9f06..be2e9d6 100644 +--- a/gl/m4/mbrtowc.m4 ++++ b/gl/m4/mbrtowc.m4 +@@ -569,7 +569,7 @@ changequote([,])dnl + int + main (void) + { +- return ! mbrtowc (&wc, "", 0, &mbs) == (size_t) -2; ++ return mbrtowc (&wc, "", 0, &mbs) != (size_t) -2; + }]])], + [gl_cv_func_mbrtowc_empty_input=yes], + [gl_cv_func_mbrtowc_empty_input=no], +-- +2.5.0 + diff --git a/findutils-4.6.0-test-lock.patch b/findutils-4.6.0-test-lock.patch new file mode 100644 index 0000000..780987e --- /dev/null +++ b/findutils-4.6.0-test-lock.patch @@ -0,0 +1,29 @@ +From 129f23ce758620fade812baab811379ce8454048 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Fri, 27 Jan 2017 11:44:41 +0100 +Subject: [PATCH] test-lock: disable the rwlock test + +It hangs indefinitely if the system rwlock implementation does not +prevent writer starvation (and glibc does not implement it). + +Bug: http://www.mail-archive.com/bug-gnulib@gnu.org/msg33017.html +--- + tests/test-lock.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/test-lock.c b/tests/test-lock.c +index a992f64..fd9c014 100644 +--- a/tests/test-lock.c ++++ b/tests/test-lock.c +@@ -42,7 +42,7 @@ + Uncomment some of these, to verify that all tests crash if no locking + is enabled. */ + #define DO_TEST_LOCK 1 +-#define DO_TEST_RWLOCK 1 ++#define DO_TEST_RWLOCK 0 + #define DO_TEST_RECURSIVE_LOCK 1 + #define DO_TEST_ONCE 1 + +-- +2.7.4 + diff --git a/findutils-4.6.0.tar.gz b/findutils-4.6.0.tar.gz new file mode 100644 index 0000000..5d4e185 Binary files /dev/null and b/findutils-4.6.0.tar.gz differ diff --git a/findutils.spec b/findutils.spec new file mode 100644 index 0000000..34a4b8a --- /dev/null +++ b/findutils.spec @@ -0,0 +1,152 @@ +Name: findutils +Epoch: 2 +Version: 4.6.0 +Release: 3 +Summary: The GNU Find Utilities +License: GPLv3+ +URL: http://www.gnu.org/software/findutils/ +Source0: https://ftp.gnu.org/pub/gnu/findutils/%{name}-%{version}.tar.gz + +# prevent mbrtowc tests from failing (#1294016) +Patch0: findutils-4.6.0-mbrtowc-tests.patch + +# do not build locate +Patch1: findutils-4.5.15-no-locate.patch + +# fix build failure with glibc-2.28 +# https://lists.gnu.org/r/bug-gnulib/2018-03/msg00000.html +Patch2: findutils-4.6.0-gnulib-fflush.patch + +# add a new option -xautofs to find to not descend into directories on autofs +# file systems +Patch3: findutils-4.4.2-xautofs.patch + +# eliminate compile-time warnings +Patch4: findutils-4.5.13-warnings.patch + +# clarify exit status handling of -exec cmd {} + in find(1) man page (#1325049) +Patch5: findutils-4.6.0-man-exec.patch + +# make sure that find -exec + passes all arguments (upstream bug #48030) +Patch6: findutils-4.6.0-exec-args.patch + +# fix build failure with glibc-2.25+ +Patch7: findutils-4.6.0-gnulib-makedev.patch + +# avoid SIGSEGV in case the internal -noop option is used (#1346471) +Patch9: findutils-4.6.0-internal-noop.patch + +# test-lock: disable the rwlock test +Patch10: findutils-4.6.0-test-lock.patch + +# import gnulib's FTS module from upstream commit 281b825e (#1544429) +Patch11: findutils-4.6.0-fts-update.patch + +# implement the -noleaf option of find (#1252549) +Patch12: findutils-4.6.0-leaf-opt.patch + +#upstream patches +Patch6000: Remove-the-enable-id-cache-configure-option.patch +Patch6001: find-Fix-a-number-of-compiler-warnings-mostly-const-.patch +Patch6002: lib-Update-the-width-of-the-st_nlink-field-and-fix-s.patch +Patch6003: regexprops-Fix-compiler-warnings-and-update-copyrigh.patch +Patch6004: Fix-bug-48314-find-fix-type-option-regression-on-som.patch +Patch6005: maint-remove-ChangeLog-2013-from-distribution-tarbal.patch +Patch6006: find-handle-more-readdir-3-errors.patch +Patch6007: find-fix-memory-leak-in-mount-list-handling.patch +Patch6008: find-fix-printf-h-for-arguments-with-one-or-more-tra.patch +Patch6009: xargs-add-o-open-tty-option.patch +Patch6010: find-avoid-strftime-s-non-portable-F-specifier.patch +Patch6011: find-avoid-usage-in-more-error-cases.patch +Patch6012: find-give-helpful-hint-for-unquoted-patterns-errors.patch +Patch6013: find-avoid-buffer-overflow-with-printf-T.patch +Patch6014: regexprops-fix-dangling-reference-to-the-ed-regular-.patch +Patch6015: find-make-delete-honour-the-ignore_readdir_race-opti.patch +Patch6016: Shorten-output-of-qmark_chars-after-replacing-a-mult.patch +Patch6017: find-process-unreadable-directories-with-depth.patch +Patch6018: ftsfind.c-avoid-buffer-overflow-in-D-code.patch +Patch6019: find-fix-printf-Y-output-to-N-for-broken-links.patch +Patch6020: print.c-move-else-into-ifdef-S_ISLNK.patch +Patch6021: find-printf-Y-handle-ENOTDIR-also-as-broken-symlink.patch +Patch6022: find-improve-warning-diagnostic-for-the-name-iname-w.patch +Patch6023: find-make-pred_empty-safer-and-avoid-fd-leaks.patch + +Buildrequires: gcc autoconf + +Provides: /bin/find +Provides: bundled(gnulib) + +%description +The GNU Find Utilities are the basic directory searching utilities of +the GNU operating system. These programs are typically used in +conjunction with other programs to provide modular and powerful +directory search and file locating capabilities to other commands. + +The tools supplied with this package are: + +find - search for files in a directory hierarchy +locate - list files in databases that match a pattern +updatedb - update a file name database +xargs - build and execute command lines from standard input + +%package_help + +%prep +%autosetup -n %{name}-%{version} -p1 + +# needed because of findutils-4.5.15-no-locate.patch +autoreconf -fiv + +%build +%configure + +%make_build + +%check +make check + +%install +%make_install + +rm -f %{buildroot}%{_infodir}/dir + +%find_lang %{name} + +%pre + +%preun help +if [ $1 = 0 ]; then + if [ -f %{_infodir}/find.info.gz ]; then + /sbin/install-info --delete %{_infodir}/find.info.gz %{_infodir}/dir || : + fi +fi + +%post help +if [ -f %{_infodir}/find.info.gz ]; then + /sbin/install-info %{_infodir}/find.info.gz %{_infodir}/dir || : +fi + +%postun + +%files -f %{name}.lang +%doc AUTHORS NEWS README THANKS TODO +%license COPYING +%{_bindir}/find +%{_bindir}/xargs + +%files help +%{_mandir}/man1/find.1* +%{_mandir}/man1/xargs.1* +%{_infodir}/find.info* +%{_infodir}/find-maint.info.gz + + +%changelog +* Tue Sep 24 2019 openEuler Buildteam - 2:4.6.0-3 +- Adjust requires + +* Fri Sep 20 2019 openEuler Buildteam - 2:4.6.0-2 +- Delete redundant information + +* Thu Aug 29 2019 openEuler Buildteam - 2:4.6.0-1 +- Package init diff --git a/ftsfind.c-avoid-buffer-overflow-in-D-code.patch b/ftsfind.c-avoid-buffer-overflow-in-D-code.patch new file mode 100644 index 0000000..da95b7f --- /dev/null +++ b/ftsfind.c-avoid-buffer-overflow-in-D-code.patch @@ -0,0 +1,41 @@ +From c7344d33587bc5b781b958315c643284e2e9cf18 Mon Sep 17 00:00:00 2001 +From: Bernhard Voelker +Date: Sun, 8 Jul 2018 00:18:03 +0200 +Subject: [PATCH 178/224] ftsfind.c: avoid buffer overflow in -D code +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reported by GCC 8.1.1: + +ftsfind.c: In function ‘get_fts_info_name’: +ftsfind.c:164:23: warning: ‘%d’ directive writing between 1 and 11 bytes into a region of size 9 [-Wformat-overflow=] + sprintf (buf, "[%d]", info); + ^~ +ftsfind.c:164:7: note: ‘sprintf’ output between 4 and 14 bytes into a destination of size 10 + sprintf (buf, "[%d]", info); + ^~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* find/ftsfind.c (get_fts_info_name): Increase buffer from 10 to 14 +to be able to hold the 11-char string representation of the %d format, +the surrounding '[' and ']', plus the terminating NULL character. +--- + find/ftsfind.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/find/ftsfind.c b/find/ftsfind.c +index 607ea8d3..57804950 100644 +--- a/find/ftsfind.c ++++ b/find/ftsfind.c +@@ -143,7 +143,7 @@ static void init_mounted_dev_list (void); + static const char * + get_fts_info_name (int info) + { +- static char buf[10]; ++ static char buf[14]; + switch (info) + { + HANDLECASE(FTS_D); +-- +2.19.1 + diff --git a/lib-Update-the-width-of-the-st_nlink-field-and-fix-s.patch b/lib-Update-the-width-of-the-st_nlink-field-and-fix-s.patch new file mode 100644 index 0000000..365acbc --- /dev/null +++ b/lib-Update-the-width-of-the-st_nlink-field-and-fix-s.patch @@ -0,0 +1,89 @@ +From 7ce6b131573accf4fbc4b2c26794fb90f6b1a44e Mon Sep 17 00:00:00 2001 +From: James Youngman +Date: Sat, 2 Jan 2016 22:58:59 +0000 +Subject: [PATCH 025/224] lib: Update the width of the st_nlink field and fix + some compiler warnings. + +* lib/listfile.h (list_file): Make the relname parameter const. +* lib/listfile.c (list_file): Make the relname parameter const. +Remove the unused local variable inode_field_width. Update +nlink_width with the greatest width of the st_nlink field, and +print the field using the maximum width (as we do for other +fields). +--- + lib/listfile.c | 27 ++++++++++++++++++++++++--- + lib/listfile.h | 2 +- + 2 files changed, 25 insertions(+), 4 deletions(-) + +diff --git a/lib/listfile.c b/lib/listfile.c +index 4b7d4b22..c6c86091 100644 +--- a/lib/listfile.c ++++ b/lib/listfile.c +@@ -111,7 +111,7 @@ static bool print_num(FILE *stream, unsigned long num, int *width) + void + list_file (const char *name, + int dir_fd, +- char *relname, ++ const char *relname, + const struct stat *statp, + time_t current_time, + int output_block_size, +@@ -126,7 +126,6 @@ list_file (const char *name, + bool output_good = true; + int chars_out; + int failed_at = 000; +- int inode_field_width; + + #if HAVE_ST_DM_MODE + /* Cray DMF: look at the file's migrated, not real, status */ +@@ -179,13 +178,35 @@ list_file (const char *name, + output_good = false; + failed_at = 250; + } ++ } ++ if (output_good) ++ { + /* modebuf includes the space between the mode and the number of links, + as the POSIX "optional alternate access method flag". */ +- if (fprintf (stream, "%s%3lu ", modebuf, (unsigned long) statp->st_nlink) < 0) ++ if (fputs (modebuf, stream) < 0) ++ { ++ output_good = false; ++ failed_at = 275; ++ } ++ } ++ if (output_good) ++ { ++ /* This format used to end in a space, but the output of "ls" ++ has only one space between the link count and the owner name, ++ so we removed the trailing space. Happily this also makes it ++ easier to update nlink_width. */ ++ chars_out = fprintf (stream, "%*lu", ++ nlink_width, (unsigned long) statp->st_nlink); ++ if (chars_out < 0) + { + output_good = false; + failed_at = 300; + } ++ else ++ { ++ if (chars_out > nlink_width) ++ nlink_width = chars_out; ++ } + } + + if (output_good) +diff --git a/lib/listfile.h b/lib/listfile.h +index 9ee71a2d..2e151659 100644 +--- a/lib/listfile.h ++++ b/lib/listfile.h +@@ -19,5 +19,5 @@ + + #if !defined LISTFILE_H + # define LISTFILE_H +-void list_file (const char *name, int dir_fd, char *relname, const struct stat *statp, time_t current_time, int output_block_size, int literal_control_chars, FILE *stream); ++void list_file (const char *name, int dir_fd, const char *relname, const struct stat *statp, time_t current_time, int output_block_size, int literal_control_chars, FILE *stream); + #endif +-- +2.19.1 + diff --git a/maint-remove-ChangeLog-2013-from-distribution-tarbal.patch b/maint-remove-ChangeLog-2013-from-distribution-tarbal.patch new file mode 100644 index 0000000..5941a36 --- /dev/null +++ b/maint-remove-ChangeLog-2013-from-distribution-tarbal.patch @@ -0,0 +1,31 @@ +From f70469712165524b6ba92bf5dc60ad9be70546cb Mon Sep 17 00:00:00 2001 +From: Bernhard Voelker +Date: Tue, 1 Nov 2016 16:34:31 +0100 +Subject: [PATCH 078/224] maint: remove ChangeLog-2013 from distribution + tarball + +* Makefile.am (EXTRA_DIST): Remove ChangeLog-2013, as its content is +shipped in the generated ChangeLog file. + +Reported by Steve in +http://lists.gnu.org/archive/html/bug-findutils/2016-10/msg00000.html +--- + Makefile.am | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index 410ee3d5..c31e7f03 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -2,7 +2,7 @@ AUTOMAKE_OPTIONS=gnits + # readme-alpha + AM_CFLAGS = $(WARN_CFLAGS) + +-EXTRA_DIST = COPYING ChangeLog ChangeLog-2013 TODO config.h.in stamp-h.in \ ++EXTRA_DIST = COPYING ChangeLog TODO config.h.in stamp-h.in \ + THANKS bootstrap \ + tool-versions.txt README-hacking + DISTCLEANFILES = tool-versions.txt +-- +2.19.1 + diff --git a/print.c-move-else-into-ifdef-S_ISLNK.patch b/print.c-move-else-into-ifdef-S_ISLNK.patch new file mode 100644 index 0000000..9ecdf92 --- /dev/null +++ b/print.c-move-else-into-ifdef-S_ISLNK.patch @@ -0,0 +1,31 @@ +From 88fc3a464476721c3f3631d56d441dff7c9e2479 Mon Sep 17 00:00:00 2001 +From: Bernhard Voelker +Date: Fri, 20 Jul 2018 10:27:56 +0200 +Subject: [PATCH 183/224] print.c: move 'else' into #ifdef S_ISLNK + +* find/print.c (do_fprintf): Move the 'else' statment into the #ifdef'ed +block to avoid compilation failure on systems without S_ISLNK (although +it seems nobody tried to build on such a platform since 2005). + +Bug introduced in commit 'FINDUTILS_4_2_23-1-63-g238d9547'. +--- + find/print.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/find/print.c b/find/print.c +index 545df96a..24bd9692 100644 +--- a/find/print.c ++++ b/find/print.c +@@ -1205,8 +1205,8 @@ do_fprintf (struct format_val *dest, + checked_fprintf (dest, segment->text, + mode_to_filetype (sbuf.st_mode & S_IFMT)); + } +-#endif /* S_ISLNK */ + else ++#endif /* S_ISLNK */ + { + checked_fprintf (dest, segment->text, + mode_to_filetype (stat_buf->st_mode & S_IFMT)); +-- +2.19.1 + diff --git a/regexprops-Fix-compiler-warnings-and-update-copyrigh.patch b/regexprops-Fix-compiler-warnings-and-update-copyrigh.patch new file mode 100644 index 0000000..b0e4cf4 --- /dev/null +++ b/regexprops-Fix-compiler-warnings-and-update-copyrigh.patch @@ -0,0 +1,87 @@ +From c83e75f548369e38e8f4c369717000552a8a1cdf Mon Sep 17 00:00:00 2001 +From: James Youngman +Date: Sun, 3 Jan 2016 23:20:54 +0000 +Subject: [PATCH 030/224] regexprops: Fix compiler warnings and update + copyright years. + +* lib/regexprops.c (newpara): Function parameter list should be +declared as void in the function definition, instead of leaving it +blank (C++ style). This fixes a GCC warning controlled by +-Wstrict-prototypes. +(beginenum): Likewise. +(endenum): Likewise. +(endtable): Likewise. +(copying): Update copyright years. +* doc/regexprops.texi: Update copyright years to match the output +of regexprops.c. +--- + doc/regexprops.texi | 4 ++-- + lib/regexprops.c | 12 ++++++------ + 2 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/doc/regexprops.texi b/doc/regexprops.texi +index 537b64e0..897a492d 100644 +--- a/doc/regexprops.texi ++++ b/doc/regexprops.texi +@@ -1,5 +1,5 @@ +-@c Copyright (C) 1994, 1996, 1998, 2000, 2001, 2003, 2004, 2005, 2006, +-@c 2007, 2009, 2010, 2011 Free Software Foundation, Inc. ++@c Copyright (C) 1994, 1996, 1998, 2000-2007, 2009-2011, ++@c 2015-2016 Free Software Foundation, Inc. + @c + @c Permission is granted to copy, distribute and/or modify this document + @c under the terms of the GNU Free Documentation License, Version 1.3 or +diff --git a/lib/regexprops.c b/lib/regexprops.c +index 3409b4c4..2327a646 100644 +--- a/lib/regexprops.c ++++ b/lib/regexprops.c +@@ -127,7 +127,7 @@ begintable_markup (char const *markup) + } + + static void +-endtable () ++endtable (void) + { + newline (); + directive ("@end table"); +@@ -135,7 +135,7 @@ endtable () + } + + static void +-beginenum () ++beginenum (void) + { + newline (); + directive ("@enumerate"); +@@ -143,7 +143,7 @@ beginenum () + } + + static void +-endenum () ++endenum (void) + { + newline (); + directive ("@end enumerate"); +@@ -151,7 +151,7 @@ endenum () + } + + static void +-newpara () ++newpara (void) + { + content ("\n\n"); + } +@@ -453,8 +453,8 @@ copying (void) + { + static const char *copy_para[]= + { +- "Copyright (C) 1994, 1996, 1998, 2000, 2001, 2003, 2004, 2005, 2006," +- ,"2007, 2009, 2010, 2011 Free Software Foundation, Inc." ++ "Copyright (C) 1994, 1996, 1998, 2000-2007, 2009-2011," ++ ,"2015-2016 Free Software Foundation, Inc." + ,"" + ,"Permission is granted to copy, distribute and/or modify this document" + ,"under the terms of the GNU Free Documentation License, Version 1.3 or" +-- +2.19.1 + diff --git a/regexprops-fix-dangling-reference-to-the-ed-regular-.patch b/regexprops-fix-dangling-reference-to-the-ed-regular-.patch new file mode 100644 index 0000000..13938cf --- /dev/null +++ b/regexprops-fix-dangling-reference-to-the-ed-regular-.patch @@ -0,0 +1,970 @@ +From e2c673cbcdc325a3a2e9dd02169bb4a42c61bc48 Mon Sep 17 00:00:00 2001 +From: James Youngman +Date: Mon, 13 Nov 2017 22:37:55 +0000 +Subject: [PATCH 144/224] regexprops: fix dangling reference to the `ed' + regular expression dialect. + +* lib/regextype.c (regex_map): Permute the entries to list POSIX +dialects before other ones, so that we don't end up with a +dangling reference to `ed' regular expressions when +context=findutils. Remove trailing white space from the output. +* doc/regexprops.texi: Regenerate this file, so that we no longer +have a dangling reference to the `ed' dialect. +* doc/find.texi (Regular Expressions): Point out the difference +between Emacs regular expressions and findutils regular +expressions: in findutils "." will match newline. +* find/find.1: Likewise. +* locate/locate.1: Likewise. Also document the --regextype option. +--- + doc/find.texi | 7 +- + doc/regexprops.texi | 376 ++++++++++++++++++++++++++++---------------- + find/find.1 | 4 +- + lib/regexprops.c | 74 ++++----- + lib/regextype.c | 14 +- + locate/locate.1 | 14 +- + 6 files changed, 306 insertions(+), 183 deletions(-) + +diff --git a/doc/find.texi b/doc/find.texi +index 2731f0af..5573d29b 100644 +--- a/doc/find.texi ++++ b/doc/find.texi +@@ -3917,8 +3917,11 @@ your locale setup affects the interpretation of regular expressions. + + There are also several different types of regular expression, and + these are interpreted differently. Normally, the type of regular +-expression used by @code{find} and @code{locate} is the same as is +-used in GNU Emacs. Both programs provide an option which allows you ++expression used by @code{find} and @code{locate} is almost identical to ++that used in GNU Emacs. The single difference is that in @code{find} ++and @code{locate}, a @samp{.} will match a newline character. ++ ++Both @code{find} and @code{locate} provide an option which allows you + to select an alternative regular expression syntax; for @code{find} + this is the @samp{-regextype} option, and for @code{locate} this is + the @samp{--regextype} option. +diff --git a/doc/regexprops.texi b/doc/regexprops.texi +index 8fee88ae..0229460e 100644 +--- a/doc/regexprops.texi ++++ b/doc/regexprops.texi +@@ -11,15 +11,15 @@ + + @menu + * findutils-default regular expression syntax:: ++* posix-awk regular expression syntax:: ++* posix-basic regular expression syntax:: ++* posix-egrep regular expression syntax:: ++* posix-extended regular expression syntax:: + * awk regular expression syntax:: + * egrep regular expression syntax:: + * emacs regular expression syntax:: + * gnu-awk regular expression syntax:: + * grep regular expression syntax:: +-* posix-awk regular expression syntax:: +-* posix-basic regular expression syntax:: +-* posix-egrep regular expression syntax:: +-* posix-extended regular expression syntax:: + @end menu + + @node findutils-default regular expression syntax +@@ -44,6 +44,7 @@ matches a @samp{?}. + + Bracket expressions are used to match ranges of characters. Bracket expressions where the range is backward, for example @samp{[z-a]}, are ignored. Within square brackets, @samp{\} is taken literally. Character classes are not supported, so for example you would need to use @samp{[0-9]} instead of @samp{[[:digit:]]}. + ++ + GNU extensions are supported: + @enumerate + +@@ -73,11 +74,10 @@ The alternation operator is @samp{\|}. + The character @samp{^} only represents the beginning of a string when it appears: + @enumerate + +-@item +-At the beginning of a regular expression ++@item At the beginning of a regular expression ++ ++@item After an open-group, signified by @samp{\(} + +-@item After an open-group, signified by +-@samp{\(} + + @item After the alternation operator @samp{\|} + +@@ -89,8 +89,8 @@ The character @samp{$} only represents the end of a string when it appears: + + @item At the end of a regular expression + +-@item Before a close-group, signified by +-@samp{\)} ++@item Before a close-group, signified by @samp{\)} ++ + @item Before the alternation operator @samp{\|} + + @end enumerate +@@ -101,8 +101,8 @@ The character @samp{$} only represents the end of a string when it appears: + + @item At the beginning of a regular expression + +-@item After an open-group, signified by +-@samp{\(} ++@item After an open-group, signified by @samp{\(} ++ + @item After the alternation operator @samp{\|} + + @end enumerate +@@ -113,8 +113,8 @@ The character @samp{$} only represents the end of a string when it appears: + The longest possible match is returned; this applies to the regular expression as a whole and (subject to this constraint) to subexpressions within groups. + + +-@node awk regular expression syntax +-@subsection @samp{awk} regular expression syntax ++@node posix-awk regular expression syntax ++@subsection @samp{posix-awk} regular expression syntax + + + The character @samp{.} matches any single character except the null character. +@@ -135,53 +135,57 @@ matches a @samp{?}. + + Bracket expressions are used to match ranges of characters. Bracket expressions where the range is backward, for example @samp{[z-a]}, are invalid. Within square brackets, @samp{\} can be used to quote the following character. Character classes are supported; for example @samp{[[:digit:]]} will match a single decimal digit. + ++ + GNU extensions are not supported and so @samp{\w}, @samp{\W}, @samp{\<}, @samp{\>}, @samp{\b}, @samp{\B}, @samp{\`}, and @samp{\'} match @samp{w}, @samp{W}, @samp{<}, @samp{>}, @samp{b}, @samp{B}, @samp{`}, and @samp{'} respectively. + +-Grouping is performed with parentheses @samp{()}. An unmatched @samp{)} matches just itself. A backslash followed by a digit matches that digit. ++ ++Grouping is performed with parentheses @samp{()}. An unmatched @samp{)} matches just itself. A backslash followed by a digit acts as a back-reference and matches the same thing as the previous grouped expression indicated by that number. For example @samp{\2} matches the second group expression. The order of group expressions is determined by the position of their opening parenthesis @samp{(}. + + The alternation operator is @samp{|}. + + The characters @samp{^} and @samp{$} always represent the beginning and end of a string respectively, except within square brackets. Within brackets, @samp{^} can be used to invert the membership of the character class being specified. + +-@samp{*}, @samp{+} and @samp{?} are special at any point in a regular expression except: ++ ++@samp{*}, @samp{+} and @samp{?} are special at any point in a regular expression except the following places, where they are not allowed: + @enumerate + + @item At the beginning of a regular expression + +-@item After an open-group, signified by +-@samp{(} ++@item After an open-group, signified by @samp{(} ++ + @item After the alternation operator @samp{|} + + @end enumerate + + +- ++Intervals are specified by @samp{@{} and @samp{@}}. ++Invalid intervals are treated as literals, for example @samp{a@{1} is treated as @samp{a\@{1} + + The longest possible match is returned; this applies to the regular expression as a whole and (subject to this constraint) to subexpressions within groups. + + +-@node egrep regular expression syntax +-@subsection @samp{egrep} regular expression syntax ++@node posix-basic regular expression syntax ++@subsection @samp{posix-basic} regular expression syntax + + +-The character @samp{.} matches any single character. ++The character @samp{.} matches any single character except the null character. + + + @table @samp + +-@item + +-indicates that the regular expression should match one or more occurrences of the previous atom or regexp. +-@item ? +-indicates that the regular expression should match zero or one occurrence of the previous atom or regexp. + @item \+ +-matches a @samp{+} ++indicates that the regular expression should match one or more occurrences of the previous atom or regexp. + @item \? +-matches a @samp{?}. ++indicates that the regular expression should match zero or one occurrence of the previous atom or regexp. ++@item + and ? ++match themselves. ++ + @end table + + + Bracket expressions are used to match ranges of characters. Bracket expressions where the range is backward, for example @samp{[z-a]}, are invalid. Within square brackets, @samp{\} is taken literally. Character classes are supported; for example @samp{[[:digit:]]} will match a single decimal digit. + ++ + GNU extensions are supported: + @enumerate + +@@ -204,24 +208,59 @@ GNU extensions are supported: + @end enumerate + + +-Grouping is performed with parentheses @samp{()}. An unmatched @samp{)} matches just itself. A backslash followed by a digit acts as a back-reference and matches the same thing as the previous grouped expression indicated by that number. For example @samp{\2} matches the second group expression. The order of group expressions is determined by the position of their opening parenthesis @samp{(}. ++Grouping is performed with backslashes followed by parentheses @samp{\(}, @samp{\)}. A backslash followed by a digit acts as a back-reference and matches the same thing as the previous grouped expression indicated by that number. For example @samp{\2} matches the second group expression. The order of group expressions is determined by the position of their opening parenthesis @samp{\(}. + +-The alternation operator is @samp{|}. ++The alternation operator is @samp{\|}. + +-The characters @samp{^} and @samp{$} always represent the beginning and end of a string respectively, except within square brackets. Within brackets, @samp{^} can be used to invert the membership of the character class being specified. ++The character @samp{^} only represents the beginning of a string when it appears: ++@enumerate + +-The characters @samp{*}, @samp{+} and @samp{?} are special anywhere in a regular expression. ++@item At the beginning of a regular expression ++ ++@item After an open-group, signified by @samp{\(} ++ ++ ++@item After the alternation operator @samp{\|} ++ ++@end enumerate ++ ++ ++The character @samp{$} only represents the end of a string when it appears: ++@enumerate ++ ++@item At the end of a regular expression ++ ++@item Before a close-group, signified by @samp{\)} ++ ++@item Before the alternation operator @samp{\|} ++ ++@end enumerate ++ ++ ++@samp{\*}, @samp{\+} and @samp{\?} are special at any point in a regular expression except: ++@enumerate ++ ++@item At the beginning of a regular expression ++ ++@item After an open-group, signified by @samp{\(} ++ ++@item After the alternation operator @samp{\|} ++ ++@end enumerate ++ ++ ++Intervals are specified by @samp{\@{} and @samp{\@}}. ++Invalid intervals such as @samp{a\@{1z} are not accepted. + +-Intervals are specified by @samp{@{} and @samp{@}}. Invalid intervals are treated as literals, for example @samp{a@{1} is treated as @samp{a\@{1} + + The longest possible match is returned; this applies to the regular expression as a whole and (subject to this constraint) to subexpressions within groups. + + +-@node emacs regular expression syntax +-@subsection @samp{emacs} regular expression syntax ++@node posix-egrep regular expression syntax ++@subsection @samp{posix-egrep} regular expression syntax + + +-The character @samp{.} matches any single character except newline. ++The character @samp{.} matches any single character. + + + @table @samp +@@ -237,7 +276,8 @@ matches a @samp{?}. + @end table + + +-Bracket expressions are used to match ranges of characters. Bracket expressions where the range is backward, for example @samp{[z-a]}, are ignored. Within square brackets, @samp{\} is taken literally. Character classes are not supported, so for example you would need to use @samp{[0-9]} instead of @samp{[[:digit:]]}. ++Bracket expressions are used to match ranges of characters. Bracket expressions where the range is backward, for example @samp{[z-a]}, are invalid. Within square brackets, @samp{\} is taken literally. Character classes are supported; for example @samp{[[:digit:]]} will match a single decimal digit. ++ + + GNU extensions are supported: + @enumerate +@@ -261,58 +301,27 @@ GNU extensions are supported: + @end enumerate + + +-Grouping is performed with backslashes followed by parentheses @samp{\(}, @samp{\)}. A backslash followed by a digit acts as a back-reference and matches the same thing as the previous grouped expression indicated by that number. For example @samp{\2} matches the second group expression. The order of group expressions is determined by the position of their opening parenthesis @samp{\(}. +- +-The alternation operator is @samp{\|}. +- +-The character @samp{^} only represents the beginning of a string when it appears: +-@enumerate +- +-@item +-At the beginning of a regular expression +- +-@item After an open-group, signified by +-@samp{\(} +- +-@item After the alternation operator @samp{\|} +- +-@end enumerate +- +- +-The character @samp{$} only represents the end of a string when it appears: +-@enumerate +- +-@item At the end of a regular expression +- +-@item Before a close-group, signified by +-@samp{\)} +-@item Before the alternation operator @samp{\|} +- +-@end enumerate +- +- +-@samp{*}, @samp{+} and @samp{?} are special at any point in a regular expression except: +-@enumerate ++Grouping is performed with parentheses @samp{()}. An unmatched @samp{)} matches just itself. A backslash followed by a digit acts as a back-reference and matches the same thing as the previous grouped expression indicated by that number. For example @samp{\2} matches the second group expression. The order of group expressions is determined by the position of their opening parenthesis @samp{(}. + +-@item At the beginning of a regular expression ++The alternation operator is @samp{|}. + +-@item After an open-group, signified by +-@samp{\(} +-@item After the alternation operator @samp{\|} ++The characters @samp{^} and @samp{$} always represent the beginning and end of a string respectively, except within square brackets. Within brackets, @samp{^} can be used to invert the membership of the character class being specified. + +-@end enumerate + ++The characters @samp{*}, @samp{+} and @samp{?} are special anywhere in a regular expression. + + ++Intervals are specified by @samp{@{} and @samp{@}}. ++Invalid intervals are treated as literals, for example @samp{a@{1} is treated as @samp{a\@{1} + + The longest possible match is returned; this applies to the regular expression as a whole and (subject to this constraint) to subexpressions within groups. + + +-@node gnu-awk regular expression syntax +-@subsection @samp{gnu-awk} regular expression syntax ++@node posix-extended regular expression syntax ++@subsection @samp{posix-extended} regular expression syntax + + +-The character @samp{.} matches any single character. ++The character @samp{.} matches any single character except the null character. + + + @table @samp +@@ -328,7 +337,8 @@ matches a @samp{?}. + @end table + + +-Bracket expressions are used to match ranges of characters. Bracket expressions where the range is backward, for example @samp{[z-a]}, are invalid. Within square brackets, @samp{\} can be used to quote the following character. Character classes are supported; for example @samp{[[:digit:]]} will match a single decimal digit. ++Bracket expressions are used to match ranges of characters. Bracket expressions where the range is backward, for example @samp{[z-a]}, are invalid. Within square brackets, @samp{\} is taken literally. Character classes are supported; for example @samp{[[:digit:]]} will match a single decimal digit. ++ + + GNU extensions are supported: + @enumerate +@@ -358,42 +368,101 @@ The alternation operator is @samp{|}. + + The characters @samp{^} and @samp{$} always represent the beginning and end of a string respectively, except within square brackets. Within brackets, @samp{^} can be used to invert the membership of the character class being specified. + +-@samp{*}, @samp{+} and @samp{?} are special at any point in a regular expression except: ++ ++@samp{*}, @samp{+} and @samp{?} are special at any point in a regular expression except the following places, where they are not allowed: + @enumerate + + @item At the beginning of a regular expression + +-@item After an open-group, signified by +-@samp{(} ++@item After an open-group, signified by @samp{(} ++ + @item After the alternation operator @samp{|} + + @end enumerate + + +-Intervals are specified by @samp{@{} and @samp{@}}. Invalid intervals are treated as literals, for example @samp{a@{1} is treated as @samp{a\@{1} ++Intervals are specified by @samp{@{} and @samp{@}}. ++Invalid intervals such as @samp{a@{1z} are not accepted. ++ + + The longest possible match is returned; this applies to the regular expression as a whole and (subject to this constraint) to subexpressions within groups. + + +-@node grep regular expression syntax +-@subsection @samp{grep} regular expression syntax ++@node awk regular expression syntax ++@subsection @samp{awk} regular expression syntax + + +-The character @samp{.} matches any single character. ++The character @samp{.} matches any single character except the null character. + + + @table @samp + +-@item \+ ++@item + + indicates that the regular expression should match one or more occurrences of the previous atom or regexp. ++@item ? ++indicates that the regular expression should match zero or one occurrence of the previous atom or regexp. ++@item \+ ++matches a @samp{+} + @item \? ++matches a @samp{?}. ++@end table ++ ++ ++Bracket expressions are used to match ranges of characters. Bracket expressions where the range is backward, for example @samp{[z-a]}, are invalid. Within square brackets, @samp{\} can be used to quote the following character. Character classes are supported; for example @samp{[[:digit:]]} will match a single decimal digit. ++ ++ ++GNU extensions are not supported and so @samp{\w}, @samp{\W}, @samp{\<}, @samp{\>}, @samp{\b}, @samp{\B}, @samp{\`}, and @samp{\'} match @samp{w}, @samp{W}, @samp{<}, @samp{>}, @samp{b}, @samp{B}, @samp{`}, and @samp{'} respectively. ++ ++ ++Grouping is performed with parentheses @samp{()}. An unmatched @samp{)} matches just itself. A backslash followed by a digit matches that digit. ++ ++The alternation operator is @samp{|}. ++ ++The characters @samp{^} and @samp{$} always represent the beginning and end of a string respectively, except within square brackets. Within brackets, @samp{^} can be used to invert the membership of the character class being specified. ++ ++ ++@samp{*}, @samp{+} and @samp{?} are special at any point in a regular expression except: ++@enumerate ++ ++@item At the beginning of a regular expression ++ ++@item After an open-group, signified by @samp{(} ++ ++@item After the alternation operator @samp{|} ++ ++@end enumerate ++ ++ ++ ++ ++The longest possible match is returned; this applies to the regular expression as a whole and (subject to this constraint) to subexpressions within groups. ++ ++ ++@node egrep regular expression syntax ++@subsection @samp{egrep} regular expression syntax ++This is a synonym for posix-egrep. ++@node emacs regular expression syntax ++@subsection @samp{emacs} regular expression syntax ++ ++ ++The character @samp{.} matches any single character except newline. ++ ++ ++@table @samp ++ ++@item + ++indicates that the regular expression should match one or more occurrences of the previous atom or regexp. ++@item ? + indicates that the regular expression should match zero or one occurrence of the previous atom or regexp. +-@item + and ? +-match themselves. ++@item \+ ++matches a @samp{+} ++@item \? ++matches a @samp{?}. + @end table + + +-Bracket expressions are used to match ranges of characters. Bracket expressions where the range is backward, for example @samp{[z-a]}, are invalid. Within square brackets, @samp{\} is taken literally. Character classes are supported; for example @samp{[[:digit:]]} will match a single decimal digit. ++Bracket expressions are used to match ranges of characters. Bracket expressions where the range is backward, for example @samp{[z-a]}, are ignored. Within square brackets, @samp{\} is taken literally. Character classes are not supported, so for example you would need to use @samp{[0-9]} instead of @samp{[[:digit:]]}. ++ + + GNU extensions are supported: + @enumerate +@@ -424,13 +493,10 @@ The alternation operator is @samp{\|}. + The character @samp{^} only represents the beginning of a string when it appears: + @enumerate + +-@item +-At the beginning of a regular expression ++@item At the beginning of a regular expression + +-@item After an open-group, signified by +-@samp{\(} ++@item After an open-group, signified by @samp{\(} + +-@item After a newline + + @item After the alternation operator @samp{\|} + +@@ -442,39 +508,35 @@ The character @samp{$} only represents the end of a string when it appears: + + @item At the end of a regular expression + +-@item Before a close-group, signified by +-@samp{\)} +-@item Before a newline ++@item Before a close-group, signified by @samp{\)} + + @item Before the alternation operator @samp{\|} + + @end enumerate + + +-@samp{\*}, @samp{\+} and @samp{\?} are special at any point in a regular expression except: ++@samp{*}, @samp{+} and @samp{?} are special at any point in a regular expression except: + @enumerate + + @item At the beginning of a regular expression + +-@item After an open-group, signified by +-@samp{\(} +-@item After a newline ++@item After an open-group, signified by @samp{\(} + + @item After the alternation operator @samp{\|} + + @end enumerate + + +-Intervals are specified by @samp{\@{} and @samp{\@}}. Invalid intervals such as @samp{a\@{1z} are not accepted. ++ + + The longest possible match is returned; this applies to the regular expression as a whole and (subject to this constraint) to subexpressions within groups. + + +-@node posix-awk regular expression syntax +-@subsection @samp{posix-awk} regular expression syntax ++@node gnu-awk regular expression syntax ++@subsection @samp{gnu-awk} regular expression syntax + + +-The character @samp{.} matches any single character except the null character. ++The character @samp{.} matches any single character. + + + @table @samp +@@ -492,7 +554,28 @@ matches a @samp{?}. + + Bracket expressions are used to match ranges of characters. Bracket expressions where the range is backward, for example @samp{[z-a]}, are invalid. Within square brackets, @samp{\} can be used to quote the following character. Character classes are supported; for example @samp{[[:digit:]]} will match a single decimal digit. + +-GNU extensions are not supported and so @samp{\w}, @samp{\W}, @samp{\<}, @samp{\>}, @samp{\b}, @samp{\B}, @samp{\`}, and @samp{\'} match @samp{w}, @samp{W}, @samp{<}, @samp{>}, @samp{b}, @samp{B}, @samp{`}, and @samp{'} respectively. ++ ++GNU extensions are supported: ++@enumerate ++ ++@item @samp{\w} matches a character within a word ++ ++@item @samp{\W} matches a character which is not within a word ++ ++@item @samp{\<} matches the beginning of a word ++ ++@item @samp{\>} matches the end of a word ++ ++@item @samp{\b} matches a word boundary ++ ++@item @samp{\B} matches characters which are not a word boundary ++ ++@item @samp{\`} matches the beginning of the whole input ++ ++@item @samp{\'} matches the end of the whole input ++ ++@end enumerate ++ + + Grouping is performed with parentheses @samp{()}. An unmatched @samp{)} matches just itself. A backslash followed by a digit acts as a back-reference and matches the same thing as the previous grouped expression indicated by that number. For example @samp{\2} matches the second group expression. The order of group expressions is determined by the position of their opening parenthesis @samp{(}. + +@@ -500,51 +583,47 @@ The alternation operator is @samp{|}. + + The characters @samp{^} and @samp{$} always represent the beginning and end of a string respectively, except within square brackets. Within brackets, @samp{^} can be used to invert the membership of the character class being specified. + +-@samp{*}, @samp{+} and @samp{?} are special at any point in a regular expression except the following places, where they are not allowed: ++ ++@samp{*}, @samp{+} and @samp{?} are special at any point in a regular expression except: + @enumerate + + @item At the beginning of a regular expression + +-@item After an open-group, signified by +-@samp{(} ++@item After an open-group, signified by @samp{(} ++ + @item After the alternation operator @samp{|} + + @end enumerate + + +-Intervals are specified by @samp{@{} and @samp{@}}. Invalid intervals are treated as literals, for example @samp{a@{1} is treated as @samp{a\@{1} ++Intervals are specified by @samp{@{} and @samp{@}}. ++Invalid intervals are treated as literals, for example @samp{a@{1} is treated as @samp{a\@{1} + + The longest possible match is returned; this applies to the regular expression as a whole and (subject to this constraint) to subexpressions within groups. + + +-@node posix-basic regular expression syntax +-@subsection @samp{posix-basic} regular expression syntax +-This is a synonym for ed. +-@node posix-egrep regular expression syntax +-@subsection @samp{posix-egrep} regular expression syntax +-This is a synonym for egrep. +-@node posix-extended regular expression syntax +-@subsection @samp{posix-extended} regular expression syntax ++@node grep regular expression syntax ++@subsection @samp{grep} regular expression syntax + + +-The character @samp{.} matches any single character except the null character. ++The character @samp{.} matches any single character. + + + @table @samp + +-@item + +-indicates that the regular expression should match one or more occurrences of the previous atom or regexp. +-@item ? +-indicates that the regular expression should match zero or one occurrence of the previous atom or regexp. + @item \+ +-matches a @samp{+} ++indicates that the regular expression should match one or more occurrences of the previous atom or regexp. + @item \? +-matches a @samp{?}. ++indicates that the regular expression should match zero or one occurrence of the previous atom or regexp. ++@item + and ? ++match themselves. ++ + @end table + + + Bracket expressions are used to match ranges of characters. Bracket expressions where the range is backward, for example @samp{[z-a]}, are invalid. Within square brackets, @samp{\} is taken literally. Character classes are supported; for example @samp{[[:digit:]]} will match a single decimal digit. + ++ + GNU extensions are supported: + @enumerate + +@@ -567,25 +646,56 @@ GNU extensions are supported: + @end enumerate + + +-Grouping is performed with parentheses @samp{()}. An unmatched @samp{)} matches just itself. A backslash followed by a digit acts as a back-reference and matches the same thing as the previous grouped expression indicated by that number. For example @samp{\2} matches the second group expression. The order of group expressions is determined by the position of their opening parenthesis @samp{(}. ++Grouping is performed with backslashes followed by parentheses @samp{\(}, @samp{\)}. A backslash followed by a digit acts as a back-reference and matches the same thing as the previous grouped expression indicated by that number. For example @samp{\2} matches the second group expression. The order of group expressions is determined by the position of their opening parenthesis @samp{\(}. + +-The alternation operator is @samp{|}. ++The alternation operator is @samp{\|}. + +-The characters @samp{^} and @samp{$} always represent the beginning and end of a string respectively, except within square brackets. Within brackets, @samp{^} can be used to invert the membership of the character class being specified. ++The character @samp{^} only represents the beginning of a string when it appears: ++@enumerate + +-@samp{*}, @samp{+} and @samp{?} are special at any point in a regular expression except the following places, where they are not allowed: ++@item At the beginning of a regular expression ++ ++@item After an open-group, signified by @samp{\(} ++ ++ ++@item After a newline ++ ++@item After the alternation operator @samp{\|} ++ ++@end enumerate ++ ++ ++The character @samp{$} only represents the end of a string when it appears: ++@enumerate ++ ++@item At the end of a regular expression ++ ++@item Before a close-group, signified by @samp{\)} ++ ++@item Before a newline ++ ++@item Before the alternation operator @samp{\|} ++ ++@end enumerate ++ ++ ++@samp{\*}, @samp{\+} and @samp{\?} are special at any point in a regular expression except: + @enumerate + + @item At the beginning of a regular expression + +-@item After an open-group, signified by +-@samp{(} +-@item After the alternation operator @samp{|} ++@item After an open-group, signified by @samp{\(} ++ ++@item After a newline ++ ++@item After the alternation operator @samp{\|} + + @end enumerate + + +-Intervals are specified by @samp{@{} and @samp{@}}. Invalid intervals such as @samp{a@{1z} are not accepted. ++Intervals are specified by @samp{\@{} and @samp{\@}}. ++Invalid intervals such as @samp{a\@{1z} are not accepted. ++ + + The longest possible match is returned; this applies to the regular expression as a whole and (subject to this constraint) to subexpressions within groups. + +diff --git a/find/find.1 b/find/find.1 +index 06ddfa5b..8b1320c1 100644 +--- a/find/find.1 ++++ b/find/find.1 +@@ -879,8 +879,8 @@ on the whole path, not a search. For example, to match a file named + `./fubar3', you can use the regular expression `.*bar.' or `.*b.*3', + but not `f.*r3'. The regular expressions understood by + .B find +-are by default Emacs Regular Expressions, but this can be +-changed with the ++are by default Emacs Regular Expressions (except that `.' matches ++newline), but this can be changed with the + .B \-regextype + option. + +diff --git a/lib/regexprops.c b/lib/regexprops.c +index fcbdd5db..b20b4a38 100644 +--- a/lib/regexprops.c ++++ b/lib/regexprops.c +@@ -78,8 +78,12 @@ directive (const char *s) + static void + comment (const char *s) + { +- directive ("@c "); +- literal (s); ++ directive ("@c"); ++ if (s[0]) ++ { ++ literal (" "); ++ literal (s); ++ } + newline (); + } + +@@ -175,7 +179,7 @@ describe_regex_syntax (int options) + + content (" the null character"); + } +- content (". "); ++ content ("."); + newpara (); + + if (!(options & RE_LIMITED_OPS)) +@@ -185,25 +189,25 @@ describe_regex_syntax (int options) + { + enum_item ("\\+"); + content ("indicates that the regular expression should match one" +- " or more occurrences of the previous atom or regexp. "); ++ " or more occurrences of the previous atom or regexp."); + enum_item ("\\?"); + content ("indicates that the regular expression should match zero" +- " or one occurrence of the previous atom or regexp. "); +- enum_item ("+ and ? "); +- content ("match themselves. "); ++ " or one occurrence of the previous atom or regexp."); ++ enum_item ("+ and ?"); ++ content ("match themselves.\n"); + } + else + { + enum_item ("+"); + content ("indicates that the regular expression should match one" +- " or more occurrences of the previous atom or regexp. "); ++ " or more occurrences of the previous atom or regexp."); + enum_item ("?"); + content ("indicates that the regular expression should match zero" +- " or one occurrence of the previous atom or regexp. "); ++ " or one occurrence of the previous atom or regexp."); + enum_item ("\\+"); + literal ("matches a @samp{+}"); + enum_item ("\\?"); +- literal ("matches a @samp{?}. "); ++ literal ("matches a @samp{?}."); + } + endtable (); + } +@@ -226,15 +230,15 @@ describe_regex_syntax (int options) + + if (options & RE_CHAR_CLASSES) + content ("Character classes are supported; for example " +- "@samp{[[:digit:]]} will match a single decimal digit. "); ++ "@samp{[[:digit:]]} will match a single decimal digit.\n"); + else + literal ("Character classes are not supported, so for example " + "you would need to use @samp{[0-9]} " +- "instead of @samp{[[:digit:]]}. "); ++ "instead of @samp{[[:digit:]]}.\n"); + + if (options & RE_HAT_LISTS_NOT_NEWLINE) + { +- literal ("Non-matching lists @samp{[^@dots{}]} do not ever match newline. "); ++ literal ("Non-matching lists @samp{[^@dots{}]} do not ever match newline.\n"); + } + newpara (); + if (options & RE_NO_GNU_OPS) +@@ -242,7 +246,7 @@ describe_regex_syntax (int options) + content ("GNU extensions are not supported and so " + "@samp{\\w}, @samp{\\W}, @samp{\\<}, @samp{\\>}, @samp{\\b}, @samp{\\B}, @samp{\\`}, and @samp{\\'} " + "match " +- "@samp{w}, @samp{W}, @samp{<}, @samp{>}, @samp{b}, @samp{B}, @samp{`}, and @samp{'} respectively. "); ++ "@samp{w}, @samp{W}, @samp{<}, @samp{>}, @samp{b}, @samp{B}, @samp{`}, and @samp{'} respectively.\n"); + } + else + { +@@ -276,7 +280,7 @@ describe_regex_syntax (int options) + + if (options & RE_NO_BK_REFS) + { +- content ("A backslash followed by a digit matches that digit. "); ++ content ("A backslash followed by a digit matches that digit."); + } + else + { +@@ -285,7 +289,7 @@ describe_regex_syntax (int options) + literal ("@samp{(}"); + else + literal ("@samp{\\(}"); +- content (". "); ++ content ("."); + } + + +@@ -293,29 +297,28 @@ describe_regex_syntax (int options) + if (!(options & RE_LIMITED_OPS)) + { + if (options & RE_NO_BK_VBAR) +- literal ("The alternation operator is @samp{|}. "); ++ literal ("The alternation operator is @samp{|}."); + else +- literal ("The alternation operator is @samp{\\|}. "); ++ literal ("The alternation operator is @samp{\\|}."); + } + newpara (); + + if (options & RE_CONTEXT_INDEP_ANCHORS) + { +- literal ("The characters @samp{^} and @samp{$} always represent the beginning and end of a string respectively, except within square brackets. Within brackets, @samp{^} can be used to invert the membership of the character class being specified. "); ++ literal ("The characters @samp{^} and @samp{$} always represent the beginning and end of a string respectively, except within square brackets. Within brackets, @samp{^} can be used to invert the membership of the character class being specified.\n"); + } + else + { + literal ("The character @samp{^} only represents the beginning of a string when it appears:"); + beginenum (); +- enum_item ("\nAt the beginning of a regular expression"); +- enum_item ("After an open-group, signified by "); ++ enum_item ("At the beginning of a regular expression"); + if (options & RE_NO_BK_PARENS) + { +- literal ("@samp{(}"); ++ enum_item ("After an open-group, signified by @samp{(}"); + } + else + { +- literal ("@samp{\\(}"); ++ enum_item ("After an open-group, signified by @samp{\\(}"); + } + newline (); + if (!(options & RE_LIMITED_OPS)) +@@ -334,14 +337,13 @@ describe_regex_syntax (int options) + literal ("The character @samp{$} only represents the end of a string when it appears:"); + beginenum (); + enum_item ("At the end of a regular expression"); +- enum_item ("Before a close-group, signified by "); + if (options & RE_NO_BK_PARENS) + { +- literal ("@samp{)}"); ++ enum_item ("Before a close-group, signified by @samp{)}"); + } + else + { +- literal ("@samp{\\)}"); ++ enum_item ("Before a close-group, signified by @samp{\\)}"); + } + if (!(options & RE_LIMITED_OPS)) + { +@@ -361,7 +363,7 @@ describe_regex_syntax (int options) + if ((options & RE_CONTEXT_INDEP_OPS) + && !(options & RE_CONTEXT_INVALID_OPS)) + { +- literal ("The characters @samp{*}, @samp{+} and @samp{?} are special anywhere in a regular expression. "); ++ literal ("The characters @samp{*}, @samp{+} and @samp{?} are special anywhere in a regular expression.\n"); + } + else + { +@@ -381,14 +383,13 @@ describe_regex_syntax (int options) + + beginenum (); + enum_item ("At the beginning of a regular expression"); +- enum_item ("After an open-group, signified by "); + if (options & RE_NO_BK_PARENS) + { +- literal ("@samp{(}"); ++ enum_item ("After an open-group, signified by @samp{(}"); + } + else + { +- literal ("@samp{\\(}"); ++ enum_item ("After an open-group, signified by @samp{\\(}"); + } + if (!(options & RE_LIMITED_OPS)) + { +@@ -410,39 +411,38 @@ describe_regex_syntax (int options) + { + if (options & RE_NO_BK_BRACES) + { +- literal ("Intervals are specified by @samp{@{} and @samp{@}}. "); ++ literal ("Intervals are specified by @samp{@{} and @samp{@}}.\n"); + if (options & RE_INVALID_INTERVAL_ORD) + { + literal ("Invalid intervals are treated as literals, for example @samp{a@{1} is treated as @samp{a\\@{1}"); + } + else + { +- literal ("Invalid intervals such as @samp{a@{1z} are not accepted. "); ++ literal ("Invalid intervals such as @samp{a@{1z} are not accepted.\n"); + } + } + else + { +- literal ("Intervals are specified by @samp{\\@{} and @samp{\\@}}. "); ++ literal ("Intervals are specified by @samp{\\@{} and @samp{\\@}}.\n"); + if (options & RE_INVALID_INTERVAL_ORD) + { + literal ("Invalid intervals are treated as literals, for example @samp{a\\@{1} is treated as @samp{a@{1}"); + } + else + { +- literal ("Invalid intervals such as @samp{a\\@{1z} are not accepted. "); ++ literal ("Invalid intervals such as @samp{a\\@{1z} are not accepted.\n"); + } + } +- + } + + newpara (); + if (options & RE_NO_POSIX_BACKTRACKING) + { +- content ("Matching succeeds as soon as the whole pattern is matched, meaning that the result may not be the longest possible match. "); ++ content ("Matching succeeds as soon as the whole pattern is matched, meaning that the result may not be the longest possible match."); + } + else + { +- content ("The longest possible match is returned; this applies to the regular expression as a whole and (subject to this constraint) to subexpressions within groups. "); ++ content ("The longest possible match is returned; this applies to the regular expression as a whole and (subject to this constraint) to subexpressions within groups."); + } + newpara (); + } +diff --git a/lib/regextype.c b/lib/regextype.c +index 8a7347dc..89416ebd 100644 +--- a/lib/regextype.c ++++ b/lib/regextype.c +@@ -56,17 +56,19 @@ struct tagRegexTypeMap + struct tagRegexTypeMap regex_map[] = + { + { "findutils-default", CONTEXT_FINDUTILS, RE_SYNTAX_EMACS|RE_DOT_NEWLINE }, ++ ++ { "posix-awk", CONTEXT_ALL, RE_SYNTAX_POSIX_AWK }, ++ { "posix-basic", CONTEXT_ALL, RE_SYNTAX_POSIX_BASIC }, ++ { "posix-egrep", CONTEXT_ALL, RE_SYNTAX_POSIX_EGREP }, ++ { "posix-extended", CONTEXT_ALL, RE_SYNTAX_POSIX_EXTENDED }, ++ { "posix-minimal-basic", CONTEXT_GENERIC, RE_SYNTAX_POSIX_MINIMAL_BASIC }, ++ + { "awk", CONTEXT_ALL, RE_SYNTAX_AWK }, +- { "egrep", CONTEXT_ALL, RE_SYNTAX_EGREP }, + { "ed", CONTEXT_GENERIC, RE_SYNTAX_ED }, ++ { "egrep", CONTEXT_ALL, RE_SYNTAX_EGREP }, + { "emacs", CONTEXT_ALL, RE_SYNTAX_EMACS }, + { "gnu-awk", CONTEXT_ALL, RE_SYNTAX_GNU_AWK }, + { "grep", CONTEXT_ALL, RE_SYNTAX_GREP }, +- { "posix-awk", CONTEXT_ALL, RE_SYNTAX_POSIX_AWK }, +- { "posix-basic", CONTEXT_ALL, RE_SYNTAX_POSIX_BASIC }, +- { "posix-egrep", CONTEXT_ALL, RE_SYNTAX_POSIX_EGREP }, +- { "posix-extended", CONTEXT_ALL, RE_SYNTAX_POSIX_EXTENDED }, +- { "posix-minimal-basic", CONTEXT_GENERIC, RE_SYNTAX_POSIX_MINIMAL_BASIC }, + { "sed", CONTEXT_GENERIC, RE_SYNTAX_SED }, + /* ,{ "posix-common", CONTEXT_GENERIC, _RE_SYNTAX_POSIX_COMMON } */ + }; +-- +2.19.1 + diff --git a/xargs-add-o-open-tty-option.patch b/xargs-add-o-open-tty-option.patch new file mode 100644 index 0000000..032a1d0 --- /dev/null +++ b/xargs-add-o-open-tty-option.patch @@ -0,0 +1,250 @@ +From 40cd25147b4461979c0d992299f2c101f9034f7a Mon Sep 17 00:00:00 2001 +From: Bernhard Voelker +Date: Tue, 6 Jun 2017 08:19:29 +0200 +Subject: [PATCH 101/224] xargs: add -o, --open-tty option + +This option is available in the xargs implementation of FreeBSD, NetBSD, +OpenBSD and in the Apple variant. Add it for compatibility. + +* xargs/xargs.c (open_tty): Add static flag for the new option. +(longopts): Add member. +(main): Handle the 'o' case in the getopt_long() loop. +(prep_child_for_exec): Redirect stdin of the child to /dev/tty when +the -o option is given. Furthermore, move the just-opened file +descriptor to STDIN_FILENO. +(usage): Document the new option. +* bootstrap.conf (gnulib_modules): Add dup2. +* xargs/xargs.1 (SYNOPSIS): Replace the too-long list of options by +"[options]" - they are listed later anyway. +(OPTIONS): Document the new option. +(STANDARDS CONFORMANCE): Mention that the -o option is an extension. +* doc/find.texi (xargs options): Document the new option. +(Invoking the shell from xargs): Amend the explanation of the +redirection example with a note about the -o option. +(Viewing And Editing): Likewise. +(Error Messages From xargs): Add the message when dup2() fails. +(NEWS): Mention the new option. + +Fixes http://savannah.gnu.org/bugs/?51151 +--- + NEWS | 4 ++++ + bootstrap.conf | 1 + + doc/find.texi | 24 ++++++++++++++++++++++++ + xargs/xargs.1 | 41 +++++++++++++---------------------------- + xargs/xargs.c | 33 ++++++++++++++++++++++++++------- + 5 files changed, 68 insertions(+), 35 deletions(-) + +diff --git a/doc/find.texi b/doc/find.texi +index 24d8ef99..4516b64c 100644 +--- a/doc/find.texi ++++ b/doc/find.texi +@@ -3746,6 +3746,17 @@ Use at most @var{max-args} arguments per command line. Fewer than + option) is exceeded, unless the @samp{-x} option is given, in which + case @code{xargs} will exit. + ++@item --open-tty ++@itemx -o ++Reopen stdin as @file{/dev/tty} in the child process before executing ++the command, thus allowing that command to be associated to the terminal ++while @code{xargs} reads from a different stream, e.g. from a pipe. ++This is useful if you want @code{xargs} to run an interactive application. ++@example ++grep -lz PATTERN * | xargs -0o vi ++@end example ++ ++ + @item --interactive + @itemx -p + Prompt the user about whether to run each command line and read a line +@@ -3877,6 +3888,10 @@ Therefore instead of keeping a @code{sh} process around for no reason, + we just arrange for the subshell to exec Emacs, saving an extra + process creation. + ++Although GNU @code{xargs} and the implementations on some other platforms ++like BSD support the @samp{-o} option to achieve the same, the above is ++the portable way to redirect stdin to @file{/dev/tty}. ++ + Sometimes, though, it can be helpful to keep the shell process around: + + @example +@@ -4050,6 +4065,10 @@ protect the @code{$@@} against expansion by your interactive shell + nothing). The capitalised @samp{Emacs} on the command line is used as + @code{$0} by the shell that @code{xargs} launches. + ++Please note that the implementations in GNU @code{xargs} and at least BSD ++support the @samp{-o} option as extension to achieve the same, while the ++above is the portable way to redirect stdin to @file{/dev/tty}. ++ + @node Archiving + @section Archiving + +@@ -5564,6 +5583,11 @@ signals to increase or decrease the parallelism of its processing. + If you don't plan to send it those signals, this warning can be ignored + (though if you're a programmer, you may want to help us figure out + why @code{xargs} is confused by your operating system). ++ ++@item failed to redirect standard input of the child process ++@code{xargs} redirects the stdin stream of the command to be run to either ++@file{/dev/null} or to @file{/dev/tty} for the @samp{-o} option. ++See the manual of the system call @code{dup2(2)}. + @end table + + @node Error Messages From locate +diff --git a/xargs/xargs.1 b/xargs/xargs.1 +index 68377868..f66dbc05 100644 +--- a/xargs/xargs.1 ++++ b/xargs/xargs.1 +@@ -4,34 +4,7 @@ xargs \- build and execute command lines from standard input + .SH SYNOPSIS + .B xargs + .nh +-[\fB\-0prtx\fR] +-[\fB\-E \fIeof-str\fR] +-[\fB\-e\fR[\fIeof-str\fR]] +-[\fB\-\-eof\fR[=\fIeof-str\fR]] +-[\fB\-\-null\fR] +-[\fB\-d \fIdelimiter\fR] +-[\fB\-\-delimiter \fIdelimiter\fR] +-[\fB\-I \fIreplace-str\fR] +-[\fB\-i\fR[\fIreplace-str\fR]] +-[\fB\-\-replace\fR[=\fIreplace-str\fR]] +-[\fB\-l\fR[\fImax-lines\fR]] +-[\fB\-L \fImax-lines\fR] +-[\fB\-\-max\-lines\fR[=\fImax-lines\fR]] +-[\fB\-n \fImax-args\fR] +-[\fB\-\-max\-args\fR=\fImax-args\fR] +-[\fB\-s \fImax-chars\fR] +-[\fB\-\-max\-chars\fR=\fImax-chars\fR] +-[\fB\-P \fImax-procs\fR] +-[\fB\-\-max\-procs\fR=\fImax-procs\fR] +-[\fB\-\-process\-slot\-var\fR=\fIname\fR] +-[\fB\-\-interactive\fR] +-[\fB\-\-verbose\fR] +-[\fB\-\-exit\fR] +-[\fB\-\-no\-run\-if\-empty\fR] +-[\fB\-\-arg\-file\fR=\fIfile\fR] +-[\fB\-\-show\-limits\fR] +-[\fB\-\-version\fR] +-[\fB\-\-help\fR] ++[\fIoptions\fR] + [\fIcommand\fR [\fIinitial-arguments\fR]] + .hy + .SH DESCRIPTION +@@ -252,6 +225,15 @@ arrange for each process to produce a separate output file (or + otherwise use separate resources). + .TP + .PD ++.B \-o, \-\-open\-tty ++Reopen stdin as ++.I /dev/tty ++in the child process before executing the command. This is useful if ++you want ++.B xargs ++to run an interactive application. ++.TP ++.PD + .B \-p, \-\-interactive + Prompt the user about whether to run each command line and read a line + from the terminal. Only run the command line if the response starts +@@ -404,6 +386,9 @@ The \-l and \-i options appear in the 1997 version of the POSIX + standard, but do not appear in the 2004 version of the standard. + Therefore you should use \-L and \-I instead, respectively. + .P ++The \-o option is an extension to the POSIX standard for better ++compatibility with BSD. ++.P + The POSIX standard allows implementations to have a limit on the size + of arguments to the + .B exec +diff --git a/xargs/xargs.c b/xargs/xargs.c +index 5cf8c131..a2917e48 100644 +--- a/xargs/xargs.c ++++ b/xargs/xargs.c +@@ -151,6 +151,9 @@ static volatile int child_error = EXIT_SUCCESS; + + static volatile int original_exit_value; + ++/* If true, open /dev/tty in the child process before executing the command. */ ++static bool open_tty = false; /* option -o */ ++ + /* If true, print each command on stderr before executing it. */ + static bool print_command = false; /* Option -t */ + +@@ -185,6 +188,7 @@ static struct option const longopts[] = + {"replace", optional_argument, NULL, 'I'}, + {"max-lines", optional_argument, NULL, 'l'}, + {"max-args", required_argument, NULL, 'n'}, ++ {"open-tty", no_argument, NULL, 'o'}, + {"interactive", no_argument, NULL, 'p'}, + {"no-run-if-empty", no_argument, NULL, 'r'}, + {"max-chars", required_argument, NULL, 's'}, +@@ -509,7 +513,7 @@ main (int argc, char **argv) + bc_use_sensible_arg_max (&bc_ctl); + } + +- while ((optc = getopt_long (argc, argv, "+0a:E:e::i::I:l::L:n:prs:txP:d:", ++ while ((optc = getopt_long (argc, argv, "+0a:E:e::i::I:l::L:n:oprs:txP:d:", + longopts, &option_index)) != -1) + { + switch (optc) +@@ -608,6 +612,10 @@ main (int argc, char **argv) + bc_ctl.exit_if_size_exceeded = true; + break; + ++ case 'o': ++ open_tty = true; ++ break; ++ + case 'p': + query_before_executing = true; + print_command = true; +@@ -1185,22 +1193,30 @@ prep_child_for_exec (void) + unsigned int slot = add_proc (0); + set_slot_var (slot); + +- if (!keep_stdin) ++ if (!keep_stdin || open_tty) + { +- const char inputfile[] = "/dev/null"; +- /* fprintf (stderr, "attaching stdin to /dev/null\n"); */ ++ int fd; ++ const char *inputfile = open_tty ? "/dev/tty" : "/dev/null"; + + close (0); +- if (open (inputfile, O_RDONLY) < 0) ++ if ((fd = open (inputfile, O_RDONLY)) < 0) + { +- /* This is not entirely fatal, since ++ /* Treat a failure to open /dev/tty as fatal. ++ * The other case is not entirely fatal, since + * executing the child with a closed + * stdin is almost as good as executing it + * with its stdin attached to /dev/null. + */ +- error (0, errno, "%s", ++ error (open_tty ? EXIT_FAILURE : 0, errno, "%s", + quotearg_n_style (0, locale_quoting_style, inputfile)); + } ++ if (STDIN_FILENO < fd) ++ { ++ if (dup2(fd, STDIN_FILENO) != 0) ++ error (EXIT_FAILURE, errno, ++ _("failed to redirect standard input of the child process")); ++ close(fd); ++ } + } + } + +@@ -1676,6 +1692,9 @@ usage (int status) + HTL (_(" -l[MAX-LINES] similar to -L but defaults to at most one non-\n" + " blank input line if MAX-LINES is not specified\n")); + HTL (_(" -n, --max-args=MAX-ARGS use at most MAX-ARGS arguments per command line\n")); ++ HTL (_(" -o, --open-tty Reopen stdin as /dev/tty in the child process\n" ++ " before executing the command; useful to run an\n" ++ " interactive application.\n")); + HTL (_(" -P, --max-procs=MAX-PROCS run at most MAX-PROCS processes at a time\n")); + HTL (_(" -p, --interactive prompt before running commands\n")); + HTL (_(" --process-slot-var=VAR set environment variable VAR in child processes\n")); +-- +2.19.1 +