]> git.saurik.com Git - apple/shell_cmds.git/commitdiff
shell_cmds-34.tar.gz mac-os-x-102 mac-os-x-1021 mac-os-x-1022 mac-os-x-1023 mac-os-x-1024 mac-os-x-1025 mac-os-x-1026 mac-os-x-1027 mac-os-x-1028 mac-os-x-1028g5 v34
authorApple <opensource@apple.com>
Thu, 11 Jul 2002 00:08:44 +0000 (00:08 +0000)
committerApple <opensource@apple.com>
Thu, 11 Jul 2002 00:08:44 +0000 (00:08 +0000)
45 files changed:
Makefile
false/false.c
find/Makefile
find/extern.h
find/find.1
find/find.c
find/find.h
find/function.c
find/ls.c
find/main.c
find/misc.c
find/operator.c
find/option.c
find/y.tab.c [new file with mode: 0644]
getopt/getopt.c
id/id.c
kill/kill.1
kill/kill.c
killall/Makefile [new file with mode: 0644]
killall/Makefile.postamble [new file with mode: 0644]
killall/Makefile.preamble [new file with mode: 0644]
killall/PB.project [new file with mode: 0644]
killall/killall.1 [new file with mode: 0644]
killall/killall.c [new file with mode: 0644]
locate/locate/locate.c
locate/locate/updatedb.csh
mktemp/Makefile [new file with mode: 0644]
mktemp/Makefile.postamble [new file with mode: 0644]
mktemp/Makefile.preamble [new file with mode: 0644]
mktemp/PB.project [new file with mode: 0644]
mktemp/mktemp.1 [new file with mode: 0644]
mktemp/mktemp.c [new file with mode: 0644]
pwd/pwd.1
renice/renice.c
su/Makefile
su/Makefile.preamble
su/su.1
su/su.c
test/Makefile.postamble
true/true.c
w/uptime.1
w/w.1
w/w.c
window/Makefile
window/tt.h

index 01625097bbcc26562654cb9ceb58628101dbf42e..d6aa7786c1fdb25a0ef48610d8b9467e894e7792 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -14,8 +14,8 @@ PROJECT_TYPE = Aggregate
 
 SUBPROJECTS = locate
 
-TOOLS = apply basename chroot date dirname echo env expr false\
-        find getopt hostname id jot kill lastcomm logname nice\
+TOOLS = killall apply basename chroot date dirname echo env expr false\
+        find getopt hostname id jot kill lastcomm logname mktemp nice\
         nohup printenv printf pwd renice script shlock sleep su\
         tee test time true uname users w whereis which who\
         window xargs yes
@@ -30,7 +30,7 @@ DEBUG_LIBS = $(LIBS)
 PROF_LIBS = $(LIBS)
 
 
-NEXTSTEP_PB_CFLAGS = -Wall -Werror
+NEXTSTEP_PB_CFLAGS = -Wall 
 
 
 NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
index 9c295223859757373969d773b661050e4617ec09..3883d89d424b167aa08bb921cdb2c7eb9ae0ef94 100644 (file)
@@ -1 +1,2 @@
-int main () { exit(1); }
\ No newline at end of file
+#include <stdlib.h>
+int main () { exit(1); }
index 2deb86426c67b1de8eee97ef5d28ca1c2db72517..c0cb27652d8670e168822f11013314a1de6b158a 100644 (file)
@@ -14,7 +14,7 @@ PROJECT_TYPE = Tool
 
 HFILES = extern.h find.h
 
-CFILES = find.c function.c ls.c main.c misc.c operator.c option.c
+CFILES = find.c function.c ls.c main.c misc.c operator.c option.c y.tab.c
 
 OTHERSRCS = Makefile Makefile.preamble Makefile.postamble find.1
 
index 013fa5fb0cc63838047928f2726bb726548bece8..d909f1e617dc8ffc13f1b95ddfb920f3b72c1dc7 100644 (file)
@@ -1,5 +1,3 @@
-/*     $NetBSD: extern.h,v 1.8 1998/02/21 22:47:20 christos Exp $      */
-
 /*-
  * Copyright (c) 1991, 1993, 1994
  *     The Regents of the University of California.  All rights reserved.
@@ -32,7 +30,8 @@
  * 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
+ *     @(#)extern.h    8.3 (Berkeley) 4/16/94
+ *     $FreeBSD: src/usr.bin/find/extern.h,v 1.9.2.4 2001/05/06 09:53:22 phk Exp $
  */
 
 #include <sys/cdefs.h>
@@ -42,42 +41,75 @@ void        *emalloc __P((unsigned int));
 PLAN   *find_create __P((char ***));
 int     find_execute __P((PLAN *, char **));
 PLAN   *find_formplan __P((char **));
-int     f_expr __P((PLAN *, FTSENT *));
 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 **));
+OPTION *option __P((char *));
+
+creat_f        c_Xmin;
+creat_f        c_Xtime;
+creat_f        c_and;
+creat_f        c_delete;
+creat_f        c_depth;
+creat_f        c_empty;
+creat_f        c_exec;
+creat_f        c_flags;
+creat_f        c_follow;
+#if !defined(__NetBSD__)
+creat_f        c_fstype;
+#endif
+creat_f        c_group;
+creat_f        c_inum;
+creat_f        c_links;
+creat_f        c_ls;
+creat_f        c_mXXdepth;
+creat_f        c_name;
+creat_f        c_newer;
+creat_f        c_nogroup;
+creat_f        c_nouser;
+creat_f        c_perm;
+creat_f        c_print;
+creat_f        c_regex;
+creat_f        c_simple;
+creat_f        c_size;
+creat_f        c_type;
+creat_f        c_user;
+creat_f        c_xdev;
 
-PLAN   *c_atime __P((char ***, int));
-PLAN   *c_ctime __P((char ***, int));
-PLAN   *c_depth __P((char ***, int));
-PLAN   *c_exec __P((char ***, int));
-PLAN   *c_follow __P((char ***, int));
-PLAN   *c_fstype __P((char ***, int));
-PLAN   *c_group __P((char ***, int));
-PLAN   *c_inum __P((char ***, int));
-PLAN   *c_links __P((char ***, int));
-PLAN   *c_ls __P((char ***, int));
-PLAN   *c_name __P((char ***, int));
-PLAN   *c_newer __P((char ***, int));
-PLAN   *c_nogroup __P((char ***, int));
-PLAN   *c_nouser __P((char ***, int));
-PLAN   *c_path __P((char ***, int));
-PLAN   *c_perm __P((char ***, int));
-PLAN   *c_print __P((char ***, int));
-PLAN   *c_print0 __P((char ***, int));
-PLAN   *c_prune __P((char ***, int));
-PLAN   *c_size __P((char ***, int));
-PLAN   *c_type __P((char ***, int));
-PLAN   *c_user __P((char ***, int));
-PLAN   *c_xdev __P((char ***, int));
-PLAN   *c_openparen __P((char ***, int));
-PLAN   *c_closeparen __P((char ***, int));
-PLAN   *c_mtime __P((char ***, int));
-PLAN   *c_not __P((char ***, int));
-PLAN   *c_or __P((char ***, int));
-PLAN   *c_null __P((char ***, int));
+exec_f f_Xmin;
+exec_f f_Xtime;
+exec_f f_always_true;
+exec_f f_closeparen;
+exec_f f_delete;
+exec_f f_empty;
+exec_f f_exec;
+exec_f f_expr;
+exec_f f_flags;
+exec_f f_fstype;
+exec_f f_group;
+exec_f f_inum;
+exec_f f_links;
+exec_f f_ls;
+exec_f f_name;
+exec_f f_newer;
+exec_f f_nogroup;
+exec_f f_not;
+exec_f f_nouser;
+exec_f f_openparen;
+exec_f f_or;
+exec_f f_path;
+exec_f f_perm;
+exec_f f_print;
+exec_f f_print0;
+exec_f f_prune;
+exec_f f_regex;
+exec_f f_size;
+exec_f f_type;
+exec_f f_user;
 
-extern int ftsoptions, isdeprecated, isdepth, isoutput, isxargs;
+extern int ftsoptions, isdeprecated, isdepth, isoutput, issort, isxargs;
+extern int mindepth, maxdepth;
+extern int regexp_flags;
index 969233768a94d04eb2318d3f2b30d22f172186fa..5794024ab428dcf8ee1b92771c3049e443eab781 100644 (file)
@@ -1,6 +1,3 @@
-.\"    $NetBSD: find.1,v 1.14 1998/05/27 13:15:30 msaitoh 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
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\"    from: @(#)find.1        8.7 (Berkeley) 5/9/95
+.\"    @(#)find.1      8.7 (Berkeley) 5/9/95
+.\" $FreeBSD: src/usr.bin/find/find.1,v 1.23.2.14 2001/12/14 15:53:30 ru Exp $
 .\"
-.Dd May 9, 1995
+.Dd May 3, 2001
 .Dt FIND 1
 .Os
 .Sh NAME
 .Nm find
 .Nd walk a file hierarchy
 .Sh SYNOPSIS
-.Nm find
+.Nm
 .Op Fl H | Fl L | Fl P
-.Op Fl Xdx
-.Op Fl f Ar file
-.Op Ar file ...
+.Op Fl EXdsx
+.Op Fl f Ar pathname
+.Op Ar pathname ...
 .Ar expression
 .Sh DESCRIPTION
-.Nm
+.Nm Find
 recursively descends the directory tree for each
-.Ar file
+.Ar pathname
 listed, evaluating an
 .Ar expression
-(composed of the ``primaries'' and ``operands'' listed below) in terms
+(composed of the
+.Dq primaries
+and
+.Dq operands
+listed below) in terms
 of each file in the tree.
 .Pp
 The options are as follows:
-.Pp
-.Bl -tag -width Ds
+.Bl -tag -width indent
+.It Fl E
+Interpret regular expressions followed by
+.Ic -regex
+and
+.Ic -iregex
+options as extended (modern) regular expressions rather than basic
+regular expressions (BRE's).
+The
+.Xr re_format 7
+manual page fully describes both formats.
 .It Fl H
 The
 .Fl H
 option causes the file information and file type (see
-.Xr stat 2 ) ,
-returned for each symbolic link encountered on the command line to be 
+.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 
+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)
+.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
@@ -84,8 +96,9 @@ be for the link itself.
 The
 .Fl P
 option causes the file information and file type (see
-.Xr stat 2)
+.Xr stat 2 )
 returned for each symbolic link to be those of the link itself.
+This is the default.
 .It Fl X
 The
 .Fl X
@@ -94,24 +107,29 @@ option is a modification to permit
 to be safely used in conjunction with
 .Xr xargs 1 .
 If a file name contains any of the delimiting characters used by
-.Xr xargs ,
+.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.
+The delimiting characters include single
+.Pq Dq Li " ' "
+and double
+.Pq Dq Li " \*q "
+quotes, backslash
+.Pq Dq Li \e ,
+space, tab and newline characters.
 .It Fl d
 The
 .Fl d
 option causes
 .Nm
-to perform a depth\-first traversal, i.e. directories
+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.
+visits directories in pre\-order, i.e., before their contents.
 Note, the default is
-.Ar not
+.Em not
 a breadth\-first traversal.
 .It Fl f
 The
@@ -121,15 +139,18 @@ option specifies a file hierarchy for
 to traverse.
 File hierarchies may also be specified as the operands immediately
 following the options.
-.It Fl h
+.It Fl s
 The
-.Fl h
-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.
+.Fl s
+option causes
+.Nm
+to traverse the file hierarchies in lexicographical order,
+i.e., alphabetical order within each directory.
+Note:
+.Ql find -s
+and
+.Ql "find | sort"
+may give different results.
 .It Fl x
 The
 .Fl x
@@ -139,62 +160,189 @@ 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 
+.Bl -tag -width indent
+.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.
+.It Ic -anewer Ar file
+Same as
+.Ic -neweram .
+.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.
-.It Ic -ctime Ar n 
+.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.
+.It Ic -cnewer Ar file
+Same as
+.Ic -newercm .
+.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.
-.It Ic -exec Ar utility Op argument ... ; 
+.It Ic -delete
+Delete found files and/or directories.
+Always returns true.
+This executes
+from the current working directory as
+.Nm
+recurses down the tree.
+It will not attempt to delete a filename with a
+.Dq Pa /
+character in its pathname relative to
+.Dq Pa \&.
+for security reasons.
+Depth\-first traversal processing is implied by this option.
+.It Ic -depth
+Always true;
+same as the
+.Fl d
+option.
+.Ic -depth
+can be useful when
+.Nm
+is used with
+.Xr cpio 1
+to process files that are contained in directories with unusual permissions.
+It enures that you have write permission while you are placing files in a
+directory, then sets the directory's permissions as the last thing.
+.It Ic -empty
+True if the current file or directory is empty.
+.It Ic -exec Ar utility Op Ar 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
+Optional
+.Ar arguments
+may be passed to the utility.
+The expression must be terminated by a semicolon
+.Pq Dq Li \&; .
+If the string
+.Dq Li {}
+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
 was executed.
-.It Ic -follow
-Follow symbolic links.
-.It Ic -fstype Ar type 
+.Ar Utility
+and
+.Ar arguments
+are not subject to the further expansion of shell patterns
+and constructs.
+.It Ic -execdir Ar utility Op Ar argument ... ;
+The
+.Ic -execdir
+primary is identical to the
+.Ic -exec
+primary with the exception that
+.Ar utility
+will be executed from the directory that holds
+the current file.
+The filename substituted for
+the string
+.Dq Li {}
+is not qualified.
+.It Ic -flags Oo Cm - Ns | Ns Cm + Oc Ns Ar flags , Ns Ar notflags
+The flags are specified using symbolic names (see
+.Xr chflags 1 ) .
+Those with the
+.Qq Li no
+prefix (except
+.Qq Li nodump )
+are said to be
+.Ar notflags .
+Flags in
+.Ar flags
+are checked to be set, and flags in
+.Ar notflags
+are checked to be not set.
+Note that this is different from
+.Ic -perm ,
+which only allows the user to specify mode bits that are set.
+.Pp
+If flags are preceded by a dash
+.Pq Dq Li - ,
+this primary evaluates to true
+if at least all of the bits in
+.Ar flags
+and none of the bits in
+.Ar notflags
+are set in the file's flags bits.
+If flags are preceded by a plus
+.Pq Dq Li + ,
+this primary evaluates to true
+if any of the bits in
+.Ar flags
+is set in the file's flags bits,
+or any of the bits in
+.Ar notflags
+is not set in the file's flags bits.
+Otherwise,
+this primary evaluates to true
+if the bits in
+.Ar flags
+exactly match the file's flags bits,
+and none of the
+.Ar flags
+bits match those of
+.Ar notflags .
+.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 filesystems
 that are available on the system:
-.Bd -literal -offset indent
-sysctl vfs
-.Ed
-In addition, there are two pseudo-types, ``local'' and ``rdonly''.
+.Pp
+.Dl "sysctl vfs"
+.Pp
+In addition, there are two pseudo-types,
+.Dq Li local
+and
+.Dq Li 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
+is being executed and the latter matches any file system which is
 mounted read-only.
-.It Ic -group Ar gname 
+.It Ic -group Ar gname
 True if the file belongs to the group
-.Ar gname  .
+.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 
+is treated as a group ID.
+.It Ic -iname Ar pattern
+Like
+.Ic -name ,
+but the match is case insensitive.
+.It Ic -inum Ar n
 True if the file has inode number
-.Ar n  .
-.It Ic -links Ar n 
+.Ar n .
+.It Ic -ipath Ar pattern
+Like
+.Ic -path ,
+but the match is case insensitive.
+.It Ic -iregex Ar pattern
+Like
+.Ic -regex ,
+but the match is case insensitive.
+.It Ic -links Ar n
 True if the file has
 .Ar n
 links.
@@ -206,97 +354,177 @@ 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 
+displayed preceded by
+.Dq Li -> .
+The format is identical to that produced by
+.Bk -words
+.Nm ls Fl dgils .
+.Ek
+.It Ic -maxdepth Ar n
+True if the depth of the current file into the tree is less than or equal to
+.Ar n .
+.It Ic -mindepth Ar n
+True if the depth of the current file into the tree is greater than or equal to
+.Ar n .
+.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.
+.It Ic -mnewer Ar file
+Same as
+.Ic -newer .
+.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.
-.It Ic \&-ok Ar utility Op argument ... ; 
+.It Ic -name Ar pattern
+True if the last component of the pathname being examined matches
+.Ar pattern .
+Special shell pattern matching characters
+.Dq ( Li \&[ ,
+.Dq Li \&] ,
+.Dq Li * ,
+and
+.Dq Li \&? )
+may be used as part of
+.Ar pattern .
+These characters may be matched explicitly by escaping them with a
+backslash
+.Pq Dq Li \e .
+.It Ic -newer Ar file
+True if the current file has a more recent last modification time than
+.Ar file .
+.It Ic -newer Ns Ar X Ns Ar Y Ar file
+True if the current file has a more recent last access time
+.Ar ( X Ns = Ns Cm a ) ,
+change time
+.Ar ( X Ns = Ns Cm c ) ,
+or modification time
+.Ar ( X Ns = Ns Cm m )
+than the last access time
+.Ar ( Y Ns = Ns Cm a ) ,
+change time
+.Ar ( Y Ns = Ns Cm c ) ,
+or modification time
+.Ar ( Y Ns = Ns Cm m )
+of
+.Ar file .
+In addition, if
+.Ar Y Ns = Ns Cm t ,
+then
+.Ar file
+is instead interpreted as a direct date specification of the form
+understood by
+.Xr cvs 1 .
+Note that
+.Ic -newermm
+is equivalent to
+.Ic -newer .
+.It Ic -nogroup
+True if the file belongs to an unknown group.
+.It Ic -nouser
+True if the file belongs to an unknown user.
+.It Ic -ok Ar utility Op Ar argument ... ;
 The
-.Ic \&-ok
+.Ic -ok
 primary is identical to the
 .Ic -exec
 primary with the exception that
 .Nm
-requests user affirmation for the execution of the utility by printing
+requests user affirmation for the execution of the
+.Ar 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
+If the response is other than
+.Dq Li y
+the command is not executed and the
 value of the
-.Ar \&ok
+.Ic -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 
+.It Ic -okdir Ar utility Op Ar argument ... ;
+The
+.Ic -okdir
+primary is identical to the
+.Ic -execdir
+primary with the same exception as described for the
+.Ic -ok
+primary.
+.It Ic -path Ar pattern
 True if the pathname being examined matches
-.Ar pattern  .
-Special shell pattern matching characters (``['', ``]'', ``*'', and ``?'')
+.Ar pattern .
+Special shell pattern matching characters
+.Dq ( Li \&[ ,
+.Dq Li \&] ,
+.Dq Li * ,
+and
+.Dq Li \&? )
 may be used as part of
-.Ar pattern  .
+.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
+backslash
+.Pq Dq Li \e .
+Slashes
+.Pq Dq Li /
+are treated as normal characters and do not have to be
 matched explicitly.
-.It Ic -perm Op Fl Ns Ar mode 
+.It Ic -perm Oo Cm - Ns | Ns Cm + Oc Ns Ar mode
 The
 .Ar mode
 may be either symbolic (see
-.Xr chmod  1  )
+.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
+If the
+.Ar mode
+is symbolic, a starting value of zero is assumed and the
+.Ar 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 )
+If the
+.Ar mode
+is octal, only bits 07777
+.Pq Dv S_ISUID | S_ISGID | S_ISTXT | S_IRWXU | S_IRWXG | 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 (``\-'').
+If the
+.Ar mode
+is preceded by a dash
+.Pq Dq Li - ,
+this primary evaluates to true
+if at least all of the bits in the
+.Ar mode
+are set in the file's mode bits.
+If the
+.Ar mode
+is preceded by a plus
+.Pq Dq Li + ,
+this primary evaluates to true
+if any of the bits in the
+.Ar mode
+are set in the file's mode bits.
+Otherwise, this primary evaluates to true if
+the bits in the
+.Ar mode
+exactly match the file's mode bits.
+Note, the first character of a symbolic mode may not be a dash
+.Pq Dq Li - .
 .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.
+It prints the pathname of the current file to standard output.
 If none of
-.Ic -exec ,
-.Ic -ls ,
-.Ic -ok ,
-nor
-.Ic -print0
+.Ic -exec , -ls , -print0 ,
+or
+.Ic -ok
 is specified, the given expression shall be effectively replaced by
-.Cm \&( Ns Ar given\& expression Ns Cm \&) 
-.Ic -print .
+.Cm \&( Ar "given expression" Cm \&) Ic -print .
 .It Ic -print0
 This primary always evaluates to true.
-It prints the pathname of the current file to standard output, followed
-by a null character.
+It prints the pathname of the current file to standard output, followed by an
+.Tn ASCII NUL
+character (character code 0).
 .It Ic -prune
 This primary always evaluates to true.
 It causes
@@ -307,22 +535,36 @@ Note, the
 primary has no effect if the
 .Fl d
 option was specified.
-.It Ic -size Ar n Ns Op Cm c 
+.It Ic -regex Ar pattern
+True if the whole path of the file matches
+.Ar pattern
+using regular expression.
+To match a file named
+.Dq Pa ./foo/xyzzy ,
+you can use the regular expression
+.Dq Li ".*/[xyz]*"
+or
+.Dq Li ".*/foo/.*" ,
+but not
+.Dq Li xyzzy
+or
+.Dq Li /foo/ .
+.It Ic -size Ar n Ns Op Cm c
 True if the file's size, rounded up, in 512\-byte blocks is
-.Ar n  .
+.Ar n .
 If
 .Ar n
-is followed by a ``c'', then the primary is true if the
+is followed by a
+.Cm c ,
+then the primary is true if the
 file's size is
 .Ar n
-bytes.
-.It Ic -type Ar t 
+bytes (characters).
+.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 W
-whiteout
+.Bl -tag -width indent -compact
 .It Cm b
 block special
 .It Cm c
@@ -338,37 +580,44 @@ FIFO
 .It Cm s
 socket
 .El
-.Pp
-.It Ic -user Ar uname 
+.It Ic -user Ar uname
 True if the file belongs to the user
-.Ar uname  .
+.Ar uname .
 If
 .Ar uname
 is numeric and there is no such user name, then
 .Ar uname
-is treated as a user id.
+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'' .
+preceded by a plus sign
+.Pq Dq Li +
+or a minus sign
+.Pq Dq Li - .
+A preceding plus sign means
+.Dq more than n ,
+a preceding minus sign means
+.Dq less than n
+and neither means
+.Dq 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 \&) 
+.Pp
+.Bl -tag -width "( expression )" -compact
+.It Cm \&( Ar expression Cm \&)
 This evaluates to true if the parenthesized expression evaluates to
 true.
 .Pp
-.It Cm \&! Ns Ar expression 
+.It Cm \&! 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 
+.It Ar expression Cm -and Ar expression
+.It Ar expression expression
 The
 .Cm -and
 operator is the logical
@@ -379,7 +628,7 @@ 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 
+.It Ar expression Cm -or Ar expression
 The
 .Cm -or
 operator is the logical
@@ -391,34 +640,49 @@ The second expression is not evaluated if the first expression is true.
 .El
 .Pp
 All operands and primaries must be separate arguments to
-.Nm ""  .
+.Nm .
 Primaries which themselves take arguments expect each argument
 to be a separate argument to
-.Nm ""  .
+.Nm .
 .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''.
+.Bl -tag -width indent
+.It Li "find / \e! -name \*q*.c\*q -print"
+Print out a list of all the files whose names do not end in
+.Pa .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
+.Pa 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
+.Pa 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
+.Pa ttt .
+.It Li "find . -newerct '1 minute ago' -print"
+Print out a list of all the files whose inode change time is more
+recent than the current time minus one minute.
 .El
 .Sh SEE ALSO
+.Xr chflags 1 ,
 .Xr chmod 1 ,
+.Xr cvs 1 ,
 .Xr locate 1 ,
+.Xr whereis 1 ,
+.Xr which 1 ,
 .Xr stat 2 ,
 .Xr fts 3 ,
-.Xr getpwent 3 ,
 .Xr getgrent 3 ,
+.Xr getpwent 3 ,
 .Xr strmode 3 ,
+.Xr re_format 7 ,
 .Xr symlink 7
 .Sh STANDARDS
 The
@@ -427,56 +691,97 @@ utility syntax is a superset of the syntax specified by the
 .St -p1003.2
 standard.
 .Pp
-The options and the
-.Ic -follow ,
-.Ic -fstype ,
-.Ic -inum ,
-.Ic -links ,
-.Ic -ls 
+All the single character options as well as the
+.Ic -iname , -inum , -iregex , -print0 , -delete , -ls ,
 and
-.Ic -print0
+.Ic -regex
 primaries are extensions to
 .St -p1003.2 .
 .Pp
 Historically, the
-.Fl d ,
-.Fl h
+.Fl d , h
 and
 .Fl x
-options were implemented using the primaries ``\-depth'', ``\-follow'',
-and ``\-xdev''.
+options were implemented using the primaries
+.Ic -depth , -follow ,
+and
+.Ic -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.
+An example is the expression
+.Ic -print Cm -o Ic -depth .
+As
+.Ic -print
+always evaluates to true, the standard order of evaluation
+implies that
+.Ic -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''.
+The operator
+.Cm -or
+was implemented as
+.Cm -o ,
+and the operator
+.Cm -and
+was implemented as
+.Cm -a .
 .Pp
 Historic implementations of the
 .Ic -exec
 and
 .Ic -ok
-primaries did not replace the string ``{}'' in the utility name or the
+primaries did not replace the string
+.Dq Li {}
+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.
+.Pp
+The
+.Fl E
+option was implemented on the analogy of
+.Xr grep 1
+and
+.Xr sed 1 .
 .Sh BUGS
 The special characters used by
 .Nm
 are also special characters to many shell programs.
-In particular, the characters ``*'', ``['', ``]'', ``?'', ``('', ``)'',
-``!'', ``\e'' and ``;'' may have to be escaped from the shell.
+In particular, the characters
+.Dq Li * ,
+.Dq Li \&[ ,
+.Dq Li \&] ,
+.Dq Li \&? ,
+.Dq Li \&( ,
+.Dq Li \&) ,
+.Dq Li \&! ,
+.Dq Li \e
+and
+.Dq Li \&;
+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 ``!''.
+it is difficult to specify files named
+.Pa -xdev
+or
+.Pa \&! .
 These problems are handled by the
 .Fl f
 option and the
 .Xr getopt 3
