summaryrefslogtreecommitdiffstats
path: root/usr.bin/find
diff options
context:
space:
mode:
authorrgrimes <rgrimes@FreeBSD.org>1994-05-27 12:33:43 +0000
committerrgrimes <rgrimes@FreeBSD.org>1994-05-27 12:33:43 +0000
commitf9ab90d9d6d02989a075d0f0074496d5b1045e4b (patch)
treeadd7e996bac5289cdc55e6935750c352505560a9 /usr.bin/find
parentbe22b15ae2ff8d7fe06b6e14fddf0c5b444a95da (diff)
downloadFreeBSD-src-f9ab90d9d6d02989a075d0f0074496d5b1045e4b.zip
FreeBSD-src-f9ab90d9d6d02989a075d0f0074496d5b1045e4b.tar.gz
BSD 4.4 Lite Usr.bin Sources
Diffstat (limited to 'usr.bin/find')
-rw-r--r--usr.bin/find/Makefile6
-rw-r--r--usr.bin/find/extern.h78
-rw-r--r--usr.bin/find/find.1454
-rw-r--r--usr.bin/find/find.c192
-rw-r--r--usr.bin/find/find.h107
-rw-r--r--usr.bin/find/function.c1069
-rw-r--r--usr.bin/find/ls.c118
-rw-r--r--usr.bin/find/main.c153
-rw-r--r--usr.bin/find/misc.c127
-rw-r--r--usr.bin/find/operator.c270
-rw-r--r--usr.bin/find/option.c150
11 files changed, 2724 insertions, 0 deletions
diff --git a/usr.bin/find/Makefile b/usr.bin/find/Makefile
new file mode 100644
index 0000000..c305d6a
--- /dev/null
+++ b/usr.bin/find/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= find
+SRCS= find.c function.c ls.c main.c misc.c operator.c option.c
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/find/extern.h b/usr.bin/find/extern.h
new file mode 100644
index 0000000..3db2d5f
--- /dev/null
+++ b/usr.bin/find/extern.h
@@ -0,0 +1,78 @@
+/*-
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. 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.
+ *
+ * @(#)extern.h 8.3 (Berkeley) 4/16/94
+ */
+
+#include <sys/cdefs.h>
+
+void brace_subst __P((char *, char **, char *, int));
+void *emalloc __P((unsigned int));
+PLAN *find_create __P((char ***));
+int find_execute __P((PLAN *, char **));
+PLAN *find_formplan __P((char **));
+PLAN *not_squish __P((PLAN *));
+PLAN *or_squish __P((PLAN *));
+PLAN *paren_squish __P((PLAN *));
+struct stat;
+void printlong __P((char *, char *, struct stat *));
+int queryuser __P((char **));
+
+PLAN *c_atime __P((char *));
+PLAN *c_ctime __P((char *));
+PLAN *c_depth __P((void));
+PLAN *c_exec __P((char ***, int));
+PLAN *c_follow __P((void));
+PLAN *c_fstype __P((char *));
+PLAN *c_group __P((char *));
+PLAN *c_inum __P((char *));
+PLAN *c_links __P((char *));
+PLAN *c_ls __P((void));
+PLAN *c_name __P((char *));
+PLAN *c_newer __P((char *));
+PLAN *c_nogroup __P((void));
+PLAN *c_nouser __P((void));
+PLAN *c_path __P((char *));
+PLAN *c_perm __P((char *));
+PLAN *c_print __P((void));
+PLAN *c_prune __P((void));
+PLAN *c_size __P((char *));
+PLAN *c_type __P((char *));
+PLAN *c_user __P((char *));
+PLAN *c_xdev __P((void));
+PLAN *c_openparen __P((void));
+PLAN *c_closeparen __P((void));
+PLAN *c_mtime __P((char *));
+PLAN *c_not __P((void));
+PLAN *c_or __P((void));
+
+extern int ftsoptions, isdeprecated, isdepth, isoutput, isxargs;
diff --git a/usr.bin/find/find.1 b/usr.bin/find/find.1
new file mode 100644
index 0000000..6523bba
--- /dev/null
+++ b/usr.bin/find/find.1
@@ -0,0 +1,454 @@
+.\" 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.
+.\"
+.\" 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. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. 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.
+.\"
+.\" @(#)find.1 8.4 (Berkeley) 4/1/94
+.\"
+.Dd April 1, 1994
+.Dt FIND 1
+.Os
+.Sh NAME
+.Nm find
+.Nd walk a file hierarchy
+.Sh SYNOPSIS
+.Nm find
+.Op Fl H | Fl L | Fl P
+.Op Fl Xdx
+.Op Fl f Ar file
+.Op Ar file ...
+.Ar expression
+.Sh DESCRIPTION
+.Nm Find
+recursively descends the directory tree for each
+.Ar file
+listed, evaluating an
+.Ar expression
+(composed of the ``primaries'' and ``operands'' listed below) in terms
+of each file in the tree.
+.Pp
+The options are as follows:
+.Pp
+.Bl -tag -width Ds
+.It Fl H
+The
+.Fl H
+option causes the file information and file type (see
+.Xr stat 2)
+returned for each symbolic link specified 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
+The
+.Fl L
+option 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
+The
+.Fl P
+option 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 X
+The
+.Fl X
+option is a modification 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 ,
+a diagnostic message is displayed on standard error, and the file
+is skipped.
+The delimiting characters include single (`` ' '') and double (`` " '')
+quotes, backslash (``\e''), space, tab and newline characters.
+.It Fl d
+The
+.Fl d
+option causes
+.Nm find
+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 find
+visits directories in pre\-order, i.e. before their contents.
+Note, the default is
+.Ar not
+a breadth\-first traversal.
+.It Fl f
+The
+.Fl f
+option specifies a file hierarchy for
+.Nm find
+to traverse.
+File hierarchies may also be specified as the operands immediately
+following the options.
+.It Fl x
+The
+.Fl x
+option prevents
+.Nm find
+from descending into directories that have a device number different
+than that of the file from which the descent began.
+.El
+.Sh PRIMARIES
+.Bl -tag -width Ds
+.It Ic -atime Ar n
+True if the difference between the file last access time and the time
+.Nm find
+was started, rounded up to the next full 24\-hour period, is
+.Ar n
+24\-hour periods.
+.It Ic -ctime Ar n
+True if the difference between the time of last change of file status
+information and the time
+.Nm find
+was started, rounded up to the next full 24\-hour period, is
+.Ar n
+24\-hour periods.
+.It Ic -exec Ar utility Op argument ... ;
+True if the program named
+.Ar utility
+returns a zero value as its exit status.
+Optional arguments may be passed to the utility.
+The expression must be terminated by a semicolon (``;'').
+If the string ``{}'' appears anywhere in the utility name or the
+arguments it is replaced by the pathname of the current file.
+.Ar Utility
+will be executed from the directory from which
+.Nm find
+was executed.
+.It Ic -fstype Ar type
+True if the file is contained in a file system of type
+.Ar type .
+Currently supported types are ``local'', ``mfs'', ``nfs'', ``msdos'',
+``rdonly'' and ``ufs''.
+The types ``local'' and ``rdonly'' are not specific file system types.
+The former matches any file system physically mounted on the system where
+the
+.Nm find
+is being executed and the latter matches any file system which is
+mounted read-only.
+.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.
+.It Ic -inum Ar n
+True if the file has inode number
+.Ar n .
+.It Ic -links Ar n
+True if the file has
+.Ar n
+links.
+.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 ``\->''.
+The format is identical to that produced by ``ls \-dgils''.
+.It Ic -mtime Ar n
+True if the difference between the file last modification time and the time
+.Nm find
+was started, rounded up to the next full 24\-hour period, is
+.Ar n
+24\-hour periods.
+.It Ic \&-ok Ar utility Ns Op argument ... ;
+The
+.Ic \&-ok
+primary is identical to the
+.Ic -exec
+primary with the exception that
+.Nm find
+requests user affirmation for the execution of the utility by printing
+a message to the terminal and reading a response.
+If the response is other than ``y'' the command is not executed and the
+value of the
+.Ar \&ok
+expression is false.
+.It Ic -name Ar pattern
+True if the last component of the pathname being examined matches
+.Ar pattern .
+Special shell pattern matching characters (``['', ``]'', ``*'', and ``?'')
+may be used as part of
+.Ar pattern .
+These characters may be matched explicitly by escaping them with a
+backslash (``\e'').
+.It Ic -newer Ar file
+True if the current file has a more recent last modification time than
+.Ar file .
+.It Ic -nouser
+True if the file belongs to an unknown user.
+.It Ic -nogroup
+True if the file belongs to an unknown group.
+.It Ic -path Ar pattern
+True if the pathname being examined matches
+.Ar pattern .
+Special shell pattern matching characters (``['', ``]'', ``*'', and ``?'')
+may be used as part of
+.Ar pattern .
+These characters may be matched explicitly by escaping them with a
+backslash (``\e'').
+Slashes (``/'') are treated as normal characters and do not have to be
+matched explicitly.
+.It Ic -perm Op Fl 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 (``\-''), 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 (``\-'').
+.It Ic -print
+This primary always evaluates to true.
+It prints the pathname of the current file to standard output.
+The expression is appended to the user specified expression if neither
+.Ic -exec ,
+.Ic -ls
+or
+.Ic \&-ok
+is specified.
+.It Ic -prune
+This primary always evaluates to true.
+It causes
+.Nm find
+to not descend into the current file.
+Note, the
+.Ic -prune
+primary has no effect if the
+.Fl d
+option was specified.
+.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 ``c'', then the primary is true if the
+file's size is
+.Ar n
+bytes.
+.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
+.El
+.Pp
+.It Ic -user Ar uname
+True if the file belongs to the user
+.Ar uname .
+If
+.Ar uname
+is numeric and there is no such user name, then
+.Ar uname
+is treated as a user id.
+.El
+.Pp
+All primaries which take a numeric argument allow the number to be
+preceded by a plus sign (``+'') or a minus sign (``\-'').
+A preceding plus sign means ``more than n'', a preceding minus sign means
+``less than n'' and neither means ``exactly n'' .
+.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 \&( Ns Ar expression Ns Cm \&)
+This evaluates to true if the parenthesized expression evaluates to
+true.
+.Pp
+.It Cm \&! Ns Ar expression
+This is the unary
+.Tn NOT
+operator.
+It evaluates to true if the expression is false.
+.Pp
+.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.
+.Pp
+.It Ar expression Cm -or Ar expression
+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 find .
+Primaries which themselves take arguments expect each argument
+to be a separate argument to
+.Nm find .
+.Sh EXAMPLES
+.Pp
+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 ``.c''.
+.It Li "find / -newer ttt -user wnj -print"
+Print out a list of all the files owned by user ``wnj'' that are newer
+than the file ``ttt''.
+.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 ``ttt''
+and owned by ``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 ``wnj'' or
+that are newer than ``ttt''.
+.El
+.Sh SEE ALSO
+.Xr chmod 1 ,
+.Xr locate 1 ,
+.Xr stat 2 ,
+.Xr fts 3 ,
+.Xr getgrent 3 ,
+.Xr getpwent 3 ,
+.Xr strmode 3 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Nm find
+utility syntax is a superset of the syntax specified by the
+.St -p1003.2
+standard.
+.Pp
+The
+.Fl s
+and
+.Fl X
+options and the
+.Ic -inum
+and
+.Ic -ls
+primaries are extensions to
+.St -p1003.2 .
+.Pp
+Historically, the
+.Fl d ,
+.Fl h
+and
+.Fl x
+options were implemented using the primaries ``\-depth'', ``\-follow'',
+and ``\-xdev''.
+These primaries always evaluated to true.
+As they were really global variables that took effect before the traversal
+began, some legal expressions could have unexpected results.
+An example is the expression ``\-print \-o \-depth''.
+As \-print always evaluates to true, the standard order of evaluation
+implies that \-depth would never be evaluated.
+This is not the case.
+.Pp
+The operator ``-or'' was implemented as ``\-o'', and the operator ``-and''
+was implemented as ``\-a''.
+.Pp
+Historic implementations of the
+.Ic exec
+and
+.Ic ok
+primaries did not replace the string ``{}'' in the utility name or the
+utility arguments if it had preceding or following non-whitespace characters.
+This version replaces it no matter where in the utility name or arguments
+it appears.
+.Sh BUGS
+The special characters used by
+.Nm find
+are also special characters to many shell programs.
+In particular, the characters ``*'', ``['', ``]'', ``?'', ``('', ``)'',
+``!'', ``\e'' and ``;'' 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 ``-xdev'' or ``!''.
+These problems are handled by the
+.Fl f
+option and the
+.Xr getopt 3
+``--'' construct.
diff --git a/usr.bin/find/find.c b/usr.bin/find/find.c
new file mode 100644
index 0000000..22fc3a3
--- /dev/null
+++ b/usr.bin/find/find.c
@@ -0,0 +1,192 @@
+/*-
+ * 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.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)find.c 8.3 (Berkeley) 4/1/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "find.h"
+
+/*
+ * find_formplan --
+ * process the command line and create a "plan" corresponding to the
+ * command arguments.
+ */
+PLAN *
+find_formplan(argv)
+ 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;
+ }
+ }
+
+ /*
+ * if the user didn't specify one of -print, -ok or -exec, then -print
+ * is assumed so we add a -print node on the end. It is possible that
+ * the user might want the -print someplace else on the command line,
+ * but there's no way to know that.
+ */
+ if (!isoutput) {
+ new = c_print();
+ if (plan == NULL)
+ tail = plan = new;
+ else {
+ tail->next = new;
+ tail = new;
+ }
+ }
+
+ /*
+ * 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);
+}
+
+FTS *tree; /* pointer to top of FTS hierarchy */
+
+/*
+ * 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.
+ */
+int
+find_execute(plan, paths)
+ PLAN *plan; /* search plan */
+ char **paths; /* array of pathnames to traverse */
+{
+ register FTSENT *entry;
+ PLAN *p;
+ int rval;
+
+ if ((tree = fts_open(paths, ftsoptions, (int (*)())NULL)) == NULL)
+ err(1, "ftsopen");
+
+ for (rval = 0; (entry = fts_read(tree)) != NULL;) {
+ switch (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:
+ (void)fflush(stdout);
+ warnx("%s: %s",
+ entry->fts_path, strerror(entry->fts_errno));
+ rval = 1;
+ continue;
+ }
+#define BADCH " \t\n\\'\""
+ if (isxargs && strpbrk(entry->fts_path, BADCH)) {
+ (void)fflush(stdout);
+ warnx("%s: illegal path", entry->fts_path);
+ rval = 1;
+ continue;
+ }
+
+ /*
+ * 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.
+ */
+ for (p = plan; p && (p->eval)(p, entry); p = p->next);
+ }
+ if (errno)
+ err(1, "fts_read");
+ return (rval);
+}
diff --git a/usr.bin/find/find.h b/usr.bin/find/find.h
new file mode 100644
index 0000000..4c4ffa5
--- /dev/null
+++ b/usr.bin/find/find.h
@@ -0,0 +1,107 @@
+/*-
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. 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.
+ *
+ * @(#)find.h 8.1 (Berkeley) 6/6/93
+ */
+
+/* node type */
+enum ntype {
+ N_AND = 1, /* must start > 0 */
+ N_ATIME, N_CLOSEPAREN, N_CTIME, N_DEPTH, N_EXEC, N_EXPR, N_FOLLOW,
+ N_FSTYPE, N_GROUP, N_INUM, N_LINKS, N_LS, 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_PRUNE, N_SIZE, N_TYPE, N_USER, N_XDEV,
+};
+
+/* node definition */
+typedef struct _plandata {
+ struct _plandata *next; /* next node */
+ int (*eval) /* node evaluation function */
+ __P((struct _plandata *, FTSENT *));
+#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_MTFLAG 1 /* fstype */
+#define F_MTTYPE 2
+#define F_ATLEAST 1 /* perm */
+ int flags; /* private flags */
+ enum ntype type; /* plan node type */
+ union {
+ 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 */
+ 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 */
+ } ex;
+ char *_a_data[2]; /* array of char pointers */
+ char *_c_data; /* char pointer */
+ } 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 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 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
+
+typedef struct _option {
+ char *name; /* option name */
+ enum ntype token; /* token type */
+ PLAN *(*create)(); /* create function: DON'T PROTOTYPE! */
+#define O_NONE 0x01 /* no call required */
+#define O_ZERO 0x02 /* pass: nothing */
+#define O_ARGV 0x04 /* pass: argv, increment argv */
+#define O_ARGVP 0x08 /* pass: *argv, N_OK || N_EXEC */
+ int flags;
+} OPTION;
+
+#include "extern.h"
diff --git a/usr.bin/find/function.c b/usr.bin/find/function.c
new file mode 100644
index 0000000..f537676
--- /dev/null
+++ b/usr.bin/find/function.c
@@ -0,0 +1,1069 @@
+/*-
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)function.c 8.6 (Berkeley) 4/1/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ucred.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/mount.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <fts.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tzfile.h>
+#include <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 PLAN *palloc __P((enum ntype, int (*) __P((PLAN *, FTSENT *))));
+
+/*
+ * find_parsenum --
+ * Parse a string of the form [+-]# and return the value.
+ */
+static long
+find_parsenum(plan, option, vp, endch)
+ PLAN *plan;
+ char *option, *vp, *endch;
+{
+ long value;
+ char *endchar, *str; /* 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 = strtol(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);
+}
+
+/*
+ * 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);
+
+/*
+ * -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, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ extern time_t now;
+
+ COMPARE((now - entry->fts_statp->st_atime +
+ SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
+}
+
+PLAN *
+c_atime(arg)
+ char *arg;
+{
+ PLAN *new;
+
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(N_ATIME, f_atime);
+ new->t_data = find_parsenum(new, "-atime", arg, NULL);
+ TIME_CORRECT(new, N_ATIME);
+ 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, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ extern time_t now;
+
+ COMPARE((now - entry->fts_statp->st_ctime +
+ SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
+}
+
+PLAN *
+c_ctime(arg)
+ char *arg;
+{
+ PLAN *new;
+
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(N_CTIME, f_ctime);
+ new->t_data = find_parsenum(new, "-ctime", arg, NULL);
+ TIME_CORRECT(new, N_CTIME);
+ return (new);
+}
+
+/*
+ * -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, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ return (1);
+}
+
+PLAN *
+c_depth()
+{
+ isdepth = 1;
+
+ return (palloc(N_DEPTH, f_always_true));
+}
+
+/*
+ * [-exec | -ok] 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 current pathname.
+ * 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, entry)
+ register PLAN *plan;
+ FTSENT *entry;
+{
+ extern int dotfd;
+ register int cnt;
+ pid_t pid;
+ int status;
+
+ 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);
+
+ switch (pid = vfork()) {
+ case -1:
+ err(1, "fork");
+ /* 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));
+}
+
+/*
+ * 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.
+ */
+PLAN *
+c_exec(argvp, isok)
+ char ***argvp;
+ int isok;
+{
+ PLAN *new; /* node returned */
+ register int cnt;
+ register char **argv, **ap, *p;
+
+ isoutput = 1;
+
+ new = palloc(N_EXEC, f_exec);
+ if (isok)
+ new->flags = F_NEEDOK;
+
+ for (ap = argv = *argvp;; ++ap) {
+ if (!*ap)
+ errx(1,
+ "%s: no terminating \";\"", isok ? "-ok" : "-exec");
+ if (**ap == ';')
+ break;
+ }
+
+ cnt = ap - *argvp + 1;
+ new->e_argv = (char **)emalloc((u_int)cnt * sizeof(char *));
+ new->e_orig = (char **)emalloc((u_int)cnt * sizeof(char *));
+ new->e_len = (int *)emalloc((u_int)cnt * sizeof(int));
+
+ 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] = emalloc((u_int)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);
+}
+
+/*
+ * -follow functions --
+ *
+ * Always true, causes symbolic links to be followed on a global
+ * basis.
+ */
+PLAN *
+c_follow()
+{
+ ftsoptions &= ~FTS_PHYSICAL;
+ ftsoptions |= FTS_LOGICAL;
+
+ return (palloc(N_FOLLOW, f_always_true));
+}
+
+/*
+ * -fstype functions --
+ *
+ * True if the file is of a certain type.
+ */
+int
+f_fstype(plan, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ static dev_t curdev; /* need a guaranteed illegal dev value */
+ static int first = 1;
+ struct statfs sb;
+ static short val;
+ char *p, save[2];
+
+ /* Only check when we cross mount point. */
+ if (first || curdev != entry->fts_statp->st_dev) {
+ curdev = entry->fts_statp->st_dev;
+
+ /*
+ * Statfs follows symlinks; find wants the link's file system,
+ * not where it points.
+ */
+ if (entry->fts_info == FTS_SL ||
+ entry->fts_info == FTS_SLNONE) {
+ if ((p = strrchr(entry->fts_accpath, '/')) != NULL)
+ ++p;
+ else
+ p = entry->fts_accpath;
+ save[0] = p[0];
+ p[0] = '.';
+ save[1] = p[1];
+ p[1] = '\0';
+
+ } else
+ p = NULL;
+
+ if (statfs(entry->fts_accpath, &sb))
+ err(1, "%s", entry->fts_accpath);
+
+ if (p) {
+ p[0] = save[0];
+ p[1] = save[1];
+ }
+
+ first = 0;
+ switch (plan->flags) {
+ case F_MTFLAG:
+ val = sb.f_flags;
+ break;
+ case F_MTTYPE:
+ val = sb.f_type;
+ break;
+ default:
+ abort();
+ }
+ }
+ switch(plan->flags) {
+ case F_MTFLAG:
+ return (val & plan->mt_data);
+ case F_MTTYPE:
+ return (val == plan->mt_data);
+ default:
+ abort();
+ }
+}
+
+PLAN *
+c_fstype(arg)
+ char *arg;
+{
+ register PLAN *new;
+
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(N_FSTYPE, f_fstype);
+ switch (*arg) {
+ case 'l':
+ if (!strcmp(arg, "local")) {
+ new->flags = F_MTFLAG;
+ new->mt_data = MNT_LOCAL;
+ return (new);
+ }
+ break;
+ case 'm':
+ if (!strcmp(arg, "mfs")) {
+ new->flags = F_MTTYPE;
+ new->mt_data = MOUNT_MFS;
+ return (new);
+ }
+ break;
+ case 'n':
+ if (!strcmp(arg, "nfs")) {
+ new->flags = F_MTTYPE;
+ new->mt_data = MOUNT_NFS;
+ return (new);
+ }
+ break;
+ case 'p':
+ if (!strcmp(arg, "msdos")) {
+ new->flags = F_MTTYPE;
+ new->mt_data = MOUNT_MSDOS;
+ return (new);
+ }
+ break;
+ case 'r':
+ if (!strcmp(arg, "rdonly")) {
+ new->flags = F_MTFLAG;
+ new->mt_data = MNT_RDONLY;
+ return (new);
+ }
+ break;
+ case 'u':
+ if (!strcmp(arg, "ufs")) {
+ new->flags = F_MTTYPE;
+ new->mt_data = MOUNT_UFS;
+ return (new);
+ }
+ break;
+ }
+ errx(1, "%s: unknown file type", arg);
+ /* NOTREACHED */
+}
+
+/*
+ * -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, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ return (entry->fts_statp->st_gid == plan->g_data);
+}
+
+PLAN *
+c_group(gname)
+ char *gname;
+{
+ PLAN *new;
+ struct group *g;
+ gid_t gid;
+
+ ftsoptions &= ~FTS_NOSTAT;
+
+ g = getgrnam(gname);
+ if (g == NULL) {
+ gid = atoi(gname);
+ if (gid == 0 && gname[0] != '0')
+ errx(1, "-group: %s: no such group", gname);
+ } else
+ gid = g->gr_gid;
+
+ new = palloc(N_GROUP, f_group);
+ new->g_data = gid;
+ return (new);
+}
+
+/*
+ * -inum n functions --
+ *
+ * True if the file has inode # n.
+ */
+int
+f_inum(plan, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ COMPARE(entry->fts_statp->st_ino, plan->i_data);
+}
+
+PLAN *
+c_inum(arg)
+ char *arg;
+{
+ PLAN *new;
+
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(N_INUM, f_inum);
+ new->i_data = find_parsenum(new, "-inum", arg, NULL);
+ return (new);
+}
+
+/*
+ * -links n functions --
+ *
+ * True if the file has n links.
+ */
+int
+f_links(plan, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ COMPARE(entry->fts_statp->st_nlink, plan->l_data);
+}
+
+PLAN *
+c_links(arg)
+ char *arg;
+{
+ PLAN *new;
+
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(N_LINKS, f_links);
+ new->l_data = (nlink_t)find_parsenum(new, "-links", arg, NULL);
+ return (new);
+}
+
+/*
+ * -ls functions --
+ *
+ * Always true - prints the current entry to stdout in "ls" format.
+ */
+int
+f_ls(plan, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
+ return (1);
+}
+
+PLAN *
+c_ls()
+{
+ ftsoptions &= ~FTS_NOSTAT;
+ isoutput = 1;
+
+ return (palloc(N_LS, f_ls));
+}
+
+/*
+ * -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, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ extern time_t now;
+
+ COMPARE((now - entry->fts_statp->st_mtime + SECSPERDAY - 1) /
+ SECSPERDAY, plan->t_data);
+}
+
+PLAN *
+c_mtime(arg)
+ char *arg;
+{
+ PLAN *new;
+
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(N_MTIME, f_mtime);
+ new->t_data = find_parsenum(new, "-mtime", 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, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ return (!fnmatch(plan->c_data, entry->fts_name, 0));
+}
+
+PLAN *
+c_name(pattern)
+ char *pattern;
+{
+ PLAN *new;
+
+ new = palloc(N_NAME, f_name);
+ new->c_data = pattern;
+ return (new);
+}
+
+/*
+ * -newer file functions --
+ *
+ * True if the current file has been modified more recently
+ * then the modification time of the file named by the pathname
+ * file.
+ */
+int
+f_newer(plan, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ return (entry->fts_statp->st_mtime > plan->t_data);
+}
+
+PLAN *
+c_newer(filename)
+ char *filename;
+{
+ PLAN *new;
+ struct stat sb;
+
+ ftsoptions &= ~FTS_NOSTAT;
+
+ if (stat(filename, &sb))
+ err(1, "%s", filename);
+ new = palloc(N_NEWER, f_newer);
+ new->t_data = sb.st_mtime;
+ 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, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ char *group_from_gid();
+
+ return (group_from_gid(entry->fts_statp->st_gid, 1) ? 0 : 1);
+}
+
+PLAN *
+c_nogroup()
+{
+ 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, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ char *user_from_uid();
+
+ return (user_from_uid(entry->fts_statp->st_uid, 1) ? 0 : 1);
+}
+
+PLAN *
+c_nouser()
+{
+ 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, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ return (!fnmatch(plan->c_data, entry->fts_path, 0));
+}
+
+PLAN *
+c_path(pattern)
+ char *pattern;
+{
+ PLAN *new;
+
+ 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, entry)
+ 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(perm)
+ char *perm;
+{
+ PLAN *new;
+ mode_t *set;
+
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(N_PERM, f_perm);
+
+ if (*perm == '-') {
+ new->flags = F_ATLEAST;
+ ++perm;
+ }
+
+ if ((set = setmode(perm)) == NULL)
+ err(1, "-perm: %s: illegal mode string", perm);
+
+ new->m_data = getmode(set, 0);
+ return (new);
+}
+
+/*
+ * -print functions --
+ *
+ * Always true, causes the current pathame to be written to
+ * standard output.
+ */
+int
+f_print(plan, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ (void)printf("%s\n", entry->fts_path);
+ return (1);
+}
+
+PLAN *
+c_print()
+{
+ isoutput = 1;
+
+ return (palloc(N_PRINT, f_print));
+}
+
+/*
+ * -prune functions --
+ *
+ * Prune a portion of the hierarchy.
+ */
+int
+f_prune(plan, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ extern FTS *tree;
+
+ if (fts_set(tree, entry, FTS_SKIP))
+ err(1, "%s", entry->fts_path);
+ return (1);
+}
+
+PLAN *
+c_prune()
+{
+ return (palloc(N_PRUNE, f_prune));
+}
+
+/*
+ * -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, entry)
+ 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(arg)
+ char *arg;
+{
+ PLAN *new;
+ char endch;
+
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(N_SIZE, f_size);
+ endch = 'c';
+ new->o_data = find_parsenum(new, "-size", 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, or f for
+ * block special file, character special file, directory, FIFO, or
+ * regular file, respectively.
+ */
+int
+f_type(plan, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ return ((entry->fts_statp->st_mode & S_IFMT) == plan->m_data);
+}
+
+PLAN *
+c_type(typestring)
+ char *typestring;
+{
+ PLAN *new;
+ mode_t mask;
+
+ 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;
+ default:
+ errx(1, "-type: %s: unknown type", 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, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ return (entry->fts_statp->st_uid == plan->u_data);
+}
+
+PLAN *
+c_user(username)
+ char *username;
+{
+ PLAN *new;
+ struct passwd *p;
+ uid_t uid;
+
+ ftsoptions &= ~FTS_NOSTAT;
+
+ p = getpwnam(username);
+ if (p == NULL) {
+ uid = atoi(username);
+ if (uid == 0 && username[0] != '0')
+ errx(1, "-user: %s: no such user", username);
+ } else
+ uid = p->pw_uid;
+
+ new = palloc(N_USER, f_user);
+ new->u_data = uid;
+ return (new);
+}
+
+/*
+ * -xdev functions --
+ *
+ * Always true, causes find not to decend past directories that have a
+ * different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
+ */
+PLAN *
+c_xdev()
+{
+ ftsoptions |= FTS_XDEV;
+
+ return (palloc(N_XDEV, f_always_true));
+}
+
+/*
+ * ( expression ) functions --
+ *
+ * True if expression is true.
+ */
+int
+f_expr(plan, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ register PLAN *p;
+ register int state;
+
+ 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()
+{
+ return (palloc(N_OPENPAREN, (int (*)())-1));
+}
+
+PLAN *
+c_closeparen()
+{
+ return (palloc(N_CLOSEPAREN, (int (*)())-1));
+}
+
+/*
+ * ! expression functions --
+ *
+ * Negation of a primary; the unary NOT operator.
+ */
+int
+f_not(plan, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ register PLAN *p;
+ register int state;
+
+ for (p = plan->p_data[0];
+ p && (state = (p->eval)(p, entry)); p = p->next);
+ return (!state);
+}
+
+PLAN *
+c_not()
+{
+ 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, entry)
+ PLAN *plan;
+ FTSENT *entry;
+{
+ register PLAN *p;
+ register int state;
+
+ 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()
+{
+ return (palloc(N_OR, f_or));
+}
+
+static PLAN *
+palloc(t, f)
+ enum ntype t;
+ int (*f) __P((PLAN *, FTSENT *));
+{
+ PLAN *new;
+
+ if ((new = malloc(sizeof(PLAN))) == NULL)
+ err(1, NULL);
+ new->type = t;
+ new->eval = f;
+ new->flags = 0;
+ new->next = NULL;
+ return (new);
+}
diff --git a/usr.bin/find/ls.c b/usr.bin/find/ls.c
new file mode 100644
index 0000000..dd51f97
--- /dev/null
+++ b/usr.bin/find/ls.c
@@ -0,0 +1,118 @@
+/*
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ls.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <tzfile.h>
+#include <unistd.h>
+#include <utmp.h>
+
+/* Derived from the print routines in the ls(1) source code. */
+
+static void printlink __P((char *));
+static void printtime __P((time_t));
+
+void
+printlong(name, accpath, sb)
+ char *name; /* filename to print */
+ char *accpath; /* current valid path to filename */
+ struct stat *sb; /* stat buffer */
+{
+ char modep[15], *user_from_uid(), *group_from_gid();
+
+ (void)printf("%6lu %4qd ", sb->st_ino, sb->st_blocks);
+ (void)strmode(sb->st_mode, modep);
+ (void)printf("%s %3u %-*s %-*s ", modep, sb->st_nlink, UT_NAMESIZE,
+ user_from_uid(sb->st_uid, 0), UT_NAMESIZE,
+ group_from_gid(sb->st_gid, 0));
+
+ if (S_ISCHR(sb->st_mode) || S_ISBLK(sb->st_mode))
+ (void)printf("%3d, %3d ", major(sb->st_rdev),
+ minor(sb->st_rdev));
+ else
+ (void)printf("%8qd ", sb->st_size);
+ printtime(sb->st_mtime);
+ (void)printf("%s", name);
+ if (S_ISLNK(sb->st_mode))
+ printlink(accpath);
+ (void)putchar('\n');
+}
+
+static void
+printtime(ftime)
+ time_t ftime;
+{
+ int i;
+ char *longstring, *ctime();
+ time_t time();
+
+ longstring = ctime((long *)&ftime);
+ for (i = 4; i < 11; ++i)
+ (void)putchar(longstring[i]);
+
+#define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY)
+ if (ftime + SIXMONTHS > time((time_t *)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(name)
+ char *name;
+{
+ int lnklen;
+ char path[MAXPATHLEN + 1];
+
+ if ((lnklen = readlink(name, path, MAXPATHLEN)) == -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
new file mode 100644
index 0000000..c8375863
--- /dev/null
+++ b/usr.bin/find/main.c
@@ -0,0 +1,153 @@
+/*-
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. 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.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1990, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 4/16/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.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 isxargs; /* don't permit xargs delimiting chars */
+
+static void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register char **p, **start;
+ int Hflag, Lflag, Pflag, ch;
+
+ (void)time(&now); /* initialize the time-of-day */
+
+ p = start = argv;
+ Hflag = Lflag = Pflag = 0;
+ ftsoptions = FTS_NOSTAT | FTS_PHYSICAL;
+ while ((ch = getopt(argc, argv, "HLPXdf:x")) != EOF)
+ switch (ch) {
+ case 'H':
+ Hflag = 1;
+ Lflag = Pflag = 0;
+ break;
+ case 'L':
+ Lflag = 1;
+ Hflag = Pflag = 0;
+ break;
+ case 'P':
+ Pflag = 1;
+ Hflag = Lflag = 0;
+ break;
+ case 'X':
+ isxargs = 1;
+ break;
+ case 'd':
+ isdepth = 1;
+ break;
+ case 'f':
+ *p++ = optarg;
+ break;
+ case 'x':
+ ftsoptions |= FTS_XDEV;
+ break;
+ case '?':
+ default:
+ break;
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (Hflag)
+ ftsoptions |= FTS_COMFOLLOW;
+ if (Lflag) {
+ ftsoptions &= ~FTS_PHYSICAL;
+ ftsoptions |= FTS_LOGICAL;
+ }
+
+ /*
+ * 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, 0)) < 0)
+ err(1, ".");
+
+ exit(find_execute(find_formplan(argv), start));
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr,
+"usage: find [-H | -L | -P] [-Xdx] [-f file] [file ...] [expression]\n");
+ exit(1);
+}
diff --git a/usr.bin/find/misc.c b/usr.bin/find/misc.c
new file mode 100644
index 0000000..1db34ce
--- /dev/null
+++ b/usr.bin/find/misc.c
@@ -0,0 +1,127 @@
+/*-
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)misc.c 8.2 (Berkeley) 4/1/94";
+#endif /* not lint */
+
+#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 "find.h"
+
+/*
+ * brace_subst --
+ * Replace occurrences of {} in s1 with s2 and return the result string.
+ */
+void
+brace_subst(orig, store, path, len)
+ char *orig, **store, *path;
+ int len;
+{
+ register int plen;
+ register char ch, *p;
+
+ plen = strlen(path);
+ for (p = *store; (ch = *orig) != '\0'; ++orig)
+ if (ch == '{' && orig[1] == '}') {
+ while ((p - *store) + plen > len)
+ if (!(*store = realloc(*store, len *= 2)))
+ err(1, NULL);
+ 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(argv)
+ register 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');
+}
+
+/*
+ * emalloc --
+ * malloc with error checking.
+ */
+void *
+emalloc(len)
+ u_int len;
+{
+ void *p;
+
+ if ((p = malloc(len)) == NULL)
+ err(1, NULL);
+ return (p);
+}
diff --git a/usr.bin/find/operator.c b/usr.bin/find/operator.c
new file mode 100644
index 0000000..a706b88
--- /dev/null
+++ b/usr.bin/find/operator.c
@@ -0,0 +1,270 @@
+/*-
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)operator.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <fts.h>
+#include <stdio.h>
+
+#include "find.h"
+
+/*
+ * yanknode --
+ * destructively removes the top from the plan
+ */
+static PLAN *
+yanknode(planp)
+ 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(planp)
+ PLAN **planp; /* pointer to top of plan (modified) */
+{
+ register 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 */
+ int f_expr();
+
+ /* 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; /* plan with ( ) nodes */
+{
+ register PLAN *expr; /* pointer to next expression */
+ register 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 it's 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; /* plan to process */
+{
+ register PLAN *next; /* next node being processed */
+ register PLAN *node; /* temporary node used in N_NOT processing */
+ register 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->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 (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; /* plan with ors to be squished */
+{
+ register PLAN *next; /* next node being processed */
+ register 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
new file mode 100644
index 0000000..9b25cee
--- /dev/null
+++ b/usr.bin/find/option.c
@@ -0,0 +1,150 @@
+/*-
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)option.c 8.2 (Berkeley) 4/16/94";
+#endif /* not lint */
+
+#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"
+
+static OPTION *option __P((char *));
+
+/* NB: the following table must be sorted lexically. */
+static OPTION const options[] = {
+ { "!", N_NOT, c_not, O_ZERO },
+ { "(", N_OPENPAREN, c_openparen, O_ZERO },
+ { ")", N_CLOSEPAREN, c_closeparen, O_ZERO },
+ { "-a", N_AND, NULL, O_NONE },
+ { "-and", N_AND, NULL, O_NONE },
+ { "-atime", N_ATIME, c_atime, O_ARGV },
+ { "-ctime", N_CTIME, c_ctime, O_ARGV },
+ { "-depth", N_DEPTH, c_depth, O_ZERO },
+ { "-exec", N_EXEC, c_exec, O_ARGVP },
+ { "-follow", N_FOLLOW, c_follow, O_ZERO },
+ { "-fstype", N_FSTYPE, c_fstype, O_ARGV },
+ { "-group", N_GROUP, c_group, O_ARGV },
+ { "-inum", N_INUM, c_inum, O_ARGV },
+ { "-links", N_LINKS, c_links, O_ARGV },
+ { "-ls", N_LS, c_ls, O_ZERO },
+ { "-mtime", N_MTIME, c_mtime, O_ARGV },
+ { "-name", N_NAME, c_name, O_ARGV },
+ { "-newer", N_NEWER, c_newer, O_ARGV },
+ { "-nogroup", N_NOGROUP, c_nogroup, O_ZERO },
+ { "-nouser", N_NOUSER, c_nouser, O_ZERO },
+ { "-o", N_OR, c_or, O_ZERO },
+ { "-ok", N_OK, c_exec, O_ARGVP },
+ { "-or", N_OR, c_or, O_ZERO },
+ { "-path", N_PATH, c_path, O_ARGV },
+ { "-perm", N_PERM, c_perm, O_ARGV },
+ { "-print", N_PRINT, c_print, O_ZERO },
+ { "-prune", N_PRUNE, c_prune, O_ZERO },
+ { "-size", N_SIZE, c_size, O_ARGV },
+ { "-type", N_TYPE, c_type, O_ARGV },
+ { "-user", N_USER, c_user, O_ARGV },
+ { "-xdev", N_XDEV, c_xdev, O_ZERO },
+};
+
+/*
+ * 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(argvp)
+ char ***argvp;
+{
+ register OPTION *p;
+ PLAN *new;
+ char **argv;
+
+ argv = *argvp;
+
+ if ((p = option(*argv)) == NULL)
+ errx(1, "%s: unknown option", *argv);
+ ++argv;
+ if (p->flags & (O_ARGV|O_ARGVP) && !*argv)
+ errx(1, "%s: requires additional arguments", *--argv);
+
+ switch(p->flags) {
+ case O_NONE:
+ new = NULL;
+ break;
+ case O_ZERO:
+ new = (p->create)();
+ break;
+ case O_ARGV:
+ new = (p->create)(*argv++);
+ break;
+ case O_ARGVP:
+ new = (p->create)(&argv, p->token == N_OK);
+ break;
+ default:
+ abort();
+ }
+ *argvp = argv;
+ return (new);
+}
+
+static OPTION *
+option(name)
+ char *name;
+{
+ OPTION tmp;
+ int typecompare __P((const void *, const void *));
+
+ tmp.name = name;
+ return ((OPTION *)bsearch(&tmp, options,
+ sizeof(options)/sizeof(OPTION), sizeof(OPTION), typecompare));
+}
+
+int
+typecompare(a, b)
+ const void *a, *b;
+{
+ return (strcmp(((OPTION *)a)->name, ((OPTION *)b)->name));
+}
OpenPOWER on IntegriCloud