From c0fcf4e10b938344ef61467570bddfdc19cc8b7b Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 11 Jul 2002 00:08:44 +0000 Subject: [PATCH] shell_cmds-34.tar.gz --- Makefile | 6 +- false/false.c | 3 +- find/Makefile | 2 +- find/extern.h | 100 ++- find/find.1 | 651 +++++++++++---- find/find.c | 68 +- find/find.h | 82 +- find/function.c | 1101 +++++++++++++++---------- find/ls.c | 30 +- find/main.c | 67 +- find/misc.c | 25 +- find/operator.c | 99 ++- find/option.c | 126 +-- find/y.tab.c | 1542 ++++++++++++++++++++++++++++++++++++ getopt/getopt.c | 1 + id/id.c | 4 +- kill/kill.1 | 30 +- kill/kill.c | 34 +- killall/Makefile | 48 ++ killall/Makefile.postamble | 1 + killall/Makefile.preamble | 1 + killall/PB.project | 0 killall/killall.1 | 152 ++++ killall/killall.c | 375 +++++++++ locate/locate/locate.c | 1 + locate/locate/updatedb.csh | 2 +- mktemp/Makefile | 50 ++ mktemp/Makefile.postamble | 1 + mktemp/Makefile.preamble | 1 + mktemp/PB.project | 27 + mktemp/mktemp.1 | 195 +++++ mktemp/mktemp.c | 151 ++++ pwd/pwd.1 | 2 +- renice/renice.c | 1 + su/Makefile | 2 +- su/Makefile.preamble | 1 + su/su.1 | 54 +- su/su.c | 700 ++++++++-------- test/Makefile.postamble | 2 + true/true.c | 1 + w/uptime.1 | 4 +- w/w.1 | 2 +- w/w.c | 2 +- window/Makefile | 4 +- window/tt.h | 2 +- 45 files changed, 4447 insertions(+), 1306 deletions(-) create mode 100644 find/y.tab.c create mode 100644 killall/Makefile create mode 100644 killall/Makefile.postamble create mode 100644 killall/Makefile.preamble create mode 100644 killall/PB.project create mode 100644 killall/killall.1 create mode 100644 killall/killall.c create mode 100644 mktemp/Makefile create mode 100644 mktemp/Makefile.postamble create mode 100644 mktemp/Makefile.preamble create mode 100644 mktemp/PB.project create mode 100644 mktemp/mktemp.1 create mode 100644 mktemp/mktemp.c diff --git a/Makefile b/Makefile index 0162509..d6aa778 100644 --- 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 diff --git a/false/false.c b/false/false.c index 9c29522..3883d89 100644 --- a/false/false.c +++ b/false/false.c @@ -1 +1,2 @@ -int main () { exit(1); } \ No newline at end of file +#include +int main () { exit(1); } diff --git a/find/Makefile b/find/Makefile index 2deb864..c0cb276 100644 --- a/find/Makefile +++ b/find/Makefile @@ -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 diff --git a/find/extern.h b/find/extern.h index 013fa5f..d909f1e 100644 --- a/find/extern.h +++ b/find/extern.h @@ -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 @@ -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; diff --git a/find/find.1 b/find/find.1 index 9692337..5794024 100644 --- a/find/find.1 +++ b/find/find.1 @@ -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 @@ -34,48 +31,63 @@ .\" 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 1 , 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 . diff --git a/find/find.c b/find/find.c index a1672ac..6a14c92 100644 --- a/find/find.c +++ b/find/find.c @@ -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. @@ -36,12 +34,12 @@ * SUCH DAMAGE. */ -#include #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 #include #include +#include #include #include #include #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); } diff --git a/find/find.h b/find/find.h index 804011f..3916769 100644 --- a/find/find.h +++ b/find/find.h @@ -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. @@ -35,36 +33,55 @@ * 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 + +/* 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" diff --git a/find/function.c b/find/function.c index efa1abe..5411be3 100644 --- a/find/function.c +++ b/find/function.c @@ -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. @@ -36,12 +34,12 @@ * SUCH DAMAGE. */ -#include #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 #include #include +#include +#include #include #include #include #include #include #include +#include #include #include #include -#include #include #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, ¬flags) == 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 */ diff --git a/find/ls.c b/find/ls.c index cdce351..d050029 100644 --- 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. @@ -33,12 +31,12 @@ * SUCH DAMAGE. */ -#include #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 #include -#include -#include -#include #include -#include #include #include -#include #include #include -#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; } diff --git a/find/main.c b/find/main.c index ed2f090..bad04a2 100644 --- a/find/main.c +++ b/find/main.c @@ -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. @@ -36,14 +34,18 @@ * SUCH DAMAGE. */ -#include +#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 #include #include +#include +#include #include #include #include @@ -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); } diff --git a/find/misc.c b/find/misc.c index cf6a85b..2ad2ace 100644 --- a/find/misc.c +++ b/find/misc.c @@ -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. @@ -36,12 +34,12 @@ * SUCH DAMAGE. */ -#include #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 #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); } diff --git a/find/operator.c b/find/operator.c index 128a785..a8feb8e 100644 --- a/find/operator.c +++ b/find/operator.c @@ -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. @@ -34,15 +32,12 @@ * 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 #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 @@ -52,69 +47,65 @@ __RCSID("$NetBSD: operator.c,v 1.6 1998/02/21 22:47:21 christos Exp $"); #include #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; diff --git a/find/option.c b/find/option.c index f531dab..7e73a5f 100644 --- a/find/option.c +++ b/find/option.c @@ -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. @@ -36,13 +34,12 @@ * SUCH DAMAGE. */ -#include #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 @@ -50,49 +47,82 @@ __RCSID("$NetBSD: option.c,v 1.9 1998/02/21 22:47:21 christos Exp $"); #include #include +#include #include #include #include #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 index 0000000..573e775 --- /dev/null +++ b/find/y.tab.c @@ -0,0 +1,1542 @@ +#include +#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 +#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 while +** at the University of North Carolina at Chapel Hill. Later tweaked by +** a couple of people on Usenet. Completely overhauled by Rich $alz +** and Jim Berets 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 +#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 +#include +#include + +/* 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 if that will be used. */ + +#if defined(vms) +# include +#else /* defined(vms) */ +# include +/* don't need xtime.h */ +# include +# include +#endif /* !defined(vms) */ + +#include + +#if defined (STDC_HEADERS) || defined (USG) +#include +#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 +#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 } +}; + + + + +/* 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); +} diff --git a/getopt/getopt.c b/getopt/getopt.c index ca485b3..7a977ea 100644 --- a/getopt/getopt.c +++ b/getopt/getopt.c @@ -8,6 +8,7 @@ __RCSID("$NetBSD: getopt.c,v 1.5 1998/02/03 03:44:22 perry Exp $"); #include #include #include +#include int main __P((int, char **)); diff --git a/id/id.c b/id/id.c index b8732a0..9ef13b4 100644 --- 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) diff --git a/kill/kill.1 b/kill/kill.1 index 5ad2a47..8e8891d 100644 --- a/kill/kill.1 +++ b/kill/kill.1 @@ -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 @@ -47,20 +46,21 @@ .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 diff --git a/kill/kill.c b/kill/kill.c index f78eba3..f2c56b7 100644 --- a/kill/kill.c +++ b/kill/kill.c @@ -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. @@ -33,18 +31,18 @@ * SUCH DAMAGE. */ -#include #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 @@ -55,11 +53,11 @@ __RCSID("$NetBSD: kill.c,v 1.16 1998/07/28 11:41:49 mycroft Exp $"); #include #include +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 index 0000000..49907b5 --- /dev/null +++ b/killall/Makefile @@ -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 index 0000000..013b558 --- /dev/null +++ b/killall/Makefile.postamble @@ -0,0 +1 @@ +include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common diff --git a/killall/Makefile.preamble b/killall/Makefile.preamble new file mode 100644 index 0000000..9e10e90 --- /dev/null +++ b/killall/Makefile.preamble @@ -0,0 +1 @@ +include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common diff --git a/killall/PB.project b/killall/PB.project new file mode 100644 index 0000000..e69de29 diff --git a/killall/killall.1 b/killall/killall.1 new file mode 100644 index 0000000..69dbc05 --- /dev/null +++ b/killall/killall.1 @@ -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 ) +.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 index 0000000..f31d084 --- /dev/null +++ b/killall/killall.c @@ -0,0 +1,375 @@ +/*- + * Copyright (c) 2000 Peter Wemm + * Copyright (c) 2000 Paul Saab + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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); +} diff --git a/locate/locate/locate.c b/locate/locate/locate.c index a780f05..67e3567 100644 --- a/locate/locate/locate.c +++ b/locate/locate/locate.c @@ -82,6 +82,7 @@ __RCSID("$NetBSD: locate.c,v 1.8 1997/10/19 04:11:56 lukem Exp $"); #include #include #include +#include #include "locate.h" #include "pathnames.h" diff --git a/locate/locate/updatedb.csh b/locate/locate/updatedb.csh index d98f902..88f977e 100644 --- a/locate/locate/updatedb.csh +++ b/locate/locate/updatedb.csh @@ -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 index 0000000..639ea42 --- /dev/null +++ b/mktemp/Makefile @@ -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 index 0000000..013b558 --- /dev/null +++ b/mktemp/Makefile.postamble @@ -0,0 +1 @@ +include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common diff --git a/mktemp/Makefile.preamble b/mktemp/Makefile.preamble new file mode 100644 index 0000000..9e10e90 --- /dev/null +++ b/mktemp/Makefile.preamble @@ -0,0 +1 @@ +include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common diff --git a/mktemp/PB.project b/mktemp/PB.project new file mode 100644 index 0000000..7a07f46 --- /dev/null +++ b/mktemp/PB.project @@ -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 index 0000000..05a2765 --- /dev/null +++ b/mktemp/mktemp.1 @@ -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 index 0000000..46e0c86 --- /dev/null +++ b/mktemp/mktemp.c @@ -0,0 +1,151 @@ +/*- + * Copyright (c) 1994, 1995, 1996, 1998 Peter Wemm + * 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 +#include +#include +#include +#include +#include + +#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); +} diff --git a/pwd/pwd.1 b/pwd/pwd.1 index 8c443c7..4b96209 100644 --- 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. diff --git a/renice/renice.c b/renice/renice.c index ba4a00d..3fd63ce 100644 --- a/renice/renice.c +++ b/renice/renice.c @@ -52,6 +52,7 @@ __RCSID("$NetBSD: renice.c,v 1.5 1997/10/19 14:01:38 lukem Exp $"); #include #include #include +#include int donice __P((int, int, int)); int main __P((int, char **)); diff --git a/su/Makefile b/su/Makefile index 06864a4..838e729 100644 --- a/su/Makefile +++ b/su/Makefile @@ -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) diff --git a/su/Makefile.preamble b/su/Makefile.preamble index 9e10e90..be85883 100644 --- a/su/Makefile.preamble +++ b/su/Makefile.preamble @@ -1 +1,2 @@ include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common +OTHER_CFLAGS = -DUSE_PAM diff --git a/su/su.1 b/su/su.1 index 8ed4b4c..f41431f 100644 --- a/su/su.1 +++ b/su/su.1 @@ -40,55 +40,28 @@ .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 750d02b..2d7018c 100644 --- 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 @@ -33,93 +31,105 @@ * SUCH DAMAGE. */ -#include #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 #include #include +#include + #include #include #include #include #include +#include #include -#ifdef SKEY -#include -#endif #include #include #include -#include -#include #include -#ifdef KERBEROS -#include -#include -#include - -#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 +#include + +#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 diff --git a/test/Makefile.postamble b/test/Makefile.postamble index 75155d2..7d04872 100644 --- a/test/Makefile.postamble +++ b/test/Makefile.postamble @@ -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" diff --git a/true/true.c b/true/true.c index f7af7e9..d973485 100644 --- a/true/true.c +++ b/true/true.c @@ -1 +1,2 @@ +#include int main () { exit(0); } diff --git a/w/uptime.1 b/w/uptime.1 index 85ca182..69b59bd 100644 --- a/w/uptime.1 +++ b/w/uptime.1 @@ -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 3517a2e..2229bfc 100644 --- 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 7e52c79..e94fc0f 100644 --- 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 */ diff --git a/window/Makefile b/window/Makefile index 674ab40..911eed3 100644 --- a/window/Makefile +++ b/window/Makefile @@ -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 diff --git a/window/tt.h b/window/tt.h index 494127d..1a76912 100644 --- a/window/tt.h +++ b/window/tt.h @@ -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. -- 2.45.2