-``--'' construct.
+.Dq Fl Fl
+construct.
+.Pp
+The
+.Ic -delete
+primary does not interact well with other options that cause the filesystem
+tree traversal options to be changed.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
index a1672acee7b9ef10f1e5bfc9e88db5663fcfbfe5..6a14c92d7ea5199e0426c063d2074d29edfe88fc 100644 (file)
@@ -1,5 +1,3 @@
-/*     $NetBSD: find.c,v 1.11 1998/02/21 22:47:20 christos Exp $       */
-
 /*-
  * Copyright (c) 1991, 1993, 1994
  *     The Regents of the University of California.  All rights reserved.
  * SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
 #ifndef lint
 #if 0
-static char sccsid[] = "from: @(#)find.c       8.5 (Berkeley) 8/5/94";
+static char sccsid[] = "@(#)find.c     8.5 (Berkeley) 8/5/94";
 #else
-__RCSID("$NetBSD: find.c,v 1.11 1998/02/21 22:47:20 christos Exp $");
+static const char rcsid[] =
+  "$FreeBSD: src/usr.bin/find/find.c,v 1.7.6.3 2001/05/06 09:53:22 phk Exp $";
 #endif
 #endif /* not lint */
 
@@ -51,12 +49,29 @@ __RCSID("$NetBSD: find.c,v 1.11 1998/02/21 22:47:20 christos Exp $");
 #include <err.h>
 #include <errno.h>
 #include <fts.h>
+#include <regex.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 
 #include "find.h"
 
+static int     find_compare __P((const FTSENT **s1, const FTSENT **s2));
+
+/*
+ * find_compare --
+ *     tell fts_open() how to order the traversal of the hierarchy. 
+ *     This variant gives lexicographical order, i.e., alphabetical
+ *     order within each directory.
+ */
+static int
+find_compare(s1, s2)
+       const FTSENT **s1, **s2;
+{
+
+       return (strcoll((*s1)->fts_name, (*s2)->fts_name));
+}
+
 /*
  * find_formplan --
  *     process the command line and create a "plan" corresponding to the
@@ -94,29 +109,36 @@ find_formplan(argv)
                        tail = new;
                }
        }
-    
+
        /*
         * if the user didn't specify one of -print, -ok or -exec, then -print
         * is assumed so we bracket the current expression with parens, if
         * necessary, and add a -print node on the end.
         */
        if (!isoutput) {
+               OPTION *p;
+               char **argv = 0;
+
                if (plan == NULL) {
-                       new = c_print(NULL, 0);
+                       p = option("-print");
+                       new = (p->create)(p, &argv);
                        tail = plan = new;
                } else {
-                       new = c_openparen(NULL, 0);
+                       p = option("(");
+                       new = (p->create)(p, &argv);
                        new->next = plan;
                        plan = new;
-                       new = c_closeparen(NULL, 0);
+                       p = option(")");
+                       new = (p->create)(p, &argv);
                        tail->next = new;
                        tail = new;
-                       new = c_print(NULL, 0);
+                       p = option("-print");
+                       new = (p->create)(p, &argv);
                        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
@@ -145,7 +167,7 @@ find_formplan(argv)
        plan = or_squish(plan);                 /* -o's */
        return (plan);
 }
+
 FTS *tree;                     /* pointer to top of FTS hierarchy */
 
 /*
@@ -161,11 +183,12 @@ find_execute(plan, paths)
        register FTSENT *entry;
        PLAN *p;
        int rval;
-    
-       if (!(tree = fts_open(paths, ftsoptions, NULL)))
+
+       tree = fts_open(paths, ftsoptions, (issort ? find_compare : NULL));
+       if (tree == NULL)
                err(1, "ftsopen");
 
-       for (rval = 0; (entry = fts_read(tree)) != NULL; ) {
+       for (rval = 0; (entry = fts_read(tree)) != NULL;) {
                switch (entry->fts_info) {
                case FTS_D:
                        if (isdepth)
@@ -195,17 +218,24 @@ find_execute(plan, paths)
                        rval = 1;
                        continue;
                }
-                
+
+               if (mindepth != -1 && entry->fts_level < mindepth)
+                       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)
-                       ;
+               for (p = plan; p && (p->execute)(p, entry); p = p->next);
+
+               if (maxdepth != -1 && entry->fts_level >= maxdepth) {
+                       if (fts_set(tree, entry, FTS_SKIP))
+                       err(1, "%s", entry->fts_path);
+                       continue;
+               }
        }
        if (errno)
                err(1, "fts_read");
-       (void)fts_close(tree);
        return (rval);
 }
index 804011fa912b2b1ad8e23fed5ebfcfa0b637a144..391676994bbf30f969e1cb9562fe03ca106dfda5 100644 (file)
@@ -1,5 +1,3 @@
-/*     $NetBSD: find.h,v 1.8 1998/02/21 22:47:20 christos Exp $        */
-
 /*-
  * Copyright (c) 1990, 1993
  *     The Regents of the University of California.  All rights reserved.
  * 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
+ *     @(#)find.h      8.1 (Berkeley) 6/6/93
+ *     $FreeBSD: src/usr.bin/find/find.h,v 1.6.2.6 2001/09/19 09:44:24 ru Exp $
  */
 
-/* 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_PRINT0, N_PRUNE, N_SIZE, N_TYPE, N_USER, N_XDEV,
-};
+#include <regex.h>
+
+/* forward declarations */
+struct _plandata;
+struct _option;
+
+/* execute function */
+typedef int exec_f __P((struct _plandata *, FTSENT *));
+/* create function */
+typedef        struct _plandata *creat_f(struct _option *, char ***);
+
+/* function modifiers */
+#define        F_NEEDOK        0x00000001      /* -ok vs. -exec */
+#define        F_EXECDIR       0x00000002      /* -execdir vs. -exec */
+#define F_TIME_A       0x00000004      /* one of -atime, -anewer, -newera* */
+#define F_TIME_C       0x00000008      /* one of -ctime, -cnewer, -newerc* */
+#define        F_TIME2_A       0x00000010      /* one of -newer?a */
+#define        F_TIME2_C       0x00000020      /* one of -newer?c */
+#define        F_TIME2_T       0x00000040      /* one of -newer?t */
+#define F_MAXDEPTH     F_TIME_A        /* maxdepth vs. mindepth */
+/* command line function modifiers */
+#define        F_EQUAL         0x00000000      /* [acm]min [acm]time inum links size */
+#define        F_LESSTHAN      0x00000100
+#define        F_GREATER       0x00000200
+#define F_ELG_MASK     0x00000300
+#define        F_ATLEAST       0x00000400      /* flags perm */
+#define F_ANY          0x00000800      /* perm */
+#define        F_MTMASK        0x00003000
+#define        F_MTFLAG        0x00000000      /* fstype */
+#define        F_MTTYPE        0x00001000
+#define        F_IGNCASE       0x00010000      /* iname ipath iregex */
 
 /* 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 */
+       struct _plandata *next;         /* next node */
+       exec_f  *execute;               /* node evaluation function */
+       int flags;                      /* private flags */
        union {
-               gid_t _g_data;                  /* gid */
-               ino_t _i_data;                  /* inode */
-               mode_t _m_data;                 /* mode mask */
+               gid_t _g_data;          /* gid */
+               ino_t _i_data;          /* inode */
+               mode_t _m_data;         /* mode mask */
+               struct {
+                       u_long _f_flags;
+                       u_long _f_notflags;
+               } fl;
                nlink_t _l_data;                /* link count */
                off_t _o_data;                  /* file size */
                time_t _t_data;                 /* time value */
@@ -78,12 +95,15 @@ typedef struct _plandata {
                } ex;
                char *_a_data[2];               /* array of char pointers */
                char *_c_data;                  /* char pointer */
+               regex_t *_re_data;              /* regex */
        } 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 fl_flags       p_un.fl._f_flags
+#define fl_notflags    p_un.fl._f_notflags
 #define        g_data  p_un._g_data
+#define        i_data  p_un._i_data
 #define        l_data  p_un._l_data
 #define        m_data  p_un._m_data
 #define        mt_data p_un._mt_data
@@ -91,16 +111,16 @@ typedef struct _plandata {
 #define        p_data  p_un._p_data
 #define        t_data  p_un._t_data
 #define        u_data  p_un._u_data
+#define        re_data p_un._re_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 */
-               __P((char ***, int));
-       int arg;                        /* function needs arg */
+       creat_f *create;                /* create function */
+       exec_f *execute;                /* execute function */
+       int flags;
 } OPTION;
 
 #include "extern.h"
index efa1abe97fc6f604d7713e59967dcd1e0ce71c2d..5411be3c1b8c7045fffdfdd3e54e5f003e694841 100644 (file)
@@ -1,5 +1,3 @@
-/*     $NetBSD: function.c,v 1.24 1998/02/21 22:47:20 christos Exp $   */
-
 /*-
  * Copyright (c) 1990, 1993
  *     The Regents of the University of California.  All rights reserved.
  * SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
 #ifndef lint
 #if 0
-static char sccsid[] = "from: @(#)function.c   8.10 (Berkeley) 5/4/95";
+static const char sccsid[] = "@(#)function.c  8.10 (Berkeley) 5/4/95";
 #else
-__RCSID("$NetBSD: function.c,v 1.24 1998/02/21 22:47:20 christos Exp $");
+static const char rcsid[] =
+  "$FreeBSD: src/usr.bin/find/function.c,v 1.22.2.9 2001/09/19 09:44:24 ru Exp $";
 #endif
 #endif /* not lint */
 
@@ -50,23 +48,27 @@ __RCSID("$NetBSD: function.c,v 1.24 1998/02/21 22:47:20 christos Exp $");
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <sys/mount.h>
+#include <sys/timeb.h>
 
+#include <dirent.h>
 #include <err.h>
 #include <errno.h>
 #include <fnmatch.h>
 #include <fts.h>
 #include <grp.h>
 #include <pwd.h>
+#include <regex.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <tzfile.h>
 #include <unistd.h>
 
 #include "find.h"
 
+time_t get_date __P((char *date, struct timeb *now));
+
 #define        COMPARE(a, b) {                                                 \
-       switch (plan->flags) {                                          \
+       switch (plan->flags & F_ELG_MASK) {                             \
        case F_EQUAL:                                                   \
                return (a == b);                                        \
        case F_LESSTHAN:                                                \
@@ -78,153 +80,275 @@ __RCSID("$NetBSD: function.c,v 1.24 1998/02/21 22:47:20 christos Exp $");
        }                                                               \
 }
 
-static long    find_parsenum __P((PLAN *, char *, char *, char *));
-       int     f_always_true __P((PLAN *, FTSENT *));
-       int     f_atime __P((PLAN *, FTSENT *));
-       int     f_ctime __P((PLAN *, FTSENT *));
-       int     f_exec __P((PLAN *, FTSENT *));
-       int     f_fstype __P((PLAN *, FTSENT *));
-       int     f_group __P((PLAN *, FTSENT *));
-       int     f_inum __P((PLAN *, FTSENT *));
-       int     f_links __P((PLAN *, FTSENT *));
-       int     f_ls __P((PLAN *, FTSENT *));
-       int     f_mtime __P((PLAN *, FTSENT *));
-       int     f_name __P((PLAN *, FTSENT *));
-       int     f_newer __P((PLAN *, FTSENT *));
-       int     f_nogroup __P((PLAN *, FTSENT *));
-       int     f_nouser __P((PLAN *, FTSENT *));
-       int     f_path __P((PLAN *, FTSENT *));
-       int     f_perm __P((PLAN *, FTSENT *));
-       int     f_print __P((PLAN *, FTSENT *));
-       int     f_print0 __P((PLAN *, FTSENT *));
-       int     f_prune __P((PLAN *, FTSENT *));
-       int     f_size __P((PLAN *, FTSENT *));
-       int     f_type __P((PLAN *, FTSENT *));
-       int     f_user __P((PLAN *, FTSENT *));
-       int     f_not __P((PLAN *, FTSENT *));
-       int     f_or __P((PLAN *, FTSENT *));
-static PLAN   *palloc __P((enum ntype, int (*) __P((PLAN *, FTSENT *))));
+static PLAN *
+palloc(option)
+       OPTION *option;
+{
+       PLAN *new;
+
+       if ((new = malloc(sizeof(PLAN))) == NULL)
+               err(1, NULL);
+       new->execute = option->execute;
+       new->flags = option->flags;
+       new->next = NULL;
+       return new;
+}
 
 /*
  * find_parsenum --
  *     Parse a string of the form [+-]# and return the value.
  */
-static long
+static long long
 find_parsenum(plan, option, vp, endch)
        PLAN *plan;
        char *option, *vp, *endch;
 {
-       long value;
+       long 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;
+               plan->flags |= F_GREATER;
                break;
        case '-':
                ++str;
-               plan->flags = F_LESSTHAN;
+               plan->flags |= F_LESSTHAN;
                break;
        default:
-               plan->flags = F_EQUAL;
+               plan->flags |= F_EQUAL;
                break;
        }
-    
+
        /*
-        * Convert the string with strtol().  Note, if strtol() returns zero
+        * Convert the string with strtoq().  Note, if strtoq() returns zero
         * and endchar points to the beginning of the string we know we have
         * a syntax error.
         */
-       value = strtol(str, &endchar, 10);
+       value = strtoq(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);
+       return value;
 }
 
+/*
+ * nextarg --
+ *     Check that another argument still exists, return a pointer to it,
+ *     and increment the argument vector pointer.
+ */
+static char *
+nextarg(option, argvp)
+       OPTION *option;
+       char ***argvp;
+{
+       char *arg;
+
+       if ((arg = **argvp) == 0)
+               errx(1, "%s: requires additional arguments", option->name);
+       (*argvp)++;
+       return arg;
+} /* nextarg() */
+
 /*
  * 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)             \
+#define        TIME_CORRECT(p) \
+       if (((p)->flags & F_ELG_MASK) == F_LESSTHAN) \
                ++((p)->t_data);
 
 /*
- * -atime n functions --
+ * -[acm]min n functions --
  *
- *     True if the difference between the file access time and the
- *     current time is n 24 hour periods.
+ *    True if the difference between the
+ *             file access time (-amin)
+ *             last change of file status information (-cmin)
+ *             file modification time (-mmin)
+ *    and the current time is n min periods.
  */
 int
-f_atime(plan, entry)
+f_Xmin(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        extern time_t now;
 
-       COMPARE((now - entry->fts_statp->st_atime +
-           SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
+       if (plan->flags & F_TIME_C) {
+               COMPARE((now - entry->fts_statp->st_ctime +
+                   60 - 1) / 60, plan->t_data);
+       } else if (plan->flags & F_TIME_A) {
+               COMPARE((now - entry->fts_statp->st_atime +
+                   60 - 1) / 60, plan->t_data);
+       } else {
+               COMPARE((now - entry->fts_statp->st_mtime +
+                   60 - 1) / 60, plan->t_data);
+       }
 }
+
 PLAN *
-c_atime(argvp, isok)
+c_Xmin(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
-       char *arg = **argvp;
+       char *nmins;
        PLAN *new;
 
-       (*argvp)++;
+       nmins = nextarg(option, argvp);
        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);
+       new = palloc(option);
+       new->t_data = find_parsenum(new, option->name, nmins, NULL);
+       TIME_CORRECT(new);
+       return new;
 }
+
 /*
- * -ctime n functions --
+ * -[acm]time n functions --
  *
- *     True if the difference between the last change of file
- *     status information and the current time is n 24 hour periods.
+ *     True if the difference between the
+ *             file access time (-atime)
+ *             last change of file status information (-ctime)
+ *             file modification time (-mtime)
+ *     and the current time is n 24 hour periods.
  */
+
 int
-f_ctime(plan, entry)
+f_Xtime(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        extern time_t now;
 
-       COMPARE((now - entry->fts_statp->st_ctime +
-           SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
+       if (plan->flags & F_TIME_C) {
+               COMPARE((now - entry->fts_statp->st_ctime +
+                   86400 - 1) / 86400, plan->t_data);
+       } else if (plan->flags & F_TIME_A) {
+               COMPARE((now - entry->fts_statp->st_atime +
+                   86400 - 1) / 86400, plan->t_data);
+       } else {
+               COMPARE((now - entry->fts_statp->st_mtime +
+                   86400 - 1) / 86400, plan->t_data);
+       }
 }
+
 PLAN *
-c_ctime(argvp, isok)
+c_Xtime(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
-       char *arg = **argvp;
+       char *ndays;
        PLAN *new;
 
-       (*argvp)++;
+       ndays = nextarg(option, argvp);
        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);
+       new = palloc(option);
+       new->t_data = find_parsenum(new, option->name, ndays, NULL);
+       TIME_CORRECT(new);
+       return new;
 }
 
+/*
+ * -maxdepth/-mindepth n functions --
+ *
+ *        Does the same as -prune if the level of the current file is
+ *        greater/less than the specified maximum/minimum depth.
+ *
+ *        Note that -maxdepth and -mindepth are handled specially in
+ *        find_execute() so their f_* functions are set to f_always_true().
+ */
+PLAN *
+c_mXXdepth(option, argvp)
+       OPTION *option;
+       char ***argvp;
+{
+       char *dstr;
+       PLAN *new;
+
+       dstr = nextarg(option, argvp);
+       if (dstr[0] == '-')
+               /* all other errors handled by find_parsenum() */
+               errx(1, "%s: %s: value must be positive", option->name, dstr);
+
+       new = palloc(option);
+       if (option->flags & F_MAXDEPTH)
+               maxdepth = find_parsenum(new, option->name, dstr, NULL);
+       else
+               mindepth = find_parsenum(new, option->name, dstr, NULL);
+       return new;
+}
+
+/*
+ * -delete functions --
+ *
+ *     True always.  Makes its best shot and continues on regardless.
+ */
+int
+f_delete(plan, entry)
+       PLAN *plan;
+       FTSENT *entry;
+{
+       /* 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 (strchr(entry->fts_accpath, '/') != NULL)
+               errx(1, "-delete: %s: relative path potentially not safe",
+                       entry->fts_accpath);
+
+       /* Turn off user immutable bits if running as root */
+       if ((entry->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
+           !(entry->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
+           geteuid() == 0)
+               chflags(entry->fts_accpath,
+                      entry->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
+
+       /* 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(option, argvp)
+       OPTION *option;
+       char ***argvp;
+{
+
+       ftsoptions &= ~FTS_NOSTAT;      /* no optimise */
+       ftsoptions |= FTS_PHYSICAL;     /* disable -follow */
+       ftsoptions &= ~FTS_LOGICAL;     /* disable -follow */
+       isoutput = 1;                   /* possible output */
+       isdepth = 1;                    /* -depth implied */
+
+       return palloc(option);
+}
+
+
 /*
  * -depth functions --
  *
@@ -237,59 +361,116 @@ f_always_true(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       return (1);
+       return 1;
 }
+
 PLAN *
-c_depth(argvp, isok)
+c_depth(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
        isdepth = 1;
 
-       return (palloc(N_DEPTH, f_always_true));
+       return palloc(option);
+}
+
+/*
+ * -empty functions --
+ *
+ *     True if the file or directory is empty
+ */
+int
+f_empty(plan, entry)
+       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)
+                       err(1, "%s", entry->fts_accpath);
+               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(option, argvp)
+       OPTION *option;
+       char ***argvp;
+{
+       ftsoptions &= ~FTS_NOSTAT;
+
+       return palloc(option);
 }
+
 /*
- * [-exec | -ok] utility [arg ... ] ; functions --
+ * [-exec | -execdir | -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.
+ *     "{}" occurs anywhere, it gets replaced by the current pathname,
+ *     or, in the case of -execdir, the current basename (filename
+ *     without leading directory prefix). For -exec and -ok,
+ *     the current directory for the execution of utility is the same as
+ *     the current directory when the find utility was started, whereas
+ *     for -execdir, it is the directory the file resides in.
  *
- *     The primary -ok is different in that it requests affirmation of the
- *     user before executing the utility.
+ *     The primary -ok differs from -exec in that it requests affirmation
+ *     of the user before executing the utility.
  */
 int
 f_exec(plan, entry)
-       PLAN *plan;
+       register PLAN *plan;
        FTSENT *entry;
 {
        extern int dotfd;
-       int cnt;
+       register int cnt;
        pid_t pid;
        int status;
+       char *file;
+
+       /* XXX - if file/dir ends in '/' this will not work -- can it? */
+       if ((plan->flags & F_EXECDIR) && \
+           (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],
-                           entry->fts_path, plan->e_len[cnt]);
+                           file, plan->e_len[cnt]);
 
-       if (plan->flags == F_NEEDOK && !queryuser(plan->e_argv))
-               return (0);
+       if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv))
+               return 0;
 
-       /* don't mix output of command with find output */
+       /* make sure find output is interspersed correctly with subprocesses */
        fflush(stdout);
        fflush(stderr);
 
-       switch (pid = vfork()) {
+       switch (pid = fork()) {
        case -1:
                err(1, "fork");
                /* NOTREACHED */
        case 0:
-               if (fchdir(dotfd)) {
+               /* change dir back from where we started */
+               if (!(plan->flags & F_EXECDIR) && fchdir(dotfd)) {
                        warn("chdir");
                        _exit(1);
                }
@@ -300,33 +481,35 @@ f_exec(plan, entry)
        pid = waitpid(pid, &status, 0);
        return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
 }
+
 /*
- * c_exec --
+ * c_exec, c_execdir, c_ok --
  *     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)
+c_exec(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
        PLAN *new;                      /* node returned */
-       int cnt;
-       char **argv, **ap, *p;
+       register int cnt;
+       register char **argv, **ap, *p;
 
+       /* XXX - was in c_execdir, but seems unnecessary!?
+       ftsoptions &= ~FTS_NOSTAT;
+       */
        isoutput = 1;
-    
-       new = palloc(N_EXEC, f_exec);
-       if (isok)
-               new->flags = F_NEEDOK;
+
+       /* XXX - this is a change from the previous coding */
+       new = palloc(option);
 
        for (ap = argv = *argvp;; ++ap) {
                if (!*ap)
                        errx(1,
-                           "%s: no terminating \";\"", isok ? "-ok" : "-exec");
+                           "%s: no terminating \";\"", option->name);
                if (**ap == ';')
                        break;
        }
@@ -352,9 +535,57 @@ c_exec(argvp, isok)
        new->e_argv[cnt] = new->e_orig[cnt] = NULL;
 
        *argvp = argv + 1;
-       return (new);
+       return new;
+}
+
+int
+f_flags(plan, entry)
+       PLAN *plan;
+       FTSENT *entry;
+{
+       u_long flags;
+
+       flags = entry->fts_statp->st_flags;
+       if (plan->flags & F_ATLEAST)
+               return (flags | plan->fl_flags) == flags &&
+                   !(flags & plan->fl_notflags);
+       else if (plan->flags & F_ANY)
+               return (flags & plan->fl_flags) ||
+                   (flags | plan->fl_notflags) != flags;
+       else
+               return flags == plan->fl_flags &&
+                   !(plan->fl_flags & plan->fl_notflags);
+}
+
+PLAN *
+c_flags(option, argvp)
+       OPTION *option;
+       char ***argvp;
+{
+       char *flags_str;
+       PLAN *new;
+       u_long flags, notflags;
+
+       flags_str = nextarg(option, argvp);
+       ftsoptions &= ~FTS_NOSTAT;
+
+       new = palloc(option);
+
+       if (*flags_str == '-') {
+               new->flags |= F_ATLEAST;
+               flags_str++;
+       } else if (*flags_str == '+') {
+               new->flags |= F_ANY;
+               flags_str++;
+       }
+       if (strtofflags(&flags_str, &flags, &notflags) == 1)
+               errx(1, "%s: %s: illegal flags string", option->name, flags_str);
+
+       new->fl_flags = flags;
+       new->fl_notflags = notflags;
+       return new;
 }
+
 /*
  * -follow functions --
  *
@@ -362,16 +593,16 @@ c_exec(argvp, isok)
  *     basis.
  */
 PLAN *
-c_follow(argvp, isok)
+c_follow(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
        ftsoptions &= ~FTS_PHYSICAL;
        ftsoptions |= FTS_LOGICAL;
 
-       return (palloc(N_FOLLOW, f_always_true));
+       return palloc(option);
 }
+
 /*
  * -fstype functions --
  *
@@ -385,8 +616,7 @@ f_fstype(plan, entry)
        static dev_t curdev;    /* need a guaranteed illegal dev value */
        static int first = 1;
        struct statfs sb;
-       static short val;
-       static char fstype[MFSNAMELEN];
+       static int val_type, val_flags;
        char *p, save[2];
 
        /* Only check when we cross mount point. */
@@ -407,8 +637,7 @@ f_fstype(plan, entry)
                        p[0] = '.';
                        save[1] = p[1];
                        p[1] = '\0';
-                       
-               } else 
+               } else
                        p = NULL;
 
                if (statfs(entry->fts_accpath, &sb))
@@ -425,54 +654,65 @@ f_fstype(plan, entry)
                 * Further tests may need both of these values, so
                 * always copy both of them.
                 */
-               val = sb.f_flags;
-               strncpy(fstype, sb.f_fstypename, MFSNAMELEN);
+               val_flags = sb.f_flags;
+               val_type = sb.f_type;
        }
-       switch (plan->flags) {
+       switch (plan->flags & F_MTMASK) {
        case F_MTFLAG:
-               return (val & plan->mt_data);   
+               return (val_flags & plan->mt_data) != 0;
        case F_MTTYPE:
-               return (strncmp(fstype, plan->c_data, MFSNAMELEN) == 0);
+               return (val_type == plan->mt_data);
        default:
                abort();
        }
 }
+
+#if !defined(__NetBSD__)
 PLAN *
