summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKiyoshi Aman <kiyoshi.aman+adelie@gmail.com>2019-06-02 05:39:48 -0500
committerKiyoshi Aman <kiyoshi.aman+adelie@gmail.com>2019-06-02 05:40:06 -0500
commit09863a10639de265b2299938a292bba15abc570a (patch)
tree1628e509cdc1915d25e54957275d8c865988d260
parent93d303d88ac036537c09d8fdc7ff80258826463a (diff)
downloaduserland-09863a10639de265b2299938a292bba15abc570a.tar.gz
userland-09863a10639de265b2299938a292bba15abc570a.tar.bz2
userland-09863a10639de265b2299938a292bba15abc570a.tar.xz
userland-09863a10639de265b2299938a292bba15abc570a.zip
usr.bin/find: replace with heirloom find
-rw-r--r--usr.bin/find/extern.h99
-rw-r--r--usr.bin/find/find.11488
-rw-r--r--usr.bin/find/find.c1696
-rw-r--r--usr.bin/find/find.h138
-rw-r--r--usr.bin/find/function.c1956
-rw-r--r--usr.bin/find/getdir.c148
-rw-r--r--usr.bin/find/getdir.h33
-rw-r--r--usr.bin/find/ls.c135
-rw-r--r--usr.bin/find/main.c154
-rw-r--r--usr.bin/find/misc.c142
-rw-r--r--usr.bin/find/operator.c263
-rw-r--r--usr.bin/find/option.c184
12 files changed, 2183 insertions, 4253 deletions
diff --git a/usr.bin/find/extern.h b/usr.bin/find/extern.h
deleted file mode 100644
index 825351e..0000000
--- a/usr.bin/find/extern.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/* $NetBSD: extern.h,v 1.29 2016/06/13 00:04:40 pgoyette Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * from: @(#)extern.h 8.3 (Berkeley) 4/16/94
- */
-
-void brace_subst(char *, char **, char *, int *);
-PLAN *find_create(char ***);
-int find_execute(PLAN *, char **);
-PLAN *find_formplan(char **);
-int find_traverse(PLAN *, int (*)(PLAN *, void *), void *);
-int f_expr(PLAN *, FTSENT *);
-PLAN *not_squish(PLAN *);
-PLAN *or_squish(PLAN *);
-PLAN *paren_squish(PLAN *);
-int plan_cleanup(PLAN *, void *);
-void printlong(char *, char *, struct stat *);
-int queryuser(char **);
-void show_path(int);
-
-PLAN *c_amin(char ***, int, char *);
-PLAN *c_anewer(char ***, int, char *);
-PLAN *c_asince(char ***, int, char *);
-PLAN *c_atime(char ***, int, char *);
-PLAN *c_cmin(char ***, int, char *);
-PLAN *c_cnewer(char ***, int, char *);
-PLAN *c_csince(char ***, int, char *);
-PLAN *c_ctime(char ***, int, char *);
-PLAN *c_delete(char ***, int, char *);
-PLAN *c_depth(char ***, int, char *);
-PLAN *c_empty(char ***, int, char *);
-PLAN *c_exec(char ***, int, char *);
-PLAN *c_execdir(char ***, int, char *);
-PLAN *c_exit(char ***, int, char *);
-PLAN *c_false(char ***, int, char *);
-PLAN *c_follow(char ***, int, char *);
-PLAN *c_fprint(char ***, int, char *);
-PLAN *c_fstype(char ***, int, char *);
-PLAN *c_group(char ***, int, char *);
-PLAN *c_iname(char ***, int, char *);
-PLAN *c_inum(char ***, int, char *);
-PLAN *c_iregex(char ***, int, char *);
-PLAN *c_links(char ***, int, char *);
-PLAN *c_ls(char ***, int, char *);
-PLAN *c_maxdepth(char ***, int, char *);
-PLAN *c_mindepth(char ***, int, char *);
-PLAN *c_mmin(char ***, int, char *);
-PLAN *c_mtime(char ***, int, char *);
-PLAN *c_name(char ***, int, char *);
-PLAN *c_newer(char ***, int, char *);
-PLAN *c_nogroup(char ***, int, char *);
-PLAN *c_nouser(char ***, int, char *);
-PLAN *c_path(char ***, int, char *);
-PLAN *c_perm(char ***, int, char *);
-PLAN *c_print(char ***, int, char *);
-PLAN *c_print0(char ***, int, char *);
-PLAN *c_printx(char ***, int, char *);
-PLAN *c_prune(char ***, int, char *);
-PLAN *c_regex(char ***, int, char *);
-PLAN *c_since(char ***, int, char *);
-PLAN *c_size(char ***, int, char *);
-PLAN *c_type(char ***, int, char *);
-PLAN *c_user(char ***, int, char *);
-PLAN *c_xdev(char ***, int, char *);
-PLAN *c_openparen(char ***, int, char *);
-PLAN *c_closeparen(char ***, int, char *);
-PLAN *c_not(char ***, int, char *);
-PLAN *c_or(char ***, int, char *);
-PLAN *c_null(char ***, int, char *);
-
-extern int ftsoptions, isdeprecated, isdepth, isoutput, issort, isxargs,
- regcomp_flags;
diff --git a/usr.bin/find/find.1 b/usr.bin/find/find.1
index 60ce94a..a12b404 100644
--- a/usr.bin/find/find.1
+++ b/usr.bin/find/find.1
@@ -1,974 +1,558 @@
-.\" $NetBSD: find.1,v 1.89 2017/07/03 21:34:57 wiz Exp $
-.\"
-.\" Copyright (c) 1990, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" This code is derived from software contributed to Berkeley by
-.\" the Institute of Electrical and Electronics Engineers, Inc.
+'\" t
+.\" Sccsid @(#)find.1 1.44 (gritter) 8/14/05
+.\" Parts taken from find(1), Unix 7th edition:
+.\" Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" Redistributions of source code and documentation must retain the
+.\" above copyright notice, this list of conditions and the following
+.\" disclaimer.
+.\" Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
-.\" 3. Neither the name of the University nor the names of its contributors
-.\" may be used to endorse or promote products derived from this software
-.\" without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
+.\" All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed or owned by Caldera
+.\" International, Inc.
+.\" Neither the name of Caldera International, Inc. nor the names of
+.\" other contributors may be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
.\"
-.\" from: @(#)find.1 8.7 (Berkeley) 5/9/95
+.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+.\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd June 13, 2016
-.Dt FIND 1
-.Os
-.Sh NAME
-.Nm find
-.Nd walk a file hierarchy
-.Sh SYNOPSIS
-.Nm
-.Op Fl H | Fl L | Fl P
-.Op Fl dEhsXx
-.Ar file
-.Op Ar file ...
-.Op Ar expression
-.Nm
-.Op Fl H | Fl L | Fl P
-.Op Fl dEhsXx
-.Fl f Ar file
-.Op Ar file ...
-.Op Ar expression
-.Sh DESCRIPTION
-.Nm
-recursively descends the directory tree for each
-.Ar file
-listed, evaluating an
-.Ar expression
-(composed of the
-.Dq primaries
+.TH FIND 1 "8/14/05" "Heirloom Toolchest" "User Commands"
+.SH NAME
+find \- find files
+.SH SYNOPSIS
+.B find
+.I pathname-list expression
+.SH DESCRIPTION
+.I Find
+recursively descends
+the directory hierarchy for
+each pathname in the
+.I pathname-list
+(i.\|e., one or more pathnames)
+seeking files that match a boolean
+.I expression
+written in the primaries given below.
+In the descriptions, the argument
+.I n
+is used as a decimal integer
+where
+.I +n
+means more than
+.I n,
+.I \-n
+means less than
+.I n
and
-.Dq operands
-listed below) in terms
-of each file in the tree.
-.Pp
-The options are as follows:
-.Bl -tag -width Ds
-.It Fl H
-Causes the file information and file type (see
-.Xr stat 2 )
-returned for each symbolic link encountered on the command line to be
-those of the file referenced by the link, not the link itself.
-If the referenced file does not exist, the file information and type will
-be for the link itself.
-File information of all symbolic links not on the command line is that
-of the link itself.
-.It Fl L
-Causes the file information and file type (see
-.Xr stat 2 )
-returned for each symbolic link to be those of the file referenced by the
-link, not the link itself.
-If the referenced file does not exist, the file information and type will
-be for the link itself.
-.It Fl P
-Causes the file information and file type (see
-.Xr stat 2 )
-returned for each symbolic link to be those of the link itself.
-.It Fl d
-Causes
-.Nm
-to perform a depth-first traversal, i.e., directories
-are visited in post-order, and all entries in a directory will be acted
-on before the directory itself.
-By default,
-.Nm
-visits directories in pre-order, i.e., before their contents.
-Note, the default is
-.Em not
-a breadth-first traversal.
-.It Fl E
-Causes
-.Ar regexp
-arguments to primaries to be interpreted as extended regular
-expressions (see
-.Xr re_format 7 ) .
-.It Fl f
-Specifies a file hierarchy for
-.Nm
-to traverse.
-File hierarchies may also be specified as the operands immediately
-following the options.
-.It Fl h
-Causes the file information and file type (see
-.Xr stat 2 )
-returned for each symbolic link to be those of the file referenced by the
-link, not the link itself.
-If the referenced file does not exist, the file information and type will
-be for the link itself.
-.It Fl s
-Causes the entries of each directory to be sorted in
-lexicographical order.
-Note that the sorting is done only inside of each directory;
-files in different directories are not sorted.
-Therefore,
-.Sq Li a/b
-appears before
-.Sq Li a.b ,
-which is different from
-.Dq Li "find ... \&| sort"
-order.
-.It Fl X
-Modifies the output to permit
-.Nm
-to be safely used in conjunction with
-.Xr xargs 1 .
-If a file name contains any of the delimiting characters used by
-.Xr xargs 1 ,
-a diagnostic message is displayed on standard error, and the file
-is skipped.
-The delimiting characters include single
-.Pq Dq \&'
-and double
-.Pq Dq \&"
-quotes, backslash
-.Pq Dq \e ,
-space, tab, and newline characters.
-Alternatively, the
-.Ic -print0
-or
-.Ic -printx
-primaries can be used to format the output in a way that
-.Xr xargs 1
-can accept.
-.It Fl x
-Restricts the search to the file system containing the
-directory specified.
-Does not list mount points to other file systems.
-.El
-.Sh PRIMARIES
-All primaries which take a numeric argument of
-.Ar n
-allow the number to be preceded by a plus sign
-.Pq Dq \&+
-or a minus sign
-.Pq Dq \- .
-A preceding plus sign means
-.Dq more than Ar n ,
-a preceding minus sign means
-.Dq less than Ar n ,
-and neither means
-.Dq exactly Ar n .
-(The argument specified for the
-.Ic -user
+.I n
+means exactly
+.IR n .
+.TP 10n
+.BR \-name " filename"
+True if the
+.I filename
+argument matches the current file name.
+Normal
+Shell
+argument syntax
+as described in
+.IR glob (7)
+may be used if escaped (watch out for
+`[', `?' and `*').
+The internationalization constructs
+`[[:class:]]', `[[=e=]]', and `[[.cs.]]'
+are understood with
+.BR /usr/5bin/s42/find ,
+.BR /usr/5bin/posix/find ,
and
-.Ic -group
-primaries
-are similarly treated if the value is numeric and does not correspond to a
-valid user or group name.)
-.Pp
-For primaries which take a
-.Ar timestamp
-argument, the argument must be valid input to
-.Xr parsedate 3 .
-If the argument contains multiple words, enclose the argument in quotes.
-.Pp
-.Bl -tag -width Ds -compact
-.It Ic -amin Ar n
-True if the difference between the file last access time and the time
-.Nm
-was started, rounded up to the next full minute, is
-.Ar n
-minutes.
-.Pp
-.It Ic -anewer Ar file
-True if the current file has a more recent last access time than
-.Ar file .
-.Pp
-.It Ic -asince Ar timestamp
-True if the file last access time is greater than the specified
-.Ar timestamp .
-.Pp
-.It Ic -atime Ar n
-True if the difference between the file last access time and the time
-.Nm
-was started, rounded up to the next full 24-hour period, is
-.Ar n
-24-hour periods.
-.Pp
-.It Ic -cmin Ar n
-True if the difference between the time of last change of file status
-information and the time
-.Nm
-was started, rounded up to the next full minute, is
-.Ar n
-minutes.
-.Pp
-.It Ic -cnewer Ar file
-True if the current file has a more recent last change time than
-.Ar file .
-.Pp
-.It Ic -csince Ar timestamp
-True if the file last status change time is greater than the specified
-.Ar timestamp .
-.Pp
-.It Ic -ctime Ar n
-True if the difference between the time of last change of file status
-information and the time
-.Nm
-was started, rounded up to the next full 24-hour period, is
-.Ar n
-24-hour periods.
-.Pp
-.It Ic -delete
-Delete found files, symbolic links, and directories.
-Always returns true.
-This executes from the current working directory as
-.Nm
-recurses down the tree.
-To avoid deleting unexpected files, it will ignore any filenames that
-.Xr fts 3
-returns that contain a
-.Dq /
-.Xr ( fts 3
-should not return such pathnames).
-Depth-first traversal processing is implied by this option.
-This primary can also be invoked as
-.Ic -rm .
-.Pp
-.It Ic -empty
-True if the current file or directory is empty.
-.Pp
-.It Ic -exec Ar utility Oo argument ... Oc Ic \&;
-.It Ic -exec Ar utility Oo argument ... Oc Ic {} Ic \&+
-Execute the specified
-.Ar utility
-with the specified arguments.
-.Pp
-The list of arguments for
-.Ar utility
-is terminated by a lone semicolon
-.Dq Ic \&;
-or plus
-.Dq Ic \&+
-character as a separate parameter.
-The command specified by
-.Ar utility
-will be executed with its current working directory being the directory
-from which
-.Nm
-was executed.
-.Pp
-If the list of arguments is terminated by a semicolon
-.Pq Dq Ic \&; ,
-then
-.Ar utility
-is invoked once per pathname.
-If
-the string
-.Dq Ic {}
-appears one or more times in the utility name or arguments,
-then it is replaced by the pathname of the current file
-(but it need not appear, in which case the pathname
-will not be passed to
-.Ar utility ) .
-The semicolon-terminated form of the
-.Ic -exec
-primary returns true if and only if
-.Ar utility
-exits with a zero exit status.
-Note that the semicolon will have to be escaped on the shell command line
-in order to be passed as a parameter.
-.Pp
-If the list of arguments is terminated by a plus sign
-.Pq Dq Ic \&+ ,
-then the pathnames for which the primary is evaluated are aggregated
-into sets, and
-.Ar utility
-will be invoked once per set, similar to
-.Xr xargs 1 .
-In this case the string
-.Dq Ic {}
-must appear, and must appear as the last item in the argument list,
-just before the
-.Dq Ic \&+
-parameter, and is replaced by the pathnames of the current set of files.
-Each set is limited to no more than 5,000 pathnames,
-and is also limited such that the total number of bytes in the argument
-list does not exceed
-.Dv ARG_MAX .
-The plus-terminated form of the
-.Ic -exec
-primary always returns true.
-If the plus-terminated form of the
-.Ic -exec
-primary results in any invocation of
-.Ar utility
-exiting with non-zero exit status, then
-.Nm
-will eventually exit with non-zero status as well,
-but this does not cause
-.Nm
-to exit early.
-.Pp
-.It Ic -execdir Ar utility Oo argument ... Oc Ic \&;
-The
-.Ic -execdir
-primary is similar to the semicolon-terminated
-.Pq Dq Ic \&;
-variant of the
-.Ic -exec
-primary, with the exception that
-.Ar utility
-will be executed from the directory that holds
-the current file.
-Only the base filename is substituted for the string
-.Dq Ic {} .
-Set aggregation
-.Pq Do Ic \&+ Dc termination
-is not supported.
-.Pp
-.It Ic -exit Op Ar status
-This primary causes
-.Nm
-to stop traversing the file system and exit immediately,
-with the specified numeric exit status.
-If the
-.Ar status
-value is not specified, then
-.Nm
-will exit with status zero.
-Note that any preceding primaries will be evaluated and acted upon
-before exiting.
-.Pp
-.It Ic -false
-This primary always evaluates to false.
-This can be used following a primary that caused the
-expression to be true to make the expression to be false.
-This can be useful after using a
-.Ic -fprint
-primary so it can continue to the next expression (using an
-.Cm -or
-operator, for example).
-.Pp
-.It Ic -flags Oo Fl Oc Ns Ar flags
-If
-.Ar flags
-are preceded by a dash
-.Pq Dq Ic \- ,
-this primary evaluates to true
-if at least all of the bits in
-.Ar flags
-are set in the file's flags bits.
+.BR /usr/5bin/posix2001/find ,
+but not with
+.BR /usr/5bin/find .
+.TP
+.BR \-perm " mode"
+True if the file permission flags
+exactly
+match the
+octal number
+or symbolic
+.I mode
+(see
+.IR chmod (1)).
If
-.Ar flags
-are not preceded by a dash, this primary evaluates to true if
-the bits in
-.Ar flags
-exactly match the file's flags bits.
-If
-.Ar flags
+.I mode
+is prefixed by a minus sign,
+the flags are compared:
+.IR (flags&mode)==mode .
+.TP
+.BR \-type " c"
+True if the type of the file
is
-.Dq none ,
-files with no flags bits set are matched.
-(See
-.Xr chflags 1
-for more information about file flags.)
-.Pp
-.It Ic -follow
-Follow symbolic links.
-.Pp
-.It Ic -fprint Ar filename
-This primary always evaluates to true.
-This creates
-.Ar filename
-or overwrites the file if it already exists.
-The file is created at startup.
-It writes the pathname of the current file to this file, followed
-by a newline character.
-The file will be empty if no files are matched.
-.Pp
-.It Ic -fstype Ar type
-True if the file is contained in a file system of type
-.Ar type .
-The
-.Xr sysctl 8
-command can be used to find out the types of file systems
-that are available on the system:
-.Bd -literal -offset indent
-sysctl vfs.generic.fstypes
-.Ed
-.Pp
-In addition, there are two pseudo-types,
-.Dq local
-and
-.Dq rdonly .
-The former matches any file system physically mounted on the system where
-the
-.Nm
-is being executed, and the latter matches any file system which is
-mounted read-only.
-.Pp
-.It Ic -group Ar gname
-True if the file belongs to the group
-.Ar gname .
-If
-.Ar gname
-is numeric and there is no such group name, then
-.Ar gname
-is treated as a group id (and considered a numeric argument).
-.Pp
-.It Ic -iname Ar pattern
-True if the last component of the pathname being examined matches
-.Ar pattern
-in a case-insensitive manner.
-Special shell pattern matching characters
-.Po
-.Dq \&[ ,
-.Dq \&] ,
-.Dq \&* ,
-and
-.Dq \&?
-.Pc
-may be used as part of
-.Ar pattern .
-These characters may be matched explicitly by escaping them with a
-backslash
-.Pq Dq \e .
-.Pp
-.It Ic -inum Ar n
-True if the file has inode number
-.Ar n .
-.Pp
-.It Ic -iregex Ar regexp
-True if the path name of the current file matches the case-insensitive
-basic regular expression
-.Pq see Xr re_format 7
-.Ar regexp .
-This is a match on the whole path, not a search for the regular expression
-within the path.
-.Pp
-.It Ic -links Ar n
+.I c,
+where
+.I c
+is
+.sp
+.TS
+lfB l.
+b block special file;
+c character special file;
+d directory;
+D Solaris door;
+f plain file;
+l symbolic link;
+n HP-UX network special file;
+p named pipe;
+s socket.
+.TE
+.TP
+.B \-follow
+Always true;
+causes find to follow symbolic links.
+The `\fB\-type\fR l' condition never occurs in this case.
+.TP
+.BR \-links " n"
True if the file has
-.Ar n
+.I n
links.
-.Pp
-.It Ic -rm
-This primary is an alias for
-.Ic -delete .
-.Pp
-.It Ic -ls
-This primary always evaluates to true.
-The following information for the current file is written to standard output:
-its inode number, size in 512-byte blocks, file permissions, number of hard
-links, owner, group, size in bytes, last modification time, and pathname.
-If the file is a block or character special file, the major and minor numbers
-will be displayed instead of the size in bytes.
-If the file is a symbolic link, the pathname of the linked-to file will be
-displayed preceded by
-.Dq -> .
-The format is identical to that produced by
-.Dq ls -dgils .
-.Pp
-.It Ic -maxdepth Ar depth
-True if the current search depth is less than or equal to what is specified in
-.Ar depth .
-.Pp
-.It Ic -mindepth Ar depth
-True if the current search depth is at least what is specified in
-.Ar depth .
-.Pp
-.It Ic -mmin Ar n
-True if the difference between the file last modification time and the time
-.Nm
-was started, rounded up to the next full minute, is
-.Ar n
-minutes.
-.Pp
-.It Ic -mtime Ar n
-True if the difference between the file last modification time and the time
-.Nm
-was started, rounded up to the next full 24-hour period, is
-.Ar n
-24-hour periods.
-.Pp
-.It Ic -ok Ar utility Oo argument ... Oc Ic \&;
+.TP
+.BR \-user " uname"
+True if the file belongs to the user
+.I uname
+(login name or numeric user ID).
+.TP
+.BR \-group " gname"
+True if the file belongs to group
+.I gname
+(group name or numeric group ID).
+.TP
+.BR \-size " n[" c ]
+True if the file is
+.I n
+blocks long (512 bytes per block),
+or, with
+.BR c ,
+.I n
+bytes long.
+.TP
+.BR \-inum " n"
+True if the file has inode number
+.I n.
+.TP
+.BR \-atime " n"
+True if the file has been accessed in
+.I n
+days.
+.TP
+.BR \-mtime " n"
+True if the file has been modified in
+.I n
+days.
+.TP
+.BR \-ctime " n"
+True if the file inode has been changed in
+.I n
+days.
+.TP
+.BR \-exec " command ... " ;
+True if the executed command returns
+a zero value as exit status.
+The end of the command must be punctuated by an (escaped)
+semicolon.
+A command argument `{}' is replaced by the
+current pathname.
+.TP
+.BR \-exec " command ... " "{} +"
+Always true.
The
-.Ic -ok
-primary is similar to the semicolon-terminated
-.Pq Dq \&;
-variant of the
-.Ic -exec
-primary, with the exception that
-.Nm
-requests user affirmation for the execution of
-.Ar utility
-by printing
-a message to the terminal and reading a response.
-If the response is other than
-.Dq y ,
-the command is not executed and the
-.Ic -ok
-primary evaluates to false.
-Set aggregation
-.Pq Do \&+ Dc termination
-is not supported.
-.Pp
-.It Ic -name Ar pattern
-True if the last component of the pathname being examined matches
-.Ar pattern .
-Special shell pattern matching characters
-.Po
-.Dq \&[ ,
-.Dq \&] ,
-.Dq \&* ,
+.B {}
+argument is replaced by a set of aggregated pathnames.
+Each pathname is passed to the command as a single argument.
+Every time a limit of arguments is reached
+by the pathnames found so far,
+the command is executed,
+and aggregating starts using a new set
+beginning with the next pathname.
+If any invocation of command
+returns a non-zero exit status,
+find will return a non-zero exit status
+when its processing is done.
+.TP
+.BR \-ok " command ... " ;
+Like
+.B \-exec
+except that the generated command is written on
+the standard output, then the standard input is read
+and the command executed only upon response
+.BR y .
+.TP
+.B \-print
+Always true;
+causes the current pathname to be printed.
+If no expression is given,
+.B \-print
+is used per default
+(as a change introduced by POSIX.2).
+.TP
+.BR \-newer " file"
+True if
+the current file has been modified more recently than the argument
+.I file.
+.TP
+.BR \-anewer " file"
+True if
+the current file has been accessed more recently than the argument
+.I file
+was modified.
+This primary is an extension.
+.TP
+.BR \-cnewer " file"
+True if a status change
+has occurred on the current file
+more recently than the argument
+.I file
+was modified.
+This primary is an extension.
+.TP
+.B \-depth
+Always true;
+causes the contents of each directory
+to be examined before the directory itselves.
+.TP
+.BR \-fstype " type"
+True if the current file
+resides on a file system of the given type.
+.TP
+.B \-local
+True if the file is on a local file system.
+Are file system types except for
+.I nfs
and
-.Dq \&?
-.Pc
-may be used as part of
-.Ar pattern .
-These characters may be matched explicitly by escaping them with a
-backslash
-.Pq Dq \e .
-.Pp
-.It Ic -newer Ar file
-True if the current file has a more recent last modification time than
-.Ar file .
-.Pp
-.It Ic -newerXY Ar reference
-For compatibility with Gnu findutils.
-.Bl -column -offset indent ".Sy findutils" ".Sy equivalent"
-.It Sy findutils Ta Sy find
-.It Sy option Ta Sy equivalent
-.It -neweraa Ta -anewer
-.It -newerat Ta -asince
-.It -newercc Ta -cnewer
-.It -newerct Ta -csince
-.It -newermm Ta -newer
-.It -newermt Ta -since
-.El
-.Pp
-Other option variants from findutils are not implemented.
-.Pp
-.It Ic -nouser
-True if the file belongs to an unknown user.
-.Pp
-.It Ic -nogroup
-True if the file belongs to an unknown group.
-.Pp
-.It Ic -path Ar pattern
-True if the pathname being examined matches
-.Ar pattern .
-Special shell pattern matching characters
-.Po
-.Dq \&[ ,
-.Dq \&] ,
-.Dq \&* ,
+.I smbfs
+are currently considered local.
+.TP
+.B \-mount
+Always true;
+restricts the search to directories
+that have the same device id
+as the currently examined path operand.
+.TP
+.B \-xdev
+The same as
+.BR \-mount .
+This primary has been introduced by POSIX.
+.TP
+.B \-nouser
+True if the file is owned by a user
+that has no login name.
+.TP
+.B \-nogroup
+True if the file is owned by a group
+that lacks a group name.
+.TP
+.B \-prune
+Always true.
+Causes the search for the current path
+to be stopped once the primary is evaluated.
+When combined with
+.BR \-depth ,
+.B \-prune
+has no effect.
+.TP
+.BR \-cpio " device"
+Always true.
+Writes the file on the named device
+in binary cpio format (5120-byte records).
+Implies
+.BR \-depth .
+.TP
+.BR \-ncpio " device"
+Always true.
+Writes the file on the named device
+in SVR4 ASCII cpio format (5120-byte records).
+Implies
+.BR \-depth .
+.PP
+The primaries may be combined using the following operators
+(in order of decreasing precedence):
+.TP 4
+1)
+A parenthesized group of primaries and operators
+(parentheses are special to the Shell and must be escaped).
+.TP 4
+2)
+The negation of a primary
+(`!' is the unary
+.I not
+operator).
+.TP 4
+3)
+Concatenation of primaries
+(the
+.I and
+operation
+is implied by the juxtaposition of two primaries
+or by an explicit
+.B \-a
+operator).
+.TP 4
+4)
+Alternation of primaries
+.RB "(`" \-o "' is the"
+.I or
+operator).
+.PP
+Options have been introduced by POSIX.1-2001
+in addition to the expression operators.
+They must preceed the
+.I pathname-list
+one the command line
+and have no effect on boolean expression processing.
+.TP
+.B \-H
+Follow symbolic links given on the command line,
+but do not follow symbolic links encountered during directory traversal.
+.TP
+.B \-L
+Follow all symbolic links found,
+like the
+.I \-follow
+primary.
+.PP
+With the
+.I \-follow
+primary or the
+.I \-L
+option, hierarchy loops caused by symbolic links are detected,
+but only
+.B /usr/5bin/posix2001/find
+prints an error message.
+The offending link is not followed,
+and operation continues with the next directory entry found.
+.SH EXAMPLES
+To remove all files named
+`a.out' or `*.o' that have not been accessed for a week:
+.IP "" .2i
+find / \\( \-name a.out \-o \-name \'*.o\' \\)
+\-atime +7 \-exec rm {} \\;
+.PP
+The rm command is executed once for each file.
+The form
+.IP "" .2i
+find / \\( \-name a.out \-o \-name \'*.o\' \\)
+\-atime +7 \-exec rm {} +
+.PP
+is faster since the rm command is executed with a set of pathnames.
+.PP
+To find all files below the directory `documents'
+that contain the regular expression `string':
+.IP "" .2i
+find documents \-type f \-exec grep string {} +
+.PP
+To find all files in the directory `home',
+not descending into its subdirectories:
+.IP "" .2i
+find home ! \-name home \-prune
+.PP
+To check whether the file `diary'
+has been updated within the last two days;
+the name of the file is printed if true,
+and is not printed otherwise:
+.IP "" .2i
+find diary \-prune \-mtime \-2
+.SH FILES
+/etc/passwd
+.br
+/etc/group
+.SH "ENVIRONMENT VARIABLES"
+.TP
+.BR LANG ", " LC_ALL
+See
+.IR locale (7).
+.TP
+.B LC_COLLATE
+Affects the collation order for range expressions,
+equivalence classes, and collation symbols in patterns with
+.BR /usr/5bin/s42/find ,
+.BR /usr/5bin/posix/find ,
and
-.Dq \&?
-.Pc
-may be used as part of
-.Ar pattern .
-These characters may be matched explicitly by escaping them with a
-backslash
-.Pq Dq \e .
-Slashes
-.Pq Dq /
-are treated as normal characters and do not have to be
-matched explicitly.
-.Pp
-.It Ic -perm Oo Fl Oc Ns Ar mode
-The
-.Ar mode
-may be either symbolic (see
-.Xr chmod 1 )
-or an octal number.
-If the mode is symbolic, a starting value of zero is assumed and the
-mode sets or clears permissions without regard to the process' file mode
-creation mask.
-If the mode is octal, only bits 07777
-.Pf ( Dv S_ISUID
-|
-.Dv S_ISGID
-|
-.Dv S_ISTXT
-|
-.Dv S_IRWXU
-|
-.Dv S_IRWXG
-|
-.Dv S_IRWXO )
-of the file's mode bits participate
-in the comparison.
-If the mode is preceded by a dash
-.Pq Dq Ic \- ,
-this primary evaluates to true
-if at least all of the bits in the mode are set in the file's mode bits.
-If the mode is not preceded by a dash, this primary evaluates to true if
-the bits in the mode exactly match the file's mode bits.
-Note, the first character of a symbolic mode may not be a dash
-.Pq Dq Ic \- .
-.Pp
-.It Ic -print
-This primary always evaluates to true.
-It prints the pathname of the current file to standard output, followed
-by a newline character.
-If none of
-.Ic -delete ,
-.Ic -exec ,
-.Ic -execdir ,
-.Ic -exit ,
-.Ic -fprint ,
-.Ic -ls ,
-.Ic -ok ,
-.Ic -print0 ,
-.Ic -printx ,
-nor
-.Ic -rm
-is specified, the given expression shall be effectively replaced by
-.Cm \&( Ns Ar given\& expression Ns Cm \&)
-.Ic -print .
-.Pp
-.It Ic -print0
-This primary always evaluates to true.
-It prints the pathname of the current file to standard output, followed
-by a NUL character.
-.Pp
-.It Ic -printx
-This primary always evaluates to true.
-It prints the pathname of the current file to standard output,
-with each space, tab, newline, backslash, dollar sign, and single,
-double, or back quotation mark prefixed by a backslash, so the output of
-.Nm
-can safely be used as input to
-.Xr xargs 1 .
-.Pp
-.It Ic -prune
-This primary always evaluates to true.
-It causes
-.Nm
-to not descend into the current file.
-Note, the
-.Ic -prune
-primary has no effect if the
-.Fl d
-option was specified.
-.Pp
-.It Ic -regex Ar regexp
-True if the path name of the current file matches the case-sensitive
-basic regular expression
-.Pq see Xr re_format 7
-.Ar regexp .
-This is a match on the whole path, not a search for the regular expression
-within the path.
-.Pp
-.It Ic -since Ar timestamp
-True if the file last modification time is more recent than
-.Ar timestamp .
-.Pp
-.It Ic -size Ar n Ns Op Cm c
-True if the file's size, rounded up, in 512-byte blocks is
-.Ar n .
-If
-.Ar n
-is followed by a
-.Dq Ic c ,
-then the primary is true if the file's size is
-.Ar n
-bytes.
-.Pp
-.It Ic -type Ar t
-True if the file is of the specified type.
-Possible file types are as follows:
-.Pp
-.Bl -tag -width flag -offset indent -compact
-.It Cm b
-block special
-.It Cm c
-character special
-.It Cm d
-directory
-.It Cm f
-regular file
-.It Cm l
-symbolic link
-.It Cm p
-FIFO
-.It Cm s
-socket
-.It Cm W
-whiteout
-.It Cm w
-whiteout
-.El
-.Pp
-.It Ic -user Ar username
-True if the file belongs to the user
-.Ar username .
-If
-.Ar username
-is numeric and there is no such user on the system, then
-.Ar username
-is treated as a user id (and considered a numeric argument).
-.Pp
-.It Ic -xdev
-This primary always evaluates to true.
-It causes find not to descend past directories that have a different
-device ID
-.Va ( st_dev ,
-see
-.Xr stat 2
-S5.6.2 [POSIX.1]).
-.El
-.Sh OPERATORS
-The primaries may be combined using the following operators.
-The operators are listed in order of decreasing precedence.
-.Bl -tag -width (expression)
-.It Cm \&( Ar expression Cm \&)
-This evaluates to true if the parenthesized expression evaluates to
-true.
-.It Cm \&! Ar expression
-This is the unary
-.Tn NOT
-operator.
-It evaluates to true if the expression is false.
-.It Ar expression Cm -and Ar expression
-.It Ar expression expression
-The
-.Cm -and
-operator is the logical
-.Tn AND
-operator.
-As it is implied by the juxtaposition of two expressions it does not
-have to be specified.
-The expression evaluates to true if both expressions are true.
-The second expression is not evaluated if the first expression is false.
-.It Ar expression Cm -or Ar expression
+.BR /usr/5bin/posix2001/find .
+.TP
+.B LC_CTYPE
+Determines the mapping of bytes to characters
+and character class expressions
+in patterns.
+.TP
+.B SYSV3
+Causes the text of some diagnostic messages to be changed;
+causes
+.I \-ncpio
+to create traditional ASCII cpio format archives.
+.SH "SEE ALSO"
+chmod(1),
+cpio(1),
+pax(1),
+sh(1),
+xargs(1),
+stat(2),
+glob(7),
+locale(7)
+.SH NOTES
+Undesired effects can result if file names printed by
+.I find
+contain newline characters,
+as shown by the following command sequence:
+.RS
+.sp
+.nf
+$ mkdir \-p \'dummy
+> /etc\'
+$ touch \'dummy
+> /etc/passwd\'
+$ find . \-print
+\&.
+\&./dummy
+.sp
+\&./dummy
+/etc
+\&./dummy
+/etc/passwd
+$\
+.fi
+.sp
+.RE
+Shell scripts or utilities unaware of this problem
+will operate on
+.I /etc/passwd
+(or other arbitrary file names)
+when reading such output;
+a malicious user might create such files
+to read or overwrite privileged information.
+To circumvent this problem,
+one of the following proposals should be taken
+unless the file hierarchy traversed by the
+.I find
+command is definitively known not to contain such file names:
+.IP \(en 2
+If the output is read by the
+.I xargs
+utility to gain faster execution by aggregating command arguments as in
+.in +2
+.sp
+find . \-print | xargs \fIcommand\fR
+.sp
+.in -2
+a safe and equally fast substitute is the
+.in +2
+.sp
+find . \-exec \fIcommand\fR {} +
+.sp
+.in -2
+operand of
+.IR find ;
+it is not portably accepted by
+.I find
+implementations, though.
+.IP \(en 2
+A universal solution for submitting file names to the
+.I xargs
+utility is given in the
+.I NOTES
+section of
+.IR xargs (1).
+.IP \(en 2
+The method employed by this script can be generalized as follows:
+If the script or utility reading the output of
+.I find
+provides the necessary parsing capabilities,
+special path prefixes can be given to the
+.I find
+command, such as
+.in +2
+.sp
+find /.//. \-print
+.sp
+.in -2
+for absolute path names or
+.in +2
+.sp
+find .//. \-print
+.sp
+.in -2
+for relative path names.
+Since adjacent slash characters never appear
+in relative file names found during directory traversal,
+they can be taken as delimiters;
+a line starts a new path name
+only if the delimiter appears.
+.IP \(en 2
The
-.Cm -or
-operator is the logical
-.Tn OR
-operator.
-The expression evaluates to true if either the first or the second expression
-is true.
-The second expression is not evaluated if the first expression is true.
-.El
-.Pp
-All operands and primaries must be separate arguments to
-.Nm .
-Primaries which themselves take arguments expect each argument
-to be a separate argument to
-.Nm .
-.Sh EXIT STATUS
+.I \-name
+operand can be used to exclude all path names
+that contain newline characters, as in
+.in +2
+.sp
+.nf
+$ find . \-name \'*
+> *\' \-prune \-o ! \-name \'*
+> *\' \-print
+.sp
+.fi
+.in -2
+Note that certain other implementations of
+.I find
+require a leading period in the pattern
+to match file names with a leading period;
+it may be necessary to exclude such patterns as well.
+.IP \(en 2
The
-.Nm
-utility normally exits 0 on success, and exits with 1 under certain
-internal error conditions.
-If any invocations of
-.Dq Ic -exec Ar ... Ic \&+
-primaries return non-zero exit-status, then
-.Nm
-will do so as well.
-.Sh EXAMPLES
-The following examples are shown as given to the shell:
-.Bl -tag -width findx
-.It Li "find / \e! -name \*q*.c\*q \-print"
-Print out a list of all the files whose names do not end in
-.Dq \&.c .
-.It Li "find / \-newer ttt \-user wnj \-print"
-Print out a list of all the files owned by user
-.Dq wnj
-that are newer than the file
-.Dq ttt .
-.It Li "find . \-type f \-mmin \-30 \-print \-or \-mindepth 1 \-prune"
-Print out a list of all the files in the current directory that are
-newer than 30 minutes.
-.It Li "find . \-type f \-atime +10 \-mindepth 2 \-print"
-Print out a list of all the files in any sub-directories that have not
-been accessed in the past ten days.
-.It Li "find . \-mtime +90 \-exec rm \-i {} + \-or \-mindepth 1 \-prune"
-Interactively remove all of the files in the current directory that have
-not been modified in 90 days.
-.It Li "find . \-type f \-mtime +90 \-ok mv {} {}.old \e;"
-Interactively rename all of the files in the current directory and all
-sub-directories that have not been modified in 90 days.
-.It Li "find / \e! \e( \-newer ttt \-user wnj \e) \-print"
-Print out a list of all the files which are not both newer than
-.Dq ttt
-and owned by
-.Dq wnj .
-.It Li "find / \e( \-newer ttt \-or \-user wnj \e) \-print"
-Print out a list of all the files that are either owned by
-.Dq wnj
-or that are newer than
-.Dq ttt .
-.It Li "find / \e( \-newer ttt \-or \-user wnj \e) \-exit 1"
-Return immediately with a value of 1 if any files are found that are either
-owned by
-.Dq wnj
-or that are newer than
-.Dq ttt ,
-but do not print them.
-.It Li "find / \e( \-newer ttt \-or \-user wnj \e) \-ls \-exit 1"
-Same as above, but list the first file matching the criteria before exiting
-with a value of 1.
-.It Li "find . \-type f \-exec sh \-c 'file=\*[q]$1\*[q]; ...;' - {} \;"
-Perform an arbitrarily complex shell command for every file.
-.El
-.Sh SEE ALSO
-.Xr chflags 1 ,
-.Xr chmod 1 ,
-.Xr locate 1 ,
-.Xr xargs 1 ,
-.Xr stat 2 ,
-.Xr fts 3 ,
-.Xr getgrent 3 ,
-.Xr getpwent 3 ,
-.Xr strmode 3 ,
-.Xr re_format 7 ,
-.Xr symlink 7 ,
-.Xr sysctl 8
-.Sh STANDARDS
+.I \-depth
+operand cannot be combined with the
+.I \-prune
+operand used in the previous example.
+When the directory name must be printed
+after file names below that directory,
+as with the
+.IR cpio
+command,
+file names that leave the specified path hierarchy
+should be filtered out:
+.in +2
+.sp
+find . \-depth | egrep \'^\e./\' | cpio \-oc \-O /dev/rmt/c0s0
+.sp
+.in -2
+(note the escaped regular expression meta-character).
+.IP \(en 2
The
-.Nm
-utility syntax is a superset of the syntax specified by the
-.St -p1003.2
-standard.
-.Pp
-The options and the
-.Ic -amin ,
-.Ic -anewer ,
-.Ic -asince ,
-.Ic -cmin ,
-.Ic -cnewer ,
-.Ic -csince ,
-.Ic -delete ,
-.Ic -empty ,
-.Ic -execdir ,
-.Ic -follow ,
-.Ic -fstype ,
-.Ic -iname ,
-.Ic -inum ,
-.Ic -iregex ,
-.Ic -links ,
-.Ic -ls ,
-.Ic -maxdepth ,
-.Ic -mindepth ,
-.Ic -mmin ,
-.Ic -path ,
-.Ic -print0 ,
-.Ic -printx ,
-.Ic -regex ,
-.Ic -rm ,
-and
-.Ic -since
-primaries are extensions to
-.St -p1003.2 .
-.Pp
-Historically, the
-.Fl d ,
-.Fl h ,
+.I \-cpio
and
-.Fl x
-options were implemented using the primaries
-.Dq Ic -depth ,
-.Dq Ic -follow ,
-and
-.Dq Ic -xdev .
-These primaries always evaluated to true, and always
-took effect when the
-.Ar expression
-was parsed, before the file system traversal began.
-As a result, some legal expressions could be confusing.
-For example, in the expression
-.Dq Ic -print Ic -or Ic -depth ,
-.Ic -print
-always evaluates to true, so the standard meaning of
-.Ic -or
-implies that
-.Ic -depth
-would never be evaluated, but that is not what happens;
-in fact,
-.Ic -depth
-takes effect immediately, without testing whether
-.Ic -print
-returns true or false.
-.Pp
-Historically, the operator
-.Dq Ic -or
-was implemented as
-.Dq Ic -o ,
-and the operator
-.Dq Ic -and
-was implemented as
-.Dq Ic -a .
-.Pp
-Historic implementations of the
-.Dq Ic -exec
-and
-.Dq Ic -ok
-primaries did not replace the string
-.Dq Ic {}
-in the utility name or the
-utility arguments if it did not appear as a separate argument.
-This version replaces it no matter where in the utility name or arguments
-it appears.
-.Pp
-Support for
-.Dq Ic -exec Ar ... Ic \&+
-is consistent with
-.Em IEEE PASC Interpretation 1003.2 #210 ,
-though the feature originated in
-.Tn SVR4 .
-.Pp
+.I \-ncpio
+operands will automatically exclude file names
+that contain newline characters
+with this
+.I find
+implementation.
+.PP
The
-.Ic -delete
-primary does not interact well with other options that cause the file system
-tree traversal options to be changed.
-.Sh HISTORY
-A much simpler
-.Nm
-command appeared in First Edition AT&T Unix.
-The syntax had become similar to the present version by
-the time of the Fifth Edition.
-.Sh BUGS
-The special characters used by
-.Nm
-are also special characters to many shell programs.
-In particular, the characters
-.Dq \&* ,
-.Dq \&[ ,
-.Dq \&] ,
-.Dq \&? ,
-.Dq \&( ,
-.Dq \&) ,
-.Dq \&! ,
-.Dq \e ,
-and
-.Dq \&;
-may have to be escaped from the shell.
-.Pp
-As there is no delimiter separating options and file names or file
-names and the
-.Ar expression ,
-it is difficult to specify files named
-.Dq -xdev
-or
-.Dq \&! .
-These problems are handled by the
-.Fl f
-option and the
-.Xr getopt 3
-.Dq --
-construct.
+.I \-print0
+operand supported by some other implementations
+is considered a very limited work-around
+since it does not allow the output to be processed
+by utilities unaware of NUL characters;
+it has therefore not been included here.
diff --git a/usr.bin/find/find.c b/usr.bin/find/find.c
index 7b966bd..c56fedc 100644
--- a/usr.bin/find/find.c
+++ b/usr.bin/find/find.c
@@ -1,297 +1,1533 @@
-/* $NetBSD: find.c,v 1.30 2016/06/13 00:04:40 pgoyette Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Cimarron D. Taylor of the University of California, Berkeley.
+/* find COMPILE: cc -o find -s -O -i find.c -lS */
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, September 2003.
+ */
+/* from Unix 7th Edition /usr/src/cmd/find.c */
+/*
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
+ * Redistributions of source code and documentation must retain the
+ * above copyright notice, this list of conditions and the following
+ * disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed or owned by Caldera
+ * International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of
+ * other contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
+ * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/types.h>
-#include <sys/stat.h>
+#if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
+#define USED __attribute__ ((used))
+#elif defined __GNUC__
+#define USED __attribute__ ((unused))
+#else
+#define USED
+#endif
+#if defined (SU3)
+static const char sccsid[] USED = "@(#)find_su3.sl 1.45 (gritter) 5/8/06";
+#elif defined (SUS)
+static const char sccsid[] USED = "@(#)find_sus.sl 1.45 (gritter) 5/8/06";
+#else
+static const char sccsid[] USED = "@(#)find.sl 1.45 (gritter) 5/8/06";
+#endif
-#include <err.h>
-#include <errno.h>
-#include <fts.h>
-#include <signal.h>
#include <stdio.h>
-#include <string.h>
#include <stdlib.h>
-#include <stdbool.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include <fcntl.h>
#include <unistd.h>
+#include <pwd.h>
+#include <time.h>
+#include <grp.h>
+#include <stdarg.h>
+#include <libgen.h>
+#include <errno.h>
+#include <locale.h>
+#include <signal.h>
+#include <fnmatch.h>
+#include <mntent.h>
+#ifndef major
+#include <sys/mkdev.h>
+#endif
+#if __NetBSD_Version__>= 300000000
+#include <sys/statvfs.h>
+#define statfs statvfs
+#endif
+#include "getdir.h"
+#define A_DAY 86400L /* a day full of seconds */
+#define EQ(x, y) (strcmp(x, y)==0)
+
+#ifndef MNTTYPE_IGNORE
+#define MNTTYPE_IGNORE ""
+#endif
+
+#ifndef S_IFDOOR
+#define S_IFDOOR 0xD000
+#endif
-#include "find.h"
+#ifndef S_IFNWK
+#define S_IFNWK 0x9000
+#endif
-static int ftscompare(const FTSENT **, const FTSENT **);
+#undef ctime
+#define ctime find_ctime
+
+static char *Pathname;
+
+struct aggregate { /* for exec ... {} + */
+ long a_cnt; /* count of arguments */
+ long a_cur; /* current position in aggregate */
+ long a_csz; /* aggregate current length */
+ long a_msz; /* aggregate maximum length */
+ char **a_vec; /* arguments */
+ char *a_spc; /* aggregate space */
+ long a_maxarg; /* maximum arguments in e_vec */
+};
+
+struct anode {
+ int (*F)(struct anode *);
+ union anode_l {
+ struct anode *L;
+ char *pat;
+ time_t t;
+ uid_t u;
+ gid_t g;
+ ino_t i;
+ nlink_t link;
+ off_t sz;
+ mode_t per;
+ int com;
+ FILE *fp;
+ char *fstype;
+ } l;
+ union anode_r {
+ struct anode *R;
+ int s;
+ pid_t pid;
+ struct aggregate *a;
+ } r;
+};
+static char *Fname;
+static time_t Now;
+static int Argc,
+ Ai,
+ Pi;
+static char **Argv;
+/* cpio stuff */
+static int Cpio;
+
+static struct stat Statb;
/*
- * find_formplan --
- * process the command line and create a "plan" corresponding to the
- * command arguments.
+ * Keep track of all visited directories, to avoid loops caused by
+ * symbolic links and to free storage and close files after fork().
*/
-PLAN *
-find_formplan(char **argv)
-{
- PLAN *plan, *tail, *new;
-
- /*
- * for each argument in the command line, determine what kind of node
- * it is, create the appropriate node type and add the new plan node
- * to the end of the existing plan. The resulting plan is a linked
- * list of plan nodes. For example, the string:
- *
- * % find . -name foo -newer bar -print
- *
- * results in the plan:
- *
- * [-name foo]--> [-newer bar]--> [-print]
- *
- * in this diagram, `[-name foo]' represents the plan node generated
- * by c_name() with an argument of foo and `-->' represents the
- * plan->next pointer.
- */
- for (plan = tail = NULL; *argv;) {
- if (!(new = find_create(&argv)))
- continue;
- if (plan == NULL)
- tail = plan = new;
- else {
- tail->next = new;
- tail = new;
+static struct visit {
+ struct getdb *v_db; /* getdb struct for this level */
+ ino_t v_ino; /* inode number */
+ int v_fd; /* file descriptor */
+ dev_t v_dev; /* device id */
+} *visited;
+static int vismax; /* number of members in visited */
+
+/*
+ * For -fstype, keep track of all filesystem types known to the system. If
+ * we had st_fstype in struct stat as SVR4 does, this would be far more
+ * reliable.
+ */
+#if defined (__linux__) || defined (_AIX) || defined (__hpux)
+static struct fstype {
+ dev_t fsdev; /* device id of filesystem */
+ char *fstype; /* filesystem type */
+} *fstypes, *fscur;
+#endif /* __linux__ || _AIX || __hpux */
+
+static int Home = -1;
+static int wanthome;
+static mode_t um; /* user's umask */
+static const char *progname;
+static int status; /* exit status */
+static int depth; /* -depth flag */
+static int Print = 1; /* implicit -print */
+static int Prune; /* -prune at this point */
+static int Mount; /* -mount, -xdev */
+static int Execplus; /* have a -exec command {} + node */
+static int HLflag; /* -H or -L option given */
+static char *Statfs; /* result of statfs() on FreeBSD */
+static int incomplete; /* encountered an incomplete statement */
+static int sysv3;
+
+static int (*statfn)(const char *, struct stat *) = lstat;
+
+static struct anode *expr(void);
+static struct anode *e1(void);
+static struct anode *e2(void);
+static struct anode *e3(void);
+static struct anode *mk(struct anode *);
+static void oper(const char **);
+static char *nxtarg(int);
+static int and(struct anode *);
+static int or(struct anode *);
+static int not(struct anode *);
+static int glob(struct anode *);
+static int print(struct anode *);
+static int prune(struct anode *);
+static int null(struct anode *);
+static int mtime(struct anode *);
+static int atime(struct anode *);
+static int ctime(struct anode *);
+static int user(struct anode *);
+static int ino(struct anode *);
+static int group(struct anode *);
+static int nogroup(struct anode *);
+static int nouser(struct anode *);
+static int links(struct anode *);
+static int size(struct anode *);
+static int sizec(struct anode *);
+static int perm(struct anode *);
+static int type(struct anode *);
+static int exeq(struct anode *);
+static int ok(struct anode *);
+static int cpio(struct anode *);
+static int newer(struct anode *);
+static int cnewer(struct anode *);
+static int anewer(struct anode *);
+static int fstype(struct anode *);
+static int local(struct anode *);
+static int scomp(long long, long long, char);
+static int doex(int, struct aggregate *);
+static struct aggregate *mkagg(long);
+static uid_t getunum(const char *);
+static gid_t getgnum(const char *);
+static const char *getuser(uid_t);
+static const char *getgroup(gid_t);
+#if defined (__linux__) || defined (_AIX) || defined (__hpux)
+static void getfscur(dev_t);
+static void getfstypes(void);
+#endif /* __linux__ || _AIX || __hpux */
+static int descend(char *, struct anode *, int);
+static int descend1(char *, struct anode *, int);
+static int descend2(char *, struct anode *, int);
+static void setpath(char *, const char *, int);
+static void pr(const char *, ...);
+static void er(const char *, ...);
+static void usage(void);
+static void *srealloc(void *, size_t);
+static void mkcpio(struct anode *, const char *, int);
+static void trailer(struct anode *, int);
+static void mknewer(struct anode *, const char *, int (*)(struct anode *));
+static mode_t newmode(const char *ms, const mode_t pm);
+
+int
+main(int argc, char **argv)
+{
+ struct anode *exlist;
+ struct anode nlist = { null, { 0 }, { 0 } };
+ int paths;
+ register char *sp = 0;
+ int i, j;
+
+ time(&Now);
+ umask(um = umask(0));
+ progname = basename(argv[0]);
+ setlocale(LC_COLLATE, "");
+ setlocale(LC_CTYPE, "");
+ if (getenv("SYSV3") != NULL)
+ sysv3 = 1;
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] != '-' || argv[i][1] == '\0')
+ break;
+ if (argv[i][1] == '-') {
+ i++;
+ break;
+ }
+ for (j = 1; argv[i][j]; j++)
+ if (argv[i][j] != 'H' && argv[i][j] != 'L')
+ goto brk;
+ for (j = 1; argv[i][j]; j++)
+ HLflag = argv[i][j];
+ }
+brk: if (HLflag == 'L')
+ statfn = stat;
+ argc -= i - 1;
+ argv += i - 1;
+ Argc = argc; Argv = argv;
+ if(argc<2) {
+ pr("insufficient number of arguments");
+ usage();
+ }
+ for(Ai = paths = 1; Ai < argc; ++Ai, ++paths)
+ if(*Argv[Ai] == '-' || EQ(Argv[Ai], "(") || EQ(Argv[Ai], "!"))
+ break;
+ if(paths == 1) /* no path-list */
+ usage();
+ if(Ai<argc) {
+ if(!(exlist = expr())) /* parse and compile the arguments */
+ er("find: parsing error");
+ if(Ai<argc) {
+ pr("bad option %s", argv[Ai]);
+ usage();
}
+ } else
+ exlist = &nlist;
+ if (paths > 2)
+ wanthome = 1;
+ if (wanthome && (Home = open(".", O_RDONLY)) < 0)
+ er("bad starting directory");
+ for(Pi = 1; Pi < paths; ++Pi) {
+ if (Pi > 1 && Home >= 0 && fchdir(Home) < 0)
+ er("bad starting directory");
+ setpath(Pathname, Argv[Pi], 0);
+ Fname = sp = Pathname;
+ do
+ if (sp[0] == '/')
+ Fname = &sp[1];
+ while (*sp++);
+ descend(Pathname, exlist, 0); /* to find files that match */
+ }
+ if(Cpio || Execplus)
+ trailer(exlist, 1);
+ exit(status);
+}
+
+/* compile time functions: priority is expr()<e1()<e2()<e3() */
+
+/*ARGSUSED*/
+static struct anode *expr(void) { /* parse ALTERNATION (-o) */
+ register struct anode * p1;
+ struct anode n = { 0, { 0 }, { 0 } };
+
+ p1 = e1() /* get left operand */ ;
+ if(EQ(nxtarg(0), "-o")) {
+ const char *ops[] = { "-o", "-a", 0 };
+ oper(ops);
+ n.F = or, n.l.L = p1, n.r.R = expr();
+ return(mk(&n));
+ }
+ else if(Ai <= Argc) --Ai;
+ return(p1);
+}
+static struct anode *e1(void) { /* parse CONCATENATION (formerly -a) */
+ register struct anode * p1;
+ register char *a;
+ struct anode n = { 0, { 0 }, { 0 } };
+
+ p1 = e2();
+ a = nxtarg(0);
+ if(EQ(a, "-a")) {
+ const char *ops[] = { "-o", "-a", 0 };
+ oper(ops);
+And:
+ n.F = and, n.l.L = p1, n.r.R = e1();
+ return(mk(&n));
+ } else if(EQ(a, "(") || EQ(a, "!") || (*a=='-' && !EQ(a, "-o"))) {
+ --Ai;
+ goto And;
+ } else if(Ai <= Argc) --Ai;
+ return(p1);
+}
+static struct anode *e2(void) { /* parse NOT (!) */
+ struct anode n = { 0, { 0 }, { 0 } };
+ if(EQ(nxtarg(0), "!")) {
+ const char *ops[] = { "-o", "-a", "!", 0 };
+ oper(ops);
+ n.F = not, n.l.L = e3();
+ return(mk(&n));
+ }
+ else if(Ai <= Argc) --Ai;
+ return(e3());
+}
+static struct anode *e3(void) { /* parse parens and predicates */
+ struct anode *p1;
+ struct anode n = { 0, { 0 }, { 0 } };
+ long i, k;
+ register char *a, *b, s, *p, *q;
+
+ a = nxtarg(0);
+ if(EQ(a, "(")) {
+ const char *ops[] = { "-o", "-a", 0 };
+ oper(ops);
+ p1 = expr();
+ a = nxtarg(1);
+ if(!EQ(a, ")")) goto err;
+ return(p1);
+ }
+ else if(EQ(a, "-depth")) {
+ depth = 1;
+ n.F = null;
+ } else if(EQ(a, "-follow")) {
+ statfn = stat;
+ n.F = null;
+ } else if(EQ(a, "-mount") || EQ(a, "-xdev")) {
+ Mount = 1;
+ n.F = null;
+ } else if(EQ(a, "-print")) {
+ Print = 0;
+ n.F = print;
+ } else if(EQ(a, "-prune"))
+ n.F = prune;
+ else if(EQ(a, "-nogroup"))
+ n.F = nogroup;
+ else if(EQ(a, "-nouser"))
+ n.F = nouser;
+ else if(EQ(a, "-local")) {
+#if defined (__linux__) || defined (_AIX) || defined (__hpux)
+ getfstypes();
+#endif /* __linux__ || _AIX || __hpux */
+ n.F = local;
+ Statfs = a;
+ }
+ if (n.F)
+ return mk(&n);
+ b = nxtarg(2);
+ s = *b;
+ /*if(s=='+') b++;*/
+ if(EQ(a, "-name"))
+ n.F = glob, n.l.pat = b;
+ else if(EQ(a, "-mtime"))
+ n.F = mtime, n.l.t = atol(b), n.r.s = s;
+ else if(EQ(a, "-atime"))
+ n.F = atime, n.l.t = atol(b), n.r.s = s;
+ else if(EQ(a, "-ctime"))
+ n.F = ctime, n.l.t = atol(b), n.r.s = s;
+ else if(EQ(a, "-user"))
+ n.F = user, n.l.u = getunum(b), n.r.s = s;
+ else if(EQ(a, "-inum"))
+ n.F = ino, n.l.i = atoll(b), n.r.s = s;
+ else if(EQ(a, "-group"))
+ n.F = group, n.l.g = getgnum(b), n.r.s = s;
+ else if(EQ(a, "-size")) {
+ n.l.sz = atoll(b), n.r.s = s;
+ while (b[0] && b[1])
+ b++;
+ if (b[0] == 'c')
+ n.F = sizec;
+ else
+ n.F = size;
+ }
+ else if(EQ(a, "-links"))
+ n.F = links, n.l.link = atol(b), n.r.s = s;
+ else if(EQ(a, "-perm")) {
+ while (*b == '-')
+ b++;
+ n.F = perm, n.l.per = newmode(b, 0), n.r.s = s;
+#if defined (SUS) || defined (SU3)
+ if (s == '-')
+ n.l.per &= 07777;
+#endif
+ }
+ else if(EQ(a, "-type")) {
+ i = b[0] == '-' || b[0] == '+' ? b[1] : b[0];
+ i = i=='d' ? S_IFDIR :
+ i=='b' ? S_IFBLK :
+ i=='c' ? S_IFCHR :
+ i=='D' ? S_IFDOOR :
+ i=='f' ? S_IFREG :
+ i=='l' ? S_IFLNK :
+ i=='n' ? S_IFNWK :
+ i=='p' ? S_IFIFO :
+ i=='s' ? S_IFSOCK :
+ 0;
+ n.F = type, n.l.per = i;
+ }
+ else if (EQ(a, "-exec")) {
+ Print = 0;
+ wanthome = 1;
+ i = Ai - 1;
+ q = "";
+ k = 0;
+ while(!EQ(p = nxtarg(1), ";")) {
+ if (EQ(p, "+") && EQ(q, "{}")) {
+ n.r.a = mkagg(k);
+ break;
+ }
+ q = p;
+ k += strlen(p) + 1;
+ }
+ n.F = exeq, n.l.com = i;
+ }
+ else if (EQ(a, "-ok")) {
+ Print = 0;
+ wanthome = 1;
+ i = Ai - 1;
+ while(!EQ(p = nxtarg(1), ";"));
+ n.F = ok, n.l.com = i;
+ }
+ else if(EQ(a, "-cpio"))
+ mkcpio(&n, b, 0);
+ else if(EQ(a, "-ncpio"))
+ mkcpio(&n, b, 1);
+ else if(EQ(a, "-newer"))
+ mknewer(&n, b, newer);
+ else if(EQ(a, "-anewer"))
+ mknewer(&n, b, anewer);
+ else if(EQ(a, "-cnewer"))
+ mknewer(&n, b, cnewer);
+ else if(EQ(a, "-fstype")) {
+#if defined (__linux__) || defined (_AIX) || defined (__hpux)
+ getfstypes();
+#endif /* __linux__ || _AIX || __hpux */
+ n.F = fstype, n.l.fstype = b;
+ Statfs = a;
+ }
+ if (n.F) {
+ if (incomplete)
+ nxtarg(1);
+ return mk(&n);
+ }
+err: pr("bad option %s", a);
+ usage();
+ /*NOTREACHED*/
+ return 0;
+}
+static struct anode *mk(struct anode *p)
+{
+ struct anode *n;
+
+ n = srealloc(NULL, sizeof *n);
+ *n = *p;
+ return(n);
+}
+static void oper(const char **ops)
+{
+ char *a;
+
+ a = nxtarg(-1);
+ while (*ops)
+ if (EQ(a, *ops++))
+ er("operand follows operand");
+ Ai--;
+}
+
+static char *nxtarg(int must) { /* get next arg from command line */
+ static int strikes = 0;
+
+ if(must==1 && Ai>=Argc || strikes==3)
+ er("incomplete statement");
+ if(Ai>=Argc) {
+ if (must >= 0)
+ strikes++;
+ incomplete = 1;
+ Ai = Argc + 1;
+ return("");
}
+ return(Argv[Ai++]);
+}
- /*
- * if the user didn't specify one of -print, -ok, -fprint, -exec, or
- * -exit, then -print is assumed so we bracket the current expression
- * with parens, if necessary, and add a -print node on the end.
- */
- if (!isoutput) {
- if (plan == NULL) {
- new = c_print(NULL, 0, NULL);
- tail = plan = new;
+/* execution time functions */
+static int and(register struct anode *p)
+{
+ return(((*p->l.L->F)(p->l.L)) && ((*p->r.R->F)(p->r.R))?1:0);
+}
+static int or(register struct anode *p)
+{
+ return(((*p->l.L->F)(p->l.L)) || ((*p->r.R->F)(p->r.R))?1:0);
+}
+static int not(register struct anode *p)
+{
+ return( !((*p->l.L->F)(p->l.L)));
+}
+static int glob(register struct anode *p)
+{
+ int val;
+#ifdef __GLIBC__
+ /* avoid glibc's broken [^...] */
+ extern char **environ;
+ char **savenv = environ;
+ char *newenv[] = { "POSIXLY_CORRECT=", NULL };
+ environ = newenv;
+#endif /* __GLIBC__ */
+ val = fnmatch(p->l.pat, Fname, FNM_PATHNAME) == 0;
+#ifdef __GLIBC__
+ environ = savenv;
+#endif /* __GLIBC__ */
+ return val;
+}
+/*ARGSUSED*/
+static int print(register struct anode *p)
+{
+ puts(Pathname);
+ return(1);
+}
+/*ARGSUSED*/
+static int prune(register struct anode *p)
+{
+ if (!depth)
+ Prune = 1;
+ return(1);
+}
+/*ARGSUSED*/
+static int null(register struct anode *p)
+{
+ return(1);
+}
+static int mtime(register struct anode *p)
+{
+ return(scomp((Now - Statb.st_mtime) / A_DAY, p->l.t, p->r.s));
+}
+static int atime(register struct anode *p)
+{
+ return(scomp((Now - Statb.st_atime) / A_DAY, p->l.t, p->r.s));
+}
+static int ctime(register struct anode *p)
+{
+ return(scomp((Now - Statb.st_ctime) / A_DAY, p->l.t, p->r.s));
+}
+static int user(register struct anode *p)
+{
+ return(scomp(Statb.st_uid, p->l.u, p->r.s));
+}
+static int ino(register struct anode *p)
+{
+ return(scomp(Statb.st_ino, p->l.u, p->r.s));
+}
+static int group(register struct anode *p)
+{
+ return(p->l.u == Statb.st_gid);
+}
+static int nogroup(register struct anode *p)
+{
+ return(getgroup(Statb.st_gid) == NULL);
+}
+static int nouser(register struct anode *p)
+{
+ return(getuser(Statb.st_uid) == NULL);
+}
+static int links(register struct anode *p)
+{
+ return(scomp(Statb.st_nlink, p->l.link, p->r.s));
+}
+static int size(register struct anode *p)
+{
+ return(scomp(Statb.st_size?(Statb.st_size+511)>>9:0, p->l.sz, p->r.s));
+}
+static int sizec(register struct anode *p)
+{
+ return(scomp(Statb.st_size, p->l.sz, p->r.s));
+}
+static int perm(register struct anode *p)
+{
+ register int i;
+ i = (p->r.s=='-') ? p->l.per : 07777; /* '-' means only arg bits */
+ return((Statb.st_mode & i & 07777) == p->l.per);
+}
+static int type(register struct anode *p)
+{
+ return((Statb.st_mode&S_IFMT)==p->l.per);
+}
+static int exeq(register struct anode *p)
+{
+ if (p->r.a) {
+ if (Pathname) {
+ size_t sz = strlen(Pathname) + 1;
+ if (p->r.a->a_csz + sz <= p->r.a->a_msz &&
+ p->r.a->a_cur < p->r.a->a_maxarg-1) {
+ strcpy(p->r.a->a_vec[p->r.a->a_cur++] =
+ &p->r.a->a_spc[p->r.a->a_csz],
+ Pathname);
+ p->r.a->a_csz += sz;
+ return 1;
+ } else {
+ if (p->r.a->a_cur == 0) {
+ p->r.a->a_vec[p->r.a->a_cur++] =
+ Pathname;
+ p->r.a->a_vec[p->r.a->a_cur] = NULL;
+ }
+ else {
+ p->r.a->a_vec[p->r.a->a_cur] = NULL;
+ fflush(stdout);
+ doex(p->l.com, p->r.a);
+ return exeq(p);
+ }
+ }
} else {
- new = c_openparen(NULL, 0, NULL);
- new->next = plan;
- plan = new;
- new = c_closeparen(NULL, 0, NULL);
- tail->next = new;
- tail = new;
- new = c_print(NULL, 0, NULL);
- tail->next = new;
- tail = new;
+ if (p->r.a->a_cur == 0)
+ return 1;
+ p->r.a->a_vec[p->r.a->a_cur] = NULL;
}
}
+ fflush(stdout); /* to flush possible `-print' */
+ return(doex(p->l.com, p->r.a));
+}
+static int ok(struct anode *p)
+{
+ char c; int yes;
+ yes = 0;
+ fflush(stdout); /* to flush possible `-print' */
+ fprintf(stderr, "< %s ... %s >? ", Argv[p->l.com], Pathname);
+ if (read(0, &c, 1) != 1)
+ exit(2);
+ yes = c == 'y';
+ if (c != '\n')
+ while (read(0, &c, 1) == 1 && c != '\n');
+ if(yes) return(doex(p->l.com, 0));
+ return(0);
+}
- /*
- * the command line has been completely processed into a search plan
- * except for the (, ), !, and -o operators. Rearrange the plan so
- * that the portions of the plan which are affected by the operators
- * are moved into operator nodes themselves. For example:
- *
- * [!]--> [-name foo]--> [-print]
- *
- * becomes
- *
- * [! [-name foo] ]--> [-print]
- *
- * and
- *
- * [(]--> [-depth]--> [-name foo]--> [)]--> [-print]
- *
- * becomes
- *
- * [expr [-depth]-->[-name foo] ]--> [-print]
- *
- * operators are handled in order of precedence.
- */
-
- plan = paren_squish(plan); /* ()'s */
- plan = not_squish(plan); /* !'s */
- plan = or_squish(plan); /* -o's */
- return (plan);
+static int cpio(struct anode *p)
+{
+ if (strchr(Pathname, '\n')) {
+ pr("file name \"%s\" contains a newline character; "
+ "file not archived", Pathname);
+ status |= 1;
+ } else
+ fprintf(p->l.fp, "%s\n", Pathname);
+ return(1);
+}
+static int newer(register struct anode *p)
+{
+ return Statb.st_mtime > p->l.t;
+}
+static int anewer(register struct anode *p)
+{
+ return Statb.st_atime > p->l.t;
+}
+static int cnewer(register struct anode *p)
+{
+ return Statb.st_ctime > p->l.t;
+}
+static int fstype(register struct anode *p)
+{
+#if defined (__linux__) || defined (_AIX) || defined (__hpux)
+ return(EQ(fscur->fstype, p->l.fstype));
+#elif defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
+ || defined (__DragonFly__) || defined (__APPLE__)
+ return(EQ(Statfs, p->l.fstype));
+#else
+ return(EQ(Statb.st_fstype, p->l.fstype));
+#endif
+}
+static int local(register struct anode *p)
+{
+#if defined (__linux__) || defined (_AIX) || defined (__hpux)
+ return(strcmp(fscur->fstype, "nfs") && strcmp(fscur->fstype, "smbfs"));
+#elif defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \
+ || defined (__DragonFly__) || defined (__APPLE__)
+ return(strcmp(Statfs, "nfs") != 0);
+#else
+ return(strcmp(Statb.st_fstype, "nfs") != 0);
+#endif
+}
+
+/* support functions */
+/* funny signed compare */
+static int scomp(register long long a, register long long b, register char s)
+{
+ if(s == '+')
+ return(a > b);
+ if(s == '-')
+ return(a < (b * -1));
+ return(a == b);
}
static int
-ftscompare(const FTSENT **e1, const FTSENT **e2)
+doex(int com, struct aggregate *a)
+{
+ register int np;
+ register char *na;
+ char **oargv;
+ int oargc;
+ static char **nargv;
+ static int narga;
+ static int ccode;
+ pid_t pid;
+
+ ccode = np = 0;
+ oargv = Argv;
+ oargc = com;
+ while (na=oargv[oargc++]) {
+ if (np >= narga-1)
+ nargv = srealloc(nargv, (narga+=20) * sizeof *nargv);
+ if(strcmp(na, ";")==0 && oargv == Argv) break;
+ if(strcmp(na, "{}")==0 && oargv == Argv) {
+ if (a) {
+ oargv = a->a_vec;
+ oargc = 0;
+ } else
+ nargv[np++] = Pathname;
+ }
+ else nargv[np++] = na;
+ }
+ if (a) {
+ a->a_cur = 0;
+ a->a_csz = 0;
+ }
+ if (np==0) return(9);
+ nargv[np] = 0;
+ if(pid = fork()) /*parent*/ while (wait(&ccode) != pid);
+ else { /*child*/
+ if (fchdir(Home) < 0) {
+ pr("bad starting directory");
+ _exit(1);
+ }
+ execvp(nargv[0], nargv);
+ _exit(1);
+ }
+ if (a && ccode) {
+ if (WIFSIGNALED(ccode))
+ status |= WTERMSIG(ccode) | 0200;
+ else if (WIFEXITED(ccode))
+ status |= WEXITSTATUS(ccode);
+ }
+ return(ccode && a==NULL ? 0:1);
+}
+
+static struct aggregate *mkagg(long baselen)
{
+ static size_t envsz;
+ extern char **environ;
+ register int i;
+ struct aggregate *a;
- return (strcoll((*e1)->fts_name, (*e2)->fts_name));
+ a = srealloc(NULL, sizeof *a);
+ if (envsz == 0)
+ for (i = 0; environ[i]; i++)
+ envsz += strlen(environ[i]) + 1;
+ a->a_msz = sysconf(_SC_ARG_MAX) - baselen - envsz - 2048;
+ a->a_spc = srealloc(NULL, a->a_msz);
+ a->a_maxarg = 8192;
+ a->a_vec = srealloc(NULL, a->a_maxarg * sizeof *a->a_vec);
+ a->a_csz = 0;
+ a->a_cur = 0;
+ Execplus = 1;
+ return a;
}
-static sigset_t ss;
-static bool notty;
+static uid_t getunum(const char *s) { /* find user name and return number */
+ struct passwd *pwd;
+ char *x;
+ uid_t u;
-static __inline void
-sig_init(void)
+ if ((pwd = getpwnam(s)) != NULL)
+ return pwd->pw_uid;
+ u = strtol(s, &x, 10);
+ if (*x == '\0')
+ return u;
+ er("cannot find %s name", s);
+ /*NOTREACHED*/
+ return 0;
+}
+
+static gid_t getgnum(const char *s) { /* find group name and return number */
+ struct group *grp;
+ char *x;
+ gid_t g;
+
+ if ((grp = getgrnam(s)) != NULL)
+ return grp->gr_gid;
+ g = strtol(s, &x, 10);
+ if (*x == '\0')
+ return g;
+ er("cannot find %s name", s);
+ /*NOTREACHED*/
+ return 0;
+}
+
+#define CACHESIZE 16
+
+static const char *getuser(uid_t uid)
{
- struct sigaction sa;
- notty = !(isatty(STDIN_FILENO) || isatty(STDOUT_FILENO) ||
- isatty(STDERR_FILENO));
- if (notty)
- return;
- sigemptyset(&ss);
- sigaddset(&ss, SIGHUP); /* block SIGINFO */
+ static struct {
+ char *name;
+ uid_t uid;
+ } cache[CACHESIZE];
+ static int last;
+ int i;
+ struct passwd *pwd;
+ const char *name;
- memset(&sa, 0, sizeof(sa));
- sa.sa_flags = SA_RESTART;
- sa.sa_handler = show_path;
- (void)sigaction(SIGHUP, &sa, NULL);
+ for (i = 0; i < CACHESIZE && cache[i].name; i++)
+ if (cache[i].uid == uid)
+ goto found;
+ if ((pwd = getpwuid(uid)) != NULL)
+ name = pwd->pw_name;
+ else
+ name = "";
+ if (i >= CACHESIZE) {
+ if (last >= CACHESIZE)
+ last = 0;
+ i = last++;
+ }
+ if (cache[i].name)
+ free(cache[i].name);
+ cache[i].name = strdup(name);
+ cache[i].uid = uid;
+found: return cache[i].name[0] ? cache[i].name : NULL;
+}
+static const char *getgroup(gid_t gid)
+{
+ static struct {
+ char *name;
+ gid_t gid;
+ } cache[CACHESIZE];
+ static int last;
+ int i;
+ struct group *grp;
+ const char *name;
+
+ for (i = 0; i < CACHESIZE && cache[i].name; i++)
+ if (cache[i].gid == gid)
+ goto found;
+ if ((grp = getgrgid(gid)) != NULL)
+ name = grp->gr_name;
+ else
+ name = "";
+ if (i >= CACHESIZE) {
+ if (last >= CACHESIZE)
+ last = 0;
+ i = last++;
+ }
+ if (cache[i].name)
+ free(cache[i].name);
+ cache[i].name = strdup(name);
+ cache[i].gid = gid;
+found: return cache[i].name[0] ? cache[i].name : NULL;
}
-static __inline void
-sig_lock(sigset_t *s)
+#if defined (__linux__) || defined (_AIX) || defined (__hpux)
+static void getfscur(dev_t dev)
{
- if (notty)
- return;
- sigprocmask(SIG_BLOCK, &ss, s);
+ int i;
+
+ for (i = 0; fstypes[i].fstype; i++)
+ if (fstypes[i].fsdev == dev) {
+ fscur = &fstypes[i];
+ return;
+ }
+ er("filesystem type for %s unknown", Pathname);
}
-static __inline void
-sig_unlock(const sigset_t *s)
+static void getfstypes(void)
{
- if (notty)
+ struct stat st;
+ FILE *fp;
+ struct mntent *mp;
+#ifdef __hpux
+ const char mtab[] = "/etc/mnttab";
+#else /* __linux__, _AIX */
+ const char mtab[] = "/etc/mtab";
+#endif /* __linux__, _AIX */
+ int i = 0;
+
+ if (fstypes)
return;
- sigprocmask(SIG_SETMASK, s, NULL);
+ if ((fp = setmntent(mtab, "r")) == NULL)
+ er("cannot open %s: %s", mtab, strerror(errno));
+ while ((mp = getmntent(fp)) != NULL) {
+ if (EQ(mp->mnt_type, MNTTYPE_IGNORE))
+ continue;
+ if (stat(mp->mnt_dir, &st) < 0)
+ continue;
+ fstypes = srealloc(fstypes, (i+1) * sizeof *fstypes);
+ fstypes[i].fsdev = st.st_dev;
+ fstypes[i].fstype = strdup(mp->mnt_type);
+ i++;
+ }
+ endmntent(fp);
}
-
-FTS *tree; /* pointer to top of FTS hierarchy */
-FTSENT *g_entry; /* shared with SIGINFO handler */
+#endif /* __linux__ || _AIX || __hpux */
/*
- * find_execute --
- * take a search plan and an array of search paths and executes the plan
- * over all FTSENT's returned for the given search paths.
+ * First part of descend, called for any file found.
*/
-int
-find_execute(PLAN *plan, char **paths)
+static int descend(char *fname, struct anode *exlist, int level)
{
- PLAN *p;
- int r, rval, cval;
- sigset_t s;
+ struct stat ost;
+ register char *c1;
+ int i;
+ int rv = 0;
+
+ if(statfn(fname, &Statb)<0) {
+ if (statfn != lstat && lstat(fname, &Statb) == 0)
+ nof: c1 = "cannot follow symbolic link %s: %s";
+ else if (sysv3)
+ c1 = "stat() failed: %s: %s";
+ else if (errno == ENOENT || errno == ENOTDIR)
+ c1 = "cannot open %s: %s";
+ else
+ c1 = "stat() error %s: %s";
+ pr(c1, Pathname, strerror(errno));
+ status = 18;
+ return(0);
+ }
+ if (level == 0 && HLflag == 'H' && (Statb.st_mode&S_IFMT) == S_IFLNK) {
+ struct stat nst;
+ if (stat(fname, &nst) == 0)
+ Statb = nst;
+ else if (errno == ELOOP)
+ goto nof;
+ }
+#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || \
+ defined (__DragonFly__) || defined (__APPLE__)
+ if (Statfs != NULL) {
+ static struct statfs sf;
+ if (statfs(fname, &sf) < 0) {
+ pr("statfs() error %s: %s", Pathname, strerror(errno));
+ status = 18;
+ return(0);
+ }
+ Statfs = sf.f_fstypename;
+ }
+#endif /* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
+ if (Mount) {
+ static dev_t curdev;
+ if (level == 0)
+ curdev = Statb.st_dev;
+ else if (curdev != Statb.st_dev)
+ return(0);
+ }
+ Prune = 0;
+ if (!depth) {
+#if defined (__linux__) || defined (_AIX) || defined (__hpux)
+ if (fstypes)
+ getfscur(Statb.st_dev);
+#endif /* __linux__ || _AIX || __hpux */
+ if((*exlist->F)(exlist) && Print)
+ puts(Pathname);
+ } else
+ ost = Statb;
+ if(Prune || (Statb.st_mode&S_IFMT)!=S_IFDIR)
+ goto reg;
+ if (statfn != lstat) {
+ for (i = 0; i < level; i++)
+ if (Statb.st_dev == visited[i].v_dev &&
+ Statb.st_ino == visited[i].v_ino) {
+#ifdef SU3
+ pr("Symbolic link loop at %s", Pathname);
+ status = 18;
+#endif /* SU3 */
+ goto reg;
+ }
+ }
+ if (level >= vismax) {
+ vismax += 20;
+ visited = srealloc(visited, sizeof *visited * vismax);
+ }
+ visited[level].v_dev = Statb.st_dev;
+ visited[level].v_ino = Statb.st_ino;
- cval = 1;
+ rv = descend1(fname, exlist, level);
- if (!(tree = fts_open(paths, ftsoptions, issort ? ftscompare : NULL)))
- err(1, "ftsopen");
+reg:
+ if (depth) {
+ Statb = ost;
+#if defined (__linux__) || defined (_AIX) || defined (__hpux)
+ if (fstypes)
+ getfscur(Statb.st_dev);
+#endif /* __linux__ || _AIX || __hpux */
+ if ((*exlist->F)(exlist) && Print)
+ puts(Pathname);
+ }
+ return(rv);
+}
- sig_init();
- sig_lock(&s);
- for (rval = 0; cval && (g_entry = fts_read(tree)) != NULL;) {
- switch (g_entry->fts_info) {
- case FTS_D:
- if (isdepth)
- continue;
- break;
- case FTS_DP:
- if (!isdepth)
- continue;
- break;
- case FTS_DNR:
- case FTS_ERR:
- case FTS_NS:
- sig_unlock(&s);
- (void)fflush(stdout);
- warnx("%s: %s",
- g_entry->fts_path, strerror(g_entry->fts_errno));
- rval = 1;
- sig_lock(&s);
- continue;
- }
-#define BADCH " \t\n\\'\""
- if (isxargs && strpbrk(g_entry->fts_path, BADCH)) {
- sig_unlock(&s);
- (void)fflush(stdout);
- warnx("%s: illegal path", g_entry->fts_path);
- rval = 1;
- sig_lock(&s);
+/*
+ * Second part of descend, called for any directory found.
+ */
+static int descend1(char *fname, struct anode *exlist, int level)
+{
+ int dir = 0; /* open directory */
+ register char *c1;
+ struct getdb *db;
+ register struct direc *dp;
+ int endofname;
+ int err;
+ int oflags = O_RDONLY;
+
+#ifdef O_DIRECTORY
+ oflags |= O_DIRECTORY;
+#endif
+#ifdef O_NOFOLLOW
+ if (statfn == lstat && (HLflag != 'H' || level > 0))
+ oflags |= O_NOFOLLOW;
+#endif
+ if ((dir = open(fname, oflags)) < 0 ||
+ fcntl(dir, F_SETFD, FD_CLOEXEC) < 0 ||
+ fchdir(dir) < 0) {
+ if (dir >= 0)
+ close(dir);
+ else if (errno == EMFILE && descend2(fname, exlist, level))
+ /*
+ * A possible performance improvement would be to
+ * call descend2() in the directory above, since
+ * the current method involves one fork() call per
+ * subdirectory at this level. The condition occurs
+ * so rarely that it seems hardly worth optimization
+ * though.
+ */
+ return 0;
+ pr("cannot open %s: %s", Pathname, strerror(errno));
+ status = 18;
+ return 0;
+ }
+ if ((db = getdb_alloc(Pathname, dir)) == NULL) {
+ write(2, "no memory\n", 10);
+ _exit(077);
+ }
+ visited[level].v_db = db;
+ visited[level].v_fd = dir;
+ for(c1 = Pathname; *c1; ++c1);
+ if(*(c1-1) == '/')
+ --c1;
+ endofname = c1 - Pathname;
+
+ while ((dp = getdir(db, &err)) != NULL) {
+ if((dp->d_name[0]=='.' && dp->d_name[1]=='\0') ||
+ (dp->d_name[0]=='.' &&
+ dp->d_name[1]=='.' && dp->d_name[2]=='\0'))
continue;
+ setpath(&Pathname[endofname], dp->d_name, 1);
+ Fname = &Pathname[endofname+1];
+ if(descend(Fname, exlist, level+1)) {
+ if (fchdir(dir) < 0)
+ er("bad directory tree");
}
+ }
+ Pathname[endofname] = '\0';
+ getdb_free(db);
+ if (err) {
+ pr("cannot read dir %s: %s", Pathname, strerror(errno));
+ status = 18;
+ }
+ close(dir);
+ visited[level].v_fd = -1;
+ return 1;
+}
+
+/*
+ * Third part of descend, called if the limit of open file descriptors
+ * is exceeded (EMFILE).
+ */
+static int descend2(char *fname, struct anode *exlist, int level)
+{
+ pid_t pid;
+ int i;
- /*
- * Call all the functions in the execution plan until one is
- * false or all have been executed. This is where we do all
- * the work specified by the user on the command line.
- */
- sig_unlock(&s);
- for (p = plan; p && (p->eval)(p, g_entry); p = p->next)
- if (p->type == N_EXIT) {
- rval = p->exit_val;
- cval = 0;
+ if (Cpio || Execplus)
+ trailer(exlist, 0);
+ fflush(stdout);
+ switch (pid = fork()) {
+ case 0:
+ for (i = 0; i < level-1; i++) {
+ if (visited[i].v_fd >= 0) {
+ getdb_free(visited[i].v_db);
+ close(visited[i].v_fd);
+ visited[i].v_fd = -1;
}
- sig_lock(&s);
+ }
+ status |= 0;
+ descend1(fname, exlist, level);
+ if (Cpio || Execplus)
+ trailer(exlist, 0);
+ exit(status);
+ /*NOTREACHED*/
+ default:
+ while (waitpid(pid, &i, 0) != pid);
+ if (i && WIFSIGNALED(i)) {
+ struct rlimit rl;
+
+ rl.rlim_cur = rl.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rl);
+ raise(WTERMSIG(i));
+ pause();
+ }
+ if (i)
+ status |= WEXITSTATUS(i);
+ return 1;
+ case -1:
+ return 0;
+ }
+}
+static void setpath(char *eos, const char *fn, int slash)
+{
+ static char *pathend;
+ char *opath;
+
+ for (;;) {
+ if (eos >= pathend) {
+ pathend += 14;
+ opath = Pathname;
+ Pathname = srealloc(Pathname, pathend - Pathname);
+ eos += Pathname - opath;
+ pathend += Pathname - opath;
+ }
+ if (slash) {
+ *eos++ = '/';
+ slash = 0;
+ } else
+ if ((*eos++ = *fn++) == '\0')
+ break;
}
+}
- sig_unlock(&s);
- if (g_entry == NULL && errno)
- err(1, "fts_read");
- (void)fts_close(tree);
+static void pr(const char *s, ...)
+{
+ va_list ap;
- /*
- * Cleanup any plans with leftover state.
- * Keep the last non-zero return value.
- */
- if ((r = find_traverse(plan, plan_cleanup, NULL)) != 0)
- rval = r;
+ fprintf(stderr, "%s: ", progname);
+ va_start(ap, s);
+ vfprintf(stderr, s, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+}
+
+static void er(const char *s, ...)
+{
+ va_list ap;
- return (rval);
+ fprintf(stderr, "%s: ", progname);
+ va_start(ap, s);
+ vfprintf(stderr, s, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ exit(1);
}
+static void usage(void)
+{
+ er("path-list predicate-list");
+}
+
+static void *srealloc(void *op, size_t n)
+{
+ void *np;
+
+ if ((np = realloc(op, n)) == NULL) {
+ write(2, "no memory\n", 10);
+ _exit(077);
+ }
+ return np;
+}
+
+static void mkcpio(struct anode *p, const char *b, int ascii)
+{
+ int fd, pd[2];
+ char flags[20], *cp;
+
+ p->F = cpio;
+ if (*b == '\0')
+ return;
+ depth = 1;
+ Print = 0;
+ Cpio = 1;
+ if (pipe(pd) < 0 || (p->l.fp = fdopen(pd[1], "w")) == NULL)
+ er("pipe() %s", strerror(errno));
+ if ((fd = creat(b, 0666)) < 0)
+ er("cannot create %s", b);
+ switch (p->r.pid = fork()) {
+ case -1:
+ er("can't fork");
+ /*NOTREACHED*/
+ case 0:
+ dup2(pd[0], 0);
+ close(pd[0]);
+ close(pd[1]);
+ dup2(fd, 1);
+ close(fd);
+ cp = flags;
+ *cp++ = '-';
+ *cp++ = 'o';
+ *cp++ = 'B';
+ if (ascii)
+ *cp++ = 'c';
+ if (statfn == stat)
+ *cp++ = 'L';
+ *cp = '\0';
+ execlp("cpio", "cpio", flags, NULL);
+ pr("cannot exec cpio: %s", strerror(errno));
+ _exit(0177);
+ /*NOTREACHED*/
+ }
+ close(pd[0]);
+ close(fd);
+}
+
+static void
+trailer(register struct anode *p, int termcpio)
+{
+ char *Opath = Pathname;
+ Pathname = 0;
+ if (p->F == or || p->F == and) {
+ trailer(p->l.L, termcpio);
+ trailer(p->r.R, termcpio);
+ } else if (p->F == not)
+ trailer(p->l.L, termcpio);
+ else if (p->F == cpio) {
+ if (termcpio) {
+ int s;
+
+ fclose(p->l.fp);
+ while (waitpid(p->r.pid, &s, 0) != p->r.pid);
+ if (s) {
+ if (WIFEXITED(s))
+ status |= WEXITSTATUS(s);
+ else if (WIFSIGNALED(s))
+ status |= WTERMSIG(s) | 0200;
+ }
+ } else
+ fflush(p->l.fp);
+ } else if (p->F == exeq && p->r.a)
+ exeq(p);
+ Pathname = Opath;
+}
+
+static void
+mknewer(struct anode *p, const char *b, int (*f)(struct anode *))
+{
+ if (*b && stat(b, &Statb) < 0)
+ er("cannot access %s", b);
+ p->l.t = Statb.st_mtime;
+ p->F = f;
+}
+
+/*
+ * Changes by Gunnar Ritter, Freiburg i. Br., Germany, September 2003.
+ */
+/* from Unix 7th Edition /usr/src/cmd/chmod.c */
/*
- * find_traverse --
- * traverse the plan tree and execute func() on all plans. This
- * does not evaluate each plan's eval() function; it is intended
- * for operations that must run on all plans, such as state
- * cleanup.
+ * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * Redistributions of source code and documentation must retain the
+ * above copyright notice, this list of conditions and the following
+ * disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed or owned by Caldera
+ * International, Inc.
+ * Neither the name of Caldera International, Inc. nor the names of
+ * other contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
*
- * If any func() returns non-zero, then so will find_traverse().
+ * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
+ * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
+ * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-int
-find_traverse(PLAN *plan, int (*func)(PLAN *, void *), void *arg)
-{
- PLAN *p;
- int r, rval;
-
- rval = 0;
- for (p = plan; p; p = p->next) {
- if ((r = func(p, arg)) != 0)
- rval = r;
- if (p->type == N_EXPR || p->type == N_OR) {
- if (p->p_data[0])
- if ((r = find_traverse(p->p_data[0],
- func, arg)) != 0)
- rval = r;
- if (p->p_data[1])
- if ((r = find_traverse(p->p_data[1],
- func, arg)) != 0)
- rval = r;
+
+#define USER 05700 /* user's bits */
+#define GROUP 02070 /* group's bits */
+#define OTHER 00007 /* other's bits */
+#define ALL 07777 /* all */
+
+#define READ 00444 /* read permit */
+#define WRITE 00222 /* write permit */
+#define EXEC 00111 /* exec permit */
+#define SETID 06000 /* set[ug]id */
+#define STICKY 01000 /* sticky bit */
+
+#ifndef S_ENFMT
+#define S_ENFMT 02000 /* mandatory locking bit */
+#endif
+
+static mode_t absol(const char **);
+static mode_t who(const char **, mode_t *);
+static int what(const char **);
+static mode_t where(const char **, mode_t, int *, int *, const mode_t);
+
+static mode_t
+newmode(const char *ms, const mode_t pm)
+{
+ register mode_t o, m, b;
+ int lock, setsgid = 0, cleared = 0, copy = 0;
+ mode_t nm, om, mm;
+ const char *mo = ms;
+
+ nm = om = pm;
+ m = absol(&ms);
+ if (!*ms) {
+ nm = m;
+ goto out;
+ }
+ if ((lock = (nm&S_IFMT) != S_IFDIR && (nm&(S_ENFMT|S_IXGRP)) == S_ENFMT)
+ == 01)
+ nm &= ~(mode_t)S_ENFMT;
+ do {
+ m = who(&ms, &mm);
+ while (o = what(&ms)) {
+ b = where(&ms, nm, &lock, &copy, pm);
+ switch (o) {
+ case '+':
+ nm |= b & m & ~mm;
+ if (b & S_ISGID)
+ setsgid = 1;
+ if (lock & 04)
+ lock |= 02;
+ break;
+ case '-':
+ nm &= ~(b & m & ~mm);
+ if (b & S_ISGID)
+ setsgid = 1;
+ if (lock & 04)
+ lock = 0;
+ break;
+ case '=':
+ nm &= ~m;
+ nm |= b & m & ~mm;
+ lock &= ~01;
+ if (lock & 04)
+ lock |= 02;
+ om = 0;
+ if (copy == 0)
+ cleared = 1;
+ break;
+ }
+ lock &= ~04;
}
+ } while (*ms++ == ',');
+ if (*--ms)
+ er("bad permissions: %s", mo);
+out: if (pm & S_IFDIR) {
+ if ((pm & S_ISGID) && setsgid == 0)
+ nm |= S_ISGID;
+ else if ((nm & S_ISGID) && setsgid == 0)
+ nm &= ~(mode_t)S_ISGID;
+ }
+ return(nm);
+}
+
+static mode_t
+absol(const char **ms)
+{
+ register int c, i;
+
+ i = 0;
+ while ((c = *(*ms)++) >= '0' && c <= '7')
+ i = (i << 3) + (c - '0');
+ (*ms)--;
+ return(i);
+}
+
+static mode_t
+who(const char **ms, mode_t *mp)
+{
+ register int m;
+
+ m = 0;
+ *mp = 0;
+ for (;;) switch (*(*ms)++) {
+ case 'u':
+ m |= USER;
+ continue;
+ case 'g':
+ m |= GROUP;
+ continue;
+ case 'o':
+ m |= OTHER;
+ continue;
+ case 'a':
+ m |= ALL;
+ continue;
+ default:
+ (*ms)--;
+ if (m == 0) {
+ m = ALL;
+ *mp = um;
+ }
+ return m;
+ }
+}
+
+static int
+what(const char **ms)
+{
+ switch (**ms) {
+ case '+':
+ case '-':
+ case '=':
+ return *(*ms)++;
+ }
+ return(0);
+}
+
+static mode_t
+where(const char **ms, mode_t om, int *lock, int *copy, const mode_t pm)
+{
+ register mode_t m;
+
+ m = 0;
+ *copy = 0;
+ switch (**ms) {
+ case 'u':
+ m = (om & USER) >> 6;
+ goto dup;
+ case 'g':
+ m = (om & GROUP) >> 3;
+ goto dup;
+ case 'o':
+ m = (om & OTHER);
+ dup:
+ *copy = 1;
+ m &= (READ|WRITE|EXEC);
+ m |= (m << 3) | (m << 6);
+ ++(*ms);
+ return m;
+ }
+ for (;;) switch (*(*ms)++) {
+ case 'r':
+ m |= READ;
+ continue;
+ case 'w':
+ m |= WRITE;
+ continue;
+ case 'x':
+ m |= EXEC;
+ continue;
+ case 'X':
+ if ((pm&S_IFMT) == S_IFDIR || (pm & EXEC))
+ m |= EXEC;
+ continue;
+ case 'l':
+ if ((pm&S_IFMT) != S_IFDIR)
+ *lock |= 04;
+ continue;
+ case 's':
+ m |= SETID;
+ continue;
+ case 't':
+ m |= STICKY;
+ continue;
+ default:
+ (*ms)--;
+ return m;
}
- return rval;
}
diff --git a/usr.bin/find/find.h b/usr.bin/find/find.h
deleted file mode 100644
index 912e60d..0000000
--- a/usr.bin/find/find.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/* $NetBSD: find.h,v 1.26 2016/06/13 00:04:40 pgoyette Exp $ */
-
-/*-
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Cimarron D. Taylor of the University of California, Berkeley.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * from: @(#)find.h 8.1 (Berkeley) 6/6/93
- */
-
-#include <regex.h>
-#include <time.h>
-
-/* node type */
-enum ntype {
- N_AND = 1, /* must start > 0 */
- N_AMIN, N_ANEWER, N_ASINCE, N_ATIME, N_CLOSEPAREN, N_CMIN, N_CNEWER,
- N_CSINCE, N_CTIME, N_DEPTH, N_EMPTY, N_EXEC, N_EXECDIR, N_EXIT,
- N_EXPR, N_FALSE, N_FLAGS, N_FOLLOW, N_FPRINT, N_FSTYPE, N_GROUP,
- N_INAME, N_INUM, N_IREGEX, N_LINKS, N_LS, N_MINDEPTH, N_MAXDEPTH,
- N_MMIN, N_MTIME, N_NAME, N_NEWER, N_NOGROUP, N_NOT, N_NOUSER, N_OK,
- N_OPENPAREN, N_OR, N_PATH, N_PERM, N_PRINT, N_PRINT0, N_PRINTX,
- N_PRUNE, N_REGEX, N_SINCE, N_SIZE, N_TYPE, N_USER, N_XDEV, N_DELETE
-};
-
-/* node definition */
-typedef struct _plandata {
- struct _plandata *next; /* next node */
- int (*eval)(struct _plandata *, FTSENT *);
- /* node evaluation function */
-#define F_EQUAL 1 /* [acm]time inum links size */
-#define F_LESSTHAN 2
-#define F_GREATER 3
-#define F_NEEDOK 1 /* exec ok */
-#define F_PLUSSET 2 /* -exec ... {} + */
-#define F_MTFLAG 1 /* fstype */
-#define F_MTTYPE 2
-#define F_ATLEAST 1 /* perm */
- int flags; /* private flags */
- enum ntype type; /* plan node type */
- union {
- u_int32_t _f_data; /* flags */
- gid_t _g_data; /* gid */
- ino_t _i_data; /* inode */
- mode_t _m_data; /* mode mask */
- nlink_t _l_data; /* link count */
- off_t _o_data; /* file size */
- time_t _t_data; /* time value */
- struct timespec _ts_data; /* time value */
- uid_t _u_data; /* uid */
- short _mt_data; /* mount flags */
- struct _plandata *_p_data[2]; /* PLAN trees */
- struct _ex {
- char **_e_argv; /* argv array */
- char **_e_orig; /* original strings */
- int *_e_len; /* allocated length */
- char **_ep_bxp; /* ptr to 1st addt'l arg */
- char *_ep_p; /* current buffer pointer */
- char *_ep_bbp; /* begin buffer pointer */
- char *_ep_ebp; /* end buffer pointer */
- int _ep_maxargs; /* max #args */
- int _ep_narg; /* # addt'l args */
- int _ep_rval; /* return value */
- } ex;
- char *_a_data[2]; /* array of char pointers */
- char *_c_data; /* char pointer */
- int _exit_val; /* exit value */
- int _max_data; /* tree depth */
- int _min_data; /* tree depth */
- regex_t _regexp_data; /* compiled regexp */
- FILE *_fprint_file; /* file stream for -fprint */
- } p_un;
-} PLAN;
-#define a_data p_un._a_data
-#define c_data p_un._c_data
-#define i_data p_un._i_data
-#define f_data p_un._f_data
-#define g_data p_un._g_data
-#define l_data p_un._l_data
-#define m_data p_un._m_data
-#define mt_data p_un._mt_data
-#define o_data p_un._o_data
-#define p_data p_un._p_data
-#define t_data p_un._t_data
-#define ts_data p_un._ts_data
-#define u_data p_un._u_data
-#define e_argv p_un.ex._e_argv
-#define e_orig p_un.ex._e_orig
-#define e_len p_un.ex._e_len
-#define ep_p p_un.ex._ep_p
-#define ep_bbp p_un.ex._ep_bbp
-#define ep_ebp p_un.ex._ep_ebp
-#define ep_bxp p_un.ex._ep_bxp
-#define ep_cnt p_un.ex._ep_cnt
-#define ep_maxargs p_un.ex._ep_maxargs
-#define ep_nline p_un.ex._ep_nline
-#define ep_narg p_un.ex._ep_narg
-#define ep_rval p_un.ex._ep_rval
-#define exit_val p_un._exit_val
-#define max_data p_un._max_data
-#define min_data p_un._min_data
-#define regexp_data p_un._regexp_data
-#define fprint_file p_un._fprint_file
-
-typedef struct _option {
- const char *name; /* option name */
- enum ntype token; /* token type */
- PLAN *(*create)(char ***, int, char *); /* create function */
- int arg; /* function needs arg */
-} OPTION;
-
-#include "extern.h"
diff --git a/usr.bin/find/function.c b/usr.bin/find/function.c
deleted file mode 100644
index be880e9..0000000
--- a/usr.bin/find/function.c
+++ /dev/null
@@ -1,1956 +0,0 @@
-/* $NetBSD: function.c,v 1.77 2018/09/04 15:16:15 kre Exp $ */
-
-/*-
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Cimarron D. Taylor of the University of California, Berkeley.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/ioctl.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <sys/wait.h>
-#include <sys/mount.h>
-#include <bsd/sys/time.h>
-
-#include <linux/fs.h>
-
-#include <dirent.h>
-#include <err.h>
-#include <errno.h>
-#include <fnmatch.h>
-#include <fts.h>
-#include <grp.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <mntent.h>
-#include <pwd.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <bsd/unistd.h>
-
-#include "find.h"
-
-#define COMPARE(a, b) { \
- switch (plan->flags) { \
- case F_EQUAL: \
- return (a == b); \
- case F_LESSTHAN: \
- return (a < b); \
- case F_GREATER: \
- return (a > b); \
- default: \
- abort(); \
- } \
-}
-
-static int64_t find_parsenum(PLAN *, const char *, const char *, char *);
-static void run_f_exec(PLAN *);
- int f_always_true(PLAN *, FTSENT *);
- int f_amin(PLAN *, FTSENT *);
- int f_anewer(PLAN *, FTSENT *);
- int f_asince(PLAN *, FTSENT *);
- int f_atime(PLAN *, FTSENT *);
- int f_cmin(PLAN *, FTSENT *);
- int f_cnewer(PLAN *, FTSENT *);
- int f_csince(PLAN *, FTSENT *);
- int f_ctime(PLAN *, FTSENT *);
- int f_delete(PLAN *, FTSENT *);
- int f_empty(PLAN *, FTSENT *);
- int f_exec(PLAN *, FTSENT *);
- int f_execdir(PLAN *, FTSENT *);
- int f_false(PLAN *, FTSENT *);
- int f_flags(PLAN *, FTSENT *);
- int f_fprint(PLAN *, FTSENT *);
- int f_fstype(PLAN *, FTSENT *);
- int f_group(PLAN *, FTSENT *);
- int f_iname(PLAN *, FTSENT *);
- int f_inum(PLAN *, FTSENT *);
- int f_links(PLAN *, FTSENT *);
- int f_ls(PLAN *, FTSENT *);
- int f_mindepth(PLAN *, FTSENT *);
- int f_maxdepth(PLAN *, FTSENT *);
- int f_mmin(PLAN *, FTSENT *);
- int f_mtime(PLAN *, FTSENT *);
- int f_name(PLAN *, FTSENT *);
- int f_newer(PLAN *, FTSENT *);
-/*
- * Unimplemented Gnu findutils options
- *
- int f_newerBB(PLAN *, FTSENT *);
- int f_newerBa(PLAN *, FTSENT *);
- int f_newerBc(PLAN *, FTSENT *);
- int f_newerBm(PLAN *, FTSENT *);
- int f_newerBt(PLAN *, FTSENT *);
- int f_neweraB(PLAN *, FTSENT *);
- int f_newerac(PLAN *, FTSENT *);
- int f_neweram(PLAN *, FTSENT *);
- int f_newerca(PLAN *, FTSENT *);
- int f_newercm(PLAN *, FTSENT *);
- int f_newercB(PLAN *, FTSENT *);
- int f_newermB(PLAN *, FTSENT *);
- int f_newerma(PLAN *, FTSENT *);
- int f_newermc(PLAN *, FTSENT *);
- *
- */
- int f_nogroup(PLAN *, FTSENT *);
- int f_nouser(PLAN *, FTSENT *);
- int f_path(PLAN *, FTSENT *);
- int f_perm(PLAN *, FTSENT *);
- int f_print(PLAN *, FTSENT *);
- int f_print0(PLAN *, FTSENT *);
- int f_printx(PLAN *, FTSENT *);
- int f_prune(PLAN *, FTSENT *);
- int f_regex(PLAN *, FTSENT *);
- int f_since(PLAN *, FTSENT *);
- int f_size(PLAN *, FTSENT *);
- int f_type(PLAN *, FTSENT *);
- int f_user(PLAN *, FTSENT *);
- int f_not(PLAN *, FTSENT *);
- int f_or(PLAN *, FTSENT *);
-static PLAN *c_regex_common(char ***, int, enum ntype, bool);
-static PLAN *palloc(enum ntype, int (*)(PLAN *, FTSENT *));
-
-extern int dotfd;
-extern FTS *tree;
-extern time_t now;
-
-/*
- * find_parsenum --
- * Parse a string of the form [+-]# and return the value.
- */
-static int64_t
-find_parsenum(PLAN *plan, const char *option, const char *vp, char *endch)
-{
- int64_t value;
- const char *str;
- char *endchar; /* Pointer to character ending conversion. */
-
- /* Determine comparison from leading + or -. */
- str = vp;
- switch (*str) {
- case '+':
- ++str;
- plan->flags = F_GREATER;
- break;
- case '-':
- ++str;
- plan->flags = F_LESSTHAN;
- break;
- default:
- plan->flags = F_EQUAL;
- break;
- }
-
- /*
- * Convert the string with strtol(). Note, if strtol() returns zero
- * and endchar points to the beginning of the string we know we have
- * a syntax error.
- */
- value = strtoll(str, &endchar, 10);
- if (value == 0 && endchar == str)
- errx(1, "%s: %s: illegal numeric value", option, vp);
- if (endchar[0] && (endch == NULL || endchar[0] != *endch))
- errx(1, "%s: %s: illegal trailing character", option, vp);
- if (endch)
- *endch = endchar[0];
- return (value);
-}
-
-/*
- * find_parsedate --
- *
- * Validate the timestamp argument or report an error
- */
-static time_t
-find_parsedate(PLAN *plan, const char *option, const char *vp)
-{
- time_t timestamp;
-
- errno = 0;
- timestamp = parsedate(vp, NULL, NULL);
- if (timestamp == -1 && errno != 0)
- errx(1, "%s: %s: invalid timestamp value", option, vp);
- return timestamp;
-}
-
-/*
- * The value of n for the inode times (atime, ctime, and mtime) is a range,
- * i.e. n matches from (n - 1) to n 24 hour periods. This interacts with
- * -n, such that "-mtime -1" would be less than 0 days, which isn't what the
- * user wanted. Correct so that -1 is "less than 1".
- */
-#define TIME_CORRECT(p, ttype) \
- if ((p)->type == ttype && (p)->flags == F_LESSTHAN) \
- ++((p)->t_data);
-
-/*
- * -amin n functions --
- *
- * True if the difference between the file access time and the
- * current time is n 1 minute periods.
- */
-int
-f_amin(PLAN *plan, FTSENT *entry)
-{
-#define SECSPERMIN 60
- COMPARE((now - entry->fts_statp->st_atime +
- SECSPERMIN - 1) / SECSPERMIN, plan->t_data);
-}
-
-PLAN *
-c_amin(char ***argvp, int isok, char *opt)
-{
- char *arg = **argvp;
- PLAN *new;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- new = palloc(N_AMIN, f_amin);
- new->t_data = find_parsenum(new, opt, arg, NULL);
- TIME_CORRECT(new, N_AMIN);
- return (new);
-}
-
-/*
- * -anewer file functions --
- *
- * True if the current file has been accessed more recently
- * than the access time of the file named by the pathname
- * file.
- */
-int
-f_anewer(PLAN *plan, FTSENT *entry)
-{
-
- return timespeccmp(&entry->fts_statp->st_atim, &plan->ts_data, >);
-}
-
-PLAN *
-c_anewer(char ***argvp, int isok, char *opt)
-{
- char *filename = **argvp;
- PLAN *new;
- struct stat sb;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- if (stat(filename, &sb))
- err(1, "%s: %s", opt, filename);
- new = palloc(N_ANEWER, f_anewer);
- new->ts_data = sb.st_atim;
- return (new);
-}
-
-/*
- * -asince "timestamp" functions --
- *
- * True if the file access time is greater than the timestamp value
- */
-int
-f_asince(PLAN *plan, FTSENT *entry)
-{
- COMPARE(entry->fts_statp->st_atime, plan->t_data);
-}
-
-PLAN *
-c_asince(char ***argvp, int isok, char *opt)
-{
- char *arg = **argvp;
- PLAN *new;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- new = palloc(N_ASINCE, f_asince);
- new->t_data = find_parsedate(new, opt, arg);
- new->flags = F_GREATER;
- return (new);
-}
-
-/*
- * -atime n functions --
- *
- * True if the difference between the file access time and the
- * current time is n 24 hour periods.
- */
-int
-f_atime(PLAN *plan, FTSENT *entry)
-{
-#define SECSPERDAY 24*60*60
- COMPARE((now - entry->fts_statp->st_atime +
- SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
-}
-
-PLAN *
-c_atime(char ***argvp, int isok, char *opt)
-{
- char *arg = **argvp;
- PLAN *new;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- new = palloc(N_ATIME, f_atime);
- new->t_data = find_parsenum(new, opt, arg, NULL);
- TIME_CORRECT(new, N_ATIME);
- return (new);
-}
-
-/*
- * -cmin n functions --
- *
- * True if the difference between the last change of file
- * status information and the current time is n 24 hour periods.
- */
-int
-f_cmin(PLAN *plan, FTSENT *entry)
-{
- COMPARE((now - entry->fts_statp->st_ctime +
- SECSPERMIN - 1) / SECSPERMIN, plan->t_data);
-}
-
-PLAN *
-c_cmin(char ***argvp, int isok, char *opt)
-{
- char *arg = **argvp;
- PLAN *new;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- new = palloc(N_CMIN, f_cmin);
- new->t_data = find_parsenum(new, opt, arg, NULL);
- TIME_CORRECT(new, N_CMIN);
- return (new);
-}
-
-/*
- * -cnewer file functions --
- *
- * True if the current file has been changed more recently
- * than the changed time of the file named by the pathname
- * file.
- */
-int
-f_cnewer(PLAN *plan, FTSENT *entry)
-{
-
- return timespeccmp(&entry->fts_statp->st_ctim, &plan->ts_data, >);
-}
-
-PLAN *
-c_cnewer(char ***argvp, int isok, char *opt)
-{
- char *filename = **argvp;
- PLAN *new;
- struct stat sb;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- if (stat(filename, &sb))
- err(1, "%s: %s ", opt, filename);
- new = palloc(N_CNEWER, f_cnewer);
- new->ts_data = sb.st_ctim;
- return (new);
-}
-
-/*
- * -csince "timestamp" functions --
- *
- * True if the file status change time is greater than the timestamp value
- */
-int
-f_csince(PLAN *plan, FTSENT *entry)
-{
- COMPARE(entry->fts_statp->st_ctime, plan->t_data);
-}
-
-PLAN *
-c_csince(char ***argvp, int isok, char *opt)
-{
- char *arg = **argvp;
- PLAN *new;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- new = palloc(N_CSINCE, f_csince);
- new->t_data = find_parsedate(new, opt, arg);
- new->flags = F_GREATER;
- return (new);
-}
-
-/*
- * -ctime n functions --
- *
- * True if the difference between the last change of file
- * status information and the current time is n 24 hour periods.
- */
-int
-f_ctime(PLAN *plan, FTSENT *entry)
-{
- COMPARE((now - entry->fts_statp->st_ctime +
- SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
-}
-
-PLAN *
-c_ctime(char ***argvp, int isok, char *opt)
-{
- char *arg = **argvp;
- PLAN *new;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- new = palloc(N_CTIME, f_ctime);
- new->t_data = find_parsenum(new, opt, arg, NULL);
- TIME_CORRECT(new, N_CTIME);
- return (new);
-}
-
-/*
- * -delete functions --
- *
- * Always true. Makes its best shot and continues on regardless.
- */
-int
-f_delete(PLAN *plan, FTSENT *entry)
-{
- int flags;
- FILE *file;
- /* ignore these from fts */
- if (strcmp(entry->fts_accpath, ".") == 0 ||
- strcmp(entry->fts_accpath, "..") == 0)
- return 1;
-
- /* sanity check */
- if (isdepth == 0 || /* depth off */
- (ftsoptions & FTS_NOSTAT) || /* not stat()ing */
- !(ftsoptions & FTS_PHYSICAL) || /* physical off */
- (ftsoptions & FTS_LOGICAL)) /* or finally, logical on */
- errx(1, "-delete: insecure options got turned on");
-
- /* Potentially unsafe - do not accept relative paths whatsoever */
- if (entry->fts_level > 0 && strchr(entry->fts_accpath, '/') != NULL)
- errx(1, "-delete: %s: relative path potentially not safe",
- entry->fts_accpath);
-
- file = fopen(entry->fts_name, "r");
- if (file == NULL) {
- warn("couldn't check flags for %s", entry->fts_name);
- } else {
- ioctl(fileno(file), FS_IOC_GETFLAGS, &flags);
- /* turn off immutable bit if running as root */
- if ((geteuid() == 0) && (flags & FS_IMMUTABLE_FL)) {
- flags = flags & ~FS_IMMUTABLE_FL;
- ioctl(fileno(file), FS_IOC_SETFLAGS, &flags);
- }
- }
-
- /* rmdir directories, unlink everything else */
- if (S_ISDIR(entry->fts_statp->st_mode)) {
- if (rmdir(entry->fts_accpath) < 0 && errno != ENOTEMPTY)
- warn("-delete: rmdir(%s)", entry->fts_path);
- } else {
- if (unlink(entry->fts_accpath) < 0)
- warn("-delete: unlink(%s)", entry->fts_path);
- }
-
- /* "succeed" */
- return 1;
-}
-
-PLAN *
-c_delete(char ***argvp, int isok, char *opt)
-{
-
- ftsoptions &= ~FTS_NOSTAT; /* no optimize */
- ftsoptions |= FTS_PHYSICAL; /* disable -follow */
- ftsoptions &= ~FTS_LOGICAL; /* disable -follow */
- isoutput = 1; /* possible output */
- isdepth = 1; /* -depth implied */
-
- return palloc(N_DELETE, f_delete);
-}
-
-/*
- * -depth functions --
- *
- * Always true, causes descent of the directory hierarchy to be done
- * so that all entries in a directory are acted on before the directory
- * itself.
- */
-int
-f_always_true(PLAN *plan, FTSENT *entry)
-{
-
- return (1);
-}
-
-PLAN *
-c_depth(char ***argvp, int isok, char *opt)
-{
- isdepth = 1;
-
- return (palloc(N_DEPTH, f_always_true));
-}
-
-/*
- * -empty functions --
- *
- * True if the file or directory is empty
- */
-int
-f_empty(PLAN *plan, FTSENT *entry)
-{
- if (S_ISREG(entry->fts_statp->st_mode) &&
- entry->fts_statp->st_size == 0)
- return (1);
- if (S_ISDIR(entry->fts_statp->st_mode)) {
- struct dirent *dp;
- int empty;
- DIR *dir;
-
- empty = 1;
- dir = opendir(entry->fts_accpath);
- if (dir == NULL)
- return (0);
- for (dp = readdir(dir); dp; dp = readdir(dir))
- if (dp->d_name[0] != '.' ||
- (dp->d_name[1] != '\0' &&
- (dp->d_name[1] != '.' || dp->d_name[2] != '\0'))) {
- empty = 0;
- break;
- }
- closedir(dir);
- return (empty);
- }
- return (0);
-}
-
-PLAN *
-c_empty(char ***argvp, int isok, char *opt)
-{
- ftsoptions &= ~FTS_NOSTAT;
-
- return (palloc(N_EMPTY, f_empty));
-}
-
-/*
- * [-exec | -ok] utility [arg ... ] ; functions --
- * [-exec | -ok] utility [arg ... ] {} + functions --
- *
- * If the end of the primary expression is delimited by a
- * semicolon: true if the executed utility returns a zero value
- * as exit status. If "{}" occurs anywhere, it gets replaced by
- * the current pathname.
- *
- * If the end of the primary expression is delimited by a plus
- * sign: always true. Pathnames for which the primary is
- * evaluated shall be aggregated into sets. The utility will be
- * executed once per set, with "{}" replaced by the entire set of
- * pathnames (as if xargs). "{}" must appear last.
- *
- * The current directory for the execution of utility is the same
- * as the current directory when the find utility was started.
- *
- * The primary -ok is different in that it requests affirmation
- * of the user before executing the utility.
- */
-int
-f_exec(PLAN *plan, FTSENT *entry)
-{
- size_t cnt;
- int l;
- pid_t pid;
- int status;
-
- if (plan->flags & F_PLUSSET) {
- /*
- * Confirm sufficient buffer space, then copy the path
- * to the buffer.
- */
- l = strlen(entry->fts_path);
- if (plan->ep_p + l < plan->ep_ebp) {
- plan->ep_bxp[plan->ep_narg++] =
- strcpy(plan->ep_p, entry->fts_path);
- plan->ep_p += l + 1;
-
- if (plan->ep_narg == plan->ep_maxargs)
- run_f_exec(plan);
- } else {
- /*
- * Without sufficient space to copy in the next
- * argument, run the command to empty out the
- * buffer before re-attepting the copy.
- */
- run_f_exec(plan);
- if ((plan->ep_p + l < plan->ep_ebp)) {
- plan->ep_bxp[plan->ep_narg++]
- = strcpy(plan->ep_p, entry->fts_path);
- plan->ep_p += l + 1;
- } else
- errx(1, "insufficient space for argument");
- }
- return (1);
- } else {
- for (cnt = 0; plan->e_argv[cnt]; ++cnt)
- if (plan->e_len[cnt])
- brace_subst(plan->e_orig[cnt],
- &plan->e_argv[cnt],
- entry->fts_path,
- &plan->e_len[cnt]);
- if (plan->flags & F_NEEDOK && !queryuser(plan->e_argv))
- return (0);
-
- /* Don't mix output of command with find output. */
- fflush(stdout);
- fflush(stderr);
-
- switch (pid = vfork()) {
- case -1:
- err(1, "vfork");
- /* NOTREACHED */
- case 0:
- if (fchdir(dotfd)) {
- warn("chdir");
- _exit(1);
- }
- execvp(plan->e_argv[0], plan->e_argv);
- warn("%s", plan->e_argv[0]);
- _exit(1);
- }
- pid = waitpid(pid, &status, 0);
- return (pid != -1 && WIFEXITED(status)
- && !WEXITSTATUS(status));
- }
-}
-
-static void
-run_f_exec(PLAN *plan)
-{
- pid_t pid;
- int rval, status;
-
- /* Ensure arg list is null terminated. */
- plan->ep_bxp[plan->ep_narg] = NULL;
-
- /* Don't mix output of command with find output. */
- fflush(stdout);
- fflush(stderr);
-
- switch (pid = vfork()) {
- case -1:
- err(1, "vfork");
- /* NOTREACHED */
- case 0:
- if (fchdir(dotfd)) {
- warn("chdir");
- _exit(1);
- }
- execvp(plan->e_argv[0], plan->e_argv);
- warn("%s", plan->e_argv[0]);
- _exit(1);
- }
-
- /* Clear out the argument list. */
- plan->ep_narg = 0;
- plan->ep_bxp[plan->ep_narg] = NULL;
- /* As well as the argument buffer. */
- plan->ep_p = plan->ep_bbp;
- *plan->ep_p = '\0';
-
- pid = waitpid(pid, &status, 0);
- if (WIFEXITED(status))
- rval = WEXITSTATUS(status);
- else
- rval = -1;
-
- /*
- * If we have a non-zero exit status, preserve it so find(1) can
- * later exit with it.
- */
- if (rval)
- plan->ep_rval = rval;
-}
-
-/*
- * c_exec --
- * build three parallel arrays, one with pointers to the strings passed
- * on the command line, one with (possibly duplicated) pointers to the
- * argv array, and one with integer values that are lengths of the
- * strings, but also flags meaning that the string has to be massaged.
- *
- * If -exec ... {} +, use only the first array, but make it large
- * enough to hold 5000 args (cf. src/usr.bin/xargs/xargs.c for a
- * discussion), and then allocate ARG_MAX - 4K of space for args.
- */
-PLAN *
-c_exec(char ***argvp, int isok, char *opt)
-{
- PLAN *new; /* node returned */
- size_t cnt;
- int brace, lastbrace;
- char **argv, **ap, *p;
-
- isoutput = 1;
-
- new = palloc(N_EXEC, f_exec);
- if (isok)
- new->flags |= F_NEEDOK;
-
- /*
- * Terminate if we encounter an arg exactly equal to ";", or an
- * arg exactly equal to "+" following an arg exactly equal to
- * "{}".
- */
- for (ap = argv = *argvp, brace = 0;; ++ap) {
- if (!*ap)
- errx(1, "%s: no terminating \";\" or \"+\"", opt);
- lastbrace = brace;
- brace = 0;
- if (strcmp(*ap, "{}") == 0)
- brace = 1;
- if (strcmp(*ap, ";") == 0)
- break;
- if (strcmp(*ap, "+") == 0 && lastbrace) {
- new->flags |= F_PLUSSET;
- break;
- }
- }
-
- /*
- * POSIX says -ok ... {} + "need not be supported," and it does
- * not make much sense anyway.
- */
- if (new->flags & F_NEEDOK && new->flags & F_PLUSSET)
- errx(1, "%s: terminating \"+\" not permitted.", opt);
-
- if (new->flags & F_PLUSSET) {
- size_t c, bufsize;
-
- cnt = ap - *argvp - 1; /* units are words */
- new->ep_maxargs = ARG_MAX / (sizeof (char *) + 16);
- if (new->ep_maxargs > 5000)
- new->ep_maxargs = 5000;
- new->e_argv = malloc((cnt + new->ep_maxargs)
- * sizeof(*new->e_argv));
-
- /* We start stuffing arguments after the user's last one. */
- new->ep_bxp = &new->e_argv[cnt];
- new->ep_narg = 0;
-
- /*
- * Count up the space of the user's arguments, and
- * subtract that from what we allocate.
- */
-#define MAXARG (ARG_MAX - 4 * 1024)
- for (argv = *argvp, c = 0, cnt = 0;
- argv < ap;
- ++argv, ++cnt) {
- c += strlen(*argv) + 1;
- if (c >= MAXARG)
- errx(1, "Arguments too long");
- new->e_argv[cnt] = *argv;
- }
- if (c + new->ep_maxargs * sizeof (char *) >= MAXARG)
- errx(1, "Arguments too long");
- bufsize = MAXARG - c - new->ep_maxargs * sizeof (char *);
-
- /*
- * Allocate, and then initialize current, base, and
- * end pointers.
- */
- new->ep_p = new->ep_bbp = malloc(bufsize + 1);
- new->ep_ebp = new->ep_bbp + bufsize - 1;
- new->ep_rval = 0;
- } else { /* !F_PLUSSET */
- cnt = ap - *argvp + 1;
- new->e_argv = malloc(cnt * sizeof(*new->e_argv));
- new->e_orig = malloc(cnt * sizeof(*new->e_orig));
- new->e_len = malloc(cnt * sizeof(*new->e_len));
-
- for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
- new->e_orig[cnt] = *argv;
- for (p = *argv; *p; ++p)
- if (p[0] == '{' && p[1] == '}') {
- new->e_argv[cnt] =
- malloc(MAXPATHLEN);
- new->e_len[cnt] = MAXPATHLEN;
- break;
- }
- if (!*p) {
- new->e_argv[cnt] = *argv;
- new->e_len[cnt] = 0;
- }
- }
- new->e_orig[cnt] = NULL;
- }
-
- new->e_argv[cnt] = NULL;
- *argvp = argv + 1;
- return (new);
-}
-
-/*
- * -execdir utility [arg ... ] ; functions --
- *
- * True if the executed utility returns a zero value as exit status.
- * The end of the primary expression is delimited by a semicolon. If
- * "{}" occurs anywhere, it gets replaced by the unqualified pathname.
- * The current directory for the execution of utility is the same as
- * the directory where the file lives.
- */
-int
-f_execdir(PLAN *plan, FTSENT *entry)
-{
- size_t cnt;
- pid_t pid;
- int status;
- char *file;
-
- /* XXX - if file/dir ends in '/' this will not work -- can it? */
- if ((file = strrchr(entry->fts_path, '/')))
- file++;
- else
- file = entry->fts_path;
-
- for (cnt = 0; plan->e_argv[cnt]; ++cnt)
- if (plan->e_len[cnt])
- brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt],
- file, &plan->e_len[cnt]);
-
- /* don't mix output of command with find output */
- fflush(stdout);
- fflush(stderr);
-
- switch (pid = vfork()) {
- case -1:
- err(1, "fork");
- /* NOTREACHED */
- case 0:
- execvp(plan->e_argv[0], plan->e_argv);
- warn("%s", plan->e_argv[0]);
- _exit(1);
- }
- pid = waitpid(pid, &status, 0);
- return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
-}
-
-/*
- * c_execdir --
- * build three parallel arrays, one with pointers to the strings passed
- * on the command line, one with (possibly duplicated) pointers to the
- * argv array, and one with integer values that are lengths of the
- * strings, but also flags meaning that the string has to be massaged.
- */
-PLAN *
-c_execdir(char ***argvp, int isok, char *opt)
-{
- PLAN *new; /* node returned */
- size_t cnt;
- char **argv, **ap, *p;
-
- ftsoptions &= ~FTS_NOSTAT;
- isoutput = 1;
-
- new = palloc(N_EXECDIR, f_execdir);
-
- for (ap = argv = *argvp;; ++ap) {
- if (!*ap)
- errx(1, "%s: no terminating \";\"", opt);
- if (**ap == ';')
- break;
- }
-
- cnt = ap - *argvp + 1;
- new->e_argv = malloc(cnt * sizeof(*new->e_argv));
- new->e_orig = malloc(cnt * sizeof(*new->e_orig));
- new->e_len = malloc(cnt * sizeof(*new->e_len));
-
- for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
- new->e_orig[cnt] = *argv;
- for (p = *argv; *p; ++p)
- if (p[0] == '{' && p[1] == '}') {
- new->e_argv[cnt] = malloc(MAXPATHLEN);
- new->e_len[cnt] = MAXPATHLEN;
- break;
- }
- if (!*p) {
- new->e_argv[cnt] = *argv;
- new->e_len[cnt] = 0;
- }
- }
- new->e_argv[cnt] = new->e_orig[cnt] = NULL;
-
- *argvp = argv + 1;
- return (new);
-}
-
-PLAN *
-c_exit(char ***argvp, int isok, char *opt)
-{
- char *arg = **argvp;
- PLAN *new;
-
- /* not technically true, but otherwise '-print' is implied */
- isoutput = 1;
-
- new = palloc(N_EXIT, f_always_true);
-
- if (arg) {
- (*argvp)++;
- new->exit_val = find_parsenum(new, opt, arg, NULL);
- } else
- new->exit_val = 0;
-
- return (new);
-}
-
-
-/*
- * -false function
- */
-int
-f_false(PLAN *plan, FTSENT *entry)
-{
-
- return (0);
-}
-
-PLAN *
-c_false(char ***argvp, int isok, char *opt)
-{
- return (palloc(N_FALSE, f_false));
-}
-
-/*
- * -follow functions --
- *
- * Always true, causes symbolic links to be followed on a global
- * basis.
- */
-PLAN *
-c_follow(char ***argvp, int isok, char *opt)
-{
- ftsoptions &= ~FTS_PHYSICAL;
- ftsoptions |= FTS_LOGICAL;
-
- return (palloc(N_FOLLOW, f_always_true));
-}
-
-/* -fprint functions --
- *
- * Causes the current pathame to be written to the defined output file.
- */
-int
-f_fprint(PLAN *plan, FTSENT *entry)
-{
-
- if (-1 == fprintf(plan->fprint_file, "%s\n", entry->fts_path))
- warn("fprintf");
-
- return(1);
-
- /* no descriptors are closed; they will be closed by
- operating system when this find command exits. */
-}
-
-PLAN *
-c_fprint(char ***argvp, int isok, char *opt)
-{
- PLAN *new;
-
- isoutput = 1; /* do not assume -print */
-
- new = palloc(N_FPRINT, f_fprint);
-
- if (NULL == (new->fprint_file = fopen(**argvp, "w")))
- err(1, "%s: %s: cannot create file", opt, **argvp);
-
- (*argvp)++;
- return (new);
-}
-#define MNT_RDONLY 0x01
-/*
- * -fstype functions --
- *
- * True if the file is of a certain type.
- */
-int
-f_fstype(PLAN *plan, FTSENT *entry)
-{
- static char *fstype = NULL;
- FILE *file;
- struct mntent *mnt;
- int flags;
- char *filename = strdup(entry->fts_name);
- char *temp = strrchr(filename, '/');
- temp[0] = '\0';
-
- file = setmntent("/etc/mtab", "r");
- if (file == NULL) {
- err(1, "couldn't read mount table");
- }
-
- while ((mnt = getmntent(file)) != NULL) {
- if (!strncmp(mnt->mnt_dir, filename, strlen(mnt->mnt_dir))) {
- fstype = strdup(mnt->mnt_type);
- if (strstr(mnt->mnt_opts, MNTOPT_RO) != NULL) {
- flags |= MNT_RDONLY;
- }
- break;
- }
- }
- endmntent(file);
-
- switch (plan->flags) {
- case F_MTFLAG:
- return (flags & plan->mt_data);
- case F_MTTYPE:
- return (strncmp(fstype, plan->c_data, sizeof(fstype)) == 0);
- default:
- abort();
- }
-}
-
-PLAN *
-c_fstype(char ***argvp, int isok, char *opt)
-{
- char *arg = **argvp;
- PLAN *new;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- new = palloc(N_FSTYPE, f_fstype);
-
- switch (*arg) {
- case 'r':
- if (!strcmp(arg, "rdonly")) {
- new->flags = F_MTFLAG;
- new->mt_data = MNT_RDONLY;
- return (new);
- }
- break;
- }
-
- new->flags = F_MTTYPE;
- new->c_data = arg;
- return (new);
-}
-
-/*
- * -group gname functions --
- *
- * True if the file belongs to the group gname. If gname is numeric and
- * an equivalent of the getgrnam() function does not return a valid group
- * name, gname is taken as a group ID.
- */
-int
-f_group(PLAN *plan, FTSENT *entry)
-{
-
- COMPARE(entry->fts_statp->st_gid, plan->g_data);
-}
-
-PLAN *
-c_group(char ***argvp, int isok, char *opt)
-{
- char *gname = **argvp;
- PLAN *new;
- struct group *g;
- gid_t gid;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- new = palloc(N_GROUP, f_group);
- g = getgrnam(gname);
- if (g == NULL) {
- if (atoi(gname) == 0 && gname[0] != '0' &&
- strcmp(gname, "+0") && strcmp(gname, "-0"))
- errx(1, "%s: %s: no such group", opt, gname);
- gid = find_parsenum(new, "-group", gname, NULL);
-
- } else {
- new->flags = F_EQUAL;
- gid = g->gr_gid;
- }
-
- new->g_data = gid;
- return (new);
-}
-
-/*
- * -inum n functions --
- *
- * True if the file has inode # n.
- */
-int
-f_inum(PLAN *plan, FTSENT *entry)
-{
-
- COMPARE(entry->fts_statp->st_ino, plan->i_data);
-}
-
-PLAN *
-c_inum(char ***argvp, int isok, char *opt)
-{
- char *arg = **argvp;
- PLAN *new;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- new = palloc(N_INUM, f_inum);
- new->i_data = find_parsenum(new, opt, arg, NULL);
- return (new);
-}
-
-/*
- * -links n functions --
- *
- * True if the file has n links.
- */
-int
-f_links(PLAN *plan, FTSENT *entry)
-{
-
- COMPARE(entry->fts_statp->st_nlink, plan->l_data);
-}
-
-PLAN *
-c_links(char ***argvp, int isok, char *opt)
-{
- char *arg = **argvp;
- PLAN *new;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- new = palloc(N_LINKS, f_links);
- new->l_data = (nlink_t)find_parsenum(new, opt, arg, NULL);
- return (new);
-}
-
-/*
- * -ls functions --
- *
- * Always true - prints the current entry to stdout in "ls" format.
- */
-int
-f_ls(PLAN *plan, FTSENT *entry)
-{
-
- printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
- return (1);
-}
-
-PLAN *
-c_ls(char ***argvp, int isok, char *opt)
-{
-
- ftsoptions &= ~FTS_NOSTAT;
- isoutput = 1;
-
- return (palloc(N_LS, f_ls));
-}
-
-/*
- * - maxdepth n functions --
- *
- * True if the current search depth is less than or equal to the
- * maximum depth specified
- */
-int
-f_maxdepth(PLAN *plan, FTSENT *entry)
-{
- extern FTS *tree;
-
- if (entry->fts_level >= plan->max_data)
- fts_set(tree, entry, FTS_SKIP);
- return (entry->fts_level <= plan->max_data);
-}
-
-PLAN *
-c_maxdepth(char ***argvp, int isok, char *opt)
-{
- char *arg = **argvp;
- PLAN *new;
-
- (*argvp)++;
- new = palloc(N_MAXDEPTH, f_maxdepth);
- new->max_data = atoi(arg);
- return (new);
-}
-
-/*
- * - mindepth n functions --
- *
- * True if the current search depth is greater than or equal to the
- * minimum depth specified
- */
-int
-f_mindepth(PLAN *plan, FTSENT *entry)
-{
- return (entry->fts_level >= plan->min_data);
-}
-
-PLAN *
-c_mindepth(char ***argvp, int isok, char *opt)
-{
- char *arg = **argvp;
- PLAN *new;
-
- (*argvp)++;
- new = palloc(N_MINDEPTH, f_mindepth);
- new->min_data = atoi(arg);
- return (new);
-}
-
-/*
- * -mmin n functions --
- *
- * True if the difference between the file modification time and the
- * current time is n 24 hour periods.
- */
-int
-f_mmin(PLAN *plan, FTSENT *entry)
-{
-#define SECSPERMIN 60
- COMPARE((now - entry->fts_statp->st_mtime + SECSPERMIN - 1) /
- SECSPERMIN, plan->t_data);
-}
-
-PLAN *
-c_mmin(char ***argvp, int isok, char *opt)
-{
- char *arg = **argvp;
- PLAN *new;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- new = palloc(N_MMIN, f_mmin);
- new->t_data = find_parsenum(new, opt, arg, NULL);
- TIME_CORRECT(new, N_MMIN);
- return (new);
-}
-
-/*
- * -mtime n functions --
- *
- * True if the difference between the file modification time and the
- * current time is n 24 hour periods.
- */
-int
-f_mtime(PLAN *plan, FTSENT *entry)
-{
- COMPARE((now - entry->fts_statp->st_mtime + SECSPERDAY - 1) /
- SECSPERDAY, plan->t_data);
-}
-
-PLAN *
-c_mtime(char ***argvp, int isok, char *opt)
-{
- char *arg = **argvp;
- PLAN *new;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- new = palloc(N_MTIME, f_mtime);
- new->t_data = find_parsenum(new, opt, arg, NULL);
- TIME_CORRECT(new, N_MTIME);
- return (new);
-}
-
-/*
- * -name functions --
- *
- * True if the basename of the filename being examined
- * matches pattern using Pattern Matching Notation S3.14
- */
-int
-f_name(PLAN *plan, FTSENT *entry)
-{
-
- return (!fnmatch(plan->c_data, entry->fts_name, 0));
-}
-
-PLAN *
-c_name(char ***argvp, int isok, char *opt)
-{
- char *pattern = **argvp;
- PLAN *new;
-
- (*argvp)++;
- new = palloc(N_NAME, f_name);
- new->c_data = pattern;
- return (new);
-}
-
-/*
- * -iname functions --
- *
- * Similar to -name, but does case insensitive matching
- *
- */
-int
-f_iname(PLAN *plan, FTSENT *entry)
-{
- return (!fnmatch(plan->c_data, entry->fts_name, FNM_CASEFOLD));
-}
-
-PLAN *
-c_iname(char ***argvp, int isok, char *opt)
-{
- char *pattern = **argvp;
- PLAN *new;
-
- (*argvp)++;
- new = palloc(N_INAME, f_iname);
- new->c_data = pattern;
- return (new);
-}
-
-/*
- * -newer file functions --
- *
- * True if the current file has been modified more recently
- * than the modification time of the file named by the pathname
- * file.
- */
-int
-f_newer(PLAN *plan, FTSENT *entry)
-{
-
- return timespeccmp(&entry->fts_statp->st_mtim, &plan->ts_data, >);
-}
-
-PLAN *
-c_newer(char ***argvp, int isok, char *opt)
-{
- char *filename = **argvp;
- PLAN *new;
- struct stat sb;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- if (stat(filename, &sb))
- err(1, "%s: %s", opt, filename);
- new = palloc(N_NEWER, f_newer);
- new->ts_data = sb.st_mtim;
- return (new);
-}
-
-/*
- * -nogroup functions --
- *
- * True if file belongs to a user ID for which the equivalent
- * of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
- */
-int
-f_nogroup(PLAN *plan, FTSENT *entry)
-{
- return getgrgid(entry->fts_statp->st_gid) != NULL;
-}
-
-PLAN *
-c_nogroup(char ***argvp, int isok, char *opt)
-{
- ftsoptions &= ~FTS_NOSTAT;
-
- return (palloc(N_NOGROUP, f_nogroup));
-}
-
-/*
- * -nouser functions --
- *
- * True if file belongs to a user ID for which the equivalent
- * of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
- */
-int
-f_nouser(PLAN *plan, FTSENT *entry)
-{
- return getpwuid(entry->fts_statp->st_uid) != NULL;
-}
-
-PLAN *
-c_nouser(char ***argvp, int isok, char *opt)
-{
- ftsoptions &= ~FTS_NOSTAT;
-
- return (palloc(N_NOUSER, f_nouser));
-}
-
-/*
- * -path functions --
- *
- * True if the path of the filename being examined
- * matches pattern using Pattern Matching Notation S3.14
- */
-int
-f_path(PLAN *plan, FTSENT *entry)
-{
-
- return (!fnmatch(plan->c_data, entry->fts_path, 0));
-}
-
-PLAN *
-c_path(char ***argvp, int isok, char *opt)
-{
- char *pattern = **argvp;
- PLAN *new;
-
- (*argvp)++;
- new = palloc(N_NAME, f_path);
- new->c_data = pattern;
- return (new);
-}
-
-/*
- * -perm functions --
- *
- * The mode argument is used to represent file mode bits. If it starts
- * with a leading digit, it's treated as an octal mode, otherwise as a
- * symbolic mode.
- */
-int
-f_perm(PLAN *plan, FTSENT *entry)
-{
- mode_t mode;
-
- mode = entry->fts_statp->st_mode &
- (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
- if (plan->flags == F_ATLEAST)
- return ((plan->m_data | mode) == mode);
- else
- return (mode == plan->m_data);
- /* NOTREACHED */
-}
-
-PLAN *
-c_perm(char ***argvp, int isok, char *opt)
-{
- char *perm = **argvp;
- PLAN *new;
- mode_t *set;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- new = palloc(N_PERM, f_perm);
-
- if (*perm == '-') {
- new->flags = F_ATLEAST;
- ++perm;
- }
-
- if ((set = setmode(perm)) == NULL)
- err(1, "%s: Cannot set file mode `%s'", opt, perm);
-
- new->m_data = getmode(set, 0);
- free(set);
- return (new);
-}
-
-/*
- * -print functions --
- *
- * Always true, causes the current pathame to be written to
- * standard output.
- */
-int
-f_print(PLAN *plan, FTSENT *entry)
-{
-
- (void)printf("%s\n", entry->fts_path);
- return (1);
-}
-
-int
-f_print0(PLAN *plan, FTSENT *entry)
-{
-
- (void)fputs(entry->fts_path, stdout);
- (void)fputc('\0', stdout);
- return (1);
-}
-
-int
-f_printx(PLAN *plan, FTSENT *entry)
-{
- char *cp;
-
- for (cp = entry->fts_path; *cp; cp++) {
- if (*cp == '\'' || *cp == '\"' || *cp == ' ' ||
- *cp == '$' || *cp == '`' ||
- *cp == '\t' || *cp == '\n' || *cp == '\\')
- fputc('\\', stdout);
-
- fputc(*cp, stdout);
- }
-
- fputc('\n', stdout);
- return (1);
-}
-
-PLAN *
-c_print(char ***argvp, int isok, char *opt)
-{
-
- isoutput = 1;
-
- return (palloc(N_PRINT, f_print));
-}
-
-PLAN *
-c_print0(char ***argvp, int isok, char *opt)
-{
-
- isoutput = 1;
-
- return (palloc(N_PRINT0, f_print0));
-}
-
-PLAN *
-c_printx(char ***argvp, int isok, char *opt)
-{
-
- isoutput = 1;
-
- return (palloc(N_PRINTX, f_printx));
-}
-
-/*
- * -prune functions --
- *
- * Prune a portion of the hierarchy.
- */
-int
-f_prune(PLAN *plan, FTSENT *entry)
-{
- if (fts_set(tree, entry, FTS_SKIP))
- err(1, "%s", entry->fts_path);
- return (1);
-}
-
-PLAN *
-c_prune(char ***argvp, int isok, char *opt)
-{
-
- return (palloc(N_PRUNE, f_prune));
-}
-
-/*
- * -regex regexp (and related) functions --
- *
- * True if the complete file path matches the regular expression regexp.
- * For -regex, regexp is a case-sensitive (basic) regular expression.
- * For -iregex, regexp is a case-insensitive (basic) regular expression.
- */
-int
-f_regex(PLAN *plan, FTSENT *entry)
-{
-
- return (regexec(&plan->regexp_data, entry->fts_path, 0, NULL, 0) == 0);
-}
-
-static PLAN *
-c_regex_common(char ***argvp, int isok, enum ntype type, bool icase)
-{
- char errbuf[LINE_MAX];
- regex_t reg;
- char *regexp = **argvp;
- char *lineregexp;
- PLAN *new;
- int rv;
- size_t len;
-
- (*argvp)++;
-
- len = strlen(regexp) + 1 + 6;
- lineregexp = malloc(len); /* max needed */
- if (lineregexp == NULL)
- err(1, NULL);
- snprintf(lineregexp, len, "^%s(%s%s)$",
- (regcomp_flags & REG_EXTENDED) ? "" : "\\", regexp,
- (regcomp_flags & REG_EXTENDED) ? "" : "\\");
- rv = regcomp(&reg, lineregexp, REG_NOSUB|regcomp_flags|
- (icase ? REG_ICASE : 0));
- free(lineregexp);
- if (rv != 0) {
- regerror(rv, &reg, errbuf, sizeof errbuf);
- errx(1, "regexp %s: %s", regexp, errbuf);
- }
-
- new = palloc(type, f_regex);
- new->regexp_data = reg;
- return (new);
-}
-
-PLAN *
-c_regex(char ***argvp, int isok, char *opt)
-{
-
- return (c_regex_common(argvp, isok, N_REGEX, false));
-}
-
-PLAN *
-c_iregex(char ***argvp, int isok, char *opt)
-{
-
- return (c_regex_common(argvp, isok, N_IREGEX, true));
-}
-
-/*
- * -since "timestamp" functions --
- *
- * True if the file modification time is greater than the timestamp value
- */
-int
-f_since(PLAN *plan, FTSENT *entry)
-{
- COMPARE(entry->fts_statp->st_mtime, plan->t_data);
-}
-
-PLAN *
-c_since(char ***argvp, int isok, char *opt)
-{
- char *arg = **argvp;
- PLAN *new;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- new = palloc(N_SINCE, f_since);
- new->t_data = find_parsedate(new, opt, arg);
- new->flags = F_GREATER;
- return (new);
-}
-
-/*
- * -size n[c] functions --
- *
- * True if the file size in bytes, divided by an implementation defined
- * value and rounded up to the next integer, is n. If n is followed by
- * a c, the size is in bytes.
- */
-#define FIND_SIZE 512
-static int divsize = 1;
-
-int
-f_size(PLAN *plan, FTSENT *entry)
-{
- off_t size;
-
- size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) /
- FIND_SIZE : entry->fts_statp->st_size;
- COMPARE(size, plan->o_data);
-}
-
-PLAN *
-c_size(char ***argvp, int isok, char *opt)
-{
- char *arg = **argvp;
- PLAN *new;
- char endch;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- new = palloc(N_SIZE, f_size);
- endch = 'c';
- new->o_data = find_parsenum(new, opt, arg, &endch);
- if (endch == 'c')
- divsize = 0;
- return (new);
-}
-
-/*
- * -type c functions --
- *
- * True if the type of the file is c, where c is b, c, d, p, f or w
- * for block special file, character special file, directory, FIFO,
- * regular file or whiteout respectively.
- */
-int
-f_type(PLAN *plan, FTSENT *entry)
-{
-
- return ((entry->fts_statp->st_mode & S_IFMT) == plan->m_data);
-}
-
-PLAN *
-c_type(char ***argvp, int isok, char *opt)
-{
- char *typestring = **argvp;
- PLAN *new;
- mode_t mask = (mode_t)0;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- switch (typestring[0]) {
- case 'b':
- mask = S_IFBLK;
- break;
- case 'c':
- mask = S_IFCHR;
- break;
- case 'd':
- mask = S_IFDIR;
- break;
- case 'f':
- mask = S_IFREG;
- break;
- case 'l':
- mask = S_IFLNK;
- break;
- case 'p':
- mask = S_IFIFO;
- break;
- case 's':
- mask = S_IFSOCK;
- break;
-#ifdef S_IFWHT
- case 'W':
- case 'w':
- mask = S_IFWHT;
-#ifdef FTS_WHITEOUT
- ftsoptions |= FTS_WHITEOUT;
-#endif
- break;
-#endif /* S_IFWHT */
- default:
- errx(1, "%s: %s: unknown type", opt, typestring);
- }
-
- new = palloc(N_TYPE, f_type);
- new->m_data = mask;
- return (new);
-}
-
-/*
- * -user uname functions --
- *
- * True if the file belongs to the user uname. If uname is numeric and
- * an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
- * return a valid user name, uname is taken as a user ID.
- */
-int
-f_user(PLAN *plan, FTSENT *entry)
-{
-
- COMPARE(entry->fts_statp->st_uid, plan->u_data);
-}
-
-PLAN *
-c_user(char ***argvp, int isok, char *opt)
-{
- char *username = **argvp;
- PLAN *new;
- struct passwd *p;
- uid_t uid;
-
- (*argvp)++;
- ftsoptions &= ~FTS_NOSTAT;
-
- new = palloc(N_USER, f_user);
- p = getpwnam(username);
- if (p == NULL) {
- if (atoi(username) == 0 && username[0] != '0' &&
- strcmp(username, "+0") && strcmp(username, "-0"))
- errx(1, "%s: %s: no such user", opt, username);
- uid = find_parsenum(new, opt, username, NULL);
-
- } else {
- new->flags = F_EQUAL;
- uid = p->pw_uid;
- }
-
- new->u_data = uid;
- return (new);
-}
-
-/*
- * -xdev functions --
- *
- * Always true, causes find not to descend past directories that have a
- * different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
- */
-PLAN *
-c_xdev(char ***argvp, int isok, char *opt)
-{
- ftsoptions |= FTS_XDEV;
-
- return (palloc(N_XDEV, f_always_true));
-}
-
-/*
- * ( expression ) functions --
- *
- * True if expression is true.
- */
-int
-f_expr(PLAN *plan, FTSENT *entry)
-{
- PLAN *p;
- int state;
-
- state = 0;
- for (p = plan->p_data[0];
- p && (state = (p->eval)(p, entry)); p = p->next);
- return (state);
-}
-
-/*
- * N_OPENPAREN and N_CLOSEPAREN nodes are temporary place markers. They are
- * eliminated during phase 2 of find_formplan() --- the '(' node is converted
- * to a N_EXPR node containing the expression and the ')' node is discarded.
- */
-PLAN *
-c_openparen(char ***argvp, int isok, char *opt)
-{
-
- return (palloc(N_OPENPAREN, (int (*)(PLAN *, FTSENT *))-1));
-}
-
-PLAN *
-c_closeparen(char ***argvp, int isok, char *opt)
-{
-
- return (palloc(N_CLOSEPAREN, (int (*)(PLAN *, FTSENT *))-1));
-}
-
-/*
- * ! expression functions --
- *
- * Negation of a primary; the unary NOT operator.
- */
-int
-f_not(PLAN *plan, FTSENT *entry)
-{
- PLAN *p;
- int state;
-
- state = 0;
- for (p = plan->p_data[0];
- p && (state = (p->eval)(p, entry)); p = p->next);
- return (!state);
-}
-
-PLAN *
-c_not(char ***argvp, int isok, char *opt)
-{
-
- return (palloc(N_NOT, f_not));
-}
-
-/*
- * expression -o expression functions --
- *
- * Alternation of primaries; the OR operator. The second expression is
- * not evaluated if the first expression is true.
- */
-int
-f_or(PLAN *plan, FTSENT *entry)
-{
- PLAN *p;
- int state;
-
- state = 0;
- for (p = plan->p_data[0];
- p && (state = (p->eval)(p, entry)); p = p->next);
-
- if (state)
- return (1);
-
- for (p = plan->p_data[1];
- p && (state = (p->eval)(p, entry)); p = p->next);
- return (state);
-}
-
-PLAN *
-c_or(char ***argvp, int isok, char *opt)
-{
-
- return (palloc(N_OR, f_or));
-}
-
-PLAN *
-c_null(char ***argvp, int isok, char *opt)
-{
-
- return (NULL);
-}
-
-
-/*
- * plan_cleanup --
- * Check and see if the specified plan has any residual state,
- * and if so, clean it up as appropriate.
- *
- * At the moment, only N_EXEC has state. Two kinds: 1)
- * lists of files to feed to subprocesses 2) State on exit
- * statusses of past subprocesses.
- */
-/* ARGSUSED1 */
-int
-plan_cleanup(PLAN *plan, void *arg)
-{
- if (plan->type==N_EXEC && plan->ep_narg)
- run_f_exec(plan);
-
- return plan->ep_rval; /* Passed save exit-status up chain */
-}
-
-static PLAN *
-palloc(enum ntype t, int (*f)(PLAN *, FTSENT *))
-{
- PLAN *new;
-
- if ((new = malloc(sizeof(PLAN))) == NULL)
- err(1, NULL);
- memset(new, 0, sizeof(PLAN));
- new->type = t;
- new->eval = f;
- return (new);
-}
diff --git a/usr.bin/find/getdir.c b/usr.bin/find/getdir.c
new file mode 100644
index 0000000..3b3669d
--- /dev/null
+++ b/usr.bin/find/getdir.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/* Sccsid @(#)getdir.c 1.20 (gritter) 5/14/06 */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include "getdir.h"
+
+#define DIBSIZE 5120
+
+struct getdb {
+#if !defined (__FreeBSD__) && !defined (__NetBSD__) && !defined (__OpenBSD__) \
+ && !defined (__DragonFly__) && !defined (__APPLE__)
+ off_t g_offs;
+#else /* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
+ long g_offs;
+#endif /* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
+ struct dirent *g_dirp;
+ const char *g_path;
+ struct direc g_dic;
+ union {
+ char g_dirbuf[DIBSIZE+1];
+ struct dirent g_dummy[1];
+ } g_u;
+ int g_num;
+ int g_fd;
+};
+
+struct getdb *
+getdb_alloc(const char *path, int fd)
+{
+ struct getdb *db;
+
+ if ((db = malloc(sizeof *db)) == NULL)
+ return NULL;
+ db->g_dirp = NULL;
+ db->g_offs = 0;
+ db->g_fd = fd;
+ db->g_path = path;
+ return db;
+}
+
+void
+getdb_free(struct getdb *db)
+{
+ free(db);
+}
+
+struct direc *
+getdir(struct getdb *db, int *err)
+{
+ int reclen;
+
+ *err = 0;
+ while (db->g_dirp == NULL)
+ {
+ /*LINTED*/
+ db->g_num = getdents(db->g_fd,
+ (struct dirent *)db->g_u.g_dirbuf,
+ DIBSIZE);
+ if (db->g_num <= 0) {
+ if (db->g_num < 0)
+ *err = errno;
+ db->g_offs = 0;
+ return NULL;
+ }
+ /*LINTED*/
+ db->g_dirp = (struct dirent *)db->g_u.g_dirbuf;
+ while (db->g_dirp &&
+#if !defined (__FreeBSD__) && !defined (__NetBSD__) && !defined (__OpenBSD__) \
+ && !defined (__DragonFly__) && !defined (__APPLE__)
+ db->g_dirp->d_ino == 0
+#else /* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
+ (db->g_dirp->d_fileno == 0
+#ifdef DT_WHT
+ || db->g_dirp->d_type == DT_WHT
+#endif
+ )
+#endif /* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
+ )
+ {
+ next:
+#ifndef __DragonFly__
+ reclen = db->g_dirp->d_reclen;
+#else
+ reclen = _DIRENT_DIRSIZ(db->g_dirp);
+#endif
+ if ((db->g_num -= reclen) == 0 || reclen == 0)
+ db->g_dirp = NULL;
+ else
+ db->g_dirp =
+ /*LINTED*/
+ (struct dirent *)((char *)db->g_dirp
+ + reclen);
+ }
+ }
+#if !defined (__FreeBSD__) && !defined (__NetBSD__) && !defined (__OpenBSD__) \
+ && !defined (__DragonFly__) && !defined (__APPLE__)
+ if (db->g_dirp->d_ino == 0)
+ goto next;
+ db->g_dic.d_ino = db->g_dirp->d_ino;
+#else /* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
+ if (db->g_dirp->d_fileno == 0
+#ifdef DT_WHT
+ || db->g_dirp->d_type == DT_WHT
+#endif
+ )
+ {
+ goto next;
+ }
+ db->g_dic.d_ino = db->g_dirp->d_fileno;
+#endif /* __FreeBSD__, __NetBSD__, __OpenBSD__, __DragonFly__, __APPLE__ */
+ db->g_dic.d_name = db->g_dirp->d_name;
+#ifndef __DragonFly__
+ reclen = db->g_dirp->d_reclen;
+#else
+ reclen = _DIRENT_DIRSIZ(db->g_dirp);
+#endif
+ if ((db->g_num -= reclen) == 0 || reclen == 0)
+ db->g_dirp = NULL;
+ else
+ /*LINTED*/
+ db->g_dirp = (struct dirent *)((char *)db->g_dirp + reclen);
+ return &(db->g_dic);
+}
diff --git a/usr.bin/find/getdir.h b/usr.bin/find/getdir.h
new file mode 100644
index 0000000..29d107b
--- /dev/null
+++ b/usr.bin/find/getdir.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/* Sccsid @(#)getdir.h 1.4 (gritter) 10/19/03 */
+
+#include <sys/types.h>
+
+struct direc {
+ unsigned long long d_ino;
+ char *d_name;
+};
+
+extern struct getdb *getdb_alloc(const char *, int);
+extern void getdb_free(struct getdb *);
+extern struct direc *getdir(struct getdb *, int *);
diff --git a/usr.bin/find/ls.c b/usr.bin/find/ls.c
deleted file mode 100644
index 14ce841..0000000
--- a/usr.bin/find/ls.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/* $NetBSD: ls.c,v 1.21 2011/08/31 16:24:57 plunky Exp $ */
-
-/*
- * Copyright (c) 1989, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-
-#include <sys/param.h>
-#include <sys/stat.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fts.h>
-#include <grp.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <bsd/string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "find.h"
-
-/* Derived from the print routines in the ls(1) source code. */
-
-static void printlink(char *);
-static void printtime(time_t);
-
-void
-printlong(char *name, /* filename to print */
- char *accpath, /* current valid path to filename */
- struct stat *sb) /* stat buffer */
-{
- char modep[15];
- struct passwd *user = getpwuid(sb->st_uid);
- struct group *group = getgrgid(sb->st_gid);
- char *username, *groupname;
-
- if (user == NULL) {
- username = malloc(21);
- snprintf(username, 20, "%d", sb->st_uid);
- } else {
- username = user->pw_name;
- }
- if (group == NULL) {
- groupname = malloc(21);
- snprintf(groupname, 20, "%d", sb->st_gid);
- } else {
- groupname = group->gr_name;
- }
-
- (void)printf("%7lu %6lld ", (u_long)sb->st_ino,
- (long long)sb->st_blocks);
- (void)strmode(sb->st_mode, modep);
- (void)printf("%s %3lu %-*s %-*s ", modep, (unsigned long)sb->st_nlink,
- LOGIN_NAME_MAX, username, LOGIN_NAME_MAX, groupname);
-
- if (S_ISCHR(sb->st_mode) || S_ISBLK(sb->st_mode))
- (void)printf("%3llu,%5llu ",
- (unsigned long long)major(sb->st_rdev),
- (unsigned long long)minor(sb->st_rdev));
- else
- (void)printf("%9lld ", (long long)sb->st_size);
- printtime(sb->st_mtime);
- (void)printf("%s", name);
- if (S_ISLNK(sb->st_mode))
- printlink(accpath);
- (void)putchar('\n');
-
- if (user == NULL) free(username);
- if (group == NULL) free(groupname);
-}
-
-static void
-printtime(time_t ftime)
-{
- int i;
- char *longstring;
-
- longstring = ctime(&ftime);
- for (i = 4; i < 11; ++i)
- (void)putchar(longstring[i]);
-#define DAYSPERNYEAR 365
-#define SECSPERDAY 24 * 60 * 60
-#define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY)
- if (ftime + SIXMONTHS > time(NULL))
- for (i = 11; i < 16; ++i)
- (void)putchar(longstring[i]);
- else {
- (void)putchar(' ');
- for (i = 20; i < 24; ++i)
- (void)putchar(longstring[i]);
- }
- (void)putchar(' ');
-}
-
-static void
-printlink(char *name)
-{
- int lnklen;
- char path[MAXPATHLEN + 1];
-
- if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
- warn("%s", name);
- return;
- }
- path[lnklen] = '\0';
- (void)printf(" -> %s", path);
-}
diff --git a/usr.bin/find/main.c b/usr.bin/find/main.c
deleted file mode 100644
index 6ff7e3c..0000000
--- a/usr.bin/find/main.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/* $NetBSD: main.c,v 1.31 2013/01/24 17:50:08 christos Exp $ */
-
-/*-
- * Copyright (c) 1990, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Cimarron D. Taylor of the University of California, Berkeley.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <fts.h>
-#include <locale.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <bsd/stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "find.h"
-
-time_t now; /* time find was run */
-int dotfd; /* starting directory */
-int ftsoptions; /* options for the ftsopen(3) call */
-int isdeprecated; /* using deprecated syntax */
-int isdepth; /* do directories on post-order visit */
-int isoutput; /* user specified output operator */
-int issort; /* sort directory entries */
-int isxargs; /* don't permit xargs delimiting chars */
-int regcomp_flags = 0; /* regex compilation flags */
-
-static void usage(void);
-
-int
-main(int argc, char *argv[])
-{
- char **p, **start;
- int ch;
-
- (void)time(&now); /* initialize the time-of-day */
- (void)setlocale(LC_ALL, "");
-
- /* array to hold dir list. at most (argc - 1) elements. */
- p = start = malloc(argc * sizeof (char *));
- if (p == NULL)
- err(1, NULL);
-
- ftsoptions = FTS_NOSTAT | FTS_PHYSICAL;
- while ((ch = getopt(argc, argv, "HLPdEf:hsXx")) != -1)
- switch (ch) {
- case 'H':
- ftsoptions &= ~FTS_LOGICAL;
- ftsoptions |= FTS_PHYSICAL|FTS_COMFOLLOW;
- break;
- case 'L':
- ftsoptions &= ~(FTS_COMFOLLOW|FTS_PHYSICAL);
- ftsoptions |= FTS_LOGICAL;
- break;
- case 'P':
- ftsoptions &= ~(FTS_COMFOLLOW|FTS_LOGICAL);
- ftsoptions |= FTS_PHYSICAL;
- break;
- case 'd':
- isdepth = 1;
- break;
- case 'E':
- regcomp_flags = REG_EXTENDED;
- break;
- case 'f':
- *p++ = optarg;
- break;
- case 'h':
- ftsoptions &= ~FTS_PHYSICAL;
- ftsoptions |= FTS_LOGICAL;
- break;
- case 's':
- issort = 1;
- break;
- case 'X':
- isxargs = 1;
- break;
- case 'x':
- ftsoptions |= FTS_XDEV;
- break;
- case '?':
- default:
- break;
- }
-
- argc -= optind;
- argv += optind;
-
- /*
- * Find first option to delimit the file list. The first argument
- * that starts with a -, or is a ! or a ( must be interpreted as a
- * part of the find expression, according to POSIX .2.
- */
- for (; *argv != NULL; *p++ = *argv++) {
- if (argv[0][0] == '-')
- break;
- if ((argv[0][0] == '!' || argv[0][0] == '(') &&
- argv[0][1] == '\0')
- break;
- }
-
- if (p == start)
- usage();
-
- *p = NULL;
-
- if ((dotfd = open(".", O_RDONLY | O_CLOEXEC, 0)) == -1)
- err(1, ".");
-
- exit(find_execute(find_formplan(argv), start));
-}
-
-static void
-usage(void)
-{
-
- (void)fprintf(stderr, "Usage: %s [-H | -L | -P] [-dEhsXx] [-f file] "
- "file [file ...] [expression]\n", getprogname());
- exit(1);
-}
diff --git a/usr.bin/find/misc.c b/usr.bin/find/misc.c
deleted file mode 100644
index a6401cb..0000000
--- a/usr.bin/find/misc.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/* $NetBSD: misc.c,v 1.14 2006/10/11 19:51:10 apb Exp $ */
-
-/*-
- * Copyright (c) 1990, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Cimarron D. Taylor of the University of California, Berkeley.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fts.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "find.h"
-
-/*
- * brace_subst --
- * Replace occurrences of {} in orig with path, and place it in a malloced
- * area of memory set in store.
- */
-void
-brace_subst(char *orig, char **store, char *path, int *len)
-{
- int nlen, plen, rest;
- char ch, *p, *ostore;
-
- plen = strlen(path);
- for (p = *store; (ch = *orig) != '\0'; ++orig)
- if (ch == '{' && orig[1] == '}') {
- /* Length of string after the {}. */
- rest = strlen(&orig[2]);
-
- nlen = *len;
- while ((p - *store) + plen + rest + 1 > nlen)
- nlen *= 2;
-
- if (nlen > *len) {
- ostore = *store;
- if ((*store = realloc(ostore, nlen)) == NULL)
- err(1, "realloc");
- *len = nlen;
- p += *store - ostore; /* Relocate. */
- }
- memmove(p, path, plen);
- p += plen;
- ++orig;
- } else
- *p++ = ch;
- *p = '\0';
-}
-
-/*
- * queryuser --
- * print a message to standard error and then read input from standard
- * input. If the input is 'y' then 1 is returned.
- */
-int
-queryuser(char **argv)
-{
- int ch, first, nl;
-
- (void)fprintf(stderr, "\"%s", *argv);
- while (*++argv)
- (void)fprintf(stderr, " %s", *argv);
- (void)fprintf(stderr, "\"? ");
- (void)fflush(stderr);
-
- first = ch = getchar();
- for (nl = 0;;) {
- if (ch == '\n') {
- nl = 1;
- break;
- }
- if (ch == EOF)
- break;
- ch = getchar();
- }
-
- if (!nl) {
- (void)fprintf(stderr, "\n");
- (void)fflush(stderr);
- }
- return (first == 'y');
-}
-
-/*
- * show_path --
- * called on SIGINFO
- */
-/* ARGSUSED */
-void
-show_path(int sig)
-{
- extern FTSENT *g_entry;
- int errno_bak;
-
- if (g_entry == NULL) {
- /*
- * not initialized yet.
- * assumption: pointer assignment is atomic.
- */
- return;
- }
-
- errno_bak = errno;
- write(STDERR_FILENO, "find path: ", 11);
- write(STDERR_FILENO, g_entry->fts_path, g_entry->fts_pathlen);
- write(STDERR_FILENO, "\n", 1);
- errno = errno_bak;
-}
diff --git a/usr.bin/find/operator.c b/usr.bin/find/operator.c
deleted file mode 100644
index e65677b..0000000
--- a/usr.bin/find/operator.c
+++ /dev/null
@@ -1,263 +0,0 @@
-/* $NetBSD: operator.c,v 1.10 2014/10/18 08:33:30 snj Exp $ */
-
-/*-
- * Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Cimarron D. Taylor of the University of California, Berkeley.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-
-#include <err.h>
-#include <fts.h>
-#include <stdio.h>
-
-#include "find.h"
-
-static PLAN *yanknode(PLAN **);
-static PLAN *yankexpr(PLAN **);
-
-/*
- * yanknode --
- * destructively removes the top from the plan
- */
-static PLAN *
-yanknode(PLAN **planp) /* pointer to top of plan (modified) */
-{
- PLAN *node; /* top node removed from the plan */
-
- if ((node = (*planp)) == NULL)
- return (NULL);
- (*planp) = (*planp)->next;
- node->next = NULL;
- return (node);
-}
-
-/*
- * yankexpr --
- * Removes one expression from the plan. This is used mainly by
- * paren_squish. In comments below, an expression is either a
- * simple node or a N_EXPR node containing a list of simple nodes.
- */
-static PLAN *
-yankexpr(PLAN **planp) /* pointer to top of plan (modified) */
-{
- PLAN *next; /* temp node holding subexpression results */
- PLAN *node; /* pointer to returned node or expression */
- PLAN *tail; /* pointer to tail of subplan */
- PLAN *subplan; /* pointer to head of ( ) expression */
-
- /* first pull the top node from the plan */
- if ((node = yanknode(planp)) == NULL)
- return (NULL);
-
- /*
- * If the node is an '(' then we recursively slurp up expressions
- * until we find its associated ')'. If it's a closing paren we
- * just return it and unwind our recursion; all other nodes are
- * complete expressions, so just return them.
- */
- if (node->type == N_OPENPAREN)
- for (tail = subplan = NULL;;) {
- if ((next = yankexpr(planp)) == NULL)
- err(1, "(: missing closing ')'");
- /*
- * If we find a closing ')' we store the collected
- * subplan in our '(' node and convert the node to
- * a N_EXPR. The ')' we found is ignored. Otherwise,
- * we just continue to add whatever we get to our
- * subplan.
- */
- if (next->type == N_CLOSEPAREN) {
- if (subplan == NULL)
- errx(1, "(): empty inner expression");
- node->p_data[0] = subplan;
- node->type = N_EXPR;
- node->eval = f_expr;
- break;
- } else {
- if (subplan == NULL)
- tail = subplan = next;
- else {
- tail->next = next;
- tail = next;
- }
- tail->next = NULL;
- }
- }
- return (node);
-}
-
-/*
- * paren_squish --
- * replaces "parentheisized" plans in our search plan with "expr" nodes.
- */
-PLAN *
-paren_squish(PLAN *plan) /* plan with ( ) nodes */
-{
- PLAN *expr; /* pointer to next expression */
- PLAN *tail; /* pointer to tail of result plan */
- PLAN *result; /* pointer to head of result plan */
-
- result = tail = NULL;
-
- /*
- * the basic idea is to have yankexpr do all our work and just
- * collect its results together.
- */
- while ((expr = yankexpr(&plan)) != NULL) {
- /*
- * if we find an unclaimed ')' it means there is a missing
- * '(' someplace.
- */
- if (expr->type == N_CLOSEPAREN)
- errx(1, "): no beginning '('");
-
- /* add the expression to our result plan */
- if (result == NULL)
- tail = result = expr;
- else {
- tail->next = expr;
- tail = expr;
- }
- tail->next = NULL;
- }
- return (result);
-}
-
-/*
- * not_squish --
- * compresses "!" expressions in our search plan.
- */
-PLAN *
-not_squish(PLAN *plan) /* plan to process */
-{
- PLAN *next; /* next node being processed */
- PLAN *node; /* temporary node used in N_NOT processing */
- PLAN *tail; /* pointer to tail of result plan */
- PLAN *result; /* pointer to head of result plan */
-
- tail = result = next = NULL;
-
- while ((next = yanknode(&plan)) != NULL) {
- /*
- * if we encounter a ( expression ) then look for nots in
- * the expr subplan.
- */
- if (next->type == N_EXPR)
- next->p_data[0] = not_squish(next->p_data[0]);
-
- /*
- * if we encounter a not, then snag the next node and place
- * it in the not's subplan. As an optimization we compress
- * several not's to zero or one not.
- */
- if (next->type == N_NOT) {
- int notlevel = 1;
-
- node = yanknode(&plan);
- while (node != NULL && node->type == N_NOT) {
- ++notlevel;
- node = yanknode(&plan);
- }
- if (node == NULL)
- errx(1, "!: no following expression");
- if (node->type == N_OR)
- errx(1, "!: nothing between ! and -o");
- if (node->type == N_EXPR)
- node = not_squish(node);
- if (notlevel % 2 != 1)
- next = node;
- else
- next->p_data[0] = node;
- }
-
- /* add the node to our result plan */
- if (result == NULL)
- tail = result = next;
- else {
- tail->next = next;
- tail = next;
- }
- tail->next = NULL;
- }
- return (result);
-}
-
-/*
- * or_squish --
- * compresses -o expressions in our search plan.
- */
-PLAN *
-or_squish(PLAN *plan) /* plan with ors to be squished */
-{
- PLAN *next; /* next node being processed */
- PLAN *tail; /* pointer to tail of result plan */
- PLAN *result; /* pointer to head of result plan */
-
- tail = result = next = NULL;
-
- while ((next = yanknode(&plan)) != NULL) {
- /*
- * if we encounter a ( expression ) then look for or's in
- * the expr subplan.
- */
- if (next->type == N_EXPR)
- next->p_data[0] = or_squish(next->p_data[0]);
-
- /* if we encounter a not then look for not's in the subplan */
- if (next->type == N_NOT)
- next->p_data[0] = or_squish(next->p_data[0]);
-
- /*
- * if we encounter an or, then place our collected plan in the
- * or's first subplan and then recursively collect the
- * remaining stuff into the second subplan and return the or.
- */
- if (next->type == N_OR) {
- if (result == NULL)
- errx(1, "-o: no expression before -o");
- next->p_data[0] = result;
- next->p_data[1] = or_squish(plan);
- if (next->p_data[1] == NULL)
- errx(1, "-o: no expression after -o");
- return (next);
- }
-
- /* add the node to our result plan */
- if (result == NULL)
- tail = result = next;
- else {
- tail->next = next;
- tail = next;
- }
- tail->next = NULL;
- }
- return (result);
-}
diff --git a/usr.bin/find/option.c b/usr.bin/find/option.c
deleted file mode 100644
index 0834c27..0000000
--- a/usr.bin/find/option.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* $NetBSD: option.c,v 1.27 2016/06/13 00:04:40 pgoyette Exp $ */
-
-/*-
- * Copyright (c) 1990, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Cimarron D. Taylor of the University of California, Berkeley.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <err.h>
-#include <fts.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "find.h"
-
-int typecompare(const void *, const void *);
-static OPTION *option(char *);
-
-/* NB: the following table must be sorted lexically. */
-static OPTION const options[] = {
- { "!", N_NOT, c_not, 0 },
- { "(", N_OPENPAREN, c_openparen, 0 },
- { ")", N_CLOSEPAREN, c_closeparen, 0 },
- { "-a", N_AND, c_null, 0 },
- { "-amin", N_AMIN, c_amin, 1 },
- { "-and", N_AND, c_null, 0 },
- { "-anewer", N_ANEWER, c_anewer, 1 },
- { "-asince", N_ASINCE, c_asince, 1 },
- { "-atime", N_ATIME, c_atime, 1 },
- { "-cmin", N_CMIN, c_cmin, 1 },
- { "-cnewer", N_CNEWER, c_cnewer, 1 },
- { "-csince", N_CSINCE, c_csince, 1 },
- { "-ctime", N_CTIME, c_ctime, 1 },
- { "-delete", N_DELETE, c_delete, 0 },
- { "-depth", N_DEPTH, c_depth, 0 },
- { "-empty", N_EMPTY, c_empty, 0 },
- { "-exec", N_EXEC, c_exec, 1 },
- { "-execdir", N_EXECDIR, c_execdir, 1 },
- { "-exit", N_EXIT, c_exit, 0 },
- { "-false", N_FALSE, c_false, 0 },
- { "-follow", N_FOLLOW, c_follow, 0 },
- { "-fprint", N_FPRINT, c_fprint, 1 },
- { "-fstype", N_FSTYPE, c_fstype, 1 },
- { "-group", N_GROUP, c_group, 1 },
- { "-iname", N_INAME, c_iname, 1 },
- { "-inum", N_INUM, c_inum, 1 },
- { "-iregex", N_IREGEX, c_iregex, 1 },
- { "-links", N_LINKS, c_links, 1 },
- { "-ls", N_LS, c_ls, 0 },
- { "-maxdepth", N_MAXDEPTH, c_maxdepth, 1 },
- { "-mindepth", N_MINDEPTH, c_mindepth, 1 },
- { "-mmin", N_MMIN, c_mmin, 1 },
- { "-mtime", N_MTIME, c_mtime, 1 },
- { "-name", N_NAME, c_name, 1 },
- { "-newer", N_NEWER, c_newer, 1 },
-
-/* Aliases for compatability with Gnu findutils */
- { "-neweraa", N_ANEWER, c_anewer, 1 },
- { "-newerat", N_ASINCE, c_asince, 1 },
- { "-newercc", N_CNEWER, c_cnewer, 1 },
- { "-newerct", N_CSINCE, c_csince, 1 },
- { "-newermm", N_NEWER, c_newer, 1 },
- { "-newermt", N_SINCE, c_since, 1 },
-
-/*
- * Unimplemented Gnu findutils options
- *
- * If you implement any of these, be sure to re-sort the table
- * in ascii(7) order!
- *
- { "-newerBB", N_UNIMPL, c_unimpl, 1 },
- { "-newerBa", N_UNIMPL, c_unimpl, 1 },
- { "-newerBc", N_UNIMPL, c_unimpl, 1 },
- { "-newerBm", N_UNIMPL, c_unimpl, 1 },
- { "-newerBt", N_UNIMPL, c_unimpl, 1 },
- { "-neweraB", N_UNIMPL, c_unimpl, 1 },
- { "-newerac", N_UNIMPL, c_unimpl, 1 },
- { "-neweram", N_UNIMPL, c_unimpl, 1 },
- { "-newerca", N_UNIMPL, c_unimpl, 1 },
- { "-newercm", N_UNIMPL, c_unimpl, 1 },
- { "-newercB", N_UNIMPL, c_unimpl, 1 },
- { "-newermB", N_UNIMPL, c_unimpl, 1 },
- { "-newerma", N_UNIMPL, c_unimpl, 1 },
- { "-newermc", N_UNIMPL, c_unimpl, 1 },
- *
- */
-
- { "-nogroup", N_NOGROUP, c_nogroup, 0 },
- { "-nouser", N_NOUSER, c_nouser, 0 },
- { "-o", N_OR, c_or, 0 },
- { "-ok", N_OK, c_exec, 1 },
- { "-or", N_OR, c_or, 0 },
- { "-path", N_PATH, c_path, 1 },
- { "-perm", N_PERM, c_perm, 1 },
- { "-print", N_PRINT, c_print, 0 },
- { "-print0", N_PRINT0, c_print0, 0 },
- { "-printx", N_PRINTX, c_printx, 0 },
- { "-prune", N_PRUNE, c_prune, 0 },
- { "-regex", N_REGEX, c_regex, 1 },
- { "-rm", N_DELETE, c_delete, 0 },
- { "-since", N_SINCE, c_since, 1 },
- { "-size", N_SIZE, c_size, 1 },
- { "-type", N_TYPE, c_type, 1 },
- { "-user", N_USER, c_user, 1 },
- { "-xdev", N_XDEV, c_xdev, 0 }
-};
-
-/*
- * find_create --
- * create a node corresponding to a command line argument.
- *
- * TODO:
- * add create/process function pointers to node, so we can skip
- * this switch stuff.
- */
-PLAN *
-find_create(char ***argvp)
-{
- OPTION *p;
- PLAN *new;
- char **argv;
- char *opt;
-
- argv = *argvp;
- opt = *argv;
-
- if ((p = option(opt)) == NULL)
- errx(1, "%s: unknown option", opt);
- ++argv;
- if (p->arg && !*argv)
- errx(1, "%s: requires additional arguments", opt);
-
- new = (p->create)(&argv, p->token == N_OK, opt);
-
- *argvp = argv;
- return (new);
-}
-
-static OPTION *
-option(char *name)
-{
- OPTION tmp;
-
- tmp.name = name;
- return ((OPTION *)bsearch(&tmp, options,
- sizeof(options)/sizeof(OPTION), sizeof(OPTION), typecompare));
-}
-
-int
-typecompare(const void *a, const void *b)
-{
-
- return (strcmp(((const OPTION *)a)->name, ((const OPTION *)b)->name));
-}