nice nohup printenv printf pwd renice script shlock sleep su\
tee test time true uname users w whereis which who xargs yes
-OTHERSRCS = PROJECT Makefile.preamble Makefile Makefile.postamble Manpages/*.1
+OTHERSRCS = PROJECT Makefile.preamble Makefile Makefile.postamble Manpages/builtin.1
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
CODE_GEN_STYLE = DYNAMIC
PROF_LIBS = $(LIBS)
-NEXTSTEP_PB_CFLAGS = -Wall
+NEXTSTEP_PB_CFLAGS = -Wall -mdynamic-no-pic
NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Postamble.Common
+BUILTIN_LINKS = alias.1 \
+ alloc.1 \
+ bg.1 \
+ bind.1 \
+ bindkey.1 \
+ break.1 \
+ breaksw.1 \
+ builtins.1 \
+ case.1 \
+ cd.1 \
+ chdir.1 \
+ command.1 \
+ complete.1 \
+ continue.1 \
+ default.1 \
+ dirs.1 \
+ do.1 \
+ done.1 \
+ echotc.1 \
+ elif.1 \
+ else.1 \
+ end.1 \
+ endif.1 \
+ endsw.1 \
+ esac.1 \
+ eval.1 \
+ exec.1 \
+ exit.1 \
+ export.1 \
+ fc.1 \
+ fg.1 \
+ fi.1 \
+ filetest.1 \
+ for.1 \
+ foreach.1 \
+ getopts.1 \
+ glob.1 \
+ goto.1 \
+ hash.1 \
+ hashstat.1 \
+ history.1 \
+ hup.1 \
+ if.1 \
+ jobid.1 \
+ jobs.1 \
+ limit.1 \
+ log.1 \
+ logout.1 \
+ ls-F.1 \
+ notify.1 \
+ onintr.1 \
+ popd.1 \
+ pushd.1 \
+ read.1 \
+ readonly.1 \
+ rehash.1 \
+ repeat.1 \
+ return.1 \
+ sched.1 \
+ set.1 \
+ setenv.1 \
+ settc.1 \
+ setty.1 \
+ setvar.1 \
+ shift.1 \
+ source.1 \
+ stop.1 \
+ suspend.1 \
+ switch.1 \
+ telltc.1 \
+ then.1 \
+ times.1 \
+ trap.1 \
+ type.1 \
+ ulimit.1 \
+ umask.1 \
+ unalias.1 \
+ uncomplete.1 \
+ unhash.1 \
+ unlimit.1 \
+ unset.1 \
+ unsetenv.1 \
+ until.1 \
+ wait.1 \
+ where.1 \
+ while.1
+
after_install::
- $(INSTALL_FILE) $(SRCROOT)/Manpages/*.1 $(DSTROOT)/usr/share/man/man1
+ @echo Installing manpage links...
+ @for manpage in $(BUILTIN_LINKS); do \
+ $(LN) -f $(DSTROOT)/usr/share/man/man1/builtin.1 $(DSTROOT)/usr/share/man/man1/$${manpage}; \
+ done
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" $FreeBSD: src/share/man/man1/builtin.1,v 1.20 2002/07/23 14:38:07 tjr Exp $
+.\" $FreeBSD: /repoman/r/ncvs/src/share/man/man1/builtin.1,v 1.25 2005/09/09 17:02:08 garys Exp $
.\"
-.Dd September 1, 1999
+.Dd February 23, 2005
.Dt BUILTIN 1
.Os
.Sh NAME
.Nm builtin ,
+.Nm \&! ,
+.Nm \&% ,
+.Nm \&. ,
+.Nm \&: ,
+.Nm \&@ ,
+.Nm \&{ ,
+.Nm \&} ,
.Nm alias ,
.Nm alloc ,
.Nm bg ,
.Nm jobs ,
.Nm kill ,
.Nm limit ,
+.Nm local ,
.Nm log ,
.Nm login ,
.Nm logout ,
.Nm readonly ,
.Nm rehash ,
.Nm repeat ,
+.Nm return ,
.Nm sched ,
.Nm set ,
.Nm setenv ,
.Nm test ,
.Nm then ,
.Nm time ,
+.Nm times ,
.Nm trap ,
.Nm true ,
.Nm type ,
.Nm where ,
.Nm which ,
.Nm while
-.Nd shell builtin commands
+.Nd shell built-in commands
.Sh SYNOPSIS
.Nm
.Op Fl options
Thus, while specifying
.Dq Ic echo
causes a builtin command to be executed under shells that support the
-builtin echo command,
+.Nm echo
+builtin command,
specifying
-.Dq Pa /bin/echo
+.Dq Ic /bin/echo
or
-.Dq Pa ./echo
+.Dq Ic ./echo
does not.
.Pp
While some builtin commands may exist in more than one shell, their
and
.Xr sh 1
shells are listed here.
-Consult the appropriate manual page for
-details on the operation of any given builtin command under those shells.
-Users of other shells will need to consult the documentation supplied
-with the other shells.
+Consult a shell's manual page for
+details on the operation its builtin commands.
+Beware that the
+.Xr sh 1
+manual page, at least, calls some of these commands
+.Dq built-in commands
+and some of them
+.Dq reserved words .
+Users of other shells may need to consult an
+.Xr info 1
+page or other sources of documentation.
+.Pp
+Commands marked
+.Dq Li No**
+under
+.Em External
+do exist externally,
+but are implemented as scripts using a builtin command of the same name.
.Bl -column ".Ic uncomplete" ".Em External" ".Xr csh 1" ".Xr sh 1" -offset indent
.It Xo
.Em "Command External" Ta Xr csh 1 Ta Xr sh 1
.Xc
-.It Ic alias Ta Yes Ta Yes Ta Yes
+.It Ic ! Ta \&No Ta \&No Ta \&Yes
+.It Ic % Ta \&No Ta Yes Ta \&No
+.It Ic . Ta \&No Ta \&No Ta Yes
+.It Ic : Ta \&No Ta Yes Ta Yes
+.It Ic @ Ta \&No Ta Yes Ta Yes
+.It Ic { Ta \&No Ta \&No Ta \&Yes
+.It Ic } Ta \&No Ta \&No Ta \&Yes
+.It Ic alias Ta \&No** Ta Yes Ta Yes
.It Ic alloc Ta \&No Ta Yes Ta \&No
-.It Ic bg Ta Yes Ta Yes Ta Yes
+.It Ic bg Ta No** Ta Yes Ta Yes
.It Ic bind Ta \&No Ta \&No Ta Yes
.It Ic bindkey Ta \&No Ta Yes Ta \&No
.It Ic break Ta \&No Ta Yes Ta \&Yes
.It Ic breaksw Ta \&No Ta Yes Ta \&No
+.It Ic builtin Ta \&No Ta \&No Ta Yes
.It Ic builtins Ta \&No Ta Yes Ta \&No
.It Ic case Ta \&No Ta Yes Ta Yes
-.It Ic cd Ta Yes Ta Yes Ta Yes
-.It Ic chdir Ta \&No Ta Yes Ta \&No
-.It Ic command Ta Yes Ta \&No Ta Yes
+.It Ic cd Ta \&No** Ta Yes Ta Yes
+.It Ic chdir Ta \&No Ta Yes Ta \&Yes
+.It Ic command Ta \&No** Ta \&No Ta Yes
.It Ic complete Ta \&No Ta Yes Ta \&No
.It Ic continue Ta \&No Ta Yes Ta \&Yes
.It Ic default Ta \&No Ta Yes Ta \&No
.It Ic exit Ta \&No Ta Yes Ta Yes
.It Ic export Ta \&No Ta \&No Ta Yes
.It Ic false Ta Yes Ta \&No Ta Yes
-.It Ic fc Ta Yes Ta \&No Ta Yes
-.It Ic fg Ta Yes Ta Yes Ta Yes
+.It Ic fc Ta \&No** Ta \&No Ta Yes
+.It Ic fg Ta \&No** Ta Yes Ta Yes
.It Ic filetest Ta \&No Ta Yes Ta \&No
.It Ic fi Ta \&No Ta \&No Ta Yes
.It Ic for Ta \&No Ta \&No Ta Yes
.It Ic foreach Ta \&No Ta Yes Ta \&No
-.It Ic getopts Ta Yes Ta \&No Ta Yes
+.It Ic getopts Ta \&No** Ta \&No Ta Yes
.It Ic glob Ta \&No Ta Yes Ta \&No
.It Ic goto Ta \&No Ta Yes Ta \&No
.It Ic hash Ta \&No Ta \&No Ta Yes
.It Ic hup Ta \&No Ta Yes Ta \&No
.It Ic if Ta \&No Ta Yes Ta \&Yes
.It Ic jobid Ta \&No Ta \&No Ta Yes
-.It Ic jobs Ta Yes Ta Yes Ta Yes
+.It Ic jobs Ta \&No** Ta Yes Ta Yes
.It Ic kill Ta Yes Ta Yes Ta \&No
.It Ic limit Ta \&No Ta Yes Ta \&No
+.It Ic local Ta \&No Ta \&No Ta Yes
.It Ic log Ta \&No Ta Yes Ta \&No
.It Ic login Ta Yes Ta Yes Ta \&No
.It Ic logout Ta \&No Ta Yes Ta \&No
.It Ic printenv Ta Yes Ta Yes Ta \&No
.It Ic pushd Ta \&No Ta Yes Ta \&No
.It Ic pwd Ta Yes Ta \&No Ta Yes
-.It Ic read Ta Yes Ta \&No Ta Yes
+.It Ic read Ta \&No** Ta \&No Ta Yes
.It Ic readonly Ta \&No Ta \&No Ta Yes
.It Ic rehash Ta \&No Ta Yes Ta \&No
.It Ic repeat Ta \&No Ta Yes Ta \&No
+.It Ic return Ta \&No Ta \&No Ta Yes
.It Ic sched Ta \&No Ta Yes Ta \&No
.It Ic set Ta \&No Ta Yes Ta \&Yes
.It Ic setenv Ta \&No Ta Yes Ta \&No
.It Ic test Ta Yes Ta \&No Ta Yes
.It Ic then Ta \&No Ta \&No Ta Yes
.It Ic time Ta Yes Ta Yes Ta \&No
+.It Ic times Ta \&No Ta \&No Ta Yes
.It Ic trap Ta \&No Ta \&No Ta Yes
.It Ic true Ta Yes Ta \&No Ta Yes
.It Ic type Ta \&No Ta \&No Ta Yes
.It Ic ulimit Ta \&No Ta \&No Ta Yes
-.It Ic umask Ta Yes Ta Yes Ta Yes
-.It Ic unalias Ta Yes Ta Yes Ta Yes
+.It Ic umask Ta \&No** Ta Yes Ta Yes
+.It Ic unalias Ta \&No** Ta Yes Ta Yes
.It Ic uncomplete Ta \&No Ta Yes Ta \&No
.It Ic unhash Ta \&No Ta Yes Ta \&No
.It Ic unlimit Ta \&No Ta Yes Ta \&No
.It Ic unset Ta \&No Ta Yes Ta Yes
.It Ic unsetenv Ta \&No Ta Yes Ta \&No
.It Ic until Ta \&No Ta \&No Ta Yes
-.It Ic wait Ta Yes Ta Yes Ta Yes
+.It Ic wait Ta \&No** Ta Yes Ta Yes
.It Ic where Ta \&No Ta Yes Ta \&No
.It Ic which Ta Yes Ta Yes Ta \&No
.It Ic while Ta \&No Ta Yes Ta \&Yes
.Xr csh 1 ,
.Xr echo 1 ,
.Xr false 1 ,
+.Xr info 1 ,
.Xr kill 1 ,
.Xr login 1 ,
.Xr nice 1 ,
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
+++ /dev/null
-.so man1/builtin.1
after_install::
mkdir -p "$(DSTROOT)$(INSTALLDIR)"
- install -c -m 555 ./generic.sh $(DSTROOT)$(INSTALLDIR)/alias
+ $(INSTALL_PROGRAM) generic.sh $(DSTROOT)$(INSTALLDIR)/alias
$(LINKPRODUCT) $(DSTROOT)$(INSTALLDIR)/bg
$(LINKPRODUCT) $(DSTROOT)$(INSTALLDIR)/cd
#!/bin/sh
-# $FreeBSD: src/usr.bin/alias/generic.sh,v 1.1 2002/07/16 22:16:03 wollman Exp $
+# $FreeBSD: src/usr.bin/alias/generic.sh,v 1.2 2005/10/24 22:32:19 cperciva Exp $
# This file is in the public domain.
-${0##*/} ${1+"$@"}
+builtin ${0##*/} ${1+"$@"}
PROJECTVERSION = 2.8
PROJECT_TYPE = Tool
-HFILES = extern.h
+HFILES = extern.h vary.h
-CFILES = date.c netdate.c
+CFILES = date.c netdate.c vary.c
OTHERSRCS = Makefile Makefile.preamble Makefile.postamble date.1
+OTHER_CFLAGS = -D__FBSDID=__RCSID
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
CODE_GEN_STYLE = DYNAMIC
-.\" $NetBSD: date.1,v 1.22 1998/06/08 09:07:13 lukem Exp $
-.\"
+.\"-
.\" Copyright (c) 1980, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" 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.
.\" SUCH DAMAGE.
.\"
.\" @(#)date.1 8.3 (Berkeley) 4/28/95
+.\" $FreeBSD: src/bin/date/date.1,v 1.72 2005/02/13 22:25:09 ru Exp $
.\"
-.Dd September 22, 2004
+.Dd August 16, 2007
.Dt DATE 1
.Os
.Sh NAME
.Nd display or set date and time
.Sh SYNOPSIS
.Nm
-.Op Fl nu
+.Op Fl ju
.Op Fl r Ar seconds
-.Op Cm + Ns Ar format
+.Oo
+.Fl v
+.Sm off
+.Op Cm + | -
+.Ar val Op Ar ymwdHMS
+.Sm on
+.Oc
+.Ar ...
+.Op Cm + Ns Ar output_fmt
+.Nm
+.Op Fl jnu
+.Sm off
+.Op Oo Oo Ar mm Oc Ar dd Oc Ar HH
+.Ar MM Oo Oo Ar cc Oc Ar yy Oc Op Ar .ss
+.Sm on
+.Nm
+.Op Fl jnu
+.Fl f Ar input_fmt new_date
+.Op Cm + Ns Ar output_fmt
.Nm
-.Op Fl u
-.Ar mmddhhmm[[cc]yy]
+.Op Fl d Ar dst
+.Op Fl t Ar minutes_west
.Sh DESCRIPTION
+When invoked without arguments, the
.Nm
-displays the current date and time when invoked without arguments.
-Providing arguments will format the date and time in a user-defined
-way or set the date. Only the superuser may set the date.
+utility displays the current date and time.
+Otherwise, depending on the options specified,
+.Nm
+will set the date and time or print it in a user-defined way.
+.Pp
+The
+.Nm
+utility displays the date and time read from the kernel clock.
+When used to set the date and time,
+both the kernel clock and the hardware clock are updated.
+.Pp
+Only the superuser may set the date,
+and if the system securelevel (see
+.Xr securelevel 8 )
+is greater than 1,
+the time may not be changed by more than 1 second.
.Pp
The options are as follows:
.Bl -tag -width Ds
+.It Fl d Ar dst
+Set the kernel's value for daylight saving time.
+If
+.Ar dst
+is non-zero, future calls
+to
+.Xr gettimeofday 2
+will return a non-zero for
+.Fa tz_dsttime .
+.It Fl f
+Use
+.Ar input_fmt
+as the format string to parse the
+.Ar new_date
+provided rather than using the default
+.Sm off
+.Oo Oo Oo
+.Ar mm Oc
+.Ar dd Oc
+.Ar HH Oc
+.Ar MM
+.Oo Oo
+.Ar cc Oc
+.Ar yy Oc Oo
+.Ar .ss Oc
+.Sm on
+format.
+Parsing is done using
+.Xr strptime 3 .
+.It Fl j
+Do not try to set the date.
+This allows you to use the
+.Fl f
+flag in addition to the
+.Cm +
+option to convert one date format to another.
.It Fl n
-The utility
+By default, if the
.Xr timed 8
-is used to synchronize the clocks on groups of machines.
-By default, if
-timed
-is running,
+daemon is running,
.Nm
-will set the time on all of the machines in the local group.
+sets the time on all of the machines in the local group.
The
.Fl n
-option stops
-.Nm
-from setting the time for other than the current machine.
-.It Fl r
-Print out the date and time that is
+option suppresses this behavior and causes the time to be set only on the
+current machine.
+.It Fl r Ar seconds
+Print the date and time represented by
+.Ar seconds ,
+where
.Ar seconds
-from the Epoch.
+is the number of seconds since the Epoch
+(00:00:00 UTC, January 1, 1970;
+see
+.Xr time 3 ) ,
+and can be specified in decimal, octal, or hex.
+.It Fl t Ar minutes_west
+Set the system's value for minutes west of
+.Tn GMT .
+.Ar minutes_west
+specifies the number of minutes returned in
+.Fa tz_minuteswest
+by future calls to
+.Xr gettimeofday 2 .
.It Fl u
Display or set the date in
.Tn UTC
-(universal) time.
+(Coordinated Universal) time.
+.It Fl v
+Adjust (i.e., take the current date and display the result of the
+adjustment; not actually set the date) the second, minute, hour, month
+day, week day, month or year according to
+.Ar val .
+If
+.Ar val
+is preceded with a plus or minus sign,
+the date is adjusted forwards or backwards according to the remaining string,
+otherwise the relevant part of the date is set.
+The date can be adjusted as many times as required using these flags.
+Flags are processed in the order given.
+.Pp
+When setting values
+(rather than adjusting them),
+seconds are in the range 0-59, minutes are in the range 0-59, hours are
+in the range 0-23, month days are in the range 1-31, week days are in the
+range 0-6 (Sun-Sat),
+months are in the range 1-12 (Jan-Dec)
+and years are in the range 80-38 or 1980-2038.
+.Pp
+If
+.Ar val
+is numeric, one of either
+.Ar y ,
+.Ar m ,
+.Ar w ,
+.Ar d ,
+.Ar H ,
+.Ar M
+or
+.Ar S
+must be used to specify which part of the date is to be adjusted.
+.Pp
+The week day or month may be specified using a name rather than a
+number.
+If a name is used with the plus
+(or minus)
+sign, the date will be put forwards
+(or backwards)
+to the next
+(previous)
+date that matches the given week day or month.
+This will not adjust the date,
+if the given week day or month is the same as the current one.
+.Pp
+When a date is adjusted to a specific value or in units greater than hours,
+daylight savings time considerations are ignored.
+Adjustments in units of hours or less honor daylight saving time.
+So, assuming the current date is March 26, 0:30 and that the DST adjustment
+means that the clock goes forward at 01:00 to 02:00, using
+.Fl v No +1H
+will adjust the date to March 26, 2:30.
+Likewise, if the date is October 29, 0:30 and the DST adjustment means that
+the clock goes back at 02:00 to 01:00, using
+.Fl v No +3H
+will be necessary to reach October 29, 2:30.
+.Pp
+When the date is adjusted to a specific value that does not actually exist
+(for example March 26, 1:30 BST 2000 in the Europe/London timezone),
+the date will be silently adjusted forwards in units of one hour until it
+reaches a valid time.
+When the date is adjusted to a specific value that occurs twice
+(for example October 29, 1:30 2000),
+the resulting timezone will be set so that the date matches the earlier of
+the two times.
+.Pp
+Adjusting the date by months is inherently ambiguous because
+a month is a unit of variable length depending on the current date.
+This kind of date adjustment is applied in the most intuitive way.
+First of all,
+.Nm
+tries to preserve the day of the month.
+If it is impossible because the target month is shorter than the present one,
+the last day of the target month will be the result.
+For example, using
+.Fl v No +1m
+on May 31 will adjust the date to June 30, while using the same option
+on January 30 will result in the date adjusted to the last day of February.
+This approach is also believed to make the most sense for shell scripting.
+Nevertheless, be aware that going forth and back by the same number of
+months may take you to a different date.
+.Pp
+Refer to the examples below for further details.
.El
.Pp
-An operand with a leading plus (``+'') sign signals a user-defined format
-string which specifies the format in which to display the date and time.
-The format string may contain any of the conversion specifications described
-in the
+An operand with a leading plus
+.Pq Sq +
+sign signals a user-defined format string
+which specifies the format in which to display the date and time.
+The format string may contain any of the conversion specifications
+described in the
.Xr strftime 3
manual page, as well as any arbitrary text.
-A <newline> character is always output after the characters specified by
+A newline
+.Pq Ql \en
+character is always output after the characters specified by
the format string.
-The format string for the default display is:
-.Bd -literal -offset indent
-``%a %b %e %H:%M:%S %Z %Y''.
-.Ed
+The format string for the default display is
+.Dq +%+ .
.Pp
If an operand does not have a leading plus sign, it is interpreted as
a value for setting the system's notion of the current date and time.
.Pp
.Bl -tag -width Ds -compact -offset indent
.It Ar cc
-The first two digits of the year (the century).
+Century
+(either 19 or 20)
+prepended to the abbreviated year.
.It Ar yy
-The second two digits of the year. If
-.Dq yy
-is specified, but
-.Dq cc
-is not, a value for
-.Dq yy
-between 69 and 99 results in a
-.Dq cc
-value of 19. Otherwise, a
-.Dq cc
-value of 20 is used.
+Year in abbreviated form
+(e.g., 89 for 1989, 06 for 2006).
.It Ar mm
-The month of the year, from 1 to 12.
+Numeric month, a number from 1 to 12.
.It Ar dd
-The day of the month, from 1 to 31.
-.It Ar hh
-The hour of the day, from 0 to 23.
-.It Ar mm
-The minute of the hour, from 0 to 59.
+Day, a number from 1 to 31.
+.It Ar HH
+Hour, a number from 0 to 23.
+.It Ar MM
+Minutes, a number from 0 to 59.
.It Ar ss
-The second of the minute, from 0 to 61.
+Seconds, a number from 0 to 61
+(59 plus a maximum of two leap seconds).
.El
.Pp
Everything but the minutes is optional.
.Pp
-Time changes for Daylight Saving and Standard time and leap seconds
-and years are handled automatically.
-.Sh ENVIRONMENT VARIABLES
+Time changes for Daylight Saving Time, standard time, leap seconds,
+and leap years are handled automatically.
+.Sh ENVIRONMENT
The following environment variables affect the execution of
-.Nm
-:
-.Bl -tag -width TZ
+.Nm :
+.Bl -tag -width Ds
.It Ev TZ
The timezone to use when displaying dates.
+The normal format is a pathname relative to
+.Pa /usr/share/zoneinfo .
+For example, the command
+.Dq TZ=America/Los_Angeles date
+displays the current time in California.
See
.Xr environ 7
for more information.
.El
.Sh FILES
.Bl -tag -width /var/log/messages -compact
-.It Pa /var/log/wtmp
-A record of date resets and time changes.
.It Pa /var/log/messages
-A record of the user setting the time.
+record of the user setting the time
.El
+.Sh EXIT STATUS
+The
+.Nm
+utility exits 0 on success, 1 if unable to set the date, and 2
+if able to set the local date, but unable to set it globally.
.Sh EXAMPLES
The command:
-.Bd -literal -offset indent
-date "+DATE: %m/%d/%y%nTIME: %H:%M:%S"
-.Ed
+.Pp
+.Dl "date ""+DATE: %Y-%m-%d%nTIME: %H:%M:%S"""
.Pp
will display:
.Bd -literal -offset indent
-DATE: 11/21/87
+DATE: 1987-11-21
TIME: 13:36:16
.Ed
.Pp
+In the Europe/London timezone, the command:
+.Pp
+.Dl "date -v1m -v+1y"
+.Pp
+will display:
+.Pp
+.Dl "Sun Jan 4 04:15:24 GMT 1998"
+.Pp
+where it is currently
+.Li "Mon Aug 4 04:15:24 BST 1997" .
+.Pp
+The command:
+.Pp
+.Dl "date -v1d -v3m -v0y -v-1d"
+.Pp
+will display the last day of February in the year 2000:
+.Pp
+.Dl "Tue Feb 29 03:18:00 GMT 2000"
+.Pp
+So will do the command:
+.Pp
+.Dl "date -v30d -v3m -v0y -v-1m"
+.Pp
+because there is no such date as the 30th of February.
+.Pp
The command:
-.Bd -literal -offset indent
-date 061316271985
-.Ed
+.Pp
+.Dl "date -v1d -v+1m -v-1d -v-fri"
+.Pp
+will display the last Friday of the month:
+.Pp
+.Dl "Fri Aug 29 04:31:11 BST 1997"
+.Pp
+where it is currently
+.Li "Mon Aug 4 04:31:11 BST 1997" .
+.Pp
+The command:
+.Pp
+.Dl "date 0613162785"
.Pp
sets the date to
.Dq Li "June 13, 1985, 4:27 PM" .
.Pp
+.Dl "date ""+%Y%m%d%H%M.%S"""
+.Pp
+may be used on one machine to print out the date
+suitable for setting on another.
+.Qq ( Li "+%m%d%H%M%Y.%S"
+for use on
+.Tn Linux . )
+.Pp
The command:
-.Bd -literal -offset indent
-date 1432
-.Ed
+.Pp
+.Dl "date 1432"
.Pp
sets the time to
.Li "2:32 PM" ,
without modifying the date.
-.Sh DIAGNOSTICS
-The following exit values are returned:
- 0 The date was written successfully (either locally or globally)
- >0 An error occurred.
.Pp
+Finally the command:
+.Pp
+.Dl "date -j -f ""%a %b %d %T %Z %Y"" ""`date`"" ""+%s"""
+.Pp
+can be used to parse the output from
+.Nm
+and express it in Epoch time.
+.Sh DIAGNOSTICS
Occasionally, when
.Xr timed 8
-synchronizes the time on many hosts, the setting of a new time value
-may require more than a few seconds.
+synchronizes the time on many hosts, the setting of a new time value may
+require more than a few seconds.
On these occasions,
.Nm
prints:
occurs when the communication
between
.Nm
-and timed fails.
+and
+.Xr timed 8
+fails.
.Sh LEGACY SYNOPSIS
-.Nm
-.Op Fl nu
-.Op Fl r Ar seconds
-.Op Cm + Ns Ar format
+As above, except for the second line, which is:
.Pp
-.Nm " "
-.Ar [[[[[cc]yy]mm]dd]hh]mm[\&.ss]
+.Nm
+.Op Fl jnu
+.Sm off
+.Op Oo Oo Oo Oo Ar cc Oc Ar yy Oc Ar mm Oc Ar dd Oc Ar HH
+.Ar MM Op Ar .ss
+.Sm on
.Sh LEGACY DIAGNOSTICS
-.Pp
-When invoked in legacy mode the following exit values are returned:
- 0 The date was written successfully
- 1 Unable to set the date
- 2 Able to set the local date, but unable to set it globally
+When invoked in legacy mode, the following exit values are returned:
+.Bl -tag -width X -compact
+.It 0
+The date was written successfully
+.It 1
+Unable to set the date
+.It 2
+Able to set the local date, but unable to set it globally
+.El
.Sh SEE ALSO
.Xr gettimeofday 2 ,
.Xr strftime 3 ,
-.Xr compat 5 ,
-.Xr utmp 5 ,
+.Xr strptime 3 ,
+.Xr utmpx 5 ,
.Xr timed 8
.Rs
.%T "TSP: The Time Synchronization Protocol for UNIX 4.3BSD"
.Sh STANDARDS
The
.Nm
-utility supports the
-.St -susv3 .
-It is also expected to be compatible with
+utility is expected to be compatible with
.St -p1003.2 .
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
-/* $NetBSD: date.c,v 1.25 1998/07/28 11:41:47 mycroft Exp $ */
-
-/*
+/*-
* Copyright (c) 1985, 1987, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* 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.
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#ifndef lint
-__COPYRIGHT(
+static char const copyright[] =
"@(#) Copyright (c) 1985, 1987, 1988, 1993\n\
- The Regents of the University of California. All rights reserved.\n");
+ The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
-#ifndef lint
#if 0
+#ifndef lint
static char sccsid[] = "@(#)date.c 8.2 (Berkeley) 4/28/95";
-#else
-__RCSID("$NetBSD: date.c,v 1.25 1998/07/28 11:41:47 mycroft Exp $");
-#endif
#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/date/date.c,v 1.47 2005/01/10 08:39:21 imp Exp $");
#include <sys/param.h>
#include <sys/time.h>
#include <ctype.h>
#include <err.h>
-#include <fcntl.h>
+#include <locale.h>
+#ifndef __APPLE__
+#include <libutil.h>
+#endif /* !__APPLE__ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <locale.h>
#include <syslog.h>
-#include <time.h>
-#include <tzfile.h>
#include <unistd.h>
-#include <util.h>
+#include <utmpx.h>
-#include "get_compat.h"
+#ifdef __APPLE__
+#include <get_compat.h>
+#include <util.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
#include "extern.h"
+#include "vary.h"
-time_t tval;
-int nflag;
-int retval = 0;
-int unix2003_std = 0; /* to determine legacy vs std mode */
+#ifndef TM_YEAR_BASE
+#define TM_YEAR_BASE 1900
+#endif
+
+static time_t tval;
+int retval;
+int unix2003_std = 0; /* to determine legacy vs std mode */
-int main __P((int, char *[]));
-static void setthetime __P((char *));
-static void badformat __P((void));
-static void badtime __P((void));
-static void usage __P((void));
+static void setthetime(const char *, const char *, int, int);
+static void badformat(void);
+static void usage(void);
int
-main(argc, argv)
- int argc;
- char *argv[];
+main(int argc, char *argv[])
{
- extern int optind;
- extern char *optarg;
+ struct timezone tz;
int ch, rflag;
- char *format, buf[1024];
-
- (void)setlocale(LC_ALL, "");
-
- if (compat_mode("bin/date", "unix2003")) /* Determine the STD */
- unix2003_std = 1;
- else
- unix2003_std = 0;
-
+ int jflag, nflag;
+ const char *format;
+ char buf[1024];
+ char *endptr, *fmt;
+ char *tmp;
+ int set_timezone;
+ struct vary *v;
+ const struct vary *badv;
+ struct tm lt;
+
+ unix2003_std = COMPAT_MODE("bin/date", "unix2003"); /* Determine the STD */
+
+ v = NULL;
+ fmt = NULL;
+ (void) setlocale(LC_TIME, "");
+ tz.tz_dsttime = tz.tz_minuteswest = 0;
rflag = 0;
- while ((ch = getopt(argc, argv, "nr:u")) != -1)
+ jflag = nflag = 0;
+ set_timezone = 0;
+ while ((ch = getopt(argc, argv, "d:f:jnr:t:uv:")) != -1)
switch((char)ch) {
+ case 'd': /* daylight savings time */
+ tz.tz_dsttime = strtol(optarg, &endptr, 10) ? 1 : 0;
+ if (endptr == optarg || *endptr != '\0')
+ usage();
+ set_timezone = 1;
+ break;
+ case 'f':
+ fmt = optarg;
+ break;
+ case 'j':
+ jflag = 1; /* don't set time */
+ break;
case 'n': /* don't set network */
nflag = 1;
break;
case 'r': /* user specified seconds */
rflag = 1;
- tval = atol(optarg);
+ tval = strtoq(optarg, &tmp, 0);
+ if (*tmp != 0)
+ usage();
+ break;
+ case 't': /* minutes west of UTC */
+ /* error check; don't allow "PST" */
+ tz.tz_minuteswest = strtol(optarg, &endptr, 10);
+ if (endptr == optarg || *endptr != '\0')
+ usage();
+ set_timezone = 1;
+ break;
+ case 'u': /* do everything in UTC */
+ (void)setenv("TZ", "UTC0", 1);
break;
- case 'u': /* do everything in GMT */
- (void)setenv("TZ", "GMT0", 1);
+ case 'v':
+ v = vary_append(v, optarg);
break;
default:
usage();
argc -= optind;
argv += optind;
+ /*
+ * If -d or -t, set the timezone or daylight savings time; this
+ * doesn't belong here; the kernel should not know about either.
+ */
+ if (set_timezone && settimeofday((struct timeval *)NULL, &tz))
+ err(1, "settimeofday (timezone)");
+
if (!rflag && time(&tval) == -1)
err(1, "time");
- format = "%a %b %e %H:%M:%S %Z %Y";
+ format = "%+";
/* allow the operands in any order */
if (*argv && **argv == '+') {
}
if (*argv) {
- setthetime(*argv);
+ setthetime(fmt, *argv, jflag, nflag);
++argv;
- }
+ } else if (fmt != NULL)
+ usage();
if (*argv && **argv == '+')
format = *argv + 1;
- (void)strftime(buf, sizeof(buf), format, localtime(&tval));
+ lt = *localtime(&tval);
+ badv = vary_apply(v, <);
+ if (badv) {
+ fprintf(stderr, "%s: Cannot apply date adjustment\n",
+ badv->arg);
+ vary_destroy(v);
+ usage();
+ }
+ vary_destroy(v);
+ (void)strftime(buf, sizeof(buf), format, <);
(void)printf("%s\n", buf);
-
- /* if date/time could not be set/notified in the other hosts as
- determined by netsetval() a return value 2 is set, which is
- to be propogated back to shell in the legacy mode.
- */
- if( unix2003_std )
- exit(0); /* set/notify time thru NTPD isn't stds */
- else
- exit(retval); /* Propogate the error condition set, if any */
+ if (fflush(stdout))
+ err(1, "stdout");
+ /*
+ * If date/time could not be set/notified in the other hosts as
+ * determined by netsetval(), a return value 2 is set, which is
+ * only propagated back to shell in legacy mode.
+ */
+ if (unix2003_std)
+ exit(0);
+ exit(retval);
}
#define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))
+#define ATOI2_OFFSET(s, o) (((s)[o] - '0') * 10 + ((s)[o + 1] - '0'))
-void
-setthetime(p)
- char *p;
+static void
+setthetime(const char *fmt, const char *p, int jflag, int nflag)
{
-
struct tm *lt;
- struct timeval tv;
const char *dot, *t;
- int yearset, len;
-
- char tmp1_p[5] = ""; /* to hold ccyy and reformat */
- char tmp2_p[16] = ""; /* ccyyMMddhhmm.ss is 15 chars */
-
- for (t = p, dot = NULL; *t; ++t) {
- if (isdigit(*t))
- continue;
- if (*t == '.' && dot == NULL) {
- dot = t;
- continue;
- }
- badformat();
- }
-
- lt = localtime(&tval);
-
- lt->tm_isdst = -1; /* Divine correct DST */
-
- if (dot != NULL) { /* .ss */
- len = strlen(dot);
- if (len != 3)
+ int century;
+ size_t length;
+
+ if (fmt != NULL) {
+ lt = localtime(&tval);
+ t = strptime(p, fmt, lt);
+ if (t == NULL) {
+ fprintf(stderr, "Failed conversion of ``%s''"
+ " using format ``%s''\n", p, fmt);
badformat();
- ++dot;
- lt->tm_sec = ATOI2(dot);
+ } else if (*t != '\0')
+ fprintf(stderr, "Warning: Ignoring %ld extraneous"
+ " characters in date string (%s)\n",
+ (long) strlen(t), t);
} else {
- len = 0;
- lt->tm_sec = 0;
- }
-
- yearset = 0;
-
- switch (strlen(p) - len) {
- case 12: /* cc */
- if(unix2003_std) {
- /* The last 4 chars are ccyy;
- reformat it to be in the first */
- strncpy(tmp1_p, &p[8], 4);
- tmp1_p[4] = '\0';
- p[8] = '\0'; /* .ss already processed; so no harm */
- strcpy(tmp2_p, p);
- strcpy(p, tmp1_p);
- strcat(p, tmp2_p);
- }
-
- lt->tm_year = ATOI2(p) * 100 - TM_YEAR_BASE;
- yearset = 1;
- /* FALLTHROUGH */
- case 10: /* yy */
- if(unix2003_std) {
- /* The last 2 chars are yy; reformat it to be in the
- first, only if already not done. */
- if (tmp1_p[0] == '\0') {
- strncpy(tmp1_p, &p[8], 2);
- tmp1_p[2] = '\0';
- p[8] = '\0'; /* .ss done; so no harm */
- strcpy(tmp2_p, p);
- strcpy(p, tmp1_p);
- strcat(p, tmp2_p);
- } else
- ; /* do nothing, already reformatted */
+ for (t = p, dot = NULL; *t; ++t) {
+ if (isdigit(*t))
+ continue;
+ if (*t == '.' && dot == NULL) {
+ dot = t;
+ continue;
+ }
+ badformat();
}
- if (yearset) {
- lt->tm_year += ATOI2(p);
- } else {
- yearset = ATOI2(p);
- if (yearset < 69)
- lt->tm_year = yearset + 2000 - TM_YEAR_BASE;
- else
- lt->tm_year = yearset + 1900 - TM_YEAR_BASE;
+ lt = localtime(&tval);
+
+ if (dot != NULL) { /* .ss */
+ dot++; /* *dot++ = '\0'; */
+ if (strlen(dot) != 2)
+ badformat();
+ lt->tm_sec = ATOI2(dot);
+ if (lt->tm_sec > 61)
+ badformat();
+ } else
+ lt->tm_sec = 0;
+
+ century = 0;
+ /* if p has a ".ss" field then let's pretend it's not there */
+ switch (length = strlen(p) - ((dot != NULL) ? 3 : 0)) {
+ case 12: /* cc */
+ lt->tm_year = (unix2003_std ? ATOI2_OFFSET(p, length - 4) : ATOI2(p)) * 100 - TM_YEAR_BASE;
+ century = 1;
+ /* FALLTHROUGH */
+ case 10: /* yy */
+ if (century)
+ lt->tm_year += (unix2003_std ? ATOI2_OFFSET(p, length - 2) : ATOI2(p));
+ else {
+ lt->tm_year = (unix2003_std ? ATOI2_OFFSET(p, length - 2) : ATOI2(p));
+ if (lt->tm_year < 69) /* hack for 2000 ;-} */
+ lt->tm_year += 2000 - TM_YEAR_BASE;
+ else
+ lt->tm_year += 1900 - TM_YEAR_BASE;
+ }
+ /* FALLTHROUGH */
+ case 8: /* mm */
+ lt->tm_mon = ATOI2(p);
+ if (lt->tm_mon > 12)
+ badformat();
+ --lt->tm_mon; /* time struct is 0 - 11 */
+ /* FALLTHROUGH */
+ case 6: /* dd */
+ lt->tm_mday = ATOI2(p);
+ if (lt->tm_mday > 31)
+ badformat();
+ /* FALLTHROUGH */
+ case 4: /* HH */
+ lt->tm_hour = ATOI2(p);
+ if (lt->tm_hour > 23)
+ badformat();
+ /* FALLTHROUGH */
+ case 2: /* MM */
+ lt->tm_min = ATOI2(p);
+ if (lt->tm_min > 59)
+ badformat();
+ break;
+ default:
+ badformat();
}
- /* FALLTHROUGH */
- case 8: /* mm */
- lt->tm_mon = ATOI2(p);
- --lt->tm_mon; /* time struct is 0 - 11 */
- /* FALLTHROUGH */
- case 6: /* dd */
- lt->tm_mday = ATOI2(p);
- /* FALLTHROUGH */
- case 4: /* hh */
- lt->tm_hour = ATOI2(p);
- /* FALLTHROUGH */
- case 2: /* mm */
- lt->tm_min = ATOI2(p);
- break;
- default:
- badformat();
}
+ /* Let mktime() decide whether summer time is in effect. */
+ lt->tm_isdst = -1;
+
/* convert broken-down time to GMT clock time */
if ((tval = mktime(lt)) == -1)
- badtime();
-
- /* set the time */
- if (nflag || netsettime(tval)) {
- logwtmp("|", "date", "");
- tv.tv_sec = tval;
- tv.tv_usec = 0;
- if (settimeofday(&tv, NULL)) {
- perror("date: settimeofday");
- exit(1);
+ errx(1, "nonexistent time");
+
+ if (!jflag) {
+ /* set the time */
+ if (nflag || netsettime(tval)) {
+ struct utmpx ut;
+ bzero(&ut, sizeof(ut));
+ ut.ut_type = OLD_TIME;
+ (void)gettimeofday(&ut.ut_tv, NULL);
+ pututxline(&ut);
+ ut.ut_tv.tv_sec = tval;
+ ut.ut_tv.tv_usec = 0;
+ if (settimeofday(&ut.ut_tv, NULL))
+ err(1, "settimeofday (timeval)");
+ ut.ut_type = NEW_TIME;
+ pututxline(&ut);
}
- logwtmp("{", "date", "");
- }
- if ((p = getlogin()) == NULL)
- p = "???";
- syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p);
+ if ((p = getlogin()) == NULL)
+ p = "???";
+ syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p);
+ }
}
static void
-badformat()
+badformat(void)
{
warnx("illegal time format");
usage();
}
static void
-badtime()
-{
- errx(1, "illegal time");
-}
-
-static void
-usage()
+usage(void)
{
- (void)fprintf(stderr,
- "usage: date [-nu] [-r seconds] [+format]\n");
- if (unix2003_std)
- (void)fprintf(stderr, " date [-u] mmddhhmm[[cc]yy]\n");
- else
- (void)fprintf(stderr, " date [[[[[cc]yy]mm]dd]hh]mm[.ss]\n");
+ (void)fprintf(stderr, "%s\n%s\n",
+ "usage: date [-jnu] [-d dst] [-r seconds] [-t west] "
+ "[-v[+|-]val[ymwdHMS]] ... ",
+ unix2003_std ? " "
+ "[-f fmt date | [[[mm]dd]HH]MM[[cc]yy][.ss]] [+format]" :
+ " "
+ "[-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format]");
exit(1);
- /* NOTREACHED */
}
-/* $NetBSD: extern.h,v 1.3 1995/03/21 09:03:52 cgd Exp $ */
-
/*-
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
* 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.
* SUCH DAMAGE.
*
* @(#)extern.h 8.1 (Berkeley) 5/31/93
+ * $FreeBSD: src/bin/date/extern.h,v 1.7 2004/04/06 20:06:45 markm Exp $
*/
-int netsettime __P((time_t));
+int netsettime(time_t);
-/* $NetBSD: netdate.c,v 1.16 1998/07/28 03:47:15 mycroft Exp $ */
-
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
* 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.
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-#ifndef lint
#if 0
-static char sccsid[] = "@(#)netdate.c 8.2 (Berkeley) 4/28/95";
-#else
-__RCSID("$NetBSD: netdate.c,v 1.16 1998/07/28 03:47:15 mycroft Exp $");
-#endif
+#ifndef lint
+static char sccsid[] = "@(#)netdate.c 8.1 (Berkeley) 5/31/93";
#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/date/netdate.c,v 1.18 2004/04/06 20:06:45 markm Exp $");
#include <sys/param.h>
#include <sys/time.h>
#include <err.h>
#include <errno.h>
-#include <stdio.h>
#include <string.h>
#include <unistd.h>
* Returns 0 on success. Returns > 0 on failure, setting retval to 2;
*/
int
-netsettime(tval)
- time_t tval;
+netsettime(time_t tval)
{
struct timeval tout;
struct servent *sp;
struct tsp msg;
- struct sockaddr_in sin, dest, from;
+ struct sockaddr_in lsin, dest, from;
fd_set ready;
long waittime;
- int s, length, timed_ack, found, error;
-#ifdef IP_PORTRANGE
- int on;
-#endif
- char hostname[MAXHOSTNAMELEN + 1];
+ int s, port, timed_ack, found, lerr;
+ socklen_t length;
+ char hostname[MAXHOSTNAMELEN];
if ((sp = getservbyname("timed", "udp")) == NULL) {
- warnx("udp/timed: unknown service");
+ warnx("timed/udp: unknown service");
return (retval = 2);
}
- (void)memset(&dest, 0, sizeof(dest));
- dest.sin_len = sizeof(struct sockaddr_in);
- dest.sin_family = AF_INET;
dest.sin_port = sp->s_port;
- dest.sin_addr.s_addr = htonl(INADDR_ANY);
+ dest.sin_family = AF_INET;
+ dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY);
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
if (errno != EPROTONOSUPPORT)
return (retval = 2);
}
-#ifdef IP_PORTRANGE
- on = IP_PORTRANGE_LOW;
- if (setsockopt(s, IPPROTO_IP, IP_PORTRANGE, &on, sizeof(on)) < 0) {
- warn("setsockopt");
+ memset(&lsin, 0, sizeof(lsin));
+ lsin.sin_family = AF_INET;
+ for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
+ lsin.sin_port = htons((u_short)port);
+ if (bind(s, (struct sockaddr *)&lsin, sizeof(lsin)) >= 0)
+ break;
+ if (errno == EADDRINUSE)
+ continue;
+ if (errno != EADDRNOTAVAIL)
+ warn("bind");
goto bad;
}
-#endif
-
- (void)memset(&sin, 0, sizeof(sin));
- sin.sin_len = sizeof(struct sockaddr_in);
- sin.sin_family = AF_INET;
- if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
- warn("bind");
+ if (port == IPPORT_RESERVED / 2) {
+ warnx("all ports in use");
goto bad;
}
-
msg.tsp_type = TSP_SETDATE;
msg.tsp_vers = TSPVERSION;
if (gethostname(hostname, sizeof(hostname))) {
warn("gethostname");
goto bad;
}
- hostname[sizeof(hostname) - 1] = '\0';
- (void)strncpy(msg.tsp_name, hostname, sizeof(hostname));
+ (void)strncpy(msg.tsp_name, hostname, sizeof(msg.tsp_name) - 1);
+ msg.tsp_name[sizeof(msg.tsp_name) - 1] = '\0';
msg.tsp_seq = htons((u_short)0);
msg.tsp_time.tv_sec = htonl((u_long)tval);
msg.tsp_time.tv_usec = htonl((u_long)0);
FD_SET(s, &ready);
found = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout);
- length = sizeof(error);
+ length = sizeof(lerr);
if (!getsockopt(s,
- SOL_SOCKET, SO_ERROR, (char *)&error, &length) && error) {
- if (error != ECONNREFUSED)
- warn("send (delayed error)");
+ SOL_SOCKET, SO_ERROR, (char *)&lerr, &length) && lerr) {
+ if (lerr != ECONNREFUSED)
+ warnc(lerr, "send (delayed error)");
goto bad;
}
(void)close(s);
return (0);
default:
- warnx("wrong ack received from timed: %s",
+ warnx("wrong ack received from timed: %s",
tsptype[msg.tsp_type]);
timed_ack = -1;
break;
--- /dev/null
+/*-
+ * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/date/vary.c,v 1.16 2004/08/09 13:43:39 yar Exp $");
+
+#include <err.h>
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include "vary.h"
+
+struct trans {
+ int val;
+ const char *str;
+};
+
+static struct trans trans_mon[] = {
+ { 1, "january" }, { 2, "february" }, { 3, "march" }, { 4, "april" },
+ { 5, "may"}, { 6, "june" }, { 7, "july" }, { 8, "august" },
+ { 9, "september" }, { 10, "october" }, { 11, "november" }, { 12, "december" },
+ { -1, NULL }
+};
+
+static struct trans trans_wday[] = {
+ { 0, "sunday" }, { 1, "monday" }, { 2, "tuesday" }, { 3, "wednesday" },
+ { 4, "thursday" }, { 5, "friday" }, { 6, "saturday" },
+ { -1, NULL }
+};
+
+static char digits[] = "0123456789";
+static int adjhour(struct tm *, char, int, int);
+
+static int
+domktime(struct tm *t, char type)
+{
+ time_t ret;
+
+ while ((ret = mktime(t)) == -1 && t->tm_year > 68 && t->tm_year < 138)
+ /* While mktime() fails, adjust by an hour */
+ adjhour(t, type == '-' ? type : '+', 1, 0);
+
+ return ret;
+}
+
+static int
+trans(const struct trans t[], const char *arg)
+{
+ int f;
+
+ for (f = 0; t[f].val != -1; f++)
+ if (!strncasecmp(t[f].str, arg, 3) ||
+ !strncasecmp(t[f].str, arg, strlen(t[f].str)))
+ return t[f].val;
+
+ return -1;
+}
+
+struct vary *
+vary_append(struct vary *v, char *arg)
+{
+ struct vary *result, **nextp;
+
+ if (v) {
+ result = v;
+ while (v->next)
+ v = v->next;
+ nextp = &v->next;
+ } else
+ nextp = &result;
+
+ if ((*nextp = (struct vary *)malloc(sizeof(struct vary))) == NULL)
+ err(1, "malloc");
+ (*nextp)->arg = arg;
+ (*nextp)->next = NULL;
+ return result;
+}
+
+static int mdays[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+static int
+daysinmonth(const struct tm *t)
+{
+ int year;
+
+ year = t->tm_year + 1900;
+
+ if (t->tm_mon == 1)
+ if (!(year % 400))
+ return 29;
+ else if (!(year % 100))
+ return 28;
+ else if (!(year % 4))
+ return 29;
+ else
+ return 28;
+ else if (t->tm_mon >= 0 && t->tm_mon < 12)
+ return mdays[t->tm_mon];
+
+ return 0;
+}
+
+
+static int
+adjyear(struct tm *t, char type, int val, int mk)
+{
+ switch (type) {
+ case '+':
+ t->tm_year += val;
+ break;
+ case '-':
+ t->tm_year -= val;
+ break;
+ default:
+ t->tm_year = val;
+ if (t->tm_year < 69)
+ t->tm_year += 100; /* as per date.c */
+ else if (t->tm_year > 1900)
+ t->tm_year -= 1900; /* struct tm holds years since 1900 */
+ break;
+ }
+ return !mk || domktime(t, type) != -1;
+}
+
+static int
+adjmon(struct tm *t, char type, int val, int istext, int mk)
+{
+ int lmdays;
+
+ if (val < 0)
+ return 0;
+
+ switch (type) {
+ case '+':
+ if (istext) {
+ if (val <= t->tm_mon)
+ val += 11 - t->tm_mon; /* early next year */
+ else
+ val -= t->tm_mon + 1; /* later this year */
+ }
+ if (val) {
+ if (!adjyear(t, '+', (t->tm_mon + val) / 12, 0))
+ return 0;
+ val %= 12;
+ t->tm_mon += val;
+ if (t->tm_mon > 11)
+ t->tm_mon -= 12;
+ }
+ break;
+
+ case '-':
+ if (istext) {
+ if (val-1 > t->tm_mon)
+ val = 13 - val + t->tm_mon; /* later last year */
+ else
+ val = t->tm_mon - val + 1; /* early this year */
+ }
+ if (val) {
+ if (!adjyear(t, '-', val / 12, 0))
+ return 0;
+ val %= 12;
+ if (val > t->tm_mon) {
+ if (!adjyear(t, '-', 1, 0))
+ return 0;
+ val -= 12;
+ }
+ t->tm_mon -= val;
+ }
+ break;
+
+ default:
+ if (val > 12 || val < 1)
+ return 0;
+ t->tm_mon = --val;
+ }
+
+ /* e.g., -v-1m on March, 31 is the last day of February in common sense */
+ lmdays = daysinmonth(t);
+ if (t->tm_mday > lmdays)
+ t->tm_mday = lmdays;
+
+ return !mk || domktime(t, type) != -1;
+}
+
+static int
+adjday(struct tm *t, char type, int val, int mk)
+{
+ int lmdays;
+
+ switch (type) {
+ case '+':
+ while (val) {
+ lmdays = daysinmonth(t);
+ if (val > lmdays - t->tm_mday) {
+ val -= lmdays - t->tm_mday + 1;
+ t->tm_mday = 1;
+ if (!adjmon(t, '+', 1, 0, 0))
+ return 0;
+ } else {
+ t->tm_mday += val;
+ val = 0;
+ }
+ }
+ break;
+ case '-':
+ while (val)
+ if (val >= t->tm_mday) {
+ val -= t->tm_mday;
+ t->tm_mday = 1;
+ if (!adjmon(t, '-', 1, 0, 0))
+ return 0;
+ t->tm_mday = daysinmonth(t);
+ } else {
+ t->tm_mday -= val;
+ val = 0;
+ }
+ break;
+ default:
+ if (val > 0 && val <= daysinmonth(t))
+ t->tm_mday = val;
+ else
+ return 0;
+ break;
+ }
+
+ return !mk || domktime(t, type) != -1;
+}
+
+static int
+adjwday(struct tm *t, char type, int val, int istext, int mk)
+{
+ if (val < 0)
+ return 0;
+
+ switch (type) {
+ case '+':
+ if (istext)
+ if (val < t->tm_wday)
+ val = 7 - t->tm_wday + val; /* early next week */
+ else
+ val -= t->tm_wday; /* later this week */
+ else
+ val *= 7; /* "-v+5w" == "5 weeks in the future" */
+ return !val || adjday(t, '+', val, mk);
+ case '-':
+ if (istext) {
+ if (val > t->tm_wday)
+ val = 7 - val + t->tm_wday; /* later last week */
+ else
+ val = t->tm_wday - val; /* early this week */
+ } else
+ val *= 7; /* "-v-5w" == "5 weeks ago" */
+ return !val || adjday(t, '-', val, mk);
+ default:
+ if (val < t->tm_wday)
+ return adjday(t, '-', t->tm_wday - val, mk);
+ else if (val > 6)
+ return 0;
+ else if (val > t->tm_wday)
+ return adjday(t, '+', val - t->tm_wday, mk);
+ }
+ return 1;
+}
+
+static int
+adjhour(struct tm *t, char type, int val, int mk)
+{
+ if (val < 0)
+ return 0;
+
+ switch (type) {
+ case '+':
+ if (val) {
+ int days;
+
+ days = (t->tm_hour + val) / 24;
+ val %= 24;
+ t->tm_hour += val;
+ t->tm_hour %= 24;
+ if (!adjday(t, '+', days, 0))
+ return 0;
+ }
+ break;
+
+ case '-':
+ if (val) {
+ int days;
+
+ days = val / 24;
+ val %= 24;
+ if (val > t->tm_hour) {
+ days++;
+ val -= 24;
+ }
+ t->tm_hour -= val;
+ if (!adjday(t, '-', days, 0))
+ return 0;
+ }
+ break;
+
+ default:
+ if (val > 23)
+ return 0;
+ t->tm_hour = val;
+ }
+
+ return !mk || domktime(t, type) != -1;
+}
+
+static int
+adjmin(struct tm *t, char type, int val, int mk)
+{
+ if (val < 0)
+ return 0;
+
+ switch (type) {
+ case '+':
+ if (val) {
+ if (!adjhour(t, '+', (t->tm_min + val) / 60, 0))
+ return 0;
+ val %= 60;
+ t->tm_min += val;
+ if (t->tm_min > 59)
+ t->tm_min -= 60;
+ }
+ break;
+
+ case '-':
+ if (val) {
+ if (!adjhour(t, '-', val / 60, 0))
+ return 0;
+ val %= 60;
+ if (val > t->tm_min) {
+ if (!adjhour(t, '-', 1, 0))
+ return 0;
+ val -= 60;
+ }
+ t->tm_min -= val;
+ }
+ break;
+
+ default:
+ if (val > 59)
+ return 0;
+ t->tm_min = val;
+ }
+
+ return !mk || domktime(t, type) != -1;
+}
+
+static int
+adjsec(struct tm *t, char type, int val, int mk)
+{
+ if (val < 0)
+ return 0;
+
+ switch (type) {
+ case '+':
+ if (val) {
+ if (!adjmin(t, '+', (t->tm_sec + val) / 60, 0))
+ return 0;
+ val %= 60;
+ t->tm_sec += val;
+ if (t->tm_sec > 59)
+ t->tm_sec -= 60;
+ }
+ break;
+
+ case '-':
+ if (val) {
+ if (!adjmin(t, '-', val / 60, 0))
+ return 0;
+ val %= 60;
+ if (val > t->tm_sec) {
+ if (!adjmin(t, '-', 1, 0))
+ return 0;
+ val -= 60;
+ }
+ t->tm_sec -= val;
+ }
+ break;
+
+ default:
+ if (val > 59)
+ return 0;
+ t->tm_sec = val;
+ }
+
+ return !mk || domktime(t, type) != -1;
+}
+
+const struct vary *
+vary_apply(const struct vary *v, struct tm *t)
+{
+ char type;
+ char which;
+ char *arg;
+ size_t len;
+ int val;
+
+ for (; v; v = v->next) {
+ type = *v->arg;
+ arg = v->arg;
+ if (type == '+' || type == '-')
+ arg++;
+ else
+ type = '\0';
+ len = strlen(arg);
+ if (len < 2)
+ return v;
+
+ if (type == '\0')
+ t->tm_isdst = -1;
+
+ if (strspn(arg, digits) != len-1) {
+ val = trans(trans_wday, arg);
+ if (val != -1) {
+ if (!adjwday(t, type, val, 1, 1))
+ return v;
+ } else {
+ val = trans(trans_mon, arg);
+ if (val != -1) {
+ if (!adjmon(t, type, val, 1, 1))
+ return v;
+ } else
+ return v;
+ }
+ } else {
+ val = atoi(arg);
+ which = arg[len-1];
+
+ switch (which) {
+ case 'S':
+ if (!adjsec(t, type, val, 1))
+ return v;
+ break;
+ case 'M':
+ if (!adjmin(t, type, val, 1))
+ return v;
+ break;
+ case 'H':
+ if (!adjhour(t, type, val, 1))
+ return v;
+ break;
+ case 'd':
+ t->tm_isdst = -1;
+ if (!adjday(t, type, val, 1))
+ return v;
+ break;
+ case 'w':
+ t->tm_isdst = -1;
+ if (!adjwday(t, type, val, 0, 1))
+ return v;
+ break;
+ case 'm':
+ t->tm_isdst = -1;
+ if (!adjmon(t, type, val, 0, 1))
+ return v;
+ break;
+ case 'y':
+ t->tm_isdst = -1;
+ if (!adjyear(t, type, val, 1))
+ return v;
+ break;
+ default:
+ return v;
+ }
+ }
+ }
+ return 0;
+}
+
+void
+vary_destroy(struct vary *v)
+{
+ struct vary *n;
+
+ while (v) {
+ n = v->next;
+ free(v);
+ v = n;
+ }
+}
--- /dev/null
+/*-
+ * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/bin/date/vary.h,v 1.4 1999/08/27 23:14:00 peter Exp $
+ */
+
+struct vary {
+ char *arg;
+ struct vary *next;
+};
+
+extern struct vary *vary_append(struct vary *v, char *arg);
+extern const struct vary *vary_apply(const struct vary *v, struct tm *t);
+extern void vary_destroy(struct vary *v);
OTHERSRCS = Makefile Makefile.preamble Makefile.postamble echo.1
+OTHER_CFLAGS = -D__FBSDID=__RCSID
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
CODE_GEN_STYLE = DYNAMIC
+.\"-
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" 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.
.\" SUCH DAMAGE.
.\"
.\" @(#)echo.1 8.1 (Berkeley) 7/22/93
-.\" $FreeBSD: src/bin/echo/echo.1,v 1.13 2001/08/15 09:09:35 ru Exp $
+.\" $FreeBSD: src/bin/echo/echo.1,v 1.19 2005/01/16 16:41:56 ru Exp $
.\"
-.Dd July 22, 1993
+.Dd April 12, 2003
.Dt ECHO 1
.Os
.Sh NAME
The following option is available:
.Bl -tag -width flag
.It Fl n
-Do not print the trailing newline character. This may also be
-achieved by appending
+Do not print the trailing newline character.
+This may also be achieved by appending
.Ql \ec
to the end of the string, as is done
by iBCS2 compatible systems.
+Note that this option as well as the effect of
+.Ql \ec
+are implementation-defined in
+.St -p1003.1-2001
+as amended by Cor.\& 1-2002.
+Applications aiming for maximum
+portability are strongly encouraged to use
+.Xr printf 1
+to suppress the newline character.
.El
.Pp
Some shells may provide a builtin
.Nm
command which is similar or identical to this utility.
+.\" 4874742
+Most notably, the builtin
+.Nm
+in
+.Xr sh 1
+does not accept the
+.Fl n
+option.
+.\" 4874742
Consult the
.Xr builtin 1
manual page.
-.Sh DIAGNOSTICS
+.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
.Xr builtin 1 ,
.Sh STANDARDS
The
.Nm
-utility is expected to be
-.St -p1003.2
-compatible.
+utility conforms to
+.St -p1003.1-2001
+as amended by Cor.\& 1-2002.
-/*
+/*-
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* 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.
* SUCH DAMAGE.
*/
+#if 0
#ifndef lint
static char const copyright[] =
"@(#) Copyright (c) 1989, 1993\n\
#endif /* not lint */
#ifndef lint
-#if 0
static char sccsid[] = "@(#)echo.c 8.1 (Berkeley) 5/31/93";
-#endif
#endif /* not lint */
+#endif
#include <sys/cdefs.h>
-__RCSID("$FreeBSD: src/bin/echo/echo.c,v 1.13 2002/06/30 05:13:53 obrien Exp $");
+__FBSDID("$FreeBSD: src/bin/echo/echo.c,v 1.18 2005/01/10 08:39:22 imp Exp $");
-#include <stdio.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
-/* ARGSUSED */
+/*
+ * Report an error and exit.
+ * Use it instead of err(3) to avoid linking-in stdio.
+ */
+static void
+errexit(const char *prog, const char *reason)
+{
+ char *errstr = strerror(errno);
+ write(STDERR_FILENO, prog, strlen(prog));
+ write(STDERR_FILENO, ": ", 2);
+ write(STDERR_FILENO, reason, strlen(reason));
+ write(STDERR_FILENO, ": ", 2);
+ write(STDERR_FILENO, errstr, strlen(errstr));
+ write(STDERR_FILENO, "\n", 1);
+ exit(1);
+}
+
int
main(int argc, char *argv[])
{
int nflag; /* if not set, output a trailing newline. */
+ int veclen; /* number of writev arguments. */
+ struct iovec *iov, *vp; /* Elements to write, current element. */
+ char space[] = " ";
+ char newline[] = "\n";
+ char *progname = argv[0];
/* This utility may NOT do getopt(3) option parsing. */
if (*++argv && !strcmp(*argv, "-n")) {
++argv;
+ --argc;
nflag = 1;
- }
- else
+ } else
nflag = 0;
+ veclen = (argc >= 2) ? (argc - 2) * 2 + 1 : 0;
+
+ if ((vp = iov = malloc((veclen + 1) * sizeof(struct iovec))) == NULL)
+ errexit(progname, "malloc");
+
while (argv[0] != NULL) {
+ size_t len;
+
+ len = strlen(argv[0]);
/*
* If the next argument is NULL then this is this
* for a trailing \c.
*/
if (argv[1] == NULL) {
- size_t len;
-
- len = strlen(argv[0]);
/* is there room for a '\c' and is there one? */
if (len >= 2 &&
argv[0][len - 2] == '\\' &&
argv[0][len - 1] == 'c') {
/* chop it and set the no-newline flag. */
- argv[0][len - 2] = '\0';
+ len -= 2;
nflag = 1;
}
}
- (void)printf("%s", argv[0]);
- if (*++argv)
- putchar(' ');
+ vp->iov_base = *argv;
+ vp++->iov_len = len;
+ if (*++argv) {
+ vp->iov_base = space;
+ vp++->iov_len = 1;
+ }
+ }
+ if (!nflag) {
+ veclen++;
+ vp->iov_base = newline;
+ vp++->iov_len = 1;
+ }
+ /* assert(veclen == (vp - iov)); */
+ while (veclen) {
+ int nwrite;
+
+ nwrite = (veclen > IOV_MAX) ? IOV_MAX : veclen;
+ if (writev(STDOUT_FILENO, iov, nwrite) == -1)
+ errexit(progname, "write");
+ iov += nwrite;
+ veclen -= nwrite;
}
- if (!nflag)
- putchar('\n');
return 0;
}
struct val *
eval6()
{
- struct val *v;
+ struct val *v;
if (token == OPERAND) {
nexttoken();
v = eval0();
if (token != LP)
- error();
+ error();
+
nexttoken();
return v;
} else {
- error();
+
+ switch (token) {
+ case DIV:
+ nexttoken();
+ tokval = make_str("/");
+ break;
+ case MUL:
+ nexttoken();
+ tokval = make_str("*");
+ break;
+ case OR:
+ nexttoken();
+ tokval = make_str("|");
+ break;
+ case AND:
+ nexttoken();
+ tokval = make_str("&");
+ break;
+ case EQ:
+ nexttoken();
+ tokval = make_str("=");
+ break;
+ case LT:
+ nexttoken();
+ tokval = make_str("<");
+ break;
+ case GT:
+ nexttoken();
+ tokval = make_str(">");
+ break;
+ case ADD:
+ nexttoken();
+ tokval = make_str("+");
+ break;
+ case SUB:
+ nexttoken();
+ tokval = make_str("-");
+ break;
+ case MOD:
+ nexttoken();
+ tokval = make_str("%");
+ break;
+ case NE:
+ nexttoken();
+ tokval = make_str("!=");
+ break;
+ case LE:
+ nexttoken();
+ tokval = make_str("<=");
+ break;
+ case MATCH:
+ nexttoken();
+ tokval = make_str(":");
+ break;
+ case GE:
+ nexttoken();
+ tokval = make_str(">=");
+ break;
+ case EOI:
+ error();
+ }
+ return tokval;
}
/* NOTREACHED */
}
(void) setlocale(LC_ALL, "");
av = argv + 1;
- if (!strcmp(*av, "--"))
+ if (*av && !strcmp(*av, "--"))
av++;
nexttoken();
vp = eval0();
HFILES = extern.h find.h
-CFILES = find.c function.c ls.c main.c misc.c operator.c option.c y.tab.c
+CFILES = find.c function.c ls.c main.c misc.c operator.c option.c
+
+OTHERLINKED = getdate.y
+OTHERLINKEDOFILES = getdate.o
OTHERSRCS = Makefile Makefile.preamble Makefile.postamble find.1
+OTHER_CFLAGS = -D__FBSDID=__RCSID -D_DARWIN_USE_64_BIT_INODE
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
CODE_GEN_STYLE = DYNAMIC
* SUCH DAMAGE.
*
* @(#)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 $
+ * $FreeBSD: src/usr.bin/find/extern.h,v 1.23 2006/05/14 20:23:00 krion Exp $
*/
#include <sys/cdefs.h>
-void brace_subst __P((char *, char **, char *, int));
-void *emalloc __P((unsigned int));
-PLAN *find_create __P((char ***));
-int find_execute __P((PLAN *, char **));
-PLAN *find_formplan __P((char **));
-PLAN *not_squish __P((PLAN *));
-PLAN *or_squish __P((PLAN *));
-PLAN *paren_squish __P((PLAN *));
+void brace_subst(char *, char **, char *, int);
+PLAN *find_create(char ***);
+int find_execute(PLAN *, char **);
+PLAN *find_formplan(char **);
+PLAN *not_squish(PLAN *);
+PLAN *or_squish(PLAN *);
+PLAN *paren_squish(PLAN *);
+struct timeb;
+time_t get_date(char *, struct timeb *);
struct stat;
-void printlong __P((char *, char *, struct stat *));
-int queryuser __P((char **));
-OPTION *option __P((char *));
+void printlong(char *, char *, struct stat *);
+int queryuser(char **);
+OPTION *lookup_option(const char *);
+void finish_execplus(void);
creat_f c_Xmin;
creat_f c_Xtime;
+creat_f c_acl;
creat_f c_and;
creat_f c_delete;
creat_f c_depth;
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;
exec_f f_Xmin;
exec_f f_Xtime;
+exec_f f_acl;
exec_f f_always_true;
exec_f f_closeparen;
exec_f f_delete;
+exec_f f_depth;
exec_f f_empty;
exec_f f_exec;
exec_f f_expr;
extern int ftsoptions, isdeprecated, isdepth, isoutput, issort, isxargs;
extern int mindepth, maxdepth;
extern int regexp_flags;
+extern time_t now;
+extern int dotfd;
+extern FTS *tree;
+.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" This code is derived from software contributed to Berkeley by
.\" SUCH DAMAGE.
.\"
.\" @(#)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 $
+.\" $FreeBSD: src/usr.bin/find/find.1,v 1.81 2006/12/13 17:02:50 ru Exp $
.\"
-.Dd May 3, 2001
+.Dd December 13, 2006
.Dt FIND 1
.Os
.Sh NAME
.Op Fl H | Fl L | Fl P
.Op Fl EXdsx
.Op Fl f Ar pathname
+.Ar pathname ...
+.Ar expression
+.Nm
+.Op Fl H | Fl L | Fl P
+.Op Fl EXdsx
+.Fl f Ar pathname
.Op Ar pathname ...
.Ar expression
.Sh DESCRIPTION
-.Nm Find
-recursively descends the directory tree for each
+The
+.Nm
+utility recursively descends the directory tree for each
.Ar pathname
listed, evaluating an
.Ar expression
.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
+Cause the file information and file type (see
.Xr stat 2 )
returned for each symbolic link specified on the command line to be
those of the file referenced by the link, not the link itself.
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
+Cause 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.
+.Pp
+This option is equivalent to the deprecated
+.Ic -follow
+primary.
.It Fl P
-The
-.Fl P
-option causes the file information and file type (see
+Cause the file information and file type (see
.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
-option is a modification to permit
+Permit
.Nm
to be safely used in conjunction with
.Xr xargs 1 .
quotes, backslash
.Pq Dq Li \e ,
space, tab and newline characters.
+.Pp
+However, you may wish to consider the
+.Fl print0
+primary in conjunction with
+.Dq Nm xargs Fl 0
+as an effective alternative.
.It Fl d
-The
-.Fl d
-option causes
+Cause
.Nm
-to perform a depth\-first traversal, i.e., directories
-are visited in post\-order and all entries in a directory will be acted
+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
.Em not
-a breadth\-first traversal.
+a breadth-first traversal.
+.Pp
+This option is equivalent to the
+.Ic -depth
+primary of
+.St -p1003.1-2001 .
+.Fl d
+can be useful when
+.Nm
+is used with
+.Xr cpio 1
+to process files that are contained in directories with unusual permissions.
+It ensures that you have write permission while you are placing files in a
+directory, then sets the directory's permissions as the last thing.
.It Fl f
-The
-.Fl f
-option specifies a file hierarchy for
+Specify a file hierarchy for
.Nm
to traverse.
File hierarchies may also be specified as the operands immediately
following the options.
.It Fl s
-The
-.Fl s
-option causes
+Cause
.Nm
to traverse the file hierarchies in lexicographical order,
i.e., alphabetical order within each directory.
.Ql "find | sort"
may give different results.
.It Fl x
-The
-.Fl x
-option prevents
+Prevent
.Nm
from descending into directories that have a device number different
than that of the file from which the descent began.
+.Pp
+This option is equivalent to the deprecated
+.Ic -xdev
+primary.
.El
.Sh PRIMARIES
.Bl -tag -width indent
+.It Ic -Bmin Ar n
+True if the difference between the time of a file's inode creation
+and the time
+.Nm
+was started, rounded up to the next full minute, is
+.Ar n
+minutes.
+.It Ic -Bnewer Ar file
+Same as
+.Ic -newerBm .
+.It Ic -Btime Ar n Ns Op Cm smhdw
+If no units are specified, this primary evaluates to
+true if the difference between the time of a file's inode creation
+and the time
+.Nm
+was started, rounded up to the next full 24-hour period, is
+.Ar n
+24-hour periods.
+.Pp
+If units are specified, this primary evaluates to
+true if the difference between the time of a file's inode creation
+and the time
+.Nm
+was started is exactly
+.Ar n
+units.
+Please refer to the
+.Ic -atime
+primary description for information on supported time units.
+.\" .It Ic -acl
+.\" May be used in conjunction with other options to locate
+.\" files with extended ACLs.
+.\" See
+.\" .Xr acl 3
+.\" for more information.
.It Ic -amin Ar n
True if the difference between the file last access time and the time
.Nm
.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
+.It Ic -atime Ar n Ns Op Cm smhdw
+If no units are specified, this primary evaluates to
+true if the difference between the file last access time and the time
+.Nm
+was started, rounded up to the next full 24-hour period, is
+.Ar n
+24-hour periods.
+.Pp
+If units are specified, this primary evaluates to
+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
+was started is exactly
.Ar n
-24\-hour periods.
+units.
+Possible time units are as follows:
+.Pp
+.Bl -tag -width indent -compact
+.It Cm s
+second
+.It Cm m
+minute (60 seconds)
+.It Cm h
+hour (60 minutes)
+.It Cm d
+day (24 hours)
+.It Cm w
+week (7 days)
+.El
+.Pp
+Any number of units may be combined in one
+.Ic -atime
+argument, for example,
+.Dq Li "-atime -1h30m" .
+Units are probably only useful when used in conjunction with the
+.Cm +
+or
+.Cm -
+modifier.
.It Ic -cmin Ar n
True if the difference between the time of last change of file status
information and the time
.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
+.It Ic -ctime Ar n Ns Op Cm smhdw
+If no units are specified, this primary evaluates to
+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
+was started, rounded up to the next full 24-hour period, is
.Ar n
-24\-hour periods.
+24-hour periods.
+.Pp
+If units are specified, this primary evaluates to
+true if the difference between the time of last change of file status
+information and the time
+.Nm
+was started is exactly
+.Ar n
+units.
+Please refer to the
+.Ic -atime
+primary description for information on supported time units.
.It Ic -delete
Delete found files and/or directories.
Always returns true.
character in its pathname relative to
.Dq Pa \&.
for security reasons.
-Depth\-first traversal processing is implied by this option.
+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 -depth Ar n
+True if the depth of the file relative to the starting point of the traversal
+is
+.Ar n .
.It Ic -empty
True if the current file or directory is empty.
-.It Ic -exec Ar utility Op Ar argument ... ;
+.It Ic -exec Ar utility Oo Ar argument ... Oc Li \&;
True if the program named
.Ar utility
returns a zero value as its exit status.
may be passed to the utility.
The expression must be terminated by a semicolon
.Pq Dq Li \&; .
+If you invoke
+.Nm
+from a shell you may need to quote the semicolon if the shell would
+otherwise treat it as a control operator.
If the string
.Dq Li {}
appears anywhere in the utility name or the
.Ar arguments
are not subject to the further expansion of shell patterns
and constructs.
-.It Ic -execdir Ar utility Op Ar argument ... ;
+.It Ic -exec Ar utility Oo Ar argument ... Oc Li {} +
+Same as
+.Ic -exec ,
+except that
+.Dq Li {}
+is replaced with as many pathnames as possible for each invocation of
+.Ar utility .
+This behaviour is similar to that of
+.Xr xargs 1 .
+.It Ic -execdir Ar utility Oo Ar argument ... Oc Li \&;
The
.Ic -execdir
primary is identical to the
.Ar type .
The
.Xr sysctl 8
-command can be used to find out the types of filesystems
+command can be used to find out the types of file systems
that are available on the system:
.Pp
.Dl "sysctl vfs"
.It Ic -ls
This primary always evaluates to true.
The following information for the current file is written to standard output:
-its inode number, size in 512\-byte blocks, file permissions, number of hard
+its inode number, size in 512-byte blocks, file permissions, number of hard
links, owner, group, size in bytes, last modification time, and pathname.
If the file is a block or character special file, the major and minor numbers
will be displayed instead of the size in bytes.
-If the file is a symbolic link, the pathname of the linked\-to file will be
+If the file is a symbolic link, the pathname of the linked-to file will be
displayed preceded by
.Dq Li -> .
The format is identical to that produced by
.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 .
+Always true; descend at most
+.Ar n
+directory levels below the command line arguments.
+If any
+.Ic -maxdepth
+primary is specified, it applies to the entire expression even if it would
+not normally be evaluated.
+.Ic -maxdepth Li 0
+limits the whole search to the command line arguments.
.It Ic -mindepth Ar n
-True if the depth of the current file into the tree is greater than or equal to
+Always true; do not apply any tests or actions at levels less than
.Ar n .
+If any
+.Ic -mindepth
+primary is specified, it applies to the entire expression even if it would
+not normally be evaluated.
+.Ic -mindepth Li 1
+processes all but the command line arguments.
.It Ic -mmin Ar n
True if the difference between the file last modification time and the time
.Nm
.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
+.It Ic -mtime Ar n Ns Op Cm smhdw
+If no units are specified, this primary evaluates to
+true if the difference between the file last modification time and the time
+.Nm
+was started, rounded up to the next full 24-hour period, is
+.Ar n
+24-hour periods.
+.Pp
+If units are specified, this primary evaluates to
+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
+was started is exactly
.Ar n
-24\-hour periods.
+units.
+Please refer to the
+.Ic -atime
+primary description for information on supported time units.
.It Ic -name Ar pattern
True if the last component of the pathname being examined matches
.Ar pattern .
.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 ) ,
+inode creation time
+.Ar ( X Ns = Ns Cm B ) ,
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 ) ,
+inode creation time
+.Ar ( Y Ns = Ns Cm B ) ,
change time
.Ar ( Y Ns = Ns Cm c ) ,
or modification time
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 ... ;
+.It Ic -ok Ar utility Oo Ar argument ... Oc Li \&;
The
.Ic -ok
primary is identical to the
.Ar utility
by printing
a message to the terminal and reading a response.
-If the response is other than
-.Dq Li y
+If the response is not affirmative
+.Ql ( y
+in the
+.Dq Li POSIX
+locale),
the command is not executed and the
value of the
.Ic -ok
expression is false.
-.It Ic -okdir Ar utility Op Ar argument ... ;
+.It Ic -okdir Ar utility Oo Ar argument ... Oc Li \&;
The
.Ic -okdir
primary is identical to the
This primary always evaluates to true.
It prints the pathname of the current file to standard output.
If none of
-.Ic -exec , -ls , -print0 ,
+.\" 4772561
+.Ic -exec , -ls , -print , -print0 ,
or
.Ic -ok
is specified, the given expression shall be effectively replaced by
.It Ic -print0
This primary always evaluates to true.
It prints the pathname of the current file to standard output, followed by an
-.Tn ASCII NUL
+.Tn ASCII
+.Dv NUL
character (character code 0).
.It Ic -prune
This primary always evaluates to true.
.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
+.It Ic -size Ar n Ns Op Cm ckMGTP
+True if the file's size, rounded up, in 512-byte blocks is
.Ar n .
If
.Ar n
file's size is
.Ar n
bytes (characters).
+Similarly if
+.Ar n
+is followed by a scale indicator then the file's size is compared to
+.Ar n
+scaled as:
+.Pp
+.Bl -tag -width indent -compact
+.It Cm k
+kilobytes (1024 bytes)
+.It Cm M
+megabytes (1024 kilobytes)
+.It Cm G
+gigabytes (1024 megabytes)
+.It Cm T
+terabytes (1024 gigabytes)
+.It Cm P
+petabytes (1024 terabytes)
+.El
+.Pp
.It Ic -type Ar t
True if the file is of the specified type.
Possible file types are as follows:
This evaluates to true if the parenthesized expression evaluates to
true.
.Pp
-.It Cm \&! Ar expression
+.It Cm \&! Ar expression
.It Cm -false Ar expression
.It Cm -not Ar expression
This is the unary
Primaries which themselves take arguments expect each argument
to be a separate argument to
.Nm .
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL , LC_COLLATE , LC_CTYPE , LC_MESSAGES
+and
+.Ev LC_TIME
+environment variables affect the execution of the
+.Nm
+utility as described in
+.Xr environ 7 .
.Sh EXAMPLES
The following examples are shown as given to the shell:
.Bl -tag -width indent
.Dq wnj
or that are newer than
.Pa ttt .
-.It Li "find . -newerct '1 minute ago' -print"
+.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.
+.It Li "find / -type f -exec echo {} \e;"
+Use the
+.Xr echo 1
+command to print out a list of all the files.
+.It Li "find -L /usr/ports/packages -type l -delete"
+Delete all broken symbolic links in
+.Pa /usr/ports/packages .
+.It Li "find /usr/src -name CVS -prune -o -depth +6 -print"
+Find files and directories that are at least seven levels deep
+in the working directory
+.Pa /usr/src .
+.It Li "find /usr/src -name CVS -prune -o -mindepth 7 -print"
+Is not equivalent to the previous example, since
+.Ic -prune
+is not evaluated below level seven.
.El
+.Sh COMPATIBILITY
+The
+.Ic -follow
+primary is deprecated; the
+.Fl L
+option should be used instead.
+See the
+.Sx STANDARDS
+section below for details.
.Sh SEE ALSO
.Xr chflags 1 ,
.Xr chmod 1 ,
.Xr locate 1 ,
.Xr whereis 1 ,
.Xr which 1 ,
+.Xr xargs 1 ,
.Xr stat 2 ,
+.\" .Xr acl 3 ,
.Xr fts 3 ,
.Xr getgrent 3 ,
.Xr getpwent 3 ,
The
.Nm
utility syntax is a superset of the syntax specified by the
-.St -p1003.2
+.St -p1003.1-2001
standard.
.Pp
-All the single character options as well as the
-.Ic -iname , -inum , -iregex , -print0 , -delete , -ls ,
+All the single character options except
+.Ic -H
and
-.Ic -regex
-primaries are extensions to
-.St -p1003.2 .
+.Ic -L
+as well as
+.Ic -amin , -anewer , -cmin , -cnewer , -delete , -empty , -fstype ,
+.Ic -iname , -inum , -iregex , -ls , -maxdepth , -mindepth , -mmin ,
+.Ic -path , -print0 , -regex
+and all of the
+.Ic -B
+birthtime related primaries are extensions to
+.St -p1003.1-2001 .
.Pp
Historically, the
-.Fl d , h
+.Fl d , L
and
.Fl x
options were implemented using the primaries
.Pp
The
.Fl E
-option was implemented on the analogy of
+option was inspired by the equivalent
.Xr grep 1
and
-.Xr sed 1 .
+.Xr sed 1
+options.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
.Sh BUGS
The special characters used by
.Nm
.Pp
The
.Ic -delete
-primary does not interact well with other options that cause the filesystem
+primary does not interact well with other options that cause the file system
tree traversal options to be changed.
-.Sh HISTORY
-A
-.Nm
-command appeared in
-.At v1 .
+.Pp
+The
+.Ic -mindepth
+and
+.Ic -maxdepth
+primaries are actually global options (as documented above).
+They should
+probably be replaced by options which look like options.
#if 0
static char sccsid[] = "@(#)find.c 8.5 (Berkeley) 8/5/94";
#else
-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 */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/find.c,v 1.18 2006/05/14 20:23:00 krion Exp $");
+
#include <sys/types.h>
#include <sys/stat.h>
#include <fts.h>
#include <regex.h>
#include <stdio.h>
-#include <string.h>
#include <stdlib.h>
-#include <unistd.h>
+#include <string.h>
#ifdef __APPLE__
-#include "get_compat.h"
+#include <get_compat.h>
+#include <unistd.h>
#else
#define COMPAT_MODE(func, mode) 1
#endif
#include "find.h"
-static int find_compare __P((const FTSENT **s1, const FTSENT **s2));
+static int find_compare(const FTSENT * const *s1, const FTSENT * const *s2);
/*
* find_compare --
* order within each directory.
*/
static int
-find_compare(s1, s2)
- const FTSENT **s1, **s2;
+find_compare(const FTSENT * const *s1, const FTSENT * const *s2)
{
return (strcoll((*s1)->fts_name, (*s2)->fts_name));
* command arguments.
*/
PLAN *
-find_formplan(argv)
- char **argv;
+find_formplan(char *argv[])
{
PLAN *plan, *tail, *new;
*/
if (!isoutput) {
OPTION *p;
- char **argv = 0;
+ char **argv1 = 0;
if (plan == NULL) {
- p = option("-print");
- new = (p->create)(p, &argv);
+ p = lookup_option("-print");
+ new = (p->create)(p, &argv1);
tail = plan = new;
} else {
- p = option("(");
- new = (p->create)(p, &argv);
+ p = lookup_option("(");
+ new = (p->create)(p, &argv1);
new->next = plan;
plan = new;
- p = option(")");
- new = (p->create)(p, &argv);
+ p = lookup_option(")");
+ new = (p->create)(p, &argv1);
tail->next = new;
tail = new;
- p = option("-print");
- new = (p->create)(p, &argv);
+ p = lookup_option("-print");
+ new = (p->create)(p, &argv1);
tail->next = new;
tail = new;
}
* over all FTSENT's returned for the given search paths.
*/
int
-find_execute(plan, paths)
- PLAN *plan; /* search plan */
- char **paths; /* array of pathnames to traverse */
+find_execute(PLAN *plan, char *paths[])
{
- register FTSENT *entry;
+ FTSENT *entry;
PLAN *p;
int rval;
- char **myPaths;
- int nonSearchableDirFound = 0;
- int pathIndex;
+ char **myPaths;
+ int nonSearchableDirFound = 0;
+ int pathIndex;
struct stat statInfo;
/* special-case directories specified on command line - explicitly examine
err(1, "ftsopen");
for (rval = nonSearchableDirFound; (entry = fts_read(tree)) != NULL;) {
+ if (maxdepth != -1 && entry->fts_level >= maxdepth) {
+ if (fts_set(tree, entry, FTS_SKIP))
+ err(1, "%s", entry->fts_path);
+ }
+
switch (entry->fts_info) {
case FTS_D:
if (isdepth)
* the work specified by the user on the command line.
*/
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;
- }
}
+ free (myPaths);
+ finish_execplus();
if (errno)
err(1, "fts_read");
-
- for (p = plan; p; p = p->next) {
- if (p->flags & F_CLEANUP) (p->execute)(p, NULL);
- }
-
- free (myPaths);
+ fts_close(tree);
return (rval);
}
* SUCH DAMAGE.
*
* @(#)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 $
+ * $FreeBSD: src/usr.bin/find/find.h,v 1.19 2006/05/14 20:23:01 krion Exp $
*/
#include <regex.h>
struct _option;
/* execute function */
-typedef int exec_f __P((struct _plandata *, FTSENT *));
+typedef int exec_f(struct _plandata *, FTSENT *);
/* create function */
typedef struct _plandata *creat_f(struct _option *, char ***);
#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 */
+#define F_DEPTH F_TIME_A /* -depth n vs. -d */
/* command line function modifiers */
#define F_EQUAL 0x00000000 /* [acm]min [acm]time inum links size */
#define F_LESSTHAN 0x00000100
#define F_MTMASK 0x00003000
#define F_MTFLAG 0x00000000 /* fstype */
#define F_MTTYPE 0x00001000
+#define F_MTUNKNOWN 0x00002000
#define F_IGNCASE 0x00010000 /* iname ipath iregex */
-#define F_CLEANUP 0x00020000 /* need an extra cleanup call at the end*/
+#define F_EXACTTIME F_IGNCASE /* -[acm]time units syntax */
+#define F_EXECPLUS 0x00020000 /* -exec ... {} + */
+#define F_TIME_B 0x00040000 /* one of -Btime, -Bnewer, -newerB* */
+#define F_TIME2_B 0x00080000 /* one of -newer?B */
/* node definition */
typedef struct _plandata {
u_long _f_notflags;
} fl;
nlink_t _l_data; /* link count */
+ short _d_data; /* level depth (-1 to N) */
off_t _o_data; /* file size */
time_t _t_data; /* time value */
uid_t _u_data; /* uid */
char **_e_argv; /* argv array */
char **_e_orig; /* original strings */
int *_e_len; /* allocated length */
+ int _e_pbnum; /* base num. of args. used */
+ int _e_ppos; /* number of arguments used */
+ int _e_pnummax; /* max. number of arguments */
+ int _e_psize; /* number of bytes of args. */
+ int _e_pbsize; /* base num. of bytes of args */
+ int _e_psizemax; /* max num. of bytes of args */
+ struct _plandata *_e_next;/* next F_EXECPLUS in tree */
} ex;
char *_a_data[2]; /* array of char pointers */
char *_c_data; /* char pointer */
} PLAN;
#define a_data p_un._a_data
#define c_data p_un._c_data
+#define d_data p_un._d_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 e_argv p_un.ex._e_argv
#define e_orig p_un.ex._e_orig
#define e_len p_un.ex._e_len
+#define e_pbnum p_un.ex._e_pbnum
+#define e_ppos p_un.ex._e_ppos
+#define e_pnummax p_un.ex._e_pnummax
+#define e_psize p_un.ex._e_psize
+#define e_pbsize p_un.ex._e_pbsize
+#define e_psizemax p_un.ex._e_psizemax
+#define e_next p_un.ex._e_next
typedef struct _option {
- char *name; /* option name */
+ const char *name; /* option name */
creat_f *create; /* create function */
exec_f *execute; /* execute function */
int flags;
#ifndef lint
#if 0
-static const char sccsid[] = "@(#)function.c 8.10 (Berkeley) 5/4/95";
-#else
-static const char rcsid[] =
- "$FreeBSD: src/usr.bin/find/function.c,v 1.22.2.9 2001/09/19 09:44:24 ru Exp $";
+static const char sccsid[] = "@(#)function.c 8.10 (Berkeley) 5/4/95";
#endif
#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/function.c,v 1.58 2006/05/27 18:27:41 krion Exp $");
+
#include <sys/param.h>
#include <sys/ucred.h>
#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/acl.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <sys/timeb.h>
-#include <sys/types.h>
-#include <sys/sysctl.h>
#include <dirent.h>
#include <err.h>
#include <fnmatch.h>
#include <fts.h>
#include <grp.h>
+#include <limits.h>
#include <pwd.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <ctype.h>
#include "find.h"
#ifdef __APPLE__
-#include "get_compat.h"
+#include <sys/sysctl.h>
+#include <get_compat.h>
#else
#define COMPAT_MODE(func, mode) 1
#endif
-time_t get_date __P((char *date, struct timeb *now));
+static PLAN *palloc(OPTION *);
+static long long find_parsenum(PLAN *, const char *, char *, char *);
+static long long find_parsetime(PLAN *, const char *, char *);
+static char *nextarg(OPTION *, char ***);
+
+extern char **environ;
+
+static PLAN *lastexecplus = NULL;
-#define COMPARE(a, b) { \
+#define COMPARE(a, b) do { \
switch (plan->flags & F_ELG_MASK) { \
case F_EQUAL: \
return (a == b); \
default: \
abort(); \
} \
-}
+} while(0)
static PLAN *
-palloc(option)
- OPTION *option;
+palloc(OPTION *option)
{
PLAN *new;
* Parse a string of the form [+-]# and return the value.
*/
static long long
-find_parsenum(plan, option, vp, endch)
- PLAN *plan;
- char *option, *vp, *endch;
+find_parsenum(PLAN *plan, const char *option, char *vp, char *endch)
{
long long value;
char *endchar, *str; /* Pointer to character ending conversion. */
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))
+ if (endchar[0] && endch == NULL)
errx(1, "%s: %s: illegal trailing character", option, vp);
if (endch)
*endch = endchar[0];
return value;
}
+/*
+ * find_parsetime --
+ * Parse a string of the form [+-]([0-9]+[smhdw]?)+ and return the value.
+ */
+static long long
+find_parsetime(PLAN *plan, const char *option, char *vp)
+{
+ long long secs, value;
+ char *str, *unit; /* Pointer to character ending conversion. */
+
+ /* Determine comparison from leading + or -. */
+ str = vp;
+ switch (*str) {
+ case '+':
+ ++str;
+ plan->flags |= F_GREATER;
+ break;
+ case '-':
+ ++str;
+ plan->flags |= F_LESSTHAN;
+ break;
+ default:
+ plan->flags |= F_EQUAL;
+ break;
+ }
+
+ value = strtoq(str, &unit, 10);
+ if (value == 0 && unit == str) {
+ errx(1, "%s: %s: illegal time value", option, vp);
+ /* NOTREACHED */
+ }
+ if (*unit == '\0')
+ return value;
+
+ /* Units syntax. */
+ secs = 0;
+ for (;;) {
+ switch(*unit) {
+ case 's': /* seconds */
+ secs += value;
+ break;
+ case 'm': /* minutes */
+ secs += value * 60;
+ break;
+ case 'h': /* hours */
+ secs += value * 3600;
+ break;
+ case 'd': /* days */
+ secs += value * 86400;
+ break;
+ case 'w': /* weeks */
+ secs += value * 604800;
+ break;
+ default:
+ errx(1, "%s: %s: bad unit '%c'", option, vp, *unit);
+ /* NOTREACHED */
+ }
+ str = unit + 1;
+ if (*str == '\0') /* EOS */
+ break;
+ value = strtoq(str, &unit, 10);
+ if (value == 0 && unit == str) {
+ errx(1, "%s: %s: illegal time value", option, vp);
+ /* NOTREACHED */
+ }
+ if (*unit == '\0') {
+ errx(1, "%s: %s: missing trailing unit", option, vp);
+ /* NOTREACHED */
+ }
+ }
+ plan->flags |= F_EXACTTIME;
+ return secs;
+}
+
/*
* 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;
+nextarg(OPTION *option, char ***argvp)
{
char *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".
+ * The value of n for the inode times (atime, birthtime, ctime, 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) \
if (((p)->flags & F_ELG_MASK) == F_LESSTHAN) \
*
* True if the difference between the
* file access time (-amin)
+ * file birth time (-Bmin)
* last change of file status information (-cmin)
* file modification time (-mmin)
* and the current time is n min periods.
*/
int
-f_Xmin(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_Xmin(PLAN *plan, FTSENT *entry)
{
- extern time_t now;
-
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 if (plan->flags & F_TIME_B) {
+ COMPARE((now - entry->fts_statp->st_birthtime +
+ 60 - 1) / 60, plan->t_data);
} else {
COMPARE((now - entry->fts_statp->st_mtime +
60 - 1) / 60, plan->t_data);
}
PLAN *
-c_Xmin(option, argvp)
- OPTION *option;
- char ***argvp;
+c_Xmin(OPTION *option, char ***argvp)
{
char *nmins;
PLAN *new;
*
* True if the difference between the
* file access time (-atime)
+ * file birth time (-Btime)
* last change of file status information (-ctime)
* file modification time (-mtime)
* and the current time is n 24 hour periods.
*/
int
-f_Xtime(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_Xtime(PLAN *plan, FTSENT *entry)
{
- extern time_t now;
-
- int fudge = COMPAT_MODE("bin/find", "unix2003") ? 0 : 86400 - 1;
+ time_t xtime;
+
+ if (plan->flags & F_TIME_A)
+ xtime = entry->fts_statp->st_atime;
+ else if (plan->flags & F_TIME_B)
+ xtime = entry->fts_statp->st_birthtime;
+ else if (plan->flags & F_TIME_C)
+ xtime = entry->fts_statp->st_ctime;
+ else
+ xtime = entry->fts_statp->st_mtime;
- if (plan->flags & F_TIME_C) {
- COMPARE((now - entry->fts_statp->st_ctime +
- fudge) / 86400, plan->t_data);
- } else if (plan->flags & F_TIME_A) {
- COMPARE((now - entry->fts_statp->st_atime +
- fudge) / 86400, plan->t_data);
- } else {
- COMPARE((now - entry->fts_statp->st_mtime +
- fudge) / 86400, plan->t_data);
- }
+ if (COMPAT_MODE("bin/find", "unix2003") || plan->flags & F_EXACTTIME)
+ COMPARE((now - xtime) / 86400, plan->t_data);
+ else
+ COMPARE((now - xtime + 86400 - 1) / 86400, plan->t_data);
}
PLAN *
-c_Xtime(option, argvp)
- OPTION *option;
- char ***argvp;
+c_Xtime(OPTION *option, char ***argvp)
{
- char *ndays;
+ char *value;
PLAN *new;
- ndays = nextarg(option, argvp);
+ value = nextarg(option, argvp);
ftsoptions &= ~FTS_NOSTAT;
new = palloc(option);
- new->t_data = find_parsenum(new, option->name, ndays, NULL);
- TIME_CORRECT(new);
+ new->t_data = find_parsetime(new, option->name, value);
+ if (!(new->flags & F_EXACTTIME))
+ TIME_CORRECT(new);
return new;
}
* find_execute() so their f_* functions are set to f_always_true().
*/
PLAN *
-c_mXXdepth(option, argvp)
- OPTION *option;
- char ***argvp;
+c_mXXdepth(OPTION *option, char ***argvp)
{
char *dstr;
PLAN *new;
return new;
}
+#ifndef __APPLE__
+/*
+ * -acl function --
+ *
+ * Show files with EXTENDED ACL attributes.
+ */
+int
+f_acl(PLAN *plan __unused, FTSENT *entry)
+{
+ int match, entries;
+ acl_entry_t ae;
+ acl_t facl;
+
+ if (S_ISLNK(entry->fts_statp->st_mode))
+ return 0;
+ if ((match = pathconf(entry->fts_accpath, _PC_ACL_EXTENDED)) <= 0) {
+ if (match < 0 && errno != EINVAL)
+ warn("%s", entry->fts_accpath);
+ else
+ return 0;
+ }
+ match = 0;
+ if ((facl = acl_get_file(entry->fts_accpath,ACL_TYPE_ACCESS)) != NULL) {
+ if (acl_get_entry(facl, ACL_FIRST_ENTRY, &ae) == 1) {
+ /*
+ * POSIX.1e requires that ACLs of type ACL_TYPE_ACCESS
+ * must have at least three entries (owner, group,
+ * other).
+ */
+ entries = 1;
+ while (acl_get_entry(facl, ACL_NEXT_ENTRY, &ae) == 1) {
+ if (++entries > 3) {
+ match = 1;
+ break;
+ }
+ }
+ }
+ acl_free(facl);
+ } else
+ warn("%s", entry->fts_accpath);
+ return match;
+}
+
+PLAN *
+c_acl(OPTION *option, char ***argvp __unused)
+{
+ ftsoptions &= ~FTS_NOSTAT;
+ return (palloc(option));
+}
+#endif /* !__APPLE__ */
+
/*
* -delete functions --
*
* True always. Makes its best shot and continues on regardless.
*/
int
-f_delete(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_delete(PLAN *plan __unused, FTSENT *entry)
{
/* ignore these from fts */
if (strcmp(entry->fts_accpath, ".") == 0 ||
}
PLAN *
-c_delete(option, argvp)
- OPTION *option;
- char ***argvp;
+c_delete(OPTION *option, char ***argvp __unused)
{
ftsoptions &= ~FTS_NOSTAT; /* no optimise */
/*
- * -depth functions --
+ * always_true --
*
- * Always true, causes descent of the directory hierarchy to be done
- * so that all entries in a directory are acted on before the directory
- * itself.
+ * Always true, used for -maxdepth, -mindepth, -xdev and -follow
*/
int
-f_always_true(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_always_true(PLAN *plan __unused, FTSENT *entry __unused)
{
return 1;
}
+/*
+ * -depth functions --
+ *
+ * With argument: True if the file is at level n.
+ * Without argument: Always true, causes descent of the directory hierarchy
+ * to be done so that all entries in a directory are acted on before the
+ * directory itself.
+ */
+int
+f_depth(PLAN *plan, FTSENT *entry)
+{
+ if (plan->flags & F_DEPTH)
+ COMPARE(entry->fts_level, plan->d_data);
+ else
+ return 1;
+}
+
PLAN *
-c_depth(option, argvp)
- OPTION *option;
- char ***argvp;
+c_depth(OPTION *option, char ***argvp)
{
- isdepth = 1;
+ PLAN *new;
+ char *str;
- return palloc(option);
-}
+ new = palloc(option);
+
+ str = **argvp;
+ if (str && !(new->flags & F_DEPTH)) {
+ /* skip leading + or - */
+ if (*str == '+' || *str == '-')
+ str++;
+ /* skip sign */
+ if (*str == '+' || *str == '-')
+ str++;
+ if (isdigit(*str))
+ new->flags |= F_DEPTH;
+ }
+ if (new->flags & F_DEPTH) { /* -depth n */
+ char *ndepth;
+
+ ndepth = nextarg(option, argvp);
+ new->d_data = find_parsenum(new, option->name, ndepth, NULL);
+ } else { /* -d */
+ isdepth = 1;
+ }
+
+ return new;
+}
+
/*
* -empty functions --
*
* True if the file or directory is empty
*/
int
-f_empty(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_empty(PLAN *plan __unused, FTSENT *entry)
{
if (S_ISREG(entry->fts_statp->st_mode) &&
entry->fts_statp->st_size == 0)
}
PLAN *
-c_empty(option, argvp)
- OPTION *option;
- char ***argvp;
+c_empty(OPTION *option, char ***argvp __unused)
{
ftsoptions &= ~FTS_NOSTAT;
* of the user before executing the utility.
*/
int
-f_exec(plan, entry)
- register PLAN *plan;
- FTSENT *entry;
+f_exec(PLAN *plan, FTSENT *entry)
{
- extern int dotfd;
- register int cnt;
+ int cnt;
pid_t pid;
int status;
- char *file = NULL;
- static char **plus_path = NULL;
- static int plus_path_cnt = 0;
- static unsigned long exec_after = 0;
- static unsigned long path_so_far = 0;
- struct _ex saved_ex;
-
- if (entry) {
- /* XXX - if file/dir ends in '/' this will not work -- can it? */
- if ((plan->flags & F_EXECDIR) &&
- (file = strrchr(entry->fts_path, '/'))) {
+ char *file;
+
+ if (entry == NULL && plan->flags & F_EXECPLUS) {
+ if (plan->e_ppos == plan->e_pbnum)
+ return (1);
+ plan->e_argv[plan->e_ppos] = NULL;
+ goto doexec;
+ }
+
+ /* XXX - if file/dir ends in '/' this will not work -- can it? */
+ if ((plan->flags & F_EXECDIR) && \
+ (file = strrchr(entry->fts_path, '/')))
file++;
- } else {
+ else
file = entry->fts_path;
- }
-
- if (plan->flags & F_CLEANUP) {
- plus_path = realloc(plus_path, sizeof(char *) * ++plus_path_cnt);
- if (!plus_path) errx(1, "out of memory");
- plus_path[plus_path_cnt -1] = strdup(file);
- if (!plus_path[plus_path_cnt -1]) errx(1, "out of memory");
-
- path_so_far += sizeof(char *) + strlen(file);
-
- if (!exec_after) {
- size_t l = sizeof(exec_after);
- int rc =
- sysctlbyname("kern.argmax", &exec_after, &l, NULL, NULL);
- if (rc < 0) {
- /* Something conservitave */
- exec_after = 16 * 1024;
- }
- }
- if (path_so_far >= exec_after) {
- return f_exec(plan, NULL);
- }
- return 1;
- }
+ if (plan->flags & F_EXECPLUS) {
+ if ((plan->e_argv[plan->e_ppos] = strdup(file)) == NULL)
+ err(1, NULL);
+ plan->e_len[plan->e_ppos] = strlen(file);
+ plan->e_psize += plan->e_len[plan->e_ppos];
+ if (++plan->e_ppos < plan->e_pnummax &&
+ plan->e_psize < plan->e_psizemax)
+ return (1);
+ plan->e_argv[plan->e_ppos] = NULL;
} else {
- if (!plus_path) return 1;
- saved_ex = plan->p_un.ex;
- int new_len = 0;
- int ocnt;
- for(cnt = 0; plan->e_argv[cnt]; ++cnt) {
- if (plan->e_len[cnt]) {
- new_len += plus_path_cnt;
- } else {
- new_len++;
- }
- }
- new_len++;
-
- plan->e_argv = malloc(sizeof(char *) * new_len);
- if (!plan->e_argv) errx(1, "out of memory");
-
- for(ocnt = cnt = 0; saved_ex._e_argv[ocnt]; ++ocnt) {
- if (saved_ex._e_len[ocnt]) {
- int ppi;
- for(ppi = 0; ppi < plus_path_cnt; ++ppi) {
- plan->e_argv[cnt++] = plus_path[ppi];
- }
-#if 0
- memmove(plan->e_argv + cnt, *plus_path,
- sizeof(char *) * plus_path_cnt);
- cnt += plus_path_cnt;
-#endif
- } else {
- plan->e_argv[cnt++] = saved_ex._e_argv[ocnt];
- }
- }
- plan->e_argv[cnt++] = NULL;
+ for (cnt = 0; plan->e_argv[cnt]; ++cnt)
+ if (plan->e_len[cnt])
+ brace_subst(plan->e_orig[cnt],
+ &plan->e_argv[cnt], file,
+ plan->e_len[cnt]);
}
- if (!(plan->flags & F_CLEANUP)) for (cnt = 0; plan->e_argv[cnt]; ++cnt)
- if (plan->e_len[cnt])
- brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt],
- file, plan->e_len[cnt]);
-
- if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv))
+doexec: if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv))
return 0;
/* make sure find output is interspersed correctly with subprocesses */
warn("%s", plan->e_argv[0]);
_exit(1);
}
- pid = waitpid(pid, &status, 0);
- if (plus_path) {
- int i;
- for(i = 0; i < plus_path_cnt; ++i) {
- free(plus_path[i]);
- }
- free(plus_path);
- plus_path = NULL;
- plus_path_cnt = 0;
- plan->p_un.ex = saved_ex;
- path_so_far = 0;
- if (WIFEXITED(status) && WEXITSTATUS(status)) {
- exit(WEXITSTATUS(status));
- }
+ if (plan->flags & F_EXECPLUS) {
+ while (--plan->e_ppos >= plan->e_pbnum)
+ free(plan->e_argv[plan->e_ppos]);
+ plan->e_ppos = plan->e_pbnum;
+ plan->e_psize = plan->e_pbsize;
}
+ pid = waitpid(pid, &status, 0);
+ if (plan->flags & F_EXECPLUS && WIFEXITED(status) && WEXITSTATUS(status))
+ _exit(WEXITSTATUS(status));
return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
}
* strings, but also flags meaning that the string has to be massaged.
*/
PLAN *
-c_exec(option, argvp)
- OPTION *option;
- char ***argvp;
+c_exec(OPTION *option, char ***argvp)
{
PLAN *new; /* node returned */
- register int cnt;
- register char **argv, **ap, *p;
- int plus_armed = 0;
+ long argmax;
+ int cnt, i;
+ char **argv, **ap, **ep, *p;
/* XXX - was in c_execdir, but seems unnecessary!?
ftsoptions &= ~FTS_NOSTAT;
for (ap = argv = *argvp;; ++ap) {
if (!*ap)
errx(1,
- "%s: no terminating \";\"", option->name);
- if (**ap == '{' && ap[0][1] == '}' && ap[0][2] == '\0') {
- plus_armed = COMPAT_MODE("bin/find", "unix2003");
- continue;
- }
- if (**ap == ';') {
+ "%s: no terminating \";\" or \"+\"", option->name);
+ if (**ap == ';')
break;
- }
- if (plus_armed && **ap == '+') {
- new->flags |= F_CLEANUP;
+ if (**ap == '+' && ap != argv && strcmp(*(ap - 1), "{}") == 0) {
+ new->flags |= F_EXECPLUS;
break;
}
- plus_armed = 0;
}
+ if (ap == argv)
+ errx(1, "%s: no command specified", option->name);
+
cnt = ap - *argvp + 1;
- new->e_argv = (char **)emalloc((u_int)cnt * sizeof(char *));
- new->e_orig = (char **)emalloc((u_int)cnt * sizeof(char *));
- new->e_len = (int *)emalloc((u_int)cnt * sizeof(int));
+ if (new->flags & F_EXECPLUS) {
+ new->e_ppos = new->e_pbnum = cnt - 2;
+ if ((argmax = sysconf(_SC_ARG_MAX)) == -1) {
+ warn("sysconf(_SC_ARG_MAX)");
+ argmax = _POSIX_ARG_MAX;
+ }
+ argmax -= 1024;
+ for (ep = environ; *ep != NULL; ep++)
+ argmax -= strlen(*ep) + 1 + sizeof(*ep);
+ argmax -= 1 + sizeof(*ep);
+ new->e_pnummax = argmax / 16;
+ argmax -= sizeof(char *) * new->e_pnummax;
+ if (argmax <= 0)
+ errx(1, "no space for arguments");
+ new->e_psizemax = argmax;
+ new->e_pbsize = 0;
+ cnt += new->e_pnummax + 1;
+ new->e_next = lastexecplus;
+ lastexecplus = new;
+ }
+ if ((new->e_argv = malloc(cnt * sizeof(char *))) == NULL)
+ err(1, NULL);
+ if ((new->e_orig = malloc(cnt * sizeof(char *))) == NULL)
+ err(1, NULL);
+ if ((new->e_len = malloc(cnt * sizeof(int))) == NULL)
+ err(1, NULL);
for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
new->e_orig[cnt] = *argv;
+ if (new->flags & F_EXECPLUS)
+ new->e_pbsize += strlen(*argv) + 1;
for (p = *argv; *p; ++p)
- if (p[0] == '{' && p[1] == '}') {
- new->e_argv[cnt] = emalloc((u_int)MAXPATHLEN);
+ if (!(new->flags & F_EXECPLUS) && p[0] == '{' &&
+ p[1] == '}') {
+ if ((new->e_argv[cnt] =
+ malloc(MAXPATHLEN)) == NULL)
+ err(1, NULL);
new->e_len[cnt] = MAXPATHLEN;
break;
}
new->e_len[cnt] = 0;
}
}
+ if (new->flags & F_EXECPLUS) {
+ new->e_psize = new->e_pbsize;
+ cnt--;
+ for (i = 0; i < new->e_pnummax; i++) {
+ new->e_argv[cnt] = NULL;
+ new->e_len[cnt] = 0;
+ cnt++;
+ }
+ argv = ap;
+ goto done;
+ }
new->e_argv[cnt] = new->e_orig[cnt] = NULL;
- *argvp = argv + 1;
+done: *argvp = argv + 1;
return new;
}
+/* Finish any pending -exec ... {} + functions. */
+void
+finish_execplus()
+{
+ PLAN *p;
+
+ p = lastexecplus;
+ while (p != NULL) {
+ (p->execute)(p, NULL);
+ p = p->e_next;
+ }
+}
+
int
-f_flags(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_flags(PLAN *plan, FTSENT *entry)
{
u_long flags;
}
PLAN *
-c_flags(option, argvp)
- OPTION *option;
- char ***argvp;
+c_flags(OPTION *option, char ***argvp)
{
char *flags_str;
PLAN *new;
* basis.
*/
PLAN *
-c_follow(option, argvp)
- OPTION *option;
- char ***argvp;
+c_follow(OPTION *option, char ***argvp __unused)
{
ftsoptions &= ~FTS_PHYSICAL;
ftsoptions |= FTS_LOGICAL;
* True if the file is of a certain type.
*/
int
-f_fstype(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_fstype(PLAN *plan, FTSENT *entry)
{
static dev_t curdev; /* need a guaranteed illegal dev value */
static int first = 1;
struct statfs sb;
static int val_type, val_flags;
- char *p, save[2];
+ char *p, save[2] = {0,0};
+
+ if ((plan->flags & F_MTMASK) == F_MTUNKNOWN)
+ return 0;
/* Only check when we cross mount point. */
if (first || curdev != entry->fts_statp->st_dev) {
curdev = entry->fts_statp->st_dev;
/*
- * Statfs follows symlinks; find wants the link's file system,
+ * Statfs follows symlinks; find wants the link's filesystem,
* not where it points.
*/
if (entry->fts_info == FTS_SL ||
}
switch (plan->flags & F_MTMASK) {
case F_MTFLAG:
- return (val_flags & plan->mt_data) != 0;
+ return val_flags & plan->mt_data;
case F_MTTYPE:
- return (val_type == plan->mt_data);
+ return val_type == plan->mt_data;
default:
abort();
}
}
-#if !defined(__NetBSD__)
PLAN *
-c_fstype(option, argvp)
- OPTION *option;
- char ***argvp;
+c_fstype(OPTION *option, char ***argvp)
{
char *fsname;
- register PLAN *new;
+ PLAN *new;
struct vfsconf vfc;
fsname = nextarg(option, argvp);
break;
}
- errx(1, "%s: unknown file type", fsname);
- /* NOTREACHED */
+ /*
+ * We need to make filesystem checks for filesystems
+ * that exists but aren't in the kernel work.
+ */
+ fprintf(stderr, "Warning: Unknown filesystem type %s\n", fsname);
+ new->flags |= F_MTUNKNOWN;
+ return new;
}
-#endif /* __NetBSD__ */
/*
* -group gname functions --
* name, gname is taken as a group ID.
*/
int
-f_group(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_group(PLAN *plan, FTSENT *entry)
{
- return entry->fts_statp->st_gid == plan->g_data;
+ COMPARE(entry->fts_statp->st_gid, plan->g_data);
}
PLAN *
-c_group(option, argvp)
- OPTION *option;
- char ***argvp;
+c_group(OPTION *option, char ***argvp)
{
char *gname;
PLAN *new;
gname = nextarg(option, argvp);
ftsoptions &= ~FTS_NOSTAT;
+ new = palloc(option);
g = getgrnam(gname);
if (g == NULL) {
+ char* cp = gname;
+ if( gname[0] == '-' || gname[0] == '+' )
+ gname++;
gid = atoi(gname);
if (gid == 0 && gname[0] != '0')
errx(1, "%s: %s: no such group", option->name, gname);
+ gid = find_parsenum(new, option->name, cp, NULL);
} else
gid = g->gr_gid;
- new = palloc(option);
new->g_data = gid;
return new;
}
* True if the file has inode # n.
*/
int
-f_inum(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_inum(PLAN *plan, FTSENT *entry)
{
COMPARE(entry->fts_statp->st_ino, plan->i_data);
}
PLAN *
-c_inum(option, argvp)
- OPTION *option;
- char ***argvp;
+c_inum(OPTION *option, char ***argvp)
{
char *inum_str;
PLAN *new;
* True if the file has n links.
*/
int
-f_links(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_links(PLAN *plan, FTSENT *entry)
{
COMPARE(entry->fts_statp->st_nlink, plan->l_data);
}
PLAN *
-c_links(option, argvp)
- OPTION *option;
- char ***argvp;
+c_links(OPTION *option, char ***argvp)
{
char *nlinks;
PLAN *new;
* Always true - prints the current entry to stdout in "ls" format.
*/
int
-f_ls(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_ls(PLAN *plan __unused, FTSENT *entry)
{
printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
return 1;
}
PLAN *
-c_ls(option, argvp)
- OPTION *option;
- char ***argvp;
+c_ls(OPTION *option, char ***argvp __unused)
{
ftsoptions &= ~FTS_NOSTAT;
isoutput = 1;
* matches pattern using Pattern Matching Notation S3.14
*/
int
-f_name(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_name(PLAN *plan, FTSENT *entry)
{
return !fnmatch(plan->c_data, entry->fts_name,
plan->flags & F_IGNCASE ? FNM_CASEFOLD : 0);
}
PLAN *
-c_name(option, argvp)
- OPTION *option;
- char ***argvp;
+c_name(OPTION *option, char ***argvp)
{
char *pattern;
PLAN *new;
* file.
*/
int
-f_newer(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_newer(PLAN *plan, FTSENT *entry)
{
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 if (plan->flags & F_TIME_B)
+ return entry->fts_statp->st_birthtime > plan->t_data;
else
return entry->fts_statp->st_mtime > plan->t_data;
}
PLAN *
-c_newer(option, argvp)
- OPTION *option;
- char ***argvp;
+c_newer(OPTION *option, char ***argvp)
{
char *fn_or_tspec;
PLAN *new;
* of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
*/
int
-f_nogroup(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_nogroup(PLAN *plan __unused, FTSENT *entry)
{
return group_from_gid(entry->fts_statp->st_gid, 1) == NULL;
}
PLAN *
-c_nogroup(option, argvp)
- OPTION *option;
- char ***argvp;
+c_nogroup(OPTION *option, char ***argvp __unused)
{
ftsoptions &= ~FTS_NOSTAT;
* of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
*/
int
-f_nouser(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_nouser(PLAN *plan __unused, FTSENT *entry)
{
return user_from_uid(entry->fts_statp->st_uid, 1) == NULL;
}
PLAN *
-c_nouser(option, argvp)
- OPTION *option;
- char ***argvp;
+c_nouser(OPTION *option, char ***argvp __unused)
{
ftsoptions &= ~FTS_NOSTAT;
* matches pattern using Pattern Matching Notation S3.14
*/
int
-f_path(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_path(PLAN *plan, FTSENT *entry)
{
return !fnmatch(plan->c_data, entry->fts_path,
plan->flags & F_IGNCASE ? FNM_CASEFOLD : 0);
* symbolic mode.
*/
int
-f_perm(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_perm(PLAN *plan, FTSENT *entry)
{
mode_t mode;
}
PLAN *
-c_perm(option, argvp)
- OPTION *option;
- char ***argvp;
+c_perm(OPTION *option, char ***argvp)
{
char *perm;
PLAN *new;
new->flags |= F_ATLEAST;
++perm;
} else if (*perm == '+') {
- if ((set = setmode(perm +1)) != NULL) {
+ if ((set = setmode(perm + 1)) != NULL) {
new->flags |= F_ANY;
++perm;
free(set);
/*
* -print functions --
*
- * Always true, causes the current pathame to be written to
+ * Always true, causes the current pathname to be written to
* standard output.
*/
int
-f_print(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_print(PLAN *plan __unused, FTSENT *entry)
{
(void)puts(entry->fts_path);
return 1;
}
PLAN *
-c_print(option, argvp)
- OPTION *option;
- char ***argvp;
+c_print(OPTION *option, char ***argvp __unused)
{
isoutput = 1;
/*
* -print0 functions --
*
- * Always true, causes the current pathame to be written to
+ * Always true, causes the current pathname to be written to
* standard output followed by a NUL character
*/
int
-f_print0(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_print0(PLAN *plan __unused, FTSENT *entry)
{
fputs(entry->fts_path, stdout);
fputc('\0', stdout);
* Prune a portion of the hierarchy.
*/
int
-f_prune(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_prune(PLAN *plan __unused, FTSENT *entry)
{
- extern FTS *tree;
-
if (fts_set(tree, entry, FTS_SKIP))
err(1, "%s", entry->fts_path);
return 1;
* regular expression.
*/
int
-f_regex(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_regex(PLAN *plan, FTSENT *entry)
{
char *str;
- size_t len;
+ int len;
regex_t *pre;
regmatch_t pmatch;
int errcode;
}
PLAN *
-c_regex(option, argvp)
- OPTION *option;
- char ***argvp;
+c_regex(OPTION *option, char ***argvp)
{
PLAN *new;
char *pattern;
/* c_simple covers c_prune, c_openparen, c_closeparen, c_not, c_or */
PLAN *
-c_simple(option, argvp)
- OPTION *option;
- char ***argvp;
+c_simple(OPTION *option, char ***argvp __unused)
{
return palloc(option);
}
*
* True if the file size in bytes, divided by an implementation defined
* value and rounded up to the next integer, is n. If n is followed by
- * a c, the size is in bytes.
+ * one of c k M G T P, the size is in bytes, kilobytes,
+ * megabytes, gigabytes, terabytes or petabytes respectively.
*/
#define FIND_SIZE 512
static int divsize = 1;
int
-f_size(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_size(PLAN *plan, FTSENT *entry)
{
off_t size;
}
PLAN *
-c_size(option, argvp)
- OPTION *option;
- char ***argvp;
+c_size(OPTION *option, char ***argvp)
{
char *size_str;
PLAN *new;
char endch;
+ off_t scale;
size_str = nextarg(option, argvp);
ftsoptions &= ~FTS_NOSTAT;
new = palloc(option);
endch = 'c';
new->o_data = find_parsenum(new, option->name, size_str, &endch);
- if (endch == 'c')
+ if (endch != '\0') {
divsize = 0;
+
+ switch (endch) {
+ case 'c': /* characters */
+ scale = 0x1LL;
+ break;
+ case 'k': /* kilobytes 1<<10 */
+ scale = 0x400LL;
+ break;
+ case 'M': /* megabytes 1<<20 */
+ scale = 0x100000LL;
+ break;
+ case 'G': /* gigabytes 1<<30 */
+ scale = 0x40000000LL;
+ break;
+ case 'T': /* terabytes 1<<40 */
+ scale = 0x1000000000LL;
+ break;
+ case 'P': /* petabytes 1<<50 */
+ scale = 0x4000000000000LL;
+ break;
+ default:
+ errx(1, "%s: %s: illegal trailing character",
+ option->name, size_str);
+ break;
+ }
+ if (new->o_data > QUAD_MAX / scale)
+ errx(1, "%s: %s: value too large",
+ option->name, size_str);
+ new->o_data *= scale;
+ }
return new;
}
* regular file or whiteout respectively.
*/
int
-f_type(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_type(PLAN *plan, FTSENT *entry)
{
return (entry->fts_statp->st_mode & S_IFMT) == plan->m_data;
}
PLAN *
-c_type(option, argvp)
- OPTION *option;
- char ***argvp;
+c_type(OPTION *option, char ***argvp)
{
char *typestring;
PLAN *new;
* return a valid user name, uname is taken as a user ID.
*/
int
-f_user(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_user(PLAN *plan, FTSENT *entry)
{
- return entry->fts_statp->st_uid == plan->u_data;
+ COMPARE(entry->fts_statp->st_uid, plan->u_data);
}
PLAN *
-c_user(option, argvp)
- OPTION *option;
- char ***argvp;
+c_user(OPTION *option, char ***argvp)
{
char *username;
PLAN *new;
username = nextarg(option, argvp);
ftsoptions &= ~FTS_NOSTAT;
+ new = palloc(option);
p = getpwnam(username);
if (p == NULL) {
+ char* cp = username;
+ if( username[0] == '-' || username[0] == '+' )
+ username++;
uid = atoi(username);
if (uid == 0 && username[0] != '0')
errx(1, "%s: %s: no such user", option->name, username);
+ uid = find_parsenum(new, option->name, cp, NULL);
} else
uid = p->pw_uid;
- new = palloc(option);
new->u_data = uid;
return new;
}
/*
* -xdev functions --
*
- * Always true, causes find not to decend past directories that have a
+ * Always true, causes find not to descend past directories that have a
* different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
*/
PLAN *
-c_xdev(option, argvp)
- OPTION *option;
- char ***argvp;
+c_xdev(OPTION *option, char ***argvp __unused)
{
ftsoptions |= FTS_XDEV;
* True if expression is true.
*/
int
-f_expr(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_expr(PLAN *plan, FTSENT *entry)
{
- register PLAN *p;
- register int state = 0;
+ PLAN *p;
+ int state = 0;
for (p = plan->p_data[0];
p && (state = (p->execute)(p, entry)); p = p->next);
*/
int
-f_openparen(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_openparen(PLAN *plan __unused, FTSENT *entry __unused)
{
abort();
}
int
-f_closeparen(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_closeparen(PLAN *plan __unused, FTSENT *entry __unused)
{
abort();
}
* AND operator. Since AND is implicit, no node is allocated.
*/
PLAN *
-c_and(option, argvp)
- OPTION *option;
- char ***argvp;
+c_and(OPTION *option __unused, char ***argvp __unused)
{
return NULL;
}
* Negation of a primary; the unary NOT operator.
*/
int
-f_not(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_not(PLAN *plan, FTSENT *entry)
{
- register PLAN *p;
- register int state = 0;
+ PLAN *p;
+ int state = 0;
for (p = plan->p_data[0];
p && (state = (p->execute)(p, entry)); p = p->next);
* not evaluated if the first expression is true.
*/
int
-f_or(plan, entry)
- PLAN *plan;
- FTSENT *entry;
+f_or(PLAN *plan, FTSENT *entry)
{
- register PLAN *p;
- register int state = 0;
+ PLAN *p;
+ int state = 0;
for (p = plan->p_data[0];
p && (state = (p->execute)(p, entry)); p = p->next);
--- /dev/null
+%{
+/*
+** Originally written by Steven M. Bellovin <smb@research.att.com> while
+** at the University of North Carolina at Chapel Hill. Later tweaked by
+** a couple of people on Usenet. Completely overhauled by Rich $alz
+** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
+**
+** This grammar has 10 shift/reduce conflicts.
+**
+** This code is in the public domain and has no copyright.
+*/
+/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
+/* SUPPRESS 288 on yyerrlab *//* Label unused */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/getdate.y,v 1.4 2005/08/25 13:44:02 roberto Exp $");
+
+#include <stdio.h>
+#include <ctype.h>
+
+/* The code at the top of get_date which figures out the offset of the
+ current time zone checks various CPP symbols to see if special
+ tricks are need, but defaults to using the gettimeofday system call.
+ Include <sys/time.h> if that will be used. */
+
+#if defined(vms)
+# include <types.h>
+#else /* defined(vms) */
+# include <sys/types.h>
+# include <sys/time.h>
+# include <sys/timeb.h>
+#endif /* !defined(vms) */
+
+#if defined (__STDC__) || defined (USG)
+#include <string.h>
+#endif
+
+/* Some old versions of bison generate parsers that use bcopy.
+ That loses on systems that don't provide the function, so we have
+ to redefine it here. */
+#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
+#define bcopy(from, to, len) memcpy ((to), (from), (len))
+#endif
+
+#if defined (__STDC__)
+#include <stdlib.h>
+#endif
+
+/* NOTES on rebuilding getdate.c (particularly for inclusion in CVS
+ releases):
+
+ We don't want to mess with all the portability hassles of alloca.
+ In particular, most (all?) versions of bison will use alloca in
+ their parser. If bison works on your system (e.g. it should work
+ with gcc), then go ahead and use it, but the more general solution
+ is to use byacc instead of bison, which should generate a portable
+ parser. I played with adding "#define alloca dont_use_alloca", to
+ give an error if the parser generator uses alloca (and thus detect
+ unportable getdate.c's), but that seems to cause as many problems
+ as it solves. */
+
+#include <time.h>
+
+#define yyparse getdate_yyparse
+#define yylex getdate_yylex
+#define yyerror getdate_yyerror
+
+static int yyparse(void);
+static int yylex(void);
+static int yyerror(const char *);
+
+time_t get_date(char *, struct timeb *);
+
+#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 {
+ const 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;
+
+%}
+
+%union {
+ time_t Number;
+ enum _MERIDIAN Meridian;
+}
+
+%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
+%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
+
+%type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
+%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE
+%type <Meridian> tMERIDIAN o_merid
+
+%%
+
+spec : /* NULL */
+ | spec item
+ ;
+
+item : time {
+ yyHaveTime++;
+ }
+ | zone {
+ yyHaveZone++;
+ }
+ | date {
+ yyHaveDate++;
+ }
+ | day {
+ yyHaveDay++;
+ }
+ | rel {
+ yyHaveRel++;
+ }
+ | number
+ ;
+
+time : tUNUMBER tMERIDIAN {
+ yyHour = $1;
+ yyMinutes = 0;
+ yySeconds = 0;
+ yyMeridian = $2;
+ }
+ | tUNUMBER ':' tUNUMBER o_merid {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = 0;
+ yyMeridian = $4;
+ }
+ | tUNUMBER ':' tUNUMBER tSNUMBER {
+ yyHour = $1;
+ yyMinutes = $3;
+ yyMeridian = MER24;
+ yyDSTmode = DSToff;
+ yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
+ }
+ | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = $5;
+ yyMeridian = $6;
+ }
+ | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = $5;
+ yyMeridian = MER24;
+ yyDSTmode = DSToff;
+ yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
+ }
+ ;
+
+zone : tZONE {
+ yyTimezone = $1;
+ yyDSTmode = DSToff;
+ }
+ | tDAYZONE {
+ yyTimezone = $1;
+ yyDSTmode = DSTon;
+ }
+ |
+ tZONE tDST {
+ yyTimezone = $1;
+ yyDSTmode = DSTon;
+ }
+ ;
+
+day : tDAY {
+ yyDayOrdinal = 1;
+ yyDayNumber = $1;
+ }
+ | tDAY ',' {
+ yyDayOrdinal = 1;
+ yyDayNumber = $1;
+ }
+ | tUNUMBER tDAY {
+ yyDayOrdinal = $1;
+ yyDayNumber = $2;
+ }
+ ;
+
+date : tUNUMBER '/' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $3;
+ }
+ | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
+ if ($1 >= 100) {
+ yyYear = $1;
+ yyMonth = $3;
+ yyDay = $5;
+ } else {
+ yyMonth = $1;
+ yyDay = $3;
+ yyYear = $5;
+ }
+ }
+ | tUNUMBER tSNUMBER tSNUMBER {
+ /* ISO 8601 format. yyyy-mm-dd. */
+ yyYear = $1;
+ yyMonth = -$2;
+ yyDay = -$3;
+ }
+ | tUNUMBER tMONTH tSNUMBER {
+ /* e.g. 17-JUN-1992. */
+ yyDay = $1;
+ yyMonth = $2;
+ yyYear = -$3;
+ }
+ | tMONTH tUNUMBER {
+ yyMonth = $1;
+ yyDay = $2;
+ }
+ | tMONTH tUNUMBER ',' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $2;
+ yyYear = $4;
+ }
+ | tUNUMBER tMONTH {
+ yyMonth = $2;
+ yyDay = $1;
+ }
+ | tUNUMBER tMONTH tUNUMBER {
+ yyMonth = $2;
+ yyDay = $1;
+ yyYear = $3;
+ }
+ ;
+
+rel : relunit tAGO {
+ yyRelSeconds = -yyRelSeconds;
+ yyRelMonth = -yyRelMonth;
+ }
+ | relunit
+ ;
+
+relunit : tUNUMBER tMINUTE_UNIT {
+ yyRelSeconds += $1 * $2 * 60L;
+ }
+ | tSNUMBER tMINUTE_UNIT {
+ yyRelSeconds += $1 * $2 * 60L;
+ }
+ | tMINUTE_UNIT {
+ yyRelSeconds += $1 * 60L;
+ }
+ | tSNUMBER tSEC_UNIT {
+ yyRelSeconds += $1;
+ }
+ | tUNUMBER tSEC_UNIT {
+ yyRelSeconds += $1;
+ }
+ | tSEC_UNIT {
+ yyRelSeconds++;
+ }
+ | tSNUMBER tMONTH_UNIT {
+ yyRelMonth += $1 * $2;
+ }
+ | tUNUMBER tMONTH_UNIT {
+ yyRelMonth += $1 * $2;
+ }
+ | tMONTH_UNIT {
+ yyRelMonth += $1;
+ }
+ ;
+
+number : tUNUMBER {
+ if (yyHaveTime && yyHaveDate && !yyHaveRel)
+ yyYear = $1;
+ else {
+ if($1>10000) {
+ yyHaveDate++;
+ yyDay= ($1)%100;
+ yyMonth= ($1/100)%100;
+ yyYear = $1/10000;
+ }
+ else {
+ yyHaveTime++;
+ if ($1 < 100) {
+ yyHour = $1;
+ yyMinutes = 0;
+ }
+ else {
+ yyHour = $1 / 100;
+ yyMinutes = $1 % 100;
+ }
+ yySeconds = 0;
+ yyMeridian = MER24;
+ }
+ }
+ }
+ ;
+
+o_merid : /* NULL */ {
+ $$ = MER24;
+ }
+ | tMERIDIAN {
+ $$ = $1;
+ }
+ ;
+
+%%
+
+/* 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, 0, 0 }
+};
+
+/* 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, 0, 0 }
+};
+
+/* 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, 0, 0 }
+};
+
+/* 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, 0, 0 }
+};
+
+/* 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, 0, 0 }
+};
+
+\f
+
+
+/* ARGSUSED */
+static int
+yyerror(const char *s __unused)
+{
+ return 0;
+}
+
+
+static time_t
+ToSeconds(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(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(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(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(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(char *buff)
+{
+ char *p;
+ char *q;
+ 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(void)
+{
+ char c;
+ 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 (struct tm *a, struct tm *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(char *p, struct timeb *now)
+{
+ struct tm *tm, gmt;
+ struct timeb ftz;
+ time_t Start;
+ time_t tod;
+ time_t nowtime;
+
+ bzero (&gmt, sizeof(struct tm));
+ 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(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) */
#ifndef lint
#if 0
static char sccsid[] = "@(#)ls.c 8.1 (Berkeley) 6/6/93";
-#else
-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 */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/ls.c,v 1.17 2004/01/20 09:27:03 des Exp $");
+
#include <sys/param.h>
#include <sys/stat.h>
#include <err.h>
#include <errno.h>
+#include <fts.h>
+#include <grp.h>
+#include <inttypes.h>
+#include <langinfo.h>
+#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
+#ifdef __APPLE__
#include <utmp.h>
+#endif /* __APPLE__ */
+
+#include "find.h"
/* Derived from the print routines in the ls(1) source code. */
-static void printlink __P((char *));
-static void printtime __P((time_t));
+static void printlink(char *);
+static void printtime(time_t);
void
-printlong(name, accpath, sb)
- char *name; /* filename to print */
- char *accpath; /* current valid path to filename */
- struct stat *sb; /* stat buffer */
+printlong(char *name, char *accpath, struct stat *sb)
{
- char modep[15], *user_from_uid(), *group_from_gid();
+ char modep[15];
- (void)printf("%6lu %4qd ", (u_long) sb->st_ino, sb->st_blocks);
+ (void)printf("%6lu %8"PRId64" ", (u_long) sb->st_ino, sb->st_blocks);
(void)strmode(sb->st_mode, modep);
+#ifdef __APPLE__
(void)printf("%s %3u %-*s %-*s ", modep, sb->st_nlink, UT_NAMESIZE,
user_from_uid(sb->st_uid, 0), UT_NAMESIZE,
+#else /* !__APPLE__ */
+ (void)printf("%s %3u %-*s %-*s ", modep, sb->st_nlink, MAXLOGNAME - 1,
+ user_from_uid(sb->st_uid, 0), MAXLOGNAME - 1,
+#endif /* __APPLE__ */
group_from_gid(sb->st_gid, 0));
if (S_ISCHR(sb->st_mode) || S_ISBLK(sb->st_mode))
(void)printf("%3d, %3d ", major(sb->st_rdev),
minor(sb->st_rdev));
else
- (void)printf("%8qd ", sb->st_size);
+ (void)printf("%8"PRId64" ", sb->st_size);
printtime(sb->st_mtime);
(void)printf("%s", name);
if (S_ISLNK(sb->st_mode))
}
static void
-printtime(ftime)
- time_t ftime;
+printtime(time_t ftime)
{
- int i;
char longstring[80];
+ static time_t lnow;
+ const char *format;
+ static int d_first = -1;
- strftime(longstring, sizeof(longstring), "%c", localtime(&ftime));
- for (i = 4; i < 11; ++i)
- (void)putchar(longstring[i]);
+ if (d_first < 0)
+ d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
+ if (lnow == 0)
+ lnow = time(NULL);
#define SIXMONTHS ((365 / 2) * 86400)
- if (ftime + SIXMONTHS > time((time_t *)NULL))
- for (i = 11; i < 16; ++i)
- (void)putchar(longstring[i]);
- else {
- (void)putchar(' ');
- for (i = 20; i < 24; ++i)
- (void)putchar(longstring[i]);
- }
- (void)putchar(' ');
+ if (ftime + SIXMONTHS > lnow && ftime < lnow + SIXMONTHS)
+ /* mmm dd hh:mm || dd mmm hh:mm */
+ format = d_first ? "%e %b %R " : "%b %e %R ";
+ else
+ /* mmm dd yyyy || dd mmm yyyy */
+ format = d_first ? "%e %b %Y " : "%b %e %Y ";
+ strftime(longstring, sizeof(longstring), format, localtime(&ftime));
+ fputs(longstring, stdout);
}
static void
-printlink(name)
- char *name;
+printlink(char *name)
{
int lnklen;
- char path[MAXPATHLEN + 1];
+ char path[MAXPATHLEN];
if ((lnklen = readlink(name, path, MAXPATHLEN - 1)) == -1) {
warn("%s", name);
#ifndef lint
#if 0
static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 5/4/95";
-#else
-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 */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/main.c,v 1.15 2003/06/14 13:00:21 markm Exp $");
+
#include <sys/types.h>
#include <sys/stat.h>
int mindepth = -1, maxdepth = -1; /* minimum and maximum depth */
int regexp_flags = REG_BASIC; /* use the "basic" regexp by default*/
-static void usage __P((void));
+static void usage(void);
int
-main(argc, argv)
- int argc;
- char *argv[];
+main(int argc, char *argv[])
{
- register char **p, **start;
+ char **p, **start;
int Hflag, Lflag, ch;
(void)setlocale(LC_ALL, "");
}
static void
-usage()
+usage(void)
{
(void)fprintf(stderr,
"usage: find [-H | -L | -P] [-EXdsx] [-f file] [file ...] [expression]\n");
#if 0
static char sccsid[] = "@(#)misc.c 8.2 (Berkeley) 4/1/94";
#else
-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 */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/misc.c,v 1.8 2005/04/02 07:44:12 tjr Exp $");
+
#include <sys/types.h>
#include <sys/stat.h>
* 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;
+brace_subst(char *orig, char **store, char *path, int len)
{
- register int plen;
- register char ch, *p;
+ int plen;
+ char ch, *p;
plen = strlen(path);
for (p = *store; (ch = *orig) != '\0'; ++orig)
/*
* queryuser --
* print a message to standard error and then read input from standard
- * input. If the input is 'y' then 1 is returned.
+ * input. If the input is an affirmative response (according to the
+ * current locale) then 1 is returned.
*/
int
-queryuser(argv)
- register char **argv;
+queryuser(char *argv[])
{
- int ch, first, nl;
+ char *p, resp[256];
(void)fprintf(stderr, "\"%s", *argv);
while (*++argv)
(void)fprintf(stderr, "\"? ");
(void)fflush(stderr);
- first = ch = getchar();
- for (nl = 0;;) {
- if (ch == '\n') {
- nl = 1;
- break;
- }
- if (ch == EOF)
- break;
- ch = getchar();
- }
-
- if (!nl) {
+ if (fgets(resp, sizeof(resp), stdin) == NULL)
+ *resp = '\0';
+ if ((p = strchr(resp, '\n')) != NULL)
+ *p = '\0';
+ else {
(void)fprintf(stderr, "\n");
(void)fflush(stderr);
}
- return (first == 'y');
-}
-
-/*
- * emalloc --
- * malloc with error checking.
- */
-void *
-emalloc(len)
- u_int len;
-{
- void *p;
-
- if ((p = malloc(len)) == NULL)
- err(1, NULL);
- return (p);
+#ifdef __APPLE__
+ return (resp[0] == 'y');
+#else
+ return (rpmatch(resp) == 1);
+#endif
}
* 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 $
*/
#ifndef lint
+#if 0
static char sccsid[] = "@(#)operator.c 8.1 (Berkeley) 6/6/93";
+#endif
#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/operator.c,v 1.14 2003/06/14 13:00:21 markm Exp $");
+
#include <sys/types.h>
#include <err.h>
#include "find.h"
+static PLAN *yanknode(PLAN **);
+static PLAN *yankexpr(PLAN **);
+
/*
* yanknode --
* destructively removes the top from the plan
*/
static PLAN *
-yanknode(planp)
- PLAN **planp; /* pointer to top of plan (modified) */
+yanknode(PLAN **planp)
{
PLAN *node; /* top node removed from the plan */
* simple node or a f_expr node containing a list of simple nodes.
*/
static PLAN *
-yankexpr(planp)
- PLAN **planp; /* pointer to top of plan (modified) */
+yankexpr(PLAN **planp)
{
- register PLAN *next; /* temp node holding subexpression results */
+ 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 */
if (node->execute == f_openparen)
for (tail = subplan = NULL;;) {
if ((next = yankexpr(planp)) == NULL)
- err(1, "(: missing closing ')'");
+ errx(1, "(: missing closing ')'");
/*
* If we find a closing ')' we store the collected
* subplan in our '(' node and convert the node to
/*
* paren_squish --
- * replaces "parentheisized" plans in our search plan with "expr" nodes.
+ * replaces "parenthesized" plans in our search plan with "expr" nodes.
*/
PLAN *
-paren_squish(plan)
- PLAN *plan; /* plan with ( ) nodes */
+paren_squish(PLAN *plan)
{
- register PLAN *expr; /* pointer to next expression */
- register PLAN *tail; /* pointer to tail of result plan */
+ PLAN *expr; /* pointer to next expression */
+ PLAN *tail; /* pointer to tail of result plan */
PLAN *result; /* pointer to head of result plan */
result = tail = NULL;
* compresses "!" expressions in our search plan.
*/
PLAN *
-not_squish(plan)
- PLAN *plan; /* plan to process */
+not_squish(PLAN *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 *next; /* next node being processed */
+ PLAN *node; /* temporary node used in f_not processing */
+ PLAN *tail; /* pointer to tail of result plan */
PLAN *result; /* pointer to head of result plan */
tail = result = NULL;
- while (next = yanknode(&plan)) {
+ while ((next = yanknode(&plan))) {
/*
* if we encounter a ( expression ) then look for nots in
* the expr subplan.
* compresses -o expressions in our search plan.
*/
PLAN *
-or_squish(plan)
- PLAN *plan; /* plan with ors to be squished */
+or_squish(PLAN *plan)
{
- register PLAN *next; /* next node being processed */
- register PLAN *tail; /* pointer to tail of result plan */
+ PLAN *next; /* next node being processed */
+ PLAN *tail; /* pointer to tail of result plan */
PLAN *result; /* pointer to head of result plan */
tail = result = next = NULL;
/*
static char sccsid[] = "@(#)option.c 8.2 (Berkeley) 4/16/94";
*/
-static const char rcsid[] =
- "$FreeBSD: src/usr.bin/find/option.c,v 1.9.2.4 2001/05/06 09:53:22 phk Exp $";
#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/option.c,v 1.25 2006/04/05 23:06:11 ceri Exp $");
+
#include <sys/types.h>
#include <sys/stat.h>
#include "find.h"
+int typecompare(const void *, const void *);
+
/* NB: the following table must be sorted lexically. */
static OPTION const options[] = {
{ "!", c_simple, f_not, 0 },
{ "(", c_simple, f_openparen, 0 },
{ ")", c_simple, f_closeparen, 0 },
+ { "-Bmin", c_Xmin, f_Xmin, F_TIME_B },
+ { "-Bnewer", c_newer, f_newer, F_TIME_B },
+ { "-Btime", c_Xtime, f_Xtime, F_TIME_B },
{ "-a", c_and, NULL, 0 },
+#ifndef __APPLE__
+ { "-acl", c_acl, f_acl, 0 },
+#endif /* !__APPLE__ */
{ "-amin", c_Xmin, f_Xmin, F_TIME_A },
{ "-and", c_and, NULL, 0 },
{ "-anewer", c_newer, f_newer, F_TIME_A },
{ "-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 },
+ { "-depth", c_depth, f_depth, 0 },
{ "-empty", c_empty, f_empty, 0 },
{ "-exec", c_exec, f_exec, 0 },
{ "-execdir", c_exec, f_exec, F_EXECDIR },
{ "-false", c_simple, f_not, 0 },
{ "-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 },
{ "-mtime", c_Xtime, f_Xtime, 0 },
{ "-name", c_name, f_name, 0 },
{ "-newer", c_newer, f_newer, 0 },
+ { "-newerBB", c_newer, f_newer, F_TIME_B | F_TIME2_B },
+ { "-newerBa", c_newer, f_newer, F_TIME_B | F_TIME2_A },
+ { "-newerBc", c_newer, f_newer, F_TIME_B | F_TIME2_C },
+ { "-newerBm", c_newer, f_newer, F_TIME_B },
+ { "-newerBt", c_newer, f_newer, F_TIME_B | F_TIME2_T },
+ { "-neweraB", c_newer, f_newer, F_TIME_A | F_TIME2_B },
{ "-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 },
+ { "-newercB", c_newer, f_newer, F_TIME_C | F_TIME2_B },
{ "-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 },
+ { "-newermB", c_newer, f_newer, F_TIME2_B },
{ "-newerma", c_newer, f_newer, F_TIME2_A },
{ "-newermc", c_newer, f_newer, F_TIME2_C },
{ "-newermm", c_newer, f_newer, 0 },
* this switch stuff.
*/
PLAN *
-find_create(argvp)
- char ***argvp;
+find_create(char ***argvp)
{
- register OPTION *p;
+ OPTION *p;
PLAN *new;
char **argv;
argv = *argvp;
- if ((p = option(*argv)) == NULL)
- errx(1, "%s: unknown expression primary", *argv);
+ if ((p = lookup_option(*argv)) == NULL)
+ errx(1, "%s: unknown option", *argv);
++argv;
new = (p->create)(p, &argv);
}
OPTION *
-option(name)
- char *name;
+lookup_option(const char *name)
{
OPTION tmp;
- int typecompare __P((const void *, const void *));
tmp.name = name;
return ((OPTION *)bsearch(&tmp, options,
}
int
-typecompare(a, b)
- const void *a, *b;
+typecompare(const void *a, const void *b)
{
- return (strcmp(((OPTION *)a)->name, ((OPTION *)b)->name));
+ return (strcmp(((const OPTION *)a)->name, ((const OPTION *)b)->name));
}
+++ /dev/null
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93";
-#else
-__IDSTRING(yyrcsid, "$NetBSD: skeleton.c,v 1.14 1997/10/20 03:41:16 lukem Exp $");
-#endif
-#endif
-#include <stdlib.h>
-#define YYBYACC 1
-#define YYMAJOR 1
-#define YYMINOR 9
-#define YYLEX yylex()
-#define YYEMPTY -1
-#define yyclearin (yychar=(YYEMPTY))
-#define yyerrok (yyerrflag=0)
-#define YYRECOVERING (yyerrflag!=0)
-#define YYPREFIX "yy"
-#line 2 "getdate.y"
-/*
-** Originally written by Steven M. Bellovin <smb@research.att.com> while
-** at the University of North Carolina at Chapel Hill. Later tweaked by
-** a couple of people on Usenet. Completely overhauled by Rich $alz
-** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
-**
-** This grammar has 10 shift/reduce conflicts.
-**
-** This code is in the public domain and has no copyright.
-*/
-/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
-/* SUPPRESS 288 on yyerrlab *//* Label unused */
-
-#ifdef HAVE_CONFIG_H
-#if defined (emacs) || defined (CONFIG_BROKETS)
-#include <config.h>
-#else
-#include "config.h"
-#endif
-#endif
-
-/* Since the code of getdate.y is not included in the Emacs executable
- itself, there is no need to #define static in this file. Even if
- the code were included in the Emacs executable, it probably
- wouldn't do any harm to #undef it here; this will only cause
- problems if we try to write to a static variable, which I don't
- think this code needs to do. */
-#ifdef emacs
-#undef static
-#endif
-
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-
-/* The code at the top of get_date which figures out the offset of the
- current time zone checks various CPP symbols to see if special
- tricks are need, but defaults to using the gettimeofday system call.
- Include <sys/time.h> if that will be used. */
-
-#if defined(vms)
-# include <types.h>
-#else /* defined(vms) */
-# include <sys/types.h>
-/* don't need xtime.h */
-# include <sys/time.h>
-# include <time.h>
-#endif /* !defined(vms) */
-
-#include <sys/timeb.h>
-
-#if defined (STDC_HEADERS) || defined (USG)
-#include <string.h>
-#endif
-
-/* Some old versions of bison generate parsers that use bcopy.
- That loses on systems that don't provide the function, so we have
- to redefine it here. */
-#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
-#define bcopy(from, to, len) memcpy ((to), (from), (len))
-#endif
-
-#if defined (STDC_HEADERS)
-#include <stdlib.h>
-#endif
-
-/* NOTES on rebuilding getdate.c (particularly for inclusion in CVS
- releases):
-
- We don't want to mess with all the portability hassles of alloca.
- In particular, most (all?) versions of bison will use alloca in
- their parser. If bison works on your system (e.g. it should work
- with gcc), then go ahead and use it, but the more general solution
- is to use byacc instead of bison, which should generate a portable
- parser. I played with adding "#define alloca dont_use_alloca", to
- give an error if the parser generator uses alloca (and thus detect
- unportable getdate.c's), but that seems to cause as many problems
- as it solves. */
-
-extern struct tm *gmtime();
-extern struct tm *localtime();
-
-#define yyparse getdate_yyparse
-#define yylex getdate_yylex
-#define yyerror getdate_yyerror
-
-static int yyparse ();
-static int yylex ();
-static int yyerror ();
-
-#define EPOCH 1970
-#define HOUR(x) ((time_t)(x) * 60)
-#define SECSPERDAY (24L * 60L * 60L)
-
-
-/*
-** An entry in the lexical lookup table.
-*/
-typedef struct _TABLE {
- char *name;
- int type;
- time_t value;
-} TABLE;
-
-
-/*
-** Daylight-savings mode: on, off, or not yet known.
-*/
-typedef enum _DSTMODE {
- DSTon, DSToff, DSTmaybe
-} DSTMODE;
-
-/*
-** Meridian: am, pm, or 24-hour style.
-*/
-typedef enum _MERIDIAN {
- MERam, MERpm, MER24
-} MERIDIAN;
-
-
-/*
-** Global variables. We could get rid of most of these by using a good
-** union as the yacc stack. (This routine was originally written before
-** yacc had the %union construct.) Maybe someday; right now we only use
-** the %union very rarely.
-*/
-static char *yyInput;
-static DSTMODE yyDSTmode;
-static time_t yyDayOrdinal;
-static time_t yyDayNumber;
-static int yyHaveDate;
-static int yyHaveDay;
-static int yyHaveRel;
-static int yyHaveTime;
-static int yyHaveZone;
-static time_t yyTimezone;
-static time_t yyDay;
-static time_t yyHour;
-static time_t yyMinutes;
-static time_t yyMonth;
-static time_t yySeconds;
-static time_t yyYear;
-static MERIDIAN yyMeridian;
-static time_t yyRelMonth;
-static time_t yyRelSeconds;
-
-#line 150 "getdate.y"
-typedef union {
- time_t Number;
- enum _MERIDIAN Meridian;
-} YYSTYPE;
-#line 172 "y.tab.c"
-#define tAGO 257
-#define tDAY 258
-#define tDAYZONE 259
-#define tID 260
-#define tMERIDIAN 261
-#define tMINUTE_UNIT 262
-#define tMONTH 263
-#define tMONTH_UNIT 264
-#define tSEC_UNIT 265
-#define tSNUMBER 266
-#define tUNUMBER 267
-#define tZONE 268
-#define tDST 269
-#define YYERRCODE 256
-short yylhs[] = { -1,
- 0, 0, 2, 2, 2, 2, 2, 2, 3, 3,
- 3, 3, 3, 4, 4, 4, 6, 6, 6, 5,
- 5, 5, 5, 5, 5, 5, 5, 7, 7, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 8, 1,
- 1,
-};
-short yylen[] = { 2,
- 0, 2, 1, 1, 1, 1, 1, 1, 2, 4,
- 4, 6, 6, 1, 1, 2, 1, 2, 2, 3,
- 5, 3, 3, 2, 4, 2, 3, 2, 1, 2,
- 2, 1, 2, 2, 1, 2, 2, 1, 1, 0,
- 1,
-};
-short yydefred[] = { 1,
- 0, 0, 15, 32, 0, 38, 35, 0, 0, 0,
- 2, 3, 4, 5, 6, 7, 8, 0, 18, 0,
- 31, 36, 33, 19, 9, 30, 0, 37, 34, 0,
- 0, 0, 16, 28, 0, 23, 27, 22, 0, 0,
- 25, 41, 11, 0, 10, 0, 0, 21, 13, 12,
-};
-short yydgoto[] = { 1,
- 45, 11, 12, 13, 14, 15, 16, 17, 18,
-};
-short yysindex[] = { 0,
- -249, -38, 0, 0, -260, 0, 0, -240, -47, -248,
- 0, 0, 0, 0, 0, 0, 0, -237, 0, -18,
- 0, 0, 0, 0, 0, 0, -262, 0, 0, -239,
- -238, -236, 0, 0, -235, 0, 0, 0, -56, -19,
- 0, 0, 0, -234, 0, -232, -258, 0, 0, 0,
-};
-short yyrindex[] = { 0,
- 0, 1, 0, 0, 0, 0, 0, 0, 69, 12,
- 0, 0, 0, 0, 0, 0, 0, 23, 0, 34,
- 0, 0, 0, 0, 0, 0, 67, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 56, 45,
- 0, 0, 0, 0, 0, 0, 56, 0, 0, 0,
-};
-short yygindex[] = { 0,
- -17, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-#define YYTABLESIZE 337
-short yytable[] = { 32,
- 17, 44, 42, 36, 37, 19, 20, 49, 2, 3,
- 31, 14, 4, 5, 6, 7, 8, 9, 10, 34,
- 33, 21, 29, 22, 23, 35, 38, 46, 39, 50,
- 40, 41, 47, 24, 48, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 20, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 40, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 26, 0, 39, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 42, 0, 0, 0, 0, 43,
- 24, 0, 0, 25, 26, 27, 28, 29, 30, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 17, 17,
- 0, 0, 17, 17, 17, 17, 17, 17, 17, 14,
- 14, 0, 0, 14, 14, 14, 14, 14, 14, 14,
- 29, 29, 0, 0, 29, 29, 29, 29, 29, 29,
- 29, 24, 24, 0, 0, 24, 24, 24, 24, 24,
- 24, 24, 20, 20, 0, 0, 20, 20, 20, 20,
- 20, 20, 20, 40, 40, 0, 0, 40, 40, 40,
- 40, 0, 40, 40, 26, 26, 0, 39, 26, 26,
- 26, 26, 0, 0, 26, 39, 39,
-};
-short yycheck[] = { 47,
- 0, 58, 261, 266, 267, 44, 267, 266, 258, 259,
- 58, 0, 262, 263, 264, 265, 266, 267, 268, 257,
- 269, 262, 0, 264, 265, 44, 266, 47, 267, 47,
- 267, 267, 267, 0, 267, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 0, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 0, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, 0, -1, 0, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 261, -1, -1, -1, -1, 266,
- 258, -1, -1, 261, 262, 263, 264, 265, 266, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, 258, 259,
- -1, -1, 262, 263, 264, 265, 266, 267, 268, 258,
- 259, -1, -1, 262, 263, 264, 265, 266, 267, 268,
- 258, 259, -1, -1, 262, 263, 264, 265, 266, 267,
- 268, 258, 259, -1, -1, 262, 263, 264, 265, 266,
- 267, 268, 258, 259, -1, -1, 262, 263, 264, 265,
- 266, 267, 268, 258, 259, -1, -1, 262, 263, 264,
- 265, -1, 267, 268, 258, 259, -1, 259, 262, 263,
- 264, 265, -1, -1, 268, 267, 268,
-};
-#define YYFINAL 1
-#ifndef YYDEBUG
-#define YYDEBUG 0
-#endif
-#define YYMAXTOKEN 269
-#if YYDEBUG
-char *yyname[] = {
-"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,"','",0,0,"'/'",0,0,0,0,0,0,0,0,0,0,"':'",0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"tAGO","tDAY",
-"tDAYZONE","tID","tMERIDIAN","tMINUTE_UNIT","tMONTH","tMONTH_UNIT","tSEC_UNIT",
-"tSNUMBER","tUNUMBER","tZONE","tDST",
-};
-char *yyrule[] = {
-"$accept : spec",
-"spec :",
-"spec : spec item",
-"item : time",
-"item : zone",
-"item : date",
-"item : day",
-"item : rel",
-"item : number",
-"time : tUNUMBER tMERIDIAN",
-"time : tUNUMBER ':' tUNUMBER o_merid",
-"time : tUNUMBER ':' tUNUMBER tSNUMBER",
-"time : tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid",
-"time : tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER",
-"zone : tZONE",
-"zone : tDAYZONE",
-"zone : tZONE tDST",
-"day : tDAY",
-"day : tDAY ','",
-"day : tUNUMBER tDAY",
-"date : tUNUMBER '/' tUNUMBER",
-"date : tUNUMBER '/' tUNUMBER '/' tUNUMBER",
-"date : tUNUMBER tSNUMBER tSNUMBER",
-"date : tUNUMBER tMONTH tSNUMBER",
-"date : tMONTH tUNUMBER",
-"date : tMONTH tUNUMBER ',' tUNUMBER",
-"date : tUNUMBER tMONTH",
-"date : tUNUMBER tMONTH tUNUMBER",
-"rel : relunit tAGO",
-"rel : relunit",
-"relunit : tUNUMBER tMINUTE_UNIT",
-"relunit : tSNUMBER tMINUTE_UNIT",
-"relunit : tMINUTE_UNIT",
-"relunit : tSNUMBER tSEC_UNIT",
-"relunit : tUNUMBER tSEC_UNIT",
-"relunit : tSEC_UNIT",
-"relunit : tSNUMBER tMONTH_UNIT",
-"relunit : tUNUMBER tMONTH_UNIT",
-"relunit : tMONTH_UNIT",
-"number : tUNUMBER",
-"o_merid :",
-"o_merid : tMERIDIAN",
-};
-#endif
-#ifdef YYSTACKSIZE
-#undef YYMAXDEPTH
-#define YYMAXDEPTH YYSTACKSIZE
-#else
-#ifdef YYMAXDEPTH
-#define YYSTACKSIZE YYMAXDEPTH
-#else
-#define YYSTACKSIZE 10000
-#define YYMAXDEPTH 10000
-#endif
-#endif
-#define YYINITSTACKSIZE 200
-int yydebug;
-int yynerrs;
-int yyerrflag;
-int yychar;
-short *yyssp;
-YYSTYPE *yyvsp;
-YYSTYPE yyval;
-YYSTYPE yylval;
-short *yyss;
-short *yysslim;
-YYSTYPE *yyvs;
-int yystacksize;
-#line 369 "getdate.y"
-
-/* Month and day table. */
-static TABLE const MonthDayTable[] = {
- { "january", tMONTH, 1 },
- { "february", tMONTH, 2 },
- { "march", tMONTH, 3 },
- { "april", tMONTH, 4 },
- { "may", tMONTH, 5 },
- { "june", tMONTH, 6 },
- { "july", tMONTH, 7 },
- { "august", tMONTH, 8 },
- { "september", tMONTH, 9 },
- { "sept", tMONTH, 9 },
- { "october", tMONTH, 10 },
- { "november", tMONTH, 11 },
- { "december", tMONTH, 12 },
- { "sunday", tDAY, 0 },
- { "monday", tDAY, 1 },
- { "tuesday", tDAY, 2 },
- { "tues", tDAY, 2 },
- { "wednesday", tDAY, 3 },
- { "wednes", tDAY, 3 },
- { "thursday", tDAY, 4 },
- { "thur", tDAY, 4 },
- { "thurs", tDAY, 4 },
- { "friday", tDAY, 5 },
- { "saturday", tDAY, 6 },
- { NULL }
-};
-
-/* Time units table. */
-static TABLE const UnitsTable[] = {
- { "year", tMONTH_UNIT, 12 },
- { "month", tMONTH_UNIT, 1 },
- { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
- { "week", tMINUTE_UNIT, 7 * 24 * 60 },
- { "day", tMINUTE_UNIT, 1 * 24 * 60 },
- { "hour", tMINUTE_UNIT, 60 },
- { "minute", tMINUTE_UNIT, 1 },
- { "min", tMINUTE_UNIT, 1 },
- { "second", tSEC_UNIT, 1 },
- { "sec", tSEC_UNIT, 1 },
- { NULL }
-};
-
-/* Assorted relative-time words. */
-static TABLE const OtherTable[] = {
- { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
- { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
- { "today", tMINUTE_UNIT, 0 },
- { "now", tMINUTE_UNIT, 0 },
- { "last", tUNUMBER, -1 },
- { "this", tMINUTE_UNIT, 0 },
- { "next", tUNUMBER, 2 },
- { "first", tUNUMBER, 1 },
-/* { "second", tUNUMBER, 2 }, */
- { "third", tUNUMBER, 3 },
- { "fourth", tUNUMBER, 4 },
- { "fifth", tUNUMBER, 5 },
- { "sixth", tUNUMBER, 6 },
- { "seventh", tUNUMBER, 7 },
- { "eighth", tUNUMBER, 8 },
- { "ninth", tUNUMBER, 9 },
- { "tenth", tUNUMBER, 10 },
- { "eleventh", tUNUMBER, 11 },
- { "twelfth", tUNUMBER, 12 },
- { "ago", tAGO, 1 },
- { NULL }
-};
-
-/* The timezone table. */
-/* Some of these are commented out because a time_t can't store a float. */
-static TABLE const TimezoneTable[] = {
- { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
- { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */
- { "utc", tZONE, HOUR( 0) },
- { "wet", tZONE, HOUR( 0) }, /* Western European */
- { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
- { "wat", tZONE, HOUR( 1) }, /* West Africa */
- { "at", tZONE, HOUR( 2) }, /* Azores */
-#if 0
- /* For completeness. BST is also British Summer, and GST is
- * also Guam Standard. */
- { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
- { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
-#endif
-#if 0
- { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */
- { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */
- { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */
-#endif
- { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
- { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
- { "est", tZONE, HOUR( 5) }, /* Eastern Standard */
- { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
- { "cst", tZONE, HOUR( 6) }, /* Central Standard */
- { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
- { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
- { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
- { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
- { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
- { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
- { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
- { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
- { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
- { "cat", tZONE, HOUR(10) }, /* Central Alaska */
- { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */
- { "nt", tZONE, HOUR(11) }, /* Nome */
- { "idlw", tZONE, HOUR(12) }, /* International Date Line West */
- { "cet", tZONE, -HOUR(1) }, /* Central European */
- { "met", tZONE, -HOUR(1) }, /* Middle European */
- { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
- { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
- { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
- { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
- { "fwt", tZONE, -HOUR(1) }, /* French Winter */
- { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
- { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */
- { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */
-#if 0
- { "it", tZONE, -HOUR(3.5) },/* Iran */
-#endif
- { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
- { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
-#if 0
- { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */
-#endif
- { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
-#if 0
- /* For completeness. NST is also Newfoundland Stanard, and SST is
- * also Swedish Summer. */
- { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */
- { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */
-#endif /* 0 */
- { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */
- { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */
-#if 0
- { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */
-#endif
- { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */
- { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */
-#if 0
- { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */
- { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */
-#endif
- { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
- { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
- { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
- { "nzt", tZONE, -HOUR(12) }, /* New Zealand */
- { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
- { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
- { "idle", tZONE, -HOUR(12) }, /* International Date Line East */
- { NULL }
-};
-
-/* Military timezone table. */
-static TABLE const MilitaryTable[] = {
- { "a", tZONE, HOUR( 1) },
- { "b", tZONE, HOUR( 2) },
- { "c", tZONE, HOUR( 3) },
- { "d", tZONE, HOUR( 4) },
- { "e", tZONE, HOUR( 5) },
- { "f", tZONE, HOUR( 6) },
- { "g", tZONE, HOUR( 7) },
- { "h", tZONE, HOUR( 8) },
- { "i", tZONE, HOUR( 9) },
- { "k", tZONE, HOUR( 10) },
- { "l", tZONE, HOUR( 11) },
- { "m", tZONE, HOUR( 12) },
- { "n", tZONE, HOUR(- 1) },
- { "o", tZONE, HOUR(- 2) },
- { "p", tZONE, HOUR(- 3) },
- { "q", tZONE, HOUR(- 4) },
- { "r", tZONE, HOUR(- 5) },
- { "s", tZONE, HOUR(- 6) },
- { "t", tZONE, HOUR(- 7) },
- { "u", tZONE, HOUR(- 8) },
- { "v", tZONE, HOUR(- 9) },
- { "w", tZONE, HOUR(-10) },
- { "x", tZONE, HOUR(-11) },
- { "y", tZONE, HOUR(-12) },
- { "z", tZONE, HOUR( 0) },
- { NULL }
-};
-
-\f
-
-
-/* ARGSUSED */
-static int
-yyerror(s)
- char *s;
-{
- return 0;
-}
-
-
-static time_t
-ToSeconds(Hours, Minutes, Seconds, Meridian)
- time_t Hours;
- time_t Minutes;
- time_t Seconds;
- MERIDIAN Meridian;
-{
- if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
- return -1;
- switch (Meridian) {
- case MER24:
- if (Hours < 0 || Hours > 23)
- return -1;
- return (Hours * 60L + Minutes) * 60L + Seconds;
- case MERam:
- if (Hours < 1 || Hours > 12)
- return -1;
- if (Hours == 12)
- Hours = 0;
- return (Hours * 60L + Minutes) * 60L + Seconds;
- case MERpm:
- if (Hours < 1 || Hours > 12)
- return -1;
- if (Hours == 12)
- Hours = 0;
- return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
- default:
- abort ();
- }
- /* NOTREACHED */
-}
-
-
-/* Year is either
- * A negative number, which means to use its absolute value (why?)
- * A number from 0 to 99, which means a year from 1900 to 1999, or
- * The actual year (>=100). */
-static time_t
-Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
- time_t Month;
- time_t Day;
- time_t Year;
- time_t Hours;
- time_t Minutes;
- time_t Seconds;
- MERIDIAN Meridian;
- DSTMODE DSTmode;
-{
- static int DaysInMonth[12] = {
- 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
- };
- time_t tod;
- time_t Julian;
- int i;
-
- if (Year < 0)
- Year = -Year;
- if (Year < 69)
- Year += 2000;
- else if (Year < 100)
- Year += 1900;
- DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
- ? 29 : 28;
- /* Checking for 2038 bogusly assumes that time_t is 32 bits. But
- I'm too lazy to try to check for time_t overflow in another way. */
- if (Year < EPOCH || Year > 2038
- || Month < 1 || Month > 12
- /* Lint fluff: "conversion from long may lose accuracy" */
- || Day < 1 || Day > DaysInMonth[(int)--Month])
- return -1;
-
- for (Julian = Day - 1, i = 0; i < Month; i++)
- Julian += DaysInMonth[i];
- for (i = EPOCH; i < Year; i++)
- Julian += 365 + (i % 4 == 0);
- Julian *= SECSPERDAY;
- Julian += yyTimezone * 60L;
- if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
- return -1;
- Julian += tod;
- if (DSTmode == DSTon
- || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
- Julian -= 60 * 60;
- return Julian;
-}
-
-
-static time_t
-DSTcorrect(Start, Future)
- time_t Start;
- time_t Future;
-{
- time_t StartDay;
- time_t FutureDay;
-
- StartDay = (localtime(&Start)->tm_hour + 1) % 24;
- FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
- return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
-}
-
-
-static time_t
-RelativeDate(Start, DayOrdinal, DayNumber)
- time_t Start;
- time_t DayOrdinal;
- time_t DayNumber;
-{
- struct tm *tm;
- time_t now;
-
- now = Start;
- tm = localtime(&now);
- now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
- now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
- return DSTcorrect(Start, now);
-}
-
-
-static time_t
-RelativeMonth(Start, RelMonth)
- time_t Start;
- time_t RelMonth;
-{
- struct tm *tm;
- time_t Month;
- time_t Year;
-
- if (RelMonth == 0)
- return 0;
- tm = localtime(&Start);
- Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;
- Year = Month / 12;
- Month = Month % 12 + 1;
- return DSTcorrect(Start,
- Convert(Month, (time_t)tm->tm_mday, Year,
- (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
- MER24, DSTmaybe));
-}
-
-
-static int
-LookupWord(buff)
- char *buff;
-{
- register char *p;
- register char *q;
- register const TABLE *tp;
- int i;
- int abbrev;
-
- /* Make it lowercase. */
- for (p = buff; *p; p++)
- if (isupper(*p))
- *p = tolower(*p);
-
- if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
- yylval.Meridian = MERam;
- return tMERIDIAN;
- }
- if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
- yylval.Meridian = MERpm;
- return tMERIDIAN;
- }
-
- /* See if we have an abbreviation for a month. */
- if (strlen(buff) == 3)
- abbrev = 1;
- else if (strlen(buff) == 4 && buff[3] == '.') {
- abbrev = 1;
- buff[3] = '\0';
- }
- else
- abbrev = 0;
-
- for (tp = MonthDayTable; tp->name; tp++) {
- if (abbrev) {
- if (strncmp(buff, tp->name, 3) == 0) {
- yylval.Number = tp->value;
- return tp->type;
- }
- }
- else if (strcmp(buff, tp->name) == 0) {
- yylval.Number = tp->value;
- return tp->type;
- }
- }
-
- for (tp = TimezoneTable; tp->name; tp++)
- if (strcmp(buff, tp->name) == 0) {
- yylval.Number = tp->value;
- return tp->type;
- }
-
- if (strcmp(buff, "dst") == 0)
- return tDST;
-
- for (tp = UnitsTable; tp->name; tp++)
- if (strcmp(buff, tp->name) == 0) {
- yylval.Number = tp->value;
- return tp->type;
- }
-
- /* Strip off any plural and try the units table again. */
- i = strlen(buff) - 1;
- if (buff[i] == 's') {
- buff[i] = '\0';
- for (tp = UnitsTable; tp->name; tp++)
- if (strcmp(buff, tp->name) == 0) {
- yylval.Number = tp->value;
- return tp->type;
- }
- buff[i] = 's'; /* Put back for "this" in OtherTable. */
- }
-
- for (tp = OtherTable; tp->name; tp++)
- if (strcmp(buff, tp->name) == 0) {
- yylval.Number = tp->value;
- return tp->type;
- }
-
- /* Military timezones. */
- if (buff[1] == '\0' && isalpha(*buff)) {
- for (tp = MilitaryTable; tp->name; tp++)
- if (strcmp(buff, tp->name) == 0) {
- yylval.Number = tp->value;
- return tp->type;
- }
- }
-
- /* Drop out any periods and try the timezone table again. */
- for (i = 0, p = q = buff; *q; q++)
- if (*q != '.')
- *p++ = *q;
- else
- i++;
- *p = '\0';
- if (i)
- for (tp = TimezoneTable; tp->name; tp++)
- if (strcmp(buff, tp->name) == 0) {
- yylval.Number = tp->value;
- return tp->type;
- }
-
- return tID;
-}
-
-
-static int
-yylex()
-{
- register char c;
- register char *p;
- char buff[20];
- int Count;
- int sign;
-
- for ( ; ; ) {
- while (isspace(*yyInput))
- yyInput++;
-
- if (isdigit(c = *yyInput) || c == '-' || c == '+') {
- if (c == '-' || c == '+') {
- sign = c == '-' ? -1 : 1;
- if (!isdigit(*++yyInput))
- /* skip the '-' sign */
- continue;
- }
- else
- sign = 0;
- for (yylval.Number = 0; isdigit(c = *yyInput++); )
- yylval.Number = 10 * yylval.Number + c - '0';
- yyInput--;
- if (sign < 0)
- yylval.Number = -yylval.Number;
- return sign ? tSNUMBER : tUNUMBER;
- }
- if (isalpha(c)) {
- for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
- if (p < &buff[sizeof buff - 1])
- *p++ = c;
- *p = '\0';
- yyInput--;
- return LookupWord(buff);
- }
- if (c != '(')
- return *yyInput++;
- Count = 0;
- do {
- c = *yyInput++;
- if (c == '\0')
- return c;
- if (c == '(')
- Count++;
- else if (c == ')')
- Count--;
- } while (Count > 0);
- }
-}
-
-#define TM_YEAR_ORIGIN 1900
-
-/* Yield A - B, measured in seconds. */
-static long
-difftm (a, b)
- struct tm *a, *b;
-{
- int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
- int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
- int days = (
- /* difference in day of year */
- a->tm_yday - b->tm_yday
- /* + intervening leap days */
- + ((ay >> 2) - (by >> 2))
- - (ay/100 - by/100)
- + ((ay/100 >> 2) - (by/100 >> 2))
- /* + difference in years * 365 */
- + (long)(ay-by) * 365
- );
- return (60*(60*(24*days + (a->tm_hour - b->tm_hour))
- + (a->tm_min - b->tm_min))
- + (a->tm_sec - b->tm_sec));
-}
-
-time_t
-get_date(p, now)
- char *p;
- struct timeb *now;
-{
- struct tm *tm, gmt;
- struct timeb ftz;
- time_t Start;
- time_t tod;
- time_t nowtime;
-
- yyInput = p;
- if (now == NULL) {
- struct tm *gmt_ptr;
-
- now = &ftz;
- (void)time (&nowtime);
-
- gmt_ptr = gmtime (&nowtime);
- if (gmt_ptr != NULL)
- {
- /* Make a copy, in case localtime modifies *tm (I think
- that comment now applies to *gmt_ptr, but I am too
- lazy to dig into how gmtime and locatime allocate the
- structures they return pointers to). */
- gmt = *gmt_ptr;
- }
-
- if (! (tm = localtime (&nowtime)))
- return -1;
-
- if (gmt_ptr != NULL)
- ftz.timezone = difftm (&gmt, tm) / 60;
- else
- /* We are on a system like VMS, where the system clock is
- in local time and the system has no concept of timezones.
- Hopefully we can fake this out (for the case in which the
- user specifies no timezone) by just saying the timezone
- is zero. */
- ftz.timezone = 0;
-
- if(tm->tm_isdst)
- ftz.timezone += 60;
- }
- else
- {
- nowtime = now->time;
- }
-
- tm = localtime(&nowtime);
- yyYear = tm->tm_year + 1900;
- yyMonth = tm->tm_mon + 1;
- yyDay = tm->tm_mday;
- yyTimezone = now->timezone;
- yyDSTmode = DSTmaybe;
- yyHour = 0;
- yyMinutes = 0;
- yySeconds = 0;
- yyMeridian = MER24;
- yyRelSeconds = 0;
- yyRelMonth = 0;
- yyHaveDate = 0;
- yyHaveDay = 0;
- yyHaveRel = 0;
- yyHaveTime = 0;
- yyHaveZone = 0;
-
- if (yyparse()
- || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
- return -1;
-
- if (yyHaveDate || yyHaveTime || yyHaveDay) {
- Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
- yyMeridian, yyDSTmode);
- if (Start < 0)
- return -1;
- }
- else {
- Start = nowtime;
- if (!yyHaveRel)
- Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
- }
-
- Start += yyRelSeconds;
- Start += RelativeMonth(Start, yyRelMonth);
-
- if (yyHaveDay && !yyHaveDate) {
- tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
- Start += tod;
- }
-
- /* Have to do *something* with a legitimate -1 so it's distinguishable
- * from the error return value. (Alternately could set errno on error.) */
- return Start == -1 ? 0 : Start;
-}
-
-
-#if defined(TEST)
-
-/* ARGSUSED */
-int
-main(ac, av)
- int ac;
- char *av[];
-{
- char buff[128];
- time_t d;
-
- (void)printf("Enter date, or blank line to exit.\n\t> ");
- (void)fflush(stdout);
- while (gets(buff) && buff[0]) {
- d = get_date(buff, (struct timeb *)NULL);
- if (d == -1)
- (void)printf("Bad format - couldn't convert.\n");
- else
- (void)printf("%s", ctime(&d));
- (void)printf("\t> ");
- (void)fflush(stdout);
- }
- exit(0);
- /* NOTREACHED */
-}
-#endif /* defined(TEST) */
-#line 1031 "y.tab.c"
-/* allocate initial stack or double stack size, up to YYMAXDEPTH */
-int yyparse __P((void));
-static int yygrowstack __P((void));
-static int yygrowstack()
-{
- int newsize, i;
- short *newss;
- YYSTYPE *newvs;
-
- if ((newsize = yystacksize) == 0)
- newsize = YYINITSTACKSIZE;
- else if (newsize >= YYMAXDEPTH)
- return -1;
- else if ((newsize *= 2) > YYMAXDEPTH)
- newsize = YYMAXDEPTH;
- i = yyssp - yyss;
- if ((newss = (short *)realloc(yyss, newsize * sizeof *newss)) == NULL)
- return -1;
- yyss = newss;
- yyssp = newss + i;
- if ((newvs = (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs)) == NULL)
- return -1;
- yyvs = newvs;
- yyvsp = newvs + i;
- yystacksize = newsize;
- yysslim = yyss + newsize - 1;
- return 0;
-}
-
-#define YYABORT goto yyabort
-#define YYREJECT goto yyabort
-#define YYACCEPT goto yyaccept
-#define YYERROR goto yyerrlab
-int
-yyparse()
-{
- int yym, yyn, yystate;
-#if YYDEBUG
- char *yys;
-
- if ((yys = getenv("YYDEBUG")) != NULL)
- {
- yyn = *yys;
- if (yyn >= '0' && yyn <= '9')
- yydebug = yyn - '0';
- }
-#endif
-
- yynerrs = 0;
- yyerrflag = 0;
- yychar = (-1);
-
- if (yyss == NULL && yygrowstack()) goto yyoverflow;
- yyssp = yyss;
- yyvsp = yyvs;
- *yyssp = yystate = 0;
-
-yyloop:
- if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
- if (yychar < 0)
- {
- if ((yychar = yylex()) < 0) yychar = 0;
-#if YYDEBUG
- if (yydebug)
- {
- yys = 0;
- if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
- if (!yys) yys = "illegal-symbol";
- printf("%sdebug: state %d, reading %d (%s)\n",
- YYPREFIX, yystate, yychar, yys);
- }
-#endif
- }
- if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
- yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
- {
-#if YYDEBUG
- if (yydebug)
- printf("%sdebug: state %d, shifting to state %d\n",
- YYPREFIX, yystate, yytable[yyn]);
-#endif
- if (yyssp >= yysslim && yygrowstack())
- {
- goto yyoverflow;
- }
- *++yyssp = yystate = yytable[yyn];
- *++yyvsp = yylval;
- yychar = (-1);
- if (yyerrflag > 0) --yyerrflag;
- goto yyloop;
- }
- if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
- yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
- {
- yyn = yytable[yyn];
- goto yyreduce;
- }
- if (yyerrflag) goto yyinrecovery;
- goto yynewerror;
-yynewerror:
- yyerror("syntax error");
- goto yyerrlab;
-yyerrlab:
- ++yynerrs;
-yyinrecovery:
- if (yyerrflag < 3)
- {
- yyerrflag = 3;
- for (;;)
- {
- if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
- yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
- {
-#if YYDEBUG
- if (yydebug)
- printf("%sdebug: state %d, error recovery shifting\
- to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
-#endif
- if (yyssp >= yysslim && yygrowstack())
- {
- goto yyoverflow;
- }
- *++yyssp = yystate = yytable[yyn];
- *++yyvsp = yylval;
- goto yyloop;
- }
- else
- {
-#if YYDEBUG
- if (yydebug)
- printf("%sdebug: error recovery discarding state %d\n",
- YYPREFIX, *yyssp);
-#endif
- if (yyssp <= yyss) goto yyabort;
- --yyssp;
- --yyvsp;
- }
- }
- }
- else
- {
- if (yychar == 0) goto yyabort;
-#if YYDEBUG
- if (yydebug)
- {
- yys = 0;
- if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
- if (!yys) yys = "illegal-symbol";
- printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
- YYPREFIX, yystate, yychar, yys);
- }
-#endif
- yychar = (-1);
- goto yyloop;
- }
-yyreduce:
-#if YYDEBUG
- if (yydebug)
- printf("%sdebug: state %d, reducing by rule %d (%s)\n",
- YYPREFIX, yystate, yyn, yyrule[yyn]);
-#endif
- yym = yylen[yyn];
- yyval = yyvsp[1-yym];
- switch (yyn)
- {
-case 3:
-#line 168 "getdate.y"
-{
- yyHaveTime++;
- }
-break;
-case 4:
-#line 171 "getdate.y"
-{
- yyHaveZone++;
- }
-break;
-case 5:
-#line 174 "getdate.y"
-{
- yyHaveDate++;
- }
-break;
-case 6:
-#line 177 "getdate.y"
-{
- yyHaveDay++;
- }
-break;
-case 7:
-#line 180 "getdate.y"
-{
- yyHaveRel++;
- }
-break;
-case 9:
-#line 186 "getdate.y"
-{
- yyHour = yyvsp[-1].Number;
- yyMinutes = 0;
- yySeconds = 0;
- yyMeridian = yyvsp[0].Meridian;
- }
-break;
-case 10:
-#line 192 "getdate.y"
-{
- yyHour = yyvsp[-3].Number;
- yyMinutes = yyvsp[-1].Number;
- yySeconds = 0;
- yyMeridian = yyvsp[0].Meridian;
- }
-break;
-case 11:
-#line 198 "getdate.y"
-{
- yyHour = yyvsp[-3].Number;
- yyMinutes = yyvsp[-1].Number;
- yyMeridian = MER24;
- yyDSTmode = DSToff;
- yyTimezone = - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60);
- }
-break;
-case 12:
-#line 205 "getdate.y"
-{
- yyHour = yyvsp[-5].Number;
- yyMinutes = yyvsp[-3].Number;
- yySeconds = yyvsp[-1].Number;
- yyMeridian = yyvsp[0].Meridian;
- }
-break;
-case 13:
-#line 211 "getdate.y"
-{
- yyHour = yyvsp[-5].Number;
- yyMinutes = yyvsp[-3].Number;
- yySeconds = yyvsp[-1].Number;
- yyMeridian = MER24;
- yyDSTmode = DSToff;
- yyTimezone = - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60);
- }
-break;
-case 14:
-#line 221 "getdate.y"
-{
- yyTimezone = yyvsp[0].Number;
- yyDSTmode = DSToff;
- }
-break;
-case 15:
-#line 225 "getdate.y"
-{
- yyTimezone = yyvsp[0].Number;
- yyDSTmode = DSTon;
- }
-break;
-case 16:
-#line 230 "getdate.y"
-{
- yyTimezone = yyvsp[-1].Number;
- yyDSTmode = DSTon;
- }
-break;
-case 17:
-#line 236 "getdate.y"
-{
- yyDayOrdinal = 1;
- yyDayNumber = yyvsp[0].Number;
- }
-break;
-case 18:
-#line 240 "getdate.y"
-{
- yyDayOrdinal = 1;
- yyDayNumber = yyvsp[-1].Number;
- }
-break;
-case 19:
-#line 244 "getdate.y"
-{
- yyDayOrdinal = yyvsp[-1].Number;
- yyDayNumber = yyvsp[0].Number;
- }
-break;
-case 20:
-#line 250 "getdate.y"
-{
- yyMonth = yyvsp[-2].Number;
- yyDay = yyvsp[0].Number;
- }
-break;
-case 21:
-#line 254 "getdate.y"
-{
- if (yyvsp[-4].Number >= 100) {
- yyYear = yyvsp[-4].Number;
- yyMonth = yyvsp[-2].Number;
- yyDay = yyvsp[0].Number;
- } else {
- yyMonth = yyvsp[-4].Number;
- yyDay = yyvsp[-2].Number;
- yyYear = yyvsp[0].Number;
- }
- }
-break;
-case 22:
-#line 265 "getdate.y"
-{
- /* ISO 8601 format. yyyy-mm-dd. */
- yyYear = yyvsp[-2].Number;
- yyMonth = -yyvsp[-1].Number;
- yyDay = -yyvsp[0].Number;
- }
-break;
-case 23:
-#line 271 "getdate.y"
-{
- /* e.g. 17-JUN-1992. */
- yyDay = yyvsp[-2].Number;
- yyMonth = yyvsp[-1].Number;
- yyYear = -yyvsp[0].Number;
- }
-break;
-case 24:
-#line 277 "getdate.y"
-{
- yyMonth = yyvsp[-1].Number;
- yyDay = yyvsp[0].Number;
- }
-break;
-case 25:
-#line 281 "getdate.y"
-{
- yyMonth = yyvsp[-3].Number;
- yyDay = yyvsp[-2].Number;
- yyYear = yyvsp[0].Number;
- }
-break;
-case 26:
-#line 286 "getdate.y"
-{
- yyMonth = yyvsp[0].Number;
- yyDay = yyvsp[-1].Number;
- }
-break;
-case 27:
-#line 290 "getdate.y"
-{
- yyMonth = yyvsp[-1].Number;
- yyDay = yyvsp[-2].Number;
- yyYear = yyvsp[0].Number;
- }
-break;
-case 28:
-#line 297 "getdate.y"
-{
- yyRelSeconds = -yyRelSeconds;
- yyRelMonth = -yyRelMonth;
- }
-break;
-case 30:
-#line 304 "getdate.y"
-{
- yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number * 60L;
- }
-break;
-case 31:
-#line 307 "getdate.y"
-{
- yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number * 60L;
- }
-break;
-case 32:
-#line 310 "getdate.y"
-{
- yyRelSeconds += yyvsp[0].Number * 60L;
- }
-break;
-case 33:
-#line 313 "getdate.y"
-{
- yyRelSeconds += yyvsp[-1].Number;
- }
-break;
-case 34:
-#line 316 "getdate.y"
-{
- yyRelSeconds += yyvsp[-1].Number;
- }
-break;
-case 35:
-#line 319 "getdate.y"
-{
- yyRelSeconds++;
- }
-break;
-case 36:
-#line 322 "getdate.y"
-{
- yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
- }
-break;
-case 37:
-#line 325 "getdate.y"
-{
- yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
- }
-break;
-case 38:
-#line 328 "getdate.y"
-{
- yyRelMonth += yyvsp[0].Number;
- }
-break;
-case 39:
-#line 333 "getdate.y"
-{
- if (yyHaveTime && yyHaveDate && !yyHaveRel)
- yyYear = yyvsp[0].Number;
- else {
- if(yyvsp[0].Number>10000) {
- yyHaveDate++;
- yyDay= (yyvsp[0].Number)%100;
- yyMonth= (yyvsp[0].Number/100)%100;
- yyYear = yyvsp[0].Number/10000;
- }
- else {
- yyHaveTime++;
- if (yyvsp[0].Number < 100) {
- yyHour = yyvsp[0].Number;
- yyMinutes = 0;
- }
- else {
- yyHour = yyvsp[0].Number / 100;
- yyMinutes = yyvsp[0].Number % 100;
- }
- yySeconds = 0;
- yyMeridian = MER24;
- }
- }
- }
-break;
-case 40:
-#line 360 "getdate.y"
-{
- yyval.Meridian = MER24;
- }
-break;
-case 41:
-#line 363 "getdate.y"
-{
- yyval.Meridian = yyvsp[0].Meridian;
- }
-break;
-#line 1487 "y.tab.c"
- }
- yyssp -= yym;
- yystate = *yyssp;
- yyvsp -= yym;
- yym = yylhs[yyn];
- if (yystate == 0 && yym == 0)
- {
-#if YYDEBUG
- if (yydebug)
- printf("%sdebug: after reduction, shifting from state 0 to\
- state %d\n", YYPREFIX, YYFINAL);
-#endif
- yystate = YYFINAL;
- *++yyssp = YYFINAL;
- *++yyvsp = yyval;
- if (yychar < 0)
- {
- if ((yychar = yylex()) < 0) yychar = 0;
-#if YYDEBUG
- if (yydebug)
- {
- yys = 0;
- if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
- if (!yys) yys = "illegal-symbol";
- printf("%sdebug: state %d, reading %d (%s)\n",
- YYPREFIX, YYFINAL, yychar, yys);
- }
-#endif
- }
- if (yychar == 0) goto yyaccept;
- goto yyloop;
- }
- if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
- yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
- yystate = yytable[yyn];
- else
- yystate = yydgoto[yym];
-#if YYDEBUG
- if (yydebug)
- printf("%sdebug: after reduction, shifting from state %d \
-to state %d\n", YYPREFIX, *yyssp, yystate);
-#endif
- if (yyssp >= yysslim && yygrowstack())
- {
- goto yyoverflow;
- }
- *++yyssp = yystate;
- *++yyvsp = yyval;
- goto yyloop;
-yyoverflow:
- yyerror("yacc stack overflow");
-yyabort:
- return (1);
-yyaccept:
- return (0);
-}
OTHERSRCS = Makefile Makefile.preamble Makefile.postamble groups.1\
id.1 whoami.1
+OTHER_CFLAGS = -D__FBSDID=__RCSID -DUSE_BSM_AUDIT
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
CODE_GEN_STYLE = DYNAMIC
.\" SUCH DAMAGE.
.\"
.\" @(#)groups.1 8.1 (Berkeley) 6/6/93
-.\" $FreeBSD: src/usr.bin/id/groups.1,v 1.8 2001/08/15 09:09:41 ru Exp $
+.\" $FreeBSD: src/usr.bin/id/groups.1,v 1.10 2006/12/23 17:14:01 ru Exp $
.\"
.Dd June 6, 1993
.Dt GROUPS 1
.Pp
The
.Nm
-utility displays the groups to which you (or the optionally specified user)
+utility displays the groups to which you (or the optionally specified
+.Ar user )
belong.
-.Sh DIAGNOSTICS
+.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
.Xr id 1
.\" SUCH DAMAGE.
.\"
.\" @(#)id.1 8.1 (Berkeley) 6/6/93
-.\" $FreeBSD: src/usr.bin/id/id.1,v 1.11 2001/08/15 09:09:41 ru Exp $
+.\" $FreeBSD: src/usr.bin/id/id.1,v 1.18 2006/09/26 22:28:12 ceri Exp $
.\"
-.Dd June 6, 1993
+.Dd September 26, 2006
.Dt ID 1
.Os
.Sh NAME
.Nm
.Op Ar user
.Nm
+.Fl A
+.Nm
.Fl G Op Fl n
.Op Ar user
.Nm
+.Fl M
+.Nm
.Fl P
.Op Ar user
.Nm
.Pp
The options are as follows:
.Bl -tag -width indent
+.It Fl A
+Display the process audit user ID and other process audit properties, which
+requires privilege.
.It Fl G
Display the different group IDs (effective, real and supplementary)
as white-space separated numbers, in no particular order.
+.It Fl M
+Display the MAC label of the current process.
.It Fl P
Display the id as a password file entry.
+.It Fl a
+Ignored for compatibility with other
+.Nm
+implementations.
.It Fl g
Display the effective group ID as a number.
.It Fl n
.It Fl u
Display the effective user ID as a number.
.El
-.Sh DIAGNOSTICS
+.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
.Xr who 1
#endif
#endif /* not lint */
#include <sys/cdefs.h>
-__RCSID("$FreeBSD: src/usr.bin/id/id.c,v 1.19 2002/09/04 23:29:02 dwmalone Exp $");
+__FBSDID("$FreeBSD: src/usr.bin/id/id.c,v 1.33 2006/12/29 12:28:34 stefanf Exp $");
#include <sys/param.h>
+#ifndef __APPLE__
+#include <sys/mac.h>
+#endif /* !__APPLE__ */
+
+#ifdef USE_BSM_AUDIT
+#include <bsm/audit.h>
+#endif
#include <err.h>
+#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
-void current(void);
+void id_print(struct passwd *, int, int, int);
void pline(struct passwd *);
void pretty(struct passwd *);
+void auditid(void);
void group(struct passwd *, int);
+void maclabel(void);
void usage(void);
-void user(struct passwd *);
-struct passwd *
- who(char *);
+struct passwd *who(char *);
int isgroups, iswhoami;
+#ifdef __APPLE__
+// SPI for 5235093
+int32_t getgrouplist_2(const char *, gid_t, gid_t **);
+#endif
+
int
main(int argc, char *argv[])
{
struct group *gr;
struct passwd *pw;
- int Gflag, Pflag, ch, gflag, id, nflag, pflag, rflag, uflag;
+ int Gflag, Mflag, Pflag, ch, gflag, id, nflag, pflag, rflag, uflag;
+ int Aflag;
const char *myname;
- Gflag = Pflag = gflag = nflag = pflag = rflag = uflag = 0;
+ Gflag = Mflag = Pflag = gflag = nflag = pflag = rflag = uflag = 0;
+ Aflag = 0;
myname = strrchr(argv[0], '/');
myname = (myname != NULL) ? myname + 1 : argv[0];
}
while ((ch = getopt(argc, argv,
- (isgroups || iswhoami) ? "" : "PGgnpru")) != -1)
+ (isgroups || iswhoami) ? "" : "APGMagnpru")) != -1)
switch(ch) {
+#ifdef USE_BSM_AUDIT
+ case 'A':
+ Aflag = 1;
+ break;
+#endif
case 'G':
Gflag = 1;
break;
+ case 'M':
+ Mflag = 1;
+ break;
case 'P':
Pflag = 1;
break;
+ case 'a':
+ break;
case 'g':
gflag = 1;
break;
if (iswhoami && argc > 0)
usage();
- switch(Gflag + Pflag + gflag + pflag + uflag) {
+ switch(Aflag + Gflag + Mflag + Pflag + gflag + pflag + uflag) {
case 1:
break;
case 0:
pw = *argv ? who(*argv) : NULL;
+ if (Mflag && pw != NULL)
+ usage();
+
+#ifdef USE_BSM_AUDIT
+ if (Aflag) {
+ auditid();
+ exit(0);
+ }
+#endif
+
if (gflag) {
id = pw ? pw->pw_gid : rflag ? getgid() : getegid();
if (nflag && (gr = getgrgid(id)))
exit(0);
}
+ if (Mflag) {
+ maclabel();
+ exit(0);
+ }
+
if (Pflag) {
pline(pw);
exit(0);
exit(0);
}
- if (pw)
- user(pw);
- else
- current();
+ if (pw) {
+ id_print(pw, 1, 0, 0);
+ }
+ else {
+ id = getuid();
+ pw = getpwuid(id);
+ id_print(pw, 0, 1, 1);
+ }
exit(0);
}
}
void
-current(void)
+id_print(struct passwd *pw, int use_ggl, int p_euid, int p_egid)
{
struct group *gr;
- struct passwd *pw;
- int cnt, id, eid, gid, egid, lastid, ngroups;
- gid_t groups[NGROUPS];
+ gid_t gid, egid, lastgid;
+ uid_t uid, euid;
+ int cnt, ngroups;
+#ifdef __APPLE__
+ gid_t *groups;
+#else
+ gid_t groups[NGROUPS + 1];
+#endif
const char *fmt;
- id = getuid();
- (void)printf("uid=%u", id);
- if ((pw = getpwuid(id)))
- (void)printf("(%s)", pw->pw_name);
- gid = getgid();
- (void)printf(" gid=%u", gid);
+#ifdef __APPLE__
+ if (pw == NULL) {
+ pw = getpwuid(getuid());
+ }
+
+ use_ggl = 1;
+#endif
+
+ if (pw != NULL) {
+ uid = pw->pw_uid;
+ gid = pw->pw_gid;
+ }
+ else {
+ uid = getuid();
+ gid = getgid();
+ }
+
+ if (use_ggl && pw != NULL) {
+#ifdef __APPLE__
+ // 5235093
+ ngroups = getgrouplist_2(pw->pw_name, gid, &groups);
+#else
+ ngroups = NGROUPS + 1;
+ getgrouplist(pw->pw_name, gid, groups, &ngroups);
+#endif
+ }
+ else {
+#ifdef __APPLE__
+ groups = malloc(NGROUPS + 1);
+#endif
+ ngroups = getgroups(NGROUPS + 1, groups);
+ }
+
+ if (pw != NULL)
+ printf("uid=%u(%s)", uid, pw->pw_name);
+ else
+ printf("uid=%u", getuid());
+ printf(" gid=%u", gid);
if ((gr = getgrgid(gid)))
(void)printf("(%s)", gr->gr_name);
- if ((eid = geteuid()) != id) {
- (void)printf(" euid=%u", eid);
- if ((pw = getpwuid(eid)))
+ if (p_euid && (euid = geteuid()) != uid) {
+ (void)printf(" euid=%u", euid);
+ if ((pw = getpwuid(euid)))
(void)printf("(%s)", pw->pw_name);
}
- if ((egid = getegid()) != gid) {
+ if (p_egid && (egid = getegid()) != gid) {
(void)printf(" egid=%u", egid);
if ((gr = getgrgid(egid)))
(void)printf("(%s)", gr->gr_name);
}
- if ((ngroups = getgroups(NGROUPS, groups))) {
- for (fmt = " groups=%u", lastid = -1, cnt = 0; cnt < ngroups;
- fmt = ", %u", lastid = id) {
- id = groups[cnt++];
- if (lastid == id)
- continue;
- (void)printf(fmt, id);
- if ((gr = getgrgid(id)))
- (void)printf("(%s)", gr->gr_name);
- }
- }
- (void)printf("\n");
-}
-
-void
-user(struct passwd *pw)
-{
- struct group *gr;
- const char *fmt;
- int cnt, gid, lastgid, ngroups, groups[NGROUPS + 1];
-
- (void)printf("uid=%u(%s)", pw->pw_uid, pw->pw_name);
- gid = pw->pw_gid;
- (void)printf(" gid=%u", gid);
- if ((gr = getgrgid(gid)))
- (void)printf("(%s)", gr->gr_name);
- ngroups = NGROUPS + 1;
- (void) getgrouplist(pw->pw_name, gid, groups, &ngroups);
fmt = " groups=%u";
for (lastgid = -1, cnt = 0; cnt < ngroups; ++cnt) {
if (lastgid == (gid = groups[cnt]))
continue;
- (void)printf(fmt, gid);
- fmt = ", %u";
+ printf(fmt, gid);
+ fmt = ",%u";
if ((gr = getgrgid(gid)))
- (void)printf("(%s)", gr->gr_name);
+ printf("(%s)", gr->gr_name);
lastgid = gid;
}
- (void)printf("\n");
+ printf("\n");
+#ifdef __APPLE__
+ free(groups);
+#endif
}
+#ifdef USE_BSM_AUDIT
+void
+auditid(void)
+{
+ auditinfo_t auditinfo;
+
+ if (getaudit(&auditinfo) < 0)
+ err(1, "getaudit");
+ printf("auid=%d\n", auditinfo.ai_auid);
+ printf("mask.success=0x%08x\n", auditinfo.ai_mask.am_success);
+ printf("mask.failure=0x%08x\n", auditinfo.ai_mask.am_failure);
+ printf("termid.port=0x%08x\n", auditinfo.ai_termid.port);
+ printf("asid=%d\n", auditinfo.ai_asid);
+}
+#endif
+
void
group(struct passwd *pw, int nflag)
{
struct group *gr;
int cnt, id, lastid, ngroups;
+#ifdef __APPLE__
+ gid_t *groups;
+#else
gid_t groups[NGROUPS + 1];
+#endif
const char *fmt;
+#ifdef __APPLE__
+ if (pw == NULL) {
+ pw = getpwuid(getuid());
+ }
+#endif
+
if (pw) {
+#ifdef __APPLE__
+ // 5235093
+ ngroups = getgrouplist_2(pw->pw_name, pw->pw_gid, &groups);
+#else
ngroups = NGROUPS + 1;
(void) getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
+#endif
} else {
+#ifdef __APPLE__
+ groups = malloc(NGROUPS + 1);
+#endif
groups[0] = getgid();
ngroups = getgroups(NGROUPS, groups + 1) + 1;
}
lastid = id;
}
(void)printf("\n");
+#ifdef __APPLE__
+ free(groups);
+#endif
+}
+
+void
+maclabel(void)
+{
+#ifdef __APPLE__
+ errx(1, "-M unsupported");
+#else /* !__APPLE__ */
+ char *string;
+ mac_t label;
+ int error;
+
+ error = mac_prepare_process_label(&label);
+ if (error == -1)
+ errx(1, "mac_prepare_type: %s", strerror(errno));
+
+ error = mac_get_proc(label);
+ if (error == -1)
+ errx(1, "mac_get_proc: %s", strerror(errno));
+
+ error = mac_to_text(label, &string);
+ if (error == -1)
+ errx(1, "mac_to_text: %s", strerror(errno));
+
+ (void)printf("%s\n", string);
+ mac_free(label);
+ free(string);
+#endif /* __APPLE__ */
}
struct passwd *
void
pline(struct passwd *pw)
{
- u_int rid;
if (!pw) {
- if ((pw = getpwuid(rid = getuid())) == NULL)
+ if ((pw = getpwuid(getuid())) == NULL)
err(1, "getpwuid");
}
else if (iswhoami)
(void)fprintf(stderr, "usage: whoami\n");
else
- (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n",
+ (void)fprintf(stderr, "%s\n%s%s\n%s\n%s\n%s\n%s\n%s\n",
"usage: id [user]",
+#ifdef USE_BSM_AUDIT
+ " id -A\n",
+#else
+ "",
+#endif
" id -G [-n] [user]",
+ " id -M",
" id -P [user]",
" id -g [-nr] [user]",
" id -p [user]",
.\" SUCH DAMAGE.
.\"
.\" @(#)whoami.1 8.1 (Berkeley) 6/6/93
-.\" $FreeBSD: src/usr.bin/id/whoami.1,v 1.8 2001/08/15 09:09:41 ru Exp $
+.\" $FreeBSD: src/usr.bin/id/whoami.1,v 1.9 2005/01/17 07:44:19 ru Exp $
.\"
.Dd June 6, 1993
.Dt WHOAMI 1
The
.Nm
utility displays your effective user ID as a name.
-.Sh DIAGNOSTICS
+.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
.Xr id 1
OTHERSRCS = Makefile Makefile.preamble Makefile.postamble killall.1
+OTHER_CFLAGS = -D__FBSDID=__RCSID
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
CODE_GEN_STYLE = DYNAMIC
.\" 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 $
+.\" $FreeBSD: src/usr.bin/killall/killall.1,v 1.34 2005/01/17 07:44:20 ru Exp $
.\"
-.Dd June 25, 1995
+.Dd January 26, 2004
.Os
.Dt KILLALL 1
.Sh NAME
.Nd kill processes by name
.Sh SYNOPSIS
.Nm
-.Op Fl d | v
-.Op Fl h | ?\&
+.Op Fl delmsvz
.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
+The
+.Nm
+utility kills processes selected by name, as opposed to the selection by pid
as done by
.Xr kill 1 .
By default, it will send a
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
+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 e
+Use the effective user ID instead of the (default) real user ID for matching
+processes specified with the
+.Fl u
+option.
.It Fl help
Give a help on the command usage and exit.
.It Fl l
.It Fl m
Match the argument
.Ar procname
-as a (case insensitive) regular expression against the names
+as a (case sensitive) regular expression against the names
of processes found.
-CAUTION! This is dangerous, a single dot will match any process
+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.
.Fl t
flags, limit potentially matching processes to those matching
the specified
-.Ar progname .
+.Ar procname .
+.It Fl z
+Do not skip zombies.
+This should not have any effect except to print a few error messages
+if there are zombie processes that match the specified pattern.
.El
.Sh ALL PROCESSES
Sending a signal to all processes with uid
-.Nm XYZ
+.Em XYZ
is already supported by
.Xr kill 1 .
So use
.Xr kill 1
-for this job (e.g. $ kill -TERM -1 or
+for this job (e.g.\& $ kill -TERM -1 or
as root $ echo kill -TERM -1 | su -m <user>)
-.Sh DIAGNOSTICS
+.Sh EXIT STATUS
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
+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
+been signalled successfully.
+Otherwise, a status of 0 will be
returned.
-.Pp
+.Sh DIAGNOSTICS
Diagnostic messages will only be printed if requested by
.Fl d
options.
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
- * $FreeBSD: src/usr.bin/killall/killall.c,v 1.15 2001/10/10 17:48:44 bde Exp $
*/
#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/killall/killall.c,v 1.31 2004/07/29 18:36:35 maxim Exp $");
+
#include <sys/param.h>
+#ifndef __APPLE__
+#include <sys/jail.h>
+#endif /* !__APPLE__ */
#include <sys/stat.h>
#include <sys/user.h>
#include <sys/sysctl.h>
#include <err.h>
#include <errno.h>
#include <unistd.h>
+#include <locale.h>
-static char *prog;
-
-static void
+static void __dead2
usage(void)
{
- fprintf(stderr, "usage: %s [-l] [-v] [-m] [-sig] [-u user] [-t tty] [-c cmd] [cmd]...\n", prog);
+#ifdef __APPLE__
+ fprintf(stderr, "usage: killall [-delmsvz] [-help]\n");
+#else /* !__APPLE__ */
+ fprintf(stderr, "usage: killall [-delmsvz] [-help] [-j jid]\n");
+#endif /* __APPLE__ */
+ fprintf(stderr,
+ " [-u user] [-t tty] [-c cmd] [-SIGNAL] [cmd]...\n");
fprintf(stderr, "At least one option or argument to specify processes must be given.\n");
exit(1);
}
strncpy(buf, str, sizeof(buf));
buf[sizeof(buf) - 1] = '\0';
for (s = buf; *s; s++)
- *s = toupper(*s);
+ *s = toupper((unsigned char)*s);
return buf;
}
int vflag = 0;
int sflag = 0;
int dflag = 0;
+ int eflag = 0;
+#ifndef __APPLE__
+ int jflag = 0;
+#endif /* !__APPLE__*/
int mflag = 0;
+ int zflag = 0;
uid_t uid = 0;
dev_t tdev = 0;
-#ifdef OLD_STYLE
- char thiscmd[MAXCOMLEN+1];
-#else
+ pid_t mypid;
+#ifdef __APPLE__
char *thiscmd;
-#endif
+#else /* !__APPLE__ */
+ char thiscmd[MAXCOMLEN + 1];
+#endif /* __APPLE__ */
pid_t thispid;
+#ifndef __APPLE__
uid_t thisuid;
+#endif /* !__APPLE__ */
dev_t thistdev;
int sig = SIGTERM;
const char *const *p;
char *ep;
int errors = 0;
+#ifndef __APPLE__
+ int jid;
+#endif /* !__APPLE__ */
int mib[4];
size_t miblen;
int st, nprocs;
int matched;
int killed = 0;
- prog = av[0];
+ setlocale(LC_ALL, "");
+
av++;
ac--;
if (**av == '-') {
++*av;
switch (**av) {
+#ifndef __APPLE__
+ case 'j':
+ ++*av;
+ if (**av == '\0')
+ ++av;
+ --ac;
+ jflag++;
+ if (!*av)
+ errx(1, "must specify jid");
+ jid = strtol(*av, &ep, 10);
+ if (!*av || *ep)
+ errx(1, "illegal jid: %s", *av);
+ if (jail_attach(jid) == -1)
+ err(1, "jail_attach(): %d", jid);
+ break;
+#endif /* !__APPLE__ */
case 'u':
++*av;
if (**av == '\0')
case 'd':
dflag++;
break;
+ case 'e':
+ eflag++;
+ break;
case 'm':
mflag++;
break;
+ case 'z':
+ zflag++;
+ break;
default:
- if (isalpha(**av)) {
+ if (isalpha((unsigned char)**av)) {
if (strncasecmp(*av, "sig", 3) == 0)
*av += 3;
for (sig = NSIG, p = sys_signame + 1;
}
if (!sig)
nosig(*av);
- } else if (isdigit(**av)) {
+ } else if (isdigit((unsigned char)**av)) {
sig = strtol(*av, &ep, 10);
if (!*av || *ep)
errx(1, "illegal signal number: %s", *av);
- if (sig < 0 || sig > NSIG)
+ if (sig < 0 || sig >= NSIG)
nosig(*av);
} else
nosig(*av);
}
}
+#ifdef __APPLE__
if (user == NULL && tty == NULL && cmd == NULL && ac == 0)
+#else /* !__APPLE__*/
+ if (user == NULL && tty == NULL && cmd == NULL && !jflag && ac == 0)
+#endif /* __APPLE__ */
usage();
if (tty) {
}
if (user) {
uid = strtol(user, &ep, 10);
- if ((ep - user) < strlen(user)) {
+ if (*user == '\0' || *ep != '\0') { /* was it a number? */
pw = getpwnam(user);
if (pw == NULL)
errx(1, "user %s does not exist", user);
size = 0;
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
+#ifdef __APPLE__
mib[2] = KERN_PROC_ALL;
+#else /* !__APPLE__ */
+ mib[2] = KERN_PROC_PROC;
+#endif /* __APPLE__ */
mib[3] = 0;
miblen = 3;
- if (user && mib[2] == KERN_PROC_ALL) {
- mib[2] = KERN_PROC_RUID;
+ if (user) {
+ mib[2] = eflag ? KERN_PROC_UID : KERN_PROC_RUID;
mib[3] = uid;
miblen = 4;
- }
- if (tty && mib[2] == KERN_PROC_ALL) {
+ } else if (tty) {
mib[2] = KERN_PROC_TTY;
mib[3] = tdev;
miblen = 4;
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",
+ fprintf(stderr, "proc size mismatch (%zu total, %zu 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);
+ mypid = getpid();
for (i = 0; i < nprocs; i++) {
-#ifndef OLD_STYLE
+#ifdef __APPLE__
+ if ((procs[i].kp_proc.p_stat & SZOMB) == SZOMB && !zflag)
+ continue;
+ thispid = procs[i].kp_proc.p_pid;
+
int mib[3], argmax;
size_t syssize;
char *procargs, *cp;
mib[1] = KERN_ARGMAX;
syssize = sizeof(argmax);
- if (sysctl(mib, 2, &argmax, &syssize, NULL, 0) == -1)
+ if (sysctl(mib, 2, &argmax, &syssize, NULL, 0) == -1)
continue;
procargs = malloc(argmax);
mib[0] = CTL_KERN;
mib[1] = KERN_PROCARGS;
- mib[2] = procs[i].kp_proc.p_pid;
-
+ mib[2] = thispid;
+
syssize = (size_t)argmax;
if (sysctl(mib, 3, procargs, &syssize, NULL, 0) == -1) {
free(procargs);
break;
}
}
+
if (cp == &procargs[syssize]) {
free(procargs);
continue;
/* Strip off any path that was specified */
for (thiscmd = cp; (cp < &procargs[syssize]) && (*cp != '\0'); cp++) {
- if( *cp == '/' ) {
- thiscmd = cp+1;
+ if (*cp == '/') {
+ thiscmd = cp + 1;
}
}
-#else
- thiscmd[MAXCOMLEN] = '\0';
-#endif
- thispid = procs[i].kp_proc.p_pid;
thistdev = procs[i].kp_eproc.e_tdev;
- thisuid = procs[i].kp_eproc.e_pcred.p_ruid; /* real uid */
+#else /* !__APPLE__ */
+ if ((procs[i].ki_stat & SZOMB) == SZOMB && !zflag)
+ continue;
+ thispid = procs[i].ki_pid;
+ strncpy(thiscmd, procs[i].ki_comm, MAXCOMLEN);
+ thiscmd[MAXCOMLEN] = '\0';
+ thistdev = procs[i].ki_tdev;
+#endif /* __APPLE__ */
+#ifndef __APPLE__
+ if (eflag)
+ thisuid = procs[i].ki_uid; /* effective uid */
+ else
+ thisuid = procs[i].ki_ruid; /* real uid */
+#endif /* !__APPLE__ */
+ if (thispid == mypid) {
+#ifdef __APPLE__
+ free(procargs);
+#endif /* __APPLE__ */
+ continue;
+ }
matched = 1;
+#ifndef __APPLE__
if (user) {
if (thisuid != uid)
matched = 0;
}
+#endif /* !__APPLE__ */
if (tty) {
if (thistdev != tdev)
matched = 0;
matched = 0;
}
}
+#ifndef __APPLE__
+ if (jflag && thispid == getpid())
+ matched = 0;
+#endif /* !__APPLE__ */
if (matched == 0) {
-#ifndef OLD_STYLE
+#ifdef __APPLE__
free(procargs);
-#endif
+#endif /* !__APPLE__ */
continue;
}
if (ac > 0)
break;
}
if (matched == 0) {
-#ifndef OLD_STYLE
+#ifdef __APPLE__
free(procargs);
-#endif
+#endif /* __APPLE__ */
continue;
}
if (dflag)
+#ifdef __APPLE__
+ printf("sig:%d, cmd:%s, pid:%d, dev:0x%x\n", sig,
+ thiscmd, thispid, thistdev);
+#else /* !__APPLE__ */
printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
thiscmd, thispid, thistdev, thisuid);
+#endif /* __APPLE__ */
if (vflag || sflag)
printf("kill -%s %d\n", upper(sys_signame[sig]),
killed++;
if (!dflag && !sflag) {
if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
- warn("kill -%s %d", upper(sys_signame[sig]),
- thispid);
+ warn("warning: kill -%s %d",
+ upper(sys_signame[sig]), thispid);
errors = 1;
}
}
+#ifdef __APPLE__
+ free(procargs);
+#endif /* __APPLE__ */
}
if (killed == 0) {
fprintf(stderr, "No matching processes %swere found\n",
: ${mklocatedb:=locate.mklocatedb} # make locate database program
: ${FCODES:=/var/db/locate.database} # the database
: ${SEARCHPATHS:="/"} # directories to be put in the database
-: ${PRUNEPATHS:="/tmp /var/tmp"} # unwanted directories
+: ${PRUNEPATHS:="/tmp /var/tmp */Backups.backupdb"} # unwanted directories
: ${FILESYSTEMS:="hfs ufs"} # allowed filesystems
: ${find:=find}
-/* $NetBSD: nohup.c,v 1.8 1997/12/23 18:21:34 ross Exp $ */
-
/*
- * Copyright (c) 1989 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Portions copyright (c) 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
+#if 0
#ifndef lint
-__COPYRIGHT(
- "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
- All rights reserved.\n");
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
-#if 0
-static char sccsid[] = "@(#)nohup.c 5.4 (Berkeley) 6/1/90";
-#endif
-__RCSID("$NetBSD: nohup.c,v 1.8 1997/12/23 18:21:34 ross Exp $");
+static char sccsid[] = "@(#)nohup.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/nohup/nohup.c,v 1.10 2003/05/03 19:44:46 obrien Exp $");
+#endif
#include <sys/param.h>
-#include <sys/file.h>
#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
#include <fcntl.h>
-#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <errno.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#include <vproc.h>
+#include <vproc_priv.h>
+#endif
-static void dofile __P((void));
-static void usage __P((void));
-int main __P((int, char **));
+static void dofile(void);
+static void usage(void);
-/* nohup shall exit with one of the following values:
- 126 - The utility was found but could not be invoked.
- 127 - An error occured in the nohup utility, or the utility could
- not be found. */
-#define EXIT_NOEXEC 126
-#define EXIT_NOTFOUND 127
-#define EXIT_MISC 127
+#define FILENAME "nohup.out"
+/*
+ * POSIX mandates that we exit with:
+ * 126 - If the utility was found, but failed to execute.
+ * 127 - If any other error occurred.
+ */
+#define EXIT_NOEXEC 126
+#define EXIT_NOTFOUND 127
+#define EXIT_MISC 127
int
-main(argc, argv)
- int argc;
- char **argv;
+main(int argc, char *argv[])
{
int exit_status;
- if (argc > 1 && !strcmp(argv[1], "--")) {
- argv++;
- argc--;
- }
- if (argc < 2)
+ while (getopt(argc, argv, "") != -1)
+ usage();
+ argc -= optind;
+ argv += optind;
+ if (argc < 1)
usage();
if (isatty(STDOUT_FILENO))
dofile();
- if (isatty(STDERR_FILENO) && dup2(STDOUT_FILENO, STDERR_FILENO) == -1) {
+ if (isatty(STDERR_FILENO) && dup2(STDOUT_FILENO, STDERR_FILENO) == -1)
/* may have just closed stderr */
- (void)fprintf(stdin, "nohup: %s\n", strerror(errno));
- exit(EXIT_MISC);
- }
+ err(EXIT_MISC, "%s", argv[0]);
- /* The nohup utility shall take the standard action for all signals
- except that SIGHUP shall be ignored. */
(void)signal(SIGHUP, SIG_IGN);
- execvp(argv[1], &argv[1]);
+#ifdef __APPLE__
+ if (_vprocmgr_move_subset_to_user(geteuid(), "Background") != NULL)
+ err(EXIT_MISC, "can't migrate to background session");
+#endif
+ execvp(*argv, argv);
exit_status = (errno == ENOENT) ? EXIT_NOTFOUND : EXIT_NOEXEC;
- (void)fprintf(stderr, "nohup: %s: %s\n", argv[1], strerror(errno));
- exit(exit_status);
+ err(exit_status, "%s", argv[0]);
}
static void
-dofile()
+dofile(void)
{
int fd;
- char *p, path[MAXPATHLEN];
-
- /* If the standard output is a terminal, all output written to
- its standard output shall be appended to the end of the file
- nohup.out in the current directory. If nohup.out cannot be
- created or opened for appending, the output shall be appended
- to the end of the file nohup.out in the directory specified
- by the HOME environment variable.
-
- If a file is created, the file's permission bits shall be
- set to S_IRUSR | S_IWUSR. */
-#define FILENAME "nohup.out"
+ char path[MAXPATHLEN];
+ const char *p;
+
+ /*
+ * POSIX mandates if the standard output is a terminal, the standard
+ * output is appended to nohup.out in the working directory. Failing
+ * that, it will be appended to nohup.out in the directory obtained
+ * from the HOME environment variable. If file creation is required,
+ * the mode_t is set to S_IRUSR | S_IWUSR.
+ */
p = FILENAME;
- if ((fd = open(p, O_RDWR|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR)) >= 0)
+ fd = open(p, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
+ if (fd != -1)
goto dupit;
- if ((p = getenv("HOME")) != NULL) {
- (void)strcpy(path, p);
- (void)strcat(path, "/");
- (void)strcat(path, FILENAME);
- if ((fd = open(p = path, O_RDWR|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR)) >= 0)
+ if ((p = getenv("HOME")) != NULL && *p != '\0' &&
+ (size_t)snprintf(path, sizeof(path), "%s/%s", p, FILENAME) <
+ sizeof(path)) {
+ fd = open(p = path, O_RDWR | O_CREAT | O_APPEND,
+ S_IRUSR | S_IWUSR);
+ if (fd != -1)
goto dupit;
}
- (void)fprintf(stderr, "nohup: can't open a nohup.out file.\n");
- exit(EXIT_MISC);
+ errx(EXIT_MISC, "can't open a nohup.out file");
-dupit: (void)lseek(fd, 0L, SEEK_END);
- if (dup2(fd, STDOUT_FILENO) == -1) {
- (void)fprintf(stderr, "nohup: %s\n", strerror(errno));
- exit(EXIT_MISC);
- }
- (void)fprintf(stderr, "sending output to %s\n", p);
+dupit:
+#ifdef __APPLE__
+ (void)lseek(fd, 0L, SEEK_END);
+#endif
+ if (dup2(fd, STDOUT_FILENO) == -1)
+ err(EXIT_MISC, NULL);
+ (void)fprintf(stderr, "appending output to %s\n", p);
}
static void
-usage()
+usage(void)
{
- (void)fprintf(stderr, "usage: nohup command\n");
+ (void)fprintf(stderr, "usage: nohup [--] utility [arguments]\n");
exit(EXIT_MISC);
}
.Ar format
.Op Ar arguments ...
.Sh DESCRIPTION
+The
.Nm
-formats and prints its arguments, after the first, under control
+utility formats and prints its arguments, after the first, under control
of the
.Ar format .
The
OTHERSRCS = Makefile Makefile.preamble Makefile.postamble pwd.1
+OTHER_CFLAGS = -D__FBSDID=__RCSID
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
CODE_GEN_STYLE = DYNAMIC
-.\" $NetBSD: pwd.1,v 1.12 1997/09/14 08:51:38 lukem Exp $
-.\"
+.\"-
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" 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.
.\" SUCH DAMAGE.
.\"
.\" @(#)pwd.1 8.2 (Berkeley) 4/28/95
+.\" $FreeBSD: src/bin/pwd/pwd.1,v 1.26 2005/01/16 16:41:58 ru Exp $
.\"
-.Dd November 2, 1998
+.Dd April 12, 2003
.Dt PWD 1
-.Os BSD 4
+.Os
.Sh NAME
.Nm pwd
.Nd return working directory name
.Sh SYNOPSIS
.Nm
-.Op Fl LP
+.Op Fl L | P
.Sh DESCRIPTION
+The
.Nm
-writes the absolute pathname of the current working directory to
+utility writes the absolute pathname of the current working directory to
the standard output.
.Pp
-The
+Some shells may provide a builtin
.Nm
-utility exits 0 on success, and >0 if an error occurs.
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
.Pp
-The following options are available:
+The options are as follows:
.Bl -tag -width indent
.It Fl L
-Print the logical path to the current working directory, as defined
-by the shell in the environment variable PWD.
+Display the logical current working directory.
.It Fl P
-Print the physical path to the current working directory, with symbolic
-links in the path resolved. This is the default.
+Display the physical current working directory (all symbolic links resolved).
.El
-.Sh STANDARDS
-The
-.Nm
-utility is expected to be
-.St -p1003.2
-compatible.
+.Pp
+If no options are specified, the
+.\" 4207130
+.Fl L
+option is assumed.
+.Sh ENVIRONMENT
+Environment variables used by
+.Nm :
+.Bl -tag -width ".Ev PWD"
+.It Ev PWD
+Logical current working directory.
+.El
+.Sh EXIT STATUS
+.Ex -std
.Sh SEE ALSO
+.Xr builtin 1 ,
.Xr cd 1 ,
.Xr csh 1 ,
+.Xr sh 1 ,
.Xr getcwd 3
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
.Sh BUGS
In
.Xr csh 1
the command
.Ic dirs
-is always faster (although it can give a different answer in the rare case
+is always faster because it is built into that shell.
+However, it can give a different answer in the rare case
that the current directory or a containing directory was moved after
-the shell descended into it).
+the shell descended into it.
+.Pp
+The
+.Fl L
+option does not work unless the
+.Ev PWD
+environment variable is exported by the shell.
-/* $NetBSD: pwd.c,v 1.10 1998/07/28 05:31:26 mycroft Exp $ */
-
-/*
+/*-
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* 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.
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
+#if 0
#ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\n\
- The Regents of the University of California. All rights reserved.\n");
+static char const copyright[] =
+"@(#) Copyright (c) 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
-#if 0
static char sccsid[] = "@(#)pwd.c 8.3 (Berkeley) 4/1/94";
-#else
-__RCSID("$NetBSD: pwd.c,v 1.10 1998/07/28 05:31:26 mycroft Exp $");
-#endif
#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/pwd/pwd.c,v 1.25 2005/02/09 17:37:38 ru Exp $");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <err.h>
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <string.h>
-char *getcwd_logical __P((char *, size_t));
-void usage __P((void));
-int main __P((int, char *[]));
+static char *getcwd_logical(void);
+void usage(void);
int
-main(argc, argv)
- int argc;
- char *argv[];
+main(int argc, char *argv[])
{
+ int physical;
int ch;
- int lFlag=0;
- char *p = NULL;
+ char *p;
+ // 4207130
+ physical = 0;
while ((ch = getopt(argc, argv, "LP")) != -1)
switch (ch) {
case 'L':
- lFlag=1;
+ physical = 0;
break;
case 'P':
- lFlag=0;
+ physical = 1;
break;
case '?':
default:
if (argc != 0)
usage();
- if (lFlag)
- p = getcwd_logical(NULL, 0);
+ /*
+ * If we're trying to find the logical current directory and that
+ * fails, behave as if -P was specified.
+ *
+ * 4701537: Only fall back if $PWD was actually wrong. We want to
+ * fail if the path is too long (errno == ENAMETOOLONG).
+ */
+ if ((!physical && (p = getcwd_logical()) != NULL) ||
+ ((physical || errno == ENOENT) && (p = getcwd(NULL, 0)) != NULL))
+ printf("%s\n", p);
else
- p = getcwd(NULL, 0);
-
- if (p == NULL) err(1, "%s", "");
-
- (void)printf("%s\n", p);
+ err(1, ".");
exit(0);
- /* NOTREACHED */
}
-char *
-getcwd_logical(pt, size)
- char *pt;
- size_t size;
+void
+usage(void)
{
- char *pwd;
- size_t pwdlen;
- dev_t dev;
- ino_t ino;
- struct stat s;
- /* Check $PWD -- if it's right, it's fast. */
- if ((pwd = getenv("PWD")) != NULL && pwd[0] == '/' && stat(pwd, &s) != -1) {
- dev = s.st_dev;
- ino = s.st_ino;
- if (stat(".", &s) != -1 && dev == s.st_dev && ino == s.st_ino) {
- pwdlen = strlen(pwd);
- if (pt) {
- if (!size) {
- errno = EINVAL;
- return (NULL);
- }
- if (pwdlen + 1 > size) {
- errno = ERANGE;
- return (NULL);
- }
- } else if ((pt = malloc(pwdlen + 1)) == NULL) {
- errno = ENOMEM;
- return (NULL);
- }
- memmove(pt, pwd, pwdlen);
- pt[pwdlen] = '\0';
- return (pt);
- }
- }
-
- return (NULL);
+ (void)fprintf(stderr, "usage: pwd [-L | -P]\n");
+ exit(1);
}
-void
-usage()
+static char *
+getcwd_logical(void)
{
- (void)fprintf(stderr, "usage: pwd [-LP]\n");
- exit(1);
- /* NOTREACHED */
+ struct stat lg, phy;
+ char *pwd;
+
+ /*
+ * Check that $PWD is an absolute logical pathname referring to
+ * the current working directory.
+ */
+ if ((pwd = getenv("PWD")) != NULL && *pwd == '/') {
+ if (stat(pwd, &lg) == -1 || stat(".", &phy) == -1)
+ return (NULL);
+ if (lg.st_dev == phy.st_dev && lg.st_ino == phy.st_ino)
+ return (pwd);
+ }
+
+ errno = ENOENT;
+ return (NULL);
}
to
.Dv PRIO_MAX .
Useful priorities are:
-20 (the affected processes will run only when nothing else
-in the system wants to),
+20 (the affected processes will run at the lowest priority),
0 (the ``base'' scheduling priority),
-anything negative (to make things go very fast).
+anything negative (lower values cause more favorable scheduling).
.Sh FILES
.Bl -tag -width /etc/passwd -compact
.It Pa /etc/passwd
OTHERSRCS = Makefile Makefile.preamble Makefile.postamble script.1
+OTHER_CFLAGS = -D__FBSDID=__RCSID
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
CODE_GEN_STYLE = DYNAMIC
-.\" $NetBSD: script.1,v 1.4 1997/10/19 22:57:47 lukem Exp $
-.\"
.\" Copyright (c) 1980, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" SUCH DAMAGE.
.\"
.\" @(#)script.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/script/script.1,v 1.21 2004/07/03 00:24:43 ru Exp $
.\"
-.Dd June 6, 1993
+.Dd January 22, 2004
.Dt SCRIPT 1
-.Os BSD 4
+.Os
.Sh NAME
.Nm script
.Nd make typescript of terminal session
.Sh SYNOPSIS
.Nm
-.Op Fl a
-.Op Ar file
+.Op Fl akq
+.Op Fl t Ar time
+.Op Ar file Op Ar command ...
.Sh DESCRIPTION
+The
.Nm
-makes a typescript of everything printed on your terminal.
+utility makes a typescript of everything printed on your terminal.
It is useful for students who need a hardcopy record of an interactive
-session as proof of an assignment, as the typescript file
+session as proof of an assignment, as the typescript file
can be printed out later with
.Xr lpr 1 .
.Pp
saves all dialogue in
.Ar file .
If no file name is given, the typescript is saved in the file
-.Pa typescript .
+.Pa typescript .
.Pp
-Option:
-.Bl -tag -width Ds
+If the argument
+.Ar command
+is given,
+.Nm
+will run the specified command with an optional argument vector
+instead of an interactive shell.
+.Pp
+The following options are available:
+.Bl -tag -width indent
.It Fl a
Append the output to
.Ar file
or
.Pa typescript ,
retaining the prior contents.
+.It Fl k
+Log keys sent to program as well as output.
+.It Fl q
+Run in quiet mode, omit the start and stop status messages.
+.It Fl t Ar time
+Specify time interval between flushing script output file.
+A value of 0
+causes
+.Nm
+to flush for every character I/O event.
+The default interval is
+30 seconds.
.El
.Pp
-The script ends when the forked shell exits (a
+The script ends when the forked shell (or command) exits (a
.Em control-D
to exit
the Bourne shell
.Pf ( Xr sh 1 ) ,
and
-.Em exit ,
+.Em exit ,
.Em logout
or
-.Em control-d
+.Em control-D
(if
.Em ignoreeof
is not set) for the
Certain interactive commands, such as
.Xr vi 1 ,
create garbage in the typescript file.
+The
.Nm
-works best with commands that do not manipulate the
-screen, the results are meant to emulate a hardcopy
-terminal.
+utility works best with commands that do not manipulate the screen.
+The results are meant to emulate a hardcopy terminal, not an addressable one.
.Sh ENVIRONMENT
The following environment variable is utilized by
-.Nm
-:
+.Nm :
.Bl -tag -width SHELL
.It Ev SHELL
If the variable
.Ev SHELL
exists, the shell forked by
.Nm
-will be that shell. If
+will be that shell.
+If
.Ev SHELL
is not set, the Bourne shell
-is assumed. (Most shells set this variable automatically).
+is assumed.
+(Most shells set this variable automatically).
.El
.Sh SEE ALSO
.Xr csh 1
command appeared in
.Bx 3.0 .
.Sh BUGS
+The
.Nm
-places
+utility places
.Sy everything
in the log file, including linefeeds and backspaces.
This is not what the naive user expects.
+.Pp
+It is not possible to specify a command without also naming the script file
+because of argument parsing compatibility issues.
+.Pp
+When running in
+.Fl k
+mode, echo cancelling is far from ideal.
+The slave terminal mode is checked
+for ECHO mode to check when to avoid manual echo logging.
+This does not
+work when in a raw mode where the program being run is doing manual echo.
-/* $NetBSD: script.c,v 1.6 1998/04/02 11:08:34 kleink Exp $ */
-
/*
* Copyright (c) 1980, 1992, 1993
* The Regents of the University of California. All rights reserved.
*/
#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD: src/usr.bin/script/script.c,v 1.24 2004/02/15 17:30:13 cperciva Exp $");
+
#ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1980, 1992, 1993\n\
- The Regents of the University of California. All rights reserved.\n");
-#endif /* not lint */
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
#ifndef lint
-#if 0
-static char sccsid[] = "@(#)script.c 8.1 (Berkeley) 6/6/93";
+static const char sccsid[] = "@(#)script.c 8.1 (Berkeley) 6/6/93";
#endif
-__RCSID("$NetBSD: script.c,v 1.6 1998/04/02 11:08:34 kleink Exp $");
-#endif /* not lint */
#include <sys/types.h>
#include <sys/wait.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#ifndef __APPLE__
+#include <libutil.h>
+#endif /* !__APPLE__ */
#include <paths.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
-#include <time.h>
-#include <tzfile.h>
#include <unistd.h>
+#ifdef __APPLE__
#include <util.h>
+#endif /* __APPLE__ */
FILE *fscript;
int master, slave;
-int child, subchild;
-int outcc;
-char *fname;
+int child;
+const char *fname;
+int qflg, ttyflg;
struct termios tt;
-void done __P((void));
-void dooutput __P((void));
-void doshell __P((void));
-void fail __P((void));
-void finish __P((int));
-int main __P((int, char **));
-void scriptflush __P((int));
+void done(int) __dead2;
+void dooutput(void);
+void doshell(char **);
+void fail(void);
+void finish(void);
+static void usage(void);
int
-main(argc, argv)
- int argc;
- char *argv[];
+main(int argc, char *argv[])
{
int cc;
- struct termios rtt;
+ struct termios rtt, stt;
struct winsize win;
- int aflg, ch;
+ int aflg, kflg, ch, n;
+ struct timeval tv, *tvp;
+ time_t tvec, start;
+ char obuf[BUFSIZ];
char ibuf[BUFSIZ];
+ fd_set rfd;
+ int flushtime = 30;
- aflg = 0;
- while ((ch = getopt(argc, argv, "a")) != -1)
+ aflg = kflg = 0;
+ while ((ch = getopt(argc, argv, "aqkt:")) != -1)
switch(ch) {
case 'a':
aflg = 1;
break;
+ case 'q':
+ qflg = 1;
+ break;
+ case 'k':
+ kflg = 1;
+ break;
+ case 't':
+ flushtime = atoi(optarg);
+ if (flushtime < 0)
+ err(1, "invalid flush time %d", flushtime);
+ break;
case '?':
default:
- (void)fprintf(stderr, "usage: script [-a] [file]\n");
- exit(1);
+ usage();
}
argc -= optind;
argv += optind;
- if (argc > 0)
+ if (argc > 0) {
fname = argv[0];
- else
+ argv++;
+ argc--;
+ } else
fname = "typescript";
if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL)
- err(1, "fopen %s", fname);
+ err(1, "%s", fname);
- (void)tcgetattr(STDIN_FILENO, &tt);
- (void)ioctl(STDIN_FILENO, TIOCGWINSZ, &win);
- if (openpty(&master, &slave, NULL, &tt, &win) == -1)
- err(1, "openpty");
+ if (ttyflg = isatty(STDIN_FILENO)) {
+ if (tcgetattr(STDIN_FILENO, &tt) == -1)
+ err(1, "tcgetattr");
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win) == -1)
+ err(1, "ioctl");
+ if (openpty(&master, &slave, NULL, &tt, &win) == -1)
+ err(1, "openpty");
+ } else {
+ if (openpty(&master, &slave, NULL, NULL, NULL) == -1)
+ err(1, "openpty");
+ }
- (void)printf("Script started, output file is %s\n", fname);
- rtt = tt;
- cfmakeraw(&rtt);
- rtt.c_lflag &= ~ECHO;
- (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt);
+ if (!qflg) {
+ tvec = time(NULL);
+ (void)printf("Script started, output file is %s\n", fname);
+ (void)fprintf(fscript, "Script started on %s", ctime(&tvec));
+ fflush(fscript);
+ }
+ if (ttyflg) {
+ rtt = tt;
+ cfmakeraw(&rtt);
+ rtt.c_lflag &= ~ECHO;
+ (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt);
+ }
- (void)signal(SIGCHLD, finish);
child = fork();
if (child < 0) {
warn("fork");
- fail();
+ done(1);
}
- if (child == 0) {
- subchild = child = fork();
- if (child < 0) {
- warn("fork");
- fail();
+ if (child == 0)
+ doshell(argv);
+#ifdef __APPLE__
+ (void)close(slave);
+#endif /* __APPLE__ */
+
+ if (flushtime > 0)
+ tvp = &tv;
+ else
+ tvp = NULL;
+
+ start = time(0);
+ FD_ZERO(&rfd);
+ for (;;) {
+ FD_SET(master, &rfd);
+ FD_SET(STDIN_FILENO, &rfd);
+ if (flushtime > 0) {
+ tv.tv_sec = flushtime;
+ tv.tv_usec = 0;
+ }
+ n = select(master + 1, &rfd, 0, 0, tvp);
+ if (n < 0 && errno != EINTR)
+ break;
+ if (n > 0 && FD_ISSET(STDIN_FILENO, &rfd)) {
+ cc = read(STDIN_FILENO, ibuf, BUFSIZ);
+ if (cc < 0)
+ break;
+ if (cc == 0)
+ (void)write(master, ibuf, 0);
+ if (cc > 0) {
+ (void)write(master, ibuf, cc);
+ if (kflg && tcgetattr(master, &stt) >= 0 &&
+ ((stt.c_lflag & ECHO) == 0)) {
+ (void)fwrite(ibuf, 1, cc, fscript);
+ }
+ }
+ }
+ if (n > 0 && FD_ISSET(master, &rfd)) {
+ cc = read(master, obuf, sizeof (obuf));
+ if (cc <= 0)
+ break;
+ (void)write(STDOUT_FILENO, obuf, cc);
+ (void)fwrite(obuf, 1, cc, fscript);
+ }
+ tvec = time(0);
+ if (tvec - start >= flushtime) {
+ fflush(fscript);
+ start = tvec;
}
- if (child)
- dooutput();
- else
- doshell();
}
-
- (void)fclose(fscript);
- while ((cc = read(STDIN_FILENO, ibuf, BUFSIZ)) > 0)
- (void)write(master, ibuf, cc);
- done();
- /* NOTREACHED */
- return (0);
+ finish();
+ done(0);
}
-void
-finish(signo)
- int signo;
+static void
+usage(void)
{
- int die, pid;
- union wait status;
-
- die = 0;
- while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0)
- if (pid == child)
- die = 1;
-
- if (die)
- done();
+ (void)fprintf(stderr,
+ "usage: script [-akq] [-t time] [file [command ...]]\n");
+ exit(1);
}
void
-dooutput()
+finish(void)
{
- struct itimerval value;
- int cc;
- time_t tvec;
- char obuf[BUFSIZ];
-
- (void)close(STDIN_FILENO);
- tvec = time(NULL);
- (void)fprintf(fscript, "Script started on %s", ctime(&tvec));
+ pid_t pid;
+ int die, e, status;
- (void)signal(SIGALRM, scriptflush);
- value.it_interval.tv_sec = SECSPERMIN / 2;
- value.it_interval.tv_usec = 0;
- value.it_value = value.it_interval;
- (void)setitimer(ITIMER_REAL, &value, NULL);
- for (;;) {
- cc = read(master, obuf, sizeof (obuf));
- if (cc <= 0)
- break;
- (void)write(1, obuf, cc);
- (void)fwrite(obuf, 1, cc, fscript);
- outcc += cc;
- }
- done();
-}
+ die = e = 0;
+ while ((pid = wait3(&status, WNOHANG, 0)) > 0)
+ if (pid == child) {
+ die = 1;
+ if (WIFEXITED(status))
+ e = WEXITSTATUS(status);
+ else if (WIFSIGNALED(status))
+ e = WTERMSIG(status);
+ else /* can't happen */
+ e = 1;
+ }
-void
-scriptflush(signo)
- int signo;
-{
- if (outcc) {
- (void)fflush(fscript);
- outcc = 0;
- }
+ if (die)
+ done(e);
}
void
-doshell()
+doshell(char **av)
{
- char *shell;
+ const char *shell;
shell = getenv("SHELL");
if (shell == NULL)
(void)close(master);
(void)fclose(fscript);
login_tty(slave);
- execl(shell, shell, "-i", NULL);
- warn("execl %s", shell);
+ if (av[0]) {
+ execvp(av[0], av);
+ warn("%s", av[0]);
+ } else {
+ execl(shell, shell, "-i", (char *)NULL);
+ warn("%s", shell);
+ }
fail();
}
void
-fail()
+fail(void)
{
-
(void)kill(0, SIGTERM);
- done();
+ done(1);
}
void
-done()
+done(int eno)
{
time_t tvec;
- if (subchild) {
- tvec = time(NULL);
- (void)fprintf(fscript,"\nScript done on %s", ctime(&tvec));
- (void)fclose(fscript);
- (void)close(master);
- } else {
+ if (ttyflg)
(void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
- (void)printf("Script done, output file is %s\n", fname);
+ tvec = time(NULL);
+ if (!qflg) {
+ (void)fprintf(fscript,"\nScript done on %s", ctime(&tvec));
+ (void)printf("\nScript done, output file is %s\n", fname);
}
- exit(0);
+ (void)fclose(fscript);
+ (void)close(master);
+ exit(eno);
}
.Nd substitute user identity
.Sh SYNOPSIS
.Nm
+.Op Fl
.Op Fl flm
-.Op Ar login
-.Op Ar -c shell arguments
+.Op Ar login Op Ar args
.Sh DESCRIPTION
.Nm
requests the password for
.Pp
The options are as follows:
.Bl -tag -width Ds
-.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 ,
int
main(int argc, char *argv[])
{
+ static char *cleanenv;
struct passwd *pwd;
struct pam_conv conv = {misc_conv, NULL};
enum tristate iscsh;
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];
+ char *username, *class, shellbuf[MAXPATHLEN];
const char *p, *user, *shell, *mytty, **nargv;
+ const char *avshell;
+ char avshellbuf[MAXPATHLEN];
shell = class = cleanenv = NULL;
asme = asthem = fastlogin = statusp = 0;
user = "root";
iscsh = UNSET;
+#ifdef __APPLE__
+ while ((ch = getopt(argc, argv, "-flm")) != -1)
+#else
while ((ch = getopt(argc, argv, "-flmc:")) != -1)
+#endif /* __APPLE__ */
switch ((char)ch) {
case 'f':
fastlogin = 1;
asme = 1;
asthem = 0;
break;
+#ifndef __APPLE__
case 'c':
class = optarg;
break;
+#endif /* !__APPLE__ */
case '?':
default:
usage();
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) {
- p = strrchr(shell, '/');
- if (p)
- ++p;
- else
- p = shell;
- iscsh = strcmp(p, "csh") ? (strcmp(p, "tcsh") ? NO : YES) : YES;
+ iscsh = strcmp(avshell, "csh") ? (strcmp(avshell, "tcsh") ? NO : YES) : YES;
}
setpriority(PRIO_PROCESS, 0, prio);
case 0:
if( setgid(pwd->pw_gid) )
err(1, "setgid");
+ /* Call initgroups(2) after setgid(2) to re-establish memberd */
+ if( initgroups(user, pwd->pw_gid) )
+ err(1, "initgroups");
if( setuid(pwd->pw_uid) )
err(1, "setuid");
if (!asme) {
if (asthem) {
p = getenv("TERM");
- *environ = NULL;
+ environ = &cleanenv;
+ }
+ if (asthem || pwd->pw_uid)
+ setenv("USER", pwd->pw_name, 1);
+ setenv("HOME", pwd->pw_dir, 1);
+ setenv("SHELL", shell, 1);
+
+ if (asthem) {
/*
* Add any environmental variables that the
* PAM modules may have set.
if (environ_pam)
export_pam_environment();
+#ifdef __APPLE__
+ /* 5276965: As documented, set $PATH. */
+ setenv("PATH", "/bin:/usr/bin", 1);
+#else
+ /* set the su'd user's environment & umask */
+ setusercontext(lc, pwd, pwd->pw_uid,
+ LOGIN_SETPATH | LOGIN_SETUMASK |
+ LOGIN_SETENV);
+#endif
if (p)
setenv("TERM", p, 1);
- if (chdir(pwd->pw_dir) < 0)
+
+ p = pam_getenv(pamh, "HOME");
+ if (chdir(p ? p : 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);
}
if (iscsh == YES) {
if (asme)
*np.a-- = "-m";
}
+
+ if (asthem) {
+ avshellbuf[0] = '-';
+ strlcpy(avshellbuf+1, avshell, sizeof(avshellbuf) - 1);
+ avshell = avshellbuf;
+ }
+
/* csh *no longer* strips the first character... */
- *np.a = asthem ? "-su" : "su";
+ *np.a = avshell;
if (ruid != 0)
syslog(LOG_NOTICE, "%s to %s%s", username, user,
usage(void)
{
+#ifdef __APPLE__
+ fprintf(stderr, "usage: su [-] [-flm] [login [args]]\n");
+#else
fprintf(stderr, "usage: su [-] [-flm] [-c class] [login [args]]\n");
+#endif /* __APPLE__ */
exit(1);
}
.Os
.Sh NAME
.Nm test ,
-.Nm [
+.Nm \&[
.Nd condition evaluation utility
.Sh SYNOPSIS
-.Nm test
+.Nm
.Ar expression
-.Nm [
+.Nm \&[
.Ar expression Cm ]
.Sh DESCRIPTION
The
-.Nm test
+.Nm
utility evaluates the expression and, if it evaluates
to true, returns a zero (true) exit status; otherwise
it returns 1 (false).
returns 1 (false).
.Pp
All operators and flags are separate arguments to the
-.Nm test
+.Nm
utility.
.Pp
-The following primaries are used to construct expression:
+The following primaries are used to construct expressions:
.Bl -tag -width Ar
.It Fl b Ar file
True if
comes after
.Ar \&s\&2
based on the ASCII value of their characters.
-.It Ar \&s\&1
-True if
-.Ar \&s\&1
-is not the null
-string.
.It Ar \&n\&1 Fl \&eq Ar \&n\&2
True if the integers
.Ar \&n\&1
operator.
.Sh GRAMMAR AMBIGUITY
The
-.Nm test
+.Nm
grammar is inherently ambiguous. In order to assure a degree of consistency,
the cases described in
.St -p1003.2
command semantics.
.Sh RETURN VALUES
The
-.Nm test
+.Nm
utility exits with one of the following values:
.Bl -tag -width Ds
.It 0
.El
.Sh STANDARDS
The
-.Nm test
+.Nm
utility implements a superset of the
.St -p1003.2
specification.
{
int res;
- if (strcmp(argv[0], "[") == 0) {
+ if (argv[0] && strcmp(argv[0], "[") == 0) {
if (strcmp(argv[--argc], "]"))
errx(2, "missing ]");
argv[argc] = NULL;
-.\" $NetBSD: uname.1,v 1.7 1997/10/20 02:16:38 lukem Exp $
+.\" $NetBSD: uname.1,v 1.12 2005/03/27 18:41:22 peter Exp $
.\"
.\" Copyright (c) 1990 The Regents of the University of California.
.\" All rights reserved.
.\" 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
+.\" 3. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" SUCH DAMAGE.
.\"
.\" from: @(#)du.1 6.13 (Berkeley) 6/20/91
-.\" $NetBSD: uname.1,v 1.7 1997/10/20 02:16:38 lukem Exp $
+.\" $NetBSD: uname.1,v 1.12 2005/03/27 18:41:22 peter Exp $
.\"
-.Dd January 26, 1994
+.Dd November 9, 1998
.Dt UNAME 1
.Os
.Sh NAME
.Nd Print operating system name
.Sh SYNOPSIS
.Nm
-.Op Fl amnpsrv
+.Op Fl amnprsv
.Sh DESCRIPTION
The
.Nm
.Pp
The following options are available:
.Bl -tag -width indent
-.It Fl a
+.It Fl a
Behave as though all of the options
-.Fl mnrsv
+.Fl mnrsv
were specified.
.It Fl m
print the machine hardware name.
that the system is known by to a communications
network).
.It Fl p
-print the generic processor type.
-.It Fl s
-print the operating system name.
+print the machine processor architecture name.
.It Fl r
print the operating system release.
+.It Fl s
+print the operating system name.
.It Fl v
print the operating system version.
.El
.Pp
-If no options are specified,
+If no options are specified,
.Nm
prints the operating system name as if the
.Fl s
.Nm
utility conforms to
.St -p1003.2-92 .
+The
+.Fl p
+option is an extension to the standard.
-/* $NetBSD: uname.c,v 1.9 1997/10/20 02:16:39 lukem Exp $ */
+/* $NetBSD: uname.c,v 1.10 1998/11/09 13:24:05 kleink Exp $ */
/*
* Copyright (c) 1994 Winning Strategies, Inc.
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: uname.c,v 1.9 1997/10/20 02:16:39 lukem Exp $");
+__RCSID("$NetBSD: uname.c,v 1.10 1998/11/09 13:24:05 kleink Exp $");
#endif /* not lint */
+#include <sys/param.h>
+#include <limits.h>
+#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
-#include <locale.h>
#include <unistd.h>
-#include <sys/utsname.h>
#include <err.h>
+#include <sys/sysctl.h>
+#include <sys/utsname.h>
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#else /* !__APPLE__ */
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
int main __P((int, char **));
static void usage __P((void));
-#define PRINT_SYSNAME 0x01
-#define PRINT_NODENAME 0x02
-#define PRINT_RELEASE 0x04
-#define PRINT_VERSION 0x08
-#define PRINT_MACHINE 0x10
-#define PRINT_PROCESSOR 0x20
-#define PRINT_ALL 0x3f
+/* Note that PRINT_MACHINE_ARCH is excluded from PRINT_ALL! */
+#define PRINT_SYSNAME 0x01
+#define PRINT_NODENAME 0x02
+#define PRINT_RELEASE 0x04
+#define PRINT_VERSION 0x08
+#define PRINT_MACHINE 0x10
+#define PRINT_MACHINE_ARCH 0x20
+#define PRINT_ALL \
+ (PRINT_SYSNAME|PRINT_NODENAME|PRINT_RELEASE|PRINT_VERSION|PRINT_MACHINE)
int
main(argc, argv)
char **argv;
{
struct utsname u;
+#ifndef __APPLE__
+ char machine_arch[SYS_NMLN];
+#endif /* !__APPLE__ */
int c;
int space = 0;
int print_mask = 0;
- setlocale(LC_ALL, "");
+ (void)setlocale(LC_ALL, "");
- while ((c = getopt(argc,argv,"amnprsv")) != -1 ) {
- switch ( c ) {
+ while ((c = getopt(argc,argv,"amnprsv")) != -1) {
+ switch (c) {
case 'a':
print_mask |= PRINT_ALL;
+#ifdef __APPLE__
+ if (!COMPAT_MODE("bin/uname", "Unix2003")) {
+ print_mask |= PRINT_MACHINE_ARCH;
+ }
+#endif /* __APPLE__ */
break;
case 'm':
print_mask |= PRINT_MACHINE;
case 'n':
print_mask |= PRINT_NODENAME;
break;
- case 'p':
- print_mask |= PRINT_PROCESSOR;
+ case 'p':
+ print_mask |= PRINT_MACHINE_ARCH;
break;
case 'r':
print_mask |= PRINT_RELEASE;
print_mask = PRINT_SYSNAME;
}
- if (uname(&u)) {
- err(1, "uname");
+ if (uname(&u) != 0) {
+ err(EXIT_FAILURE, "uname");
/* NOTREACHED */
}
+#ifndef __APPLE__
+ if (print_mask & PRINT_MACHINE_ARCH) {
+ int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
+ size_t len = sizeof (machine_arch);
+ if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), machine_arch,
+ &len, NULL, 0) < 0)
+ err(EXIT_FAILURE, "sysctl");
+ }
+#else /* __APPLE__ */
/*
* Let's allow the user to override the output of uname via the shell environment.
* This is a useful feature for cross-compiling (eg. during an OS bringup).
s = getenv ("UNAME_VERSION"); if (s) strncpy (u.version, s, sizeof (u.version));
s = getenv ("UNAME_MACHINE"); if (s) strncpy (u.machine, s, sizeof (u.machine));
}
+#endif /* !__APPLE__ */
if (print_mask & PRINT_SYSNAME) {
space++;
if (space++) putchar(' ');
fputs(u.machine, stdout);
}
- if (print_mask & PRINT_PROCESSOR) {
+ if (print_mask & PRINT_MACHINE_ARCH) {
if (space++) putchar(' ');
+#ifndef __APPLE__
+ fputs(machine_arch, stdout);
+#else
#if defined(__ppc__)
fputs("powerpc", stdout);
#elif defined(__i386__)
#else
fputs("unknown", stdout);
#endif
+#endif /* __APPLE__ */
}
putchar('\n');
- exit(0);
+ exit(EXIT_SUCCESS);
/* NOTREACHED */
}
usage()
{
fprintf(stderr, "usage: uname [-amnprsv]\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
lists the login names of the users currently on the system,
in sorted order, space separated, on a single line.
.Sh FILES
-.Bl -tag -width /var/run/utmp
-.It Pa /var/run/utmp
+.Bl -tag -width /var/run/utmpx
+.It Pa /var/run/utmpx
.El
.Sh SEE ALSO
.Xr finger 1 ,
.Xr last 1 ,
.Xr who 1 ,
-.Xr utmp 5
+.Xr utmpx 5
.Sh HISTORY
The
.Nm
#include <unistd.h>
#include <string.h>
#include <unistd.h>
-#include <utmp.h>
+#include <utmpx.h>
-typedef char namebuf[UT_NAMESIZE];
+typedef char namebuf[_UTX_USERSIZE];
int main __P((int, char **));
int scmp __P((const void *, const void *));
int ncnt = 0;
int nmax = 0;
int cnt;
- struct utmp utmp;
+ struct utmpx *ux;
int ch;
while ((ch = getopt(argc, argv, "")) != -1)
argc -= optind;
argv += optind;
- if (!freopen(_PATH_UTMP, "r", stdin)) {
- err(1, "can't open %s", _PATH_UTMP);
- /* NOTREACHED */
- }
+ setutxent();
- while (fread((char *)&utmp, sizeof(utmp), 1, stdin) == 1) {
- if (*utmp.ut_name) {
+ while ((ux = getutxent()) != NULL) {
+ if (*ux->ut_user && ux->ut_type == USER_PROCESS)
+ {
if (ncnt >= nmax) {
nmax += 32;
names = realloc(names,
}
}
- (void)strncpy(names[ncnt], utmp.ut_name, UT_NAMESIZE);
+ (void)strncpy(names[ncnt], ux->ut_user, _UTX_USERSIZE);
++ncnt;
}
}
if (ncnt) {
- qsort(names, ncnt, UT_NAMESIZE, scmp);
- (void)printf("%.*s", UT_NAMESIZE, names[0]);
+ qsort(names, ncnt, _UTX_USERSIZE, scmp);
+ (void)printf("%.*s", _UTX_USERSIZE, names[0]);
for (cnt = 1; cnt < ncnt; ++cnt)
- if (strncmp(names[cnt], names[cnt - 1], UT_NAMESIZE))
- (void)printf(" %.*s", UT_NAMESIZE, names[cnt]);
+ if (strncmp(names[cnt], names[cnt - 1], _UTX_USERSIZE))
+ (void)printf(" %.*s", _UTX_USERSIZE, names[cnt]);
(void)printf("\n");
}
exit(0);
scmp(p, q)
const void *p, *q;
{
- return(strncmp((char *) p, (char *) q, UT_NAMESIZE));
+ return(strncmp((char *) p, (char *) q, _UTX_USERSIZE));
}
PROF_LIBS = $(LIBS)
-NEXTSTEP_PB_CFLAGS = -no-cpp-precomp -Wno-error -DSUCKAGE=1000000000000
+NEXTSTEP_PB_CFLAGS = -no-cpp-precomp -Wno-error -DHAVE_KVM=0 -DHAVE_UTMPX=1
NEXTSTEP_BUILD_OUTPUT_DIR = /tmp/$(NAME)/Build
* 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
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
extern int use_ampm;
-struct extern_proc;
-void pr_attime(time_t *, time_t *);
-int pr_idle(time_t);
-int proc_compare(struct extern_proc *, struct extern_proc *);
+struct kinfo_proc;
+#ifdef __APPLE__
#define KI_PROC(ki) (&(ki)->kp->kp_proc)
+#endif
+
+void pr_attime(time_t *, time_t *);
+int pr_idle(time_t);
+int proc_compare(struct kinfo_proc *, struct kinfo_proc *);
* 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
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* 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
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
#include <sys/cdefs.h>
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/w/pr_time.c,v 1.19 2002/06/07 01:41:54 jmallett Exp $");
+#endif
+
#ifndef lint
static const char sccsid[] = "@(#)pr_time.c 8.2 (Berkeley) 4/4/94";
#endif
* Print the time since the user logged in.
*/
void
-pr_attime(started, now)
- time_t *started, *now;
+pr_attime(time_t *started, time_t *now)
{
static char buf[256];
struct tm tp, tm;
* Returns number of excess characters that were used for long idle time.
*/
int
-pr_idle(idle)
- time_t idle;
+pr_idle(time_t idle)
{
/* If idle more than 36 hours, print as a number of days. */
if (idle >= 36 * 3600) {
* 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
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-
+#if 0
#ifndef lint
-static const char sccsid[] = "@(#)proc_compare.c 8.2 (Berkeley) 9/23/93";
+static char sccsid[] = "@(#)proc_compare.c 8.2 (Berkeley) 9/23/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/w/proc_compare.c,v 1.9 2004/04/14 09:34:17 bde Exp $");
#endif
#include <sys/param.h>
+#ifdef __APPLE__
+#include <sys/time.h>
+#endif
+#include <sys/proc.h>
#include <sys/time.h>
#include <sys/user.h>
* with the highest cpu utilization is picked (p_estcpu). Ties are
* broken by picking the highest pid.
* 3) The sleeper with the shortest sleep time is next. With ties,
- * we pick out just "short-term" sleepers (PS_SINTR == 0).
+ * we pick out just "short-term" sleepers (TDF_SINTR == 0).
* 4) Further ties are broken by picking the highest pid.
*
* If you change this, be sure to consider making the change in the kernel
* TODO - consider whether pctcpu should be used.
*/
-#include <sys/cdefs.h>
-
+#if !HAVE_KVM
+#define ki_estcpu p_estcpu
+#define ki_pid p_pid
+#define ki_slptime p_slptime
+#define ki_stat p_stat
+#define ki_tdflags p_tdflags
+#endif
-#define ISRUN(p) (((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))
+#define ISRUN(p) (((p)->ki_stat == SRUN) || ((p)->ki_stat == SIDL))
#define TESTAB(a, b) ((a)<<1 | (b))
#define ONLYA 2
#define ONLYB 1
#define BOTH 3
+#if HAVE_KVM
+int
+proc_compare(struct kinfo_proc *p1, struct kinfo_proc *p2)
+{
+#else
int
-proc_compare(p1, p2)
- struct extern_proc *p1, *p2;
+proc_compare(struct kinfo_proc *arg1, struct kinfo_proc *arg2)
{
+ struct extern_proc* p1 = &arg1->kp_proc;
+ struct extern_proc* p2 = &arg2->kp_proc;
+#endif
if (p1 == NULL)
return (1);
/*
* tie - favor one with highest recent cpu utilization
*/
- if (p2->p_estcpu > p1->p_estcpu)
+ if (p2->ki_estcpu > p1->ki_estcpu)
return (1);
- if (p1->p_estcpu > p2->p_estcpu)
+ if (p1->ki_estcpu > p2->ki_estcpu)
return (0);
- return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
+ return (p2->ki_pid > p1->ki_pid); /* tie - return highest pid */
}
/*
* weed out zombies
*/
- switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {
+ switch (TESTAB(p1->ki_stat == SZOMB, p2->ki_stat == SZOMB)) {
case ONLYA:
return (1);
case ONLYB:
return (0);
case BOTH:
- return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
+ return (p2->ki_pid > p1->ki_pid); /* tie - return highest pid */
}
/*
* pick the one with the smallest sleep time
*/
- if (p2->p_slptime > p1->p_slptime)
+ if (p2->ki_slptime > p1->ki_slptime)
return (0);
- if (p1->p_slptime > p2->p_slptime)
+ if (p1->ki_slptime > p2->ki_slptime)
return (1);
- return (p2->p_pid > p1->p_pid); /* tie - return highest pid */
+#ifndef __APPLE__
+ /*
+ * favor one sleeping in a non-interruptible sleep
+ */
+ if (p1->ki_tdflags & TDF_SINTR && (p2->ki_tdflags & TDF_SINTR) == 0)
+ return (1);
+ if (p2->ki_tdflags & TDF_SINTR && (p1->ki_tdflags & TDF_SINTR) == 0)
+ return (0);
+#endif
+ return (p2->ki_pid > p1->ki_pid); /* tie - return highest pid */
}
.\" 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
+.\" 3. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" SUCH DAMAGE.
.\"
.\" @(#)uptime.1 8.2 (Berkeley) 4/18/94
-.\" $FreeBSD: src/usr.bin/w/uptime.1,v 1.7 2001/07/15 08:01:40 dd Exp $
+.\" $FreeBSD: src/usr.bin/w/uptime.1,v 1.8 2002/05/09 11:47:40 joe Exp $
.\"
.Dd April 18, 1994
.Dt UPTIME 1
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 /mach
-.It Pa /mach
-system name list
-.El
.Sh SEE ALSO
.Xr w 1
.Sh HISTORY
.\" 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.
.\" SUCH DAMAGE.
.\"
.\" @(#)w.1 8.1 (Berkeley) 6/6/93
-.\" $FreeBSD: src/usr.bin/w/w.1,v 1.17 2001/07/26 19:20:13 brian Exp $
+.\" $FreeBSD: src/usr.bin/w/w.1,v 1.20 2005/02/13 22:25:25 ru Exp $
.\"
.Dd June 6, 1993
.Dt W 1
.Nd "display who is logged in and what they are doing"
.Sh SYNOPSIS
.Nm
-.Op Fl dhin
-.Op Fl M Ar core
-.Op Fl N Ar system
+.Op Fl hin
.Op Ar user ...
.Sh DESCRIPTION
The
.Pp
The options are as follows:
.Bl -tag -width Ds
-.It Fl d
-dumps out the entire process list on a per controlling
-tty basis, instead of just the top level process.
.It Fl h
Suppress the heading.
.It Fl i
Output is sorted by idle time.
-.It Fl M
-Extract values associated with the name list from the specified
-core instead of the default
-.Dq /dev/kmem .
-.It Fl N
-Extract the name list from the specified system instead of the
-default
-.Dq /mach .
-.It Fl n
-Don't attempt to resolve network addresses (normally
-.Nm
-interprets addresses and attempts to display them as names).
.El
.Pp
If one or more
.Ar user
names are specified, the output is restricted to those users.
-.Sh FILES
-.Bl -tag -width /var/run/utmp -compact
-.It Pa /var/run/utmp
-list of users on the system
-.El
+.Sh COMPATIBILITY
+The
+.Fl M ,
+.FL N ,
+.Fl d ,
+.Fl f ,
+.Fl l ,
+.Fl n ,
+.Fl s ,
+and
+.Fl w
+flags are no longer supported.
.Sh SEE ALSO
.Xr finger 1 ,
.Xr ps 1 ,
.Xr uptime 1 ,
.Xr who 1
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
.Sh BUGS
The notion of the
.Dq current process
utility does not know about the new conventions for detection of background
jobs.
It will sometimes find a background job instead of the right one.
-.Sh COMPATIBILITY
-The
-.Fl f ,
-.Fl l ,
-.Fl s ,
-and
-.Fl w
-flags are no longer supported.
-.Sh HISTORY
-The
-.Nm
-command appeared in
-.Bx 3.0 .
/*-
* Copyright (c) 1980, 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
+ * Portions copyright (c) 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 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
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
#include <sys/cdefs.h>
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/w/w.c,v 1.58 2005/06/04 23:40:09 gad Exp $");
+#endif
+
#ifndef lint
static const char copyright[] =
"@(#) Copyright (c) 1980, 1991, 1993, 1994\n\
#include <sys/socket.h>
#include <sys/tty.h>
+#ifndef __APPLE__
+#include <machine/cpu.h>
+#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#if HAVE_KVM
#include <kvm.h>
+#endif
+#include <langinfo.h>
+#include <libutil.h>
#include <limits.h>
#include <locale.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <timeconv.h>
#include <unistd.h>
+#if HAVE_UTMPX
+#include <utmpx.h>
+/* use utmp values so formatting is the same */
+#define UT_NAMESIZE 8
+#define UT_LINESIZE 8
+#else /* HAVE_UTMPX */
#include <utmp.h>
+#endif /* HAVE_UTMPX */
#include <vis.h>
#include "extern.h"
struct timeval boottime;
+#if !HAVE_UTMPX
struct utmp utmp;
+#endif
struct winsize ws;
+#if HAVE_KVM
kvm_t *kd;
+#endif
time_t now; /* the current time of day */
int ttywidth; /* width of tty */
int argwidth; /* width of tty */
int header = 1; /* true if -h flag: don't print heading */
+#if !HAVE_UTMPX
int nflag; /* true if -n flag: don't convert addrs */
+#endif
+#ifndef __APPLE__
int dflag; /* true if -d flag: output debug info */
+#endif
int sortidle; /* sort by idle time */
int use_ampm; /* use AM/PM time */
int use_comma; /* use comma as floats separator */
*/
struct entry {
struct entry *next;
+#if HAVE_UTMPX
+ struct utmpx utmp;
+#else
struct utmp utmp;
+#endif
dev_t tdev; /* dev_t of terminal */
time_t idle; /* idle time of terminal in seconds */
struct kinfo_proc *kp; /* `most interesting' proc */
struct kinfo_proc *dkp; /* debug option proc list */
} *ep, *ehead = NULL, **nextp = &ehead;
+#ifndef __APPLE__
+#define debugproc(p) *((struct kinfo_proc **)&(p)->ki_udata)
+#else
#define debugproc(p) *((struct kinfo_proc **)&(p)->ki_spare[0])
+#endif
/* W_DISPHOSTSIZE should not be greater than UT_HOSTSIZE */
#define W_DISPHOSTSIZE 16
static struct stat *ttystat(char *, int);
static void usage(int);
static int this_is_uptime(const char *s);
+#if !HAVE_KVM
static void w_getargv(void);
+#endif
char *fmt_argv(char **, char *, int); /* ../../bin/ps/fmt.c */
int
-main(argc, argv)
- int argc;
- char **argv;
+main(int argc, char *argv[])
{
- struct kinfo_proc *kp, *kprocbuf;
+ struct kinfo_proc *kp;
+ struct kinfo_proc *kprocbuf;
struct kinfo_proc *dkp;
struct stat *stp;
+#if HAVE_UTMPX
+ struct utmpx *ux;
+#else
FILE *ut;
+#endif
time_t touched;
+#if HAVE_KVM
int ch, i, nentries, nusers, wcmd, longidle, dropgid;
const char *memf, *nlistf, *p;
+#else
+ int ch, i, nentries, nusers, wcmd, longidle;
+ const char *p;
+#endif /* HAVE_KVM */
char *x_suffix;
+#ifdef __APPLE__
+ char buf[MAXHOSTNAMELEN];
+#else
char buf[MAXHOSTNAMELEN], errbuf[_POSIX2_LINE_MAX];
char fn[MAXHOSTNAMELEN];
+#endif /* __APPLE__ */
char *dot;
+#if !HAVE_KVM
int local_error = 0, retry_count = 0;
size_t bufSize = 0;
size_t orig_bufSize = 0;
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
+#endif
(void)setlocale(LC_ALL, "");
- /*
+#ifndef __APPLE__
use_ampm = (*nl_langinfo(T_FMT_AMPM) != '\0');
use_comma = (*nl_langinfo(RADIXCHAR) != ',');
- */
+#endif
/* Are we w(1) or uptime(1)? */
if (this_is_uptime(argv[0]) == 0) {
p = "dhiflM:N:nsuw";
}
+#if HAVE_KVM
dropgid = 0;
- memf = nlistf = NULL;
+ memf = nlistf = _PATH_DEVNULL;
+#endif
while ((ch = getopt(argc, argv, p)) != -1)
switch (ch) {
+#ifndef __APPLE__
case 'd':
dflag = 1;
break;
+#endif
case 'h':
header = 0;
break;
case 'i':
sortidle = 1;
break;
+#if HAVE_KVM
case 'M':
header = 0;
memf = optarg;
nlistf = optarg;
dropgid = 1;
break;
+#endif /* HAVE_KVM */
+#if !HAVE_UTMPX
case 'n':
nflag = 1;
break;
+#else /* !HAVE_UTMPX */
+ case 'n':
+#endif /* !HAVE_UTMPX */
case 'f': case 'l': case 's': case 'u': case 'w':
+#if !HAVE_KVM
+ case 'M': case 'N':
+#endif
+#ifdef __APPLE__
+ case 'd':
+ warnx("[-MNdflnsuw] no longer supported");
+#else
warnx("[-flsuw] no longer supported");
+#endif
/* FALLTHROUGH */
case '?':
default:
_res.retrans = 2; /* resolver timeout to 2 seconds per try */
_res.retry = 1; /* only try once.. */
+#if HAVE_KVM
/*
* Discard setgid privileges if not the running kernel so that bad
* guys can't print interesting stuff from kernel memory.
if (dropgid)
setgid(getgid());
-#ifdef OLD_PROC
if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL)
errx(1, "%s", errbuf);
#endif
(void)time(&now);
+#if HAVE_UTMPX
+ setutxent();
+#else
if ((ut = fopen(_PATH_UTMP, "r")) == NULL)
err(1, "%s", _PATH_UTMP);
+#endif
if (*argv)
sel_users = argv;
+#if HAVE_UTMPX
+ for (nusers = 0; (ux = getutxent());) {
+ if (ux->ut_user[0] == '\0' || ux->ut_type != USER_PROCESS)
+ continue;
+ if (!(stp = ttystat(ux->ut_line, sizeof(ux->ut_line))))
+ continue; /* corrupted record */
+#else
for (nusers = 0; fread(&utmp, sizeof(utmp), 1, ut);) {
if (utmp.ut_name[0] == '\0')
continue;
if (!(stp = ttystat(utmp.ut_line, UT_LINESIZE)))
continue; /* corrupted record */
+#endif
++nusers;
if (wcmd == 0)
continue;
usermatch = 0;
for (user = sel_users; !usermatch && *user; user++)
+#if HAVE_UTMPX
+ if (!strncmp(ux->ut_user, *user, sizeof(ux->ut_user)))
+#else
if (!strncmp(utmp.ut_name, *user, UT_NAMESIZE))
+#endif
usermatch = 1;
if (!usermatch)
continue;
errx(1, "calloc");
*nextp = ep;
nextp = &ep->next;
+#if HAVE_UTMPX
+ memmove(&ep->utmp, ux, sizeof(*ux));
+#else
memmove(&ep->utmp, &utmp, sizeof(struct utmp));
+#endif
ep->tdev = stp->st_rdev;
#ifdef CPU_CONSDEV
/*
}
#endif
touched = stp->st_atime;
+#ifdef __APPLE__
+ if (touched < ep->utmp.ut_tv.tv_sec) {
+ /* tty untouched since before login */
+ touched = ep->utmp.ut_tv.tv_sec;
+ }
+#else
if (touched < ep->utmp.ut_time) {
/* tty untouched since before login */
touched = ep->utmp.ut_time;
}
+#endif
if ((ep->idle = now - touched) < 0)
ep->idle = 0;
}
+#if HAVE_UTMPX
+ endutxent();
+#else
(void)fclose(ut);
+#endif
if (header || wcmd == 0) {
pr_header(&now, nusers);
if (wcmd == 0) {
-#ifdef OLD_PROC
+#if HAVE_KVM
(void)kvm_close(kd);
#endif
exit(0);
HEADER_LOGIN_IDLE HEADER_WHAT);
}
-#ifdef OLD_PROC
+#if HAVE_KVM
if ((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == NULL)
err(1, "%s", kvm_geterr(kd));
#else
sleep(1);
}
nentries = bufSize / sizeof(struct kinfo_proc);
-#endif
+#endif /* !HAVE_KVM */
+
+#if !HAVE_KVM
+#define ki_stat kp_proc.p_stat
+#define ki_pgid kp_eproc.e_pgid
+#define ki_tpgid kp_eproc.e_tpgid
+#define ki_tdev kp_eproc.e_tdev
+#endif /* !HAVE_KVM */
for (i = 0; i < nentries; i++, kp++) {
- if (kp->kp_proc.p_stat == SIDL || kp->kp_proc.p_stat == SZOMB)
+ if (kp->ki_stat == SIDL || kp->ki_stat == SZOMB)
continue;
for (ep = ehead; ep != NULL; ep = ep->next) {
- if (ep->tdev == kp->kp_eproc.e_tdev) {
+ if (ep->tdev == kp->ki_tdev) {
/*
* proc is associated with this terminal
*/
- if (ep->kp == NULL && kp->kp_eproc.e_pgid == kp->kp_eproc.e_tpgid) {
+ if (ep->kp == NULL && kp->ki_pgid == kp->ki_tpgid) {
/*
* Proc is 'most interesting'
*/
- if (proc_compare(&ep->kp->kp_proc, &kp->kp_proc))
+ if (proc_compare(ep->kp, kp))
ep->kp = kp;
}
/*
*/
dkp = ep->dkp;
ep->dkp = kp;
-/* --bbraun
+#ifndef __APPLE__
debugproc(kp) = dkp;
-*/
+#endif
}
}
}
ep->args = strdup("-");
continue;
}
-#ifdef OLD_PROC
+#if HAVE_KVM
ep->args = fmt_argv(kvm_getargv(kd, ep->kp, argwidth),
- ep->kp->kp_proc.p_comm, MAXCOMLEN);
+ ep->kp->ki_comm, MAXCOMLEN);
#else
w_getargv();
-#endif
+#endif /* HAVE_KVM */
if (ep->args == NULL)
err(1, NULL);
}
}
for (ep = ehead; ep != NULL; ep = ep->next) {
+#if HAVE_UTMPX
+ char host_buf[sizeof(ep->utmp.ut_host) + 1];
+ strlcpy(host_buf, ep->utmp.ut_host, sizeof(host_buf));
+#else
char host_buf[UT_HOSTSIZE + 1];
struct sockaddr_storage ss;
struct sockaddr *sa = (struct sockaddr *)&ss;
struct sockaddr_in *lsin = (struct sockaddr_in *)&ss;
-#ifdef SUCKAGE
- struct hostent *hp;
-#else
struct sockaddr_in6 *lsin6 = (struct sockaddr_in6 *)&ss;
-#endif
+ time_t t;
int isaddr;
host_buf[UT_HOSTSIZE] = '\0';
strncpy(host_buf, ep->utmp.ut_host, UT_HOSTSIZE);
+#endif /* HAVE_UTMPX */
p = *host_buf ? host_buf : "-";
if ((x_suffix = strrchr(p, ':')) != NULL) {
if ((dot = strchr(x_suffix, '.')) != NULL &&
else
x_suffix = NULL;
}
+#if !HAVE_UTMPX
if (!nflag) {
/* Attempt to change an IP address into a name */
isaddr = 0;
memset(&ss, '\0', sizeof(ss));
-#ifdef SUCKAGE
- if (inet_aton(p, &lsin->sin_addr) ) {
- lsin->sin_len = sizeof(*lsin);
- lsin->sin_family = AF_INET;
- isaddr = 1;
- }
-
- hp = gethostbyaddr((char *)&lsin->sin_addr, sizeof(lsin->sin_addr), AF_INET);
- if( hp ) {
- p = hp->h_name;
- }
-#else
if (inet_pton(AF_INET6, p, &lsin6->sin6_addr) == 1) {
lsin6->sin6_len = sizeof(*lsin6);
lsin6->sin6_family = AF_INET6;
if (isaddr && realhostname_sa(fn, sizeof(fn), sa,
sa->sa_len) == HOSTNAME_FOUND)
p = fn;
-#endif
}
+#endif /* !HAVE_UTMPX */
if (x_suffix) {
(void)snprintf(buf, sizeof(buf), "%s:%s", p, x_suffix);
p = buf;
}
-#ifndef SUCKAGE
+#ifndef __APPLE__
if (dflag) {
for (dkp = ep->dkp; dkp != NULL; dkp = debugproc(dkp)) {
const char *ptr;
dkp->ki_pid, ptr);
}
}
-#endif
+#endif /* !__APPLE__ */
(void)printf("%-*.*s %-*.*s %-*.*s ",
+#if HAVE_UTMPX
+ UT_NAMESIZE, (int)sizeof(ep->utmp.ut_user), ep->utmp.ut_user,
+ UT_LINESIZE, (int)sizeof(ep->utmp.ut_line),
+#else
UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name,
UT_LINESIZE, UT_LINESIZE,
+#endif
strncmp(ep->utmp.ut_line, "tty", 3) &&
strncmp(ep->utmp.ut_line, "cua", 3) ?
ep->utmp.ut_line : ep->utmp.ut_line + 3,
W_DISPHOSTSIZE, W_DISPHOSTSIZE, *p ? p : "-");
- pr_attime(&ep->utmp.ut_time, &now);
+#ifdef __APPLE__
+ pr_attime(&ep->utmp.ut_tv.tv_sec, &now);
+#else
+ t = _time_to_time32(ep->utmp.ut_time);
+ pr_attime(&t, &now);
+#endif
longidle = pr_idle(ep->idle);
(void)printf("%.*s\n", argwidth - longidle, ep->args);
-#ifndef OLD_PROC
+#ifdef __APPLE__
free(ep->args);
#endif
}
-#ifdef OLD_PROC
+#if HAVE_KVM
(void)kvm_close(kd);
#else
free(kprocbuf);
-#endif
+#endif /* HAVE_KVM */
exit(0);
}
static void
-pr_header(nowp, nusers)
- time_t *nowp;
- int nusers;
+pr_header(time_t *nowp, int nusers)
{
double avenrun[3];
time_t uptime;
/*
* Print time of day.
*/
- (void)strftime(buf, sizeof(buf) - 1,
- use_ampm ? "%l:%M%p" : "%k:%M", localtime(nowp));
- buf[sizeof(buf) - 1] = '\0';
- (void)printf("%s ", buf);
-
+ if (strftime(buf, sizeof(buf),
+ use_ampm ? "%l:%M%p" : "%k:%M", localtime(nowp)) != 0)
+ (void)printf("%s ", buf);
/*
* Print how long system has been up.
* (Found by looking getting "boottime" from the kernel)
}
static struct stat *
-ttystat(line, sz)
- char *line;
- int sz;
+ttystat(char *line, int sz)
{
static struct stat sb;
char ttybuf[MAXPATHLEN];
(void)snprintf(ttybuf, sizeof(ttybuf), "%s%.*s", _PATH_DEV, sz, line);
- if (stat(ttybuf, &sb)) {
+ if (stat(ttybuf, &sb) == 0) {
+ return (&sb);
+ } else {
warn("%s", ttybuf);
return (NULL);
}
- return (&sb);
}
static void
-usage(wcmd)
- int wcmd;
+usage(int wcmd)
{
if (wcmd)
(void)fprintf(stderr,
- "usage: w [-dhin] [-M core] [-N system] [user ...]\n");
+ "usage: w [hi] [user ...]\n");
else
(void)fprintf(stderr, "usage: uptime\n");
exit(1);
}
static int
-this_is_uptime(s)
- const char *s;
+this_is_uptime(const char *s)
{
const char *u;
return (-1);
}
+#if !HAVE_KVM
static void
w_getargv(void)
{
asprintf(&ep->args, "%s", KI_PROC(ep)->p_comm);
return;
}
+#endif /* HAVE_KVM */
PROJECTVERSION = 2.8
PROJECT_TYPE = Tool
-OTHERLINKED = which.csh
+CFILES = which.c
OTHERSRCS = Makefile Makefile.preamble Makefile.postamble which.1
-OTHERLINKEDOFILES = which.o
+OTHER_CFLAGS = -D__FBSDID=__RCSID
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
CODE_GEN_STYLE = DYNAMIC
-SHELLTOOL = which.csh
-
include $(CoreOSMakefiles)/ProjectBuilder/Makefile.Preamble.Common
-.\" $NetBSD: which.1,v 1.4 1997/10/20 03:19:23 lukem Exp $
-.\"
-.\" Copyright (c) 1980, 1991 Regents of the University of California.
-.\" All rights reserved.
+.\" Manpage Copyright (c) 1995, Jordan Hubbard <jkh@FreeBSD.org>
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" 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
+.\" This product includes software developed by the FreeBSD Project
+.\" its contributors.
+.\" 4. Neither the name of the FreeBSD Project 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.
+.\" THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTOR ``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 CONTRIBUTOR 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: @(#)which.1 6.3 (Berkeley) 4/23/91
-.\" $NetBSD: which.1,v 1.4 1997/10/20 03:19:23 lukem Exp $
+.\" $FreeBSD: src/usr.bin/which/which.1,v 1.25 2005/02/10 16:04:22 ru Exp $
.\"
-.Dd April 23, 1991
+.Dd June 21, 2002
.Dt WHICH 1
-.Os BSD 3
+.Os
.Sh NAME
.Nm which
.Nd "locate a program file in the user's path"
.Sh SYNOPSIS
.Nm
-.Op Ar name
-.Ar ...
+.Op Fl as
+.Ar program ...
.Sh DESCRIPTION
+The
.Nm
-takes a list of names and looks for the files which would be
-executed had these names been given as commands.
-Each argument is expanded if it is aliased,
-and searched for along the user's path.
-Both aliases and path are taken from the user's
-.Pa \&.cshrc
-file.
-.Sh FILES
-.Bl -tag -width ~/\&.cshrc
-.It Pa ~/\&.cshrc
-source of aliases and path values
+utility
+takes a list of command names and searches the path for each executable
+file that would be run had these commands actually been invoked.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl a
+List all instances of executables found (instead of just the first one
+of each).
+.It Fl s
+No output, just return 0 if any of the executables are found, or 1 if
+none are found.
.El
-.Sh DIAGNOSTICS
-A diagnostic is given for names which are aliased to more than a single
-word,
-or if an executable file with the argument name was not found in the path.
-.Sh BUGS
-Must be executed by a
+.Pp
+Some shells may provide a builtin
+.Nm
+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 ,
-or some other shell which knows about aliases.
+.Xr find 1 ,
+.Xr locate 1 ,
+.Xr whereis 1
.Sh HISTORY
The
.Nm
-command appeared in
-.Bx 3.0 .
+command first appeared in
+.Fx 2.1 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+utility was originally written in Perl and was contributed by
+.An Wolfram Schneider Aq wosch@FreeBSD.org .
+The current version of
+.Nm
+was rewritten in C by
+.An Daniel Papasian Aq dpapasia@andrew.cmu.edu .
--- /dev/null
+/**
+ * Copyright (c) 2000 Dan Papasian. 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD: src/usr.bin/which/which.c,v 1.6 2005/02/10 16:04:22 ru Exp $");
+
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void usage(void);
+static int print_matches(char *, char *);
+
+int silent;
+int allpaths;
+
+int
+main(int argc, char **argv)
+{
+ char *p, *path;
+ ssize_t pathlen;
+ int opt, status;
+
+ status = EXIT_SUCCESS;
+
+ while ((opt = getopt(argc, argv, "as")) != -1) {
+ switch (opt) {
+ case 'a':
+ allpaths = 1;
+ break;
+ case 's':
+ silent = 1;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ argv += optind;
+ argc -= optind;
+
+ if (argc == 0)
+ usage();
+
+ if ((p = getenv("PATH")) == NULL)
+ exit(EXIT_FAILURE);
+ pathlen = strlen(p) + 1;
+ path = malloc(pathlen);
+ if (path == NULL)
+ err(EXIT_FAILURE, NULL);
+
+ while (argc > 0) {
+ memcpy(path, p, pathlen);
+
+ if (strlen(*argv) >= FILENAME_MAX ||
+ print_matches(path, *argv) == -1)
+ status = EXIT_FAILURE;
+
+ argv++;
+ argc--;
+ }
+
+ exit(status);
+}
+
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr, "usage: which [-as] program ...\n");
+ exit(EXIT_FAILURE);
+}
+
+static int
+is_there(char *candidate)
+{
+ struct stat fin;
+
+ /* XXX work around access(2) false positives for superuser */
+ if (access(candidate, X_OK) == 0 &&
+ stat(candidate, &fin) == 0 &&
+ S_ISREG(fin.st_mode) &&
+ (getuid() != 0 ||
+ (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) {
+ if (!silent)
+ printf("%s\n", candidate);
+ return (1);
+ }
+ return (0);
+}
+
+static int
+print_matches(char *path, char *filename)
+{
+ char candidate[PATH_MAX];
+ const char *d;
+ int found;
+
+ if (strchr(filename, '/') != NULL)
+ return (is_there(filename) ? 0 : -1);
+ found = 0;
+ while ((d = strsep(&path, ":")) != NULL) {
+ if (*d == '\0')
+ d = ".";
+ if (snprintf(candidate, sizeof(candidate), "%s/%s", d,
+ filename) >= (int)sizeof(candidate))
+ continue;
+ if (is_there(candidate)) {
+ found = 1;
+ if (!allpaths)
+ break;
+ }
+ }
+ return (found ? 0 : -1);
+}
+
+++ /dev/null
-#!/bin/csh
-#
-# DO NOT USE "csh -f"
-#
-# Copyright (c) 1983 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.
-#
-# @(#)which.csh 5.5 (Berkeley) 4/18/91
-#
-
-# which : tells you which program you get
-#
-set prompt = "% "
-set noglob
-foreach arg ( $argv )
- set alius = `alias $arg`
- switch ( $#alius )
- case 0 :
- breaksw
- case 1 :
- set arg = $alius[1]
- breaksw
- default :
- echo ${arg}: " " aliased to $alius
- continue
- endsw
- unset found
- if ( $arg:h != $arg:t ) then
- if ( -e $arg ) then
- echo $arg
- else
- echo $arg not found
- endif
- continue
- else
- foreach i ( $path )
- if ( -x $i/$arg && ! -d $i/$arg ) then
- echo $i/$arg
- set found
- break
- endif
- end
- endif
- if ( ! $?found ) then
- echo no $arg in $path
- endif
-end
Show idle time for each user in hours and minutes as
.Ar hh Ns : Ns Ar mm ,
.Ql \&.
-if the user has been idle less that a minute, and
+if the user has been idle less than a minute, and
.Dq Li old
if the user has been idle more than 24 hours.
+Additionally, display the PID of the user's login process.
.It Cm am I
Equivalent to
.Fl m .
By default,
.Nm
gathers information from the file
-.Pa /var/run/utmp .
+.Pa /var/run/utmpx .
An alternate
.Ar file
-may be specified which is usually
-.Pa /var/log/wtmp
-(or
-.Pa /var/log/wtmp.[0-6]
-depending on site policy as
-.Pa wtmp
-can grow quite large and daily versions may or may not
-be kept around after compression by
-.Xr ac 8 ) .
-The
-.Pa wtmp
-file contains a record of every login, logout,
-crash, shutdown and date change
-since
-.Pa wtmp
-was last truncated or
-created.
-.Pp
-If
-.Pa /var/log/wtmp
-is being used as the file, the user name may be empty
-or one of the special characters '|', '}' and '~'.
-Logouts produce
-an output line without any user name.
-For more information on the
-special characters, see
-.Xr utmp 5 .
+may be specified.
+.Sh LEGACY DESCRIPTION
+In legacy mode,
+.Fl u
+does not display the PID of the user's login process.
.Sh ENVIRONMENT
The
.Ev COLUMNS , LANG , LC_ALL
as described in
.Xr environ 7 .
.Sh FILES
-.Bl -tag -width /var/log/wtmp.[0-6] -compact
-.It Pa /var/run/utmp
-.It Pa /var/log/wtmp
-.It Pa /var/log/wtmp.[0-6]
+.Bl -tag -width /var/log/utmpx -compact
+.It Pa /var/run/utmpx
.El
.Sh DIAGNOSTICS
.Ex -std
.Xr last 1 ,
.Xr users 1 ,
.Xr w 1 ,
-.Xr utmp 5
+.Xr compat 5 ,
+.Xr utmpx 5
.Sh STANDARDS
The
.Nm
#include <time.h>
#include <timeconv.h>
#include <unistd.h>
-#include <utmp.h>
#include <utmpx.h>
+/* from utmp.h; used only for print formatting */
+#define UT_NAMESIZE 8
+#define UT_LINESIZE 8
+#define UT_HOSTSIZE 16
+
static void heading(void);
-static void process_utmp(FILE *);
-static void process_wtmp(FILE *);
-static void quick(FILE *);
-static void row(struct utmp *);
+static void process_utmp(void);
+static void process_wtmp();
+static void quick(void);
+static void row(const struct utmpx *);
static int ttywidth(void);
static void usage(void);
-static void whoami(FILE *);
+static void whoami(void);
static int bflag; /* date & time of last reboot */
static int dflag; /* dead processes */
#define COMPAT_MODE(a,b) (1)
#endif /* __APPLE__ */
static int unix2003_std;
-static struct utmpx *utx_db = NULL;
int
main(int argc, char *argv[])
{
int ch;
- const char *file;
- FILE *fp;
- FILE *wtmp_fp;
setlocale(LC_TIME, "");
if (argc > 1)
usage();
- if (*argv != NULL)
- file = *argv;
- else
- file = _PATH_UTMP;
- if ((fp = fopen(file, "r")) == NULL)
- err(1, "%s", file);
+ if (*argv != NULL) {
+ if (!utmpxname(*argv) || !wtmpxname(*argv))
+ usage();
+ }
if (qflag)
- quick(fp);
+ quick();
else {
if (sflag)
Tflag = uflag = 0;
if (Hflag)
heading();
if (mflag)
- whoami(fp);
+ whoami();
else
- /* read and process utmp file for relevant options */
+ /* read and process utmpx file for relevant options */
if( Tflag || uflag || !(bflag || dflag || lflag || pflag || rflag) )
- process_utmp(fp);
+ process_utmp();
}
- fclose(fp);
-
/* read and process wtmp file for relevant options */
if (bflag || dflag || lflag || pflag || rflag ) {
- /* Open the wtmp file */
- if ((wtmp_fp = fopen(_PATH_WTMP, "r")) == NULL)
- err(1, "%s", _PATH_WTMP);
- else {
- process_wtmp(wtmp_fp);
- fclose(wtmp_fp);
- }
+ process_wtmp();
}
- if (utx_db) {
- endutxent(); /* close db */
- }
+ endutxent();
exit(0);
}
}
static void
-row(struct utmp *ut)
+row(const struct utmpx *ut)
{
- char buf[80], tty[sizeof(_PATH_DEV) + UT_LINESIZE];
+ char buf[80], tty[sizeof(_PATH_DEV) + _UTX_LINESIZE];
struct stat sb;
time_t idle, t;
static int d_first = -1;
if (Tflag || uflag) {
snprintf(tty, sizeof(tty), "%s%.*s", _PATH_DEV,
- UT_LINESIZE, ut->ut_line);
+ _UTX_LINESIZE, ut->ut_line);
state = '?';
idle = 0;
if (stat(tty, &sb) == 0) {
}
if (unix2003_std && !Tflag) {
/* uflag without Tflag */
- struct utmpx * utx = NULL;
- if (!utx_db) {
- utx_db = getutxent(); /* just to open db */
- }
- if (utx_db) {
- struct utmpx this_line;
- setutxent(); /* reset db */
- memset(&this_line, 0, sizeof(this_line));
-/*
- strcpy(this_line.ut_user, ut->ut_name);
-*/
- strcpy(this_line.ut_line, ut->ut_line);
- utx = getutxline(&this_line);
- }
- if (utx) {
+ if (ut->ut_pid) {
snprintf(login_pidstr,sizeof(login_pidstr),
- "%8d",utx->ut_pid);
+ "%8d",ut->ut_pid);
} else {
strcpy(login_pidstr," ?");
}
}
}
- printf("%-*.*s ", UT_NAMESIZE, UT_NAMESIZE, ut->ut_name);
+ printf("%-*.*s ", UT_NAMESIZE, _UTX_USERSIZE, ut->ut_user);
if (Tflag)
printf("%c ", state);
- printf("%-*.*s ", UT_LINESIZE, UT_LINESIZE, ut->ut_line);
- t = _time32_to_time(ut->ut_time);
+ printf("%-*.*s ", UT_LINESIZE, _UTX_LINESIZE, ut->ut_line);
+ t = _time32_to_time(ut->ut_tv.tv_sec);
tm = localtime(&t);
strftime(buf, sizeof(buf), d_first ? "%e %b %R" : "%b %e %R", tm);
printf("%-*s ", 12, buf);
}
}
if (*ut->ut_host != '\0')
- printf("(%.*s)", UT_HOSTSIZE, ut->ut_host);
+ printf("(%.*s)", _UTX_HOSTSIZE, ut->ut_host);
putchar('\n');
}
static void
-process_utmp(FILE *fp)
+process_utmp(void)
{
- struct utmp ut;
+ struct utmpx *ut;
- while (fread(&ut, sizeof(ut), 1, fp) == 1)
- if (*ut.ut_name != '\0') {
- row(&ut);
+ while ((ut = getutxent()) != NULL)
+ if (*ut->ut_user != '\0' && ut->ut_type == USER_PROCESS) {
+ row(ut);
}
}
/* For some options, process the wtmp file to generate output */
static void
-process_wtmp(FILE *fp)
+process_wtmp(void)
{
- struct utmp ut;
- struct utmp lboot_ut = { "", "", "", 0 };
+ struct utmpx *ut;
+ struct utmpx lboot_ut;
int num = 0; /* count of user entries */
- while (fread(&ut, sizeof(ut), 1, fp) == 1)
- if (*ut.ut_name != '\0') {
- if (bflag && (!strcmp(ut.ut_name, "reboot"))) {
- memcpy(&lboot_ut, &ut, sizeof(ut));
- }
- else
- num++;
- };
+ setutxent_wtmp(0); /* zero means reverse chronological */
+ lboot_ut.ut_type = 0;
+ while (!lboot_ut.ut_type && (ut = getutxent_wtmp()) != NULL) {
+ switch(ut->ut_type) {
+ case BOOT_TIME:
+ lboot_ut = *ut;
+ strcpy(lboot_ut.ut_user, "reboot");
+ strcpy(lboot_ut.ut_line, "~");
+ break;
+ case INIT_PROCESS:
+ case LOGIN_PROCESS:
+ case USER_PROCESS:
+ case DEAD_PROCESS:
+ num++;
+ break;
+ }
+ }
+ endutxent_wtmp();
- if (bflag && (!strcmp(lboot_ut.ut_name, "reboot")))
+ if (bflag && lboot_ut.ut_type)
row(&lboot_ut);
/* run level of the init process is unknown in BSD system. If multi
}
static void
-quick(FILE *fp)
+quick(void)
{
- struct utmp ut;
+ struct utmpx *ut;
int col, ncols, num;
ncols = ttywidth();
col = num = 0;
- while (fread(&ut, sizeof(ut), 1, fp) == 1) {
- if (*ut.ut_name == '\0')
+ while ((ut = getutxent()) != NULL) {
+ if (*ut->ut_user == '\0' || ut->ut_type != USER_PROCESS)
continue;
- printf("%-*.*s", UT_NAMESIZE, UT_NAMESIZE, ut.ut_name);
+ printf("%-*.*s", UT_NAMESIZE, _UTX_USERSIZE, ut->ut_user);
if (++col < ncols / (UT_NAMESIZE + 1))
putchar(' ');
else {
}
static void
-whoami(FILE *fp)
+whoami(void)
{
- struct utmp ut;
+ struct utmpx ut;
+ struct utmpx *u;
struct passwd *pwd;
const char *name, *p, *tty;
else if ((p = strrchr(tty, '/')) != NULL)
tty = p + 1;
+ memset(&ut, 0, sizeof(ut));
+ strncpy(ut.ut_line, tty, sizeof(ut.ut_line));
+ memcpy(ut.ut_id, tty + (strlen(tty) - sizeof(ut.ut_id)), sizeof(ut.ut_id));
+ ut.ut_type = USER_PROCESS;
/* Search utmp for our tty, dump first matching record. */
- while (fread(&ut, sizeof(ut), 1, fp) == 1)
- if (*ut.ut_name != '\0' && strncmp(ut.ut_line, tty,
- UT_LINESIZE) == 0) {
- row(&ut);
- return;
- }
+ u = getutxid(&ut);
+ if (u) {
+ row(u);
+ return;
+ }
- /* Not found; fill the utmp structure with the information we have. */
- memset(&ut, 0, sizeof(ut));
+ /* Not found; fill the utmpx structure with the information we have. */
if ((pwd = getpwuid(getuid())) != NULL)
name = pwd->pw_name;
else
name = "?";
- strncpy(ut.ut_name, name, UT_NAMESIZE);
- strncpy(ut.ut_line, tty, UT_LINESIZE);
- ut.ut_time = _time_to_time32(time(NULL));
+ strncpy(ut.ut_user, name, _UTX_USERSIZE);
+ ut.ut_tv.tv_sec = _time_to_time32(time(NULL));
row(&ut);
}
OTHERSRCS = Makefile Makefile.preamble Makefile.postamble xargs.1
+OTHER_CFLAGS = -D__FBSDID=__RCSID
MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
CODE_GEN_STYLE = DYNAMIC
-/* $NetBSD: pathnames.h,v 1.4 1995/11/15 16:11:17 thorpej Exp $ */
-
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*/
#include <sys/cdefs.h>
-__RCSID("$FreeBSD: src/usr.bin/xargs/strnsubst.c,v 1.6 2002/06/22 12:58:42 jmallett Exp $");
+__FBSDID("$FreeBSD: src/usr.bin/xargs/strnsubst.c,v 1.7 2004/10/18 15:40:47 cperciva Exp $");
#include <err.h>
#include <stdlib.h>
replstr = "";
if (match == NULL || replstr == NULL || maxsize == strlen(s1)) {
- strncpy(s2, s1, maxsize);
- s2[maxsize - 1] = '\0';
+ strlcpy(s2, s1, maxsize);
goto done;
}
this = strstr(s1, match);
if (this == NULL)
break;
- if ((strlen(s2) + ((uintptr_t)this - (uintptr_t)s1) +
- (strlen(replstr) - 1)) > maxsize && *replstr != '\0') {
- strncat(s2, s1, maxsize);
- s2[maxsize - 1] = '\0';
+ if ((strlen(s2) + strlen(s1) + strlen(replstr) -
+ strlen(match) + 1) > maxsize) {
+ strlcat(s2, s1, maxsize);
goto done;
}
strncat(s2, s1, (uintptr_t)this - (uintptr_t)s1);
.\" SUCH DAMAGE.
.\"
.\" @(#)xargs.1 8.1 (Berkeley) 6/6/93
-.\" $FreeBSD: src/usr.bin/xargs/xargs.1,v 1.23 2002/06/22 12:47:56 jmallett Exp $
+.\" $FreeBSD: src/usr.bin/xargs/xargs.1,v 1.34 2005/05/21 09:55:09 ru Exp $
.\" $xMach: xargs.1,v 1.2 2002/02/23 05:23:37 tim Exp $
.\"
-.Dd May 7, 2001
+.Dd August 2, 2004
.Dt XARGS 1
.Os
.Sh NAME
.Nd "construct argument list(s) and execute utility"
.Sh SYNOPSIS
.Nm
-.Op Fl 0pt
+.Op Fl 0opt
.Op Fl E Ar eofstr
.Oo
.Fl I Ar replstr
.Fl n Ar number
.Op Fl x
.Oc
+.Op Fl P Ar maxprocs
.Op Fl s Ar size
.Op Ar utility Op Ar argument ...
.Sh DESCRIPTION
The
.Nm
-utility reads space, tab, newline and end-of-file delimited arguments
-from the standard input and executes the specified
+utility reads space, tab, newline and end-of-file delimited strings
+from the standard input and executes
.Ar utility
-with them as
+with the strings as
arguments.
.Pp
-The utility and any arguments specified on the command line are given
-to the
+Any arguments specified on the command line are given to
.Ar utility
upon each invocation, followed by some number of the arguments read
-from standard input.
-The
-.Ar utility
+from the standard input of
+.Nm .
+The utility
is repeatedly executed until standard input is exhausted.
.Pp
Spaces, tabs and newlines may be embedded in arguments using single
.It Fl I Ar replstr
Execute
.Ar utility
-for each input line, replacing one or more occurences of
+for each input line, replacing one or more occurrences of
.Ar replstr
in up to
.Ar replacements
will use the data read from standard input to replace the first occurrence of
.Ar replstr
instead of appending that data after all other arguments.
-This option will not effect how many arguments will be read from input
+This option will not affect how many arguments will be read from input
.Pq Fl n ,
or the size of the command(s)
.Nm
.Ar utility
for every
.Ar number
-lines read.
+non-empty lines read.
+A line ending with a space continues to the next non-empty line.
If EOF is reached and fewer lines have been read than
.Ar number
then
.Ar utility
will be called with the available lines.
+The
+.Fl L
+and
+.Fl n
+options are mutually-exclusive; the last one given will be used.
.It Fl n Ar number
Set the maximum number of arguments taken from standard input for each
-invocation of the utility.
+invocation of
+.Ar utility .
An invocation of
.Ar utility
will use less than
The current default value for
.Ar number
is 5000.
+.It Fl o
+Reopen stdin as
+.Pa /dev/tty
+in the child process before executing the command.
+This is useful if you want
+.Nm
+to run an interactive application.
+.It Fl P Ar maxprocs
+Parallel mode: run at most
+.Ar maxprocs
+invocations of
+.Ar utility
+at once.
.It Fl p
Echo each command to be executed and ask the user whether it should be
executed.
Specify the maximum number of arguments that
.Fl I
will do replacement in.
+If
+.Ar replacements
+is negative, the number of arguments in which to replace is unbounded.
.It Fl s Ar size
Set the maximum number of bytes for the command line length provided to
.Ar utility .
arguments will not fit in the specified (or default) command line length.
.El
.Pp
-If no
+If
.Ar utility
-is specified,
+is omitted,
.Xr echo 1
is used.
.Pp
utility exits immediately (without processing any further input) if a
command line cannot be assembled,
.Ar utility
-cannot be invoked, an invocation of the utility is terminated by a signal
-or an invocation of the utility exits with a value of 255.
-.Sh DIAGNOSTICS
+cannot be invoked, an invocation of
+.Ar utility
+is terminated by a signal,
+or an invocation of
+.Ar utility
+exits with a value of 255.
+.Sh LEGACY DESCRIPTION
+In legacy mode, the
+.Fl L
+option treats all newlines as end-of-line, regardless of whether
+the line is empty or ends with a space.
+In addition, the
+.Fl L
+and
+.Fl n
+options are not mutually-exclusive.
+.Sh EXIT STATUS
The
.Nm
utility exits with a value of 0 if no error occurs.
.Sh SEE ALSO
.Xr echo 1 ,
.Xr find 1 ,
-.Xr execvp 3
+.Xr execvp 3 ,
+.Xr compat 5
.Sh STANDARDS
The
.Nm
.St -p1003.2
compliant.
The
-.Fl J
+.Fl J , o , P
and
.Fl R
options are non-standard
.Xr execvp 3
failing with
.Er E2BIG .
+.Pp
+The
+.Nm
+utility does not take multibyte characters into account when performing
+string comparisons for the
+.Fl I
+and
+.Fl J
+options, which may lead to incorrect results in some locales.
* $xMach: xargs.c,v 1.6 2002/02/23 05:27:47 tim Exp $
*/
+#if 0
#ifndef lint
static const char copyright[] =
"@(#) Copyright (c) 1990, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
-#if 0
#ifndef lint
static char sccsid[] = "@(#)xargs.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#endif
-
#include <sys/cdefs.h>
-__RCSID("$FreeBSD: src/usr.bin/xargs/xargs.c,v 1.41 2002/07/01 03:21:05 tjr Exp $");
+__FBSDID("$FreeBSD: src/usr.bin/xargs/xargs.c,v 1.57 2005/02/27 02:01:31 gad Exp $");
-#include <sys/types.h>
+#include <sys/param.h>
#include <sys/wait.h>
#include <err.h>
#include <errno.h>
+#include <fcntl.h>
+#include <langinfo.h>
#include <locale.h>
#include <paths.h>
#include <regex.h>
static void run(char **);
static void usage(void);
void strnsubst(char **, const char *, const char *, size_t);
+static void waitchildren(const char *, int);
+
+static int last_was_newline = 1;
+static int last_was_blank = 0;
static char echo[] = _PATH_ECHO;
-static char **av, **bxp, **ep, **exp, **xp;
+static char **av, **bxp, **ep, **endxp, **xp;
static char *argp, *bbp, *ebp, *inpline, *p, *replstr;
static const char *eofstr;
-static int count, insingle, indouble, pflag, tflag, Rflag, rval, zflag;
+static int count, insingle, indouble, oflag, pflag, tflag, Rflag, rval, zflag;
static int cnt, Iflag, jfound, Lflag, wasquoted, xflag;
-static int last_was_newline = 1;
-static int last_was_blank = 0;
+static int curprocs, maxprocs;
+
+static volatile int childerr;
extern char **environ;
long arg_max;
int ch, Jflag, nargs, nflag, nline;
size_t linelen;
+ char *endptr;
inpline = replstr = NULL;
ep = environ;
eofstr = "";
Jflag = nflag = 0;
+ (void)setlocale(LC_ALL, "");
+
/*
* POSIX.2 limits the exec line length to ARG_MAX - 2K. Running that
* caused some E2BIG errors, so it was changed to ARG_MAX - 4K. Given
/* 1 byte for each '\0' */
nline -= strlen(*ep++) + 1 + sizeof(*ep);
}
- while ((ch = getopt(argc, argv, "0E:I:J:L:n:pR:s:tx")) != -1)
+ maxprocs = 1;
+ while ((ch = getopt(argc, argv, "0E:I:J:L:n:oP:pR:s:tx")) != -1)
switch(ch) {
case 'E':
eofstr = optarg;
break;
case 'n':
nflag = 1;
+ if ((nargs = atoi(optarg)) <= 0)
+ errx(1, "illegal argument count");
if (COMPAT_MODE("bin/xargs", "Unix2003")) {
Lflag = 0; /* Override */
}
- if ((nargs = atoi(optarg)) <= 0)
- errx(1, "illegal argument count");
+ break;
+ case 'o':
+ oflag = 1;
+ break;
+ case 'P':
+ if ((maxprocs = atoi(optarg)) <= 0)
+ errx(1, "max. processes must be >0");
break;
case 'p':
pflag = 1;
break;
case 'R':
- if ((Rflag = atoi(optarg)) <= 0)
- errx(1, "illegal number of replacements");
+ Rflag = strtol(optarg, &endptr, 10);
+ if (*endptr != '\0')
+ errx(1, "replacements must be a number");
break;
case 's':
nline = atoi(optarg);
* count doesn't include the trailing NULL pointer, so the malloc
* added in an extra slot.
*/
- exp = (xp = bxp) + nargs;
+ endxp = (xp = bxp) + nargs;
/*
* Allocate buffer space for the arguments read from stdin and the
switch(ch = getchar()) {
case EOF:
/* No arguments since last exec. */
- if (p == bbp)
+ if (p == bbp) {
+ waitchildren(*argv, 1);
exit(rval);
+ }
goto arg1;
case ' ':
last_was_blank = 1;
goto addch;
goto arg2;
case '\0':
- if (zflag)
+ if (zflag) {
+ /*
+ * Increment 'count', so that nulls will be treated
+ * as end-of-line, as well as end-of-argument. This
+ * is needed so -0 works properly with -I and -L.
+ */
+ count++;
goto arg2;
+ }
goto addch;
case '\n':
+ if (zflag)
+ goto addch;
if (COMPAT_MODE("bin/xargs", "Unix2003")) {
if (last_was_newline) {
/* don't count empty line */
count++;
}
last_was_newline = 1;
- if (zflag)
- goto addch;
/* Quotes do not escape newlines. */
arg1: if (insingle || indouble)
/*
* If this string is not zero
* length, append a space for
- * seperation before the next
+ * separation before the next
* argument.
*/
if ((curlen = strlen(inpline)))
* of input lines, as specified by -L is the same as
* maxing out on arguments.
*/
- if (xp == exp || p > ebp || ch == EOF ||
+ if (xp == endxp || p > ebp || ch == EOF ||
(Lflag <= count && xflag) || foundeof) {
- if (xflag && xp != exp && p > ebp)
+ if (xflag && xp != endxp && p > ebp)
errx(1, "insufficient space for arguments");
if (jfound) {
for (avj = argv; *avj; avj++)
*xp++ = *avj;
}
prerun(argc, av);
- if (ch == EOF || foundeof)
+ if (ch == EOF || foundeof) {
+ waitchildren(*argv, 1);
exit(rval);
+ }
p = bbp;
xp = bxp;
count = 0;
last_was_blank = 0;
if (ch != '\n' || last_was_backslashed)
last_was_newline = 0;
- return;
}
/*
/*
* For each argument to utility, if we have not used up
* the number of replacements we are allowed to do, and
- * if the argument contains at least one occurance of
+ * if the argument contains at least one occurrence of
* replstr, call strnsubst(), else just save the string.
* Iterations over elements of avj and tmp are done
* where appropriate.
*tmp = *avj++;
if (repls && strstr(*tmp, replstr) != NULL) {
strnsubst(tmp++, replstr, inpline, (size_t)255);
- repls--;
+ if (repls > 0)
+ repls--;
} else {
if ((*tmp = strdup(*tmp)) == NULL)
errx(1, "strdup failed");
static void
run(char **argv)
{
- volatile int childerr;
- char **avec;
pid_t pid;
- int status;
+ int fd;
+ char **avec;
/*
* If the user wants to be notified of each command before it is
case -1:
err(1, "vfork");
case 0:
+ if (oflag) {
+ if ((fd = open(_PATH_TTY, O_RDONLY)) == -1)
+ err(1, "can't open /dev/tty");
+ } else {
+ fd = open(_PATH_DEVNULL, O_RDONLY);
+ }
+ if (fd > STDIN_FILENO) {
+ if (dup2(fd, STDIN_FILENO) != 0)
+ err(1, "can't dup2 to stdin");
+ close(fd);
+ }
execvp(argv[0], argv);
childerr = errno;
_exit(1);
}
- pid = waitpid(pid, &status, 0);
- if (pid == -1)
- err(1, "waitpid");
- /* If we couldn't invoke the utility, exit. */
- if (childerr != 0)
- err(childerr == ENOENT ? 127 : 126, "%s", *argv);
- /* If utility signaled or exited with a value of 255, exit 1-125. */
- if (WIFSIGNALED(status) || WEXITSTATUS(status) == 255)
- exit(1);
- if (WEXITSTATUS(status))
- rval = 1;
+ curprocs++;
+ waitchildren(*argv, 0);
+}
+
+static void
+waitchildren(const char *name, int waitall)
+{
+ pid_t pid;
+ int status;
+
+ while ((pid = waitpid(-1, &status, !waitall && curprocs < maxprocs ?
+ WNOHANG : 0)) > 0) {
+ curprocs--;
+ /* If we couldn't invoke the utility, exit. */
+ if (childerr != 0) {
+ errno = childerr;
+ err(errno == ENOENT ? 127 : 126, "%s", name);
+ }
+ /*
+ * If utility signaled or exited with a value of 255,
+ * exit 1-125.
+ */
+ if (WIFSIGNALED(status) || WEXITSTATUS(status) == 255)
+ exit(1);
+ if (WEXITSTATUS(status))
+ rval = 1;
+ }
+ if (pid == -1 && errno != ECHILD)
+ err(1, "wait3");
}
/*
(void)fprintf(stderr, "?...");
(void)fflush(stderr);
if ((response = fgetln(ttyfp, &rsize)) == NULL ||
- regcomp(&cre,
- "^[yY]",
- REG_BASIC) != 0) {
+ regcomp(&cre, nl_langinfo(YESEXPR), REG_BASIC) != 0) {
(void)fclose(ttyfp);
return (0);
}
usage(void)
{
fprintf(stderr,
-"usage: xargs [-0pt] [-E eofstr] [-I replstr [-R replacements]] [-J replstr]\n"
-" [-L number] [-n number [-x] [-s size] [utility [argument ...]]\n");
+"usage: xargs [-0opt] [-E eofstr] [-I replstr [-R replacements]] [-J replstr]\n"
+" [-L number] [-n number [-x]] [-P maxprocs] [-s size]\n"
+" [utility [argument ...]]\n");
exit(1);
}