-c_fstype(argvp, isok)
+c_fstype(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
-       char *arg = **argvp;
-       PLAN *new;
-    
-       (*argvp)++;
+       char *fsname;
+       register PLAN *new;
+       struct vfsconf vfc;
+
+       fsname = nextarg(option, argvp);
        ftsoptions &= ~FTS_NOSTAT;
-    
-       new = palloc(N_FSTYPE, f_fstype);
 
-       switch (*arg) {
+       new = palloc(option);
+
+       /*
+        * Check first for a filesystem name.
+        */
+       if (getvfsbyname(fsname, &vfc) == 0) {
+               new->flags |= F_MTTYPE;
+               new->mt_data = vfc.vfc_typenum;
+               return new;
+       }
+
+       switch (*fsname) {
        case 'l':
-               if (!strcmp(arg, "local")) {
-                       new->flags = F_MTFLAG;
+               if (!strcmp(fsname, "local")) {
+                       new->flags |= F_MTFLAG;
                        new->mt_data = MNT_LOCAL;
-                       return (new);
+                       return new;
                }
                break;
        case 'r':
-               if (!strcmp(arg, "rdonly")) {
-                       new->flags = F_MTFLAG;
+               if (!strcmp(fsname, "rdonly")) {
+                       new->flags |= F_MTFLAG;
                        new->mt_data = MNT_RDONLY;
-                       return (new);
+                       return new;
                }
                break;
        }
 
-       new->flags = F_MTTYPE;
-       new->c_data = arg;
-       return (new);
+       errx(1, "%s: unknown file type", fsname);
+       /* NOTREACHED */
 }
+#endif /* __NetBSD__ */
+
 /*
  * -group gname functions --
  *
@@ -485,33 +725,33 @@ f_group(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       return (entry->fts_statp->st_gid == plan->g_data);
+       return entry->fts_statp->st_gid == plan->g_data;
 }
+
 PLAN *
-c_group(argvp, isok)
+c_group(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
-       char *gname = **argvp;
+       char *gname;
        PLAN *new;
        struct group *g;
        gid_t gid;
-    
-       (*argvp)++;
+
+       gname = nextarg(option, argvp);
        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);
+                       errx(1, "%s: %s: no such group", option->name, gname);
        } else
                gid = g->gr_gid;
-    
-       new = palloc(N_GROUP, f_group);
+
+       new = palloc(option);
        new->g_data = gid;
-       return (new);
+       return new;
 }
 
 /*
@@ -526,23 +766,23 @@ f_inum(plan, entry)
 {
        COMPARE(entry->fts_statp->st_ino, plan->i_data);
 }
+
 PLAN *
-c_inum(argvp, isok)
+c_inum(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
-       char *arg = **argvp;
+       char *inum_str;
        PLAN *new;
-    
-       (*argvp)++;
+
+       inum_str = nextarg(option, argvp);
        ftsoptions &= ~FTS_NOSTAT;
-    
-       new = palloc(N_INUM, f_inum);
-       new->i_data = find_parsenum(new, "-inum", arg, NULL);
-       return (new);
+
+       new = palloc(option);
+       new->i_data = find_parsenum(new, option->name, inum_str, NULL);
+       return new;
 }
+
 /*
  * -links n functions --
  *
@@ -555,23 +795,23 @@ f_links(plan, entry)
 {
        COMPARE(entry->fts_statp->st_nlink, plan->l_data);
 }
+
 PLAN *
-c_links(argvp, isok)
+c_links(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
-       char *arg = **argvp;
+       char *nlinks;
        PLAN *new;
-    
-       (*argvp)++;
+
+       nlinks = nextarg(option, argvp);
        ftsoptions &= ~FTS_NOSTAT;
-    
-       new = palloc(N_LINKS, f_links);
-       new->l_data = (nlink_t)find_parsenum(new, "-links", arg, NULL);
-       return (new);
+
+       new = palloc(option);
+       new->l_data = (nlink_t)find_parsenum(new, option->name, nlinks, NULL);
+       return new;
 }
+
 /*
  * -ls functions --
  *
@@ -583,52 +823,18 @@ f_ls(plan, entry)
        FTSENT *entry;
 {
        printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
-       return (1);
-}
-PLAN *
-c_ls(argvp, isok)
-       char ***argvp;
-       int isok;
-{
-       ftsoptions &= ~FTS_NOSTAT;
-       isoutput = 1;
-    
-       return (palloc(N_LS, f_ls));
+       return 1;
 }
 
-/*
- * -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(argvp, isok)
+c_ls(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
-       char *arg = **argvp;
-       PLAN *new;
-
-       (*argvp)++;
        ftsoptions &= ~FTS_NOSTAT;
+       isoutput = 1;
 
-       new = palloc(N_MTIME, f_mtime);
-       new->t_data = find_parsenum(new, "-mtime", arg, NULL);
-       TIME_CORRECT(new, N_MTIME);
-       return (new);
+       return palloc(option);
 }
 
 /*
@@ -642,23 +848,24 @@ f_name(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       return (!fnmatch(plan->c_data, entry->fts_name, 0));
+       return !fnmatch(plan->c_data, entry->fts_name,
+           plan->flags & F_IGNCASE ? FNM_CASEFOLD : 0);
 }
+
 PLAN *
-c_name(argvp, isok)
+c_name(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
-       char *pattern = **argvp;
+       char *pattern;
        PLAN *new;
 
-       (*argvp)++;
-       new = palloc(N_NAME, f_name);
+       pattern = nextarg(option, argvp);
+       new = palloc(option);
        new->c_data = pattern;
-       return (new);
+       return new;
 }
+
 /*
  * -newer file functions --
  *
@@ -671,28 +878,45 @@ f_newer(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       return (entry->fts_statp->st_mtime > plan->t_data);
+       if (plan->flags & F_TIME_C)
+               return entry->fts_statp->st_ctime > plan->t_data;
+       else if (plan->flags & F_TIME_A)
+               return entry->fts_statp->st_atime > plan->t_data;
+       else
+               return entry->fts_statp->st_mtime > plan->t_data;
 }
+
 PLAN *
-c_newer(argvp, isok)
+c_newer(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
-       char *filename = **argvp;
+       char *fn_or_tspec;
        PLAN *new;
        struct stat sb;
-    
-       (*argvp)++;
+
+       fn_or_tspec = nextarg(option, argvp);
        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);
+       new = palloc(option);
+       /* compare against what */
+       if (option->flags & F_TIME2_T) {
+               new->t_data = get_date(fn_or_tspec, (struct timeb *) 0);
+               if (new->t_data == (time_t) -1)
+                       errx(1, "Can't parse date/time: %s", fn_or_tspec);
+       } else {
+               if (stat(fn_or_tspec, &sb))
+                       err(1, "%s", fn_or_tspec);
+               if (option->flags & F_TIME2_C)
+                       new->t_data = sb.st_ctime;
+               else if (option->flags & F_TIME2_A)
+                       new->t_data = sb.st_atime;
+               else
+                       new->t_data = sb.st_mtime;
+       }
+       return new;
 }
+
 /*
  * -nogroup functions --
  *
@@ -704,20 +928,19 @@ f_nogroup(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-
-       return (group_from_gid(entry->fts_statp->st_gid, 1) ? 0 : 1);
+       return group_from_gid(entry->fts_statp->st_gid, 1) == NULL;
 }
+
 PLAN *
-c_nogroup(argvp, isok)
+c_nogroup(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
        ftsoptions &= ~FTS_NOSTAT;
 
-       return (palloc(N_NOGROUP, f_nogroup));
+       return palloc(option);
 }
+
 /*
  * -nouser functions --
  *
@@ -729,20 +952,19 @@ f_nouser(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-
-       return (user_from_uid(entry->fts_statp->st_uid, 1) ? 0 : 1);
+       return user_from_uid(entry->fts_statp->st_uid, 1) == NULL;
 }
+
 PLAN *
-c_nouser(argvp, isok)
+c_nouser(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
        ftsoptions &= ~FTS_NOSTAT;
 
-       return (palloc(N_NOUSER, f_nouser));
+       return palloc(option);
 }
+
 /*
  * -path functions --
  *
@@ -754,23 +976,12 @@ f_path(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       return (!fnmatch(plan->c_data, entry->fts_path, 0));
+       return !fnmatch(plan->c_data, entry->fts_path,
+           plan->flags & F_IGNCASE ? FNM_CASEFOLD : 0);
 }
-PLAN *
-c_path(argvp, isok)
-       char ***argvp;
-       int isok;
-{
-       char *pattern = **argvp;
-       PLAN *new;
 
-       (*argvp)++;
-       new = palloc(N_NAME, f_path);
-       new->c_data = pattern;
-       return (new);
-}
+/* c_path is the same as c_name */
+
 /*
  * -perm functions --
  *
@@ -787,39 +998,45 @@ f_perm(plan, entry)
 
        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);
+       if (plan->flags & F_ATLEAST)
+               return (plan->m_data | mode) == mode;
+       else if (plan->flags & F_ANY)
+               return (mode & plan->m_data);
        else
-               return (mode == plan->m_data);
+               return mode == plan->m_data;
        /* NOTREACHED */
 }
+
 PLAN *
-c_perm(argvp, isok)
+c_perm(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
-       char *perm = **argvp;
+       char *perm;
        PLAN *new;
        mode_t *set;
 
-       (*argvp)++;
+       perm = nextarg(option, argvp);
        ftsoptions &= ~FTS_NOSTAT;
 
-       new = palloc(N_PERM, f_perm);
+       new = palloc(option);
 
        if (*perm == '-') {
-               new->flags = F_ATLEAST;
+               new->flags |= F_ATLEAST;
+               ++perm;
+       } else if (*perm == '+') {
+               new->flags |= F_ANY;
                ++perm;
        }
 
        if ((set = setmode(perm)) == NULL)
-               err(1, "-perm: %s: illegal mode string", perm);
+               errx(1, "%s: %s: illegal mode string", option->name, perm);
 
        new->m_data = getmode(set, 0);
-       return (new);
+       free(set);
+       return new;
 }
+
 /*
  * -print functions --
  *
@@ -831,40 +1048,38 @@ f_print(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       (void)printf("%s\n", entry->fts_path);
-       return (1);
+       (void)puts(entry->fts_path);
+       return 1;
 }
 
-int
-f_print0(plan, entry)
-       PLAN *plan;
-       FTSENT *entry;
-{
-       (void)fputs(entry->fts_path, stdout);
-       (void)fputc('\0', stdout);
-       return (1);
-}
 PLAN *
-c_print(argvp, isok)
+c_print(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
        isoutput = 1;
 
-       return (palloc(N_PRINT, f_print));
+       return palloc(option);
 }
 
-PLAN *
-c_print0(argvp, isok)
-       char ***argvp;
-       int isok;
+/*
+ * -print0 functions --
+ *
+ *     Always true, causes the current pathame to be written to
+ *     standard output followed by a NUL character
+ */
+int
+f_print0(plan, entry)
+       PLAN *plan;
+       FTSENT *entry;
 {
-       isoutput = 1;
-
-       return (palloc(N_PRINT0, f_print0));
+       fputs(entry->fts_path, stdout);
+       fputc('\0', stdout);
+       return 1;
 }
+
+/* c_print0 is the same as c_print */
+
 /*
  * -prune functions --
  *
@@ -879,17 +1094,92 @@ f_prune(plan, entry)
 
        if (fts_set(tree, entry, FTS_SKIP))
                err(1, "%s", entry->fts_path);
-       return (1);
+       return 1;
 }
+
+/* c_prune == c_simple */
+
+/*
+ * -regex functions --
+ *
+ *     True if the whole path of the file matches pattern using
+ *     regular expression.
+ */
+int
+f_regex(plan, entry)
+       PLAN *plan;
+       FTSENT *entry;
+{
+       char *str;
+       size_t len;
+       regex_t *pre;
+       regmatch_t pmatch;
+       int errcode;
+       char errbuf[LINE_MAX];
+       int matched;
+
+       pre = plan->re_data;
+       str = entry->fts_path;
+       len = strlen(str);
+       matched = 0;
+
+       pmatch.rm_so = 0;
+       pmatch.rm_eo = len;
+
+       errcode = regexec(pre, str, 1, &pmatch, REG_STARTEND);
+
+       if (errcode != 0 && errcode != REG_NOMATCH) {
+               regerror(errcode, pre, errbuf, sizeof errbuf);
+               errx(1, "%s: %s",
+                    plan->flags & F_IGNCASE ? "-iregex" : "-regex", errbuf);
+       }
+
+       if (errcode == 0 && pmatch.rm_so == 0 && pmatch.rm_eo == len)
+               matched = 1;
+
+       return matched;
+}
+
 PLAN *
-c_prune(argvp, isok)
+c_regex(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
-       return (palloc(N_PRUNE, f_prune));
+       PLAN *new;
+       char *pattern;
+       regex_t *pre;
+       int errcode;
+       char errbuf[LINE_MAX];
+
+       if ((pre = malloc(sizeof(regex_t))) == NULL)
+               err(1, NULL);
+
+       pattern = nextarg(option, argvp);
+
+       if ((errcode = regcomp(pre, pattern,
+           regexp_flags | (option->flags & F_IGNCASE ? REG_ICASE : 0))) != 0) {
+               regerror(errcode, pre, errbuf, sizeof errbuf);
+               errx(1, "%s: %s: %s",
+                    option->flags & F_IGNCASE ? "-iregex" : "-regex",
+                    pattern, errbuf);
+       }
+
+       new = palloc(option);
+       new->re_data = pre;
+
+       return new;
+}
+
+/* c_simple covers c_prune, c_openparen, c_closeparen, c_not, c_or */
+
+PLAN *
+c_simple(option, argvp)
+       OPTION *option;
+       char ***argvp;
+{
+       return palloc(option);
 }
+
 /*
  * -size n[c] functions --
  *
@@ -911,27 +1201,27 @@ f_size(plan, entry)
            FIND_SIZE : entry->fts_statp->st_size;
        COMPARE(size, plan->o_data);
 }
+
 PLAN *
-c_size(argvp, isok)
+c_size(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
-       char *arg = **argvp;
+       char *size_str;
        PLAN *new;
        char endch;
-    
-       (*argvp)++;
+
+       size_str = nextarg(option, argvp);
        ftsoptions &= ~FTS_NOSTAT;
 
-       new = palloc(N_SIZE, f_size);
+       new = palloc(option);
        endch = 'c';
-       new->o_data = find_parsenum(new, "-size", arg, &endch);
+       new->o_data = find_parsenum(new, option->name, size_str, &endch);
        if (endch == 'c')
                divsize = 0;
-       return (new);
+       return new;
 }
+
 /*
  * -type c functions --
  *
@@ -944,30 +1234,22 @@ f_type(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       return ((entry->fts_statp->st_mode & S_IFMT) == plan->m_data);
+       return (entry->fts_statp->st_mode & S_IFMT) == plan->m_data;
 }
+
 PLAN *
-c_type(argvp, isok)
+c_type(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
-       char *typestring = **argvp;
+       char *typestring;
        PLAN *new;
-       mode_t  mask = (mode_t)0;
-    
-       (*argvp)++;
+       mode_t  mask;
+
+       typestring = nextarg(option, argvp);
        ftsoptions &= ~FTS_NOSTAT;
 
        switch (typestring[0]) {
-#ifdef S_IFWHT
-      case 'W':
-#ifdef FTS_WHITEOUT
-             ftsoptions |= FTS_WHITEOUT;
-#endif
-              mask = S_IFWHT;
-              break;
-#endif
        case 'b':
                mask = S_IFBLK;
                break;
@@ -996,14 +1278,14 @@ c_type(argvp, isok)
                break;
 #endif /* FTS_WHITEOUT */
        default:
-               errx(1, "-type: %s: unknown type", typestring);
+               errx(1, "%s: %s: unknown type", option->name, typestring);
        }
-    
-       new = palloc(N_TYPE, f_type);
+
+       new = palloc(option);
        new->m_data = mask;
-       return (new);
+       return new;
 }
+
 /*
  * -user uname functions --
  *
@@ -1016,35 +1298,35 @@ f_user(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       return (entry->fts_statp->st_uid == plan->u_data);
+       return entry->fts_statp->st_uid == plan->u_data;
 }
+
 PLAN *
-c_user(argvp, isok)
+c_user(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
-       char *username = **argvp;
+       char *username;
        PLAN *new;
        struct passwd *p;
        uid_t uid;
-    
-       (*argvp)++;
+
+       username = nextarg(option, argvp);
        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);
+                       errx(1, "%s: %s: no such user", option->name, username);
        } else
                uid = p->pw_uid;
 
-       new = palloc(N_USER, f_user);
+       new = palloc(option);
        new->u_data = uid;
-       return (new);
+       return new;
 }
+
 /*
  * -xdev functions --
  *
@@ -1052,13 +1334,13 @@ c_user(argvp, isok)
  *     different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
  */
 PLAN *
-c_xdev(argvp, isok)
+c_xdev(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
        ftsoptions |= FTS_XDEV;
 
-       return (palloc(N_XDEV, f_always_true));
+       return palloc(option);
 }
 
 /*
@@ -1071,36 +1353,51 @@ f_expr(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       PLAN *p;
-       int state;
+       register PLAN *p;
+       register int state = 0;
 
-       state = 0;
        for (p = plan->p_data[0];
-           p && (state = (p->eval)(p, entry)); p = p->next);
-       return (state);
+           p && (state = (p->execute)(p, entry)); p = p->next);
+       return state;
 }
+
 /*
- * N_OPENPAREN and N_CLOSEPAREN nodes are temporary place markers.  They are
+ * f_openparen and f_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.
+ * to a f_expr node containing the expression and the ')' node is discarded.
+ * The functions themselves are only used as constants.
  */
-PLAN *
-c_openparen(argvp, isok)
-       char ***argvp;
-       int isok;
+
+int
+f_openparen(plan, entry)
+       PLAN *plan;
+       FTSENT *entry;
+{
+       abort();
+}
+
+int
+f_closeparen(plan, entry)
+       PLAN *plan;
+       FTSENT *entry;
 {
-       return (palloc(N_OPENPAREN, (int (*) __P((PLAN *, FTSENT *)))-1));
+       abort();
 }
+
+/* c_openparen == c_simple */
+/* c_closeparen == c_simple */
+
+/*
+ * AND operator. Since AND is implicit, no node is allocated.
+ */
 PLAN *
-c_closeparen(argvp, isok)
+c_and(option, argvp)
+       OPTION *option;
        char ***argvp;
-       int isok;
 {
-       return (palloc(N_CLOSEPAREN, (int (*) __P((PLAN *, FTSENT *)))-1));
+       return NULL;
 }
+
 /*
  * ! expression functions --
  *
@@ -1111,23 +1408,16 @@ f_not(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       PLAN *p;
-       int state;
+       register PLAN *p;
+       register int state = 0;
 
-       state = 0;
        for (p = plan->p_data[0];
-           p && (state = (p->eval)(p, entry)); p = p->next);
-       return (!state);
+           p && (state = (p->execute)(p, entry)); p = p->next);
+       return !state;
 }
-PLAN *
-c_not(argvp, isok)
-       char ***argvp;
-       int isok;
-{
-       return (palloc(N_NOT, f_not));
-}
+
+/* c_not == c_simple */
+
 /*
  * expression -o expression functions --
  *
@@ -1139,49 +1429,18 @@ f_or(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
-       PLAN *p;
-       int state;
+       register PLAN *p;
+       register int state = 0;
 
-       state = 0;
        for (p = plan->p_data[0];
-           p && (state = (p->eval)(p, entry)); p = p->next);
+           p && (state = (p->execute)(p, entry)); p = p->next);
 
        if (state)
-               return (1);
+               return 1;
 
        for (p = plan->p_data[1];
-           p && (state = (p->eval)(p, entry)); p = p->next);
-       return (state);
+           p && (state = (p->execute)(p, entry)); p = p->next);
+       return state;
 }
 
-PLAN *
-c_or(argvp, isok)
-       char ***argvp;
-       int isok;
-{
-       return (palloc(N_OR, f_or));
-}
-
-PLAN *
-c_null(argvp, isok)
-       char ***argvp;
-       int isok;
-{
-       return NULL;
-}
-
-static PLAN *
-palloc(t, f)
-       enum ntype t;
-       int (*f) __P((PLAN *, FTSENT *));
-{
-       PLAN *new;
-
-       if ((new = malloc(sizeof(PLAN))) == NULL)
-               err(1, "%s", "");
-       new->type = t;
-       new->eval = f;
-       new->flags = 0;
-       new->next = NULL;
-       return (new);
-}
+/* c_or == c_simple */
index cdce351297ea394dab5b8dc3fa5ddb4b74f38b4a..d05002910d582a4606399364ecd9c0124e16e372 100644 (file)
--- a/find/ls.c
+++ b/find/ls.c
@@ -1,5 +1,3 @@
-/*     $NetBSD: ls.c,v 1.10 1998/03/03 02:22:40 thorpej Exp $  */
-
 /*
  * Copyright (c) 1989, 1993
  *     The Regents of the University of California.  All rights reserved.
  * SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
 #ifndef lint
 #if 0
-static char sccsid[] = "from: @(#)ls.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)ls.c       8.1 (Berkeley) 6/6/93";
 #else
-__RCSID("$NetBSD: ls.c,v 1.10 1998/03/03 02:22:40 thorpej Exp $");
+static const char rcsid[] =
+  "$FreeBSD: src/usr.bin/find/ls.c,v 1.5.6.2 2001/05/06 09:53:22 phk Exp $";
 #endif
 #endif /* not lint */
 
@@ -47,19 +45,12 @@ __RCSID("$NetBSD: ls.c,v 1.10 1998/03/03 02:22:40 thorpej Exp $");
 
 #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 <time.h>
-#include <tzfile.h>
 #include <unistd.h>
 #include <utmp.h>
 
-#include "find.h"
-
 /* Derived from the print routines in the ls(1) source code. */
 
 static void printlink __P((char *));
