>From 6c37ce48a1eb3d1f21a1848cc9c40f2cdb191e88 Mon Sep 17 00:00:00 2001 From: Bernhard Voelker Date: Sun, 10 Apr 2016 14:58:55 +0200 Subject: [PATCH 1/2] find: support list of file types for -type and -xtype * find/defs.h (enum file_type): Add enumeration for all (supported) file types. (struct predicate): Replace 'type' by 'types' as an array of bool for the above enum file_type. * find/parser.c (insert_type): Treat the argument to -type and -xtype as a comma-separated list of type letters: instead of storing the single type of the predicate, save the searched type letters in the above 'types' array. * find/pred.c (pred_type): Change the comparison against the saved file type predicate: now check if the type of the actual file is in the array of searched 'types'. * find/testsuite/test_type-list.sh: Add test. * find/testsuite/Makefile.am: Reference the test. * find/find.1: Document the new feature. * doc/find.texi: Likewise. * NEWS: Likewise. RFE originally initiated by Young Mo Kang in http://lists.gnu.org/archive/html/bug-findutils/2016-02/msg00025.html --- NEWS | 5 + doc/find.texi | 4 + find/defs.h | 23 ++- find/find.1 | 19 +++ find/parser.c | 252 +++++++++++++++++------------ find/pred.c | 77 +++++++-- find/testsuite/Makefile.am | 1 + find/testsuite/test_type-list.sh | 340 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 598 insertions(+), 123 deletions(-) create mode 100755 find/testsuite/test_type-list.sh diff --git a/NEWS b/NEWS index 556eab8..59f6cb9 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,11 @@ the --help option. Previously, when the user passed invalid options or arguments, the user's attention to the corresponding error diagnostic was distracted by that lengthy text. +find now accepts multiple file type arguments to the -type and -xtype +options separated by comma ','. For example, to search for symbolic +links and directories simply provide the shorter '-type l,d' instead +of the - yet more portable - '( -type l -o -type d )'. + ** Bug Fixes #46784: frcode drops last char if no final newline diff --git a/doc/find.texi b/doc/find.texi index 634e229..93c67c3 100644 --- a/doc/find.texi +++ b/doc/find.texi @@ -1081,6 +1081,10 @@ socket @item D door (Solaris) @end table + +As a GNU extension, multiple file types can be provided as a combined list +separated by comma @samp{,}. For example, @samp{-type f,d,l} is logically +interpreted as @samp{( -type f -o -type d -o -type l )}. @end deffn @deffn Test -xtype c diff --git a/find/defs.h b/find/defs.h index 9311565..52e522f 100644 --- a/find/defs.h +++ b/find/defs.h @@ -163,6 +163,27 @@ struct size_val uintmax_t size; }; +/* Supported file types for the -type/-xtype options. */ +enum file_type + { + FTYPE_BLK, + FTYPE_CHR, + FTYPE_DIR, + FTYPE_REG, +#ifdef S_IFLNK + FTYPE_LNK, +#endif +#ifdef S_IFIFO + FTYPE_FIFO, +#endif +#ifdef S_IFSOCK + FTYPE_SOCK, +#endif +#ifdef S_IFDOOR + FTYPE_DOOR, +#endif + FTYPE_COUNT + }; enum xval { @@ -305,7 +326,7 @@ struct predicate struct time_val reftime; /* newer newerXY anewer cnewer mtime atime ctime mmin amin cmin */ struct perm_val perm; /* perm */ struct samefile_file_id samefileid; /* samefile */ - mode_t type; /* type */ + bool types[FTYPE_COUNT]; /* file type(s) */ struct format_val printf_vec; /* printf fprintf fprint ls fls print0 fprint0 print */ security_context_t scontext; /* security context */ } args; diff --git a/find/find.1 b/find/find.1 index c948b4b..7b626b5 100644 --- a/find/find.1 +++ b/find/find.1 @@ -954,6 +954,9 @@ socket .IP D door (Solaris) .RE +.IP +To search for more than one type at once, you can supply the combined list of +type letters separated by a comma `,' (GNU extension). .IP "\-uid \fIn\fR" File's numeric user ID is \fIn\fR. @@ -1653,6 +1656,8 @@ previous versions of findutils. .IP \fB\-type\fR Supported. POSIX specifies `b', `c', `d', `l', `p', `f' and `s'. GNU find also supports `D', representing a Door, where the OS provides these. +Furthermore, GNU find allows multiple types to be specified at once in a +comma-separated list. .IP \fB\-ok\fR Supported. @@ -2087,6 +2092,20 @@ discovered (for example we do not search project3/src because we already found project3/.svn), but ensures sibling directories (project2 and project3) are found. +.P +.nf +.B find /tmp -type f,d,l +.fi + +Search for files, directories, and symbolic links in the directory +.B /tmp +passing these types as a comma-separated list (GNU extension), +which is otherwise equivalent to the longer, yet more portable: + +.nf +.B find /tmp \e( -type f -o -type d -o -type l \e) +.fi + .SH EXIT STATUS .PP .B find diff --git a/find/parser.c b/find/parser.c index 57fb296..dfe0523 100644 --- a/find/parser.c +++ b/find/parser.c @@ -2679,131 +2679,171 @@ insert_type (char **argv, int *arg_ptr, PRED_FUNC which_pred) { struct predicate *our_pred; - float rate = 0.01; const char *typeletter; + const char *pred_string = which_pred == pred_xtype ? "-xtype" : "-type"; - if (collect_arg (argv, arg_ptr, &typeletter)) + if (! collect_arg (argv, arg_ptr, &typeletter)) + return false; + + if (!*typeletter) { - if (strlen (typeletter) != 1u) - { - error (EXIT_FAILURE, 0, - _("Arguments to -type should contain only one letter")); - /*NOTREACHED*/ - return false; - } + error (EXIT_FAILURE, 0, + _("Arguments to %s should contain at least one letter"), + pred_string); + /*NOTREACHED*/ + return false; + } - /* From a real system here are the counts of files by type: - Type Count Fraction - f 4410884 0.875 - d 464722 0.0922 - l 156662 0.0311 - b 4476 0.000888 - c 2233 0.000443 - s 80 1.59e-05 - p 38 7.54e-06 - */ - { - mode_t type_cell; + our_pred = insert_primary_withpred (entry, which_pred, typeletter); + our_pred->est_success_rate = 0.0; - switch (typeletter[0]) - { - case 'b': /* block special */ - type_cell = S_IFBLK; - rate = 0.000888f; - break; - case 'c': /* character special */ - type_cell = S_IFCHR; - rate = 0.000443f; - break; - case 'd': /* directory */ - type_cell = S_IFDIR; - rate = 0.0922f; - break; - case 'f': /* regular file */ - type_cell = S_IFREG; - rate = 0.875f; - break; - case 'l': /* symbolic link */ + /* Figure out if we will need to stat the file, because if we don't + * need to follow symlinks, we can avoid a stat call by using + * struct dirent.d_type. + */ + if (which_pred == pred_xtype) + { + our_pred->need_stat = true; + our_pred->need_type = false; + } + else + { + our_pred->need_stat = false; /* struct dirent is enough */ + our_pred->need_type = true; + } + + /* From a real system here are the counts of files by type: + Type Count Fraction + f 4410884 0.875 + d 464722 0.0922 + l 156662 0.0311 + b 4476 0.000888 + c 2233 0.000443 + s 80 1.59e-05 + p 38 7.54e-06 + */ + + for (; *typeletter; ) + { + unsigned int type_cell; + float rate = 0.01; + + switch (*typeletter) + { + case 'b': /* block special */ + type_cell = FTYPE_BLK; + rate = 0.000888f; + break; + case 'c': /* character special */ + type_cell = FTYPE_CHR; + rate = 0.000443f; + break; + case 'd': /* directory */ + type_cell = FTYPE_DIR; + rate = 0.0922f; + break; + case 'f': /* regular file */ + type_cell = FTYPE_REG; + rate = 0.875f; + break; + case 'l': /* symbolic link */ #ifdef S_IFLNK - type_cell = S_IFLNK; - rate = 0.0311f; + type_cell = FTYPE_LNK; + rate = 0.0311f; #else - type_cell = 0; - error (EXIT_FAILURE, 0, - _("-type %c is not supported because symbolic links " - "are not supported on the platform find was compiled on."), - (*typeletter)); + type_cell = 0; + error (EXIT_FAILURE, 0, + _("%s %c is not supported because symbolic links " + "are not supported on the platform find was compiled on."), + pred_string, (*typeletter)); #endif - break; - case 'p': /* pipe */ + break; + case 'p': /* pipe */ #ifdef S_IFIFO - type_cell = S_IFIFO; - rate = 7.554e-6f; + type_cell = FTYPE_FIFO; + rate = 7.554e-6f; #else - type_cell = 0; - error (EXIT_FAILURE, 0, - _("-type %c is not supported because FIFOs " - "are not supported on the platform find was compiled on."), - (*typeletter)); + type_cell = 0; + error (EXIT_FAILURE, 0, + _("%s %c is not supported because FIFOs " + "are not supported on the platform find was compiled on."), + pred_string, (*typeletter)); #endif - break; - case 's': /* socket */ + break; + case 's': /* socket */ #ifdef S_IFSOCK - type_cell = S_IFSOCK; - rate = 1.59e-5f; + type_cell = FTYPE_SOCK; + rate = 1.59e-5f; #else - type_cell = 0; - error (EXIT_FAILURE, 0, - _("-type %c is not supported because named sockets " - "are not supported on the platform find was compiled on."), - (*typeletter)); + type_cell = 0; + error (EXIT_FAILURE, 0, + _("%s %c is not supported because named sockets " + "are not supported on the platform find was compiled on."), + pred_string, (*typeletter)); #endif - break; - case 'D': /* Solaris door */ + break; + case 'D': /* Solaris door */ #ifdef S_IFDOOR - type_cell = S_IFDOOR; - /* There are no Solaris doors on the example system surveyed - * above, but if someone uses -type D, they are presumably - * expecting to find a non-zero number. We guess at a - * rate. */ - rate = 1.0e-5f; + type_cell = FTYPE_DOOR; + /* There are no Solaris doors on the example system surveyed + * above, but if someone uses -type D, they are presumably + * expecting to find a non-zero number. We guess at a + * rate. */ + rate = 1.0e-5f; #else - type_cell = 0; - error (EXIT_FAILURE, 0, - _("-type %c is not supported because Solaris doors " - "are not supported on the platform find was compiled on."), - (*typeletter)); + type_cell = 0; + error (EXIT_FAILURE, 0, + _("%s %c is not supported because Solaris doors " + "are not supported on the platform find was compiled on."), + pred_string, (*typeletter)); #endif - break; - default: /* None of the above ... nuke 'em. */ - type_cell = 0; - error (EXIT_FAILURE, 0, - _("Unknown argument to -type: %c"), (*typeletter)); - /*NOTREACHED*/ - return false; - } - our_pred = insert_primary_withpred (entry, which_pred, typeletter); - our_pred->est_success_rate = rate; - - /* Figure out if we will need to stat the file, because if we don't - * need to follow symlinks, we can avoid a stat call by using - * struct dirent.d_type. - */ - if (which_pred == pred_xtype) - { - our_pred->need_stat = true; - our_pred->need_type = false; - } - else - { - our_pred->need_stat = false; /* struct dirent is enough */ - our_pred->need_type = true; - } - our_pred->args.type = type_cell; + break; + default: /* None of the above ... nuke 'em. */ + type_cell = 0; + error (EXIT_FAILURE, 0, + _("Unknown argument to %s: %c"), pred_string, (*typeletter)); + /*NOTREACHED*/ + return false; } - return true; + + if (our_pred->args.types[type_cell]) + { + error (EXIT_FAILURE, 0, + _("Duplicate file type '%c' in the argument list to %s."), + (*typeletter), pred_string); + } + + our_pred->est_success_rate += rate; + our_pred->args.types[type_cell] = true; + + /* Advance. + * Currently, only 1-character file types separated by ',' are supported. + */ + typeletter++; + if (*typeletter) + { + if (*typeletter != ',') + { + error (EXIT_FAILURE, 0, + _("Must separate multiple arguments to %s using: ','"), + pred_string); + /*NOTREACHED*/ + return false; + } + typeletter++; + if (!*typeletter) + { + error (EXIT_FAILURE, 0, + _("Last file type in list argument to %s " + "is missing, i.e., list is ending on: ','"), + pred_string); + /*NOTREACHED*/ + return false; + } + } } - return false; + + return true; } diff --git a/find/pred.c b/find/pred.c index d633ab9..f7e9b59 100644 --- a/find/pred.c +++ b/find/pred.c @@ -1032,7 +1032,7 @@ bool pred_type (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) { mode_t mode; - mode_t type = pred_ptr->args.type; + enum file_type type = FTYPE_COUNT; assert (state.have_type); @@ -1052,31 +1052,76 @@ pred_type (const char *pathname, struct stat *stat_buf, struct predicate *pred_p mode = state.type; #ifndef S_IFMT - /* POSIX system; check `mode' the slow way. */ - if ((S_ISBLK (mode) && type == S_IFBLK) - || (S_ISCHR (mode) && type == S_IFCHR) - || (S_ISDIR (mode) && type == S_IFDIR) - || (S_ISREG (mode) && type == S_IFREG) + /* POSIX system; check `mode' the slow way. + * Search in the order of probability (f,d,l,b,c,s,p,D). + */ + if (S_ISREG (mode)) + type = FTYPE_REG; + else if (S_ISDIR (mode)) + type = FTYPE_DIR; #ifdef S_IFLNK - || (S_ISLNK (mode) && type == S_IFLNK) -#endif -#ifdef S_IFIFO - || (S_ISFIFO (mode) && type == S_IFIFO) + else if (S_ISLNK (mode)) + type = FTYPE_LNK; #endif + else if (S_ISBLK (mode)) + type = FTYPE_BLK; + else if (S_ISCHR (mode)) + type = FTYPE_CHR; #ifdef S_IFSOCK - || (S_ISSOCK (mode) && type == S_IFSOCK) + else if (S_ISSOCK (mode)) + type = FTYPE_SOCK; +#endif +#ifdef S_IFIFO + else if (S_ISFIFO (mode)) + type = FTYPE_FIFO; #endif #ifdef S_IFDOOR - || (S_ISDOOR (mode) && type == S_IFDOOR) + else if (S_ISDOOR (mode)) + type = FTYPE_DOOR; #endif - ) #else /* S_IFMT */ /* Unix system; check `mode' the fast way. */ - if ((mode & S_IFMT) == type) + switch (mode & S_IFMT) + { + case S_IFREG: + type = FTYPE_REG; + break; + case S_IFDIR: + type = FTYPE_DIR; + break; +#ifdef S_IFLNK + case S_IFLNK: + type = FTYPE_LNK; + break; +#endif + case S_IFBLK: + type = FTYPE_BLK; + break; + case S_IFCHR: + type = FTYPE_CHR; + break; +#ifdef S_IFSOCK + case S_IFSOCK: + type = FTYPE_SOCK; + break; +#endif +#ifdef S_IFIFO + case S_IFIFO: + type = FTYPE_FIFO; + break; +#endif +#ifdef S_IFDOOR + case S_IFDOOR: + type = FTYPE_DOOR; + break; +#endif + } #endif /* S_IFMT */ - return (true); + + if ((type != FTYPE_COUNT) && pred_ptr->args.types[type]) + return true; else - return (false); + return false; } bool diff --git a/find/testsuite/Makefile.am b/find/testsuite/Makefile.am index 228957f..65d5d32 100644 --- a/find/testsuite/Makefile.am +++ b/find/testsuite/Makefile.am @@ -257,6 +257,7 @@ sv-bug-32043.sh \ test_escapechars.sh \ test_escape_c.sh \ test_inode.sh \ +test_type-list.sh \ sv-34079.sh \ sv-34976-execdir-fd-leak.sh diff --git a/find/testsuite/test_type-list.sh b/find/testsuite/test_type-list.sh new file mode 100755 index 0000000..c500b02 --- /dev/null +++ b/find/testsuite/test_type-list.sh @@ -0,0 +1,340 @@ +#! /bin/sh +# Copyright (C) 2016 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# This test verifies find's behavior regarding comma-separated file +# type arguments to the -type/-xtype options. + +testname="$(basename $0)" + +. "${srcdir}"/binary_locations.sh + +die() { + echo "$@" >&2 + exit 1 +} + +# This is used to simplify checking of the return value +# which is useful when ensuring a command fails as desired. +# I.e., just doing `command ... &&fail=1` will not catch +# a segfault in command for example. With this helper you +# instead check an explicit exit code like +# returns_ 1 command ... || fail +returns_ () { + # Disable tracing so it doesn't interfere with stderr of the wrapped command + { set +x; } 2>/dev/null + + local exp_exit="$1" + shift + "$@" + test $? -eq $exp_exit && ret_=0 || ret_=1 + + set -x + { return $ret_; } 2>/dev/null +} + +# Define the nicest compare available (borrowed from gnulib). +if diff_out_=`exec 2>/dev/null; diff -u "$0" "$0" < /dev/null` \ + && diff -u Makefile "$0" 2>/dev/null | grep '^[+]#!' >/dev/null; then + # diff accepts the -u option and does not (like AIX 7 'diff') produce an + # extra space on column 1 of every content line. + if test -z "$diff_out_"; then + compare () { diff -u "$@"; } + else + compare () + { + if diff -u "$@" > diff.out; then + # No differences were found, but Solaris 'diff' produces output + # "No differences encountered". Hide this output. + rm -f diff.out + true + else + cat diff.out + rm -f diff.out + false + fi + } + fi +elif diff_out_=`exec 2>/dev/null; diff -c "$0" "$0" < /dev/null`; then + if test -z "$diff_out_"; then + compare () { diff -c "$@"; } + else + compare () + { + if diff -c "$@" > diff.out; then + # No differences were found, but AIX and HP-UX 'diff' produce output + # "No differences encountered" or "There are no differences between the + # files.". Hide this output. + rm -f diff.out + true + else + cat diff.out + rm -f diff.out + false + fi + } + fi +elif cmp -s /dev/null /dev/null 2>/dev/null; then + compare () { cmp -s "$@"; } +else + compare () { cmp "$@"; } +fi + +# Check if the given file type is supported by find. +# Used for the file type compiled in conditionally: l,p,s,D) +find_supports_type() { + find '.' -maxdepth 0 -type "$1" +} + +# Create test files of all possible types (if possible): +# f,d,p,l,b,c,s,D, and a dangling symlink. +make_test_data() { + d="$1" + ( + cd "$1" || exit 1 + # regular file + : > reg || exit 1 + # directory + mkdir dir || exit 1 + # BLK device + mknod blk b 0 0 || : # ignore failure + # CHR device + mknod chr c 0 0 || : # ignore failure + + # FIFO + if [ $HAVE_FIFO = 1 ]; then + mkfifo fifo || : # ignore failure + fi + + # Socket: try various ways to create one. + if [ $HAVE_SOCK = 1 ]; then + perl -e ' + use IO::Socket::UNIX; + my $s = IO::Socket::UNIX->new (Type => SOCK_STREAM(), Local => "sock");' + + test -S sock \ + || python -c \ + "import socket as s; + sock = s.socket(s.AF_UNIX); + sock.bind('sock'); + " + # Also the netcat family leaves the socket behind ... + test -S sock \ + || { nc -lU sock & pid=$!; \ + sleep 1; kill $pid; wait $pid; } + test -S sock \ + || { netcat -lU sock & pid=$!; \ + sleep 1; kill $pid; wait $pid; } + # ... while socat has to be forcefully killed. + test -S sock \ + || { socat unix-listen:sock fd:2 & pid=$!; \ + sleep 1; kill -9 $!; wait $pid; } + fi + + # Door: not that easy. + if [ $HAVE_DOOR = 1 ]; then + : # TODO + fi + + # Symbolic links to all types, and a dangling one. + if [ $HAVE_LINK = 1 ]; then + test -f reg && ln -s reg reg-link + test -d dir && ln -s dir dir-link + test -b blk && ln -s blk blk-link + test -c chr && ln -s chr chr-link + test -S sock && ln -s sock sock-link + test -p fifo && ln -s fifo fifo-link + ln -s enoent dangling-link + fi + ) \ + || die "failed to set up the test in ${outdir}" +} + +set -x +outdir="$(mktemp -d)" || die "FAIL: could not create a test directory." +all="${outdir}.all" +exp="${outdir}.exp" +out="${outdir}.out" +err="${outdir}.err" + +# Check what file types are compiled into find(1). +find_supports_type l && HAVE_LINK=1 || HAVE_LINK=0 +find_supports_type p && HAVE_FIFO=1 || HAVE_FIFO=0 +find_supports_type s && HAVE_SOCK=1 || HAVE_SOCK=0 +find_supports_type D && HAVE_DOOR=1 || HAVE_DOOR=0 + +# Create some test files. +make_test_data "${outdir}" \ + && "${ftsfind}" "${outdir}" -mindepth 1 > $all \ + && sort -o $all $all \ + || die "FAIL: failed to set up the test in ${outdir}" +# Just to see what's there. +"${ftsfind}" "${outdir}" -mindepth 1 -ls + +fail=0 +for exe in "${ftsfind}" "${oldfind}"; do + + # Negative tests first. Expect the output to be empty. + : > $exp + + # Ensure empty type arguments are rejected. + returns_ 1 "${exe}" "${outdir}" -mindepth 1 -type '' > $out 2> $err || fail=1 + compare $exp $out || fail=1 + grep 'Arguments to -type should contain at least one letter' $err \ + || { cat $err; fail=1; } + + returns_ 1 "${exe}" "${outdir}" -mindepth 1 -xtype '' > $out 2> $err || fail=1 + compare $exp $out || fail=1 + grep 'Arguments to -xtype should contain at least one letter' $err \ + || { cat $err; fail=1; } + + # Ensure non-separated type arguments are rejected. + returns_ 1 "${exe}" "${outdir}" -mindepth 1 -type fd > $out 2> $err || fail=1 + compare $exp $out || fail=1 + grep 'Must separate multiple arguments to -type' $err \ + || { cat $err; fail=1; } + + returns_ 1 "${exe}" "${outdir}" -mindepth 1 -xtype fd > $out 2> $err || fail=1 + compare $exp $out || fail=1 + grep 'Must separate multiple arguments to -xtype' $err \ + || { cat $err; fail=1; } + + # Ensure unterminated type list arguments are rejected. + returns_ 1 "${exe}" "${outdir}" -mindepth 1 -type f, > $out 2> $err || fail=1 + compare $exp $out || fail=1 + grep 'Last file type in list argument to -type is missing' $err \ + || { cat $err; fail=1; } + + returns_ 1 "${exe}" "${outdir}" -mindepth 1 -xtype f, > $out 2> $err || fail=1 + compare $exp $out || fail=1 + grep 'Last file type in list argument to -xtype is missing' $err \ + || { cat $err; fail=1; } + + # Ensure duplicate entries in the type list arguments are rejected. + returns_ 1 "${exe}" "${outdir}" -mindepth 1 -type f,f > $out 2> $err || fail=1 + compare $exp $out || fail=1 + grep 'Duplicate file type .* in the argument list to -type' $err \ + || { cat $err; fail=1; } + + returns_ 1 "${exe}" "${outdir}" -mindepth 1 -xtype f,f > $out 2> $err || fail=1 + compare $exp $out || fail=1 + grep 'Duplicate file type .* in the argument list to -xtype' $err \ + || { cat $err; fail=1; } + + # Continue with positive tests. + # Files and directories. + grep -e '/reg$' -e '/dir$' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -type f,d > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + grep -e '/reg' -e '/dir' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -xtype f,d > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + # Block devices. + grep -e '/reg$' -e '/dir$' -e '/blk$' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -type b,f,d > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + grep -e '/reg' -e '/dir' -e '/blk' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -xtype b,f,d > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + # Character devices. + grep -e '/reg$' -e '/dir$' -e '/chr$' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -type f,c,d > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + grep -e '/reg' -e '/dir' -e '/chr' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -xtype f,c,d > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + # FIFOs. + if [ $HAVE_FIFO = 1 ]; then + grep -e '/reg$' -e '/dir$' -e '/fifo$' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -type f,d,p > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + grep -e '/reg' -e '/dir' -e '/fifo' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -xtype f,d,p > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + fi + + # Sockets. + if [ $HAVE_SOCK = 1 ]; then + grep -e '/reg$' -e '/dir$' -e '/sock$' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -type f,d,s > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + grep -e '/reg' -e '/dir' -e '/sock' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -xtype f,d,s > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + fi + + # Symbolic links. + if [ $HAVE_LINK = 1 ]; then + + grep -e '/reg$' -e 'link$' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -type f,l > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + grep -e '/reg' -e 'dangling-link$' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -xtype f,l > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + fi + + # -xtype: all but the dangling symlink. + t='f,d,b,c' + [ $HAVE_FIFO = 1 ] && t="$t,p" + [ $HAVE_SOCK = 1 ] && t="$t,s" + [ $HAVE_DOOR = 1 ] && t="$t,D" + grep -v 'dangling-link$' $all > $exp + "${exe}" "${outdir}" -mindepth 1 -xtype "$t" > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + + # negation + if [ $HAVE_LINK = 1 ]; then + "${exe}" "${outdir}" -mindepth 1 -not -xtype l > $out || fail=1 + sort -o $out $out + compare $exp $out || fail=1; + fi + + # Finally: full list + [ $HAVE_LINK = 1 ] && t="$t,l" + "${exe}" "${outdir}" -mindepth 1 -type "$t" > $out || fail=1 + sort -o $out $out + compare $all $out || fail=1; + + "${exe}" "${outdir}" -mindepth 1 -xtype "$t" > $out || fail=1 + sort -o $out $out + compare $all $out || fail=1; +done + +rm -rf "${outdir}" $all $exp $out $err || exit 1 +exit $fail -- 2.1.4