Compare commits

...

11 Commits
rawhide ... f12

Author SHA1 Message Date
Fedora Release Engineering 7193b676ef dist-git conversion 2010-07-28 14:26:31 +00:00
Kamil Dudka 89e5e78ea6 - fix Savannah bug #29949 2010-06-01 10:46:25 +00:00
Kamil Dudka dc337378c1 - mention -xautofs in the output of --help (#590166) 2010-05-10 15:48:44 +00:00
Kamil Dudka 6c45934950 trivial follow-up 2010-05-06 20:46:33 +00:00
Kamil Dudka 6848c7e31b - backport of patches for upstream bugs #19593 and #27563 (rhbz #493143) 2010-05-06 15:09:17 +00:00
Kamil Dudka 2b969d355f fix mistakenly stated bug ID in the ChangeLog 2010-03-30 12:09:33 +00:00
Kamil Dudka 685e8366e3 synced with devel 2009-11-26 18:20:59 +00:00
Bill Nottingham ca73160123 Fix typo that causes a failure to update the common directory. (releng
#2781)
2009-11-26 01:27:27 +00:00
Kamil Dudka 0f19737980 F-12 branch synced with devel 2009-11-18 18:43:36 +00:00
Kamil Dudka 723ddb7a97 - make it possible to recognize an autofs filesystem by find
- add a new find's option -xautofs to not descend directories on autofs
    filesystems
2009-10-20 12:51:28 +00:00
Jesse Keating 11088d0573 Initialize branch F-12 for findutils 2009-09-29 04:50:57 +00:00
16 changed files with 3595 additions and 557 deletions

View File

View File

@ -1,21 +0,0 @@
# Makefile for source rpm: findutils
# $Id: Makefile,v 1.1 2004/09/09 04:42:40 cvsdist Exp $
NAME := findutils
SPECFILE = $(firstword $(wildcard *.spec))
define find-makefile-common
for d in common ../common ../../common ; do if [ -f $$d/Makefile.common ] ; then if [ -f $$d/CVS/Root -a -w $$/Makefile.common ] ; then cd $$d ; cvs -Q update ; fi ; echo "$$d/Makefile.common" ; break ; fi ; done
endef
MAKEFILE_COMMON := $(shell $(find-makefile-common))
ifeq ($(MAKEFILE_COMMON),)
# attempt a checkout
define checkout-makefile-common
test -f CVS/Root && { cvs -Q -d $$(cat CVS/Root) checkout common && echo "common/Makefile.common" ; } || { echo "ERROR: I can't figure out how to checkout the 'common' module." ; exit -1 ; } >&2
endef
MAKEFILE_COMMON := $(shell $(checkout-makefile-common))
endif
include $(MAKEFILE_COMMON)

View File

@ -10,15 +10,3 @@ diff -up findutils-4.4.2/Makefile.am_old findutils-4.4.2/Makefile.am
ACLOCAL_AMFLAGS = -I gnulib/m4 -I m4 ACLOCAL_AMFLAGS = -I gnulib/m4 -I m4
diff -up findutils-4.4.2/Makefile.in_old findutils-4.4.2/Makefile.in
--- findutils-4.4.2/Makefile.in_old 2009-06-30 14:54:00.000000000 +0200
+++ findutils-4.4.2/Makefile.in 2009-06-30 14:54:35.000000000 +0200
@@ -607,7 +607,7 @@ EXTRA_DIST = COPYING ChangeLog TODO conf
DISTCLEANFILES = tool-versions.txt
# "tests" is the gnulib unit test dir.
-SUBDIRS = gnulib tests build-aux lib find xargs locate doc po m4
+SUBDIRS = gnulib tests build-aux lib find xargs doc po m4
ACLOCAL_AMFLAGS = -I gnulib/m4 -I m4
TESTFILE_SUFFIXES = .exp .xo .xe .xi
all: config.h

View File

@ -1,517 +0,0 @@
diff -up findutils-4.4.2/configure.ac_old findutils-4.4.2/configure.ac
--- findutils-4.4.2/configure.ac_old 2009-07-01 10:24:04.000000000 +0200
+++ findutils-4.4.2/configure.ac 2009-07-01 10:24:46.000000000 +0200
@@ -114,6 +114,16 @@ AC_CHECK_LIB([m],[fabs],[FINDLIBS="-lm $
AC_DEFINE_UNQUOTED(HAVE_FABS_IN_LIBM,1,[fabs is defined in -lm]))
AC_SUBST([FINDLIBS])
+AC_ARG_WITH([selinux],
+ AS_HELP_STRING([--without-selinux], [disable SELinux support]),
+ [:],
+[AC_CHECK_LIB([selinux], [is_selinux_enabled],
+ [with_selinux=yes], [with_selinux=no])])
+if test x$with_selinux != xno; then
+ AC_DEFINE([WITH_SELINUX], [1], [Define to support SELinux])
+ AC_SUBST([LIBSELINUX], [-lselinux])
+fi
+
dnl Checks for header files.
AC_HEADER_STDC
dnl Assume unistd.h is present - coreutils does too.
diff -up findutils-4.4.2/doc/find.texi_old findutils-4.4.2/doc/find.texi
--- findutils-4.4.2/doc/find.texi_old 2009-07-01 10:25:09.000000000 +0200
+++ findutils-4.4.2/doc/find.texi 2009-07-01 10:26:37.000000000 +0200
@@ -7,7 +7,6 @@
@c %**end of header
@include version.texi
-@include ../locate/dblocation.texi
@iftex
@finalout
@@ -1242,6 +1241,14 @@ situation.
@end deffn
+@deffn Test -context pattern
+True if file's SELinux context matches the pattern @var{pattern}.
+The pattern uses shell glob matching.
+
+This predicate is supported only on @code{find} versions compiled with
+SELinux support and only when SELinux is enabled.
+@end deffn
+
@node Contents
@section Contents
@@ -1826,6 +1833,9 @@ value used for BLOCKSIZE is system-depen
bytes. If the file size is zero, the value printed is undefined. On
systems which lack support for st_blocks, a file's sparseness is
assumed to be 1.0.
+@item %Z
+File's SELinux context, or empty string if the file has no SELinux context
+or this version of find does not support SELinux.
@end table
@node Location Directives
diff -up findutils-4.4.2/find/defs.h_old findutils-4.4.2/find/defs.h
--- findutils-4.4.2/find/defs.h_old 2009-07-01 12:38:32.000000000 +0200
+++ findutils-4.4.2/find/defs.h 2009-07-01 12:52:47.000000000 +0200
@@ -91,6 +91,9 @@ int get_statinfo PARAMS((const char *pat
#define MODE_RWX (S_IXUSR | S_IXGRP | S_IXOTH | MODE_RW)
#define MODE_ALL (S_ISUID | S_ISGID | S_ISVTX | MODE_RWX)
+#ifdef WITH_SELINUX
+#include <selinux/selinux.h>
+#endif
struct predicate;
struct options;
@@ -315,6 +318,9 @@ struct predicate
struct samefile_file_id samefileid; /* samefile */
mode_t type; /* type */
struct format_val printf_vec; /* printf fprintf fprint ls fls print0 fprint0 print */
+#ifdef WITH_SELINUX
+ security_context_t scontext; /* scontext */
+#endif
} args;
/* The next predicate in the user input sequence,
@@ -459,6 +465,9 @@ PREDICATEFUNCTION pred_used;
PREDICATEFUNCTION pred_user;
PREDICATEFUNCTION pred_writable;
PREDICATEFUNCTION pred_xtype;
+#ifdef WITH_SELINUX
+PREDICATEFUNCTION pred_context;
+#endif
@@ -601,6 +610,10 @@ struct options
*/
int regex_options;
+#ifdef WITH_SELINUX
+ int (*x_getfilecon) ();
+#endif
+
/* Optimisation level. One is the default.
*/
unsigned short optimisation_level;
diff -up findutils-4.4.2/find/find.1_old findutils-4.4.2/find/find.1
--- findutils-4.4.2/find/find.1_old 2009-07-01 10:30:04.000000000 +0200
+++ findutils-4.4.2/find/find.1 2009-07-01 10:30:59.000000000 +0200
@@ -933,6 +933,8 @@ if \fIc\fR is `l'. In other words, for
checks the type of the file that
.B \-type
does not check.
+.IP "\-context \fIpattern\fR"
+(SELinux only) Security context of the file matches glob \fIpattern\fR.
.SS ACTIONS
.IP "\-delete\fR"
@@ -1354,6 +1356,8 @@ File's type (like in
U=unknown type (shouldn't happen)
.IP %Y
File's type (like %y), plus follow symlinks: L=loop, N=nonexistent
+.IP %Z
+(SELinux only) file's security context.
.PP
A `%' character followed by any other character is discarded, but the
other character is printed (don't rely on this, as further format
diff -up findutils-4.4.2/find/find.c_old findutils-4.4.2/find/find.c
--- findutils-4.4.2/find/find.c_old 2009-07-01 10:26:53.000000000 +0200
+++ findutils-4.4.2/find/find.c 2009-07-01 10:29:52.000000000 +0200
@@ -120,6 +120,36 @@ int get_current_dirfd(void)
return AT_FDCWD;
}
+#ifdef WITH_SELINUX
+static int
+fallback_getfilecon(const char *name, security_context_t *p, int prev_rv)
+{
+ /* Our original getfilecon() call failed. Perhaps we can't follow a
+ * symbolic link. If that might be the problem, lgetfilecon() the link.
+ * Otherwise, admit defeat.
+ */
+ switch (errno)
+ {
+ case ENOENT:
+ case ENOTDIR:
+#ifdef DEBUG_STAT
+ fprintf(stderr, "fallback_getfilecon(): getfilecon(%s) failed; falling back on lgetfilecon()\n", name);
+#endif
+ return lgetfilecon(name, p);
+
+ case EACCES:
+ case EIO:
+ case ELOOP:
+ case ENAMETOOLONG:
+#ifdef EOVERFLOW
+ case EOVERFLOW: /* EOVERFLOW is not #defined on UNICOS. */
+#endif
+ default:
+ return prev_rv;
+ }
+}
+#endif /* WITH_SELINUX */
+
int
main (int argc, char **argv)
@@ -1270,7 +1300,7 @@ process_path (char *pathname, char *name
static void
process_dir (char *pathname, char *name, int pathlen, const struct stat *statp, char *parent)
{
- int subdirs_left; /* Number of unexamined subdirs in PATHNAME. */
+ int subdirs_left = 0; /* Number of unexamined subdirs in PATHNAME. */
boolean subdirs_unreliable; /* if true, cannot use dir link count as subdir limif (if false, it may STILL be unreliable) */
unsigned int idx; /* Which entry are we on? */
struct stat stat_buf;
diff -up findutils-4.4.2/find/Makefile.am_old findutils-4.4.2/find/Makefile.am
--- findutils-4.4.2/find/Makefile.am_old 2009-07-01 10:35:04.000000000 +0200
+++ findutils-4.4.2/find/Makefile.am 2009-07-01 10:35:37.000000000 +0200
@@ -26,7 +26,7 @@ endif
EXTRA_DIST = defs.h $(man_MANS)
INCLUDES = -I../gnulib/lib -I$(top_srcdir)/lib -I$(top_srcdir)/gnulib/lib -I../intl -DLOCALEDIR=\"$(localedir)\"
-LDADD = ./libfindtools.a ../lib/libfind.a ../gnulib/lib/libgnulib.a @INTLLIBS@ @LIB_CLOCK_GETTIME@ @FINDLIBS@
+LDADD = ./libfindtools.a ../lib/libfind.a ../gnulib/lib/libgnulib.a @INTLLIBS@ @LIB_CLOCK_GETTIME@ @FINDLIBS@ @LIBSELINUX@
man_MANS = find.1
SUBDIRS = . testsuite
diff -up findutils-4.4.2/find/parser.c_old findutils-4.4.2/find/parser.c
--- findutils-4.4.2/find/parser.c_old 2009-07-01 10:35:43.000000000 +0200
+++ findutils-4.4.2/find/parser.c 2009-07-01 12:38:19.000000000 +0200
@@ -53,6 +53,10 @@
#include <unistd.h>
#include <sys/stat.h>
+#ifdef WITH_SELINUX
+#include <selinux/selinux.h>
+#endif
+
#if ENABLE_NLS
# include <libintl.h>
# define _(Text) gettext (Text)
@@ -155,6 +159,9 @@ static boolean parse_noignore_race PARAM
static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
+#ifdef WITH_SELINUX
+static boolean parse_context PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
+#endif
boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
@@ -251,6 +258,9 @@ static struct parser_table const parse_t
PARSE_TEST ("cmin", cmin), /* GNU */
PARSE_TEST ("cnewer", cnewer), /* GNU */
{ARG_TEST, "ctime", parse_time, pred_ctime}, /* POSIX */
+#ifdef WITH_SELINUX
+ PARSE_TEST ("context", context), /* GNU */
+#endif
PARSE_POSOPT ("daystart", daystart), /* GNU */
PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
@@ -347,6 +357,89 @@ static struct parser_table const parse_t
static const char *first_nonoption_arg = NULL;
static const struct parser_table *noop = NULL;
+#ifdef WITH_SELINUX
+static int
+fallback_getfilecon(const char *name, security_context_t *p, int prev_rv)
+{
+ /* Our original getfilecon() call failed. Perhaps we can't follow a
+ * symbolic link. If that might be the problem, lgetfilecon() the link.
+ * Otherwise, admit defeat.
+ */
+ switch (errno)
+ {
+ case ENOENT:
+ case ENOTDIR:
+#ifdef DEBUG_STAT
+ fprintf(stderr, "fallback_getfilecon(): getfilecon(%s) failed; falling back on lgetfilecon()\n", name);
+#endif
+ return lgetfilecon(name, p);
+
+ case EACCES:
+ case EIO:
+ case ELOOP:
+ case ENAMETOOLONG:
+#ifdef EOVERFLOW
+ case EOVERFLOW: /* EOVERFLOW is not #defined on UNICOS. */
+#endif
+ default:
+ return prev_rv;
+ }
+}
+
+/* optionh_getfilecon() implements the getfilecon operation when the
+ * -H option is in effect.
+ *
+ * If the item to be examined is a command-line argument, we follow
+ * symbolic links. If the getfilecon() call fails on the command-line
+ * item, we fall back on the properties of the symbolic link.
+ *
+ * If the item to be examined is not a command-line argument, we
+ * examine the link itself.
+ */
+int
+optionh_getfilecon(const char *name, security_context_t *p)
+{
+ if (0 == state.curdepth)
+ {
+ /* This file is from the command line; deference the link (if it
+ * is a link).
+ */
+ int rv = getfilecon(name, p);
+ if (0 == rv)
+ return 0; /* success */
+ else
+ return fallback_getfilecon(name, p, rv);
+ }
+ else
+ {
+ /* Not a file on the command line; do not derefernce the link.
+ */
+ return lgetfilecon(name, p);
+ }
+}
+/* optionl_getfilecon() implements the getfilecon operation when the
+ * -L option is in effect. That option makes us examine the thing the
+ * symbolic link points to, not the symbolic link itself.
+ */
+int
+optionl_getfilecon(const char *name, security_context_t *p)
+{
+ int rv = getfilecon(name, p);
+ if (0 == rv)
+ return 0; /* normal case. */
+ else
+ return fallback_getfilecon(name, p, rv);
+}
+/* optionp_getfilecon() implements the stat operation when the -P
+ * option is in effect (this is also the default). That option makes
+ * us examine the symbolic link itself, not the thing it points to.
+ */
+int
+optionp_getfilecon(const char *name, security_context_t *p)
+{
+ return lgetfilecon(name, p);
+}
+#endif /* WITH_SELINUX */
void
check_option_combinations(const struct predicate *p)
@@ -450,11 +543,17 @@ set_follow_state(enum SymlinkOption opt)
{
case SYMLINK_ALWAYS_DEREF: /* -L */
options.xstat = optionl_stat;
+#ifdef WITH_SELINUX
+ options.x_getfilecon = optionl_getfilecon;
+#endif
options.no_leaf_check = true;
break;
case SYMLINK_NEVER_DEREF: /* -P (default) */
options.xstat = optionp_stat;
+#ifdef WITH_SELINUX
+ options.x_getfilecon = optionp_getfilecon;
+#endif
/* Can't turn no_leaf_check off because the user might have specified
* -noleaf anyway
*/
@@ -462,6 +561,9 @@ set_follow_state(enum SymlinkOption opt)
case SYMLINK_DEREF_ARGSONLY: /* -H */
options.xstat = optionh_stat;
+#ifdef WITH_SELINUX
+ options.x_getfilecon = optionh_getfilecon;
+#endif
options.no_leaf_check = true;
}
}
@@ -1127,8 +1229,12 @@ tests (N can be +N or -N or N): -amin N
-nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
-readable -writable -executable\n\
-wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
- -used N -user NAME -xtype [bcdpfls]\n"));
+ -used N -user NAME -xtype [bcdpfls]"));
+#ifdef WITH_SELINUX
puts (_("\
+ -context CONTEXT\n"));
+#endif
+ puts (_("\n\
actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
-fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
-exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
@@ -2518,6 +2624,10 @@ parse_version (const struct parser_table
printf("LEAF_OPTIMISATION ");
++features;
#endif
+#if defined(WITH_SELINUX)
+ printf("SELINUX ");
+ ++features;
+#endif
flags = 0;
if (is_fts_enabled(&flags))
@@ -2552,6 +2662,32 @@ parse_version (const struct parser_table
exit (0);
}
+#ifdef WITH_SELINUX
+static boolean
+parse_context (const struct parser_table* entry, char **argv, int *arg_ptr)
+{
+ struct predicate *our_pred;
+
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return false;
+
+ if (is_selinux_enabled() <= 0)
+ {
+ error (1, 0, _("invalid predicate -context: SELinux is not enabled."));
+ return false;
+ }
+ our_pred = insert_primary (entry);
+ our_pred->need_stat = false;
+#ifdef DEBUG
+ our_pred->p_name = find_pred_name (pred_context);
+#endif /*DEBUG*/
+ our_pred->args.scontext = argv[*arg_ptr];
+
+ (*arg_ptr)++;
+ return true;
+}
+#endif /* WITH_SELINUX */
+
static boolean
parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
{
@@ -2803,7 +2939,7 @@ insert_fprintf (struct format_val *vec,
if (*scan2 == '.')
for (scan2++; ISDIGIT (*scan2); scan2++)
/* Do nothing. */ ;
- if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2))
+ if (strchr ("abcdDfFgGhHiklmMnpPsStuUyYZ", *scan2))
{
segmentp = make_segment (segmentp, format, scan2 - format,
KIND_FORMAT, *scan2, 0,
@@ -2930,6 +3066,7 @@ make_segment (struct segment **segment,
case 'h': /* leading directories part of path */
case 'p': /* pathname */
case 'P': /* pathname with ARGV element stripped */
+ case 'Z': /* SELinux security context */
*fmt++ = 's';
break;
diff -up findutils-4.4.2/find/pred.c_old findutils-4.4.2/find/pred.c
--- findutils-4.4.2/find/pred.c_old 2009-07-01 10:31:11.000000000 +0200
+++ findutils-4.4.2/find/pred.c 2009-07-01 10:33:45.000000000 +0200
@@ -48,6 +48,10 @@
#include "error.h"
#include "verify.h"
+#ifdef WITH_SELINUX
+#include <selinux/selinux.h>
+#endif /*WITH_SELINUX*/
+
#if ENABLE_NLS
# include <libintl.h>
# define _(Text) gettext (Text)
@@ -230,6 +234,9 @@ struct pred_assoc pred_table[] =
{pred_user, "user "},
{pred_writable, "writable "},
{pred_xtype, "xtype "},
+#ifdef WITH_SELINUX
+ {pred_context, "context"},
+#endif /*WITH_SELINUX*/
{0, "none "}
};
#endif
@@ -1054,6 +1061,27 @@ do_fprintf(struct format_val *dest,
mode_to_filetype(stat_buf->st_mode & S_IFMT));
}
break;
+ case 'Z': /* SELinux security context */
+#ifdef WITH_SELINUX
+ {
+ security_context_t scontext;
+ int rv;
+ rv = (*options.x_getfilecon) (state.rel_pathname, &scontext);
+
+ if (rv < 0)
+ {
+ fprintf (stderr, "getfilecon(%s): %s", pathname,
+ strerror(errno));
+ fflush (stderr);
+ }
+ else
+ {
+ checked_fprintf (dest, segment->text, scontext);
+ freecon (scontext);
+ }
+ }
+#endif /* WITH_SELINUX */
+ break;
}
/* end of KIND_FORMAT case */
break;
@@ -1844,6 +1872,32 @@ pred_xtype (const char *pathname, struct
*/
return (pred_type (pathname, &sbuf, pred_ptr));
}
+
+#ifdef WITH_SELINUX
+
+boolean
+pred_context (const char *pathname, struct stat *stat_buf,
+ struct predicate *pred_ptr)
+{
+ int rv;
+ security_context_t scontext;
+
+ rv = (*options.x_getfilecon) (state.rel_pathname, &scontext);
+
+ if (rv < 0)
+ {
+ fprintf (stderr, "getfilecon(%s): %s\n", pathname, strerror(errno));
+ fflush (stderr);
+ return false;
+ }
+
+ rv = (fnmatch (pred_ptr->args.scontext, scontext, 0) == 0);
+ freecon (scontext);
+ return rv;
+}
+
+#endif /*WITH_SELINUX*/
+
/* 1) fork to get a child; parent remembers the child pid
2) child execs the command requested
diff -up findutils-4.4.2/find/tree.c_old findutils-4.4.2/find/tree.c
--- findutils-4.4.2/find/tree.c_old 2009-07-01 10:33:57.000000000 +0200
+++ findutils-4.4.2/find/tree.c 2009-07-01 10:34:54.000000000 +0200
@@ -953,7 +953,8 @@ static struct pred_cost_lookup costlooku
{ pred_used , NeedsStatInfo },
{ pred_user , NeedsStatInfo },
{ pred_writable , NeedsAccessInfo },
- { pred_xtype , NeedsType } /* roughly correct unless most files are symlinks */
+ { pred_xtype , NeedsType }, /* roughly correct unless most files are symlinks */
+ { pred_context , NeedsNothing } /* remove warning only:) */
};
static int pred_table_sorted = 0;
@@ -1434,6 +1435,9 @@ get_new_pred (const struct parser_table
last_pred->need_stat = true;
last_pred->need_type = true;
last_pred->args.str = NULL;
+#ifdef WITH_SELINUX
+ last_pred->args.scontext = NULL;
+#endif
last_pred->pred_next = NULL;
last_pred->pred_left = NULL;
last_pred->pred_right = NULL;

View File

@ -0,0 +1,87 @@
diff -rup findutils-4.4.2.orig/find/fstype.c findutils-4.4.2/find/fstype.c
--- findutils-4.4.2.orig/find/fstype.c 2009-05-16 17:17:01.000000000 +0200
+++ findutils-4.4.2/find/fstype.c 2009-10-20 12:47:10.589871024 +0200
@@ -205,7 +205,72 @@ must_read_fs_list(bool need_fs_type)
return entries;
}
+/* Return the device number from MOUNT_OPTIONS, if possible.
+ Otherwise return (dev_t) -1. Taken from 'mountlist' module
+ from gnulib. */
+static dev_t
+dev_from_mount_options (char const *mount_options)
+{
+ /* GNU/Linux allows file system implementations to define their own
+ meaning for "dev=" mount options, so don't trust the meaning
+ here. */
+# ifndef __linux__
+
+ static char const dev_pattern[] = ",dev=";
+ char const *devopt = strstr (mount_options, dev_pattern);
+
+ if (devopt)
+ {
+ char const *optval = devopt + sizeof dev_pattern - 1;
+ char *optvalend;
+ unsigned long int dev;
+ errno = 0;
+ dev = strtoul (optval, &optvalend, 16);
+ if (optval != optvalend
+ && (*optvalend == '\0' || *optvalend == ',')
+ && ! (dev == ULONG_MAX && errno == ERANGE)
+ && dev == (dev_t) dev)
+ return dev;
+ }
+
+# endif
+ (void) mount_options;
+ return -1;
+}
+
+/* Return true if the file described by STATP is on autofs file system
+ and call set_fstype_devno () if the autofs file system is matched. */
+static bool
+filesystem_check_autofs (const struct stat *statp)
+{
+ FILE *fp;
+ struct mntent *mnt;
+ struct mount_entry entry;
+ bool match = false;
+
+ /* open /proc/mounts because autofs is not listed in /etc/mtab */
+ fp = setmntent ("/proc/mounts", "r");
+ if (fp == NULL)
+ return false;
+ while ((mnt = getmntent (fp)))
+ {
+ if (0 != strcmp ("autofs", mnt->mnt_type))
+ continue;
+
+ entry.me_mountdir = mnt->mnt_dir;
+ entry.me_dev = dev_from_mount_options (mnt->mnt_opts);
+ set_fstype_devno (&entry);
+ if (entry.me_dev == statp->st_dev)
+ {
+ match = true;
+ break;
+ }
+ }
+
+ endmntent (fp);
+ return match;
+}
/* Return a newly allocated string naming the type of file system that the
file PATH, described by STATP, is on.
@@ -244,6 +309,10 @@ file_system_type_uncached (const struct
}
free_file_system_list(entries);
+ /* check for autofs */
+ if (type == NULL && filesystem_check_autofs (statp))
+ type = xstrdup ("autofs");
+
/* Don't cache unknown values. */
fstype_known = (type != NULL);

View File

@ -0,0 +1,27 @@
This patch is already applied on gnulib upstream git.
diff --git a/gnulib/lib/fts.c b/gnulib/lib/fts.c
index ceb8935..2f1eda4 100644
--- a/gnulib/lib/fts.c
+++ b/gnulib/lib/fts.c
@@ -974,6 +974,20 @@ fts_build (register FTS *sp, int type)
opening it. */
if (cur->fts_info == FTS_NSOK)
cur->fts_info = fts_stat(sp, cur, false);
+ else if (sp->fts_options & FTS_TIGHT_CYCLE_CHECK) {
+ /* Now read the stat info again after opening a directory to
+ * reveal eventual changes caused by a submount triggered by
+ * the traverse. But do it only for utilities which use
+ * FTS_TIGHT_CYCLE_CHECK. Therefore only find and du can
+ * benefit from this feature for now.
+ */
+ LEAVE_DIR (sp, cur, "4");
+ fts_stat (sp, cur, false);
+ if (! enter_dir (sp, cur)) {
+ __set_errno (ENOMEM);
+ return NULL;
+ }
+ }
/*
* Nlinks is the number of possible entries of type directory in the

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,463 @@
NEWS | 6 +++
doc/find.texi | 18 +++++++-
find/Makefile.am | 2 +-
find/defs.h | 6 +++
find/find.1 | 4 ++
find/parser.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
find/pred.c | 47 ++++++++++++++++++++
find/tree.c | 2 +
8 files changed, 209 insertions(+), 4 deletions(-)
diff --git a/NEWS b/NEWS
index d00862f..6b8b725 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,11 @@
GNU findutils NEWS - User visible changes. -*- outline -*- (allout)
+* Major changes in release 4.4.2, 2009-11-26
+
+** Functional Enhancements to find
+
+patch #4848: Patch - Support for SELinux
+
* Major changes in release 4.4.2, 2009-05-16
** Bug Fixes
diff --git a/doc/find.texi b/doc/find.texi
index 8944096..4d71066 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
@@ -1242,6 +1241,14 @@ situation.
@end deffn
+@deffn Test -context pattern
+True if file's SELinux context matches the pattern @var{pattern}.
+The pattern uses shell glob matching.
+
+This predicate is supported only on @code{find} versions compiled with
+SELinux support and only when SELinux is enabled.
+@end deffn
+
@node Contents
@section Contents
@@ -1737,6 +1744,7 @@ from the novel you are reading.
* Size Directives::
* Location Directives::
* Time Directives::
+* Other Directives::
* Formatting Flags::
@end menu
@@ -1894,6 +1902,14 @@ File's last modification time in the format specified by @var{k}
(@pxref{Time Formats}).
@end table
+@node Other Directives
+@subsubsection Other Directives
+
+@table @code
+@item %Z
+File's SELinux context, or empty string if the file has no SELinux context.
+@end table
+
@node Time Formats
@subsection Time Formats
diff --git a/find/Makefile.am b/find/Makefile.am
index b001509..6fc7df3 100644
--- a/find/Makefile.am
+++ b/find/Makefile.am
@@ -26,7 +26,7 @@ endif
EXTRA_DIST = defs.h $(man_MANS)
INCLUDES = -I../gnulib/lib -I$(top_srcdir)/lib -I$(top_srcdir)/gnulib/lib -I../intl -DLOCALEDIR=\"$(localedir)\"
-LDADD = ./libfindtools.a ../lib/libfind.a ../gnulib/lib/libgnulib.a @INTLLIBS@ @LIB_CLOCK_GETTIME@ @FINDLIBS@
+LDADD = ./libfindtools.a ../lib/libfind.a ../gnulib/lib/libgnulib.a @INTLLIBS@ @LIB_CLOCK_GETTIME@ @FINDLIBS@ @LIB_SELINUX@
man_MANS = find.1
SUBDIRS = . testsuite
diff --git a/find/defs.h b/find/defs.h
index a0e7059..36d428d 100644
--- a/find/defs.h
+++ b/find/defs.h
@@ -48,6 +48,7 @@ Please stop compiling the program now
#include <stdbool.h> /* for bool/boolean */
#include <stdint.h> /* for uintmax_t */
#include <sys/stat.h> /* S_ISUID etc. */
+#include <selinux/selinux.h>
@@ -315,6 +316,7 @@ struct predicate
struct samefile_file_id samefileid; /* samefile */
mode_t type; /* type */
struct format_val printf_vec; /* printf fprintf fprint ls fls print0 fprint0 print */
+ security_context_t scontext; /* security context */
} args;
/* The next predicate in the user input sequence,
@@ -459,6 +461,7 @@ PREDICATEFUNCTION pred_used;
PREDICATEFUNCTION pred_user;
PREDICATEFUNCTION pred_writable;
PREDICATEFUNCTION pred_xtype;
+PREDICATEFUNCTION pred_context;
@@ -604,6 +607,9 @@ struct options
*/
int regex_options;
+ /* function used to get file context */
+ int (*x_getfilecon) (int, const char *, security_context_t *);
+
/* Optimisation level. One is the default.
*/
unsigned short optimisation_level;
diff --git a/find/find.1 b/find/find.1
index f9c61a3..27ad1da 100644
--- a/find/find.1
+++ b/find/find.1
@@ -936,6 +936,8 @@ if \fIc\fR is `l'. In other words, for symbolic links,
checks the type of the file that
.B \-type
does not check.
+.IP "\-context \fIpattern\fR"
+(SELinux only) Security context of the file matches glob \fIpattern\fR.
.SS ACTIONS
.IP "\-delete\fR"
@@ -1357,6 +1359,8 @@ File's type (like in
U=unknown type (shouldn't happen)
.IP %Y
File's type (like %y), plus follow symlinks: L=loop, N=nonexistent
+.IP %Z
+(SELinux only) file's security context.
.PP
A `%' character followed by any other character is discarded, but the
other character is printed (don't rely on this, as further format
diff --git a/find/parser.c b/find/parser.c
index 411fd96..3f237eb 100644
--- a/find/parser.c
+++ b/find/parser.c
@@ -53,6 +53,8 @@
#include <unistd.h>
#include <sys/stat.h>
+#include "selinux-at.h"
+
#if ENABLE_NLS
# include <libintl.h>
# define _(Text) gettext (Text)
@@ -156,6 +158,7 @@ static boolean parse_noignore_race PARAMS((const struct parser_table*, char *arg
static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
static boolean parse_xtype PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
static boolean parse_quit PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
+static boolean parse_context PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
boolean parse_print PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
@@ -252,6 +255,7 @@ static struct parser_table const parse_table[] =
PARSE_TEST ("cmin", cmin), /* GNU */
PARSE_TEST ("cnewer", cnewer), /* GNU */
{ARG_TEST, "ctime", parse_time, pred_ctime}, /* POSIX */
+ PARSE_TEST ("context", context), /* GNU */
PARSE_POSOPT ("daystart", daystart), /* GNU */
PARSE_ACTION ("delete", delete), /* GNU, Mac OS, FreeBSD */
PARSE_OPTION ("d", d), /* Mac OS X, FreeBSD, NetBSD, OpenBSD, but deprecated in favour of -depth */
@@ -349,6 +353,86 @@ static struct parser_table const parse_table[] =
static const char *first_nonoption_arg = NULL;
static const struct parser_table *noop = NULL;
+static int
+fallback_getfilecon (int fd, const char *name, security_context_t *p,
+ int prev_rv)
+{
+ /* Our original getfilecon () call failed. Perhaps we can't follow a
+ * symbolic link. If that might be the problem, lgetfilecon () the link.
+ * Otherwise, admit defeat. */
+ switch (errno)
+ {
+ case ENOENT:
+ case ENOTDIR:
+#ifdef DEBUG_STAT
+ fprintf (stderr, "fallback_getfilecon(): getfilecon(%s) failed; falling "
+ "back on lgetfilecon()\n", name);
+#endif
+ return lgetfileconat (fd, name, p);
+
+ case EACCES:
+ case EIO:
+ case ELOOP:
+ case ENAMETOOLONG:
+#ifdef EOVERFLOW
+ case EOVERFLOW: /* EOVERFLOW is not #defined on UNICOS. */
+#endif
+ default:
+ return prev_rv;
+ }
+}
+
+/* optionh_getfilecon () implements the getfilecon operation when the
+ * -H option is in effect.
+ *
+ * If the item to be examined is a command-line argument, we follow
+ * symbolic links. If the getfilecon () call fails on the command-line
+ * item, we fall back on the properties of the symbolic link.
+ *
+ * If the item to be examined is not a command-line argument, we
+ * examine the link itself. */
+int
+optionh_getfilecon (int fd, const char *name, security_context_t *p)
+{
+ int rv;
+ if (0 == state.curdepth)
+ {
+ /* This file is from the command line; dereference the link (if it is
+ a link). */
+ rv = getfileconat (fd, name, p);
+ if (0 == rv)
+ return 0; /* success */
+ else
+ return fallback_getfilecon (fd, name, p, rv);
+ }
+ else
+ {
+ /* Not a file on the command line; do not dereference the link. */
+ return lgetfileconat (fd, name, p);
+ }
+}
+
+/* optionl_getfilecon () implements the getfilecon operation when the
+ * -L option is in effect. That option makes us examine the thing the
+ * symbolic link points to, not the symbolic link itself. */
+int
+optionl_getfilecon (int fd, const char *name, security_context_t *p)
+{
+ int rv = getfileconat (fd, name, p);
+ if (0 == rv)
+ return 0; /* normal case. */
+ else
+ return fallback_getfilecon (fd, name, p, rv);
+}
+
+/* optionp_getfilecon () implements the stat operation when the -P
+ * option is in effect (this is also the default). That option makes
+ * us examine the symbolic link itself, not the thing it points to. */
+int
+optionp_getfilecon (int fd, const char *name, security_context_t *p)
+{
+ return lgetfileconat (fd, name, p);
+}
void
check_option_combinations(const struct predicate *p)
@@ -452,11 +536,13 @@ set_follow_state(enum SymlinkOption opt)
{
case SYMLINK_ALWAYS_DEREF: /* -L */
options.xstat = optionl_stat;
+ options.x_getfilecon = optionl_getfilecon;
options.no_leaf_check = true;
break;
case SYMLINK_NEVER_DEREF: /* -P (default) */
options.xstat = optionp_stat;
+ options.x_getfilecon = optionp_getfilecon;
/* Can't turn no_leaf_check off because the user might have specified
* -noleaf anyway
*/
@@ -464,6 +550,7 @@ set_follow_state(enum SymlinkOption opt)
case SYMLINK_DEREF_ARGSONLY: /* -H */
options.xstat = optionh_stat;
+ options.x_getfilecon = optionh_getfilecon;
options.no_leaf_check = true;
}
}
@@ -1129,8 +1216,10 @@ tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N\n\
-nouser -nogroup -path PATTERN -perm [+-]MODE -regex PATTERN\n\
-readable -writable -executable\n\
-wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N\n\
- -used N -user NAME -xtype [bcdpfls]\n"));
+ -used N -user NAME -xtype [bcdpfls]"));
puts (_("\
+ -context CONTEXT\n"));
+ puts (_("\n\
actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print \n\
-fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit\n\
-exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;\n\
@@ -2520,6 +2609,11 @@ parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
printf("LEAF_OPTIMISATION ");
++features;
#endif
+ if (0 < is_selinux_enabled ())
+ {
+ printf ("SELINUX ");
+ ++features;
+ }
flags = 0;
if (is_fts_enabled(&flags))
@@ -2555,6 +2649,31 @@ parse_version (const struct parser_table* entry, char **argv, int *arg_ptr)
}
static boolean
+parse_context (const struct parser_table* entry, char **argv, int *arg_ptr)
+{
+ struct predicate *our_pred;
+
+ if ((argv == NULL) || (argv[*arg_ptr] == NULL))
+ return false;
+
+ if (is_selinux_enabled () <= 0)
+ {
+ error (1, 0, _("invalid predicate -context: SELinux is not enabled."));
+ return false;
+ }
+ our_pred = insert_primary (entry);
+ our_pred->est_success_rate = 0.01f;
+ our_pred->need_stat = false;
+#ifdef DEBUG
+ our_pred->p_name = find_pred_name (pred_context);
+#endif /*DEBUG*/
+ our_pred->args.scontext = argv[*arg_ptr];
+
+ (*arg_ptr)++;
+ return true;
+}
+
+static boolean
parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
{
options.stay_on_filesystem = true;
@@ -2812,7 +2931,7 @@ insert_fprintf (struct format_val *vec,
if (*scan2 == '.')
for (scan2++; ISDIGIT (*scan2); scan2++)
/* Do nothing. */ ;
- if (strchr ("abcdDfFgGhHiklmMnpPsStuUyY", *scan2))
+ if (strchr ("abcdDfFgGhHiklmMnpPsStuUyYZ", *scan2))
{
segmentp = make_segment (segmentp, format, scan2 - format,
KIND_FORMAT, *scan2, 0,
@@ -2942,6 +3061,11 @@ make_segment (struct segment **segment,
*fmt++ = 's';
break;
+ case 'Z': /* SELinux security context */
+ mycost = NeedsAccessInfo;
+ *fmt++ = 's';
+ break;
+
case 'H': /* ARGV element file was found under */
*fmt++ = 's';
break;
diff --git a/find/pred.c b/find/pred.c
index b1f48a0..7c34119 100644
--- a/find/pred.c
+++ b/find/pred.c
@@ -48,6 +48,8 @@
#include "error.h"
#include "verify.h"
+#include <selinux/selinux.h>
+
#if ENABLE_NLS
# include <libintl.h>
# define _(Text) gettext (Text)
@@ -230,6 +232,7 @@ struct pred_assoc pred_table[] =
{pred_user, "user "},
{pred_writable, "writable "},
{pred_xtype, "xtype "},
+ {pred_context, "context"},
{0, "none "}
};
#endif
@@ -1054,6 +1057,30 @@ do_fprintf(struct format_val *dest,
mode_to_filetype(stat_buf->st_mode & S_IFMT));
}
break;
+
+ case 'Z': /* SELinux security context */
+ {
+ security_context_t scontext;
+ int rv = (*options.x_getfilecon) (state.cwd_dir_fd, state.rel_pathname,
+ &scontext);
+ if (rv < 0)
+ {
+ /* If getfilecon fails, there will in the general case
+ still be some text to print. We just make %Z expand
+ to an empty string. */
+ checked_fprintf (dest, segment->text, "");
+
+ error (0, errno, "getfilecon: %s",
+ safely_quote_err_filename (0, pathname));
+ state.exit_status = 1;
+ }
+ else
+ {
+ checked_fprintf (dest, segment->text, scontext);
+ freecon (scontext);
+ }
+ }
+ break;
}
/* end of KIND_FORMAT case */
break;
@@ -1844,6 +1871,26 @@ pred_xtype (const char *pathname, struct stat *stat_buf, struct predicate *pred_
*/
return (pred_type (pathname, &sbuf, pred_ptr));
}
+
+
+boolean
+pred_context (const char *pathname, struct stat *stat_buf,
+ struct predicate *pred_ptr)
+{
+ security_context_t scontext;
+ int rv = (*options.x_getfilecon) (state.cwd_dir_fd, state.rel_pathname,
+ &scontext);
+ if (rv < 0)
+ {
+ error (0, errno, "getfilecon: %s", safely_quote_err_filename (0, pathname));
+ return false;
+ }
+
+ rv = (fnmatch (pred_ptr->args.scontext, scontext, 0) == 0);
+ freecon (scontext);
+ return rv;
+}
+
/* 1) fork to get a child; parent remembers the child pid
2) child execs the command requested
diff --git a/find/tree.c b/find/tree.c
index 7420c60..ecdd4c9 100644
--- a/find/tree.c
+++ b/find/tree.c
@@ -904,6 +904,7 @@ static struct pred_cost_lookup costlookup[] =
{ pred_cmin , NeedsStatInfo, },
{ pred_cnewer , NeedsStatInfo, },
{ pred_comma , NeedsNothing, },
+ { pred_context , NeedsAccessInfo },
{ pred_ctime , NeedsStatInfo, },
{ pred_delete , NeedsSyncDiskHit },
{ pred_empty , NeedsStatInfo },
@@ -1434,6 +1435,7 @@ get_new_pred (const struct parser_table *entry)
last_pred->need_stat = true;
last_pred->need_type = true;
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;

View File

@ -0,0 +1,123 @@
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 2e5958d..8944096 100644
--- a/doc/find.texi
+++ b/doc/find.texi
@@ -1413,6 +1413,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 1708d83..a0e7059 100644
--- a/find/defs.h
+++ b/find/defs.h
@@ -550,6 +550,9 @@ struct options
/* If true, don't cross filesystem boundaries. */
boolean stay_on_filesystem;
+ /* If true, don't descend directories on autofs filesystems. */
+ boolean 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 8b67ae3..f9c61a3 100644
--- a/find/find.1
+++ b/find/find.1
@@ -451,6 +451,9 @@ if standard input is a tty, and to
.B \-nowarn
otherwise.
+.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 b59d896..838b81f 100644
--- a/find/ftsfind.c
+++ b/find/ftsfind.c
@@ -525,6 +525,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 534b670..411fd96 100644
--- a/find/parser.c
+++ b/find/parser.c
@@ -150,6 +150,7 @@ static boolean parse_user PARAMS((const struct parser_table*, char *arg
static boolean parse_version PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
static boolean parse_wholename PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
static boolean parse_xdev PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
+static boolean parse_xautofs PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
static boolean parse_ignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
static boolean parse_noignore_race PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
static boolean parse_warn PARAMS((const struct parser_table*, char *argv[], int *arg_ptr));
@@ -320,6 +321,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.
@@ -1117,7 +1119,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\
@@ -2560,6 +2562,13 @@ parse_xdev (const struct parser_table* entry, char **argv, int *arg_ptr)
}
static boolean
+parse_xautofs (const struct parser_table* entry, char **argv, int *arg_ptr)
+{
+ options.bypass_autofs = true;
+ return parse_noop(entry, argv, arg_ptr);
+}
+
+static boolean
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 a06eada..d3cb467 100644
--- a/find/util.c
+++ b/find/util.c
@@ -933,6 +933,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)

View File

@ -0,0 +1,192 @@
ChangeLog | 16 +++++++
find/testsuite/Makefile.am | 3 +
find/testsuite/config/unix.exp | 9 ++++
find/testsuite/find.gnu/execdir-multiple.exp | 55 ++++++++++++++++++++++++++
find/testsuite/find.gnu/execdir-multiple.xo | 24 +++++++++++
find/testsuite/find.gnu/execdir-pwd1.exp | 20 +++++++++
6 files changed, 127 insertions(+), 0 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index be93846..34552d5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2010-04-10 James Youngman <jay@gnu.org>
+
+ Add a test which checks $CWD for find -execdir {} +/;
+ * find/testsuite/find.gnu/execdir-multiple.exp: New test; verifies
+ that for -execdir +, all the execs occur with the correct working
+ directory.
+ * find/testsuite/find.gnu/execdir-multiple.xo: Expected output for
+ this test.
+ * find/testsuite/Makefile.am (EXTRA_DIST_EXP): Add the new test.
+ (EXTRA_DIST_XO): Add the expected output file.
+ * find/testsuite/config/unix.exp (mkdir): Create proc "mkdir"
+ which creates a directory.
+ * find/testsuite/find.gnu/execdir-pwd1.exp: New test.
+ * find/testsuite/Makefile.am (EXTRA_DIST_EXP): Add
+ execdir-pwd1.exp.
+
2009-05-16 James Youngman <jay@gnu.org>
Apply typo fix from <petrosyan@gmail.com> (tiny change).
diff --git a/find/testsuite/Makefile.am b/find/testsuite/Makefile.am
index dca30e6..1447132 100644
--- a/find/testsuite/Makefile.am
+++ b/find/testsuite/Makefile.am
@@ -14,6 +14,7 @@ find.gnu/depth.xo \
find.gnu/depth-d.xo \
find.gnu/empty.xo \
find.gnu/execdir-hier.xo \
+find.gnu/execdir-multiple.xo \
find.gnu/execdir-one.xo \
find.gnu/execdir-root-only.xo \
find.gnu/exec-many-rtn-failure.xo \
@@ -114,8 +115,10 @@ find.gnu/depth-d.exp \
find.gnu/empty.exp \
find.gnu/execdir-hier.exp \
find.gnu/execdir-in-unreadable.exp \
+find.gnu/execdir-multiple.exp \
find.gnu/execdir-one.exp \
find.gnu/execdir-pwd.exp \
+find.gnu/execdir-pwd1.exp \
find.gnu/execdir-root-only.exp \
find.gnu/exec-many-rtn-failure.exp \
find.gnu/exec-many-rtn-success.exp \
diff --git a/find/testsuite/config/unix.exp b/find/testsuite/config/unix.exp
index 087aeb2..968eb9d 100644
--- a/find/testsuite/config/unix.exp
+++ b/find/testsuite/config/unix.exp
@@ -259,6 +259,15 @@ proc touch args {
}
}
+proc mkdir { dirname } {
+ # Not all versions of Tcl offer 'file mkdir'.
+ set failed [ catch "file mkdir $dirname" result ]
+ if $failed {
+ # Fall back on the external command.
+ send_log "file mkdir does not work, falling back on exec mkdir\n"
+ exec mkdir "$dirname"
+ }
+}
proc safe_path [ ] {
diff --git a/find/testsuite/find.gnu/execdir-multiple.exp b/find/testsuite/find.gnu/execdir-multiple.exp
new file mode 100644
index 0000000..6d4bd66
--- /dev/null
+++ b/find/testsuite/find.gnu/execdir-multiple.exp
@@ -0,0 +1,55 @@
+# tests for -execdir ... \+
+
+# Create 4 empty files in each of 6 directories.
+# Also create a shell script in each of those 6 directories.
+# Run a find command which runs the shell script for each empty file.
+# Check to make sure that each file is mentioned exactly once, and that
+# the command was run with the correct working directory.
+#
+# The output is a sequence of lines of this form:
+#
+# cwd ./basename
+#
+# cmd is the basename of the current directory at the time the command
+# is run by -execidr. ./basename is the name of the file that was matched
+# (that is, it's the value passed in {}).
+
+# $body is the body of a shell script we use for testing.
+# It prints a series of lines of the form described above.
+# One line is printed for each command-line argument.
+set body {#! /bin/sh
+set -e
+here=`pwd`
+d=`basename $here`
+
+for arg;
+do
+ echo "$d" "$arg"
+done | LC_ALL=C sort
+}
+
+
+if { [ safe_path ] } {
+ global SKIP_OLD
+
+ exec rm -rf tmp
+ mkdir tmp
+
+ # Put a copy of our shell script in each
+ # directory, plus some files.
+ foreach dir { a b c d e f } {
+ mkdir "tmp/$dir"
+ set script_name "tmp/$dir/runme"
+ set f [open "$script_name" "w" 0700 ]
+ puts $f "$body"
+ close $f
+ foreach item { one two three four } {
+ touch "tmp/$dir/$item"
+ }
+ }
+
+ set SKIP_OLD 1
+ find_start p {tmp -type f -empty -execdir sh ./runme \{\} + } ""
+ set SKIP_OLD 0
+ exec rm -rf tmp
+}
diff --git a/find/testsuite/find.gnu/execdir-multiple.xo b/find/testsuite/find.gnu/execdir-multiple.xo
new file mode 100644
index 0000000..a4f93d9
--- /dev/null
+++ b/find/testsuite/find.gnu/execdir-multiple.xo
@@ -0,0 +1,24 @@
+a ./one
+a ./two
+a ./three
+a ./four
+b ./one
+b ./two
+b ./three
+b ./four
+c ./one
+c ./two
+c ./three
+c ./four
+d ./one
+d ./two
+d ./three
+d ./four
+e ./one
+e ./two
+e ./three
+e ./four
+f ./one
+f ./two
+f ./three
+f ./four
diff --git a/find/testsuite/find.gnu/execdir-pwd1.exp b/find/testsuite/find.gnu/execdir-pwd1.exp
new file mode 100644
index 0000000..e9863ac
--- /dev/null
+++ b/find/testsuite/find.gnu/execdir-pwd1.exp
@@ -0,0 +1,20 @@
+# tests for working directory of -execdir {} \;
+if { [ safe_path ] } {
+ global SKIP_OLD
+
+ exec rm -rf tmp
+ exec mkdir tmp
+
+ # Create an empty shell script.
+ exec touch tmp/foo
+ exec chmod +x tmp/foo
+
+ # The -execdir should find the "foo" in the current directory.
+ # If not, the find command is probably executing the command
+ # built up by -execdir in the wrong directory.
+
+ set SKIP_OLD 1
+ find_start p {tmp -name foo -execdir sh ./foo \{\} \; } ""
+ set SKIP_OLD 0
+ exec rm -rf tmp
+}

View File

@ -0,0 +1,945 @@
ChangeLog | 83 +++++++++++++++++++++++++++++++++++++++++++++
find/defs.h | 14 ++++----
find/find.c | 69 +++++--------------------------------
find/finddata.c | 12 +-----
find/ftsfind.c | 49 ++-------------------------
find/parser.c | 35 ++++++------------
find/pred.c | 92 +++++++++++++++++++++++++++++++++-----------------
find/util.c | 89 +++++++++++++++++++++++++++++++++++++++---------
import-gnulib.config | 1 +
lib/dircallback.c | 36 +++++++++++++++++++-
lib/dircallback.h | 5 ++-
lib/listfile.c | 2 +-
12 files changed, 291 insertions(+), 196 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 34552d5..fefc1b8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,88 @@
2010-04-10 James Youngman <jay@gnu.org>
+ Exec predicates now store which directory they want to run in.
+ * lib/dircallback.c (run_in_dirfd): New name for old run_in_dir
+ function.
+ (run_in_dir): Like the old function of the same name, but now
+ takes an argument const struct saved_cwd *.
+ * lib/dircallback.h: Update declarations of run_in_dirfd and
+ run_in_dir.
+ * find/util.c: Include dircallback.h, xalloc.h, save-cwd.h.
+ (do_complete_pending_execdirs): Remove dir_fd parameter, since the
+ per-predicate data structures now indicate what directory they
+ need to be run in. Instead of calling bc_do_exec directly, use a
+ callback 'exec_cb' that uses run_in_dir (which now takes a
+ saved_cwd* parameter instead of a file descriptor).
+ (do_exec): Called by do_complete_pending_execdirs, and simply uses
+ run_in_dir to call exec_cb, restoring the working directory
+ afterward.
+ (record_initial_cwd): New function, initialises the global
+ variable initial_wd.
+ (cleanup_initial_cwd): New function, cleans up the global variable
+ initial_wd.
+ (cleanup): Call cleanup_initial_cwd.
+ (get_start_dirfd): Remove.
+ (is_exec_in_local_dir): New function; true for predicates -execdir
+ and -okdir.
+ * find/pred.c: Include save-cwd.h.
+ (record_exec_dir): New function, sets the value of
+ execp->wd_for_exec if needed.
+ (new_impl_pred_exec): Remove the obsolete dir_fd parameter. Call
+ record_exec_dir.
+ (pred_exec): Don't pass the dir_fd parameter.
+ (pred_execdir): Likewise.
+ (pred_ok): Likewise.
+ (pred_okdir): Likewise.
+ (can_access): Call run_in_dirfd rather than run_in_dir (the
+ function was renamed).
+ (prep_child_for_exec): Remove dir_fd parameter; don't fchdir to
+ that. Call restore_cwd instead (passing a saved_cwd* parameter
+ which replaced dir_fd).
+ (launch): Remove references to execp->use_current_dir.
+ (launch): Change references to execp->dir_fd to execp->wd_for_exec.
+ * find/parser.c: Correct indentiation of declaration of
+ insert_exec_ok and remove the obsolete dir_fd parameter.
+ (parse_exec): Don't pass the dir_fd parameter to insert_exec_ok.
+ (parse_execdir): Likewise.
+ (parse_ok): Likewise.
+ (parse_okdir): Likewise.
+ (insert_exec_ok): Remove obsolete dir_fd paramter. Initialise
+ execp->wd_for_exec, either to NULL (for -*dir) or to the
+ initial_wd.
+ * find/ftsfind.c: Remove get_current_dirfd. Remove
+ complete_execdirs_cb.
+ (consider_visiting): Call complete_pending_execdirs directly.
+ (main): Call record_initial_cwd to record the initial working
+ directory, early on. Don't initialise starting_dir or
+ starting_desc, they have been removed.
+ * find/finddata.c: Include save-cwd.h. Remove starting_dir and
+ starting_desc. Add new global variable initial_wd. It is a struct
+ saved_wd* and represents find's initial working directory.
+ * find/find.c: Include save-cwd.h.
+ (main): Call record_initial_cwd in order to initialise the
+ global variable initial_wd Don't set starting_desc and
+ starting_dir, since those variables have been removed.
+ (safely_chdir): Don't pass an fd to complete_pending_execdirs.
+ (chdir_back): Remove the safety check (since we are using fchdir
+ and in any case no longer have all the data that the existing
+ wd_sanity_check function wants).
+ (do_process_top_dir): Don't pass an fd to
+ complete_pending_execdirs.
+ (process_dir): Likewise.
+ * find/defs.h (struct exec_val): Remove use_current_dir and
+ dir_fd. Replace with wd_for_exec, which is a struct saved_wd*.
+ (get_start_dirfd): Remove prototype.
+ (get_current_dirfd): Remove prototype.
+ (complete_pending_execdirs): No longer takes dir_fd parameter.
+ (record_initial_cwd): Add prototype.
+ (is_exec_in_local_dir): Add prototype.
+ (options): Declare.
+ (initial_wd): Add declaration. It is a struct saved_wd* and
+ represents find's initial working directory.
+ (starting_dir): Remove declaration of global variable.
+ (starting_desc): Remove declaration of global variable.
+ * import-gnulib.config (modules): Import module save-cwd.
+
Add a test which checks $CWD for find -execdir {} +/;
* find/testsuite/find.gnu/execdir-multiple.exp: New test; verifies
that for -execdir +, all the execs occur with the correct working
diff --git a/find/defs.h b/find/defs.h
index 36d428d..b4c1339 100644
--- a/find/defs.h
+++ b/find/defs.h
@@ -196,9 +196,8 @@ struct exec_val
struct buildcmd_state state;
char **replace_vec; /* Command arguments (for ";" style) */
int num_args;
- boolean use_current_dir; /* If nonzero, don't chdir to start dir */
boolean close_stdin; /* If true, close stdin in the child. */
- int dir_fd; /* The directory to do the exec in. */
+ struct saved_cwd *wd_for_exec;/* What directory to perform the exec in. */
};
/* The format string for a -printf or -fprintf is chopped into one or
@@ -337,8 +336,6 @@ struct predicate
/* find.c, ftsfind.c */
boolean is_fts_enabled(int *ftsoptions);
-int get_start_dirfd(void);
-int get_current_dirfd(void);
/* find library function declarations. */
@@ -493,8 +490,11 @@ struct predicate *insert_primary_withpred PARAMS((const struct parser_table *ent
void usage PARAMS((FILE *fp, int status, char *msg));
extern boolean check_nofollow(void);
void complete_pending_execs(struct predicate *p);
-void complete_pending_execdirs(int dir_fd); /* Passing dir_fd is an unpleasant CodeSmell. */
+void complete_pending_execdirs(void);
const char *safely_quote_err_filename (int n, char const *arg);
+void record_initial_cwd (void);
+boolean is_exec_in_local_dir(const PRED_FUNC pred_func);
+
void fatal_file_error(const char *name) ATTRIBUTE_NORETURN;
void nonfatal_file_error(const char *name);
@@ -660,10 +660,10 @@ struct state
};
/* finddata.c */
+extern struct options options;
extern struct state state;
-extern char const *starting_dir;
-extern int starting_desc;
extern char *program_name;
+extern struct saved_cwd *initial_wd;
#endif
diff --git a/find/find.c b/find/find.c
index 171988f..badcf3c 100644
--- a/find/find.c
+++ b/find/find.c
@@ -52,6 +52,7 @@
#include "quotearg.h"
#include "xgetcwd.h"
#include "error.h"
+#include "save-cwd.h"
#ifdef HAVE_LOCALE_H
#include <locale.h>
@@ -131,6 +132,8 @@ main (int argc, char **argv)
program_name = argv[0];
state.exit_status = 0;
+ record_initial_cwd ();
+
/* Set the option defaults before we do the locale
* initialisation as check_nofollow() needs to be executed in the
* POSIX locale.
@@ -183,23 +186,6 @@ main (int argc, char **argv)
}
- starting_desc = open (".", O_RDONLY
-#if defined O_LARGEFILE
- |O_LARGEFILE
-#endif
- );
- if (0 <= starting_desc && fchdir (starting_desc) != 0)
- {
- close (starting_desc);
- starting_desc = -1;
- }
-
- if (starting_desc < 0)
- {
- starting_dir = xgetcwd ();
- if (! starting_dir)
- error (1, errno, _("cannot get current directory"));
- }
set_stat_placeholders(&starting_stat_buf);
if ((*options.xstat) (".", &starting_stat_buf) != 0)
error (1, errno, _("cannot stat current directory"));
@@ -876,7 +862,7 @@ safely_chdir(const char *dest,
* processed, do them now because they must be done in the same
* directory.
*/
- complete_pending_execdirs(get_current_dirfd());
+ complete_pending_execdirs ();
#if !defined(O_NOFOLLOW)
options.open_nofollow_available = false;
@@ -911,45 +897,10 @@ safely_chdir(const char *dest,
static void
chdir_back (void)
{
- struct stat stat_buf;
- boolean dummy;
-
- if (starting_desc < 0)
- {
- if (options.debug_options & DebugSearch)
- fprintf(stderr, "chdir_back(): chdir(\"%s\")\n", starting_dir);
-
-#ifdef STAT_MOUNTPOINTS
- /* We will need the mounted device list. Get it now if we don't
- * already have it.
- */
- if (NULL == mounted_devices)
- init_mounted_dev_list(1);
-#endif
-
- if (chdir (starting_dir) != 0)
- fatal_file_error(starting_dir);
-
- wd_sanity_check(starting_dir,
- program_name,
- starting_dir,
- starting_stat_buf.st_dev,
- starting_stat_buf.st_ino,
- &stat_buf, 0, __LINE__,
- TraversingUp,
- FATAL_IF_SANITY_CHECK_FAILS,
- &dummy);
- }
- else
- {
- if (options.debug_options & DebugSearch)
- fprintf(stderr, "chdir_back(): chdir(<starting-point>)\n");
+ if (options.debug_options & DebugSearch)
+ fprintf (stderr, "chdir_back(): chdir to start point\n");
- if (fchdir (starting_desc) != 0)
- {
- fatal_file_error(starting_dir);
- }
- }
+ restore_cwd (initial_wd);
}
/* Move to the parent of a given directory and then call a function,
@@ -1038,7 +989,7 @@ static void do_process_top_dir(char *pathname,
(void) pstat;
process_path (pathname, base, false, ".", mode);
- complete_pending_execdirs(get_current_dirfd());
+ complete_pending_execdirs ();
}
static void do_process_predicate(char *pathname,
@@ -1326,7 +1277,7 @@ process_dir (char *pathname, char *name, int pathlen, const struct stat *statp,
* yet been processed, do them now because they must be done in
* the same directory.
*/
- complete_pending_execdirs(get_current_dirfd());
+ complete_pending_execdirs ();
if (strcmp (name, "."))
{
@@ -1464,7 +1415,7 @@ process_dir (char *pathname, char *name, int pathlen, const struct stat *statp,
* yet been processed, do them now because they must be done in
* the same directory.
*/
- complete_pending_execdirs(get_current_dirfd());
+ complete_pending_execdirs ();
if (strcmp (name, "."))
{
diff --git a/find/finddata.c b/find/finddata.c
index 373eb38..dcc8261 100644
--- a/find/finddata.c
+++ b/find/finddata.c
@@ -19,6 +19,7 @@
#include <config.h>
#include "defs.h"
+#include "save-cwd.h"
/* Name this program was run with. */
@@ -26,13 +27,4 @@ char *program_name;
struct options options;
struct state state;
-
-/* The full path of the initial working directory, or "." if
- STARTING_DESC is nonnegative. */
-char const *starting_dir = ".";
-
-/* A file descriptor open to the initial working directory.
- Doing it this way allows us to work when the i.w.d. has
- unreadable parents. */
-int starting_desc;
-
+struct saved_cwd *initial_wd = NULL;
diff --git a/find/ftsfind.c b/find/ftsfind.c
index 838b81f..9945abd 100644
--- a/find/ftsfind.c
+++ b/find/ftsfind.c
@@ -98,24 +98,6 @@ static int ftsoptions = FTS_NOSTAT|FTS_TIGHT_CYCLE_CHECK;
static int prev_depth = INT_MIN; /* fts_level can be < 0 */
static int curr_fd = -1;
-int get_current_dirfd(void)
-{
- if (ftsoptions & FTS_CWDFD)
- {
- assert (curr_fd != -1);
- assert ( (AT_FDCWD == curr_fd) || (curr_fd >= 0) );
-
- if (AT_FDCWD == curr_fd)
- return starting_desc;
- else
- return curr_fd;
- }
- else
- {
- return AT_FDCWD;
- }
-}
-
static void left_dir(void)
{
if (ftsoptions & FTS_CWDFD)
@@ -324,15 +306,6 @@ symlink_loop(const char *name)
}
-static int
-complete_execdirs_cb(void *context)
-{
- (void) context;
- /* By the tme this callback is called, the current directory is correct. */
- complete_pending_execdirs(AT_FDCWD);
- return 0;
-}
-
static void
show_outstanding_execdirs(FILE *fp)
{
@@ -566,7 +539,7 @@ consider_visiting(FTS *p, FTSENT *ent)
if (state.execdirs_outstanding)
{
show_outstanding_execdirs(stderr);
- run_in_dir(p->fts_cwd_fd, complete_execdirs_cb, NULL);
+ complete_pending_execdirs ();
}
if (ent->fts_info == FTS_DP)
@@ -670,6 +643,8 @@ main (int argc, char **argv)
state.execdirs_outstanding = false;
state.cwd_dir_fd = AT_FDCWD;
+ record_initial_cwd ();
+
/* Set the option defaults before we do the locale initialisation as
* check_nofollow() needs to be executed in the POSIX locale.
*/
@@ -719,24 +694,6 @@ main (int argc, char **argv)
}
- starting_desc = open (".", O_RDONLY
-#if defined O_LARGEFILE
- |O_LARGEFILE
-#endif
- );
- if (0 <= starting_desc && fchdir (starting_desc) != 0)
- {
- close (starting_desc);
- starting_desc = -1;
- }
- if (starting_desc < 0)
- {
- starting_dir = xgetcwd ();
- if (! starting_dir)
- error (1, errno, _("cannot get current directory"));
- }
-
-
process_all_startpoints(argc-end_of_leading_options, argv+end_of_leading_options);
/* If "-exec ... {} +" has been used, there may be some
diff --git a/find/parser.c b/find/parser.c
index 3f237eb..b96d317 100644
--- a/find/parser.c
+++ b/find/parser.c
@@ -181,7 +181,6 @@ static struct segment **make_segment PARAMS((struct segment **segment,
struct predicate *pred));
static boolean insert_exec_ok PARAMS((const char *action,
const struct parser_table *entry,
- int dir_fd,
char *argv[],
int *arg_ptr));
static boolean get_comp_type PARAMS((const char **str,
@@ -928,13 +927,13 @@ parse_empty (const struct parser_table* entry, char **argv, int *arg_ptr)
static boolean
parse_exec (const struct parser_table* entry, char **argv, int *arg_ptr)
{
- return insert_exec_ok ("-exec", entry, get_start_dirfd(), argv, arg_ptr);
+ return insert_exec_ok ("-exec", entry, argv, arg_ptr);
}
static boolean
parse_execdir (const struct parser_table* entry, char **argv, int *arg_ptr)
{
- return insert_exec_ok ("-execdir", entry, -1, argv, arg_ptr);
+ return insert_exec_ok ("-execdir", entry, argv, arg_ptr);
}
static boolean
@@ -1790,13 +1789,13 @@ parse_nowarn (const struct parser_table* entry, char **argv, int *arg_ptr)
static boolean
parse_ok (const struct parser_table* entry, char **argv, int *arg_ptr)
{
- return insert_exec_ok ("-ok", entry, get_start_dirfd(), argv, arg_ptr);
+ return insert_exec_ok ("-ok", entry, argv, arg_ptr);
}
static boolean
parse_okdir (const struct parser_table* entry, char **argv, int *arg_ptr)
{
- return insert_exec_ok ("-okdir", entry, -1, argv, arg_ptr);
+ return insert_exec_ok ("-okdir", entry, argv, arg_ptr);
}
boolean
@@ -3158,11 +3157,10 @@ check_path_safety(const char *action, char **argv)
/* handles both exec and ok predicate */
static boolean
-new_insert_exec_ok (const char *action,
- const struct parser_table *entry,
- int dir_fd,
- char **argv,
- int *arg_ptr)
+insert_exec_ok (const char *action,
+ const struct parser_table *entry,
+ char **argv,
+ int *arg_ptr)
{
int start, end; /* Indexes in ARGV of start & end of cmd. */
int i; /* Index into cmd args */
@@ -3183,6 +3181,7 @@ new_insert_exec_ok (const char *action,
our_pred->need_type = our_pred->need_stat = false;
execp = &our_pred->args.exec_vec;
+ execp->wd_for_exec = NULL;
if ((func != pred_okdir) && (func != pred_ok))
{
@@ -3202,13 +3201,14 @@ new_insert_exec_ok (const char *action,
if ((func == pred_execdir) || (func == pred_okdir))
{
+ execp->wd_for_exec = NULL;
options.ignore_readdir_race = false;
check_path_safety(action, argv);
- execp->use_current_dir = true;
}
else
{
- execp->use_current_dir = false;
+ assert (NULL != initial_wd);
+ execp->wd_for_exec = initial_wd;
}
our_pred->args.exec_vec.multiple = 0;
@@ -3361,17 +3361,6 @@ new_insert_exec_ok (const char *action,
-static boolean
-insert_exec_ok (const char *action,
- const struct parser_table *entry,
- int dir_fd,
- char **argv,
- int *arg_ptr)
-{
- return new_insert_exec_ok(action, entry, dir_fd, argv, arg_ptr);
-}
-
-
/* Get a timestamp and comparison type.
diff --git a/find/pred.c b/find/pred.c
index 7c34119..d057d48 100644
--- a/find/pred.c
+++ b/find/pred.c
@@ -47,6 +47,7 @@
#include "dircallback.h"
#include "error.h"
#include "verify.h"
+#include "save-cwd.h"
#include <selinux/selinux.h>
@@ -502,8 +503,30 @@ pred_empty (const char *pathname, struct stat *stat_buf, struct predicate *pred_
return (false);
}
+
static boolean
-new_impl_pred_exec (int dir_fd, const char *pathname,
+record_exec_dir (struct exec_val *execp)
+{
+ if (!execp->wd_for_exec)
+ {
+ /* working directory not already known, so must be a *dir variant,
+ and this must be the first arg we added. However, this may
+ be -execdir foo {} \; (i.e. not multiple). */
+ assert (!execp->state.todo);
+
+ /* Record the WD. */
+ execp->wd_for_exec = xmalloc (sizeof (*execp->wd_for_exec));
+ execp->wd_for_exec->name = NULL;
+ execp->wd_for_exec->desc = openat (state.cwd_dir_fd, ".", O_RDONLY);
+ if (execp->wd_for_exec->desc < 0)
+ return false;
+ }
+ return true;
+}
+
+
+static boolean
+new_impl_pred_exec (const char *pathname,
struct stat *stat_buf,
struct predicate *pred_ptr,
const char *prefix, size_t pfxlen)
@@ -512,7 +535,32 @@ new_impl_pred_exec (int dir_fd, const char *pathname,
size_t len = strlen(pathname);
(void) stat_buf;
- execp->dir_fd = dir_fd;
+
+ if (is_exec_in_local_dir (pred_ptr->pred_func))
+ {
+ /* For -execdir/-okdir predicates, the parser did not fill in
+ the wd_for_exec member of sturct exec_val. So for those
+ predicates, we do so now.
+ */
+ if (!record_exec_dir (execp))
+ {
+ error (EXIT_FAILURE, errno,
+ _("Failed to save working directory in order to "
+ "run a command on %s"),
+ safely_quote_err_filename (0, pathname));
+ /*NOTREACHED*/
+ }
+ }
+ else
+ {
+ /* For the others (-exec, -ok), the parser should
+ have set wd_for_exec to initial_wd, indicating
+ that the exec should take place from find's initial
+ working directory.
+ */
+ assert (execp->wd_for_exec == initial_wd);
+ }
+
if (execp->multiple)
{
/* Push the argument onto the current list.
@@ -558,8 +606,7 @@ new_impl_pred_exec (int dir_fd, const char *pathname,
boolean
pred_exec (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
{
- return new_impl_pred_exec(get_start_dirfd(),
- pathname, stat_buf, pred_ptr, NULL, 0);
+ return new_impl_pred_exec(pathname, stat_buf, pred_ptr, NULL, 0);
}
boolean
@@ -567,8 +614,7 @@ pred_execdir (const char *pathname, struct stat *stat_buf, struct predicate *pre
{
const char *prefix = (state.rel_pathname[0] == '/') ? NULL : "./";
(void) &pathname;
- return new_impl_pred_exec (get_current_dirfd(),
- state.rel_pathname, stat_buf, pred_ptr,
+ return new_impl_pred_exec (state.rel_pathname, stat_buf, pred_ptr,
prefix, (prefix ? 2 : 0));
}
@@ -1460,8 +1506,7 @@ boolean
pred_ok (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
{
if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname))
- return new_impl_pred_exec (get_start_dirfd(),
- pathname, stat_buf, pred_ptr, NULL, 0);
+ return new_impl_pred_exec (pathname, stat_buf, pred_ptr, NULL, 0);
else
return false;
}
@@ -1471,8 +1516,7 @@ pred_okdir (const char *pathname, struct stat *stat_buf, struct predicate *pred_
{
const char *prefix = (state.rel_pathname[0] == '/') ? NULL : "./";
if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname))
- return new_impl_pred_exec (get_current_dirfd(),
- state.rel_pathname, stat_buf, pred_ptr,
+ return new_impl_pred_exec (state.rel_pathname, stat_buf, pred_ptr,
prefix, (prefix ? 2 : 0));
else
return false;
@@ -1573,7 +1617,7 @@ can_access(int access_type)
args.filename = state.rel_pathname;
args.access_type = access_type;
args.cb_errno = 0;
- return 0 == run_in_dir(state.cwd_dir_fd, access_callback, &args);
+ return 0 == run_in_dirfd (state.cwd_dir_fd, access_callback, &args);
}
@@ -1912,7 +1956,7 @@ pred_context (const char *pathname, struct stat *stat_buf,
static boolean
-prep_child_for_exec (boolean close_stdin, int dir_fd)
+prep_child_for_exec (boolean close_stdin, const struct saved_cwd *wd)
{
boolean ok = true;
if (close_stdin)
@@ -1948,17 +1992,10 @@ prep_child_for_exec (boolean close_stdin, int dir_fd)
* announcement of a call to stat() anyway, as we're about to exec
* something.
*/
- if (dir_fd != AT_FDCWD)
+ if (0 != restore_cwd (wd))
{
- assert (dir_fd >= 0);
- if (0 != fchdir(dir_fd))
- {
- /* If we cannot execute our command in the correct directory,
- * we should not execute it at all.
- */
- error(0, errno, _("Failed to change directory"));
- ok = false;
- }
+ error (0, errno, _("Failed to change directory"));
+ ok = false;
}
return ok;
}
@@ -1974,13 +2011,6 @@ launch (const struct buildcmd_control *ctl,
static int first_time = 1;
const struct exec_val *execp = buildstate->usercontext;
- if (!execp->use_current_dir)
- {
- assert (starting_desc >= 0);
- assert (execp->dir_fd == starting_desc);
- }
-
-
/* Null terminate the arg list. */
bc_push_arg (ctl, buildstate, (char *) NULL, 0, NULL, 0, false);
@@ -2001,8 +2031,8 @@ launch (const struct buildcmd_control *ctl,
if (child_pid == 0)
{
/* We are the child. */
- assert (starting_desc >= 0);
- if (!prep_child_for_exec(execp->close_stdin, execp->dir_fd))
+ assert (NULL != execp->wd_for_exec);
+ if (!prep_child_for_exec (execp->close_stdin, execp->wd_for_exec))
{
_exit(1);
}
diff --git a/find/util.c b/find/util.c
index d3cb467..da4fc62 100644
--- a/find/util.c
+++ b/find/util.c
@@ -36,6 +36,9 @@
#include "error.h"
#include "verify.h"
#include "openat.h"
+#include "dircallback.h"
+#include "xalloc.h"
+#include "save-cwd.h"
#if ENABLE_NLS
# include <libintl.h>
@@ -282,6 +285,26 @@ check_nofollow(void)
#endif
+static int
+exec_cb (void *context)
+{
+ struct exec_val *execp = context;
+ launch (&execp->ctl, &execp->state);
+ return 0;
+}
+
+static void
+do_exec (struct exec_val *execp)
+{
+ run_in_dir (execp->wd_for_exec, exec_cb, execp);
+ if (execp->wd_for_exec != initial_wd)
+ {
+ free_cwd (execp->wd_for_exec);
+ free (execp->wd_for_exec);
+ execp->wd_for_exec = NULL;
+ }
+}
+
/* Examine the predicate list for instances of -execdir or -okdir
* which have been terminated with '+' (build argument list) rather
@@ -289,14 +312,14 @@ check_nofollow(void)
* have no effect if there are no arguments waiting).
*/
static void
-do_complete_pending_execdirs(struct predicate *p, int dir_fd)
+do_complete_pending_execdirs(struct predicate *p)
{
if (NULL == p)
return;
assert (state.execdirs_outstanding);
- do_complete_pending_execdirs(p->pred_left, dir_fd);
+ do_complete_pending_execdirs(p->pred_left);
if (pred_is(p, pred_execdir) || pred_is(p, pred_okdir))
{
@@ -311,25 +334,24 @@ do_complete_pending_execdirs(struct predicate *p, int dir_fd)
if (execp->state.todo)
{
/* There are not-yet-executed arguments. */
- launch (&execp->ctl, &execp->state);
+ do_exec (execp);
}
}
}
- do_complete_pending_execdirs(p->pred_right, dir_fd);
+ do_complete_pending_execdirs(p->pred_right);
}
void
-complete_pending_execdirs(int dir_fd)
+complete_pending_execdirs (void)
{
if (state.execdirs_outstanding)
{
- do_complete_pending_execdirs(get_eval_tree(), dir_fd);
+ do_complete_pending_execdirs(get_eval_tree());
state.execdirs_outstanding = false;
}
}
-
/* Examine the predicate list for instances of -exec which have been
* terminated with '+' (build argument list) rather than ';' (singles
@@ -365,6 +387,37 @@ complete_pending_execs(struct predicate *p)
complete_pending_execs(p->pred_right);
}
+
+void
+record_initial_cwd (void)
+{
+ initial_wd = xmalloc (sizeof (*initial_wd));
+ if (0 != save_cwd (initial_wd))
+ {
+ error (EXIT_FAILURE, errno,
+ _("failed to save initial working directory"));
+ }
+}
+
+static void
+cleanup_initial_cwd (void)
+{
+ if (0 == restore_cwd (initial_wd))
+ {
+ free_cwd (initial_wd);
+ free (initial_wd);
+ initial_wd = NULL;
+ }
+ else
+ {
+ /* since we may already be in atexit, die with _exit(). */
+ error (0, errno,
+ _("failed to restore initial working directory"));
+ _exit (EXIT_FAILURE);
+ }
+}
+
+
static void
traverse_tree(struct predicate *tree,
@@ -424,9 +477,11 @@ cleanup(void)
if (eval_tree)
{
traverse_tree(eval_tree, complete_pending_execs);
- complete_pending_execdirs(get_current_dirfd());
+ complete_pending_execdirs ();
traverse_tree(eval_tree, flush_and_close_output_files);
}
+
+ cleanup_initial_cwd ();
}
/* Savannah bug #16378 manifests as an assertion failure in pred_type()
@@ -963,15 +1018,6 @@ set_option_defaults(struct options *p)
}
-/* get_start_dirfd
- *
- * Returns the fd for the directory we started in.
- */
-int get_start_dirfd(void)
-{
- return starting_desc;
-}
-
/* apply_predicate
*
*/
@@ -997,6 +1043,15 @@ apply_predicate(const char *pathname, struct stat *stat_buf, struct predicate *p
}
}
+/* is_exec_in_local_dir
+ *
+ */
+bool
+is_exec_in_local_dir (const PRED_FUNC pred_func)
+{
+ return pred_execdir == pred_func || pred_okdir == pred_func;
+}
+
/* safely_quote_err_filename
*
diff --git a/import-gnulib.config b/import-gnulib.config
index f2e8998..b1f0851 100644
--- a/import-gnulib.config
+++ b/import-gnulib.config
@@ -67,6 +67,7 @@ quotearg
realloc
regex
rpmatch
+save-cwd
savedir
stat-macros
stat-time
diff --git a/lib/dircallback.c b/lib/dircallback.c
index 5dbf3b3..f96fccc 100644
--- a/lib/dircallback.c
+++ b/lib/dircallback.c
@@ -54,7 +54,41 @@
int
-run_in_dir (int dir_fd, int (*callback)(void*), void *usercontext)
+run_in_dir (const struct saved_cwd *there,
+ int (*callback)(void*), void *usercontext)
+{
+ int err = -1;
+ int saved_errno = 0;
+ struct saved_cwd here;
+ if (0 == save_cwd (&here))
+ {
+ if (0 == restore_cwd (there))
+ {
+ err = callback(usercontext);
+ saved_errno = (err < 0 ? errno : 0);
+ }
+ else
+ {
+ openat_restore_fail (errno);
+ }
+
+ if (restore_cwd (&here) != 0)
+ openat_restore_fail (errno);
+
+ free_cwd (&here);
+ }
+ else
+ {
+ openat_save_fail (errno);
+ }
+ if (saved_errno)
+ errno = saved_errno;
+ return err;
+}
+
+
+int
+run_in_dirfd (int dir_fd, int (*callback)(void*), void *usercontext)
{
if (dir_fd == AT_FDCWD)
{
diff --git a/lib/dircallback.h b/lib/dircallback.h
index 41ea282..3234113 100644
--- a/lib/dircallback.h
+++ b/lib/dircallback.h
@@ -19,6 +19,9 @@
#if !defined DIRCALLBACK_H
# define DIRCALLBACK_H
-int run_in_dir (int dir_fd, int (*callback)(void*), void *usercontext);
+struct saved_cwd;
+
+int run_in_dirfd (int fd, int (*callback)(void*), void *usercontext);
+int run_in_dir (struct saved_cwd*, int (*callback)(void*), void *usercontext);
#endif
diff --git a/lib/listfile.c b/lib/listfile.c
index ca9eae2..b5bee54 100644
--- a/lib/listfile.c
+++ b/lib/listfile.c
@@ -424,7 +424,7 @@ get_link_name_at (const char *name, int dir_fd, char *relname)
args.result = NULL;
args.name = name;
args.relname = relname;
- if (0 == run_in_dir(dir_fd, get_link_name_cb, &args))
+ if (0 == run_in_dirfd (dir_fd, get_link_name_cb, &args))
return args.result;
else
return NULL;

View File

@ -0,0 +1,107 @@
ChangeLog | 10 ++++++++++
NEWS | 15 +++++++++++++++
find/ftsfind.c | 37 +++++++++++++++++++------------------
3 files changed, 44 insertions(+), 18 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index fefc1b8..98d7962 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
2010-04-10 James Youngman <jay@gnu.org>
+ Fix Savannah bug #19593, -execdir .... {} + has suboptimal performance
+ * find/ftsfind.c (consider_visiting): Don't call
+ complete_pending_execdirs for every file we visit.
+ (find): Instead, call complete_pending_execdirs every time we
+ see a file which isn't at the same nesting level as the previous
+ file we saw. This is an improvement but not optimal (since
+ descending into a subdirectory will cause us to issue an exec
+ before we've finished with the current directory).
+ * NEWS: Mention this change.
+
Exec predicates now store which directory they want to run in.
* lib/dircallback.c (run_in_dirfd): New name for old run_in_dir
function.
diff --git a/NEWS b/NEWS
index 6b8b725..569ff51 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,20 @@
GNU findutils NEWS - User visible changes. -*- outline -*- (allout)
+* Major changes in release 4.4.3-git, YYYY-MM-DD
+
+** Bug Fixes
+
+#19593: -execdir .... {} + has suboptimal performance (see below)
+
+** Performance changes
+
+The find program will once again build argument lists longer than 1
+with "-execdir ...+". The upper limit of 1 argument for execdir was
+introduced as a workaround in findutils-4.3.4. The limit is now
+removed, but find still does not issue the maximum possible number of
+arguments, since an exec will occur each time find encounters a
+subdirectory (if at least one argument is pending).
+
* Major changes in release 4.4.2, 2009-11-26
** Functional Enhancements to find
diff --git a/find/ftsfind.c b/find/ftsfind.c
index 9945abd..3c9ae1d 100644
--- a/find/ftsfind.c
+++ b/find/ftsfind.c
@@ -524,24 +524,6 @@ consider_visiting(FTS *p, FTSENT *ent)
visit(p, ent, &statbuf);
}
- /* XXX: if we allow a build-up of pending arguments for "-execdir foo {} +"
- * we need to execute them in the same directory as we found the item.
- * If we are trying to do "find a -execdir echo {} +", we will need to
- * echo
- * a while in the original working directory
- * b while in a
- * c while in b (just before leaving b)
- *
- * These restrictions are hard to satisfy while using fts(). The reason is
- * that it doesn't tell us just before we leave a directory. For the moment,
- * we punt and don't allow the arguments to build up.
- */
- if (state.execdirs_outstanding)
- {
- show_outstanding_execdirs(stderr);
- complete_pending_execdirs ();
- }
-
if (ent->fts_info == FTS_DP)
{
/* we're leaving a directory. */
@@ -591,8 +573,27 @@ find(char *arg)
}
else
{
+ int level = INT_MIN;
+
while ( (ent=fts_read(p)) != NULL )
{
+ if (state.execdirs_outstanding)
+ {
+ /* If we changed level, perform any outstanding
+ * execdirs. If we see a sequence of directory entries
+ * like this: fffdfffdfff, we could build a command line
+ * of 9 files, but this simple-minded implementation
+ * builds a command line for only 3 files at a time
+ * (since fts descends into the directories).
+ */
+ if ((int)ent->fts_level != level)
+ {
+ show_outstanding_execdirs (stderr);
+ complete_pending_execdirs ();
+ }
+ }
+ level = (int)ent->fts_level;
+
state.have_stat = false;
state.have_type = false;
state.type = 0;

View File

@ -0,0 +1,277 @@
ChangeLog | 21 +++++++++
NEWS | 2 +
find/pred.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++-----------
3 files changed, 132 insertions(+), 24 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 98d7962..8e5d0ce 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2010-04-11 James Youngman <jay@gnu.org>
+
+ Fix Savannah bug #27563, -L breaks -execdir.
+ * find/pred.c (mdir_name): New function, taken from newer gnulib.
+ (initialise_wd_for_exec): New function, factoring out part of the body
+ of record_exec_dir.
+ (record_exec_dir): If state.rel_pathname contains a /, extract the
+ directory part and initialise execp->wd_for_exec to point at that
+ directory.
+ (impl_pred_exec): Rename new_impl_pred_exec to impl_pred_exec.
+ Drop the prefix and pfxlen parameters. Compute the base name of
+ the target and pass that to the bc_push_arg function instead of
+ state.rel_pathname. Deal with state.rel_pathname being an
+ absolute path (e.g. find / -execdir...). Introduce a new
+ variable, result, allowing us to free the buffer used for the base
+ name in the return path.
+ (pred_exec): Don't pass the prefix and the prefix length any more.
+ (pred_execdir): Likewise.
+ (pred_ok): Likewise.
+ (pred_okdir): Likewise.
+
2010-04-10 James Youngman <jay@gnu.org>
Fix Savannah bug #19593, -execdir .... {} + has suboptimal performance
diff --git a/NEWS b/NEWS
index 569ff51..c8eb0bc 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,8 @@ GNU findutils NEWS - User visible changes. -*- outline -*- (allout)
** Bug Fixes
+#27563: -L breaks -execdir
+
#19593: -execdir .... {} + has suboptimal performance (see below)
** Performance changes
diff --git a/find/pred.c b/find/pred.c
index d057d48..cf25184 100644
--- a/find/pred.c
+++ b/find/pred.c
@@ -504,6 +504,57 @@ pred_empty (const char *pathname, struct stat *stat_buf, struct predicate *pred_
}
+/* In general, we can't use the builtin `dirname' function if available,
+ since it has different meanings in different environments.
+ In some environments the builtin `dirname' modifies its argument.
+
+ Return the leading directories part of FILE, allocated with malloc.
+ Works properly even if there are trailing slashes (by effectively
+ ignoring them). Return NULL on failure.
+
+ If lstat (FILE) would succeed, then { chdir (dir_name (FILE));
+ lstat (base_name (FILE)); } will access the same file. Likewise,
+ if the sequence { chdir (dir_name (FILE));
+ rename (base_name (FILE), "foo"); } succeeds, you have renamed FILE
+ to "foo" in the same directory FILE was in. */
+
+static char *
+mdir_name (char const *file)
+{
+ size_t length = dir_len (file);
+ bool append_dot = (length == 0
+ || (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
+ && length == FILE_SYSTEM_PREFIX_LEN (file)
+ && file[2] != '\0' && ! ISSLASH (file[2])));
+ char *dir = malloc (length + append_dot + 1);
+ if (!dir)
+ return NULL;
+ memcpy (dir, file, length);
+ if (append_dot)
+ dir[length++] = '.';
+ dir[length] = '\0';
+ return dir;
+}
+
+
+/* Initialise exec->wd_for_exec.
+
+ We save in exec->wd_for_exec the directory whose path relative to
+ cwd_df is dir.
+ */
+static boolean
+initialise_wd_for_exec (struct exec_val *execp, int cwd_fd, const char *dir)
+{
+ execp->wd_for_exec = xmalloc (sizeof (*execp->wd_for_exec));
+ execp->wd_for_exec->name = NULL;
+ execp->wd_for_exec->desc = openat (cwd_fd, dir, O_RDONLY);
+ if (execp->wd_for_exec->desc < 0)
+ return false;
+
+ return true;
+}
+
+
static boolean
record_exec_dir (struct exec_val *execp)
{
@@ -514,29 +565,46 @@ record_exec_dir (struct exec_val *execp)
be -execdir foo {} \; (i.e. not multiple). */
assert (!execp->state.todo);
- /* Record the WD. */
- execp->wd_for_exec = xmalloc (sizeof (*execp->wd_for_exec));
- execp->wd_for_exec->name = NULL;
- execp->wd_for_exec->desc = openat (state.cwd_dir_fd, ".", O_RDONLY);
- if (execp->wd_for_exec->desc < 0)
- return false;
+ /* Record the WD. If we're using -L or fts chooses to do so for
+ any other reason, state.cwd_dir_fd may in fact not be the
+ directory containing the target file. When this happens,
+ rel_path will contain directory components (since it is the
+ path from state.cwd_dir_fd to the target file).
+
+ We deal with this by extracting any directory part and using
+ that to adjust what goes into execp->wd_for_exec.
+ */
+ if (strchr (state.rel_pathname, '/'))
+ {
+ char *dir = mdir_name (state.rel_pathname);
+ bool result = initialise_wd_for_exec (execp, state.cwd_dir_fd, dir);
+ free (dir);
+ return result;
+ }
+ else
+ {
+ return initialise_wd_for_exec (execp, state.cwd_dir_fd, ".");
+ }
}
return true;
}
static boolean
-new_impl_pred_exec (const char *pathname,
- struct stat *stat_buf,
- struct predicate *pred_ptr,
- const char *prefix, size_t pfxlen)
+impl_pred_exec (const char *pathname,
+ struct stat *stat_buf,
+ struct predicate *pred_ptr)
{
struct exec_val *execp = &pred_ptr->args.exec_vec;
- size_t len = strlen(pathname);
+ char *target;
+ bool result;
+ const bool local = is_exec_in_local_dir (pred_ptr->pred_func);
+ char *prefix;
+ size_t pfxlen;
(void) stat_buf;
- if (is_exec_in_local_dir (pred_ptr->pred_func))
+ if (local)
{
/* For -execdir/-okdir predicates, the parser did not fill in
the wd_for_exec member of sturct exec_val. So for those
@@ -550,6 +618,18 @@ new_impl_pred_exec (const char *pathname,
safely_quote_err_filename (0, pathname));
/*NOTREACHED*/
}
+ target = base_name (state.rel_pathname);
+ if ('/' == target[0])
+ {
+ /* find / execdir ls -d {} \; */
+ prefix = NULL;
+ pfxlen = 0;
+ }
+ else
+ {
+ prefix = "./";
+ pfxlen = 2u;
+ }
}
else
{
@@ -559,6 +639,9 @@ new_impl_pred_exec (const char *pathname,
working directory.
*/
assert (execp->wd_for_exec == initial_wd);
+ target = (char *) pathname;
+ prefix = NULL;
+ pfxlen = 0u;
}
if (execp->multiple)
@@ -569,7 +652,7 @@ new_impl_pred_exec (const char *pathname,
*/
bc_push_arg(&execp->ctl,
&execp->state,
- pathname, len+1,
+ target, strlen (target)+1,
prefix, pfxlen,
0);
@@ -579,7 +662,7 @@ new_impl_pred_exec (const char *pathname,
/* POSIX: If the primary expression is punctuated by a plus
* sign, the primary shall always evaluate as true
*/
- return true;
+ result = true;
}
else
{
@@ -592,30 +675,34 @@ new_impl_pred_exec (const char *pathname,
execp->replace_vec[i],
strlen(execp->replace_vec[i]),
prefix, pfxlen,
- pathname, len,
+ target, strlen (target),
0);
}
/* Actually invoke the command. */
- return execp->ctl.exec_callback(&execp->ctl,
+ result = execp->ctl.exec_callback(&execp->ctl,
&execp->state);
}
+ if (target != pathname)
+ {
+ assert (local);
+ free (target);
+ }
+ return result;
}
boolean
pred_exec (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
{
- return new_impl_pred_exec(pathname, stat_buf, pred_ptr, NULL, 0);
+ return impl_pred_exec(pathname, stat_buf, pred_ptr);
}
boolean
pred_execdir (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
{
- const char *prefix = (state.rel_pathname[0] == '/') ? NULL : "./";
(void) &pathname;
- return new_impl_pred_exec (state.rel_pathname, stat_buf, pred_ptr,
- prefix, (prefix ? 2 : 0));
+ return impl_pred_exec (state.rel_pathname, stat_buf, pred_ptr);
}
boolean
@@ -1506,7 +1593,7 @@ boolean
pred_ok (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
{
if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname))
- return new_impl_pred_exec (pathname, stat_buf, pred_ptr, NULL, 0);
+ return impl_pred_exec (pathname, stat_buf, pred_ptr);
else
return false;
}
@@ -1514,10 +1601,8 @@ pred_ok (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr
boolean
pred_okdir (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
{
- const char *prefix = (state.rel_pathname[0] == '/') ? NULL : "./";
if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname))
- return new_impl_pred_exec (state.rel_pathname, stat_buf, pred_ptr,
- prefix, (prefix ? 2 : 0));
+ return impl_pred_exec (state.rel_pathname, stat_buf, pred_ptr);
else
return false;
}

View File

@ -0,0 +1,103 @@
ChangeLog | 11 +++++++++++
find/testsuite/Makefile.am | 4 ++++
find/testsuite/find.gnu/sv-bug-27563-execdir.exp | 6 ++++++
find/testsuite/find.gnu/sv-bug-27563-execdir.xo | 1 +
find/testsuite/find.posix/sv-bug-27563-exec.exp | 6 ++++++
find/testsuite/find.posix/sv-bug-27563-exec.xo | 1 +
6 files changed, 29 insertions(+), 0 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 8e5d0ce..5702e66 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
2010-04-11 James Youngman <jay@gnu.org>
+ Add a test case for Savannah bug 27563 (-L breaks -execdir).
+ * find/testsuite/Makefile.am (EXTRA_DIST_EXP): Add
+ find.gnu/sv-bug-27563-execdir.exp and
+ find.posix/sv-bug-27563-exec.exp.
+ (EXTRA_DIST_XO): Add find.gnu/sv-bug-27563-execdir.xo and
+ find.posix/sv-bug-27563-exec.xo.
+ * find/testsuite/find.gnu/sv-bug-27563-execdir.exp: New test.
+ * find/testsuite/find.posix/sv-bug-27563-exec.exp: New test.
+ * find/testsuite/find.gnu/sv-bug-27563-execdir.xo: Expected output.
+ * find/testsuite/find.posix/sv-bug-27563-exec.xo: Expected output.
+
Fix Savannah bug #27563, -L breaks -execdir.
* find/pred.c (mdir_name): New function, taken from newer gnulib.
(initialise_wd_for_exec): New function, factoring out part of the body
diff --git a/find/testsuite/Makefile.am b/find/testsuite/Makefile.am
index 1447132..aa32d4b 100644
--- a/find/testsuite/Makefile.am
+++ b/find/testsuite/Makefile.am
@@ -63,6 +63,7 @@ find.gnu/samefile-same.xo \
find.gnu/samefile-symlink.xo \
find.gnu/sv-bug-17782.xo \
find.gnu/sv-bug-18222.xo \
+find.gnu/sv-bug-27563-execdir.xo \
find.gnu/true.xo \
find.gnu/wholename.xo \
find.gnu/xtype-symlink.xo \
@@ -78,6 +79,7 @@ find.posix/grouping.xo \
find.posix/links.xo \
find.posix/sv-bug-11175.xo \
find.posix/sv-bug-12181.xo \
+find.posix/sv-bug-27563-exec.xo \
find.posix/depth1.xo \
find.posix/mtime0.xo \
find.posix/sizes.xo \
@@ -179,6 +181,7 @@ find.gnu/sv-bug-17490.exp \
find.gnu/sv-bug-17782.exp \
find.gnu/sv-bug-18222.exp \
find.gnu/sv-bug-24169.exp \
+find.gnu/sv-bug-27563-execdir.exp \
find.gnu/quit.exp \
find.gnu/used-invarg.exp \
find.gnu/used-missing.exp \
@@ -199,6 +202,7 @@ find.posix/links.exp \
find.posix/mtime0.exp \
find.posix/sv-bug-11175.exp \
find.posix/sv-bug-12181.exp \
+find.posix/sv-bug-27563-exec.exp \
find.posix/depth1.exp \
find.posix/sizes.exp \
find.posix/name.exp \
diff --git a/find/testsuite/find.gnu/sv-bug-27563-execdir.exp b/find/testsuite/find.gnu/sv-bug-27563-execdir.exp
new file mode 100644
index 0000000..c67fc88
--- /dev/null
+++ b/find/testsuite/find.gnu/sv-bug-27563-execdir.exp
@@ -0,0 +1,6 @@
+# tests for Savannah bug 27563 (result of find -L -exec ls {} \;)
+exec rm -rf tmp
+exec mkdir tmp
+exec touch tmp/yyyy
+find_start p {-L tmp -name yyyy -execdir ls \{\} \; }
+exec rm -rf tmp
diff --git a/find/testsuite/find.gnu/sv-bug-27563-execdir.xo b/find/testsuite/find.gnu/sv-bug-27563-execdir.xo
new file mode 100644
index 0000000..285260b
--- /dev/null
+++ b/find/testsuite/find.gnu/sv-bug-27563-execdir.xo
@@ -0,0 +1 @@
+./yyyy
diff --git a/find/testsuite/find.posix/sv-bug-27563-exec.exp b/find/testsuite/find.posix/sv-bug-27563-exec.exp
new file mode 100644
index 0000000..d18b0c1
--- /dev/null
+++ b/find/testsuite/find.posix/sv-bug-27563-exec.exp
@@ -0,0 +1,6 @@
+# tests for Savannah bug 27563 (result of find -L -exec ls {} \;)
+exec rm -rf tmp
+exec mkdir tmp
+exec touch tmp/yyyy
+find_start p {-L tmp -name yyyy -exec ls \{\} \; }
+exec rm -rf tmp
diff --git a/find/testsuite/find.posix/sv-bug-27563-exec.xo b/find/testsuite/find.posix/sv-bug-27563-exec.xo
new file mode 100644
index 0000000..cd491dd
--- /dev/null
+++ b/find/testsuite/find.posix/sv-bug-27563-exec.xo
@@ -0,0 +1 @@
+tmp/yyyy

View File

@ -0,0 +1,70 @@
ChangeLog | 9 +++++++++
NEWS | 2 ++
find/pred.c | 10 ++++------
find/testsuite/find.gnu/execdir-multiple.exp | 1 +
4 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 5702e66..97b1b7c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2010-05-24 Kamil Dudka <kdudka@redhat.com>
+
+ Fix Savannah bug #29949, -execdir does not change working directory
+ * find/pred.c (record_exec_dir): Do not throw the execdir when not
+ working in the cumulative mode.
+ * find/testsuite/find.gnu/execdir-multiple.exp: Add a test-case for
+ the bug #29949.
+ * NEWS: Mention this bugfix.
+
2010-04-11 James Youngman <jay@gnu.org>
Add a test case for Savannah bug 27563 (-L breaks -execdir).
diff --git a/NEWS b/NEWS
index c8eb0bc..2ba2111 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,8 @@ GNU findutils NEWS - User visible changes. -*- outline -*- (allout)
** Bug Fixes
+#29949: find -execdir does not change working directory
+
#27563: -L breaks -execdir
#19593: -execdir .... {} + has suboptimal performance (see below)
diff --git a/find/pred.c b/find/pred.c
index cf25184..cac74d1 100644
--- a/find/pred.c
+++ b/find/pred.c
@@ -558,13 +558,11 @@ initialise_wd_for_exec (struct exec_val *execp, int cwd_fd, const char *dir)
static boolean
record_exec_dir (struct exec_val *execp)
{
- if (!execp->wd_for_exec)
+ /* working directory not already known, so must be a *dir variant,
+ and this must be the first arg we added. However, this may
+ be -execdir foo {} \; (i.e. not multiple). */
+ if (!execp->state.todo)
{
- /* working directory not already known, so must be a *dir variant,
- and this must be the first arg we added. However, this may
- be -execdir foo {} \; (i.e. not multiple). */
- assert (!execp->state.todo);
-
/* Record the WD. If we're using -L or fts chooses to do so for
any other reason, state.cwd_dir_fd may in fact not be the
directory containing the target file. When this happens,
diff --git a/find/testsuite/find.gnu/execdir-multiple.exp b/find/testsuite/find.gnu/execdir-multiple.exp
index 6d4bd66..495b93b 100644
--- a/find/testsuite/find.gnu/execdir-multiple.exp
+++ b/find/testsuite/find.gnu/execdir-multiple.exp
@@ -49,6 +49,7 @@ if { [ safe_path ] } {
}
set SKIP_OLD 1
+ find_start p {tmp -type f -empty -execdir sh ./runme \{\} \; } ""
find_start p {tmp -type f -empty -execdir sh ./runme \{\} + } ""
set SKIP_OLD 0
exec rm -rf tmp

View File

@ -1,7 +1,7 @@
Summary: The GNU versions of find utilities (find and xargs) Summary: The GNU versions of find utilities (find and xargs)
Name: findutils Name: findutils
Version: 4.4.2 Version: 4.4.2
Release: 3%{?dist} Release: 8%{?dist}
Epoch: 1 Epoch: 1
License: GPLv3+ License: GPLv3+
Group: Applications/File Group: Applications/File
@ -9,7 +9,30 @@ URL: http://www.gnu.org/software/findutils/
Source0: ftp://ftp.gnu.org/gnu/findutils/%{name}-%{version}.tar.gz Source0: ftp://ftp.gnu.org/gnu/findutils/%{name}-%{version}.tar.gz
Source1: ftp://ftp.gnu.org/gnu/findutils/%{name}-%{version}.tar.gz.sig Source1: ftp://ftp.gnu.org/gnu/findutils/%{name}-%{version}.tar.gz.sig
Patch1: findutils-4.4.0-no-locate.patch Patch1: findutils-4.4.0-no-locate.patch
Patch2: findutils-4.4.0-selinux.patch Patch2: findutils-4.4.2-autofs.patch
Patch3: findutils-4.4.2-xautofs.patch
Patch4: findutils-4.4.2-fts-remount.patch
Patch5: findutils-4.4.2-selinux.patch
Patch6: findutils-4.4.2-selinux-gnulib.patch
# backport of upstream commit 41896c730790d6afa9feabc867aaa14198873a76
Patch7: findutils-4.5.8-0001-41896c7.patch
# backport of upstream commit 7dc70069a3095a42eadb22b24cb9260c243aff8f
Patch8: findutils-4.5.8-0002-7dc7006.patch
# backport of upstream commit 27a7e451b84808408bf23b3f8a0363acb36e1a96
Patch9: findutils-4.5.8-0003-27a7e45.patch
# backport of upstream commit e1d0a991e96ee164d74579efc027b09336e50c79
Patch10: findutils-4.5.8-0004-e1d0a99.patch
# backport of upstream commit a1f54022d1913a92ccb728211127d5c238397eb6
Patch11: findutils-4.5.8-0005-a1f5402.patch
# Fix Savannah bug #29949, -execdir does not change working directory
Patch12: findutils-4.5.8-0006-Fix-Savannah-bug-29949.patch
Requires(post): /sbin/install-info Requires(post): /sbin/install-info
Requires(preun): /sbin/install-info Requires(preun): /sbin/install-info
Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
@ -21,7 +44,7 @@ BuildRequires: libselinux-devel
The findutils package contains programs which will help you locate The findutils package contains programs which will help you locate
files on your system. The find utility searches through a hierarchy files on your system. The find utility searches through a hierarchy
of directories looking for files which match a certain set of criteria of directories looking for files which match a certain set of criteria
(such as a filename pattern). The xargs utility builds and executes (such as a file name pattern). The xargs utility builds and executes
command lines from standard input arguments (usually lists of file command lines from standard input arguments (usually lists of file
names generated by the find command). names generated by the find command).
@ -30,8 +53,18 @@ useful for finding things on your system.
%prep %prep
%setup -q %setup -q
%patch1 -p1 -b .no-locate %patch1 -p1
%patch2 -p1 -b .selinux %patch2 -p1
%patch3 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
%patch8 -p1
%patch9 -p1
%patch10 -p1
%patch11 -p1
%patch12 -p1
autoreconf autoreconf
@ -40,7 +73,7 @@ autoreconf
%configure %configure
%undefine optflags %undefine optflags
make make %{?_smp_mflags}
%check %check
make check make check
@ -77,7 +110,7 @@ fi
rm -rf $RPM_BUILD_ROOT rm -rf $RPM_BUILD_ROOT
%files -f %{name}.lang %files -f %{name}.lang
%defattr(-,root,root) %defattr(-,root,root,-)
%doc AUTHORS COPYING NEWS README THANKS TODO %doc AUTHORS COPYING NEWS README THANKS TODO
/bin/find /bin/find
%{_bindir}/find %{_bindir}/find
@ -89,6 +122,24 @@ rm -rf $RPM_BUILD_ROOT
%{_infodir}/find-maint.info.gz %{_infodir}/find-maint.info.gz
%changelog %changelog
* Tue Jun 01 2010 Kamil Dudka <kdudka@redhat.com> - 1:4.4.2-8
- fix Savannah bug #29949
* Mon May 10 2010 Kamil Dudka <kdudka@redhat.com> - 1:4.4.2-7
- backport of patches for upstream bugs #19593 and #27563 (rhbz #493143)
- mention -xautofs in the output of --help (#590166)
* Thu Nov 26 2009 Kamil Dudka <kdudka@redhat.com> - 1:4.4.2-6
- update SELinux patch to the latest upstream (gnulib based) version
* Wed Nov 18 2009 Kamil Dudka <kdudka@redhat.com> - 1:4.4.2-5
- do not fail silently on a remount during traverse (#538536)
* Tue Oct 20 2009 Kamil Dudka <kdudka@redhat.com> - 1:4.4.2-4
- make it possible to recognize an autofs filesystem by find
- add a new find's option -xautofs to not descend directories on autofs
filesystems
* Mon Sep 14 2009 Kamil Dudka <kdudka@redhat.com> - 1:4.4.2-3 * Mon Sep 14 2009 Kamil Dudka <kdudka@redhat.com> - 1:4.4.2-3
- do process install-info only without --excludedocs(#515914) - do process install-info only without --excludedocs(#515914)