@@ -71,10 +62,9 @@ printlong(name, accpath, sb)
        char *accpath;                  /* current valid path to filename */
        struct stat *sb;                /* stat buffer */
 {
-       char modep[15];
+       char modep[15], *user_from_uid(), *group_from_gid();
 
-       (void)printf("%6lu %4qd ", (u_long)sb->st_ino,
-           (long long)sb->st_blocks);
+       (void)printf("%6lu %4qd ", (u_long) 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,
@@ -84,7 +74,7 @@ printlong(name, accpath, sb)
                (void)printf("%3d, %3d ", major(sb->st_rdev),
                    minor(sb->st_rdev));
        else
-               (void)printf("%8qd ", (long long)sb->st_size);
+               (void)printf("%8qd ", sb->st_size);
        printtime(sb->st_mtime);
        (void)printf("%s", name);
        if (S_ISLNK(sb->st_mode))
@@ -97,13 +87,13 @@ printtime(ftime)
        time_t ftime;
 {
        int i;
-       char *longstring;
+       char longstring[80];
 
-       longstring = ctime(&ftime);
+       strftime(longstring, sizeof(longstring), "%c", localtime(&ftime));
        for (i = 4; i < 11; ++i)
                (void)putchar(longstring[i]);
 
-#define        SIXMONTHS       ((DAYSPERNYEAR / 2) * SECSPERDAY)
+#define        SIXMONTHS       ((365 / 2) * 86400)
        if (ftime + SIXMONTHS > time((time_t *)NULL))
                for (i = 11; i < 16; ++i)
                        (void)putchar(longstring[i]);
@@ -122,7 +112,7 @@ printlink(name)
        int lnklen;
        char path[MAXPATHLEN + 1];
 
-       if ((lnklen = readlink(name, path, MAXPATHLEN)) == -1) {
+       if ((lnklen = readlink(name, path, MAXPATHLEN - 1)) == -1) {
                warn("%s", name);
                return;
        }
index ed2f090aef3b9b2b517ce07194d541715c2e354d..bad04a212ed6dc698a0b884921416f89f0699668 100644 (file)
@@ -1,5 +1,3 @@
-/*     $NetBSD: main.c,v 1.10 1998/02/10 21:52:51 cgd Exp $    */
-
 /*-
  * Copyright (c) 1990, 1993, 1994
  *     The Regents of the University of California.  All rights reserved.
  * SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
+#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
 #if 0
 static char sccsid[] = "@(#)main.c     8.4 (Berkeley) 5/4/95";
 #else
-__COPYRIGHT("@(#) Copyright (c) 1990, 1993, 1994\n\
-       The Regents of the University of California.  All rights reserved.\n");
-__RCSID("$NetBSD: main.c,v 1.10 1998/02/10 21:52:51 cgd Exp $");
+static const char rcsid[] =
+  "$FreeBSD: src/usr.bin/find/main.c,v 1.9.6.2 2001/02/25 21:56:59 knu Exp $";
 #endif
 #endif /* not lint */
 
@@ -54,6 +56,8 @@ __RCSID("$NetBSD: main.c,v 1.10 1998/02/10 21:52:51 cgd Exp $");
 #include <errno.h>
 #include <fcntl.h>
 #include <fts.h>
+#include <locale.h>
+#include <regex.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
@@ -67,9 +71,11 @@ 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;                    /* do hierarchies in lexicographical order */
 int isxargs;                   /* don't permit xargs delimiting chars */
+int mindepth = -1, maxdepth = -1; /* minimum and maximum depth */
+int regexp_flags = REG_BASIC;  /* use the "basic" regexp by default*/
 
-int main __P((int, char **));
 static void usage __P((void));
 
 int
@@ -77,30 +83,31 @@ main(argc, argv)
        int argc;
        char *argv[];
 {
-       char **p, **start;
-       int ch;
+       register char **p, **start;
+       int Hflag, Lflag, 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 = alloca(argc * sizeof (char *));
+       (void)time(&now);       /* initialize the time-of-day */
 
+       p = start = argv;
+       Hflag = Lflag = 0;
        ftsoptions = FTS_NOSTAT | FTS_PHYSICAL;
-       while ((ch = getopt(argc, argv, "HLPXdf:x")) != EOF)
-               switch(ch) {
+       while ((ch = getopt(argc, argv, "EHLPXdf:sx")) != -1)
+               switch (ch) {
+               case 'E':
+                       regexp_flags |= REG_EXTENDED;
+                       break;
                case 'H':
-                       ftsoptions |= FTS_COMFOLLOW;
-#if 0  /* XXX necessary? */
-                       ftsoptions &= ~FTS_LOGICAL;
-#endif
+                       Hflag = 1;
+                       Lflag = 0;
                        break;
                case 'L':
-                       ftsoptions &= ~FTS_COMFOLLOW;
-                       ftsoptions |= FTS_LOGICAL;
+                       Lflag = 1;
+                       Hflag = 0;
                        break;
                case 'P':
-                       ftsoptions &= ~(FTS_COMFOLLOW|FTS_LOGICAL);
-                       ftsoptions |= FTS_PHYSICAL;
+                       Hflag = Lflag = 0;
                        break;
                case 'X':
                        isxargs = 1;
@@ -111,9 +118,8 @@ main(argc, argv)
                case 'f':
                        *p++ = optarg;
                        break;
-               case 'h':
-                       ftsoptions &= ~FTS_PHYSICAL;
-                       ftsoptions |= FTS_LOGICAL;
+               case 's':
+                       issort = 1;
                        break;
                case 'x':
                        ftsoptions |= FTS_XDEV;
@@ -123,9 +129,16 @@ main(argc, argv)
                        break;
                }
 
-       argc -= optind; 
+       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
@@ -153,6 +166,6 @@ static void
 usage()
 {
        (void)fprintf(stderr,
-"usage: find [-H | -L | -P] [-Xdhx] [-f file] [file ...] [expression]\n");
+"usage: find [-H | -L | -P] [-EXdsx] [-f file] [file ...] [expression]\n");
        exit(1);
 }
index cf6a85bbd3869289617fa6a01bee7b313d7ba53f..2ad2ace83f8e987530d017196343fd0a4552b826 100644 (file)
@@ -1,5 +1,3 @@
-/*     $NetBSD: misc.c,v 1.7 1998/02/02 14:02:25 mrg Exp $     */
-
 /*-
  * Copyright (c) 1990, 1993, 1994
  *     The Regents of the University of California.  All rights reserved.
  * SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
 #ifndef lint
 #if 0
-static char sccsid[] = "from: @(#)misc.c       8.2 (Berkeley) 4/1/94";
+static char sccsid[] = "@(#)misc.c     8.2 (Berkeley) 4/1/94";
 #else
-__RCSID("$NetBSD: misc.c,v 1.7 1998/02/02 14:02:25 mrg Exp $");
+static const char rcsid[] =
+  "$FreeBSD: src/usr.bin/find/misc.c,v 1.2.12.1 2000/06/23 18:38:46 roberto Exp $";
 #endif
 #endif /* not lint */
 
@@ -56,26 +54,25 @@ __RCSID("$NetBSD: misc.c,v 1.7 1998/02/02 14:02:25 mrg Exp $");
 #include <string.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.
+ *     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;
 {
-       int plen;
-       char ch, *p;
+       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, "realloc");
+                                       err(1, NULL);
                        memmove(p, path, plen);
                        p += plen;
                        ++orig;
@@ -91,7 +88,7 @@ brace_subst(orig, store, path, len)
  */
 int
 queryuser(argv)
-       char **argv;
+       register char **argv;
 {
        int ch, first, nl;
 
@@ -118,7 +115,7 @@ queryuser(argv)
        }
         return (first == 'y');
 }
+
 /*
  * emalloc --
  *     malloc with error checking.
@@ -130,6 +127,6 @@ emalloc(len)
        void *p;
 
        if ((p = malloc(len)) == NULL)
-               err(1, "malloc");
+               err(1, NULL);
        return (p);
 }
index 128a785fe4bef213046f92b80564ff6b53912cc3..a8feb8e3322e16c6d919adfeb8d39497e1c9fff7 100644 (file)
@@ -1,5 +1,3 @@
-/*     $NetBSD: operator.c,v 1.6 1998/02/21 22:47:21 christos Exp $    */
-
 /*-
  * Copyright (c) 1990, 1993
  *     The Regents of the University of California.  All rights reserved.
  * 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.
+ *
+ * $FreeBSD: src/usr.bin/find/operator.c,v 1.5.6.1 2001/05/06 09:53:22 phk Exp $
  */
 
-#include <sys/cdefs.h>
 #ifndef lint
-#if 0
-static char sccsid[] = "from: @(#)operator.c   8.1 (Berkeley) 6/6/93";
-#else
-__RCSID("$NetBSD: operator.c,v 1.6 1998/02/21 22:47:21 christos Exp $");
-#endif
+static char sccsid[] = "@(#)operator.c 8.1 (Berkeley) 6/6/93";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -52,69 +47,65 @@ __RCSID("$NetBSD: operator.c,v 1.6 1998/02/21 22:47:21 christos Exp $");
 #include <stdio.h>
 
 #include "find.h"
-    
-static PLAN *yanknode __P((PLAN **));
-static PLAN *yankexpr __P((PLAN **));
 
 /*
  * yanknode --
  *     destructively removes the top from the plan
  */
 static PLAN *
-yanknode(planp)    
+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.
+ *     simple node or a f_expr node containing a list of simple nodes.
  */
 static PLAN *
-yankexpr(planp)    
+yankexpr(planp)
        PLAN **planp;           /* pointer to top of plan (modified) */
 {
-       PLAN *next;             /* temp node holding subexpression results */
+       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 */
-    
+
        /* 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)
+       if (node->execute == f_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,
+                        * a f_expr.  The ')' we found is ignored.  Otherwise,
                         * we just continue to add whatever we get to our
                         * subplan.
                         */
-                       if (next->type == N_CLOSEPAREN) {
+                       if (next->execute == f_closeparen) {
                                if (subplan == NULL)
                                        errx(1, "(): empty inner expression");
                                node->p_data[0] = subplan;
-                               node->type = N_EXPR;
-                               node->eval = f_expr;
+                               node->execute = f_expr;
                                break;
                        } else {
                                if (subplan == NULL)
@@ -128,7 +119,7 @@ yankexpr(planp)
                }
        return (node);
 }
+
 /*
  * paren_squish --
  *     replaces "parentheisized" plans in our search plan with "expr" nodes.
@@ -137,22 +128,22 @@ PLAN *
 paren_squish(plan)
        PLAN *plan;             /* plan with ( ) nodes */
 {
-       PLAN *expr;             /* pointer to next expression */
-       PLAN *tail;             /* pointer to tail of result plan */
+       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.
+        * 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)
+               if (expr->execute == f_closeparen)
                        errx(1, "): no beginning '('");
 
                /* add the expression to our result plan */
@@ -166,7 +157,7 @@ paren_squish(plan)
        }
        return (result);
 }
+
 /*
  * not_squish --
  *     compresses "!" expressions in our search plan.
@@ -175,19 +166,19 @@ PLAN *
 not_squish(plan)
        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 */
+       register PLAN *next;    /* next node being processed */
+       register PLAN *node;    /* temporary node used in f_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) {
+
+       tail = result = NULL;
+
+       while (next = yanknode(&plan)) {
                /*
                 * if we encounter a ( expression ) then look for nots in
                 * the expr subplan.
                 */
-               if (next->type == N_EXPR)
+               if (next->execute == f_expr)
                        next->p_data[0] = not_squish(next->p_data[0]);
 
                /*
@@ -195,18 +186,24 @@ not_squish(plan)
                 * it in the not's subplan.  As an optimization we compress
                 * several not's to zero or one not.
                 */
-               if (next->type == N_NOT) {
+               if (next->execute == f_not) {
                        int notlevel = 1;
 
                        node = yanknode(&plan);
-                       while (node->type == N_NOT) {
+                       while (node != NULL && node->execute == f_not) {
                                ++notlevel;
                                node = yanknode(&plan);
                        }
                        if (node == NULL)
                                errx(1, "!: no following expression");
-                       if (node->type == N_OR)
+                       if (node->execute == f_or)
                                errx(1, "!: nothing between ! and -o");
+                       /*
+                        * If we encounter ! ( expr ) then look for nots in
+                        * the expr subplan.
+                        */
+                       if (node->execute == f_expr)
+                               node->p_data[0] = not_squish(node->p_data[0]);
                        if (notlevel % 2 != 1)
                                next = node;
                        else
@@ -224,7 +221,7 @@ not_squish(plan)
        }
        return (result);
 }
+
 /*
  * or_squish --
  *     compresses -o expressions in our search plan.
@@ -233,22 +230,22 @@ PLAN *
 or_squish(plan)
        PLAN *plan;             /* plan with ors to be squished */
 {
-       PLAN *next;             /* next node being processed */
-       PLAN *tail;             /* pointer to tail of result plan */
+       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)
+               if (next->execute == f_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)
+               /* if we encounter a not then look for or's in the subplan */
+               if (next->execute == f_not)
                        next->p_data[0] = or_squish(next->p_data[0]);
 
                /*
@@ -256,7 +253,7 @@ or_squish(plan)
                 * 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 (next->execute == f_or) {
                        if (result == NULL)
                                errx(1, "-o: no expression before -o");
                        next->p_data[0] = result;
index f531dab0f69f95a6b838814f70dc32fbf051bd19..7e73a5fdc5032e56f11ae613704b0e5f1236bae9 100644 (file)
@@ -1,5 +1,3 @@
-/*     $NetBSD: option.c,v 1.9 1998/02/21 22:47:21 christos Exp $      */
-
 /*-
  * Copyright (c) 1990, 1993, 1994
  *     The Regents of the University of California.  All rights reserved.
  * SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
 #ifndef lint
-#if 0
-static char sccsid[] = "from: @(#)option.c     8.2 (Berkeley) 4/16/94";
-#else
-__RCSID("$NetBSD: option.c,v 1.9 1998/02/21 22:47:21 christos Exp $");
-#endif
+/*
+static char sccsid[] = "@(#)option.c   8.2 (Berkeley) 4/16/94";
+*/
+static const char rcsid[] =
+  "$FreeBSD: src/usr.bin/find/option.c,v 1.9.2.4 2001/05/06 09:53:22 phk Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -50,49 +47,82 @@ __RCSID("$NetBSD: option.c,v 1.9 1998/02/21 22:47:21 christos Exp $");
 
 #include <err.h>
 #include <fts.h>
+#include <regex.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "find.h"
 
-int typecompare __P((const void *, const void *));
-static OPTION *option __P((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 },
-       { "-and",       N_AND,          c_null,         0 },
-       { "-atime",     N_ATIME,        c_atime,        1 },
-       { "-ctime",     N_CTIME,        c_ctime,        1 },
-       { "-depth",     N_DEPTH,        c_depth,        0 },
-       { "-exec",      N_EXEC,         c_exec,         1 },
-       { "-follow",    N_FOLLOW,       c_follow,       0 },
-       { "-fstype",    N_FSTYPE,       c_fstype,       1 },
-       { "-group",     N_GROUP,        c_group,        1 },
-       { "-inum",      N_INUM,         c_inum,         1 },
-       { "-links",     N_LINKS,        c_links,        1 },
-       { "-ls",        N_LS,           c_ls,           0 },
-       { "-mtime",     N_MTIME,        c_mtime,        1 },
-       { "-name",      N_NAME,         c_name,         1 },
-       { "-newer",     N_NEWER,        c_newer,        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 },
-       { "-prune",     N_PRUNE,        c_prune,        0 },
-       { "-size",      N_SIZE,         c_size,         1 },
-       { "-type",      N_TYPE,         c_type,         1 },
-       { "-user",      N_USER,         c_user,         1 },
-       { "-xdev",      N_XDEV,         c_xdev,         0 }
+       { "!",          c_simple,       f_not,          0 },
+       { "(",          c_simple,       f_openparen,    0 },
+       { ")",          c_simple,       f_closeparen,   0 },
+       { "-a",         c_and,          NULL,           0 },
+       { "-amin",      c_Xmin,         f_Xmin,         F_TIME_A },
+       { "-and",       c_and,          NULL,           0 },
+       { "-anewer",    c_newer,        f_newer,        F_TIME_A },
+       { "-atime",     c_Xtime,        f_Xtime,        F_TIME_A },
+       { "-cmin",      c_Xmin,         f_Xmin,         F_TIME_C },
+       { "-cnewer",    c_newer,        f_newer,        F_TIME_C },
+       { "-ctime",     c_Xtime,        f_Xtime,        F_TIME_C },
+       { "-delete",    c_delete,       f_delete,       0 },
+       { "-depth",     c_depth,        f_always_true,  0 },
+       { "-empty",     c_empty,        f_empty,        0 },
+       { "-exec",      c_exec,         f_exec,         0 },
+       { "-execdir",   c_exec,         f_exec,         F_EXECDIR },
+       { "-flags",     c_flags,        f_flags,        0 },
+       { "-follow",    c_follow,       f_always_true,  0 },
+/*
+ * NetBSD doesn't provide a getvfsbyname(), so this option
+ * is not available if using a NetBSD kernel.
+ */
+#if !defined(__NetBSD__)
+       { "-fstype",    c_fstype,       f_fstype,       0 },
+#endif
+       { "-group",     c_group,        f_group,        0 },
+       { "-iname",     c_name,         f_name,         F_IGNCASE },
+       { "-inum",      c_inum,         f_inum,         0 },
+       { "-ipath",     c_name,         f_path,         F_IGNCASE },
+       { "-iregex",    c_regex,        f_regex,        F_IGNCASE },
+       { "-links",     c_links,        f_links,        0 },
+       { "-ls",        c_ls,           f_ls,           0 },
+       { "-maxdepth",  c_mXXdepth,     f_always_true,  F_MAXDEPTH },
+       { "-mindepth",  c_mXXdepth,     f_always_true,  0 },
+       { "-mmin",      c_Xmin,         f_Xmin,         0 },
+       { "-mnewer",    c_newer,        f_newer,        0 },
+       { "-mtime",     c_Xtime,        f_Xtime,        0 },
+       { "-name",      c_name,         f_name,         0 },
+       { "-newer",     c_newer,        f_newer,        0 },
+       { "-neweraa",   c_newer,        f_newer,        F_TIME_A | F_TIME2_A },
+       { "-newerac",   c_newer,        f_newer,        F_TIME_A | F_TIME2_C },
+       { "-neweram",   c_newer,        f_newer,        F_TIME_A },
+       { "-newerat",   c_newer,        f_newer,        F_TIME_A | F_TIME2_T },
+       { "-newerca",   c_newer,        f_newer,        F_TIME_C | F_TIME2_A },
+       { "-newercc",   c_newer,        f_newer,        F_TIME_C | F_TIME2_C },
+       { "-newercm",   c_newer,        f_newer,        F_TIME_C },
+       { "-newerct",   c_newer,        f_newer,        F_TIME_C | F_TIME2_T },
+       { "-newerma",   c_newer,        f_newer,        F_TIME2_A },
+       { "-newermc",   c_newer,        f_newer,        F_TIME2_C },
+       { "-newermm",   c_newer,        f_newer,        0 },
+       { "-newermt",   c_newer,        f_newer,        F_TIME2_T },
+       { "-nogroup",   c_nogroup,      f_nogroup,      0 },
+       { "-nouser",    c_nouser,       f_nouser,       0 },
+       { "-o",         c_simple,       f_or,           0 },
+       { "-ok",        c_exec,         f_exec,         F_NEEDOK },
+       { "-okdir",     c_exec,         f_exec,         F_NEEDOK | F_EXECDIR },
+       { "-or",        c_simple,       f_or,           0 },
+       { "-path",      c_name,         f_path,         0 },
+       { "-perm",      c_perm,         f_perm,         0 },
+       { "-print",     c_print,        f_print,        0 },
+       { "-print0",    c_print,        f_print0,       0 },
+       { "-prune",     c_simple,       f_prune,        0 },
+       { "-regex",     c_regex,        f_regex,        0 },
+       { "-size",      c_size,         f_size,         0 },
+       { "-type",      c_type,         f_type,         0 },
+       { "-user",      c_user,         f_user,         0 },
+       { "-xdev",      c_xdev,         f_always_true,  0 },
 };
 
 /*
@@ -107,7 +137,7 @@ PLAN *
 find_create(argvp)
        char ***argvp;
 {
-       OPTION *p;
+       register OPTION *p;
        PLAN *new;
        char **argv;
 
@@ -116,20 +146,18 @@ find_create(argvp)
        if ((p = option(*argv)) == NULL)
                errx(1, "%s: unknown option", *argv);
        ++argv;
-       if (p->arg && !*argv)
-               errx(1, "%s: requires additional arguments", *--argv);
-
-       new = (p->create)(&argv, p->token == N_OK);
 
+       new = (p->create)(p, &argv);
        *argvp = argv;
        return (new);
 }
 
-static OPTION *
+OPTION *
 option(name)
        char *name;
 {
        OPTION tmp;
+       int typecompare __P((const void *, const void *));
 
        tmp.name = name;
        return ((OPTION *)bsearch(&tmp, options,
diff --git a/find/y.tab.c b/find/y.tab.c
new file mode 100644 (file)
index 0000000..573e775
--- /dev/null
@@ -0,0 +1,1542 @@
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char yysccsid[] = "@(#)yaccpar  1.9 (Berkeley) 02/21/93";
+#else
+__IDSTRING(yyrcsid, "$NetBSD: skeleton.c,v 1.14 1997/10/20 03:41:16 lukem Exp $");
+#endif
+#endif
+#include <stdlib.h>
+#define YYBYACC 1
+#define YYMAJOR 1
+#define YYMINOR 9
+#define YYLEX yylex()
+#define YYEMPTY -1
+#define yyclearin (yychar=(YYEMPTY))
+#define yyerrok (yyerrflag=0)
+#define YYRECOVERING (yyerrflag!=0)
+#define YYPREFIX "yy"
+#line 2 "getdate.y"
+/*
+**  Originally written by Steven M. Bellovin <smb@research.att.com> while
+**  at the University of North Carolina at Chapel Hill.  Later tweaked by
+**  a couple of people on Usenet.  Completely overhauled by Rich $alz
+**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
+**
+**  This grammar has 10 shift/reduce conflicts.
+**
+**  This code is in the public domain and has no copyright.
+*/
+/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
+/* SUPPRESS 288 on yyerrlab *//* Label unused */
+
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
+/* Since the code of getdate.y is not included in the Emacs executable
+   itself, there is no need to #define static in this file.  Even if
+   the code were included in the Emacs executable, it probably
+   wouldn't do any harm to #undef it here; this will only cause
+   problems if we try to write to a static variable, which I don't
+   think this code needs to do.  */
+#ifdef emacs
+#undef static
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+/* The code at the top of get_date which figures out the offset of the
+   current time zone checks various CPP symbols to see if special
+   tricks are need, but defaults to using the gettimeofday system call.
+   Include <sys/time.h> if that will be used.  */
+
+#if    defined(vms)
+# include <types.h>
+#else /* defined(vms) */
+# include <sys/types.h>
+/* don't need xtime.h */
+# include <sys/time.h>
+# include <time.h>
+#endif /* !defined(vms) */
+
+#include <sys/timeb.h>
+
+#if defined (STDC_HEADERS) || defined (USG)
+#include <string.h>
+#endif
+
+/* Some old versions of bison generate parsers that use bcopy.
+   That loses on systems that don't provide the function, so we have
+   to redefine it here.  */
+#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
+#define bcopy(from, to, len) memcpy ((to), (from), (len))
+#endif
+
+#if defined (STDC_HEADERS)
+#include <stdlib.h>
+#endif
+
+/* NOTES on rebuilding getdate.c (particularly for inclusion in CVS
+   releases):
+
+   We don't want to mess with all the portability hassles of alloca.
+   In particular, most (all?) versions of bison will use alloca in
+   their parser.  If bison works on your system (e.g. it should work
+   with gcc), then go ahead and use it, but the more general solution
+   is to use byacc instead of bison, which should generate a portable
+   parser.  I played with adding "#define alloca dont_use_alloca", to
+   give an error if the parser generator uses alloca (and thus detect
+   unportable getdate.c's), but that seems to cause as many problems
+   as it solves.  */
+
+extern struct tm       *gmtime();
+extern struct tm       *localtime();
+
+#define yyparse getdate_yyparse
+#define yylex getdate_yylex
+#define yyerror getdate_yyerror
+
+static int yyparse ();
+static int yylex ();
+static int yyerror ();
+
+#define EPOCH          1970
+#define HOUR(x)                ((time_t)(x) * 60)
+#define SECSPERDAY     (24L * 60L * 60L)
+
+
+/*
+**  An entry in the lexical lookup table.
+*/
+typedef struct _TABLE {
+    char       *name;
+    int                type;
+    time_t     value;
+} TABLE;
+
+
+/*
+**  Daylight-savings mode:  on, off, or not yet known.
+*/
+typedef enum _DSTMODE {
+    DSTon, DSToff, DSTmaybe
+} DSTMODE;
+
+/*
+**  Meridian:  am, pm, or 24-hour style.
+*/
+typedef enum _MERIDIAN {
+    MERam, MERpm, MER24
+} MERIDIAN;
+
+
+/*
+**  Global variables.  We could get rid of most of these by using a good
+**  union as the yacc stack.  (This routine was originally written before
+**  yacc had the %union construct.)  Maybe someday; right now we only use
+**  the %union very rarely.
+*/
+static char    *yyInput;
+static DSTMODE yyDSTmode;
+static time_t  yyDayOrdinal;
+static time_t  yyDayNumber;
+static int     yyHaveDate;
+static int     yyHaveDay;
+static int     yyHaveRel;
+static int     yyHaveTime;
+static int     yyHaveZone;
+static time_t  yyTimezone;
+static time_t  yyDay;
+static time_t  yyHour;
+static time_t  yyMinutes;
+static time_t  yyMonth;
+static time_t  yySeconds;
+static time_t  yyYear;
+static MERIDIAN        yyMeridian;
+static time_t  yyRelMonth;
+static time_t  yyRelSeconds;
+
+#line 150 "getdate.y"
+typedef union {
+    time_t             Number;
+    enum _MERIDIAN     Meridian;
+} YYSTYPE;
+#line 172 "y.tab.c"
+#define tAGO 257
+#define tDAY 258
+#define tDAYZONE 259
+#define tID 260
+#define tMERIDIAN 261
+#define tMINUTE_UNIT 262
+#define tMONTH 263
+#define tMONTH_UNIT 264
+#define tSEC_UNIT 265
+#define tSNUMBER 266
+#define tUNUMBER 267
+#define tZONE 268
+#define tDST 269
+#define YYERRCODE 256
+short yylhs[] = {                                        -1,
+    0,    0,    2,    2,    2,    2,    2,    2,    3,    3,
+    3,    3,    3,    4,    4,    4,    6,    6,    6,    5,
+    5,    5,    5,    5,    5,    5,    5,    7,    7,    9,
+    9,    9,    9,    9,    9,    9,    9,    9,    8,    1,
+    1,
+};
+short yylen[] = {                                         2,
+    0,    2,    1,    1,    1,    1,    1,    1,    2,    4,
+    4,    6,    6,    1,    1,    2,    1,    2,    2,    3,
+    5,    3,    3,    2,    4,    2,    3,    2,    1,    2,
+    2,    1,    2,    2,    1,    2,    2,    1,    1,    0,
+    1,
+};
+short yydefred[] = {                                      1,
+    0,    0,   15,   32,    0,   38,   35,    0,    0,    0,
+    2,    3,    4,    5,    6,    7,    8,    0,   18,    0,
+   31,   36,   33,   19,    9,   30,    0,   37,   34,    0,
+    0,    0,   16,   28,    0,   23,   27,   22,    0,    0,
+   25,   41,   11,    0,   10,    0,    0,   21,   13,   12,
+};
+short yydgoto[] = {                                       1,
+   45,   11,   12,   13,   14,   15,   16,   17,   18,
+};
+short yysindex[] = {                                      0,
+ -249,  -38,    0,    0, -260,    0,    0, -240,  -47, -248,
+    0,    0,    0,    0,    0,    0,    0, -237,    0,  -18,
+    0,    0,    0,    0,    0,    0, -262,    0,    0, -239,
+ -238, -236,    0,    0, -235,    0,    0,    0,  -56,  -19,
+    0,    0,    0, -234,    0, -232, -258,    0,    0,    0,
+};
+short yyrindex[] = {                                      0,
+    0,    1,    0,    0,    0,    0,    0,    0,   69,   12,
+    0,    0,    0,    0,    0,    0,    0,   23,    0,   34,
+    0,    0,    0,    0,    0,    0,   67,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,   56,   45,
+    0,    0,    0,    0,    0,    0,   56,    0,    0,    0,
+};
+short yygindex[] = {                                      0,
+  -17,    0,    0,    0,    0,    0,    0,    0,    0,
+};
+#define YYTABLESIZE 337
+short yytable[] = {                                      32,
+   17,   44,   42,   36,   37,   19,   20,   49,    2,    3,
+   31,   14,    4,    5,    6,    7,    8,    9,   10,   34,
+   33,   21,   29,   22,   23,   35,   38,   46,   39,   50,
+   40,   41,   47,   24,   48,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,   20,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,   40,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,   26,    0,   39,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,   42,    0,    0,    0,    0,   43,
+   24,    0,    0,   25,   26,   27,   28,   29,   30,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,   17,   17,
+    0,    0,   17,   17,   17,   17,   17,   17,   17,   14,
+   14,    0,    0,   14,   14,   14,   14,   14,   14,   14,
+   29,   29,    0,    0,   29,   29,   29,   29,   29,   29,
+   29,   24,   24,    0,    0,   24,   24,   24,   24,   24,
+   24,   24,   20,   20,    0,    0,   20,   20,   20,   20,
+   20,   20,   20,   40,   40,    0,    0,   40,   40,   40,
+   40,    0,   40,   40,   26,   26,    0,   39,   26,   26,
+   26,   26,    0,    0,   26,   39,   39,
+};
+short yycheck[] = {                                      47,
+    0,   58,  261,  266,  267,   44,  267,  266,  258,  259,
+   58,    0,  262,  263,  264,  265,  266,  267,  268,  257,
+  269,  262,    0,  264,  265,   44,  266,   47,  267,   47,
+  267,  267,  267,    0,  267,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,    0,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,    0,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,    0,   -1,    0,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,  261,   -1,   -1,   -1,   -1,  266,
+  258,   -1,   -1,  261,  262,  263,  264,  265,  266,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  258,  259,
+   -1,   -1,  262,  263,  264,  265,  266,  267,  268,  258,
+  259,   -1,   -1,  262,  263,  264,  265,  266,  267,  268,
+  258,  259,   -1,   -1,  262,  263,  264,  265,  266,  267,
+  268,  258,  259,   -1,   -1,  262,  263,  264,  265,  266,
+  267,  268,  258,  259,   -1,   -1,  262,  263,  264,  265,
+  266,  267,  268,  258,  259,   -1,   -1,  262,  263,  264,
+  265,   -1,  267,  268,  258,  259,   -1,  259,  262,  263,
+  264,  265,   -1,   -1,  268,  267,  268,
+};
+#define YYFINAL 1
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 269
+#if YYDEBUG
+char *yyname[] = {
+"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,"','",0,0,"'/'",0,0,0,0,0,0,0,0,0,0,"':'",0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"tAGO","tDAY",
+"tDAYZONE","tID","tMERIDIAN","tMINUTE_UNIT","tMONTH","tMONTH_UNIT","tSEC_UNIT",
+"tSNUMBER","tUNUMBER","tZONE","tDST",
+};
+char *yyrule[] = {
+"$accept : spec",
+"spec :",
+"spec : spec item",
+"item : time",
+"item : zone",
+"item : date",
+"item : day",
+"item : rel",
+"item : number",
+"time : tUNUMBER tMERIDIAN",
+"time : tUNUMBER ':' tUNUMBER o_merid",
+"time : tUNUMBER ':' tUNUMBER tSNUMBER",
+"time : tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid",
+"time : tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER",
+"zone : tZONE",
+"zone : tDAYZONE",
+"zone : tZONE tDST",
+"day : tDAY",
+"day : tDAY ','",
+"day : tUNUMBER tDAY",
+"date : tUNUMBER '/' tUNUMBER",
+"date : tUNUMBER '/' tUNUMBER '/' tUNUMBER",
+"date : tUNUMBER tSNUMBER tSNUMBER",
+"date : tUNUMBER tMONTH tSNUMBER",
+"date : tMONTH tUNUMBER",
+"date : tMONTH tUNUMBER ',' tUNUMBER",
+"date : tUNUMBER tMONTH",
+"date : tUNUMBER tMONTH tUNUMBER",
+"rel : relunit tAGO",
+"rel : relunit",
+"relunit : tUNUMBER tMINUTE_UNIT",
+"relunit : tSNUMBER tMINUTE_UNIT",
+"relunit : tMINUTE_UNIT",
+"relunit : tSNUMBER tSEC_UNIT",
+"relunit : tUNUMBER tSEC_UNIT",
+"relunit : tSEC_UNIT",
+"relunit : tSNUMBER tMONTH_UNIT",
+"relunit : tUNUMBER tMONTH_UNIT",
+"relunit : tMONTH_UNIT",
+"number : tUNUMBER",
+"o_merid :",
+"o_merid : tMERIDIAN",
+};
+#endif
+#ifdef YYSTACKSIZE
+#undef YYMAXDEPTH
+#define YYMAXDEPTH YYSTACKSIZE
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 10000
+#define YYMAXDEPTH 10000
+#endif
+#endif
+#define YYINITSTACKSIZE 200
+int yydebug;
+int yynerrs;
+int yyerrflag;
+int yychar;
+short *yyssp;
+YYSTYPE *yyvsp;
+YYSTYPE yyval;
+YYSTYPE yylval;
+short *yyss;
+short *yysslim;
+YYSTYPE *yyvs;
+int yystacksize;
+#line 369 "getdate.y"
+
+/* Month and day table. */
+static TABLE const MonthDayTable[] = {
+    { "january",       tMONTH,  1 },
+    { "february",      tMONTH,  2 },
+    { "march",         tMONTH,  3 },
+    { "april",         tMONTH,  4 },
+    { "may",           tMONTH,  5 },
+    { "june",          tMONTH,  6 },
+    { "july",          tMONTH,  7 },
+    { "august",                tMONTH,  8 },
+    { "september",     tMONTH,  9 },
+    { "sept",          tMONTH,  9 },
+    { "october",       tMONTH, 10 },
+    { "november",      tMONTH, 11 },
+    { "december",      tMONTH, 12 },
+    { "sunday",                tDAY, 0 },
+    { "monday",                tDAY, 1 },
+    { "tuesday",       tDAY, 2 },
+    { "tues",          tDAY, 2 },
+    { "wednesday",     tDAY, 3 },
+    { "wednes",                tDAY, 3 },
+    { "thursday",      tDAY, 4 },
+    { "thur",          tDAY, 4 },
+    { "thurs",         tDAY, 4 },
+    { "friday",                tDAY, 5 },
+    { "saturday",      tDAY, 6 },
+    { NULL }
+};
+
+/* Time units table. */
+static TABLE const UnitsTable[] = {
+    { "year",          tMONTH_UNIT,    12 },
+    { "month",         tMONTH_UNIT,    1 },
+    { "fortnight",     tMINUTE_UNIT,   14 * 24 * 60 },
+    { "week",          tMINUTE_UNIT,   7 * 24 * 60 },
+    { "day",           tMINUTE_UNIT,   1 * 24 * 60 },
+    { "hour",          tMINUTE_UNIT,   60 },
+    { "minute",                tMINUTE_UNIT,   1 },
+    { "min",           tMINUTE_UNIT,   1 },
+    { "second",                tSEC_UNIT,      1 },
+    { "sec",           tSEC_UNIT,      1 },
+    { NULL }
+};
+
+/* Assorted relative-time words. */
+static TABLE const OtherTable[] = {
+    { "tomorrow",      tMINUTE_UNIT,   1 * 24 * 60 },
+    { "yesterday",     tMINUTE_UNIT,   -1 * 24 * 60 },
+    { "today",         tMINUTE_UNIT,   0 },
+    { "now",           tMINUTE_UNIT,   0 },
+    { "last",          tUNUMBER,       -1 },
+    { "this",          tMINUTE_UNIT,   0 },
+    { "next",          tUNUMBER,       2 },
+    { "first",         tUNUMBER,       1 },
+/*  { "second",                tUNUMBER,       2 }, */
+    { "third",         tUNUMBER,       3 },
+    { "fourth",                tUNUMBER,       4 },
+    { "fifth",         tUNUMBER,       5 },
+    { "sixth",         tUNUMBER,       6 },
+    { "seventh",       tUNUMBER,       7 },
+    { "eighth",                tUNUMBER,       8 },
+    { "ninth",         tUNUMBER,       9 },
+    { "tenth",         tUNUMBER,       10 },
+    { "eleventh",      tUNUMBER,       11 },
+    { "twelfth",       tUNUMBER,       12 },
+    { "ago",           tAGO,   1 },
+    { NULL }
+};
+
+/* The timezone table. */
+/* Some of these are commented out because a time_t can't store a float. */
+static TABLE const TimezoneTable[] = {
+    { "gmt",   tZONE,     HOUR( 0) },  /* Greenwich Mean */
+    { "ut",    tZONE,     HOUR( 0) },  /* Universal (Coordinated) */
+    { "utc",   tZONE,     HOUR( 0) },
+    { "wet",   tZONE,     HOUR( 0) },  /* Western European */
+    { "bst",   tDAYZONE,  HOUR( 0) },  /* British Summer */
+    { "wat",   tZONE,     HOUR( 1) },  /* West Africa */
+    { "at",    tZONE,     HOUR( 2) },  /* Azores */
+#if    0
+    /* For completeness.  BST is also British Summer, and GST is
+     * also Guam Standard. */
+    { "bst",   tZONE,     HOUR( 3) },  /* Brazil Standard */
+    { "gst",   tZONE,     HOUR( 3) },  /* Greenland Standard */
+#endif
+#if 0
+    { "nft",   tZONE,     HOUR(3.5) }, /* Newfoundland */
+    { "nst",   tZONE,     HOUR(3.5) }, /* Newfoundland Standard */
+    { "ndt",   tDAYZONE,  HOUR(3.5) }, /* Newfoundland Daylight */
+#endif
+    { "ast",   tZONE,     HOUR( 4) },  /* Atlantic Standard */
+    { "adt",   tDAYZONE,  HOUR( 4) },  /* Atlantic Daylight */
+    { "est",   tZONE,     HOUR( 5) },  /* Eastern Standard */
+    { "edt",   tDAYZONE,  HOUR( 5) },  /* Eastern Daylight */
+    { "cst",   tZONE,     HOUR( 6) },  /* Central Standard */
+    { "cdt",   tDAYZONE,  HOUR( 6) },  /* Central Daylight */
+    { "mst",   tZONE,     HOUR( 7) },  /* Mountain Standard */
+    { "mdt",   tDAYZONE,  HOUR( 7) },  /* Mountain Daylight */
+    { "pst",   tZONE,     HOUR( 8) },  /* Pacific Standard */
+    { "pdt",   tDAYZONE,  HOUR( 8) },  /* Pacific Daylight */
+    { "yst",   tZONE,     HOUR( 9) },  /* Yukon Standard */
+    { "ydt",   tDAYZONE,  HOUR( 9) },  /* Yukon Daylight */
+    { "hst",   tZONE,     HOUR(10) },  /* Hawaii Standard */
+    { "hdt",   tDAYZONE,  HOUR(10) },  /* Hawaii Daylight */
+    { "cat",   tZONE,     HOUR(10) },  /* Central Alaska */
+    { "ahst",  tZONE,     HOUR(10) },  /* Alaska-Hawaii Standard */
+    { "nt",    tZONE,     HOUR(11) },  /* Nome */
+    { "idlw",  tZONE,     HOUR(12) },  /* International Date Line West */
+    { "cet",   tZONE,     -HOUR(1) },  /* Central European */
+    { "met",   tZONE,     -HOUR(1) },  /* Middle European */
+    { "mewt",  tZONE,     -HOUR(1) },  /* Middle European Winter */
+    { "mest",  tDAYZONE,  -HOUR(1) },  /* Middle European Summer */
+    { "swt",   tZONE,     -HOUR(1) },  /* Swedish Winter */
+    { "sst",   tDAYZONE,  -HOUR(1) },  /* Swedish Summer */
+    { "fwt",   tZONE,     -HOUR(1) },  /* French Winter */
+    { "fst",   tDAYZONE,  -HOUR(1) },  /* French Summer */
+    { "eet",   tZONE,     -HOUR(2) },  /* Eastern Europe, USSR Zone 1 */
+    { "bt",    tZONE,     -HOUR(3) },  /* Baghdad, USSR Zone 2 */
+#if 0
+    { "it",    tZONE,     -HOUR(3.5) },/* Iran */
+#endif
+    { "zp4",   tZONE,     -HOUR(4) },  /* USSR Zone 3 */
+    { "zp5",   tZONE,     -HOUR(5) },  /* USSR Zone 4 */
+#if 0
+    { "ist",   tZONE,     -HOUR(5.5) },/* Indian Standard */
+#endif
+    { "zp6",   tZONE,     -HOUR(6) },  /* USSR Zone 5 */
+#if    0
+    /* For completeness.  NST is also Newfoundland Stanard, and SST is
+     * also Swedish Summer. */
+    { "nst",   tZONE,     -HOUR(6.5) },/* North Sumatra */
+    { "sst",   tZONE,     -HOUR(7) },  /* South Sumatra, USSR Zone 6 */
+#endif /* 0 */
+    { "wast",  tZONE,     -HOUR(7) },  /* West Australian Standard */
+    { "wadt",  tDAYZONE,  -HOUR(7) },  /* West Australian Daylight */
+#if 0
+    { "jt",    tZONE,     -HOUR(7.5) },/* Java (3pm in Cronusland!) */
+#endif
+    { "cct",   tZONE,     -HOUR(8) },  /* China Coast, USSR Zone 7 */
+    { "jst",   tZONE,     -HOUR(9) },  /* Japan Standard, USSR Zone 8 */
+#if 0
+    { "cast",  tZONE,     -HOUR(9.5) },/* Central Australian Standard */
+    { "cadt",  tDAYZONE,  -HOUR(9.5) },/* Central Australian Daylight */
+#endif
+    { "east",  tZONE,     -HOUR(10) }, /* Eastern Australian Standard */
+    { "eadt",  tDAYZONE,  -HOUR(10) }, /* Eastern Australian Daylight */
+    { "gst",   tZONE,     -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
+    { "nzt",   tZONE,     -HOUR(12) }, /* New Zealand */
+    { "nzst",  tZONE,     -HOUR(12) }, /* New Zealand Standard */
+    { "nzdt",  tDAYZONE,  -HOUR(12) }, /* New Zealand Daylight */
+    { "idle",  tZONE,     -HOUR(12) }, /* International Date Line East */
+    {  NULL  }
+};
+
+/* Military timezone table. */
+static TABLE const MilitaryTable[] = {
+    { "a",     tZONE,  HOUR(  1) },
+    { "b",     tZONE,  HOUR(  2) },
+    { "c",     tZONE,  HOUR(  3) },
+    { "d",     tZONE,  HOUR(  4) },
+    { "e",     tZONE,  HOUR(  5) },
+    { "f",     tZONE,  HOUR(  6) },
+    { "g",     tZONE,  HOUR(  7) },
+    { "h",     tZONE,  HOUR(  8) },
+    { "i",     tZONE,  HOUR(  9) },
+    { "k",     tZONE,  HOUR( 10) },
+    { "l",     tZONE,  HOUR( 11) },
+    { "m",     tZONE,  HOUR( 12) },
+    { "n",     tZONE,  HOUR(- 1) },
+    { "o",     tZONE,  HOUR(- 2) },
+    { "p",     tZONE,  HOUR(- 3) },
+    { "q",     tZONE,  HOUR(- 4) },
+    { "r",     tZONE,  HOUR(- 5) },
+    { "s",     tZONE,  HOUR(- 6) },
+    { "t",     tZONE,  HOUR(- 7) },
+    { "u",     tZONE,  HOUR(- 8) },
+    { "v",     tZONE,  HOUR(- 9) },
+    { "w",     tZONE,  HOUR(-10) },
+    { "x",     tZONE,  HOUR(-11) },
+    { "y",     tZONE,  HOUR(-12) },
+    { "z",     tZONE,  HOUR(  0) },
+    { NULL }
+};
+
+\f
+
+
+/* ARGSUSED */
+static int
+yyerror(s)
+    char       *s;
+{
+  return 0;
+}
+
+
+static time_t
+ToSeconds(Hours, Minutes, Seconds, Meridian)
+    time_t     Hours;
+    time_t     Minutes;
+    time_t     Seconds;
+    MERIDIAN   Meridian;
+{
+    if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
+       return -1;
+    switch (Meridian) {
+    case MER24:
+       if (Hours < 0 || Hours > 23)
+           return -1;
+       return (Hours * 60L + Minutes) * 60L + Seconds;
+    case MERam:
+       if (Hours < 1 || Hours > 12)
+           return -1;
+       if (Hours == 12)
+           Hours = 0;
+       return (Hours * 60L + Minutes) * 60L + Seconds;
+    case MERpm:
+       if (Hours < 1 || Hours > 12)
+           return -1;
+       if (Hours == 12)
+           Hours = 0;
+       return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
+    default:
+       abort ();
+    }
+    /* NOTREACHED */
+}
+
+
+/* Year is either
+   * A negative number, which means to use its absolute value (why?)
+   * A number from 0 to 99, which means a year from 1900 to 1999, or
+   * The actual year (>=100).  */
+static time_t
+Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
+    time_t     Month;
+    time_t     Day;
+    time_t     Year;
+    time_t     Hours;
+    time_t     Minutes;
+    time_t     Seconds;
+    MERIDIAN   Meridian;
+    DSTMODE    DSTmode;
+{
+    static int DaysInMonth[12] = {
+       31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+    };
+    time_t     tod;
+    time_t     Julian;
+    int                i;
+
+    if (Year < 0)
+       Year = -Year;
+    if (Year < 69)
+       Year += 2000;
+    else if (Year < 100)
+       Year += 1900;
+    DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
+                   ? 29 : 28;
+    /* Checking for 2038 bogusly assumes that time_t is 32 bits.  But
+       I'm too lazy to try to check for time_t overflow in another way.  */
+    if (Year < EPOCH || Year > 2038
+     || Month < 1 || Month > 12
+     /* Lint fluff:  "conversion from long may lose accuracy" */
+     || Day < 1 || Day > DaysInMonth[(int)--Month])
+       return -1;
+
+    for (Julian = Day - 1, i = 0; i < Month; i++)
+       Julian += DaysInMonth[i];
+    for (i = EPOCH; i < Year; i++)
+       Julian += 365 + (i % 4 == 0);
+    Julian *= SECSPERDAY;
+    Julian += yyTimezone * 60L;
+    if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
+       return -1;
+    Julian += tod;
+    if (DSTmode == DSTon
+     || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
+       Julian -= 60 * 60;
+    return Julian;
+}
+
+
+static time_t
+DSTcorrect(Start, Future)
+    time_t     Start;
+    time_t     Future;
+{
+    time_t     StartDay;
+    time_t     FutureDay;
+
+    StartDay = (localtime(&Start)->tm_hour + 1) % 24;
+    FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
+    return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
+}
+
+
+static time_t
+RelativeDate(Start, DayOrdinal, DayNumber)
+    time_t     Start;
+    time_t     DayOrdinal;
+    time_t     DayNumber;
+{
+    struct tm  *tm;
+    time_t     now;
+
+    now = Start;
+    tm = localtime(&now);
+    now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
+    now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
+    return DSTcorrect(Start, now);
+}
+
+
+static time_t
+RelativeMonth(Start, RelMonth)
+    time_t     Start;
+    time_t     RelMonth;
+{
+    struct tm  *tm;
+    time_t     Month;
+    time_t     Year;
+
+    if (RelMonth == 0)
+       return 0;
+    tm = localtime(&Start);
+    Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;
+    Year = Month / 12;
+    Month = Month % 12 + 1;
+    return DSTcorrect(Start,
+           Convert(Month, (time_t)tm->tm_mday, Year,
+               (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
+               MER24, DSTmaybe));
+}
+
+
+static int
+LookupWord(buff)
+    char               *buff;
+{
+    register char      *p;
+    register char      *q;
+    register const TABLE       *tp;
+    int                        i;
+    int                        abbrev;
+
+    /* Make it lowercase. */
+    for (p = buff; *p; p++)
+       if (isupper(*p))
+           *p = tolower(*p);
+
+    if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
+       yylval.Meridian = MERam;
+       return tMERIDIAN;
+    }
+    if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
+       yylval.Meridian = MERpm;
+       return tMERIDIAN;
+    }
+
+    /* See if we have an abbreviation for a month. */
+    if (strlen(buff) == 3)
+       abbrev = 1;
+    else if (strlen(buff) == 4 && buff[3] == '.') {
+       abbrev = 1;
+       buff[3] = '\0';
+    }
+    else
+       abbrev = 0;
+
+    for (tp = MonthDayTable; tp->name; tp++) {
+       if (abbrev) {
+           if (strncmp(buff, tp->name, 3) == 0) {
+               yylval.Number = tp->value;
+               return tp->type;
+           }
+       }
+       else if (strcmp(buff, tp->name) == 0) {
+           yylval.Number = tp->value;
+           return tp->type;
+       }
+    }
+
+    for (tp = TimezoneTable; tp->name; tp++)
+       if (strcmp(buff, tp->name) == 0) {
+           yylval.Number = tp->value;
+           return tp->type;
+       }
+
+    if (strcmp(buff, "dst") == 0) 
+       return tDST;
+
+    for (tp = UnitsTable; tp->name; tp++)
+       if (strcmp(buff, tp->name) == 0) {
+           yylval.Number = tp->value;
+           return tp->type;
+       }
+
+    /* Strip off any plural and try the units table again. */
+    i = strlen(buff) - 1;
+    if (buff[i] == 's') {
+       buff[i] = '\0';
+       for (tp = UnitsTable; tp->name; tp++)
+           if (strcmp(buff, tp->name) == 0) {
+               yylval.Number = tp->value;
+               return tp->type;
+           }
+       buff[i] = 's';          /* Put back for "this" in OtherTable. */
+    }
+
+    for (tp = OtherTable; tp->name; tp++)
+       if (strcmp(buff, tp->name) == 0) {
+           yylval.Number = tp->value;
+           return tp->type;
+       }
+
+    /* Military timezones. */
+    if (buff[1] == '\0' && isalpha(*buff)) {
+       for (tp = MilitaryTable; tp->name; tp++)
+           if (strcmp(buff, tp->name) == 0) {
+               yylval.Number = tp->value;
+               return tp->type;
+           }
+    }
+
+    /* Drop out any periods and try the timezone table again. */
+    for (i = 0, p = q = buff; *q; q++)
+       if (*q != '.')
+           *p++ = *q;
+       else
+           i++;
+    *p = '\0';
+    if (i)
+       for (tp = TimezoneTable; tp->name; tp++)
+           if (strcmp(buff, tp->name) == 0) {
+               yylval.Number = tp->value;
+               return tp->type;
+           }
+
+    return tID;
+}
+
+
+static int
+yylex()
+{
+    register char      c;
+    register char      *p;
+    char               buff[20];
+    int                        Count;
+    int                        sign;
+
+    for ( ; ; ) {
+       while (isspace(*yyInput))
+           yyInput++;
+
+       if (isdigit(c = *yyInput) || c == '-' || c == '+') {
+           if (c == '-' || c == '+') {
+               sign = c == '-' ? -1 : 1;
+               if (!isdigit(*++yyInput))
+                   /* skip the '-' sign */
+                   continue;
+           }
+           else
+               sign = 0;
+           for (yylval.Number = 0; isdigit(c = *yyInput++); )
+               yylval.Number = 10 * yylval.Number + c - '0';
+           yyInput--;
+           if (sign < 0)
+               yylval.Number = -yylval.Number;
+           return sign ? tSNUMBER : tUNUMBER;
+       }
+       if (isalpha(c)) {
+           for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
+               if (p < &buff[sizeof buff - 1])
+                   *p++ = c;
+           *p = '\0';
+           yyInput--;
+           return LookupWord(buff);
+       }
+       if (c != '(')
+           return *yyInput++;
+       Count = 0;
+       do {
+           c = *yyInput++;
+           if (c == '\0')
+               return c;
+           if (c == '(')
+               Count++;
+           else if (c == ')')
+               Count--;
+       } while (Count > 0);
+    }
+}
+
+#define TM_YEAR_ORIGIN 1900
+
+/* Yield A - B, measured in seconds.  */
+static long
+difftm (a, b)
+     struct tm *a, *b;
+{
+  int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+  int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+  int days = (
+             /* difference in day of year */
+             a->tm_yday - b->tm_yday
+             /* + intervening leap days */
+             +  ((ay >> 2) - (by >> 2))
+             -  (ay/100 - by/100)
+             +  ((ay/100 >> 2) - (by/100 >> 2))
+             /* + difference in years * 365 */
+             +  (long)(ay-by) * 365
+             );
+  return (60*(60*(24*days + (a->tm_hour - b->tm_hour))
+             + (a->tm_min - b->tm_min))
+         + (a->tm_sec - b->tm_sec));
+}
+
+time_t
+get_date(p, now)
+    char               *p;
+    struct timeb       *now;
+{
+    struct tm          *tm, gmt;
+    struct timeb       ftz;
+    time_t             Start;
+    time_t             tod;
+    time_t nowtime;
+
+    yyInput = p;
+    if (now == NULL) {
+       struct tm *gmt_ptr;
+
+        now = &ftz;
+       (void)time (&nowtime);
+
+       gmt_ptr = gmtime (&nowtime);
+       if (gmt_ptr != NULL)
+       {
+           /* Make a copy, in case localtime modifies *tm (I think
+              that comment now applies to *gmt_ptr, but I am too
+              lazy to dig into how gmtime and locatime allocate the
+              structures they return pointers to).  */
+           gmt = *gmt_ptr;
+       }
+
+       if (! (tm = localtime (&nowtime)))
+           return -1;
+
+       if (gmt_ptr != NULL)
+           ftz.timezone = difftm (&gmt, tm) / 60;
+       else
+           /* We are on a system like VMS, where the system clock is
+              in local time and the system has no concept of timezones.
+              Hopefully we can fake this out (for the case in which the
+              user specifies no timezone) by just saying the timezone
+              is zero.  */
+           ftz.timezone = 0;
+
+       if(tm->tm_isdst)
+           ftz.timezone += 60;
+    }
+    else
+    {
+       nowtime = now->time;
+    }
+
+    tm = localtime(&nowtime);
+    yyYear = tm->tm_year + 1900;
+    yyMonth = tm->tm_mon + 1;
+    yyDay = tm->tm_mday;
+    yyTimezone = now->timezone;
+    yyDSTmode = DSTmaybe;
+    yyHour = 0;
+    yyMinutes = 0;
+    yySeconds = 0;
+    yyMeridian = MER24;
+    yyRelSeconds = 0;
+    yyRelMonth = 0;
+    yyHaveDate = 0;
+    yyHaveDay = 0;
+    yyHaveRel = 0;
+    yyHaveTime = 0;
+    yyHaveZone = 0;
+
+    if (yyparse()
+     || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
+       return -1;
+
+    if (yyHaveDate || yyHaveTime || yyHaveDay) {
+       Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
+                   yyMeridian, yyDSTmode);
+       if (Start < 0)
+           return -1;
+    }
+    else {
+       Start = nowtime;
+       if (!yyHaveRel)
+           Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
+    }
+
+    Start += yyRelSeconds;
+    Start += RelativeMonth(Start, yyRelMonth);
+
+    if (yyHaveDay && !yyHaveDate) {
+       tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
+       Start += tod;
+    }
+
+    /* Have to do *something* with a legitimate -1 so it's distinguishable
+     * from the error return value.  (Alternately could set errno on error.) */
+    return Start == -1 ? 0 : Start;
+}
+
+
+#if    defined(TEST)
+
+/* ARGSUSED */
+int
+main(ac, av)
+    int                ac;
+    char       *av[];
+{
+    char       buff[128];
+    time_t     d;
+
+    (void)printf("Enter date, or blank line to exit.\n\t> ");
+    (void)fflush(stdout);
+    while (gets(buff) && buff[0]) {
+       d = get_date(buff, (struct timeb *)NULL);
+       if (d == -1)
+           (void)printf("Bad format - couldn't convert.\n");
+       else
+           (void)printf("%s", ctime(&d));
+       (void)printf("\t> ");
+       (void)fflush(stdout);
+    }
+    exit(0);
+    /* NOTREACHED */
+}
+#endif /* defined(TEST) */
+#line 1031 "y.tab.c"
+/* allocate initial stack or double stack size, up to YYMAXDEPTH */
+int yyparse __P((void));
+static int yygrowstack __P((void));
+static int yygrowstack()
+{
+    int newsize, i;
+    short *newss;
+    YYSTYPE *newvs;
+
+    if ((newsize = yystacksize) == 0)
+        newsize = YYINITSTACKSIZE;
+    else if (newsize >= YYMAXDEPTH)
+        return -1;
+    else if ((newsize *= 2) > YYMAXDEPTH)
+        newsize = YYMAXDEPTH;
+    i = yyssp - yyss;
+    if ((newss = (short *)realloc(yyss, newsize * sizeof *newss)) == NULL)
+        return -1;
+    yyss = newss;
+    yyssp = newss + i;
+    if ((newvs = (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs)) == NULL)
+        return -1;
+    yyvs = newvs;
+    yyvsp = newvs + i;
+    yystacksize = newsize;
+    yysslim = yyss + newsize - 1;
+    return 0;
+}
+
+#define YYABORT goto yyabort
+#define YYREJECT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR goto yyerrlab
+int
+yyparse()
+{
+    int yym, yyn, yystate;
+#if YYDEBUG
+    char *yys;
+
+    if ((yys = getenv("YYDEBUG")) != NULL)
+    {
+        yyn = *yys;
+        if (yyn >= '0' && yyn <= '9')
+            yydebug = yyn - '0';
+    }
+#endif
+
+    yynerrs = 0;
+    yyerrflag = 0;
+    yychar = (-1);
+
+    if (yyss == NULL && yygrowstack()) goto yyoverflow;
+    yyssp = yyss;
+    yyvsp = yyvs;
+    *yyssp = yystate = 0;
+
+yyloop:
+    if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
+    if (yychar < 0)
+    {
+        if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+        if (yydebug)
+        {
+            yys = 0;
+            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+            if (!yys) yys = "illegal-symbol";
+            printf("%sdebug: state %d, reading %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+    }
+    if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: state %d, shifting to state %d\n",
+                    YYPREFIX, yystate, yytable[yyn]);
+#endif
+        if (yyssp >= yysslim && yygrowstack())
+        {
+            goto yyoverflow;
+        }
+        *++yyssp = yystate = yytable[yyn];
+        *++yyvsp = yylval;
+        yychar = (-1);
+        if (yyerrflag > 0)  --yyerrflag;
+        goto yyloop;
+    }
+    if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+    {
+        yyn = yytable[yyn];
+        goto yyreduce;
+    }
+    if (yyerrflag) goto yyinrecovery;
+    goto yynewerror;
+yynewerror:
+    yyerror("syntax error");
+    goto yyerrlab;
+yyerrlab:
+    ++yynerrs;
+yyinrecovery:
+    if (yyerrflag < 3)
+    {
+        yyerrflag = 3;
+        for (;;)
+        {
+            if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
+                    yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: state %d, error recovery shifting\
+ to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
+#endif
+                if (yyssp >= yysslim && yygrowstack())
+                {
+                    goto yyoverflow;
+                }
+                *++yyssp = yystate = yytable[yyn];
+                *++yyvsp = yylval;
+                goto yyloop;
+            }
+            else
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: error recovery discarding state %d\n",
+                            YYPREFIX, *yyssp);
+#endif
+                if (yyssp <= yyss) goto yyabort;
+                --yyssp;
+                --yyvsp;
+            }
+        }
+    }
+    else
+    {
+        if (yychar == 0) goto yyabort;
+#if YYDEBUG
+        if (yydebug)
+        {
+            yys = 0;
+            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+            if (!yys) yys = "illegal-symbol";
+            printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+        yychar = (-1);
+        goto yyloop;
+    }
+yyreduce:
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: state %d, reducing by rule %d (%s)\n",
+                YYPREFIX, yystate, yyn, yyrule[yyn]);
+#endif
+    yym = yylen[yyn];
+    yyval = yyvsp[1-yym];
+    switch (yyn)
+    {
+case 3:
+#line 168 "getdate.y"
+{
+           yyHaveTime++;
+       }
+break;
+case 4:
+#line 171 "getdate.y"
+{
+           yyHaveZone++;
+       }
+break;
+case 5:
+#line 174 "getdate.y"
+{
+           yyHaveDate++;
+       }
+break;
+case 6:
+#line 177 "getdate.y"
+{
+           yyHaveDay++;
+       }
+break;
+case 7:
+#line 180 "getdate.y"
+{
+           yyHaveRel++;
+       }
+break;
+case 9:
+#line 186 "getdate.y"
+{
+           yyHour = yyvsp[-1].Number;
+           yyMinutes = 0;
+           yySeconds = 0;
+           yyMeridian = yyvsp[0].Meridian;
+       }
+break;
+case 10:
+#line 192 "getdate.y"
+{
+           yyHour = yyvsp[-3].Number;
+           yyMinutes = yyvsp[-1].Number;
+           yySeconds = 0;
+           yyMeridian = yyvsp[0].Meridian;
+       }
+break;
+case 11:
+#line 198 "getdate.y"
+{
+           yyHour = yyvsp[-3].Number;
+           yyMinutes = yyvsp[-1].Number;
+           yyMeridian = MER24;
+           yyDSTmode = DSToff;
+           yyTimezone = - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60);
+       }
+break;
+case 12:
+#line 205 "getdate.y"
+{
+           yyHour = yyvsp[-5].Number;
+           yyMinutes = yyvsp[-3].Number;
+           yySeconds = yyvsp[-1].Number;
+           yyMeridian = yyvsp[0].Meridian;
+       }
+break;
+case 13:
+#line 211 "getdate.y"
+{
+           yyHour = yyvsp[-5].Number;
+           yyMinutes = yyvsp[-3].Number;
+           yySeconds = yyvsp[-1].Number;
+           yyMeridian = MER24;
+           yyDSTmode = DSToff;
+           yyTimezone = - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60);
+       }
+break;
+case 14:
+#line 221 "getdate.y"
+{
+           yyTimezone = yyvsp[0].Number;
+           yyDSTmode = DSToff;
+       }
+break;
+case 15:
+#line 225 "getdate.y"
+{
+           yyTimezone = yyvsp[0].Number;
+           yyDSTmode = DSTon;
+       }
+break;
+case 16:
+#line 230 "getdate.y"
+{
+           yyTimezone = yyvsp[-1].Number;
+           yyDSTmode = DSTon;
+       }
+break;
+case 17:
+#line 236 "getdate.y"
+{
+           yyDayOrdinal = 1;
+           yyDayNumber = yyvsp[0].Number;
+       }
+break;
+case 18:
+#line 240 "getdate.y"
+{
+           yyDayOrdinal = 1;
+           yyDayNumber = yyvsp[-1].Number;
+       }
+break;
+case 19:
+#line 244 "getdate.y"
+{
+           yyDayOrdinal = yyvsp[-1].Number;
+           yyDayNumber = yyvsp[0].Number;
+       }
+break;
+case 20:
+#line 250 "getdate.y"
+{
+           yyMonth = yyvsp[-2].Number;
+           yyDay = yyvsp[0].Number;
+       }
+break;
+case 21:
+#line 254 "getdate.y"
+{
+           if (yyvsp[-4].Number >= 100) {
+               yyYear = yyvsp[-4].Number;
+               yyMonth = yyvsp[-2].Number;
+               yyDay = yyvsp[0].Number;
+           } else {
+               yyMonth = yyvsp[-4].Number;
+               yyDay = yyvsp[-2].Number;
+               yyYear = yyvsp[0].Number;
+           }
+       }
+break;
+case 22:
+#line 265 "getdate.y"
+{
+           /* ISO 8601 format.  yyyy-mm-dd.  */
+           yyYear = yyvsp[-2].Number;
+           yyMonth = -yyvsp[-1].Number;
+           yyDay = -yyvsp[0].Number;
+       }
+break;
+case 23:
+#line 271 "getdate.y"
+{
+           /* e.g. 17-JUN-1992.  */
+           yyDay = yyvsp[-2].Number;
+           yyMonth = yyvsp[-1].Number;
+           yyYear = -yyvsp[0].Number;
+       }
+break;
+case 24:
+#line 277 "getdate.y"
+{
+           yyMonth = yyvsp[-1].Number;
+           yyDay = yyvsp[0].Number;
+       }
+break;
+case 25:
+#line 281 "getdate.y"
+{
+           yyMonth = yyvsp[-3].Number;
+           yyDay = yyvsp[-2].Number;
+           yyYear = yyvsp[0].Number;
+       }
+break;
+case 26:
+#line 286 "getdate.y"
+{
+           yyMonth = yyvsp[0].Number;
+           yyDay = yyvsp[-1].Number;
+       }
+break;
+case 27:
+#line 290 "getdate.y"
+{
+           yyMonth = yyvsp[-1].Number;
+           yyDay = yyvsp[-2].Number;
+           yyYear = yyvsp[0].Number;
+       }
+break;
+case 28:
+#line 297 "getdate.y"
+{
+           yyRelSeconds = -yyRelSeconds;
+           yyRelMonth = -yyRelMonth;
+       }
+break;
+case 30:
+#line 304 "getdate.y"
+{
+           yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number * 60L;
+       }
+break;
+case 31:
+#line 307 "getdate.y"
+{
+           yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number * 60L;
+       }
+break;
+case 32:
+#line 310 "getdate.y"
+{
+           yyRelSeconds += yyvsp[0].Number * 60L;
+       }
+break;
+case 33:
+#line 313 "getdate.y"
+{
+           yyRelSeconds += yyvsp[-1].Number;
+       }
+break;
+case 34:
+#line 316 "getdate.y"
+{
+           yyRelSeconds += yyvsp[-1].Number;
+       }
+break;
+case 35:
+#line 319 "getdate.y"
+{
+           yyRelSeconds++;
+       }
+break;
+case 36:
+#line 322 "getdate.y"
+{
+           yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
+       }
+break;
+case 37:
+#line 325 "getdate.y"
+{
+           yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
+       }
+break;
+case 38:
+#line 328 "getdate.y"
+{
+           yyRelMonth += yyvsp[0].Number;
+       }
+break;
+case 39:
+#line 333 "getdate.y"
+{
+           if (yyHaveTime && yyHaveDate && !yyHaveRel)
+               yyYear = yyvsp[0].Number;
+           else {
+               if(yyvsp[0].Number>10000) {
+                   yyHaveDate++;
+                   yyDay= (yyvsp[0].Number)%100;
+                   yyMonth= (yyvsp[0].Number/100)%100;
+                   yyYear = yyvsp[0].Number/10000;
+               }
+               else {
+                   yyHaveTime++;
+                   if (yyvsp[0].Number < 100) {
+                       yyHour = yyvsp[0].Number;
+                       yyMinutes = 0;
+                   }
+                   else {
+                       yyHour = yyvsp[0].Number / 100;
+                       yyMinutes = yyvsp[0].Number % 100;
+                   }
+                   yySeconds = 0;
+                   yyMeridian = MER24;
+               }
+           }
+       }
+break;
+case 40:
+#line 360 "getdate.y"
+{
+           yyval.Meridian = MER24;
+       }
+break;
+case 41:
+#line 363 "getdate.y"
+{
+           yyval.Meridian = yyvsp[0].Meridian;
+       }
+break;
+#line 1487 "y.tab.c"
+    }
+    yyssp -= yym;
+    yystate = *yyssp;
+    yyvsp -= yym;
+    yym = yylhs[yyn];
+    if (yystate == 0 && yym == 0)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: after reduction, shifting from state 0 to\
+ state %d\n", YYPREFIX, YYFINAL);
+#endif
+        yystate = YYFINAL;
+        *++yyssp = YYFINAL;
+        *++yyvsp = yyval;
+        if (yychar < 0)
+        {
+            if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+            if (yydebug)
+            {
+                yys = 0;
+                if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+                if (!yys) yys = "illegal-symbol";
+                printf("%sdebug: state %d, reading %d (%s)\n",
+                        YYPREFIX, YYFINAL, yychar, yys);
+            }
+#endif
+        }
+        if (yychar == 0) goto yyaccept;
+        goto yyloop;
+    }
+    if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
+        yystate = yytable[yyn];
+    else
+        yystate = yydgoto[yym];
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: after reduction, shifting from state %d \
+to state %d\n", YYPREFIX, *yyssp, yystate);
+#endif
+    if (yyssp >= yysslim && yygrowstack())
+    {
+        goto yyoverflow;
+    }
+    *++yyssp = yystate;
+    *++yyvsp = yyval;
+    goto yyloop;
+yyoverflow:
+    yyerror("yacc stack overflow");
+yyabort:
+    return (1);
+yyaccept:
+    return (0);
+}
index ca485b3b97326a05890985b7b0846b6ea227e062..7a977ea6052e134818a529c8d9066bbadef996d2 100644 (file)
@@ -8,6 +8,7 @@ __RCSID("$NetBSD: getopt.c,v 1.5 1998/02/03 03:44:22 perry Exp $");
 #include <errno.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <stdlib.h>
 
 int    main __P((int, char **));
 
diff --git a/id/id.c b/id/id.c
index b8732a0776be31d74aa3e2343e04ad5c5aa297c9..9ef13b475b2cf54a4e8d60e47065efd8cb5a1d0a 100644 (file)
--- a/id/id.c
+++ b/id/id.c
@@ -191,9 +191,9 @@ pretty(pw)
                
                if ((eid = geteuid()) != rid) {
                        if ((pw = getpwuid(eid)) != NULL)
-                               (void)printf("euid\t%s", pw->pw_name);
+                               (void)printf("euid\t%s\n", pw->pw_name);
                        else
-                               (void)printf("euid\t%u", eid);
+                               (void)printf("euid\t%u\n", eid);
                }
                if ((rid = getgid()) != (eid = getegid())) {
                        if ((gr = getgrgid(rid)) != NULL)
index 5ad2a47c0b76ba886e95b53112eb1f21c3216f3d..8e8891db7981c1845585b2eca153fc407691d4ce 100644 (file)
@@ -1,5 +1,3 @@
-.\"    $NetBSD: kill.1,v 1.10 1997/10/20 08:52:10 enami Exp $
-.\"
 .\" Copyright (c) 1980, 1990, 1993
 .\"    The Regents of the University of California.  All rights reserved.
 .\"
@@ -35,6 +33,7 @@
 .\" SUCH DAMAGE.
 .\"
 .\"    @(#)kill.1      8.2 (Berkeley) 4/28/95
+.\" $FreeBSD: src/bin/kill/kill.1,v 1.11.2.1 2000/12/08 13:34:35 ru Exp $
 .\"
 .Dd April 28, 1995
 .Dt KILL 1
 .Op Fl s Ar signal_name
 .Ar pid
 \&...
-.Nm ""
+.Nm
 .Fl l
 .Op Ar exit_status
-.Nm ""
+.Nm
 .Fl signal_name
 .Ar pid
 \&...
-.Nm ""
+.Nm
 .Fl signal_number
 .Ar pid
 \&...
 .Sh DESCRIPTION
-The kill utility sends a signal to the processes specified
-by the pid operand(s).
+The
+.Nm
+utility sends a signal to the processes specified by the pid operand(s).
 .Pp
 Only the super-user may send signals to other users' processes.
 .Pp
@@ -110,18 +110,16 @@ ALRM (alarm clock)
 TERM (software termination signal)
 .El
 .Pp
+Some shells may provide a builtin
 .Nm
-is a built-in to
-.Xr csh  1  ;
-it allows job specifiers of the form ``%...'' as arguments
-so process id's are not as often used as
-.Nm
-arguments.
-See
-.Xr csh  1
-for details.
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
 .Sh SEE ALSO
+.Xr builtin 1 ,
 .Xr csh 1 ,
+.Xr killall 1 ,
 .Xr ps 1 ,
 .Xr kill 2 ,
 .Xr sigaction 2
index f78eba32fbb0d1f46a91046c25b845d23098bc75..f2c56b7af37e928f1b20cd854c990530575d627b 100644 (file)
@@ -1,5 +1,3 @@
-/*     $NetBSD: kill.c,v 1.16 1998/07/28 11:41:49 mycroft Exp $        */
-
 /*
  * Copyright (c) 1988, 1993, 1994
  *     The Regents of the University of California.  All rights reserved.
  * SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
 #ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\n\
-       The Regents of the University of California.  All rights reserved.\n");
+static char const copyright[] =
+"@(#) Copyright (c) 1988, 1993, 1994\n\
+       The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
 #if 0
 static char sccsid[] = "@(#)kill.c     8.4 (Berkeley) 4/28/95";
-#else
-__RCSID("$NetBSD: kill.c,v 1.16 1998/07/28 11:41:49 mycroft Exp $");
 #endif
+static const char rcsid[] =
+  "$FreeBSD: src/bin/kill/kill.c,v 1.11.2.1 2001/08/01 02:42:56 obrien Exp $";
 #endif /* not lint */
 
 #include <ctype.h>
@@ -55,11 +53,11 @@ __RCSID("$NetBSD: kill.c,v 1.16 1998/07/28 11:41:49 mycroft Exp $");
 #include <stdlib.h>
 #include <string.h>
 
+int main __P((int, char *[]));
 void nosig __P((char *));
 void printsignals __P((FILE *));
 int signame_to_signum __P((char *));
 void usage __P((void));
-int main __P((int, char *[]));
 
 int
 main(argc, argv)
@@ -83,13 +81,13 @@ main(argc, argv)
                        if (!isdigit(**argv))
                                usage();
                        numsig = strtol(*argv, &ep, 10);
-                       if (*ep)
+                       if (!**argv || *ep)
                                errx(1, "illegal signal number: %s", *argv);
                        if (numsig >= 128)
                                numsig -= 128;
                        if (numsig <= 0 || numsig >= NSIG)
                                nosig(*argv);
-                       (void)printf("%s\n", sys_signame[numsig]);
+                       printf("%s\n", sys_signame[numsig]);
                        exit(0);
                }
                printsignals(stdout);
@@ -115,7 +113,7 @@ main(argc, argv)
                                nosig(*argv);
                } else if (isdigit(**argv)) {
                        numsig = strtol(*argv, &ep, 10);
-                       if (!*argv || *ep)
+                       if (!**argv || *ep)
                                errx(1, "illegal signal number: %s", *argv);
                        if (numsig < 0 || numsig >= NSIG)
                                nosig(*argv);
@@ -139,7 +137,6 @@ main(argc, argv)
        }
 
        exit(errors);
-       /* NOTREACHED */
 }
 
 int
@@ -148,7 +145,7 @@ signame_to_signum(sig)
 {
        int n;
 
-       if (!strncasecmp(sig, "sig", 3))
+       if (!strncasecmp(sig, "sig", (size_t)3))
                sig += 3;
        for (n = 1; n < NSIG; n++) {
                if (!strcasecmp(sys_signame[n], sig))
@@ -165,7 +162,6 @@ nosig(name)
        warnx("unknown signal %s; valid signals:", name);
        printsignals(stderr);
        exit(1);
-       /* NOTREACHED */
 }
 
 void
@@ -187,10 +183,10 @@ void
 usage()
 {
 
-       (void)fprintf(stderr, "usage: kill [-s signal_name] pid ...\n");
-       (void)fprintf(stderr, "       kill -l [exit_status]\n");
-       (void)fprintf(stderr, "       kill -signal_name pid ...\n");
-       (void)fprintf(stderr, "       kill -signal_number pid ...\n");
+       (void)fprintf(stderr, "%s\n%s\n%s\n%s\n",
+               "usage: kill [-s signal_name] pid ...",
+               "       kill -l [exit_status]",
+               "       kill -signal_name pid ...",
+               "       kill -signal_number pid ...");
        exit(1);
-       /* NOTREACHED */
 }
diff --git a/killall/Makefile b/killall/Makefile
new file mode 100644 (file)
index 0000000..49907b5
--- /dev/null
@@ -0,0 +1,48 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = killall
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+CFILES = killall.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble killall.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /usr/bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/killall/Makefile.postamble b/killall/Makefile.postamble
new file mode 100644 (file)
index 0000000..013b558
--- /dev/null
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/killall/Makefile.preamble b/killall/Makefile.preamble
new file mode 100644 (file)
index 0000000..9e10e90
--- /dev/null
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/killall/PB.project b/killall/PB.project
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/killall/killall.1 b/killall/killall.1
new file mode 100644 (file)
index 0000000..69dbc05
--- /dev/null
@@ -0,0 +1,152 @@
+.\" Copyright (C) 1995 by Joerg Wunsch, Dresden
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
+.\"
+.\" $FreeBSD: src/usr.bin/killall/killall.1,v 1.22 2001/11/30 00:30:28 bsd Exp $
+.\"
+.Dd June 25, 1995
+.Os
+.Dt KILLALL 1
+.Sh NAME
+.Nm killall
+.Nd kill processes by name
+.Sh SYNOPSIS
+.Nm
+.Op Fl d | v
+.Op Fl h | ?\&
+.Op Fl help
+.Op Fl l
+.Op Fl m
+.Op Fl s
+.Op Fl u Ar user
+.Op Fl t Ar tty
+.Op Fl c Ar procname
+.Op Fl SIGNAL
+.Op Ar procname ...
+.Sh DESCRIPTION
+.Nm Killall
+kills processes selected by name, as opposed to the selection by pid
+as done by
+.Xr kill 1 .
+By default, it will send a
+.Dv TERM
+signal to all processes with a real UID identical to the
+caller of
+.Nm
+that match the name
+.Ar procname .
+The super-user is allowed to kill any process.
+.Pp
+The options are as follows:
+.Bl -tag -width 10n -offset indent
+.It Fl d | v
+Be more verbose about what will be done.  For a single
+.Fl d
+option, a list of the processes that will be sent the signal will be
+printed, or a message indicating that no matching processes have been
+found.
+.It Fl h | ?\&
+.It Fl help
+Give a help on the command usage and exit.
+.It Fl l
+List the names of the available signals and exit, like in
+.Xr kill 1 .
+.It Fl m
+Match the argument
+.Ar procname
+as a (case insensitive) regular expression against the names
+of processes found.
+CAUTION!  This is dangerous, a single dot will match any process
+running under the real UID of the caller.
+.It Fl s
+Show only what would be done, but do not send any signal.
+.It Fl SIGNAL
+Send a different signal instead of the default
+.Dv TERM .
+The signal may be specified either as a name
+(with or without a leading
+.Dv SIG ) ,
+or numerically.
+.It Fl u Ar user
+Limit potentially matching processes to those belonging to
+the specified
+.Ar user .
+.It Fl t Ar tty
+Limit potentially matching processes to those running on
+the specified
+.Ar tty .
+.It Fl c Ar procname
+When used with the
+.Fl u
+or
+.Fl t
+flags, limit potentially matching processes to those matching
+the specified
+.Ar progname .
+.El
+.Sh ALL PROCESSES
+Sending a signal to all processes with uid
+.Nm XYZ
+is already supported by
+.Xr kill 1 .
+So use
+.Xr kill 1
+for this job (e.g. $ kill -TERM -1 or
+as root $ echo kill -TERM -1 | su -m <user>)
+.Sh DIAGNOSTICS
+The
+.Nm
+command will respond with a short usage message and exit with a status
+of 2 in case of a command error.  A status of 1 will be returned if
+either no matching process has been found or not all processes have
+been signalled successfully.  Otherwise, a status of 0 will be
+returned.
+.Pp
+Diagnostic messages will only be printed if requested by
+.Fl d
+options.
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr sysctl 3
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Fx 2.1 .
+It has been modeled after the
+.Nm
+command as available on other platforms.
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+program was originally written in Perl and was contributed by
+.An Wolfram Schneider ,
+this manual page has been written by
+.An J\(:org Wunsch .
+The current version of
+.Nm
+was rewritten in C by
+.An Peter Wemm
+using
+.Xr sysctl 3 .
diff --git a/killall/killall.c b/killall/killall.c
new file mode 100644 (file)
index 0000000..f31d084
--- /dev/null
@@ -0,0 +1,375 @@
+/*-
+ * Copyright (c) 2000 Peter Wemm <peter@FreeBSD.org>
+ * Copyright (c) 2000 Paul Saab <ps@FreeBSD.org>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD: src/usr.bin/killall/killall.c,v 1.15 2001/10/10 17:48:44 bde Exp $
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/user.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pwd.h>
+#include <signal.h>
+#include <regex.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+
+static char    *prog;
+
+static void 
+usage(void)
+{
+
+       fprintf(stderr, "usage: %s [-l] [-v] [-m] [-sig] [-u user] [-t tty] [-c cmd] [cmd]...\n", prog);
+       fprintf(stderr, "At least one option or argument to specify processes must be given.\n");
+       exit(1);
+}
+
+static char *
+upper(const char *str)
+{
+       static char buf[80];
+       char *s;
+
+       strncpy(buf, str, sizeof(buf));
+       buf[sizeof(buf) - 1] = '\0';
+       for (s = buf; *s; s++)
+               *s = toupper(*s);
+       return buf;
+}
+
+
+static void
+printsig(FILE *fp)
+{
+       const char      *const * p;
+       int             cnt;
+       int             offset = 0;
+
+       for (cnt = NSIG, p = sys_signame + 1; --cnt; ++p) {
+               offset += fprintf(fp, "%s ", upper(*p));
+               if (offset >= 75 && cnt > 1) {
+                       offset = 0;
+                       fprintf(fp, "\n");
+               }
+       }
+       fprintf(fp, "\n");
+}
+
+static void
+nosig(char *name)
+{
+
+       warnx("unknown signal %s; valid signals:", name);
+       printsig(stderr);
+       exit(1);
+}
+
+int
+main(int ac, char **av)
+{
+       struct kinfo_proc *procs = NULL, *newprocs;
+       struct stat     sb;
+       struct passwd   *pw;
+       regex_t         rgx;
+       regmatch_t      pmatch;
+       int             i, j;
+       char            buf[256];
+       char            *user = NULL;
+       char            *tty = NULL;
+       char            *cmd = NULL;
+       int             vflag = 0;
+       int             sflag = 0;
+       int             dflag = 0;
+       int             mflag = 0;
+       uid_t           uid = 0;
+       dev_t           tdev = 0;
+       char            thiscmd[MAXCOMLEN + 1];
+       pid_t           thispid;
+       uid_t           thisuid;
+       dev_t           thistdev;
+       int             sig = SIGTERM;
+       const char *const *p;
+       char            *ep;
+       int             errors = 0;
+       int             mib[4];
+       size_t          miblen;
+       int             st, nprocs;
+       size_t          size;
+       int             matched;
+       int             killed = 0;
+
+       prog = av[0];
+       av++;
+       ac--;
+
+       while (ac > 0) {
+               if (strcmp(*av, "-l") == 0) {
+                       printsig(stdout);
+                       exit(0);
+               }
+               if (strcmp(*av, "-help") == 0)
+                       usage();
+               if (**av == '-') {
+                       ++*av;
+                       switch (**av) {
+                       case 'u':
+                               ++*av;
+                               if (**av == '\0')
+                                       ++av;
+                               --ac;
+                               user = *av;
+                               break;
+                       case 't':
+                               ++*av;
+                               if (**av == '\0')
+                                       ++av;
+                               --ac;
+                               tty = *av;
+                               break;
+                       case 'c':
+                               ++*av;
+                               if (**av == '\0')
+                                       ++av;
+                               --ac;
+                               cmd = *av;
+                               break;
+                       case 'v':
+                               vflag++;
+                               break;
+                       case 's':
+                               sflag++;
+                               break;
+                       case 'd':
+                               dflag++;
+                               break;
+                       case 'm':
+                               mflag++;
+                               break;
+                       default:
+                               if (isalpha(**av)) {
+                                       if (strncasecmp(*av, "sig", 3) == 0)
+                                               *av += 3;
+                                       for (sig = NSIG, p = sys_signame + 1;
+                                            --sig; ++p)
+                                               if (strcasecmp(*p, *av) == 0) {
+                                                       sig = p - sys_signame;
+                                                       break;
+                                               }
+                                       if (!sig)
+                                               nosig(*av);
+                               } else if (isdigit(**av)) {
+                                       sig = strtol(*av, &ep, 10);
+                                       if (!*av || *ep)
+                                               errx(1, "illegal signal number: %s", *av);
+                                       if (sig < 0 || sig > NSIG)
+                                               nosig(*av);
+                               } else
+                                       nosig(*av);
+                       }
+                       ++av;
+                       --ac;
+               } else {
+                       break;
+               }
+       }
+
+       if (user == NULL && tty == NULL && cmd == NULL && ac == 0)
+               usage();
+
+       if (tty) {
+               if (strncmp(tty, "/dev/", 5) == 0)
+                       snprintf(buf, sizeof(buf), "%s", tty);
+               else if (strncmp(tty, "tty", 3) == 0)
+                       snprintf(buf, sizeof(buf), "/dev/%s", tty);
+               else
+                       snprintf(buf, sizeof(buf), "/dev/tty%s", tty);
+               if (stat(buf, &sb) < 0)
+                       err(1, "stat(%s)", buf);
+               if (!S_ISCHR(sb.st_mode))
+                       errx(1, "%s: not a character device", buf);
+               tdev = sb.st_rdev;
+               if (dflag)
+                       printf("ttydev:0x%x\n", tdev);
+       }
+       if (user) {
+               uid = strtol(user, &ep, 10);
+               if ((ep - user) < strlen(user)) {
+                       pw = getpwnam(user);
+                       if (pw == NULL)
+                               errx(1, "user %s does not exist", user);
+                       uid = pw->pw_uid;
+                       if (dflag)
+                               printf("uid:%d\n", uid);
+               }
+       } else {
+               uid = getuid();
+               if (uid != 0) {
+                       pw = getpwuid(uid);
+                       if (pw)
+                               user = pw->pw_name;
+                       if (dflag)
+                               printf("uid:%d\n", uid);
+               }
+       }
+       size = 0;
+       mib[0] = CTL_KERN;
+       mib[1] = KERN_PROC;
+       mib[2] = KERN_PROC_ALL;
+       mib[3] = 0;
+       miblen = 3;
+
+       if (user && mib[2] == KERN_PROC_ALL) {
+               mib[2] = KERN_PROC_RUID;
+               mib[3] = uid;
+               miblen = 4;
+       }
+       if (tty && mib[2] == KERN_PROC_ALL) {
+               mib[2] = KERN_PROC_TTY;
+               mib[3] = tdev;
+               miblen = 4;
+       }
+
+       st = sysctl(mib, miblen, NULL, &size, NULL, 0);
+       do {
+               size += size / 10;
+               newprocs = realloc(procs, size);
+               if (newprocs == 0) {
+                       if (procs)
+                               free(procs);
+                       errx(1, "could not reallocate memory");
+               }
+               procs = newprocs;
+               st = sysctl(mib, miblen, procs, &size, NULL, 0);
+       } while (st == -1 && errno == ENOMEM);
+       if (st == -1)
+               err(1, "could not sysctl(KERN_PROC)");
+       if (size % sizeof(struct kinfo_proc) != 0) {
+               fprintf(stderr, "proc size mismatch (%d total, %d chunks)\n",
+                       size, sizeof(struct kinfo_proc));
+               fprintf(stderr, "userland out of sync with kernel, recompile libkvm etc\n");
+               exit(1);
+       }
+       nprocs = size / sizeof(struct kinfo_proc);
+       if (dflag)
+               printf("nprocs %d\n", nprocs);
+
+       for (i = 0; i < nprocs; i++) {
+               thispid = procs[i].kp_proc.p_pid;
+               strncpy(thiscmd, procs[i].kp_proc.p_comm, MAXCOMLEN);
+               thiscmd[MAXCOMLEN] = '\0';
+               thistdev = procs[i].kp_eproc.e_tdev;
+               thisuid = procs[i].kp_eproc.e_pcred.p_ruid;     /* real uid */
+
+               matched = 1;
+               if (user) {
+                       if (thisuid != uid)
+                               matched = 0;
+               }
+               if (tty) {
+                       if (thistdev != tdev)
+                               matched = 0;
+               }
+               if (cmd) {
+                       if (mflag) {
+                               if (regcomp(&rgx, cmd,
+                                   REG_EXTENDED|REG_NOSUB) != 0) {
+                                       mflag = 0;
+                                       warnx("%s: illegal regexp", cmd);
+                               }
+                       }
+                       if (mflag) {
+                               pmatch.rm_so = 0;
+                               pmatch.rm_eo = strlen(thiscmd);
+                               if (regexec(&rgx, thiscmd, 0, &pmatch,
+                                   REG_STARTEND) != 0)
+                                       matched = 0;
+                               regfree(&rgx);
+                       } else {
+                               if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0)
+                                       matched = 0;
+                       }
+               }
+               if (matched == 0)
+                       continue;
+               if (ac > 0)
+                       matched = 0;
+               for (j = 0; j < ac; j++) {
+                       if (mflag) {
+                               if (regcomp(&rgx, av[j],
+                                   REG_EXTENDED|REG_NOSUB) != 0) {
+                                       mflag = 0;
+                                       warnx("%s: illegal regexp", av[j]);
+                               }
+                       }
+                       if (mflag) {
+                               pmatch.rm_so = 0;
+                               pmatch.rm_eo = strlen(thiscmd);
+                               if (regexec(&rgx, thiscmd, 0, &pmatch,
+                                   REG_STARTEND) == 0)
+                                       matched = 1;
+                               regfree(&rgx);
+                       } else {
+                               if (strcmp(thiscmd, av[j]) == 0)
+                                       matched = 1;
+                       }
+                       if (matched)
+                               break;
+               }
+               if (matched == 0)
+                       continue;
+               if (dflag)
+                       printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
+                           thiscmd, thispid, thistdev, thisuid);
+
+               if (vflag || sflag)
+                       printf("kill -%s %d\n", upper(sys_signame[sig]),
+                           thispid);
+
+               killed++;
+               if (!dflag && !sflag) {
+                       if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
+                               warn("kill -%s %d", upper(sys_signame[sig]),
+                                   thispid);
+                               errors = 1;
+                       }
+               }
+       }
+       if (killed == 0) {
+               fprintf(stderr, "No matching processes %swere found\n",
+                   getuid() != 0 ? "belonging to you " : "");
+               errors = 1;
+       }
+       exit(errors);
+}
index a780f055c6aba44d0ed024e07166e5718e1b4c26..67e3567100abb8c6a5b89069b5dabb07539a016d 100644 (file)
@@ -82,6 +82,7 @@ __RCSID("$NetBSD: locate.c,v 1.8 1997/10/19 04:11:56 lukem Exp $");
 #include <unistd.h>
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
 
 #include "locate.h"
 #include "pathnames.h"
index d98f90217a01e34e39bf4d5abe01e1f811686f33..88f977ef0a80b389eac6b509396e1190c9d8cd77 100644 (file)
@@ -60,7 +60,7 @@ set errs = $TMPDIR/locate.errs.$$
 
 # search locally or everything
 # find ${SRCHPATHS} -print | \
-find ${SRCHPATHS} \( ! -fstype local -o -fstype fdesc -o -fstype kernfs \) -a \
+find ${SRCHPATHS} \( ! -fstype local -o -fstype fdesc -o -fstype devfs \) -a \
                -prune -o -print | \
        tr '/' '\001' | \
        (sort -T "$TMPDIR" -f; echo $status > $errs) | tr '\001' '/' > $filelist
diff --git a/mktemp/Makefile b/mktemp/Makefile
new file mode 100644 (file)
index 0000000..639ea42
--- /dev/null
@@ -0,0 +1,50 @@
+#
+# Generated by the NeXT Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = mktemp
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+HFILES = 
+
+CFILES = mktemp.c
+
+OTHERSRCS = Makefile Makefile.preamble Makefile.postamble mktemp.1
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /usr/bin
+LIBS = 
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
diff --git a/mktemp/Makefile.postamble b/mktemp/Makefile.postamble
new file mode 100644 (file)
index 0000000..013b558
--- /dev/null
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
diff --git a/mktemp/Makefile.preamble b/mktemp/Makefile.preamble
new file mode 100644 (file)
index 0000000..9e10e90
--- /dev/null
@@ -0,0 +1 @@
+include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
diff --git a/mktemp/PB.project b/mktemp/PB.project
new file mode 100644 (file)
index 0000000..7a07f46
--- /dev/null
@@ -0,0 +1,27 @@
+{
+    DYNAMIC_CODE_GEN = YES; 
+    FILESTABLE = {
+        FRAMEWORKS = (); 
+        H_FILES = (); 
+        OTHER_LINKED = (mktemp.c); 
+        OTHER_SOURCES = (Makefile, Makefile.preamble, Makefile.postamble, mktemp.1); 
+        SUBPROJECTS = (); 
+    }; 
+    LANGUAGE = English; 
+    LOCALIZABLE_FILES = {}; 
+    MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; 
+    NEXTSTEP_BUILDDIR = "/tmp/$(NAME)/Build"; 
+    NEXTSTEP_BUILDTOOL = /bin/gnumake; 
+    NEXTSTEP_INSTALLDIR = /usr/bin; 
+    NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; 
+    NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; 
+    PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; 
+    PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; 
+    PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; 
+    PROJECTNAME = mktemp; 
+    PROJECTTYPE = Tool; 
+    PROJECTVERSION = 2.8; 
+    WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; 
+    WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; 
+    WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; 
+}
diff --git a/mktemp/mktemp.1 b/mktemp/mktemp.1
new file mode 100644 (file)
index 0000000..05a2765
--- /dev/null
@@ -0,0 +1,195 @@
+.\" Copyright (c) 1989, 1991, 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.
+.\"
+.\" From: $OpenBSD: mktemp.1,v 1.8 1998/03/19 06:13:37 millert Exp $
+.\" $FreeBSD: src/usr.bin/mktemp/mktemp.1,v 1.7.2.6 2001/07/22 12:40:27 dd Exp $
+.\"
+.Dd November 20, 1996
+.Dt MKTEMP 1
+.Os
+.Sh NAME
+.Nm mktemp
+.Nd make temporary file name (unique)
+.Sh SYNOPSIS
+.Nm
+.Op Fl d
+.Op Fl q
+.Op Fl t Ar prefix
+.Op Fl u
+.Ar template ...
+.Nm
+.Op Fl d
+.Op Fl q
+.Op Fl u
+.Fl t Ar prefix
+.Sh DESCRIPTION
+The
+.Nm
+utility takes each of the given file name templates and overwrites a
+portion of it to create a file name.  This file name is unique
+and suitable for use by the application.  The template may be
+any file name with some number of
+.Ql X Ns s
+appended
+to it, for example
+.Pa /tmp/temp.XXXX .
+The trailing
+.Ql X Ns s
+are replaced with the current process number and/or a
+unique letter combination.
+The number of unique file names
+.Nm
+can return depends on the number of
+.Ql X Ns s
+provided; six
+.Ql X Ns s
+will
+result in
+.Nm
+testing roughly 26 ** 6 combinations.
+.Pp
+If
+.Nm
+can successfully generate a unique file name, the file
+is created with mode 0600 (unless the
+.Fl u
+flag is given) and the filename is printed
+to standard output.
+.Pp
+If the
+.Fl t Ar prefix
+option is given,
+.Nm
+will generate an template string based on the
+.Ar prefix
+and the
+.Ev TMPDIR
+environment variable if set.
+The default location if
+.Ev TMPDIR
+is not set is
+.Pa /tmp .
+Care should
+be taken to ensure that it is appropriate to use an environment variable
+potentially supplied by the user.
+.Pp
+Any number of temporary files may be created in a single invocation,
+including one based on the internal template resulting from the
+.Fl t
+flag.
+.Pp
+.Nm Mktemp
+is provided to allow shell scripts to safely use temporary files.
+Traditionally, many shell scripts take the name of the program with
+the pid as a suffix and use that as a temporary file name.  This
+kind of naming scheme is predictable and the race condition it creates
+is easy for an attacker to win.  A safer, though still inferior, approach
+is to make a temporary directory using the same naming scheme.  While
+this does allow one to guarantee that a temporary file will not be
+subverted, it still allows a simple denial of service attack.  For these
+reasons it is suggested that
+.Nm
+be used instead.
+.Sh OPTIONS
+The available options are as follows:
+.Bl -tag -width indent
+.It Fl d
+Make a directory instead of a file.
+.It Fl q
+Fail silently if an error occurs.  This is useful if
+a script does not want error output to go to standard error.
+.It Fl t Ar prefix
+Generate a template (using the supplied
+.Ar prefix
+and
+.Ev TMPDIR
+if set) to create a filename template.
+.It Fl u
+Operate in
+.Dq unsafe
+mode.  The temp file will be unlinked before
+.Nm
+exits.  This is slightly better than
+.Xr mktemp 3
+but still introduces a race condition.  Use of this
+option is not encouraged.
+.El
+.Sh DIAGNOSTICS
+The
+.Nm
+utility
+exits 0 on success, and 1 if an error occurs.
+.Sh EXAMPLES
+The following
+.Xr sh 1
+fragment illustrates a simple use of
+.Nm
+where the script should quit if it cannot get a safe
+temporary file.
+.Bd -literal -offset indent
+tempfoo=`basename $0`
+TMPFILE=`mktemp /tmp/${tempfoo}.XXXXXX` || exit 1
+echo "program output" >> $TMPFILE
+.Ed
+.Pp
+To allow the use of $TMPDIR:
+.Bd -literal -offset indent
+tempfoo=`basename $0`
+TMPFILE=`mktemp -t ${tempfoo}` || exit 1
+echo "program output" >> $TMPFILE
+.Ed
+.Pp
+In this case, we want the script to catch the error itself.
+.Bd -literal -offset indent
+tempfoo=`basename $0`
+TMPFILE=`mktemp -q /tmp/${tempfoo}.XXXXXX`
+if [ $? -ne 0 ]; then
+       echo "$0: Can't create temp file, exiting..."
+       exit 1
+fi
+.Ed
+.Sh SEE ALSO
+.Xr mkdtemp 3 ,
+.Xr mkstemp 3 ,
+.Xr mktemp 3 ,
+.Xr environ 7
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.Ox 2.1 .
+This implementation was written independently based on the
+.Ox
+man page, and
+first appeared in
+.Fx 2.2.7 .
+This man page is taken from
+.Ox
diff --git a/mktemp/mktemp.c b/mktemp/mktemp.c
new file mode 100644 (file)
index 0000000..46e0c86
--- /dev/null
@@ -0,0 +1,151 @@
+/*-
+ * Copyright (c) 1994, 1995, 1996, 1998 Peter Wemm <peter@netplex.com.au>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ */
+
+/*
+ * This program was originally written long ago, originally for a non
+ * BSD-like OS without mkstemp().  It's been modified over the years
+ * to use mkstemp() rather than the original O_CREAT|O_EXCL/fstat/lstat
+ * etc style hacks.
+ * A cleanup, misc options and mkdtemp() calls were added to try and work
+ * more like the OpenBSD version - which was first to publish the interface.
+ */
+
+#include <err.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef lint
+static const char rcsid[] =
+       "$FreeBSD: src/usr.bin/mktemp/mktemp.c,v 1.2.6.1 2000/10/15 11:37:43 alex Exp $";
+#endif /* not lint */
+
+static void usage __P((void));
+
+int
+main(int argc, char **argv)
+{
+       int c, fd, ret;
+       char *tmpdir, *prefix;
+       char *name;
+       int dflag, qflag, tflag, uflag;
+
+       ret = dflag = qflag = tflag = uflag = 0;
+       prefix = "mktemp";
+       name = NULL;
+
+       while ((c = getopt(argc, argv, "dqt:u")) != -1)
+               switch (c) {
+               case 'd':
+                       dflag++;
+                       break;
+
+               case 'q':
+                       qflag++;
+                       break;
+
+               case 't':
+                       prefix = optarg;
+                       tflag++;
+                       break;
+
+               case 'u':
+                       uflag++;
+                       break;
+
+               default:
+                       usage();
+               }
+
+       argc -= optind;
+       argv += optind;
+
+       if (tflag) {
+               tmpdir = getenv("TMPDIR");
+               if (tmpdir == NULL)
+                       asprintf(&name, "%s%s.XXXXXXXX", _PATH_TMP, prefix);
+               else
+                       asprintf(&name, "%s/%s.XXXXXXXX", tmpdir, prefix);
+               /* if this fails, the program is in big trouble already */
+               if (name == NULL) {
+                       if (qflag)
+                               return (1);
+                       else
+                               errx(1, "cannot generate template");
+               }
+       } else if (argc < 1) {
+               usage();
+       }
+               
+       /* generate all requested files */
+       while (name != NULL || argc > 0) {
+               if (name == NULL) {
+                       name = strdup(argv[0]);
+                       argv++;
+                       argc--;
+               }
+               if (dflag) {
+                       if (mkdtemp(name) == NULL) {
+                               ret = 1;
+                               if (!qflag)
+                                       warn("mkdtemp failed on %s", name);
+                       } else {
+                               printf("%s\n", name);
+                               if (uflag)
+                                       rmdir(name);
+                       }
+               } else {
+                       fd = mkstemp(name);
+                       if (fd < 0) {
+                               ret = 1;
+                               if (!qflag)
+                                       warn("mkstemp failed on %s", name);
+                       } else {
+                               close(fd);
+                               if (uflag)
+                                       unlink(name);
+                               printf("%s\n", name);
+                       }
+               }
+               if (name)
+                       free(name);
+               name = NULL;
+       }
+       return (ret);
+}
+
+static void
+usage()
+{
+       fprintf(stderr,
+               "usage: mktemp [-d] [-q] [-t prefix] [-u] template ...\n");
+       fprintf(stderr,
+               "       mktemp [-d] [-q] [-u] -t prefix \n");
+       exit (1);
+}
index 8c443c75b95e4f1fb754257d7ab0d71e6a44efca..4b96209235647ea7b398872b5216d5d0150b5889 100644 (file)
--- a/pwd/pwd.1
+++ b/pwd/pwd.1
@@ -58,7 +58,7 @@ The following options are available:
 .Bl -tag -width indent
 .It Fl L
 Print the logical path to the current working directory, as defined
-by the shell in the evironment variable PWD.
+by the shell in the environment variable PWD.
 .It Fl P
 Print the physical path to the current working directory, with symbolic
 links in the path resolved. This is the default.
index ba4a00d6b5b830c5c554a3f4dae74345edb833a0..3fd63cedac36da911a1ec102a42f311df3423c30 100644 (file)
@@ -52,6 +52,7 @@ __RCSID("$NetBSD: renice.c,v 1.5 1997/10/19 14:01:38 lukem Exp $");
 #include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 int    donice __P((int, int, int));
 int    main __P((int, char **));
index 06864a4690f53616afe3675d0f0922201f5049ca..838e729d14f1422d23da876300dcc641a5ff093e 100644 (file)
@@ -21,7 +21,7 @@ MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
 CODE_GEN_STYLE = DYNAMIC
 MAKEFILE = tool.make
 NEXTSTEP_INSTALLDIR = /usr/bin
-LIBS = 
+LIBS = -lpam -lpam_misc
 DEBUG_LIBS = $(LIBS)
 PROF_LIBS = $(LIBS)
 
index 9e10e90bb6746d84796f702e9cf6b6039454678d..be85883fd331b480f973f962e4edd8b0d8380448 100644 (file)
@@ -1 +1,2 @@
 include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
+OTHER_CFLAGS = -DUSE_PAM
diff --git a/su/su.1 b/su/su.1
index 8ed4b4c1e4bbf9509fd1a936c0ee84164a5f5c65..f41431ff4e5145226e5b034a29e4621c13dd961f 100644 (file)
--- a/su/su.1
+++ b/su/su.1
 .Nd substitute user identity
 .Sh SYNOPSIS
 .Nm
-.Op Fl Kflm
-.Op Ar login Op Ar "shell arguments"
+.Op Fl flm
+.Op Ar login 
+.Op Ar -c shell arguments
 .Sh DESCRIPTION
 .Nm
-requests the Kerberos password for
+requests the password for
 .Ar login
-(or for
-.Dq Ar login Ns .root ,
-if no login is provided), and switches to
-that user and group ID after obtaining a Kerberos ticket granting ticket.
+and switches to
+that user and group ID after obtaining proper authentication.
 A shell is then executed, and any additional
 .Ar "shell arguments"
 after the login name
 are passed to the shell.
-.Nm
-will resort to the local password file to find the password for
-.Ar login
-if there is a Kerberos error.
 If
 .Nm
 is executed by root, no password is requested and a shell
-with the appropriate user ID is executed; no additional Kerberos tickets
-are obtained.
-.Pp
-Alternatively, if the user enters the password "s/key", authentication
-will use the S/Key one-time password system as described in
-.Xr skey 1 .
-S/Key is a Trademark of Bellcore.
-.Pp
-By default, the environment is unmodified with the exception of
-.Ev USER ,
-.Ev HOME ,
-and
-.Ev SHELL .
-.Ev HOME
-and
-.Ev SHELL
-are set to the target login's default values.
-.Ev USER
-is set to the target login, unless the target login has a user ID of 0,
-in which case it is unmodified.
-The invoked shell is the target login's.
-This is the traditional behavior of
-.Nm su .
+with the appropriate user ID is executed.
 .Pp
 The options are as follows:
 .Bl -tag -width Ds
-.It Fl K
-Do not attempt to use Kerberos to authenticate the user.
+.It Fl c
+Invoke the following command in a subshell as the specified user.
 .It Fl f
 If the invoked shell is
 .Xr csh 1 ,
@@ -118,6 +91,7 @@ is imported from your current environment.
 The invoked shell is the target login's, and
 .Nm
 will change directory to the target login's home directory.
+This option is identical to just passing "-", as in "su -".
 .It Fl m
 Leave the environment unmodified.
 The invoked shell is your login shell, and no directory changes are made.
@@ -139,10 +113,10 @@ overrides any previous ones.
 .Pp
 Only users in group
 .Dq wheel
-(normally gid 0),
-as listed in
-.Pa /etc/group ,
-can
+(normally gid 0)
+or group
+.Dq admin
+(normally gid 20) can
 .Nm
 to
 .Dq root .
diff --git a/su/su.c b/su/su.c
index 750d02b3f941925aa31dfb37cecb18e5417db544..2d7018c98d6373e19402a3fcaf6d84d571869cf9 100644 (file)
--- a/su/su.c
+++ b/su/su.c
@@ -1,8 +1,6 @@
-/*     $NetBSD: su.c,v 1.26 1998/08/25 20:59:40 ross Exp $     */
-
 /*
- * Copyright (c) 1988 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1988, 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
  * SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
 #ifndef lint
-__COPYRIGHT(
-    "@(#) Copyright (c) 1988 The Regents of the University of California.\n\
All rights reserved.\n");
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1993, 1994\n\
      The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
 #if 0
-static char sccsid[] = "@(#)su.c       8.3 (Berkeley) 4/2/94";*/
-#else
-__RCSID("$NetBSD: su.c,v 1.26 1998/08/25 20:59:40 ross Exp $");
+static char sccsid[] = "@(#)su.c       8.3 (Berkeley) 4/2/94";
 #endif
+static const char rcsid[] =
+  "$FreeBSD: src/usr.bin/su/su.c,v 1.48 2002/01/24 16:20:17 des Exp $";
 #endif /* not lint */
 
 #include <sys/param.h>
 #include <sys/time.h>
 #include <sys/resource.h>
+#include <sys/wait.h>
+
 #include <err.h>
 #include <errno.h>
 #include <grp.h>
 #include <paths.h>
 #include <pwd.h>
+#include <signal.h>
 #include <stdio.h>
-#ifdef SKEY
-#include <skey.h>
-#endif
 #include <stdlib.h>
 #include <string.h>
 #include <syslog.h>
-#include <time.h>
-#include <tzfile.h>
 #include <unistd.h>
 
-#ifdef KERBEROS
-#include <kerberosIV/des.h>
-#include <kerberosIV/krb.h>
-#include <netdb.h>
-
-#define        ARGSTR  "-Kflm"
-
-int use_kerberos = 1;
-
-static int kerberos __P((char *, char *, int));
-static int koktologin __P((char *, char *, char *));
-
-#else
-#define        ARGSTR  "-flm"
-#endif
-
-#ifndef        SUGROUP
-#define        SUGROUP "wheel"
-#endif
-
-
-int main __P((int, char **));
-
-static int chshell __P((const char *));
-static char *ontty __P((void));
-
+#include <pam/pam_appl.h>
+#include <pam/pam_misc.h>
+
+#define PAM_END() do {                                         \
+       int local_ret;                                          \
+       if (pamh != NULL && creds_set) {                        \
+               local_ret = pam_setcred(pamh, PAM_DELETE_CRED); \
+               if (local_ret != PAM_SUCCESS)                   \
+                       syslog(LOG_ERR, "pam_setcred: %s",      \
+                               pam_strerror(pamh, local_ret)); \
+               local_ret = pam_close_session(pamh, 0);         \
+               local_ret = pam_end(pamh, local_ret);           \
+               if (local_ret != PAM_SUCCESS)                   \
+                       syslog(LOG_ERR, "pam_end: %s",          \
+                               pam_strerror(pamh, local_ret)); \
+       }                                                       \
+} while (0)
+
+
+#define PAM_SET_ITEM(what, item) do {                          \
+       int local_ret;                                          \
+       local_ret = pam_set_item(pamh, what, item);             \
+       if (local_ret != PAM_SUCCESS) {                         \
+               syslog(LOG_ERR, "pam_set_item(" #what "): %s",  \
+                       pam_strerror(pamh, local_ret));         \
+               errx(1, "pam_set_item(" #what "): %s",          \
+                       pam_strerror(pamh, local_ret));         \
+       }                                                       \
+} while (0)
+
+enum tristate { UNSET, YES, NO };
+
+static pam_handle_t *pamh = NULL;
+static int     creds_set = 0;
+static char    **environ_pam;
+
+static char    *ontty(void);
+static int     chshell(char *);
+static void    usage(void);
+static int     export_pam_environment(void);
+static int     ok_to_export(const char *);
+
+extern char    **environ;
 
 int
-main(argc, argv)
-       int argc;
-       char **argv;
+main(int argc, char *argv[])
 {
-       extern char *__progname;
-       extern char **environ;
-       struct passwd *pwd;
-       char *p;
-       struct timeval tp;
-       uid_t ruid;
-       gid_t usergid;
-       int asme, ch, asthem, fastlogin, prio;
-       enum { UNSET, YES, NO } iscsh = UNSET;
-       char *user, *shell, *avshell, *username, *cleanenv[10], **np;
-       char shellbuf[MAXPATHLEN], avshellbuf[MAXPATHLEN];
-
-       asme = asthem = fastlogin = 0;
-       shell = NULL;
-       while ((ch = getopt(argc, argv, ARGSTR)) != -1)
-               switch((char)ch) {
-#ifdef KERBEROS
-               case 'K':
-                       use_kerberos = 0;
-                       break;
-#endif
+       struct passwd   *pwd;
+       struct pam_conv conv = {misc_conv, NULL};
+       enum tristate   iscsh;
+       union {
+               const char      **a;
+               char            * const *b;
+       }               np;
+       uid_t           ruid;
+       gid_t           gid;
+       int             asme, ch, asthem, fastlogin, prio, i, setwhat, retcode,
+                       statusp, child_pid, child_pgrp, ret_pid;
+       char            *username, *cleanenv, *class, shellbuf[MAXPATHLEN];
+       const char      *p, *user, *shell, *mytty, **nargv;
+
+       shell = class = cleanenv = NULL;
+       asme = asthem = fastlogin = statusp = 0;
+       user = "root";
+       iscsh = UNSET;
+
+       while ((ch = getopt(argc, argv, "-flmc:")) != -1)
+               switch ((char)ch) {
                case 'f':
                        fastlogin = 1;
                        break;
@@ -132,373 +142,313 @@ main(argc, argv)
                        asme = 1;
                        asthem = 0;
                        break;
+               case 'c':
+                       class = optarg;
+                       break;
                case '?':
                default:
-                       (void)fprintf(stderr,
-                           "Usage: %s [%s] [login [shell arguments]]\n",
-                           __progname, ARGSTR);
-                       exit(1);
+                       usage();
                }
+
+       if (optind < argc)
+               user = argv[optind++];
+
+       if (user == NULL)
+               usage();
+
+       if (strlen(user) > MAXLOGNAME - 1)
+               errx(1, "username too long");
+
+       nargv = malloc(sizeof(char *) * (argc + 4));
+       if (nargv == NULL)
+               errx(1, "malloc failure");
+
+       nargv[argc + 3] = NULL;
+       for (i = argc; i >= optind; i--)
+               nargv[i + 3] = argv[i];
+       np.a = &nargv[i + 3];
+
        argv += optind;
 
        errno = 0;
        prio = getpriority(PRIO_PROCESS, 0);
        if (errno)
                prio = 0;
-       (void)setpriority(PRIO_PROCESS, 0, -2);
-       openlog("su", LOG_CONS, 0);
 
-       /* get current login name and shell */
+       setpriority(PRIO_PROCESS, 0, -2);
+       openlog("su", LOG_CONS, LOG_AUTH);
+
+       /* get current login name, real uid and shell */
        ruid = getuid();
        username = getlogin();
-       if (username == NULL || (pwd = getpwnam(username)) == NULL ||
-           pwd->pw_uid != ruid)
+       pwd = getpwnam(username);
+       if (username == NULL || pwd == NULL || pwd->pw_uid != ruid)
                pwd = getpwuid(ruid);
        if (pwd == NULL)
                errx(1, "who are you?");
+       gid = pwd->pw_gid;
+
        username = strdup(pwd->pw_name);
-       usergid = pwd->pw_gid;
        if (username == NULL)
-               err(1, "strdup");
+               err(1, "strdup failure");
 
        if (asme) {
-               if (pwd->pw_shell && *pwd->pw_shell) {
+               if (pwd->pw_shell != NULL && *pwd->pw_shell != '\0') {
+                       /* must copy - pwd memory is recycled */
                        shell = strncpy(shellbuf, pwd->pw_shell,
-                           sizeof(shellbuf) - 1);
+                           sizeof(shellbuf));
                        shellbuf[sizeof(shellbuf) - 1] = '\0';
-               } else {
+               }
+               else {
                        shell = _PATH_BSHELL;
                        iscsh = NO;
                }
        }
-       /* get target login information, default to root */
-       user = *argv ? *argv : "root";
-       np = *argv ? argv : argv-1;
 
-       if ((pwd = getpwnam(user)) == NULL)
-               errx(1, "unknown login %s", user);
+       /* Do the whole PAM startup thing */
+       retcode = pam_start("su", user, &conv, &pamh);
+       if (retcode != PAM_SUCCESS) {
+               syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, retcode));
+               errx(1, "pam_start: %s", pam_strerror(pamh, retcode));
+       }
 
-       if (ruid
-#ifdef KERBEROS
-           && (!use_kerberos || kerberos(username, user, pwd->pw_uid))
-#endif
-          ) {
-                gid_t groups[NGROUPS_MAX];
-                int   numgroups;
-
-               /*
-                * Only allow those in group SUGROUP to su to root.
-                */
-                if (pwd->pw_uid == 0 &&
-                   (initgroups(username, usergid) == 0) &&
-                    ((numgroups = getgroups(NGROUPS_MAX, groups)) > 0)) {
-                       int i;
-                       int wheel = 0;
-                        gid_t wheelgid = 0;
-                        struct group *wheelgroup;
-
-                        if ((wheelgroup = getgrnam(SUGROUP)) != NULL) {
-                               wheelgid = wheelgroup->gr_gid;
-
-                               for (i = 0; i < numgroups; i++) {
-                                       if (groups[i] == wheelgid) {
-                                               wheel = 1;
-                                               break;
-                                        }
-                                }
-                        } else {
-                               /* If we can't get the gid for SUGROUP, then let anyone su */
-                               warnx("unknown secondary group %s; anyone can su %s.", SUGROUP, user);
-                               wheel = 1;
-                        }
-
-                        if (!wheel)
-                               errx(1,
-                                     "you are not listed in the correct secondary group (%s) to su %s.",
-                                     SUGROUP, user);
-                }
-
-               /* if target requires a password, verify it */
-               if (*pwd->pw_passwd) {
-                       p = getpass("Password:");
-#ifdef SKEY
-                       if (strcasecmp(p, "s/key") == 0) {
-                               if (skey_haskey(user))
-                                       errx(1, "Sorry, you have no s/key.");
-                               else {
-                                       if (skey_authenticate(user)) {
-                                               goto badlogin;
-                                       }
-                               }
-
-                       } else
-#endif
-                       if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) {
-#ifdef SKEY
-badlogin:
-#endif
-                               fprintf(stderr, "Sorry\n");
-                               syslog(LOG_AUTH|LOG_WARNING,
-                                       "BAD SU %s to %s%s", username,
-                                       user, ontty());
-                               exit(1);
-                       }
+       PAM_SET_ITEM(PAM_RUSER, getlogin());
+
+       mytty = ttyname(STDERR_FILENO);
+       if (!mytty)
+               mytty = "tty";
+       PAM_SET_ITEM(PAM_TTY, mytty);
+
+       retcode = pam_authenticate(pamh, 0);
+       if (retcode != PAM_SUCCESS) {
+               syslog(LOG_ERR, "pam_authenticate: %s",
+                   pam_strerror(pamh, retcode));
+               errx(1, "Sorry");
+       }
+       retcode = pam_get_item(pamh, PAM_USER, (const void **)&p);
+       if (retcode == PAM_SUCCESS)
+               user = p;
+       else
+               syslog(LOG_ERR, "pam_get_item(PAM_USER): %s",
+                   pam_strerror(pamh, retcode));
+
+       retcode = pam_acct_mgmt(pamh, 0);
+       if (retcode == PAM_NEW_AUTHTOK_REQD) {
+               retcode = pam_chauthtok(pamh,
+                       PAM_CHANGE_EXPIRED_AUTHTOK);
+               if (retcode != PAM_SUCCESS) {
+                       syslog(LOG_ERR, "pam_chauthtok: %s",
+                           pam_strerror(pamh, retcode));
+                       errx(1, "Sorry");
                }
        }
+       if (retcode != PAM_SUCCESS) {
+               syslog(LOG_ERR, "pam_acct_mgmt: %s",
+                       pam_strerror(pamh, retcode));
+               errx(1, "Sorry");
+       }
 
+       /* get target login information, default to root */
+       pwd = getpwnam(user);
+       if (pwd == NULL)
+               errx(1, "unknown login: %s", user);
+
+       /* if asme and non-standard target shell, must be root */
        if (asme) {
-               /* if asme and non-standard target shell, must be root */
-               if (!chshell(pwd->pw_shell) && ruid)
-                       errx(1,"permission denied (shell).");
-       else if (pwd->pw_shell && *pwd->pw_shell) {
+               if (ruid != 0 && !chshell(pwd->pw_shell))
+                       errx(1, "permission denied (shell).");
+       }
+       else if (pwd->pw_shell && *pwd->pw_shell) {
                shell = pwd->pw_shell;
                iscsh = UNSET;
-       } else {
+       }
+       else {
                shell = _PATH_BSHELL;
                iscsh = NO;
        }
 
-       if ((p = strrchr(shell, '/')) != NULL)
-               avshell = p+1;
-       else
-               avshell = shell;
-
        /* if we're forking a csh, we want to slightly muck the args */
-       if (iscsh == UNSET)
-               iscsh = strstr(avshell, "csh") ? YES : NO;
-
-       /* set permissions */
-       if (setgid(pwd->pw_gid) < 0)
-               err(1, "setgid");
-       if (initgroups(user, pwd->pw_gid))
-               errx(1, "initgroups failed");
-       if (setuid(pwd->pw_uid) < 0)
-               err(1, "setuid");
-
-       if (!asme) {
-               if (asthem) {
-                       p = getenv("TERM");
-                       cleanenv[0] = NULL;
-                       environ = cleanenv;
-                       (void)setenv("PATH", _PATH_DEFPATH, 1);
-                       if (p)
-                               (void)setenv("TERM", p, 1);
-                       if (chdir(pwd->pw_dir) < 0)
-                               errx(1, "no directory");
-               }
-               if (asthem || pwd->pw_uid)
-                       (void)setenv("USER", pwd->pw_name, 1);
-               (void)setenv("HOME", pwd->pw_dir, 1);
-               (void)setenv("SHELL", shell, 1);
+       if (iscsh == UNSET) {
+               p = strrchr(shell, '/');
+               if (p)
+                       ++p;
+               else
+                       p = shell;
+               iscsh = strcmp(p, "csh") ? (strcmp(p, "tcsh") ? NO : YES) : YES;
        }
+       setpriority(PRIO_PROCESS, 0, prio);
 
-       if (iscsh == YES) {
-               if (fastlogin)
-                       *np-- = "-f";
-               if (asme)
-                       *np-- = "-m";
-       }
+       /*
+        * PAM modules might add supplementary groups in pam_setcred(), so
+        * initialize them first.
+        */
+       if( initgroups(user, pwd->pw_gid) )
+               err(1, "initgroups failed");
 
-       if (asthem) {
-               avshellbuf[0] = '-';
-               (void)strncpy(avshellbuf+1, avshell, sizeof(avshellbuf) - 2);
-               avshell = avshellbuf;
-       } else if (iscsh == YES) {
-               /* csh strips the first character... */
-               avshellbuf[0] = '_';
-               (void)strncpy(avshellbuf+1, avshell, sizeof(avshellbuf) - 2);
-               avshell = avshellbuf;
-       }
-       *np = avshell;
-
-       if (pwd->pw_change || pwd->pw_expire)
-               (void)gettimeofday(&tp, (struct timezone *)NULL);
-       if (pwd->pw_change) {
-               if (tp.tv_sec >= pwd->pw_change) {
-                       (void)printf("%s -- %s's password has expired.\n",
-                                    (ruid ? "Sorry" : "Note"), user);
-                       if (ruid != 0)
-                               exit(1);
-               } else if (pwd->pw_change - tp.tv_sec <
-                   _PASSWORD_WARNDAYS * SECSPERDAY)
-                       (void)printf("Warning: %s's password expires on %s",
-                                    user, ctime(&pwd->pw_change));
+       retcode = pam_open_session(pamh, 0);
+       if( retcode != PAM_SUCCESS ) {
+               syslog(LOG_ERR, "pam_open_session(pamh, 0): %s", 
+                       pam_strerror(pamh, retcode));
        }
-       if (pwd->pw_expire) {
-               if (tp.tv_sec >= pwd->pw_expire) {
-                       (void)printf("%s -- %s's account has expired.\n",
-                                    (ruid ? "Sorry" : "Note"), user);
-                       if (ruid != 0)
-                               exit(1);
-               } else if (pwd->pw_expire - tp.tv_sec <
-                   _PASSWORD_WARNDAYS * SECSPERDAY)
-                       (void)printf("Warning: %s's account expires on %s",
-                                    user, ctime(&pwd->pw_expire));
-       }
-       if (ruid != 0)
-               syslog(LOG_NOTICE|LOG_AUTH, "%s to %s%s",
-                   username, user, ontty());
-
-       (void)setpriority(PRIO_PROCESS, 0, prio);
-
-       execv(shell, np);
-       err(1, "%s", shell);
-        /* NOTREACHED */
-}
 
-static int
-chshell(sh)
-       const char *sh;
-{
-       const char *cp;
+       retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+       if (retcode != PAM_SUCCESS)
+               syslog(LOG_ERR, "pam_setcred(pamh, PAM_ESTABLISH_CRED): %s",
+                   pam_strerror(pamh, retcode));
+       else
+               creds_set = 1;
 
-       while ((cp = getusershell()) != NULL)
-               if (!strcmp(cp, sh))
-                       return (1);
-       return (0);
-}
+       /*
+        * We must fork() before setuid() because we need to call
+        * pam_setcred(pamh, PAM_DELETE_CRED) as root.
+        */
 
-static char *
-ontty()
-{
-       char *p;
-       static char buf[MAXPATHLEN + 4];
+       statusp = 1;
+       child_pid = fork();
+       switch (child_pid) {
+       default:
+               while ((ret_pid = waitpid(child_pid, &statusp, WUNTRACED)) != -1) {
+                       if (WIFSTOPPED(statusp)) {
+                               child_pgrp = tcgetpgrp(1);
+                               kill(getpid(), SIGSTOP);
+                               tcsetpgrp(1, child_pgrp);
+                               kill(child_pid, SIGCONT); 
+                               statusp = 1;
+                               continue;
+                       }
+                       break;
+               }
+               if (ret_pid == -1)
+                       err(1, "waitpid");
+               PAM_END();
+               exit(WEXITSTATUS(statusp));
+       case -1:
+               err(1, "fork");
+               PAM_END();
+               exit(1);
+       case 0:
+               if( setgid(pwd->pw_gid) )
+                       err(1, "setgid");
+               if( setuid(pwd->pw_uid) )
+                       err(1, "setuid");
+
+               if (!asme) {
+                       if (asthem) {
+                               p = getenv("TERM");
+                               *environ = NULL;
+
+                               /*
+                                * Add any environmental variables that the
+                                * PAM modules may have set.
+                                */
+                               environ_pam = pam_getenvlist(pamh);
+                               if (environ_pam)
+                                       export_pam_environment();
+
+                               if (p)
+                                       setenv("TERM", p, 1);
+                               if (chdir(pwd->pw_dir) < 0)
+                                       errx(1, "no directory");
+                       }
+                       if (asthem || pwd->pw_uid)
+                               setenv("USER", pwd->pw_name, 1);
+                       setenv("HOME", pwd->pw_dir, 1);
+                       setenv("SHELL", shell, 1);
+               }
 
-       buf[0] = 0;
-       if ((p = ttyname(STDERR_FILENO)) != NULL)
-               (void)snprintf(buf, sizeof buf, " on %s", p);
-       return (buf);
+               if (iscsh == YES) {
+                       if (fastlogin)
+                               *np.a-- = "-f";
+                       if (asme)
+                               *np.a-- = "-m";
+               }
+               /* csh strips the first character... */
+               *np.a = asthem ? "-su" : iscsh == YES ? "_su" : "su";
+
+               if (ruid != 0)
+                       syslog(LOG_NOTICE, "%s to %s%s", username, user,
+                           ontty());
+
+               execv(shell, np.b);
+               err(1, "%s", shell);
+       }
 }
 
-#ifdef KERBEROS
 static int
-kerberos(username, user, uid)
-       char *username, *user;
-       int uid;
+export_pam_environment(void)
 {
-       KTEXT_ST ticket;
-       AUTH_DAT authdata;
-       struct hostent *hp;
-       int kerno;
-       u_long faddr;
-       char lrealm[REALM_SZ], krbtkfile[MAXPATHLEN];
-       char hostname[MAXHOSTNAMELEN + 1], savehost[MAXHOSTNAMELEN + 1];
-
-       if (krb_get_lrealm(lrealm, 1) != KSUCCESS)
-               return (1);
-       if (koktologin(username, lrealm, user) && !uid) {
-               warnx("kerberos: not in %s's ACL.", user);
-               return (1);
-       }
-       (void)(void)snprintf(krbtkfile, sizeof krbtkfile, "%s_%s_%d", TKT_ROOT,
-           user, getuid());
-
-       (void)setenv("KRBTKFILE", krbtkfile, 1);
-       (void)krb_set_tkt_string(krbtkfile);
-       /*
-        * Set real as well as effective ID to 0 for the moment,
-        * to make the kerberos library do the right thing.
-        */
-       if (setuid(0) < 0) {
-               warn("setuid");
-               return (1);
-       }
+       char    **pp;
 
-       /*
-        * Little trick here -- if we are su'ing to root,
-        * we need to get a ticket for "xxx.root", where xxx represents
-        * the name of the person su'ing.  Otherwise (non-root case),
-        * we need to get a ticket for "yyy.", where yyy represents
-        * the name of the person being su'd to, and the instance is null
-        *
-        * We should have a way to set the ticket lifetime,
-        * with a system default for root.
-        */
-       kerno = krb_get_pw_in_tkt((uid == 0 ? username : user),
-               (uid == 0 ? "root" : ""), lrealm,
-               "krbtgt", lrealm, DEFAULT_TKT_LIFE, 0);
-
-       if (kerno != KSUCCESS) {
-               if (kerno == KDC_PR_UNKNOWN) {
-                       warnx("kerberos: principal unknown: %s.%s@%s",
-                               (uid == 0 ? username : user),
-                               (uid == 0 ? "root" : ""), lrealm);
-                       return (1);
-               }
-               warnx("kerberos: unable to su: %s", krb_err_txt[kerno]);
-               syslog(LOG_NOTICE|LOG_AUTH,
-                   "BAD Kerberos SU: %s to %s%s: %s",
-                   username, user, ontty(), krb_err_txt[kerno]);
-               return (1);
+       for (pp = environ_pam; *pp != NULL; pp++) {
+               if (ok_to_export(*pp))
+                       putenv(*pp);
+               free(*pp);
        }
+       return PAM_SUCCESS;
+}
 
-       if (chown(krbtkfile, uid, -1) < 0) {
-               warn("chown");
-               (void)unlink(krbtkfile);
-               return (1);
+/*
+ * Sanity checks on PAM environmental variables:
+ * - Make sure there is an '=' in the string.
+ * - Make sure the string doesn't run on too long.
+ * - Do not export certain variables.  This list was taken from the
+ *   Solaris pam_putenv(3) man page.
+ */
+static int
+ok_to_export(const char *s)
+{
+       static const char *noexport[] = {
+               "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH",
+               "IFS", "PATH", NULL
+       };
+       const char **pp;
+       size_t n;
+
+       if (strlen(s) > 1024 || strchr(s, '=') == NULL)
+               return 0;
+       if (strncmp(s, "LD_", 3) == 0)
+               return 0;
+       for (pp = noexport; *pp != NULL; pp++) {
+               n = strlen(*pp);
+               if (s[n] == '=' && strncmp(s, *pp, n) == 0)
+                       return 0;
        }
+       return 1;
+}
 
-       (void)setpriority(PRIO_PROCESS, 0, -2);
+static void
+usage(void)
+{
 
-       if (gethostname(hostname, sizeof(hostname)) == -1) {
-               warn("gethostname");
-               dest_tkt();
-               return (1);
-       }
-       hostname[sizeof(hostname) - 1] = '\0';
-
-       (void)strncpy(savehost, krb_get_phost(hostname), sizeof(savehost));
-       savehost[sizeof(savehost) - 1] = '\0';
-
-       kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33);
-
-       if (kerno == KDC_PR_UNKNOWN) {
-               warnx("Warning: TGT not verified.");
-               syslog(LOG_NOTICE|LOG_AUTH,
-                   "%s to %s%s, TGT not verified (%s); %s.%s not registered?",
-                   username, user, ontty(), krb_err_txt[kerno],
-                   "rcmd", savehost);
-       } else if (kerno != KSUCCESS) {
-               warnx("Unable to use TGT: %s", krb_err_txt[kerno]);
-               syslog(LOG_NOTICE|LOG_AUTH, "failed su: %s to %s%s: %s",
-                   username, user, ontty(), krb_err_txt[kerno]);
-               dest_tkt();
-               return (1);
-       } else {
-               if (!(hp = gethostbyname(hostname))) {
-                       warnx("can't get addr of %s", hostname);
-                       dest_tkt();
-                       return (1);
-               }
-               memmove((char *)&faddr, (char *)hp->h_addr, sizeof(faddr));
-
-               if ((kerno = krb_rd_req(&ticket, "rcmd", savehost, faddr,
-                   &authdata, "")) != KSUCCESS) {
-                       warnx("kerberos: unable to verify rcmd ticket: %s\n",
-                           krb_err_txt[kerno]);
-                       syslog(LOG_NOTICE|LOG_AUTH,
-                           "failed su: %s to %s%s: %s", username,
-                            user, ontty(), krb_err_txt[kerno]);
-                       dest_tkt();
-                       return (1);
-               }
-       }
-       return (0);
+       fprintf(stderr, "usage: su [-] [-flm] [-c class] [login [args]]\n");
+       exit(1);
 }
 
 static int
-koktologin(name, realm, toname)
-       char *name, *realm, *toname;
+chshell(char *sh)
 {
-       AUTH_DAT *kdata;
-       AUTH_DAT kdata_st;
-
-       kdata = &kdata_st;
-       memset((char *)kdata, 0, sizeof(*kdata));
-       (void)strncpy(kdata->pname, name, sizeof(kdata->pname) - 1);
-       (void)strncpy(kdata->pinst,
-           ((strcmp(toname, "root") == 0) ? "root" : ""), sizeof(kdata->pinst) - 1);
-       (void)strncpy(kdata->prealm, realm, sizeof(kdata->prealm) - 1);
-       return (kuserok(kdata, toname));
+       int r;
+       char *cp;
+
+       r = 0;
+       setusershell();
+       do {
+               cp = getusershell();
+               r = strcmp(cp, sh);
+       } while (!r && cp != NULL);
+       endusershell();
+       return r;
+}
+
+static char *
+ontty(void)
+{
+       char *p;
+       static char buf[MAXPATHLEN + 4];
+
+       buf[0] = 0;
+       p = ttyname(STDERR_FILENO);
+       if (p)
+               snprintf(buf, sizeof(buf), " on %s", p);
+       return buf;
 }
-#endif
index 75155d21c2585fc898da066b0c1c519cf771a03c..7d0487270bb074b502ab83ee1c6735eef21a0dc3 100644 (file)
@@ -4,3 +4,5 @@ OTHERSRCS += '[.1'
 
 after_install::
        $(LINKPRODUCT) $(DSTROOT)$(INSTALLDIR)/[
+       mkdir -p "$(DSTROOT)/usr/share/man/man1"
+       ln -f "$(DSTROOT)/usr/share/man/man1/test.1" "$(DSTROOT)/usr/share/man/man1/[.1"
index f7af7e9940d183a9b6dfc97b06eb7257a103a45a..d973485a7336c162f0d79f5d7dd5667719bb5658 100644 (file)
@@ -1 +1,2 @@
+#include <stdlib.h>
 int main () { exit(0); }
index 85ca1829e225870d10fbe3ab39957a238db1dac1..69b59bd9516f7d29c8f023ff93f8b9c35d82242d 100644 (file)
@@ -49,8 +49,8 @@ the length of time the system has been up,
 the number of users, and the load average of the system over the last
 1, 5, and 15 minutes.
 .Sh FILES
-.Bl -tag -width /netbsd
-.It Pa /netbsd
+.Bl -tag -width /mach
+.It Pa /mach
 system name list
 .El
 .Sh SEE ALSO
diff --git a/w/w.1 b/w/w.1
index 3517a2ec6f4ed36f26b9d6636d466fd95327bed4..2229bfcf7ab69fb34b335a17917624bba57976b0 100644 (file)
--- a/w/w.1
+++ b/w/w.1
@@ -74,7 +74,7 @@ core instead of the default
 .It Fl N
 Extract the name list from the specified system instead of the
 default
-.Dq /netbsd .
+.Dq /mach .
 .It Fl n
 Show network addresses as numbers (normally
 .Nm
diff --git a/w/w.c b/w/w.c
index 7e52c79624b3513cf648fcbb1c16a4c95ed7d95a..e94fc0f9d240590a4e50b10b4f831cc534a0f52c 100644 (file)
--- a/w/w.c
+++ b/w/w.c
@@ -188,7 +188,7 @@ main(argc, argv)
        else
                (void)setegid(egid);
 
-       if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == NULL)
+       if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL)
                errx(1, "%s", errbuf);
 
        /* get rid of it now anyway */
index 674ab406b3a778f85fbb978458f57971be5d39e5..911eed33c5784f313fac84bf588d2c795e243ae4 100644 (file)
@@ -38,12 +38,12 @@ MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
 CODE_GEN_STYLE = DYNAMIC
 MAKEFILE = tool.make
 NEXTSTEP_INSTALLDIR = /usr/bin
-LIBS = 
+LIBS = -lcurses
 DEBUG_LIBS = $(LIBS)
 PROF_LIBS = $(LIBS)
 
 
-NEXTSTEP_PB_CFLAGS = -Wno-error
+NEXTSTEP_PB_CFLAGS = 
 
 
 NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
index 494127dd6019e59d12b2aaa1af1d42a74f3dc422..1a76912df490dc9eb65009da2d2a491a0342599a 100644 (file)
@@ -124,7 +124,7 @@ struct tt_tab {
        int tt_len;
        int (*tt_func) __P((void));
 };
-EXTERN struct tt_tab tt_tab[];
+extern struct tt_tab tt_tab[11];
 
 /*
  * Clean interface to termcap routines.